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
@@ -0,0 +1,378 @@
1
+ // GSD-2 + metrics-scope.test.ts: tests for scope-aware metrics variants (C6)
2
+
3
+ import { describe, test, beforeEach, afterEach } from "node:test";
4
+ import assert from "node:assert/strict";
5
+ import {
6
+ mkdtempSync,
7
+ mkdirSync,
8
+ readFileSync,
9
+ rmSync,
10
+ realpathSync,
11
+ writeFileSync,
12
+ } from "node:fs";
13
+ import { join } from "node:path";
14
+ import { tmpdir } from "node:os";
15
+ import { spawnSync } from "node:child_process";
16
+
17
+ import {
18
+ initMetrics,
19
+ resetMetrics,
20
+ getLedger,
21
+ snapshotUnitMetrics,
22
+ initMetricsByScope,
23
+ getLedgerByScope,
24
+ resetMetricsByScope,
25
+ snapshotUnitMetricsByScope,
26
+ type MetricsLedger,
27
+ type UnitMetrics,
28
+ } from "../metrics.js";
29
+ import { createWorkspace, scopeMilestone } from "../workspace.js";
30
+
31
+ // ─── Helpers ────────────────────────────────────────────────────────────────
32
+
33
+ function makeProjectDir(): string {
34
+ const dir = realpathSync(mkdtempSync(join(tmpdir(), "gsd-metrics-scope-")));
35
+ mkdirSync(join(dir, ".gsd"), { recursive: true });
36
+ return dir;
37
+ }
38
+
39
+ function mockCtx(messages: any[] = []): any {
40
+ const entries = messages.map((msg, i) => ({
41
+ type: "message",
42
+ id: `entry-${i}`,
43
+ parentId: i > 0 ? `entry-${i - 1}` : null,
44
+ timestamp: new Date().toISOString(),
45
+ message: msg,
46
+ }));
47
+ return {
48
+ sessionManager: { getEntries: () => entries },
49
+ model: { id: "test-model" },
50
+ };
51
+ }
52
+
53
+ function assistantMsg(input = 1000, output = 500): any {
54
+ return {
55
+ role: "assistant",
56
+ content: [{ type: "text", text: "done" }],
57
+ usage: {
58
+ input,
59
+ output,
60
+ cacheRead: 0,
61
+ cacheWrite: 0,
62
+ totalTokens: input + output,
63
+ cost: { total: 0.01 },
64
+ },
65
+ };
66
+ }
67
+
68
+ // ─── Tests ──────────────────────────────────────────────────────────────────
69
+
70
+ describe("ByScope variant writes to the same path as legacy variant", () => {
71
+ let projectDir: string;
72
+
73
+ beforeEach(() => {
74
+ projectDir = makeProjectDir();
75
+ resetMetrics();
76
+ });
77
+
78
+ afterEach(() => {
79
+ resetMetrics();
80
+ rmSync(projectDir, { recursive: true, force: true });
81
+ });
82
+
83
+ test("metrics.json written by snapshotUnitMetrics matches path used by snapshotUnitMetricsByScope", () => {
84
+ const ws = createWorkspace(projectDir);
85
+ const scope = scopeMilestone(ws, "M001");
86
+
87
+ const ctx = mockCtx([assistantMsg()]);
88
+ const startedAt = Date.now() - 5000;
89
+
90
+ // Write via legacy path
91
+ initMetrics(projectDir);
92
+ snapshotUnitMetrics(ctx, "execute-task", "M001/S01/T01", startedAt, "test-model");
93
+ resetMetrics();
94
+
95
+ // Read via scope path
96
+ initMetricsByScope(scope);
97
+ const scopedLedger = getLedgerByScope(scope);
98
+ assert.ok(scopedLedger, "scoped ledger should load the same metrics.json");
99
+ assert.equal(scopedLedger!.units.length, 1, "should see the unit written by legacy path");
100
+ assert.equal(scopedLedger!.units[0].id, "M001/S01/T01");
101
+ resetMetricsByScope(scope);
102
+ });
103
+
104
+ test("snapshotUnitMetricsByScope writes to the same metrics.json as the legacy path", () => {
105
+ const ws = createWorkspace(projectDir);
106
+ const scope = scopeMilestone(ws, "M001");
107
+ const ctx = mockCtx([assistantMsg()]);
108
+ const startedAt = Date.now() - 5000;
109
+
110
+ // Write via scope path (no initMetrics called)
111
+ snapshotUnitMetricsByScope(scope, ctx, "execute-task", "M001/S01/T01", startedAt, "test-model");
112
+ resetMetricsByScope(scope);
113
+
114
+ // Read via legacy path
115
+ initMetrics(projectDir);
116
+ const legacyLedger = getLedger();
117
+ assert.ok(legacyLedger, "legacy path should read what the scope variant wrote");
118
+ assert.equal(legacyLedger!.units.length, 1);
119
+ assert.equal(legacyLedger!.units[0].id, "M001/S01/T01");
120
+ resetMetrics();
121
+ });
122
+ });
123
+
124
+ describe("ByScope variant is pinned to scope — cwd-drift does not move write target", () => {
125
+ let projectDir: string;
126
+
127
+ beforeEach(() => {
128
+ projectDir = makeProjectDir();
129
+ resetMetrics();
130
+ });
131
+
132
+ afterEach(() => {
133
+ resetMetrics();
134
+ rmSync(projectDir, { recursive: true, force: true });
135
+ });
136
+
137
+ test("write target is the scope's projectRoot regardless of process.cwd()", () => {
138
+ const ws = createWorkspace(projectDir);
139
+ const scope = scopeMilestone(ws, "M001");
140
+ const ctx = mockCtx([assistantMsg()]);
141
+ const startedAt = Date.now() - 3000;
142
+
143
+ // Record projectRoot before writing
144
+ const expectedMetricsPath = join(ws.projectRoot, ".gsd", "metrics.json");
145
+
146
+ snapshotUnitMetricsByScope(scope, ctx, "execute-task", "M001/S01/T01", startedAt, "test-model");
147
+
148
+ // Verify the file was written to the expected location
149
+ const raw = readFileSync(expectedMetricsPath, "utf-8");
150
+ const parsed: MetricsLedger = JSON.parse(raw);
151
+ assert.equal(parsed.units.length, 1);
152
+ assert.equal(parsed.units[0].id, "M001/S01/T01");
153
+
154
+ resetMetricsByScope(scope);
155
+ });
156
+
157
+ test("two scopes for different projectRoots write to separate metrics.json files", () => {
158
+ const projectDir2 = makeProjectDir();
159
+ try {
160
+ const ws1 = createWorkspace(projectDir);
161
+ const ws2 = createWorkspace(projectDir2);
162
+ const scope1 = scopeMilestone(ws1, "M001");
163
+ const scope2 = scopeMilestone(ws2, "M002");
164
+
165
+ const ctx = mockCtx([assistantMsg()]);
166
+ const startedAt = Date.now() - 3000;
167
+
168
+ snapshotUnitMetricsByScope(scope1, ctx, "execute-task", "M001/S01/T01", startedAt, "test-model");
169
+ snapshotUnitMetricsByScope(scope2, ctx, "execute-task", "M002/S01/T01", startedAt, "test-model");
170
+
171
+ const metrics1 = JSON.parse(
172
+ readFileSync(join(ws1.projectRoot, ".gsd", "metrics.json"), "utf-8"),
173
+ ) as MetricsLedger;
174
+ const metrics2 = JSON.parse(
175
+ readFileSync(join(ws2.projectRoot, ".gsd", "metrics.json"), "utf-8"),
176
+ ) as MetricsLedger;
177
+
178
+ assert.equal(metrics1.units.length, 1);
179
+ assert.equal(metrics1.units[0].id, "M001/S01/T01");
180
+ assert.equal(metrics2.units.length, 1);
181
+ assert.equal(metrics2.units[0].id, "M002/S01/T01");
182
+
183
+ resetMetricsByScope(scope1);
184
+ resetMetricsByScope(scope2);
185
+ } finally {
186
+ rmSync(projectDir2, { recursive: true, force: true });
187
+ }
188
+ });
189
+ });
190
+
191
+ describe("ByScope works without calling initMetrics", () => {
192
+ let projectDir: string;
193
+
194
+ beforeEach(() => {
195
+ projectDir = makeProjectDir();
196
+ // Deliberately do NOT call initMetrics / resetMetrics
197
+ });
198
+
199
+ afterEach(() => {
200
+ resetMetrics();
201
+ rmSync(projectDir, { recursive: true, force: true });
202
+ });
203
+
204
+ test("snapshotUnitMetricsByScope succeeds without initMetrics having been called", () => {
205
+ const ws = createWorkspace(projectDir);
206
+ const scope = scopeMilestone(ws, "M001");
207
+ const ctx = mockCtx([assistantMsg()]);
208
+
209
+ // Confirm singleton was never initialized
210
+ assert.equal(getLedger(), null, "module singleton should be null — initMetrics was never called");
211
+
212
+ const unit = snapshotUnitMetricsByScope(
213
+ scope,
214
+ ctx,
215
+ "execute-task",
216
+ "M001/S01/T01",
217
+ Date.now() - 2000,
218
+ "test-model",
219
+ );
220
+ assert.ok(unit, "snapshotUnitMetricsByScope should return a unit");
221
+ assert.equal(unit!.id, "M001/S01/T01");
222
+
223
+ // Verify on disk
224
+ const raw = readFileSync(join(projectDir, ".gsd", "metrics.json"), "utf-8");
225
+ const parsed: MetricsLedger = JSON.parse(raw);
226
+ assert.equal(parsed.units.length, 1);
227
+
228
+ resetMetricsByScope(scope);
229
+ });
230
+
231
+ test("initMetricsByScope succeeds without initMetrics having been called", () => {
232
+ const ws = createWorkspace(projectDir);
233
+ const scope = scopeMilestone(ws, "M001");
234
+
235
+ assert.equal(getLedger(), null);
236
+
237
+ initMetricsByScope(scope);
238
+ const l = getLedgerByScope(scope);
239
+ assert.ok(l, "getLedgerByScope should return a ledger after initMetricsByScope");
240
+ assert.equal(l!.version, 1);
241
+ assert.equal(l!.units.length, 0);
242
+
243
+ resetMetricsByScope(scope);
244
+ });
245
+ });
246
+
247
+ describe("ByScope atomic write-merge — concurrent writers do not clobber", () => {
248
+ let projectDir: string;
249
+
250
+ beforeEach(() => {
251
+ projectDir = makeProjectDir();
252
+ resetMetrics();
253
+ });
254
+
255
+ afterEach(() => {
256
+ resetMetrics();
257
+ rmSync(projectDir, { recursive: true, force: true });
258
+ });
259
+
260
+ // Worker script: same lock+merge semantics as saveLedger, written in plain CJS
261
+ // so it can run as a child process without loading the full extension tree.
262
+ const MERGE_WORKER = `
263
+ const { openSync, closeSync, unlinkSync, existsSync, readFileSync, mkdirSync, renameSync } = require('node:fs');
264
+ const { dirname } = require('node:path');
265
+ const { randomBytes } = require('node:crypto');
266
+
267
+ const metricsPath = process.env.GSD_SCOPE_METRICS_PATH;
268
+ const milestoneId = process.env.GSD_SCOPE_MILESTONE_ID;
269
+ const lockPath = metricsPath + '.lock';
270
+
271
+ function acquireLock(lp, ms) {
272
+ const deadline = Date.now() + ms;
273
+ while (Date.now() < deadline) {
274
+ try { const fd = openSync(lp, 'wx'); closeSync(fd); return true; }
275
+ catch { const w = Date.now() + Math.min(50, deadline - Date.now()); while (Date.now() < w) {} }
276
+ }
277
+ return false;
278
+ }
279
+ function releaseLock(lp) { try { unlinkSync(lp); } catch {} }
280
+ function saveAtomic(fp, data) {
281
+ mkdirSync(dirname(fp), { recursive: true });
282
+ const tmp = fp + '.tmp.' + randomBytes(4).toString('hex');
283
+ require('node:fs').writeFileSync(tmp, JSON.stringify(data, null, 2) + '\\n', 'utf-8');
284
+ renameSync(tmp, fp);
285
+ }
286
+ function dedup(units) {
287
+ const m = new Map();
288
+ for (const u of units) {
289
+ const k = u.type + '\\0' + u.id + '\\0' + u.startedAt;
290
+ const e = m.get(k);
291
+ if (!e || u.finishedAt > e.finishedAt) m.set(k, u);
292
+ }
293
+ return Array.from(m.values());
294
+ }
295
+
296
+ const unit = {
297
+ type: 'execute-task', id: milestoneId + '/S01/T01', model: 'test',
298
+ startedAt: 1000, finishedAt: Date.now(),
299
+ tokens: { input: 10, output: 5, cacheRead: 0, cacheWrite: 0, total: 15 },
300
+ cost: 0.001, toolCalls: 0, assistantMessages: 1, userMessages: 1,
301
+ };
302
+ const workerLedger = { version: 1, projectStartedAt: 1000, units: [unit] };
303
+
304
+ const acquired = acquireLock(lockPath, 5000);
305
+ try {
306
+ let diskUnits = [];
307
+ if (existsSync(metricsPath)) {
308
+ try { const p = JSON.parse(readFileSync(metricsPath, 'utf-8')); if (p && Array.isArray(p.units)) diskUnits = p.units; } catch {}
309
+ }
310
+ saveAtomic(metricsPath, { ...workerLedger, units: dedup([...diskUnits, ...workerLedger.units]) });
311
+ } finally {
312
+ if (acquired) releaseLock(lockPath);
313
+ }
314
+ `;
315
+
316
+ function spawnMergeWorker(metricsPath: string, milestoneId: string): void {
317
+ const result = spawnSync(process.execPath, ["-e", MERGE_WORKER], {
318
+ env: {
319
+ ...process.env,
320
+ GSD_SCOPE_METRICS_PATH: metricsPath,
321
+ GSD_SCOPE_MILESTONE_ID: milestoneId,
322
+ },
323
+ encoding: "utf-8",
324
+ timeout: 10_000,
325
+ });
326
+ if (result.error) throw result.error;
327
+ if (result.status !== 0) {
328
+ throw new Error(`Worker for ${milestoneId} failed:\n${result.stderr}`);
329
+ }
330
+ }
331
+
332
+ test("snapshotUnitMetricsByScope preserves a pre-existing entry written by a concurrent worker", () => {
333
+ const ws = createWorkspace(projectDir);
334
+ const scope = scopeMilestone(ws, "M002");
335
+ const metricsPath = join(ws.projectRoot, ".gsd", "metrics.json");
336
+
337
+ // Simulate a concurrent worker that already wrote M001's entry to disk
338
+ spawnMergeWorker(metricsPath, "M001");
339
+
340
+ // Now write M002 via scope variant — must preserve M001's entry
341
+ const ctx = mockCtx([assistantMsg()]);
342
+ snapshotUnitMetricsByScope(
343
+ scope,
344
+ ctx,
345
+ "execute-task",
346
+ "M002/S01/T01",
347
+ Date.now() - 2000,
348
+ "test-model",
349
+ );
350
+
351
+ const raw = readFileSync(metricsPath, "utf-8");
352
+ const parsed: MetricsLedger = JSON.parse(raw);
353
+ assert.equal(parsed.units.length, 2, "both M001 and M002 units must be in metrics.json");
354
+
355
+ const ids = parsed.units.map((u: UnitMetrics) => u.id);
356
+ assert.ok(ids.some((id) => id.startsWith("M001")), "M001 unit must be preserved");
357
+ assert.ok(ids.some((id) => id.startsWith("M002")), "M002 unit must be present");
358
+
359
+ resetMetricsByScope(scope);
360
+ });
361
+
362
+ test("idempotent ByScope snapshot does not duplicate units on disk", () => {
363
+ const ws = createWorkspace(projectDir);
364
+ const scope = scopeMilestone(ws, "M001");
365
+ const ctx = mockCtx([assistantMsg()]);
366
+ const startedAt = Date.now() - 3000;
367
+ const metricsPath = join(ws.projectRoot, ".gsd", "metrics.json");
368
+
369
+ // Snapshot twice with same type+id+startedAt
370
+ snapshotUnitMetricsByScope(scope, ctx, "execute-task", "M001/S01/T01", startedAt, "test-model");
371
+ snapshotUnitMetricsByScope(scope, ctx, "execute-task", "M001/S01/T01", startedAt, "test-model");
372
+
373
+ const parsed: MetricsLedger = JSON.parse(readFileSync(metricsPath, "utf-8"));
374
+ assert.equal(parsed.units.length, 1, "duplicate snapshots must not create duplicate entries");
375
+
376
+ resetMetricsByScope(scope);
377
+ });
378
+ });