@opengsd/gsd-pi 1.4.0 → 1.5.0

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 (329) hide show
  1. package/README.md +11 -11
  2. package/dist/onboarding.js +11 -0
  3. package/dist/resources/.managed-resources-content-hash +1 -1
  4. package/dist/resources/GSD-WORKFLOW.md +20 -25
  5. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +118 -53
  6. package/dist/resources/extensions/cursor-cli/index.js +16 -0
  7. package/dist/resources/extensions/cursor-cli/models.js +63 -0
  8. package/dist/resources/extensions/cursor-cli/package.json +11 -0
  9. package/dist/resources/extensions/cursor-cli/readiness.js +128 -0
  10. package/dist/resources/extensions/cursor-cli/stream-adapter.js +353 -0
  11. package/dist/resources/extensions/gsd/activity-log.js +4 -1
  12. package/dist/resources/extensions/gsd/artifact-verification.js +25 -9
  13. package/dist/resources/extensions/gsd/auto/closeout.js +45 -42
  14. package/dist/resources/extensions/gsd/auto/finalize.js +9 -0
  15. package/dist/resources/extensions/gsd/auto/orchestrator.js +1 -1
  16. package/dist/resources/extensions/gsd/auto/run-unit.js +5 -2
  17. package/dist/resources/extensions/gsd/auto/schedule-wakeup.js +3 -0
  18. package/dist/resources/extensions/gsd/auto-dispatch.js +15 -5
  19. package/dist/resources/extensions/gsd/auto-model-selection.js +36 -18
  20. package/dist/resources/extensions/gsd/auto-prompts.js +76 -2
  21. package/dist/resources/extensions/gsd/auto-start.js +4 -3
  22. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +4 -0
  23. package/dist/resources/extensions/gsd/auto-worktree.js +38 -11
  24. package/dist/resources/extensions/gsd/auto.js +23 -3
  25. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -0
  26. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +114 -5
  27. package/dist/resources/extensions/gsd/bootstrap/schedule-wakeup-tool.js +58 -9
  28. package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +10 -2
  29. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +14 -1
  30. package/dist/resources/extensions/gsd/codebase-generator.js +157 -19
  31. package/dist/resources/extensions/gsd/commands/handlers/core.js +40 -4
  32. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +153 -1
  33. package/dist/resources/extensions/gsd/commands-worktree.js +11 -2
  34. package/dist/resources/extensions/gsd/db/queries.js +39 -0
  35. package/dist/resources/extensions/gsd/discussion-handoff.js +8 -3
  36. package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -2
  37. package/dist/resources/extensions/gsd/doctor-engine-checks.js +206 -14
  38. package/dist/resources/extensions/gsd/doctor-providers.js +38 -10
  39. package/dist/resources/extensions/gsd/doctor.js +93 -3
  40. package/dist/resources/extensions/gsd/exec-sandbox.js +6 -2
  41. package/dist/resources/extensions/gsd/flat-phase-migration.js +74 -23
  42. package/dist/resources/extensions/gsd/git-service.js +14 -18
  43. package/dist/resources/extensions/gsd/gsd-db.js +52 -0
  44. package/dist/resources/extensions/gsd/guidance.js +1 -0
  45. package/dist/resources/extensions/gsd/guided-flow.js +40 -2
  46. package/dist/resources/extensions/gsd/key-manager.js +1 -0
  47. package/dist/resources/extensions/gsd/markdown-renderer.js +25 -8
  48. package/dist/resources/extensions/gsd/migrate-external.js +24 -7
  49. package/dist/resources/extensions/gsd/milestone-merge-transaction.js +3 -3
  50. package/dist/resources/extensions/gsd/preferences-diagnostics.js +24 -1
  51. package/dist/resources/extensions/gsd/preferences-models.js +6 -4
  52. package/dist/resources/extensions/gsd/preferences-validation.js +25 -2
  53. package/dist/resources/extensions/gsd/preferences.js +29 -2
  54. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -2
  55. package/dist/resources/extensions/gsd/redact-secrets.js +37 -0
  56. package/dist/resources/extensions/gsd/repo-identity.js +16 -0
  57. package/dist/resources/extensions/gsd/repository-registry.js +6 -1
  58. package/dist/resources/extensions/gsd/root-write-leak-guard.js +4 -2
  59. package/dist/resources/extensions/gsd/safe-fs.js +23 -2
  60. package/dist/resources/extensions/gsd/skills/gsd-headless/SKILL.md +7 -9
  61. package/dist/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -0
  62. package/dist/resources/extensions/gsd/tools/plan-task.js +76 -8
  63. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +40 -0
  64. package/dist/resources/extensions/gsd/unit-context-manifest.js +5 -4
  65. package/dist/resources/extensions/gsd/unit-registry.js +27 -2
  66. package/dist/resources/extensions/gsd/unit-runtime.js +21 -0
  67. package/dist/resources/extensions/gsd/workspace.js +26 -8
  68. package/dist/resources/extensions/gsd/worktree-lifecycle.js +67 -5
  69. package/dist/resources/extensions/gsd/worktree-manager.js +97 -4
  70. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  71. package/dist/web/standalone/.next/BUILD_ID +1 -1
  72. package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
  73. package/dist/web/standalone/.next/build-manifest.json +2 -2
  74. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  91. package/dist/web/standalone/.next/server/app/index.html +1 -1
  92. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app-paths-manifest.json +7 -7
  99. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  100. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  102. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  103. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  104. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  105. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  106. package/dist/wizard.d.ts +8 -0
  107. package/dist/wizard.js +8 -1
  108. package/integrations/hermes/CONTEXT.md +47 -0
  109. package/integrations/hermes/README.md +21 -0
  110. package/integrations/hermes/__init__.py +31 -0
  111. package/integrations/hermes/docs/issue-1162-grilling.md +197 -0
  112. package/integrations/hermes/docs/setup.md +4 -0
  113. package/integrations/hermes/open_gsd_hermes/commands.py +141 -0
  114. package/integrations/hermes/open_gsd_hermes/config.py +2 -0
  115. package/integrations/hermes/open_gsd_hermes/gsd_client.py +594 -31
  116. package/integrations/hermes/open_gsd_hermes/notifications.py +10 -1
  117. package/integrations/hermes/plugin.yaml +4 -0
  118. package/integrations/hermes/tests/test_config.py +6 -0
  119. package/integrations/hermes/tests/test_directory_loader.py +37 -0
  120. package/integrations/hermes/tests/test_gsd_client_cache.py +3 -0
  121. package/integrations/hermes/tests/test_gsd_client_execute.py +35 -0
  122. package/integrations/hermes/tests/test_gsd_client_process_cwd.py +22 -0
  123. package/integrations/hermes/tests/test_gsd_client_timeout.py +98 -0
  124. package/integrations/hermes/tests/test_milestone_client.py +447 -0
  125. package/integrations/hermes/tests/test_new_milestone_command.py +313 -0
  126. package/integrations/hermes/tests/test_supervisor_fsm.py +40 -0
  127. package/package.json +8 -8
  128. package/packages/cloud-mcp-gateway/dist/auth-store.d.ts +1 -0
  129. package/packages/cloud-mcp-gateway/dist/auth-store.d.ts.map +1 -1
  130. package/packages/cloud-mcp-gateway/dist/auth-store.js +21 -1
  131. package/packages/cloud-mcp-gateway/dist/auth-store.js.map +1 -1
  132. package/packages/cloud-mcp-gateway/dist/auth-store.test.js +34 -0
  133. package/packages/cloud-mcp-gateway/dist/auth-store.test.js.map +1 -1
  134. package/packages/cloud-mcp-gateway/package.json +2 -2
  135. package/packages/contracts/package.json +1 -1
  136. package/packages/daemon/dist/cloud-runtime.d.ts +2 -0
  137. package/packages/daemon/dist/cloud-runtime.d.ts.map +1 -1
  138. package/packages/daemon/dist/cloud-runtime.js +25 -1
  139. package/packages/daemon/dist/cloud-runtime.js.map +1 -1
  140. package/packages/daemon/dist/cloud-runtime.test.js +51 -0
  141. package/packages/daemon/dist/cloud-runtime.test.js.map +1 -1
  142. package/packages/daemon/dist/message-batcher.d.ts +7 -0
  143. package/packages/daemon/dist/message-batcher.d.ts.map +1 -1
  144. package/packages/daemon/dist/message-batcher.js +13 -0
  145. package/packages/daemon/dist/message-batcher.js.map +1 -1
  146. package/packages/daemon/dist/message-batcher.test.js +48 -0
  147. package/packages/daemon/dist/message-batcher.test.js.map +1 -1
  148. package/packages/daemon/dist/session-manager.js +1 -1
  149. package/packages/daemon/dist/session-manager.js.map +1 -1
  150. package/packages/daemon/package.json +5 -5
  151. package/packages/gsd-agent-core/dist/compaction/compaction.d.ts +13 -1
  152. package/packages/gsd-agent-core/dist/compaction/compaction.d.ts.map +1 -1
  153. package/packages/gsd-agent-core/dist/compaction/compaction.js +15 -1
  154. package/packages/gsd-agent-core/dist/compaction/compaction.js.map +1 -1
  155. package/packages/gsd-agent-core/dist/session/agent-session-navigation.d.ts.map +1 -1
  156. package/packages/gsd-agent-core/dist/session/agent-session-navigation.js +4 -1
  157. package/packages/gsd-agent-core/dist/session/agent-session-navigation.js.map +1 -1
  158. package/packages/gsd-agent-core/package.json +5 -5
  159. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts.map +1 -1
  160. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js +1 -0
  161. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js.map +1 -1
  162. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js +1 -1
  163. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js.map +1 -1
  164. package/packages/gsd-agent-modes/package.json +7 -7
  165. package/packages/mcp-server/dist/server.d.ts +18 -5
  166. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  167. package/packages/mcp-server/dist/server.js +46 -5
  168. package/packages/mcp-server/dist/server.js.map +1 -1
  169. package/packages/mcp-server/dist/session-manager.js +1 -1
  170. package/packages/mcp-server/dist/session-manager.js.map +1 -1
  171. package/packages/mcp-server/package.json +4 -4
  172. package/packages/native/package.json +1 -1
  173. package/packages/pi-agent-core/package.json +1 -1
  174. package/packages/pi-ai/dist/env-api-keys.d.ts.map +1 -1
  175. package/packages/pi-ai/dist/env-api-keys.js +3 -0
  176. package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
  177. package/packages/pi-ai/dist/types.d.ts +2 -2
  178. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  179. package/packages/pi-ai/dist/types.js.map +1 -1
  180. package/packages/pi-ai/package.json +1 -1
  181. package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
  182. package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -0
  183. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  184. package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts +1 -0
  185. package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts.map +1 -1
  186. package/packages/pi-coding-agent/dist/core/session-manager-types.js.map +1 -1
  187. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  188. package/packages/pi-coding-agent/dist/core/session-manager.js +3 -0
  189. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  190. package/packages/pi-coding-agent/package.json +7 -7
  191. package/packages/pi-tui/package.json +2 -2
  192. package/packages/rpc-client/dist/rpc-client.js +1 -1
  193. package/packages/rpc-client/dist/rpc-client.js.map +1 -1
  194. package/packages/rpc-client/package.json +2 -2
  195. package/pkg/package.json +1 -1
  196. package/scripts/link-workspace-packages.cjs +14 -4
  197. package/src/resources/GSD-WORKFLOW.md +20 -25
  198. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +130 -51
  199. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +371 -39
  200. package/src/resources/extensions/cursor-cli/index.ts +18 -0
  201. package/src/resources/extensions/cursor-cli/models.ts +65 -0
  202. package/src/resources/extensions/cursor-cli/package.json +11 -0
  203. package/src/resources/extensions/cursor-cli/readiness.ts +143 -0
  204. package/src/resources/extensions/cursor-cli/stream-adapter.ts +440 -0
  205. package/src/resources/extensions/cursor-cli/tests/index.test.ts +54 -0
  206. package/src/resources/extensions/cursor-cli/tests/readiness.test.ts +29 -0
  207. package/src/resources/extensions/cursor-cli/tests/stream-adapter.test.ts +166 -0
  208. package/src/resources/extensions/gsd/activity-log.ts +4 -1
  209. package/src/resources/extensions/gsd/artifact-verification.ts +25 -9
  210. package/src/resources/extensions/gsd/auto/closeout.ts +54 -56
  211. package/src/resources/extensions/gsd/auto/finalize.ts +8 -0
  212. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
  213. package/src/resources/extensions/gsd/auto/orchestrator.ts +1 -1
  214. package/src/resources/extensions/gsd/auto/run-unit.ts +5 -2
  215. package/src/resources/extensions/gsd/auto/schedule-wakeup.ts +8 -0
  216. package/src/resources/extensions/gsd/auto-dispatch.ts +17 -5
  217. package/src/resources/extensions/gsd/auto-model-selection.ts +49 -18
  218. package/src/resources/extensions/gsd/auto-prompts.ts +73 -2
  219. package/src/resources/extensions/gsd/auto-start.ts +4 -3
  220. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +4 -0
  221. package/src/resources/extensions/gsd/auto-worktree.ts +50 -11
  222. package/src/resources/extensions/gsd/auto.ts +22 -3
  223. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -0
  224. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +128 -5
  225. package/src/resources/extensions/gsd/bootstrap/schedule-wakeup-tool.ts +80 -12
  226. package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +12 -2
  227. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +23 -1
  228. package/src/resources/extensions/gsd/codebase-generator.ts +179 -18
  229. package/src/resources/extensions/gsd/commands/handlers/core.ts +39 -3
  230. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +135 -1
  231. package/src/resources/extensions/gsd/commands-worktree.ts +13 -2
  232. package/src/resources/extensions/gsd/db/queries.ts +40 -0
  233. package/src/resources/extensions/gsd/discussion-handoff.ts +10 -2
  234. package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -2
  235. package/src/resources/extensions/gsd/doctor-engine-checks.ts +269 -18
  236. package/src/resources/extensions/gsd/doctor-providers.ts +39 -10
  237. package/src/resources/extensions/gsd/doctor-types.ts +5 -1
  238. package/src/resources/extensions/gsd/doctor.ts +95 -3
  239. package/src/resources/extensions/gsd/exec-sandbox.ts +6 -2
  240. package/src/resources/extensions/gsd/flat-phase-migration.ts +98 -22
  241. package/src/resources/extensions/gsd/git-service.ts +14 -17
  242. package/src/resources/extensions/gsd/gsd-db.ts +72 -0
  243. package/src/resources/extensions/gsd/guidance.ts +2 -0
  244. package/src/resources/extensions/gsd/guided-flow.ts +45 -2
  245. package/src/resources/extensions/gsd/key-manager.ts +1 -0
  246. package/src/resources/extensions/gsd/markdown-renderer.ts +25 -7
  247. package/src/resources/extensions/gsd/migrate-external.ts +23 -6
  248. package/src/resources/extensions/gsd/milestone-merge-transaction.ts +4 -4
  249. package/src/resources/extensions/gsd/model-router.ts +4 -5
  250. package/src/resources/extensions/gsd/preferences-diagnostics.ts +24 -0
  251. package/src/resources/extensions/gsd/preferences-models.ts +6 -3
  252. package/src/resources/extensions/gsd/preferences-validation.ts +28 -2
  253. package/src/resources/extensions/gsd/preferences.ts +38 -4
  254. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -2
  255. package/src/resources/extensions/gsd/redact-secrets.ts +40 -0
  256. package/src/resources/extensions/gsd/repo-identity.ts +17 -0
  257. package/src/resources/extensions/gsd/repository-registry.ts +7 -1
  258. package/src/resources/extensions/gsd/root-write-leak-guard.ts +3 -2
  259. package/src/resources/extensions/gsd/safe-fs.ts +22 -2
  260. package/src/resources/extensions/gsd/skills/gsd-headless/SKILL.md +7 -9
  261. package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -0
  262. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +131 -5
  263. package/src/resources/extensions/gsd/tests/auto-migrating-recovery.test.ts +18 -0
  264. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +178 -0
  265. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +43 -1
  266. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +54 -0
  267. package/src/resources/extensions/gsd/tests/auto-remote-session-lock-cleanup.test.ts +41 -0
  268. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +41 -0
  269. package/src/resources/extensions/gsd/tests/auto-session-scope.test.ts +4 -4
  270. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +3 -0
  271. package/src/resources/extensions/gsd/tests/auto-timeout-recovery-harness-abort.test.ts +55 -0
  272. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +8 -0
  273. package/src/resources/extensions/gsd/tests/batch-task-query.test.ts +85 -0
  274. package/src/resources/extensions/gsd/tests/check-auto-start-ready-guard.test.ts +29 -0
  275. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +365 -0
  276. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +62 -1
  277. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +138 -1
  278. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +397 -5
  279. package/src/resources/extensions/gsd/tests/doctor-workspace.test.ts +207 -0
  280. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +38 -1
  281. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +87 -19
  282. package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +89 -0
  283. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +9 -0
  284. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
  285. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +122 -0
  286. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +4 -4
  287. package/src/resources/extensions/gsd/tests/migrate-external-worktree.test.ts +116 -0
  288. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +152 -22
  289. package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +1 -1
  290. package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +2 -2
  291. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +50 -6
  292. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +17 -0
  293. package/src/resources/extensions/gsd/tests/plan-task.test.ts +264 -1
  294. package/src/resources/extensions/gsd/tests/preferences.test.ts +150 -0
  295. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +142 -0
  296. package/src/resources/extensions/gsd/tests/recovery-verify-logs.test.ts +4 -4
  297. package/src/resources/extensions/gsd/tests/redact-secrets.test.ts +56 -0
  298. package/src/resources/extensions/gsd/tests/register-hooks-flat-phase-migration.test.ts +73 -0
  299. package/src/resources/extensions/gsd/tests/register-hooks-loop-guard-auto.test.ts +275 -0
  300. package/src/resources/extensions/gsd/tests/repository-registry.test.ts +41 -2
  301. package/src/resources/extensions/gsd/tests/require-slice-discussion-dispatch.test.ts +55 -0
  302. package/src/resources/extensions/gsd/tests/root-write-leak-guard.test.ts +31 -9
  303. package/src/resources/extensions/gsd/tests/schedule-wakeup-tool.test.ts +167 -0
  304. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -0
  305. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -1
  306. package/src/resources/extensions/gsd/tests/status-per-repo.test.ts +94 -0
  307. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +35 -0
  308. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +63 -0
  309. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +66 -18
  310. package/src/resources/extensions/gsd/tests/unit-registry.test.ts +56 -0
  311. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +30 -0
  312. package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +52 -0
  313. package/src/resources/extensions/gsd/tests/validator-scope-parity.test.ts +53 -1
  314. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +208 -1
  315. package/src/resources/extensions/gsd/tests/workspace.test.ts +18 -4
  316. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +4 -4
  317. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +2 -2
  318. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +31 -1
  319. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +32 -0
  320. package/src/resources/extensions/gsd/tools/plan-task.ts +107 -9
  321. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +58 -0
  322. package/src/resources/extensions/gsd/unit-context-manifest.ts +11 -5
  323. package/src/resources/extensions/gsd/unit-registry.ts +34 -2
  324. package/src/resources/extensions/gsd/unit-runtime.ts +42 -0
  325. package/src/resources/extensions/gsd/workspace.ts +42 -8
  326. package/src/resources/extensions/gsd/worktree-lifecycle.ts +135 -11
  327. package/src/resources/extensions/gsd/worktree-manager.ts +143 -5
  328. /package/dist/web/standalone/.next/static/{zQLcXm0Za8lexoXtgDpMG → bCg3aYrFN1DKZr2dqgE7L}/_buildManifest.js +0 -0
  329. /package/dist/web/standalone/.next/static/{zQLcXm0Za8lexoXtgDpMG → bCg3aYrFN1DKZr2dqgE7L}/_ssgManifest.js +0 -0
