gsd-pi 2.78.1-dev.b0759e59b → 2.78.1-dev.d8826a445

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 (300) hide show
  1. package/README.md +8 -5
  2. package/dist/headless-recover.d.ts +23 -0
  3. package/dist/headless-recover.js +93 -0
  4. package/dist/headless.js +9 -0
  5. package/dist/help-text.js +1 -0
  6. package/dist/resources/.managed-resources-content-hash +1 -1
  7. package/dist/resources/extensions/browser-tools/tools/intent.js +8 -1
  8. package/dist/resources/extensions/gsd/auto/phases.js +7 -2
  9. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  10. package/dist/resources/extensions/gsd/auto-dispatch.js +7 -58
  11. package/dist/resources/extensions/gsd/auto-post-unit.js +14 -28
  12. package/dist/resources/extensions/gsd/auto-start.js +1 -8
  13. package/dist/resources/extensions/gsd/auto-worktree.js +244 -216
  14. package/dist/resources/extensions/gsd/auto.js +86 -7
  15. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +1 -1
  16. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +9 -77
  17. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +17 -16
  18. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +67 -55
  19. package/dist/resources/extensions/gsd/commands-codebase.js +2 -2
  20. package/dist/resources/extensions/gsd/commands-handlers.js +5 -5
  21. package/dist/resources/extensions/gsd/commands-logs.js +2 -2
  22. package/dist/resources/extensions/gsd/commands-scan.js +2 -2
  23. package/dist/resources/extensions/gsd/commands-ship.js +2 -2
  24. package/dist/resources/extensions/gsd/commands-workflow-templates.js +5 -5
  25. package/dist/resources/extensions/gsd/db-writer.js +106 -95
  26. package/dist/resources/extensions/gsd/delegation-policy.js +155 -0
  27. package/dist/resources/extensions/gsd/dispatch-guard.js +6 -10
  28. package/dist/resources/extensions/gsd/doctor-engine-checks.js +2 -2
  29. package/dist/resources/extensions/gsd/gsd-db.js +268 -8
  30. package/dist/resources/extensions/gsd/guided-flow-queue.js +1 -1
  31. package/dist/resources/extensions/gsd/guided-flow.js +141 -32
  32. package/dist/resources/extensions/gsd/markdown-renderer.js +14 -51
  33. package/dist/resources/extensions/gsd/metrics.js +287 -1
  34. package/dist/resources/extensions/gsd/parallel-merge.js +14 -13
  35. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +5 -2
  36. package/dist/resources/extensions/gsd/paths.js +114 -9
  37. package/dist/resources/extensions/gsd/prompts/complete-slice.md +4 -4
  38. package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -3
  39. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +8 -1
  40. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +22 -7
  41. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +6 -2
  42. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -1
  43. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +6 -0
  44. package/dist/resources/extensions/gsd/queue-order.js +6 -1
  45. package/dist/resources/extensions/gsd/rethink.js +2 -2
  46. package/dist/resources/extensions/gsd/state.js +91 -372
  47. package/dist/resources/extensions/gsd/templates/project.md +10 -0
  48. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -5
  49. package/dist/resources/extensions/gsd/tools/complete-slice.js +7 -12
  50. package/dist/resources/extensions/gsd/tools/complete-task.js +19 -31
  51. package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -5
  52. package/dist/resources/extensions/gsd/workflow-manifest.js +2 -1
  53. package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +3 -21
  54. package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
  55. package/dist/resources/extensions/gsd/workflow-reconcile.js +3 -3
  56. package/dist/resources/extensions/gsd/workspace.js +59 -0
  57. package/dist/resources/extensions/gsd/worktree-command.js +4 -3
  58. package/dist/resources/extensions/gsd/worktree-resolver.js +15 -2
  59. package/dist/resources/extensions/gsd/write-intercept.js +3 -3
  60. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  61. package/dist/web/standalone/.next/BUILD_ID +1 -1
  62. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  63. package/dist/web/standalone/.next/build-manifest.json +2 -2
  64. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  65. package/dist/web/standalone/.next/required-server-files.json +1 -1
  66. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  67. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  75. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  83. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  84. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  85. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  86. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  87. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  88. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  89. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  90. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  91. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  92. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  93. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  94. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  95. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  96. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  97. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  98. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  99. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  100. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  101. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  102. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  103. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  104. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  105. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  106. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  107. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  108. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  109. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  110. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  111. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  112. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  113. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  114. package/dist/web/standalone/.next/server/app/index.html +1 -1
  115. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  122. package/dist/web/standalone/.next/server/chunks/6336.js +1 -0
  123. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  124. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  126. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  127. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  128. package/dist/web/standalone/server.js +1 -1
  129. package/package.json +1 -1
  130. package/packages/mcp-server/README.md +2 -11
  131. package/packages/mcp-server/dist/remote-questions.d.ts +27 -0
  132. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -1
  133. package/packages/mcp-server/dist/remote-questions.js +28 -0
  134. package/packages/mcp-server/dist/remote-questions.js.map +1 -1
  135. package/packages/mcp-server/dist/server.d.ts +28 -0
  136. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  137. package/packages/mcp-server/dist/server.js +94 -4
  138. package/packages/mcp-server/dist/server.js.map +1 -1
  139. package/packages/mcp-server/dist/workflow-tools.d.ts +6 -0
  140. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  141. package/packages/mcp-server/dist/workflow-tools.js +56 -2
  142. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  143. package/packages/mcp-server/src/mcp-server.test.ts +226 -0
  144. package/packages/mcp-server/src/parse-workflow-args.test.ts +80 -0
  145. package/packages/mcp-server/src/remote-questions.test.ts +103 -0
  146. package/packages/mcp-server/src/remote-questions.ts +35 -0
  147. package/packages/mcp-server/src/server.ts +129 -6
  148. package/packages/mcp-server/src/workflow-tools.ts +62 -3
  149. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  150. package/src/resources/extensions/browser-tools/tools/intent.ts +13 -2
  151. package/src/resources/extensions/gsd/auto/phases.ts +8 -2
  152. package/src/resources/extensions/gsd/auto/session.ts +4 -0
  153. package/src/resources/extensions/gsd/auto-dispatch.ts +14 -62
  154. package/src/resources/extensions/gsd/auto-post-unit.ts +15 -27
  155. package/src/resources/extensions/gsd/auto-start.ts +1 -8
  156. package/src/resources/extensions/gsd/auto-worktree.ts +286 -251
  157. package/src/resources/extensions/gsd/auto.ts +102 -7
  158. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +1 -1
  159. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +9 -84
  160. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +17 -17
  161. package/src/resources/extensions/gsd/bootstrap/tests/write-gate-basepath.test.ts +103 -0
  162. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +80 -55
  163. package/src/resources/extensions/gsd/commands-codebase.ts +2 -2
  164. package/src/resources/extensions/gsd/commands-handlers.ts +5 -5
  165. package/src/resources/extensions/gsd/commands-logs.ts +2 -2
  166. package/src/resources/extensions/gsd/commands-scan.ts +2 -2
  167. package/src/resources/extensions/gsd/commands-ship.ts +2 -2
  168. package/src/resources/extensions/gsd/commands-workflow-templates.ts +5 -5
  169. package/src/resources/extensions/gsd/db-writer.ts +123 -94
  170. package/src/resources/extensions/gsd/delegation-policy.ts +197 -0
  171. package/src/resources/extensions/gsd/dispatch-guard.ts +6 -11
  172. package/src/resources/extensions/gsd/doctor-engine-checks.ts +2 -2
  173. package/src/resources/extensions/gsd/gsd-db.ts +269 -8
  174. package/src/resources/extensions/gsd/guided-flow-queue.ts +1 -1
  175. package/src/resources/extensions/gsd/guided-flow.ts +181 -32
  176. package/src/resources/extensions/gsd/markdown-renderer.ts +13 -64
  177. package/src/resources/extensions/gsd/metrics.ts +321 -1
  178. package/src/resources/extensions/gsd/parallel-merge.ts +14 -13
  179. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +5 -2
  180. package/src/resources/extensions/gsd/paths.ts +122 -9
  181. package/src/resources/extensions/gsd/prompts/complete-slice.md +4 -4
  182. package/src/resources/extensions/gsd/prompts/execute-task.md +3 -3
  183. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +8 -1
  184. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +22 -7
  185. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +6 -2
  186. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -1
  187. package/src/resources/extensions/gsd/prompts/plan-milestone.md +6 -0
  188. package/src/resources/extensions/gsd/queue-order.ts +6 -1
  189. package/src/resources/extensions/gsd/rethink.ts +2 -2
  190. package/src/resources/extensions/gsd/state.ts +91 -389
  191. package/src/resources/extensions/gsd/templates/project.md +10 -0
  192. package/src/resources/extensions/gsd/tests/artifact-corruption-2630.test.ts +1 -0
  193. package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +14 -14
  194. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +6 -0
  195. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +21 -34
  196. package/src/resources/extensions/gsd/tests/auto-session-scope.test.ts +331 -0
  197. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +176 -0
  198. package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +6 -7
  199. package/src/resources/extensions/gsd/tests/complete-task.test.ts +8 -6
  200. package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +12 -27
  201. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +18 -5
  202. package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +4 -4
  203. package/src/resources/extensions/gsd/tests/db-writer-path-containment.test.ts +152 -0
  204. package/src/resources/extensions/gsd/tests/db-writer-root-artifact.test.ts +221 -0
  205. package/src/resources/extensions/gsd/tests/db-writer-scope.test.ts +230 -0
  206. package/src/resources/extensions/gsd/tests/db-writer.test.ts +14 -16
  207. package/src/resources/extensions/gsd/tests/delegation-policy.test.ts +151 -0
  208. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +6 -5
  209. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +10 -38
  210. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +136 -56
  211. package/src/resources/extensions/gsd/tests/derive-state-draft.test.ts +3 -0
  212. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +119 -61
  213. package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -0
  214. package/src/resources/extensions/gsd/tests/dispatch-backgroundable-annotation.test.ts +55 -0
  215. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +6 -20
  216. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +4 -5
  217. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +14 -15
  218. package/src/resources/extensions/gsd/tests/draft-promotion.test.ts +3 -23
  219. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +11 -16
  220. package/src/resources/extensions/gsd/tests/escalation.test.ts +2 -1
  221. package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +193 -0
  222. package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound-corrections.test.ts +246 -0
  223. package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound.test.ts +218 -0
  224. package/src/resources/extensions/gsd/tests/gsd-db-failed-open-restore.test.ts +117 -0
  225. package/src/resources/extensions/gsd/tests/gsd-db-workspace-scope.test.ts +226 -0
  226. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +2 -1
  227. package/src/resources/extensions/gsd/tests/gsd-root-canonical.test.ts +66 -0
  228. package/src/resources/extensions/gsd/tests/gsd-root-home-guard.test.ts +68 -5
  229. package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +15 -36
  230. package/src/resources/extensions/gsd/tests/guided-flow-prompt-consolidation.test.ts +4 -4
  231. package/src/resources/extensions/gsd/tests/handler-worktree-write-isolation.test.ts +57 -0
  232. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +15 -15
  233. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +15 -5
  234. package/src/resources/extensions/gsd/tests/integration/workspace-collapse-integration.test.ts +371 -0
  235. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +14 -8
  236. package/src/resources/extensions/gsd/tests/md-importer.test.ts +2 -1
  237. package/src/resources/extensions/gsd/tests/memory-store.test.ts +3 -2
  238. package/src/resources/extensions/gsd/tests/metrics-atomic-merge.test.ts +222 -0
  239. package/src/resources/extensions/gsd/tests/metrics-lock-hardening.test.ts +400 -0
  240. package/src/resources/extensions/gsd/tests/metrics-lock-not-acquired.test.ts +141 -0
  241. package/src/resources/extensions/gsd/tests/metrics-lock-retry-sleep.test.ts +287 -0
  242. package/src/resources/extensions/gsd/tests/metrics-prune-cache-invalidation.test.ts +149 -0
  243. package/src/resources/extensions/gsd/tests/metrics-scope.test.ts +378 -0
  244. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +329 -0
  245. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +2 -0
  246. package/src/resources/extensions/gsd/tests/path-cache-decoupled.test.ts +209 -0
  247. package/src/resources/extensions/gsd/tests/path-normalization-unified.test.ts +175 -0
  248. package/src/resources/extensions/gsd/tests/paths-cache.test.ts +170 -0
  249. package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +120 -0
  250. package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +25 -16
  251. package/src/resources/extensions/gsd/tests/projection-regression.test.ts +1 -0
  252. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +150 -7
  253. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +184 -0
  254. package/src/resources/extensions/gsd/tests/register-hooks-compaction-checkpoint.test.ts +6 -1
  255. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +28 -16
  256. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +3 -0
  257. package/src/resources/extensions/gsd/tests/resolve-ts.mjs +4 -0
  258. package/src/resources/extensions/gsd/tests/resume-missing-worktree-warning.test.ts +209 -0
  259. package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +3 -4
  260. package/src/resources/extensions/gsd/tests/slice-disk-reconcile.test.ts +10 -56
  261. package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +15 -16
  262. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -0
  263. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +23 -27
  264. package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +13 -14
  265. package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +4 -3
  266. package/src/resources/extensions/gsd/tests/sync-layer-scope.test.ts +453 -0
  267. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +10 -33
  268. package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +162 -0
  269. package/src/resources/extensions/gsd/tests/teardown-cleanup-parity.test.ts +102 -0
  270. package/src/resources/extensions/gsd/tests/teardown-failure-clears-registry.test.ts +186 -0
  271. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +1 -1
  272. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +7 -8
  273. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +9 -15
  274. package/src/resources/extensions/gsd/tests/validator-scope-parity.test.ts +239 -0
  275. package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +12 -7
  276. package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +4 -4
  277. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +26 -3
  278. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +9 -15
  279. package/src/resources/extensions/gsd/tests/workspace.test.ts +190 -0
  280. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +13 -0
  281. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +65 -71
  282. package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +26 -151
  283. package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +35 -35
  284. package/src/resources/extensions/gsd/tests/write-gate.test.ts +67 -52
  285. package/src/resources/extensions/gsd/tests/write-intercept.test.ts +1 -1
  286. package/src/resources/extensions/gsd/tools/complete-milestone.ts +7 -5
  287. package/src/resources/extensions/gsd/tools/complete-slice.ts +7 -14
  288. package/src/resources/extensions/gsd/tools/complete-task.ts +19 -34
  289. package/src/resources/extensions/gsd/tools/validate-milestone.ts +7 -5
  290. package/src/resources/extensions/gsd/workflow-manifest.ts +4 -1
  291. package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -18
  292. package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
  293. package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
  294. package/src/resources/extensions/gsd/workspace.ts +95 -0
  295. package/src/resources/extensions/gsd/worktree-command.ts +4 -3
  296. package/src/resources/extensions/gsd/worktree-resolver.ts +16 -2
  297. package/src/resources/extensions/gsd/write-intercept.ts +3 -3
  298. package/dist/web/standalone/.next/server/chunks/8527.js +0 -1
  299. /package/dist/web/standalone/.next/static/{rk1EN3FQTE6Z1yalkW_GE → AT5qi39nKXkdmQIOIoh0f}/_buildManifest.js +0 -0
  300. /package/dist/web/standalone/.next/static/{rk1EN3FQTE6Z1yalkW_GE → AT5qi39nKXkdmQIOIoh0f}/_ssgManifest.js +0 -0
