gsd-pi 2.81.0-dev.72a81bdf3 → 2.82.0-dev.20138ae42

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 (463) hide show
  1. package/README.md +50 -31
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/GSD-WORKFLOW.md +10 -1
  4. package/dist/resources/extensions/browser-tools/tools/screenshot.js +1 -0
  5. package/dist/resources/extensions/browser-tools/tools/zoom.js +1 -0
  6. package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
  7. package/dist/resources/extensions/cmux/index.js +5 -0
  8. package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
  9. package/dist/resources/extensions/gsd/auto/loop.js +5 -5
  10. package/dist/resources/extensions/gsd/auto/orchestrator.js +124 -6
  11. package/dist/resources/extensions/gsd/auto/phases.js +30 -1
  12. package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
  13. package/dist/resources/extensions/gsd/auto-dashboard.js +66 -1
  14. package/dist/resources/extensions/gsd/auto-dispatch.js +13 -6
  15. package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
  16. package/dist/resources/extensions/gsd/auto-post-unit.js +233 -127
  17. package/dist/resources/extensions/gsd/auto-prompts.js +13 -5
  18. package/dist/resources/extensions/gsd/auto-recovery.js +31 -1
  19. package/dist/resources/extensions/gsd/auto-start.js +85 -12
  20. package/dist/resources/extensions/gsd/auto-verification.js +28 -22
  21. package/dist/resources/extensions/gsd/auto-worktree.js +111 -1
  22. package/dist/resources/extensions/gsd/auto.js +158 -55
  23. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +25 -6
  24. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +9 -8
  25. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +9 -2
  26. package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +21 -9
  27. package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
  28. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -2
  29. package/dist/resources/extensions/gsd/clean-root-preflight.js +170 -8
  30. package/dist/resources/extensions/gsd/commands/catalog.js +4 -1
  31. package/dist/resources/extensions/gsd/commands/handlers/core.js +38 -1
  32. package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
  33. package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
  34. package/dist/resources/extensions/gsd/context-store.js +112 -0
  35. package/dist/resources/extensions/gsd/crash-recovery.js +31 -5
  36. package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
  37. package/dist/resources/extensions/gsd/db-writer.js +150 -84
  38. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
  39. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  40. package/dist/resources/extensions/gsd/doctor-git-checks.js +41 -6
  41. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
  42. package/dist/resources/extensions/gsd/doctor.js +2 -28
  43. package/dist/resources/extensions/gsd/export-html.js +27 -425
  44. package/dist/resources/extensions/gsd/git-service.js +39 -1
  45. package/dist/resources/extensions/gsd/gsd-db.js +1 -0
  46. package/dist/resources/extensions/gsd/guided-flow.js +93 -111
  47. package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
  48. package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
  49. package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
  50. package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
  51. package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
  52. package/dist/resources/extensions/gsd/markdown-renderer.js +6 -1
  53. package/dist/resources/extensions/gsd/md-importer.js +1 -1
  54. package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
  55. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
  56. package/dist/resources/extensions/gsd/migrate/command.js +5 -0
  57. package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
  58. package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
  59. package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
  60. package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
  61. package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
  62. package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
  63. package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
  64. package/dist/resources/extensions/gsd/pending-auto-start.js +52 -0
  65. package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
  66. package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
  67. package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
  68. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  69. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  70. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  71. package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
  72. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  73. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  74. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  75. package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
  76. package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  77. package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  78. package/dist/resources/extensions/gsd/prompts/system.md +2 -2
  79. package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
  80. package/dist/resources/extensions/gsd/smart-entry-routing.js +36 -0
  81. package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
  82. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
  83. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
  84. package/dist/resources/extensions/gsd/status-guards.js +4 -0
  85. package/dist/resources/extensions/gsd/templates/knowledge.md +2 -2
  86. package/dist/resources/extensions/gsd/templates/plan.md +8 -5
  87. package/dist/resources/extensions/gsd/templates/task-plan.md +4 -2
  88. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
  89. package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
  90. package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
  91. package/dist/resources/extensions/gsd/tools/plan-slice.js +89 -14
  92. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +119 -0
  93. package/dist/resources/extensions/gsd/unit-context-manifest.js +32 -10
  94. package/dist/resources/extensions/gsd/validation.js +23 -1
  95. package/dist/resources/extensions/gsd/verification-gate.js +68 -7
  96. package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
  97. package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
  98. package/dist/resources/extensions/gsd/worktree-lifecycle.js +54 -10
  99. package/dist/resources/extensions/shared/html-shell.js +388 -0
  100. package/dist/resources/extensions/subagent/index.js +448 -78
  101. package/dist/resources/extensions/subagent/launch.js +77 -0
  102. package/dist/resources/extensions/subagent/run-store.js +148 -0
  103. package/dist/resources/extensions/visual-brief/artifact-policy.js +29 -0
  104. package/dist/resources/extensions/visual-brief/extension-manifest.json +8 -0
  105. package/dist/resources/extensions/visual-brief/index.js +5 -0
  106. package/dist/resources/extensions/visual-brief/page-contract.js +124 -0
  107. package/dist/resources/extensions/visual-brief/prompts.js +140 -0
  108. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  109. package/dist/web/standalone/.next/BUILD_ID +1 -1
  110. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  111. package/dist/web/standalone/.next/build-manifest.json +3 -3
  112. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  113. package/dist/web/standalone/.next/react-loadable-manifest.json +3 -3
  114. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  116. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  124. package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  125. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  127. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
  128. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
  129. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  130. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -5
  131. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  132. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
  134. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  135. package/dist/web/standalone/.next/server/app/index.html +1 -1
  136. package/dist/web/standalone/.next/server/app/index.rsc +4 -7
  137. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -7
  139. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  140. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -5
  141. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
  142. package/dist/web/standalone/.next/server/app/page.js +2 -2
  143. package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
  144. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  146. package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
  147. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  151. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  152. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  153. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  154. package/dist/web/standalone/.next/static/chunks/2973.33f26573894b6153.js +2 -0
  155. package/dist/web/standalone/.next/static/chunks/{8359.e059d86b255fce1c.js → 8359.7eb3bb8f8ecf4c01.js} +2 -2
  156. package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
  157. package/dist/web/standalone/.next/static/chunks/{webpack-de742b64187e13fe.js → webpack-9a4db269f9ed63ad.js} +1 -1
  158. package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
  159. package/package.json +6 -5
  160. package/packages/contracts/dist/rpc.test.js +7 -0
  161. package/packages/contracts/dist/rpc.test.js.map +1 -1
  162. package/packages/contracts/dist/workflow.d.ts +21 -0
  163. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  164. package/packages/contracts/dist/workflow.js +24 -0
  165. package/packages/contracts/dist/workflow.js.map +1 -1
  166. package/packages/contracts/src/rpc.test.ts +8 -0
  167. package/packages/contracts/src/workflow.ts +24 -0
  168. package/packages/daemon/package.json +2 -2
  169. package/packages/mcp-server/README.md +14 -3
  170. package/packages/mcp-server/dist/workflow-tools.d.ts +0 -3
  171. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  172. package/packages/mcp-server/dist/workflow-tools.js +80 -0
  173. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  174. package/packages/mcp-server/package.json +2 -2
  175. package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
  176. package/packages/mcp-server/src/workflow-tools.test.ts +23 -1
  177. package/packages/mcp-server/src/workflow-tools.ts +168 -0
  178. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  179. package/packages/native/package.json +1 -1
  180. package/packages/native/tsconfig.json +2 -1
  181. package/packages/native/tsconfig.tsbuildinfo +1 -1
  182. package/packages/pi-agent-core/package.json +1 -1
  183. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  184. package/packages/pi-ai/dist/index.d.ts +2 -2
  185. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  186. package/packages/pi-ai/dist/index.js +1 -1
  187. package/packages/pi-ai/dist/index.js.map +1 -1
  188. package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
  189. package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
  190. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  191. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
  192. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
  193. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
  194. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
  195. package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
  196. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  197. package/packages/pi-ai/dist/providers/simple-options.js +5 -6
  198. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  199. package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
  200. package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
  201. package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
  202. package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
  203. package/packages/pi-ai/dist/providers/transform-messages.d.ts +11 -0
  204. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  205. package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
  206. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  207. package/packages/pi-ai/package.json +1 -1
  208. package/packages/pi-ai/src/index.ts +7 -2
  209. package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
  210. package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
  211. package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
  212. package/packages/pi-ai/src/providers/simple-options.ts +5 -6
  213. package/packages/pi-ai/src/providers/transform-messages.ts +24 -0
  214. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  215. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
  216. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
  217. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
  218. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
  219. package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
  220. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  221. package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
  222. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  223. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  224. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +24 -6
  225. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  226. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
  227. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
  228. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
  229. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
  230. package/packages/pi-coding-agent/package.json +1 -1
  231. package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
  232. package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
  233. package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
  234. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
  235. package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
  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 +5 -0
  239. package/packages/pi-tui/dist/tui.js.map +1 -1
  240. package/packages/pi-tui/package.json +1 -1
  241. package/packages/pi-tui/src/tui.ts +6 -0
  242. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  243. package/packages/rpc-client/package.json +1 -1
  244. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  245. package/pkg/package.json +1 -1
  246. package/src/resources/GSD-WORKFLOW.md +10 -1
  247. package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
  248. package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
  249. package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
  250. package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
  251. package/src/resources/extensions/cmux/index.ts +6 -0
  252. package/src/resources/extensions/gsd/auto/contracts.ts +59 -16
  253. package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
  254. package/src/resources/extensions/gsd/auto/loop.ts +8 -5
  255. package/src/resources/extensions/gsd/auto/orchestrator.ts +129 -6
  256. package/src/resources/extensions/gsd/auto/phases.ts +36 -1
  257. package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
  258. package/src/resources/extensions/gsd/auto-dashboard.ts +72 -1
  259. package/src/resources/extensions/gsd/auto-dispatch.ts +14 -6
  260. package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
  261. package/src/resources/extensions/gsd/auto-post-unit.ts +266 -139
  262. package/src/resources/extensions/gsd/auto-prompts.ts +13 -5
  263. package/src/resources/extensions/gsd/auto-recovery.ts +29 -0
  264. package/src/resources/extensions/gsd/auto-start.ts +92 -9
  265. package/src/resources/extensions/gsd/auto-verification.ts +36 -34
  266. package/src/resources/extensions/gsd/auto-worktree.ts +119 -1
  267. package/src/resources/extensions/gsd/auto.ts +167 -53
  268. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +33 -6
  269. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +9 -8
  270. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +10 -2
  271. package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +19 -7
  272. package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
  273. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +19 -3
  274. package/src/resources/extensions/gsd/clean-root-preflight.ts +174 -8
  275. package/src/resources/extensions/gsd/commands/catalog.ts +4 -1
  276. package/src/resources/extensions/gsd/commands/handlers/core.ts +41 -1
  277. package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
  278. package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
  279. package/src/resources/extensions/gsd/context-store.ts +120 -1
  280. package/src/resources/extensions/gsd/crash-recovery.ts +30 -4
  281. package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
  282. package/src/resources/extensions/gsd/db-writer.ts +167 -84
  283. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
  284. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  285. package/src/resources/extensions/gsd/doctor-git-checks.ts +44 -6
  286. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
  287. package/src/resources/extensions/gsd/doctor-types.ts +2 -0
  288. package/src/resources/extensions/gsd/doctor.ts +2 -27
  289. package/src/resources/extensions/gsd/export-html.ts +27 -427
  290. package/src/resources/extensions/gsd/git-service.ts +45 -1
  291. package/src/resources/extensions/gsd/gsd-db.ts +3 -0
  292. package/src/resources/extensions/gsd/guided-flow.ts +126 -128
  293. package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
  294. package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
  295. package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
  296. package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
  297. package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
  298. package/src/resources/extensions/gsd/markdown-renderer.ts +6 -1
  299. package/src/resources/extensions/gsd/md-importer.ts +1 -1
  300. package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
  301. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
  302. package/src/resources/extensions/gsd/migrate/command.ts +5 -0
  303. package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
  304. package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
  305. package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
  306. package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
  307. package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
  308. package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
  309. package/src/resources/extensions/gsd/native-git-bridge.ts +54 -12
  310. package/src/resources/extensions/gsd/pending-auto-start.ts +79 -0
  311. package/src/resources/extensions/gsd/post-execution-checks.ts +87 -2
  312. package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -1
  313. package/src/resources/extensions/gsd/prompt-loader.ts +1 -1
  314. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  315. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  316. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  317. package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
  318. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  319. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  320. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  321. package/src/resources/extensions/gsd/prompts/queue.md +4 -4
  322. package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  323. package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  324. package/src/resources/extensions/gsd/prompts/system.md +2 -2
  325. package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
  326. package/src/resources/extensions/gsd/smart-entry-routing.ts +77 -0
  327. package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
  328. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
  329. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
  330. package/src/resources/extensions/gsd/status-guards.ts +5 -0
  331. package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
  332. package/src/resources/extensions/gsd/templates/plan.md +8 -5
  333. package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
  334. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +71 -0
  335. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
  336. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +129 -0
  337. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +487 -4
  338. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +12 -11
  339. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +53 -2
  340. package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
  341. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +15 -1
  342. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +4 -4
  343. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
  344. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
  345. package/src/resources/extensions/gsd/tests/brief-command.test.ts +89 -0
  346. package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
  347. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +107 -2
  348. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
  349. package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
  350. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
  351. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
  352. package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
  353. package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
  354. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +43 -2
  355. package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
  356. package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
  357. package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
  358. package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
  359. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
  360. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +39 -0
  361. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
  362. package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +38 -0
  363. package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
  364. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
  365. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
  366. package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
  367. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +106 -0
  368. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +59 -11
  369. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
  370. package/src/resources/extensions/gsd/tests/guided-tool-contract.test.ts +65 -0
  371. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +7 -7
  372. package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
  373. package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
  374. package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
  375. package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +44 -0
  376. package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
  377. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +103 -1
  378. package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
  379. package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
  380. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
  381. package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
  382. package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
  383. package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
  384. package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
  385. package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
  386. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
  387. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
  388. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
  389. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
  390. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
  391. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
  392. package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
  393. package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +29 -5
  394. package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
  395. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
  396. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
  397. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
  398. package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
  399. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
  400. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
  401. package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
  402. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
  403. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +8 -0
  404. package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
  405. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +20 -1
  406. package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
  407. package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +46 -2
  408. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
  409. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
  410. package/src/resources/extensions/gsd/tests/smart-entry-routing.test.ts +113 -0
  411. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +53 -2
  412. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +6 -0
  413. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
  414. package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
  415. package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
  416. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +86 -7
  417. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
  418. package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +78 -0
  419. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +1 -1
  420. package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
  421. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
  422. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
  423. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
  424. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +25 -0
  425. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +54 -0
  426. package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
  427. package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
  428. package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
  429. package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
  430. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +135 -0
  431. package/src/resources/extensions/gsd/types.ts +1 -1
  432. package/src/resources/extensions/gsd/unit-context-manifest.ts +47 -11
  433. package/src/resources/extensions/gsd/validation.ts +23 -1
  434. package/src/resources/extensions/gsd/verification-gate.ts +78 -6
  435. package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
  436. package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
  437. package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
  438. package/src/resources/extensions/gsd/worktree-lifecycle.ts +61 -10
  439. package/src/resources/extensions/shared/html-shell.ts +412 -0
  440. package/src/resources/extensions/subagent/index.ts +567 -103
  441. package/src/resources/extensions/subagent/launch.ts +131 -0
  442. package/src/resources/extensions/subagent/run-store.ts +218 -0
  443. package/src/resources/extensions/subagent/tests/launch.test.ts +115 -0
  444. package/src/resources/extensions/subagent/tests/run-store.test.ts +111 -0
  445. package/src/resources/extensions/visual-brief/artifact-policy.ts +41 -0
  446. package/src/resources/extensions/visual-brief/extension-manifest.json +8 -0
  447. package/src/resources/extensions/visual-brief/index.ts +8 -0
  448. package/src/resources/extensions/visual-brief/page-contract.ts +136 -0
  449. package/src/resources/extensions/visual-brief/prompts.ts +183 -0
  450. package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +212 -0
  451. package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
  452. package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +0 -1
  453. package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
  454. package/dist/web/standalone/.next/static/css/54ec2745c1da488b.css +0 -1
  455. package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
  456. package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  457. package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
  458. package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
  459. package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  460. package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
  461. package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  462. /package/dist/web/standalone/.next/static/{rIkMv4YSNlfSeqmGqWVns → xRy4LqKSNKdT7y6ATYyEl}/_buildManifest.js +0 -0
  463. /package/dist/web/standalone/.next/static/{rIkMv4YSNlfSeqmGqWVns → xRy4LqKSNKdT7y6ATYyEl}/_ssgManifest.js +0 -0
