gsd-pi 2.44.0-dev.62b5d6c → 2.44.0-dev.848dd4c

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 (190) hide show
  1. package/README.md +30 -12
  2. package/dist/resources/extensions/gsd/auto-start.js +10 -0
  3. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
  4. package/dist/web/standalone/.next/BUILD_ID +1 -1
  5. package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -18
  6. package/dist/web/standalone/.next/build-manifest.json +2 -2
  7. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  8. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  9. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  10. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  11. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  12. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  13. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  14. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  15. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  16. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  17. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  18. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  19. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  20. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  21. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  22. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  23. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  24. package/dist/web/standalone/.next/server/app/index.html +1 -1
  25. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  26. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  28. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  30. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  31. package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -18
  32. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  33. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  34. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  35. package/package.json +1 -1
  36. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
  37. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  38. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
  39. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  40. package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
  41. package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
  42. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
  43. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
  44. package/packages/pi-coding-agent/dist/core/session-manager.test.js +30 -34
  45. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  46. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
  47. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
  48. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
  49. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
  50. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
  51. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
  52. package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
  53. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
  54. package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
  55. package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
  56. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
  57. package/src/resources/extensions/gsd/auto-start.ts +14 -0
  58. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
  59. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
  60. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +14 -16
  61. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
  62. package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
  63. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +465 -523
  64. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
  65. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
  66. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +533 -656
  67. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
  68. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
  69. package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
  70. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
  71. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
  72. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
  73. package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
  74. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +38 -59
  75. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +228 -263
  76. package/src/resources/extensions/gsd/tests/complete-task.test.ts +250 -302
  77. package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
  78. package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
  79. package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
  80. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
  81. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
  82. package/src/resources/extensions/gsd/tests/db-writer.test.ts +390 -420
  83. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
  84. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +68 -83
  85. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +152 -183
  86. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
  87. package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
  88. package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
  89. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
  90. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +164 -180
  91. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
  92. package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
  93. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +27 -29
  94. package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
  95. package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +54 -75
  96. package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +21 -32
  97. package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
  98. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +38 -44
  99. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
  100. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
  101. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +54 -60
  102. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
  103. package/src/resources/extensions/gsd/tests/doctor.test.ts +104 -134
  104. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
  105. package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
  106. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
  107. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
  108. package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +30 -42
  109. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +198 -206
  110. package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
  111. package/src/resources/extensions/gsd/tests/git-service.test.ts +285 -388
  112. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
  113. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
  114. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
  115. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
  116. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +81 -103
  117. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
  118. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
  119. package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
  120. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -102
  121. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
  122. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
  123. package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
  124. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
  125. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
  126. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +150 -194
  127. package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
  128. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
  129. package/src/resources/extensions/gsd/tests/memory-store.test.ts +80 -93
  130. package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
  131. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +83 -93
  132. package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
  133. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
  134. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
  135. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +87 -96
  136. package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +125 -164
  137. package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
  138. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +35 -36
  139. package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
  140. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
  141. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
  142. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
  143. package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
  144. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
  145. package/src/resources/extensions/gsd/tests/parsers.test.ts +546 -611
  146. package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
  147. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
  148. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
  149. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
  150. package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
  151. package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
  152. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
  153. package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
  154. package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
  155. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
  156. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
  157. package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
  158. package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
  159. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
  160. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
  161. package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
  162. package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
  163. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
  164. package/src/resources/extensions/gsd/tests/shared-wal.test.ts +19 -26
  165. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
  166. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
  167. package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
  168. package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
  169. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
  170. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +9 -11
  171. package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
  172. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
  173. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
  174. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
  175. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
  176. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
  177. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
  178. package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
  179. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
  180. package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
  181. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
  182. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
  183. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
  184. package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
  185. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
  186. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
  187. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
  188. package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
  189. /package/dist/web/standalone/.next/static/{fOnWQBjWXMKUs4bqTg530 → -zps1Q9mQmioAKLcQiCr8}/_buildManifest.js +0 -0
  190. /package/dist/web/standalone/.next/static/{fOnWQBjWXMKUs4bqTg530 → -zps1Q9mQmioAKLcQiCr8}/_ssgManifest.js +0 -0
