@opengsd/gsd-pi 1.4.0-dev.c18009cd → 1.5.0-dev.553dc518

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 (274) hide show
  1. package/README.md +10 -10
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/gsd/auto/closeout.js +97 -5
  4. package/dist/resources/extensions/gsd/auto/orchestrator.js +4 -3
  5. package/dist/resources/extensions/gsd/auto/pre-dispatch.js +6 -3
  6. package/dist/resources/extensions/gsd/auto/unit-phase.js +5 -9
  7. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +4 -5
  8. package/dist/resources/extensions/gsd/auto-start.js +3 -2
  9. package/dist/resources/extensions/gsd/auto-worktree-branch-lifecycle.js +189 -0
  10. package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +133 -0
  11. package/dist/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.js +35 -0
  12. package/dist/resources/extensions/gsd/auto-worktree-creation.js +130 -0
  13. package/dist/resources/extensions/gsd/auto-worktree-entry.js +118 -0
  14. package/dist/resources/extensions/gsd/auto-worktree-merge-already-merged.js +98 -0
  15. package/dist/resources/extensions/gsd/auto-worktree-merge-branch-head.js +52 -0
  16. package/dist/resources/extensions/gsd/auto-worktree-merge-cleanup.js +87 -0
  17. package/dist/resources/extensions/gsd/auto-worktree-merge-code-changes.js +46 -0
  18. package/dist/resources/extensions/gsd/auto-worktree-merge-db-ready.js +68 -0
  19. package/dist/resources/extensions/gsd/auto-worktree-merge-integration-branch.js +51 -0
  20. package/dist/resources/extensions/gsd/auto-worktree-merge-message.js +106 -0
  21. package/dist/resources/extensions/gsd/auto-worktree-merge-pre-teardown.js +64 -0
  22. package/dist/resources/extensions/gsd/auto-worktree-merge-stash.js +168 -0
  23. package/dist/resources/extensions/gsd/auto-worktree-merge.js +302 -0
  24. package/dist/resources/extensions/gsd/auto-worktree-milestone-shelter.js +119 -0
  25. package/dist/resources/extensions/gsd/auto-worktree-path-resolution.js +5 -0
  26. package/dist/resources/extensions/gsd/auto-worktree-path-utils.js +5 -0
  27. package/dist/resources/extensions/gsd/auto-worktree-resource-version.js +41 -0
  28. package/dist/resources/extensions/gsd/auto-worktree-runtime-cleanup.js +99 -0
  29. package/dist/resources/extensions/gsd/auto-worktree-session-registry.js +57 -0
  30. package/dist/resources/extensions/gsd/auto-worktree-sync.js +249 -0
  31. package/dist/resources/extensions/gsd/auto-worktree-teardown.js +120 -0
  32. package/dist/resources/extensions/gsd/auto-worktree.js +20 -2073
  33. package/dist/resources/extensions/gsd/auto.js +9 -3
  34. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +1 -1
  35. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +19 -1
  36. package/dist/resources/extensions/gsd/bootstrap/system-context.js +1 -1
  37. package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +118 -21
  38. package/dist/resources/extensions/gsd/commands-handlers.js +1 -1
  39. package/dist/resources/extensions/gsd/commands-workflow-templates.js +3 -3
  40. package/dist/resources/extensions/gsd/db/queries.js +9 -9
  41. package/dist/resources/extensions/gsd/doctor-engine-checks.js +93 -11
  42. package/dist/resources/extensions/gsd/flat-phase-migration.js +14 -3
  43. package/dist/resources/extensions/gsd/forensics.js +1 -1
  44. package/dist/resources/extensions/gsd/git-conflict-resolve.js +2 -2
  45. package/dist/resources/extensions/gsd/git-service.js +45 -0
  46. package/dist/resources/extensions/gsd/gsd-db.js +11 -0
  47. package/dist/resources/extensions/gsd/guided-flow.js +6 -10
  48. package/dist/resources/extensions/gsd/markdown-renderer.js +15 -3
  49. package/dist/resources/extensions/gsd/milestone-merge-transaction.js +11 -0
  50. package/dist/resources/extensions/gsd/milestone-settlement.js +1 -1
  51. package/dist/resources/extensions/gsd/parallel-merge.js +1 -1
  52. package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -1
  53. package/dist/resources/extensions/gsd/preferences-types.js +1 -0
  54. package/dist/resources/extensions/gsd/preferences-validation.js +82 -0
  55. package/dist/resources/extensions/gsd/prompts/system.md +6 -6
  56. package/dist/resources/extensions/gsd/quick.js +12 -3
  57. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +2 -1
  58. package/dist/resources/extensions/gsd/state/derive/from-db.js +88 -153
  59. package/dist/resources/extensions/gsd/tool-contract.js +14 -0
  60. package/dist/resources/extensions/gsd/unit-registry.js +12 -2
  61. package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +1 -1
  62. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -1
  63. package/dist/resources/extensions/gsd/workspace-git-preflight.js +2 -2
  64. package/dist/resources/extensions/gsd/worktree-command.js +1 -1
  65. package/dist/resources/extensions/gsd/worktree-lifecycle.js +14 -9
  66. package/dist/resources/extensions/gsd/worktree-reentry.js +2 -1
  67. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  68. package/dist/web/standalone/.next/BUILD_ID +1 -1
  69. package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
  70. package/dist/web/standalone/.next/build-manifest.json +2 -2
  71. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  72. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  73. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  81. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/index.html +1 -1
  89. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app-paths-manifest.json +8 -8
  96. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  97. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  98. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  99. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  100. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  101. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  102. package/integrations/hermes/open_gsd_hermes/gsd_client.py +24 -35
  103. package/integrations/hermes/tests/test_gsd_client_timeout.py +4 -4
  104. package/package.json +6 -6
  105. package/packages/cloud-mcp-gateway/package.json +2 -2
  106. package/packages/contracts/package.json +1 -1
  107. package/packages/daemon/package.json +4 -4
  108. package/packages/gsd-agent-core/dist/export-html/template.js +53 -4
  109. package/packages/gsd-agent-core/package.json +5 -5
  110. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  111. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +3 -2
  112. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  113. package/packages/gsd-agent-modes/package.json +7 -7
  114. package/packages/mcp-server/package.json +4 -4
  115. package/packages/native/package.json +1 -1
  116. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  117. package/packages/pi-agent-core/dist/agent-loop.js +14 -9
  118. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  119. package/packages/pi-agent-core/package.json +1 -1
  120. package/packages/pi-ai/dist/index.d.ts +1 -0
  121. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  122. package/packages/pi-ai/dist/index.js +1 -0
  123. package/packages/pi-ai/dist/index.js.map +1 -1
  124. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  125. package/packages/pi-ai/dist/providers/transform-messages.js +7 -3
  126. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  127. package/packages/pi-ai/dist/tool-result-content.d.ts +3 -0
  128. package/packages/pi-ai/dist/tool-result-content.d.ts.map +1 -0
  129. package/packages/pi-ai/dist/tool-result-content.js +62 -0
  130. package/packages/pi-ai/dist/tool-result-content.js.map +1 -0
  131. package/packages/pi-ai/dist/types.d.ts +8 -20
  132. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  133. package/packages/pi-ai/dist/types.js.map +1 -1
  134. package/packages/pi-ai/package.json +1 -1
  135. package/packages/pi-coding-agent/package.json +7 -7
  136. package/packages/pi-tui/package.json +2 -2
  137. package/packages/rpc-client/package.json +2 -2
  138. package/pkg/dist/core/export-html/template.js +53 -4
  139. package/pkg/package.json +1 -1
  140. package/src/resources/extensions/gsd/auto/closeout.ts +114 -7
  141. package/src/resources/extensions/gsd/auto/orchestrator.ts +4 -3
  142. package/src/resources/extensions/gsd/auto/pre-dispatch.ts +6 -3
  143. package/src/resources/extensions/gsd/auto/unit-phase.ts +5 -9
  144. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +4 -5
  145. package/src/resources/extensions/gsd/auto-start.ts +4 -2
  146. package/src/resources/extensions/gsd/auto-worktree-branch-lifecycle.ts +237 -0
  147. package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +166 -0
  148. package/src/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.ts +37 -0
  149. package/src/resources/extensions/gsd/auto-worktree-creation.ts +171 -0
  150. package/src/resources/extensions/gsd/auto-worktree-entry.ts +154 -0
  151. package/src/resources/extensions/gsd/auto-worktree-merge-already-merged.ts +161 -0
  152. package/src/resources/extensions/gsd/auto-worktree-merge-branch-head.ts +83 -0
  153. package/src/resources/extensions/gsd/auto-worktree-merge-cleanup.ts +132 -0
  154. package/src/resources/extensions/gsd/auto-worktree-merge-code-changes.ts +71 -0
  155. package/src/resources/extensions/gsd/auto-worktree-merge-db-ready.ts +112 -0
  156. package/src/resources/extensions/gsd/auto-worktree-merge-integration-branch.ts +99 -0
  157. package/src/resources/extensions/gsd/auto-worktree-merge-message.ts +166 -0
  158. package/src/resources/extensions/gsd/auto-worktree-merge-pre-teardown.ts +93 -0
  159. package/src/resources/extensions/gsd/auto-worktree-merge-stash.ts +213 -0
  160. package/src/resources/extensions/gsd/auto-worktree-merge.ts +391 -0
  161. package/src/resources/extensions/gsd/auto-worktree-milestone-shelter.ts +159 -0
  162. package/src/resources/extensions/gsd/auto-worktree-path-resolution.ts +6 -0
  163. package/src/resources/extensions/gsd/auto-worktree-path-utils.ts +10 -0
  164. package/src/resources/extensions/gsd/auto-worktree-resource-version.ts +44 -0
  165. package/src/resources/extensions/gsd/auto-worktree-runtime-cleanup.ts +119 -0
  166. package/src/resources/extensions/gsd/auto-worktree-session-registry.ts +71 -0
  167. package/src/resources/extensions/gsd/auto-worktree-sync.ts +370 -0
  168. package/src/resources/extensions/gsd/auto-worktree-teardown.ts +161 -0
  169. package/src/resources/extensions/gsd/auto-worktree.ts +69 -2429
  170. package/src/resources/extensions/gsd/auto.ts +11 -17
  171. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +1 -1
  172. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +19 -1
  173. package/src/resources/extensions/gsd/bootstrap/system-context.ts +1 -1
  174. package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +152 -21
  175. package/src/resources/extensions/gsd/commands-handlers.ts +1 -1
  176. package/src/resources/extensions/gsd/commands-workflow-templates.ts +3 -3
  177. package/src/resources/extensions/gsd/db/queries.ts +9 -9
  178. package/src/resources/extensions/gsd/doctor-engine-checks.ts +109 -10
  179. package/src/resources/extensions/gsd/flat-phase-migration.ts +14 -3
  180. package/src/resources/extensions/gsd/forensics.ts +1 -1
  181. package/src/resources/extensions/gsd/git-conflict-resolve.ts +2 -2
  182. package/src/resources/extensions/gsd/git-service.ts +53 -0
  183. package/src/resources/extensions/gsd/gsd-db.ts +13 -0
  184. package/src/resources/extensions/gsd/guided-flow.ts +7 -11
  185. package/src/resources/extensions/gsd/markdown-renderer.ts +15 -3
  186. package/src/resources/extensions/gsd/milestone-merge-transaction.ts +15 -0
  187. package/src/resources/extensions/gsd/milestone-settlement.ts +1 -1
  188. package/src/resources/extensions/gsd/parallel-merge.ts +1 -1
  189. package/src/resources/extensions/gsd/parallel-orchestrator.ts +3 -1
  190. package/src/resources/extensions/gsd/preferences-types.ts +30 -0
  191. package/src/resources/extensions/gsd/preferences-validation.ts +69 -0
  192. package/src/resources/extensions/gsd/prompts/system.md +6 -6
  193. package/src/resources/extensions/gsd/quick.ts +11 -3
  194. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +3 -1
  195. package/src/resources/extensions/gsd/state/derive/from-db.ts +201 -157
  196. package/src/resources/extensions/gsd/tests/auto-loop-no-copy-artifacts.test.ts +2 -1
  197. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +1 -1
  198. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +2 -1
  199. package/src/resources/extensions/gsd/tests/auto-worktree-auto-resolve.test.ts +1 -1
  200. package/src/resources/extensions/gsd/tests/auto-worktree-merge-already-merged.test.ts +177 -0
  201. package/src/resources/extensions/gsd/tests/auto-worktree-merge-branch-head.test.ts +118 -0
  202. package/src/resources/extensions/gsd/tests/auto-worktree-merge-cleanup.test.ts +115 -0
  203. package/src/resources/extensions/gsd/tests/auto-worktree-merge-code-changes.test.ts +76 -0
  204. package/src/resources/extensions/gsd/tests/auto-worktree-merge-db-ready.test.ts +140 -0
  205. package/src/resources/extensions/gsd/tests/auto-worktree-merge-integration-branch.test.ts +123 -0
  206. package/src/resources/extensions/gsd/tests/auto-worktree-merge-message.test.ts +114 -0
  207. package/src/resources/extensions/gsd/tests/auto-worktree-merge-pre-teardown.test.ts +84 -0
  208. package/src/resources/extensions/gsd/tests/auto-worktree-merge-stash.test.ts +70 -0
  209. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-shelter.test.ts +52 -0
  210. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +6 -6
  211. package/src/resources/extensions/gsd/tests/auto-worktree-resource-version.test.ts +59 -0
  212. package/src/resources/extensions/gsd/tests/auto-worktree-untracked-content.test.ts +3 -1
  213. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +1 -1
  214. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -0
  215. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +174 -0
  216. package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +1 -1
  217. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +44 -1
  218. package/src/resources/extensions/gsd/tests/flat-phase-renderer.test.ts +25 -1
  219. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +40 -0
  220. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +4 -6
  221. package/src/resources/extensions/gsd/tests/integration/auto-stash-merge.test.ts +2 -1
  222. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +3 -3
  223. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +7 -8
  224. package/src/resources/extensions/gsd/tests/integration/feature-branch-lifecycle-integration.test.ts +2 -5
  225. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +76 -0
  226. package/src/resources/extensions/gsd/tests/integration/merge-cwd-restore.test.ts +1 -1
  227. package/src/resources/extensions/gsd/tests/integration/merge-preserve-worktree-on-preteardown-error.test.ts +1 -1
  228. package/src/resources/extensions/gsd/tests/integration/merge-strategy-regular.test.ts +2 -1
  229. package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +5 -7
  230. package/src/resources/extensions/gsd/tests/integration/workspace-collapse-integration.test.ts +2 -4
  231. package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +1 -1
  232. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +1 -1
  233. package/src/resources/extensions/gsd/tests/merge-self-branch-guard.test.ts +1 -1
  234. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +439 -0
  235. package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +24 -0
  236. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +1 -1
  237. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +3 -3
  238. package/src/resources/extensions/gsd/tests/parallel-worker-lock-contention.test.ts +1 -1
  239. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +1 -4
  240. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +5 -0
  241. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +20 -0
  242. package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +3 -5
  243. package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +2 -1
  244. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +2 -1
  245. package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +1 -1
  246. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +1 -1
  247. package/src/resources/extensions/gsd/tests/system-flat-phase-layout.test.ts +33 -0
  248. package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +4 -4
  249. package/src/resources/extensions/gsd/tests/teardown-cleanup-parity.test.ts +2 -1
  250. package/src/resources/extensions/gsd/tests/teardown-failure-clears-registry.test.ts +4 -4
  251. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +103 -0
  252. package/src/resources/extensions/gsd/tests/uat-stuck-loop-orphaned-worktree.test.ts +1 -1
  253. package/src/resources/extensions/gsd/tests/unit-registry.test.ts +26 -1
  254. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +1 -1
  255. package/src/resources/extensions/gsd/tests/worktree-db-respawn-truncation.test.ts +1 -1
  256. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +1 -3
  257. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +1 -1
  258. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +1 -1
  259. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +1 -1
  260. package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +1 -1
  261. package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +2 -1
  262. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +5 -2
  263. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +1 -1
  264. package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +1 -1
  265. package/src/resources/extensions/gsd/tool-contract.ts +29 -0
  266. package/src/resources/extensions/gsd/unit-registry.ts +16 -2
  267. package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +1 -1
  268. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -1
  269. package/src/resources/extensions/gsd/workspace-git-preflight.ts +2 -2
  270. package/src/resources/extensions/gsd/worktree-command.ts +1 -1
  271. package/src/resources/extensions/gsd/worktree-lifecycle.ts +19 -15
  272. package/src/resources/extensions/gsd/worktree-reentry.ts +2 -1
  273. /package/dist/web/standalone/.next/static/{L2UMqXELiDH3oz-7yguXp → ZpFDazP-38PXBPiI_LdZf}/_buildManifest.js +0 -0
  274. /package/dist/web/standalone/.next/static/{L2UMqXELiDH3oz-7yguXp → ZpFDazP-38PXBPiI_LdZf}/_ssgManifest.js +0 -0