@@ -1,7 +1,24 @@
1
1
  import { describe, test } from "node:test";
2
2
  import assert from "node:assert/strict";
3
- import { mapContentBlock, parseMcpToolName, PartialMessageBuilder } from "../partial-builder.ts";
4
- import type { BetaContentBlock, BetaRawMessageStreamEvent } from "../sdk-types.ts";
3
+ import { mapContentBlock, mapUsage, parseMcpToolName, PartialMessageBuilder } from "../partial-builder.ts";
4
+ import type { BetaContentBlock, BetaRawMessageStreamEvent, NonNullableUsage } from "../sdk-types.ts";
5
+
6
+ describe("mapUsage", () => {
7
+ test("excludes cumulative cache reads from context-sized totalTokens (#5243)", () => {
8
+ const usage: NonNullableUsage = {
9
+ input_tokens: 150_000,
10
+ output_tokens: 2_000,
11
+ cache_read_input_tokens: 900_000,
12
+ cache_creation_input_tokens: 3_000,
13
+ };
14
+
15
+ const mapped = mapUsage(usage, 1.23);
16
+
17
+ assert.equal(mapped.cacheRead, 900_000);
18
+ assert.equal(mapped.totalTokens, 155_000);
19
+ assert.equal(mapped.cost.total, 1.23);
20
+ });
21
+ });
5
22
 
