@codexa/cli 9.0.9 → 9.0.11

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,703 @@
1
+ import { getDb } from "../db/connection";
2
+ import { initSchema } from "../db/schema";
3
+ import { resolveSpec, resolveSpecOrNull } from "./spec-resolver";
4
+
5
+ // ─────────────────────────────────────────────────────────────────
6
+ // Interfaces
7
+ // ─────────────────────────────────────────────────────────────────
8
+
9
+ export interface TeammateConfig {
10
+ role: string;
11
+ domain: string;
12
+ taskIds: number[];
13
+ spawnPrompt: string;
14
+ }
15
+
16
+ export interface TeamSuggestion {
17
+ recommended: boolean;
18
+ mode: "team" | "subagent";
19
+ reason: string;
20
+ envVarSet: boolean;
21
+ teamConfig?: {
22
+ phase: "imp" | "rev" | "architect";
23
+ teammates: TeammateConfig[];
24
+ estimatedParallelism: number;
25
+ leadSpawnInstruction: string;
26
+ };
27
+ }
28
+
29
+ // ─────────────────────────────────────────────────────────────────
30
+ // Main Command
31
+ // ─────────────────────────────────────────────────────────────────
32
+
33
+ export function teamSuggest(options: {
34
+ json?: boolean;
35
+ phase?: string;
36
+ spec?: string;
37
+ }): void {
38
+ initSchema();
39
+ const db = getDb();
40
+
41
+ const envVarSet = process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS === "1";
42
+
43
+ // Phase pode ser fornecida ou detectada
44
+ let spec: any = null;
45
+ let phase = options.phase;
46
+
47
+ if (!phase) {
48
+ spec = resolveSpecOrNull(options.spec);
49
+ if (spec) {
50
+ phase = detectPhase(db, spec);
51
+ } else {
52
+ phase = "unknown";
53
+ }
54
+ } else {
55
+ spec = resolveSpecOrNull(options.spec);
56
+ }
57
+
58
+ let result: TeamSuggestion;
59
+
60
+ if (phase === "imp" && spec) {
61
+ result = suggestForImp(db, spec, envVarSet);
62
+ } else if (phase === "rev" && spec) {
63
+ result = suggestForRev(db, spec, envVarSet);
64
+ } else if (phase === "architect") {
65
+ result = suggestForArchitect(db, spec, envVarSet);
66
+ } else {
67
+ result = {
68
+ recommended: false,
69
+ mode: "subagent",
70
+ reason: `Fase atual (${phase}) nao suporta teams.`,
71
+ envVarSet,
72
+ };
73
+ }
74
+
75
+ if (options.json) {
76
+ console.log(JSON.stringify(result, null, 2));
77
+ } else {
78
+ printTeamSuggestion(result);
79
+ }
80
+ }
81
+
82
+ // ─────────────────────────────────────────────────────────────────
83
+ // Phase Detection
84
+ // ─────────────────────────────────────────────────────────────────
85
+
86
+ export function detectPhase(db: any, spec: any): string {
87
+ if (spec.phase === "implementing") return "imp";
88
+ if (spec.phase === "reviewing") return "rev";
89
+
90
+ // Verificar se ha analise arquitetural pendente
91
+ const pendingAnalysis = db
92
+ .query("SELECT id FROM architectural_analyses WHERE status = 'pending' LIMIT 1")
93
+ .get();
94
+ if (pendingAnalysis) return "architect";
95
+
96
+ return spec.phase;
97
+ }
98
+
99
+ // ─────────────────────────────────────────────────────────────────
100
+ // IMP Phase
101
+ // ─────────────────────────────────────────────────────────────────
102
+
103
+ function suggestForImp(db: any, spec: any, envVarSet: boolean): TeamSuggestion {
104
+ // 1. Buscar tasks pending com dependencias satisfeitas
105
+ const allTasks = db
106
+ .query("SELECT * FROM tasks WHERE spec_id = ? AND status = 'pending'")
107
+ .all(spec.id) as any[];
108
+
109
+ const available = allTasks.filter((t: any) => {
110
+ if (!t.depends_on) return true;
111
+ const deps = JSON.parse(t.depends_on) as number[];
112
+ return deps.every((depNum) => {
113
+ const dep = db
114
+ .query("SELECT status FROM tasks WHERE spec_id = ? AND number = ?")
115
+ .get(spec.id, depNum) as any;
116
+ return dep?.status === "done";
117
+ });
118
+ });
119
+
120
+ const parallelizable = available.filter((t: any) => t.can_parallel);
121
+
122
+ // 2. Agrupar por dominio (campo agent)
123
+ const byDomain = new Map<string, any[]>();
124
+ for (const task of parallelizable) {
125
+ const domain = task.agent || "general";
126
+ if (!byDomain.has(domain)) byDomain.set(domain, []);
127
+ byDomain.get(domain)!.push(task);
128
+ }
129
+
130
+ // 3. Recomendar se >= 3 tasks em >= 2 dominios
131
+ if (parallelizable.length < 3 || byDomain.size < 2) {
132
+ return {
133
+ recommended: false,
134
+ mode: "subagent",
135
+ reason: `${parallelizable.length} tasks paralelas em ${byDomain.size} dominio(s). Minimo: 3 tasks, 2 dominios.`,
136
+ envVarSet,
137
+ };
138
+ }
139
+
140
+ if (!envVarSet) {
141
+ return {
142
+ recommended: true,
143
+ mode: "subagent",
144
+ reason: "Team recomendado mas CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS nao definida. Usando subagent.",
145
+ envVarSet: false,
146
+ };
147
+ }
148
+
149
+ // 4. Gerar teammates
150
+ const teammates: TeammateConfig[] = [];
151
+ for (const [domain, tasks] of byDomain) {
152
+ teammates.push({
153
+ role: `${domain}-implementer`,
154
+ domain,
155
+ taskIds: tasks.map((t: any) => t.id),
156
+ spawnPrompt: buildImpSpawnPrompt(spec, domain, tasks),
157
+ });
158
+ }
159
+
160
+ return {
161
+ recommended: true,
162
+ mode: "team",
163
+ reason: `${parallelizable.length} tasks paralelas em ${byDomain.size} dominios.`,
164
+ envVarSet: true,
165
+ teamConfig: {
166
+ phase: "imp",
167
+ teammates,
168
+ estimatedParallelism: parallelizable.length,
169
+ leadSpawnInstruction: buildLeadSpawnInstruction(teammates, "imp"),
170
+ },
171
+ };
172
+ }
173
+
174
+ // ─────────────────────────────────────────────────────────────────
175
+ // REV Phase
176
+ // ─────────────────────────────────────────────────────────────────
177
+
178
+ function suggestForRev(db: any, spec: any, envVarSet: boolean): TeamSuggestion {
179
+ const totalTasks = (db
180
+ .query("SELECT COUNT(*) as count FROM tasks WHERE spec_id = ?")
181
+ .get(spec.id) as any).count;
182
+
183
+ const artifactCount = (db
184
+ .query("SELECT COUNT(*) as count FROM artifacts WHERE spec_id = ?")
185
+ .get(spec.id) as any).count;
186
+
187
+ if (totalTasks < 3 && artifactCount < 5) {
188
+ return {
189
+ recommended: false,
190
+ mode: "subagent",
191
+ reason: `${totalTasks} tasks, ${artifactCount} artefatos. Reviewer unico suficiente.`,
192
+ envVarSet,
193
+ };
194
+ }
195
+
196
+ if (!envVarSet) {
197
+ return {
198
+ recommended: true,
199
+ mode: "subagent",
200
+ reason: "Team recomendado mas env var nao definida.",
201
+ envVarSet: false,
202
+ };
203
+ }
204
+
205
+ const artifactList = (db
206
+ .query("SELECT path FROM artifacts WHERE spec_id = ?")
207
+ .all(spec.id) as any[]).map((a: any) => a.path);
208
+
209
+ const lenses = ["security", "performance", "standards"] as const;
210
+ const teammates: TeammateConfig[] = lenses.map((lens) => ({
211
+ role: `${lens}-reviewer`,
212
+ domain: "review",
213
+ taskIds: [],
214
+ spawnPrompt: buildRevSpawnPrompt(spec, lens, artifactList),
215
+ }));
216
+
217
+ return {
218
+ recommended: true,
219
+ mode: "team",
220
+ reason: `${totalTasks} tasks, ${artifactCount} artefatos. 3 reviewers recomendados.`,
221
+ envVarSet: true,
222
+ teamConfig: {
223
+ phase: "rev",
224
+ teammates,
225
+ estimatedParallelism: 3,
226
+ leadSpawnInstruction: buildLeadSpawnInstruction(teammates, "rev"),
227
+ },
228
+ };
229
+ }
230
+
231
+ // ─────────────────────────────────────────────────────────────────
232
+ // Architect Phase
233
+ // ─────────────────────────────────────────────────────────────────
234
+
235
+ function suggestForArchitect(db: any, spec: any, envVarSet: boolean): TeamSuggestion {
236
+ const analysis = db
237
+ .query("SELECT * FROM architectural_analyses WHERE status = 'pending' ORDER BY id DESC LIMIT 1")
238
+ .get() as any;
239
+
240
+ if (!analysis) {
241
+ return {
242
+ recommended: false,
243
+ mode: "subagent",
244
+ reason: "Nenhuma analise arquitetural pendente.",
245
+ envVarSet,
246
+ };
247
+ }
248
+
249
+ if (!envVarSet) {
250
+ return {
251
+ recommended: true,
252
+ mode: "subagent",
253
+ reason: "Team recomendado mas env var nao definida.",
254
+ envVarSet: false,
255
+ };
256
+ }
257
+
258
+ const project = db.query("SELECT * FROM project LIMIT 1").get() as any;
259
+ const stackSummary = project?.stack ? JSON.parse(project.stack) : {};
260
+
261
+ const teammates: TeammateConfig[] = [
262
+ {
263
+ role: "architect-alpha",
264
+ domain: "architecture",
265
+ taskIds: [],
266
+ spawnPrompt: buildArchitectSpawnPrompt(analysis, stackSummary, "alpha"),
267
+ },
268
+ {
269
+ role: "architect-beta",
270
+ domain: "architecture",
271
+ taskIds: [],
272
+ spawnPrompt: buildArchitectSpawnPrompt(analysis, stackSummary, "beta"),
273
+ },
274
+ {
275
+ role: "devil-advocate",
276
+ domain: "architecture",
277
+ taskIds: [],
278
+ spawnPrompt: buildDevilAdvocatePrompt(analysis),
279
+ },
280
+ ];
281
+
282
+ return {
283
+ recommended: true,
284
+ mode: "team",
285
+ reason: `Analise "${analysis.name}" pendente. Hipoteses competidoras recomendadas.`,
286
+ envVarSet: true,
287
+ teamConfig: {
288
+ phase: "architect",
289
+ teammates,
290
+ estimatedParallelism: 3,
291
+ leadSpawnInstruction: buildLeadSpawnInstruction(teammates, "architect"),
292
+ },
293
+ };
294
+ }
295
+
296
+ // ─────────────────────────────────────────────────────────────────
297
+ // Lead Spawn Instruction (natural language)
298
+ // ─────────────────────────────────────────────────────────────────
299
+
300
+ export function buildLeadSpawnInstruction(teammates: TeammateConfig[], phase: string): string {
301
+ const phaseDescriptions: Record<string, string> = {
302
+ imp: "implement parallel tasks",
303
+ rev: "review artifacts with specialized lenses",
304
+ architect: "propose competing architectural approaches",
305
+ };
306
+
307
+ const teammateLines = teammates.map((t) =>
308
+ `- "${t.role}" with the prompt: "${t.spawnPrompt.replace(/"/g, '\\"').substring(0, 200)}..."`
309
+ ).join("\n");
310
+
311
+ return `Create an agent team to ${phaseDescriptions[phase] || phase}. Spawn these teammates:
312
+
313
+ ${teammateLines}
314
+
315
+ Use delegate mode — do NOT implement anything yourself. Only coordinate, monitor messages, and synthesize results.
316
+ Wait for all teammates to finish before proceeding.`;
317
+ }
318
+
319
+ // ─────────────────────────────────────────────────────────────────
320
+ // Spawn Prompts: IMP
321
+ // ─────────────────────────────────────────────────────────────────
322
+
323
+ export function buildImpSpawnPrompt(spec: any, domain: string, tasks: any[]): string {
324
+ const taskList = tasks.map((t: any) =>
325
+ `- Task #${t.number}: ${t.name} (ID: ${t.id}, arquivos: ${t.files || "a definir"})`
326
+ ).join("\n");
327
+
328
+ return `## IDENTIDADE
329
+
330
+ Voce e um TEAMMATE de implementacao do Codexa Workflow.
331
+ Voce NAO e o orquestrador. Voce NAO coordena. Voce EXECUTA tasks.
332
+ Dominio: ${domain}
333
+
334
+ ## FEATURE
335
+
336
+ ${spec.name}
337
+
338
+ ## SUAS TASKS
339
+
340
+ ${taskList}
341
+
342
+ ## INSTRUCOES
343
+
344
+ Para CADA task atribuida a voce, execute na ordem:
345
+
346
+ ### 1. Iniciar Task
347
+ \`\`\`bash
348
+ codexa task start <TASK_ID> --json
349
+ \`\`\`
350
+ Leia o \`subagentContext\` e \`context\` retornados. Estes sao suas instrucoes de implementacao.
351
+
352
+ ### 2. Implementar
353
+ Use \`Read\`, \`Write\`, \`Edit\` para criar/modificar os arquivos listados.
354
+
355
+ **Regras de implementacao**:
356
+ - Siga os standards REQUIRED recebidos no contexto
357
+ - A cada 3 arquivos modificados, verifique blockers:
358
+ \`\`\`bash
359
+ codexa knowledge list --severity critical --unread
360
+ \`\`\`
361
+ - Se encontrar blocker critico: envie \`message\` ao lead explicando e PARE
362
+
363
+ ### 3. Completar Task
364
+ \`\`\`bash
365
+ codexa task done <TASK_ID> --output '{"status":"completed","summary":"descricao do que foi feito","files_created":["..."],"files_modified":["..."],"reasoning":{"approach":"como abordou o problema (min 20 chars)"}}'
366
+ \`\`\`
367
+
368
+ ### 4. Comunicar
369
+ Apos completar cada task, comunique via Agent Teams messaging (nativo):
370
+ - **Mensagem ao lead**: Use a ferramenta \`message\` para enviar resumo da task completada ao lead
371
+ - **Mensagem a outro teammate**: Use a ferramenta \`message\` para enviar diretamente ao teammate afetado
372
+ - **Persistir knowledge**: Para discoveries relevantes alem desta sessao:
373
+ \`\`\`bash
374
+ codexa knowledge add --content "DISCOVERY: descricao" --category discovery --severity info
375
+ \`\`\`
376
+
377
+ > **IMPORTANTE**: Use \`message\` (nativo Agent Teams) para comunicacao entre sessoes.
378
+ > Use \`codexa knowledge add\` (CLI) para persistir informacao no SQLite para futuras tasks.
379
+ > Ambos sao complementares — messaging e instantaneo, knowledge e persistente.
380
+
381
+ ### 5. Proxima Task
382
+ Apos completar, prossiga para a proxima task da sua lista.
383
+ Se todas suas tasks estao done, envie mensagem ao lead via \`message\` informando conclusao.
384
+
385
+ ## TASK LIST — REGRA CRITICA
386
+
387
+ Existem DUAS task lists neste ambiente:
388
+ 1. **Codexa tasks** (SQLite, via CLI): Esta e a source of truth. Use \`codexa task start/done\`.
389
+ 2. **Task list nativa** (Agent Teams): Usada APENAS pelo lead para coordenacao.
390
+
391
+ **Voce como teammate**: Use SOMENTE Codexa tasks (\`codexa task start\`, \`codexa task done\`).
392
+ NAO interaja com a task list nativa do Agent Teams — o lead gerencia ela.
393
+
394
+ ## CONTEXTO ON-DEMAND
395
+
396
+ Se precisar de mais contexto alem do minimal:
397
+ \`\`\`bash
398
+ codexa context detail standards # Regras do projeto
399
+ codexa context detail decisions # Decisoes anteriores
400
+ codexa context detail patterns # Patterns de codigo
401
+ codexa context detail knowledge # Knowledge de outras tasks
402
+ codexa context detail architecture # Analise arquitetural
403
+ \`\`\`
404
+
405
+ ## REGRAS ABSOLUTAS
406
+
407
+ 1. SEMPRE use \`codexa task start\` ANTES de implementar (gates de qualidade)
408
+ 2. SEMPRE use \`codexa task done --output\` APOS implementar (gates enforced)
409
+ 3. NUNCA modifique arquivos de tasks de outros teammates
410
+ 4. SEMPRE inclua \`reasoning.approach\` no retorno (minimo 20 chars — Gate 4.4)
411
+ 5. Se bloqueado: envie \`message\` ao lead com contexto completo
412
+ 6. Registre discoveries: \`codexa knowledge add\` (persistente) + \`message\` ao afetado (instantaneo)
413
+ 7. NAO tente coordenar outros teammates — isso e papel do lead
414
+ 8. Use SOMENTE Codexa tasks (CLI) — IGNORE a task list nativa do Agent Teams
415
+ 9. Comunicacao entre sessoes: SEMPRE via ferramentas \`message\`/\`broadcast\` do Agent Teams`;
416
+ }
417
+
418
+ // ─────────────────────────────────────────────────────────────────
419
+ // Spawn Prompts: REV
420
+ // ─────────────────────────────────────────────────────────────────
421
+
422
+ export function buildRevSpawnPrompt(spec: any, lens: string, artifactPaths: string[]): string {
423
+ const lensDescriptions: Record<string, string> = {
424
+ security: "SEGURANCA: OWASP Top 10 (injection, XSS, SSRF, CSRF), autenticacao/autorizacao (JWT, sessions, RBAC), secrets hardcoded, dependencias com vulnerabilidades, sanitizacao de input, file access, HTTP headers",
425
+ performance: "PERFORMANCE: N+1 queries, SELECT * sem necessidade, memory leaks, falta de memoizacao, queries sem index, renderizacoes desnecessarias (React), bundle size, lazy loading ausente, cache strategies",
426
+ standards: "STANDARDS E QUALIDADE: Conformidade com standards REQUIRED do projeto, DRY (utilities duplicadas), naming conventions, patterns do projeto seguidos, TypeScript types (sem 'any' injustificado), cobertura de testes, tratamento de erros",
427
+ };
428
+
429
+ return `## IDENTIDADE
430
+
431
+ Voce e um TEAMMATE revisor do Codexa Workflow.
432
+ Sua lente de analise: **${lens.toUpperCase()}**
433
+ Voce NAO modifica codigo. Voce ANALISA e REPORTA.
434
+
435
+ ## FEATURE REVISADA
436
+
437
+ ${spec.name}
438
+
439
+ ## SUA LENTE
440
+
441
+ ${lensDescriptions[lens] || lens}
442
+
443
+ ## ARTEFATOS PARA REVISAO
444
+
445
+ ${artifactPaths.map((p) => `- ${p}`).join("\n")}
446
+
447
+ ## INSTRUCOES
448
+
449
+ ### 1. Obter Contexto
450
+ \`\`\`bash
451
+ codexa review start --json
452
+ codexa context detail standards
453
+ \`\`\`
454
+
455
+ ### 2. Ler Artefatos
456
+ Leia CADA arquivo listado acima usando a ferramenta Read.
457
+
458
+ ### 3. Analisar com Sua Lente
459
+ Aplique APENAS sua lente (${lens}). NAO repita analises de outras lentes.
460
+ Para cada arquivo, identifique problemas por severidade.
461
+
462
+ ### 4. Enviar Findings ao Lead
463
+ Use a ferramenta \`message\` (nativa do Agent Teams) para enviar ao lead no formato:
464
+
465
+ \`\`\`
466
+ ## [${lens.toUpperCase()}] Review — ${spec.name}
467
+
468
+ ### Criticos (bloqueiam aprovacao)
469
+ - [arquivo:linha] Problema. Remediacao sugerida.
470
+
471
+ ### Altos (recomenda bloqueio)
472
+ - [arquivo:linha] Problema.
473
+
474
+ ### Medios (warning)
475
+ - [arquivo:linha] Observacao.
476
+
477
+ ### Baixos (sugestao)
478
+ - [arquivo:linha] Melhoria opcional.
479
+
480
+ ### Resultado: APROVADO | REPROVADO | RESSALVAS
481
+ Justificativa: ...
482
+ \`\`\`
483
+
484
+ ### 5. Registrar Knowledge
485
+ Para cada finding CRITICO ou ALTO:
486
+ \`\`\`bash
487
+ codexa knowledge add --content "REVIEW [${lens}]: problema em arquivo:linha" --category discovery --severity warning
488
+ \`\`\`
489
+
490
+ ## COMUNICACAO
491
+
492
+ - **Enviar findings ao lead**: Use a ferramenta \`message\` (nativa Agent Teams)
493
+ - **Persistir findings criticos**: Use \`codexa knowledge add\` (CLI) para SQLite
494
+ - NAO use a task list nativa do Agent Teams — apenas o lead gerencia ela
495
+
496
+ ## REGRAS
497
+
498
+ 1. NAO modifique nenhum arquivo
499
+ 2. Analise APENAS com sua lente (${lens})
500
+ 3. Seja ESPECIFICO: arquivo, linha, problema, sugestao de correcao
501
+ 4. Envie TODOS os findings ao lead via ferramenta \`message\`
502
+ 5. Registre findings criticos/altos via \`codexa knowledge add\` (persistencia SQLite)
503
+ 6. IGNORE a task list nativa do Agent Teams`;
504
+ }
505
+
506
+ // ─────────────────────────────────────────────────────────────────
507
+ // Spawn Prompts: Architect
508
+ // ─────────────────────────────────────────────────────────────────
509
+
510
+ export function buildArchitectSpawnPrompt(analysis: any, stackSummary: any, role: string): string {
511
+ return `## IDENTIDADE
512
+
513
+ Voce e o ARCHITECT ${role.toUpperCase()} do Codexa Workflow.
514
+ Voce propoe UMA abordagem INDEPENDENTE para o problema.
515
+ NAO consulte propostas de outros architects antes de formular a sua.
516
+
517
+ ## PROBLEMA
518
+
519
+ ${analysis.name}
520
+
521
+ ## STACK ATUAL
522
+
523
+ ${JSON.stringify(stackSummary, null, 2)}
524
+
525
+ ## INSTRUCOES
526
+
527
+ ### 1. Explorar Codebase
528
+ Use grepai para pesquisa semantica:
529
+ \`\`\`bash
530
+ grepai search "architecture layers and boundaries" --json --compact
531
+ grepai search "integration points for: ${analysis.name}" --json --compact
532
+ \`\`\`
533
+
534
+ Tambem use \`grepai trace\` para entender call graphs.
535
+
536
+ ### 2. Contextualizar
537
+ \`\`\`bash
538
+ codexa context detail standards
539
+ codexa context detail architecture
540
+ codexa context detail patterns
541
+ \`\`\`
542
+
543
+ ### 3. Propor Abordagem
544
+
545
+ Crie sua proposta seguindo os 8 headers OBRIGATORIOS:
546
+
547
+ 1. **## Contexto e Entendimento** — O que voce entendeu do problema
548
+ 2. **## Stack e Arquitetura Atual** — Estado atual do sistema
549
+ 3. **## Solucao Proposta** — SUA abordagem unica com justificativa
550
+ 4. **## Diagramas** — Minimo 2 diagramas Mermaid (arquitetura + fluxo)
551
+ 5. **## Baby Steps** — Passos atomicos (1-3 arquivos cada), formato:
552
+ ### N. Nome
553
+ **O que**: descricao
554
+ **Por que**: justificativa
555
+ **Resultado**: output esperado
556
+ **Arquivos**: lista
557
+ **Agente**: backend|frontend|database|testing|general
558
+ **Depende de**: N (ou nenhum)
559
+ 6. **## Riscos e Mitigacoes** — Trade-offs explicitos
560
+ 7. **## Alternativas Descartadas** — O que voce considerou e descartou
561
+ 8. **## Decisoes Arquiteturais** — ADRs (Architecture Decision Records)
562
+
563
+ ### 4. Enviar ao Lead
564
+ Use a ferramenta \`message\` (nativa Agent Teams) para enviar proposta completa ao lead.
565
+
566
+ ### 5. Responder Criticas
567
+ Voce recebera criticas do devil's advocate via \`message\` (entrega automatica).
568
+ - Responda via \`message\` ao devil's advocate com justificativas tecnicas
569
+ - Reconheca pontos fracos legitimos
570
+ - Proponha ajustes se necessario
571
+ - Envie versao revisada ao lead via \`message\`
572
+
573
+ ## COMUNICACAO
574
+
575
+ - **Proposta ao lead**: ferramenta \`message\` (nativa Agent Teams)
576
+ - **Resposta a criticas**: ferramenta \`message\` ao devil's advocate
577
+ - **NAO** leia arquivos criados por outros architects (independencia)
578
+ - **NAO** use a task list nativa do Agent Teams
579
+
580
+ ## REGRAS
581
+
582
+ 1. Proposta INDEPENDENTE — nao leia propostas de outros antes
583
+ 2. NUNCA escreva codigo de implementacao
584
+ 3. Minimo 2 diagramas Mermaid
585
+ 4. Baby steps atomicos (1-3 arquivos cada)
586
+ 5. Trade-offs EXPLICITOS para cada decisao
587
+ 6. Considere escalabilidade, manutenibilidade, seguranca
588
+ 7. Comunicacao SOMENTE via ferramenta \`message\` do Agent Teams`;
589
+ }
590
+
591
+ // ─────────────────────────────────────────────────────────────────
592
+ // Spawn Prompts: Devil's Advocate
593
+ // ─────────────────────────────────────────────────────────────────
594
+
595
+ export function buildDevilAdvocatePrompt(analysis: any): string {
596
+ return `## IDENTIDADE
597
+
598
+ Voce e o DEVIL'S ADVOCATE do Codexa Workflow.
599
+ Seu papel e DESAFIAR propostas arquiteturais, encontrando pontos fracos,
600
+ riscos nao considerados, e alternativas melhores.
601
+
602
+ ## PROBLEMA EM ANALISE
603
+
604
+ ${analysis.name}
605
+
606
+ ## INSTRUCOES
607
+
608
+ ### 1. Aguardar Propostas
609
+ Propostas dos architects (alpha e beta) serao entregues automaticamente via
610
+ o sistema de messaging do Agent Teams. Voce recebera as mensagens sem precisar
611
+ fazer polling — o Agent Teams entrega mensagens automaticamente na sua sessao.
612
+ Aguarde ate receber AMBAS as propostas antes de iniciar a critica.
613
+
614
+ ### 2. Analisar Criticamente CADA Proposta
615
+
616
+ Para cada proposta, avalie:
617
+ - **Viabilidade**: A solucao e realista para o contexto?
618
+ - **Escalabilidade**: Funciona com 10x mais dados/usuarios?
619
+ - **Manutenibilidade**: Outro dev entende em 6 meses?
620
+ - **Seguranca**: Ha vetores de ataque nao considerados?
621
+ - **Complexidade**: E a solucao mais simples possivel?
622
+ - **Trade-offs ocultos**: Que custos nao foram mencionados?
623
+ - **Baby steps**: Sao realmente atomicos? Dependencias corretas?
624
+
625
+ ### 3. Enviar Criticas ao Lead
626
+
627
+ Para CADA proposta, use a ferramenta \`message\` para enviar critica estruturada ao lead:
628
+
629
+ \`\`\`
630
+ ## Critica: Proposta [ALPHA/BETA]
631
+
632
+ ### Pontos Fortes
633
+ - ...
634
+
635
+ ### Pontos Fracos
636
+ - ...
637
+
638
+ ### Riscos Nao Considerados
639
+ - ...
640
+
641
+ ### Perguntas para o Architect
642
+ - ...
643
+
644
+ ### Veredito: FORTE | VIAVEL | FRACO
645
+ Justificativa: ...
646
+ \`\`\`
647
+
648
+ ### 4. Enviar Criticas aos Architects
649
+
650
+ Apos criticar cada proposta, envie tambem via \`message\` ao architect correspondente
651
+ para que ele possa defender/ajustar sua proposta.
652
+
653
+ ### 5. Recomendar ao Lead
654
+
655
+ Apos criticar ambas e receber defesas, envie recomendacao final ao lead via \`message\`:
656
+ - Qual proposta e mais robusta e por que
657
+ - Sugestoes de melhoria combinando elementos de ambas
658
+ - Riscos que persistem independente da escolha
659
+
660
+ ## COMUNICACAO
661
+
662
+ - **Receber propostas**: Automatico via Agent Teams messaging (sem polling)
663
+ - **Enviar criticas ao lead**: ferramenta \`message\`
664
+ - **Enviar criticas aos architects**: ferramenta \`message\` direta ao architect
665
+ - **NAO** use a task list nativa do Agent Teams
666
+
667
+ ## REGRAS
668
+
669
+ 1. Seja JUSTO — critique com fundamento, nao por criticar
670
+ 2. NAO proponha sua propria solucao — apenas critique
671
+ 3. Base criticas em principios de engenharia (SOLID, KISS, YAGNI)
672
+ 4. Considere o contexto real do projeto (stack, team size, constraints)
673
+ 5. Comunicacao SOMENTE via ferramenta \`message\` do Agent Teams
674
+ 6. IGNORE a task list nativa do Agent Teams`;
675
+ }
676
+
677
+ // ─────────────────────────────────────────────────────────────────
678
+ // Output Formatting
679
+ // ─────────────────────────────────────────────────────────────────
680
+
681
+ function printTeamSuggestion(result: TeamSuggestion): void {
682
+ console.log(`\n${"─".repeat(50)}`);
683
+ console.log(`Agent Teams - Sugestao`);
684
+ console.log(`${"─".repeat(50)}`);
685
+
686
+ console.log(` Recomendado: ${result.recommended ? "SIM" : "NAO"}`);
687
+ console.log(` Modo: ${result.mode}`);
688
+ console.log(` Env var: ${result.envVarSet ? "definida" : "NAO definida"}`);
689
+ console.log(` Motivo: ${result.reason}`);
690
+
691
+ if (result.teamConfig) {
692
+ const tc = result.teamConfig;
693
+ console.log(`\n Fase: ${tc.phase}`);
694
+ console.log(` Paralelismo: ${tc.estimatedParallelism}`);
695
+ console.log(` Teammates (${tc.teammates.length}):`);
696
+ for (const tm of tc.teammates) {
697
+ const taskInfo = tm.taskIds.length > 0 ? ` [tasks: ${tm.taskIds.join(",")}]` : "";
698
+ console.log(` - ${tm.role} (${tm.domain})${taskInfo}`);
699
+ }
700
+ }
701
+
702
+ console.log(`\n${"─".repeat(50)}\n`);
703
+ }