@@ -6,7 +6,7 @@ import { cpSync, existsSync, mkdirSync, readdirSync, renameSync, rmSync, statSyn
6
6
  import { join } from "node:path";
7
7
 
8
8
  import { renderAllFromDb, renderRoadmapFromDb } from "./markdown-renderer.js";
9
- import { getAllMilestones, getMilestoneSlices } from "./gsd-db.js";
9
+ import { deleteArtifactsByPathPrefix, getAllMilestones, getMilestoneSlices } from "./gsd-db.js";
10
10
  import { migrateFromMarkdown } from "./md-importer.js";
11
11
  import { countDbHierarchy } from "./migration-auto-check.js";
12
12
  import { logWarning } from "./workflow-logger.js";
@@ -195,7 +195,8 @@ export function pruneStaleFlatPhaseBackups(basePath: string): number {
195
195
  * 2. Rename .gsd/milestones/ aside so path resolvers target phases/
196
196
  * 3. Render flat-phase from the DB (which already has the data)
197
197
  * 4. Verify counts match
198
- * 5. Remove the renamed legacy tree
198
+ * 5. Prune legacy milestones/ artifact rows
199
+ * 6. Remove the renamed legacy tree
199
200
  *
200
201
  * Idempotent: if .gsd/milestones/ doesn't exist, returns immediately.
201
202
  */
@@ -313,7 +314,17 @@ export async function migrateToFlatPhase(basePath: string): Promise<void> {
313
314
  throw new Error("flat-phase migration verification failed: no artifacts rendered");
314
315
  }
315
316
 
316
- // 6. Verified — remove the renamed legacy tree (backup already on disk).
317
+ // 6. Verified — prune legacy artifact rows now that renderAllFromDb has
318
+ // re-inserted flat-phase rows for artifacts that still have files.
319
+ try {
320
+ deleteArtifactsByPathPrefix("milestones/");
321
+ } catch (err) {
322
+ logWarning("migration", `flat-phase migration could not prune legacy artifact rows: ${(err as Error).message}`);
323
+ rollbackPartialMigration(basePath, backupDir, migratingPath);
324
+ throw err;
325
+ }
326
+
327
+ // 7. Remove the renamed legacy tree (backup already on disk).
317
328
  try {
318
329
  removePathWithRetries(migratingPath);
319
330
  } catch (err) {
@@ -30,7 +30,7 @@ import { loadPrompt } from "./prompt-loader.js";
30
30
  import { gsdRoot } from "./paths.js";
31
31
  import { isDbAvailable, getHierarchyCompletionCounts } from "./gsd-db.js";
32
32
  import { formatDuration } from "../shared/format-utils.js";
33
- import { getAutoWorktreePath } from "./auto-worktree.js";
33
+ import { getAutoWorktreePath } from "./auto-worktree-path-resolution.js";
34
34
  import { clearGSDPreferencesCache, loadEffectiveGSDPreferences, loadGlobalGSDPreferences, getGlobalGSDPreferencesPath } from "./preferences.js";
35
35
  import { showNextAction } from "../shared/tui.js";
36
36
  import {
@@ -7,9 +7,9 @@ import {
7
7
  nativeCheckoutTheirs,
8
8
  nativeRmForce,
9
9
  } from "./native-git-bridge.js";
10
- import { isSafeToAutoResolve } from "./auto-worktree.js";
10
+ import { isSafeToAutoResolve } from "./auto-worktree-conflict-auto-resolve.js";
11
11
 
12
- export { isSafeToAutoResolve } from "./auto-worktree.js";
12
+ export { isSafeToAutoResolve } from "./auto-worktree-conflict-auto-resolve.js";
13
13
 
14
14
  export interface AutoResolveSafePathsResult {
15
15
  resolved: string[];
@@ -704,6 +704,59 @@ export function runGit(basePath: string, args: string[], options: { allowFailure
704
704
  }
705
705
  }
706
706
 
707
+ /**
708
+ * Arguments for creating a task/workflow branch.
709
+ *
710
+ * When the current branch is a leftover GSD task branch (workflow template,
711
+ * quick task, or slice), the new branch starts from `baseBranch` — the
712
+ * caller's resolved integration branch, normally `GitServiceImpl.getMainBranch()`
713
+ * so `main_branch` preference, milestone integration branch, and worktree base
714
+ * all take priority over repo-default detection. Branching from HEAD there
715
+ * silently stacks consecutive workflow branches on top of each other, so every
716
+ * new gsd/* branch (and its eventual PR) drags along the previous workflow's
717
+ * commits.
718
+ *
719
+ * On any other branch (a user's feature branch, a worktree base, the main
720
+ * branch itself) the legacy branch-from-HEAD behavior is kept: basing new work
721
+ * on the branch the user chose to stand on is intentional there.
722
+ *
723
+ * Falls back to branch-from-HEAD, with a logged warning, when the base branch
724
+ * has no local ref or the working tree is still dirty (a start point that
725
+ * changes the tree would abort the checkout or strand in-flight changes).
726
+ * The base is the local ref — deliberately no fetch, so branch creation stays
727
+ * offline-safe even if the local base is behind its remote.
728
+ */
729
+ export function taskBranchArgs(basePath: string, branchName: string, currentBranch: string, baseBranch: string): string[] {
730
+ const args = ["checkout", "-b", branchName];
731
+ const onTaskBranch =
732
+ WORKFLOW_BRANCH_RE.test(currentBranch) ||
733
+ QUICK_BRANCH_RE.test(currentBranch) ||
734
+ SLICE_BRANCH_RE.test(currentBranch);
735
+ if (!onTaskBranch || !baseBranch || baseBranch === currentBranch) return args;
736
+ try {
737
+ if (!nativeBranchExists(basePath, baseBranch)) {
738
+ logWarning(
739
+ "engine",
740
+ `taskBranchArgs: base branch "${baseBranch}" has no local ref — branching ${branchName} from HEAD (${currentBranch})`,
741
+ { file: "git-service.ts" },
742
+ );
743
+ return args;
744
+ }
745
+ if (nativeHasChanges(basePath)) {
746
+ logWarning(
747
+ "engine",
748
+ `taskBranchArgs: working tree still dirty after auto-commit — branching ${branchName} from HEAD (${currentBranch}) to preserve in-flight changes`,
749
+ { file: "git-service.ts" },
750
+ );
751
+ return args;
752
+ }
753
+ } catch {
754
+ return args;
755
+ }
756
+ args.push(baseBranch);
757
+ return args;
758
+ }
759
+
707
760
  // ─── Commit Type Inference ─────────────────────────────────────────────────
708
761
 
709
762
  /**
@@ -1397,6 +1397,19 @@ export function deleteArtifactByPath(path: string): void {
1397
1397
  getDbOrNull()!.prepare("DELETE FROM artifacts WHERE path = :path").run({ ":path": path });
1398
1398
  }
1399
1399
 
1400
+ /** Delete artifact rows whose paths share a DB-relative prefix. */
1401
+ export function deleteArtifactsByPathPrefix(prefix: string): number {
1402
+ if (!getDbOrNull()!) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
1403
+ return transaction(() => {
1404
+ const likePrefix = `${prefix}%`;
1405
+ const countRow = getDbOrNull()!.prepare(
1406
+ "SELECT COUNT(*) AS count FROM artifacts WHERE path LIKE :prefix",
1407
+ ).get({ ":prefix": likePrefix });
1408
+ getDbOrNull()!.prepare("DELETE FROM artifacts WHERE path LIKE :prefix").run({ ":prefix": likePrefix });
1409
+ return Number(countRow?.["count"] ?? 0);
1410
+ });
1411
+ }
1412
+
1400
1413
  /**
1401
1414
  * Drop hierarchy rows in dependency order inside a transaction. Used by
1402
1415
  * `gsd recover --confirm` to rebuild engine state from markdown.
@@ -51,7 +51,7 @@ import { nativeAddAll, nativeCommit, nativeHasCommittedHead, nativeIsRepo, nativ
51
51
  import { isInheritedRepo } from "./repo-identity.js";
52
52
  import { ensureGitignore, ensurePreferences, untrackRuntimeFiles } from "./gitignore.js";
53
53
  import { getIsolationMode, loadEffectiveGSDPreferences } from "./preferences.js";
54
- import { getAutoWorktreePath } from "./auto-worktree.js";
54
+ import { getAutoWorktreePath } from "./auto-worktree-path-resolution.js";
55
55
  import { resolveUokFlags } from "./uok/flags.js";
56
56
  import { ensurePlanV2Graph, isMissingFinalizedContextResult } from "./uok/plan-v2.js";
57
57
  import { detectProjectState, hasGsdBootstrapArtifacts } from "./detection.js";
@@ -94,7 +94,7 @@ import {
94
94
  import { probeCoversRequiredWorkflowTools } from "./tool-surface-readiness.js";
95
95
  import { getRequiredWorkflowToolsForUnit } from "./unit-tool-contracts.js";
96
96
  import { isWorkflowToolSurfaceName } from "./workflow-tool-surface.js";
97
- import { getUnitWorkflowDispatchReadinessError } from "./tool-contract.js";
97
+ import { getUnitWorkflowDispatchReadinessErrorForModel } from "./tool-contract.js";
98
98
  import {
99
99
  runPreparation,
100
100
  formatCodebaseBrief,
@@ -613,7 +613,7 @@ interface DispatchWorkflowOptions {
613
613
  deps?: {
614
614
  loadPreferences?: typeof loadEffectiveGSDPreferences;
615
615
  selectModel?: typeof selectAndApplyModel;
616
- getDispatchReadinessError?: typeof getUnitWorkflowDispatchReadinessError;
616
+ getDispatchReadinessError?: typeof getUnitWorkflowDispatchReadinessErrorForModel;
617
617
  };
618
618
  }
619
619
 
@@ -730,7 +730,7 @@ async function dispatchWorkflow(
730
730
  const loadPreferences = resolvedOptions.deps?.loadPreferences ?? loadEffectiveGSDPreferences;
731
731
  const selectModel = resolvedOptions.deps?.selectModel ?? selectAndApplyModel;
732
732
  const getDispatchReadinessError = resolvedOptions.deps?.getDispatchReadinessError
733
- ?? getUnitWorkflowDispatchReadinessError;
733
+ ?? getUnitWorkflowDispatchReadinessErrorForModel;
734
734
 
735
735
  // Route through the dynamic routing pipeline (complexity classification,
736
736
  // tier downgrade, fallback chains) — same path as auto-mode dispatches (#2958).
@@ -750,16 +750,12 @@ async function dispatchWorkflow(
750
750
  }
751
751
 
752
752
  const compatibilityError = getDispatchReadinessError({
753
- provider: result.appliedModel?.provider ?? ctx.model?.provider,
753
+ model: result.appliedModel,
754
+ fallbackModel: ctx.model,
755
+ getProviderAuthMode: (provider) => ctx.modelRegistry.getProviderAuthMode(provider),
754
756
  projectRoot,
755
757
  surface: "guided flow",
756
758
  unitType,
757
- authMode: result.appliedModel?.provider
758
- ? ctx.modelRegistry.getProviderAuthMode(result.appliedModel.provider)
759
- : ctx.model?.provider
760
- ? ctx.modelRegistry.getProviderAuthMode(ctx.model.provider)
761
- : undefined,
762
- baseUrl: result.appliedModel?.baseUrl ?? ctx.model?.baseUrl,
763
759
  // Guided flow starts the MCP workflow server as part of dispatch, so the
764
760
  // parent session's activeTools doesn't include MCP tools yet. The MCP
765
761
  // launch config check (detectWorkflowMcpLaunchConfig) is the right gate
@@ -1299,9 +1299,21 @@ export async function renderAssessmentFromDb(
1299
1299
  sliceId: string,
1300
1300
  assessmentData: AssessmentData,
1301
1301
  ): Promise<{ assessmentPath: string; content: string }> {
1302
- // Flat-phase: assessment file lives in the phase dir
1303
- const slicePath = resolveSlicePath(basePath, milestoneId, sliceId)
1304
- ?? join(milestonesDir(basePath), canonicalPhaseDirName(milestoneId, getMilestone(milestoneId)?.title));
1302
+ // Flat-phase: the assessment file lives in the phase dir, NOT in a slices/SID/
1303
+ // subdir. resolveSlicePath() detects a slices/SID/ dir unconditionally, so a
1304
+ // stray slices/SID/ created by an earlier planning step would send this write
1305
+ // to a hybrid path (wrong dir, flat filename) that verification cannot find.
1306
+ // Guard with the same legacy-base check relSlicePath() uses so flat-phase
1307
+ // milestones always target the phase dir.
1308
+ const mDir = resolveMilestonePath(basePath, milestoneId);
1309
+ const legacyBase = legacyMilestonesDir(basePath);
1310
+ const isLegacyLayout = mDir
1311
+ ? mDir.startsWith(legacyBase + "/") || mDir.startsWith(legacyBase + "\\")
1312
+ : false;
1313
+ const fallbackDir = join(milestonesDir(basePath), canonicalPhaseDirName(milestoneId, getMilestone(milestoneId)?.title));
1314
+ const slicePath = isLegacyLayout
1315
+ ? (resolveSlicePath(basePath, milestoneId, sliceId) ?? fallbackDir)
1316
+ : (mDir ?? fallbackDir);
1305
1317
  const phaseNum = milestoneIdToPhaseNum(milestoneId);
1306
1318
  const planNum = sliceIdToPlanNum(sliceId);
1307
1319
  const absPath = join(slicePath, planFileName(phaseNum, planNum, "ASSESSMENT"));
@@ -1,6 +1,8 @@
1
1
  // Project/App: gsd-pi
2
2
  // File Purpose: Process-level transaction wrapper for milestone merge closeout.
3
3
 
4
+ import { mergeMilestoneToMain } from "./auto-worktree-merge.js";
5
+
4
6
  export interface MilestoneMergeTransactionResult {
5
7
  pushed: boolean;
6
8
  codeFilesChanged: boolean;
@@ -45,3 +47,16 @@ export function createMilestoneMergeTransaction(
45
47
  );
46
48
  };
47
49
  }
50
+
51
+ /**
52
+ * Production merge transaction adapter.
53
+ *
54
+ * This is the only production construction point that knows the legacy
55
+ * `auto-worktree.ts` merge primitive. Lifecycle callers depend on the
56
+ * transaction runner interface, not the legacy implementation module.
57
+ */
58
+ export function createDefaultMilestoneMergeTransaction(
59
+ mergeMilestone: MilestoneMergeTransactionRunner = mergeMilestoneToMain,
60
+ ): MilestoneMergeTransactionRunner {
61
+ return createMilestoneMergeTransaction(mergeMilestone);
62
+ }
@@ -1,7 +1,7 @@
1
1
  // Project/App: gsd-pi
2
2
  // File Purpose: Milestone closeout settlement state across DB proof, artifacts, merge, and cleanup.
3
3
 
4
- import { isInAutoWorktree } from "./auto-worktree.js";
4
+ import { isInAutoWorktree } from "./auto-worktree-entry.js";
5
5
  import {
6
6
  formatCloseoutProofBlock,
7
7
  proveMilestoneCloseout,
@@ -10,7 +10,7 @@ import { join } from "node:path";
10
10
  import { spawnSync } from "node:child_process";
11
11
  import { resolveGsdPathContract } from "./paths.js";
12
12
  import { worktreePathFor, worktreesDirs } from "./worktree-placement.js";
13
- import { getAutoWorktreePath } from "./auto-worktree.js";
13
+ import { getAutoWorktreePath } from "./auto-worktree-path-resolution.js";
14
14
  import { buildWorktreeLifecycleDeps } from "./auto.js";
15
15
  import {
16
16
  mergeMilestoneStandalone,
@@ -21,7 +21,9 @@ import { join, dirname } from "node:path";
21
21
  import { fileURLToPath } from "node:url";
22
22
  import { gsdRoot } from "./paths.js";
23
23
  import { createWorktree, worktreePath } from "./worktree-manager.js";
24
- import { autoWorktreeBranch, fastForwardReusedMilestoneBranchIfSafe, runWorktreePostCreateHook, syncGsdStateToWorktreeByScope } from "./auto-worktree.js";
24
+ import { autoWorktreeBranch, fastForwardReusedMilestoneBranchIfSafe } from "./auto-worktree-branch-lifecycle.js";
25
+ import { syncGsdStateToWorktreeByScope } from "./auto-worktree-sync.js";
26
+ import { runWorktreePostCreateHook } from "./worktree-post-create-hook.js";
25
27
  import { nativeBranchExists } from "./native-git-bridge.js";
26
28
  import { readIntegrationBranch } from "./git-service.js";
27
29
  import { createWorkspace, scopeMilestone } from "./workspace.js";
@@ -29,6 +29,33 @@ export interface ContextManagementConfig {
29
29
  tool_result_max_chars?: number; // default: 800, range: 200-10000
30
30
  }
31
31
 
32
+ /**
33
+ * User-tunable thresholds for the tool-call loop guard (#1198). Keeps the two
34
+ * guards separately configurable: the identical-args guard (catches real
35
+ * infinite loops) and the repeated-tool-name cap (catches improvisation loops,
36
+ * more likely to false-positive on legitimate automation). All fields are
37
+ * optional; omitted fields fall back to the built-in defaults so existing
38
+ * installs keep their current behavior. Also overridable via GSD_TOOL_LOOP_*
39
+ * environment variables.
40
+ */
41
+ export interface ToolCallLoopGuardConfig {
42
+ /** Master switch for both guards. Default: true. */
43
+ enabled?: boolean;
44
+ /** Identical-args sliding-window guard. */
45
+ identical_args?: {
46
+ enabled?: boolean; // default: true
47
+ max_consecutive_calls?: number; // default: 4, min: 1
48
+ };
49
+ /** Per-tool-name cap, independent of args. */
50
+ repeated_tool?: {
51
+ enabled?: boolean; // default: true
52
+ default_cap?: number; // default: 6, min: 1
53
+ repeatable_cap?: number; // default: 15, min: 1
54
+ /** Additional tool names exempt from the per-tool cap (merged with built-in defaults). */
55
+ exempt_tools?: string[];
56
+ };
57
+ }
58
+
32
59
  /**
33
60
  * Opt-in tool-output sandboxing for sub-sessions. When enabled, the gsd_exec
34
61
  * MCP tool runs scripts in an isolated subprocess and returns only a short
@@ -139,6 +166,7 @@ export const KNOWN_PREFERENCE_KEYS = new Set<string>([
139
166
  "min_request_interval_ms",
140
167
  "stale_commit_threshold_minutes",
141
168
  "context_management",
169
+ "tool_call_loop_guard",
142
170
  "experimental",
143
171
  "codebase",
144
172
  "slice_parallel",
@@ -440,6 +468,8 @@ export interface GSDPreferences {
440
468
  */
441
469
  context_window_override?: number;
442
470
  context_management?: ContextManagementConfig;
471
+ /** User-tunable tool-call loop guard thresholds (#1198). */
472
+ tool_call_loop_guard?: ToolCallLoopGuardConfig;
443
473
  /**
444
474
  * Tool-output sandboxing via gsd_exec. Keeps sub-session context windows
445
475
  * clean by running scripts in a subprocess and only surfacing a short
@@ -794,6 +794,75 @@ export function validatePreferences(preferences: GSDPreferences): {
794
794
  }
795
795
  }
796
796
 
797
+ // ─── Tool-call loop guard (#1198) ────────────────────────────────────────
798
+ if (preferences.tool_call_loop_guard !== undefined) {
799
+ if (typeof preferences.tool_call_loop_guard === "object" && preferences.tool_call_loop_guard !== null) {
800
+ const g = preferences.tool_call_loop_guard as unknown as Record<string, unknown>;
801
+ const validGuard: Record<string, unknown> = {};
802
+
803
+ if (g.enabled !== undefined) {
804
+ if (typeof g.enabled === "boolean") validGuard.enabled = g.enabled;
805
+ else errors.push("tool_call_loop_guard.enabled must be a boolean");
806
+ }
807
+
808
+ if (g.identical_args !== undefined) {
809
+ if (typeof g.identical_args === "object" && g.identical_args !== null) {
810
+ const ia = g.identical_args as Record<string, unknown>;
811
+ const validIa: Record<string, unknown> = {};
812
+ if (ia.enabled !== undefined) {
813
+ if (typeof ia.enabled === "boolean") validIa.enabled = ia.enabled;
814
+ else errors.push("tool_call_loop_guard.identical_args.enabled must be a boolean");
815
+ }
816
+ if (ia.max_consecutive_calls !== undefined) {
817
+ const n = ia.max_consecutive_calls;
818
+ if (typeof n === "number" && Number.isInteger(n) && n >= 1) validIa.max_consecutive_calls = n;
819
+ else errors.push("tool_call_loop_guard.identical_args.max_consecutive_calls must be an integer >= 1");
820
+ }
821
+ if (Object.keys(validIa).length > 0) validGuard.identical_args = validIa;
822
+ } else {
823
+ errors.push("tool_call_loop_guard.identical_args must be an object");
824
+ }
825
+ }
826
+
827
+ if (g.repeated_tool !== undefined) {
828
+ if (typeof g.repeated_tool === "object" && g.repeated_tool !== null) {
829
+ const rt = g.repeated_tool as Record<string, unknown>;
830
+ const validRt: Record<string, unknown> = {};
831
+ if (rt.enabled !== undefined) {
832
+ if (typeof rt.enabled === "boolean") validRt.enabled = rt.enabled;
833
+ else errors.push("tool_call_loop_guard.repeated_tool.enabled must be a boolean");
834
+ }
835
+ if (rt.default_cap !== undefined) {
836
+ const n = rt.default_cap;
837
+ if (typeof n === "number" && Number.isInteger(n) && n >= 1) validRt.default_cap = n;
838
+ else errors.push("tool_call_loop_guard.repeated_tool.default_cap must be an integer >= 1");
839
+ }
840
+ if (rt.repeatable_cap !== undefined) {
841
+ const n = rt.repeatable_cap;
842
+ if (typeof n === "number" && Number.isInteger(n) && n >= 1) validRt.repeatable_cap = n;
843
+ else errors.push("tool_call_loop_guard.repeated_tool.repeatable_cap must be an integer >= 1");
844
+ }
845
+ if (rt.exempt_tools !== undefined) {
846
+ if (Array.isArray(rt.exempt_tools) && rt.exempt_tools.every((t) => typeof t === "string")) {
847
+ validRt.exempt_tools = rt.exempt_tools;
848
+ } else {
849
+ errors.push("tool_call_loop_guard.repeated_tool.exempt_tools must be an array of strings");
850
+ }
851
+ }
852
+ if (Object.keys(validRt).length > 0) validGuard.repeated_tool = validRt;
853
+ } else {
854
+ errors.push("tool_call_loop_guard.repeated_tool must be an object");
855
+ }
856
+ }
857
+
858
+ if (Object.keys(validGuard).length > 0) {
859
+ validated.tool_call_loop_guard = validGuard as any;
860
+ }
861
+ } else {
862
+ errors.push("tool_call_loop_guard must be an object");
863
+ }
864
+ }
865
+
797
866
  // ─── Context Mode (gsd_exec sandbox) ────────────────────────────────────
798
867
  if (preferences.context_mode !== undefined) {
799
868
  if (typeof preferences.context_mode === "object" && preferences.context_mode !== null) {
@@ -38,7 +38,7 @@ If a `GSD Skill Preferences` block appears below, treat it as durable guidance f
38
38
 
39
39
  ### Naming Convention
40
40
 
41
- Directories use bare IDs. Files use ID-SUFFIX format. Milestones: `M001/` or `M{seq}-{rand6}/` when `unique_milestone_ids: true`; files like `M001-CONTEXT.md`, `M001-ROADMAP.md`, `M001-RESEARCH.md`. Slices: `S01/` with `S01-PLAN.md`, `S01-RESEARCH.md`, `S01-SUMMARY.md`, `S01-UAT.md`. Tasks: `T01-PLAN.md`, `T01-SUMMARY.md`. Titles live inside content, not names.
41
+ GSD projects use a flat-phase layout. Phase directories are `{MM}-{slug}` where `{MM}` is the zero-padded phase number and `{slug}` is derived from the phase title (e.g. `47-real-time-runtime-hardening`). Phase-level files are `{MM}-SUFFIX.md` (e.g. `47-CONTEXT.md`, `47-RESEARCH.md`, `47-ROADMAP.md`, `47-VALIDATION.md`, `47-SUMMARY.md`). Slice/plan files live directly in the phase directory as `{MM}-{SS}-SUFFIX.md` (e.g. `47-01-PLAN.md`, `47-01-SUMMARY.md`, `47-01-UAT.md`). Task plan content lives inside the slice plan file (`{MM}-{SS}-PLAN.md`) as checkboxes; there is no `tasks/` subdirectory and no `tasks/T##-PLAN.md`. Titles live inside content, not names. Prefer GSD-provided layout-aware paths/resolvers over hardcoding artifact paths, since phase slugs are title-derived.
42
42
 
43
43
  ### Directory Structure
44
44
 
@@ -46,13 +46,13 @@ Directories use bare IDs. Files use ID-SUFFIX format. Milestones: `M001/` or `M{
46
46
  .gsd/
47
47
  PROJECT.md, REQUIREMENTS.md, DECISIONS.md, KNOWLEDGE.md, CODEBASE.md, OVERRIDES.md, QUEUE.md, STATE.md
48
48
  runtime/, activity/, worktrees/
49
- milestones/M001/
50
- M001-CONTEXT.md, M001-RESEARCH.md, M001-ROADMAP.md, M001-SUMMARY.md
51
- slices/S01/
52
- S01-CONTEXT.md, S01-RESEARCH.md, S01-PLAN.md, S01-SUMMARY.md, S01-UAT.md
53
- tasks/T01-PLAN.md, tasks/T01-SUMMARY.md
49
+ phases/{MM}-{slug}/
50
+ {MM}-CONTEXT.md, {MM}-RESEARCH.md, {MM}-ROADMAP.md, {MM}-VALIDATION.md, {MM}-SUMMARY.md
51
+ {MM}-{SS}-PLAN.md, {MM}-{SS}-SUMMARY.md, {MM}-{SS}-UAT.md
54
52
  ```
55
53
 
54
+ Task plan content is embedded in `{MM}-{SS}-PLAN.md`; do not expect `tasks/T##-PLAN.md`.
55
+
56
56
  `runtime/`, `activity/`, `worktrees/`, and `STATE.md` are system-managed. `PROJECT.md` is current state; `REQUIREMENTS.md` is the active capability contract; `DECISIONS.md` and `KNOWLEDGE.md` are append-only; `CODEBASE.md` is an auto-refreshed codebase map.
57
57
 
58
58
  ### Isolation Model
@@ -15,7 +15,7 @@ import { isAbsolute, join, relative, resolve } from "node:path";
15
15
  import { QUICK_BRANCH_RE } from "./branch-patterns.js";
16
16
  import { loadPrompt } from "./prompt-loader.js";
17
17
  import { gsdRoot } from "./paths.js";
18
- import { GitServiceImpl, runGit } from "./git-service.js";
18
+ import { GitServiceImpl, runGit, taskBranchArgs } from "./git-service.js";
19
19
  import { loadEffectiveGSDPreferences } from "./preferences.js";
20
20
  import { nativeBranchExists, nativeDetectMainBranch, nativeDiffNumstat } from "./native-git-bridge.js";
21
21
  import { nativeHasStagedChanges } from "./native-git-bridge.js";
@@ -365,6 +365,7 @@ export async function handleQuick(
365
365
  const git = new GitServiceImpl(basePath, gitPrefs);
366
366
  const branchName = `gsd/quick/${taskNum}-${slug}`;
367
367
  let originalBranch = git.getCurrentBranch();
368
+ let returnBranch = originalBranch;
368
369
 
369
370
  const { getIsolationMode } = await import("./preferences.js");
370
371
  const usesBranch = getIsolationMode() !== "none" && isGitOpsEnabled();
@@ -381,7 +382,14 @@ export async function handleQuick(
381
382
  }
382
383
  } catch { /* nothing to commit — fine */ }
383
384
 
384
- runGit(basePath, ["checkout", "-b", branchName]);
385
+ const branchArgs = taskBranchArgs(basePath, branchName, current, git.getMainBranch());
386
+ const startPoint = branchArgs[3];
387
+ // When the quick branch is redirected off a stale task branch, the
388
+ // squash-merge on closeout must return to the same base — merging a
389
+ // base-branch-rooted quick branch back into the stale task branch
390
+ // would drag the base's newer history into it.
391
+ if (startPoint) returnBranch = startPoint;
392
+ runGit(basePath, branchArgs);
385
393
  branchCreated = true;
386
394
  }
387
395
  } catch (err) {
@@ -395,7 +403,7 @@ export async function handleQuick(
395
403
  if (actualBranch === branchName && originalBranch !== branchName) {
396
404
  persistPendingReturn({
397
405
  basePath,
398
- originalBranch,
406
+ originalBranch: returnBranch,
399
407
  quickBranch: branchName,
400
408
  taskNum,
401
409
  slug,
@@ -30,7 +30,9 @@ import { isAbsolute, join, dirname, resolve } from "node:path";
30
30
  import { fileURLToPath } from "node:url";
31
31
  import { gsdRoot } from "./paths.js";
32
32
  import { createWorktree, worktreePath, removeWorktree } from "./worktree-manager.js";
33
- import { autoWorktreeBranch, runWorktreePostCreateHook, syncGsdStateToWorktreeByScope } from "./auto-worktree.js";
33
+ import { autoWorktreeBranch } from "./auto-worktree-branch-lifecycle.js";
34
+ import { syncGsdStateToWorktreeByScope } from "./auto-worktree-sync.js";
35
+ import { runWorktreePostCreateHook } from "./worktree-post-create-hook.js";
34
36
  import { createWorkspace, scopeMilestone } from "./workspace.js";
35
37
  import {
36
38
  writeSessionStatus,