6
23
  describe("PartialMessageBuilder — malformed tool arguments (#2574)", () => {
7
24
  /**
@@ -374,6 +374,12 @@ export class CmuxClient {
374
374
  const stdout = await this.runAsync(["send-surface", "--surface", surfaceId, payload]);
375
375
  return stdout !== null;
376
376
  }
377
+
378
+ // Send Ctrl-C (ETX) to a surface to interrupt the running command.
379
+ async sendInterrupt(surfaceId: string): Promise<boolean> {
380
+ const stdout = await this.runAsync(["send-surface", "--surface", surfaceId, "\x03"]);
381
+ return stdout !== null;
382
+ }
377
383
  }
378
384
 
379
385
  export function syncCmuxSidebar(preferences: CmuxPreferences | undefined, state: CmuxState): void {
@@ -2,27 +2,31 @@
2
2
  // File Purpose: Auto Orchestration module interfaces and ADR-015 invariant adapter contracts.
3
3
 
4
4
  import type { GSDState } from "../types.js";
5
+ import type { MinimalModelRegistry } from "../context-budget.js";
5
6
 
6
7
  export interface AutoSessionContext {
7
8
  basePath: string;
8
9
  trigger: "guided-flow" | "resume" | "auto-loop" | "manual";
9
10
  }
10
11
 
12
+ export interface UnitRef {
13
+ unitType: string;
14
+ unitId: string;
15
+ }
16
+
11
17
  export interface AutoStatus {
12
18
  phase: "idle" | "running" | "paused" | "stopped" | "error";
13
- activeUnit?: {
14
- unitType: string;
15
- unitId: string;
16
- };
19
+ activeUnit?: UnitRef;
17
20
  lastTransitionAt?: number;
18
21
  transitionCount: number;
19
22
  }
20
23
 
21
- export interface AutoAdvanceResult {
22
- kind: "advanced" | "blocked" | "paused" | "stopped" | "error";
23
- reason?: string;
24
- stateSnapshot?: GSDState;
25
- }
24
+ export type AutoAdvanceResult =
25
+ | { kind: "advanced"; unit: UnitRef; stateSnapshot: GSDState }
26
+ | { kind: "blocked"; reason: string; action: "pause" | "stop"; stateSnapshot?: GSDState }
27
+ | { kind: "stopped"; reason: string; stateSnapshot?: GSDState }
28
+ | { kind: "paused"; reason: string }
29
+ | { kind: "error"; reason: string };
26
30
 
27
31
  export interface AutoOrchestrationModule {
28
32
  start(sessionContext: AutoSessionContext): Promise<AutoAdvanceResult>;
@@ -33,12 +37,30 @@ export interface AutoOrchestrationModule {
33
37
  }
34
38
 
35
39
  export interface DispatchAdapter {
36
- decideNextUnit(input: { stateSnapshot: GSDState }): Promise<{
37
- unitType: string;
38
- unitId: string;
39
- reason: string;
40
- preconditions: string[];
41
- } | null>;
40
+ decideNextUnit(input: {
41
+ stateSnapshot: GSDState;
42
+ /** Mirrors `DispatchContext.structuredQuestionsAvailable` — "true"/"false" string per the dispatch contract. */
43
+ structuredQuestionsAvailable?: "true" | "false";
44
+ /** Session model context window in tokens, forwarded to the budget engine. */
45
+ sessionContextWindow?: number;
46
+ /** Session model provider, used for provider-specific effective context windows. */
47
+ sessionProvider?: string;
48
+ /** Model registry for executor-model lookups inside the budget engine. */
49
+ modelRegistry?: MinimalModelRegistry;
50
+ }): Promise<
51
+ | {
52
+ kind: "blocked";
53
+ reason: string;
54
+ action: "pause" | "stop";
55
+ }
56
+ | {
57
+ unitType: string;
58
+ unitId: string;
59
+ reason: string;
60
+ preconditions: string[];
61
+ }
62
+ | null
63
+ >;
42
64
  }
