dual-brain 0.2.8 → 0.2.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,405 @@
1
+ import { readFileSync, readdirSync, existsSync } from 'node:fs';
2
+ import { join, dirname } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ const AGENTS_DIR = __dirname;
7
+ const SKILLS_DIR = join(AGENTS_DIR, '..', '..', 'skills');
8
+
9
+ // Agent declarations loaded at startup
10
+ let _agents = null;
11
+ let _skills = null;
12
+
13
+ export function getAgents() {
14
+ if (_agents) return _agents;
15
+ _agents = new Map();
16
+
17
+ // Load built-in agents
18
+ for (const agent of BUILT_IN_AGENTS) {
19
+ _agents.set(agent.id, agent);
20
+ }
21
+
22
+ // Load custom agents from .claude/agents/ if they exist
23
+ const customDir = join(AGENTS_DIR, '..', '..', '.claude', 'agents');
24
+ if (existsSync(customDir)) {
25
+ for (const file of readdirSync(customDir).filter(f => f.endsWith('.md'))) {
26
+ try {
27
+ const content = readFileSync(join(customDir, file), 'utf8');
28
+ const parsed = parseAgentMd(content);
29
+ if (parsed) _agents.set(parsed.id, parsed);
30
+ } catch {}
31
+ }
32
+ }
33
+
34
+ return _agents;
35
+ }
36
+
37
+ export function getSkills() {
38
+ if (_skills) return _skills;
39
+ _skills = new Map();
40
+
41
+ for (const skill of BUILT_IN_SKILLS) {
42
+ _skills.set(skill.command, skill);
43
+ }
44
+
45
+ return _skills;
46
+ }
47
+
48
+ export function matchAgent(intent, risk, taskType) {
49
+ const agents = getAgents();
50
+ const matches = [];
51
+
52
+ for (const [id, agent] of agents) {
53
+ let score = 0;
54
+ if (agent.intents && agent.intents.includes(intent)) score += 10;
55
+ if (agent.taskTypes && agent.taskTypes.some(t => taskType.includes(t))) score += 5;
56
+ if (agent.minRisk && riskLevel(risk) >= riskLevel(agent.minRisk)) score += 3;
57
+ if (score > 0) matches.push({ ...agent, score });
58
+ }
59
+
60
+ return matches.sort((a, b) => b.score - a.score);
61
+ }
62
+
63
+ export function matchSkill(command) {
64
+ const skills = getSkills();
65
+ const cmd = command.replace(/^\//, '').split(' ')[0].toLowerCase();
66
+ return skills.get(cmd) || null;
67
+ }
68
+
69
+ export function skillToTaskBrief(command, args) {
70
+ const skill = matchSkill(command);
71
+ if (!skill) return null;
72
+
73
+ return {
74
+ objective: skill.objective(args),
75
+ scope: skill.scope || [],
76
+ tier: skill.tier,
77
+ model: skill.model,
78
+ risk: skill.risk || 'low',
79
+ acceptanceCriteria: skill.acceptanceCriteria || [],
80
+ agentId: skill.agent,
81
+ cost: skill.cost,
82
+ };
83
+ }
84
+
85
+ function riskLevel(r) {
86
+ return { low: 1, medium: 2, high: 3, critical: 4 }[r] || 0;
87
+ }
88
+
89
+ function parseAgentMd(content) {
90
+ // Parse YAML frontmatter from .claude/agents/*.md
91
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
92
+ if (!match) return null;
93
+
94
+ const meta = {};
95
+ for (const line of match[1].split('\n')) {
96
+ const [key, ...rest] = line.split(':');
97
+ if (key && rest.length) meta[key.trim()] = rest.join(':').trim();
98
+ }
99
+
100
+ return {
101
+ id: meta.name || 'unknown',
102
+ name: meta.name || 'Unknown Agent',
103
+ tier: meta.tier || 'execute',
104
+ model: meta.model || 'sonnet',
105
+ intents: (meta.intents || '').split(',').map(s => s.trim()),
106
+ taskTypes: (meta.taskTypes || '').split(',').map(s => s.trim()),
107
+ prompt: content.replace(/^---[\s\S]*?---\n/, ''),
108
+ };
109
+ }
110
+
111
+ // ── Built-in Agents ──────────────────────────────────────────────────────
112
+
113
+ const BUILT_IN_AGENTS = [
114
+ {
115
+ id: 'reviewer',
116
+ name: 'Code Reviewer',
117
+ tier: 'execute',
118
+ model: 'sonnet',
119
+ cost: 'cheap',
120
+ intents: ['review', 'audit', 'check'],
121
+ taskTypes: ['code-review', 'pr-review', 'diff-review'],
122
+ contract: {
123
+ inputs: ['diff', 'base_branch', 'focus_areas'],
124
+ outputs: ['findings', 'severity', 'suggestions', 'verdict'],
125
+ },
126
+ prompt: `You are a code reviewer. Review the provided diff for: correctness, security issues, performance problems, code style, and test coverage gaps. For each finding, provide: severity (critical/high/medium/low), file and line, description, and suggested fix. Return structured JSON: { "verdict": "approve|request_changes|comment", "findings": [...], "summary": "..." }`,
127
+ },
128
+ {
129
+ id: 'debugger',
130
+ name: 'Debugger',
131
+ tier: 'execute',
132
+ model: 'sonnet',
133
+ cost: 'cheap',
134
+ intents: ['debug', 'fix', 'investigate', 'error'],
135
+ taskTypes: ['bug-fix', 'error-investigation', 'crash-analysis'],
136
+ contract: {
137
+ inputs: ['error_message', 'stack_trace', 'reproduction_steps', 'relevant_files'],
138
+ outputs: ['root_cause', 'patch', 'tests', 'confidence'],
139
+ },
140
+ prompt: `You are a debugger. Given an error, stack trace, or bug description: 1) Reproduce or trace the issue, 2) Identify root cause, 3) Implement the fix, 4) Add a regression test. Return: { "root_cause": "...", "files_changed": [...], "tests_added": [...], "confidence": "high|medium|low" }`,
141
+ },
142
+ {
143
+ id: 'test-writer',
144
+ name: 'Test Writer',
145
+ tier: 'execute',
146
+ model: 'sonnet',
147
+ cost: 'cheap',
148
+ intents: ['test', 'coverage', 'spec'],
149
+ taskTypes: ['test-generation', 'test-coverage', 'fixture-creation'],
150
+ contract: {
151
+ inputs: ['target_file', 'test_framework', 'existing_tests'],
152
+ outputs: ['test_file', 'test_count', 'coverage_areas', 'edge_cases'],
153
+ },
154
+ prompt: `You are a test writer. Given a source file, generate comprehensive tests covering: happy path, edge cases, error conditions, and boundary values. Match the existing test framework and style. Return: { "test_file": "...", "tests": [...], "edge_cases_covered": [...] }`,
155
+ },
156
+ {
157
+ id: 'architect',
158
+ name: 'Architect',
159
+ tier: 'think',
160
+ model: 'opus',
161
+ cost: 'full',
162
+ intents: ['design', 'architect', 'plan', 'structure'],
163
+ taskTypes: ['architecture', 'system-design', 'api-design', 'module-design'],
164
+ contract: {
165
+ inputs: ['goal', 'constraints', 'existing_architecture', 'scale_requirements'],
166
+ outputs: ['design', 'modules', 'interfaces', 'tradeoffs', 'risks'],
167
+ },
168
+ prompt: `You are a software architect. Design the system or module with: clear module boundaries, well-defined interfaces, explicit tradeoffs, and identified risks. Return: { "design": "...", "modules": [...], "interfaces": [...], "tradeoffs": [...], "risks": [...] }`,
169
+ },
170
+ {
171
+ id: 'security',
172
+ name: 'Security Auditor',
173
+ tier: 'execute',
174
+ model: 'sonnet',
175
+ cost: 'full',
176
+ intents: ['security', 'vulnerability', 'owasp', 'secrets'],
177
+ taskTypes: ['security-audit', 'vulnerability-scan', 'secret-detection', 'auth-review'],
178
+ minRisk: 'medium',
179
+ contract: {
180
+ inputs: ['scope', 'diff', 'dependencies', 'config_files'],
181
+ outputs: ['vulnerabilities', 'severity', 'remediation', 'compliance'],
182
+ },
183
+ prompt: `You are a security auditor. Scan for: OWASP Top 10 vulnerabilities, hardcoded secrets, insecure dependencies, auth/authz issues, injection vectors, and data exposure. Return: { "vulnerabilities": [{ "type": "...", "severity": "critical|high|medium|low", "file": "...", "line": N, "remediation": "..." }], "clean": true/false }`,
184
+ },
185
+ {
186
+ id: 'refactor',
187
+ name: 'Refactorer',
188
+ tier: 'execute',
189
+ model: 'sonnet',
190
+ cost: 'cheap',
191
+ intents: ['refactor', 'cleanup', 'simplify', 'extract'],
192
+ taskTypes: ['refactoring', 'code-cleanup', 'extraction', 'rename'],
193
+ contract: {
194
+ inputs: ['target', 'goal', 'constraints', 'preserve_behavior'],
195
+ outputs: ['patch', 'behavior_preserved', 'tests_updated'],
196
+ },
197
+ prompt: `You are a refactoring specialist. Improve code structure while preserving behavior. Verify with existing tests. Return: { "changes": [...], "behavior_preserved": true, "tests_passing": true }`,
198
+ },
199
+ {
200
+ id: 'docs',
201
+ name: 'Documentation Writer',
202
+ tier: 'execute',
203
+ model: 'sonnet',
204
+ cost: 'cheap',
205
+ intents: ['document', 'readme', 'api-doc', 'explain'],
206
+ taskTypes: ['documentation', 'readme-update', 'api-docs', 'changelog'],
207
+ contract: {
208
+ inputs: ['files', 'audience', 'format', 'existing_docs'],
209
+ outputs: ['docs_patch', 'sections_updated'],
210
+ },
211
+ prompt: `You are a documentation writer. Generate clear, concise documentation for the specified code. Match existing doc style. Return: { "docs": "...", "sections": [...] }`,
212
+ },
213
+ {
214
+ id: 'researcher',
215
+ name: 'Research Agent',
216
+ tier: 'search',
217
+ model: 'haiku',
218
+ cost: 'cheap',
219
+ intents: ['research', 'lookup', 'find', 'search', 'explore'],
220
+ taskTypes: ['web-search', 'docs-lookup', 'api-exploration', 'codebase-search'],
221
+ contract: {
222
+ inputs: ['query', 'domains', 'freshness_requirement'],
223
+ outputs: ['sources', 'summary', 'references', 'confidence'],
224
+ },
225
+ prompt: `You are a research agent. Find accurate, current information. Cite sources. Distinguish facts from opinions. Return: { "answer": "...", "sources": [...], "confidence": "high|medium|low" }`,
226
+ },
227
+ {
228
+ id: 'performance',
229
+ name: 'Performance Optimizer',
230
+ tier: 'execute',
231
+ model: 'sonnet',
232
+ cost: 'cheap',
233
+ intents: ['optimize', 'performance', 'speed', 'profile', 'bottleneck'],
234
+ taskTypes: ['performance-optimization', 'profiling', 'bottleneck-detection'],
235
+ contract: {
236
+ inputs: ['hot_path', 'metrics', 'budget_ms'],
237
+ outputs: ['bottlenecks', 'optimizations', 'patch', 'expected_improvement'],
238
+ },
239
+ prompt: `You are a performance specialist. Profile, identify bottlenecks, and optimize. Measure before/after. Return: { "bottlenecks": [...], "optimizations": [...], "expected_speedup": "..." }`,
240
+ },
241
+ {
242
+ id: 'devops',
243
+ name: 'DevOps Engineer',
244
+ tier: 'execute',
245
+ model: 'sonnet',
246
+ cost: 'full',
247
+ intents: ['deploy', 'ci', 'docker', 'infrastructure', 'pipeline'],
248
+ taskTypes: ['deployment', 'ci-cd', 'docker', 'infrastructure', 'monitoring'],
249
+ minRisk: 'medium',
250
+ contract: {
251
+ inputs: ['goal', 'environment', 'constraints', 'current_config'],
252
+ outputs: ['config', 'commands', 'risks', 'rollback_plan'],
253
+ },
254
+ prompt: `You are a DevOps engineer. Configure infrastructure, CI/CD, and deployment with: security best practices, rollback plans, and monitoring. Return: { "config_changes": [...], "commands": [...], "risks": [...], "rollback": "..." }`,
255
+ },
256
+ ];
257
+
258
+ // ── Built-in Skills ──────────────────────────────────────────────────────
259
+
260
+ const BUILT_IN_SKILLS = [
261
+ {
262
+ command: 'review',
263
+ agent: 'reviewer',
264
+ tier: 'execute',
265
+ model: 'sonnet',
266
+ cost: 'cheap',
267
+ description: 'Review current changes or a specific file',
268
+ objective: (args) => args ? `Review changes in ${args}` : 'Review all uncommitted changes',
269
+ acceptanceCriteria: ['All findings include severity and file location', 'Verdict is clear'],
270
+ },
271
+ {
272
+ command: 'debug',
273
+ agent: 'debugger',
274
+ tier: 'execute',
275
+ model: 'sonnet',
276
+ cost: 'cheap',
277
+ description: 'Investigate and fix an error',
278
+ objective: (args) => `Debug: ${args || 'investigate recent error'}`,
279
+ acceptanceCriteria: ['Root cause identified', 'Fix implemented', 'Regression test added'],
280
+ },
281
+ {
282
+ command: 'test',
283
+ agent: 'test-writer',
284
+ tier: 'execute',
285
+ model: 'sonnet',
286
+ cost: 'cheap',
287
+ description: 'Generate tests for a file',
288
+ objective: (args) => `Generate comprehensive tests for ${args || 'changed files'}`,
289
+ acceptanceCriteria: ['Tests cover happy path and edge cases', 'Tests pass'],
290
+ },
291
+ {
292
+ command: 'plan',
293
+ agent: 'architect',
294
+ tier: 'think',
295
+ model: 'opus',
296
+ cost: 'full',
297
+ description: 'Create an execution plan for a task',
298
+ objective: (args) => `Create execution plan: ${args || 'current task'}`,
299
+ acceptanceCriteria: ['Steps are concrete and ordered', 'Risks identified', 'Acceptance criteria per step'],
300
+ },
301
+ {
302
+ command: 'audit',
303
+ agent: 'security',
304
+ tier: 'execute',
305
+ model: 'sonnet',
306
+ cost: 'cheap',
307
+ description: 'Run a security, quality, or dependency audit',
308
+ objective: (args) => `Audit: ${args || 'security scan of current changes'}`,
309
+ acceptanceCriteria: ['All findings include severity', 'Remediation steps provided'],
310
+ },
311
+ {
312
+ command: 'fix',
313
+ agent: 'debugger',
314
+ tier: 'execute',
315
+ model: 'sonnet',
316
+ cost: 'cheap',
317
+ description: 'Fix a specific issue',
318
+ objective: (args) => `Fix: ${args}`,
319
+ acceptanceCriteria: ['Issue resolved', 'Tests pass', 'No regressions'],
320
+ },
321
+ {
322
+ command: 'explain',
323
+ agent: 'researcher',
324
+ tier: 'search',
325
+ model: 'haiku',
326
+ cost: 'cheap',
327
+ description: 'Explain how code works',
328
+ objective: (args) => `Explain: ${args || 'current file'}`,
329
+ },
330
+ {
331
+ command: 'refactor',
332
+ agent: 'refactor',
333
+ tier: 'execute',
334
+ model: 'sonnet',
335
+ cost: 'cheap',
336
+ description: 'Refactor code for clarity or performance',
337
+ objective: (args) => `Refactor: ${args || 'current file'}`,
338
+ acceptanceCriteria: ['Behavior preserved', 'Tests still pass'],
339
+ },
340
+ {
341
+ command: 'doc',
342
+ agent: 'docs',
343
+ tier: 'execute',
344
+ model: 'sonnet',
345
+ cost: 'cheap',
346
+ description: 'Generate or update documentation',
347
+ objective: (args) => `Document: ${args || 'changed files'}`,
348
+ },
349
+ {
350
+ command: 'brainstorm',
351
+ agent: 'architect',
352
+ tier: 'think',
353
+ model: 'sonnet',
354
+ cost: 'cheap',
355
+ description: 'Generate ideas and explore options',
356
+ objective: (args) => `Brainstorm: ${args || 'current challenge'}`,
357
+ },
358
+ {
359
+ command: 'search',
360
+ agent: 'researcher',
361
+ tier: 'search',
362
+ model: 'haiku',
363
+ cost: 'cheap',
364
+ description: 'Search web, docs, or codebase',
365
+ objective: (args) => `Search: ${args}`,
366
+ },
367
+ {
368
+ command: 'status',
369
+ agent: null, // deterministic, no agent needed
370
+ tier: 'free',
371
+ cost: 'free',
372
+ description: 'Show system health and status',
373
+ objective: () => 'Display system status',
374
+ },
375
+ {
376
+ command: 'deploy',
377
+ agent: 'devops',
378
+ tier: 'execute',
379
+ model: 'sonnet',
380
+ cost: 'full',
381
+ risk: 'high',
382
+ description: 'Run deployment workflow',
383
+ objective: (args) => `Deploy: ${args || 'production'}`,
384
+ acceptanceCriteria: ['Deployment successful', 'Health check passes', 'Rollback plan documented'],
385
+ },
386
+ {
387
+ command: 'perf',
388
+ agent: 'performance',
389
+ tier: 'execute',
390
+ model: 'sonnet',
391
+ cost: 'cheap',
392
+ description: 'Profile and optimize performance',
393
+ objective: (args) => `Optimize performance: ${args || 'hot paths'}`,
394
+ },
395
+ {
396
+ command: 'release',
397
+ agent: 'docs',
398
+ tier: 'execute',
399
+ model: 'sonnet',
400
+ cost: 'cheap',
401
+ description: 'Generate changelog and release checklist',
402
+ objective: (args) => `Prepare release: ${args || 'current version'}`,
403
+ acceptanceCriteria: ['Changelog generated', 'Version bumped', 'Doctor passes'],
404
+ },
405
+ ];