gsd-pi 2.80.0-dev.2848d9009 → 2.80.0-dev.3065f7bfa

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 (377) hide show
  1. package/README.md +4 -2
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/gsd/auto/loop.js +32 -1
  4. package/dist/resources/extensions/gsd/auto/phases.js +178 -108
  5. package/dist/resources/extensions/gsd/auto/resolve.js +17 -0
  6. package/dist/resources/extensions/gsd/auto/run-unit.js +20 -30
  7. package/dist/resources/extensions/gsd/auto/session.js +8 -0
  8. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +5 -32
  9. package/dist/resources/extensions/gsd/auto-dispatch.js +16 -0
  10. package/dist/resources/extensions/gsd/auto-post-unit.js +17 -4
  11. package/dist/resources/extensions/gsd/auto-prompts.js +103 -16
  12. package/dist/resources/extensions/gsd/auto-recovery.js +43 -1
  13. package/dist/resources/extensions/gsd/auto-start.js +197 -6
  14. package/dist/resources/extensions/gsd/auto-supervisor.js +8 -1
  15. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +2 -2
  16. package/dist/resources/extensions/gsd/auto-worktree.js +111 -1
  17. package/dist/resources/extensions/gsd/auto.js +86 -26
  18. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +42 -2
  19. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +49 -36
  20. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +15 -5
  21. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +33 -20
  22. package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +7 -1
  23. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +9 -3
  24. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +8 -2
  25. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +259 -28
  26. package/dist/resources/extensions/gsd/bootstrap/system-context.js +82 -23
  27. package/dist/resources/extensions/gsd/clean-root-preflight.js +24 -6
  28. package/dist/resources/extensions/gsd/commands-handlers.js +23 -9
  29. package/dist/resources/extensions/gsd/context-budget.js +37 -2
  30. package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
  31. package/dist/resources/extensions/gsd/db/unit-dispatches.js +39 -0
  32. package/dist/resources/extensions/gsd/db-base-schema.js +4 -2
  33. package/dist/resources/extensions/gsd/db-migration-steps.js +6 -0
  34. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +2 -0
  35. package/dist/resources/extensions/gsd/git-service.js +36 -4
  36. package/dist/resources/extensions/gsd/gsd-db.js +46 -13
  37. package/dist/resources/extensions/gsd/guided-flow.js +99 -38
  38. package/dist/resources/extensions/gsd/memory-store.js +69 -12
  39. package/dist/resources/extensions/gsd/migrate/command.js +40 -1
  40. package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
  41. package/dist/resources/extensions/gsd/native-git-bridge.js +32 -8
  42. package/dist/resources/extensions/gsd/orphan-stash-audit.js +101 -0
  43. package/dist/resources/extensions/gsd/parallel-orchestrator.js +13 -3
  44. package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
  45. package/dist/resources/extensions/gsd/pre-execution-checks.js +22 -0
  46. package/dist/resources/extensions/gsd/prompt-loader.js +28 -2
  47. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +16 -13
  48. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  49. package/dist/resources/extensions/gsd/prompts/execute-task.md +4 -2
  50. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  51. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  52. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
  53. package/dist/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  54. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  55. package/dist/resources/extensions/gsd/quick.js +34 -2
  56. package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
  57. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
  58. package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
  59. package/dist/resources/extensions/gsd/tools/memory-tools.js +1 -0
  60. package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
  61. package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
  62. package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
  63. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +1 -1
  64. package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
  65. package/dist/resources/extensions/gsd/unit-runtime.js +22 -0
  66. package/dist/resources/extensions/gsd/workflow-protocol.js +131 -0
  67. package/dist/resources/extensions/gsd/worktree-resolver.js +68 -21
  68. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  69. package/dist/web/standalone/.next/BUILD_ID +1 -1
  70. package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
  71. package/dist/web/standalone/.next/build-manifest.json +2 -2
  72. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  73. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/index.html +1 -1
  90. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
  97. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  98. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  99. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  100. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  101. package/package.json +3 -3
  102. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  103. package/packages/mcp-server/dist/workflow-tools.js +22 -17
  104. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  105. package/packages/mcp-server/src/workflow-tools.test.ts +75 -2
  106. package/packages/mcp-server/src/workflow-tools.ts +30 -16
  107. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  108. package/packages/native/tsconfig.tsbuildinfo +1 -1
  109. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  110. package/packages/pi-agent-core/dist/agent-loop.js +4 -1
  111. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  112. package/packages/pi-agent-core/dist/agent.d.ts +5 -0
  113. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  114. package/packages/pi-agent-core/dist/agent.js +2 -0
  115. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  116. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  117. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  118. package/packages/pi-agent-core/dist/index.js +2 -0
  119. package/packages/pi-agent-core/dist/index.js.map +1 -1
  120. package/packages/pi-agent-core/dist/token-audit.d.ts +47 -0
  121. package/packages/pi-agent-core/dist/token-audit.d.ts.map +1 -0
  122. package/packages/pi-agent-core/dist/token-audit.js +221 -0
  123. package/packages/pi-agent-core/dist/token-audit.js.map +1 -0
  124. package/packages/pi-agent-core/dist/types.d.ts +9 -0
  125. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  126. package/packages/pi-agent-core/dist/types.js.map +1 -1
  127. package/packages/pi-agent-core/src/agent-loop.test.ts +128 -0
  128. package/packages/pi-agent-core/src/agent-loop.ts +4 -1
  129. package/packages/pi-agent-core/src/agent.ts +8 -0
  130. package/packages/pi-agent-core/src/index.ts +2 -0
  131. package/packages/pi-agent-core/src/token-audit.test.ts +189 -0
  132. package/packages/pi-agent-core/src/token-audit.ts +287 -0
  133. package/packages/pi-agent-core/src/types.ts +14 -0
  134. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  135. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +32 -0
  136. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  137. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +18 -0
  138. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  139. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +12 -0
  140. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  141. package/packages/pi-coding-agent/dist/core/agent-session.js +44 -7
  142. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  143. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +3 -1
  144. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  145. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
  146. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  147. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
  148. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  149. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
  150. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
  151. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
  152. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
  153. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
  154. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
  155. package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
  156. package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
  157. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
  158. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
  159. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
  160. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
  161. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  162. package/packages/pi-coding-agent/dist/core/extensions/loader.js +8 -0
  163. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  164. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +3 -0
  165. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  166. package/packages/pi-coding-agent/dist/core/extensions/runner.js +6 -6
  167. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  168. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +5 -3
  169. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  170. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +39 -1
  171. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  172. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  173. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +2 -0
  174. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -1
  175. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts +2 -0
  176. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts.map +1 -0
  177. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js +46 -0
  178. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js.map +1 -0
  179. package/packages/pi-coding-agent/dist/core/sdk.d.ts +10 -2
  180. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  181. package/packages/pi-coding-agent/dist/core/sdk.js +74 -2
  182. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  183. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
  184. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  185. package/packages/pi-coding-agent/dist/core/settings-manager.js +25 -0
  186. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  187. package/packages/pi-coding-agent/dist/core/skill-tool.test.js +22 -0
  188. package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -1
  189. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +6 -7
  190. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  191. package/packages/pi-coding-agent/dist/core/system-prompt.js +2 -3
  192. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  193. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  194. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  195. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +3 -0
  196. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  197. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  198. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +13 -5
  199. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  200. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +53 -0
  201. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  202. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  203. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +3 -0
  204. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  205. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
  206. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
  207. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +10 -0
  208. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
  209. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
  210. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
  211. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
  212. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +36 -0
  213. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +25 -0
  214. package/packages/pi-coding-agent/src/core/agent-session.ts +48 -7
  215. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +3 -1
  216. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
  217. package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
  218. package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
  219. package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
  220. package/packages/pi-coding-agent/src/core/extensions/loader.ts +10 -0
  221. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +5 -3
  222. package/packages/pi-coding-agent/src/core/extensions/runner.ts +8 -5
  223. package/packages/pi-coding-agent/src/core/extensions/types.ts +42 -1
  224. package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +2 -0
  225. package/packages/pi-coding-agent/src/core/sdk-tool-filter.test.ts +60 -0
  226. package/packages/pi-coding-agent/src/core/sdk.ts +85 -3
  227. package/packages/pi-coding-agent/src/core/settings-manager.ts +39 -1
  228. package/packages/pi-coding-agent/src/core/skill-tool.test.ts +28 -0
  229. package/packages/pi-coding-agent/src/core/system-prompt.ts +8 -10
  230. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +4 -0
  231. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +56 -0
  232. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +22 -7
  233. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +3 -0
  234. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +14 -0
  235. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
  236. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  237. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  238. package/packages/pi-tui/dist/tui.js +18 -8
  239. package/packages/pi-tui/dist/tui.js.map +1 -1
  240. package/packages/pi-tui/src/tui.ts +20 -8
  241. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  242. package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -2
  243. package/src/resources/extensions/gsd/auto/loop.ts +50 -8
  244. package/src/resources/extensions/gsd/auto/phases.ts +251 -172
  245. package/src/resources/extensions/gsd/auto/resolve.ts +23 -1
  246. package/src/resources/extensions/gsd/auto/run-unit.ts +25 -30
  247. package/src/resources/extensions/gsd/auto/session.ts +8 -0
  248. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +8 -34
  249. package/src/resources/extensions/gsd/auto-dispatch.ts +16 -0
  250. package/src/resources/extensions/gsd/auto-post-unit.ts +18 -4
  251. package/src/resources/extensions/gsd/auto-prompts.ts +112 -15
  252. package/src/resources/extensions/gsd/auto-recovery.ts +54 -0
  253. package/src/resources/extensions/gsd/auto-start.ts +230 -9
  254. package/src/resources/extensions/gsd/auto-supervisor.ts +7 -0
  255. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +2 -2
  256. package/src/resources/extensions/gsd/auto-worktree.ts +123 -0
  257. package/src/resources/extensions/gsd/auto.ts +98 -21
  258. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +49 -1
  259. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +50 -36
  260. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +16 -5
  261. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +34 -19
  262. package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +8 -1
  263. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +10 -3
  264. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +9 -2
  265. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +305 -28
  266. package/src/resources/extensions/gsd/bootstrap/system-context.ts +90 -22
  267. package/src/resources/extensions/gsd/clean-root-preflight.ts +32 -7
  268. package/src/resources/extensions/gsd/commands-handlers.ts +34 -15
  269. package/src/resources/extensions/gsd/context-budget.ts +44 -2
  270. package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
  271. package/src/resources/extensions/gsd/db/unit-dispatches.ts +41 -0
  272. package/src/resources/extensions/gsd/db-base-schema.ts +4 -2
  273. package/src/resources/extensions/gsd/db-migration-steps.ts +8 -0
  274. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +3 -0
  275. package/src/resources/extensions/gsd/git-service.ts +46 -8
  276. package/src/resources/extensions/gsd/gsd-db.ts +50 -13
  277. package/src/resources/extensions/gsd/guided-flow.ts +123 -45
  278. package/src/resources/extensions/gsd/memory-store.ts +77 -12
  279. package/src/resources/extensions/gsd/migrate/command.ts +47 -1
  280. package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
  281. package/src/resources/extensions/gsd/native-git-bridge.ts +39 -6
  282. package/src/resources/extensions/gsd/orphan-stash-audit.ts +117 -0
  283. package/src/resources/extensions/gsd/parallel-orchestrator.ts +13 -3
  284. package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
  285. package/src/resources/extensions/gsd/pre-execution-checks.ts +23 -0
  286. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  287. package/src/resources/extensions/gsd/prompt-loader.ts +27 -2
  288. package/src/resources/extensions/gsd/prompts/complete-milestone.md +16 -13
  289. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  290. package/src/resources/extensions/gsd/prompts/execute-task.md +4 -2
  291. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  292. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  293. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
  294. package/src/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  295. package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  296. package/src/resources/extensions/gsd/quick.ts +37 -2
  297. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +2 -2
  298. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +417 -10
  299. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +56 -13
  300. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +14 -1
  301. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +168 -6
  302. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +15 -6
  303. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +14 -1
  304. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +31 -0
  305. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +3 -2
  306. package/src/resources/extensions/gsd/tests/context-budget.test.ts +10 -1
  307. package/src/resources/extensions/gsd/tests/context-store.test.ts +7 -1
  308. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +55 -0
  309. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
  310. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +5 -1
  311. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +313 -0
  312. package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
  313. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
  314. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +5 -2
  315. package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +219 -0
  316. package/src/resources/extensions/gsd/tests/finalize-survivor-branch.test.ts +132 -0
  317. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +54 -0
  318. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +6 -3
  319. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +239 -1
  320. package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +32 -0
  321. package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -0
  322. package/src/resources/extensions/gsd/tests/memory-decay-factor.test.ts +90 -0
  323. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +1 -0
  324. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
  325. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
  326. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +242 -0
  327. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +34 -2
  328. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +3 -0
  329. package/src/resources/extensions/gsd/tests/orphan-merge-bootstrap.test.ts +133 -0
  330. package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +201 -0
  331. package/src/resources/extensions/gsd/tests/parallel-orchestrator-fast-forward.test.ts +113 -0
  332. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
  333. package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
  334. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +45 -5
  335. package/src/resources/extensions/gsd/tests/prompt-duplication-cuts.test.ts +230 -0
  336. package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
  337. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +19 -0
  338. package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +3 -3
  339. package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
  340. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +38 -17
  341. package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
  342. package/src/resources/extensions/gsd/tests/select-resumable-milestone.test.ts +96 -0
  343. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +106 -0
  344. package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
  345. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +20 -0
  346. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -1
  347. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +55 -0
  348. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -0
  349. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +9 -0
  350. package/src/resources/extensions/gsd/tests/system-context-memory.test.ts +112 -0
  351. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +7 -9
  352. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +291 -0
  353. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +136 -4
  354. package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +30 -0
  355. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +37 -0
  356. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -4
  357. package/src/resources/extensions/gsd/tests/workflow-protocol-excerpt.test.ts +99 -0
  358. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +3 -0
  359. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +1 -0
  360. package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +22 -19
  361. package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +66 -0
  362. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +167 -4
  363. package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
  364. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
  365. package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
  366. package/src/resources/extensions/gsd/tools/memory-tools.ts +1 -0
  367. package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
  368. package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
  369. package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
  370. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +1 -1
  371. package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
  372. package/src/resources/extensions/gsd/unit-runtime.ts +25 -0
  373. package/src/resources/extensions/gsd/workflow-protocol.ts +160 -0
  374. package/src/resources/extensions/gsd/worktree-resolver.ts +85 -19
  375. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +0 -97
  376. /package/dist/web/standalone/.next/static/{vaQ47E8aNlbbNEDoeME6G → O2WvnXROue6l7nAp_4dhC}/_buildManifest.js +0 -0
  377. /package/dist/web/standalone/.next/static/{vaQ47E8aNlbbNEDoeME6G → O2WvnXROue6l7nAp_4dhC}/_ssgManifest.js +0 -0
