@codexa/cli 9.0.10 → 9.0.12
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.
- package/commands/team.test.ts +253 -0
- package/commands/team.ts +703 -0
- package/package.json +1 -1
- package/workflow.ts +17 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "bun:test";
|
|
2
|
+
import { Database } from "bun:sqlite";
|
|
3
|
+
import {
|
|
4
|
+
detectPhase,
|
|
5
|
+
buildLeadSpawnInstruction,
|
|
6
|
+
buildImpSpawnPrompt,
|
|
7
|
+
buildRevSpawnPrompt,
|
|
8
|
+
buildArchitectSpawnPrompt,
|
|
9
|
+
buildArchitectReviewerPrompt,
|
|
10
|
+
type TeammateConfig,
|
|
11
|
+
} from "./team";
|
|
12
|
+
|
|
13
|
+
// ─────────────────────────────────────────────────────────────────
|
|
14
|
+
// Helpers
|
|
15
|
+
// ─────────────────────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
function createTestDb(): Database {
|
|
18
|
+
const db = new Database(":memory:");
|
|
19
|
+
|
|
20
|
+
db.run(`CREATE TABLE specs (
|
|
21
|
+
id TEXT PRIMARY KEY, name TEXT, phase TEXT, approved_at TEXT,
|
|
22
|
+
analysis_id TEXT, created_at TEXT, updated_at TEXT
|
|
23
|
+
)`);
|
|
24
|
+
|
|
25
|
+
db.run(`CREATE TABLE tasks (
|
|
26
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT, spec_id TEXT, number INTEGER,
|
|
27
|
+
name TEXT, depends_on TEXT, can_parallel INTEGER DEFAULT 1,
|
|
28
|
+
agent TEXT, files TEXT, status TEXT DEFAULT 'pending',
|
|
29
|
+
checkpoint TEXT, started_at TEXT, completed_at TEXT
|
|
30
|
+
)`);
|
|
31
|
+
|
|
32
|
+
db.run(`CREATE TABLE artifacts (
|
|
33
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT, spec_id TEXT,
|
|
34
|
+
task_ref INTEGER, path TEXT, action TEXT, created_at TEXT
|
|
35
|
+
)`);
|
|
36
|
+
|
|
37
|
+
db.run(`CREATE TABLE architectural_analyses (
|
|
38
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, status TEXT DEFAULT 'pending'
|
|
39
|
+
)`);
|
|
40
|
+
|
|
41
|
+
db.run(`CREATE TABLE project (
|
|
42
|
+
id TEXT PRIMARY KEY DEFAULT 'default', stack TEXT,
|
|
43
|
+
cli_version TEXT, typecheck_command TEXT, grepai_workspace TEXT
|
|
44
|
+
)`);
|
|
45
|
+
|
|
46
|
+
db.run("INSERT INTO project (id) VALUES ('default')");
|
|
47
|
+
|
|
48
|
+
return db;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function insertSpec(db: Database, id: string, name: string, phase: string): void {
|
|
52
|
+
db.run("INSERT INTO specs (id, name, phase, created_at) VALUES (?, ?, ?, datetime('now'))", [id, name, phase]);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function insertTask(
|
|
56
|
+
db: Database,
|
|
57
|
+
specId: string,
|
|
58
|
+
number: number,
|
|
59
|
+
name: string,
|
|
60
|
+
options: { agent?: string; canParallel?: boolean; dependsOn?: number[]; status?: string } = {}
|
|
61
|
+
): number {
|
|
62
|
+
const result = db.run(
|
|
63
|
+
`INSERT INTO tasks (spec_id, number, name, agent, can_parallel, depends_on, status)
|
|
64
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
65
|
+
[
|
|
66
|
+
specId,
|
|
67
|
+
number,
|
|
68
|
+
name,
|
|
69
|
+
options.agent || "general",
|
|
70
|
+
options.canParallel !== false ? 1 : 0,
|
|
71
|
+
options.dependsOn ? JSON.stringify(options.dependsOn) : null,
|
|
72
|
+
options.status || "pending",
|
|
73
|
+
]
|
|
74
|
+
);
|
|
75
|
+
return Number(result.lastInsertRowid);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function insertArtifact(db: Database, specId: string, taskRef: number, path: string): void {
|
|
79
|
+
db.run("INSERT INTO artifacts (spec_id, task_ref, path, action) VALUES (?, ?, ?, 'created')", [specId, taskRef, path]);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ─────────────────────────────────────────────────────────────────
|
|
83
|
+
// Tests
|
|
84
|
+
// ─────────────────────────────────────────────────────────────────
|
|
85
|
+
|
|
86
|
+
describe("detectPhase", () => {
|
|
87
|
+
it("detecta imp quando spec.phase = implementing", () => {
|
|
88
|
+
const db = createTestDb();
|
|
89
|
+
const spec = { phase: "implementing" };
|
|
90
|
+
expect(detectPhase(db, spec)).toBe("imp");
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("detecta rev quando spec.phase = reviewing", () => {
|
|
94
|
+
const db = createTestDb();
|
|
95
|
+
const spec = { phase: "reviewing" };
|
|
96
|
+
expect(detectPhase(db, spec)).toBe("rev");
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("detecta architect quando ha analise pendente", () => {
|
|
100
|
+
const db = createTestDb();
|
|
101
|
+
db.run("INSERT INTO architectural_analyses (name, status) VALUES ('test', 'pending')");
|
|
102
|
+
const spec = { phase: "planning" };
|
|
103
|
+
expect(detectPhase(db, spec)).toBe("architect");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("retorna phase original se nao ha analise pendente", () => {
|
|
107
|
+
const db = createTestDb();
|
|
108
|
+
const spec = { phase: "planning" };
|
|
109
|
+
expect(detectPhase(db, spec)).toBe("planning");
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe("buildLeadSpawnInstruction", () => {
|
|
114
|
+
it("gera instrucao em linguagem natural", () => {
|
|
115
|
+
const teammates: TeammateConfig[] = [
|
|
116
|
+
{ role: "backend-implementer", domain: "backend", taskIds: [1], spawnPrompt: "test prompt" },
|
|
117
|
+
];
|
|
118
|
+
const instruction = buildLeadSpawnInstruction(teammates, "imp");
|
|
119
|
+
expect(instruction).toContain("Create an agent team");
|
|
120
|
+
expect(instruction).toContain("delegate mode");
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("inclui nome de todos teammates", () => {
|
|
124
|
+
const teammates: TeammateConfig[] = [
|
|
125
|
+
{ role: "backend-implementer", domain: "backend", taskIds: [1], spawnPrompt: "p1" },
|
|
126
|
+
{ role: "frontend-implementer", domain: "frontend", taskIds: [2], spawnPrompt: "p2" },
|
|
127
|
+
];
|
|
128
|
+
const instruction = buildLeadSpawnInstruction(teammates, "imp");
|
|
129
|
+
expect(instruction).toContain("backend-implementer");
|
|
130
|
+
expect(instruction).toContain("frontend-implementer");
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("inclui instrucao de delegate mode", () => {
|
|
134
|
+
const teammates: TeammateConfig[] = [
|
|
135
|
+
{ role: "test", domain: "test", taskIds: [], spawnPrompt: "p" },
|
|
136
|
+
];
|
|
137
|
+
const instruction = buildLeadSpawnInstruction(teammates, "rev");
|
|
138
|
+
expect(instruction).toContain("do NOT implement anything yourself");
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("usa descricao correta por fase", () => {
|
|
142
|
+
const tm: TeammateConfig[] = [{ role: "r", domain: "d", taskIds: [], spawnPrompt: "p" }];
|
|
143
|
+
expect(buildLeadSpawnInstruction(tm, "imp")).toContain("implement parallel tasks");
|
|
144
|
+
expect(buildLeadSpawnInstruction(tm, "rev")).toContain("review artifacts");
|
|
145
|
+
expect(buildLeadSpawnInstruction(tm, "architect")).toContain("competing architectural");
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe("buildImpSpawnPrompt", () => {
|
|
150
|
+
it("inclui identidade de teammate", () => {
|
|
151
|
+
const prompt = buildImpSpawnPrompt({ name: "Test Feature" }, "backend", [
|
|
152
|
+
{ number: 1, name: "Task 1", id: 10, files: '["src/a.ts"]' },
|
|
153
|
+
]);
|
|
154
|
+
expect(prompt).toContain("TEAMMATE de implementacao");
|
|
155
|
+
expect(prompt).toContain("Dominio: backend");
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("inclui secao TASK LIST com instrucao de ignorar nativa", () => {
|
|
159
|
+
const prompt = buildImpSpawnPrompt({ name: "F" }, "backend", [
|
|
160
|
+
{ number: 1, name: "T1", id: 1, files: null },
|
|
161
|
+
]);
|
|
162
|
+
expect(prompt).toContain("TASK LIST");
|
|
163
|
+
expect(prompt).toContain("IGNORE");
|
|
164
|
+
expect(prompt).toContain("Codexa tasks");
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("inclui instrucao de messaging nativo", () => {
|
|
168
|
+
const prompt = buildImpSpawnPrompt({ name: "F" }, "backend", [
|
|
169
|
+
{ number: 1, name: "T1", id: 1, files: null },
|
|
170
|
+
]);
|
|
171
|
+
expect(prompt).toContain("ferramenta `message`");
|
|
172
|
+
expect(prompt).toContain("codexa knowledge add");
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("lista todas tasks atribuidas", () => {
|
|
176
|
+
const prompt = buildImpSpawnPrompt({ name: "F" }, "backend", [
|
|
177
|
+
{ number: 1, name: "Create schema", id: 10, files: '["db/schema.ts"]' },
|
|
178
|
+
{ number: 2, name: "Add migration", id: 11, files: null },
|
|
179
|
+
]);
|
|
180
|
+
expect(prompt).toContain("Task #1: Create schema");
|
|
181
|
+
expect(prompt).toContain("Task #2: Add migration");
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
describe("buildRevSpawnPrompt", () => {
|
|
186
|
+
it("inclui lente correta", () => {
|
|
187
|
+
const prompt = buildRevSpawnPrompt({ name: "F" }, "security", ["src/a.ts"]);
|
|
188
|
+
expect(prompt).toContain("**SECURITY**");
|
|
189
|
+
expect(prompt).toContain("OWASP");
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("inclui instrucao de message para enviar findings", () => {
|
|
193
|
+
const prompt = buildRevSpawnPrompt({ name: "F" }, "performance", ["src/a.ts"]);
|
|
194
|
+
expect(prompt).toContain("ferramenta `message`");
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("inclui instrucao de ignorar task list nativa", () => {
|
|
198
|
+
const prompt = buildRevSpawnPrompt({ name: "F" }, "standards", ["src/a.ts"]);
|
|
199
|
+
expect(prompt).toContain("IGNORE a task list nativa");
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("lista artefatos para revisao", () => {
|
|
203
|
+
const prompt = buildRevSpawnPrompt({ name: "F" }, "security", ["src/a.ts", "src/b.ts"]);
|
|
204
|
+
expect(prompt).toContain("- src/a.ts");
|
|
205
|
+
expect(prompt).toContain("- src/b.ts");
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
describe("buildArchitectSpawnPrompt", () => {
|
|
210
|
+
it("inclui identidade de architect", () => {
|
|
211
|
+
const prompt = buildArchitectSpawnPrompt({ name: "Add auth" }, {}, "alpha");
|
|
212
|
+
expect(prompt).toContain("ARCHITECT ALPHA");
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it("inclui instrucao de message para proposta", () => {
|
|
216
|
+
const prompt = buildArchitectSpawnPrompt({ name: "Add auth" }, {}, "beta");
|
|
217
|
+
expect(prompt).toContain("ferramenta `message`");
|
|
218
|
+
expect(prompt).toContain("Enviar ao Lead");
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it("inclui 8 headers obrigatorios", () => {
|
|
222
|
+
const prompt = buildArchitectSpawnPrompt({ name: "Add auth" }, {}, "alpha");
|
|
223
|
+
expect(prompt).toContain("Contexto e Entendimento");
|
|
224
|
+
expect(prompt).toContain("Baby Steps");
|
|
225
|
+
expect(prompt).toContain("Decisoes Arquiteturais");
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
describe("buildArchitectReviewerPrompt", () => {
|
|
230
|
+
it("inclui explicacao de entrega automatica de mensagens", () => {
|
|
231
|
+
const prompt = buildArchitectReviewerPrompt({ name: "Add auth" });
|
|
232
|
+
expect(prompt).toContain("entregues automaticamente");
|
|
233
|
+
expect(prompt).toContain("sem precisar");
|
|
234
|
+
expect(prompt).toContain("polling");
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it("instrui a aguardar AMBAS propostas", () => {
|
|
238
|
+
const prompt = buildArchitectReviewerPrompt({ name: "Add auth" });
|
|
239
|
+
expect(prompt).toContain("AMBAS as propostas");
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("inclui formato estruturado de critica", () => {
|
|
243
|
+
const prompt = buildArchitectReviewerPrompt({ name: "Add auth" });
|
|
244
|
+
expect(prompt).toContain("Pontos Fortes");
|
|
245
|
+
expect(prompt).toContain("Pontos Fracos");
|
|
246
|
+
expect(prompt).toContain("FORTE | VIAVEL | FRACO");
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it("inclui instrucao de IGNORE task list nativa", () => {
|
|
250
|
+
const prompt = buildArchitectReviewerPrompt({ name: "Add auth" });
|
|
251
|
+
expect(prompt).toContain("IGNORE a task list nativa");
|
|
252
|
+
});
|
|
253
|
+
});
|
package/commands/team.ts
ADDED
|
@@ -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: "architect-reviewer",
|
|
276
|
+
domain: "architecture",
|
|
277
|
+
taskIds: [],
|
|
278
|
+
spawnPrompt: buildArchitectReviewerPrompt(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 Architect Reviewer via \`message\` (entrega automatica).
|
|
568
|
+
- Responda via \`message\` ao Architect Reviewer 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 Architect Reviewer
|
|
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: Architect Reviewer
|
|
593
|
+
// ─────────────────────────────────────────────────────────────────
|
|
594
|
+
|
|
595
|
+
export function buildArchitectReviewerPrompt(analysis: any): string {
|
|
596
|
+
return `## IDENTIDADE
|
|
597
|
+
|
|
598
|
+
Voce e o ARCHITECT REVIEWER 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
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codexa/cli",
|
|
3
|
-
"version": "9.0.
|
|
3
|
+
"version": "9.0.12",
|
|
4
4
|
"description": "Orchestrated workflow system for Claude Code - manages feature development through parallel subagents with structured phases, gates, and quality enforcement.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/workflow.ts
CHANGED
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
architectExport,
|
|
41
41
|
architectCancel,
|
|
42
42
|
} from "./commands/architect";
|
|
43
|
+
import { teamSuggest } from "./commands/team";
|
|
43
44
|
import { initSchema } from "./db/schema";
|
|
44
45
|
import { getDb, closeDb } from "./db/connection";
|
|
45
46
|
import { execSync } from "child_process";
|
|
@@ -987,6 +988,22 @@ architectCmd
|
|
|
987
988
|
architectCancel(options);
|
|
988
989
|
});
|
|
989
990
|
|
|
991
|
+
// ═══════════════════════════════════════════════════════════════
|
|
992
|
+
// AGENT TEAMS (Experimental)
|
|
993
|
+
// ═══════════════════════════════════════════════════════════════
|
|
994
|
+
|
|
995
|
+
const teamCmd = program.command("team").description("Comandos de Agent Teams (experimental)");
|
|
996
|
+
|
|
997
|
+
teamCmd
|
|
998
|
+
.command("suggest")
|
|
999
|
+
.description("Sugere modo de execucao (team vs subagent) para a fase atual")
|
|
1000
|
+
.option("--json", "Saida em JSON")
|
|
1001
|
+
.option("--phase <phase>", "Fase especifica (imp, rev, architect)")
|
|
1002
|
+
.option("--spec <id>", "ID do spec (padrao: mais recente)")
|
|
1003
|
+
.action(wrapAction((options) => {
|
|
1004
|
+
teamSuggest(options);
|
|
1005
|
+
}));
|
|
1006
|
+
|
|
990
1007
|
// ═══════════════════════════════════════════════════════════════
|
|
991
1008
|
// PLUGIN
|
|
992
1009
|
// ═══════════════════════════════════════════════════════════════
|