43
65
 
44
66
  export interface RecoveryAdapter {
@@ -70,11 +92,31 @@ export interface WorktreeAdapter {
70
92
  cleanupOnStop(reason: string): Promise<void>;
71
93
  }
72
94
 
95
+ export type HealthGateResult =
96
+ | { kind: "pass"; fixesApplied?: readonly string[] }
97
+ | { kind: "fail"; reason: string }
98
+ | { kind: "threw"; error: unknown };
99
+
73
100
  export interface HealthAdapter {
74
- preAdvanceGate(): Promise<{ allow: boolean; reason?: string }>;
101
+ checkResourcesStale(): string | null;
102
+ preAdvanceGate(): Promise<HealthGateResult>;
75
103
  postAdvanceRecord(result: AutoAdvanceResult): Promise<void>;
76
104
  }
77
105
 
106
+ export interface UokGateInput {
107
+ gateId: string;
108
+ gateType: "policy" | "execution";
109
+ outcome: "pass" | "fail" | "manual-attention";
110
+ failureClass: "none" | "policy" | "manual-attention";
111
+ rationale: string;
112
+ findings?: string;
113
+ milestoneId?: string;
114
+ }
115
+
116
+ export interface UokGateAdapter {
117
+ emit(input: UokGateInput): Promise<void>;
118
+ }
119
+
78
120
  export interface RuntimePersistenceAdapter {
79
121
  ensureLockOwnership(): Promise<void>;
80
122
  journalTransition(event: {
@@ -101,4 +143,5 @@ export interface AutoOrchestratorDeps {
101
143
  health: HealthAdapter;
102
144
  runtime: RuntimePersistenceAdapter;
103
145
  notifications: NotificationAdapter;
146
+ uokGate: UokGateAdapter;
104
147
  }
@@ -7,9 +7,14 @@
7
7
  */
8
8
 
9
9
  /**
10
- * Error codes indicating infrastructure failures that cannot be recovered by
11
- * retrying. Each retry re-dispatches the unit at full LLM cost, so we bail
12
- * immediately rather than burning budget on guaranteed failures.
10
+ * Error codes indicating infrastructure-level failures from the OS,
11
+ * filesystem, or network. This set includes permanent resource failures
12
+ * (ENOSPC, ENOMEM, EROFS), transient resource exhaustion (EAGAIN, ENOBUFS),
13
+ * and network/offline errors (ECONNREFUSED, ENOTFOUND, ENETUNREACH).
14
+ *
15
+ * Transient git failures are retried separately through
16
+ * TRANSIENT_GIT_RETRY_CODES in native-git-bridge.ts before escalating to the
17
+ * auto-loop.
13
18
  */
14
19
  export const INFRA_ERROR_CODES: ReadonlySet<string> = new Set([
15
20
  "ENOSPC", // disk full
@@ -19,6 +24,7 @@ export const INFRA_ERROR_CODES: ReadonlySet<string> = new Set([
19
24
  "EMFILE", // too many open files (process)
20
25
  "ENFILE", // too many open files (system)
21
26
  "EAGAIN", // resource temporarily unavailable (resource exhaustion)
27
+ "ENOBUFS", // no buffer space available (transient pipe exhaustion)
22
28
  "ECONNREFUSED", // connection refused (offline / local server down)
23
29
  "ENOTFOUND", // DNS lookup failed (offline / no network)
24
30
  "ENETUNREACH", // network unreachable (offline / no route)
@@ -78,7 +78,10 @@ import { createWorkflowTurnReporter } from "./workflow-turn-reporter.js";
78
78
  import { validateWorkflowSessionLock } from "./workflow-session-lock.js";
79
79
  import { dequeueSidecarItem } from "./workflow-sidecar-queue.js";
80
80
  import { maintainWorkerHeartbeat } from "./workflow-worker-heartbeat.js";
81
- import { measureMemoryPressure } from "./workflow-memory-pressure.js";
81
+ import {
82
+ measureMemoryPressure,
83
+ shouldCheckMemoryPressure,
84
+ } from "./workflow-memory-pressure.js";
82
85
  import { buildSidecarIterationData } from "./workflow-sidecar-iteration.js";
83
86
  import {
84
87
  createExecutionGraphUnitDispatchDeps,
@@ -203,9 +206,9 @@ function logCustomVerifyRetrySaveFailure(err: unknown): void {
203
206
  }
204
207
 
205
208
  // ── Memory pressure monitoring (#3331) ──────────────────────────────────
206
- // Check heap usage every N iterations and trigger graceful shutdown before
207
- // the OS OOM killer sends SIGKILL. The threshold is 90% of the V8 heap
208
- // limit (--max-old-space-size or default ~1.5-4GB depending on platform).
209
+ // Check heap usage on session startup, then every N iterations, and trigger
210
+ // graceful shutdown before the OS OOM killer sends SIGKILL. The threshold is
211
+ // 90% of the V8 heap limit (--max-old-space-size or default ~1.5-4GB depending on platform).
209
212
  const MEMORY_CHECK_INTERVAL = 5; // check every 5 iterations
210
213
  const MAX_CUSTOM_ENGINE_VERIFY_RETRIES = 3;
211
214
 
@@ -372,7 +375,7 @@ export async function autoLoop(
372
375
 
373
376
  // ── Memory pressure check (#3331) ──
374
377
  // Graceful shutdown before OOM killer sends SIGKILL.
375
- if (iteration % MEMORY_CHECK_INTERVAL === 0) {
378
+ if (shouldCheckMemoryPressure(iteration, MEMORY_CHECK_INTERVAL)) {
376
379
  const mem = measureMemoryPressure();
377
380
  debugLog("autoLoop", { phase: "memory-check", ...mem });
378
381
  const memoryDecision = decideMemoryPressure({ ...mem, iteration });
@@ -7,6 +7,16 @@ function now(): number {
7
7
  return Date.now();
8
8
  }
9
9
 
10
+ /**
11
+ * Size of the dispatch-decision ring buffer used by the Auto Orchestration
12
+ * module's stuck-loop detector. When the same `${unitType}:${unitId}` key
13
+ * fills the window, advance() blocks with `action: "stop"`.
14
+ *
15
+ * Mirrors the legacy `STUCK_WINDOW_SIZE` in auto/phases.ts so behaviour is
16
+ * preserved across the eventual cutover (issue #5791).
17
+ */
18
+ export const STUCK_WINDOW_SIZE = 6;
19
+
10
20
  export class AutoOrchestrator implements AutoOrchestrationModule {
11
21
  private status: AutoStatus = {
12
22
  phase: "idle",
@@ -14,6 +24,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
14
24
  };
15
25
  private readonly deps: AutoOrchestratorDeps;
16
26
  private lastAdvanceKey: string | null = null;
27
+ private dispatchKeyWindow: string[] = [];
17
28
 
18
29
  public constructor(deps: AutoOrchestratorDeps) {
19
30
  this.deps = deps;
@@ -21,6 +32,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
21
32
 
22
33
  public async start(_sessionContext: AutoSessionContext): Promise<AutoAdvanceResult> {
23
34
  this.lastAdvanceKey = null;
35
+ this.dispatchKeyWindow = [];
24
36
  this.status.phase = "running";
25
37
  this.bumpTransition();
26
38
  await this.deps.runtime.journalTransition({ name: "start" });
@@ -31,19 +43,72 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
31
43
  public async advance(): Promise<AutoAdvanceResult> {
32
44
  try {
33
45
  await this.deps.runtime.ensureLockOwnership();
46
+
47
+ const staleMsg = this.deps.health.checkResourcesStale();
48
+ if (staleMsg) {
49
+ await this.deps.uokGate.emit({
50
+ gateId: "resource-version-guard",
51
+ gateType: "policy",
52
+ outcome: "fail",
53
+ failureClass: "policy",
54
+ rationale: "resource version guard blocked dispatch",
55
+ findings: staleMsg,
56
+ });
57
+ const blocked: AutoAdvanceResult = { kind: "blocked", reason: staleMsg, action: "stop" };
58
+ await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
59
+ await this.deps.health.postAdvanceRecord(blocked);
60
+ return blocked;
61
+ }
62
+ await this.deps.uokGate.emit({
63
+ gateId: "resource-version-guard",
64
+ gateType: "policy",
65
+ outcome: "pass",
66
+ failureClass: "none",
67
+ rationale: "resource version guard passed",
68
+ });
69
+
34
70
  const gate = await this.deps.health.preAdvanceGate();
35
- if (!gate.allow) {
36
- const blocked: AutoAdvanceResult = { kind: "blocked", reason: gate.reason ?? "health gate blocked" };
71
+ if (gate.kind === "fail") {
72
+ await this.deps.uokGate.emit({
73
+ gateId: "pre-dispatch-health-gate",
74
+ gateType: "execution",
75
+ outcome: "manual-attention",
76
+ failureClass: "manual-attention",
77
+ rationale: "pre-dispatch health gate blocked dispatch",
78
+ findings: gate.reason,
79
+ });
80
+ const blocked: AutoAdvanceResult = { kind: "blocked", reason: gate.reason, action: "pause" };
37
81
  await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
38
82
  await this.deps.health.postAdvanceRecord(blocked);
39
83
  return blocked;
40
84
  }
85
+ if (gate.kind === "threw") {
86
+ await this.deps.uokGate.emit({
87
+ gateId: "pre-dispatch-health-gate",
88
+ gateType: "execution",
89
+ outcome: "manual-attention",
90
+ failureClass: "manual-attention",
91
+ rationale: "pre-dispatch health gate threw unexpectedly",
92
+ findings: String(gate.error),
93
+ });
94
+ // intentional fall-through: matches runPreDispatch behaviour
95
+ } else {
96
+ await this.deps.uokGate.emit({
97
+ gateId: "pre-dispatch-health-gate",
98
+ gateType: "execution",
99
+ outcome: "pass",
100
+ failureClass: "none",
101
+ rationale: "pre-dispatch health gate passed",
102
+ findings: gate.fixesApplied?.join(", ") ?? "",
103
+ });
104
+ }
41
105
 
42
106
  const reconciliation = await this.deps.stateReconciliation.reconcileBeforeDispatch();
43
107
  if (!reconciliation.ok || !reconciliation.stateSnapshot) {
44
108
  const blocked: AutoAdvanceResult = {
45
109
  kind: "blocked",
46
- reason: reconciliation.reason,
110
+ reason: reconciliation.reason ?? "state reconciliation produced no snapshot",
111
+ action: "pause",
47
112
  stateSnapshot: reconciliation.stateSnapshot,
48
113
  };
49
114
  await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
@@ -57,15 +122,64 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
57
122
  this.status.phase = "stopped";
58
123
  this.status.activeUnit = undefined;
59
124
  this.lastAdvanceKey = null;
125
+ this.dispatchKeyWindow = [];
60
126
  this.bumpTransition();
61
127
  await this.deps.runtime.journalTransition({ name: "advance-stopped", reason: stopped.reason });
62
128
  await this.deps.health.postAdvanceRecord(stopped);
63
129
  return stopped;
64
130
  }
131
+ if (!("unitType" in decision)) {
132
+ const blocked: AutoAdvanceResult = {
133
+ kind: "blocked",
134
+ reason: decision.reason,
135
+ action: decision.action,
136
+ stateSnapshot: reconciliation.stateSnapshot,
137
+ };
138
+ await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
139
+ await this.deps.health.postAdvanceRecord(blocked);
140
+ return blocked;
141
+ }
65
142
 
66
143
  const nextKey = `${decision.unitType}:${decision.unitId}`;
67
- if (this.lastAdvanceKey === nextKey) {
68
- const blocked: AutoAdvanceResult = { kind: "blocked", reason: "idempotent advance: unit already active" };
144
+
145
+ // Record every dispatch decision in the ring buffer before pre-flight
146
+ // checks so the stuck-loop detector observes the full decision history
147
+ // (including decisions that idempotency would otherwise short-circuit).
148
+ // The ring is capped at STUCK_WINDOW_SIZE and evicts oldest-first.
149
+ this.dispatchKeyWindow.push(nextKey);
150
+ if (this.dispatchKeyWindow.length > STUCK_WINDOW_SIZE) {
151
+ this.dispatchKeyWindow.shift();
152
+ }
153
+
154
+ // Idempotency: same key as immediately previous successful advance.
155
+ // This is the soft, fast-path block kept from #5786. It only fires when
156
+ // the ring is NOT yet saturated for this key — once the ring is full of
157
+ // `nextKey`, the stuck-loop verdict takes precedence (see below). Both
158
+ // checks coexist: idempotency for the common immediate-repeat case,
159
+ // stuck-loop for the saturated-window case.
160
+ const matchingCount = this.dispatchKeyWindow.filter((k) => k === nextKey).length;
161
+ if (this.lastAdvanceKey === nextKey && matchingCount < STUCK_WINDOW_SIZE) {
162
+ const blocked: AutoAdvanceResult = { kind: "blocked", reason: "idempotent advance: unit already active", action: "stop" };
163
+ await this.deps.runtime.journalTransition({
164
+ name: "advance-blocked",
165
+ reason: blocked.reason,
166
+ unitType: decision.unitType,
167
+ unitId: decision.unitId,
168
+ });
169
+ await this.deps.health.postAdvanceRecord(blocked);
170
+ return blocked;
171
+ }
172
+
173
+ // Stuck-loop detection: when the ring is saturated with copies of
174
+ // `nextKey` (count >= STUCK_WINDOW_SIZE), the orchestrator has been
175
+ // picking the same unit across the whole window and must hard-stop with
176
+ // a diagnosable reason.
177
+ if (matchingCount >= STUCK_WINDOW_SIZE) {
178
+ const blocked: AutoAdvanceResult = {
179
+ kind: "blocked",
180
+ reason: `stuck-loop: ${nextKey} picked ${matchingCount} times`,
181
+ action: "stop",
182
+ };
69
183
  await this.deps.runtime.journalTransition({
70
184
  name: "advance-blocked",
71
185
  reason: blocked.reason,
@@ -81,6 +195,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
81
195
  const blocked: AutoAdvanceResult = {
82
196
  kind: "blocked",
83
197
  reason: contract.reason,
198
+ action: "pause",
84
199
  stateSnapshot: reconciliation.stateSnapshot,
85
200
  };
86
201
  await this.deps.runtime.journalTransition({
@@ -98,6 +213,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
98
213
  const blocked: AutoAdvanceResult = {
99
214
  kind: "blocked",
100
215
  reason: worktree.reason,
216
+ action: "pause",
101
217
  stateSnapshot: reconciliation.stateSnapshot,
102
218
  };
103
219
  await this.deps.runtime.journalTransition({
@@ -123,7 +239,11 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
123
239
  });
124
240
  await this.deps.worktree.syncAfterUnit(decision.unitType, decision.unitId);
125
241
 
126
- const advanced: AutoAdvanceResult = { kind: "advanced", stateSnapshot: reconciliation.stateSnapshot };
242
+ const advanced: AutoAdvanceResult = {
243
+ kind: "advanced",
244
+ unit: { unitType: decision.unitType, unitId: decision.unitId },
245
+ stateSnapshot: reconciliation.stateSnapshot,
246
+ };
127
247
  await this.deps.health.postAdvanceRecord(advanced);
128
248
  return advanced;
129
249
  } catch (error) {
@@ -148,6 +268,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
148
268
 
149
269
  if (result.kind === "stopped") {
150
270
  this.lastAdvanceKey = null;
271
+ this.dispatchKeyWindow = [];
151
272
  this.status.activeUnit = undefined;
152
273
  }
153
274
  this.bumpTransition();
@@ -173,6 +294,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
173
294
 
174
295
  public async resume(): Promise<AutoAdvanceResult> {
175
296
  this.lastAdvanceKey = null;
297
+ this.dispatchKeyWindow = [];
176
298
  this.status.phase = "running";
177
299
  this.bumpTransition();
178
300
  await this.deps.runtime.journalTransition({ name: "resume" });
@@ -188,6 +310,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
188
310
  this.status.phase = "stopped";
189
311
  this.status.activeUnit = undefined;
190
312
  this.lastAdvanceKey = null;
313
+ this.dispatchKeyWindow = [];
191
314
  this.bumpTransition();
192
315
  await this.deps.runtime.journalTransition({ name: "stop", reason });
193
316
  await this.deps.notifications.notifyLifecycle({ name: "stop", detail: reason });
@@ -77,6 +77,7 @@ import { resolveManifest } from "../unit-context-manifest.js";
77
77
  import { createWorktreeSafetyModule, type WorktreeSafetyResult } from "../worktree-safety.js";
78
78
  import { isSuspiciousGhostCompletion } from "../auto-unit-closeout.js";
79
79
  import { decideVerificationRetry, verificationRetryKey } from "./verification-retry-policy.js";
80
+ import { buildPhaseHandoffOutcome, setAutoOutcomeWidget } from "../auto-dashboard.js";
80
81
 
81
82
  // ─── Path Comparison Helper ───────────────────────────────────────────────
82
83
  /** Compare two paths for physical identity, tolerating trailing slashes and symlinks. */
@@ -1327,9 +1328,15 @@ export async function runDispatch(
1327
1328
  }
1328
1329
 
1329
1330
  const guardBasePath = _resolveDispatchGuardBasePath(s);
1331
+ let mainBranch = "main";
1332
+ try {
1333
+ mainBranch = deps.getMainBranch(guardBasePath);
1334
+ } catch (err) {
1335
+ debugLog("autoLoop", { phase: "getMainBranch-failed", error: String(err) });
1336
+ }
1330
1337
  const priorSliceBlocker = deps.getPriorSliceCompletionBlocker(
1331
1338
  guardBasePath,
1332
- deps.getMainBranch(guardBasePath),
1339
+ mainBranch,
1333
1340
  unitType,
1334
1341
  unitId,
1335
1342
  );
@@ -2233,6 +2240,20 @@ export async function runUnitPhase(
2233
2240
  await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
2234
2241
  return { action: "break", reason: "session-timeout" };
2235
2242
  }
2243
+ if (
2244
+ unitResult.errorContext?.isTransient &&
2245
+ errorCategory === "aborted"
2246
+ ) {
2247
+ ctx.ui.notify(
2248
+ `Unit ${unitType} ${unitId} was aborted by the user. Pausing auto-mode (recoverable).`,
2249
+ "warning",
2250
+ );
2251
+ debugLog("autoLoop", { phase: "unit-aborted-transient-pause", unitType, unitId, category: errorCategory });
2252
+ await deps.pauseAuto(ctx, pi);
2253
+ await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
2254
+ await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
2255
+ return { action: "break", reason: "unit-aborted-pause" };
2256
+ }
2236
2257
  // All other cancelled states (structural errors, non-transient failures): hard stop
2237
2258
  if (s.currentUnit) {
2238
2259
  await deps.closeoutUnit(
@@ -2582,6 +2603,20 @@ export async function runFinalize(
2582
2603
  lastProgressAt: Date.now(),
2583
2604
  lastProgressKind: "finalize-success",
2584
2605
  });
2606
+ if (
2607
+ !preUnitSnapshot.type.startsWith("hook/") &&
2608
+ preUnitSnapshot.type !== "custom-step" &&
2609
+ preUnitSnapshot.type !== "complete-milestone"
2610
+ ) {
2611
+ setAutoOutcomeWidget(ctx, {
2612
+ ...buildPhaseHandoffOutcome({
2613
+ unitType: preUnitSnapshot.type,
2614
+ unitId: preUnitSnapshot.id,
2615
+ agentEndMessages: s.lastUnitAgentEndMessages,
2616
+ }),
2617
+ startedAt: s.autoStartTime,
2618
+ });
2619
+ }
2585
2620
  }
2586
2621
  s.currentUnit = null;
2587
2622
  clearCurrentPhase();
@@ -19,6 +19,19 @@ export interface MeasureMemoryPressureDeps {
19
19
  heapLimitBytes: () => number;
20
20
  }
21
21
 
22
+ /**
23
+ * Returns true on auto-mode startup, then every configured interval.
24
+ *
25
+ * Iteration 1 is checked explicitly so early session memory pressure cannot
26
+ * bypass the periodic interval guard.
27
+ */
28
+ export function shouldCheckMemoryPressure(iteration: number, interval: number): boolean {
29
+ if (!Number.isInteger(interval) || interval <= 0) {
30
+ throw new Error("Memory pressure check interval must be a positive integer");
31
+ }
32
+ return iteration === 1 || iteration % interval === 0;
33
+ }
34
+
22
35
  function defaultHeapLimitBytes(): number {
23
36
  const v8 = require("node:v8") as {
24
37
  getHeapStatistics?: () => { heap_size_limit?: number };
@@ -120,6 +120,26 @@ export interface AutoOutcomeSurfaceSnapshot {
120
120
  startedAt?: number;
121
121
  }
122
122
 
123
+ export function buildPhaseHandoffOutcome(input: {
124
+ unitType: string;
125
+ unitId: string;
126
+ agentEndMessages?: unknown[] | null;
127
+ }): AutoOutcomeSurfaceSnapshot {
128
+ const phase = unitPhaseLabel(input.unitType);
129
+ const detail =
130
+ extractLastAssistantSummary(input.agentEndMessages) ??
131
+ `Completed ${unitVerb(input.unitType)} ${input.unitId}.`;
132
+
133
+ return {
134
+ status: "complete",
135
+ title: `${phase} complete`,
136
+ detail,
137
+ unitLabel: `${unitVerb(input.unitType)} ${input.unitId}`,
138
+ nextAction: "Preparing the next phase. Review this handoff while the next session starts.",
139
+ commands: ["/gsd status for overview", "/gsd visualize to inspect", "/gsd notifications for history"],
140
+ };
141
+ }
142
+
123
143
  // ─── Unit Description Helpers ─────────────────────────────────────────────────
124
144
 
125
145
  export function unitVerb(unitType: string): string {
@@ -631,7 +651,6 @@ export function updateProgressWidget(
631
651
  tierBadge?: string,
632
652
  ): void {
633
653
  if (!ctx.hasUI) return;
634
- ctx.ui.setWidget("gsd-outcome", undefined);
635
654
 
636
655
  // Welcome header is a startup-only banner — permanently suppress it once
637
656
  // auto-mode activates. The dashboard widget owns all status from here.
@@ -1145,3 +1164,55 @@ function normalizeRollupText(value: string | null | undefined): string | null {
1145
1164
  if (!clean || clean === "(none)" || clean === "None." || clean === "Not provided.") return null;
1146
1165
  return clean;
1147
1166
  }
1167
+
1168
+ function isAssistantMessage(value: unknown): boolean {
1169
+ if (!value || typeof value !== "object") return false;
1170
+ const record = value as Record<string, unknown>;
1171
+ if (record.role === "assistant") return true;
1172
+
1173
+ const message = record.message;
1174
+ if (message && typeof message === "object") {
1175
+ return (message as Record<string, unknown>).role === "assistant";
1176
+ }
1177
+
1178
+ return false;
1179
+ }
1180
+
1181
+ function extractLastAssistantSummary(messages: unknown[] | null | undefined): string | null {
1182
+ if (!messages || messages.length === 0) return null;
1183
+ for (let i = messages.length - 1; i >= 0; i--) {
1184
+ if (!isAssistantMessage(messages[i])) continue;
1185
+ const text = extractMessageText(messages[i]);
1186
+ const clean = normalizeRollupText(text);
1187
+ if (clean) return truncateToWidth(clean, 220, "…");
1188
+ }
1189
+ return null;
1190
+ }
1191
+
1192
+ function extractMessageText(value: unknown): string | null {
1193
+ if (typeof value === "string") return value;
1194
+ if (!value || typeof value !== "object") return null;
1195
+
1196
+ const record = value as Record<string, unknown>;
1197
+ if (typeof record.content === "string") return record.content;
1198
+
1199
+ const message = record.message;
1200
+ if (message && typeof message === "object") {
1201
+ return extractMessageText(message);
1202
+ }
1203
+
1204
+ const content = record.content;
1205
+ if (Array.isArray(content)) {
1206
+ const parts = content
1207
+ .map((part) => {
1208
+ if (typeof part === "string") return part;
1209
+ if (!part || typeof part !== "object") return "";
1210
+ const partRecord = part as Record<string, unknown>;
1211
+ return typeof partRecord.text === "string" ? partRecord.text : "";
1212
+ })
1213
+ .filter(Boolean);
1214
+ return parts.length > 0 ? parts.join(" ") : null;
1215
+ }
1216
+
1217
+ return null;
1218
+ }