gsd-pi 2.76.0-dev.fe143342a → 2.77.0-dev.1d17f366c

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 (597) hide show
  1. package/README.md +17 -35
  2. package/dist/claude-cli-check.js +32 -3
  3. package/dist/cli-web-branch.d.ts +1 -0
  4. package/dist/cli-web-branch.js +3 -0
  5. package/dist/cli.js +38 -2
  6. package/dist/extension-discovery.d.ts +6 -0
  7. package/dist/extension-discovery.js +37 -0
  8. package/dist/extension-registry.d.ts +3 -0
  9. package/dist/extension-sort.d.ts +18 -0
  10. package/dist/extension-sort.js +114 -0
  11. package/dist/extension-validator.d.ts +47 -0
  12. package/dist/extension-validator.js +127 -0
  13. package/dist/loader.js +35 -7
  14. package/dist/onboarding.js +45 -0
  15. package/dist/provider-migrations.d.ts +18 -0
  16. package/dist/provider-migrations.js +14 -0
  17. package/dist/resources/extensions/claude-code-cli/readiness.js +4 -3
  18. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +78 -59
  19. package/dist/resources/extensions/cmux/index.js +20 -0
  20. package/dist/resources/extensions/github-sync/templates.js +103 -0
  21. package/dist/resources/extensions/google-search/extension-manifest.json +5 -4
  22. package/dist/resources/extensions/google-search/index.js +3 -375
  23. package/dist/resources/extensions/gsd/abandon-detect.js +44 -0
  24. package/dist/resources/extensions/gsd/auto/loop.js +90 -2
  25. package/dist/resources/extensions/gsd/auto/phases.js +95 -21
  26. package/dist/resources/extensions/gsd/auto/resolve.js +24 -0
  27. package/dist/resources/extensions/gsd/auto/run-unit.js +48 -4
  28. package/dist/resources/extensions/gsd/auto/session.js +18 -1
  29. package/dist/resources/extensions/gsd/auto/turn-epoch.js +95 -0
  30. package/dist/resources/extensions/gsd/auto-dispatch.js +115 -17
  31. package/dist/resources/extensions/gsd/auto-loop.js +1 -1
  32. package/dist/resources/extensions/gsd/auto-model-selection.js +1 -1
  33. package/dist/resources/extensions/gsd/auto-post-unit.js +90 -2
  34. package/dist/resources/extensions/gsd/auto-prompts.js +14 -0
  35. package/dist/resources/extensions/gsd/auto-recovery.js +46 -1
  36. package/dist/resources/extensions/gsd/auto-start.js +45 -39
  37. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +11 -5
  38. package/dist/resources/extensions/gsd/auto-unit-closeout.js +11 -2
  39. package/dist/resources/extensions/gsd/auto-worktree.js +109 -61
  40. package/dist/resources/extensions/gsd/auto.js +97 -31
  41. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +27 -1
  42. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +4 -2
  43. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +11 -0
  44. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +17 -6
  45. package/dist/resources/extensions/gsd/bootstrap/system-context.js +11 -6
  46. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +34 -2
  47. package/dist/resources/extensions/gsd/clean-root-preflight.js +93 -0
  48. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +31 -4
  49. package/dist/resources/extensions/gsd/commands-cmux.js +9 -6
  50. package/dist/resources/extensions/gsd/commands-extensions.js +634 -43
  51. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +968 -23
  52. package/dist/resources/extensions/gsd/dispatch-guard.js +29 -3
  53. package/dist/resources/extensions/gsd/file-lock.js +49 -9
  54. package/dist/resources/extensions/gsd/git-service.js +1 -0
  55. package/dist/resources/extensions/gsd/gitignore.js +2 -0
  56. package/dist/resources/extensions/gsd/gsd-db.js +90 -30
  57. package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -1
  58. package/dist/resources/extensions/gsd/guided-flow.js +212 -9
  59. package/dist/resources/extensions/gsd/health-widget.js +4 -1
  60. package/dist/resources/extensions/gsd/journal.js +17 -2
  61. package/dist/resources/extensions/gsd/key-manager.js +22 -0
  62. package/dist/resources/extensions/gsd/milestone-actions.js +15 -0
  63. package/dist/resources/extensions/gsd/milestone-summary-classifier.js +37 -0
  64. package/dist/resources/extensions/gsd/model-router.js +36 -3
  65. package/dist/resources/extensions/gsd/notifications.js +30 -16
  66. package/dist/resources/extensions/gsd/pre-execution-checks.js +31 -6
  67. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +29 -2
  68. package/dist/resources/extensions/gsd/prompts/discuss.md +29 -2
  69. package/dist/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  70. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  71. package/dist/resources/extensions/gsd/prompts/system.md +1 -0
  72. package/dist/resources/extensions/gsd/reports.js +5 -4
  73. package/dist/resources/extensions/gsd/safety/evidence-collector.js +96 -0
  74. package/dist/resources/extensions/gsd/safety/file-change-validator.js +12 -4
  75. package/dist/resources/extensions/gsd/safety/safety-harness.js +5 -1
  76. package/dist/resources/extensions/gsd/state-transition-matrix.js +118 -0
  77. package/dist/resources/extensions/gsd/state.js +25 -25
  78. package/dist/resources/extensions/gsd/token-counter.js +22 -5
  79. package/dist/resources/extensions/gsd/tools/complete-milestone.js +16 -10
  80. package/dist/resources/extensions/gsd/tools/complete-slice.js +21 -0
  81. package/dist/resources/extensions/gsd/tools/complete-task.js +31 -0
  82. package/dist/resources/extensions/gsd/uok/audit.js +18 -2
  83. package/dist/resources/extensions/gsd/uok/dispatch-envelope.js +33 -0
  84. package/dist/resources/extensions/gsd/uok/execution-graph.js +10 -0
  85. package/dist/resources/extensions/gsd/uok/gitops.js +2 -1
  86. package/dist/resources/extensions/gsd/uok/loop-adapter.js +37 -10
  87. package/dist/resources/extensions/gsd/uok/parity-report.js +58 -0
  88. package/dist/resources/extensions/gsd/uok/plan-v2.js +30 -7
  89. package/dist/resources/extensions/gsd/uok/writer.js +82 -0
  90. package/dist/resources/extensions/gsd/workflow-logger.js +10 -2
  91. package/dist/resources/extensions/gsd/worktree-manager.js +1 -0
  92. package/dist/resources/extensions/gsd/worktree-resolver.js +50 -10
  93. package/dist/resources/extensions/mcp-client/auth.js +10 -1
  94. package/dist/resources/extensions/mcp-client/index.js +118 -9
  95. package/dist/resources/extensions/shared/cmux-events.js +12 -0
  96. package/dist/resources/extensions/shared/rtk-session-stats.js +1 -2
  97. package/dist/resources/skills/create-skill/SKILL.md +2 -2
  98. package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +4 -4
  99. package/dist/resources/skills/create-skill/workflows/audit-skill.md +4 -4
  100. package/dist/resources/skills/create-skill/workflows/create-new-skill.md +5 -5
  101. package/dist/resources/skills/verify-before-complete/SKILL.md +2 -1
  102. package/dist/resources/skills/write-docs/SKILL.md +2 -1
  103. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  104. package/dist/web/standalone/.next/BUILD_ID +1 -1
  105. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  106. package/dist/web/standalone/.next/build-manifest.json +3 -3
  107. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  108. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  109. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  110. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  118. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  127. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  129. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  131. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  133. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  135. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  137. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  139. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  141. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  143. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  145. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  147. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  149. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  151. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  153. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  155. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  157. package/dist/web/standalone/.next/server/app/api/notifications/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  159. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  161. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  163. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  165. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  167. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  169. package/dist/web/standalone/.next/server/app/api/session/events/route.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  171. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  173. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  175. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  177. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  179. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  181. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  183. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  185. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  187. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  189. package/dist/web/standalone/.next/server/app/index.html +1 -1
  190. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  191. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  192. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  193. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  194. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  195. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  196. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  197. package/dist/web/standalone/.next/server/chunks/1926.js +1 -0
  198. package/dist/web/standalone/.next/server/chunks/6897.js +2 -2
  199. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  201. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  202. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  203. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  204. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  205. package/dist/web/standalone/.next/static/chunks/2826.e9f5195e91f9cad2.js +11 -0
  206. package/dist/web/standalone/.next/static/chunks/{webpack-5fc74f13a25fa1bb.js → webpack-2e68521d7c82f7c2.js} +1 -1
  207. package/dist/welcome-screen.js +6 -1
  208. package/dist/wizard.js +2 -0
  209. package/package.json +16 -14
  210. package/packages/daemon/package.json +2 -2
  211. package/packages/mcp-server/README.md +3 -3
  212. package/packages/mcp-server/dist/env-writer.d.ts +1 -0
  213. package/packages/mcp-server/dist/env-writer.d.ts.map +1 -1
  214. package/packages/mcp-server/dist/env-writer.js +74 -6
  215. package/packages/mcp-server/dist/env-writer.js.map +1 -1
  216. package/packages/mcp-server/dist/remote-questions.d.ts +45 -0
  217. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -0
  218. package/packages/mcp-server/dist/remote-questions.js +732 -0
  219. package/packages/mcp-server/dist/remote-questions.js.map +1 -0
  220. package/packages/mcp-server/dist/server.d.ts +7 -0
  221. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  222. package/packages/mcp-server/dist/server.js +95 -10
  223. package/packages/mcp-server/dist/server.js.map +1 -1
  224. package/packages/mcp-server/dist/session-manager.d.ts +14 -0
  225. package/packages/mcp-server/dist/session-manager.d.ts.map +1 -1
  226. package/packages/mcp-server/dist/session-manager.js +49 -1
  227. package/packages/mcp-server/dist/session-manager.js.map +1 -1
  228. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  229. package/packages/mcp-server/dist/workflow-tools.js +15 -6
  230. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  231. package/packages/mcp-server/package.json +9 -3
  232. package/packages/mcp-server/src/env-writer.test.ts +79 -1
  233. package/packages/mcp-server/src/env-writer.ts +76 -6
  234. package/packages/mcp-server/src/mcp-server.test.ts +67 -0
  235. package/packages/mcp-server/src/readers/readers.test.ts +5 -1
  236. package/packages/mcp-server/src/remote-questions.test.ts +294 -0
  237. package/packages/mcp-server/src/remote-questions.ts +916 -0
  238. package/packages/mcp-server/src/server.ts +118 -16
  239. package/packages/mcp-server/src/session-manager.ts +43 -1
  240. package/packages/mcp-server/src/workflow-tools.test.ts +44 -0
  241. package/packages/mcp-server/src/workflow-tools.ts +19 -6
  242. package/packages/mcp-server/tsconfig.test.json +19 -0
  243. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  244. package/packages/native/package.json +6 -1
  245. package/packages/native/src/__tests__/clipboard.test.mjs +69 -23
  246. package/packages/native/tsconfig.tsbuildinfo +1 -1
  247. package/packages/pi-agent-core/package.json +6 -1
  248. package/packages/pi-agent-core/src/agent-loop.test.ts +220 -15
  249. package/packages/pi-ai/dist/models/custom.d.ts +38 -0
  250. package/packages/pi-ai/dist/models/custom.d.ts.map +1 -1
  251. package/packages/pi-ai/dist/models/custom.js +41 -0
  252. package/packages/pi-ai/dist/models/custom.js.map +1 -1
  253. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +1 -1
  254. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  255. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  256. package/packages/pi-ai/dist/providers/anthropic-shared.js +27 -4
  257. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  258. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  259. package/packages/pi-ai/dist/providers/anthropic.js +8 -3
  260. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  261. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts +2 -0
  262. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts.map +1 -0
  263. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +80 -0
  264. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -0
  265. package/packages/pi-ai/dist/providers/simple-options.d.ts +10 -0
  266. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  267. package/packages/pi-ai/dist/providers/simple-options.js +16 -1
  268. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  269. package/packages/pi-ai/package.json +6 -1
  270. package/packages/pi-ai/src/models/custom.ts +42 -0
  271. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +1 -1
  272. package/packages/pi-ai/src/providers/anthropic-shared.ts +26 -5
  273. package/packages/pi-ai/src/providers/anthropic.ts +9 -3
  274. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +98 -0
  275. package/packages/pi-ai/src/providers/simple-options.ts +17 -1
  276. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  277. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +3 -2
  278. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  279. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +2 -0
  280. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  281. package/packages/pi-coding-agent/dist/core/agent-session.js +7 -0
  282. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  283. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +25 -0
  284. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  285. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +105 -6
  286. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  287. package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js +230 -28
  288. package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js.map +1 -1
  289. package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts +30 -2
  290. package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts.map +1 -1
  291. package/packages/pi-coding-agent/dist/core/compaction/utils.js +113 -12
  292. package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
  293. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts +1 -0
  294. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
  295. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +29 -18
  296. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  297. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.d.ts +2 -0
  298. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.d.ts.map +1 -0
  299. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.js +130 -0
  300. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.js.map +1 -0
  301. package/packages/pi-coding-agent/dist/core/compaction-utils.test.js +56 -1
  302. package/packages/pi-coding-agent/dist/core/compaction-utils.test.js.map +1 -1
  303. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js +8 -15
  304. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js.map +1 -1
  305. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.d.ts +25 -0
  306. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.d.ts.map +1 -0
  307. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.js +109 -0
  308. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.js.map +1 -0
  309. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.d.ts +67 -0
  310. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.d.ts.map +1 -0
  311. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.js +167 -0
  312. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.js.map +1 -0
  313. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +3 -2
  314. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  315. package/packages/pi-coding-agent/dist/core/extensions/loader.js +24 -8
  316. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  317. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -0
  318. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  319. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  320. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +14 -0
  321. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  322. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  323. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +11 -0
  324. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
  325. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +2 -2
  326. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  327. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts +2 -0
  328. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts.map +1 -0
  329. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js +203 -0
  330. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js.map +1 -0
  331. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  332. package/packages/pi-coding-agent/dist/core/model-registry.js +14 -0
  333. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  334. package/packages/pi-coding-agent/dist/core/resource-loader.js +1 -1
  335. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  336. package/packages/pi-coding-agent/dist/core/sdk.d.ts +1 -0
  337. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  338. package/packages/pi-coding-agent/dist/core/sdk.js +4 -1
  339. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  340. package/packages/pi-coding-agent/dist/core/sdk.test.js +19 -1
  341. package/packages/pi-coding-agent/dist/core/sdk.test.js.map +1 -1
  342. package/packages/pi-coding-agent/dist/core/session-manager.js +1 -1
  343. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  344. package/packages/pi-coding-agent/dist/core/session-manager.test.js +21 -1
  345. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  346. package/packages/pi-coding-agent/dist/core/system-prompt.js +3 -3
  347. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  348. package/packages/pi-coding-agent/dist/core/tools/path-utils.test.js +2 -1
  349. package/packages/pi-coding-agent/dist/core/tools/path-utils.test.js.map +1 -1
  350. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js +15 -6
  351. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js.map +1 -1
  352. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  353. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -5
  354. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  355. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts +7 -1
  356. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  357. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +31 -9
  358. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
  359. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +14 -0
  360. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  361. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  362. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +13 -1
  363. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  364. package/packages/pi-coding-agent/package.json +6 -1
  365. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +3 -2
  366. package/packages/pi-coding-agent/src/core/agent-session.ts +11 -0
  367. package/packages/pi-coding-agent/src/core/compaction/compaction.test.ts +368 -28
  368. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +122 -6
  369. package/packages/pi-coding-agent/src/core/compaction/utils.ts +111 -13
  370. package/packages/pi-coding-agent/src/core/compaction-orchestrator.test.ts +154 -0
  371. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +32 -18
  372. package/packages/pi-coding-agent/src/core/compaction-utils.test.ts +68 -1
  373. package/packages/pi-coding-agent/src/core/discovery-cache.test.ts +9 -18
  374. package/packages/pi-coding-agent/src/core/extensions/extension-discovery.ts +119 -0
  375. package/packages/pi-coding-agent/src/core/extensions/extension-registry.ts +222 -0
  376. package/packages/pi-coding-agent/src/core/extensions/loader.ts +24 -11
  377. package/packages/pi-coding-agent/src/core/extensions/runner.ts +2 -0
  378. package/packages/pi-coding-agent/src/core/extensions/types.ts +15 -0
  379. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +13 -0
  380. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +2 -2
  381. package/packages/pi-coding-agent/src/core/model-registry-custom-caps.test.ts +245 -0
  382. package/packages/pi-coding-agent/src/core/model-registry.ts +16 -0
  383. package/packages/pi-coding-agent/src/core/resource-loader.ts +1 -1
  384. package/packages/pi-coding-agent/src/core/sdk.test.ts +25 -1
  385. package/packages/pi-coding-agent/src/core/sdk.ts +10 -3
  386. package/packages/pi-coding-agent/src/core/session-manager.test.ts +30 -1
  387. package/packages/pi-coding-agent/src/core/session-manager.ts +1 -1
  388. package/packages/pi-coding-agent/src/core/system-prompt.ts +3 -3
  389. package/packages/pi-coding-agent/src/core/tools/path-utils.test.ts +2 -1
  390. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/provider-display-name.test.ts +17 -7
  391. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +14 -5
  392. package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +45 -11
  393. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +14 -0
  394. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +13 -1
  395. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  396. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +12 -5
  397. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  398. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +21 -0
  399. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  400. package/packages/pi-tui/dist/stdin-buffer.d.ts +7 -0
  401. package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
  402. package/packages/pi-tui/dist/stdin-buffer.js +20 -0
  403. package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
  404. package/packages/pi-tui/package.json +6 -1
  405. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +20 -5
  406. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +27 -0
  407. package/packages/pi-tui/src/stdin-buffer.ts +26 -0
  408. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  409. package/packages/rpc-client/package.json +6 -1
  410. package/pkg/package.json +1 -1
  411. package/scripts/install.js +512 -0
  412. package/scripts/lib/workspace-manifest.cjs +86 -0
  413. package/scripts/link-workspace-packages.cjs +5 -17
  414. package/scripts/postinstall.js +9 -178
  415. package/src/resources/extensions/claude-code-cli/readiness.ts +4 -3
  416. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +91 -63
  417. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +114 -12
  418. package/src/resources/extensions/cmux/index.ts +35 -10
  419. package/src/resources/extensions/github-sync/templates.ts +151 -0
  420. package/src/resources/extensions/github-sync/tests/templates.test.ts +59 -0
  421. package/src/resources/extensions/google-search/extension-manifest.json +5 -4
  422. package/src/resources/extensions/google-search/index.ts +9 -470
  423. package/src/resources/extensions/gsd/abandon-detect.ts +62 -0
  424. package/src/resources/extensions/gsd/auto/loop-deps.ts +14 -1
  425. package/src/resources/extensions/gsd/auto/loop.ts +104 -2
  426. package/src/resources/extensions/gsd/auto/phases.ts +123 -21
  427. package/src/resources/extensions/gsd/auto/resolve.ts +29 -0
  428. package/src/resources/extensions/gsd/auto/run-unit.ts +56 -4
  429. package/src/resources/extensions/gsd/auto/session.ts +28 -1
  430. package/src/resources/extensions/gsd/auto/turn-epoch.ts +108 -0
  431. package/src/resources/extensions/gsd/auto/types.ts +1 -1
  432. package/src/resources/extensions/gsd/auto-dispatch.ts +117 -16
  433. package/src/resources/extensions/gsd/auto-loop.ts +1 -1
  434. package/src/resources/extensions/gsd/auto-model-selection.ts +1 -1
  435. package/src/resources/extensions/gsd/auto-post-unit.ts +92 -3
  436. package/src/resources/extensions/gsd/auto-prompts.ts +28 -1
  437. package/src/resources/extensions/gsd/auto-recovery.ts +40 -1
  438. package/src/resources/extensions/gsd/auto-start.ts +48 -52
  439. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +12 -5
  440. package/src/resources/extensions/gsd/auto-unit-closeout.ts +14 -3
  441. package/src/resources/extensions/gsd/auto-worktree.ts +122 -68
  442. package/src/resources/extensions/gsd/auto.ts +105 -35
  443. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +34 -1
  444. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +6 -2
  445. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +11 -0
  446. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +18 -6
  447. package/src/resources/extensions/gsd/bootstrap/system-context.ts +13 -9
  448. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +35 -2
  449. package/src/resources/extensions/gsd/clean-root-preflight.ts +111 -0
  450. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +27 -8
  451. package/src/resources/extensions/gsd/commands-cmux.ts +10 -6
  452. package/src/resources/extensions/gsd/commands-extensions.ts +747 -41
  453. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +898 -32
  454. package/src/resources/extensions/gsd/dispatch-guard.ts +26 -2
  455. package/src/resources/extensions/gsd/file-lock.ts +84 -11
  456. package/src/resources/extensions/gsd/git-service.ts +1 -0
  457. package/src/resources/extensions/gsd/gitignore.ts +2 -1
  458. package/src/resources/extensions/gsd/gsd-db.ts +92 -32
  459. package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -1
  460. package/src/resources/extensions/gsd/guided-flow.ts +259 -10
  461. package/src/resources/extensions/gsd/health-widget.ts +3 -1
  462. package/src/resources/extensions/gsd/journal.ts +29 -3
  463. package/src/resources/extensions/gsd/key-manager.ts +22 -0
  464. package/src/resources/extensions/gsd/milestone-actions.ts +18 -0
  465. package/src/resources/extensions/gsd/milestone-summary-classifier.ts +42 -0
  466. package/src/resources/extensions/gsd/model-router.ts +42 -1
  467. package/src/resources/extensions/gsd/notifications.ts +27 -15
  468. package/src/resources/extensions/gsd/pre-execution-checks.ts +33 -7
  469. package/src/resources/extensions/gsd/preferences-types.ts +8 -0
  470. package/src/resources/extensions/gsd/prompts/discuss-headless.md +29 -2
  471. package/src/resources/extensions/gsd/prompts/discuss.md +29 -2
  472. package/src/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  473. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  474. package/src/resources/extensions/gsd/prompts/system.md +1 -0
  475. package/src/resources/extensions/gsd/reports.ts +5 -4
  476. package/src/resources/extensions/gsd/safety/evidence-collector.ts +119 -0
  477. package/src/resources/extensions/gsd/safety/file-change-validator.ts +16 -3
  478. package/src/resources/extensions/gsd/safety/safety-harness.ts +9 -0
  479. package/src/resources/extensions/gsd/state-transition-matrix.ts +152 -0
  480. package/src/resources/extensions/gsd/state.ts +35 -30
  481. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +238 -4
  482. package/src/resources/extensions/gsd/tests/auto-mode-guards.test.ts +79 -0
  483. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +12 -0
  484. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +122 -0
  485. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +141 -0
  486. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +63 -0
  487. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +23 -0
  488. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +186 -0
  489. package/src/resources/extensions/gsd/tests/cmux.test.ts +5 -9
  490. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +15 -0
  491. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +61 -1
  492. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  493. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  494. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +161 -0
  495. package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +1 -0
  496. package/src/resources/extensions/gsd/tests/derive-state.test.ts +1 -2
  497. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +14 -9
  498. package/src/resources/extensions/gsd/tests/dispatch-guard-summary-db-mismatch.test.ts +77 -0
  499. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +25 -0
  500. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +14 -0
  501. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +31 -0
  502. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +1 -1
  503. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +1 -1
  504. package/src/resources/extensions/gsd/tests/escalation.test.ts +1 -1
  505. package/src/resources/extensions/gsd/tests/exec-history.test.ts +113 -0
  506. package/src/resources/extensions/gsd/tests/execution-entry-missing-context-4671.test.ts +173 -0
  507. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +38 -0
  508. package/src/resources/extensions/gsd/tests/file-lock.test.ts +86 -12
  509. package/src/resources/extensions/gsd/tests/google-search-stub.test.ts +131 -0
  510. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +296 -1
  511. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +117 -0
  512. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +30 -0
  513. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +4 -2
  514. package/src/resources/extensions/gsd/tests/integration/gitignore-tracked-gsd.test.ts +1 -0
  515. package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +30 -0
  516. package/src/resources/extensions/gsd/tests/integration/worktree-e2e.test.ts +11 -0
  517. package/src/resources/extensions/gsd/tests/issue-4540-regressions.test.ts +288 -0
  518. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +66 -0
  519. package/src/resources/extensions/gsd/tests/key-manager.test.ts +2 -0
  520. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +76 -0
  521. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  522. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +12 -0
  523. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  524. package/src/resources/extensions/gsd/tests/milestone-status-authoritative.test.ts +3 -3
  525. package/src/resources/extensions/gsd/tests/milestone-summary-classifier.test.ts +30 -0
  526. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +4 -2
  527. package/src/resources/extensions/gsd/tests/parallel-commit-scope.test.ts +5 -0
  528. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +19 -0
  529. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +150 -0
  530. package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +37 -0
  531. package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +272 -0
  532. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +337 -0
  533. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +44 -0
  534. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +39 -25
  535. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +181 -0
  536. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +13 -7
  537. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +388 -0
  538. package/src/resources/extensions/gsd/tests/require-slice-discussion-dispatch.test.ts +170 -0
  539. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +9 -3
  540. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +230 -0
  541. package/src/resources/extensions/gsd/tests/rewrite-docs-abandon-detect.test.ts +195 -0
  542. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +205 -0
  543. package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +413 -0
  544. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +32 -40
  545. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +112 -0
  546. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +56 -0
  547. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +24 -0
  548. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +44 -0
  549. package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +2 -2
  550. package/src/resources/extensions/gsd/tests/token-counter.test.ts +105 -1
  551. package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +107 -0
  552. package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +50 -2
  553. package/src/resources/extensions/gsd/tests/turn-epoch.test.ts +162 -0
  554. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +51 -0
  555. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +16 -0
  556. package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +65 -0
  557. package/src/resources/extensions/gsd/tests/uok-parity-report.test.ts +42 -0
  558. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +42 -2
  559. package/src/resources/extensions/gsd/tests/uok-writer.test.ts +75 -0
  560. package/src/resources/extensions/gsd/tests/validate-extension-package.test.ts +168 -0
  561. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +138 -5
  562. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +25 -2
  563. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +65 -2
  564. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +35 -0
  565. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +6 -1
  566. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +78 -5
  567. package/src/resources/extensions/gsd/tests/write-gate.test.ts +64 -0
  568. package/src/resources/extensions/gsd/token-counter.ts +22 -5
  569. package/src/resources/extensions/gsd/tools/complete-milestone.ts +15 -9
  570. package/src/resources/extensions/gsd/tools/complete-slice.ts +38 -0
  571. package/src/resources/extensions/gsd/tools/complete-task.ts +49 -0
  572. package/src/resources/extensions/gsd/uok/audit.ts +20 -2
  573. package/src/resources/extensions/gsd/uok/contracts.ts +65 -0
  574. package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +56 -0
  575. package/src/resources/extensions/gsd/uok/execution-graph.ts +22 -0
  576. package/src/resources/extensions/gsd/uok/gitops.ts +6 -1
  577. package/src/resources/extensions/gsd/uok/loop-adapter.ts +45 -10
  578. package/src/resources/extensions/gsd/uok/parity-report.ts +84 -0
  579. package/src/resources/extensions/gsd/uok/plan-v2.ts +39 -8
  580. package/src/resources/extensions/gsd/uok/writer.ts +113 -0
  581. package/src/resources/extensions/gsd/workflow-logger.ts +23 -3
  582. package/src/resources/extensions/gsd/worktree-manager.ts +1 -0
  583. package/src/resources/extensions/gsd/worktree-resolver.ts +54 -9
  584. package/src/resources/extensions/mcp-client/auth.ts +12 -1
  585. package/src/resources/extensions/mcp-client/index.ts +129 -10
  586. package/src/resources/extensions/shared/cmux-events.ts +59 -0
  587. package/src/resources/extensions/shared/rtk-session-stats.ts +1 -2
  588. package/src/resources/skills/create-skill/SKILL.md +2 -2
  589. package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +4 -4
  590. package/src/resources/skills/create-skill/workflows/audit-skill.md +4 -4
  591. package/src/resources/skills/create-skill/workflows/create-new-skill.md +5 -5
  592. package/src/resources/skills/verify-before-complete/SKILL.md +2 -1
  593. package/src/resources/skills/write-docs/SKILL.md +2 -1
  594. package/dist/web/standalone/.next/server/chunks/7461.js +0 -1
  595. package/dist/web/standalone/.next/static/chunks/2826.e59e8578e2e28639.js +0 -9
  596. /package/dist/web/standalone/.next/static/{n21VtX2hZlkpdEUO_nU4z → vidAVJkURvTJ0_V2-64ro}/_buildManifest.js +0 -0
  597. /package/dist/web/standalone/.next/static/{n21VtX2hZlkpdEUO_nU4z → vidAVJkURvTJ0_V2-64ro}/_ssgManifest.js +0 -0
