@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
@@ -428,6 +428,52 @@ test("checkEngineHealth repair prunes stale phases artifact rows with present mi
428
428
  assert.deepEqual(rows.map((row) => row.path), []);
429
429
  });
430
430
 
431
+ test("checkEngineHealth repair keeps phases rows whose own file is still present", async (t) => {
432
+ const base = mkdtempSync(join(tmpdir(), "gsd-doctor-keep-present-phase-artifact-"));
433
+ t.after(() => rmSync(base, { recursive: true, force: true }));
434
+
435
+ const gsdDir = join(base, ".gsd");
436
+ const livePath = "phases/01-m001/01-01-PLAN.md";
437
+ const replacementPath = "milestones/M001/slices/S01/S01-PLAN.md";
438
+ // Both the active phases/ file AND a legacy milestones/ copy exist on disk.
439
+ // The row is "fixable" (a milestones replacement is present), but its own
440
+ // file is present too — repair must not drop the live row.
441
+ mkdirSync(join(gsdDir, "phases", "01-m001"), { recursive: true });
442
+ writeFileSync(join(gsdDir, livePath), "# Plan\n", "utf-8");
443
+ mkdirSync(join(gsdDir, "milestones", "M001", "slices", "S01"), { recursive: true });
444
+ writeFileSync(join(gsdDir, replacementPath), "# Plan\n", "utf-8");
445
+
446
+ openDatabase(join(gsdDir, "gsd.db"));
447
+ insertArtifact({
448
+ path: livePath,
449
+ artifact_type: "PLAN",
450
+ milestone_id: "M001",
451
+ slice_id: "S01",
452
+ task_id: null,
453
+ full_content: "# plan\n",
454
+ });
455
+
456
+ const issues: any[] = [];
457
+ const fixes: string[] = [];
458
+ await checkEngineHealth(base, issues, fixes, { repair: true });
459
+
460
+ assert.equal(
461
+ fixes.some((fix) => fix.includes(livePath)),
462
+ false,
463
+ "repair must not prune a row whose own file is present on disk",
464
+ );
465
+ assert.equal(
466
+ issues.some((issue) => issue.code === "artifact_file_missing" && issue.file === livePath),
467
+ false,
468
+ "a present artifact must not be reported missing",
469
+ );
470
+
471
+ const rows = _getAdapter()!
472
+ .prepare("SELECT path FROM artifacts ORDER BY path")
473
+ .all() as Array<{ path: string }>;
474
+ assert.deepEqual(rows.map((row) => row.path), [livePath]);
475
+ });
476
+
431
477
  test("checkEngineHealth repair prunes stale phases task rows against tasks/<T>-<TYPE>.md replacements", async (t) => {
432
478
  const base = mkdtempSync(join(tmpdir(), "gsd-doctor-prune-stale-task-phase-artifact-"));
433
479
  t.after(() => rmSync(base, { recursive: true, force: true }));
@@ -540,6 +586,134 @@ test("checkEngineHealth marks escaped phases rows fixable when a milestones repl
540
586
  assert.equal(issue.fixable, true, "escaped phases rows with a milestones replacement must be marked fixable");
541
587
  });
542
588
 
589
+ test("checkEngineHealth resolves legacy milestones rows through flat-phase files", async (t) => {
590
+ const base = mkdtempSync(join(tmpdir(), "gsd-doctor-flat-fallback-"));
591
+ t.after(() => rmSync(base, { recursive: true, force: true }));
592
+
593
+ const gsdDir = join(base, ".gsd");
594
+ const flatPath = "phases/01-foundation/01-01-PLAN.md";
595
+ const legacyPath = "milestones/M001/slices/S01/S01-PLAN.md";
596
+ mkdirSync(join(gsdDir, "phases", "01-foundation"), { recursive: true });
597
+ writeFileSync(join(gsdDir, flatPath), "# Plan\n", "utf-8");
598
+
599
+ openDatabase(join(gsdDir, "gsd.db"));
600
+ insertArtifact({
601
+ path: legacyPath,
602
+ artifact_type: "PLAN",
603
+ milestone_id: "M001",
604
+ slice_id: "S01",
605
+ task_id: null,
606
+ full_content: "# legacy plan row\n",
607
+ });
608
+
609
+ const issues: any[] = [];
610
+ await checkEngineHealth(base, issues, []);
611
+
612
+ assert.equal(
613
+ issues.some((issue) => issue.code === "artifact_file_missing" && issue.file === legacyPath),
614
+ false,
615
+ "legacy milestones rows should not be reported missing when the flat-phase file exists",
616
+ );
617
+ });
618
+
619
+ test("checkEngineHealth repair prunes stale milestones rows with present flat-phase files", async (t) => {
620
+ const base = mkdtempSync(join(tmpdir(), "gsd-doctor-prune-stale-legacy-artifact-"));
621
+ t.after(() => rmSync(base, { recursive: true, force: true }));
622
+
623
+ const gsdDir = join(base, ".gsd");
624
+ const flatPath = "phases/01-foundation/01-01-PLAN.md";
625
+ const stalePath = "milestones/M001/slices/S01/S01-PLAN.md";
626
+ mkdirSync(join(gsdDir, "phases", "01-foundation"), { recursive: true });
627
+ writeFileSync(join(gsdDir, flatPath), "# Plan\n", "utf-8");
628
+
629
+ openDatabase(join(gsdDir, "gsd.db"));
630
+ insertArtifact({
631
+ path: stalePath,
632
+ artifact_type: "PLAN",
633
+ milestone_id: "M001",
634
+ slice_id: "S01",
635
+ task_id: null,
636
+ full_content: "# stale plan row\n",
637
+ });
638
+
639
+ const issues: any[] = [];
640
+ const fixes: string[] = [];
641
+ await checkEngineHealth(base, issues, fixes, { repair: true });
642
+
643
+ assert.equal(
644
+ issues.some((issue) => issue.code === "artifact_file_missing" && issue.file === stalePath),
645
+ false,
646
+ "repair should not report stale legacy rows it pruned",
647
+ );
648
+ assert.ok(fixes.includes(`pruned stale legacy artifact row ${stalePath}`));
649
+
650
+ const rows = _getAdapter()!
651
+ .prepare("SELECT path FROM artifacts ORDER BY path")
652
+ .all() as Array<{ path: string }>;
653
+ assert.deepEqual(rows.map((row) => row.path), []);
654
+ });
655
+
656
+ test("checkEngineHealth marks stale milestones task rows without flat files fixable", async (t) => {
657
+ const base = mkdtempSync(join(tmpdir(), "gsd-doctor-fixable-stale-legacy-task-artifact-"));
658
+ t.after(() => rmSync(base, { recursive: true, force: true }));
659
+
660
+ const gsdDir = join(base, ".gsd");
661
+ const stalePath = "milestones/M001/slices/S01/tasks/T01-PLAN.md";
662
+ mkdirSync(join(gsdDir, "phases", "01-foundation"), { recursive: true });
663
+
664
+ openDatabase(join(gsdDir, "gsd.db"));
665
+ insertArtifact({
666
+ path: stalePath,
667
+ artifact_type: "PLAN",
668
+ milestone_id: "M001",
669
+ slice_id: "S01",
670
+ task_id: "T01",
671
+ full_content: "# stale task plan row\n",
672
+ });
673
+
674
+ const issues: any[] = [];
675
+ await checkEngineHealth(base, issues, []);
676
+
677
+ const issue = issues.find((candidate) => candidate.code === "artifact_file_missing" && candidate.file === stalePath);
678
+ assert.ok(issue, "missing stale legacy task row should still be reported when repair is off");
679
+ assert.equal(issue.fixable, true, "stale legacy task rows without flat files should be fixable");
680
+ });
681
+
682
+ test("checkEngineHealth repair prunes stale milestones task rows without flat files", async (t) => {
683
+ const base = mkdtempSync(join(tmpdir(), "gsd-doctor-prune-stale-legacy-task-artifact-"));
684
+ t.after(() => rmSync(base, { recursive: true, force: true }));
685
+
686
+ const gsdDir = join(base, ".gsd");
687
+ const stalePath = "milestones/M001/slices/S01/tasks/T01-PLAN.md";
688
+ mkdirSync(join(gsdDir, "phases", "01-foundation"), { recursive: true });
689
+
690
+ openDatabase(join(gsdDir, "gsd.db"));
691
+ insertArtifact({
692
+ path: stalePath,
693
+ artifact_type: "PLAN",
694
+ milestone_id: "M001",
695
+ slice_id: "S01",
696
+ task_id: "T01",
697
+ full_content: "# stale task plan row\n",
698
+ });
699
+
700
+ const issues: any[] = [];
701
+ const fixes: string[] = [];
702
+ await checkEngineHealth(base, issues, fixes, { repair: true });
703
+
704
+ assert.equal(
705
+ issues.some((issue) => issue.code === "artifact_file_missing" && issue.file === stalePath),
706
+ false,
707
+ "repair should prune stale legacy task rows that have no flat file representation",
708
+ );
709
+ assert.ok(fixes.includes(`pruned stale legacy artifact row ${stalePath}`));
710
+
711
+ const rows = _getAdapter()!
712
+ .prepare("SELECT path FROM artifacts ORDER BY path")
713
+ .all() as Array<{ path: string }>;
714
+ assert.deepEqual(rows.map((row) => row.path), []);
715
+ });
716
+
543
717
  function taskSummary(id: string, verificationResult = "passed"): string {
544
718
  return [
545
719
  "---",
@@ -13,7 +13,7 @@ import { basename, join } from "node:path";
13
13
  import {
14
14
  fastForwardReusedMilestoneBranchIfSafe,
15
15
  _isBranchCheckedOutElsewhere,
16
- } from "../auto-worktree.js";
16
+ } from "../auto-worktree-branch-lifecycle.js";
17
17
 
18
18
  const NO_PROMPT_ENV = {
19
19
  ...process.env,
@@ -13,7 +13,7 @@ import {
13
13
  needsFlatPhaseMigration,
14
14
  pruneStaleFlatPhaseBackups,
15
15
  } from "../flat-phase-migration.ts";
16
- import { openDatabase, closeDatabase, insertMilestone, insertSlice, insertTask, getAllMilestones, getMilestoneSlices, getSliceTasks } from "../gsd-db.ts";
16
+ import { openDatabase, closeDatabase, insertArtifact, insertMilestone, insertSlice, insertTask, getAllMilestones, getMilestoneSlices, getSliceTasks, _getAdapter } from "../gsd-db.ts";
17
17
 
18
18
  const tmpDirs: string[] = [];
19
19
  function makeTmp(options: { withTask?: boolean } = {}): string {
@@ -120,6 +120,49 @@ test("migrateToFlatPhase preserves milestone/slice/task counts in DB", async ()
120
120
  assert.equal(getSliceTasks("M001", "S01").length, tasksBefore);
121
121
  });
122
122
 
123
+ test("migrateToFlatPhase prunes legacy milestones artifact rows after flat render", async () => {
124
+ const base = makeTmp();
125
+ insertArtifact({
126
+ path: "milestones/M001/M001-ROADMAP.md",
127
+ artifact_type: "ROADMAP",
128
+ milestone_id: "M001",
129
+ slice_id: null,
130
+ task_id: null,
131
+ full_content: "# M001: Foundation\n",
132
+ });
133
+ insertArtifact({
134
+ path: "milestones/M001/slices/S01/S01-PLAN.md",
135
+ artifact_type: "PLAN",
136
+ milestone_id: "M001",
137
+ slice_id: "S01",
138
+ task_id: null,
139
+ full_content: "# Plan\n",
140
+ });
141
+ insertArtifact({
142
+ path: "milestones/M001/slices/S01/tasks/T01-PLAN.md",
143
+ artifact_type: "PLAN",
144
+ milestone_id: "M001",
145
+ slice_id: "S01",
146
+ task_id: "T01",
147
+ full_content: "# Task Plan\n",
148
+ });
149
+
150
+ await migrateToFlatPhase(base);
151
+
152
+ const rows = _getAdapter()!
153
+ .prepare("SELECT path FROM artifacts ORDER BY path")
154
+ .all() as Array<{ path: string }>;
155
+ assert.equal(
156
+ rows.some((row) => row.path.startsWith("milestones/")),
157
+ false,
158
+ "legacy milestones/ artifact rows should be pruned after successful flat migration",
159
+ );
160
+ assert.ok(
161
+ rows.some((row) => row.path.startsWith("phases/")),
162
+ "flat-phase render should leave replacement projection rows in the artifacts table",
163
+ );
164
+ });
165
+
123
166
  test("migrateToFlatPhase is idempotent (second run is a no-op)", async () => {
124
167
  const base = makeTmp();
125
168
  await migrateToFlatPhase(base);
@@ -7,7 +7,8 @@ import { join } from "node:path";
7
7
  import { tmpdir } from "node:os";
8
8
  import { randomUUID } from "node:crypto";
9
9
 
10
- import { renderPlanFromDb, renderRoadmapFromDb } from "../markdown-renderer.ts";
10
+ import { renderPlanFromDb, renderRoadmapFromDb, renderAssessmentFromDb } from "../markdown-renderer.ts";
11
+ import { clearPathCache } from "../paths.ts";
11
12
  import { openDatabase, closeDatabase, insertMilestone, insertSlice, insertTask } from "../gsd-db.ts";
12
13
 
13
14
  const tmpDirs: string[] = [];
@@ -81,3 +82,26 @@ test("renderPlanFromDb does NOT write per-task plan files", async () => {
81
82
  // taskPlanPaths should be empty — no per-task files written
82
83
  assert.equal(result.taskPlanPaths.length, 0);
83
84
  });
85
+
86
+ // Regression for #1190: a stray slices/SID/ subdir inside a flat-phase milestone
87
+ // must not divert the ASSESSMENT write into slices/SID/ (a hybrid path that
88
+ // auto-mode verification cannot find). It must land at the phase root.
89
+ test("renderAssessmentFromDb writes to the phase root even when a stray slices/SID/ dir exists", async () => {
90
+ const base = makeTmp();
91
+ const plan = await renderPlanFromDb(base, "M001", "S01");
92
+ const phaseDir = plan.planPath.slice(0, plan.planPath.lastIndexOf("01-01-PLAN.md"));
93
+
94
+ // Simulate the anomaly: an earlier planning step created slices/S01/ inside
95
+ // the flat-phase dir.
96
+ mkdirSync(join(phaseDir, "slices", "S01"), { recursive: true });
97
+ clearPathCache();
98
+
99
+ const result = await renderAssessmentFromDb(base, "M001", "S01", {
100
+ verdict: "on-track",
101
+ assessment: "Roadmap is on track.",
102
+ });
103
+
104
+ assert.match(result.assessmentPath, /phases[/\\]01-[^/\\]+[/\\]01-01-ASSESSMENT\.md$/);
105
+ assert.ok(!result.assessmentPath.includes(join("slices", "S01")), "must not write under slices/S01/");
106
+ assert.ok(existsSync(result.assessmentPath), "assessment file should exist at the phase root");
107
+ });
@@ -33,6 +33,10 @@ import {
33
33
  getMilestoneSliceSummaries,
34
34
  getClosedSliceIds,
35
35
  getActiveMilestoneFromDb,
36
+ getActiveSliceFromDb,
37
+ getActiveTaskFromDb,
38
+ getActiveTaskIdFromDb,
39
+ getSliceTaskCounts,
36
40
  deleteMilestone,
37
41
  clearEngineHierarchy,
38
42
  recordMilestoneCommitAttribution,
@@ -240,6 +244,42 @@ describe('gsd-db', () => {
240
244
  closeDatabase();
241
245
  });
242
246
 
247
+ test("gsd-db: active readers use the shared closed-status vocabulary", () => {
248
+ openDatabase(":memory:");
249
+
250
+ try {
251
+ insertMilestone({ id: "M001", title: "Status vocabulary", status: "active" });
252
+ insertSlice({ id: "S01", milestoneId: "M001", title: "Closed dep", status: "closed", sequence: 1 });
253
+ insertSlice({ id: "S02", milestoneId: "M001", title: "Runnable", status: "pending", depends: ["S01"], sequence: 2 });
254
+ insertTask({ id: "T01", sliceId: "S02", milestoneId: "M001", title: "Skipped", status: "skipped", sequence: 1 });
255
+ insertTask({ id: "T02", sliceId: "S02", milestoneId: "M001", title: "Closed", status: "closed", sequence: 2 });
256
+ insertTask({ id: "T03", sliceId: "S02", milestoneId: "M001", title: "Pending", status: "pending", sequence: 3 });
257
+
258
+ assert.equal(
259
+ getActiveSliceFromDb("M001")?.id,
260
+ "S02",
261
+ "closed dependency slices must satisfy dependencies and be excluded from active slice selection",
262
+ );
263
+ assert.equal(
264
+ getActiveTaskFromDb("M001", "S02")?.id,
265
+ "T03",
266
+ "skipped/closed tasks must be excluded from active task selection",
267
+ );
268
+ assert.equal(
269
+ getActiveTaskIdFromDb("M001", "S02")?.id,
270
+ "T03",
271
+ "lightweight active task selection must use the same closed-status vocabulary",
272
+ );
273
+ assert.deepEqual(
274
+ getSliceTaskCounts("M001", "S02"),
275
+ { total: 3, done: 2, pending: 1 },
276
+ "slice task counts must derive done/pending from the shared closed-status vocabulary",
277
+ );
278
+ } finally {
279
+ closeDatabase();
280
+ }
281
+ });
282
+
243
283
  test('gsd-db: active_decisions view excludes superseded', () => {
244
284
  openDatabase(':memory:');
245
285
 
@@ -25,12 +25,10 @@ import { join } from "node:path";
25
25
  import { tmpdir } from "node:os";
26
26
  import { execSync } from "node:child_process";
27
27
 
28
- import {
29
- createAutoWorktree,
30
- isInAutoWorktree,
31
- getAutoWorktreeOriginalBase,
32
- mergeMilestoneToMain,
33
- } from "../../auto-worktree.ts";
28
+ import { createAutoWorktree } from "../../auto-worktree-creation.ts";
29
+ import { isInAutoWorktree } from "../../auto-worktree-entry.ts";
30
+ import { mergeMilestoneToMain } from "../../auto-worktree-merge.ts";
31
+ import { getAutoWorktreeOriginalBase } from "../../auto-worktree-session-registry.ts";
34
32
 
35
33
  function run(command: string, cwd: string): string {
36
34
  return execSync(command, {
@@ -12,7 +12,8 @@ import { join } from "node:path";
12
12
  import { tmpdir } from "node:os";
13
13
  import { execSync } from "node:child_process";
14
14
 
15
- import { createAutoWorktree, mergeMilestoneToMain } from "../../auto-worktree.ts";
15
+ import { createAutoWorktree } from "../../auto-worktree-creation.ts";
16
+ import { mergeMilestoneToMain } from "../../auto-worktree-merge.ts";
16
17
  import { nativeMergeSquash } from "../../native-git-bridge.ts";
17
18
 
18
19
  function run(cmd: string, cwd: string): string {
@@ -19,12 +19,12 @@ import { join } from "node:path";
19
19
  import { tmpdir } from "node:os";
20
20
  import { execSync } from "node:child_process";
21
21
 
22
+ import { createAutoWorktree } from "../../auto-worktree-creation.ts";
22
23
  import {
23
- createAutoWorktree,
24
24
  mergeMilestoneToMain,
25
- getAutoWorktreeOriginalBase,
26
25
  _setRestoreEntryFnForTests,
27
- } from "../../auto-worktree.ts";
26
+ } from "../../auto-worktree-merge.ts";
27
+ import { getAutoWorktreeOriginalBase } from "../../auto-worktree-session-registry.ts";
28
28
  import { getSliceBranchName } from "../../worktree.ts";
29
29
  import { nativeMergeSquash } from "../../native-git-bridge.ts";
30
30
  import { drainLogs, setStderrLoggingEnabled } from "../../workflow-logger.ts";
@@ -17,17 +17,16 @@ import {
17
17
  writeGsdMilestoneContext,
18
18
  } from "./gsd-integration-fixture.ts";
19
19
 
20
+ import { createAutoWorktree } from "../../auto-worktree-creation.ts";
21
+ import { enterAutoWorktree, isInAutoWorktree } from "../../auto-worktree-entry.ts";
22
+ import { getAutoWorktreePath } from "../../auto-worktree-path-resolution.ts";
20
23
  import {
21
- createAutoWorktree,
22
- teardownAutoWorktree,
23
- isInAutoWorktree,
24
- getAutoWorktreePath,
25
- enterAutoWorktree,
26
- getAutoWorktreeOriginalBase,
27
24
  getActiveAutoWorktreeContext,
28
- syncGsdStateToWorktree,
25
+ getAutoWorktreeOriginalBase,
29
26
  _resetAutoWorktreeOriginalBaseForTests,
30
- } from "../../auto-worktree.ts";
27
+ } from "../../auto-worktree-session-registry.ts";
28
+ import { syncGsdStateToWorktree } from "../../auto-worktree-sync.ts";
29
+ import { teardownAutoWorktree } from "../../auto-worktree-teardown.ts";
31
30
 
32
31
  // Note: execSync is used intentionally in tests for git operations with
33
32
  // controlled, hardcoded inputs (no user input). This is safe and matches
@@ -22,11 +22,8 @@ import { join } from "node:path";
22
22
  import { tmpdir } from "node:os";
23
23
  import { execSync } from "node:child_process";
24
24
 
25
- import {
26
- createAutoWorktree,
27
- mergeMilestoneToMain,
28
- autoWorktreeBranch,
29
- } from "../../auto-worktree.ts";
25
+ import { createAutoWorktree } from "../../auto-worktree-creation.ts";
26
+ import { mergeMilestoneToMain } from "../../auto-worktree-merge.ts";
30
27
  import { captureIntegrationBranch, getSliceBranchName } from "../../worktree.ts";
31
28
  import { writeIntegrationBranch, readIntegrationBranch } from "../../git-service.ts";
32
29
  import { nextMilestoneId, generateMilestoneSuffix } from "../../guided-flow.ts";
@@ -15,6 +15,7 @@ import {
15
15
  RUNTIME_EXCLUSION_PATHS,
16
16
  VALID_BRANCH_NAME,
17
17
  runGit,
18
+ taskBranchArgs,
18
19
  readIntegrationBranch,
19
20
  resolveMilestoneIntegrationBranch,
20
21
  writeIntegrationBranch,
@@ -1119,6 +1120,81 @@ process.exit(result.status ?? 0);
1119
1120
  rmSync(repo, { recursive: true, force: true });
1120
1121
  }
1121
1122
 
1123
+ // ─── taskBranchArgs ───────────────────────────────────────────────────
1124
+
1125
+ test('taskBranchArgs starts new workflow branches from the base branch, not from HEAD', () => {
1126
+ const repo = initBranchTestRepo();
1127
+
1128
+ assert.deepStrictEqual(
1129
+ taskBranchArgs(repo, "gsd/spike/first", "main", "main"),
1130
+ ["checkout", "-b", "gsd/spike/first"],
1131
+ "branching while on the base branch itself needs no explicit start point",
1132
+ );
1133
+
1134
+ // Simulate a finished workflow left checked out with its own commit.
1135
+ run("git checkout -b gsd/spike/first", repo);
1136
+ createFile(repo, "first.txt", "first workflow output");
1137
+ runGit(repo, ["add", "-A"]);
1138
+ runGit(repo, ["commit", "-m", "first workflow work"]);
1139
+ _resetHasChangesCache();
1140
+
1141
+ const args = taskBranchArgs(repo, "gsd/spike/second", "gsd/spike/first", "main");
1142
+ assert.deepStrictEqual(
1143
+ args,
1144
+ ["checkout", "-b", "gsd/spike/second", "main"],
1145
+ "next workflow branch starts from the base so workflows do not stack",
1146
+ );
1147
+
1148
+ runGit(repo, args);
1149
+ assert.deepStrictEqual(
1150
+ run("git rev-parse HEAD", repo),
1151
+ run("git rev-parse main", repo),
1152
+ "second workflow branch points at the base, without the first workflow's commit",
1153
+ );
1154
+
1155
+ rmSync(repo, { recursive: true, force: true });
1156
+ });
1157
+
1158
+ test('taskBranchArgs keeps branch-from-HEAD on user branches and unsafe states', () => {
1159
+ const repo = initBranchTestRepo();
1160
+
1161
+ // Manual feature branch: the user chose to stand here — new workflow
1162
+ // branches base on it, never silently jump to main.
1163
+ run("git checkout -b feature/login", repo);
1164
+ createFile(repo, "feature.txt", "feature work");
1165
+ runGit(repo, ["add", "-A"]);
1166
+ runGit(repo, ["commit", "-m", "feature work"]);
1167
+ _resetHasChangesCache();
1168
+ assert.deepStrictEqual(
1169
+ taskBranchArgs(repo, "gsd/spike/from-feature", "feature/login", "main"),
1170
+ ["checkout", "-b", "gsd/spike/from-feature"],
1171
+ "a manual feature branch is a deliberate base — no redirect to main",
1172
+ );
1173
+
1174
+ // Base branch without a local ref (e.g. origin/HEAD names a branch that
1175
+ // was never checked out locally): fall back to HEAD instead of failing.
1176
+ run("git checkout -b gsd/spike/stale", repo);
1177
+ _resetHasChangesCache();
1178
+ assert.deepStrictEqual(
1179
+ taskBranchArgs(repo, "gsd/spike/next", "gsd/spike/stale", "no-such-branch"),
1180
+ ["checkout", "-b", "gsd/spike/next"],
1181
+ "missing local base ref falls back to branch-from-HEAD",
1182
+ );
1183
+
1184
+ // Dirty tree on a task branch: a tree-changing start point would abort
1185
+ // the checkout or strand the changes — fall back to HEAD.
1186
+ createFile(repo, "dirty.txt", "uncommitted");
1187
+ runGit(repo, ["add", "-A"]);
1188
+ _resetHasChangesCache();
1189
+ assert.deepStrictEqual(
1190
+ taskBranchArgs(repo, "gsd/spike/next", "gsd/spike/stale", "main"),
1191
+ ["checkout", "-b", "gsd/spike/next"],
1192
+ "dirty working tree falls back to branch-from-HEAD",
1193
+ );
1194
+
1195
+ rmSync(repo, { recursive: true, force: true });
1196
+ });
1197
+
1122
1198
  // ═══════════════════════════════════════════════════════════════════════
1123
1199
  // S05: Enhanced features — snapshots, pre-merge checks
1124
1200
  // ═══════════════════════════════════════════════════════════════════════
@@ -28,7 +28,7 @@ import { join } from "node:path";
28
28
  import { tmpdir } from "node:os";
29
29
  import { execSync } from "node:child_process";
30
30
 
31
- import { mergeMilestoneToMain } from "../../auto-worktree.ts";
31
+ import { mergeMilestoneToMain } from "../../auto-worktree-merge.ts";
32
32
  import { MergeConflictError } from "../../git-service.ts";
33
33
 
34
34
  function run(cmd: string, cwd: string): string {
@@ -6,7 +6,7 @@ import { join } from "node:path";
6
6
  import { tmpdir } from "node:os";
7
7
 
8
8
  import { GSDError } from "../../errors.js";
9
- import { mergeMilestoneToMain } from "../../auto-worktree.ts";
9
+ import { mergeMilestoneToMain } from "../../auto-worktree-merge.ts";
10
10
 
11
11
  function run(cmd: string, cwd: string): string {
12
12
  return execSync(cmd, {
@@ -29,7 +29,8 @@ import { join } from "node:path";
29
29
  import { tmpdir } from "node:os";
30
30
  import { execSync } from "node:child_process";
31
31
 
32
- import { createAutoWorktree, mergeMilestoneToMain } from "../../auto-worktree.ts";
32
+ import { createAutoWorktree } from "../../auto-worktree-creation.ts";
33
+ import { mergeMilestoneToMain } from "../../auto-worktree-merge.ts";
33
34
  import { closeDatabase } from "../../gsd-db.ts";
34
35
  import { getSliceBranchName } from "../../worktree.ts";
35
36
 
@@ -16,13 +16,11 @@ import { execSync } from "node:child_process";
16
16
  import { dirname } from "node:path";
17
17
  import { fileURLToPath } from "node:url";
18
18
 
19
- import {
20
- createAutoWorktree,
21
- teardownAutoWorktree,
22
- isInAutoWorktree,
23
- getAutoWorktreeOriginalBase,
24
- mergeMilestoneToMain,
25
- } from "../../auto-worktree.ts";
19
+ import { createAutoWorktree } from "../../auto-worktree-creation.ts";
20
+ import { isInAutoWorktree } from "../../auto-worktree-entry.ts";
21
+ import { mergeMilestoneToMain } from "../../auto-worktree-merge.ts";
22
+ import { getAutoWorktreeOriginalBase } from "../../auto-worktree-session-registry.ts";
23
+ import { teardownAutoWorktree } from "../../auto-worktree-teardown.ts";
26
24
 
27
25
  const __dirname = dirname(fileURLToPath(import.meta.url));
28
26
 
@@ -25,10 +25,8 @@ import {
25
25
  markDepthVerified,
26
26
  clearDiscussionFlowState,
27
27
  } from "../../bootstrap/write-gate.ts";
28
- import {
29
- teardownAutoWorktree,
30
- _resetAutoWorktreeOriginalBaseForTests,
31
- } from "../../auto-worktree.ts";
28
+ import { _resetAutoWorktreeOriginalBaseForTests } from "../../auto-worktree-session-registry.ts";
29
+ import { teardownAutoWorktree } from "../../auto-worktree-teardown.ts";
32
30
  import {
33
31
  openDatabaseByWorkspace,
34
32
  closeAllDatabases,
@@ -8,7 +8,7 @@ import { join } from "node:path";
8
8
  import { tmpdir } from "node:os";
9
9
  import { execFileSync } from "node:child_process";
10
10
 
11
- import { mergeMilestoneToMain } from "../auto-worktree.ts";
11
+ import { mergeMilestoneToMain } from "../auto-worktree-merge.ts";
12
12
  import { checkCloseoutConsistencyGate } from "../closeout-consistency-gate.ts";
13
13
  import {
14
14
  closeDatabase,
@@ -14,7 +14,7 @@ import { tmpdir } from "node:os";
14
14
  import { delimiter, join } from "node:path";
15
15
  import { execFileSync } from "node:child_process";
16
16
 
17
- import { mergeMilestoneToMain } from "../auto-worktree.ts";
17
+ import { mergeMilestoneToMain } from "../auto-worktree-merge.ts";
18
18
  import { closeDatabase, insertAssessment, insertMilestone, insertSlice, openDatabase } from "../gsd-db.ts";
19
19
  import { GIT_NO_PROMPT_ENV } from "../git-constants.js";
20
20
  import { _clearGsdRootCache } from "../paths.ts";
@@ -19,7 +19,7 @@ import { join } from "node:path";
19
19
  import { tmpdir } from "node:os";
20
20
  import { execFileSync } from "node:child_process";
21
21
 
22
- import { mergeMilestoneToMain } from "../auto-worktree.ts";
22
+ import { mergeMilestoneToMain } from "../auto-worktree-merge.ts";
23
23
  import { _resetServiceCache } from "../worktree.ts";
24
24
  import { _clearGsdRootCache } from "../paths.ts";
25
25