@codexa/cli 9.0.31 → 9.0.32
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/architect.ts +52 -87
- package/commands/check.ts +22 -23
- package/commands/clear.ts +42 -48
- package/commands/decide.ts +46 -44
- package/commands/discover.ts +81 -94
- package/commands/integration.test.ts +262 -313
- package/commands/knowledge.test.ts +56 -61
- package/commands/knowledge.ts +126 -131
- package/commands/patterns.ts +28 -43
- package/commands/plan.ts +50 -48
- package/commands/product.ts +57 -59
- package/commands/research.ts +64 -77
- package/commands/review.ts +100 -86
- package/commands/simplify.ts +24 -35
- package/commands/spec-resolver.test.ts +52 -48
- package/commands/spec-resolver.ts +21 -23
- package/commands/standards.ts +20 -27
- package/commands/sync.ts +2 -8
- package/commands/task.ts +106 -97
- package/commands/team.test.ts +22 -83
- package/commands/team.ts +62 -50
- package/commands/utils.ts +83 -81
- package/context/assembly.ts +0 -1
- package/context/generator.ts +66 -79
- package/context/sections.ts +8 -14
- package/db/connection.ts +195 -19
- package/db/schema.test.ts +288 -299
- package/db/schema.ts +297 -394
- package/db/test-helpers.ts +18 -29
- package/gates/standards-validator.test.ts +83 -86
- package/gates/standards-validator.ts +9 -41
- package/gates/validator.test.ts +13 -22
- package/gates/validator.ts +69 -107
- package/package.json +2 -1
- package/protocol/process-return.ts +41 -57
- package/simplify/prompt-builder.test.ts +44 -42
- package/simplify/prompt-builder.ts +12 -14
- package/workflow.ts +159 -174
package/commands/team.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { dbGet, dbAll } from "../db/connection";
|
|
2
2
|
import { initSchema } from "../db/schema";
|
|
3
3
|
import { resolveSpec, resolveSpecOrNull } from "./spec-resolver";
|
|
4
4
|
|
|
@@ -30,39 +30,37 @@ export interface TeamSuggestion {
|
|
|
30
30
|
// Main Command
|
|
31
31
|
// ─────────────────────────────────────────────────────────────────
|
|
32
32
|
|
|
33
|
-
export function teamSuggest(options: {
|
|
33
|
+
export async function teamSuggest(options: {
|
|
34
34
|
json?: boolean;
|
|
35
35
|
phase?: string;
|
|
36
36
|
spec?: string;
|
|
37
|
-
}): void {
|
|
38
|
-
initSchema();
|
|
39
|
-
const db = getDb();
|
|
37
|
+
}): Promise<void> {
|
|
38
|
+
await initSchema();
|
|
40
39
|
|
|
41
40
|
const envVarSet = process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS === "1";
|
|
42
41
|
|
|
43
|
-
// Phase pode ser fornecida ou detectada
|
|
44
42
|
let spec: any = null;
|
|
45
43
|
let phase = options.phase;
|
|
46
44
|
|
|
47
45
|
if (!phase) {
|
|
48
|
-
spec = resolveSpecOrNull(options.spec);
|
|
46
|
+
spec = await resolveSpecOrNull(options.spec);
|
|
49
47
|
if (spec) {
|
|
50
|
-
phase = detectPhase(
|
|
48
|
+
phase = await detectPhase(spec);
|
|
51
49
|
} else {
|
|
52
50
|
phase = "unknown";
|
|
53
51
|
}
|
|
54
52
|
} else {
|
|
55
|
-
spec = resolveSpecOrNull(options.spec);
|
|
53
|
+
spec = await resolveSpecOrNull(options.spec);
|
|
56
54
|
}
|
|
57
55
|
|
|
58
56
|
let result: TeamSuggestion;
|
|
59
57
|
|
|
60
58
|
if (phase === "imp" && spec) {
|
|
61
|
-
result = suggestForImp(
|
|
59
|
+
result = await suggestForImp(spec, envVarSet);
|
|
62
60
|
} else if (phase === "rev" && spec) {
|
|
63
|
-
result = suggestForRev(
|
|
61
|
+
result = await suggestForRev(spec, envVarSet);
|
|
64
62
|
} else if (phase === "architect") {
|
|
65
|
-
result = suggestForArchitect(
|
|
63
|
+
result = await suggestForArchitect(spec, envVarSet);
|
|
66
64
|
} else {
|
|
67
65
|
result = {
|
|
68
66
|
recommended: false,
|
|
@@ -83,14 +81,14 @@ export function teamSuggest(options: {
|
|
|
83
81
|
// Phase Detection
|
|
84
82
|
// ─────────────────────────────────────────────────────────────────
|
|
85
83
|
|
|
86
|
-
export function detectPhase(
|
|
84
|
+
export async function detectPhase(spec: any): Promise<string> {
|
|
87
85
|
if (spec.phase === "implementing") return "imp";
|
|
88
86
|
if (spec.phase === "reviewing") return "rev";
|
|
89
87
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
88
|
+
const pendingAnalysis = await dbGet<any>(
|
|
89
|
+
"SELECT id FROM architectural_analyses WHERE status = 'pending' LIMIT 1",
|
|
90
|
+
[]
|
|
91
|
+
);
|
|
94
92
|
if (pendingAnalysis) return "architect";
|
|
95
93
|
|
|
96
94
|
return spec.phase;
|
|
@@ -100,26 +98,35 @@ export function detectPhase(db: any, spec: any): string {
|
|
|
100
98
|
// IMP Phase
|
|
101
99
|
// ─────────────────────────────────────────────────────────────────
|
|
102
100
|
|
|
103
|
-
function suggestForImp(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const available
|
|
110
|
-
|
|
101
|
+
async function suggestForImp(spec: any, envVarSet: boolean): Promise<TeamSuggestion> {
|
|
102
|
+
const allTasks = await dbAll<any>(
|
|
103
|
+
"SELECT * FROM tasks WHERE spec_id = ? AND status = 'pending'",
|
|
104
|
+
[spec.id]
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const available: any[] = [];
|
|
108
|
+
for (const t of allTasks) {
|
|
109
|
+
if (!t.depends_on) {
|
|
110
|
+
available.push(t);
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
111
113
|
const deps = JSON.parse(t.depends_on) as number[];
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
let allDone = true;
|
|
115
|
+
for (const depNum of deps) {
|
|
116
|
+
const dep = await dbGet<any>(
|
|
117
|
+
"SELECT status FROM tasks WHERE spec_id = ? AND number = ?",
|
|
118
|
+
[spec.id, depNum]
|
|
119
|
+
);
|
|
120
|
+
if (dep?.status !== "done") {
|
|
121
|
+
allDone = false;
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (allDone) available.push(t);
|
|
126
|
+
}
|
|
119
127
|
|
|
120
128
|
const parallelizable = available.filter((t: any) => t.can_parallel);
|
|
121
129
|
|
|
122
|
-
// 2. Agrupar por dominio (campo agent)
|
|
123
130
|
const byDomain = new Map<string, any[]>();
|
|
124
131
|
for (const task of parallelizable) {
|
|
125
132
|
const domain = task.agent || "general";
|
|
@@ -127,7 +134,6 @@ function suggestForImp(db: any, spec: any, envVarSet: boolean): TeamSuggestion {
|
|
|
127
134
|
byDomain.get(domain)!.push(task);
|
|
128
135
|
}
|
|
129
136
|
|
|
130
|
-
// 3. Recomendar se >= 3 tasks em >= 2 dominios
|
|
131
137
|
if (parallelizable.length < 3 || byDomain.size < 2) {
|
|
132
138
|
return {
|
|
133
139
|
recommended: false,
|
|
@@ -146,7 +152,6 @@ function suggestForImp(db: any, spec: any, envVarSet: boolean): TeamSuggestion {
|
|
|
146
152
|
};
|
|
147
153
|
}
|
|
148
154
|
|
|
149
|
-
// 4. Gerar teammates
|
|
150
155
|
const teammates: TeammateConfig[] = [];
|
|
151
156
|
for (const [domain, tasks] of byDomain) {
|
|
152
157
|
teammates.push({
|
|
@@ -175,14 +180,18 @@ function suggestForImp(db: any, spec: any, envVarSet: boolean): TeamSuggestion {
|
|
|
175
180
|
// REV Phase
|
|
176
181
|
// ─────────────────────────────────────────────────────────────────
|
|
177
182
|
|
|
178
|
-
function suggestForRev(
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
183
|
+
async function suggestForRev(spec: any, envVarSet: boolean): Promise<TeamSuggestion> {
|
|
184
|
+
const totalTasksRow = await dbGet<any>(
|
|
185
|
+
"SELECT COUNT(*) as count FROM tasks WHERE spec_id = ?",
|
|
186
|
+
[spec.id]
|
|
187
|
+
);
|
|
188
|
+
const totalTasks = totalTasksRow?.count ?? 0;
|
|
182
189
|
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
190
|
+
const artifactCountRow = await dbGet<any>(
|
|
191
|
+
"SELECT COUNT(*) as count FROM artifacts WHERE spec_id = ?",
|
|
192
|
+
[spec.id]
|
|
193
|
+
);
|
|
194
|
+
const artifactCount = artifactCountRow?.count ?? 0;
|
|
186
195
|
|
|
187
196
|
if (totalTasks < 3 && artifactCount < 5) {
|
|
188
197
|
return {
|
|
@@ -202,9 +211,11 @@ function suggestForRev(db: any, spec: any, envVarSet: boolean): TeamSuggestion {
|
|
|
202
211
|
};
|
|
203
212
|
}
|
|
204
213
|
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
214
|
+
const artifactRows = await dbAll<any>(
|
|
215
|
+
"SELECT path FROM artifacts WHERE spec_id = ?",
|
|
216
|
+
[spec.id]
|
|
217
|
+
);
|
|
218
|
+
const artifactList = artifactRows.map((a: any) => a.path);
|
|
208
219
|
|
|
209
220
|
const lenses = ["security", "performance", "standards"] as const;
|
|
210
221
|
const teammates: TeammateConfig[] = lenses.map((lens) => ({
|
|
@@ -232,10 +243,11 @@ function suggestForRev(db: any, spec: any, envVarSet: boolean): TeamSuggestion {
|
|
|
232
243
|
// Architect Phase
|
|
233
244
|
// ─────────────────────────────────────────────────────────────────
|
|
234
245
|
|
|
235
|
-
function suggestForArchitect(
|
|
236
|
-
const analysis =
|
|
237
|
-
|
|
238
|
-
|
|
246
|
+
async function suggestForArchitect(spec: any, envVarSet: boolean): Promise<TeamSuggestion> {
|
|
247
|
+
const analysis = await dbGet<any>(
|
|
248
|
+
"SELECT * FROM architectural_analyses WHERE status = 'pending' ORDER BY id DESC LIMIT 1",
|
|
249
|
+
[]
|
|
250
|
+
);
|
|
239
251
|
|
|
240
252
|
if (!analysis) {
|
|
241
253
|
return {
|
|
@@ -255,7 +267,7 @@ function suggestForArchitect(db: any, spec: any, envVarSet: boolean): TeamSugges
|
|
|
255
267
|
};
|
|
256
268
|
}
|
|
257
269
|
|
|
258
|
-
const project =
|
|
270
|
+
const project = await dbGet<any>("SELECT * FROM project LIMIT 1", []);
|
|
259
271
|
const stackSummary = project?.stack ? JSON.parse(project.stack) : {};
|
|
260
272
|
|
|
261
273
|
const teammates: TeammateConfig[] = [
|
package/commands/utils.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { dbGet, dbAll, dbRun } from "../db/connection";
|
|
2
2
|
import { initSchema, getArchitecturalAnalysisForSpec, detectStuckTasks } from "../db/schema";
|
|
3
3
|
import { getKnowledgeForTask } from "./knowledge";
|
|
4
4
|
import { getLibContextsForAgent } from "./research";
|
|
@@ -13,20 +13,18 @@ export { AGENT_DOMAIN, getAgentDomain, domainToScope } from "../context/domains"
|
|
|
13
13
|
export { resolveAgent, resolveAgentName, suggestAgent, getCanonicalAgentNames } from "../context/agent-registry";
|
|
14
14
|
export { loadAgentExpertise, getAgentDescription } from "../context/agent-expertise";
|
|
15
15
|
|
|
16
|
-
export function status(json: boolean = false, specId?: string): void {
|
|
17
|
-
initSchema();
|
|
18
|
-
|
|
19
|
-
const db = getDb();
|
|
16
|
+
export async function status(json: boolean = false, specId?: string): Promise<void> {
|
|
17
|
+
await initSchema();
|
|
20
18
|
|
|
21
19
|
// Se --spec fornecido, mostra spec especifico
|
|
22
20
|
// Se nao fornecido, mostra todos os ativos (multi-spec)
|
|
23
21
|
if (specId) {
|
|
24
|
-
const spec = resolveSpec(specId);
|
|
25
|
-
showSingleSpecStatus(
|
|
22
|
+
const spec = await resolveSpec(specId);
|
|
23
|
+
await showSingleSpecStatus(spec, json);
|
|
26
24
|
return;
|
|
27
25
|
}
|
|
28
26
|
|
|
29
|
-
const allSpecs = getAllActiveSpecs();
|
|
27
|
+
const allSpecs = await getAllActiveSpecs();
|
|
30
28
|
|
|
31
29
|
if (allSpecs.length === 0) {
|
|
32
30
|
if (json) {
|
|
@@ -40,18 +38,18 @@ export function status(json: boolean = false, specId?: string): void {
|
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
if (allSpecs.length === 1) {
|
|
43
|
-
showSingleSpecStatus(
|
|
41
|
+
await showSingleSpecStatus(allSpecs[0], json);
|
|
44
42
|
return;
|
|
45
43
|
}
|
|
46
44
|
|
|
47
45
|
// Multi-spec: show summary table
|
|
48
|
-
showMultiSpecStatus(
|
|
46
|
+
await showMultiSpecStatus(allSpecs, json);
|
|
49
47
|
}
|
|
50
48
|
|
|
51
|
-
function showSingleSpecStatus(
|
|
52
|
-
const context =
|
|
53
|
-
const tasks =
|
|
54
|
-
const decisions =
|
|
49
|
+
async function showSingleSpecStatus(spec: any, json: boolean): Promise<void> {
|
|
50
|
+
const context = await dbGet<any>("SELECT * FROM context WHERE spec_id = ?", [spec.id]);
|
|
51
|
+
const tasks = await dbAll<any>("SELECT * FROM tasks WHERE spec_id = ?", [spec.id]);
|
|
52
|
+
const decisions = await dbAll<any>("SELECT * FROM decisions WHERE spec_id = ? AND status = 'active'", [spec.id]);
|
|
55
53
|
|
|
56
54
|
const tasksDone = tasks.filter((t: any) => t.status === "done").length;
|
|
57
55
|
const tasksRunning = tasks.filter((t: any) => t.status === "running").length;
|
|
@@ -94,7 +92,7 @@ function showSingleSpecStatus(db: any, spec: any, json: boolean): void {
|
|
|
94
92
|
console.log(` Pendentes: ${tasksPending}`);
|
|
95
93
|
|
|
96
94
|
if (tasksRunning > 0) {
|
|
97
|
-
const stuck = detectStuckTasks(spec.id);
|
|
95
|
+
const stuck = await detectStuckTasks(spec.id);
|
|
98
96
|
if (stuck.length > 0) {
|
|
99
97
|
console.log(`\n[!] AVISO: ${stuck.length} task(s) parada(s) ha mais de 30 minutos:`);
|
|
100
98
|
for (const t of stuck) {
|
|
@@ -136,19 +134,20 @@ function showSingleSpecStatus(db: any, spec: any, json: boolean): void {
|
|
|
136
134
|
console.log();
|
|
137
135
|
}
|
|
138
136
|
|
|
139
|
-
function showMultiSpecStatus(
|
|
137
|
+
async function showMultiSpecStatus(specs: any[], json: boolean): Promise<void> {
|
|
140
138
|
if (json) {
|
|
141
|
-
const specsData =
|
|
142
|
-
|
|
139
|
+
const specsData = [];
|
|
140
|
+
for (const spec of specs) {
|
|
141
|
+
const tasks = await dbAll<any>("SELECT * FROM tasks WHERE spec_id = ?", [spec.id]);
|
|
143
142
|
const done = tasks.filter((t: any) => t.status === "done").length;
|
|
144
|
-
|
|
143
|
+
specsData.push({
|
|
145
144
|
id: spec.id,
|
|
146
145
|
name: spec.name,
|
|
147
146
|
phase: spec.phase,
|
|
148
147
|
progress: tasks.length > 0 ? Math.round((done / tasks.length) * 100) : 0,
|
|
149
148
|
tasks: { done, total: tasks.length },
|
|
150
|
-
};
|
|
151
|
-
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
152
151
|
console.log(JSON.stringify({ active: true, version: pkg.version, specs: specsData }));
|
|
153
152
|
return;
|
|
154
153
|
}
|
|
@@ -158,7 +157,7 @@ function showMultiSpecStatus(db: any, specs: any[], json: boolean): void {
|
|
|
158
157
|
console.log(`${"=".repeat(60)}\n`);
|
|
159
158
|
|
|
160
159
|
for (const spec of specs) {
|
|
161
|
-
const tasks =
|
|
160
|
+
const tasks = await dbAll<any>("SELECT * FROM tasks WHERE spec_id = ?", [spec.id]);
|
|
162
161
|
const done = tasks.filter((t: any) => t.status === "done").length;
|
|
163
162
|
const progress = tasks.length > 0 ? Math.round((done / tasks.length) * 100) : 0;
|
|
164
163
|
const bar = "\u2588".repeat(Math.floor(progress / 5)) + "\u2591".repeat(20 - Math.floor(progress / 5));
|
|
@@ -173,19 +172,18 @@ function showMultiSpecStatus(db: any, specs: any[], json: boolean): void {
|
|
|
173
172
|
console.log(`Use: status --spec <id> para detalhes de uma feature\n`);
|
|
174
173
|
}
|
|
175
174
|
|
|
176
|
-
export function contextExport(options: { task?: string; json?: boolean; specId?: string; }): void {
|
|
177
|
-
initSchema();
|
|
175
|
+
export async function contextExport(options: { task?: string; json?: boolean; specId?: string; }): Promise<void> {
|
|
176
|
+
await initSchema();
|
|
178
177
|
|
|
179
|
-
const
|
|
178
|
+
const spec = await resolveSpec(options.specId);
|
|
180
179
|
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const
|
|
188
|
-
const project = db.query("SELECT * FROM project WHERE id = 'default'").get() as any;
|
|
180
|
+
const context = await dbGet<any>("SELECT * FROM context WHERE spec_id = ?", [spec.id]);
|
|
181
|
+
const decisions = await dbAll<any>(
|
|
182
|
+
"SELECT * FROM decisions WHERE spec_id = ? AND status = 'active'",
|
|
183
|
+
[spec.id]
|
|
184
|
+
);
|
|
185
|
+
const artifacts = await dbAll<any>("SELECT * FROM artifacts WHERE spec_id = ?", [spec.id]);
|
|
186
|
+
const project = await dbGet<any>("SELECT * FROM project WHERE id = 'default'", ["default"]);
|
|
189
187
|
|
|
190
188
|
let taskContext = null;
|
|
191
189
|
let standards: any[] = [];
|
|
@@ -194,7 +192,7 @@ export function contextExport(options: { task?: string; json?: boolean; specId?:
|
|
|
194
192
|
|
|
195
193
|
if (options.task) {
|
|
196
194
|
const taskId = parseInt(options.task);
|
|
197
|
-
const task =
|
|
195
|
+
const task = await dbGet<any>("SELECT * FROM tasks WHERE id = ?", [taskId]);
|
|
198
196
|
if (task) {
|
|
199
197
|
taskContext = {
|
|
200
198
|
id: task.id,
|
|
@@ -206,13 +204,12 @@ export function contextExport(options: { task?: string; json?: boolean; specId?:
|
|
|
206
204
|
|
|
207
205
|
// Obter standards para o agente da task
|
|
208
206
|
const domain = domainToScope(getAgentDomain(task.agent));
|
|
209
|
-
standards =
|
|
210
|
-
|
|
211
|
-
`SELECT * FROM standards
|
|
207
|
+
standards = await dbAll<any>(
|
|
208
|
+
`SELECT * FROM standards
|
|
212
209
|
WHERE scope = 'all' OR scope = ?
|
|
213
|
-
ORDER BY enforcement DESC, category
|
|
214
|
-
|
|
215
|
-
|
|
210
|
+
ORDER BY enforcement DESC, category`,
|
|
211
|
+
[domain]
|
|
212
|
+
);
|
|
216
213
|
|
|
217
214
|
standards = standards.map((std) => ({
|
|
218
215
|
category: std.category,
|
|
@@ -223,7 +220,8 @@ export function contextExport(options: { task?: string; json?: boolean; specId?:
|
|
|
223
220
|
}));
|
|
224
221
|
|
|
225
222
|
// Obter knowledge broadcast (automatico)
|
|
226
|
-
|
|
223
|
+
const rawKnowledge = await getKnowledgeForTask(spec.id, taskId);
|
|
224
|
+
knowledge = rawKnowledge.map((k) => ({
|
|
227
225
|
id: k.id,
|
|
228
226
|
category: k.category,
|
|
229
227
|
content: k.content,
|
|
@@ -240,9 +238,9 @@ export function contextExport(options: { task?: string; json?: boolean; specId?:
|
|
|
240
238
|
}
|
|
241
239
|
|
|
242
240
|
// Obter contexto de produto
|
|
243
|
-
const productContext =
|
|
244
|
-
const productGoals =
|
|
245
|
-
const productFeatures =
|
|
241
|
+
const productContext = await dbGet<any>("SELECT * FROM product_context WHERE id = 'default'", ["default"]);
|
|
242
|
+
const productGoals = await dbAll<any>("SELECT * FROM product_goals WHERE product_id = 'default'", ["default"]);
|
|
243
|
+
const productFeatures = await dbAll<any>("SELECT * FROM product_features WHERE product_id = 'default'", ["default"]);
|
|
246
244
|
|
|
247
245
|
const exportData = {
|
|
248
246
|
spec: {
|
|
@@ -291,16 +289,16 @@ export function contextExport(options: { task?: string; json?: boolean; specId?:
|
|
|
291
289
|
console.log(JSON.stringify(exportData, null, 2));
|
|
292
290
|
}
|
|
293
291
|
|
|
294
|
-
export function contextDetail(section: string, json: boolean = false, specId?: string): void {
|
|
295
|
-
initSchema();
|
|
296
|
-
const db = getDb();
|
|
292
|
+
export async function contextDetail(section: string, json: boolean = false, specId?: string): Promise<void> {
|
|
293
|
+
await initSchema();
|
|
297
294
|
|
|
298
|
-
const spec = resolveSpec(specId);
|
|
295
|
+
const spec = await resolveSpec(specId);
|
|
299
296
|
|
|
300
297
|
// Encontrar task running (para contexto relevante)
|
|
301
|
-
const runningTask =
|
|
302
|
-
"SELECT * FROM tasks WHERE spec_id = ? AND status = 'running' LIMIT 1"
|
|
303
|
-
|
|
298
|
+
const runningTask = await dbGet<any>(
|
|
299
|
+
"SELECT * FROM tasks WHERE spec_id = ? AND status = 'running' LIMIT 1",
|
|
300
|
+
[spec.id]
|
|
301
|
+
);
|
|
304
302
|
|
|
305
303
|
const domain = domainToScope(getAgentDomain(runningTask?.agent));
|
|
306
304
|
|
|
@@ -308,9 +306,10 @@ export function contextDetail(section: string, json: boolean = false, specId?: s
|
|
|
308
306
|
|
|
309
307
|
switch (section) {
|
|
310
308
|
case "standards": {
|
|
311
|
-
const standards =
|
|
312
|
-
"SELECT * FROM standards WHERE scope = 'all' OR scope = ? ORDER BY enforcement DESC, category"
|
|
313
|
-
|
|
309
|
+
const standards = await dbAll<any>(
|
|
310
|
+
"SELECT * FROM standards WHERE scope = 'all' OR scope = ? ORDER BY enforcement DESC, category",
|
|
311
|
+
[domain]
|
|
312
|
+
);
|
|
314
313
|
|
|
315
314
|
if (json) { console.log(JSON.stringify({ standards })); return; }
|
|
316
315
|
|
|
@@ -334,9 +333,10 @@ export function contextDetail(section: string, json: boolean = false, specId?: s
|
|
|
334
333
|
}
|
|
335
334
|
|
|
336
335
|
case "decisions": {
|
|
337
|
-
const decisions =
|
|
338
|
-
"SELECT * FROM decisions WHERE spec_id = ? AND status = 'active' ORDER BY created_at DESC"
|
|
339
|
-
|
|
336
|
+
const decisions = await dbAll<any>(
|
|
337
|
+
"SELECT * FROM decisions WHERE spec_id = ? AND status = 'active' ORDER BY created_at DESC",
|
|
338
|
+
[spec.id]
|
|
339
|
+
);
|
|
340
340
|
|
|
341
341
|
if (json) { console.log(JSON.stringify({ decisions })); return; }
|
|
342
342
|
|
|
@@ -351,9 +351,10 @@ export function contextDetail(section: string, json: boolean = false, specId?: s
|
|
|
351
351
|
}
|
|
352
352
|
|
|
353
353
|
case "patterns": {
|
|
354
|
-
const patterns =
|
|
355
|
-
"SELECT * FROM implementation_patterns ORDER BY category, name"
|
|
356
|
-
|
|
354
|
+
const patterns = await dbAll<any>(
|
|
355
|
+
"SELECT * FROM implementation_patterns ORDER BY category, name",
|
|
356
|
+
[]
|
|
357
|
+
);
|
|
357
358
|
|
|
358
359
|
if (json) { console.log(JSON.stringify({ patterns })); return; }
|
|
359
360
|
|
|
@@ -375,9 +376,10 @@ export function contextDetail(section: string, json: boolean = false, specId?: s
|
|
|
375
376
|
}
|
|
376
377
|
|
|
377
378
|
case "knowledge": {
|
|
378
|
-
const knowledge =
|
|
379
|
-
"SELECT k.*, t.number as task_number FROM knowledge k LEFT JOIN tasks t ON k.task_origin = t.id WHERE k.spec_id = ? ORDER BY k.severity DESC, k.created_at DESC LIMIT 50"
|
|
380
|
-
|
|
379
|
+
const knowledge = await dbAll<any>(
|
|
380
|
+
"SELECT k.*, t.number as task_number FROM knowledge k LEFT JOIN tasks t ON k.task_origin = t.id WHERE k.spec_id = ? ORDER BY k.severity DESC, k.created_at DESC LIMIT 50",
|
|
381
|
+
[spec.id]
|
|
382
|
+
);
|
|
381
383
|
|
|
382
384
|
if (json) { console.log(JSON.stringify({ knowledge })); return; }
|
|
383
385
|
|
|
@@ -391,7 +393,7 @@ export function contextDetail(section: string, json: boolean = false, specId?: s
|
|
|
391
393
|
}
|
|
392
394
|
|
|
393
395
|
case "architecture": {
|
|
394
|
-
const analysis = getArchitecturalAnalysisForSpec(spec.name, spec.id);
|
|
396
|
+
const analysis = await getArchitecturalAnalysisForSpec(spec.name, spec.id);
|
|
395
397
|
if (!analysis) {
|
|
396
398
|
output = "Nenhuma analise arquitetural encontrada.";
|
|
397
399
|
break;
|
|
@@ -430,21 +432,20 @@ export function contextDetail(section: string, json: boolean = false, specId?: s
|
|
|
430
432
|
console.log(output || "\nNenhum dado encontrado.\n");
|
|
431
433
|
}
|
|
432
434
|
|
|
433
|
-
export function recover(options: {
|
|
435
|
+
export async function recover(options: {
|
|
434
436
|
list?: boolean;
|
|
435
437
|
snapshot?: string;
|
|
436
438
|
restore?: boolean;
|
|
437
439
|
auto?: boolean;
|
|
438
|
-
}): void {
|
|
439
|
-
initSchema();
|
|
440
|
-
|
|
441
|
-
const db = getDb();
|
|
440
|
+
}): Promise<void> {
|
|
441
|
+
await initSchema();
|
|
442
442
|
|
|
443
443
|
// Listar snapshots
|
|
444
444
|
if (options.list) {
|
|
445
|
-
const snapshots =
|
|
446
|
-
|
|
447
|
-
|
|
445
|
+
const snapshots = await dbAll<any>(
|
|
446
|
+
"SELECT id, spec_id, trigger, created_at FROM snapshots ORDER BY created_at DESC LIMIT 20",
|
|
447
|
+
[]
|
|
448
|
+
);
|
|
448
449
|
|
|
449
450
|
if (snapshots.length === 0) {
|
|
450
451
|
console.log("\nNenhum snapshot disponivel.\n");
|
|
@@ -466,10 +467,10 @@ export function recover(options: {
|
|
|
466
467
|
let snapshot: any;
|
|
467
468
|
|
|
468
469
|
if (options.auto) {
|
|
469
|
-
snapshot =
|
|
470
|
+
snapshot = await dbGet<any>("SELECT * FROM snapshots ORDER BY created_at DESC LIMIT 1", []);
|
|
470
471
|
} else if (options.snapshot) {
|
|
471
472
|
const snapshotId = parseInt(options.snapshot);
|
|
472
|
-
snapshot =
|
|
473
|
+
snapshot = await dbGet<any>("SELECT * FROM snapshots WHERE id = ?", [snapshotId]);
|
|
473
474
|
}
|
|
474
475
|
|
|
475
476
|
if (!snapshot) {
|
|
@@ -483,7 +484,7 @@ export function recover(options: {
|
|
|
483
484
|
|
|
484
485
|
// 1. Restaurar spec
|
|
485
486
|
if (data.spec) {
|
|
486
|
-
|
|
487
|
+
await dbRun(
|
|
487
488
|
`UPDATE specs SET phase = ?, approved_at = ?, updated_at = ? WHERE id = ?`,
|
|
488
489
|
[data.spec.phase, data.spec.approved_at, now, data.spec.id]
|
|
489
490
|
);
|
|
@@ -492,7 +493,7 @@ export function recover(options: {
|
|
|
492
493
|
|
|
493
494
|
// 2. Restaurar context
|
|
494
495
|
if (data.context) {
|
|
495
|
-
|
|
496
|
+
await dbRun(
|
|
496
497
|
`UPDATE context SET
|
|
497
498
|
objective = ?, approach = ?, constraints = ?, patterns = ?,
|
|
498
499
|
current_task = ?, last_checkpoint = ?, updated_at = ?
|
|
@@ -514,7 +515,7 @@ export function recover(options: {
|
|
|
514
515
|
// 3. Restaurar status das tasks
|
|
515
516
|
if (data.tasks && Array.isArray(data.tasks)) {
|
|
516
517
|
for (const task of data.tasks) {
|
|
517
|
-
|
|
518
|
+
await dbRun(
|
|
518
519
|
`UPDATE tasks SET status = ?, checkpoint = ?, completed_at = ? WHERE id = ?`,
|
|
519
520
|
[task.status, task.checkpoint, task.completed_at, task.id]
|
|
520
521
|
);
|
|
@@ -541,7 +542,7 @@ export function recover(options: {
|
|
|
541
542
|
// Mostrar detalhes de snapshot específico
|
|
542
543
|
if (options.snapshot) {
|
|
543
544
|
const snapshotId = parseInt(options.snapshot);
|
|
544
|
-
const snapshot =
|
|
545
|
+
const snapshot = await dbGet<any>("SELECT * FROM snapshots WHERE id = ?", [snapshotId]);
|
|
545
546
|
|
|
546
547
|
if (!snapshot) {
|
|
547
548
|
throw new CodexaError("Snapshot #" + snapshotId + " nao encontrado.");
|
|
@@ -560,9 +561,10 @@ export function recover(options: {
|
|
|
560
561
|
}
|
|
561
562
|
|
|
562
563
|
// Mostrar ultimo snapshot
|
|
563
|
-
const last =
|
|
564
|
-
|
|
565
|
-
|
|
564
|
+
const last = await dbGet<any>(
|
|
565
|
+
"SELECT * FROM snapshots ORDER BY created_at DESC LIMIT 1",
|
|
566
|
+
[]
|
|
567
|
+
);
|
|
566
568
|
|
|
567
569
|
if (!last) {
|
|
568
570
|
console.log("\nNenhum snapshot disponivel.\n");
|