@dewtech/dare-cli 2.16.0 → 2.17.0

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.
Files changed (86) hide show
  1. package/README.md +98 -0
  2. package/dist/__tests__/refine.test.d.ts +2 -0
  3. package/dist/__tests__/refine.test.d.ts.map +1 -0
  4. package/dist/__tests__/refine.test.js +186 -0
  5. package/dist/__tests__/refine.test.js.map +1 -0
  6. package/dist/__tests__/review.test.d.ts +2 -0
  7. package/dist/__tests__/review.test.d.ts.map +1 -0
  8. package/dist/__tests__/review.test.js +242 -0
  9. package/dist/__tests__/review.test.js.map +1 -0
  10. package/dist/__tests__/update.test.d.ts +2 -0
  11. package/dist/__tests__/update.test.d.ts.map +1 -0
  12. package/dist/__tests__/update.test.js +150 -0
  13. package/dist/__tests__/update.test.js.map +1 -0
  14. package/dist/bin/dare.js +6 -0
  15. package/dist/bin/dare.js.map +1 -1
  16. package/dist/commands/execute.d.ts.map +1 -1
  17. package/dist/commands/execute.js +76 -0
  18. package/dist/commands/execute.js.map +1 -1
  19. package/dist/commands/refine.d.ts +16 -0
  20. package/dist/commands/refine.d.ts.map +1 -0
  21. package/dist/commands/refine.js +167 -0
  22. package/dist/commands/refine.js.map +1 -0
  23. package/dist/commands/review.d.ts +16 -0
  24. package/dist/commands/review.d.ts.map +1 -0
  25. package/dist/commands/review.js +106 -0
  26. package/dist/commands/review.js.map +1 -0
  27. package/dist/commands/update.d.ts +13 -0
  28. package/dist/commands/update.d.ts.map +1 -0
  29. package/dist/commands/update.js +149 -0
  30. package/dist/commands/update.js.map +1 -0
  31. package/dist/types/Refine.types.d.ts +96 -0
  32. package/dist/types/Refine.types.d.ts.map +1 -0
  33. package/dist/types/Refine.types.js +19 -0
  34. package/dist/types/Refine.types.js.map +1 -0
  35. package/dist/types/Review.types.d.ts +86 -0
  36. package/dist/types/Review.types.d.ts.map +1 -0
  37. package/dist/types/Review.types.js +15 -0
  38. package/dist/types/Review.types.js.map +1 -0
  39. package/dist/types/UpdateManifest.types.d.ts +91 -0
  40. package/dist/types/UpdateManifest.types.d.ts.map +1 -0
  41. package/dist/types/UpdateManifest.types.js +13 -0
  42. package/dist/types/UpdateManifest.types.js.map +1 -0
  43. package/dist/utils/ReviewRunner.d.ts +42 -0
  44. package/dist/utils/ReviewRunner.d.ts.map +1 -0
  45. package/dist/utils/ReviewRunner.js +175 -0
  46. package/dist/utils/ReviewRunner.js.map +1 -0
  47. package/dist/utils/UpdateApplier.d.ts +42 -0
  48. package/dist/utils/UpdateApplier.d.ts.map +1 -0
  49. package/dist/utils/UpdateApplier.js +207 -0
  50. package/dist/utils/UpdateApplier.js.map +1 -0
  51. package/dist/utils/UpdateDetector.d.ts +56 -0
  52. package/dist/utils/UpdateDetector.d.ts.map +1 -0
  53. package/dist/utils/UpdateDetector.js +164 -0
  54. package/dist/utils/UpdateDetector.js.map +1 -0
  55. package/dist/utils/complexity-analyzer.d.ts +60 -0
  56. package/dist/utils/complexity-analyzer.d.ts.map +1 -0
  57. package/dist/utils/complexity-analyzer.js +292 -0
  58. package/dist/utils/complexity-analyzer.js.map +1 -0
  59. package/dist/utils/project-generator.d.ts.map +1 -1
  60. package/dist/utils/project-generator.js +21 -2
  61. package/dist/utils/project-generator.js.map +1 -1
  62. package/dist/utils/static-analyzer.d.ts +29 -0
  63. package/dist/utils/static-analyzer.d.ts.map +1 -0
  64. package/dist/utils/static-analyzer.js +390 -0
  65. package/dist/utils/static-analyzer.js.map +1 -0
  66. package/dist/utils/version-compare.d.ts +27 -0
  67. package/dist/utils/version-compare.d.ts.map +1 -0
  68. package/dist/utils/version-compare.js +47 -0
  69. package/dist/utils/version-compare.js.map +1 -0
  70. package/package.json +1 -1
  71. package/templates/UPDATE-MANIFEST.json +48 -0
  72. package/templates/ide/antigravity/.agents/skills/dare-blueprint/SKILL.md +180 -36
  73. package/templates/ide/antigravity/.agents/skills/dare-refine/SKILL.md +114 -0
  74. package/templates/ide/antigravity/.agents/skills/dare-review/SKILL.md +111 -0
  75. package/templates/ide/antigravity/.agents/skills/dare-tasks/SKILL.md +41 -0
  76. package/templates/ide/antigravity/templates/TASK-SPEC-template.md +45 -4
  77. package/templates/ide/claude/.claude/commands/dare-blueprint.md +56 -0
  78. package/templates/ide/claude/.claude/commands/dare-dag-build.md +41 -0
  79. package/templates/ide/claude/.claude/commands/dare-refine.md +145 -0
  80. package/templates/ide/claude/.claude/commands/dare-review.md +113 -0
  81. package/templates/ide/claude/templates/TASK-SPEC-template.md +45 -4
  82. package/templates/ide/cursor/.cursor/commands/generate-blueprint.md +45 -0
  83. package/templates/ide/cursor/.cursor/commands/generate-tasks.md +42 -0
  84. package/templates/ide/cursor/.cursor/commands/refine-task.md +107 -0
  85. package/templates/ide/cursor/.cursor/commands/review-task.md +91 -0
  86. package/templates/ide/cursor/templates/TASK-SPEC-template.md +45 -4