@@ -112,8 +112,22 @@ const CONTEXT_MODE_LANE_LABELS: Record<Exclude<ContextModePolicy, "none">, strin
112
112
  docs: "documentation",
113
113
  };
114
114
 
115
- const CONTEXT_MODE_GUIDANCE =
116
- "Use `gsd_exec` for noisy commands, `gsd_exec_search` before reruns, and `gsd_resume` after compaction or resume.";
115
+ const CONTEXT_MODE_GUIDANCE_BY_LANE: Record<Exclude<ContextModePolicy, "none">, string> = {
116
+ interview:
117
+ "Use `gsd_resume` to restore prior discussion, `gsd_exec` for noisy discovery, and `gsd_exec_search` before repeating scans.",
118
+ research:
119
+ "Use `gsd_exec` for noisy research scans, `gsd_exec_search` before reruns, and `gsd_resume` to restore prior findings.",
120
+ planning:
121
+ "Use `gsd_resume` for planning continuity, `gsd_exec` for noisy checks, and `gsd_exec_search` before rerunning diagnostics.",
122
+ execution:
123
+ "Use `gsd_exec` for builds, tests, and diagnostics, `gsd_exec_search` before reruns, and `gsd_resume` after compaction or resume.",
124
+ verification:
125
+ "Use `gsd_exec` for verification commands, `gsd_exec_search` to reuse prior evidence, and `gsd_resume` after compaction or resume.",
126
+ orchestration:
127
+ "Use `gsd_resume` before resuming orchestration, `gsd_exec_search` to reuse prior runs, and `gsd_exec` for noisy coordination checks.",
128
+ docs:
129
+ "Use `gsd_resume` for prior context, `gsd_exec_search` for saved evidence, and `gsd_exec` for noisy doc validation commands.",
130
+ };
117
131
 
