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
@@ -20,9 +20,9 @@ import type {
20
20
  GSDTask,
21
21
  GSDRequirement,
22
22
  } from '../migrate/types.ts';
23
- import { createTestContext } from './test-helpers.ts';
23
+ import { describe, test, beforeEach, afterEach } from 'node:test';
24
+ import assert from 'node:assert/strict';
24
25
 
25
- const { assertEq, assertTrue, report } = createTestContext();
26
26
  // ─── Fixture Builders ──────────────────────────────────────────────────────
27
27
 
28
28
  function makeTask(id: string, title: string, done: boolean, hasSummary: boolean): GSDTask {
@@ -130,11 +130,9 @@ function buildCompleteProject(): GSDProject {
130
130
  // Tests
131
131
  // ═══════════════════════════════════════════════════════════════════════════
132
132
 
133
- async function main(): Promise<void> {
134
-
135
133
  // ─── Scenario 1: Incomplete project ────────────────────────────────────
136
- console.log('\n=== Scenario 1: Incomplete project — write, parse, deriveState ===');
137
- {
134
+
135
+ test('Scenario 1: Incomplete project — write, parse, deriveState', async () => {
138
136
  const base = mkdtempSync(join(tmpdir(), 'gsd-writer-int-'));
139
137
  try {
140
138
  const project = buildIncompleteProject();
@@ -145,64 +143,64 @@ async function main(): Promise<void> {
145
143
  const gsd = join(base, '.gsd');
146
144
  const m = join(gsd, 'milestones', 'M001');
147
145
 
148
- assertTrue(existsSync(join(m, 'M001-ROADMAP.md')), 'incomplete: M001-ROADMAP.md exists');
149
- assertTrue(existsSync(join(m, 'M001-CONTEXT.md')), 'incomplete: M001-CONTEXT.md exists');
150
- assertTrue(existsSync(join(m, 'M001-RESEARCH.md')), 'incomplete: M001-RESEARCH.md exists');
151
- assertTrue(existsSync(join(m, 'slices', 'S01', 'S01-PLAN.md')), 'incomplete: S01-PLAN.md exists');
152
- assertTrue(existsSync(join(m, 'slices', 'S02', 'S02-PLAN.md')), 'incomplete: S02-PLAN.md exists');
153
- assertTrue(existsSync(join(m, 'slices', 'S01', 'S01-SUMMARY.md')), 'incomplete: S01-SUMMARY.md exists');
154
- assertTrue(!existsSync(join(m, 'slices', 'S02', 'S02-SUMMARY.md')), 'incomplete: S02-SUMMARY.md NOT written (null)');
155
- assertTrue(existsSync(join(gsd, 'REQUIREMENTS.md')), 'incomplete: REQUIREMENTS.md exists');
156
- assertTrue(existsSync(join(gsd, 'PROJECT.md')), 'incomplete: PROJECT.md exists');
157
- assertTrue(existsSync(join(gsd, 'DECISIONS.md')), 'incomplete: DECISIONS.md exists');
158
- assertTrue(existsSync(join(gsd, 'STATE.md')), 'incomplete: STATE.md exists');
146
+ assert.ok(existsSync(join(m, 'M001-ROADMAP.md')), 'incomplete: M001-ROADMAP.md exists');
147
+ assert.ok(existsSync(join(m, 'M001-CONTEXT.md')), 'incomplete: M001-CONTEXT.md exists');
148
+ assert.ok(existsSync(join(m, 'M001-RESEARCH.md')), 'incomplete: M001-RESEARCH.md exists');
149
+ assert.ok(existsSync(join(m, 'slices', 'S01', 'S01-PLAN.md')), 'incomplete: S01-PLAN.md exists');
150
+ assert.ok(existsSync(join(m, 'slices', 'S02', 'S02-PLAN.md')), 'incomplete: S02-PLAN.md exists');
151
+ assert.ok(existsSync(join(m, 'slices', 'S01', 'S01-SUMMARY.md')), 'incomplete: S01-SUMMARY.md exists');
152
+ assert.ok(!existsSync(join(m, 'slices', 'S02', 'S02-SUMMARY.md')), 'incomplete: S02-SUMMARY.md NOT written (null)');
153
+ assert.ok(existsSync(join(gsd, 'REQUIREMENTS.md')), 'incomplete: REQUIREMENTS.md exists');
154
+ assert.ok(existsSync(join(gsd, 'PROJECT.md')), 'incomplete: PROJECT.md exists');
155
+ assert.ok(existsSync(join(gsd, 'DECISIONS.md')), 'incomplete: DECISIONS.md exists');
156
+ assert.ok(existsSync(join(gsd, 'STATE.md')), 'incomplete: STATE.md exists');
159
157
 
160
158
  // Task files
161
- assertTrue(existsSync(join(m, 'slices', 'S01', 'tasks', 'T01-PLAN.md')), 'incomplete: T01-PLAN.md exists');
162
- assertTrue(existsSync(join(m, 'slices', 'S01', 'tasks', 'T01-SUMMARY.md')), 'incomplete: T01-SUMMARY.md exists');
163
- assertTrue(existsSync(join(m, 'slices', 'S01', 'tasks', 'T02-PLAN.md')), 'incomplete: T02-PLAN.md exists (auth task)');
164
- assertTrue(existsSync(join(m, 'slices', 'S01', 'tasks', 'T02-SUMMARY.md')), 'incomplete: T02-SUMMARY.md exists (auth task)');
165
- assertTrue(existsSync(join(m, 'slices', 'S02', 'tasks', 'T03-PLAN.md')), 'incomplete: T03-PLAN.md exists');
166
- assertTrue(!existsSync(join(m, 'slices', 'S02', 'tasks', 'T03-SUMMARY.md')), 'incomplete: T03-SUMMARY.md NOT written (null)');
159
+ assert.ok(existsSync(join(m, 'slices', 'S01', 'tasks', 'T01-PLAN.md')), 'incomplete: T01-PLAN.md exists');
160
+ assert.ok(existsSync(join(m, 'slices', 'S01', 'tasks', 'T01-SUMMARY.md')), 'incomplete: T01-SUMMARY.md exists');
161
+ assert.ok(existsSync(join(m, 'slices', 'S01', 'tasks', 'T02-PLAN.md')), 'incomplete: T02-PLAN.md exists (auth task)');
162
+ assert.ok(existsSync(join(m, 'slices', 'S01', 'tasks', 'T02-SUMMARY.md')), 'incomplete: T02-SUMMARY.md exists (auth task)');
163
+ assert.ok(existsSync(join(m, 'slices', 'S02', 'tasks', 'T03-PLAN.md')), 'incomplete: T03-PLAN.md exists');
164
+ assert.ok(!existsSync(join(m, 'slices', 'S02', 'tasks', 'T03-SUMMARY.md')), 'incomplete: T03-SUMMARY.md NOT written (null)');
167
165
 
168
166
  // WrittenFiles counts
169
167
  console.log(' --- WrittenFiles counts ---');
170
- assertEq(result.counts.roadmaps, 1, 'incomplete: WrittenFiles roadmaps count');
171
- assertEq(result.counts.plans, 2, 'incomplete: WrittenFiles plans count');
172
- assertEq(result.counts.taskPlans, 3, 'incomplete: WrittenFiles taskPlans count');
173
- assertEq(result.counts.taskSummaries, 2, 'incomplete: WrittenFiles taskSummaries count');
174
- assertEq(result.counts.sliceSummaries, 1, 'incomplete: WrittenFiles sliceSummaries count');
175
- assertEq(result.counts.research, 1, 'incomplete: WrittenFiles research count');
176
- assertEq(result.counts.requirements, 1, 'incomplete: WrittenFiles requirements count');
177
- assertEq(result.counts.contexts, 1, 'incomplete: WrittenFiles contexts count');
168
+ assert.deepStrictEqual(result.counts.roadmaps, 1, 'incomplete: WrittenFiles roadmaps count');
169
+ assert.deepStrictEqual(result.counts.plans, 2, 'incomplete: WrittenFiles plans count');
170
+ assert.deepStrictEqual(result.counts.taskPlans, 3, 'incomplete: WrittenFiles taskPlans count');
171
+ assert.deepStrictEqual(result.counts.taskSummaries, 2, 'incomplete: WrittenFiles taskSummaries count');
172
+ assert.deepStrictEqual(result.counts.sliceSummaries, 1, 'incomplete: WrittenFiles sliceSummaries count');
173
+ assert.deepStrictEqual(result.counts.research, 1, 'incomplete: WrittenFiles research count');
174
+ assert.deepStrictEqual(result.counts.requirements, 1, 'incomplete: WrittenFiles requirements count');
175
+ assert.deepStrictEqual(result.counts.contexts, 1, 'incomplete: WrittenFiles contexts count');
178
176
 
179
177
  // (b) parseRoadmap on written roadmap
180
178
  console.log(' --- parseRoadmap ---');
181
179
  const roadmapContent = readFileSync(join(m, 'M001-ROADMAP.md'), 'utf-8');
182
180
  const roadmap = parseRoadmap(roadmapContent);
183
- assertEq(roadmap.slices.length, 2, 'incomplete: roadmap has 2 slices');
184
- assertTrue(roadmap.slices[0].done === true, 'incomplete: roadmap S01 is done');
185
- assertTrue(roadmap.slices[1].done === false, 'incomplete: roadmap S02 is not done');
186
- assertEq(roadmap.slices[0].id, 'S01', 'incomplete: roadmap slice 0 id');
187
- assertEq(roadmap.slices[1].id, 'S02', 'incomplete: roadmap slice 1 id');
181
+ assert.deepStrictEqual(roadmap.slices.length, 2, 'incomplete: roadmap has 2 slices');
182
+ assert.ok(roadmap.slices[0].done === true, 'incomplete: roadmap S01 is done');
183
+ assert.ok(roadmap.slices[1].done === false, 'incomplete: roadmap S02 is not done');
184
+ assert.deepStrictEqual(roadmap.slices[0].id, 'S01', 'incomplete: roadmap slice 0 id');
185
+ assert.deepStrictEqual(roadmap.slices[1].id, 'S02', 'incomplete: roadmap slice 1 id');
188
186
 
189
187
  // (c) parsePlan on S01 plan
190
188
  console.log(' --- parsePlan S01 ---');
191
189
  const s01PlanContent = readFileSync(join(m, 'slices', 'S01', 'S01-PLAN.md'), 'utf-8');
192
190
  const s01Plan = parsePlan(s01PlanContent);
193
- assertEq(s01Plan.tasks.length, 2, 'incomplete: S01 plan has 2 tasks');
194
- assertTrue(s01Plan.tasks[0].done === true, 'incomplete: S01 T01 is done');
195
- assertTrue(s01Plan.tasks[1].done === true, 'incomplete: S01 T02 is done');
191
+ assert.deepStrictEqual(s01Plan.tasks.length, 2, 'incomplete: S01 plan has 2 tasks');
192
+ assert.ok(s01Plan.tasks[0].done === true, 'incomplete: S01 T01 is done');
193
+ assert.ok(s01Plan.tasks[1].done === true, 'incomplete: S01 T02 is done');
196
194
 
197
195
  // (d) parseSummary on S01 summary
198
196
  console.log(' --- parseSummary S01 ---');
199
197
  const s01SummaryContent = readFileSync(join(m, 'slices', 'S01', 'S01-SUMMARY.md'), 'utf-8');
200
198
  const s01Summary = parseSummary(s01SummaryContent);
201
- assertTrue(
199
+ assert.ok(
202
200
  (s01Summary.frontmatter.key_files as string[]).length > 0,
203
201
  'incomplete: S01 summary has key_files',
204
202
  );
205
- assertTrue(
203
+ assert.ok(
206
204
  (s01Summary.frontmatter.provides as string[]).length > 0,
207
205
  'incomplete: S01 summary has provides',
208
206
  );
@@ -211,50 +209,50 @@ async function main(): Promise<void> {
211
209
  console.log(' --- deriveState ---');
212
210
  invalidateAllCaches();
213
211
  const state = await deriveState(base);
214
- assertEq(state.phase, 'executing', 'incomplete: deriveState phase is executing');
215
- assertTrue(state.activeMilestone !== null, 'incomplete: deriveState has activeMilestone');
216
- assertEq(state.activeMilestone!.id, 'M001', 'incomplete: deriveState activeMilestone is M001');
217
- assertTrue(state.activeSlice !== null, 'incomplete: deriveState has activeSlice');
218
- assertEq(state.activeSlice!.id, 'S02', 'incomplete: deriveState activeSlice is S02');
219
- assertTrue(state.activeTask !== null, 'incomplete: deriveState has activeTask');
220
- assertEq(state.activeTask!.id, 'T03', 'incomplete: deriveState activeTask is T03');
221
- assertTrue(state.progress!.slices !== undefined, 'incomplete: deriveState has slices progress');
222
- assertEq(state.progress!.slices!.done, 1, 'incomplete: deriveState slices done count');
223
- assertEq(state.progress!.slices!.total, 2, 'incomplete: deriveState slices total count');
224
- assertTrue(state.progress!.tasks !== undefined, 'incomplete: deriveState has tasks progress');
212
+ assert.deepStrictEqual(state.phase, 'executing', 'incomplete: deriveState phase is executing');
213
+ assert.ok(state.activeMilestone !== null, 'incomplete: deriveState has activeMilestone');
214
+ assert.deepStrictEqual(state.activeMilestone!.id, 'M001', 'incomplete: deriveState activeMilestone is M001');
215
+ assert.ok(state.activeSlice !== null, 'incomplete: deriveState has activeSlice');
216
+ assert.deepStrictEqual(state.activeSlice!.id, 'S02', 'incomplete: deriveState activeSlice is S02');
217
+ assert.ok(state.activeTask !== null, 'incomplete: deriveState has activeTask');
218
+ assert.deepStrictEqual(state.activeTask!.id, 'T03', 'incomplete: deriveState activeTask is T03');
219
+ assert.ok(state.progress!.slices !== undefined, 'incomplete: deriveState has slices progress');
220
+ assert.deepStrictEqual(state.progress!.slices!.done, 1, 'incomplete: deriveState slices done count');
221
+ assert.deepStrictEqual(state.progress!.slices!.total, 2, 'incomplete: deriveState slices total count');
222
+ assert.ok(state.progress!.tasks !== undefined, 'incomplete: deriveState has tasks progress');
225
223
  // S02 has 1 task, 0 done (only active slice tasks counted)
226
- assertEq(state.progress!.tasks!.done, 0, 'incomplete: deriveState tasks done (in active slice)');
227
- assertEq(state.progress!.tasks!.total, 1, 'incomplete: deriveState tasks total (in active slice)');
224
+ assert.deepStrictEqual(state.progress!.tasks!.done, 0, 'incomplete: deriveState tasks done (in active slice)');
225
+ assert.deepStrictEqual(state.progress!.tasks!.total, 1, 'incomplete: deriveState tasks total (in active slice)');
228
226
  // Requirements
229
- assertEq(state.requirements!.active, 1, 'incomplete: deriveState requirements active');
230
- assertEq(state.requirements!.validated, 1, 'incomplete: deriveState requirements validated');
231
- assertEq(state.requirements!.deferred, 1, 'incomplete: deriveState requirements deferred');
232
- assertEq(state.requirements!.outOfScope, 1, 'incomplete: deriveState requirements outOfScope');
227
+ assert.deepStrictEqual(state.requirements!.active, 1, 'incomplete: deriveState requirements active');
228
+ assert.deepStrictEqual(state.requirements!.validated, 1, 'incomplete: deriveState requirements validated');
229
+ assert.deepStrictEqual(state.requirements!.deferred, 1, 'incomplete: deriveState requirements deferred');
230
+ assert.deepStrictEqual(state.requirements!.outOfScope, 1, 'incomplete: deriveState requirements outOfScope');
233
231
 
234
232
  // (f) generatePreview
235
233
  console.log(' --- generatePreview ---');
236
234
  const preview = generatePreview(project);
237
- assertEq(preview.milestoneCount, 1, 'incomplete: preview milestoneCount');
238
- assertEq(preview.totalSlices, 2, 'incomplete: preview totalSlices');
239
- assertEq(preview.totalTasks, 3, 'incomplete: preview totalTasks');
240
- assertEq(preview.doneSlices, 1, 'incomplete: preview doneSlices');
241
- assertEq(preview.doneTasks, 2, 'incomplete: preview doneTasks');
242
- assertEq(preview.sliceCompletionPct, 50, 'incomplete: preview sliceCompletionPct');
243
- assertEq(preview.taskCompletionPct, 67, 'incomplete: preview taskCompletionPct');
244
- assertEq(preview.requirements.active, 1, 'incomplete: preview requirements active');
245
- assertEq(preview.requirements.validated, 1, 'incomplete: preview requirements validated');
246
- assertEq(preview.requirements.deferred, 1, 'incomplete: preview requirements deferred');
247
- assertEq(preview.requirements.outOfScope, 1, 'incomplete: preview requirements outOfScope');
248
- assertEq(preview.requirements.total, 4, 'incomplete: preview requirements total');
235
+ assert.deepStrictEqual(preview.milestoneCount, 1, 'incomplete: preview milestoneCount');
236
+ assert.deepStrictEqual(preview.totalSlices, 2, 'incomplete: preview totalSlices');
237
+ assert.deepStrictEqual(preview.totalTasks, 3, 'incomplete: preview totalTasks');
238
+ assert.deepStrictEqual(preview.doneSlices, 1, 'incomplete: preview doneSlices');
239
+ assert.deepStrictEqual(preview.doneTasks, 2, 'incomplete: preview doneTasks');
240
+ assert.deepStrictEqual(preview.sliceCompletionPct, 50, 'incomplete: preview sliceCompletionPct');
241
+ assert.deepStrictEqual(preview.taskCompletionPct, 67, 'incomplete: preview taskCompletionPct');
242
+ assert.deepStrictEqual(preview.requirements.active, 1, 'incomplete: preview requirements active');
243
+ assert.deepStrictEqual(preview.requirements.validated, 1, 'incomplete: preview requirements validated');
244
+ assert.deepStrictEqual(preview.requirements.deferred, 1, 'incomplete: preview requirements deferred');
245
+ assert.deepStrictEqual(preview.requirements.outOfScope, 1, 'incomplete: preview requirements outOfScope');
246
+ assert.deepStrictEqual(preview.requirements.total, 4, 'incomplete: preview requirements total');
249
247
 
250
248
  } finally {
251
249
  rmSync(base, { recursive: true, force: true });
252
250
  }
253
- }
251
+ });
254
252
 
255
253
  // ─── Scenario 2: Fully complete project ────────────────────────────────
256
- console.log('\n=== Scenario 2: Fully complete project — deriveState phase ===');
257
- {
254
+
255
+ test('Scenario 2: Fully complete project — deriveState phase', async () => {
258
256
  const base = mkdtempSync(join(tmpdir(), 'gsd-writer-int-complete-'));
259
257
  try {
260
258
  const project = buildCompleteProject();
@@ -262,43 +260,36 @@ async function main(): Promise<void> {
262
260
 
263
261
  // Null research should NOT produce a file
264
262
  const m = join(base, '.gsd', 'milestones', 'M001');
265
- assertTrue(!existsSync(join(m, 'M001-RESEARCH.md')), 'complete: M001-RESEARCH.md NOT written (null)');
263
+ assert.ok(!existsSync(join(m, 'M001-RESEARCH.md')), 'complete: M001-RESEARCH.md NOT written (null)');
266
264
  // No REQUIREMENTS.md since empty requirements
267
- assertTrue(!existsSync(join(base, '.gsd', 'REQUIREMENTS.md')), 'complete: REQUIREMENTS.md NOT written (empty)');
265
+ assert.ok(!existsSync(join(base, '.gsd', 'REQUIREMENTS.md')), 'complete: REQUIREMENTS.md NOT written (empty)');
268
266
  // Completed milestone should have VALIDATION and SUMMARY from migration (#819)
269
- assertTrue(existsSync(join(m, 'M001-VALIDATION.md')), 'complete: M001-VALIDATION.md written for completed milestone');
270
- assertTrue(existsSync(join(m, 'M001-SUMMARY.md')), 'complete: M001-SUMMARY.md written for completed milestone');
267
+ assert.ok(existsSync(join(m, 'M001-VALIDATION.md')), 'complete: M001-VALIDATION.md written for completed milestone');
268
+ assert.ok(existsSync(join(m, 'M001-SUMMARY.md')), 'complete: M001-SUMMARY.md written for completed milestone');
271
269
 
272
270
  // deriveState: all slices done, all tasks done — migration now writes
273
271
  // VALIDATION.md and SUMMARY.md for completed milestones (#819),
274
272
  // so the milestone should be fully complete.
275
273
  invalidateAllCaches();
276
274
  const state = await deriveState(base);
277
- assertEq(state.phase, 'complete', 'complete: deriveState phase is complete (validation + summary written by migration)');
275
+ assert.deepStrictEqual(state.phase, 'complete', 'complete: deriveState phase is complete (validation + summary written by migration)');
278
276
  // When all milestones are complete, activeMilestone points to the last entry (for display)
279
- assertTrue(state.activeMilestone !== null, 'complete: deriveState has activeMilestone (last entry)');
280
- assertEq(state.activeMilestone!.id, 'M001', 'complete: deriveState activeMilestone is M001');
277
+ assert.ok(state.activeMilestone !== null, 'complete: deriveState has activeMilestone (last entry)');
278
+ assert.deepStrictEqual(state.activeMilestone!.id, 'M001', 'complete: deriveState activeMilestone is M001');
281
279
 
282
280
  // generatePreview for complete project
283
281
  const preview = generatePreview(project);
284
- assertEq(preview.milestoneCount, 1, 'complete: preview milestoneCount');
285
- assertEq(preview.totalSlices, 1, 'complete: preview totalSlices');
286
- assertEq(preview.doneSlices, 1, 'complete: preview doneSlices');
287
- assertEq(preview.totalTasks, 1, 'complete: preview totalTasks');
288
- assertEq(preview.doneTasks, 1, 'complete: preview doneTasks');
289
- assertEq(preview.sliceCompletionPct, 100, 'complete: preview sliceCompletionPct');
290
- assertEq(preview.taskCompletionPct, 100, 'complete: preview taskCompletionPct');
291
- assertEq(preview.requirements.total, 0, 'complete: preview requirements total');
282
+ assert.deepStrictEqual(preview.milestoneCount, 1, 'complete: preview milestoneCount');
283
+ assert.deepStrictEqual(preview.totalSlices, 1, 'complete: preview totalSlices');
284
+ assert.deepStrictEqual(preview.doneSlices, 1, 'complete: preview doneSlices');
285
+ assert.deepStrictEqual(preview.totalTasks, 1, 'complete: preview totalTasks');
286
+ assert.deepStrictEqual(preview.doneTasks, 1, 'complete: preview doneTasks');
287
+ assert.deepStrictEqual(preview.sliceCompletionPct, 100, 'complete: preview sliceCompletionPct');
288
+ assert.deepStrictEqual(preview.taskCompletionPct, 100, 'complete: preview taskCompletionPct');
289
+ assert.deepStrictEqual(preview.requirements.total, 0, 'complete: preview requirements total');
292
290
 
293
291
  } finally {
294
292
  rmSync(base, { recursive: true, force: true });
295
293
  }
296
- }
297
-
298
- report();
299
- }
300
-
301
- main().catch((err) => {
302
- console.error('Unhandled error:', err);
303
- process.exit(1);
304
294
  });
295
+