@codexa/cli 9.0.23 → 9.0.25

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.
@@ -37,7 +37,7 @@ export function cleanupContextFiles(specId: string): void {
37
37
  const { readdirSync, unlinkSync } = require("fs");
38
38
  const files = readdirSync(dir) as string[];
39
39
  for (const file of files) {
40
- if (file.startsWith("task-") && file.endsWith(".md")) {
40
+ if ((file.startsWith("task-") || file.startsWith("simplify-")) && file.endsWith(".md")) {
41
41
  unlinkSync(join(dir, file));
42
42
  }
43
43
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codexa/cli",
3
- "version": "9.0.23",
3
+ "version": "9.0.25",
4
4
  "description": "Orchestrated workflow system for Claude Code - manages feature development through parallel subagents with structured phases, gates, and quality enforcement.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -15,6 +15,7 @@
15
15
  "gates/",
16
16
  "protocol/",
17
17
  "detectors/",
18
+ "simplify/",
18
19
  "templates/"
19
20
  ],
20
21
  "scripts": {
@@ -0,0 +1,256 @@
1
+ import { describe, it, expect, beforeEach } from "bun:test";
2
+ import { getDb } from "../db/connection";
3
+ import { initSchema, runMigrations } from "../db/schema";
4
+ import {
5
+ buildSimplifyPrompt,
6
+ getStandardsForSimplify,
7
+ formatStandardsBlock,
8
+ type SimplifyFile,
9
+ } from "./prompt-builder";
10
+ import { writeFileSync, mkdirSync, existsSync, rmSync } from "fs";
11
+ import { join } from "path";
12
+
13
+ // ═══════════════════════════════════════════════════════════════
14
+ // HELPERS
15
+ // ═══════════════════════════════════════════════════════════════
16
+
17
+ const TMP_DIR = join(process.cwd(), ".codexa", "test-tmp-simplify");
18
+
19
+ function ensureTmpDir() {
20
+ if (!existsSync(TMP_DIR)) {
21
+ mkdirSync(TMP_DIR, { recursive: true });
22
+ }
23
+ }
24
+
25
+ function createTmpFile(name: string, content: string): string {
26
+ ensureTmpDir();
27
+ const path = join(TMP_DIR, name);
28
+ writeFileSync(path, content);
29
+ return path;
30
+ }
31
+
32
+ function insertStandard(opts: {
33
+ category: string;
34
+ scope: string;
35
+ rule: string;
36
+ enforcement?: string;
37
+ examples?: string;
38
+ anti_examples?: string;
39
+ semantic_query?: string | null;
40
+ }) {
41
+ const db = getDb();
42
+ db.run(
43
+ `INSERT INTO standards (category, scope, rule, examples, anti_examples, enforcement, semantic_query, expect, source, created_at)
44
+ VALUES (?, ?, ?, ?, ?, ?, ?, 'no_match', 'test', datetime('now'))`,
45
+ [
46
+ opts.category,
47
+ opts.scope,
48
+ opts.rule,
49
+ opts.examples || null,
50
+ opts.anti_examples || null,
51
+ opts.enforcement || "required",
52
+ opts.semantic_query || null,
53
+ ]
54
+ );
55
+ }
56
+
57
+ // ═══════════════════════════════════════════════════════════════
58
+ // TESTS
59
+ // ═══════════════════════════════════════════════════════════════
60
+
61
+ describe("simplify prompt-builder", () => {
62
+ beforeEach(() => {
63
+ initSchema();
64
+ runMigrations();
65
+ const db = getDb();
66
+ db.run("DELETE FROM standards");
67
+ // Cleanup tmp
68
+ if (existsSync(TMP_DIR)) {
69
+ rmSync(TMP_DIR, { recursive: true, force: true });
70
+ }
71
+ });
72
+
73
+ // ── getStandardsForSimplify ─────────────────────────────────
74
+
75
+ 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
+
81
+ const backendStds = getStandardsForSimplify("backend");
82
+ expect(backendStds.length).toBe(2);
83
+ expect(backendStds.map(s => s.rule)).toContain("Global rule");
84
+ expect(backendStds.map(s => s.rule)).toContain("Backend rule");
85
+ expect(backendStds.map(s => s.rule)).not.toContain("Frontend rule");
86
+ });
87
+
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" });
91
+
92
+ const allStds = getStandardsForSimplify("all");
93
+ expect(allStds.length).toBe(1);
94
+ expect(allStds[0].rule).toBe("Global rule");
95
+ });
96
+
97
+ it("returns empty array when no standards exist", () => {
98
+ const stds = getStandardsForSimplify("backend");
99
+ expect(stds.length).toBe(0);
100
+ });
101
+
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" });
105
+
106
+ const stds = getStandardsForSimplify("all");
107
+ expect(stds[0].rule).toBe("Required");
108
+ expect(stds[1].rule).toBe("Recommended");
109
+ });
110
+ });
111
+
112
+ // ── formatStandardsBlock ────────────────────────────────────
113
+
114
+ describe("formatStandardsBlock", () => {
115
+ it("formats standards with examples and anti_examples", () => {
116
+ const standards = [
117
+ {
118
+ id: 1,
119
+ category: "code",
120
+ scope: "all",
121
+ rule: "Use function declaration",
122
+ examples: JSON.stringify(["function foo() {}"]),
123
+ anti_examples: JSON.stringify(["const foo = () => {}"]),
124
+ enforcement: "required",
125
+ semantic_query: null,
126
+ },
127
+ ];
128
+
129
+ const block = formatStandardsBlock(standards);
130
+ expect(block).toContain("## Standards do Projeto");
131
+ expect(block).toContain("### Obrigatorios (required)");
132
+ expect(block).toContain("[code] Use function declaration");
133
+ expect(block).toContain("Bom: function foo() {}");
134
+ expect(block).toContain("Ruim: const foo = () => {}");
135
+ });
136
+
137
+ it("formats standards with semantic_query", () => {
138
+ const standards = [
139
+ {
140
+ id: 1,
141
+ category: "practice",
142
+ scope: "all",
143
+ rule: "No console.log in production",
144
+ examples: null,
145
+ anti_examples: null,
146
+ enforcement: "required",
147
+ semantic_query: "console.log statements in non-test files",
148
+ },
149
+ ];
150
+
151
+ const block = formatStandardsBlock(standards);
152
+ expect(block).toContain('Detectar: "console.log statements in non-test files"');
153
+ });
154
+
155
+ it("separates required and recommended sections", () => {
156
+ const standards = [
157
+ {
158
+ id: 1, category: "code", scope: "all", rule: "Required rule",
159
+ examples: null, anti_examples: null, enforcement: "required", semantic_query: null,
160
+ },
161
+ {
162
+ id: 2, category: "code", scope: "all", rule: "Recommended rule",
163
+ examples: null, anti_examples: null, enforcement: "recommended", semantic_query: null,
164
+ },
165
+ ];
166
+
167
+ const block = formatStandardsBlock(standards);
168
+ expect(block).toContain("### Obrigatorios (required)");
169
+ expect(block).toContain("### Recomendados (recommended)");
170
+ expect(block).toContain("Required rule");
171
+ expect(block).toContain("Recommended rule");
172
+ });
173
+
174
+ it("returns empty string when no standards", () => {
175
+ expect(formatStandardsBlock([])).toBe("");
176
+ });
177
+ });
178
+
179
+ // ── buildSimplifyPrompt ─────────────────────────────────────
180
+
181
+ describe("buildSimplifyPrompt", () => {
182
+ it("builds refactor prompt with standards and files", () => {
183
+ insertStandard({
184
+ category: "code",
185
+ scope: "all",
186
+ rule: "Use function declarations",
187
+ examples: JSON.stringify(["function foo() {}"]),
188
+ anti_examples: JSON.stringify(["const foo = () => {}"]),
189
+ });
190
+
191
+ const filePath = createTmpFile("test.ts", "export function hello() {}");
192
+ const files: SimplifyFile[] = [{ path: filePath, action: "created" }];
193
+
194
+ const prompt = buildSimplifyPrompt(files, "all", "refactor");
195
+
196
+ expect(prompt).toContain("## Standards do Projeto");
197
+ expect(prompt).toContain("Use function declarations");
198
+ expect(prompt).toContain("## Arquivos para Simplificar");
199
+ expect(prompt).toContain("(criado)");
200
+ expect(prompt).toContain("## Instrucoes");
201
+ expect(prompt).toContain("Preservem funcionalidade");
202
+ });
203
+
204
+ it("builds audit prompt with analysis-only instructions", () => {
205
+ insertStandard({ category: "code", scope: "all", rule: "Some rule" });
206
+
207
+ const filePath = createTmpFile("test2.ts", "export const x = 1;");
208
+ const files: SimplifyFile[] = [{ path: filePath, action: "modified" }];
209
+
210
+ const prompt = buildSimplifyPrompt(files, "all", "audit");
211
+
212
+ expect(prompt).toContain("NAO aplique mudancas");
213
+ expect(prompt).toContain("reporte oportunidades");
214
+ expect(prompt).toContain("(modificado)");
215
+ });
216
+
217
+ it("handles no standards gracefully", () => {
218
+ const filePath = createTmpFile("test3.ts", "export const y = 2;");
219
+ const files: SimplifyFile[] = [{ path: filePath, action: "created" }];
220
+
221
+ const prompt = buildSimplifyPrompt(files, "all", "refactor");
222
+
223
+ // Should still have files and instructions sections
224
+ expect(prompt).toContain("## Arquivos para Simplificar");
225
+ expect(prompt).toContain("## Instrucoes");
226
+ // Should NOT have standards section
227
+ expect(prompt).not.toContain("## Standards do Projeto");
228
+ });
229
+
230
+ it("filters out non-existing files", () => {
231
+ const filePath = createTmpFile("exists.ts", "export const z = 3;");
232
+ const files: SimplifyFile[] = [
233
+ { path: filePath, action: "created" },
234
+ { path: "/nonexistent/file.ts", action: "modified" },
235
+ ];
236
+
237
+ const prompt = buildSimplifyPrompt(files, "all", "refactor");
238
+
239
+ expect(prompt).toContain("exists.ts");
240
+ expect(prompt).not.toContain("nonexistent");
241
+ });
242
+
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" });
246
+
247
+ const filePath = createTmpFile("test4.ts", "export const a = 1;");
248
+ const files: SimplifyFile[] = [{ path: filePath, action: "created" }];
249
+
250
+ const prompt = buildSimplifyPrompt(files, "backend", "refactor");
251
+
252
+ expect(prompt).toContain("Backend only rule");
253
+ expect(prompt).not.toContain("Frontend only rule");
254
+ });
255
+ });
256
+ });
@@ -0,0 +1,198 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // SIMPLIFY PROMPT BUILDER (v10.1)
3
+ // Builds rich simplification prompts using Codexa standards
4
+ // from SQLite. Generates context files for the simplifier agent.
5
+ // ═══════════════════════════════════════════════════════════════
6
+
7
+ import { getDb } from "../db/connection";
8
+ import { existsSync } from "fs";
9
+ import { resolve, join } from "path";
10
+ import { ensureContextDir } from "../context/file-writer";
11
+
12
+ // ═══════════════════════════════════════════════════════════════
13
+ // INTERFACES
14
+ // ═══════════════════════════════════════════════════════════════
15
+
16
+ interface StandardRow {
17
+ id: number;
18
+ category: string;
19
+ scope: string;
20
+ rule: string;
21
+ examples: string | null;
22
+ anti_examples: string | null;
23
+ enforcement: string;
24
+ semantic_query: string | null;
25
+ }
26
+
27
+ export interface SimplifyFile {
28
+ path: string;
29
+ action: "created" | "modified";
30
+ }
31
+
32
+ export type SimplifyMode = "refactor" | "audit";
33
+
34
+ // ═══════════════════════════════════════════════════════════════
35
+ // STANDARDS RETRIEVAL
36
+ // ═══════════════════════════════════════════════════════════════
37
+
38
+ export function getStandardsForSimplify(agentDomain: string): StandardRow[] {
39
+ const db = getDb();
40
+ return db
41
+ .query(
42
+ `SELECT id, category, scope, rule, examples, anti_examples, enforcement, semantic_query
43
+ FROM standards
44
+ WHERE (scope = 'all' OR scope = ?)
45
+ ORDER BY enforcement DESC, category`
46
+ )
47
+ .all(agentDomain) as StandardRow[];
48
+ }
49
+
50
+ // ═══════════════════════════════════════════════════════════════
51
+ // STANDARDS FORMATTING
52
+ // ═══════════════════════════════════════════════════════════════
53
+
54
+ export function formatStandardsBlock(standards: StandardRow[]): string {
55
+ if (standards.length === 0) return "";
56
+
57
+ const required = standards.filter(s => s.enforcement === "required");
58
+ const recommended = standards.filter(s => s.enforcement === "recommended");
59
+
60
+ let block = "## Standards do Projeto\n";
61
+
62
+ if (required.length > 0) {
63
+ block += "\n### Obrigatorios (required)\n";
64
+ block += formatStandardsList(required);
65
+ }
66
+
67
+ if (recommended.length > 0) {
68
+ block += "\n### Recomendados (recommended)\n";
69
+ block += formatStandardsList(recommended);
70
+ }
71
+
72
+ return block;
73
+ }
74
+
75
+ function formatStandardsList(standards: StandardRow[]): string {
76
+ let result = "";
77
+
78
+ for (const std of standards) {
79
+ result += `\n- [${std.category}] ${std.rule}`;
80
+
81
+ // Add good examples
82
+ const examples = parseJsonArray(std.examples);
83
+ if (examples.length > 0) {
84
+ for (const ex of examples.slice(0, 2)) {
85
+ result += `\n Bom: ${ex}`;
86
+ }
87
+ }
88
+
89
+ // Add bad examples (anti-patterns)
90
+ const antiExamples = parseJsonArray(std.anti_examples);
91
+ if (antiExamples.length > 0) {
92
+ for (const anti of antiExamples.slice(0, 2)) {
93
+ result += `\n Ruim: ${anti}`;
94
+ }
95
+ }
96
+
97
+ // Add semantic detection hint
98
+ if (std.semantic_query) {
99
+ result += `\n Detectar: "${std.semantic_query}"`;
100
+ }
101
+ }
102
+
103
+ return result + "\n";
104
+ }
105
+
106
+ function parseJsonArray(json: string | null): string[] {
107
+ if (!json) return [];
108
+ try {
109
+ const parsed = JSON.parse(json);
110
+ return Array.isArray(parsed) ? parsed : [];
111
+ } catch {
112
+ return [];
113
+ }
114
+ }
115
+
116
+ // ═══════════════════════════════════════════════════════════════
117
+ // PROMPT BUILDER
118
+ // ═══════════════════════════════════════════════════════════════
119
+
120
+ export function buildSimplifyPrompt(
121
+ files: SimplifyFile[],
122
+ agentDomain: string,
123
+ mode: SimplifyMode
124
+ ): string {
125
+ const standards = getStandardsForSimplify(agentDomain);
126
+ const existingFiles = files.filter(f => existsSync(f.path));
127
+
128
+ let prompt = "";
129
+
130
+ // Standards section
131
+ const standardsBlock = formatStandardsBlock(standards);
132
+ if (standardsBlock) {
133
+ prompt += standardsBlock + "\n";
134
+ }
135
+
136
+ // Files section
137
+ prompt += "## Arquivos para Simplificar\n\n";
138
+ if (existingFiles.length === 0) {
139
+ prompt += "Nenhum arquivo encontrado.\n";
140
+ } else {
141
+ for (const file of existingFiles) {
142
+ prompt += `- \`${file.path}\` (${file.action === "created" ? "criado" : "modificado"})\n`;
143
+ }
144
+ }
145
+
146
+ // Instructions section
147
+ prompt += "\n## Instrucoes\n\n";
148
+
149
+ if (mode === "refactor") {
150
+ prompt += `Voce e um especialista em simplificacao de codigo. Analise os arquivos listados e aplique refinamentos que:
151
+
152
+ 1. **Preservem funcionalidade**: Nunca altere o que o codigo faz — apenas como faz.
153
+ 2. **Sigam os standards acima**: Aplique todas as regras obrigatorias. Considere as recomendadas.
154
+ 3. **Melhorem clareza**: Reduza complexidade, nesting, redundancias, abstracoes desnecessarias.
155
+ 4. **Mantenham equilibrio**: Evite over-simplificacao. Codigo explicito > codigo compacto.
156
+ 5. **Foquem no escopo**: Apenas refine os arquivos listados.
157
+
158
+ Apos simplificar, liste as mudancas significativas realizadas.`;
159
+ } else {
160
+ prompt += `Voce e um especialista em simplificacao de codigo. Analise os arquivos listados e reporte oportunidades de simplificacao.
161
+
162
+ **NAO aplique mudancas.** Apenas gere um relatorio com:
163
+
164
+ 1. **Oportunidades por arquivo**: Liste cada oportunidade com severidade (alta/media/baixa).
165
+ 2. **Violacoes de standards**: Identifique codigo que viola os standards obrigatorios acima.
166
+ 3. **Over-engineering**: Identifique abstracoes desnecessarias, complexidade excessiva.
167
+ 4. **Resumo**: Contagem de oportunidades por severidade.
168
+
169
+ Formato do relatorio:
170
+ \`\`\`
171
+ ### <arquivo>
172
+ - [alta] <descricao da oportunidade>
173
+ - [media] <descricao>
174
+ - [baixa] <descricao>
175
+
176
+ ### Resumo
177
+ - Alta: N oportunidades
178
+ - Media: N oportunidades
179
+ - Baixa: N oportunidades
180
+ \`\`\``;
181
+ }
182
+
183
+ return prompt;
184
+ }
185
+
186
+ // ═══════════════════════════════════════════════════════════════
187
+ // CONTEXT FILE WRITER
188
+ // ═══════════════════════════════════════════════════════════════
189
+
190
+ export function writeSimplifyContext(
191
+ identifier: string,
192
+ content: string
193
+ ): string {
194
+ const dir = ensureContextDir();
195
+ const filePath = join(dir, `simplify-${identifier}.md`);
196
+ Bun.write(filePath, content);
197
+ return resolve(filePath);
198
+ }