gsd-pi 2.44.0-dev.62b5d6c → 2.44.0-dev.a5271fc

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 (198) 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/bootstrap/system-context.js +46 -12
  4. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
  5. package/dist/resources/extensions/gsd/preferences.js +9 -1
  6. package/dist/resources/extensions/gsd/state.js +19 -2
  7. package/dist/web/standalone/.next/BUILD_ID +1 -1
  8. package/dist/web/standalone/.next/app-path-routes-manifest.json +19 -19
  9. package/dist/web/standalone/.next/build-manifest.json +2 -2
  10. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  11. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  12. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  13. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  14. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  15. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  16. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  17. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  18. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  19. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  20. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  21. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  22. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  23. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  24. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  25. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  26. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/index.html +1 -1
  28. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  30. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  31. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  32. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  33. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  34. package/dist/web/standalone/.next/server/app-paths-manifest.json +19 -19
  35. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  36. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  37. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  38. package/package.json +1 -1
  39. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
  40. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  41. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
  42. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  43. package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
  44. package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
  45. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
  46. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
  47. package/packages/pi-coding-agent/dist/core/session-manager.test.js +30 -34
  48. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  49. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
  50. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
  51. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
  52. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
  53. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
  54. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
  55. package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
  56. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
  57. package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
  58. package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
  59. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
  60. package/src/resources/extensions/gsd/auto-start.ts +14 -0
  61. package/src/resources/extensions/gsd/bootstrap/system-context.ts +48 -11
  62. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
  63. package/src/resources/extensions/gsd/preferences.ts +11 -1
  64. package/src/resources/extensions/gsd/state.ts +19 -1
  65. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
  66. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +14 -16
  67. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
  68. package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
  69. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +465 -523
  70. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
  71. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
  72. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +533 -656
  73. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
  74. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
  75. package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
  76. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
  77. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
  78. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
  79. package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
  80. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +38 -59
  81. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +228 -263
  82. package/src/resources/extensions/gsd/tests/complete-task.test.ts +250 -302
  83. package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
  84. package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
  85. package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
  86. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
  87. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
  88. package/src/resources/extensions/gsd/tests/db-writer.test.ts +390 -420
  89. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
  90. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +68 -83
  91. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +183 -181
  92. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
  93. package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
  94. package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
  95. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
  96. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +164 -180
  97. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
  98. package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
  99. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +27 -29
  100. package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
  101. package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +54 -75
  102. package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +21 -32
  103. package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
  104. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +38 -44
  105. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
  106. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
  107. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +54 -60
  108. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
  109. package/src/resources/extensions/gsd/tests/doctor.test.ts +104 -134
  110. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
  111. package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
  112. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
  113. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
  114. package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +30 -42
  115. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +198 -206
  116. package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
  117. package/src/resources/extensions/gsd/tests/git-service.test.ts +285 -388
  118. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
  119. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
  120. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
  121. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
  122. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +81 -103
  123. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
  124. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
  125. package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
  126. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -102
  127. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
  128. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
  129. package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
  130. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
  131. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
  132. package/src/resources/extensions/gsd/tests/knowledge.test.ts +89 -0
  133. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +150 -194
  134. package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
  135. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
  136. package/src/resources/extensions/gsd/tests/memory-store.test.ts +80 -93
  137. package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
  138. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +83 -93
  139. package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
  140. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
  141. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
  142. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +87 -96
  143. package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +125 -164
  144. package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
  145. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +35 -36
  146. package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
  147. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
  148. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
  149. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
  150. package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
  151. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
  152. package/src/resources/extensions/gsd/tests/parsers.test.ts +546 -611
  153. package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
  154. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
  155. package/src/resources/extensions/gsd/tests/preferences.test.ts +27 -0
  156. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
  157. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
  158. package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
  159. package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
  160. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
  161. package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
  162. package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
  163. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
  164. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
  165. package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
  166. package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
  167. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
  168. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
  169. package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
  170. package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
  171. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
  172. package/src/resources/extensions/gsd/tests/shared-wal.test.ts +19 -26
  173. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
  174. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
  175. package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
  176. package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
  177. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
  178. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +9 -11
  179. package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
  180. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
  181. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
  182. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
  183. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
  184. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
  185. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
  186. package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
  187. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
  188. package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
  189. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
  190. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
  191. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
  192. package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
  193. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
  194. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
  195. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
  196. package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
  197. /package/dist/web/standalone/.next/static/{fOnWQBjWXMKUs4bqTg530 → JyimLR2pZuvKEzv26gI3w}/_buildManifest.js +0 -0
  198. /package/dist/web/standalone/.next/static/{fOnWQBjWXMKUs4bqTg530 → JyimLR2pZuvKEzv26gI3w}/_ssgManifest.js +0 -0