118
132
  /**
119
133
  * Render the Context Mode instruction lane for a unit type. Unknown unit
@@ -129,15 +143,16 @@ export function composeContextModeInstructions(
129
143
  if (!manifest || manifest.contextMode === "none") return "";
130
144
 
131
145
  const lane = CONTEXT_MODE_LANE_LABELS[manifest.contextMode];
146
+ const guidance = CONTEXT_MODE_GUIDANCE_BY_LANE[manifest.contextMode];
132
147
  if (opts.renderMode === "nested") {
133
- return `Context Mode (${lane} lane): ${CONTEXT_MODE_GUIDANCE}`;
148
+ return `Context Mode (${lane} lane): ${guidance}`;
134
149
  }
135
150
 
136
151
  return [
137
152
  "## Context Mode",
138
153
  "",
139
154
  `Lane: **${lane} lane**.`,
140
- CONTEXT_MODE_GUIDANCE,
155
+ guidance,
141
156
  ].join("\n");
142
157
  }
143
158
 
@@ -10,6 +10,8 @@ import {
10
10
  } from "./paths.js";
11
11
  import { loadFile, parseTaskPlanMustHaves, countMustHavesMentionedInSummary } from "./files.js";
12
12
  import { parseUnitId } from "./unit-id.js";
13
+ import { getTask, isDbAvailable, refreshOpenDatabaseFromDisk } from "./gsd-db.js";
14
+ import { isClosedStatus } from "./status-guards.js";
13
15
 
14
16
  // Per-record advisory lock — prevents read-modify-write races between
15
17
  // concurrent writers updating disjoint fields of the same runtime record.
@@ -67,17 +69,32 @@ export type UnitRuntimePhase =
67
69
  | "wrapup-warning-sent"
68
70
  | "timeout"
69
71
  | "finalize-timeout"
72
+ | "crashed"
70
73
  | "recovered"
71
74
  | "finalized"
72
75
  | "paused"
73
76
  | "skipped";
74
77
 
78
+ export const IN_FLIGHT_RUNTIME_PHASES: ReadonlySet<UnitRuntimePhase> = new Set([
79
+ "dispatched",
80
+ "wrapup-warning-sent",
81
+ "timeout",
82
+ "finalize-timeout",
83
+ "crashed",
84
+ "paused",
85
+ ]);
86
+
87
+ export function isInFlightRuntimePhase(phase: UnitRuntimePhase): boolean {
88
+ return IN_FLIGHT_RUNTIME_PHASES.has(phase);
89
+ }
90
+
75
91
  export interface ExecuteTaskRecoveryStatus {
76
92
  planPath: string;
77
93
  summaryPath: string;
78
94
  summaryExists: boolean;
79
95
  taskChecked: boolean;
80
96
  nextActionAdvanced: boolean;
97
+ dbComplete: boolean;
81
98
  mustHaveCount: number;
82
99
  mustHavesMentionedInSummary: number;
83
100
  }
@@ -199,6 +216,12 @@ export async function inspectExecuteTaskDurability(
199
216
  const escapedTid = tid.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
200
217
  const taskChecked = !!planContent && new RegExp(`^- \\[[xX]\\] \\*\\*${escapedTid}:`, "m").test(planContent);
201
218
  const nextActionAdvanced = !new RegExp(`Execute ${tid}\\b`).test(stateContent);
219
+ let dbComplete = false;
220
+ if (isDbAvailable()) {
221
+ refreshOpenDatabaseFromDisk();
222
+ const task = getTask(mid, sid, tid);
223
+ dbComplete = !!task && isClosedStatus(task.status);
224
+ }
202
225
 
203
226
  // Must-have coverage: load task plan and count mentions in summary
204
227
  let mustHaveCount = 0;
@@ -225,12 +248,14 @@ export async function inspectExecuteTaskDurability(
225
248
  summaryExists,
226
249
  taskChecked,
227
250
  nextActionAdvanced,
251
+ dbComplete,
228
252
  mustHaveCount,
229
253
  mustHavesMentionedInSummary,
230
254
  };
231
255
  }
232
256
 
233
257
  export function formatExecuteTaskRecoveryStatus(status: ExecuteTaskRecoveryStatus): string {
258
+ if (status.dbComplete) return "DB task status is closed";
234
259
  const missing = [] as string[];
235
260
  if (!status.summaryExists) missing.push(`summary missing (${status.summaryPath})`);
236
261
  if (!status.taskChecked) missing.push(`task checkbox unchecked in ${status.planPath}`);
@@ -0,0 +1,160 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Shared capped workflow protocol and doctor-heal prompt payload helpers.
3
+
4
+ const DEFAULT_WORKFLOW_PROTOCOL_EXCERPT_CHARS = 4_000;
5
+ const MIN_WORKFLOW_PROTOCOL_EXCERPT_CHARS = 1_000;
6
+ const DEFAULT_DOCTOR_SUMMARY_CHARS = 2_400;
7
+ const DEFAULT_DOCTOR_ISSUE_CHARS = 300;
8
+ const DEFAULT_DOCTOR_MAX_ISSUES = 12;
9
+ const DEFAULT_DOCTOR_ISSUES_CHARS = 4_000;
10
+
11
+ export function buildWorkflowProtocolExcerpt(
12
+ workflow: string,
13
+ workflowPath: string,
14
+ opts: { maxChars?: number } = {},
15
+ ): string {
16
+ const limit = opts.maxChars ?? getWorkflowProtocolExcerptLimit();
17
+ const trimmed = workflow.trim();
18
+ const excerpt = buildPrioritizedWorkflowExcerpt(trimmed, limit);
19
+ const truncated = trimmed.length > limit;
20
+ const lines = [
21
+ "## GSD Workflow Protocol Excerpt",
22
+ `Source: \`${workflowPath}\``,
23
+ "",
24
+ excerpt,
25
+ ];
26
+ if (truncated) {
27
+ lines.push(
28
+ "",
29
+ "[Workflow Protocol Truncated]",
30
+ "The full workflow protocol remains available at the source path above. Read it only if this excerpt lacks a rule required for the dispatched task.",
31
+ );
32
+ }
33
+ return lines.join("\n");
34
+ }
35
+
36
+ export function buildWorkflowDispatchContent(opts: {
37
+ workflow: string;
38
+ workflowPath: string;
39
+ task: string;
40
+ maxProtocolChars?: number;
41
+ }): string {
42
+ return [
43
+ "Read the following GSD workflow protocol excerpt and execute exactly. Use the source path for a full protocol read only if the excerpt lacks a required rule.",
44
+ "",
45
+ buildWorkflowProtocolExcerpt(opts.workflow, opts.workflowPath, { maxChars: opts.maxProtocolChars }),
46
+ "",
47
+ "## Your Task",
48
+ "",
49
+ opts.task.trim(),
50
+ ].join("\n");
51
+ }
52
+
53
+ export function buildDoctorHealSummary(reportText: string, opts: { maxChars?: number } = {}): string {
54
+ const limit = opts.maxChars ?? DEFAULT_DOCTOR_SUMMARY_CHARS;
55
+ const lines = reportText.split(/\r?\n/).map((line) => line.trimEnd());
56
+ const summaryLines = lines.filter((line) =>
57
+ line.length > 0 && (
58
+ /^#/.test(line) ||
59
+ /^(scope|status|summary|checks?|errors?|warnings?|fixes?|issues?)\b/i.test(line) ||
60
+ /doctor/i.test(line)
61
+ ),
62
+ );
63
+ const selected = summaryLines.length > 0 ? summaryLines : lines.filter((line) => line.trim()).slice(0, 24);
64
+ return capText(selected.join("\n"), limit, "Full doctor report is available in the command output; use the structured issue list below for repairs.");
65
+ }
66
+
67
+ export function buildDoctorHealIssuePayload(
68
+ structuredIssues: string,
69
+ opts: { maxIssues?: number; maxIssueChars?: number; maxChars?: number } = {},
70
+ ): string {
71
+ const maxIssues = opts.maxIssues ?? DEFAULT_DOCTOR_MAX_ISSUES;
72
+ const maxIssueChars = opts.maxIssueChars ?? DEFAULT_DOCTOR_ISSUE_CHARS;
73
+ const maxChars = opts.maxChars ?? DEFAULT_DOCTOR_ISSUES_CHARS;
74
+ const blocks = splitIssueBlocks(structuredIssues);
75
+ const topBlocks = blocks.slice(0, maxIssues).map((block) =>
76
+ capText(block, maxIssueChars, "Issue details truncated; inspect the relevant artifact before editing."),
77
+ );
78
+ if (blocks.length > maxIssues) {
79
+ topBlocks.push(`[${blocks.length - maxIssues} additional actionable issue(s) omitted from prompt. Re-run /gsd doctor heal after this repair pass.]`);
80
+ }
81
+ return capText(topBlocks.join("\n\n"), maxChars, "Structured issue list truncated; repair top actionable issues first and re-run doctor heal.");
82
+ }
83
+
84
+ function getWorkflowProtocolExcerptLimit(): number {
85
+ const raw = process.env.PI_GSD_WORKFLOW_PROTOCOL_MAX_CHARS;
86
+ if (!raw) return DEFAULT_WORKFLOW_PROTOCOL_EXCERPT_CHARS;
87
+ const parsed = Number(raw);
88
+ if (!Number.isFinite(parsed) || parsed < MIN_WORKFLOW_PROTOCOL_EXCERPT_CHARS) {
89
+ return DEFAULT_WORKFLOW_PROTOCOL_EXCERPT_CHARS;
90
+ }
91
+ return Math.floor(parsed);
92
+ }
93
+
94
+ function buildPrioritizedWorkflowExcerpt(workflow: string, limit: number): string {
95
+ if (workflow.length <= limit) return workflow;
96
+ const sections = splitMarkdownSections(workflow);
97
+ const wanted = [
98
+ /^# /,
99
+ /^## Quick Start\b/i,
100
+ /^## The Hierarchy\b/i,
101
+ /^## The Phases\b/i,
102
+ /^### Phase 4: Execute\b/i,
103
+ /^### Phase 5: Verify\b/i,
104
+ /^### Observable Truths\b/i,
105
+ /^### Artifacts\b/i,
106
+ /^### Key Links\b/i,
107
+ /^### Phase 6: Summarize\b/i,
108
+ /^### Phase 7: Advance\b/i,
109
+ ];
110
+ const selected: string[] = [];
111
+ const used = new Set<number>();
112
+ for (const pattern of wanted) {
113
+ const index = sections.findIndex((section, sectionIndex) =>
114
+ !used.has(sectionIndex) && pattern.test(section.heading),
115
+ );
116
+ if (index >= 0) {
117
+ used.add(index);
118
+ selected.push(sections[index].text);
119
+ }
120
+ }
121
+ const body = selected.length > 0 ? selected.join("\n\n") : workflow;
122
+ return capText(body, limit, "Workflow protocol excerpt capped; read the source path for omitted details.");
123
+ }
124
+
125
+ function splitMarkdownSections(markdown: string): Array<{ heading: string; text: string }> {
126
+ const lines = markdown.split(/\r?\n/);
127
+ const sections: Array<{ heading: string; text: string }> = [];
128
+ let currentHeading = lines[0]?.startsWith("#") ? lines[0] : "# Preamble";
129
+ let current: string[] = [];
130
+ for (const line of lines) {
131
+ if (/^#{1,3}\s+/.test(line) && current.length > 0) {
132
+ sections.push({ heading: currentHeading, text: current.join("\n").trim() });
133
+ currentHeading = line;
134
+ current = [line];
135
+ continue;
136
+ }
137
+ if (/^#{1,3}\s+/.test(line)) currentHeading = line;
138
+ current.push(line);
139
+ }
140
+ if (current.length > 0) {
141
+ sections.push({ heading: currentHeading, text: current.join("\n").trim() });
142
+ }
143
+ return sections.filter((section) => section.text.length > 0);
144
+ }
145
+
146
+ function splitIssueBlocks(structuredIssues: string): string[] {
147
+ const trimmed = structuredIssues.trim();
148
+ if (!trimmed) return ["No structured issue details were provided."];
149
+ const split = trimmed.split(/\n(?=(?:#{2,6}\s+|\d+\.\s+|- \*\*|- \[[ x]\]))/i)
150
+ .map((block) => block.trim())
151
+ .filter(Boolean);
152
+ return split.length > 0 ? split : [trimmed];
153
+ }
154
+
155
+ function capText(text: string, limit: number, notice: string): string {
156
+ if (text.length <= limit) return text;
157
+ const suffix = `\n\n[Truncated]\n${notice}`;
158
+ const headBudget = Math.max(0, limit - suffix.length);
159
+ return `${text.slice(0, headBudget).trimEnd()}${suffix}`;
160
+ }
@@ -25,7 +25,7 @@ import { emitWorktreeCreated, emitWorktreeMerged } from "./worktree-telemetry.js
25
25
  import { getCollapseCadence, getMilestoneResquash, resquashMilestoneOnMain } from "./slice-cadence.js";
26
26
  import { loadEffectiveGSDPreferences } from "./preferences.js";
27
27
  import { resolveWorktreeProjectRoot, normalizeWorktreePathForCompare } from "./worktree-root.js";
28
- import { claimMilestoneLease, releaseMilestoneLease } from "./db/milestone-leases.js";
28
+ import { claimMilestoneLease, refreshMilestoneLease, releaseMilestoneLease } from "./db/milestone-leases.js";
29
29
 
30
30
  // ─── Path Comparison Helper ────────────────────────────────────────────────
31
31
  /**
@@ -40,6 +40,16 @@ function isSamePath(a: string, b: string): boolean {
40
40
  return normalizeWorktreePathForCompare(a) === normalizeWorktreePathForCompare(b);
41
41
  }
42
42
 
43
+ class UserNotifiedError extends Error {
44
+ readonly cause?: unknown;
45
+
46
+ constructor(message: string, cause?: unknown) {
47
+ super(message);
48
+ this.name = "UserNotifiedError";
49
+ this.cause = cause;
50
+ }
51
+ }
52
+
43
53
  // ─── Dependency Interface ──────────────────────────────────────────────────
44
54
 
45
55
  export interface WorktreeResolverDeps {
@@ -71,6 +81,13 @@ export interface WorktreeResolverDeps {
71
81
  milestoneId: string,
72
82
  ) => void;
73
83
  getCurrentBranch: (basePath: string) => string;
84
+ /**
85
+ * Force-checkout the named branch in `basePath`. Required by `_mergeBranchMode`
86
+ * when it discovers the working tree is not on the milestone branch — preflight
87
+ * stash + later operations may have switched HEAD to main, and silently skipping
88
+ * the merge would strand the milestone's commits.
89
+ */
90
+ checkoutBranch: (basePath: string, branch: string) => void;
74
91
  autoWorktreeBranch: (milestoneId: string) => string;