@@ -0,0 +1,152 @@
1
+ import type { Phase } from "./types.js";
2
+
3
+ export type StateTransitionReasonCode =
4
+ | "state"
5
+ | "manual"
6
+ | "recovery"
7
+ | "dependency"
8
+ | "policy"
9
+ | "retry";
10
+
11
+ export interface StateTransitionEntry {
12
+ from: Phase | "*";
13
+ event: string;
14
+ guard: string;
15
+ to: Phase;
16
+ onFail: Phase | "manual-attention" | "blocked" | "no-transition";
17
+ reasonCode: StateTransitionReasonCode;
18
+ }
19
+
20
+ export const STATE_TRANSITION_MATRIX: readonly StateTransitionEntry[] = [
21
+ {
22
+ from: "needs-discussion",
23
+ event: "context-ready",
24
+ guard: "CONTEXT artifact exists or PRD/context express path produced context",
25
+ to: "researching",
26
+ onFail: "needs-discussion",
27
+ reasonCode: "state",
28
+ },
29
+ {
30
+ from: "researching",
31
+ event: "research-ready",
32
+ guard: "RESEARCH artifact exists or research is explicitly skipped",
33
+ to: "planning",
34
+ onFail: "researching",
35
+ reasonCode: "state",
36
+ },
37
+ {
38
+ from: "planning",
39
+ event: "plan-ready",
40
+ guard: "ROADMAP/PLAN artifacts exist and plan gate passes",
41
+ to: "executing",
42
+ onFail: "replanning-slice",
43
+ reasonCode: "state",
44
+ },
45
+ {
46
+ from: "executing",
47
+ event: "task-dispatched",
48
+ guard: "task inputs are ready and dependencies are closed",
49
+ to: "executing",
50
+ onFail: "blocked",
51
+ reasonCode: "dependency",
52
+ },
53
+ {
54
+ from: "executing",
55
+ event: "slice-complete",
56
+ guard: "all slice tasks are closed and verification gate passes",
57
+ to: "summarizing",
58
+ onFail: "validating-milestone",
59
+ reasonCode: "state",
60
+ },
61
+ {
62
+ from: "summarizing",
63
+ event: "summary-ready",
64
+ guard: "SUMMARY artifact exists for the completed work unit",
65
+ to: "validating-milestone",
66
+ onFail: "summarizing",
67
+ reasonCode: "state",
68
+ },
69
+ {
70
+ from: "validating-milestone",
71
+ event: "validation-pass",
72
+ guard: "validation verdict is terminal and not remediation-required",
73
+ to: "completing-milestone",
74
+ onFail: "blocked",
75
+ reasonCode: "state",
76
+ },
77
+ {
78
+ from: "blocked",
79
+ event: "recovery-plan-ready",
80
+ guard: "reassessment produced an executable next action",
81
+ to: "executing",
82
+ onFail: "blocked",
83
+ reasonCode: "recovery",
84
+ },
85
+ {
86
+ from: "replanning-slice",
87
+ event: "replan-ready",
88
+ guard: "replacement slice/task plan exists and plan gate passes",
89
+ to: "executing",
90
+ onFail: "blocked",
91
+ reasonCode: "recovery",
92
+ },
93
+ {
94
+ from: "completing-milestone",
95
+ event: "closeout-complete",
96
+ guard: "closeout gate passes and git transaction succeeds",
97
+ to: "complete",
98
+ onFail: "blocked",
99
+ reasonCode: "state",
100
+ },
101
+ {
102
+ from: "*",
103
+ event: "manual-block",
104
+ guard: "operator or hard gate requested manual attention",
105
+ to: "blocked",
106
+ onFail: "manual-attention",
107
+ reasonCode: "manual",
108
+ },
109
+ {
110
+ from: "*",
111
+ event: "retryable-failure",
112
+ guard: "retry budget remains for failure class",
113
+ to: "executing",
114
+ onFail: "blocked",
115
+ reasonCode: "retry",
116
+ },
117
+ ] as const;
118
+
119
+ export interface MatrixValidationResult {
120
+ ok: boolean;
121
+ missingEvents: string[];
122
+ duplicateKeys: string[];
123
+ }
124
+
125
+ export function findTransition(
126
+ from: Phase,
127
+ event: string,
128
+ ): StateTransitionEntry | undefined {
129
+ return STATE_TRANSITION_MATRIX.find((entry) =>
130
+ (entry.from === from || entry.from === "*") && entry.event === event,
131
+ );
132
+ }
133
+
134
+ export function validateTransitionMatrix(requiredEvents: readonly string[]): MatrixValidationResult {
135
+ const seen = new Set<string>();
136
+ const duplicateKeys: string[] = [];
137
+
138
+ for (const entry of STATE_TRANSITION_MATRIX) {
139
+ const key = `${entry.from}:${entry.event}`;
140
+ if (seen.has(key)) duplicateKeys.push(key);
141
+ seen.add(key);
142
+ }
143
+
144
+ const availableEvents = new Set(STATE_TRANSITION_MATRIX.map((entry) => entry.event));
145
+ const missingEvents = requiredEvents.filter((event) => !availableEvents.has(event));
146
+
147
+ return {
148
+ ok: missingEvents.length === 0 && duplicateKeys.length === 0,
149
+ missingEvents,
150
+ duplicateKeys,
151
+ };
152
+ }
@@ -46,6 +46,7 @@ import { logWarning, logError } from './workflow-logger.js';
46
46
  import { extractVerdict } from './verdict-parser.js';
