dual-brain 7.1.3 → 7.1.4

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.
@@ -1,659 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * agent-fleet.mjs — Agent type taxonomy for the dual-brain orchestrator.
4
- *
5
- * Defines the full fleet of specialized agent types, their capabilities,
6
- * prompt templates, and dispatch configs. The head agent (Opus) uses this
7
- * to select and configure subagents — it never implements anything itself.
8
- *
9
- * Exports: AGENT_TYPES, dispatchFleetAgent, getAgentRecommendation
10
- * CLI: node hooks/agent-fleet.mjs --list
11
- * node hooks/agent-fleet.mjs --recommend "refactor the auth module"
12
- */
13
-
14
- // ─── Agent Type Definitions ───────────────────────────────────────────────────
15
-
16
- const AGENT_TYPES = {
17
-
18
- brainstorm: {
19
- name: 'brainstorm',
20
- description: 'Creative ideation, architecture exploration, "what if" scenarios. Generates options with pros/cons/effort, not decisions.',
21
- tier: 'think',
22
- readOnly: true,
23
- maxDurationMs: 120_000,
24
- defaultEffort: { claude: 'high', openai: 'high' },
25
- defaultModel: { claude: 'opus', openai: 'gpt-5.5' },
26
- preferredProvider: 'claude',
27
- outputFormat: {
28
- ideas: [{ title: 'string', summary: 'string', pros: ['string'], cons: ['string'], effort: 'low|medium|high', risk: 'low|medium|high|critical' }],
29
- recommended: 'title of top pick',
30
- open_questions: ['string'],
31
- },
32
- promptTemplate: (payload) => `
33
- You are a creative brainstorming agent. Your role is to generate a rich set of ideas, approaches, and architectural options for the task below. You are NOT making a final decision — that is the head agent's job.
34
-
35
- CONSTRAINTS:
36
- - Do NOT use Edit, Write, or any file-modification tools.
37
- - Do NOT implement anything. Think, explore, propose.
38
- - Be creative. Include unconventional approaches alongside safe ones.
39
- - For each idea, state realistic pros, cons, effort, and risk.
40
-
41
- TASK:
42
- ${payload.task}
43
-
44
- ${payload.context ? `CONTEXT:\n${payload.context}\n` : ''}
45
- ${payload.files?.length ? `RELEVANT FILES:\n${payload.files.join('\n')}\n` : ''}
46
- ${payload.constraints ? `CONSTRAINTS FROM HEAD AGENT:\n${payload.constraints}\n` : ''}
47
-
48
- Respond with a JSON object matching this schema exactly:
49
- ${JSON.stringify(AGENT_TYPES.brainstorm.outputFormat, null, 2)}
50
- `.trim(),
51
- },
52
-
53
- research: {
54
- name: 'research',
55
- description: 'Deep codebase exploration: find patterns, understand architecture, trace dependencies. Returns findings with file refs and confidence.',
56
- tier: 'search',
57
- readOnly: true,
58
- maxDurationMs: 180_000,
59
- defaultEffort: { claude: 'medium', openai: 'medium' },
60
- defaultModel: { claude: 'sonnet', openai: 'gpt-5.4' },
61
- preferredProvider: 'claude',
62
- outputFormat: {
63
- findings: [{ summary: 'string', files: ['path:line'], confidence: 'low|medium|high', detail: 'string' }],
64
- architecture_notes: 'string',
65
- dependencies_found: ['string'],
66
- gaps: ['string — what could not be determined'],
67
- },
68
- promptTemplate: (payload) => `
69
- You are a research agent specializing in deep codebase exploration. Your job is to thoroughly investigate the codebase, trace relationships, and surface findings with precise file references.
70
-
71
- CONSTRAINTS:
72
- - Do NOT use Edit, Write, or any file-modification tools. Read-only.
73
- - Cite every finding with a specific file path and line number where possible.
74
- - Rate your confidence in each finding (low/medium/high).
75
- - Note any gaps — things you could not determine from the code alone.
76
-
77
- RESEARCH QUESTION:
78
- ${payload.task}
79
-
80
- ${payload.files?.length ? `START WITH THESE FILES:\n${payload.files.join('\n')}\n` : ''}
81
- ${payload.context ? `BACKGROUND:\n${payload.context}\n` : ''}
82
-
83
- Respond with a JSON object matching this schema exactly:
84
- ${JSON.stringify(AGENT_TYPES.research.outputFormat, null, 2)}
85
- `.trim(),
86
- },
87
-
88
- analyst: {
89
- name: 'analyst',
90
- description: 'Data analysis, benchmark interpretation, cost modeling, trade-off analysis. Returns structured analysis with numbers and recommendations.',
91
- tier: 'think',
92
- readOnly: true,
93
- maxDurationMs: 120_000,
94
- defaultEffort: { claude: 'high', openai: 'high' },
95
- defaultModel: { claude: 'opus', openai: 'gpt-5.5' },
96
- preferredProvider: 'claude',
97
- outputFormat: {
98
- summary: 'string',
99
- data_points: [{ label: 'string', value: 'string|number', unit: 'string', interpretation: 'string' }],
100
- trade_offs: [{ option: 'string', benefit: 'string', cost: 'string', verdict: 'string' }],
101
- recommendation: 'string',
102
- confidence: 'low|medium|high',
103
- caveats: ['string'],
104
- },
105
- promptTemplate: (payload) => `
106
- You are an analyst agent. Your job is to analyze data, interpret benchmarks, model costs, and produce rigorous trade-off analysis. You deal in numbers and evidence, not opinions.
107
-
108
- CONSTRAINTS:
109
- - Do NOT use Edit, Write, or any file-modification tools. Read-only.
110
- - Ground every claim in data. State assumptions explicitly.
111
- - Quantify wherever possible. Avoid vague language.
112
- - Rate your confidence and list caveats.
113
-
114
- ANALYSIS REQUEST:
115
- ${payload.task}
116
-
117
- ${payload.data ? `INPUT DATA:\n${payload.data}\n` : ''}
118
- ${payload.context ? `CONTEXT:\n${payload.context}\n` : ''}
119
- ${payload.files?.length ? `RELEVANT FILES:\n${payload.files.join('\n')}\n` : ''}
120
-
121
- Respond with a JSON object matching this schema exactly:
122
- ${JSON.stringify(AGENT_TYPES.analyst.outputFormat, null, 2)}
123
- `.trim(),
124
- },
125
-
126
- planner: {
127
- name: 'planner',
128
- description: 'Break down work into tasks, estimate effort, identify dependencies, design implementation order. Returns a task list with dependency graph.',
129
- tier: 'think',
130
- readOnly: true,
131
- maxDurationMs: 90_000,
132
- defaultEffort: { claude: 'high', openai: 'high' },
133
- defaultModel: { claude: 'opus', openai: 'gpt-5.5' },
134
- preferredProvider: 'claude',
135
- outputFormat: {
136
- tasks: [{
137
- id: 'string',
138
- title: 'string',
139
- description: 'string',
140
- tier: 'search|execute|think',
141
- agentType: 'research|worker|reviewer|tester|documenter|specialist',
142
- effort: 'trivial|simple|moderate|complex',
143
- risk: 'low|medium|high|critical',
144
- dependsOn: ['task_id'],
145
- files: ['path'],
146
- acceptanceCriteria: ['string'],
147
- }],
148
- waves: [{ wave: 'number', taskIds: ['string'], rationale: 'string' }],
149
- totalEffortEstimate: 'string',
150
- risks: ['string'],
151
- open_questions: ['string'],
152
- },
153
- promptTemplate: (payload) => `
154
- You are a planning agent. Your job is to decompose a body of work into well-defined tasks, organize them into dependency-ordered waves, and produce acceptance criteria for each task. Planners do not implement — they plan.
155
-
156
- CONSTRAINTS:
157
- - Do NOT use Edit, Write, or any file-modification tools. Read-only.
158
- - Every task must have clear acceptance criteria.
159
- - Identify dependencies explicitly — tasks that share files are NOT safe to parallelize.
160
- - Assign each task to a specific agent type from the fleet.
161
- - Group independent tasks into the same wave; dependent tasks into later waves.
162
-
163
- WORK TO PLAN:
164
- ${payload.task}
165
-
166
- ${payload.context ? `CONTEXT:\n${payload.context}\n` : ''}
167
- ${payload.files?.length ? `FILES IN SCOPE:\n${payload.files.join('\n')}\n` : ''}
168
- ${payload.constraints ? `CONSTRAINTS:\n${payload.constraints}\n` : ''}
169
-
170
- Respond with a JSON object matching this schema exactly:
171
- ${JSON.stringify(AGENT_TYPES.planner.outputFormat, null, 2)}
172
- `.trim(),
173
- },
174
-
175
- reviewer: {
176
- name: 'reviewer',
177
- description: 'Code review, security audit, quality assessment. Returns issues with severity, location, and fix suggestions.',
178
- tier: 'think',
179
- readOnly: true,
180
- maxDurationMs: 180_000,
181
- defaultEffort: { claude: 'high', openai: 'high' },
182
- defaultModel: { claude: 'opus', openai: 'gpt-5.5' },
183
- preferredProvider: 'claude',
184
- outputFormat: {
185
- verdict: 'pass|issues_found|blocking',
186
- issues: [{
187
- severity: 'info|warning|error|critical',
188
- category: 'correctness|security|performance|style|maintainability',
189
- file: 'string',
190
- line: 'number|null',
191
- description: 'string',
192
- suggestion: 'string',
193
- }],
194
- summary: 'string',
195
- must_fix_before_merge: ['issue description'],
196
- nice_to_fix: ['issue description'],
197
- },
198
- promptTemplate: (payload) => `
199
- You are a code reviewer agent. Your job is to perform a thorough, actionable review of the code diff or files provided. Flag real issues — not style nitpicks unless they indicate deeper problems.
200
-
201
- CONSTRAINTS:
202
- - Do NOT use Edit, Write, or any file-modification tools. Read-only.
203
- - For every issue, give the file path, approximate line, severity, and a concrete fix suggestion.
204
- - Categorize: correctness, security, performance, style, maintainability.
205
- - Security issues are always "critical" severity.
206
- - Be honest: if the code is clean, say so.
207
-
208
- ${payload.diff ? `DIFF TO REVIEW:\n${payload.diff}\n` : ''}
209
- ${payload.files?.length ? `FILES TO REVIEW:\n${payload.files.join('\n')}\n` : ''}
210
- ${payload.context ? `CONTEXT / PR DESCRIPTION:\n${payload.context}\n` : ''}
211
- ${payload.task ? `SPECIFIC FOCUS:\n${payload.task}\n` : ''}
212
-
213
- Respond with a JSON object matching this schema exactly:
214
- ${JSON.stringify(AGENT_TYPES.reviewer.outputFormat, null, 2)}
215
- `.trim(),
216
- },
217
-
218
- worker: {
219
- name: 'worker',
220
- description: 'Implementation: file edits, test writing, feature building. Not read-only. Returns files changed, tests run, edge cases handled.',
221
- tier: 'execute',
222
- readOnly: false,
223
- maxDurationMs: 300_000,
224
- defaultEffort: { claude: 'medium', openai: 'medium' },
225
- defaultModel: { claude: 'sonnet', openai: 'gpt-5.3-codex' },
226
- preferredProvider: 'openai',
227
- outputFormat: {
228
- files_changed: [{ path: 'string', action: 'created|modified|deleted', summary: 'string' }],
229
- tests_run: [{ name: 'string', result: 'pass|fail|skip', detail: 'string' }],
230
- edge_cases_handled: ['string'],
231
- edge_cases_not_handled: ['string'],
232
- notes: 'string',
233
- },
234
- promptTemplate: (payload) => `
235
- You are a worker agent responsible for implementation. Execute the task below precisely, following the acceptance criteria. Write clean, minimal code — do not gold-plate.
236
-
237
- TASK:
238
- ${payload.task}
239
-
240
- ${payload.acceptanceCriteria?.length ? `ACCEPTANCE CRITERIA:\n${payload.acceptanceCriteria.map((c, i) => `${i + 1}. ${c}`).join('\n')}\n` : ''}
241
- ${payload.files?.length ? `FILES IN SCOPE:\n${payload.files.join('\n')}\n` : ''}
242
- ${payload.context ? `CONTEXT:\n${payload.context}\n` : ''}
243
- ${payload.constraints ? `CONSTRAINTS:\n${payload.constraints}\n` : ''}
244
-
245
- After completing work, respond with a JSON object matching this schema exactly:
246
- ${JSON.stringify(AGENT_TYPES.worker.outputFormat, null, 2)}
247
- `.trim(),
248
- },
249
-
250
- debugger: {
251
- name: 'debugger',
252
- description: 'Investigate failures, trace bugs, diagnose issues. Read-only investigation with root cause analysis and fix recommendation.',
253
- tier: 'think',
254
- readOnly: true,
255
- maxDurationMs: 240_000,
256
- defaultEffort: { claude: 'high', openai: 'high' },
257
- defaultModel: { claude: 'sonnet', openai: 'gpt-5.4' },
258
- preferredProvider: 'claude',
259
- outputFormat: {
260
- root_cause: 'string',
261
- reproduction_steps: ['string'],
262
- affected_files: [{ path: 'string', line: 'number|null', issue: 'string' }],
263
- hypothesis: 'string',
264
- fix_recommendation: 'string',
265
- fix_complexity: 'trivial|simple|moderate|complex',
266
- confidence: 'low|medium|high',
267
- dead_ends: ['string — things that looked relevant but were not'],
268
- },
269
- promptTemplate: (payload) => `
270
- You are a debugger agent. Your job is to investigate failures, trace bugs, and produce a precise root cause analysis with a clear fix recommendation. Think like a detective: follow the evidence, discard red herrings, state your confidence.
271
-
272
- CONSTRAINTS:
273
- - Do NOT use Edit, Write, or any file-modification tools. Investigation only.
274
- - Document dead ends — what you ruled out and why.
275
- - State reproduction steps if you can determine them.
276
- - Rate your confidence in the root cause.
277
-
278
- ISSUE TO INVESTIGATE:
279
- ${payload.task}
280
-
281
- ${payload.errorOutput ? `ERROR OUTPUT / STACK TRACE:\n${payload.errorOutput}\n` : ''}
282
- ${payload.files?.length ? `FILES TO INVESTIGATE:\n${payload.files.join('\n')}\n` : ''}
283
- ${payload.context ? `CONTEXT:\n${payload.context}\n` : ''}
284
-
285
- Respond with a JSON object matching this schema exactly:
286
- ${JSON.stringify(AGENT_TYPES.debugger.outputFormat, null, 2)}
287
- `.trim(),
288
- },
289
-
290
- documenter: {
291
- name: 'documenter',
292
- description: 'Write docs, update READMEs, generate API docs. Limited to documentation files. Returns docs written/updated.',
293
- tier: 'execute',
294
- readOnly: false,
295
- maxDurationMs: 180_000,
296
- defaultEffort: { claude: 'medium', openai: 'low' },
297
- defaultModel: { claude: 'sonnet', openai: 'gpt-4.1' },
298
- preferredProvider: 'openai',
299
- allowedFilePatterns: ['*.md', '*.mdx', '*.txt', '*.rst', 'docs/**', 'README*', 'CHANGELOG*', '*.jsdoc', '*.typedoc'],
300
- outputFormat: {
301
- docs_written: [{ path: 'string', type: 'new|updated', summary: 'string' }],
302
- coverage: 'string — what is now documented',
303
- gaps: ['string — things that still need docs'],
304
- },
305
- promptTemplate: (payload) => `
306
- You are a documentation agent. Write clear, accurate, developer-friendly documentation. Match the existing doc style in the project. Do not invent behavior — document what the code actually does.
307
-
308
- CONSTRAINTS:
309
- - Only modify documentation files (*.md, *.mdx, *.txt, *.rst, docs/**, README*, CHANGELOG*, *.jsdoc).
310
- - Do NOT modify source code files.
311
- - Match existing tone and formatting conventions.
312
- - Accurate > comprehensive. Do not document things you are not sure about.
313
-
314
- DOCUMENTATION TASK:
315
- ${payload.task}
316
-
317
- ${payload.files?.length ? `SOURCE FILES TO DOCUMENT:\n${payload.files.join('\n')}\n` : ''}
318
- ${payload.context ? `CONTEXT:\n${payload.context}\n` : ''}
319
- ${payload.existingDocStyle ? `EXISTING DOC STYLE NOTES:\n${payload.existingDocStyle}\n` : ''}
320
-
321
- After completing work, respond with a JSON object matching this schema exactly:
322
- ${JSON.stringify(AGENT_TYPES.documenter.outputFormat, null, 2)}
323
- `.trim(),
324
- },
325
-
326
- tester: {
327
- name: 'tester',
328
- description: 'Write and run tests, verify edge cases, check coverage. Limited to test files. Returns test results and coverage delta.',
329
- tier: 'execute',
330
- readOnly: false,
331
- maxDurationMs: 300_000,
332
- defaultEffort: { claude: 'medium', openai: 'medium' },
333
- defaultModel: { claude: 'sonnet', openai: 'gpt-5.4-mini' },
334
- preferredProvider: 'openai',
335
- allowedFilePatterns: ['*.test.*', '*.spec.*', '__tests__/**', 'test/**', 'tests/**', '*.test.mjs', '*.test.js', '*.test.ts'],
336
- outputFormat: {
337
- tests_written: [{ file: 'string', count: 'number', cases: ['string'] }],
338
- tests_run: [{ name: 'string', result: 'pass|fail|skip', duration_ms: 'number', error: 'string|null' }],
339
- coverage: { before: 'string|null', after: 'string|null', delta: 'string|null' },
340
- edge_cases_covered: ['string'],
341
- edge_cases_missing: ['string'],
342
- },
343
- promptTemplate: (payload) => `
344
- You are a testing agent. Write thorough, focused tests. Prefer testing behavior over implementation details. Cover happy paths, error paths, and edge cases. Run the tests and report results.
345
-
346
- CONSTRAINTS:
347
- - Only create or modify test files (*.test.*, *.spec.*, __tests__/**, test/**, tests/**).
348
- - Do NOT modify production source files.
349
- - Tests must be deterministic and independent (no shared mutable state between tests).
350
- - If a test fails, investigate — do not simply delete or skip it.
351
-
352
- TESTING TASK:
353
- ${payload.task}
354
-
355
- ${payload.files?.length ? `SOURCE FILES TO TEST:\n${payload.files.join('\n')}\n` : ''}
356
- ${payload.context ? `CONTEXT:\n${payload.context}\n` : ''}
357
- ${payload.testFramework ? `TEST FRAMEWORK: ${payload.testFramework}\n` : ''}
358
-
359
- After completing work, respond with a JSON object matching this schema exactly:
360
- ${JSON.stringify(AGENT_TYPES.tester.outputFormat, null, 2)}
361
- `.trim(),
362
- },
363
-
364
- specialist: {
365
- name: 'specialist',
366
- description: 'Domain-specific expert (security, performance, accessibility, i18n, etc). Takes a domain parameter. Returns domain-specific analysis.',
367
- tier: 'think',
368
- readOnly: true,
369
- maxDurationMs: 180_000,
370
- defaultEffort: { claude: 'high', openai: 'high' },
371
- defaultModel: { claude: 'opus', openai: 'gpt-5.5' },
372
- preferredProvider: 'claude',
373
- outputFormat: {
374
- domain: 'string',
375
- summary: 'string',
376
- findings: [{
377
- severity: 'info|warning|error|critical',
378
- area: 'string',
379
- file: 'string|null',
380
- line: 'number|null',
381
- description: 'string',
382
- recommendation: 'string',
383
- reference: 'string|null — spec, standard, or CVE if applicable',
384
- }],
385
- score: 'number 0-10 (10 = excellent)',
386
- verdict: 'pass|needs_attention|failing',
387
- next_steps: ['string'],
388
- },
389
- promptTemplate: (payload) => `
390
- You are a specialist agent with deep expertise in ${payload.domain || 'your domain'}. Apply rigorous ${payload.domain || 'domain'}-specific analysis to the code and files provided. Reference standards, specifications, and best practices for the domain.
391
-
392
- CONSTRAINTS:
393
- - Do NOT use Edit, Write, or any file-modification tools. Read-only.
394
- - Cite specific standards, specs, or CVEs where applicable.
395
- - Score the subject matter on a 0–10 scale with clear criteria.
396
- - Distinguish between blocking issues and improvement opportunities.
397
-
398
- DOMAIN: ${payload.domain || 'unspecified — infer from task'}
399
-
400
- ANALYSIS REQUEST:
401
- ${payload.task}
402
-
403
- ${payload.files?.length ? `FILES TO ANALYZE:\n${payload.files.join('\n')}\n` : ''}
404
- ${payload.context ? `CONTEXT:\n${payload.context}\n` : ''}
405
-
406
- Respond with a JSON object matching this schema exactly:
407
- ${JSON.stringify(AGENT_TYPES.specialist.outputFormat, null, 2)}
408
- `.trim(),
409
- },
410
- };
411
-
412
- // ─── Pipeline Presets ─────────────────────────────────────────────────────────
413
- // Common agent pipelines for known task shapes.
414
-
415
- const PIPELINE_PRESETS = [
416
- // More-specific patterns first to prevent early-exit on broad verbs like "add", "write"
417
- {
418
- label: 'security-review',
419
- pattern: /\b(auth|secret|credential|token|password|encrypt|security|vulnerability)\b/i,
420
- risk: ['high', 'critical'],
421
- pipeline: ['specialist', 'reviewer', 'planner'],
422
- rationale: 'Security specialist identifies issues, reviewer confirms, planner orders remediation.',
423
- },
424
- {
425
- label: 'ideate-then-plan',
426
- pattern: /\b(architect|design|how should|system|approach|strategy)\b/i,
427
- risk: ['any'],
428
- pipeline: ['brainstorm', 'analyst', 'planner'],
429
- rationale: 'Generate options, analyze trade-offs, produce an ordered task plan.',
430
- },
431
- {
432
- label: 'debug-then-fix',
433
- pattern: /\b(debug|investigate|broken|failing|not working|why (is|does|isn't|doesn't))\b/i,
434
- risk: ['any'],
435
- pipeline: ['debugger', 'worker', 'tester'],
436
- rationale: 'Diagnose root cause, implement fix, verify with regression tests.',
437
- },
438
- {
439
- label: 'audit-and-remediate',
440
- pattern: /\b(audit|remediat|fix all|clean up|improve|assess)\b/i,
441
- risk: ['any'],
442
- pipeline: ['research', 'analyst', 'planner', 'worker', 'reviewer'],
443
- rationale: 'Full audit cycle: discover, analyze, plan, fix, verify.',
444
- },
445
- {
446
- label: 'design-then-build',
447
- pattern: /\b(refactor|restructure|redesign|extract|split|consolidate)\b/i,
448
- risk: ['medium', 'high'],
449
- pipeline: ['research', 'planner', 'worker', 'reviewer'],
450
- rationale: 'Understand current state, plan the change, execute, then review.',
451
- },
452
- {
453
- label: 'document-existing',
454
- pattern: /\b(document|readme|jsdoc|api\s*docs|write\s*docs?|add\s*docs?|update\s*docs?|generate\s*docs?)\b/i,
455
- risk: ['low', 'medium'],
456
- pipeline: ['research', 'documenter'],
457
- rationale: 'Understand the code first, then write accurate docs.',
458
- },
459
- {
460
- label: 'test-coverage',
461
- pattern: /\b(test\s+coverage|missing\s+tests?|add\s+tests?\s+for|write\s+tests?\s+for)\b/i,
462
- risk: ['low', 'medium'],
463
- pipeline: ['research', 'tester'],
464
- rationale: 'Understand what exists, then write targeted tests.',
465
- },
466
- {
467
- label: 'explore-then-build',
468
- pattern: /\b(implement|build|add|create|write)\b/i,
469
- risk: ['low', 'medium'],
470
- pipeline: ['research', 'worker', 'tester'],
471
- rationale: 'Understand the codebase, implement, verify with tests.',
472
- },
473
- ];
474
-
475
- // ─── dispatchFleetAgent ───────────────────────────────────────────────────────
476
-
477
- /**
478
- * Build a dispatch config for a fleet agent. Does NOT execute — the orchestrator does.
479
- *
480
- * @param {string} type — key from AGENT_TYPES
481
- * @param {object} payload — task-specific data (task, files, context, domain, etc.)
482
- * @param {object} [options]
483
- * @param {string} [options.provider] — force 'claude' or 'openai'
484
- * @param {number} [options.budgetPressure] — 0–1, influences model downgrade
485
- * @returns {object} dispatch config
486
- */
487
- function dispatchFleetAgent(type, payload = {}, options = {}) {
488
- const agentDef = AGENT_TYPES[type];
489
- if (!agentDef) {
490
- const valid = Object.keys(AGENT_TYPES).join(', ');
491
- throw new Error(`Unknown agent type "${type}". Valid types: ${valid}`);
492
- }
493
-
494
- const provider = options.provider || agentDef.preferredProvider;
495
- const budgetPressure = options.budgetPressure ?? 0;
496
-
497
- // Model selection with optional budget downgrade
498
- let claudeModel = agentDef.defaultModel.claude;
499
- let openaiModel = agentDef.defaultModel.openai;
500
-
501
- if (budgetPressure > 0.9) {
502
- // Aggressive downgrade for non-critical agents
503
- if (claudeModel === 'opus') claudeModel = 'sonnet';
504
- if (openaiModel === 'gpt-5.5') openaiModel = 'gpt-5.4';
505
- } else if (budgetPressure > 0.7) {
506
- if (claudeModel === 'opus' && agentDef.tier !== 'think') claudeModel = 'sonnet';
507
- }
508
-
509
- const selectedModel = provider === 'claude' ? claudeModel : openaiModel;
510
- const effort = agentDef.defaultEffort[provider] || 'medium';
511
-
512
- const prompt = agentDef.promptTemplate(payload);
513
-
514
- return {
515
- agentType: type,
516
- provider,
517
- model: selectedModel,
518
- effort,
519
- tier: agentDef.tier,
520
- readOnly: agentDef.readOnly,
521
- maxDurationMs: agentDef.maxDurationMs,
522
- prompt,
523
- outputFormat: agentDef.outputFormat,
524
- payload, // pass through for logging/resumability
525
- ...(agentDef.allowedFilePatterns ? { allowedFilePatterns: agentDef.allowedFilePatterns } : {}),
526
- };
527
- }
528
-
529
- // ─── getAgentRecommendation ───────────────────────────────────────────────────
530
-
531
- /**
532
- * Recommend agent type(s) for a given task profile. Returns a pipeline.
533
- *
534
- * @param {string} intent — natural language task description
535
- * @param {string} [risk] — 'low' | 'medium' | 'high' | 'critical'
536
- * @param {string} [complexity] — 'trivial' | 'simple' | 'moderate' | 'complex'
537
- * @returns {{ pipeline: string[], rationale: string, preset: string|null }}
538
- */
539
- function getAgentRecommendation(intent, risk = 'medium', complexity = 'moderate') {
540
- // Try pipeline presets first
541
- for (const preset of PIPELINE_PRESETS) {
542
- const riskMatch = preset.risk.includes('any') || preset.risk.includes(risk);
543
- if (preset.pattern.test(intent) && riskMatch) {
544
- return {
545
- pipeline: preset.pipeline,
546
- rationale: preset.rationale,
547
- preset: preset.label,
548
- };
549
- }
550
- }
551
-
552
- // Fallback: derive from risk + complexity
553
- if (risk === 'critical') {
554
- return {
555
- pipeline: ['specialist', 'reviewer', 'planner', 'worker', 'reviewer'],
556
- rationale: 'Critical risk: specialist audit, review, plan, implement, re-review.',
557
- preset: null,
558
- };
559
- }
560
-
561
- if (complexity === 'complex') {
562
- return {
563
- pipeline: ['research', 'planner', 'worker', 'reviewer'],
564
- rationale: 'Complex task: explore, plan, build, verify.',
565
- preset: null,
566
- };
567
- }
568
-
569
- if (complexity === 'moderate') {
570
- return {
571
- pipeline: ['research', 'worker', 'tester'],
572
- rationale: 'Moderate complexity: understand context, implement, verify.',
573
- preset: null,
574
- };
575
- }
576
-
577
- // Simple / trivial
578
- return {
579
- pipeline: ['worker'],
580
- rationale: 'Simple task: direct implementation.',
581
- preset: null,
582
- };
583
- }
584
-
585
- // ─── CLI ──────────────────────────────────────────────────────────────────────
586
-
587
- if (process.argv[1] && new URL(import.meta.url).pathname === process.argv[1]) {
588
- const args = process.argv.slice(2);
589
-
590
- if (args.includes('--list')) {
591
- console.log('\nAgent Fleet — Available Types\n');
592
- for (const [key, def] of Object.entries(AGENT_TYPES)) {
593
- const rw = def.readOnly ? 'read-only' : 'read/write';
594
- const dur = `${def.maxDurationMs / 1000}s max`;
595
- console.log(` ${key.padEnd(12)} [${def.tier.padEnd(7)}] [${rw.padEnd(10)}] [${dur.padEnd(8)}]`);
596
- console.log(` ${def.description}`);
597
- console.log(` Claude: ${def.defaultModel.claude}, OpenAI: ${def.defaultModel.openai} (prefers ${def.preferredProvider})\n`);
598
- }
599
- process.exit(0);
600
- }
601
-
602
- const recommendIdx = args.indexOf('--recommend');
603
- if (recommendIdx !== -1) {
604
- const utterance = args[recommendIdx + 1] || args.find(a => !a.startsWith('--')) || '';
605
- if (!utterance) {
606
- console.error('Usage: node hooks/agent-fleet.mjs --recommend "description"');
607
- process.exit(1);
608
- }
609
-
610
- // Basic risk/complexity inference for CLI use
611
- const RISK_WORDS = /\b(auth|secret|credential|token|password|encrypt|security|vulnerability|billing|migration)\b/i;
612
- const COMPLEX_WORDS = /\b(refactor|redesign|architect|audit|all|entire|everywhere|across)\b/i;
613
-
614
- const risk = RISK_WORDS.test(utterance) ? 'high' : 'medium';
615
- const complexity = COMPLEX_WORDS.test(utterance) ? 'complex' : 'moderate';
616
-
617
- const rec = getAgentRecommendation(utterance, risk, complexity);
618
-
619
- console.log('\nAgent Recommendation\n');
620
- console.log(`Task: ${utterance}`);
621
- console.log(`Risk: ${risk} Complexity: ${complexity}`);
622
- console.log(`Preset: ${rec.preset || '(none — derived from risk/complexity)'}`);
623
- console.log(`Pipeline: ${rec.pipeline.join(' → ')}`);
624
- console.log(`Rationale: ${rec.rationale}`);
625
- console.log('\nWave breakdown:');
626
- rec.pipeline.forEach((agentType, i) => {
627
- const def = AGENT_TYPES[agentType];
628
- const rw = def.readOnly ? 'read-only' : 'read/write';
629
- console.log(` Wave ${i + 1}: ${agentType.padEnd(12)} [${def.tier}] [${rw}] — ${def.description}`);
630
- });
631
- console.log('');
632
-
633
- process.exit(0);
634
- }
635
-
636
- // General dispatch preview
637
- const type = args.find(a => !a.startsWith('--'));
638
- if (type) {
639
- const payload = { task: 'CLI preview — no real task provided' };
640
- try {
641
- const config = dispatchFleetAgent(type, payload);
642
- console.log(JSON.stringify(config, null, 2));
643
- } catch (err) {
644
- console.error(`Error: ${err.message}`);
645
- process.exit(1);
646
- }
647
- process.exit(0);
648
- }
649
-
650
- console.log('Usage:');
651
- console.log(' node hooks/agent-fleet.mjs --list');
652
- console.log(' node hooks/agent-fleet.mjs --recommend "refactor the auth module"');
653
- console.log(' node hooks/agent-fleet.mjs <agentType> # preview dispatch config');
654
- process.exit(0);
655
- }
656
-
657
- // ─── Exports ──────────────────────────────────────────────────────────────────
658
-
659
- export { AGENT_TYPES, PIPELINE_PRESETS, dispatchFleetAgent, getAgentRecommendation };