75
92
  resolveMilestoneFile: (
76
93
  basePath: string,
@@ -207,23 +224,44 @@ export class WorktreeResolver {
207
224
  // milestone (re-entry within the same session).
208
225
  if (this.s.workerId) {
209
226
  if (this.s.currentMilestoneId === milestoneId && this.s.milestoneLeaseToken !== null) {
210
- // Already held — no-op, the heartbeat in loop.ts refreshes TTL.
211
- } else {
212
- // If we held a different milestone, release it first so other
213
- // workers don't have to wait for TTL.
214
- if (this.s.currentMilestoneId && this.s.currentMilestoneId !== milestoneId && this.s.milestoneLeaseToken !== null) {
215
- try {
216
- releaseMilestoneLease(this.s.workerId, this.s.currentMilestoneId, this.s.milestoneLeaseToken);
217
- } catch (err) {
218
- debugLog("WorktreeResolver", {
219
- action: "enterMilestone",
220
- milestoneId,
221
- releasePriorLeaseError: err instanceof Error ? err.message : String(err),
222
- });
223
- }
227
+ const refreshed = refreshMilestoneLease(
228
+ this.s.workerId,
229
+ milestoneId,
230
+ this.s.milestoneLeaseToken,
231
+ );
232
+ if (refreshed) {
233
+ debugLog("WorktreeResolver", {
234
+ action: "enterMilestone",
235
+ milestoneId,
236
+ leaseRefreshed: true,
237
+ fencingToken: this.s.milestoneLeaseToken,
238
+ });
239
+ } else {
240
+ debugLog("WorktreeResolver", {
241
+ action: "enterMilestone",
242
+ milestoneId,
243
+ staleLeaseToken: this.s.milestoneLeaseToken,
244
+ });
224
245
  this.s.milestoneLeaseToken = null;
225
246
  }
247
+ }
248
+
249
+ // If we held a different milestone, release it first so other
250
+ // workers don't have to wait for TTL.
251
+ if (this.s.currentMilestoneId && this.s.currentMilestoneId !== milestoneId && this.s.milestoneLeaseToken !== null) {
252
+ try {
253
+ releaseMilestoneLease(this.s.workerId, this.s.currentMilestoneId, this.s.milestoneLeaseToken);
254
+ } catch (err) {
255
+ debugLog("WorktreeResolver", {
256
+ action: "enterMilestone",
257
+ milestoneId,
258
+ releasePriorLeaseError: err instanceof Error ? err.message : String(err),
259
+ });
260
+ }
261
+ this.s.milestoneLeaseToken = null;
262
+ }
226
263
 
264
+ if (this.s.milestoneLeaseToken === null) {
227
265
  try {
228
266
  const claim = claimMilestoneLease(this.s.workerId, milestoneId);
229
267
  if (claim.ok) {
@@ -803,16 +841,41 @@ export class WorktreeResolver {
803
841
  const milestoneBranch = this.deps.autoWorktreeBranch(milestoneId);
804
842
 
805
843
  if (currentBranch !== milestoneBranch) {
844
+ // #5538-followup: previous behavior was to silently `return false`
845
+ // when HEAD wasn't on the milestone branch — that let the loop
846
+ // advance with the milestone's commits stranded on the branch (the
847
+ // exact failure mode reported in the test12345 repro). Attempt
848
+ // recovery by force-checking-out the milestone branch; if the
849
+ // checkout fails, throw so the caller pauses auto-mode and the user
850
+ // sees the failure instead of a silent merge skip.
806
851
  debugLog("WorktreeResolver", {
807
852
  action: "mergeAndExit",
808
853
  milestoneId,
809
854
  mode: "branch",
810
- skipped: true,
811
- reason: "not-on-milestone-branch",
855
+ recovery: "checkout-milestone-branch",
812
856
  currentBranch,
813
857
  milestoneBranch,
814
858
  });
815
- return false;
859
+ try {
860
+ this.deps.checkoutBranch(this.s.basePath, milestoneBranch);
861
+ } catch (checkoutErr) {
862
+ const checkoutMsg = checkoutErr instanceof Error ? checkoutErr.message : String(checkoutErr);
863
+ ctx.notify(
864
+ `Cannot merge milestone ${milestoneId}: working tree is on ${currentBranch} and checkout to ${milestoneBranch} failed (${checkoutMsg}). Resolve manually and run /gsd auto to resume.`,
865
+ "error",
866
+ );
867
+ throw new UserNotifiedError(checkoutMsg, checkoutErr);
868
+ }
869
+
870
+ const reverify = this.deps.getCurrentBranch(this.s.basePath);
871
+ if (reverify !== milestoneBranch) {
872
+ const reverifyMsg = `branch checkout to ${milestoneBranch} reported success but current branch is ${reverify}`;
873
+ ctx.notify(
874
+ `Cannot merge milestone ${milestoneId}: ${reverifyMsg}. Resolve manually and run /gsd auto to resume.`,
875
+ "error",
876
+ );
877
+ throw new UserNotifiedError(reverifyMsg);
878
+ }
816
879
  }
817
880
 
818
881
  const roadmapPath = this.deps.resolveMilestoneFile(
@@ -869,7 +932,9 @@ export class WorktreeResolver {
869
932
  result: "error",
870
933
  error: msg,
871
934
  });
872
- ctx.notify(`Milestone merge failed (branch mode): ${msg}`, "warning");
935
+ if (!(err instanceof UserNotifiedError)) {
936
+ ctx.notify(`Milestone merge failed (branch mode): ${msg}`, "warning");
937
+ }
873
938
  // Re-throw all errors so callers can apply their own recovery logic (#4380).
874
939
  throw err;
875
940
  }
@@ -897,6 +962,7 @@ export class WorktreeResolver {
897
962
  try {
898
963
  this.mergeAndExit(currentMilestoneId, ctx);
899
964
  } catch (err) {
965
+ if (err instanceof UserNotifiedError) throw err;
900
966
  // mergeAndExit emits a warning and restores state when it fails during
901
967
  // merge/cleanup. But if it throws before recovery runs (e.g., in
902
968
  // validateMilestoneId or emitJournalEvent), basePath won't be restored
@@ -1,97 +0,0 @@
1
- /**
2
- * phases-merge-error-stops-auto.test.ts — Regression test for #2766.
3
- *
4
- * When mergeAndExit throws a non-MergeConflictError, the auto loop must
5
- * stop instead of continuing with unmerged work. This test verifies that
6
- * all catch blocks in auto/phases.ts that handle mergeAndExit errors
7
- * call stopAuto and return { action: "break" } for non-conflict errors.
8
- */
9
-
10
- import { readFileSync } from "node:fs";
11
- import { join } from "node:path";
12
- import { createTestContext } from "./test-helpers.ts";
13
-
14
- const { assertTrue, report } = createTestContext();
15
-
16
- const phasesPath = join(import.meta.dirname, "..", "auto", "phases.ts");
17
- const phasesSrc = readFileSync(phasesPath, "utf-8");
18
-
19
- console.log("\n=== #2766: Non-MergeConflictError stops auto mode ===");
20
-
21
- // ── Test 1: every mergeAndExit call site has a catch (mergeErr) block ──
22
-
23
- // Count all mergeAndExit catch blocks by finding "} catch (mergeErr)" patterns
24
- const mergeAndExitCallCount = [...phasesSrc.matchAll(/\.mergeAndExit\(/g)].length;
25
- const mergeErrCatchCount = [...phasesSrc.matchAll(/\} catch \(mergeErr\)/g)].length;
26
- assertTrue(
27
- mergeErrCatchCount === mergeAndExitCallCount && mergeAndExitCallCount > 0,
28
- `every mergeAndExit call site has a catch (mergeErr) block (calls=${mergeAndExitCallCount}, catches=${mergeErrCatchCount})`,
29
- );
30
-
31
- // ── Test 2: Every mergeErr catch block handles non-MergeConflictError ───
32
-
33
- // Find each catch block and verify it has the non-conflict error handling pattern
34
- const catchPattern = /\} catch \(mergeErr\) \{/g;
35
- let match;
36
- let blocksWithNonConflictHandling = 0;
37
- let blocksTotal = 0;
38
-
39
- while ((match = catchPattern.exec(phasesSrc)) !== null) {
40
- blocksTotal++;
41
- // Look at the ~800 chars after the catch to find both the MergeConflictError
42
- // instanceof check AND the non-conflict handling
43
- const afterCatch = phasesSrc.slice(match.index, match.index + 1200);
44
-
45
- const hasInstanceofCheck = afterCatch.includes("instanceof MergeConflictError");
46
- const hasNonConflictStop = afterCatch.includes('reason: "merge-failed"');
47
- const hasStopAuto = afterCatch.includes("stopAuto");
48
- const hasLogError = afterCatch.includes("logError");
49
-
50
- if (hasInstanceofCheck && hasNonConflictStop && hasStopAuto && hasLogError) {
51
- blocksWithNonConflictHandling++;
52
- }
53
- }
54
-
55
- assertTrue(
56
- blocksWithNonConflictHandling === blocksTotal && blocksTotal >= 3,
57
- `all ${blocksTotal} mergeAndExit catch blocks stop auto on non-conflict errors (${blocksWithNonConflictHandling}/${blocksTotal})`,
58
- );
59
-
60
- // ── Test 3: Non-conflict handler returns break (does not continue) ──────
61
-
62
- // Verify the pattern: after the MergeConflictError instanceof block,
63
- // the non-conflict path returns { action: "break", reason: "merge-failed" }
64
- const mergeFailedReasons = [...phasesSrc.matchAll(/reason: "merge-failed"/g)].length;
65
- assertTrue(
66
- mergeFailedReasons >= 3,
67
- `all catch blocks return reason: "merge-failed" (found ${mergeFailedReasons}, expected >= 3)`,
68
- );
69
-
70
- // ── Test 4: Non-conflict handler notifies user ──────────────────────────
71
-
72
- // Each non-conflict block should call ctx.ui.notify with error severity
73
- const notifyErrorPattern = /Merge failed:.*Resolve and run \/gsd auto to resume/g;
74
- const notifyCount = [...phasesSrc.matchAll(notifyErrorPattern)].length;
75
- assertTrue(
76
- notifyCount >= 3,
77
- `all catch blocks notify user about merge failure (found ${notifyCount}, expected >= 3)`,
78
- );
79
-
80
- // ── Test 5: logError replaces logWarning for non-conflict merge errors ──
81
-
82
- // The old code used logWarning — verify logError is used instead
83
- const logWarningMergePattern = /logWarning\(.*Milestone merge failed with non-conflict error/g;
84
- const logWarningCount = [...phasesSrc.matchAll(logWarningMergePattern)].length;
85
- assertTrue(
86
- logWarningCount === 0,
87
- "logWarning is no longer used for non-conflict merge errors (replaced by logError)",
88
- );
89
-
90
- const logErrorMergePattern = /logError\(.*Milestone merge failed with non-conflict error/g;
91
- const logErrorCount = [...phasesSrc.matchAll(logErrorMergePattern)].length;
92
- assertTrue(
93
- logErrorCount >= 3,
94
- `logError is used for non-conflict merge errors (found ${logErrorCount}, expected >= 3)`,
95
- );
96
-
97
- report();