@@ -11,6 +11,16 @@
11
11
 
12
12
  {{theOneThingThatMustWorkEvenIfEverythingElseIsCut}}
13
13
 
14
+ ## Project Shape
15
+
16
+ <!-- Drives questioning depth in downstream stages. `simple` → short plain-text
17
+ rounds, fast PROJECT/CONTEXT/REQUIREMENTS writes. `complex` → researched
18
+ 3–4-option questions with an "Other — let me discuss" hatch.
19
+ Default to `complex` when uncertain. -->
20
+
21
+ - **Complexity:** {{simple | complex}}
22
+ - **Why:** {{one-line rationale citing the signals that decided it}}
23
+
14
24
  ## Current State
15
25
 
16
26
  {{whatHasBeenBuiltSoFar — what works, what exists, what's deployed}}
@@ -107,6 +107,7 @@ function makeMilestoneRow(overrides?: Partial<MilestoneRow>): MilestoneRow {
107
107
  definition_of_done: [],
108
108
  requirement_coverage: '',
109
109
  boundary_map_markdown: '',
110
+ sequence: 0,
110
111
  ...overrides,
111
112
  };
112
113
  }
@@ -35,7 +35,7 @@ import { _setAutoActiveForTest } from '../auto.ts';
35
35
  // Reset all relevant state before and after each test.
36
36
  function resetState(): void {
37
37
  _setAutoActiveForTest(false);
38
- clearDiscussionFlowState();
38
+ clearDiscussionFlowState(process.cwd());
39
39
  }
40
40
 
41
41
  describe('auto-discuss-milestone-deadlock-4973', () => {
@@ -51,7 +51,7 @@ describe('auto-discuss-milestone-deadlock-4973', () => {
51
51
  _setAutoActiveForTest(true);
52
52
 
53
53
  // Before mark: blocked
54
- const snapshotBefore = loadWriteGateSnapshot();
54
+ const snapshotBefore = loadWriteGateSnapshot(process.cwd());
55
55
  const beforeResult = shouldBlockContextArtifactSaveInSnapshot(
56
56
  snapshotBefore,
57
57
  'CONTEXT',
@@ -61,10 +61,10 @@ describe('auto-discuss-milestone-deadlock-4973', () => {
61
61
  assert.strictEqual(beforeResult.block, true, 'should block before markDepthVerified');
62
62
 
63
63
  // Simulate what the dispatch rule now does in auto-mode
64
- markDepthVerified('M001');
64
+ markDepthVerified('M001', process.cwd());
65
65
 
66
66
  // After mark: unblocked
67
- const snapshotAfter = loadWriteGateSnapshot();
67
+ const snapshotAfter = loadWriteGateSnapshot(process.cwd());
68
68
  const afterResult = shouldBlockContextArtifactSaveInSnapshot(
69
69
  snapshotAfter,
70
70
  'CONTEXT',
@@ -87,7 +87,7 @@ describe('auto-discuss-milestone-deadlock-4973', () => {
87
87
  assert.strictEqual(beforeResult.block, true, 'write should be blocked before markDepthVerified');
88
88
 
89
89
  // Simulate dispatch rule auto-mark
90
- markDepthVerified('M001');
90
+ markDepthVerified('M001', process.cwd());
91
91
 
92
92
  // After mark: unblocked
93
93
  const afterResult = shouldBlockContextWrite('write', contextPath, 'M001');
@@ -109,8 +109,8 @@ describe('auto-discuss-milestone-deadlock-4973', () => {
109
109
  // the dispatch-site call site is safe regardless of prior session state.
110
110
  test('Test 3: session_switch ordering — clearDiscussionFlowState clears mark; dispatch-site call re-establishes it', () => {
111
111
  // Simulate a mark from a prior session
112
- markDepthVerified('M001');
113
- let snapshot = loadWriteGateSnapshot();
112
+ markDepthVerified('M001', process.cwd());
113
+ let snapshot = loadWriteGateSnapshot(process.cwd());
114
114
  assert.strictEqual(
115
115
  isMilestoneDepthVerifiedInSnapshot(snapshot, 'M001'),
116
116
  true,
@@ -119,8 +119,8 @@ describe('auto-discuss-milestone-deadlock-4973', () => {
119
119
 
120
120
  // session_switch fires clearDiscussionFlowState() — this is exactly what
121
121
  // register-hooks.ts:106 does
122
- clearDiscussionFlowState();
123
- snapshot = loadWriteGateSnapshot();
122
+ clearDiscussionFlowState(process.cwd());
123
+ snapshot = loadWriteGateSnapshot(process.cwd());
124
124
  assert.strictEqual(
125
125
  isMilestoneDepthVerifiedInSnapshot(snapshot, 'M001'),
126
126
  false,
@@ -130,9 +130,9 @@ describe('auto-discuss-milestone-deadlock-4973', () => {
130
130
  // Now the dispatch rule fires (after session_switch cleared state)
131
131
  // and re-establishes the mark for the new session
132
132
  _setAutoActiveForTest(true);
133
- markDepthVerified('M001'); // this is what the dispatch rule does
133
+ markDepthVerified('M001', process.cwd()); // this is what the dispatch rule does
134
134
 
135
- snapshot = loadWriteGateSnapshot();
135
+ snapshot = loadWriteGateSnapshot(process.cwd());
136
136
  assert.strictEqual(
137
137
  isMilestoneDepthVerifiedInSnapshot(snapshot, 'M001'),
138
138
  true,
@@ -158,7 +158,7 @@ describe('auto-discuss-milestone-deadlock-4973', () => {
158
158
 
159
159
  // CONTEXT artifact save is still blocked
160
160
  const snapshotResult = shouldBlockContextArtifactSaveInSnapshot(
161
- loadWriteGateSnapshot(),
161
+ loadWriteGateSnapshot(process.cwd()),
162
162
  'CONTEXT',
163
163
  'M002',
164
164
  null,
@@ -238,7 +238,7 @@ describe('auto-discuss-milestone-deadlock-4973', () => {
238
238
  );
239
239
 
240
240
  // ── Deep auto-mode case: the user-facing approval gate must stay closed ──
241
- clearDiscussionFlowState();
241
+ clearDiscussionFlowState(process.cwd());
242
242
  if (existsSync(snapshotFile)) unlinkSync(snapshotFile);
243
243
  _setAutoActiveForTest(true);
244
244
  const deepCtx = {
@@ -264,7 +264,7 @@ describe('auto-discuss-milestone-deadlock-4973', () => {
264
264
  // ── Interactive case: the rule must NOT call markDepthVerified ──
265
265
  // clearDiscussionFlowState() only deletes the snapshot at process.cwd(),
266
266
  // so we must explicitly remove the snapshot under our tempBase too.
267
- clearDiscussionFlowState();
267
+ clearDiscussionFlowState(process.cwd());
268
268
  if (existsSync(snapshotFile)) unlinkSync(snapshotFile);
269
269
  _setAutoActiveForTest(false);
270
270
  snap = loadWriteGateSnapshot(tempBase);
@@ -40,6 +40,12 @@ test("auto.ts validates milestone before restoring paused session (#1664)", () =
40
40
  "auto.ts must check for SUMMARY file to detect completed milestones",
41
41
  );
42
42
 
43
+ assert.ok(
44
+ source.includes("await ensureDbOpen(base)") &&
45
+ source.indexOf("await ensureDbOpen(base)") < source.indexOf('resolveMilestoneFile(base, meta.milestoneId, "SUMMARY")'),
46
+ "auto.ts must open the canonical DB before using SUMMARY as a paused-session fallback",
47
+ );
48
+
43
49
  // Resume path must sanitize paused session file metadata before unlink/recovery.
44
50
  assert.ok(
45
51
  source.includes("normalizeSessionFilePath(meta.sessionFile ?? null)"),
@@ -1,13 +1,12 @@
1
1
  /**
2
- * Regression test for #3673 — auto-remediate stale slice DB status
2
+ * Regression test for DB-authoritative rogue detection.
3
3
  *
4
- * When complete-slice fails after writing SUMMARY.md but before calling
5
- * updateSliceStatus(), the DB stays stale and the post-unit check
6
- * previously reported this as a "rogue" artifact, causing infinite
7
- * re-dispatch. The fix calls updateSliceStatus() to sync the DB.
4
+ * A SUMMARY.md on disk is a projection/diagnostic. Runtime post-unit checks
5
+ * must not use it to mark the DB slice complete; explicit import/recovery
6
+ * commands own markdown-to-DB behavior.
8
7
  *
9
- * This structural test verifies updateSliceStatus is imported and called
10
- * in the complete-slice branch of auto-post-unit.ts.
8
+ * This structural test verifies the complete-slice rogue branch reports the
9
+ * stale projection without calling updateSliceStatus().
11
10
  */
12
11
 
13
12
  import { describe, test } from 'node:test';
@@ -22,38 +21,26 @@ const __dirname = dirname(__filename);
22
21
 
23
22
  const source = readFileSync(join(__dirname, '..', 'auto-post-unit.ts'), 'utf-8');
24
23
 
25
- describe('auto-remediate stale slice status (#3673)', () => {
26
- test('updateSliceStatus is imported from gsd-db', () => {
27
- assert.match(source, /import\s*\{[^}]*updateSliceStatus[^}]*\}\s*from\s*["']\.\/gsd-db/,
28
- 'updateSliceStatus should be imported from gsd-db');
24
+ describe('DB-authoritative slice rogue detection', () => {
25
+ test('updateSliceStatus is not imported for post-unit rogue reconciliation', () => {
26
+ assert.doesNotMatch(source, /import\s*\{[^}]*updateSliceStatus[^}]*\}\s*from\s*["']\.\/gsd-db/,
27
+ 'auto-post-unit must not import updateSliceStatus for disk-to-DB reconciliation');
29
28
  });
30
29
 
31
- test('updateSliceStatus is called with "complete" status', () => {
32
- assert.match(source, /updateSliceStatus\(mid,\s*sid,\s*["']complete["']/,
33
- 'updateSliceStatus should be called with "complete" status');
30
+ test('complete-slice rogue branch does not mark DB complete from disk', () => {
31
+ assert.doesNotMatch(source, /updateSliceStatus\(mid,\s*sid,\s*["']complete["']/,
32
+ 'SUMMARY.md on disk must not mark slice complete in DB');
34
33
  });
35
34
 
36
- test('remediation is wrapped in try-catch for fallback to rogue detection', () => {
37
- // The updateSliceStatus call should be in a try block with a catch
38
- // that falls back to rogues.push
39
- const updateIdx = source.indexOf('updateSliceStatus(mid, sid');
40
- assert.ok(updateIdx > 0, 'updateSliceStatus call should exist');
41
-
42
- // Find surrounding try-catch
43
- const before = source.slice(Math.max(0, updateIdx - 200), updateIdx);
44
- assert.match(before, /try\s*\{/,
45
- 'updateSliceStatus should be inside a try block');
46
-
47
- // Bound the region to stop before the rogue fallback so /catch/ only
48
- // matches this try block's catch, not an unrelated later one.
49
- const after = extractSourceRegion(source, 'updateSliceStatus(mid, sid', 'rogues.push({');
50
- assert.match(after, /catch/,
51
- 'try block should have a catch for fallback');
35
+ test('explicit rogue diagnostic reports stale slice summary projection', () => {
36
+ const branch = extractSourceRegion(source, 'unitType === "complete-slice"', 'unitType === "plan-milestone"');
37
+ assert.match(branch, /rogues\.push\(\{\s*path:\s*summaryPath,\s*unitType,\s*unitId\s*\}\)/,
38
+ 'complete-slice branch should report stale SUMMARY.md as rogue');
52
39
  });
53
40
 
54
- test('rogue detection still exists as fallback', () => {
55
- // rogues.push should appear in the catch block
56
- assert.match(source, /rogues\.push\(\{.*path:\s*summaryPath/,
57
- 'rogues.push fallback should still exist');
41
+ test('post-unit runtime does not call rogue diagnostics automatically', () => {
42
+ const postUnit = extractSourceRegion(source, 'export async function postUnitPostVerification');
43
+ assert.doesNotMatch(postUnit, /detectRogueFileWrites\(/,
44
+ 'runtime post-unit path must not scan disk projections for rogue files');
58
45
  });
59
46
  });
@@ -0,0 +1,331 @@
1
+ // GSD-2 + Tests for MilestoneScope threading through AutoSession state (C2)
2
+ //
3
+ // Strategy: construct AutoSession directly + call createWorkspace/scopeMilestone
4
+ // to mirror the rebuildScope() helper in auto.ts — avoids importing the full
5
+ // auto.ts module (too many .js resolved imports).
6
+
7
+ import { describe, test, beforeEach, afterEach } from "node:test";
8
+ import assert from "node:assert/strict";
9
+ import { mkdtempSync, mkdirSync, rmSync, realpathSync, existsSync } from "node:fs";
10
+ import { join } from "node:path";
11
+ import { tmpdir } from "node:os";
12
+
13
+ import { AutoSession } from "../auto/session.ts";
14
+ import { createWorkspace, scopeMilestone } from "../workspace.ts";
15
+ import type { MilestoneScope } from "../workspace.ts";
16
+
17
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
18
+
19
+ function makeProjectDir(): string {
20
+ const dir = realpathSync(mkdtempSync(join(tmpdir(), "gsd-scope-test-")));
21
+ mkdirSync(join(dir, ".gsd", "milestones"), { recursive: true });
22
+ return dir;
23
+ }
24
+
25
+ function makeWorktreeDir(projectDir: string, milestoneId: string): string {
26
+ const wt = join(projectDir, ".gsd", "worktrees", milestoneId);
27
+ mkdirSync(wt, { recursive: true });
28
+ return wt;
29
+ }
30
+
31
+ /**
32
+ * Mirror the rebuildScope() helper from auto.ts — computes s.scope from the
33
+ * same inputs so tests can verify the behaviour without importing auto.ts.
34
+ */
35
+ function applyRebuildScope(
36
+ s: AutoSession,
37
+ rawPath: string,
38
+ milestoneId: string | null,
39
+ ): void {
40
+ if (!milestoneId) {
41
+ s.scope = null;
42
+ return;
43
+ }
44
+ try {
45
+ const workspace = createWorkspace(rawPath);
46
+ s.scope = scopeMilestone(workspace, milestoneId);
47
+ } catch {
48
+ s.scope = null;
49
+ }
50
+ }
51
+
52
+ // ─── Tests ───────────────────────────────────────────────────────────────────
53
+
54
+ describe("AutoSession.scope — project mode (basePath equals originalBasePath)", () => {
55
+ let s: AutoSession;
56
+ let projectDir: string;
57
+
58
+ beforeEach(() => {
59
+ projectDir = makeProjectDir();
60
+ s = new AutoSession();
61
+ });
62
+
63
+ afterEach(() => {
64
+ rmSync(projectDir, { recursive: true, force: true });
65
+ });
66
+
67
+ test("scope is null when milestoneId is null", () => {
68
+ s.basePath = projectDir;
69
+ s.originalBasePath = projectDir;
70
+ s.currentMilestoneId = null;
71
+
72
+ applyRebuildScope(s, projectDir, null);
73
+
74
+ assert.equal(s.scope, null);
75
+ });
76
+
77
+ test("scope mode is 'project' when basePath equals originalBasePath", () => {
78
+ const mid = "M001";
79
+ s.basePath = projectDir;
80
+ s.originalBasePath = projectDir;
81
+ s.currentMilestoneId = mid;
82
+
83
+ applyRebuildScope(s, projectDir, mid);
84
+
85
+ assert.ok(s.scope, "scope should be set");
86
+ assert.equal(s.scope.workspace.mode, "project");
87
+ assert.equal(s.scope.milestoneId, mid);
88
+ });
89
+
90
+ test("scope projectRoot matches realpath of projectDir", () => {
91
+ const mid = "M001";
92
+ s.basePath = projectDir;
93
+ s.originalBasePath = projectDir;
94
+ s.currentMilestoneId = mid;
95
+
96
+ applyRebuildScope(s, projectDir, mid);
97
+
98
+ assert.ok(s.scope, "scope should be set");
99
+ assert.equal(s.scope.workspace.projectRoot, realpathSync(projectDir));
100
+ });
101
+
102
+ test("scope worktreeRoot is null in project mode", () => {
103
+ const mid = "M001";
104
+ s.basePath = projectDir;
105
+ s.originalBasePath = projectDir;
106
+ s.currentMilestoneId = mid;
107
+
108
+ applyRebuildScope(s, projectDir, mid);
109
+
110
+ assert.ok(s.scope, "scope should be set");
111
+ assert.equal(s.scope.workspace.worktreeRoot, null);
112
+ });
113
+
114
+ test("scope path methods resolve under the .gsd directory", () => {
115
+ const mid = "M002";
116
+ s.basePath = projectDir;
117
+ s.originalBasePath = projectDir;
118
+ s.currentMilestoneId = mid;
119
+
120
+ applyRebuildScope(s, projectDir, mid);
121
+
122
+ assert.ok(s.scope, "scope should be set");
123
+ const gsd = join(projectDir, ".gsd");
124
+ assert.equal(s.scope.contextFile(), join(gsd, "milestones", mid, `${mid}-CONTEXT.md`));
125
+ assert.equal(s.scope.roadmapFile(), join(gsd, "milestones", mid, `${mid}-ROADMAP.md`));
126
+ assert.equal(s.scope.stateFile(), join(gsd, "STATE.md"));
127
+ });
128
+ });
129
+
130
+ describe("AutoSession.scope — worktree mode (basePath differs from originalBasePath)", () => {
131
+ let s: AutoSession;
132
+ let projectDir: string;
133
+ let worktreeDir: string;
134
+
135
+ beforeEach(() => {
136
+ projectDir = makeProjectDir();
137
+ worktreeDir = makeWorktreeDir(projectDir, "M001");
138
+ s = new AutoSession();
139
+ });
140
+
141
+ afterEach(() => {
142
+ rmSync(projectDir, { recursive: true, force: true });
143
+ });
144
+
145
+ test("scope mode is 'worktree' when basePath is the worktree path", () => {
146
+ const mid = "M001";
147
+ s.basePath = worktreeDir;
148
+ s.originalBasePath = projectDir;
149
+ s.currentMilestoneId = mid;
150
+
151
+ applyRebuildScope(s, worktreeDir, mid);
152
+
153
+ assert.ok(s.scope, "scope should be set");
154
+ assert.equal(s.scope.workspace.mode, "worktree");
155
+ });
156
+
157
+ test("scope worktreeRoot matches realpath of worktreeDir", () => {
158
+ const mid = "M001";
159
+ s.basePath = worktreeDir;
160
+ s.originalBasePath = projectDir;
161
+ s.currentMilestoneId = mid;
162
+
163
+ applyRebuildScope(s, worktreeDir, mid);
164
+
165
+ assert.ok(s.scope, "scope should be set");
166
+ assert.equal(s.scope.workspace.worktreeRoot, realpathSync(worktreeDir));
167
+ });
168
+
169
+ test("scope projectRoot resolves to project root (not worktree)", () => {
170
+ const mid = "M001";
171
+ s.basePath = worktreeDir;
172
+ s.originalBasePath = projectDir;
173
+ s.currentMilestoneId = mid;
174
+
175
+ applyRebuildScope(s, worktreeDir, mid);
176
+
177
+ assert.ok(s.scope, "scope should be set");
178
+ assert.equal(s.scope.workspace.projectRoot, realpathSync(projectDir));
179
+ });
180
+
181
+ test("scope milestoneId matches the milestone being tracked", () => {
182
+ const mid = "M001";
183
+ s.basePath = worktreeDir;
184
+ s.originalBasePath = projectDir;
185
+ s.currentMilestoneId = mid;
186
+
187
+ applyRebuildScope(s, worktreeDir, mid);
188
+
189
+ assert.ok(s.scope, "scope should be set");
190
+ assert.equal(s.scope.milestoneId, mid);
191
+ });
192
+ });
193
+
194
+ describe("AutoSession.scope — milestoneId change rebuilds scope", () => {
195
+ let s: AutoSession;
196
+ let projectDir: string;
197
+
198
+ beforeEach(() => {
199
+ projectDir = makeProjectDir();
200
+ s = new AutoSession();
201
+ });
202
+
203
+ afterEach(() => {
204
+ rmSync(projectDir, { recursive: true, force: true });
205
+ });
206
+
207
+ test("scope reflects the new milestoneId after rebuild", () => {
208
+ s.basePath = projectDir;
209
+ s.originalBasePath = projectDir;
210
+ s.currentMilestoneId = "M001";
211
+ applyRebuildScope(s, projectDir, "M001");
212
+
213
+ assert.ok(s.scope, "initial scope should be set");
214
+ assert.equal(s.scope.milestoneId, "M001");
215
+
216
+ // Simulate milestone transition mid-session
217
+ s.currentMilestoneId = "M002";
218
+ applyRebuildScope(s, projectDir, "M002");
219
+
220
+ assert.ok(s.scope, "scope should be set after transition");
221
+ assert.equal(s.scope.milestoneId, "M002");
222
+ });
223
+
224
+ test("scope contextFile changes when milestoneId changes", () => {
225
+ s.basePath = projectDir;
226
+ s.originalBasePath = projectDir;
227
+
228
+ s.currentMilestoneId = "M001";
229
+ applyRebuildScope(s, projectDir, "M001");
230
+ const ctxM001 = s.scope?.contextFile();
231
+
232
+ s.currentMilestoneId = "M002";
233
+ applyRebuildScope(s, projectDir, "M002");
234
+ const ctxM002 = s.scope?.contextFile();
235
+
236
+ assert.ok(ctxM001, "M001 contextFile should be set");
237
+ assert.ok(ctxM002, "M002 contextFile should be set");
238
+ assert.notEqual(ctxM001, ctxM002, "contextFile must differ between milestone IDs");
239
+ assert.ok(ctxM001.includes("M001"), "M001 path should contain M001");
240
+ assert.ok(ctxM002.includes("M002"), "M002 path should contain M002");
241
+ });
242
+ });
243
+
244
+ describe("AutoSession.scope — resume from persisted state", () => {
245
+ let s: AutoSession;
246
+ let projectDir: string;
247
+ let worktreeDir: string;
248
+
249
+ beforeEach(() => {
250
+ projectDir = makeProjectDir();
251
+ worktreeDir = makeWorktreeDir(projectDir, "M003");
252
+ s = new AutoSession();
253
+ });
254
+
255
+ afterEach(() => {
256
+ rmSync(projectDir, { recursive: true, force: true });
257
+ });
258
+
259
+ test("resume without worktree: scope mode is project, projectRoot is base", () => {
260
+ // Mirror the paused-session resume path:
261
+ // s.currentMilestoneId = meta.milestoneId
262
+ // s.originalBasePath = meta.originalBasePath || base
263
+ // rawPath = originalBasePath (no worktreePath present)
264
+ const mid = "M003";
265
+ s.currentMilestoneId = mid;
266
+ s.originalBasePath = projectDir;
267
+ s.basePath = projectDir;
268
+
269
+ applyRebuildScope(s, s.originalBasePath, s.currentMilestoneId);
270
+
271
+ assert.ok(s.scope, "scope should be reconstructed");
272
+ assert.equal(s.scope.milestoneId, mid);
273
+ assert.equal(s.scope.workspace.mode, "project");
274
+ assert.equal(s.scope.workspace.projectRoot, realpathSync(projectDir));
275
+ assert.equal(s.scope.workspace.worktreeRoot, null);
276
+ });
277
+
278
+ test("resume with valid worktree path: scope mode is worktree", () => {
279
+ // Mirror the paused-session resume path where worktreePath exists on disk:
280
+ // rawPath = worktreePath (existsSync true)
281
+ const mid = "M003";
282
+ s.currentMilestoneId = mid;
283
+ s.originalBasePath = projectDir;
284
+ s.basePath = worktreeDir;
285
+
286
+ assert.ok(existsSync(worktreeDir), "worktreeDir must exist for this test");
287
+
288
+ applyRebuildScope(s, worktreeDir, s.currentMilestoneId);
289
+
290
+ assert.ok(s.scope, "scope should be reconstructed");
291
+ assert.equal(s.scope.milestoneId, mid);
292
+ assert.equal(s.scope.workspace.mode, "worktree");
293
+ assert.equal(s.scope.workspace.projectRoot, realpathSync(projectDir));
294
+ assert.equal(s.scope.workspace.worktreeRoot, realpathSync(worktreeDir));
295
+ });
296
+
297
+ test("scope is consistent with direct createWorkspace + scopeMilestone for same inputs", () => {
298
+ const mid = "M003";
299
+ s.currentMilestoneId = mid;
300
+ s.originalBasePath = projectDir;
301
+ s.basePath = projectDir;
302
+
303
+ applyRebuildScope(s, projectDir, mid);
304
+ assert.ok(s.scope, "scope should be set");
305
+
306
+ // Build expected scope via lower-level API to verify equivalence
307
+ const ws = createWorkspace(projectDir);
308
+ const expected = scopeMilestone(ws, mid);
309
+
310
+ assert.equal(s.scope.milestoneId, expected.milestoneId);
311
+ assert.equal(s.scope.contextFile(), expected.contextFile());
312
+ assert.equal(s.scope.roadmapFile(), expected.roadmapFile());
313
+ assert.equal(s.scope.stateFile(), expected.stateFile());
314
+ assert.equal(s.scope.dbPath(), expected.dbPath());
315
+ assert.equal(s.scope.milestoneDir(), expected.milestoneDir());
316
+ assert.equal(s.scope.metaJson(), expected.metaJson());
317
+ });
318
+
319
+ test("reset() clears scope", () => {
320
+ const mid = "M003";
321
+ s.basePath = projectDir;
322
+ s.originalBasePath = projectDir;
323
+ s.currentMilestoneId = mid;
324
+
325
+ applyRebuildScope(s, projectDir, mid);
326
+ assert.ok(s.scope, "scope should be set before reset");
327
+
328
+ s.reset();
329
+ assert.equal(s.scope, null, "scope must be null after reset()");
330
+ });
331
+ });