47
47
  import { loadEffectiveGSDPreferences } from './preferences.js';
48
48
  import { detectPendingEscalation } from './escalation.js';
49
+ import { isTerminalMilestoneSummaryContent } from './milestone-summary-classifier.js';
49
50
 
50
51
  import {
51
52
  isDbAvailable,
@@ -139,6 +140,14 @@ export function isValidationTerminal(validationContent: string): boolean {
139
140
  return extractVerdict(validationContent) != null;
140
141
  }
141
142
 
143
+ async function isTerminalMilestoneSummaryFile(
144
+ path: string,
145
+ loader: (path: string) => Promise<string | null>,
146
+ ): Promise<boolean> {
147
+ const content = await loader(path);
148
+ return content != null && isTerminalMilestoneSummaryContent(content);
149
+ }
150
+
142
151
  // ─── State Derivation ──────────────────────────────────────────────────────
143
152
 
144
153
  // ── deriveState memoization ─────────────────────────────────────────────────
@@ -211,15 +220,15 @@ export async function getActiveMilestoneId(basePath: string): Promise<string | n
211
220
  const content = roadmapFile ? await loadFile(roadmapFile) : null;
212
221
  if (!content) {
213
222
  const summaryFile = resolveMilestoneFile(basePath, mid, "SUMMARY");
214
- if (summaryFile) continue;
223
+ if (summaryFile && await isTerminalMilestoneSummaryFile(summaryFile, loadFile)) continue;
215
224
  if (isGhostMilestone(basePath, mid)) continue;
216
225
  return mid;
217
226
  }
218
227
  const roadmap = parseRoadmap(content);
219
- if (!isMilestoneComplete(roadmap)) {
220
- const summaryFile = resolveMilestoneFile(basePath, mid, "SUMMARY");
221
- if (!summaryFile) return mid;
222
- }
228
+ const summaryFile = resolveMilestoneFile(basePath, mid, "SUMMARY");
229
+ if (summaryFile && await isTerminalMilestoneSummaryFile(summaryFile, loadFile)) continue;
230
+ if (!isMilestoneComplete(roadmap)) return mid;
231
+ return mid;
223
232
  }
