@codexa/cli 9.0.30 → 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.
@@ -9,7 +9,7 @@
9
9
  * - Patterns descobertos
10
10
  */
11
11
 
12
- import { getDb } from "../db/connection";
12
+ import { dbGet, dbAll, dbRun } from "../db/connection";
13
13
  import { SubagentReturn, Knowledge } from "./subagent-protocol";
14
14
  import { addReasoning, addGraphRelation, upsertUtility, getNextDecisionId, runInTransaction } from "../db/schema";
15
15
  import { extractUtilitiesFromFile, inferScopeFromPath } from "../commands/patterns";
@@ -22,9 +22,9 @@ interface ProcessResult {
22
22
  conflictsDetected: number;
23
23
  artifactsAdded: number;
24
24
  patternsAdded: number;
25
- reasoningAdded: number; // v8.0
26
- relationsAdded: number; // v8.0
27
- utilitiesRegistered: number; // v8.5
25
+ reasoningAdded: number;
26
+ relationsAdded: number;
27
+ utilitiesRegistered: number;
28
28
  errors: string[];
29
29
  }
30
30
 
@@ -32,24 +32,21 @@ interface ProcessResult {
32
32
  * Processa o retorno de um subagent e registra automaticamente
33
33
  * todos os dados extraidos no banco
34
34
  */
35
- export function processSubagentReturn(
35
+ export async function processSubagentReturn(
36
36
  specId: string,
37
37
  taskId: number,
38
38
  taskNumber: number,
39
39
  data: SubagentReturn
40
- ): ProcessResult {
41
- // v10.2: Wrap entire processing in atomic transaction
42
- // Prevents race conditions in parallel tasks (pattern storage, knowledge dedup)
43
- return runInTransaction(() => processSubagentReturnInner(specId, taskId, taskNumber, data));
40
+ ): Promise<ProcessResult> {
41
+ return await runInTransaction(async (tx) => await processSubagentReturnInner(specId, taskId, taskNumber, data));
44
42
  }
45
43
 
46
- function processSubagentReturnInner(
44
+ async function processSubagentReturnInner(
47
45
  specId: string,
48
46
  taskId: number,
49
47
  taskNumber: number,
50
48
  data: SubagentReturn
51
- ): ProcessResult {
52
- const db = getDb();
49
+ ): Promise<ProcessResult> {
53
50
  const now = new Date().toISOString();
54
51
  const result: ProcessResult = {
55
52
  success: true,
@@ -68,14 +65,14 @@ function processSubagentReturnInner(
68
65
  if (data.knowledge_to_broadcast && data.knowledge_to_broadcast.length > 0) {
69
66
  for (const k of data.knowledge_to_broadcast) {
70
67
  try {
71
- // v8.3: Deduplicacao - verificar se knowledge identico ja existe
72
- const existing = db.query(
73
- `SELECT id FROM knowledge WHERE spec_id = ? AND category = ? AND content = ? LIMIT 1`
74
- ).get(specId, k.category, k.content) as any;
68
+ const existing = await dbGet<any>(
69
+ `SELECT id FROM knowledge WHERE spec_id = ? AND category = ? AND content = ? LIMIT 1`,
70
+ [specId, k.category, k.content]
71
+ );
75
72
 
76
- if (existing) continue; // Skip duplicata
73
+ if (existing) continue;
77
74
 
78
- db.run(
75
+ await dbRun(
79
76
  `INSERT INTO knowledge (spec_id, task_origin, category, content, severity, broadcast_to, created_at)
80
77
  VALUES (?, ?, ?, ?, ?, 'all', ?)`,
81
78
  [specId, taskId, k.category, k.content, k.severity, now]
@@ -96,7 +93,7 @@ function processSubagentReturnInner(
96
93
  while (retries > 0 && !inserted) {
97
94
  try {
98
95
  const decisionId = getNextDecisionId(specId);
99
- db.run(
96
+ await dbRun(
100
97
  `INSERT INTO decisions (id, spec_id, task_ref, title, decision, rationale, status, created_at)
101
98
  VALUES (?, ?, ?, ?, ?, ?, 'active', ?)`,
102
99
  [decisionId, specId, taskNumber, dec.title, dec.decision, dec.rationale || null, now]
@@ -119,9 +116,10 @@ function processSubagentReturnInner(
119
116
  // 2b. v9.5: Conflict check (WARNING, nao bloqueia subagent)
120
117
  if (savedDecisionIds.length > 0) {
121
118
  try {
122
- const existingDecisions = db
123
- .query("SELECT * FROM decisions WHERE spec_id = ? AND status = 'active'")
124
- .all(specId) as any[];
119
+ const existingDecisions = await dbAll<any>(
120
+ "SELECT * FROM decisions WHERE spec_id = ? AND status = 'active'",
121
+ [specId]
122
+ );
125
123
 
126
124
  for (const dec of data.decisions_made!) {
127
125
  const othersOnly = existingDecisions.filter(
@@ -132,7 +130,7 @@ function processSubagentReturnInner(
132
130
  const analysis = detectConflicts(dec.title, dec.decision, othersOnly);
133
131
  if (analysis.hasConflict) {
134
132
  for (const conflict of analysis.conflictingDecisions) {
135
- db.run(
133
+ await dbRun(
136
134
  `INSERT INTO knowledge (spec_id, task_origin, category, content, severity, broadcast_to, created_at)
137
135
  VALUES (?, ?, 'decision', ?, 'warning', 'all', ?)`,
138
136
  [specId, taskId,
@@ -157,7 +155,7 @@ function processSubagentReturnInner(
157
155
 
158
156
  for (const file of allFiles) {
159
157
  try {
160
- db.run(
158
+ await dbRun(
161
159
  `INSERT OR REPLACE INTO artifacts (spec_id, task_ref, path, action, created_at)
162
160
  VALUES (?, ?, ?, ?, ?)`,
163
161
  [specId, taskNumber, file.path, file.action, now]
@@ -171,11 +169,10 @@ function processSubagentReturnInner(
171
169
  // 4. Registrar Patterns descobertos no contexto
172
170
  if (data.patterns_discovered && data.patterns_discovered.length > 0) {
173
171
  try {
174
- const context = db.query("SELECT * FROM context WHERE spec_id = ?").get(specId) as any;
172
+ const context = await dbGet<any>("SELECT * FROM context WHERE spec_id = ?", [specId]);
175
173
  const currentPatterns = context?.patterns ? JSON.parse(context.patterns) : [];
176
174
 
177
175
  for (const pattern of data.patterns_discovered) {
178
- // v10.0: Dedup — skip if pattern text already exists
179
176
  if (currentPatterns.some((p: any) => p.pattern === pattern)) {
180
177
  continue;
181
178
  }
@@ -187,12 +184,11 @@ function processSubagentReturnInner(
187
184
  result.patternsAdded++;
188
185
  }
189
186
 
190
- // v10.0: Cap at 50 patterns (keep most recent)
191
187
  if (currentPatterns.length > 50) {
192
188
  currentPatterns.splice(0, currentPatterns.length - 50);
193
189
  }
194
190
 
195
- db.run(
191
+ await dbRun(
196
192
  "UPDATE context SET patterns = ?, updated_at = ? WHERE spec_id = ?",
197
193
  [JSON.stringify(currentPatterns), now, specId]
198
194
  );
@@ -206,12 +202,13 @@ function processSubagentReturnInner(
206
202
  for (const pattern of data.patterns_discovered) {
207
203
  try {
208
204
  const content = `Pattern descoberto: ${pattern}`;
209
- const existing = db.query(
210
- `SELECT id FROM knowledge WHERE spec_id = ? AND category = 'pattern' AND content = ? LIMIT 1`
211
- ).get(specId, content) as any;
205
+ const existing = await dbGet<any>(
206
+ `SELECT id FROM knowledge WHERE spec_id = ? AND category = 'pattern' AND content = ? LIMIT 1`,
207
+ [specId, content]
208
+ );
212
209
 
213
210
  if (!existing) {
214
- db.run(
211
+ await dbRun(
215
212
  `INSERT INTO knowledge (spec_id, task_origin, category, content, severity, broadcast_to, created_at)
216
213
  VALUES (?, ?, 'pattern', ?, 'info', 'all', ?)`,
217
214
  [specId, taskId, content, now]
@@ -225,7 +222,7 @@ function processSubagentReturnInner(
225
222
  if (data.status === "blocked" && data.blockers) {
226
223
  for (const blocker of data.blockers) {
227
224
  try {
228
- db.run(
225
+ await dbRun(
229
226
  `INSERT INTO knowledge (spec_id, task_origin, category, content, severity, broadcast_to, created_at)
230
227
  VALUES (?, ?, 'blocker', ?, 'critical', 'all', ?)`,
231
228
  [specId, taskId, blocker, now]
@@ -240,9 +237,8 @@ function processSubagentReturnInner(
240
237
  // 6. v8.0: Registrar Reasoning no reasoning_log
241
238
  if (data.reasoning) {
242
239
  try {
243
- // Abordagem principal
244
240
  if (data.reasoning.approach) {
245
- addReasoning(specId, taskId, {
241
+ await addReasoning(specId, taskId, {
246
242
  category: "decision",
247
243
  thought: `Abordagem: ${data.reasoning.approach}`,
248
244
  relatedFiles: [...data.files_created, ...data.files_modified],
@@ -251,10 +247,9 @@ function processSubagentReturnInner(
251
247
  result.reasoningAdded++;
252
248
  }
253
249
 
254
- // Desafios encontrados
255
250
  if (data.reasoning.challenges && data.reasoning.challenges.length > 0) {
256
251
  for (const challenge of data.reasoning.challenges) {
257
- addReasoning(specId, taskId, {
252
+ await addReasoning(specId, taskId, {
258
253
  category: "challenge",
259
254
  thought: challenge,
260
255
  relatedFiles: [...data.files_created, ...data.files_modified],
@@ -264,10 +259,9 @@ function processSubagentReturnInner(
264
259
  }
265
260
  }
266
261
 
267
- // Alternativas consideradas
268
262
  if (data.reasoning.alternatives && data.reasoning.alternatives.length > 0) {
269
263
  for (const alt of data.reasoning.alternatives) {
270
- addReasoning(specId, taskId, {
264
+ await addReasoning(specId, taskId, {
271
265
  category: "decision",
272
266
  thought: `Alternativa considerada: ${alt}`,
273
267
  relatedFiles: [...data.files_created, ...data.files_modified],
@@ -277,9 +271,8 @@ function processSubagentReturnInner(
277
271
  }
278
272
  }
279
273
 
280
- // Recomendações para próximas tasks
281
274
  if (data.reasoning.recommendations) {
282
- addReasoning(specId, taskId, {
275
+ await addReasoning(specId, taskId, {
283
276
  category: "recommendation",
284
277
  thought: data.reasoning.recommendations,
285
278
  relatedFiles: [...data.files_created, ...data.files_modified],
@@ -294,9 +287,8 @@ function processSubagentReturnInner(
294
287
 
295
288
  // 7. v8.0: Criar relações no knowledge graph
296
289
  try {
297
- // Relação: task -> arquivos criados
298
290
  for (const file of data.files_created) {
299
- addGraphRelation(specId, {
291
+ await addGraphRelation(specId, {
300
292
  sourceType: "task",
301
293
  sourceId: String(taskId),
302
294
  targetType: "file",
@@ -306,9 +298,8 @@ function processSubagentReturnInner(
306
298
  result.relationsAdded++;
307
299
  }
308
300
 
309
- // Relação: task -> arquivos modificados
310
301
  for (const file of data.files_modified) {
311
- addGraphRelation(specId, {
302
+ await addGraphRelation(specId, {
312
303
  sourceType: "task",
313
304
  sourceId: String(taskId),
314
305
  targetType: "file",
@@ -318,11 +309,10 @@ function processSubagentReturnInner(
318
309
  result.relationsAdded++;
319
310
  }
320
311
 
321
- // Relação: decision -> arquivos (usa IDs salvos na seção 2, não gera novos)
322
312
  if (savedDecisionIds.length > 0) {
323
313
  for (const decisionId of savedDecisionIds) {
324
314
  for (const file of [...data.files_created, ...data.files_modified]) {
325
- addGraphRelation(specId, {
315
+ await addGraphRelation(specId, {
326
316
  sourceType: "decision",
327
317
  sourceId: decisionId,
328
318
  targetType: "file",
@@ -334,11 +324,10 @@ function processSubagentReturnInner(
334
324
  }
335
325
  }
336
326
 
337
- // Relação: pattern -> arquivos (se patterns descobertos)
338
327
  if (data.patterns_discovered) {
339
328
  for (const pattern of data.patterns_discovered) {
340
329
  for (const file of data.files_created) {
341
- addGraphRelation(specId, {
330
+ await addGraphRelation(specId, {
342
331
  sourceType: "pattern",
343
332
  sourceId: pattern,
344
333
  targetType: "file",
@@ -355,10 +344,9 @@ function processSubagentReturnInner(
355
344
 
356
345
  // 8. v8.5: Registrar utilities de arquivos criados/modificados (DRY map)
357
346
  try {
358
- // 8a. Usar utilities declaradas pelo subagent (metadata mais rica)
359
347
  if (data.utilities_created && data.utilities_created.length > 0) {
360
348
  for (const util of data.utilities_created) {
361
- upsertUtility({
349
+ await upsertUtility({
362
350
  filePath: util.file,
363
351
  utilityName: util.name,
364
352
  utilityType: util.type || "function",
@@ -370,12 +358,11 @@ function processSubagentReturnInner(
370
358
  }
371
359
  }
372
360
 
373
- // 8b. Fallback: escanear exports de arquivos criados/modificados
374
361
  for (const file of allFiles.map(f => f.path)) {
375
362
  const utilities = extractUtilitiesFromFile(file);
376
363
  const scope = inferScopeFromPath(file);
377
364
  for (const util of utilities) {
378
- upsertUtility({
365
+ await upsertUtility({
379
366
  filePath: file,
380
367
  utilityName: util.name,
381
368
  utilityType: util.type,
@@ -386,7 +373,6 @@ function processSubagentReturnInner(
386
373
  }
387
374
  }
388
375
  } catch (e) {
389
- // Nao-critico: nao falhar processamento por extracao de utilities
390
376
  result.errors.push(`Aviso utilities: ${(e as Error).message}`);
391
377
  }
392
378
 
@@ -415,14 +401,12 @@ export function formatProcessResult(result: ProcessResult): string {
415
401
  if (result.patternsAdded > 0) {
416
402
  output += ` + ${result.patternsAdded} pattern(s) adicionado(s) ao contexto\n`;
417
403
  }
418
- // v8.0: Novas métricas
419
404
  if (result.reasoningAdded > 0) {
420
405
  output += ` + ${result.reasoningAdded} raciocinio(s) registrado(s) no historico\n`;
421
406
  }
422
407
  if (result.relationsAdded > 0) {
423
408
  output += ` + ${result.relationsAdded} relacao(oes) criada(s) no grafo de conhecimento\n`;
424
409
  }
425
- // v8.5: Utilities registradas
426
410
  if (result.utilitiesRegistered > 0) {
427
411
  output += ` + ${result.utilitiesRegistered} utilidade(s) registrada(s) no mapa DRY\n`;
428
412
  }
@@ -435,4 +419,4 @@ export function formatProcessResult(result: ProcessResult): string {
435
419
  }
436
420
 
437
421
  return output;
438
- }
422
+ }
@@ -1,5 +1,6 @@
1
- import { describe, it, expect, beforeEach } from "bun:test";
2
- import { getDb } from "../db/connection";
1
+ import { describe, it, expect, beforeEach, afterEach } from "bun:test";
2
+ import { createClient } from "@libsql/client";
3
+ import { setClient, resetClient, dbRun } from "../db/connection";
3
4
  import { initSchema, runMigrations } from "../db/schema";
4
5
  import {
5
6
  buildSimplifyPrompt,
@@ -29,7 +30,7 @@ function createTmpFile(name: string, content: string): string {
29
30
  return path;
30
31
  }
31
32
 
32
- function insertStandard(opts: {
33
+ async function insertStandard(opts: {
33
34
  category: string;
34
35
  scope: string;
35
36
  rule: string;
@@ -38,8 +39,7 @@ function insertStandard(opts: {
38
39
  anti_examples?: string;
39
40
  semantic_query?: string | null;
40
41
  }) {
41
- const db = getDb();
42
- db.run(
42
+ await dbRun(
43
43
  `INSERT INTO standards (category, scope, rule, examples, anti_examples, enforcement, semantic_query, expect, source, created_at)
44
44
  VALUES (?, ?, ?, ?, ?, ?, ?, 'no_match', 'test', datetime('now'))`,
45
45
  [
@@ -59,51 +59,55 @@ function insertStandard(opts: {
59
59
  // ═══════════════════════════════════════════════════════════════
60
60
 
61
61
  describe("simplify prompt-builder", () => {
62
- beforeEach(() => {
63
- initSchema();
64
- runMigrations();
65
- const db = getDb();
66
- db.run("DELETE FROM standards");
67
- // Cleanup tmp
62
+ beforeEach(async () => {
63
+ const client = createClient({ url: ":memory:" });
64
+ setClient(client);
65
+ await initSchema();
66
+ await runMigrations();
67
+ await dbRun("DELETE FROM standards");
68
68
  if (existsSync(TMP_DIR)) {
69
69
  rmSync(TMP_DIR, { recursive: true, force: true });
70
70
  }
71
71
  });
72
72
 
73
+ afterEach(() => {
74
+ resetClient();
75
+ });
76
+
73
77
  // ── getStandardsForSimplify ─────────────────────────────────
74
78
 
75
79
  describe("getStandardsForSimplify", () => {
76
- it("returns standards filtered by scope", () => {
77
- insertStandard({ category: "code", scope: "all", rule: "Global rule" });
78
- insertStandard({ category: "code", scope: "backend", rule: "Backend rule" });
79
- insertStandard({ category: "code", scope: "frontend", rule: "Frontend rule" });
80
+ it("returns standards filtered by scope", async () => {
81
+ await insertStandard({ category: "code", scope: "all", rule: "Global rule" });
82
+ await insertStandard({ category: "code", scope: "backend", rule: "Backend rule" });
83
+ await insertStandard({ category: "code", scope: "frontend", rule: "Frontend rule" });
80
84
 
81
- const backendStds = getStandardsForSimplify("backend");
85
+ const backendStds = await getStandardsForSimplify("backend");
82
86
  expect(backendStds.length).toBe(2);
83
87
  expect(backendStds.map(s => s.rule)).toContain("Global rule");
84
88
  expect(backendStds.map(s => s.rule)).toContain("Backend rule");
85
89
  expect(backendStds.map(s => s.rule)).not.toContain("Frontend rule");
86
90
  });
87
91
 
88
- it("returns all standards when scope is 'all'", () => {
89
- insertStandard({ category: "code", scope: "all", rule: "Global rule" });
90
- insertStandard({ category: "code", scope: "backend", rule: "Backend rule" });
92
+ it("returns all standards when scope is 'all'", async () => {
93
+ await insertStandard({ category: "code", scope: "all", rule: "Global rule" });
94
+ await insertStandard({ category: "code", scope: "backend", rule: "Backend rule" });
91
95
 
92
- const allStds = getStandardsForSimplify("all");
96
+ const allStds = await getStandardsForSimplify("all");
93
97
  expect(allStds.length).toBe(1);
94
98
  expect(allStds[0].rule).toBe("Global rule");
95
99
  });
96
100
 
97
- it("returns empty array when no standards exist", () => {
98
- const stds = getStandardsForSimplify("backend");
101
+ it("returns empty array when no standards exist", async () => {
102
+ const stds = await getStandardsForSimplify("backend");
99
103
  expect(stds.length).toBe(0);
100
104
  });
101
105
 
102
- it("orders required before recommended", () => {
103
- insertStandard({ category: "code", scope: "all", rule: "Recommended", enforcement: "recommended" });
104
- insertStandard({ category: "code", scope: "all", rule: "Required", enforcement: "required" });
106
+ it("orders required before recommended", async () => {
107
+ await insertStandard({ category: "code", scope: "all", rule: "Recommended", enforcement: "recommended" });
108
+ await insertStandard({ category: "code", scope: "all", rule: "Required", enforcement: "required" });
105
109
 
106
- const stds = getStandardsForSimplify("all");
110
+ const stds = await getStandardsForSimplify("all");
107
111
  expect(stds[0].rule).toBe("Required");
108
112
  expect(stds[1].rule).toBe("Recommended");
109
113
  });
@@ -179,8 +183,8 @@ describe("simplify prompt-builder", () => {
179
183
  // ── buildSimplifyPrompt ─────────────────────────────────────
180
184
 
181
185
  describe("buildSimplifyPrompt", () => {
182
- it("builds refactor prompt with standards and files", () => {
183
- insertStandard({
186
+ it("builds refactor prompt with standards and files", async () => {
187
+ await insertStandard({
184
188
  category: "code",
185
189
  scope: "all",
186
190
  rule: "Use function declarations",
@@ -191,7 +195,7 @@ describe("simplify prompt-builder", () => {
191
195
  const filePath = createTmpFile("test.ts", "export function hello() {}");
192
196
  const files: SimplifyFile[] = [{ path: filePath, action: "created" }];
193
197
 
194
- const prompt = buildSimplifyPrompt(files, "all", "refactor");
198
+ const prompt = await buildSimplifyPrompt(files, "all", "refactor");
195
199
 
196
200
  expect(prompt).toContain("## Standards do Projeto");
197
201
  expect(prompt).toContain("Use function declarations");
@@ -201,53 +205,51 @@ describe("simplify prompt-builder", () => {
201
205
  expect(prompt).toContain("Preservem funcionalidade");
202
206
  });
203
207
 
204
- it("builds audit prompt with analysis-only instructions", () => {
205
- insertStandard({ category: "code", scope: "all", rule: "Some rule" });
208
+ it("builds audit prompt with analysis-only instructions", async () => {
209
+ await insertStandard({ category: "code", scope: "all", rule: "Some rule" });
206
210
 
207
211
  const filePath = createTmpFile("test2.ts", "export const x = 1;");
208
212
  const files: SimplifyFile[] = [{ path: filePath, action: "modified" }];
209
213
 
210
- const prompt = buildSimplifyPrompt(files, "all", "audit");
214
+ const prompt = await buildSimplifyPrompt(files, "all", "audit");
211
215
 
212
216
  expect(prompt).toContain("NAO aplique mudancas");
213
217
  expect(prompt).toContain("reporte oportunidades");
214
218
  expect(prompt).toContain("(modificado)");
215
219
  });
216
220
 
217
- it("handles no standards gracefully", () => {
221
+ it("handles no standards gracefully", async () => {
218
222
  const filePath = createTmpFile("test3.ts", "export const y = 2;");
219
223
  const files: SimplifyFile[] = [{ path: filePath, action: "created" }];
220
224
 
221
- const prompt = buildSimplifyPrompt(files, "all", "refactor");
225
+ const prompt = await buildSimplifyPrompt(files, "all", "refactor");
222
226
 
223
- // Should still have files and instructions sections
224
227
  expect(prompt).toContain("## Arquivos para Simplificar");
225
228
  expect(prompt).toContain("## Instrucoes");
226
- // Should NOT have standards section
227
229
  expect(prompt).not.toContain("## Standards do Projeto");
228
230
  });
229
231
 
230
- it("filters out non-existing files", () => {
232
+ it("filters out non-existing files", async () => {
231
233
  const filePath = createTmpFile("exists.ts", "export const z = 3;");
232
234
  const files: SimplifyFile[] = [
233
235
  { path: filePath, action: "created" },
234
236
  { path: "/nonexistent/file.ts", action: "modified" },
235
237
  ];
236
238
 
237
- const prompt = buildSimplifyPrompt(files, "all", "refactor");
239
+ const prompt = await buildSimplifyPrompt(files, "all", "refactor");
238
240
 
239
241
  expect(prompt).toContain("exists.ts");
240
242
  expect(prompt).not.toContain("nonexistent");
241
243
  });
242
244
 
243
- it("filters standards by scope", () => {
244
- insertStandard({ category: "code", scope: "backend", rule: "Backend only rule" });
245
- insertStandard({ category: "code", scope: "frontend", rule: "Frontend only rule" });
245
+ it("filters standards by scope", async () => {
246
+ await insertStandard({ category: "code", scope: "backend", rule: "Backend only rule" });
247
+ await insertStandard({ category: "code", scope: "frontend", rule: "Frontend only rule" });
246
248
 
247
249
  const filePath = createTmpFile("test4.ts", "export const a = 1;");
248
250
  const files: SimplifyFile[] = [{ path: filePath, action: "created" }];
249
251
 
250
- const prompt = buildSimplifyPrompt(files, "backend", "refactor");
252
+ const prompt = await buildSimplifyPrompt(files, "backend", "refactor");
251
253
 
252
254
  expect(prompt).toContain("Backend only rule");
253
255
  expect(prompt).not.toContain("Frontend only rule");
@@ -4,7 +4,7 @@
4
4
  // from SQLite. Generates context files for the simplifier agent.
5
5
  // ═══════════════════════════════════════════════════════════════
6
6
 
7
- import { getDb } from "../db/connection";
7
+ import { dbAll } from "../db/connection";
8
8
  import { existsSync, mkdirSync } from "fs";
9
9
  import { resolve, join } from "path";
10
10
 
@@ -42,16 +42,14 @@ export type SimplifyMode = "refactor" | "audit";
42
42
  // STANDARDS RETRIEVAL
43
43
  // ═══════════════════════════════════════════════════════════════
44
44
 
45
- export function getStandardsForSimplify(agentDomain: string): StandardRow[] {
46
- const db = getDb();
47
- return db
48
- .query(
49
- `SELECT id, category, scope, rule, examples, anti_examples, enforcement, semantic_query
50
- FROM standards
51
- WHERE (scope = 'all' OR scope = ?)
52
- ORDER BY enforcement DESC, category`
53
- )
54
- .all(agentDomain) as StandardRow[];
45
+ export async function getStandardsForSimplify(agentDomain: string): Promise<StandardRow[]> {
46
+ return dbAll<StandardRow>(
47
+ `SELECT id, category, scope, rule, examples, anti_examples, enforcement, semantic_query
48
+ FROM standards
49
+ WHERE (scope = 'all' OR scope = ?)
50
+ ORDER BY enforcement DESC, category`,
51
+ [agentDomain]
52
+ );
55
53
  }
56
54
 
57
55
  // ═══════════════════════════════════════════════════════════════
@@ -124,12 +122,12 @@ function parseJsonArray(json: string | null): string[] {
124
122
  // PROMPT BUILDER
125
123
  // ═══════════════════════════════════════════════════════════════
126
124
 
127
- export function buildSimplifyPrompt(
125
+ export async function buildSimplifyPrompt(
128
126
  files: SimplifyFile[],
129
127
  agentDomain: string,
130
128
  mode: SimplifyMode
131
- ): string {
132
- const standards = getStandardsForSimplify(agentDomain);
129
+ ): Promise<string> {
130
+ const standards = await getStandardsForSimplify(agentDomain);
133
131
  const existingFiles = files.filter(f => existsSync(f.path));
134
132
 
135
133
  let prompt = "";