@@ -21,6 +21,8 @@ import { existsSync, readFileSync, unlinkSync } from "node:fs";
21
21
  import { randomUUID } from "node:crypto";
22
22
  import { join } from "node:path";
23
23
 
24
+ import type { PreflightResult, PostflightResult } from "./clean-root-preflight.js";
25
+
24
26
  import type { AutoSession } from "./auto/session.js";
25
27
  import { debugLog } from "./debug-logger.js";
26
28
  import { logWarning } from "./workflow-logger.js";
@@ -153,11 +155,11 @@ export interface WorktreeLifecycleDeps {
153
155
  /**
154
156
  * Milestone Merge Transaction Module runner.
155
157
  *
156
- * The field name is preserved for existing test fixtures, but production
157
- * wiring now supplies the named transaction wrapper rather than the raw
158
- * squash-merge primitive directly.
158
+ * The field name describes the lifecycle seam; production wiring supplies
159
+ * the named transaction wrapper rather than the raw legacy
160
+ * auto-worktree primitive directly.
159
161
  */
160
- mergeMilestoneToMain: MilestoneMergeTransactionRunner;
162
+ mergeMilestone: MilestoneMergeTransactionRunner;
161
163
 
162
164
  // ADR-016 phase 2 / C1 + C2 + C3 + C4 inlined the following fields as
163
165
  // direct imports — leaf primitives that did not vary across callers:
@@ -238,7 +240,106 @@ export interface StrandedMilestoneAdoptionOptions {
238
240
 
239
241
  export type ExitResult =
240
242
  | { ok: true; merged: boolean; codeFilesChanged: boolean }
241
- | { ok: false; reason: "merge-conflict" | "teardown-failed"; cause?: unknown };
243
+ | {
244
+ ok: false;
245
+ reason:
246
+ | "merge-conflict"
247
+ | "teardown-failed"
248
+ | "preflight-dirty-overlap"
249
+ | "preflight-unmerged-conflicts"
250
+ | "merge-failed"
251
+ | "postflight-stash-restore-failed";
252
+ cause?: unknown;
253
+ postflight?: PostflightResult;
254
+ };
255
+
256
+ export interface GuardedMilestoneMergeDeps {
257
+ preflightCleanRoot: (
258
+ basePath: string,
259
+ milestoneId: string,
260
+ notify: NotifyCtx["notify"],
261
+ ) => PreflightResult;
262
+ postflightPopStash: (
263
+ basePath: string,
264
+ milestoneId: string,
265
+ stashMarker: string | undefined,
266
+ notify: NotifyCtx["notify"],
267
+ ) => PostflightResult;
268
+ }
269
+
270
+ /**
271
+ * Optional `exitMilestone(..., { merge: true, guardedMerge })` contract for callers
272
+ * that need root-clean preflight and postflight stash restoration around the
273
+ * lifecycle-owned merge attempt. `projectRoot` is the workspace root whose
274
+ * user changes are protected by the supplied guard functions.
275
+ */
276
+ export interface GuardedMilestoneMergeOptions extends GuardedMilestoneMergeDeps {
277
+ projectRoot: string;
278
+ }
279
+
280
+ type GuardedMilestoneMergeResult = ExitResult;
281
+
282
+ function preflightBlockedMergeReason(
283
+ blockedReason: PreflightResult["blockedReason"],
284
+ ): Extract<ExitResult, { ok: false }>["reason"] {
285
+ if (blockedReason?.startsWith("unmerged-conflicts")) {
286
+ return "preflight-unmerged-conflicts";
287
+ }
288
+ return "preflight-dirty-overlap";
289
+ }
290
+
291
+ /**
292
+ * Run a milestone merge behind the Worktree Lifecycle seam with the root-clean
293
+ * stash guard that protects user changes around merge.
294
+ *
295
+ * The helper owns the invariant ordering (preflight -> merge callback ->
296
+ * postflight on every attempted merge path) and returns the same typed result
297
+ * shape as `exitMilestone`. Auto closeout remains responsible for translating
298
+ * that result into loop policy (pause vs. stop, visible transcript
299
+ * preservation, projection rebuild).
300
+ */
301
+ function runGuardedMilestoneMerge(request: {
302
+ merge: () => ExitResult;
303
+ guard: GuardedMilestoneMergeOptions;
304
+ milestoneId: string;
305
+ notify: NotifyCtx["notify"];
306
+ }): GuardedMilestoneMergeResult {
307
+ const { merge, guard, milestoneId, notify } = request;
308
+ const preflight = guard.preflightCleanRoot(guard.projectRoot, milestoneId, notify);
309
+ if (preflight.blocked) {
310
+ return {
311
+ ok: false,
312
+ reason: preflightBlockedMergeReason(preflight.blockedReason),
313
+ };
314
+ }
315
+
316
+ let mergeError: unknown = null;
317
+ const exitResult = merge();
318
+ if (!exitResult.ok) {
319
+ mergeError = exitResult.cause ?? new Error(`exit ${exitResult.reason}`);
320
+ }
321
+
322
+ let postflight: PostflightResult | undefined;
323
+ if (preflight.stashPushed) {
324
+ postflight = guard.postflightPopStash(
325
+ guard.projectRoot,
326
+ milestoneId,
327
+ preflight.stashMarker,
328
+ notify,
329
+ );
330
+ }
331
+
332
+ if (mergeError instanceof MergeConflictError) {
333
+ return { ok: false, reason: "merge-conflict", cause: mergeError, postflight };
334
+ }
335
+ if (mergeError) {
336
+ return { ok: false, reason: "merge-failed", cause: mergeError, postflight };
337
+ }
338
+ if (postflight?.needsManualRecovery) {
339
+ return { ok: false, reason: "postflight-stash-restore-failed", postflight };
340
+ }
341
+ return exitResult;
342
+ }
242
343
 
243
344
  /**
244
345
  * Session-less merge entry context. Per ADR-016 phase 2 / A1 (#5616), the
@@ -1046,7 +1147,7 @@ function _mergeWorktreeModeImpl(
1046
1147
  };
1047
1148
  }
1048
1149
 
1049
- const mergeResult = deps.mergeMilestoneToMain(
1150
+ const mergeResult = deps.mergeMilestone(
1050
1151
  originalBasePath,
1051
1152
  milestoneId,
1052
1153
  roadmapResolution.content,
@@ -1213,7 +1314,7 @@ function _mergeBranchModeImpl(
1213
1314
  };
1214
1315
  }
1215
1316
 
1216
- const mergeResult = deps.mergeMilestoneToMain(
1317
+ const mergeResult = deps.mergeMilestone(
1217
1318
  worktreeBasePath,
1218
1319
  milestoneId,
1219
1320
  roadmapResolution.content,
@@ -1444,18 +1545,41 @@ export class WorktreeLifecycle {
1444
1545
  * With `opts.merge === false`, runs auto-commit and teardown without
1445
1546
  * merging to main.
1446
1547
  *
1548
+ * When `opts.guardedMerge` is present with `opts.merge === true`, the
1549
+ * lifecycle verb also owns the root-clean guard around the merge: preflight
1550
+ * runs before the inner merge, postflight stash restore runs after every
1551
+ * attempted merge path, and guard failures are returned as typed
1552
+ * `ExitResult` reasons.
1553
+ *
1447
1554
  * Returns a typed `ExitResult`. `MergeConflictError` is surfaced as
1448
1555
  * `{ ok: false, reason: "merge-conflict", cause }` instead of thrown,
1449
- * giving callers a typed branch for the expected failure path.
1450
- * Unexpected failures (filesystem, git permissions, etc.) are wrapped
1451
- * as `{ ok: false, reason: "teardown-failed", cause }` so callers always
1556
+ * giving callers a typed branch for the expected failure path. Guarded merge
1557
+ * failures surface as `preflight-dirty-overlap`,
1558
+ * `preflight-unmerged-conflicts`, `merge-failed`, or
1559
+ * `postflight-stash-restore-failed`. Unexpected failures (filesystem, git
1560
+ * permissions, etc.) are wrapped as
1561
+ * `{ ok: false, reason: "teardown-failed", cause }` so callers always
1452
1562
  * receive a discriminated union — no exceptions for any expected outcome.
1453
1563
  */
1454
1564
  exitMilestone(
1455
1565
  milestoneId: string,
1456
- opts: { merge: boolean; preserveBranch?: boolean; preserveWorktree?: boolean },
1566
+ opts: {
1567
+ merge: boolean;
1568
+ preserveBranch?: boolean;
1569
+ preserveWorktree?: boolean;
1570
+ guardedMerge?: GuardedMilestoneMergeOptions;
1571
+ },
1457
1572
  ctx: NotifyCtx,
1458
1573
  ): ExitResult {
1574
+ if (opts.merge && opts.guardedMerge) {
1575
+ return runGuardedMilestoneMerge({
1576
+ merge: () => this.exitMilestone(milestoneId, { merge: true }, ctx),
1577
+ guard: opts.guardedMerge,
1578
+ milestoneId,
1579
+ notify: ctx.notify,
1580
+ });
1581
+ }
1582
+
1459
1583
  if (opts.merge) {
1460
1584
  try {
1461
1585
  const merged = this._mergeAndExit(milestoneId, ctx);
@@ -19,7 +19,7 @@
19
19
  * 4. remove() — git worktree remove + branch cleanup
20
20
  */
21
21
 
22
- import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, realpathSync, rmSync, statSync, unlinkSync } from "node:fs";
22
+ import { cpSync, existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
23
23
  import { execFileSync } from "node:child_process";
24
24
  import { join, resolve, sep } from "node:path";
25
25
  import { GSDError, GSD_PARSE_ERROR, GSD_STALE_STATE, GSD_LOCK_HELD, GSD_GIT_ERROR, GSD_MERGE_CONFLICT } from "./errors.js";
@@ -227,6 +227,113 @@ function isRegisteredGitWorktreeAtPath(basePath: string, wtPath: string): boolea
227
227
  }
228
228
  }
229
229
 
230
+ function inspectUncommittedWorktreeState(wtPath: string): { dirty: boolean; status: string } {
231
+ try {
232
+ const status = execFileSync(
233
+ "git",
234
+ ["status", "--porcelain=v1", "--untracked-files=all"],
235
+ { cwd: wtPath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
236
+ ).trimEnd();
237
+ return { dirty: status.length > 0, status };
238
+ } catch (err) {
239
+ const message = err instanceof Error ? err.message : String(err);
240
+ logWarning(
241
+ "worktree",
242
+ `dirty worktree inspection failed for ${wtPath}: ${message}`,
243
+ );
244
+ // Fail closed: unknown state must quarantine rather than force-remove.
245
+ return { dirty: true, status: `git status failed: ${message}` };
246
+ }
247
+ }
248
+
249
+ function timestampForPath(): string {
250
+ return new Date().toISOString().replace(/[:.]/g, "-");
251
+ }
252
+
253
+ function uniqueQuarantinePath(basePath: string, name: string): string {
254
+ const root = join(basePath, ".gsd", "quarantine", "worktrees");
255
+ const baseName = `${name}-${timestampForPath()}`;
256
+ let candidate = join(root, baseName);
257
+ let suffix = 2;
258
+ while (existsSync(candidate)) {
259
+ candidate = join(root, `${baseName}-${suffix}`);
260
+ suffix++;
261
+ }
262
+ return candidate;
263
+ }
264
+
265
+ function quarantineDirtyWorktree(
266
+ basePath: string,
267
+ name: string,
268
+ branch: string,
269
+ wtPath: string,
270
+ status: string,
271
+ ): string | null {
272
+ const quarantinePath = uniqueQuarantinePath(basePath, name);
273
+ mkdirSync(join(basePath, ".gsd", "quarantine", "worktrees"), { recursive: true });
274
+
275
+ let moved = false;
276
+ try {
277
+ renameSync(wtPath, quarantinePath);
278
+ moved = true;
279
+ } catch (renameErr) {
280
+ logWarning(
281
+ "worktree",
282
+ `dirty worktree rename quarantine failed for ${name}: ${renameErr instanceof Error ? renameErr.message : String(renameErr)}; trying copy snapshot`,
283
+ );
284
+ try {
285
+ cpSync(wtPath, quarantinePath, { recursive: true, force: false, errorOnExist: true });
286
+ } catch (copyErr) {
287
+ logWarning(
288
+ "reconcile",
289
+ `Dirty worktree quarantine failed; preserving original worktree ${wtPath}: ${copyErr instanceof Error ? copyErr.message : String(copyErr)}`,
290
+ { worktree: name, path: wtPath },
291
+ );
292
+ return null;
293
+ }
294
+ }
295
+
296
+ try {
297
+ const gitFile = join(quarantinePath, ".git");
298
+ if (existsSync(gitFile) && lstatSync(gitFile).isFile()) {
299
+ unlinkSync(gitFile);
300
+ }
301
+ } catch (err) {
302
+ logWarning(
303
+ "worktree",
304
+ `failed to remove quarantined worktree git pointer: ${err instanceof Error ? err.message : String(err)}`,
305
+ );
306
+ }
307
+
308
+ try {
309
+ writeFileSync(
310
+ join(quarantinePath, ".gsd-quarantine.json"),
311
+ JSON.stringify({
312
+ kind: "dirty-worktree",
313
+ worktree: name,
314
+ branch,
315
+ originalPath: wtPath,
316
+ moved,
317
+ quarantinedAt: new Date().toISOString(),
318
+ status,
319
+ }, null, 2) + "\n",
320
+ "utf-8",
321
+ );
322
+ } catch (err) {
323
+ logWarning(
324
+ "worktree",
325
+ `failed to write worktree quarantine metadata: ${err instanceof Error ? err.message : String(err)}`,
326
+ );
327
+ }
328
+
329
+ logWarning(
330
+ "reconcile",
331
+ `Quarantined dirty worktree ${name} at ${quarantinePath} before removal. Branch ${branch} was preserved.`,
332
+ { worktree: name, path: quarantinePath, branch },
333
+ );
334
+ return quarantinePath;
335
+ }
336
+
230
337
  /** True when `wtPath` has a git worktree checkout marker (`.git` file with gitdir pointer). */
231
338
  export function isLiveGitWorktreeCheckout(wtPath: string): boolean {
232
339
  const gitPath = join(wtPath, ".git");
@@ -730,12 +837,13 @@ export function removeWorktree(
730
837
  basePath: string,
731
838
  name: string,
732
839
  opts: { deleteBranch?: boolean; force?: boolean; branch?: string } = {},
733
- ): void {
840
+ ): boolean {
734
841
  basePath = normalizeBasePathForWorktreeOps(basePath);
735
842
 
736
843
  let wtPath = worktreePath(basePath, name);
737
844
  const branch = opts.branch ?? worktreeBranchName(name);
738
845
  const { deleteBranch = true, force = true } = opts;
846
+ let deleteBranchAfterRemoval = deleteBranch;
739
847
 
740
848
  // Resolve the ACTUAL worktree path from git's worktree list.
741
849
  // The computed path may differ when .gsd/ is (or was) a symlink to an
@@ -788,10 +896,10 @@ export function removeWorktree(
788
896
 
789
897
  if (!existsSync(wtPath)) {
790
898
  nativeWorktreePrune(basePath);
791
- if (deleteBranch) {
899
+ if (deleteBranchAfterRemoval) {
792
900
  deleteBranchIfPresent(basePath, branch, "nativeBranchDelete failed");
793
901
  }
794
- return;
902
+ return true;
795
903
  }
796
904
 
797
905
  // Submodule safety (#2337): detect submodules with uncommitted changes
@@ -873,6 +981,35 @@ export function removeWorktree(
873
981
  }
874
982
  }
875
983
 
984
+ // Dirty-worktree quarantine (#2365): once submodule (#2337) and nested-.git
985
+ // (#2616) rescue have run — they commit/clean the tree first — quarantine any
986
+ // uncommitted state that remains instead of force-deleting it. Gate on a live
987
+ // git checkout so a stale local directory left behind by state-sync (which
988
+ // has no `.git` file and is not a registered worktree) is removed normally
989
+ // rather than quarantined; otherwise its branch would never be deleted and
990
+ // the worktree would never be unregistered (#1852).
991
+ if (force && resolvedPathSafe && isLiveGitWorktreeCheckout(resolvedWtPath)) {
992
+ const dirtyState = inspectUncommittedWorktreeState(resolvedWtPath);
993
+ if (dirtyState.dirty) {
994
+ const quarantinePath = quarantineDirtyWorktree(
995
+ basePath,
996
+ name,
997
+ branch,
998
+ resolvedWtPath,
999
+ dirtyState.status,
1000
+ );
1001
+ if (!quarantinePath) {
1002
+ return false;
1003
+ }
1004
+
1005
+ deleteBranchAfterRemoval = false;
1006
+ if (!existsSync(resolvedWtPath)) {
1007
+ nativeWorktreePrune(basePath);
1008
+ return true;
1009
+ }
1010
+ }
1011
+ }
1012
+
876
1013
  // Remove worktree — only use force/rmSync when the path is safely contained
877
1014
  if (resolvedPathSafe) {
878
1015
  // Remove worktree: try non-force first when submodules have changes,
@@ -923,9 +1060,10 @@ export function removeWorktree(
923
1060
  // Prune stale entries so git knows the worktree is gone
924
1061
  nativeWorktreePrune(basePath);
925
1062
 
926
- if (deleteBranch) {
1063
+ if (deleteBranchAfterRemoval) {
927
1064
  deleteBranchIfPresent(basePath, branch, "final branch delete failed");
928
1065
  }
1066
+ return true;
929
1067
  }
930
1068
 
931
1069
  /**