224
233
  return null;
225
234
  }
@@ -668,7 +677,6 @@ function resolveSliceDependencies(activeMilestoneSlices: SliceRow[]): { activeSl
668
677
  }
669
678
  }
670
679
 
671
- // First pass: find a slice with ALL dependencies satisfied (strict)
672
680
  let bestFallback: SliceRow | null = null;
673
681
  let bestFallbackSatisfied = -1;
674
682
 
@@ -678,7 +686,6 @@ function resolveSliceDependencies(activeMilestoneSlices: SliceRow[]): { activeSl
678
686
  if (s.depends.every(dep => doneSliceIds.has(dep))) {
679
687
  return { activeSlice: { id: s.id, title: s.title }, activeSliceRow: s };
680
688
  }
681
- // Track the slice with the most satisfied dependencies as fallback
682
689
  const satisfied = s.depends.filter(dep => doneSliceIds.has(dep)).length;
683
690
  if (satisfied > bestFallbackSatisfied || (satisfied === bestFallbackSatisfied && !bestFallback)) {
684
691
  bestFallback = s;
@@ -686,16 +693,13 @@ function resolveSliceDependencies(activeMilestoneSlices: SliceRow[]): { activeSl
686
693
  }
687
694
  }
688
695
 
689
- // Fallback: if no slice has all deps met but there ARE incomplete non-deferred
690
- // slices, pick the one with the most deps satisfied. This prevents hard-blocking
691
- // when dependency metadata is stale (e.g. after reassessment added/removed slices)
692
- // or when deps reference slices from previous milestones.
693
696
  if (bestFallback) {
694
697
  const unmet = bestFallback.depends.filter(dep => !doneSliceIds.has(dep));
695
- logWarning("state",
698
+ logWarning(
699
+ "state",
696
700
  `No slice has all deps satisfied — falling back to ${bestFallback.id} ` +
697
- `(${bestFallbackSatisfied}/${bestFallback.depends.length} deps met, ` +
698
- `unmet: ${unmet.join(", ")})`,
701
+ `(${bestFallbackSatisfied}/${bestFallback.depends.length} deps met, ` +
702
+ `unmet: ${unmet.join(", ")})`,
699
703
  { mid: activeMilestoneSlices[0]?.milestone_id, sid: bestFallback.id },
700
704
  );
701
705
  return { activeSlice: { id: bestFallback.id, title: bestFallback.title }, activeSliceRow: bestFallback };
@@ -1160,7 +1164,7 @@ export async function _deriveStateImpl(basePath: string): Promise<GSDState> {
1160
1164
  const rc = rf ? await cachedLoadFile(rf) : null;
1161
1165
  if (!rc) {
1162
1166
  const sf = resolveMilestoneFile(basePath, mid, "SUMMARY");
1163
- if (sf) completeMilestoneIds.add(mid);
1167
+ if (sf && await isTerminalMilestoneSummaryFile(sf, cachedLoadFile)) completeMilestoneIds.add(mid);
1164
1168
  continue;
1165
1169
  }
1166
1170
  const rmap = parseRoadmap(rc);
@@ -1169,11 +1173,11 @@ export async function _deriveStateImpl(basePath: string): Promise<GSDState> {
1169
1173
  // Summary is the terminal artifact — if it exists, the milestone is
1170
1174
  // complete even when roadmap checkboxes weren't ticked (#864).
1171
1175
  const sf = resolveMilestoneFile(basePath, mid, "SUMMARY");
1172
- if (sf) completeMilestoneIds.add(mid);
1176
+ if (sf && await isTerminalMilestoneSummaryFile(sf, cachedLoadFile)) completeMilestoneIds.add(mid);
1173
1177
  continue;
1174
1178
  }
1175
1179
  const sf = resolveMilestoneFile(basePath, mid, "SUMMARY");
1176
- if (sf) completeMilestoneIds.add(mid);
1180
+ if (sf && await isTerminalMilestoneSummaryFile(sf, cachedLoadFile)) completeMilestoneIds.add(mid);
1177
1181
  }
1178
1182
 
1179
1183
  // Phase 2: Build registry using cached roadmaps (no re-parsing or re-reading)
@@ -1201,12 +1205,14 @@ export async function _deriveStateImpl(basePath: string): Promise<GSDState> {
1201
1205
  const summaryFile = resolveMilestoneFile(basePath, mid, "SUMMARY");
1202
1206
  if (summaryFile) {
1203
1207
  const summaryContent = await cachedLoadFile(summaryFile);
1204
- const summaryTitle = summaryContent
1205
- ? (parseSummary(summaryContent).title || mid)
1206
- : mid;
1207
- registry.push({ id: mid, title: summaryTitle, status: 'complete' });
1208
- completeMilestoneIds.add(mid);
1209
- continue;
1208
+ if (summaryContent != null && isTerminalMilestoneSummaryContent(summaryContent)) {
1209
+ const summaryTitle = summaryContent
1210
+ ? (parseSummary(summaryContent).title || mid)
1211
+ : mid;
1212
+ registry.push({ id: mid, title: summaryTitle, status: 'complete' });
1213
+ completeMilestoneIds.add(mid);
1214
+ continue;
1215
+ }
1210
1216
  }
1211
1217
  // Ghost milestone (only META.json, no CONTEXT/ROADMAP/SUMMARY) — skip entirely
1212
1218
  if (isGhostMilestone(basePath, mid)) continue;
@@ -1262,7 +1268,7 @@ export async function _deriveStateImpl(basePath: string): Promise<GSDState> {
1262
1268
  // needs-remediation is terminal but requires re-validation (#3596)
1263
1269
  const needsRevalidation = !validationTerminal || verdict === 'needs-remediation';
1264
1270
 
1265
- if (summaryFile) {
1271
+ if (summaryFile && await isTerminalMilestoneSummaryFile(summaryFile, cachedLoadFile)) {
1266
1272
  // Summary exists → milestone is complete regardless of validation state.
1267
1273
  // The summary is the terminal artifact (#864).
1268
1274
  registry.push({ id: mid, title, status: 'complete' });
@@ -1288,7 +1294,7 @@ export async function _deriveStateImpl(basePath: string): Promise<GSDState> {
1288
1294
  // Roadmap slices not all checked — but if a summary exists, the milestone
1289
1295
  // is still complete. The summary is the terminal artifact (#864).
1290
1296
  const summaryFile = resolveMilestoneFile(basePath, mid, "SUMMARY");
1291
- if (summaryFile) {
1297
+ if (summaryFile && await isTerminalMilestoneSummaryFile(summaryFile, cachedLoadFile)) {
1292
1298
  registry.push({ id: mid, title, status: 'complete' });
1293
1299
  } else if (!activeMilestoneFound) {
1294
1300
  // Check milestone-level dependencies before promoting to active.
@@ -1572,7 +1578,6 @@ export async function _deriveStateImpl(basePath: string): Promise<GSDState> {
1572
1578
  activeSlice = { id: s.id, title: s.title };
1573
1579
  break;
1574
1580
  }
1575
- // Track best fallback
1576
1581
  const satisfied = s.depends.filter(dep => doneSliceIds.has(dep)).length;
1577
1582
  if (satisfied > bestFallbackLegacySatisfied) {
1578
1583
  bestFallbackLegacy = s;
@@ -1580,13 +1585,13 @@ export async function _deriveStateImpl(basePath: string): Promise<GSDState> {
1580
1585
  }
1581
1586
  }
1582
1587
 
1583
- // Fallback: if no slice has all deps met, pick the one with the most deps satisfied
1584
1588
  if (!activeSlice && bestFallbackLegacy) {
1585
1589
  const unmet = bestFallbackLegacy.depends.filter(dep => !doneSliceIds.has(dep));
1586
- logWarning("state",
1590
+ logWarning(
1591
+ "state",
1587
1592
  `No slice has all deps satisfied — falling back to ${bestFallbackLegacy.id} ` +
1588
- `(${bestFallbackLegacySatisfied}/${bestFallbackLegacy.depends.length} deps met, ` +
1589
- `unmet: ${unmet.join(", ")})`,
1593
+ `(${bestFallbackLegacySatisfied}/${bestFallbackLegacy.depends.length} deps met, ` +
1594
+ `unmet: ${unmet.join(", ")})`,
1590
1595
  );
1591
1596
  activeSlice = { id: bestFallbackLegacy.id, title: bestFallbackLegacy.title };
1592
1597
  }
@@ -10,6 +10,7 @@ import {
10
10
  autoLoop,
11
11
  detectStuck,
12
12
  _resetPendingResolve,
13
+ _hasPendingResolveForTest,
13
14
  _setActiveSession,
14
15
  isSessionSwitchInFlight,
15
16
  type UnitResult,
@@ -35,12 +36,15 @@ function makeMockSession(opts?: {
35
36
  newSessionDelayMs?: number;
36
37
  onNewSessionStart?: (session: any) => void;
37
38
  onNewSessionSettle?: (session: any) => void;
39
+ /** Called after the delay with the aborted state of any passed abortSignal.
40
+ * Used to verify that runUnit passes an aborted signal on late resolution (#3731). */
41
+ onSignalCheck?: (aborted: boolean) => void;
38
42
  }) {
39
43
  const session = {
40
44
  active: true,
41
45
  verbose: false,
42
46
  cmdCtx: {
43
- newSession: () => {
47
+ newSession: (options?: { abortSignal?: AbortSignal }) => {
44
48
  opts?.onNewSessionStart?.(session);
45
49
  if (opts?.newSessionThrows) {
46
50
  return Promise.reject(new Error(opts.newSessionThrows));
@@ -50,11 +54,17 @@ function makeMockSession(opts?: {
50
54
  if (delay > 0) {
51
55
  return new Promise<{ cancelled: boolean }>((res) =>
52
56
  setTimeout(() => {
57
+ // Simulate AgentSession.newSession() checking abortSignal after
58
+ // its internal async work (abort()) completes — this is where the
59
+ // real code captures process.cwd() and rebuilds the tool runtime.
60
+ // If the signal is aborted, the real code discards the session.
61
+ opts?.onSignalCheck?.(options?.abortSignal?.aborted ?? false);
53
62
  opts?.onNewSessionSettle?.(session);
54
63
  res(result);
55
64
  }, delay),
56
65
  );
57
66
  }
67
+ opts?.onSignalCheck?.(options?.abortSignal?.aborted ?? false);
58
68
  opts?.onNewSessionSettle?.(session);
59
69
  return Promise.resolve(result);
60
70
  },
@@ -349,6 +359,182 @@ test("runUnit cancels before dispatch when model restore fails after newSession"
349
359
  ]);
350
360
  });
351
361
 
362
+ test("runUnit cancels before dispatch when provider is not request-ready (#4555)", async () => {
363
+ _resetPendingResolve();
364
+
365
+ const ctx = makeMockCtx();
366
+ ctx.model = { provider: "anthropic", id: "claude-opus-4-6" };
367
+ ctx.modelRegistry = {
368
+ isProviderRequestReady: (_provider: string) => false,
369
+ };
370
+
371
+ const pi = makeMockPi();
372
+ const s = makeMockSession();
373
+
374
+ const result = await runUnit(ctx, pi, s, "task", "T01", "prompt");
375
+
376
+ assert.equal(result.status, "cancelled");
377
+ assert.equal(result.errorContext?.category, "provider");
378
+ assert.match(
379
+ result.errorContext?.message ?? "",
380
+ /Provider anthropic is not request-ready/,
381
+ );
382
+ assert.equal(pi.calls.length, 0, "sendMessage must not be called when provider is not ready");
383
+ assert.equal(_hasPendingResolveForTest(), false, "provider cancellation must clear the pending resolver");
384
+ });
385
+
386
+ test("runUnit cancels before dispatch using currentUnitModel provider when set (#4555)", async () => {
387
+ _resetPendingResolve();
388
+
389
+ const ctx = makeMockCtx();
390
+ // ctx.model uses "openai" which IS ready — if the code ignores currentUnitModel
391
+ // and falls back to ctx.model.provider, the unit would NOT be cancelled. The
392
+ // test therefore differentiates: only a bug (wrong provider lookup) would pass.
393
+ ctx.model = { provider: "openai", id: "gpt-4o" };
394
+ // modelRegistry says anthropic is not ready but openai is
395
+ ctx.modelRegistry = {
396
+ isProviderRequestReady: (provider: string) => provider === "openai",
397
+ };
398
+
399
+ const pi = makeMockPi();
400
+ const s = makeMockSession();
401
+ // currentUnitModel overrides the provider used in the readiness check
402
+ s.currentUnitModel = { provider: "anthropic", id: "claude-opus-4-6" };
403
+
404
+ const result = await runUnit(ctx, pi, s, "task", "T01", "prompt");
405
+
406
+ assert.equal(result.status, "cancelled");
407
+ assert.equal(result.errorContext?.category, "provider");
408
+ assert.match(
409
+ result.errorContext?.message ?? "",
410
+ /Provider anthropic is not request-ready/,
411
+ );
412
+ assert.equal(pi.calls.length, 0, "sendMessage must not be called — anthropic (currentUnitModel) is not ready");
413
+ });
414
+
415
+ test("runUnit does not cancel before dispatch when provider is request-ready (#4555)", async () => {
416
+ _resetPendingResolve();
417
+
418
+ const ctx = makeMockCtx();
419
+ ctx.model = { provider: "anthropic", id: "claude-opus-4-6" };
420
+ ctx.modelRegistry = {
421
+ isProviderRequestReady: (_provider: string) => true,
422
+ };
423
+
424
+ const pi = makeMockPi();
425
+ const s = makeMockSession();
426
+
427
+ const resultPromise = runUnit(ctx, pi, s, "task", "T01", "prompt");
428
+
429
+ await new Promise((r) => setTimeout(r, 10));
430
+ resolveAgentEnd(makeEvent());
431
+
432
+ const result = await resultPromise;
433
+ assert.equal(result.status, "completed");
434
+ assert.equal(pi.calls.length, 1, "sendMessage must be called when provider is ready");
435
+ });
436
+
437
+ test("runUnit proceeds when modelRegistry is absent (no readiness check available) (#4555)", async () => {
438
+ _resetPendingResolve();
439
+
440
+ const ctx = makeMockCtx();
441
+ ctx.model = { provider: "anthropic", id: "claude-opus-4-6" };
442
+ // No modelRegistry on ctx — pre-check should be skipped
443
+
444
+ const pi = makeMockPi();
445
+ const s = makeMockSession();
446
+
447
+ const resultPromise = runUnit(ctx, pi, s, "task", "T01", "prompt");
448
+
449
+ await new Promise((r) => setTimeout(r, 10));
450
+ resolveAgentEnd(makeEvent());
451
+
452
+ const result = await resultPromise;
453
+ assert.equal(result.status, "completed");
454
+ assert.equal(pi.calls.length, 1);
455
+ });
456
+
457
+ test("runUnit proceeds when isProviderRequestReady throws (defensive) (#4555)", async () => {
458
+ _resetPendingResolve();
459
+
460
+ const ctx = makeMockCtx();
461
+ ctx.model = { provider: "anthropic", id: "claude-opus-4-6" };
462
+ ctx.modelRegistry = {
463
+ isProviderRequestReady: (_provider: string) => {
464
+ throw new Error("registry error");
465
+ },
466
+ };
467
+
468
+ const pi = makeMockPi();
469
+ const s = makeMockSession();
470
+
471
+ const result = await runUnit(ctx, pi, s, "task", "T01", "prompt");
472
+
473
+ // When the readyCheck throws, ready=false → unit cancelled
474
+ assert.equal(result.status, "cancelled");
475
+ assert.equal(result.errorContext?.category, "provider");
476
+ assert.equal(pi.calls.length, 0);
477
+ });
478
+
479
+ test("late-resolving newSession() after timeout receives aborted signal so tool runtime is not configured with root cwd (#3731)", async () => {
480
+ // When newSession() times out in runUnit(), auto-mode restores cwd to project
481
+ // root. If newSession() later resolves, it must NOT use process.cwd() to
482
+ // configure the tool runtime (which would give it root cwd, not worktree cwd).
483
+ //
484
+ // The fix: runUnit creates an AbortController, aborts it on timeout, and passes
485
+ // the signal to newSession(). AgentSession.newSession() checks the signal after
486
+ // its internal await this.abort() completes and returns early (discards) if aborted.
487
+ //
488
+ // This test uses mock.timers to control timing precisely.
489
+ _resetPendingResolve();
490
+ mock.timers.enable();
491
+
492
+ try {
493
+ let abortedWhenLateSessionSettled: boolean | null = null;
494
+
495
+ // newSession mock simulates AgentSession.newSession() behavior:
496
+ // after an internal delay (representing await this.abort()), it checks the
497
+ // abortSignal — that's where the real code would capture process.cwd() and
498
+ // call _buildRuntime. If aborted, the real code must discard the session.
499
+ const s = makeMockSession({
500
+ newSessionDelayMs: 200_000, // longer than NEW_SESSION_TIMEOUT_MS (120s)
501
+ onSignalCheck: (aborted) => {
502
+ abortedWhenLateSessionSettled = aborted;
503
+ },
504
+ });
505
+
506
+ const ctx = makeMockCtx();
507
+ const pi = makeMockPi();
508
+
509
+ const resultPromise = runUnit(ctx, pi, s, "task", "T01", "prompt");
510
+
511
+ // Tick past the 120s NEW_SESSION_TIMEOUT_MS — runUnit returns cancelled
512
+ mock.timers.tick(121_000);
513
+ await Promise.resolve();
514
+
515
+ const result = await resultPromise;
516
+ assert.equal(result.status, "cancelled", "runUnit must return cancelled on session timeout");
517
+
518
+ // Tick past the delayed newSession (200s total) — the late newSession resolves
519
+ mock.timers.tick(80_000);
520
+ // Drain microtask queue so the .finally() and setTimeout callbacks run
521
+ await Promise.resolve();
522
+ await Promise.resolve();
523
+
524
+ // The key assertion: when the late newSession() resolves, runUnit must have
525
+ // passed an aborted AbortSignal. Without the fix, no signal is passed and
526
+ // abortedWhenLateSessionSettled would be false (or null, if signal not passed at all).
527
+ assert.equal(
528
+ abortedWhenLateSessionSettled,
529
+ true,
530
+ "runUnit must pass an aborted AbortSignal to newSession() when it resolves after the session-creation timeout (#3731). " +
531
+ "Without this, AgentSession.newSession() captures root process.cwd() and rebuilds the tool runtime with wrong cwd.",
532
+ );
533
+ } finally {
534
+ mock.timers.reset();
535
+ }
536
+ });
537
+
352
538
  // ─── Structural assertions ───────────────────────────────────────────────────
353
539
 
354
540
  test("auto-loop.ts exports autoLoop, runUnit, resolveAgentEnd", async () => {
@@ -409,7 +595,7 @@ test("auto/phases.ts: selectAndApplyModel called exactly once and before updateP
409
595
  // Extract the runUnitPhase function body
410
596
  const fnStart = src.indexOf("export async function runUnitPhase");
411
597
  assert.ok(fnStart > 0, "runUnitPhase should exist in phases.ts");
412
- const fnBody = src.slice(fnStart, fnStart + 12000);
598
+ const fnBody = src.slice(fnStart, fnStart + 16000);
413
599
 
414
600
  // selectAndApplyModel must appear exactly once
415
601
  const allOccurrences = [...fnBody.matchAll(/selectAndApplyModel\(/g)];
@@ -497,6 +683,8 @@ function makeMockDeps(
497
683
  autoWorktreeBranch: () => "auto/M001",
498
684
  resolveMilestoneFile: () => null,
499
685
  reconcileMergeState: () => "clean",
686
+ preflightCleanRoot: () => ({ stashPushed: false, summary: "" }),
687
+ postflightPopStash: () => {},
500
688
  getLedger: () => null,
501
689
  getProjectTotals: () => ({ cost: 0 }),
502
690
  formatCost: (c: number) => `$${c.toFixed(2)}`,
@@ -663,6 +851,45 @@ test("autoLoop exits on terminal complete state", async (t) => {
663
851
  );
664
852
  });
665
853
 
854
+ test("autoLoop pauses when provider readiness cancels before dispatch", async () => {
855
+ _resetPendingResolve();
856
+
857
+ const notifications: Array<{ message: string; level?: string }> = [];
858
+ const ctx = makeMockCtx();
859
+ ctx.ui.setStatus = () => {};
860
+ ctx.ui.notify = (message: string, level?: string) => {
861
+ notifications.push({ message, level });
862
+ };
863
+ ctx.model = { provider: "anthropic", id: "claude-opus-4-6" };
864
+ ctx.modelRegistry = {
865
+ getProviderAuthMode: () => "api-key",
866
+ isProviderRequestReady: () => false,
867
+ };
868
+
869
+ const pi = makeMockPi();
870
+ const s = makeLoopSession();
871
+ const deps = makeMockDeps({
872
+ selectAndApplyModel: async () => ({
873
+ routing: null,
874
+ appliedModel: { provider: "anthropic", id: "claude-opus-4-6" },
875
+ }),
876
+ });
877
+
878
+ await autoLoop(ctx, pi, s, deps);
879
+
880
+ assert.equal(pi.calls.length, 0, "provider readiness cancellation must not dispatch a message");
881
+ assert.ok(deps.callLog.includes("pauseAuto"), "provider readiness cancellation should pause auto-mode");
882
+ assert.ok(!deps.callLog.includes("stopAuto"), "provider readiness cancellation should not hard-stop auto-mode");
883
+ assert.ok(
884
+ !deps.callLog.includes("postUnitPreVerification"),
885
+ "post-unit verification must not run after pre-dispatch provider cancellation",
886
+ );
887
+ assert.ok(
888
+ notifications.some(n => /Provider anthropic is not request-ready/.test(n.message)),
889
+ "provider pause should notify with the readiness failure",
890
+ );
891
+ });
892
+
666
893
  test("autoLoop passes structured session-lock failure details to the handler", async () => {
667
894
  _resetPendingResolve();
668
895
 
@@ -1423,9 +1650,16 @@ test("auto-timeout-recovery.ts calls resolveAgentEnd instead of dispatchNextUnit
1423
1650
  !src.includes("await dispatchNextUnit"),
1424
1651
  "auto-timeout-recovery.ts must not call dispatchNextUnit",
1425
1652
  );
1653
+ // After PR #4716, advance branches go through bumpAndResolveSynthetic()
1654
+ // (which bumps the turn epoch and calls resolveAgentEnd atomically).
1655
+ // Either direct resolveAgentEnd() or the helper satisfies the invariant:
1656
+ // the loop must be re-iterated on timeout recovery.
1657
+ const reIteratesLoop =
1658
+ src.includes("resolveAgentEnd(") ||
1659
+ src.includes("bumpAndResolveSynthetic(");
1426
1660
  assert.ok(
1427
- src.includes("resolveAgentEnd("),
1428
- "auto-timeout-recovery.ts must call resolveAgentEnd to re-iterate the loop on timeout recovery",
1661
+ reIteratesLoop,
1662
+ "auto-timeout-recovery.ts must call resolveAgentEnd (directly or via bumpAndResolveSynthetic) to re-iterate the loop on timeout recovery",
1429
1663
  );
1430
1664
  });
1431
1665