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
@@ -106,6 +106,13 @@ export class AutoSession {
106
106
  * stale context bleeding into unrelated slices.
107
107
  */
108
108
  lastPreExecFailure = null;
109
+ /**
110
+ * Tracks how many consecutive times each slice unit has failed pre-execution
111
+ * checks. Keyed by unitId (e.g. "M001/S01"). Used to break the infinite
112
+ * plan-slice → pre-exec fail → re-dispatch loop when the planner cannot fix
113
+ * the issues after MAX_PRE_EXEC_RETRIES re-attempts.
114
+ */
115
+ preExecRetryCount = new Map();
109
116
  // ── Tool invocation errors (#2883) ──────────────────────────────────
110
117
  /** Set when a GSD tool execution ends with isError due to malformed/truncated
111
118
  * JSON arguments. Checked by postUnitPreVerification to break retry loops. */
@@ -258,6 +265,7 @@ export class AutoSession {
258
265
  this.rewriteAttemptCount = 0;
259
266
  this.consecutiveCompleteBootstraps = 0;
260
267
  this.lastPreExecFailure = null;
268
+ this.preExecRetryCount.clear();
261
269
  this.lastToolInvocationError = null;
262
270
  this.lastUnitAgentEndMessages = null;
263
271
  this.lastGitActionFailure = null;
@@ -11,7 +11,6 @@ import { buildResearchSlicePrompt, buildResearchMilestonePrompt, buildPlanSliceP
11
11
  import { loadEffectiveGSDPreferences } from "./preferences.js";
12
12
  import { pauseAuto } from "./auto.js";
13
13
  import { resolveCanonicalMilestoneRoot } from "./worktree-manager.js";
14
- import { logWarning } from "./workflow-logger.js";
15
14
  import { getWorkflowTransportSupportError, getRequiredWorkflowToolsForAutoUnit, } from "./workflow-mcp.js";
16
15
  export async function dispatchDirectPhase(ctx, pi, phase, base) {
17
16
  const state = await deriveState(base);
@@ -231,36 +230,10 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
231
230
  return;
232
231
  }
233
232
  ctx.ui.notify(`Dispatching ${unitType} for ${unitId}...`, "info");
234
- const originalCwd = process.cwd();
235
- try {
236
- // Ensure cwd matches dispatchBase BEFORE newSession() captures it. Synchronous —
237
- // no awaits between chdir and newSession.
238
- try {
239
- if (process.cwd() !== dispatchBase) {
240
- process.chdir(dispatchBase);
241
- }
242
- }
243
- catch (err) {
244
- const msg = `Failed to chdir before direct-dispatch newSession (basePath: ${dispatchBase}): ${err instanceof Error ? err.message : String(err)}`;
245
- logWarning("engine", msg, { file: "auto-direct-dispatch.ts", basePath: dispatchBase, error: err instanceof Error ? err.message : String(err) });
246
- ctx.ui.notify(`${msg}. Cancelling dispatch to avoid running in the wrong directory.`, "error");
247
- return;
248
- }
249
- const result = await ctx.newSession();
250
- if (result.cancelled) {
251
- ctx.ui.notify("Session creation cancelled.", "warning");
252
- return;
253
- }
254
- pi.sendMessage({ customType: "gsd-dispatch", content: prompt, display: false }, { triggerTurn: true });
255
- }
256
- finally {
257
- try {
258
- if (process.cwd() !== originalCwd) {
259
- process.chdir(originalCwd);
260
- }
261
- }
262
- catch (err) {
263
- logWarning("engine", `Failed to restore cwd after direct dispatch: ${err instanceof Error ? err.message : String(err)}`, { file: "auto-direct-dispatch.ts", basePath: originalCwd });
264
- }
233
+ const result = await ctx.newSession({ workspaceRoot: dispatchBase });
234
+ if (result.cancelled) {
235
+ ctx.ui.notify("Session creation cancelled.", "warning");
236
+ return;
265
237
  }
238
+ pi.sendMessage({ customType: "gsd-dispatch", content: prompt, display: false }, { triggerTurn: true });
266
239
  }
@@ -791,6 +791,22 @@ export const DISPATCH_RULES = [
791
791
  const unitId = `${mid}/${sid}`;
792
792
  let priorPreExecFailure;
793
793
  if (session?.lastPreExecFailure?.unitId === unitId) {
794
+ // Circuit breaker: stop re-dispatching after 2 failed retries. The
795
+ // planner has had multiple attempts with injected failure context and
796
+ // still cannot produce a valid plan — human review is required.
797
+ const MAX_PRE_EXEC_RETRIES = 2;
798
+ const retryCount = session.preExecRetryCount?.get(unitId) ?? 0;
799
+ if (retryCount >= MAX_PRE_EXEC_RETRIES) {
800
+ const findings = session.lastPreExecFailure.blockingFindings.join("; ");
801
+ session.lastPreExecFailure = null;
802
+ session.preExecRetryCount?.delete(unitId);
803
+ return {
804
+ action: "stop",
805
+ reason: `Pre-execution checks failed ${retryCount} times for ${unitId} — manual intervention required. Blocking findings: ${findings}. Fix the plan manually, then run /gsd auto to resume.`,
806
+ level: "error",
807
+ matchedRule: "planning → plan-slice",
808
+ };
809
+ }
794
810
  priorPreExecFailure = {
795
811
  blockingFindings: session.lastPreExecFailure.blockingFindings,
796
812
  verdictExcerpt: session.lastPreExecFailure.verdictExcerpt,
@@ -1123,8 +1123,11 @@ export async function postUnitPostVerification(pctx) {
1123
1123
  return;
1124
1124
  }
1125
1125
  const strictMode = prefs?.enhanced_verification_strict === true;
1126
- // Run pre-execution checks
1127
- const result = await runPreExecutionChecks(tasks, s.basePath);
1126
+ // Run pre-execution checks against the canonical project root. In
1127
+ // worktree isolation, s.basePath can point at a metadata-only worktree,
1128
+ // while source files remain under the project root.
1129
+ const preExecutionBasePath = s.canonicalProjectRoot;
1130
+ const result = await runPreExecutionChecks(tasks, preExecutionBasePath);
1128
1131
  // Log summary to stderr in existing verification output format
1129
1132
  const emoji = result.status === "pass" ? "✅" : result.status === "warn" ? "⚠️" : "❌";
1130
1133
  process.stderr.write(`gsd-pre-exec: ${emoji} Pre-execution checks ${result.status} for ${mid}/${sid} (${result.durationMs}ms)\n`);
@@ -1134,12 +1137,12 @@ export async function postUnitPostVerification(pctx) {
1134
1137
  process.stderr.write(`gsd-pre-exec: ${checkEmoji} [${check.category}] ${check.target}: ${check.message}\n`);
1135
1138
  }
1136
1139
  // Write evidence JSON to slice artifacts directory
1137
- const slicePath = resolveSlicePath(s.basePath, mid, sid);
1140
+ const slicePath = resolveSlicePath(preExecutionBasePath, mid, sid);
1138
1141
  const evidenceFileName = `${sid}-PRE-EXEC-VERIFY.json`;
1139
1142
  let evidencePath = join(".gsd", "milestones", mid, "slices", sid, evidenceFileName);
1140
1143
  if (slicePath) {
1141
1144
  writePreExecutionEvidence(result, slicePath, mid, sid);
1142
- evidencePath = relative(s.basePath, join(slicePath, evidenceFileName)) || evidenceFileName;
1145
+ evidencePath = relative(preExecutionBasePath, join(slicePath, evidenceFileName)) || evidenceFileName;
1143
1146
  }
1144
1147
  if (uokFlags.gates) {
1145
1148
  const failedChecks = result.checks
@@ -1187,6 +1190,9 @@ export async function postUnitPostVerification(pctx) {
1187
1190
  blockingFindings: blockingChecks.map(c => `[${c.category}] ${c.target}: ${c.message}`),
1188
1191
  verdictExcerpt: `status=${result.status}; ${blockingCount} blocking issue${blockingCount === 1 ? "" : "s"} detected`,
1189
1192
  };
1193
+ // Track consecutive pre-exec failures per slice for loop detection.
1194
+ const retryKey = currentUnit.id;
1195
+ s.preExecRetryCount.set(retryKey, (s.preExecRetryCount.get(retryKey) ?? 0) + 1);
1190
1196
  preExecPauseNeeded = true;
1191
1197
  }
1192
1198
  else if (result.status === "warn") {
@@ -1199,9 +1205,16 @@ export async function postUnitPostVerification(pctx) {
1199
1205
  blockingFindings: warnChecks.map(c => `[${c.category}] ${c.target}: ${c.message}`),
1200
1206
  verdictExcerpt: `status=${result.status} (strict mode); ${warnChecks.length} warning${warnChecks.length === 1 ? "" : "s"} treated as blocking`,
1201
1207
  };
1208
+ const retryKey = currentUnit.id;
1209
+ s.preExecRetryCount.set(retryKey, (s.preExecRetryCount.get(retryKey) ?? 0) + 1);
1202
1210
  preExecPauseNeeded = true;
1203
1211
  }
1204
1212
  }
1213
+ // Reset the retry counter when checks pass — a successful re-plan
1214
+ // should not carry over a stale failure count into future slices.
1215
+ if (result.status === "pass") {
1216
+ s.preExecRetryCount.delete(currentUnit.id);
1217
+ }
1205
1218
  debugLog("postUnitPostVerification", {
1206
1219
  phase: "pre-execution-checks",
1207
1220
  status: result.status,
@@ -21,6 +21,7 @@ import { assertGateCoverage, getGatesForTurn, } from "./gate-registry.js";
21
21
  import { formatDecisionsCompact, formatRequirementsCompact } from "./structured-data-formatter.js";
22
22
  import { readPhaseAnchor, formatAnchorForPrompt } from "./phase-anchor.js";
23
23
  import { composeContextModeInstructions, composeInlinedContext } from "./unit-context-composer.js";
24
+ import { readCompactionSnapshot } from "./compaction-snapshot.js";
24
25
  import { logWarning } from "./workflow-logger.js";
25
26
  import { inlineGraphSubgraph } from "./graph-context.js";
26
27
  import { buildExtractionStepsBlock } from "./commands-extract-learnings.js";
@@ -28,12 +29,12 @@ import { resolveSkillManifest, warnIfManifestHasMissingSkills } from "./skill-ma
28
29
  import { classifyProject } from "./detection.js";
29
30
  // ─── Preamble Cap ─────────────────────────────────────────────────────────────
30
31
  /**
31
- * Historical static ceiling for the preamble cap. Kept as an upper bound even
32
+ * Static ceiling for the preamble cap. Kept as an upper bound even
32
33
  * after context-window-aware sizing so large-window users don't suddenly see
33
- * 10× looser caps than before. Small-window users get a tighter cap derived
34
+ * 10× looser caps than needed. Small-window users get a tighter cap derived
34
35
  * from their configured executor window.
35
36
  */
36
- const MAX_PREAMBLE_CHARS = 30_000;
37
+ const MAX_PREAMBLE_CHARS = 20_000;
37
38
  /**
38
39
  * Resolve prompt budgets from the configured executor context window.
39
40
  *
@@ -162,8 +163,8 @@ function formatCloseoutReviewInstructions(validationContent, validationRel, curr
162
163
  ].join("\n");
163
164
  }
164
165
  function capPreamble(preamble) {
165
- // Cap inlined context at min(historical 30K ceiling, scaled inline budget).
166
- // The ceiling preserves pre-fix behavior for large-window users; the scaled
166
+ // Cap inlined context at min(static ceiling, scaled inline budget).
167
+ // The ceiling bounds repeated auto prompt payloads; the scaled
167
168
  // budget tightens the cap for small-window users whose true safe limit is
168
169
  // below 30K. `computeBudgets` allocates 40% of total chars to inline context.
169
170
  const budget = Math.min(MAX_PREAMBLE_CHARS, resolvePromptBudgets().inlineContextBudgetChars);
@@ -178,8 +179,19 @@ function renderContextModeForPrompt(unitType, base, renderMode = "standalone") {
178
179
  renderMode,
179
180
  });
180
181
  }
181
- function prependContextModeToBlock(unitType, base, block, renderMode = "standalone") {
182
+ function renderContextModeBlockForPrompt(unitType, base, renderMode = "standalone") {
182
183
  const contextMode = renderContextModeForPrompt(unitType, base, renderMode);
184
+ if (!contextMode)
185
+ return "";
186
+ if (renderMode === "nested")
187
+ return contextMode;
188
+ const snapshot = readCompactionSnapshot(base);
189
+ if (!snapshot?.trim())
190
+ return contextMode;
191
+ return `${contextMode}\n\n## Context Snapshot\nSource: \`.gsd/last-snapshot.md\`\n\n${snapshot.trimEnd()}`;
192
+ }
193
+ function prependContextModeToBlock(unitType, base, block, renderMode = "standalone") {
194
+ const contextMode = renderContextModeBlockForPrompt(unitType, base, renderMode);
183
195
  if (!contextMode)
184
196
  return block;
185
197
  if (!block.trim())
@@ -559,9 +571,77 @@ export async function buildSliceSummaryExcerpt(absPath, relPath, sid) {
559
571
  }
560
572
  catch {
561
573
  // Defensive — any parse failure falls back to full inline.
562
- return `### ${sid} Summary\nSource: \`${relPath}\`\n\n${content.trim()}`;
574
+ return `### ${sid} Summary\nSource: \`${relPath}\`\n\n${capMalformedSummary(content, relPath)}`;
563
575
  }
564
576
  }
577
+ export async function buildTaskSummaryExcerpt(absPath, relPath, tid, options) {
578
+ const label = options?.blocker ? "Blocker Task Summary" : "Task Summary";
579
+ const header = `### ${label}: ${tid} (excerpt)\nSource: \`${relPath}\``;
580
+ const content = absPath ? await loadFile(absPath) : null;
581
+ if (!content) {
582
+ return `${header}\n\n_(not found — file does not exist yet)_`;
583
+ }
584
+ try {
585
+ const s = parseSummary(content);
586
+ if (!s.frontmatter.id) {
587
+ return `### ${label}: ${tid}\nSource: \`${relPath}\`\n\n${capMalformedSummary(content, relPath)}`;
588
+ }
589
+ const lines = [header, ""];
590
+ if (s.title)
591
+ lines.push(`**Title:** ${s.title}`);
592
+ if (s.oneLiner)
593
+ lines.push(`**One-liner:** ${s.oneLiner}`);
594
+ if (s.frontmatter.verification_result) {
595
+ lines.push(`**Verification:** \`${s.frontmatter.verification_result}\``);
596
+ }
597
+ lines.push(`**Blocker discovered:** ${s.frontmatter.blocker_discovered ? "yes — read full summary if blocker details are insufficient" : "no"}`);
598
+ if (s.frontmatter.provides.length > 0)
599
+ lines.push(`**Provides:** ${s.frontmatter.provides.slice(0, 4).join("; ")}`);
600
+ if (s.frontmatter.key_decisions.length > 0)
601
+ lines.push(`**Key decisions:** ${s.frontmatter.key_decisions.slice(0, 4).join("; ")}`);
602
+ if (s.frontmatter.patterns_established.length > 0)
603
+ lines.push(`**Patterns established:** ${s.frontmatter.patterns_established.slice(0, 4).join("; ")}`);
604
+ if (s.frontmatter.key_files.length > 0) {
605
+ const files = s.frontmatter.key_files.slice(0, 6);
606
+ const more = s.frontmatter.key_files.length > files.length ? ` (+${s.frontmatter.key_files.length - files.length} more)` : "";
607
+ lines.push(`**Key files:** ${files.join(", ")}${more}`);
608
+ }
609
+ const SECTION_CAP_CHARS = 500;
610
+ const capSection = (body) => {
611
+ const trimmed = body.trim();
612
+ if (trimmed.length <= SECTION_CAP_CHARS)
613
+ return trimmed;
614
+ return `${trimmed.slice(0, SECTION_CAP_CHARS)}\n… (truncated — see full \`${relPath}\`)`;
615
+ };
616
+ const verification = extractMarkdownSection(content, "Verification");
617
+ const diagnostics = extractMarkdownSection(content, "Diagnostics");
618
+ const knownIssues = extractMarkdownSection(content, "Known Issues");
619
+ if (verification && verification.trim()) {
620
+ lines.push("", "#### Verification", capSection(verification));
621
+ }
622
+ if (diagnostics && diagnostics.trim()) {
623
+ lines.push("", "#### Diagnostics", capSection(diagnostics));
624
+ }
625
+ if (s.deviations && s.deviations.trim()) {
626
+ lines.push("", "#### Deviations", capSection(s.deviations));
627
+ }
628
+ if (knownIssues && knownIssues.trim()) {
629
+ lines.push("", "#### Known issues", capSection(knownIssues));
630
+ }
631
+ lines.push("", `> **On-demand:** read \`${relPath}\` only when this excerpt is absent/truncated or you need fuller blocker, implementation, or file-change evidence.`);
632
+ return lines.join("\n");
633
+ }
634
+ catch {
635
+ return `### ${label}: ${tid}\nSource: \`${relPath}\`\n\n${capMalformedSummary(content, relPath)}`;
636
+ }
637
+ }
638
+ function capMalformedSummary(content, relPath) {
639
+ const trimmed = content.trim();
640
+ const limit = 1_500;
641
+ if (trimmed.length <= limit)
642
+ return trimmed;
643
+ return `${trimmed.slice(0, limit).trimEnd()}\n\n[Truncated malformed summary — read \`${relPath}\` for full details.]`;
644
+ }
565
645
  /**
566
646
  * Load and inline dependency slice summaries (full content, not just paths).
567
647
  */
@@ -814,12 +894,12 @@ export async function inlineKnowledgeScoped(base, keywords) {
814
894
  * plan-milestone, complete-slice, complete-milestone, validate-milestone,
815
895
  * reassess-roadmap) previously injected the full KNOWLEDGE.md (~226KB for a
816
896
  * real project) on every invocation. This helper scopes by caller-supplied
817
- * keywords and caps the payload at `maxChars` (default 30,000 chars).
897
+ * keywords and caps the payload at `maxChars` (default 12,000 chars).
818
898
  *
819
899
  * Returns null when no KNOWLEDGE.md exists or no entries match any keyword.
820
900
  */
821
901
  export async function inlineKnowledgeBudgeted(base, keywords, options) {
822
- const DEFAULT_MAX_CHARS = 30_000;
902
+ const DEFAULT_MAX_CHARS = 12_000;
823
903
  const HARD_MAX_CHARS = 100_000;
824
904
  const raw = Number(options?.maxChars ?? DEFAULT_MAX_CHARS);
825
905
  const maxChars = Number.isFinite(raw)
@@ -1812,8 +1892,17 @@ export async function buildPlanSlicePrompt(mid, _midTitle, sid, sTitle, base, le
1812
1892
  `The previous plan-slice attempt was blocked by pre-execution validation.\n` +
1813
1893
  `Gate verdict: ${verdictExcerpt}\n\n` +
1814
1894
  `Blocked references that must be resolved in this plan:\n${findingsList}\n\n` +
1815
- `Revise the plan so that every reference listed above is satisfied before execution begins. ` +
1816
- `Do not reproduce the same file paths, package names, or task ordering that caused these failures.`);
1895
+ `**How to fix each type of issue:**\n` +
1896
+ `- **"[file] X doesn't exist and isn't created by prior or same-task outputs"**: ` +
1897
+ `Either (a) add an earlier task that creates X on disk before the task that needs it, ` +
1898
+ `or (b) if this task IS the one that creates X, move X from inputs to expected_output. ` +
1899
+ `Do NOT put X in a task's expected_output if that task only reads or verifies X — only tasks that actually write X to disk should list it in expected_output.\n` +
1900
+ `- **"[file] X: Task T_early reads X but it's created by task T_late (sequence violation)"**: ` +
1901
+ `Either (a) reorder tasks so T_late (the creator) runs before T_early (the reader), ` +
1902
+ `or (b) if T_late doesn't actually create X (it only reads/tests it), remove X from T_late's expected_output entirely.\n` +
1903
+ `- **"[package] P not found on npm"**: Either remove the npm install for P, or use the correct package name.\n\n` +
1904
+ `Every file listed in a task's inputs must either exist on disk already or appear in an earlier task's expected_output. ` +
1905
+ `A task's expected_output must only list files it actually writes to disk.`);
1817
1906
  }
1818
1907
  return renderSlicePrompt({
1819
1908
  mid, sid, sTitle, base,
@@ -2036,11 +2125,9 @@ export async function buildCompleteSlicePrompt(mid, midTitle, sid, sTitle, base,
2036
2125
  const blocks = [];
2037
2126
  for (const file of summaryFiles) {
2038
2127
  const absPath = join(tDir, file);
2039
- const content = await loadFile(absPath);
2040
- if (!content)
2041
- continue;
2042
2128
  const relPath = `${sRel}/tasks/${file}`;
2043
- blocks.push(`### Task Summary: ${file.replace(/-SUMMARY\.md$/i, "")}\nSource: \`${relPath}\`\n\n${content.trim()}`);
2129
+ const taskId = file.replace(/-SUMMARY\.md$/i, "");
2130
+ blocks.push(await buildTaskSummaryExcerpt(absPath, relPath, taskId));
2044
2131
  }
2045
2132
  return blocks.length > 0 ? blocks.join("\n\n---\n\n") : null;
2046
2133
  }
@@ -2387,7 +2474,7 @@ export async function buildReplanSlicePrompt(mid, midTitle, sid, sTitle, base) {
2387
2474
  const relPath = `${sRel}/tasks/${file}`;
2388
2475
  if (summary.frontmatter.blocker_discovered) {
2389
2476
  blockerTaskId = summary.frontmatter.id || file.replace(/-SUMMARY\.md$/i, "");
2390
- inlined.push(`### Blocker Task Summary: ${blockerTaskId}\nSource: \`${relPath}\`\n\n${content.trim()}`);
2477
+ inlined.push(await buildTaskSummaryExcerpt(absPath, relPath, blockerTaskId, { blocker: true }));
2391
2478
  }
2392
2479
  }
2393
2480
  }
@@ -30,7 +30,49 @@ import { getProjectResearchStatus } from "./project-research-policy.js";
30
30
  // Re-export so existing consumers of auto-recovery.ts keep working.
31
31
  export { resolveExpectedArtifactPath, diagnoseExpectedArtifact };
32
32
  export { classifyMilestoneSummaryContent, } from "./milestone-summary-classifier.js";
33
- // ─── Artifact Resolution & Verification ───────────────────────────────────────
33
+ export function refreshRecoveryDbForArtifact(unitType, unitId) {
34
+ if (unitType !== "plan-slice" && unitType !== "execute-task")
35
+ return { ok: true };
36
+ if (!isDbAvailable())
37
+ return { ok: true };
38
+ if (!refreshOpenDatabaseFromDisk()) {
39
+ return {
40
+ ok: false,
41
+ fatal: unitType === "execute-task",
42
+ reason: `${unitType}-db-refresh-failed`,
43
+ message: `Stuck recovery found ${unitType} ${unitId} artifacts, but the DB refresh failed.`,
44
+ };
45
+ }
46
+ if (unitType !== "execute-task")
47
+ return { ok: true };
48
+ const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
49
+ if (!mid || !sid || !tid) {
50
+ return {
51
+ ok: false,
52
+ fatal: true,
53
+ reason: "execute-task-invalid-unit-id",
54
+ message: `Stuck recovery found execute-task ${unitId} artifacts, but the unit id could not be parsed for DB verification.`,
55
+ };
56
+ }
57
+ const task = getTask(mid, sid, tid);
58
+ if (!task) {
59
+ return {
60
+ ok: false,
61
+ fatal: true,
62
+ reason: "execute-task-artifact-db-missing",
63
+ message: `Stuck recovery found execute-task ${unitId} artifacts, but no matching DB task row exists after refresh.`,
64
+ };
65
+ }
66
+ if (!isClosedStatus(task.status)) {
67
+ return {
68
+ ok: false,
69
+ fatal: true,
70
+ reason: "execute-task-artifact-db-mismatch",
71
+ message: `Stuck recovery found execute-task ${unitId} artifacts, but the DB task status is still '${task.status}' after refresh.`,
72
+ };
73
+ }
74
+ return { ok: true };
75
+ }
34
76
  function hasCapturedWorkflowPrefs(base) {
35
77
  const prefsPath = resolveExpectedArtifactPath("workflow-preferences", "WORKFLOW-PREFS", base);
36
78
  if (!prefsPath || !existsSync(prefsPath))
@@ -34,6 +34,7 @@ import { snapshotSkills } from "./skill-discovery.js";
34
34
  import { isDbAvailable, getMilestone, openDatabase, getDbStatus } from "./gsd-db.js";
35
35
  import { isClosedStatus } from "./status-guards.js";
36
36
  import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
37
+ import { auditOrphanedPreflightStashes } from "./orphan-stash-audit.js";
37
38
  import { debugLog, enableDebug, isDebugEnabled, getDebugLogPath, } from "./debug-logger.js";
38
39
  import { logWarning, logError } from "./workflow-logger.js";
39
40
  import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, } from "node:fs";
@@ -224,6 +225,139 @@ export function auditOrphanedMilestoneBranches(basePath, isolationMode) {
224
225
  }
225
226
  return { recovered, warnings };
226
227
  }
228
+ /**
229
+ * Pure decision function for picking which orphan milestone the auto-loop
230
+ * should resume the merge transition for. Extracted so it can be unit-tested
231
+ * without spinning up a git repo or a SQLite DB.
232
+ *
233
+ * Returns the lexicographically-greatest milestone id (e.g. "M002" beats
234
+ * "M001") whose branch is unmerged AND has commits ahead of main AND whose
235
+ * status is `complete`. Lex-ordering matches the project's M00x convention,
236
+ * which is the most-recently-completed milestone in practice.
237
+ * `isComplete` errors propagate; `commitsAhead` errors are treated as 0.
238
+ */
239
+ export function _selectResumableMilestone(branchNames, mergedBranches, isComplete, commitsAhead) {
240
+ const candidates = [];
241
+ for (const branch of branchNames) {
242
+ if (!branch.startsWith("milestone/"))
243
+ continue;
244
+ const milestoneId = branch.slice("milestone/".length);
245
+ if (mergedBranches.has(branch))
246
+ continue;
247
+ if (!isComplete(milestoneId))
248
+ continue;
249
+ let ahead = 0;
250
+ try {
251
+ ahead = commitsAhead(branch);
252
+ }
253
+ catch {
254
+ continue;
255
+ }
256
+ if (ahead <= 0)
257
+ continue;
258
+ candidates.push(milestoneId);
259
+ }
260
+ if (candidates.length === 0)
261
+ return null;
262
+ candidates.sort();
263
+ return candidates[candidates.length - 1];
264
+ }
265
+ /**
266
+ * Find the most-recent completed milestone whose branch still has unmerged
267
+ * commits ahead of the integration branch. Used by `bootstrapAutoSession`
268
+ * to seed `s.currentMilestoneId` so the auto-loop's transition guard at
269
+ * `phases.ts:730` fires on the first iteration after a process restart —
270
+ * without this, the in-memory-only `s.currentMilestoneId` is `null` after
271
+ * restart, the guard short-circuits, and the orphaned milestone branch
272
+ * never gets merged into main (#5538-followup).
273
+ *
274
+ * Returns null when isolation is `none`, the DB is unavailable, or no
275
+ * orphan candidate exists. All git failures degrade silently — startup
276
+ * must never block on this defensive lookup.
277
+ */
278
+ export function findUnmergedCompletedMilestone(basePath, isolationMode) {
279
+ if (isolationMode === "none")
280
+ return null;
281
+ if (!isDbAvailable())
282
+ return null;
283
+ let milestoneBranches;
284
+ try {
285
+ milestoneBranches = nativeBranchList(basePath, "milestone/*");
286
+ }
287
+ catch {
288
+ return null;
289
+ }
290
+ if (milestoneBranches.length === 0)
291
+ return null;
292
+ let mainBranch;
293
+ try {
294
+ mainBranch = nativeDetectMainBranch(basePath);
295
+ }
296
+ catch {
297
+ mainBranch = "main";
298
+ }
299
+ let mergedBranches;
300
+ try {
301
+ mergedBranches = new Set(nativeBranchListMerged(basePath, mainBranch, "milestone/*"));
302
+ }
303
+ catch {
304
+ mergedBranches = new Set();
305
+ }
306
+ return _selectResumableMilestone(milestoneBranches, mergedBranches, (milestoneId) => {
307
+ const row = getMilestone(milestoneId);
308
+ return !!row && row.status === "complete";
309
+ }, (branch) => nativeCommitCountBetween(basePath, mainBranch, branch));
310
+ }
311
+ /**
312
+ * Run `mergeAndExit` for a milestone whose worktree/branch finalization
313
+ * never completed in a prior session — the active-milestone in phase
314
+ * `complete` with a survivor `milestone/<id>` branch still around.
315
+ *
316
+ * Wraps the call in try/catch so a thrown error from `_mergeBranchMode`
317
+ * (made fail-loud in commit 68ef58a3c) is converted into a user-facing
318
+ * error notify instead of an unhandled exception that propagates through
319
+ * `bootstrapAutoSession` to the slash-command caller's `.catch` block.
320
+ *
321
+ * Returns `{ merged: true }` on success; `{ merged: false, error }` on
322
+ * throw — caller decides whether to abort bootstrap.
323
+ */
324
+ export function _finalizeSurvivorBranch(resolver, milestoneId, ui) {
325
+ ui.notify(`Milestone ${milestoneId} is complete but branch/worktree was not finalized. Running merge now.`, "info");
326
+ try {
327
+ resolver.mergeAndExit(milestoneId, { notify: ui.notify.bind(ui) });
328
+ return { merged: true };
329
+ }
330
+ catch (err) {
331
+ const msg = err instanceof Error ? err.message : String(err);
332
+ ui.notify(`Survivor-branch finalization for ${milestoneId} failed: ${msg}. Resolve manually and re-run /gsd auto.`, "error");
333
+ return { merged: false, error: err };
334
+ }
335
+ }
336
+ /**
337
+ * Merge a milestone whose DB row is `complete` but whose branch is still
338
+ * unmerged into the integration branch. Called from `bootstrapAutoSession`
339
+ * for orphans surfaced by `findUnmergedCompletedMilestone`.
340
+ *
341
+ * Notifies the user before and after, swallowing errors so a transient git
342
+ * failure never blocks bootstrap. Returns `{ merged: true }` when the
343
+ * underlying `mergeAndExit` completes; `{ merged: false, error }` on throw.
344
+ *
345
+ * Extracted to keep `bootstrapAutoSession` testable: the merge call and the
346
+ * notify shape are exercised against a mock resolver in
347
+ * `tests/orphan-merge-bootstrap.test.ts`.
348
+ */
349
+ export function _mergeOrphanCompletedMilestone(resolver, orphanId, ui) {
350
+ ui.notify(`Detected unmerged completed milestone ${orphanId}. Merging now.`, "info");
351
+ try {
352
+ resolver.mergeAndExit(orphanId, { notify: ui.notify.bind(ui) });
353
+ return { merged: true };
354
+ }
355
+ catch (err) {
356
+ const msg = err instanceof Error ? err.message : String(err);
357
+ ui.notify(`Could not merge orphan milestone ${orphanId}: ${msg}. Resolve manually and re-run /gsd auto.`, "warning");
358
+ return { merged: false, error: err };
359
+ }
360
+ }
227
361
  export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, requestedStepMode, deps, interrupted) {
228
362
  const { shouldUseWorktreeIsolation, registerSigtermHandler, lockBase, buildResolver, } = deps;
229
363
  const dirCheck = validateDirectory(base);
@@ -420,6 +554,33 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
420
554
  // Non-fatal — the audit is defensive, never block bootstrap
421
555
  logWarning("bootstrap", `orphaned milestone branch audit failed: ${err instanceof Error ? err.message : String(err)}`);
422
556
  }
557
+ // ── Orphaned preflight-stash audit (#5538-followup) ──
558
+ // Reapplies pre-merge stashes whose milestone is now complete but whose
559
+ // postflight pop was skipped by an interrupted merge in a prior session.
560
+ // Uses `git stash apply` (not pop) so the entry remains as a backup.
561
+ try {
562
+ if (isDbAvailable()) {
563
+ const stashAudit = auditOrphanedPreflightStashes(base, (milestoneId) => {
564
+ const row = getMilestone(milestoneId);
565
+ return !!row && isClosedStatus(row.status);
566
+ });
567
+ for (const entry of stashAudit.applied) {
568
+ ctx.ui.notify(`Orphan audit: applied preflight stash ${entry.stashRef} for completed milestone ${entry.milestoneId}. The stash entry is preserved as a backup.`, "info");
569
+ }
570
+ for (const msg of stashAudit.warnings) {
571
+ ctx.ui.notify(`Orphan audit: ${msg}`, "warning");
572
+ }
573
+ if (stashAudit.applied.length > 0) {
574
+ debugLog("orphan-stash-audit", {
575
+ applied: stashAudit.applied,
576
+ warnings: stashAudit.warnings,
577
+ });
578
+ }
579
+ }
580
+ }
581
+ catch (err) {
582
+ logWarning("bootstrap", `orphaned preflight-stash audit failed: ${err instanceof Error ? err.message : String(err)}`);
583
+ }
423
584
  let state = await deriveState(base);
424
585
  // Stale worktree state recovery (#654)
425
586
  if (state.activeMilestone &&
@@ -476,16 +637,46 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
476
637
  // hasSurvivorBranch after a successful promotion.
477
638
  if (decideSurvivorAction(hasSurvivorBranch, state.phase) === "finalize") {
478
639
  const mid = state.activeMilestone.id;
479
- ctx.ui.notify(`Milestone ${mid} is complete but branch/worktree was not finalized. Running merge now.`, "info");
480
- const resolver = buildResolver();
481
- resolver.mergeAndExit(mid, {
482
- notify: ctx.ui.notify.bind(ctx.ui),
483
- });
640
+ // Commit 68ef58a3c made `_mergeBranchMode` throw on wrong-branch
641
+ // instead of returning false silently. Wrap the call so the throw is
642
+ // converted into an error notify + clean bootstrap abort, not an
643
+ // unhandled exception propagating to the slash-command caller (#5549
644
+ // post-merge audit, R2).
645
+ const finalize = _finalizeSurvivorBranch(buildResolver(), mid, ctx.ui);
646
+ if (!finalize.merged) {
647
+ return releaseLockAndReturn();
648
+ }
484
649
  invalidateAllCaches();
485
650
  state = await deriveState(base);
486
651
  // Clear survivor flag — finalization is done
487
652
  hasSurvivorBranch = false;
488
653
  }
654
+ // ── Orphan-completed-milestone merge (#5538-followup) ──
655
+ // A process killed between `complete-milestone` (DB flip + SUMMARY write)
656
+ // and the loop's transition-guard merge strands the milestone branch
657
+ // forever: `s.currentMilestoneId` is in-memory only, so on the next
658
+ // bootstrap the guard at phases.ts:730 sees `mid === s.currentMilestoneId`
659
+ // and short-circuits.
660
+ //
661
+ // The earlier attempt at this fix seeded `s.currentMilestoneId` to the
662
+ // orphan id pre-state-derivation, but the unconditional assignment at
663
+ // line 948 (`s.currentMilestoneId = state.activeMilestone?.id ?? null`)
664
+ // immediately overwrote the seed. Active-merge is the more durable fix:
665
+ // call `mergeAndExit` directly during bootstrap, then re-derive state so
666
+ // the loop's normal flow continues without an in-memory hint.
667
+ //
668
+ // Mirrors the survivor-finalize block above. Failures degrade to a
669
+ // warning notify so a transient git error doesn't block bootstrap.
670
+ {
671
+ const orphan = findUnmergedCompletedMilestone(base, getIsolationMode(base));
672
+ if (orphan && orphan !== state.activeMilestone?.id) {
673
+ const result = _mergeOrphanCompletedMilestone(buildResolver(), orphan, ctx.ui);
674
+ if (result.merged) {
675
+ invalidateAllCaches();
676
+ state = await deriveState(base);
677
+ }
678
+ }
679
+ }
489
680
  const effectivePrefs = loadEffectiveGSDPreferences(base)?.preferences;
490
681
  const { shouldRunDeepProjectSetup } = await import("./auto-dispatch.js");
491
682
  const deepProjectStagePending = shouldRunDeepProjectSetup(state, effectivePrefs, base, { hasSurvivorBranch });
@@ -590,7 +781,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
590
781
  s.resourceVersionOnStart = readResourceVersion();
591
782
  s.pendingQuickTasks = [];
592
783
  s.currentUnit = null;
593
- s.currentMilestoneId = deepProjectStagePending ? null : state.activeMilestone?.id ?? null;
784
+ s.currentMilestoneId ??= deepProjectStagePending ? null : state.activeMilestone?.id ?? null;
594
785
  s.originalModelId = startModelSnapshot?.id ?? ctx.model?.id ?? null;
595
786
  s.originalModelProvider = startModelSnapshot?.provider ?? ctx.model?.provider ?? null;
596
787
  s.originalThinkingLevel = startThinkingSnapshot ?? null;