@@ -12,20 +12,16 @@
12
12
  * Also covers dependency expansion (range syntax) and edge cases.
13
13
  */
14
14
 
15
+ import { describe, test } from 'node:test';
16
+ import assert from 'node:assert/strict';
15
17
  import { parseRoadmapSlices, expandDependencies } from '../roadmap-slices.ts';
16
- import { createTestContext } from './test-helpers.ts';
17
-
18
- const { assertEq, assertTrue, report } = createTestContext();
19
-
20
- async function main(): Promise<void> {
21
-
22
18
  // ═══════════════════════════════════════════════════════════════════════
23
19
  // A. Standard machine-readable format (should always work)
24
20
  // ═══════════════════════════════════════════════════════════════════════
25
21
 
26
- console.log('\n=== A. Standard checkbox format ===');
27
22
 
28
- {
23
+ describe('roadmap-parse-regression', () => {
24
+ test('A. Standard checkbox format', () => {
29
25
  const content = [
30
26
  '# M001: Test Project',
31
27
  '',
@@ -40,30 +36,27 @@ async function main(): Promise<void> {
40
36
  ].join('\n');
41
37
 
42
38
  const slices = parseRoadmapSlices(content);
43
- assertEq(slices.length, 3, 'standard format: 3 slices');
44
- assertEq(slices[0].id, 'S01', 'S01 id');
45
- assertEq(slices[0].title, 'First Slice', 'S01 title');
46
- assertEq(slices[0].done, false, 'S01 not done');
47
- assertEq(slices[0].risk, 'low', 'S01 risk');
48
- assertEq(slices[0].depends.length, 0, 'S01 no deps');
49
-
50
- assertEq(slices[1].id, 'S02', 'S02 id');
51
- assertEq(slices[1].depends.length, 1, 'S02 has 1 dep');
52
- assertEq(slices[1].depends[0], 'S01', 'S02 depends on S01');
53
-
54
- assertEq(slices[2].id, 'S03', 'S03 id');
55
- assertEq(slices[2].done, true, 'S03 is done');
56
- assertEq(slices[2].risk, 'high', 'S03 risk');
57
- assertEq(slices[2].depends.length, 2, 'S03 has 2 deps');
58
- }
39
+ assert.deepStrictEqual(slices.length, 3, 'standard format: 3 slices');
40
+ assert.deepStrictEqual(slices[0].id, 'S01', 'S01 id');
41
+ assert.deepStrictEqual(slices[0].title, 'First Slice', 'S01 title');
42
+ assert.deepStrictEqual(slices[0].done, false, 'S01 not done');
43
+ assert.deepStrictEqual(slices[0].risk, 'low', 'S01 risk');
44
+ assert.deepStrictEqual(slices[0].depends.length, 0, 'S01 no deps');
45
+
46
+ assert.deepStrictEqual(slices[1].id, 'S02', 'S02 id');
47
+ assert.deepStrictEqual(slices[1].depends.length, 1, 'S02 has 1 dep');
48
+ assert.deepStrictEqual(slices[1].depends[0], 'S01', 'S02 depends on S01');
49
+
50
+ assert.deepStrictEqual(slices[2].id, 'S03', 'S03 id');
51
+ assert.deepStrictEqual(slices[2].done, true, 'S03 is done');
52
+ assert.deepStrictEqual(slices[2].risk, 'high', 'S03 risk');
53
+ assert.deepStrictEqual(slices[2].depends.length, 2, 'S03 has 2 deps');
54
+ });
59
55
 
60
56
  // ═══════════════════════════════════════════════════════════════════════
61
57
  // B. Prose fallback: H2 with colon (the only format the old regex matched)
62
58
  // ═══════════════════════════════════════════════════════════════════════
63
-
64
- console.log('\n=== B. Prose fallback: H2 with colon ===');
65
-
66
- {
59
+ test('B. Prose fallback: H2 with colon', () => {
67
60
  const content = [
68
61
  '# M001: Test',
69
62
  '',
@@ -78,20 +71,17 @@ async function main(): Promise<void> {
78
71
  ].join('\n');
79
72
 
80
73
  const slices = parseRoadmapSlices(content);
81
- assertEq(slices.length, 2, 'prose H2 colon: 2 slices');
82
- assertEq(slices[0].id, 'S01', 'S01 id');
83
- assertEq(slices[0].title, 'Setup Foundation', 'S01 title');
84
- assertEq(slices[1].id, 'S02', 'S02 id');
85
- assertEq(slices[1].title, 'Core Features', 'S02 title');
86
- }
74
+ assert.deepStrictEqual(slices.length, 2, 'prose H2 colon: 2 slices');
75
+ assert.deepStrictEqual(slices[0].id, 'S01', 'S01 id');
76
+ assert.deepStrictEqual(slices[0].title, 'Setup Foundation', 'S01 title');
77
+ assert.deepStrictEqual(slices[1].id, 'S02', 'S02 id');
78
+ assert.deepStrictEqual(slices[1].title, 'Core Features', 'S02 title');
79
+ });
87
80
 
88
81
  // ═══════════════════════════════════════════════════════════════════════
89
82
  // C. Regression #1248: H3 headers (the old regex only matched ##)
90
83
  // ═══════════════════════════════════════════════════════════════════════
91
-
92
- console.log('\n=== C. #1248: H3 headers ===');
93
-
94
- {
84
+ test('C. #1248: H3 headers', () => {
95
85
  const content = [
96
86
  '# M001: Test',
97
87
  '',
@@ -106,18 +96,15 @@ async function main(): Promise<void> {
106
96
  ].join('\n');
107
97
 
108
98
  const slices = parseRoadmapSlices(content);
109
- assertEq(slices.length, 2, '#1248 H3: 2 slices parsed');
110
- assertEq(slices[0].id, 'S01', 'S01 from H3');
111
- assertEq(slices[1].id, 'S02', 'S02 from H3');
112
- }
99
+ assert.deepStrictEqual(slices.length, 2, '#1248 H3: 2 slices parsed');
100
+ assert.deepStrictEqual(slices[0].id, 'S01', 'S01 from H3');
101
+ assert.deepStrictEqual(slices[1].id, 'S02', 'S02 from H3');
102
+ });
113
103
 
114
104
  // ═══════════════════════════════════════════════════════════════════════
115
105
  // D. Regression #1248: H4 headers
116
106
  // ═══════════════════════════════════════════════════════════════════════
117
-
118
- console.log('\n=== D. #1248: H4 headers ===');
119
-
120
- {
107
+ test('D. #1248: H4 headers', () => {
121
108
  const content = [
122
109
  '# M001: Test',
123
110
  '',
@@ -128,16 +115,13 @@ async function main(): Promise<void> {
128
115
  ].join('\n');
129
116
 
130
117
  const slices = parseRoadmapSlices(content);
131
- assertEq(slices.length, 2, '#1248 H4: 2 slices parsed');
132
- }
118
+ assert.deepStrictEqual(slices.length, 2, '#1248 H4: 2 slices parsed');
119
+ });
133
120
 
134
121
  // ═══════════════════════════════════════════════════════════════════════
135
122
  // E. Regression #1248: H1 header (unusual but LLMs produce it)
136
123
  // ═══════════════════════════════════════════════════════════════════════
137
-
138
- console.log('\n=== E. #1248: H1 headers ===');
139
-
140
- {
124
+ test('E. #1248: H1 headers', () => {
141
125
  const content = [
142
126
  '# S01: Setup Foundation',
143
127
  '',
@@ -150,97 +134,76 @@ async function main(): Promise<void> {
150
134
  ].join('\n');
151
135
 
152
136
  const slices = parseRoadmapSlices(content);
153
- assertEq(slices.length, 2, '#1248 H1: 2 slices parsed');
154
- }
137
+ assert.deepStrictEqual(slices.length, 2, '#1248 H1: 2 slices parsed');
138
+ });
155
139
 
156
140
  // ═══════════════════════════════════════════════════════════════════════
157
141
  // F. Regression #1248: Bold-wrapped IDs
158
142
  // ═══════════════════════════════════════════════════════════════════════
159
-
160
- console.log('\n=== F. #1248: Bold-wrapped ===');
161
-
162
- {
143
+ test('F. #1248: Bold-wrapped', () => {
163
144
  const content1 = '## **S01: Setup Foundation**\n\nDo stuff.\n\n## **S02: Features**\n\nMore stuff.\n';
164
145
  const slices1 = parseRoadmapSlices(content1);
165
- assertEq(slices1.length, 2, 'bold-wrapped: 2 slices');
166
- assertEq(slices1[0].title, 'Setup Foundation', 'bold-wrapped: title extracted without bold');
146
+ assert.deepStrictEqual(slices1.length, 2, 'bold-wrapped: 2 slices');
147
+ assert.deepStrictEqual(slices1[0].title, 'Setup Foundation', 'bold-wrapped: title extracted without bold');
167
148
 
168
149
  const content2 = '## **S01**: Setup Foundation\n\n## **S02**: Features\n';
169
150
  const slices2 = parseRoadmapSlices(content2);
170
- assertEq(slices2.length, 2, 'bold ID only: 2 slices');
171
- }
151
+ assert.deepStrictEqual(slices2.length, 2, 'bold ID only: 2 slices');
152
+ });
172
153
 
173
154
  // ═══════════════════════════════════════════════════════════════════════
174
155
  // G. Regression #1248: Dot separator
175
156
  // ═══════════════════════════════════════════════════════════════════════
176
-
177
- console.log('\n=== G. #1248: Dot separator ===');
178
-
179
- {
157
+ test('G. #1248: Dot separator', () => {
180
158
  const content = '## S01. Setup Foundation\n\n## S02. Core Features\n';
181
159
  const slices = parseRoadmapSlices(content);
182
- assertEq(slices.length, 2, 'dot separator: 2 slices');
183
- assertEq(slices[0].title, 'Setup Foundation', 'dot separator: title');
184
- }
160
+ assert.deepStrictEqual(slices.length, 2, 'dot separator: 2 slices');
161
+ assert.deepStrictEqual(slices[0].title, 'Setup Foundation', 'dot separator: title');
162
+ });
185
163
 
186
164
  // ═══════════════════════════════════════════════════════════════════════
187
165
  // H. Regression #1248: Em dash separator
188
166
  // ═══════════════════════════════════════════════════════════════════════
189
-
190
- console.log('\n=== H. #1248: Em/en dash separators ===');
191
-
192
- {
167
+ test('H. #1248: Em/en dash separators', () => {
193
168
  const content = '## S01 — Setup Foundation\n\n## S02 – Core Features\n';
194
169
  const slices = parseRoadmapSlices(content);
195
- assertEq(slices.length, 2, 'em/en dash: 2 slices');
196
- }
170
+ assert.deepStrictEqual(slices.length, 2, 'em/en dash: 2 slices');
171
+ });
197
172
 
198
173
  // ═══════════════════════════════════════════════════════════════════════
199
174
  // I. Regression #1248: Space-only separator (no punctuation)
200
175
  // ═══════════════════════════════════════════════════════════════════════
201
-
202
- console.log('\n=== I. #1248: Space-only separator ===');
203
-
204
- {
176
+ test('I. #1248: Space-only separator', () => {
205
177
  const content = '## S01 Setup Foundation\n\n## S02 Core Features\n';
206
178
  const slices = parseRoadmapSlices(content);
207
- assertEq(slices.length, 2, 'space-only: 2 slices');
208
- assertEq(slices[0].title, 'Setup Foundation', 'space-only: title');
209
- }
179
+ assert.deepStrictEqual(slices.length, 2, 'space-only: 2 slices');
180
+ assert.deepStrictEqual(slices[0].title, 'Setup Foundation', 'space-only: title');
181
+ });
210
182
 
211
183
  // ═══════════════════════════════════════════════════════════════════════
212
184
  // J. Regression #1248: Non-zero-padded IDs
213
185
  // ═══════════════════════════════════════════════════════════════════════
214
-
215
- console.log('\n=== J. #1248: Non-zero-padded IDs ===');
216
-
217
- {
186
+ test('J. #1248: Non-zero-padded IDs', () => {
218
187
  const content = '## S1: Setup\n\n## S2: Features\n';
219
188
  const slices = parseRoadmapSlices(content);
220
- assertEq(slices.length, 2, 'non-padded: 2 slices');
221
- assertEq(slices[0].id, 'S1', 'non-padded: S1');
222
- }
189
+ assert.deepStrictEqual(slices.length, 2, 'non-padded: 2 slices');
190
+ assert.deepStrictEqual(slices[0].id, 'S1', 'non-padded: S1');
191
+ });
223
192
 
224
193
  // ═══════════════════════════════════════════════════════════════════════
225
194
  // K. Regression #1248: "Slice" prefix
226
195
  // ═══════════════════════════════════════════════════════════════════════
227
-
228
- console.log('\n=== K. #1248: "Slice" prefix ===');
229
-
230
- {
196
+ test('K. #1248: "Slice" prefix', () => {
231
197
  const content = '## Slice S01: Setup Foundation\n\n## Slice S02: Core Features\n';
232
198
  const slices = parseRoadmapSlices(content);
233
- assertEq(slices.length, 2, 'Slice prefix: 2 slices');
234
- assertEq(slices[0].id, 'S01', 'Slice prefix: S01');
235
- }
199
+ assert.deepStrictEqual(slices.length, 2, 'Slice prefix: 2 slices');
200
+ assert.deepStrictEqual(slices[0].id, 'S01', 'Slice prefix: S01');
201
+ });
236
202
 
237
203
  // ═══════════════════════════════════════════════════════════════════════
238
204
  // L. Prose with "Depends on:" line
239
205
  // ═══════════════════════════════════════════════════════════════════════
240
-
241
- console.log('\n=== L. Prose with Depends on: ===');
242
-
243
- {
206
+ test('L. Prose with Depends on:', () => {
244
207
  const content = [
245
208
  '## S01: Foundation',
246
209
  '',
@@ -254,20 +217,17 @@ async function main(): Promise<void> {
254
217
  ].join('\n');
255
218
 
256
219
  const slices = parseRoadmapSlices(content);
257
- assertEq(slices.length, 2, 'prose deps: 2 slices');
258
- assertEq(slices[1].depends.length, 1, 'S02 has 1 dep');
259
- assertEq(slices[1].depends[0], 'S01', 'S02 depends on S01');
260
- }
220
+ assert.deepStrictEqual(slices.length, 2, 'prose deps: 2 slices');
221
+ assert.deepStrictEqual(slices[1].depends.length, 1, 'S02 has 1 dep');
222
+ assert.deepStrictEqual(slices[1].depends[0], 'S01', 'S02 depends on S01');
223
+ });
261
224
 
262
225
  // ═══════════════════════════════════════════════════════════════════════
263
226
  // M. Empty / edge cases
264
227
  // ═══════════════════════════════════════════════════════════════════════
265
-
266
- console.log('\n=== M. Edge cases ===');
267
-
268
- {
269
- assertEq(parseRoadmapSlices('').length, 0, 'empty content → 0 slices');
270
- assertEq(parseRoadmapSlices('# Just a title\n\nSome text.').length, 0, 'no slices at all → 0');
228
+ test('M. Edge cases', () => {
229
+ assert.deepStrictEqual(parseRoadmapSlices('').length, 0, 'empty content → 0 slices');
230
+ assert.deepStrictEqual(parseRoadmapSlices('# Just a title\n\nSome text.').length, 0, 'no slices at all → 0');
271
231
 
272
232
  // Mixed format: ## Slices section with one checkbox + prose below
273
233
  const mixed = [
@@ -281,81 +241,69 @@ async function main(): Promise<void> {
281
241
  ].join('\n');
282
242
  const mixedSlices = parseRoadmapSlices(mixed);
283
243
  // The ## Slices section takes priority — prose headers outside it aren't picked up
284
- assertEq(mixedSlices.length, 1, 'mixed: only 1 slice from ## Slices section');
285
- assertEq(mixedSlices[0].id, 'S01', 'mixed: S01 from checkbox');
286
- }
244
+ assert.deepStrictEqual(mixedSlices.length, 1, 'mixed: only 1 slice from ## Slices section');
245
+ assert.deepStrictEqual(mixedSlices[0].id, 'S01', 'mixed: S01 from checkbox');
246
+ });
287
247
 
288
248
  // ═══════════════════════════════════════════════════════════════════════
289
249
  // N. Dependency range expansion
290
250
  // ═══════════════════════════════════════════════════════════════════════
291
-
292
- console.log('\n=== N. Dependency range expansion ===');
293
-
294
- {
295
- assertEq(
251
+ test('N. Dependency range expansion', () => {
252
+ assert.deepStrictEqual(
296
253
  expandDependencies(['S01-S04']),
297
254
  ['S01', 'S02', 'S03', 'S04'],
298
255
  'S01-S04 → 4 individual deps',
299
256
  );
300
257
 
301
- assertEq(
258
+ assert.deepStrictEqual(
302
259
  expandDependencies(['S01..S03']),
303
260
  ['S01', 'S02', 'S03'],
304
261
  'S01..S03 → 3 individual deps',
305
262
  );
306
263
 
307
- assertEq(
264
+ assert.deepStrictEqual(
308
265
  expandDependencies(['S01']),
309
266
  ['S01'],
310
267
  'single dep passes through',
311
268
  );
312
269
 
313
- assertEq(
270
+ assert.deepStrictEqual(
314
271
  expandDependencies(['S01', 'S03-S05']),
315
272
  ['S01', 'S03', 'S04', 'S05'],
316
273
  'mixed single + range',
317
274
  );
318
275
 
319
- assertEq(
276
+ assert.deepStrictEqual(
320
277
  expandDependencies(['']),
321
278
  [],
322
279
  'empty string filtered out',
323
280
  );
324
- }
281
+ });
325
282
 
326
283
  // ═══════════════════════════════════════════════════════════════════════
327
284
  // O. No-separator colon-less: "S01:Title" (no space after colon)
328
285
  // ═══════════════════════════════════════════════════════════════════════
329
-
330
- console.log('\n=== O. No space after colon ===');
331
-
332
- {
286
+ test('O. No space after colon', () => {
333
287
  const content = '## S01:Foundation\n\n## S02:Features\n';
334
288
  const slices = parseRoadmapSlices(content);
335
289
  // The regex uses [:\s.—–-]* which allows colon with no space
336
- assertEq(slices.length, 2, 'no-space-colon: 2 slices');
337
- }
290
+ assert.deepStrictEqual(slices.length, 2, 'no-space-colon: 2 slices');
291
+ });
338
292
 
339
293
  // ═══════════════════════════════════════════════════════════════════════
340
294
  // P. Three-digit padded IDs
341
295
  // ═══════════════════════════════════════════════════════════════════════
342
-
343
- console.log('\n=== P. Three-digit padded IDs ===');
344
-
345
- {
296
+ test('P. Three-digit padded IDs', () => {
346
297
  const content = '## S001: Foundation\n\n## S002: Features\n';
347
298
  const slices = parseRoadmapSlices(content);
348
- assertEq(slices.length, 2, 'three-digit: 2 slices');
349
- assertEq(slices[0].id, 'S001', 'three-digit: S001');
350
- }
299
+ assert.deepStrictEqual(slices.length, 2, 'three-digit: 2 slices');
300
+ assert.deepStrictEqual(slices[0].id, 'S001', 'three-digit: S001');
301
+ });
351
302
 
352
303
  // ═══════════════════════════════════════════════════════════════════════
353
304
  // Q. Regression #1736: Table format under ## Slices
354
305
  // ═══════════════════════════════════════════════════════════════════════
355
-
356
- console.log('\n=== Q. #1736: Table format under ## Slices ===');
357
-
358
- {
306
+ test('Q. #1736: Table format under ## Slices', () => {
359
307
  const content = [
360
308
  '# M001: Test',
361
309
  '',
@@ -371,22 +319,19 @@ async function main(): Promise<void> {
371
319
  ].join('\n');
372
320
 
373
321
  const slices = parseRoadmapSlices(content);
374
- assertEq(slices.length, 3, '#1736 table: 3 slices');
375
- assertEq(slices[0].id, 'S01', '#1736 table: S01 id');
376
- assertEq(slices[0].title, 'Setup Foundation', '#1736 table: S01 title');
377
- assertEq(slices[0].done, true, '#1736 table: S01 done');
378
- assertEq(slices[0].risk, 'low', '#1736 table: S01 risk');
379
- assertEq(slices[1].done, false, '#1736 table: S02 not done');
380
- assertEq(slices[2].done, true, '#1736 table: S03 done');
381
- }
322
+ assert.deepStrictEqual(slices.length, 3, '#1736 table: 3 slices');
323
+ assert.deepStrictEqual(slices[0].id, 'S01', '#1736 table: S01 id');
324
+ assert.deepStrictEqual(slices[0].title, 'Setup Foundation', '#1736 table: S01 title');
325
+ assert.deepStrictEqual(slices[0].done, true, '#1736 table: S01 done');
326
+ assert.deepStrictEqual(slices[0].risk, 'low', '#1736 table: S01 risk');
327
+ assert.deepStrictEqual(slices[1].done, false, '#1736 table: S02 not done');
328
+ assert.deepStrictEqual(slices[2].done, true, '#1736 table: S03 done');
329
+ });
382
330
 
383
331
  // ═══════════════════════════════════════════════════════════════════════
384
332
  // R. Regression #1736: Table format under ## Slice Overview
385
333
  // ═══════════════════════════════════════════════════════════════════════
386
-
387
- console.log('\n=== R. #1736: Table format under ## Slice Overview ===');
388
-
389
- {
334
+ test('R. #1736: Table format under ## Slice Overview', () => {
390
335
  const content = [
391
336
  '# M002: Overview Heading',
392
337
  '',
@@ -400,18 +345,15 @@ async function main(): Promise<void> {
400
345
  ].join('\n');
401
346
 
402
347
  const slices = parseRoadmapSlices(content);
403
- assertEq(slices.length, 2, '#1736 overview: 2 slices');
404
- assertEq(slices[0].done, true, '#1736 overview: S01 done');
405
- assertEq(slices[1].done, false, '#1736 overview: S02 not done');
406
- }
348
+ assert.deepStrictEqual(slices.length, 2, '#1736 overview: 2 slices');
349
+ assert.deepStrictEqual(slices[0].done, true, '#1736 overview: S01 done');
350
+ assert.deepStrictEqual(slices[1].done, false, '#1736 overview: S02 not done');
351
+ });
407
352
 
408
353
  // ═══════════════════════════════════════════════════════════════════════
409
354
  // S. Regression #1736: Table with Done/Complete text status
410
355
  // ═══════════════════════════════════════════════════════════════════════
411
-
412
- console.log('\n=== S. #1736: Table with text status ===');
413
-
414
- {
356
+ test('S. #1736: Table with text status', () => {
415
357
  const content = [
416
358
  '# M003: Status Text',
417
359
  '',
@@ -426,19 +368,16 @@ async function main(): Promise<void> {
426
368
  ].join('\n');
427
369
 
428
370
  const slices = parseRoadmapSlices(content);
429
- assertEq(slices.length, 3, '#1736 text status: 3 slices');
430
- assertTrue(slices[0].done, '#1736 text status: Done = true');
431
- assertTrue(!slices[1].done, '#1736 text status: Pending = false');
432
- assertTrue(slices[2].done, '#1736 text status: Completed = true');
433
- }
371
+ assert.deepStrictEqual(slices.length, 3, '#1736 text status: 3 slices');
372
+ assert.ok(slices[0].done, '#1736 text status: Done = true');
373
+ assert.ok(!slices[1].done, '#1736 text status: Pending = false');
374
+ assert.ok(slices[2].done, '#1736 text status: Completed = true');
375
+ });
434
376
 
435
377
  // ═══════════════════════════════════════════════════════════════════════
436
378
  // T. Regression #1736: Checkbox format still works after table support
437
379
  // ═══════════════════════════════════════════════════════════════════════
438
-
439
- console.log('\n=== T. #1736: Checkbox format unchanged ===');
440
-
441
- {
380
+ test('T. #1736: Checkbox format unchanged', () => {
442
381
  const content = [
443
382
  '# M005: Unchanged',
444
383
  '',
@@ -451,16 +390,10 @@ async function main(): Promise<void> {
451
390
  ].join('\n');
452
391
 
453
392
  const slices = parseRoadmapSlices(content);
454
- assertEq(slices.length, 2, '#1736 checkbox compat: 2 slices');
455
- assertEq(slices[0].done, true, '#1736 checkbox compat: S01 done');
456
- assertEq(slices[0].demo, 'demo works.', '#1736 checkbox compat: demo');
457
- assertEq(slices[1].done, false, '#1736 checkbox compat: S02 not done');
458
- }
459
-
460
- report();
461
- }
462
-
463
- main().catch((error) => {
464
- console.error(error);
465
- process.exit(1);
393
+ assert.deepStrictEqual(slices.length, 2, '#1736 checkbox compat: 2 slices');
394
+ assert.deepStrictEqual(slices[0].done, true, '#1736 checkbox compat: S01 done');
395
+ assert.deepStrictEqual(slices[0].demo, 'demo works.', '#1736 checkbox compat: demo');
396
+ assert.deepStrictEqual(slices[1].done, false, '#1736 checkbox compat: S02 not done');
397
+ });
398
+
466
399
  });