package/README.md CHANGED
@@ -375,6 +375,104 @@ of each canonical DARE artifact, active GraphRAG backend, and task progress.
375
375
  dare info
376
376
  ```
377
377
 
378
+ ### `dare review` ← new in v2.17.0
379
+
380
+ **Anti-stub gate.** Audita os arquivos que uma task tocou e detecta padrões de "fake completeness": `TODO`/`FIXME`, stubs (`throw new Error('not implemented')`, `todo!()`, `NotImplementedError`), funções vazias, retorno-fantasma (`return null` como única statement), mocks fora de testes (`jest.fn`, `vi.mock`, `sinon.stub`, `MagicMock`), comentários-placeholder (`// implement later`).
381
+
382
+ A camada estática (regex, determinística) é só metade. A IDE agent pode rodar a skill `dare-review` / `review-task` para validar critério-a-critério se a implementação atende a spec, emitir um `SemanticVerdict` JSON, e o CLI funde os dois numa única decisão.
383
+
384
+ ```bash
385
+ # Audita os arquivos listados em DARE/EXECUTION/task-034.md
386
+ dare review task-034
387
+
388
+ # Em CI:
389
+ dare review task-034 --strict --format json
390
+
391
+ # Lista explícita de arquivos:
392
+ dare review task-034 --files src/auth/login.ts src/auth/register.ts
393
+
394
+ # Funde com verdito semântico do agente:
395
+ dare review task-034 --from-agent .dare/verdict-task-034.json
396
+ ```
397
+
398
+ **Gate opt-in no Ralph Loop:** com `review.onComplete: true` em `dare.config.json`, `dare execute --complete <id>` bloqueia DONE se a review falhar. Para projetos novos (`dare init` v2.17+) já vem ligado; projetos legados permanecem off até o dev flipar.
399
+
400
+ ### `dare refine` ← new in v2.17.0
401
+
402
+ **Anti-monstro.** Mede complexidade de uma task e, opcionalmente, propõe quebra em sub-tasks menores. Heurística determinística pesa # arquivos, # funções/endpoints, # testes, # dependências, keywords "pesadas" (refactor/migrate/integrate/multiple) — produz um score em LOW (0–5) / MED (6–12) / HIGH (13–20) / CRITICAL (21+).
403
+
404
+ ```bash
405
+ # Apenas mede e reporta:
406
+ dare refine task-034
407
+
408
+ # Mede + propõe quebra em sub-tasks (task-034a, task-034b, ...):
409
+ dare refine task-034 --split
410
+
411
+ # Anota TASKS.md marcando a task para split (o agente regenera as specs):
412
+ dare refine task-034 --split --apply
413
+
414
+ # Em CI: exit code 2 se HIGH/CRITICAL:
415
+ dare refine task-034 --strict
416
+ ```
417
+
418
+ A camada determinística agrupa arquivos por diretório raiz. A IDE agent (skills `dare-refine` / `refine-task`) refina o split semanticamente — por camada (Model/Controller/Service), por endpoint, por feature, refactor-then-feature, migration-then-code.
419
+
420
+ Thresholds configuráveis em `dare.config.json`:
421
+
422
+ ```jsonc
423
+ {
424
+ "refine": {
425
+ "thresholds": { "low": 5, "med": 12, "high": 20 }
426
+ }
427
+ }
428
+ ```
429
+
430
+ ### `dare update` ← new in v2.17.0
431
+
432
+ Sync the **project's DARE setup** (templates, slash commands, skills, schema)
433
+ with the version of the CLI currently installed. Useful when you upgrade the
434
+ CLI globally (`npm install -g @dewtech/dare-cli@latest`) and want a previous
435
+ project to pick up the new improvements — **without touching your DESIGN /
436
+ BLUEPRINT / TASKS / dare-dag.yaml artifacts**.
437
+
438
+ Different from upgrading the CLI itself: `npm update -g @dewtech/dare-cli`
439
+ changes the binary on your machine; `dare update` changes the *project files
440
+ on disk* to match what that binary now ships.
441
+
442
+ ```bash
443
+ dare update # interactive (recommended)
444
+ dare update --dry-run # preview: shows changelog + affected files, writes nothing
445
+ dare update --yes # CI: apply, preserve customizations, no prompts
446
+ dare update --force # also overwrite files the dev customized (dangerous)
447
+ dare update --target 2.17.0 # update to a specific release instead of the installed CLI
448
+ ```
449
+
450
+ **What it does:**
451
+
452
+ 1. Reads `version` from `dare.config.json` (the project's last-known DARE version).
453
+ 2. Loads `templates/UPDATE-MANIFEST.json` (ships with the CLI) and lists every
454
+ release between the project's version and the CLI's version.
455
+ 3. Prints the changelog for each pending release and the list of files
456
+ affected for your IDE (cursor / claude-code / antigravity / hybrid).
457
+ 4. For each file, classifies the situation:
458
+ - **identical** → skip
459
+ - **missing** → create
460
+ - **apply** → file matches the previous template hash, safe to overwrite
461
+ - **customized** → file diverges from the previous template; prompt
462
+ (`keep` / `replace`) unless `--yes` (keep) or `--force` (replace).
463
+ 5. Backs up every affected file to `.dare/backup-<from-version>/` before
464
+ writing.
465
+ 6. Runs any schema migrations declared by the release (e.g. renaming a
466
+ config field).
467
+ 7. Stamps `version` and `updatedAt` in `dare.config.json`.
468
+
469
+ **Adding entries when you cut a release:** each new CLI version that ships
470
+ template changes needs a corresponding entry in `templates/UPDATE-MANIFEST.json`
471
+ listing `changes` (added / modified / removed / renamed) and optional
472
+ `migrations`. The applier filters changes by `appliesTo: [ide]`, so a
473
+ template that's cursor-only won't be installed in a Claude Code project and
474
+ vice versa.
475
+
378
476
  ### `dare validate`
379
477
 
380
478
  Static checks on `dare-dag.yaml` — ideal for pre-commit hooks and CI.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=refine.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refine.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/refine.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,186 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+ import os from 'os';
5
+ import { analyzeTaskComplexity, proposeSplit, levelFromScore, } from '../utils/complexity-analyzer.js';
6
+ async function makeTempDir() {
7
+ return fs.mkdtemp(path.join(os.tmpdir(), 'dare-refine-test-'));
8
+ }
9
+ async function writeFile(dir, rel, content) {
10
+ const abs = path.join(dir, rel);
11
+ await fs.ensureDir(path.dirname(abs));
12
+ await fs.writeFile(abs, content);
13
+ }
14
+ // ── levelFromScore ────────────────────────────────────────────────────────────
15
+ describe('levelFromScore', () => {
16
+ it('maps scores to default buckets', () => {
17
+ expect(levelFromScore(0)).toBe('LOW');
18
+ expect(levelFromScore(5)).toBe('LOW');
19
+ expect(levelFromScore(6)).toBe('MED');
20
+ expect(levelFromScore(12)).toBe('MED');
21
+ expect(levelFromScore(13)).toBe('HIGH');
22
+ expect(levelFromScore(20)).toBe('HIGH');
23
+ expect(levelFromScore(21)).toBe('CRITICAL');
24
+ expect(levelFromScore(50)).toBe('CRITICAL');
25
+ });
26
+ it('respects custom thresholds', () => {
27
+ const t = { low: 2, med: 4, high: 6 };
28
+ expect(levelFromScore(2, t)).toBe('LOW');
29
+ expect(levelFromScore(3, t)).toBe('MED');
30
+ expect(levelFromScore(4, t)).toBe('MED');
31
+ expect(levelFromScore(5, t)).toBe('HIGH');
32
+ expect(levelFromScore(6, t)).toBe('HIGH');
33
+ expect(levelFromScore(7, t)).toBe('CRITICAL');
34
+ });
35
+ });
36
+ // ── analyzeTaskComplexity ─────────────────────────────────────────────────────
37
+ describe('analyzeTaskComplexity', () => {
38
+ let tmp;
39
+ beforeEach(async () => {
40
+ tmp = await makeTempDir();
41
+ });
42
+ afterEach(async () => {
43
+ await fs.remove(tmp);
44
+ });
45
+ it('returns no-spec signal when spec is missing', async () => {
46
+ const r = await analyzeTaskComplexity('task-ghost', tmp);
47
+ expect(r).not.toBeNull();
48
+ expect(r?.specPath).toBeNull();
49
+ expect(r?.signals[0].kind).toBe('no-spec');
50
+ });
51
+ it('scores a tiny task as LOW', async () => {
52
+ await writeFile(tmp, 'DARE/EXECUTION/task-001.md', `
53
+ # Task 001
54
+
55
+ ## 3. Arquivos
56
+
57
+ | Ação | Caminho |
58
+ |------|---------|
59
+ | CRIAR | \`src/foo.ts\` |
60
+
61
+ ## 4. Implementação
62
+
63
+ - [ ] Teste do caminho feliz
64
+ `);
65
+ const r = await analyzeTaskComplexity('task-001', tmp);
66
+ expect(r?.level).toBe('LOW');
67
+ expect(r?.recommendsSplit).toBe(false);
68
+ });
69
+ it('scores a big task as HIGH/CRITICAL', async () => {
70
+ await writeFile(tmp, 'DARE/EXECUTION/task-002.md', `
71
+ # Task 002
72
+
73
+ > **Complexidade:** HIGH
74
+
75
+ ## 3. Arquivos
76
+
77
+ | Ação | Caminho |
78
+ |------|---------|
79
+ | CRIAR | \`src/a.ts\` |
80
+ | CRIAR | \`src/b.ts\` |
81
+ | CRIAR | \`src/c.ts\` |
82
+ | CRIAR | \`src/d.ts\` |
83
+ | CRIAR | \`src/e.ts\` |
84
+ | CRIAR | \`src/f.ts\` |
85
+ | CRIAR | \`src/g.ts\` |
86
+ | MODIFICAR | \`tests/a.test.ts\` |
87
+
88
+ ## 4. Implementação
89
+
90
+ Implementar:
91
+ - \`POST /auth/register\`
92
+ - \`POST /auth/login\`
93
+ - \`POST /auth/refresh\`
94
+ - \`POST /auth/logout\`
95
+ - \`GET /auth/me\`
96
+
97
+ Vamos refactor o UserService e migrate o schema para suportar profile_settings.
98
+ Precisamos integrate com o serviço externo de email também.
99
+
100
+ - [ ] Teste do happy path
101
+ - [ ] Teste de email inválido
102
+ - [ ] Teste de senha fraca
103
+ - [ ] Teste de email duplicado
104
+ - [ ] Teste de rate limit
105
+ - [ ] Teste de refresh expirado
106
+ - [ ] Teste de logout idempotente
107
+ `);
108
+ const r = await analyzeTaskComplexity('task-002', tmp);
109
+ expect(['HIGH', 'CRITICAL']).toContain(r?.level);
110
+ expect(r?.recommendsSplit).toBe(true);
111
+ // Should attribute weight to multiple signal kinds
112
+ const kinds = r?.signals.map((s) => s.kind) ?? [];
113
+ expect(kinds).toContain('files');
114
+ expect(kinds).toContain('functions');
115
+ expect(kinds).toContain('tests');
116
+ expect(kinds).toContain('keywords');
117
+ expect(kinds).toContain('author-high');
118
+ });
119
+ it('counts depends_on when caller provides it', async () => {
120
+ await writeFile(tmp, 'DARE/EXECUTION/task-003.md', `## 3. Arquivos\n| CRIAR | \`a.ts\` |`);
121
+ const r0 = await analyzeTaskComplexity('task-003', tmp, { dependsOnCount: 0 });
122
+ const r4 = await analyzeTaskComplexity('task-003', tmp, { dependsOnCount: 4 });
123
+ expect((r4?.score ?? 0)).toBeGreaterThan(r0?.score ?? 0);
124
+ expect(r4?.signals.some((s) => s.kind === 'dependencies')).toBe(true);
125
+ });
126
+ it('honors custom thresholds from options', async () => {
127
+ await writeFile(tmp, 'DARE/EXECUTION/task-004.md', `| CRIAR | \`a.ts\` |\n| CRIAR | \`b.ts\` |`);
128
+ const r = await analyzeTaskComplexity('task-004', tmp, {
129
+ thresholds: { low: 0.5, med: 1, high: 1.5 },
130
+ });
131
+ expect(r?.level).toBe('CRITICAL'); // tiny score still tripped by aggressive thresholds
132
+ });
133
+ });
134
+ // ── proposeSplit ──────────────────────────────────────────────────────────────
135
+ describe('proposeSplit', () => {
136
+ it('returns empty proposal when no files listed', () => {
137
+ const p = proposeSplit('task-001', []);
138
+ expect(p.subtasks).toHaveLength(0);
139
+ expect(p.notes).toContain('Nenhum arquivo listado');
140
+ });
141
+ it('groups by top-level directory', () => {
142
+ const p = proposeSplit('task-002', [
143
+ 'src/auth/login.ts',
144
+ 'src/auth/register.ts',
145
+ 'src/users/profile.ts',
146
+ 'tests/auth/login.test.ts',
147
+ ]);
148
+ // 3 groups: src/auth, src/users, tests/auth
149
+ expect(p.subtasks).toHaveLength(3);
150
+ expect(p.subtasks.map((s) => s.id)).toEqual([
151
+ 'task-002a',
152
+ 'task-002b',
153
+ 'task-002c',
154
+ ]);
155
+ });
156
+ it('splits overlarge groups by maxFilesPerSubtask', () => {
157
+ const files = Array.from({ length: 9 }, (_, i) => `src/auth/file${i}.ts`);
158
+ const p = proposeSplit('task-003', files, { maxFilesPerSubtask: 3 });
159
+ // 9 files / 3 per chunk = 3 chunks (all from same group)
160
+ expect(p.subtasks).toHaveLength(3);
161
+ expect(p.subtasks.every((s) => s.files.length <= 3)).toBe(true);
162
+ });
163
+ it('assigns sequential letter suffixes', () => {
164
+ const p = proposeSplit('task-004', [
165
+ 'a/one.ts',
166
+ 'b/one.ts',
167
+ 'c/one.ts',
168
+ 'd/one.ts',
169
+ ]);
170
+ const ids = p.subtasks.map((s) => s.id);
171
+ expect(ids[0]).toBe('task-004a');
172
+ expect(ids[1]).toBe('task-004b');
173
+ expect(ids[2]).toBe('task-004c');
174
+ expect(ids[3]).toBe('task-004d');
175
+ });
176
+ it('preserves files within each sub-task', () => {
177
+ const p = proposeSplit('task-005', [
178
+ 'src/auth/a.ts',
179
+ 'src/auth/b.ts',
180
+ 'src/users/c.ts',
181
+ ]);
182
+ const authSub = p.subtasks.find((s) => s.title.includes('src/auth'));
183
+ expect(authSub?.files).toEqual(['src/auth/a.ts', 'src/auth/b.ts']);
184
+ });
185
+ });
186
+ //# sourceMappingURL=refine.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refine.test.js","sourceRoot":"","sources":["../../src/__tests__/refine.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=review.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/review.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,242 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+ import os from 'os';
5
+ import { analyzeFile, isTestFile, runStaticAnalysis, } from '../utils/static-analyzer.js';
6
+ import { parseFilesFromSpec, runReview, } from '../utils/ReviewRunner.js';
7
+ // Temp dir helper — each test gets its own sandbox.
8
+ async function makeTempDir() {
9
+ return fs.mkdtemp(path.join(os.tmpdir(), 'dare-review-test-'));
10
+ }
11
+ async function writeFile(dir, rel, content) {
12
+ const abs = path.join(dir, rel);
13
+ await fs.ensureDir(path.dirname(abs));
14
+ await fs.writeFile(abs, content);
15
+ }
16
+ // ── isTestFile ────────────────────────────────────────────────────────────────
17
+ describe('isTestFile', () => {
18
+ it('matches *.test.ts', () => {
19
+ expect(isTestFile('src/foo.test.ts')).toBe(true);
20
+ expect(isTestFile('src/foo.spec.ts')).toBe(true);
21
+ });
22
+ it('matches __tests__ directories', () => {
23
+ expect(isTestFile('src/__tests__/foo.ts')).toBe(true);
24
+ expect(isTestFile('src\\__tests__\\foo.ts')).toBe(true);
25
+ });
26
+ it('matches Go/Python test conventions', () => {
27
+ expect(isTestFile('pkg/auth/auth_test.go')).toBe(true);
28
+ expect(isTestFile('tests/test_auth.py')).toBe(true);
29
+ });
30
+ it('rejects production files', () => {
31
+ expect(isTestFile('src/auth/login.ts')).toBe(false);
32
+ expect(isTestFile('src/controllers/users.go')).toBe(false);
33
+ });
34
+ });
35
+ // ── parseFilesFromSpec ────────────────────────────────────────────────────────
36
+ describe('parseFilesFromSpec', () => {
37
+ it('extracts files from a CRIAR/MODIFICAR table', () => {
38
+ const md = `
39
+ ## 3. ARQUIVOS
40
+
41
+ | Ação | Caminho | Descrição |
42
+ |------|---------|-----------|
43
+ | CRIAR | \`src/auth/login.ts\` | Login handler |
44
+ | MODIFICAR | \`src/routes.ts\` | Wire route |
45
+ | CRIAR | \`tests/auth.test.ts\` | Tests |
46
+ `;
47
+ expect(parseFilesFromSpec(md)).toEqual([
48
+ 'src/auth/login.ts',
49
+ 'src/routes.ts',
50
+ 'tests/auth.test.ts',
51
+ ]);
52
+ });
53
+ it('accepts English actions too', () => {
54
+ const md = `
55
+ | Action | Path |
56
+ | CREATE | \`a.ts\` |
57
+ | MODIFY | \`b.ts\` |
58
+ | UPDATE | \`c.ts\` |
59
+ `;
60
+ expect(parseFilesFromSpec(md)).toEqual(['a.ts', 'b.ts', 'c.ts']);
61
+ });
62
+ it('de-duplicates paths', () => {
63
+ const md = `
64
+ | MODIFICAR | \`src/a.ts\` |
65
+ | MODIFICAR | \`src/a.ts\` |
66
+ `;
67
+ expect(parseFilesFromSpec(md)).toEqual(['src/a.ts']);
68
+ });
69
+ it('ignores rows without a backtick path', () => {
70
+ const md = `
71
+ | CRIAR | descrição sem path | x |
72
+ | MODIFICAR | \`src/real.ts\` | x |
73
+ `;
74
+ expect(parseFilesFromSpec(md)).toEqual(['src/real.ts']);
75
+ });
76
+ });
77
+ // ── Static analyzer detectors ─────────────────────────────────────────────────
78
+ describe('static-analyzer: detectors', () => {
79
+ let tmp;
80
+ beforeEach(async () => {
81
+ tmp = await makeTempDir();
82
+ });
83
+ afterEach(async () => {
84
+ await fs.remove(tmp);
85
+ });
86
+ async function analyze(rel, content) {
87
+ await writeFile(tmp, rel, content);
88
+ return analyzeFile(path.join(tmp, rel), rel);
89
+ }
90
+ function kinds(report) {
91
+ return report.violations.map((v) => v.kind);
92
+ }
93
+ it('detects TODO/FIXME/XXX/HACK in comments', async () => {
94
+ const r = await analyze('src/a.ts', `// TODO: implement\nconst x = 1; // FIXME later\n// XXX broken\n/* HACK */`);
95
+ const found = kinds(r);
96
+ expect(found.filter((k) => k === 'todo-marker').length).toBeGreaterThanOrEqual(4);
97
+ });
98
+ it('ignores TODO inside string literals', async () => {
99
+ const r = await analyze('src/a.ts', `const msg = "TODO: not a real comment";\nconst real = 1;`);
100
+ expect(kinds(r)).not.toContain('todo-marker');
101
+ });
102
+ it('detects throw new Error("not implemented") and friends', async () => {
103
+ const r = await analyze('src/b.ts', `function x() { throw new Error('not implemented'); }\nfunction y() { throw new Error('todo'); }`);
104
+ const stubs = r.violations.filter((v) => v.kind === 'not-implemented-stub');
105
+ expect(stubs.length).toBeGreaterThanOrEqual(2);
106
+ });
107
+ it('detects Rust unimplemented!() and todo!()', async () => {
108
+ const r = await analyze('src/lib.rs', `fn a() { unimplemented!() }\nfn b() { todo!() }`);
109
+ expect(kinds(r)).toContain('not-implemented-stub');
110
+ });
111
+ it('detects Python raise NotImplementedError', async () => {
112
+ const r = await analyze('src/x.py', `def foo():\n raise NotImplementedError\n`);
113
+ expect(kinds(r)).toContain('not-implemented-stub');
114
+ });
115
+ it('detects empty function single-line (TS)', async () => {
116
+ const r = await analyze('src/c.ts', `function foo() {}\nconst bar = () => {};\nfunction baz() { /* real */ return 1; }`);
117
+ const empties = r.violations.filter((v) => v.kind === 'empty-function');
118
+ expect(empties.length).toBeGreaterThanOrEqual(1);
119
+ });
120
+ it('detects empty multi-line function (TS)', async () => {
121
+ const r = await analyze('src/d.ts', `function alpha() {\n}\nfunction beta() {\n const x = 1;\n return x;\n}`);
122
+ const empties = r.violations.filter((v) => v.kind === 'empty-function');
123
+ expect(empties.length).toBe(1);
124
+ });
125
+ it('detects Python def x(): pass', async () => {
126
+ const r = await analyze('src/e.py', `def foo():\n pass\n`);
127
+ expect(kinds(r)).toContain('empty-function');
128
+ });
129
+ it('detects phantom returns (only stmt is return null)', async () => {
130
+ const r = await analyze('src/f.ts', `function getUser(id: string) {\n return null;\n}\nfunction getOther() {\n const x = compute();\n return x;\n}`);
131
+ const phantoms = r.violations.filter((v) => v.kind === 'phantom-return');
132
+ expect(phantoms.length).toBe(1);
133
+ });
134
+ it('detects placeholder comments', async () => {
135
+ const r = await analyze('src/g.ts', `// implement later\n// stub\n# placeholder\n// fixme implement\nconst real = 1;`);
136
+ const placeholders = r.violations.filter((v) => v.kind === 'placeholder-comment');
137
+ expect(placeholders.length).toBeGreaterThanOrEqual(3);
138
+ });
139
+ it('detects production mocks (jest.fn, sinon.stub, vi.mock)', async () => {
140
+ const r = await analyze('src/h.ts', `const x = jest.fn();\nconst y = sinon.stub();\nvi.mock('foo');`);
141
+ const mocks = r.violations.filter((v) => v.kind === 'production-mock');
142
+ expect(mocks.length).toBeGreaterThanOrEqual(3);
143
+ });
144
+ it('does NOT flag mocks in test files', async () => {
145
+ const r = await analyze('src/h.test.ts', `const x = jest.fn();\nvi.mock('foo');`);
146
+ expect(r.isTestFile).toBe(true);
147
+ expect(kinds(r)).not.toContain('production-mock');
148
+ });
149
+ it('runs clean on a real-looking implementation', async () => {
150
+ const r = await analyze('src/auth/login.ts', `
151
+ import { hash } from 'crypto';
152
+
153
+ export async function login(email: string, password: string) {
154
+ if (!email || !password) {
155
+ throw new Error('email and password are required');
156
+ }
157
+ const user = await db.users.findOne({ email });
158
+ if (!user) return { ok: false, code: 401 };
159
+ const ok = await verify(user.passwordHash, password);
160
+ if (!ok) return { ok: false, code: 401 };
161
+ return { ok: true, token: signToken(user.id) };
162
+ }
163
+ `.trim());
164
+ expect(r.violations).toEqual([]);
165
+ });
166
+ });
167
+ // ── runStaticAnalysis + runReview end-to-end ──────────────────────────────────
168
+ describe('runStaticAnalysis', () => {
169
+ let tmp;
170
+ beforeEach(async () => {
171
+ tmp = await makeTempDir();
172
+ });
173
+ afterEach(async () => {
174
+ await fs.remove(tmp);
175
+ });
176
+ it('scans multiple files in parallel', async () => {
177
+ await writeFile(tmp, 'src/a.ts', `function x() {} // empty`);
178
+ await writeFile(tmp, 'src/b.ts', `// TODO\nconst y = 1;`);
179
+ await writeFile(tmp, 'src/c.ts', `export const PI = 3.14;`);
180
+ const reports = await runStaticAnalysis(tmp, ['src/a.ts', 'src/b.ts', 'src/c.ts']);
181
+ expect(reports).toHaveLength(3);
182
+ expect(reports[0].violations.length).toBeGreaterThan(0);
183
+ expect(reports[1].violations.length).toBeGreaterThan(0);
184
+ expect(reports[2].violations).toEqual([]);
185
+ });
186
+ it('returns clean report for missing files', async () => {
187
+ const reports = await runStaticAnalysis(tmp, ['does/not/exist.ts']);
188
+ expect(reports[0].violations).toEqual([]);
189
+ });
190
+ });
191
+ describe('runReview end-to-end', () => {
192
+ let tmp;
193
+ beforeEach(async () => {
194
+ tmp = await makeTempDir();
195
+ });
196
+ afterEach(async () => {
197
+ await fs.remove(tmp);
198
+ });
199
+ it('parses spec, scans listed files, fails on errors', async () => {
200
+ await writeFile(tmp, 'DARE/EXECUTION/task-001.md', `
201
+ ## 3. ARQUIVOS
202
+
203
+ | Ação | Caminho | Descrição |
204
+ |------|---------|-----------|
205
+ | CRIAR | \`src/foo.ts\` | Foo handler |
206
+ `);
207
+ await writeFile(tmp, 'src/foo.ts', `function foo() { throw new Error('not implemented'); }`);
208
+ const report = await runReview('task-001', { projectRoot: tmp });
209
+ expect(report.taskId).toBe('task-001');
210
+ expect(report.filesScanned).toEqual(['src/foo.ts']);
211
+ expect(report.failed).toBe(true);
212
+ expect(report.totals.errors).toBeGreaterThan(0);
213
+ });
214
+ it('passes when nothing is found', async () => {
215
+ await writeFile(tmp, 'DARE/EXECUTION/task-002.md', `| MODIFICAR | \`src/clean.ts\` | x |`);
216
+ await writeFile(tmp, 'src/clean.ts', `export const X = 1;`);
217
+ const report = await runReview('task-002', { projectRoot: tmp });
218
+ expect(report.failed).toBe(false);
219
+ expect(report.totals.errors).toBe(0);
220
+ });
221
+ it('merges --from-agent semantic verdict', async () => {
222
+ await writeFile(tmp, 'DARE/EXECUTION/task-003.md', `| MODIFICAR | \`src/clean.ts\` | x |`);
223
+ await writeFile(tmp, 'src/clean.ts', `export const X = 1;`);
224
+ await writeFile(tmp, 'verdict.json', JSON.stringify({
225
+ passed: false,
226
+ unmetCriteria: ['Missing password regex'],
227
+ notes: 'Stub-free but spec not satisfied',
228
+ }));
229
+ const report = await runReview('task-003', {
230
+ projectRoot: tmp,
231
+ fromAgent: path.join(tmp, 'verdict.json'),
232
+ });
233
+ expect(report.semantic?.passed).toBe(false);
234
+ expect(report.failed).toBe(true); // semantic failure flips it
235
+ });
236
+ it('returns empty report when no files can be resolved', async () => {
237
+ const report = await runReview('task-ghost', { projectRoot: tmp });
238
+ expect(report.filesScanned).toHaveLength(0);
239
+ expect(report.failed).toBe(false);
240
+ });
241
+ });
242
+ //# sourceMappingURL=review.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.test.js","sourceRoot":"","sources":["../../src/__tests__/review.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=update.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/update.test.ts"],"names":[],"mappings":""}