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
@@ -38,361 +38,315 @@ function cleanup(dir: string): void {
38
38
 
39
39
  // ─── detectProjectState ─────────────────────────────────────────────────────────
40
40
 
41
- test("detectProjectState: empty directory returns state=none", () => {
41
+ test("detectProjectState: empty directory returns state=none", (t) => {
42
42
  const dir = makeTempDir("empty");
43
- try {
44
- const result = detectProjectState(dir);
45
- assert.equal(result.state, "none");
46
- assert.equal(result.v1, undefined);
47
- assert.equal(result.v2, undefined);
48
- } finally {
49
- cleanup(dir);
50
- }
43
+ t.after(() => cleanup(dir));
44
+
45
+ const result = detectProjectState(dir);
46
+ assert.equal(result.state, "none");
47
+ assert.equal(result.v1, undefined);
48
+ assert.equal(result.v2, undefined);
51
49
  });
52
50
 
53
- test("detectProjectState: directory with .gsd/milestones/M001 returns v2-gsd", () => {
51
+ test("detectProjectState: directory with .gsd/milestones/M001 returns v2-gsd", (t) => {
54
52
  const dir = makeTempDir("v2-gsd");
55
- try {
56
- mkdirSync(join(dir, ".gsd", "milestones", "M001"), { recursive: true });
57
- const result = detectProjectState(dir);
58
- assert.equal(result.state, "v2-gsd");
59
- assert.ok(result.v2);
60
- assert.equal(result.v2!.milestoneCount, 1);
61
- } finally {
62
- cleanup(dir);
63
- }
53
+ t.after(() => cleanup(dir));
54
+
55
+ mkdirSync(join(dir, ".gsd", "milestones", "M001"), { recursive: true });
56
+ const result = detectProjectState(dir);
57
+ assert.equal(result.state, "v2-gsd");
58
+ assert.ok(result.v2);
59
+ assert.equal(result.v2!.milestoneCount, 1);
64
60
  });
65
61
 
66
- test("detectProjectState: directory with empty .gsd/milestones returns v2-gsd-empty", () => {
62
+ test("detectProjectState: directory with empty .gsd/milestones returns v2-gsd-empty", (t) => {
67
63
  const dir = makeTempDir("v2-empty");
68
- try {
69
- mkdirSync(join(dir, ".gsd", "milestones"), { recursive: true });
70
- const result = detectProjectState(dir);
71
- assert.equal(result.state, "v2-gsd-empty");
72
- assert.ok(result.v2);
73
- assert.equal(result.v2!.milestoneCount, 0);
74
- } finally {
75
- cleanup(dir);
76
- }
64
+ t.after(() => cleanup(dir));
65
+
66
+ mkdirSync(join(dir, ".gsd", "milestones"), { recursive: true });
67
+ const result = detectProjectState(dir);
68
+ assert.equal(result.state, "v2-gsd-empty");
69
+ assert.ok(result.v2);
70
+ assert.equal(result.v2!.milestoneCount, 0);
77
71
  });
78
72
 
79
- test("detectProjectState: directory with .planning/ returns v1-planning", () => {
73
+ test("detectProjectState: directory with .planning/ returns v1-planning", (t) => {
80
74
  const dir = makeTempDir("v1-planning");
81
- try {
82
- mkdirSync(join(dir, ".planning", "phases", "01-setup"), { recursive: true });
83
- writeFileSync(join(dir, ".planning", "ROADMAP.md"), "# Roadmap\n", "utf-8");
84
- const result = detectProjectState(dir);
85
- assert.equal(result.state, "v1-planning");
86
- assert.ok(result.v1);
87
- assert.equal(result.v1!.hasRoadmap, true);
88
- assert.equal(result.v1!.hasPhasesDir, true);
89
- assert.equal(result.v1!.phaseCount, 1);
90
- } finally {
91
- cleanup(dir);
92
- }
75
+ t.after(() => cleanup(dir));
76
+
77
+ mkdirSync(join(dir, ".planning", "phases", "01-setup"), { recursive: true });
78
+ writeFileSync(join(dir, ".planning", "ROADMAP.md"), "# Roadmap\n", "utf-8");
79
+ const result = detectProjectState(dir);
80
+ assert.equal(result.state, "v1-planning");
81
+ assert.ok(result.v1);
82
+ assert.equal(result.v1!.hasRoadmap, true);
83
+ assert.equal(result.v1!.hasPhasesDir, true);
84
+ assert.equal(result.v1!.phaseCount, 1);
93
85
  });
94
86
 
95
- test("detectProjectState: v2 takes priority over v1 when both exist", () => {
87
+ test("detectProjectState: v2 takes priority over v1 when both exist", (t) => {
96
88
  const dir = makeTempDir("both");
97
- try {
98
- mkdirSync(join(dir, ".gsd", "milestones", "M001"), { recursive: true });
99
- mkdirSync(join(dir, ".planning"), { recursive: true });
100
- const result = detectProjectState(dir);
101
- assert.equal(result.state, "v2-gsd");
102
- } finally {
103
- cleanup(dir);
104
- }
89
+ t.after(() => cleanup(dir));
90
+
91
+ mkdirSync(join(dir, ".gsd", "milestones", "M001"), { recursive: true });
92
+ mkdirSync(join(dir, ".planning"), { recursive: true });
93
+ const result = detectProjectState(dir);
94
+ assert.equal(result.state, "v2-gsd");
105
95
  });
106
96
 
107
- test("detectProjectState: detects preferences in .gsd/", () => {
97
+ test("detectProjectState: detects preferences in .gsd/", (t) => {
108
98
  const dir = makeTempDir("prefs");
109
- try {
110
- mkdirSync(join(dir, ".gsd", "milestones"), { recursive: true });
111
- writeFileSync(join(dir, ".gsd", "preferences.md"), "---\nversion: 1\n---\n", "utf-8");
112
- const result = detectProjectState(dir);
113
- assert.ok(result.v2);
114
- assert.equal(result.v2!.hasPreferences, true);
115
- } finally {
116
- cleanup(dir);
117
- }
99
+ t.after(() => cleanup(dir));
100
+
101
+ mkdirSync(join(dir, ".gsd", "milestones"), { recursive: true });
102
+ writeFileSync(join(dir, ".gsd", "preferences.md"), "---\nversion: 1\n---\n", "utf-8");
103
+ const result = detectProjectState(dir);
104
+ assert.ok(result.v2);
105
+ assert.equal(result.v2!.hasPreferences, true);
118
106
  });
119
107
 
120
108
  // ─── detectV1Planning ───────────────────────────────────────────────────────────
121
109
 
122
- test("detectV1Planning: returns null for missing .planning/", () => {
110
+ test("detectV1Planning: returns null for missing .planning/", (t) => {
123
111
  const dir = makeTempDir("no-v1");
124
- try {
125
- assert.equal(detectV1Planning(dir), null);
126
- } finally {
127
- cleanup(dir);
128
- }
112
+ t.after(() => cleanup(dir));
113
+
114
+ assert.equal(detectV1Planning(dir), null);
129
115
  });
130
116
 
131
- test("detectV1Planning: returns null when .planning is a file", () => {
117
+ test("detectV1Planning: returns null when .planning is a file", (t) => {
132
118
  const dir = makeTempDir("v1-file");
133
- try {
134
- writeFileSync(join(dir, ".planning"), "not a directory", "utf-8");
135
- assert.equal(detectV1Planning(dir), null);
136
- } finally {
137
- cleanup(dir);
138
- }
119
+ t.after(() => cleanup(dir));
120
+
121
+ writeFileSync(join(dir, ".planning"), "not a directory", "utf-8");
122
+ assert.equal(detectV1Planning(dir), null);
139
123
  });
140
124
 
141
- test("detectV1Planning: detects phases directory with multiple phases", () => {
125
+ test("detectV1Planning: detects phases directory with multiple phases", (t) => {
142
126
  const dir = makeTempDir("v1-phases");
143
- try {
144
- mkdirSync(join(dir, ".planning", "phases", "01-setup"), { recursive: true });
145
- mkdirSync(join(dir, ".planning", "phases", "02-core"), { recursive: true });
146
- mkdirSync(join(dir, ".planning", "phases", "03-deploy"), { recursive: true });
147
- const result = detectV1Planning(dir);
148
- assert.ok(result);
149
- assert.equal(result!.phaseCount, 3);
150
- assert.equal(result!.hasPhasesDir, true);
151
- } finally {
152
- cleanup(dir);
153
- }
127
+ t.after(() => cleanup(dir));
128
+
129
+ mkdirSync(join(dir, ".planning", "phases", "01-setup"), { recursive: true });
130
+ mkdirSync(join(dir, ".planning", "phases", "02-core"), { recursive: true });
131
+ mkdirSync(join(dir, ".planning", "phases", "03-deploy"), { recursive: true });
132
+ const result = detectV1Planning(dir);
133
+ assert.ok(result);
134
+ assert.equal(result!.phaseCount, 3);
135
+ assert.equal(result!.hasPhasesDir, true);
154
136
  });
155
137
 
156
- test("detectV1Planning: detects ROADMAP.md", () => {
138
+ test("detectV1Planning: detects ROADMAP.md", (t) => {
157
139
  const dir = makeTempDir("v1-roadmap");
158
- try {
159
- mkdirSync(join(dir, ".planning"), { recursive: true });
160
- writeFileSync(join(dir, ".planning", "ROADMAP.md"), "# Roadmap", "utf-8");
161
- const result = detectV1Planning(dir);
162
- assert.ok(result);
163
- assert.equal(result!.hasRoadmap, true);
164
- assert.equal(result!.hasPhasesDir, false);
165
- assert.equal(result!.phaseCount, 0);
166
- } finally {
167
- cleanup(dir);
168
- }
140
+ t.after(() => cleanup(dir));
141
+
142
+ mkdirSync(join(dir, ".planning"), { recursive: true });
143
+ writeFileSync(join(dir, ".planning", "ROADMAP.md"), "# Roadmap", "utf-8");
144
+ const result = detectV1Planning(dir);
145
+ assert.ok(result);
146
+ assert.equal(result!.hasRoadmap, true);
147
+ assert.equal(result!.hasPhasesDir, false);
148
+ assert.equal(result!.phaseCount, 0);
169
149
  });
170
150
 
171
151
  // ─── detectProjectSignals ───────────────────────────────────────────────────────
172
152
 
173
- test("detectProjectSignals: empty directory", () => {
153
+ test("detectProjectSignals: empty directory", (t) => {
174
154
  const dir = makeTempDir("signals-empty");
175
- try {
176
- const signals = detectProjectSignals(dir);
177
- assert.deepEqual(signals.detectedFiles, []);
178
- assert.equal(signals.isGitRepo, false);
179
- assert.equal(signals.isMonorepo, false);
180
- assert.equal(signals.primaryLanguage, undefined);
181
- assert.equal(signals.hasCI, false);
182
- assert.equal(signals.hasTests, false);
183
- assert.deepEqual(signals.verificationCommands, []);
184
- } finally {
185
- cleanup(dir);
186
- }
155
+ t.after(() => cleanup(dir));
156
+
157
+ const signals = detectProjectSignals(dir);
158
+ assert.deepEqual(signals.detectedFiles, []);
159
+ assert.equal(signals.isGitRepo, false);
160
+ assert.equal(signals.isMonorepo, false);
161
+ assert.equal(signals.primaryLanguage, undefined);
162
+ assert.equal(signals.hasCI, false);
163
+ assert.equal(signals.hasTests, false);
164
+ assert.deepEqual(signals.verificationCommands, []);
187
165
  });
188
166
 
189
- test("detectProjectSignals: Node.js project", () => {
167
+ test("detectProjectSignals: Node.js project", (t) => {
190
168
  const dir = makeTempDir("signals-node");
191
- try {
192
- writeFileSync(
193
- join(dir, "package.json"),
194
- JSON.stringify({
195
- name: "test-project",
196
- scripts: {
197
- test: "jest",
198
- build: "tsc",
199
- lint: "eslint .",
200
- },
201
- }),
202
- "utf-8",
203
- );
204
- writeFileSync(join(dir, "package-lock.json"), "{}", "utf-8");
205
- mkdirSync(join(dir, ".git"), { recursive: true });
206
-
207
- const signals = detectProjectSignals(dir);
208
- assert.ok(signals.detectedFiles.includes("package.json"));
209
- assert.equal(signals.primaryLanguage, "javascript/typescript");
210
- assert.equal(signals.isGitRepo, true);
211
- assert.equal(signals.packageManager, "npm");
212
- assert.ok(signals.verificationCommands.includes("npm test"));
213
- assert.ok(signals.verificationCommands.some(c => c.includes("build")));
214
- assert.ok(signals.verificationCommands.some(c => c.includes("lint")));
215
- } finally {
216
- cleanup(dir);
217
- }
169
+ t.after(() => cleanup(dir));
170
+
171
+ writeFileSync(
172
+ join(dir, "package.json"),
173
+ JSON.stringify({
174
+ name: "test-project",
175
+ scripts: {
176
+ test: "jest",
177
+ build: "tsc",
178
+ lint: "eslint .",
179
+ },
180
+ }),
181
+ "utf-8",
182
+ );
183
+ writeFileSync(join(dir, "package-lock.json"), "{}", "utf-8");
184
+ mkdirSync(join(dir, ".git"), { recursive: true });
185
+
186
+ const signals = detectProjectSignals(dir);
187
+ assert.ok(signals.detectedFiles.includes("package.json"));
188
+ assert.equal(signals.primaryLanguage, "javascript/typescript");
189
+ assert.equal(signals.isGitRepo, true);
190
+ assert.equal(signals.packageManager, "npm");
191
+ assert.ok(signals.verificationCommands.includes("npm test"));
192
+ assert.ok(signals.verificationCommands.some(c => c.includes("build")));
193
+ assert.ok(signals.verificationCommands.some(c => c.includes("lint")));
218
194
  });
219
195
 
220
- test("detectProjectSignals: Rust project", () => {
196
+ test("detectProjectSignals: Rust project", (t) => {
221
197
  const dir = makeTempDir("signals-rust");
222
- try {
223
- writeFileSync(join(dir, "Cargo.toml"), '[package]\nname = "test"\n', "utf-8");
224
- const signals = detectProjectSignals(dir);
225
- assert.ok(signals.detectedFiles.includes("Cargo.toml"));
226
- assert.equal(signals.primaryLanguage, "rust");
227
- assert.ok(signals.verificationCommands.includes("cargo test"));
228
- assert.ok(signals.verificationCommands.includes("cargo clippy"));
229
- } finally {
230
- cleanup(dir);
231
- }
198
+ t.after(() => cleanup(dir));
199
+
200
+ writeFileSync(join(dir, "Cargo.toml"), '[package]\nname = "test"\n', "utf-8");
201
+ const signals = detectProjectSignals(dir);
202
+ assert.ok(signals.detectedFiles.includes("Cargo.toml"));
203
+ assert.equal(signals.primaryLanguage, "rust");
204
+ assert.ok(signals.verificationCommands.includes("cargo test"));
205
+ assert.ok(signals.verificationCommands.includes("cargo clippy"));
232
206
  });
233
207
 
234
- test("detectProjectSignals: Go project", () => {
208
+ test("detectProjectSignals: Go project", (t) => {
235
209
  const dir = makeTempDir("signals-go");
236
- try {
237
- writeFileSync(join(dir, "go.mod"), "module example.com/test\n", "utf-8");
238
- const signals = detectProjectSignals(dir);
239
- assert.ok(signals.detectedFiles.includes("go.mod"));
240
- assert.equal(signals.primaryLanguage, "go");
241
- assert.ok(signals.verificationCommands.includes("go test ./..."));
242
- } finally {
243
- cleanup(dir);
244
- }
210
+ t.after(() => cleanup(dir));
211
+
212
+ writeFileSync(join(dir, "go.mod"), "module example.com/test\n", "utf-8");
213
+ const signals = detectProjectSignals(dir);
214
+ assert.ok(signals.detectedFiles.includes("go.mod"));
215
+ assert.equal(signals.primaryLanguage, "go");
216
+ assert.ok(signals.verificationCommands.includes("go test ./..."));
245
217
  });
246
218
 
247
- test("detectProjectSignals: Python project", () => {
219
+ test("detectProjectSignals: Python project", (t) => {
248
220
  const dir = makeTempDir("signals-python");
249
- try {
250
- writeFileSync(join(dir, "pyproject.toml"), "[tool.poetry]\n", "utf-8");
251
- const signals = detectProjectSignals(dir);
252
- assert.ok(signals.detectedFiles.includes("pyproject.toml"));
253
- assert.equal(signals.primaryLanguage, "python");
254
- assert.ok(signals.verificationCommands.includes("pytest"));
255
- } finally {
256
- cleanup(dir);
257
- }
221
+ t.after(() => cleanup(dir));
222
+
223
+ writeFileSync(join(dir, "pyproject.toml"), "[tool.poetry]\n", "utf-8");
224
+ const signals = detectProjectSignals(dir);
225
+ assert.ok(signals.detectedFiles.includes("pyproject.toml"));
226
+ assert.equal(signals.primaryLanguage, "python");
227
+ assert.ok(signals.verificationCommands.includes("pytest"));
258
228
  });
259
229
 
260
- test("detectProjectSignals: monorepo detection via workspaces", () => {
230
+ test("detectProjectSignals: monorepo detection via workspaces", (t) => {
261
231
  const dir = makeTempDir("signals-monorepo");
262
- try {
263
- writeFileSync(
264
- join(dir, "package.json"),
265
- JSON.stringify({ name: "mono", workspaces: ["packages/*"] }),
266
- "utf-8",
267
- );
268
- const signals = detectProjectSignals(dir);
269
- assert.equal(signals.isMonorepo, true);
270
- } finally {
271
- cleanup(dir);
272
- }
232
+ t.after(() => cleanup(dir));
233
+
234
+ writeFileSync(
235
+ join(dir, "package.json"),
236
+ JSON.stringify({ name: "mono", workspaces: ["packages/*"] }),
237
+ "utf-8",
238
+ );
239
+ const signals = detectProjectSignals(dir);
240
+ assert.equal(signals.isMonorepo, true);
273
241
  });
274
242
 
275
- test("detectProjectSignals: monorepo detection via turbo.json", () => {
243
+ test("detectProjectSignals: monorepo detection via turbo.json", (t) => {
276
244
  const dir = makeTempDir("signals-turbo");
277
- try {
278
- writeFileSync(join(dir, "package.json"), JSON.stringify({ name: "test" }), "utf-8");
279
- writeFileSync(join(dir, "turbo.json"), "{}", "utf-8");
280
- const signals = detectProjectSignals(dir);
281
- assert.equal(signals.isMonorepo, true);
282
- } finally {
283
- cleanup(dir);
284
- }
245
+ t.after(() => cleanup(dir));
246
+
247
+ writeFileSync(join(dir, "package.json"), JSON.stringify({ name: "test" }), "utf-8");
248
+ writeFileSync(join(dir, "turbo.json"), "{}", "utf-8");
249
+ const signals = detectProjectSignals(dir);
250
+ assert.equal(signals.isMonorepo, true);
285
251
  });
286
252
 
287
- test("detectProjectSignals: CI detection", () => {
253
+ test("detectProjectSignals: CI detection", (t) => {
288
254
  const dir = makeTempDir("signals-ci");
289
- try {
290
- mkdirSync(join(dir, ".github", "workflows"), { recursive: true });
291
- const signals = detectProjectSignals(dir);
292
- assert.equal(signals.hasCI, true);
293
- } finally {
294
- cleanup(dir);
295
- }
255
+ t.after(() => cleanup(dir));
256
+
257
+ mkdirSync(join(dir, ".github", "workflows"), { recursive: true });
258
+ const signals = detectProjectSignals(dir);
259
+ assert.equal(signals.hasCI, true);
296
260
  });
297
261
 
298
- test("detectProjectSignals: test detection via jest config", () => {
262
+ test("detectProjectSignals: test detection via jest config", (t) => {
299
263
  const dir = makeTempDir("signals-tests");
300
- try {
301
- writeFileSync(join(dir, "jest.config.ts"), "export default {}", "utf-8");
302
- const signals = detectProjectSignals(dir);
303
- assert.equal(signals.hasTests, true);
304
- } finally {
305
- cleanup(dir);
306
- }
264
+ t.after(() => cleanup(dir));
265
+
266
+ writeFileSync(join(dir, "jest.config.ts"), "export default {}", "utf-8");
267
+ const signals = detectProjectSignals(dir);
268
+ assert.equal(signals.hasTests, true);
307
269
  });
308
270
 
309
- test("detectProjectSignals: package manager detection", () => {
271
+ test("detectProjectSignals: package manager detection", (t) => {
310
272
  const dir1 = makeTempDir("pm-pnpm");
311
273
  const dir2 = makeTempDir("pm-yarn");
312
274
  const dir3 = makeTempDir("pm-bun");
313
- try {
314
- writeFileSync(join(dir1, "pnpm-lock.yaml"), "", "utf-8");
315
- writeFileSync(join(dir1, "package.json"), "{}", "utf-8");
316
- assert.equal(detectProjectSignals(dir1).packageManager, "pnpm");
317
-
318
- writeFileSync(join(dir2, "yarn.lock"), "", "utf-8");
319
- writeFileSync(join(dir2, "package.json"), "{}", "utf-8");
320
- assert.equal(detectProjectSignals(dir2).packageManager, "yarn");
321
-
322
- writeFileSync(join(dir3, "bun.lockb"), "", "utf-8");
323
- writeFileSync(join(dir3, "package.json"), "{}", "utf-8");
324
- assert.equal(detectProjectSignals(dir3).packageManager, "bun");
325
- } finally {
275
+ t.after(() => {
326
276
  cleanup(dir1);
327
277
  cleanup(dir2);
328
278
  cleanup(dir3);
329
- }
279
+ });
280
+
281
+ writeFileSync(join(dir1, "pnpm-lock.yaml"), "", "utf-8");
282
+ writeFileSync(join(dir1, "package.json"), "{}", "utf-8");
283
+ assert.equal(detectProjectSignals(dir1).packageManager, "pnpm");
284
+
285
+ writeFileSync(join(dir2, "yarn.lock"), "", "utf-8");
286
+ writeFileSync(join(dir2, "package.json"), "{}", "utf-8");
287
+ assert.equal(detectProjectSignals(dir2).packageManager, "yarn");
288
+
289
+ writeFileSync(join(dir3, "bun.lockb"), "", "utf-8");
290
+ writeFileSync(join(dir3, "package.json"), "{}", "utf-8");
291
+ assert.equal(detectProjectSignals(dir3).packageManager, "bun");
330
292
  });
331
293
 
332
- test("detectProjectSignals: skips default npm test script", () => {
294
+ test("detectProjectSignals: skips default npm test script", (t) => {
333
295
  const dir = makeTempDir("signals-default-test");
334
- try {
335
- writeFileSync(
336
- join(dir, "package.json"),
337
- JSON.stringify({
338
- name: "test",
339
- scripts: { test: 'echo "Error: no test specified" && exit 1' },
340
- }),
341
- "utf-8",
342
- );
343
- const signals = detectProjectSignals(dir);
344
- // Should NOT include the default npm test script
345
- assert.equal(
346
- signals.verificationCommands.some(c => c.includes("test")),
347
- false,
348
- );
349
- } finally {
350
- cleanup(dir);
351
- }
296
+ t.after(() => cleanup(dir));
297
+
298
+ writeFileSync(
299
+ join(dir, "package.json"),
300
+ JSON.stringify({
301
+ name: "test",
302
+ scripts: { test: 'echo "Error: no test specified" && exit 1' },
303
+ }),
304
+ "utf-8",
305
+ );
306
+ const signals = detectProjectSignals(dir);
307
+ // Should NOT include the default npm test script
308
+ assert.equal(
309
+ signals.verificationCommands.some(c => c.includes("test")),
310
+ false,
311
+ );
352
312
  });
353
313
 
354
- test("detectProjectSignals: pnpm uses pnpm commands", () => {
314
+ test("detectProjectSignals: pnpm uses pnpm commands", (t) => {
355
315
  const dir = makeTempDir("signals-pnpm-cmds");
356
- try {
357
- writeFileSync(
358
- join(dir, "package.json"),
359
- JSON.stringify({
360
- name: "test",
361
- scripts: { test: "vitest", build: "tsc" },
362
- }),
363
- "utf-8",
364
- );
365
- writeFileSync(join(dir, "pnpm-lock.yaml"), "", "utf-8");
366
- const signals = detectProjectSignals(dir);
367
- assert.ok(signals.verificationCommands.includes("pnpm test"));
368
- assert.ok(signals.verificationCommands.includes("pnpm run build"));
369
- } finally {
370
- cleanup(dir);
371
- }
316
+ t.after(() => cleanup(dir));
317
+
318
+ writeFileSync(
319
+ join(dir, "package.json"),
320
+ JSON.stringify({
321
+ name: "test",
322
+ scripts: { test: "vitest", build: "tsc" },
323
+ }),
324
+ "utf-8",
325
+ );
326
+ writeFileSync(join(dir, "pnpm-lock.yaml"), "", "utf-8");
327
+ const signals = detectProjectSignals(dir);
328
+ assert.ok(signals.verificationCommands.includes("pnpm test"));
329
+ assert.ok(signals.verificationCommands.includes("pnpm run build"));
372
330
  });
373
331
 
374
- test("detectProjectSignals: Ruby project with rspec", () => {
332
+ test("detectProjectSignals: Ruby project with rspec", (t) => {
375
333
  const dir = makeTempDir("signals-ruby");
376
- try {
377
- writeFileSync(join(dir, "Gemfile"), 'source "https://rubygems.org"\n', "utf-8");
378
- mkdirSync(join(dir, "spec"), { recursive: true });
379
- const signals = detectProjectSignals(dir);
380
- assert.ok(signals.detectedFiles.includes("Gemfile"));
381
- assert.equal(signals.primaryLanguage, "ruby");
382
- assert.ok(signals.verificationCommands.includes("bundle exec rspec"));
383
- } finally {
384
- cleanup(dir);
385
- }
334
+ t.after(() => cleanup(dir));
335
+
336
+ writeFileSync(join(dir, "Gemfile"), 'source "https://rubygems.org"\n', "utf-8");
337
+ mkdirSync(join(dir, "spec"), { recursive: true });
338
+ const signals = detectProjectSignals(dir);
339
+ assert.ok(signals.detectedFiles.includes("Gemfile"));
340
+ assert.equal(signals.primaryLanguage, "ruby");
341
+ assert.ok(signals.verificationCommands.includes("bundle exec rspec"));
386
342
  });
387
343
 
388
- test("detectProjectSignals: Makefile with test target", () => {
344
+ test("detectProjectSignals: Makefile with test target", (t) => {
389
345
  const dir = makeTempDir("signals-make");
390
- try {
391
- writeFileSync(join(dir, "Makefile"), "test:\n\tgo test ./...\n\nbuild:\n\tgo build\n", "utf-8");
392
- const signals = detectProjectSignals(dir);
393
- assert.ok(signals.detectedFiles.includes("Makefile"));
394
- assert.ok(signals.verificationCommands.includes("make test"));
395
- } finally {
396
- cleanup(dir);
397
- }
346
+ t.after(() => cleanup(dir));
347
+
348
+ writeFileSync(join(dir, "Makefile"), "test:\n\tgo test ./...\n\nbuild:\n\tgo build\n", "utf-8");
349
+ const signals = detectProjectSignals(dir);
350
+ assert.ok(signals.detectedFiles.includes("Makefile"));
351
+ assert.ok(signals.verificationCommands.includes("make test"));
398
352
  });