@@ -1,4 +1,3 @@
1
- import { createTestContext } from './test-helpers.ts';
2
1
  import {
3
2
  openDatabase,
4
3
  closeDatabase,
@@ -21,94 +20,90 @@ import {
21
20
  formatMemoriesForPrompt,
22
21
  } from '../memory-store.ts';
23
22
  import type { MemoryAction } from '../memory-store.ts';
24
-
25
- const { assertEq, assertTrue, assertMatch, report } = createTestContext();
23
+ import { describe, test, beforeEach, afterEach } from 'node:test';
24
+ import assert from 'node:assert/strict';
26
25
 
27
26
  // ═══════════════════════════════════════════════════════════════════════════
28
27
  // memory-store: fallback when DB not open
29
28
  // ═══════════════════════════════════════════════════════════════════════════
30
29
 
31
- console.log('\n=== memory-store: fallback returns empty when DB not open ===');
32
- {
30
+ test('memory-store: fallback returns empty when DB not open', () => {
33
31
  closeDatabase();
34
- assertTrue(!isDbAvailable(), 'DB should not be available');
32
+ assert.ok(!isDbAvailable(), 'DB should not be available');
35
33
 
36
- assertEq(getActiveMemories(), [], 'getActiveMemories returns [] when DB closed');
37
- assertEq(getActiveMemoriesRanked(), [], 'getActiveMemoriesRanked returns [] when DB closed');
38
- assertEq(nextMemoryId(), 'MEM001', 'nextMemoryId returns MEM001 when DB closed');
39
- assertEq(createMemory({ category: 'test', content: 'test' }), null, 'createMemory returns null when DB closed');
40
- assertTrue(!reinforceMemory('MEM001'), 'reinforceMemory returns false when DB closed');
41
- assertTrue(!isUnitProcessed('test/key'), 'isUnitProcessed returns false when DB closed');
42
- }
34
+ assert.deepStrictEqual(getActiveMemories(), [], 'getActiveMemories returns [] when DB closed');
35
+ assert.deepStrictEqual(getActiveMemoriesRanked(), [], 'getActiveMemoriesRanked returns [] when DB closed');
36
+ assert.deepStrictEqual(nextMemoryId(), 'MEM001', 'nextMemoryId returns MEM001 when DB closed');
37
+ assert.deepStrictEqual(createMemory({ category: 'test', content: 'test' }), null, 'createMemory returns null when DB closed');
38
+ assert.ok(!reinforceMemory('MEM001'), 'reinforceMemory returns false when DB closed');
39
+ assert.ok(!isUnitProcessed('test/key'), 'isUnitProcessed returns false when DB closed');
40
+ });
43
41
 
44
42
  // ═══════════════════════════════════════════════════════════════════════════
45
43
  // memory-store: CRUD operations
46
44
  // ═══════════════════════════════════════════════════════════════════════════
47
45
 
48
- console.log('\n=== memory-store: create and query memories ===');
49
- {
46
+ test('memory-store: create and query memories', () => {
50
47
  openDatabase(':memory:');
51
48
 
52
49
  // Create memories
53
50
  const id1 = createMemory({ category: 'gotcha', content: 'esbuild drops .node binaries' });
54
- assertTrue(id1 !== null, 'createMemory should return an ID');
55
- assertEq(id1, 'MEM001', 'first memory ID should be MEM001');
51
+ assert.ok(id1 !== null, 'createMemory should return an ID');
52
+ assert.deepStrictEqual(id1, 'MEM001', 'first memory ID should be MEM001');
56
53
 
57
54
  const id2 = createMemory({ category: 'convention', content: 'use :memory: for tests', confidence: 0.9 });
58
- assertEq(id2, 'MEM002', 'second memory ID should be MEM002');
55
+ assert.deepStrictEqual(id2, 'MEM002', 'second memory ID should be MEM002');
59
56
 
60
57
  const id3 = createMemory({ category: 'architecture', content: 'extensions discovered from src/resources/' });
61
- assertEq(id3, 'MEM003', 'third memory ID should be MEM003');
58
+ assert.deepStrictEqual(id3, 'MEM003', 'third memory ID should be MEM003');
62
59
 
63
60
  // Query all active
64
61
  const active = getActiveMemories();
65
- assertEq(active.length, 3, 'should have 3 active memories');
66
- assertEq(active[0].category, 'gotcha', 'first memory category');
67
- assertEq(active[0].content, 'esbuild drops .node binaries', 'first memory content');
68
- assertEq(active[1].confidence, 0.9, 'second memory confidence');
62
+ assert.deepStrictEqual(active.length, 3, 'should have 3 active memories');
63
+ assert.deepStrictEqual(active[0].category, 'gotcha', 'first memory category');
64
+ assert.deepStrictEqual(active[0].content, 'esbuild drops .node binaries', 'first memory content');
65
+ assert.deepStrictEqual(active[1].confidence, 0.9, 'second memory confidence');
69
66
 
70
67
  closeDatabase();
71
- }
68
+ });
72
69
 
73
70
  // ═══════════════════════════════════════════════════════════════════════════
74
71
  // memory-store: update and reinforce
75
72
  // ═══════════════════════════════════════════════════════════════════════════
76
73
 
77
- console.log('\n=== memory-store: update and reinforce ===');
78
- {
74
+ test('memory-store: update and reinforce', () => {
79
75
  openDatabase(':memory:');
80
76
 
81
77
  createMemory({ category: 'gotcha', content: 'original content' });
82
78
 
83
79
  // Update content
84
80
  const updated = updateMemoryContent('MEM001', 'revised content', 0.95);
85
- assertTrue(updated, 'updateMemoryContent should return true');
81
+ assert.ok(updated, 'updateMemoryContent should return true');
86
82
 
87
83
  const active = getActiveMemories();
88
- assertEq(active[0].content, 'revised content', 'content should be updated');
89
- assertEq(active[0].confidence, 0.95, 'confidence should be updated');
84
+ assert.deepStrictEqual(active[0].content, 'revised content', 'content should be updated');
85
+ assert.deepStrictEqual(active[0].confidence, 0.95, 'confidence should be updated');
90
86
 
91
87
  // Reinforce
92
88
  const reinforced = reinforceMemory('MEM001');
93
- assertTrue(reinforced, 'reinforceMemory should return true');
89
+ assert.ok(reinforced, 'reinforceMemory should return true');
94
90
 
95
91
  const after = getActiveMemories();
96
- assertEq(after[0].hit_count, 1, 'hit_count should be 1 after reinforce');
92
+ assert.deepStrictEqual(after[0].hit_count, 1, 'hit_count should be 1 after reinforce');
97
93
 
98
94
  // Reinforce again
99
95
  reinforceMemory('MEM001');
100
96
  const after2 = getActiveMemories();
101
- assertEq(after2[0].hit_count, 2, 'hit_count should be 2 after second reinforce');
97
+ assert.deepStrictEqual(after2[0].hit_count, 2, 'hit_count should be 2 after second reinforce');
102
98
 
103
99
  closeDatabase();
104
- }
100
+ });
105
101
 
106
102
  // ═══════════════════════════════════════════════════════════════════════════
107
103
  // memory-store: supersede
108
104
  // ═══════════════════════════════════════════════════════════════════════════
109
105
 
110
- console.log('\n=== memory-store: supersede ===');
111
- {
106
+ test('memory-store: supersede', () => {
112
107
  openDatabase(':memory:');
113
108
 
114
109
  createMemory({ category: 'convention', content: 'old convention' });
@@ -117,18 +112,17 @@ console.log('\n=== memory-store: supersede ===');
117
112
  supersedeMemory('MEM001', 'MEM002');
118
113
 
119
114
  const active = getActiveMemories();
120
- assertEq(active.length, 1, 'should have 1 active memory after supersede');
121
- assertEq(active[0].id, 'MEM002', 'active memory should be MEM002');
115
+ assert.deepStrictEqual(active.length, 1, 'should have 1 active memory after supersede');
116
+ assert.deepStrictEqual(active[0].id, 'MEM002', 'active memory should be MEM002');
122
117
 
123
118
  closeDatabase();
124
- }
119
+ });
125
120
 
126
121
  // ═══════════════════════════════════════════════════════════════════════════
127
122
  // memory-store: ranked query ordering
128
123
  // ═══════════════════════════════════════════════════════════════════════════
129
124
 
130
- console.log('\n=== memory-store: ranked query ordering ===');
131
- {
125
+ test('memory-store: ranked query ordering', () => {
132
126
  openDatabase(':memory:');
133
127
 
134
128
  // Low confidence, no hits
@@ -142,45 +136,43 @@ console.log('\n=== memory-store: ranked query ordering ===');
142
136
  for (let i = 0; i < 10; i++) reinforceMemory('MEM003');
143
137
 
144
138
  const ranked = getActiveMemoriesRanked(10);
145
- assertEq(ranked.length, 3, 'should have 3 ranked memories');
139
+ assert.deepStrictEqual(ranked.length, 3, 'should have 3 ranked memories');
146
140
  // MEM003: 0.7 * (1 + 10*0.1) = 0.7 * 2.0 = 1.4
147
141
  // MEM002: 0.95 * (1 + 0*0.1) = 0.95
148
142
  // MEM001: 0.5 * (1 + 0*0.1) = 0.5
149
- assertEq(ranked[0].id, 'MEM003', 'highest ranked should be MEM003 (reinforced)');
150
- assertEq(ranked[1].id, 'MEM002', 'second ranked should be MEM002 (high confidence)');
151
- assertEq(ranked[2].id, 'MEM001', 'lowest ranked should be MEM001');
143
+ assert.deepStrictEqual(ranked[0].id, 'MEM003', 'highest ranked should be MEM003 (reinforced)');
144
+ assert.deepStrictEqual(ranked[1].id, 'MEM002', 'second ranked should be MEM002 (high confidence)');
145
+ assert.deepStrictEqual(ranked[2].id, 'MEM001', 'lowest ranked should be MEM001');
152
146
 
153
147
  // Test limit
154
148
  const limited = getActiveMemoriesRanked(2);
155
- assertEq(limited.length, 2, 'limit should cap results');
149
+ assert.deepStrictEqual(limited.length, 2, 'limit should cap results');
156
150
 
157
151
  closeDatabase();
158
- }
152
+ });
159
153
 
160
154
  // ═══════════════════════════════════════════════════════════════════════════
161
155
  // memory-store: processed unit tracking
162
156
  // ═══════════════════════════════════════════════════════════════════════════
163
157
 
164
- console.log('\n=== memory-store: processed unit tracking ===');
165
- {
158
+ test('memory-store: processed unit tracking', () => {
166
159
  openDatabase(':memory:');
167
160
 
168
- assertTrue(!isUnitProcessed('execute-task/M001/S01/T01'), 'should not be processed initially');
161
+ assert.ok(!isUnitProcessed('execute-task/M001/S01/T01'), 'should not be processed initially');
169
162
 
170
163
  markUnitProcessed('execute-task/M001/S01/T01', '/path/to/activity.jsonl');
171
164
 
172
- assertTrue(isUnitProcessed('execute-task/M001/S01/T01'), 'should be processed after marking');
173
- assertTrue(!isUnitProcessed('execute-task/M001/S01/T02'), 'different key should not be processed');
165
+ assert.ok(isUnitProcessed('execute-task/M001/S01/T01'), 'should be processed after marking');
166
+ assert.ok(!isUnitProcessed('execute-task/M001/S01/T02'), 'different key should not be processed');
174
167
 
175
168
  closeDatabase();
176
- }
169
+ });
177
170
 
178
171
  // ═══════════════════════════════════════════════════════════════════════════
179
172
  // memory-store: enforce memory cap
180
173
  // ═══════════════════════════════════════════════════════════════════════════
181
174
 
182
- console.log('\n=== memory-store: enforce memory cap ===');
183
- {
175
+ test('memory-store: enforce memory cap', () => {
184
176
  openDatabase(':memory:');
185
177
 
186
178
  // Create 5 memories with varying confidence
@@ -194,23 +186,22 @@ console.log('\n=== memory-store: enforce memory cap ===');
194
186
  enforceMemoryCap(3);
195
187
 
196
188
  const active = getActiveMemories();
197
- assertEq(active.length, 3, 'should have 3 active memories after cap enforcement');
189
+ assert.deepStrictEqual(active.length, 3, 'should have 3 active memories after cap enforcement');
198
190
 
199
191
  // The 2 lowest-ranked (MEM003=0.3 and MEM002=0.5) should be superseded
200
192
  const ids = active.map(m => m.id).sort();
201
- assertTrue(ids.includes('MEM001'), 'MEM001 (0.9) should survive');
202
- assertTrue(ids.includes('MEM004'), 'MEM004 (0.95) should survive');
203
- assertTrue(ids.includes('MEM005'), 'MEM005 (0.7) should survive');
193
+ assert.ok(ids.includes('MEM001'), 'MEM001 (0.9) should survive');
194
+ assert.ok(ids.includes('MEM004'), 'MEM004 (0.95) should survive');
195
+ assert.ok(ids.includes('MEM005'), 'MEM005 (0.7) should survive');
204
196
 
205
197
  closeDatabase();
206
- }
198
+ });
207
199
 
208
200
  // ═══════════════════════════════════════════════════════════════════════════
209
201
  // memory-store: applyMemoryActions transaction
210
202
  // ═══════════════════════════════════════════════════════════════════════════
211
203
 
212
- console.log('\n=== memory-store: applyMemoryActions ===');
213
- {
204
+ test('memory-store: applyMemoryActions', () => {
214
205
  openDatabase(':memory:');
215
206
 
216
207
  const actions: MemoryAction[] = [
@@ -221,7 +212,7 @@ console.log('\n=== memory-store: applyMemoryActions ===');
221
212
  applyMemoryActions(actions, 'execute-task', 'M001/S01/T01');
222
213
 
223
214
  let active = getActiveMemories();
224
- assertEq(active.length, 2, 'should have 2 memories after CREATE actions');
215
+ assert.deepStrictEqual(active.length, 2, 'should have 2 memories after CREATE actions');
225
216
 
226
217
  // Now apply UPDATE + REINFORCE
227
218
  const updateActions: MemoryAction[] = [
@@ -232,8 +223,8 @@ console.log('\n=== memory-store: applyMemoryActions ===');
232
223
  applyMemoryActions(updateActions, 'execute-task', 'M001/S01/T02');
233
224
 
234
225
  active = getActiveMemories();
235
- assertEq(active.find(m => m.id === 'MEM001')?.content, 'updated gotcha', 'MEM001 should be updated');
236
- assertEq(active.find(m => m.id === 'MEM002')?.hit_count, 1, 'MEM002 should be reinforced');
226
+ assert.deepStrictEqual(active.find(m => m.id === 'MEM001')?.content, 'updated gotcha', 'MEM001 should be updated');
227
+ assert.deepStrictEqual(active.find(m => m.id === 'MEM002')?.hit_count, 1, 'MEM002 should be reinforced');
237
228
 
238
229
  // SUPERSEDE
239
230
  const supersedeActions: MemoryAction[] = [
@@ -244,19 +235,18 @@ console.log('\n=== memory-store: applyMemoryActions ===');
244
235
  applyMemoryActions(supersedeActions, 'execute-task', 'M001/S01/T03');
245
236
 
246
237
  active = getActiveMemories();
247
- assertEq(active.length, 2, 'should have 2 active after supersede');
248
- assertTrue(!active.find(m => m.id === 'MEM001'), 'MEM001 should be superseded');
249
- assertTrue(!!active.find(m => m.id === 'MEM003'), 'MEM003 should be active');
238
+ assert.deepStrictEqual(active.length, 2, 'should have 2 active after supersede');
239
+ assert.ok(!active.find(m => m.id === 'MEM001'), 'MEM001 should be superseded');
240
+ assert.ok(!!active.find(m => m.id === 'MEM003'), 'MEM003 should be active');
250
241
 
251
242
  closeDatabase();
252
- }
243
+ });
253
244
 
254
245
  // ═══════════════════════════════════════════════════════════════════════════
255
246
  // memory-store: formatMemoriesForPrompt
256
247
  // ═══════════════════════════════════════════════════════════════════════════
257
248
 
258
- console.log('\n=== memory-store: formatMemoriesForPrompt ===');
259
- {
249
+ test('memory-store: formatMemoriesForPrompt', () => {
260
250
  openDatabase(':memory:');
261
251
 
262
252
  createMemory({ category: 'gotcha', content: 'esbuild drops .node binaries' });
@@ -267,18 +257,18 @@ console.log('\n=== memory-store: formatMemoriesForPrompt ===');
267
257
  const memories = getActiveMemoriesRanked(30);
268
258
  const formatted = formatMemoriesForPrompt(memories);
269
259
 
270
- assertTrue(formatted.includes('## Project Memory (auto-learned)'), 'should have header');
271
- assertTrue(formatted.includes('### Gotcha'), 'should have gotcha category');
272
- assertTrue(formatted.includes('### Convention'), 'should have convention category');
273
- assertTrue(formatted.includes('### Architecture'), 'should have architecture category');
274
- assertTrue(formatted.includes('- esbuild drops .node binaries'), 'should have gotcha content');
275
- assertTrue(formatted.includes('- use :memory: for tests'), 'should have convention content');
260
+ assert.ok(formatted.includes('## Project Memory (auto-learned)'), 'should have header');
261
+ assert.ok(formatted.includes('### Gotcha'), 'should have gotcha category');
262
+ assert.ok(formatted.includes('### Convention'), 'should have convention category');
263
+ assert.ok(formatted.includes('### Architecture'), 'should have architecture category');
264
+ assert.ok(formatted.includes('- esbuild drops .node binaries'), 'should have gotcha content');
265
+ assert.ok(formatted.includes('- use :memory: for tests'), 'should have convention content');
276
266
 
277
267
  // Test empty memories
278
268
  closeDatabase();
279
269
  openDatabase(':memory:');
280
270
  const emptyFormatted = formatMemoriesForPrompt([]);
281
- assertEq(emptyFormatted, '', 'empty memories should return empty string');
271
+ assert.deepStrictEqual(emptyFormatted, '', 'empty memories should return empty string');
282
272
 
283
273
  // Test token budget truncation
284
274
  closeDatabase();
@@ -288,58 +278,55 @@ console.log('\n=== memory-store: formatMemoriesForPrompt ===');
288
278
  }
289
279
  const budgetMemories = getActiveMemoriesRanked(30);
290
280
  const truncated = formatMemoriesForPrompt(budgetMemories, 500);
291
- assertTrue(truncated.length < 2500, `formatted length ${truncated.length} should be under budget`);
281
+ assert.ok(truncated.length < 2500, `formatted length ${truncated.length} should be under budget`);
292
282
 
293
283
  closeDatabase();
294
- }
284
+ });
295
285
 
296
286
  // ═══════════════════════════════════════════════════════════════════════════
297
287
  // memory-store: ID generation
298
288
  // ═══════════════════════════════════════════════════════════════════════════
299
289
 
300
- console.log('\n=== memory-store: ID generation ===');
301
- {
290
+ test('memory-store: ID generation', () => {
302
291
  openDatabase(':memory:');
303
292
 
304
- assertEq(nextMemoryId(), 'MEM001', 'first ID should be MEM001');
293
+ assert.deepStrictEqual(nextMemoryId(), 'MEM001', 'first ID should be MEM001');
305
294
 
306
295
  createMemory({ category: 'test', content: 'test' });
307
- assertEq(nextMemoryId(), 'MEM002', 'after first create, next should be MEM002');
296
+ assert.deepStrictEqual(nextMemoryId(), 'MEM002', 'after first create, next should be MEM002');
308
297
 
309
298
  // Create several more
310
299
  for (let i = 0; i < 98; i++) createMemory({ category: 'test', content: `test ${i}` });
311
- assertEq(nextMemoryId(), 'MEM100', 'after 99 creates, next should be MEM100');
300
+ assert.deepStrictEqual(nextMemoryId(), 'MEM100', 'after 99 creates, next should be MEM100');
312
301
 
313
302
  closeDatabase();
314
- }
303
+ });
315
304
 
316
305
  // ═══════════════════════════════════════════════════════════════════════════
317
306
  // memory-store: schema migration (v2 → v3)
318
307
  // ═══════════════════════════════════════════════════════════════════════════
319
308
 
320
- console.log('\n=== memory-store: schema includes memories table ===');
321
- {
309
+ test('memory-store: schema includes memories table', () => {
322
310
  openDatabase(':memory:');
323
311
 
324
312
  const adapter = _getAdapter()!;
325
313
 
326
314
  // Verify memories table exists
327
315
  const memCount = adapter.prepare('SELECT count(*) as cnt FROM memories').get();
328
- assertEq(memCount?.['cnt'], 0, 'memories table should exist and be empty');
316
+ assert.deepStrictEqual(memCount?.['cnt'], 0, 'memories table should exist and be empty');
329
317
 
330
318
  // Verify memory_processed_units table exists
331
319
  const procCount = adapter.prepare('SELECT count(*) as cnt FROM memory_processed_units').get();
332
- assertEq(procCount?.['cnt'], 0, 'memory_processed_units table should exist and be empty');
320
+ assert.deepStrictEqual(procCount?.['cnt'], 0, 'memory_processed_units table should exist and be empty');
333
321
 
334
322
  // Verify active_memories view exists
335
323
  const viewCount = adapter.prepare('SELECT count(*) as cnt FROM active_memories').get();
336
- assertEq(viewCount?.['cnt'], 0, 'active_memories view should exist');
324
+ assert.deepStrictEqual(viewCount?.['cnt'], 0, 'active_memories view should exist');
337
325
 
338
326
  // Verify schema version is 10 (after M001 planning migrations)
339
327
  const version = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
340
- assertEq(version?.['v'], 10, 'schema version should be 10');
328
+ assert.deepStrictEqual(version?.['v'], 10, 'schema version should be 10');
341
329
 
342
330
  closeDatabase();
343
- }
331
+ });
344
332
 
345
- report();
@@ -15,9 +15,9 @@ import {
15
15
  writeGSDDirectory,
16
16
  } from '../migrate/index.ts';
17
17
  import { deriveState } from '../state.ts';
18
- import { createTestContext } from './test-helpers.ts';
18
+ import { describe, test, beforeEach, afterEach } from 'node:test';
19
+ import assert from 'node:assert/strict';
19
20
 
20
- const { assertEq, assertTrue, report } = createTestContext();
21
21
  // ─── Fixture Helpers ───────────────────────────────────────────────────────
22
22
 
23
23
  const SAMPLE_PROJECT = `# Integration Test Project
@@ -195,11 +195,9 @@ function createCompleteFixture(): string {
195
195
  // Tests
196
196
  // ═══════════════════════════════════════════════════════════════════════════
197
197
 
198
- async function main(): Promise<void> {
199
-
200
198
  // ─── Test 1: Path resolution — .planning appended when missing ─────────
201
- console.log('\n=== Path resolution: .planning appended when source path lacks it ===');
202
- {
199
+
200
+ test('Path resolution: .planning appended when source path lacks it', () => {
203
201
  const base = createCompleteFixture();
204
202
  try {
205
203
  // Simulate the command's path resolution logic
@@ -207,16 +205,16 @@ async function main(): Promise<void> {
207
205
  if (!sourcePath.endsWith('.planning')) {
208
206
  sourcePath = join(sourcePath, '.planning');
209
207
  }
210
- assertTrue(sourcePath.endsWith('.planning'), 'path-resolution: .planning appended');
211
- assertTrue(existsSync(sourcePath), 'path-resolution: appended path exists');
208
+ assert.ok(sourcePath.endsWith('.planning'), 'path-resolution: .planning appended');
209
+ assert.ok(existsSync(sourcePath), 'path-resolution: appended path exists');
212
210
  } finally {
213
211
  rmSync(base, { recursive: true, force: true });
214
212
  }
215
- }
213
+ });
216
214
 
217
215
  // ─── Test 2: Path resolution — .planning used as-is ────────────────────
218
- console.log('\n=== Path resolution: .planning used as-is when already present ===');
219
- {
216
+
217
+ test('Path resolution: .planning used as-is when already present', () => {
220
218
  const base = createCompleteFixture();
221
219
  try {
222
220
  const planningPath = join(base, '.planning');
@@ -224,39 +222,39 @@ async function main(): Promise<void> {
224
222
  if (!sourcePath.endsWith('.planning')) {
225
223
  sourcePath = join(sourcePath, '.planning');
226
224
  }
227
- assertEq(sourcePath, resolve(planningPath), 'path-resolution: .planning not double-appended');
228
- assertTrue(existsSync(sourcePath), 'path-resolution: direct path exists');
225
+ assert.deepStrictEqual(sourcePath, resolve(planningPath), 'path-resolution: .planning not double-appended');
226
+ assert.ok(existsSync(sourcePath), 'path-resolution: direct path exists');
229
227
  } finally {
230
228
  rmSync(base, { recursive: true, force: true });
231
229
  }
232
- }
230
+ });
233
231
 
234
232
  // ─── Test 3: Validation gating — non-existent path ─────────────────────
235
- console.log('\n=== Validation gating: non-existent path returns invalid ===');
236
- {
233
+
234
+ test('Validation gating: non-existent path returns invalid', async () => {
237
235
  const fakePath = join(tmpdir(), 'gsd-cmd-nonexistent-' + Date.now(), '.planning');
238
236
  const result = await validatePlanningDirectory(fakePath);
239
- assertEq(result.valid, false, 'validation: non-existent path is invalid');
240
- assertTrue(result.issues.length > 0, 'validation: has issues for non-existent path');
237
+ assert.deepStrictEqual(result.valid, false, 'validation: non-existent path is invalid');
238
+ assert.ok(result.issues.length > 0, 'validation: has issues for non-existent path');
241
239
  const hasFatal = result.issues.some(i => i.severity === 'fatal');
242
- assertTrue(hasFatal, 'validation: non-existent path has fatal issue');
243
- }
240
+ assert.ok(hasFatal, 'validation: non-existent path has fatal issue');
241
+ });
244
242
 
245
243
  // ─── Test 4: Validation gating — valid fixture passes ──────────────────
246
- console.log('\n=== Validation gating: valid fixture passes validation ===');
247
- {
244
+
245
+ test('Validation gating: valid fixture passes validation', async () => {
248
246
  const base = createCompleteFixture();
249
247
  try {
250
248
  const result = await validatePlanningDirectory(join(base, '.planning'));
251
- assertTrue(result.valid === true, 'validation: valid fixture passes');
249
+ assert.ok(result.valid === true, 'validation: valid fixture passes');
252
250
  } finally {
253
251
  rmSync(base, { recursive: true, force: true });
254
252
  }
255
- }
253
+ });
256
254
 
257
255
  // ─── Test 5: Full pipeline round-trip ──────────────────────────────────
258
- console.log('\n=== Full pipeline: parse → transform → preview → write → deriveState ===');
259
- {
256
+
257
+ test('Full pipeline: parse → transform → preview → write → deriveState', async () => {
260
258
  const base = createCompleteFixture();
261
259
  const writeTarget = mkdtempSync(join(tmpdir(), 'gsd-cmd-write-'));
262
260
  try {
@@ -264,17 +262,17 @@ async function main(): Promise<void> {
264
262
 
265
263
  // (a) Validate
266
264
  const validation = await validatePlanningDirectory(planningPath);
267
- assertTrue(validation.valid === true, 'pipeline: validation passes');
265
+ assert.ok(validation.valid === true, 'pipeline: validation passes');
268
266
 
269
267
  // (b) Parse
270
268
  const parsed = await parsePlanningDirectory(planningPath);
271
- assertTrue(parsed.roadmap !== null, 'pipeline: roadmap parsed');
272
- assertTrue(Object.keys(parsed.phases).length >= 2, 'pipeline: phases parsed');
269
+ assert.ok(parsed.roadmap !== null, 'pipeline: roadmap parsed');
270
+ assert.ok(Object.keys(parsed.phases).length >= 2, 'pipeline: phases parsed');
273
271
 
274
272
  // (c) Transform
275
273
  const project = transformToGSD(parsed);
276
- assertTrue(project.milestones.length >= 1, 'pipeline: has milestones');
277
- assertTrue(project.milestones[0].slices.length >= 1, 'pipeline: has slices');
274
+ assert.ok(project.milestones.length >= 1, 'pipeline: has milestones');
275
+ assert.ok(project.milestones[0].slices.length >= 1, 'pipeline: has slices');
278
276
 
279
277
  // Count totals for preview verification
280
278
  let totalTasks = 0;
@@ -294,76 +292,69 @@ async function main(): Promise<void> {
294
292
 
295
293
  // (d) Preview — verify counts match project data
296
294
  const preview = generatePreview(project);
297
- assertEq(preview.milestoneCount, project.milestones.length, 'pipeline: preview milestoneCount');
298
- assertEq(preview.totalSlices, totalSlices, 'pipeline: preview totalSlices');
299
- assertEq(preview.totalTasks, totalTasks, 'pipeline: preview totalTasks');
300
- assertEq(preview.doneSlices, doneSlices, 'pipeline: preview doneSlices');
301
- assertEq(preview.doneTasks, doneTasks, 'pipeline: preview doneTasks');
295
+ assert.deepStrictEqual(preview.milestoneCount, project.milestones.length, 'pipeline: preview milestoneCount');
296
+ assert.deepStrictEqual(preview.totalSlices, totalSlices, 'pipeline: preview totalSlices');
297
+ assert.deepStrictEqual(preview.totalTasks, totalTasks, 'pipeline: preview totalTasks');
298
+ assert.deepStrictEqual(preview.doneSlices, doneSlices, 'pipeline: preview doneSlices');
299
+ assert.deepStrictEqual(preview.doneTasks, doneTasks, 'pipeline: preview doneTasks');
302
300
 
303
301
  // Completion percentages
304
302
  const expectedSlicePct = totalSlices > 0 ? Math.round((doneSlices / totalSlices) * 100) : 0;
305
303
  const expectedTaskPct = totalTasks > 0 ? Math.round((doneTasks / totalTasks) * 100) : 0;
306
- assertEq(preview.sliceCompletionPct, expectedSlicePct, 'pipeline: preview sliceCompletionPct');
307
- assertEq(preview.taskCompletionPct, expectedTaskPct, 'pipeline: preview taskCompletionPct');
304
+ assert.deepStrictEqual(preview.sliceCompletionPct, expectedSlicePct, 'pipeline: preview sliceCompletionPct');
305
+ assert.deepStrictEqual(preview.taskCompletionPct, expectedTaskPct, 'pipeline: preview taskCompletionPct');
308
306
 
309
307
  // Requirements in preview
310
- assertEq(preview.requirements.active, 1, 'pipeline: preview requirements active');
311
- assertEq(preview.requirements.validated, 1, 'pipeline: preview requirements validated');
312
- assertEq(preview.requirements.total, 2, 'pipeline: preview requirements total');
308
+ assert.deepStrictEqual(preview.requirements.active, 1, 'pipeline: preview requirements active');
309
+ assert.deepStrictEqual(preview.requirements.validated, 1, 'pipeline: preview requirements validated');
310
+ assert.deepStrictEqual(preview.requirements.total, 2, 'pipeline: preview requirements total');
313
311
 
314
312
  // (e) Write
315
313
  const result = await writeGSDDirectory(project, writeTarget);
316
- assertTrue(result.paths.length > 0, 'pipeline: files written');
314
+ assert.ok(result.paths.length > 0, 'pipeline: files written');
317
315
 
318
316
  // Key files exist
319
317
  const gsd = join(writeTarget, '.gsd');
320
- assertTrue(existsSync(join(gsd, 'PROJECT.md')), 'pipeline: PROJECT.md written');
321
- assertTrue(existsSync(join(gsd, 'STATE.md')), 'pipeline: STATE.md written');
322
- assertTrue(existsSync(join(gsd, 'REQUIREMENTS.md')), 'pipeline: REQUIREMENTS.md written');
318
+ assert.ok(existsSync(join(gsd, 'PROJECT.md')), 'pipeline: PROJECT.md written');
319
+ assert.ok(existsSync(join(gsd, 'STATE.md')), 'pipeline: STATE.md written');
320
+ assert.ok(existsSync(join(gsd, 'REQUIREMENTS.md')), 'pipeline: REQUIREMENTS.md written');
323
321
 
324
322
  const m001 = join(gsd, 'milestones', 'M001');
325
- assertTrue(existsSync(join(m001, 'M001-ROADMAP.md')), 'pipeline: M001-ROADMAP.md written');
326
- assertTrue(existsSync(join(m001, 'M001-CONTEXT.md')), 'pipeline: M001-CONTEXT.md written');
323
+ assert.ok(existsSync(join(m001, 'M001-ROADMAP.md')), 'pipeline: M001-ROADMAP.md written');
324
+ assert.ok(existsSync(join(m001, 'M001-CONTEXT.md')), 'pipeline: M001-CONTEXT.md written');
327
325
 
328
326
  // At least one slice plan exists
329
327
  const s01Plan = join(m001, 'slices', 'S01', 'S01-PLAN.md');
330
- assertTrue(existsSync(s01Plan), 'pipeline: S01-PLAN.md written');
328
+ assert.ok(existsSync(s01Plan), 'pipeline: S01-PLAN.md written');
331
329
 
332
330
  // (f) deriveState — coherent state from written output
333
331
  console.log(' --- deriveState ---');
334
332
  const state = await deriveState(writeTarget);
335
- assertTrue(state.phase !== undefined, 'pipeline: deriveState returns phase');
336
- assertTrue(state.activeMilestone !== null, 'pipeline: deriveState has activeMilestone');
337
- assertEq(state.activeMilestone!.id, 'M001', 'pipeline: deriveState activeMilestone is M001');
338
- assertTrue(state.progress!.slices !== undefined, 'pipeline: deriveState has slices progress');
339
- assertTrue(state.progress!.tasks !== undefined, 'pipeline: deriveState has tasks progress');
333
+ assert.ok(state.phase !== undefined, 'pipeline: deriveState returns phase');
334
+ assert.ok(state.activeMilestone !== null, 'pipeline: deriveState has activeMilestone');
335
+ assert.deepStrictEqual(state.activeMilestone!.id, 'M001', 'pipeline: deriveState activeMilestone is M001');
336
+ assert.ok(state.progress!.slices !== undefined, 'pipeline: deriveState has slices progress');
337
+ assert.ok(state.progress!.tasks !== undefined, 'pipeline: deriveState has tasks progress');
340
338
 
341
339
  } finally {
342
340
  rmSync(base, { recursive: true, force: true });
343
341
  rmSync(writeTarget, { recursive: true, force: true });
344
342
  }
345
- }
343
+ });
346
344
 
347
345
  // ─── Test 6: .gsd/ exists detection ────────────────────────────────────
348
- console.log('\n=== .gsd/ exists detection ===');
349
- {
346
+
347
+ test('.gsd/ exists detection', () => {
350
348
  const base = mkdtempSync(join(tmpdir(), 'gsd-cmd-exists-'));
351
349
  try {
352
350
  // No .gsd/ yet
353
- assertTrue(!existsSync(join(base, '.gsd')), 'exists-detection: .gsd absent initially');
351
+ assert.ok(!existsSync(join(base, '.gsd')), 'exists-detection: .gsd absent initially');
354
352
 
355
353
  // Create .gsd/
356
354
  mkdirSync(join(base, '.gsd'), { recursive: true });
357
- assertTrue(existsSync(join(base, '.gsd')), 'exists-detection: .gsd detected after creation');
355
+ assert.ok(existsSync(join(base, '.gsd')), 'exists-detection: .gsd detected after creation');
358
356
  } finally {
359
357
  rmSync(base, { recursive: true, force: true });
360
358
  }
361
- }
362
-
363
- report();
364
- }
365
-
366
- main().catch((err) => {
367
- console.error('Unhandled error:', err);
368
- process.exit(1);
369
359
  });
360
+