Files
devclaw-gitea/lib/roles/registry.ts
Lauren ten Hoor be8e0f4db1 refactor: Centralize role types and configuration (#190)
Creates a single source of truth for all worker roles via lib/roles/.

## New: lib/roles/

- **registry.ts** — All role definitions (dev, qa, architect) with
  levels, models, emoji, completion results, session key patterns
- **types.ts** — RoleConfig interface
- **selectors.ts** — Query helpers: getRole(), getLevelsForRole(),
  resolveModel(), isValidResult(), roleForLevel(), etc.
- **index.ts** — Barrel exports

## Migrated Files

- **lib/tiers.ts** — Now delegates to registry (backward compat kept)
- **lib/dispatch.ts** — Uses registry for emoji resolution
- **lib/bootstrap-hook.ts** — Uses registry for session key pattern
- **lib/services/tick.ts** — Uses registry for level detection
- **lib/services/heartbeat.ts** — Uses registry for role iteration
- **lib/tools/health.ts** — Uses registry for role iteration
- **lib/tools/work-start.ts** — Uses registry for role enum
- **lib/tools/work-finish.ts** — Uses registry for result validation
- **lib/tools/project-register.ts** — Uses registry for level lists

## Key Benefits

- Adding a new role = add entry to registry.ts (single file)
- No more scattered role unions ("dev" | "qa" | "architect")
- Type-safe role/level/result validation from registry
- Session key pattern auto-generated from registry
- All 64 tests passing (22 new registry tests + 42 existing)
2026-02-14 17:15:54 +08:00

76 lines
1.9 KiB
TypeScript

/**
* roles/registry.ts — Single source of truth for all worker roles.
*
* Adding a new role? Just add an entry here. Everything else derives from this.
*
* Each role defines:
* - Identity (id, displayName)
* - Levels and models
* - Emoji for announcements
* - Valid completion results
* - Session key matching
* - Notification preferences
*/
import type { RoleConfig } from "./types.js";
export const ROLE_REGISTRY: Record<string, RoleConfig> = {
dev: {
id: "dev",
displayName: "DEV",
levels: ["junior", "medior", "senior"],
defaultLevel: "medior",
models: {
junior: "anthropic/claude-haiku-4-5",
medior: "anthropic/claude-sonnet-4-5",
senior: "anthropic/claude-opus-4-5",
},
emoji: {
junior: "⚡",
medior: "🔧",
senior: "🧠",
},
fallbackEmoji: "🔧",
completionResults: ["done", "blocked"],
sessionKeyPattern: "dev",
notifications: { onStart: true, onComplete: true },
},
qa: {
id: "qa",
displayName: "QA",
levels: ["reviewer", "tester"],
defaultLevel: "reviewer",
models: {
reviewer: "anthropic/claude-sonnet-4-5",
tester: "anthropic/claude-haiku-4-5",
},
emoji: {
reviewer: "🔍",
tester: "👀",
},
fallbackEmoji: "🔍",
completionResults: ["pass", "fail", "refine", "blocked"],
sessionKeyPattern: "qa",
notifications: { onStart: true, onComplete: true },
},
architect: {
id: "architect",
displayName: "ARCHITECT",
levels: ["opus", "sonnet"],
defaultLevel: "sonnet",
models: {
opus: "anthropic/claude-opus-4-5",
sonnet: "anthropic/claude-sonnet-4-5",
},
emoji: {
opus: "🏗️",
sonnet: "📐",
},
fallbackEmoji: "🏗️",
completionResults: ["done", "blocked"],
sessionKeyPattern: "architect",
notifications: { onStart: true, onComplete: true },
},
};