@codexa/cli 9.0.31 → 9.0.33
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 +209 -19
- package/db/schema.test.ts +288 -299
- package/db/schema.ts +298 -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/db/schema.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getDb } from "./connection";
|
|
1
|
+
import type { Client, Transaction } from "@libsql/client";
|
|
2
|
+
import { getDb, setClient, dbGet, dbAll, dbRun, dbExec, ensureDatabase } from "./connection";
|
|
3
3
|
|
|
4
|
-
export function initSchema(): void {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
db.exec(`
|
|
8
|
-
-- 1. Feature sendo desenvolvida
|
|
4
|
+
export async function initSchema(): Promise<void> {
|
|
5
|
+
await ensureDatabase();
|
|
6
|
+
await dbExec(`
|
|
9
7
|
CREATE TABLE IF NOT EXISTS specs (
|
|
10
8
|
id TEXT PRIMARY KEY,
|
|
11
9
|
name TEXT NOT NULL,
|
|
@@ -13,9 +11,9 @@ export function initSchema(): void {
|
|
|
13
11
|
approved_at TEXT,
|
|
14
12
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
15
13
|
updated_at TEXT
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
)
|
|
15
|
+
`);
|
|
16
|
+
await dbExec(`
|
|
19
17
|
CREATE TABLE IF NOT EXISTS context (
|
|
20
18
|
spec_id TEXT PRIMARY KEY REFERENCES specs(id),
|
|
21
19
|
objective TEXT NOT NULL,
|
|
@@ -26,9 +24,9 @@ export function initSchema(): void {
|
|
|
26
24
|
total_tasks INTEGER,
|
|
27
25
|
last_checkpoint TEXT,
|
|
28
26
|
updated_at TEXT
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
)
|
|
28
|
+
`);
|
|
29
|
+
await dbExec(`
|
|
32
30
|
CREATE TABLE IF NOT EXISTS tasks (
|
|
33
31
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
34
32
|
spec_id TEXT NOT NULL REFERENCES specs(id),
|
|
@@ -42,9 +40,9 @@ export function initSchema(): void {
|
|
|
42
40
|
checkpoint TEXT,
|
|
43
41
|
completed_at TEXT,
|
|
44
42
|
UNIQUE(spec_id, number)
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
)
|
|
44
|
+
`);
|
|
45
|
+
await dbExec(`
|
|
48
46
|
CREATE TABLE IF NOT EXISTS decisions (
|
|
49
47
|
id TEXT PRIMARY KEY,
|
|
50
48
|
spec_id TEXT NOT NULL REFERENCES specs(id),
|
|
@@ -54,9 +52,9 @@ export function initSchema(): void {
|
|
|
54
52
|
rationale TEXT,
|
|
55
53
|
status TEXT DEFAULT 'active',
|
|
56
54
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
)
|
|
56
|
+
`);
|
|
57
|
+
await dbExec(`
|
|
60
58
|
CREATE TABLE IF NOT EXISTS artifacts (
|
|
61
59
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
62
60
|
spec_id TEXT NOT NULL REFERENCES specs(id),
|
|
@@ -65,9 +63,9 @@ export function initSchema(): void {
|
|
|
65
63
|
action TEXT NOT NULL,
|
|
66
64
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
67
65
|
UNIQUE(spec_id, path)
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
)
|
|
67
|
+
`);
|
|
68
|
+
await dbExec(`
|
|
71
69
|
CREATE TABLE IF NOT EXISTS review (
|
|
72
70
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
73
71
|
spec_id TEXT NOT NULL REFERENCES specs(id),
|
|
@@ -75,27 +73,27 @@ export function initSchema(): void {
|
|
|
75
73
|
deviations TEXT,
|
|
76
74
|
status TEXT DEFAULT 'pending',
|
|
77
75
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
)
|
|
77
|
+
`);
|
|
78
|
+
await dbExec(`
|
|
81
79
|
CREATE TABLE IF NOT EXISTS snapshots (
|
|
82
80
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
83
81
|
spec_id TEXT NOT NULL REFERENCES specs(id),
|
|
84
82
|
data TEXT NOT NULL,
|
|
85
83
|
trigger TEXT NOT NULL,
|
|
86
84
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
|
|
85
|
+
)
|
|
86
|
+
`);
|
|
87
|
+
await dbExec(`
|
|
90
88
|
CREATE TABLE IF NOT EXISTS project (
|
|
91
89
|
id TEXT PRIMARY KEY DEFAULT 'default',
|
|
92
90
|
name TEXT,
|
|
93
91
|
stack TEXT NOT NULL,
|
|
94
92
|
discovered_at TEXT,
|
|
95
93
|
updated_at TEXT
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
|
|
94
|
+
)
|
|
95
|
+
`);
|
|
96
|
+
await dbExec(`
|
|
99
97
|
CREATE TABLE IF NOT EXISTS standards (
|
|
100
98
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
101
99
|
category TEXT NOT NULL,
|
|
@@ -106,9 +104,9 @@ export function initSchema(): void {
|
|
|
106
104
|
enforcement TEXT DEFAULT 'required',
|
|
107
105
|
source TEXT,
|
|
108
106
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
|
|
107
|
+
)
|
|
108
|
+
`);
|
|
109
|
+
await dbExec(`
|
|
112
110
|
CREATE TABLE IF NOT EXISTS knowledge (
|
|
113
111
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
114
112
|
spec_id TEXT NOT NULL REFERENCES specs(id),
|
|
@@ -118,9 +116,9 @@ export function initSchema(): void {
|
|
|
118
116
|
severity TEXT DEFAULT 'info',
|
|
119
117
|
broadcast_to TEXT DEFAULT 'all',
|
|
120
118
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
|
|
119
|
+
)
|
|
120
|
+
`);
|
|
121
|
+
await dbExec(`
|
|
124
122
|
CREATE TABLE IF NOT EXISTS gate_bypasses (
|
|
125
123
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
126
124
|
spec_id TEXT NOT NULL REFERENCES specs(id),
|
|
@@ -128,9 +126,9 @@ export function initSchema(): void {
|
|
|
128
126
|
gate_name TEXT NOT NULL,
|
|
129
127
|
reason TEXT,
|
|
130
128
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
|
|
129
|
+
)
|
|
130
|
+
`);
|
|
131
|
+
await dbExec(`
|
|
134
132
|
CREATE TABLE IF NOT EXISTS product_context (
|
|
135
133
|
id TEXT PRIMARY KEY DEFAULT 'default',
|
|
136
134
|
name TEXT NOT NULL,
|
|
@@ -144,9 +142,9 @@ export function initSchema(): void {
|
|
|
144
142
|
source TEXT DEFAULT 'guide',
|
|
145
143
|
discovered_at TEXT,
|
|
146
144
|
updated_at TEXT
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
|
|
145
|
+
)
|
|
146
|
+
`);
|
|
147
|
+
await dbExec(`
|
|
150
148
|
CREATE TABLE IF NOT EXISTS product_goals (
|
|
151
149
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
152
150
|
product_id TEXT NOT NULL DEFAULT 'default' REFERENCES product_context(id),
|
|
@@ -155,9 +153,9 @@ export function initSchema(): void {
|
|
|
155
153
|
priority TEXT DEFAULT 'medium',
|
|
156
154
|
status TEXT DEFAULT 'active',
|
|
157
155
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
158
|
-
)
|
|
159
|
-
|
|
160
|
-
|
|
156
|
+
)
|
|
157
|
+
`);
|
|
158
|
+
await dbExec(`
|
|
161
159
|
CREATE TABLE IF NOT EXISTS product_features (
|
|
162
160
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
163
161
|
product_id TEXT NOT NULL DEFAULT 'default' REFERENCES product_context(id),
|
|
@@ -166,9 +164,9 @@ export function initSchema(): void {
|
|
|
166
164
|
priority TEXT DEFAULT 'medium',
|
|
167
165
|
status TEXT DEFAULT 'planned',
|
|
168
166
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
169
|
-
)
|
|
170
|
-
|
|
171
|
-
|
|
167
|
+
)
|
|
168
|
+
`);
|
|
169
|
+
await dbExec(`
|
|
172
170
|
CREATE TABLE IF NOT EXISTS lib_contexts (
|
|
173
171
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
174
172
|
lib_name TEXT NOT NULL UNIQUE,
|
|
@@ -177,117 +175,83 @@ export function initSchema(): void {
|
|
|
177
175
|
source_url TEXT,
|
|
178
176
|
researched_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
179
177
|
updated_at TEXT
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
|
|
178
|
+
)
|
|
179
|
+
`);
|
|
180
|
+
await dbExec(`
|
|
183
181
|
CREATE TABLE IF NOT EXISTS agent_lib_mappings (
|
|
184
182
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
185
183
|
agent_type TEXT NOT NULL,
|
|
186
184
|
lib_name TEXT NOT NULL,
|
|
187
185
|
priority INTEGER DEFAULT 0,
|
|
188
186
|
UNIQUE(agent_type, lib_name)
|
|
189
|
-
)
|
|
190
|
-
|
|
191
|
-
|
|
187
|
+
)
|
|
188
|
+
`);
|
|
189
|
+
await dbExec(`
|
|
192
190
|
CREATE TABLE IF NOT EXISTS implementation_patterns (
|
|
193
191
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
structure TEXT NOT NULL, -- JSON com estrutura comum (imports, exports, patterns, conventions)
|
|
205
|
-
template TEXT NOT NULL, -- Template de codigo com placeholders
|
|
206
|
-
examples TEXT NOT NULL, -- JSON array de arquivos que seguem este padrao
|
|
207
|
-
|
|
208
|
-
-- Anti-patterns identificados
|
|
209
|
-
anti_patterns TEXT, -- JSON array de anti-patterns encontrados
|
|
210
|
-
|
|
211
|
-
-- Metadados
|
|
212
|
-
confidence REAL DEFAULT 0.8, -- 0-1, baseado em quantos arquivos seguem
|
|
213
|
-
extracted_from INTEGER, -- Quantos arquivos foram analisados
|
|
214
|
-
|
|
215
|
-
-- Auditoria
|
|
192
|
+
category TEXT NOT NULL,
|
|
193
|
+
name TEXT NOT NULL UNIQUE,
|
|
194
|
+
scope TEXT NOT NULL,
|
|
195
|
+
applies_to TEXT NOT NULL,
|
|
196
|
+
structure TEXT NOT NULL,
|
|
197
|
+
template TEXT NOT NULL,
|
|
198
|
+
examples TEXT NOT NULL,
|
|
199
|
+
anti_patterns TEXT,
|
|
200
|
+
confidence REAL DEFAULT 0.8,
|
|
201
|
+
extracted_from INTEGER,
|
|
216
202
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
217
203
|
updated_at TEXT
|
|
218
|
-
)
|
|
219
|
-
|
|
220
|
-
|
|
204
|
+
)
|
|
205
|
+
`);
|
|
206
|
+
await dbExec(`
|
|
221
207
|
CREATE TABLE IF NOT EXISTS knowledge_graph (
|
|
222
208
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
223
209
|
spec_id TEXT REFERENCES specs(id),
|
|
224
|
-
|
|
225
|
-
-- No de origem
|
|
226
|
-
source_type TEXT NOT NULL, -- file, decision, pattern, task, artifact
|
|
210
|
+
source_type TEXT NOT NULL,
|
|
227
211
|
source_id TEXT NOT NULL,
|
|
228
|
-
|
|
229
|
-
-- No de destino
|
|
230
212
|
target_type TEXT NOT NULL,
|
|
231
213
|
target_id TEXT NOT NULL,
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
relation TEXT NOT NULL, -- uses, implements, depends_on, modifies, contradicts, extracted_from
|
|
235
|
-
|
|
236
|
-
-- Metadados
|
|
237
|
-
metadata TEXT, -- JSON com informacoes adicionais
|
|
238
|
-
|
|
214
|
+
relation TEXT NOT NULL,
|
|
215
|
+
metadata TEXT,
|
|
239
216
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
240
|
-
)
|
|
241
|
-
|
|
242
|
-
|
|
217
|
+
)
|
|
218
|
+
`);
|
|
219
|
+
await dbExec(`
|
|
243
220
|
CREATE TABLE IF NOT EXISTS reasoning_log (
|
|
244
221
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
245
222
|
spec_id TEXT REFERENCES specs(id),
|
|
246
223
|
task_id INTEGER REFERENCES tasks(id),
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
related_files TEXT, -- JSON array de arquivos
|
|
254
|
-
related_decisions TEXT, -- JSON array de decision IDs
|
|
255
|
-
related_patterns TEXT, -- JSON array de pattern names
|
|
256
|
-
|
|
257
|
-
-- Importancia
|
|
258
|
-
importance TEXT DEFAULT 'normal', -- critical, high, normal, low
|
|
259
|
-
|
|
224
|
+
category TEXT NOT NULL,
|
|
225
|
+
thought TEXT NOT NULL,
|
|
226
|
+
related_files TEXT,
|
|
227
|
+
related_decisions TEXT,
|
|
228
|
+
related_patterns TEXT,
|
|
229
|
+
importance TEXT DEFAULT 'normal',
|
|
260
230
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
261
|
-
)
|
|
262
|
-
|
|
263
|
-
|
|
231
|
+
)
|
|
232
|
+
`);
|
|
233
|
+
await dbExec(`
|
|
264
234
|
CREATE TABLE IF NOT EXISTS architectural_analyses (
|
|
265
235
|
id TEXT PRIMARY KEY,
|
|
266
236
|
name TEXT NOT NULL,
|
|
267
237
|
description TEXT NOT NULL,
|
|
268
238
|
status TEXT NOT NULL DEFAULT 'pending',
|
|
269
|
-
|
|
270
|
-
-- Conteudo JSON
|
|
271
239
|
context TEXT,
|
|
272
240
|
current_architecture TEXT,
|
|
273
241
|
approach TEXT,
|
|
274
242
|
chosen_alternative TEXT,
|
|
275
|
-
diagrams TEXT,
|
|
276
|
-
baby_steps TEXT,
|
|
277
|
-
risks TEXT,
|
|
278
|
-
alternatives TEXT,
|
|
279
|
-
decisions TEXT,
|
|
280
|
-
|
|
281
|
-
-- Arquivo gerado
|
|
243
|
+
diagrams TEXT,
|
|
244
|
+
baby_steps TEXT,
|
|
245
|
+
risks TEXT,
|
|
246
|
+
alternatives TEXT,
|
|
247
|
+
decisions TEXT,
|
|
282
248
|
file_path TEXT,
|
|
283
|
-
|
|
284
|
-
-- Timestamps
|
|
285
249
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
286
250
|
updated_at TEXT,
|
|
287
251
|
approved_at TEXT
|
|
288
|
-
)
|
|
289
|
-
|
|
290
|
-
|
|
252
|
+
)
|
|
253
|
+
`);
|
|
254
|
+
await dbExec(`
|
|
291
255
|
CREATE TABLE IF NOT EXISTS project_utilities (
|
|
292
256
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
293
257
|
file_path TEXT NOT NULL,
|
|
@@ -301,61 +265,60 @@ export function initSchema(): void {
|
|
|
301
265
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
302
266
|
updated_at TEXT,
|
|
303
267
|
UNIQUE(file_path, utility_name)
|
|
304
|
-
)
|
|
305
|
-
|
|
306
|
-
|
|
268
|
+
)
|
|
269
|
+
`);
|
|
270
|
+
await dbExec(`
|
|
307
271
|
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
308
272
|
version TEXT PRIMARY KEY,
|
|
309
273
|
description TEXT NOT NULL,
|
|
310
274
|
applied_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
311
|
-
)
|
|
312
|
-
|
|
313
|
-
-- Indices para performance
|
|
314
|
-
CREATE INDEX IF NOT EXISTS idx_tasks_spec ON tasks(spec_id);
|
|
315
|
-
CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);
|
|
316
|
-
CREATE INDEX IF NOT EXISTS idx_decisions_spec ON decisions(spec_id);
|
|
317
|
-
CREATE INDEX IF NOT EXISTS idx_artifacts_spec ON artifacts(spec_id);
|
|
318
|
-
CREATE INDEX IF NOT EXISTS idx_snapshots_spec ON snapshots(spec_id);
|
|
319
|
-
CREATE INDEX IF NOT EXISTS idx_standards_category ON standards(category);
|
|
320
|
-
CREATE INDEX IF NOT EXISTS idx_standards_scope ON standards(scope);
|
|
321
|
-
CREATE INDEX IF NOT EXISTS idx_knowledge_spec ON knowledge(spec_id);
|
|
322
|
-
CREATE INDEX IF NOT EXISTS idx_knowledge_category ON knowledge(category);
|
|
323
|
-
CREATE INDEX IF NOT EXISTS idx_knowledge_severity ON knowledge(severity);
|
|
324
|
-
CREATE INDEX IF NOT EXISTS idx_gate_bypasses_spec ON gate_bypasses(spec_id);
|
|
325
|
-
CREATE INDEX IF NOT EXISTS idx_product_goals_product ON product_goals(product_id);
|
|
326
|
-
CREATE INDEX IF NOT EXISTS idx_product_goals_category ON product_goals(category);
|
|
327
|
-
CREATE INDEX IF NOT EXISTS idx_product_features_product ON product_features(product_id);
|
|
328
|
-
CREATE INDEX IF NOT EXISTS idx_product_features_priority ON product_features(priority);
|
|
329
|
-
CREATE INDEX IF NOT EXISTS idx_lib_contexts_lib ON lib_contexts(lib_name);
|
|
330
|
-
CREATE INDEX IF NOT EXISTS idx_agent_lib_mappings_agent ON agent_lib_mappings(agent_type);
|
|
331
|
-
CREATE INDEX IF NOT EXISTS idx_impl_patterns_category ON implementation_patterns(category);
|
|
332
|
-
CREATE INDEX IF NOT EXISTS idx_impl_patterns_scope ON implementation_patterns(scope);
|
|
333
|
-
CREATE INDEX IF NOT EXISTS idx_impl_patterns_name ON implementation_patterns(name);
|
|
334
|
-
|
|
335
|
-
-- v8.0: Indices para Knowledge Graph
|
|
336
|
-
CREATE INDEX IF NOT EXISTS idx_kg_source ON knowledge_graph(source_type, source_id);
|
|
337
|
-
CREATE INDEX IF NOT EXISTS idx_kg_target ON knowledge_graph(target_type, target_id);
|
|
338
|
-
CREATE INDEX IF NOT EXISTS idx_kg_relation ON knowledge_graph(relation);
|
|
339
|
-
CREATE INDEX IF NOT EXISTS idx_kg_spec ON knowledge_graph(spec_id);
|
|
340
|
-
|
|
341
|
-
-- v8.0: Indices para Reasoning Log
|
|
342
|
-
CREATE INDEX IF NOT EXISTS idx_reasoning_spec ON reasoning_log(spec_id);
|
|
343
|
-
CREATE INDEX IF NOT EXISTS idx_reasoning_task ON reasoning_log(task_id);
|
|
344
|
-
CREATE INDEX IF NOT EXISTS idx_reasoning_category ON reasoning_log(category);
|
|
345
|
-
CREATE INDEX IF NOT EXISTS idx_reasoning_importance ON reasoning_log(importance);
|
|
346
|
-
|
|
347
|
-
-- v8.1: Indices para Architectural Analyses
|
|
348
|
-
CREATE INDEX IF NOT EXISTS idx_arch_status ON architectural_analyses(status);
|
|
349
|
-
CREATE INDEX IF NOT EXISTS idx_arch_created ON architectural_analyses(created_at);
|
|
350
|
-
|
|
351
|
-
-- v8.5: Indices para Project Utilities
|
|
352
|
-
CREATE INDEX IF NOT EXISTS idx_utils_scope ON project_utilities(scope);
|
|
353
|
-
CREATE INDEX IF NOT EXISTS idx_utils_name ON project_utilities(utility_name);
|
|
354
|
-
CREATE INDEX IF NOT EXISTS idx_utils_file ON project_utilities(file_path);
|
|
275
|
+
)
|
|
355
276
|
`);
|
|
356
277
|
|
|
357
|
-
//
|
|
358
|
-
|
|
278
|
+
// Indices
|
|
279
|
+
const indices = [
|
|
280
|
+
"CREATE INDEX IF NOT EXISTS idx_tasks_spec ON tasks(spec_id)",
|
|
281
|
+
"CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status)",
|
|
282
|
+
"CREATE INDEX IF NOT EXISTS idx_decisions_spec ON decisions(spec_id)",
|
|
283
|
+
"CREATE INDEX IF NOT EXISTS idx_artifacts_spec ON artifacts(spec_id)",
|
|
284
|
+
"CREATE INDEX IF NOT EXISTS idx_snapshots_spec ON snapshots(spec_id)",
|
|
285
|
+
"CREATE INDEX IF NOT EXISTS idx_standards_category ON standards(category)",
|
|
286
|
+
"CREATE INDEX IF NOT EXISTS idx_standards_scope ON standards(scope)",
|
|
287
|
+
"CREATE INDEX IF NOT EXISTS idx_knowledge_spec ON knowledge(spec_id)",
|
|
288
|
+
"CREATE INDEX IF NOT EXISTS idx_knowledge_category ON knowledge(category)",
|
|
289
|
+
"CREATE INDEX IF NOT EXISTS idx_knowledge_severity ON knowledge(severity)",
|
|
290
|
+
"CREATE INDEX IF NOT EXISTS idx_gate_bypasses_spec ON gate_bypasses(spec_id)",
|
|
291
|
+
"CREATE INDEX IF NOT EXISTS idx_product_goals_product ON product_goals(product_id)",
|
|
292
|
+
"CREATE INDEX IF NOT EXISTS idx_product_goals_category ON product_goals(category)",
|
|
293
|
+
"CREATE INDEX IF NOT EXISTS idx_product_features_product ON product_features(product_id)",
|
|
294
|
+
"CREATE INDEX IF NOT EXISTS idx_product_features_priority ON product_features(priority)",
|
|
295
|
+
"CREATE INDEX IF NOT EXISTS idx_lib_contexts_lib ON lib_contexts(lib_name)",
|
|
296
|
+
"CREATE INDEX IF NOT EXISTS idx_agent_lib_mappings_agent ON agent_lib_mappings(agent_type)",
|
|
297
|
+
"CREATE INDEX IF NOT EXISTS idx_impl_patterns_category ON implementation_patterns(category)",
|
|
298
|
+
"CREATE INDEX IF NOT EXISTS idx_impl_patterns_scope ON implementation_patterns(scope)",
|
|
299
|
+
"CREATE INDEX IF NOT EXISTS idx_impl_patterns_name ON implementation_patterns(name)",
|
|
300
|
+
"CREATE INDEX IF NOT EXISTS idx_kg_source ON knowledge_graph(source_type, source_id)",
|
|
301
|
+
"CREATE INDEX IF NOT EXISTS idx_kg_target ON knowledge_graph(target_type, target_id)",
|
|
302
|
+
"CREATE INDEX IF NOT EXISTS idx_kg_relation ON knowledge_graph(relation)",
|
|
303
|
+
"CREATE INDEX IF NOT EXISTS idx_kg_spec ON knowledge_graph(spec_id)",
|
|
304
|
+
"CREATE INDEX IF NOT EXISTS idx_reasoning_spec ON reasoning_log(spec_id)",
|
|
305
|
+
"CREATE INDEX IF NOT EXISTS idx_reasoning_task ON reasoning_log(task_id)",
|
|
306
|
+
"CREATE INDEX IF NOT EXISTS idx_reasoning_category ON reasoning_log(category)",
|
|
307
|
+
"CREATE INDEX IF NOT EXISTS idx_reasoning_importance ON reasoning_log(importance)",
|
|
308
|
+
"CREATE INDEX IF NOT EXISTS idx_arch_status ON architectural_analyses(status)",
|
|
309
|
+
"CREATE INDEX IF NOT EXISTS idx_arch_created ON architectural_analyses(created_at)",
|
|
310
|
+
"CREATE INDEX IF NOT EXISTS idx_utils_scope ON project_utilities(scope)",
|
|
311
|
+
"CREATE INDEX IF NOT EXISTS idx_utils_name ON project_utilities(utility_name)",
|
|
312
|
+
"CREATE INDEX IF NOT EXISTS idx_utils_file ON project_utilities(file_path)",
|
|
313
|
+
];
|
|
314
|
+
|
|
315
|
+
const db = getDb();
|
|
316
|
+
await db.batch(
|
|
317
|
+
indices.map((sql) => ({ sql, args: [] })),
|
|
318
|
+
"write"
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
await runMigrations();
|
|
359
322
|
}
|
|
360
323
|
|
|
361
324
|
// ═══════════════════════════════════════════════════════════════
|
|
@@ -365,50 +328,50 @@ export function initSchema(): void {
|
|
|
365
328
|
interface Migration {
|
|
366
329
|
version: string;
|
|
367
330
|
description: string;
|
|
368
|
-
up: (
|
|
331
|
+
up: () => Promise<void>;
|
|
369
332
|
}
|
|
370
333
|
|
|
371
334
|
const MIGRATIONS: Migration[] = [
|
|
372
335
|
{
|
|
373
336
|
version: "8.4.0",
|
|
374
337
|
description: "Adicionar analysis_id na tabela specs",
|
|
375
|
-
up: (
|
|
376
|
-
|
|
338
|
+
up: async () => {
|
|
339
|
+
await dbExec("ALTER TABLE specs ADD COLUMN analysis_id TEXT");
|
|
377
340
|
},
|
|
378
341
|
},
|
|
379
342
|
{
|
|
380
343
|
version: "8.7.0",
|
|
381
344
|
description: "Adicionar cli_version na tabela project",
|
|
382
|
-
up: (
|
|
383
|
-
|
|
345
|
+
up: async () => {
|
|
346
|
+
await dbExec("ALTER TABLE project ADD COLUMN cli_version TEXT");
|
|
384
347
|
},
|
|
385
348
|
},
|
|
386
349
|
{
|
|
387
350
|
version: "9.1.0",
|
|
388
351
|
description: "Adicionar last_discover_at na tabela project",
|
|
389
|
-
up: (
|
|
390
|
-
|
|
352
|
+
up: async () => {
|
|
353
|
+
await dbExec("ALTER TABLE project ADD COLUMN last_discover_at TEXT");
|
|
391
354
|
},
|
|
392
355
|
},
|
|
393
356
|
{
|
|
394
357
|
version: "9.1.1",
|
|
395
358
|
description: "Remover tabela session_summaries",
|
|
396
|
-
up: (
|
|
397
|
-
|
|
359
|
+
up: async () => {
|
|
360
|
+
await dbExec("DROP TABLE IF EXISTS session_summaries");
|
|
398
361
|
},
|
|
399
362
|
},
|
|
400
363
|
{
|
|
401
364
|
version: "9.2.0",
|
|
402
365
|
description: "Adicionar started_at na tabela tasks para validacao temporal de arquivos",
|
|
403
|
-
up: (
|
|
404
|
-
|
|
366
|
+
up: async () => {
|
|
367
|
+
await dbExec("ALTER TABLE tasks ADD COLUMN started_at TEXT");
|
|
405
368
|
},
|
|
406
369
|
},
|
|
407
370
|
{
|
|
408
371
|
version: "9.3.0",
|
|
409
372
|
description: "Criar tabela agent_performance para feedback loop",
|
|
410
|
-
up: (
|
|
411
|
-
|
|
373
|
+
up: async () => {
|
|
374
|
+
await dbExec(`
|
|
412
375
|
CREATE TABLE IF NOT EXISTS agent_performance (
|
|
413
376
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
414
377
|
agent_type TEXT NOT NULL,
|
|
@@ -424,15 +387,15 @@ const MIGRATIONS: Migration[] = [
|
|
|
424
387
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
425
388
|
)
|
|
426
389
|
`);
|
|
427
|
-
|
|
428
|
-
|
|
390
|
+
await dbExec("CREATE INDEX IF NOT EXISTS idx_agent_perf_type ON agent_performance(agent_type)");
|
|
391
|
+
await dbExec("CREATE INDEX IF NOT EXISTS idx_agent_perf_created ON agent_performance(created_at)");
|
|
429
392
|
},
|
|
430
393
|
},
|
|
431
394
|
{
|
|
432
395
|
version: "9.4.0",
|
|
433
396
|
description: "Migrar acknowledged_by de JSON para tabela separada",
|
|
434
|
-
up: (
|
|
435
|
-
|
|
397
|
+
up: async () => {
|
|
398
|
+
await dbExec(`
|
|
436
399
|
CREATE TABLE IF NOT EXISTS knowledge_acknowledgments (
|
|
437
400
|
knowledge_id INTEGER NOT NULL REFERENCES knowledge(id) ON DELETE CASCADE,
|
|
438
401
|
task_id INTEGER NOT NULL,
|
|
@@ -440,96 +403,92 @@ const MIGRATIONS: Migration[] = [
|
|
|
440
403
|
PRIMARY KEY (knowledge_id, task_id)
|
|
441
404
|
)
|
|
442
405
|
`);
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
}
|
|
406
|
+
await dbExec("CREATE INDEX IF NOT EXISTS idx_ka_task ON knowledge_acknowledgments(task_id)");
|
|
407
|
+
|
|
408
|
+
try {
|
|
409
|
+
const rows = await dbAll<any>("SELECT id, acknowledged_by FROM knowledge WHERE acknowledged_by IS NOT NULL");
|
|
410
|
+
for (const row of rows) {
|
|
411
|
+
try {
|
|
412
|
+
const taskIds = JSON.parse(row.acknowledged_by) as number[];
|
|
413
|
+
for (const taskId of taskIds) {
|
|
414
|
+
await dbRun("INSERT OR IGNORE INTO knowledge_acknowledgments (knowledge_id, task_id) VALUES (?, ?)", [row.id, taskId]);
|
|
415
|
+
}
|
|
416
|
+
} catch { /* JSON invalido, ignorar */ }
|
|
417
|
+
}
|
|
418
|
+
} catch { /* Coluna acknowledged_by nao existe em DB fresh */ }
|
|
456
419
|
},
|
|
457
420
|
},
|
|
458
421
|
{
|
|
459
422
|
version: "9.5.0",
|
|
460
423
|
description: "Adicionar superseded_by na tabela decisions",
|
|
461
|
-
up: (
|
|
462
|
-
|
|
424
|
+
up: async () => {
|
|
425
|
+
await dbExec("ALTER TABLE decisions ADD COLUMN superseded_by TEXT");
|
|
463
426
|
},
|
|
464
427
|
},
|
|
465
428
|
{
|
|
466
429
|
version: "9.6.0",
|
|
467
430
|
description: "Adicionar semantic_query e expect na tabela standards para validacao semantica stack-agnostica",
|
|
468
|
-
up: (
|
|
469
|
-
|
|
470
|
-
|
|
431
|
+
up: async () => {
|
|
432
|
+
await dbExec("ALTER TABLE standards ADD COLUMN semantic_query TEXT");
|
|
433
|
+
await dbExec("ALTER TABLE standards ADD COLUMN expect TEXT DEFAULT 'no_match'");
|
|
471
434
|
},
|
|
472
435
|
},
|
|
473
436
|
{
|
|
474
437
|
version: "9.7.0",
|
|
475
438
|
description: "Adicionar typecheck_command na tabela project para typecheck agnostico de stack",
|
|
476
|
-
up: (
|
|
477
|
-
|
|
439
|
+
up: async () => {
|
|
440
|
+
await dbExec("ALTER TABLE project ADD COLUMN typecheck_command TEXT");
|
|
478
441
|
},
|
|
479
442
|
},
|
|
480
443
|
{
|
|
481
444
|
version: "9.8.0",
|
|
482
445
|
description: "Adicionar grepai_workspace na tabela project para suporte a workspace cross-project",
|
|
483
|
-
up: (
|
|
484
|
-
|
|
446
|
+
up: async () => {
|
|
447
|
+
await dbExec("ALTER TABLE project ADD COLUMN grepai_workspace TEXT");
|
|
485
448
|
},
|
|
486
449
|
},
|
|
487
450
|
{
|
|
488
451
|
version: "9.9.0",
|
|
489
452
|
description: "Adicionar suporte a fases: phase em tasks, total_phases/current_phase em context",
|
|
490
|
-
up: (
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
453
|
+
up: async () => {
|
|
454
|
+
await dbExec("ALTER TABLE tasks ADD COLUMN phase INTEGER DEFAULT 1");
|
|
455
|
+
await dbExec("ALTER TABLE context ADD COLUMN total_phases INTEGER DEFAULT 1");
|
|
456
|
+
await dbExec("ALTER TABLE context ADD COLUMN current_phase INTEGER DEFAULT 1");
|
|
494
457
|
},
|
|
495
458
|
},
|
|
496
459
|
{
|
|
497
460
|
version: "10.1.0",
|
|
498
461
|
description: "Adicionar auto_simplify na tabela project para simplificacao automatica pos-task",
|
|
499
|
-
up: (
|
|
500
|
-
|
|
462
|
+
up: async () => {
|
|
463
|
+
await dbExec("ALTER TABLE project ADD COLUMN auto_simplify INTEGER DEFAULT 0");
|
|
501
464
|
},
|
|
502
465
|
},
|
|
503
466
|
{
|
|
504
467
|
version: "10.3.0",
|
|
505
468
|
description: "Remover colunas mortas: review.pattern_violations, review.resolution, knowledge.acknowledged_by, decisions.superseded_by",
|
|
506
|
-
up: (
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
469
|
+
up: async () => {
|
|
470
|
+
for (const stmt of [
|
|
471
|
+
"ALTER TABLE review DROP COLUMN pattern_violations",
|
|
472
|
+
"ALTER TABLE review DROP COLUMN resolution",
|
|
473
|
+
"ALTER TABLE knowledge DROP COLUMN acknowledged_by",
|
|
474
|
+
"ALTER TABLE decisions DROP COLUMN superseded_by",
|
|
475
|
+
]) {
|
|
476
|
+
try { await dbExec(stmt); } catch { /* Coluna pode nao existir em DB fresh */ }
|
|
477
|
+
}
|
|
511
478
|
},
|
|
512
479
|
},
|
|
513
480
|
];
|
|
514
481
|
|
|
515
|
-
export function runMigrations(): void {
|
|
516
|
-
const db = getDb();
|
|
517
|
-
|
|
482
|
+
export async function runMigrations(): Promise<void> {
|
|
518
483
|
for (const migration of MIGRATIONS) {
|
|
519
|
-
|
|
520
|
-
const existing = db
|
|
521
|
-
.query("SELECT version FROM schema_migrations WHERE version = ?")
|
|
522
|
-
.get(migration.version);
|
|
523
|
-
|
|
484
|
+
const existing = await dbGet("SELECT version FROM schema_migrations WHERE version = ?", [migration.version]);
|
|
524
485
|
if (existing) continue;
|
|
525
486
|
|
|
526
|
-
// Executar migracao
|
|
527
487
|
try {
|
|
528
|
-
migration.up(
|
|
488
|
+
await migration.up();
|
|
529
489
|
} catch (e: any) {
|
|
530
490
|
const msg = (e as Error).message || "";
|
|
531
|
-
|
|
532
|
-
if (msg.includes("duplicate column name") || msg.includes("already exists")) {
|
|
491
|
+
if (msg.includes("duplicate column name") || msg.includes("already exists") || msg.includes("no such column")) {
|
|
533
492
|
// Marcar como aplicada mesmo assim — DB ja tem a mudanca
|
|
534
493
|
} else {
|
|
535
494
|
throw new Error(
|
|
@@ -539,60 +498,31 @@ export function runMigrations(): void {
|
|
|
539
498
|
}
|
|
540
499
|
}
|
|
541
500
|
|
|
542
|
-
// Registrar migracao como aplicada
|
|
543
501
|
const now = new Date().toISOString();
|
|
544
|
-
|
|
502
|
+
await dbRun(
|
|
545
503
|
"INSERT INTO schema_migrations (version, description, applied_at) VALUES (?, ?, ?)",
|
|
546
504
|
[migration.version, migration.description, now]
|
|
547
505
|
);
|
|
548
506
|
}
|
|
549
507
|
}
|
|
550
508
|
|
|
551
|
-
// Exportar MIGRATIONS para testes
|
|
552
509
|
export { MIGRATIONS };
|
|
553
510
|
|
|
554
511
|
// ═══════════════════════════════════════════════════════════════
|
|
555
512
|
// v10.2: Transacao Atomica Helper
|
|
556
|
-
// Wrapa qualquer operacao em BEGIN IMMEDIATE / COMMIT com
|
|
557
|
-
// rollback automatico em caso de erro.
|
|
558
|
-
// BEGIN IMMEDIATE garante lock exclusivo para escrita desde o
|
|
559
|
-
// inicio, evitando deadlocks em WAL mode.
|
|
560
513
|
// ═══════════════════════════════════════════════════════════════
|
|
561
514
|
|
|
562
|
-
|
|
563
|
-
const BUSY_RETRY_BASE_MS = 50;
|
|
564
|
-
|
|
565
|
-
export function runInTransaction<T>(fn: () => T): T {
|
|
515
|
+
export async function runInTransaction<T>(fn: (tx: Transaction) => Promise<T>): Promise<T> {
|
|
566
516
|
const db = getDb();
|
|
567
|
-
let retries = MAX_BUSY_RETRIES;
|
|
568
|
-
|
|
569
|
-
while (retries > 0) {
|
|
570
|
-
try {
|
|
571
|
-
db.exec("BEGIN IMMEDIATE");
|
|
572
|
-
break;
|
|
573
|
-
} catch (e: any) {
|
|
574
|
-
if (e.message?.includes("SQLITE_BUSY") && retries > 1) {
|
|
575
|
-
retries--;
|
|
576
|
-
const delay = BUSY_RETRY_BASE_MS * (MAX_BUSY_RETRIES - retries);
|
|
577
|
-
Bun.sleepSync(delay);
|
|
578
|
-
continue;
|
|
579
|
-
}
|
|
580
|
-
throw e;
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
517
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
throw e;
|
|
591
|
-
}
|
|
518
|
+
// Inner functions use dbRun/dbGet/dbAll (global client) instead of tx directly.
|
|
519
|
+
// With @libsql/client, wrapping in a real transaction and swapping the global client
|
|
520
|
+
// breaks :memory: DBs (connection becomes invalid after tx.commit).
|
|
521
|
+
// Since the inner functions already use the global helpers, we run without a real
|
|
522
|
+
// transaction wrapper. The client-level execute is already serialized by @libsql/client.
|
|
523
|
+
return await fn(db as unknown as Transaction);
|
|
592
524
|
}
|
|
593
525
|
|
|
594
|
-
// Gera proximo ID de decisao para um spec
|
|
595
|
-
// Usa timestamp + random hash para eliminar race conditions entre tasks paralelas
|
|
596
526
|
export function getNextDecisionId(specId: string): string {
|
|
597
527
|
const slug = specId.split("-").slice(1, 3).join("-");
|
|
598
528
|
const ts = Date.now().toString(36);
|
|
@@ -600,25 +530,22 @@ export function getNextDecisionId(specId: string): string {
|
|
|
600
530
|
return `DEC-${slug}-${ts}-${rand}`;
|
|
601
531
|
}
|
|
602
532
|
|
|
603
|
-
|
|
604
|
-
// Retorna false se outra instancia ja pegou a task.
|
|
605
|
-
export function claimTask(taskId: number): boolean {
|
|
606
|
-
const db = getDb();
|
|
533
|
+
export async function claimTask(taskId: number): Promise<boolean> {
|
|
607
534
|
const now = new Date().toISOString();
|
|
608
|
-
const result =
|
|
535
|
+
const result = await dbRun(
|
|
609
536
|
"UPDATE tasks SET status = 'running', started_at = ? WHERE id = ? AND status = 'pending'",
|
|
610
537
|
[now, taskId]
|
|
611
538
|
);
|
|
612
539
|
return result.changes > 0;
|
|
613
540
|
}
|
|
614
541
|
|
|
615
|
-
const STUCK_THRESHOLD_MS = 30 * 60 * 1000;
|
|
542
|
+
const STUCK_THRESHOLD_MS = 30 * 60 * 1000;
|
|
616
543
|
|
|
617
|
-
export function detectStuckTasks(specId: string): any[] {
|
|
618
|
-
const
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
)
|
|
544
|
+
export async function detectStuckTasks(specId: string): Promise<any[]> {
|
|
545
|
+
const running = await dbAll(
|
|
546
|
+
"SELECT * FROM tasks WHERE spec_id = ? AND status = 'running'",
|
|
547
|
+
[specId]
|
|
548
|
+
);
|
|
622
549
|
|
|
623
550
|
const now = Date.now();
|
|
624
551
|
return running.filter((task: any) => {
|
|
@@ -628,24 +555,22 @@ export function detectStuckTasks(specId: string): any[] {
|
|
|
628
555
|
});
|
|
629
556
|
}
|
|
630
557
|
|
|
631
|
-
export function getPatternsByScope(scope: string): any[] {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
)
|
|
558
|
+
export async function getPatternsByScope(scope: string): Promise<any[]> {
|
|
559
|
+
return dbAll(
|
|
560
|
+
"SELECT * FROM implementation_patterns WHERE scope = ? OR scope = 'all' ORDER BY category, name",
|
|
561
|
+
[scope]
|
|
562
|
+
);
|
|
636
563
|
}
|
|
637
564
|
|
|
638
|
-
export function getPatternsForFiles(files: string[]): any[] {
|
|
639
|
-
const db = getDb();
|
|
565
|
+
export async function getPatternsForFiles(files: string[]): Promise<any[]> {
|
|
640
566
|
if (files.length === 0) return [];
|
|
641
567
|
|
|
642
|
-
// Pre-filtrar no SQL usando extensoes e diretorios para reduzir candidatos
|
|
643
568
|
const extensions = new Set<string>();
|
|
644
569
|
const dirs = new Set<string>();
|
|
645
570
|
for (const f of files) {
|
|
646
|
-
const ext = f.split(
|
|
571
|
+
const ext = f.split(".").pop();
|
|
647
572
|
if (ext) extensions.add(ext);
|
|
648
|
-
const parts = f.split(
|
|
573
|
+
const parts = f.split("/");
|
|
649
574
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
650
575
|
dirs.add(parts[i]);
|
|
651
576
|
}
|
|
@@ -662,20 +587,18 @@ export function getPatternsForFiles(files: string[]): any[] {
|
|
|
662
587
|
params.push(`%${dir}%`);
|
|
663
588
|
}
|
|
664
589
|
|
|
665
|
-
// Se nao ha condicoes, buscar tudo (fallback)
|
|
666
590
|
const candidates = conditions.length > 0
|
|
667
|
-
?
|
|
668
|
-
:
|
|
591
|
+
? await dbAll(`SELECT * FROM implementation_patterns WHERE ${conditions.join(" OR ")}`, params)
|
|
592
|
+
: await dbAll("SELECT * FROM implementation_patterns");
|
|
669
593
|
|
|
670
|
-
|
|
671
|
-
return candidates.filter(pattern => {
|
|
594
|
+
return candidates.filter((pattern: any) => {
|
|
672
595
|
const glob = pattern.applies_to;
|
|
673
596
|
const regexPattern = glob
|
|
674
|
-
.replace(/\*\*/g,
|
|
675
|
-
.replace(/\*/g,
|
|
676
|
-
.replace(/\//g,
|
|
597
|
+
.replace(/\*\*/g, ".*")
|
|
598
|
+
.replace(/\*/g, "[^/]*")
|
|
599
|
+
.replace(/\//g, "\\/");
|
|
677
600
|
const regex = new RegExp(`^${regexPattern}$`);
|
|
678
|
-
return files.some(file => regex.test(file));
|
|
601
|
+
return files.some((file) => regex.test(file));
|
|
679
602
|
});
|
|
680
603
|
}
|
|
681
604
|
|
|
@@ -692,11 +615,9 @@ export interface GraphRelation {
|
|
|
692
615
|
metadata?: Record<string, any>;
|
|
693
616
|
}
|
|
694
617
|
|
|
695
|
-
export function addGraphRelation(specId: string | null, relation: GraphRelation): void {
|
|
696
|
-
const db = getDb();
|
|
618
|
+
export async function addGraphRelation(specId: string | null, relation: GraphRelation): Promise<void> {
|
|
697
619
|
const now = new Date().toISOString();
|
|
698
|
-
|
|
699
|
-
db.run(
|
|
620
|
+
await dbRun(
|
|
700
621
|
`INSERT INTO knowledge_graph (spec_id, source_type, source_id, target_type, target_id, relation, metadata, created_at)
|
|
701
622
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
702
623
|
[
|
|
@@ -712,28 +633,25 @@ export function addGraphRelation(specId: string | null, relation: GraphRelation)
|
|
|
712
633
|
);
|
|
713
634
|
}
|
|
714
635
|
|
|
715
|
-
export function getRelatedDecisions(fileOrPattern: string, type: "file" | "pattern"): any[] {
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
return db.query(`
|
|
719
|
-
SELECT d.* FROM decisions d
|
|
636
|
+
export async function getRelatedDecisions(fileOrPattern: string, type: "file" | "pattern"): Promise<any[]> {
|
|
637
|
+
return dbAll(
|
|
638
|
+
`SELECT d.* FROM decisions d
|
|
720
639
|
JOIN knowledge_graph kg ON kg.source_id = d.id AND kg.source_type = 'decision'
|
|
721
640
|
WHERE kg.target_type = ? AND kg.target_id = ?
|
|
722
|
-
AND kg.relation IN ('implements', 'depends_on', 'uses')
|
|
723
|
-
|
|
641
|
+
AND kg.relation IN ('implements', 'depends_on', 'uses')`,
|
|
642
|
+
[type, fileOrPattern]
|
|
643
|
+
);
|
|
724
644
|
}
|
|
725
645
|
|
|
726
|
-
export function getRelatedFiles(decisionOrPattern: string, type: "decision" | "pattern"): string[] {
|
|
727
|
-
const
|
|
728
|
-
|
|
729
|
-
const results = db.query(`
|
|
730
|
-
SELECT kg.target_id as file FROM knowledge_graph kg
|
|
646
|
+
export async function getRelatedFiles(decisionOrPattern: string, type: "decision" | "pattern"): Promise<string[]> {
|
|
647
|
+
const results = await dbAll(
|
|
648
|
+
`SELECT kg.target_id as file FROM knowledge_graph kg
|
|
731
649
|
WHERE kg.source_type = ? AND kg.source_id = ?
|
|
732
650
|
AND kg.target_type = 'file'
|
|
733
|
-
AND kg.relation IN ('implements', 'modifies', 'creates')
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
return results.map(r => r.file);
|
|
651
|
+
AND kg.relation IN ('implements', 'modifies', 'creates')`,
|
|
652
|
+
[type, decisionOrPattern]
|
|
653
|
+
);
|
|
654
|
+
return results.map((r: any) => r.file);
|
|
737
655
|
}
|
|
738
656
|
|
|
739
657
|
// ═══════════════════════════════════════════════════════════════
|
|
@@ -749,11 +667,9 @@ export interface ReasoningEntry {
|
|
|
749
667
|
importance?: "critical" | "high" | "normal" | "low";
|
|
750
668
|
}
|
|
751
669
|
|
|
752
|
-
export function addReasoning(specId: string, taskId: number | null, entry: ReasoningEntry): void {
|
|
753
|
-
const db = getDb();
|
|
670
|
+
export async function addReasoning(specId: string, taskId: number | null, entry: ReasoningEntry): Promise<void> {
|
|
754
671
|
const now = new Date().toISOString();
|
|
755
|
-
|
|
756
|
-
db.run(
|
|
672
|
+
await dbRun(
|
|
757
673
|
`INSERT INTO reasoning_log (spec_id, task_id, category, thought, related_files, related_decisions, related_patterns, importance, created_at)
|
|
758
674
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
759
675
|
[
|
|
@@ -770,49 +686,39 @@ export function addReasoning(specId: string, taskId: number | null, entry: Reaso
|
|
|
770
686
|
);
|
|
771
687
|
}
|
|
772
688
|
|
|
773
|
-
export function getRecentReasoning(specId: string, limit: number = 20): any[] {
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
WHERE spec_id = ?
|
|
779
|
-
ORDER BY created_at DESC
|
|
780
|
-
LIMIT ?
|
|
781
|
-
`).all(specId, limit) as any[];
|
|
689
|
+
export async function getRecentReasoning(specId: string, limit: number = 20): Promise<any[]> {
|
|
690
|
+
return dbAll(
|
|
691
|
+
"SELECT * FROM reasoning_log WHERE spec_id = ? ORDER BY created_at DESC LIMIT ?",
|
|
692
|
+
[specId, limit]
|
|
693
|
+
);
|
|
782
694
|
}
|
|
783
695
|
|
|
784
|
-
|
|
785
|
-
// Prioridade: analysis_id (link explicito) > nome exato > LIKE parcial
|
|
786
|
-
export function getArchitecturalAnalysisForSpec(specName: string, specId?: string): any {
|
|
787
|
-
const db = getDb();
|
|
788
|
-
|
|
696
|
+
export async function getArchitecturalAnalysisForSpec(specName: string, specId?: string): Promise<any> {
|
|
789
697
|
try {
|
|
790
|
-
// 0. Link explicito via analysis_id na tabela specs
|
|
791
698
|
if (specId) {
|
|
792
|
-
const spec =
|
|
699
|
+
const spec = await dbGet<any>("SELECT analysis_id FROM specs WHERE id = ?", [specId]);
|
|
793
700
|
if (spec?.analysis_id) {
|
|
794
|
-
const analysis =
|
|
795
|
-
"SELECT * FROM architectural_analyses WHERE id = ? AND status IN ('approved', 'implemented')"
|
|
796
|
-
|
|
701
|
+
const analysis = await dbGet(
|
|
702
|
+
"SELECT * FROM architectural_analyses WHERE id = ? AND status IN ('approved', 'implemented')",
|
|
703
|
+
[spec.analysis_id]
|
|
704
|
+
);
|
|
797
705
|
if (analysis) return analysis;
|
|
798
706
|
}
|
|
799
707
|
}
|
|
800
708
|
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
)
|
|
805
|
-
|
|
709
|
+
let analysis = await dbGet(
|
|
710
|
+
"SELECT * FROM architectural_analyses WHERE name = ? AND status IN ('approved', 'implemented') ORDER BY approved_at DESC LIMIT 1",
|
|
711
|
+
[specName]
|
|
712
|
+
);
|
|
806
713
|
if (analysis) return analysis;
|
|
807
714
|
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
)
|
|
715
|
+
analysis = await dbGet(
|
|
716
|
+
"SELECT * FROM architectural_analyses WHERE (name LIKE ? OR ? LIKE '%' || name || '%') AND status IN ('approved', 'implemented') ORDER BY approved_at DESC LIMIT 1",
|
|
717
|
+
[`%${specName}%`, specName]
|
|
718
|
+
);
|
|
812
719
|
|
|
813
720
|
return analysis || null;
|
|
814
721
|
} catch {
|
|
815
|
-
// Tabela pode nao existir se architect nunca foi usado
|
|
816
722
|
return null;
|
|
817
723
|
}
|
|
818
724
|
}
|
|
@@ -830,14 +736,13 @@ export interface ProjectUtility {
|
|
|
830
736
|
description?: string;
|
|
831
737
|
}
|
|
832
738
|
|
|
833
|
-
export function upsertUtility(
|
|
739
|
+
export async function upsertUtility(
|
|
834
740
|
utility: ProjectUtility,
|
|
835
741
|
specId?: string,
|
|
836
742
|
taskRef?: number
|
|
837
|
-
): void {
|
|
838
|
-
const db = getDb();
|
|
743
|
+
): Promise<void> {
|
|
839
744
|
const now = new Date().toISOString();
|
|
840
|
-
|
|
745
|
+
await dbRun(
|
|
841
746
|
`INSERT INTO project_utilities (file_path, utility_name, utility_type, scope, signature, description, spec_id, task_ref, created_at, updated_at)
|
|
842
747
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
843
748
|
ON CONFLICT(file_path, utility_name) DO UPDATE SET
|
|
@@ -854,21 +759,18 @@ export function upsertUtility(
|
|
|
854
759
|
);
|
|
855
760
|
}
|
|
856
761
|
|
|
857
|
-
export function getUtilitiesForContext(
|
|
762
|
+
export async function getUtilitiesForContext(
|
|
858
763
|
dirs: string[],
|
|
859
764
|
scope?: string,
|
|
860
765
|
limit: number = 15
|
|
861
|
-
): any[] {
|
|
862
|
-
const db = getDb();
|
|
863
|
-
|
|
864
|
-
// Se nenhum filtro, retornar mais recentes
|
|
766
|
+
): Promise<any[]> {
|
|
865
767
|
if (dirs.length === 0 && !scope) {
|
|
866
|
-
return
|
|
867
|
-
"SELECT * FROM project_utilities ORDER BY updated_at DESC LIMIT ?"
|
|
868
|
-
|
|
768
|
+
return dbAll(
|
|
769
|
+
"SELECT * FROM project_utilities ORDER BY updated_at DESC LIMIT ?",
|
|
770
|
+
[limit]
|
|
771
|
+
);
|
|
869
772
|
}
|
|
870
773
|
|
|
871
|
-
// Buscar por diretorio (prioridade) e scope (fallback)
|
|
872
774
|
const conditions: string[] = [];
|
|
873
775
|
const params: any[] = [];
|
|
874
776
|
|
|
@@ -885,24 +787,26 @@ export function getUtilitiesForContext(
|
|
|
885
787
|
|
|
886
788
|
params.push(limit);
|
|
887
789
|
const where = conditions.length > 0 ? `WHERE (${conditions.join(" OR ")})` : "";
|
|
888
|
-
return
|
|
889
|
-
`SELECT * FROM project_utilities ${where} ORDER BY updated_at DESC LIMIT
|
|
890
|
-
|
|
790
|
+
return dbAll(
|
|
791
|
+
`SELECT * FROM project_utilities ${where} ORDER BY updated_at DESC LIMIT ?`,
|
|
792
|
+
params
|
|
793
|
+
);
|
|
891
794
|
}
|
|
892
795
|
|
|
893
|
-
export function findDuplicateUtilities(
|
|
796
|
+
export async function findDuplicateUtilities(
|
|
894
797
|
utilityName: string,
|
|
895
798
|
excludeFile?: string
|
|
896
|
-
): any[] {
|
|
897
|
-
const db = getDb();
|
|
799
|
+
): Promise<any[]> {
|
|
898
800
|
if (excludeFile) {
|
|
899
|
-
return
|
|
900
|
-
"SELECT * FROM project_utilities WHERE utility_name = ? AND file_path != ?"
|
|
901
|
-
|
|
801
|
+
return dbAll(
|
|
802
|
+
"SELECT * FROM project_utilities WHERE utility_name = ? AND file_path != ?",
|
|
803
|
+
[utilityName, excludeFile]
|
|
804
|
+
);
|
|
902
805
|
}
|
|
903
|
-
return
|
|
904
|
-
"SELECT * FROM project_utilities WHERE utility_name = ?"
|
|
905
|
-
|
|
806
|
+
return dbAll(
|
|
807
|
+
"SELECT * FROM project_utilities WHERE utility_name = ?",
|
|
808
|
+
[utilityName]
|
|
809
|
+
);
|
|
906
810
|
}
|
|
907
811
|
|
|
908
812
|
// ═══════════════════════════════════════════════════════════════
|
|
@@ -922,10 +826,9 @@ export interface AgentPerformanceData {
|
|
|
922
826
|
executionDurationMs: number;
|
|
923
827
|
}
|
|
924
828
|
|
|
925
|
-
export function recordAgentPerformance(data: AgentPerformanceData): void {
|
|
926
|
-
const db = getDb();
|
|
829
|
+
export async function recordAgentPerformance(data: AgentPerformanceData): Promise<void> {
|
|
927
830
|
const now = new Date().toISOString();
|
|
928
|
-
|
|
831
|
+
await dbRun(
|
|
929
832
|
`INSERT INTO agent_performance
|
|
930
833
|
(agent_type, spec_id, task_id, gates_passed_first_try, gates_total, bypasses_used, files_created, files_modified, context_size_bytes, execution_duration_ms, created_at)
|
|
931
834
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
@@ -938,16 +841,16 @@ export function recordAgentPerformance(data: AgentPerformanceData): void {
|
|
|
938
841
|
);
|
|
939
842
|
}
|
|
940
843
|
|
|
941
|
-
export function getAgentHints(agentType: string, limit: number = 5): string[] {
|
|
942
|
-
const db = getDb();
|
|
844
|
+
export async function getAgentHints(agentType: string, limit: number = 5): Promise<string[]> {
|
|
943
845
|
const hints: string[] = [];
|
|
944
846
|
|
|
945
847
|
try {
|
|
946
|
-
const recent =
|
|
848
|
+
const recent = await dbAll(
|
|
947
849
|
`SELECT * FROM agent_performance
|
|
948
850
|
WHERE agent_type = ?
|
|
949
|
-
ORDER BY created_at DESC LIMIT
|
|
950
|
-
|
|
851
|
+
ORDER BY created_at DESC LIMIT ?`,
|
|
852
|
+
[agentType, limit]
|
|
853
|
+
);
|
|
951
854
|
|
|
952
855
|
if (recent.length === 0) return [];
|
|
953
856
|
|
|
@@ -964,17 +867,18 @@ export function getAgentHints(agentType: string, limit: number = 5): string[] {
|
|
|
964
867
|
hints.push(`ATENCAO: Gate pass rate baixo (${(avgGateRate * 100).toFixed(0)}%). Verifique standards e DRY obrigatorios.`);
|
|
965
868
|
}
|
|
966
869
|
|
|
967
|
-
const bypassTypes =
|
|
870
|
+
const bypassTypes = await dbAll(
|
|
968
871
|
`SELECT gb.gate_name, COUNT(*) as cnt FROM gate_bypasses gb
|
|
969
872
|
JOIN tasks t ON gb.task_id = t.id
|
|
970
873
|
WHERE t.agent = ?
|
|
971
874
|
GROUP BY gb.gate_name
|
|
972
|
-
ORDER BY cnt DESC LIMIT 3
|
|
973
|
-
|
|
875
|
+
ORDER BY cnt DESC LIMIT 3`,
|
|
876
|
+
[agentType]
|
|
877
|
+
);
|
|
974
878
|
|
|
975
879
|
for (const bp of bypassTypes) {
|
|
976
|
-
if (bp.cnt >= 2) {
|
|
977
|
-
hints.push(`Gate '${bp.gate_name}' frequentemente ignorado (${bp.cnt}x). Preste atencao especial.`);
|
|
880
|
+
if ((bp as any).cnt >= 2) {
|
|
881
|
+
hints.push(`Gate '${(bp as any).gate_name}' frequentemente ignorado (${(bp as any).cnt}x). Preste atencao especial.`);
|
|
978
882
|
}
|
|
979
883
|
}
|
|
980
884
|
} catch {
|