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
@@ -10,7 +10,7 @@ import { loadFile, saveFile } from "./files.js";
10
10
  import { isDbAvailable, getMilestoneSlices } from "./gsd-db.js";
11
11
  import { parseRoadmapSlices } from "./roadmap-slices.js";
12
12
  import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
13
- import { buildSkillActivationBlock } from "./auto-prompts.js";
13
+ import { buildDiscussMilestonePrompt, buildSkillActivationBlock } from "./auto-prompts.js";
14
14
  import { deriveState } from "./state.js";
15
15
  import { invalidateAllCaches } from "./cache.js";
16
16
  import { startAutoDetached } from "./auto.js";
@@ -27,7 +27,7 @@ import { isInheritedRepo } from "./repo-identity.js";
27
27
  import { ensureGitignore, ensurePreferences, untrackRuntimeFiles } from "./gitignore.js";
28
28
  import { loadEffectiveGSDPreferences } from "./preferences.js";
29
29
  import { resolveUokFlags } from "./uok/flags.js";
30
- import { ensurePlanV2Graph } from "./uok/plan-v2.js";
30
+ import { ensurePlanV2Graph, isMissingFinalizedContextResult } from "./uok/plan-v2.js";
31
31
  import { detectProjectState } from "./detection.js";
32
32
  import { showProjectInit, offerMigration } from "./init-wizard.js";
33
33
  import { validateDirectory } from "./validate-directory.js";
@@ -65,20 +65,30 @@ function runPlanV2Gate(ctx, basePath, state) {
65
65
  const prefs = loadEffectiveGSDPreferences()?.preferences;
66
66
  const uokFlags = resolveUokFlags(prefs);
67
67
  if (!uokFlags.planV2 || !needsPlanV2Gate(state))
68
- return true;
68
+ return "pass";
69
69
  const compiled = ensurePlanV2Graph(basePath, state);
70
70
  if (!compiled.ok) {
71
+ if (isMissingFinalizedContextResult(compiled)) {
72
+ return "recover-missing-context";
73
+ }
71
74
  const reason = compiled.reason ?? "plan-v2 compilation failed";
72
- ctx.ui.notify(`Plan gate failed-closed: ${reason}. Complete plan/discuss artifacts before execution.`, "error");
73
- return false;
75
+ ctx.ui.notify(`Plan gate failed-closed: ${reason}. Complete plan/discuss artifacts before execution.\n\nIf this keeps happening, try: /gsd doctor heal`, "error");
76
+ return "block";
74
77
  }
75
- return true;
78
+ return "pass";
76
79
  }
77
80
  // ─── Commit Instruction Helpers ──────────────────────────────────────────────
78
81
  /** Build commit instruction for planning prompts. .gsd/ is managed externally and always gitignored. */
79
82
  function buildDocsCommitInstruction(_message) {
80
83
  return "Do not commit planning artifacts — .gsd/ is managed externally.";
81
84
  }
85
+ // #4573: cap for how many times we nudge the LLM after a premature ready
86
+ // phrase before giving up and asking the user to re-run /gsd.
87
+ const MAX_READY_REJECTS = 2;
88
+ // #4573: matches the canonical ready phrase the discuss prompt asks the LLM
89
+ // to emit. Accepts any M-prefixed milestone ID (three digits + optional
90
+ // suffix) with optional trailing punctuation.
91
+ const READY_PHRASE_RE = /\bMilestone\s+M\d{3}[A-Z0-9-]*\s+ready\.?/i;
82
92
  const pendingAutoStartMap = new Map();
83
93
  /**
84
94
  * Backward-compat bridge: returns a mutable reference to the entry matching
@@ -225,6 +235,188 @@ export function checkAutoStartAfterDiscuss() {
225
235
  startAutoDetached(ctx, pi, basePath, false, { step });
226
236
  return true;
227
237
  }
238
+ /**
239
+ * Extract the concatenated text content from an assistant message, whether it
240
+ * stores content as a string or as an array of text blocks.
241
+ */
242
+ function extractAssistantText(msg) {
243
+ if (!msg)
244
+ return "";
245
+ const content = msg.content;
246
+ if (typeof content === "string")
247
+ return content;
248
+ if (!Array.isArray(content))
249
+ return "";
250
+ const parts = [];
251
+ for (const block of content) {
252
+ if (!block || typeof block !== "object")
253
+ continue;
254
+ if (block.type === "text" && typeof block.text === "string")
255
+ parts.push(block.text);
256
+ }
257
+ return parts.join("\n");
258
+ }
259
+ /**
260
+ * Return true if the assistant message contains any tool-use block.
261
+ */
262
+ function hasToolUse(msg) {
263
+ if (!msg)
264
+ return false;
265
+ const content = msg.content;
266
+ if (!Array.isArray(content))
267
+ return false;
268
+ return content.some((b) => b && typeof b === "object" && (b.type === "tool_use" || b.type === "tool-use"));
269
+ }
270
+ /**
271
+ * #4573 — Detect and recover from the "ready phrase without files" failure mode.
272
+ *
273
+ * When the LLM emits "Milestone {{id}} ready." but has not written CONTEXT.md
274
+ * or ROADMAP.md, `checkAutoStartAfterDiscuss()` silently returns false and the
275
+ * next /gsd invocation loops into the "All milestones complete" warning.
276
+ *
277
+ * This function, called from `handleAgentEnd` after `checkAutoStartAfterDiscuss`
278
+ * returns false, pattern-matches the ready phrase on the last assistant message.
279
+ * If it fired AND neither CONTEXT.md nor ROADMAP.md exists, it:
280
+ * 1. Notifies the user that the signal was rejected.
281
+ * 2. Injects a system message via `pi.sendMessage(..., {triggerTurn:true})`
282
+ * telling the LLM the signal was premature and to emit the writes now.
283
+ * 3. Caps at `MAX_READY_REJECTS` per-entry; beyond that, gives up and asks
284
+ * the user to re-run /gsd.
285
+ *
286
+ * Returns true when a nudge (or give-up) was emitted, signaling the caller to
287
+ * skip `resolveAgentEnd`.
288
+ */
289
+ export function maybeHandleReadyPhraseWithoutFiles(event) {
290
+ const entry = _getPendingAutoStart();
291
+ if (!entry)
292
+ return false;
293
+ const { ctx, pi, basePath, milestoneId } = entry;
294
+ // Gate: last assistant message must contain the ready phrase
295
+ const lastMsg = event.messages[event.messages.length - 1];
296
+ const text = extractAssistantText(lastMsg);
297
+ if (!READY_PHRASE_RE.test(text))
298
+ return false;
299
+ // Gate: artifacts must still be missing — if they exist, the happy path
300
+ // already fired and we have nothing to do.
301
+ const contextFile = resolveMilestoneFile(basePath, milestoneId, "CONTEXT");
302
+ const roadmapFile = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
303
+ if (contextFile || roadmapFile)
304
+ return false;
305
+ entry.readyRejectCount = (entry.readyRejectCount ?? 0) + 1;
306
+ if (entry.readyRejectCount > MAX_READY_REJECTS) {
307
+ // Give up: clear state and tell the user to re-run /gsd. Avoids an
308
+ // infinite nudge loop when the LLM never produces the writes.
309
+ pendingAutoStartMap.delete(basePath);
310
+ ctx.ui.notify(`Milestone ${milestoneId}: LLM signaled "ready" ${entry.readyRejectCount} times without writing files. ` +
311
+ `Stopping auto-nudge. Run /gsd to try again.`, "error");
312
+ return true;
313
+ }
314
+ ctx.ui.notify(`Milestone ${milestoneId}: "ready" signal rejected — CONTEXT.md and ROADMAP.md are missing. Asking the LLM to complete the writes.`, "warning");
315
+ const nudge = `You emitted "Milestone ${milestoneId} ready." but neither ` +
316
+ `.gsd/milestones/${milestoneId}/${milestoneId}-CONTEXT.md nor ` +
317
+ `.gsd/milestones/${milestoneId}/${milestoneId}-ROADMAP.md exists on disk. ` +
318
+ `The ready phrase is a POST-WRITE signal and has been rejected. ` +
319
+ `In this turn: (1) write PROJECT.md, REQUIREMENTS.md, and the milestone ` +
320
+ `CONTEXT.md, (2) call gsd_plan_milestone, then (3) emit the ready phrase. ` +
321
+ `Do not describe these steps — execute them as tool calls. ` +
322
+ `This is retry ${entry.readyRejectCount}/${MAX_READY_REJECTS}; further ` +
323
+ `premature signals will clear the session.`;
324
+ try {
325
+ pi.sendMessage({ customType: "gsd-ready-no-files", content: nudge, display: false }, { triggerTurn: true });
326
+ }
327
+ catch (e) {
328
+ logWarning("guided", `ready-phrase nudge sendMessage failed: ${e.message}`);
329
+ return false;
330
+ }
331
+ return true;
332
+ }
333
+ /**
334
+ * #4573 — Detect and recover from the "announces tool, never calls it" stall.
335
+ *
336
+ * The LLM emits text like "I'll now write the CONTEXT.md file" but the turn
337
+ * ends with zero tool-use blocks. The harness has no post-turn tool-call
338
+ * validation, so the unit promise resolves and the user sees a stalled state.
339
+ *
340
+ * This function, called from `handleAgentEnd`, inspects the last assistant
341
+ * message. If ALL of the following are true, it injects a recovery message:
342
+ * - Text-only (no tool-use blocks)
343
+ * - Contains a commit-intent phrase ("I'll write", "I'll call", etc.)
344
+ * - Auto-mode is active OR a discussion autostart is pending
345
+ * - `emptyTurnRetryCount` is under the cap
346
+ *
347
+ * Per-handler state is held on the `PendingAutoStartEntry` when present, and
348
+ * on a module-level map otherwise. The counter resets on any successful
349
+ * tool-use turn via `resetEmptyTurnCounter`.
350
+ */
351
+ const emptyTurnCounterByBase = new Map();
352
+ const MAX_EMPTY_TURN_RETRIES = 2;
353
+ // Phrases that indicate the LLM is about to do something but has not yet.
354
+ // Kept tight to avoid flagging legitimate narration like "I'll wait for your answer."
355
+ const COMMIT_INTENT_RE = /\b(?:I['’]ll|I will|Next,? I['’]ll|Now I['’]ll|Let me|I['’]m going to|I am going to)\s+(?:now\s+)?(?:write|create|call|invoke|update|add|make|run|execute|generate|produce|emit|compose|implement|save|apply|commit)\b/i;
356
+ /**
357
+ * Reset the empty-turn counter for a basePath after a successful tool-use turn.
358
+ * Called from handleAgentEnd when the last message contains tool_use blocks.
359
+ */
360
+ export function resetEmptyTurnCounter(basePath) {
361
+ if (basePath)
362
+ emptyTurnCounterByBase.delete(basePath);
363
+ else
364
+ emptyTurnCounterByBase.clear();
365
+ }
366
+ export function maybeHandleEmptyIntentTurn(event, isAuto) {
367
+ // Gate: only fire when there is system-driven work in flight. Interactive
368
+ // /gsd discuss (user-driven) produces legitimate text-only turns.
369
+ if (!isAuto && pendingAutoStartMap.size === 0)
370
+ return false;
371
+ const lastMsg = event.messages[event.messages.length - 1];
372
+ if (!lastMsg)
373
+ return false;
374
+ if (hasToolUse(lastMsg))
375
+ return false;
376
+ const text = extractAssistantText(lastMsg).trim();
377
+ if (!text)
378
+ return false;
379
+ // Skip if the LLM is emitting the ready phrase — that is the ready-no-files
380
+ // path, handled by maybeHandleReadyPhraseWithoutFiles.
381
+ if (READY_PHRASE_RE.test(text))
382
+ return false;
383
+ // Skip if the LLM is clearly handing back to the user. Keep the heuristic
384
+ // tight: a trailing question mark on the last non-empty line is the common
385
+ // signal for "I asked the user a question and stopped."
386
+ const lines = text.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
387
+ const lastLine = lines[lines.length - 1] ?? "";
388
+ if (lastLine.endsWith("?"))
389
+ return false;
390
+ // Must contain a commit-intent phrase — this is the stall we care about.
391
+ if (!COMMIT_INTENT_RE.test(text))
392
+ return false;
393
+ // Resolve the target basePath + pi for injection. Prefer the pending
394
+ // autostart entry (discuss flow); otherwise we cannot inject.
395
+ const entry = _getPendingAutoStart();
396
+ if (!entry)
397
+ return false;
398
+ const { ctx, pi, basePath } = entry;
399
+ const count = (emptyTurnCounterByBase.get(basePath) ?? 0) + 1;
400
+ emptyTurnCounterByBase.set(basePath, count);
401
+ if (count > MAX_EMPTY_TURN_RETRIES) {
402
+ ctx.ui.notify(`Empty-turn recovery: LLM announced intent ${count} times without calling any tool. ` +
403
+ `Stopping auto-nudge.`, "error");
404
+ return false; // let the normal flow resolve/pause the unit
405
+ }
406
+ ctx.ui.notify(`Empty-turn detected: LLM announced intent but called no tool. Prompting it to execute.`, "info");
407
+ const nudge = `Your last turn announced an action (e.g. "I'll write…" or "Let me call…") ` +
408
+ `but contained no tool call. The system records zero tool-use blocks for ` +
409
+ `that turn. Execute the announced action NOW as a tool call in this turn. ` +
410
+ `Do not describe it again. Retry ${count}/${MAX_EMPTY_TURN_RETRIES}.`;
411
+ try {
412
+ pi.sendMessage({ customType: "gsd-empty-turn-recovery", content: nudge, display: false }, { triggerTurn: true });
413
+ }
414
+ catch (e) {
415
+ logWarning("guided", `empty-turn nudge sendMessage failed: ${e.message}`);
416
+ return false;
417
+ }
418
+ return true;
419
+ }
228
420
  /**
229
421
  * Extract milestone IDs from PROJECT.md milestone sequence table.
230
422
  * Looks for rows like "| M001 | Name | Status |" and extracts the ID column.
@@ -480,8 +672,13 @@ export async function showHeadlessMilestoneCreation(ctx, pi, basePath, seedConte
480
672
  const prompt = buildHeadlessDiscussPrompt(nextId, seedContext, basePath);
481
673
  // Set pending auto start (auto-mode triggers on "Milestone X ready." via checkAutoStartAfterDiscuss)
482
674
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, createdAt: Date.now() });
483
- // Dispatch headless milestone creation is a planning activity
484
- await dispatchWorkflow(pi, prompt, "gsd-run", ctx, "plan-milestone");
675
+ // Dispatch as discuss-milestone. The LLM writes PROJECT.md, REQUIREMENTS.md,
676
+ // and CONTEXT.md, then calls gsd_plan_milestone — this is semantically the
677
+ // discuss path, just non-interactive. Using "plan-milestone" here caused
678
+ // model/tool routing to skip discuss-flow tool scoping and
679
+ // `checkAutoStartAfterDiscuss` guardrails that rely on the
680
+ // "discuss-"-prefixed unitType.
681
+ await dispatchWorkflow(pi, prompt, "gsd-run", ctx, "discuss-milestone");
485
682
  }
486
683
  // ─── Discuss Flow ─────────────────────────────────────────────────────────────
487
684
  /**
@@ -1133,7 +1330,8 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1133
1330
  catch (err) {
1134
1331
  logWarning("guided", `STATE.md rebuild failed: ${err.message}`);
1135
1332
  }
1136
- if (!runPlanV2Gate(ctx, basePath, state))
1333
+ const planV2GateDecision = runPlanV2Gate(ctx, basePath, state);
1334
+ if (planV2GateDecision === "block")
1137
1335
  return;
1138
1336
  if (!state.activeMilestone?.id) {
1139
1337
  // Guard: if a discuss session is already in flight, don't re-inject the prompt.
@@ -1208,6 +1406,11 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1208
1406
  }
1209
1407
  const milestoneId = state.activeMilestone.id;
1210
1408
  const milestoneTitle = state.activeMilestone.title;
1409
+ if (planV2GateDecision === "recover-missing-context") {
1410
+ pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId, step: stepMode, createdAt: Date.now() });
1411
+ await dispatchWorkflow(pi, await buildDiscussMilestonePrompt(milestoneId, milestoneTitle, basePath, getStructuredQuestionsAvailability(pi, ctx)), "gsd-discuss", ctx, "discuss-milestone");
1412
+ return;
1413
+ }
1211
1414
  // ── All milestones complete → New milestone ──────────────────────────
1212
1415
  if (state.phase === "complete") {
1213
1416
  const choice = await showNextAction(ctx, {
@@ -91,6 +91,7 @@ export function initHealthWidget(ctx) {
91
91
  let data = initialData;
92
92
  let cachedLines;
93
93
  let refreshInFlight = false;
94
+ let isDisposed = false;
94
95
  const refresh = async () => {
95
96
  if (refreshInFlight)
96
97
  return;
@@ -98,7 +99,8 @@ export function initHealthWidget(ctx) {
98
99
  try {
99
100
  data = loadHealthWidgetData(basePath);
100
101
  cachedLines = undefined;
101
- _tui.requestRender();
102
+ if (!isDisposed)
103
+ _tui.requestRender();
102
104
  }
103
105
  catch { /* non-fatal */ }
104
106
  finally {
@@ -122,6 +124,7 @@ export function initHealthWidget(ctx) {
122
124
  },
123
125
  invalidate() { cachedLines = undefined; cachedWidth = undefined; },
124
126
  dispose() {
127
+ isDisposed = true;
125
128
  clearInterval(refreshTimer);
126
129
  },
127
130
  };
@@ -11,8 +11,10 @@
11
11
  * - queryJournal() enables programmatic filtering by flowId, eventType, unitId, time range
12
12
  * - Silent failure: journal writes never throw — absence of events is the failure signal
13
13
  */
14
- import { appendFileSync, mkdirSync, readdirSync, readFileSync } from "node:fs";
14
+ import { appendFileSync, closeSync, existsSync, mkdirSync, openSync, readdirSync, readFileSync, } from "node:fs";
15
15
  import { join } from "node:path";
16
+ import { isStaleWrite } from "./auto/turn-epoch.js";
17
+ import { withFileLockSync } from "./file-lock.js";
16
18
  import { gsdRoot } from "./paths.js";
17
19
  import { buildAuditEnvelope, emitUokAuditEvent } from "./uok/audit.js";
18
20
  import { isUnifiedAuditEnabled } from "./uok/audit-toggle.js";
@@ -26,12 +28,25 @@ import { isUnifiedAuditEnabled } from "./uok/audit-toggle.js";
26
28
  * Never throws — all errors are silently caught.
27
29
  */
28
30
  export function emitJournalEvent(basePath, entry) {
31
+ // Drop writes from a turn superseded by timeout recovery / cancellation.
32
+ // See auto/turn-epoch.ts for the full rationale.
33
+ if (isStaleWrite("journal"))
34
+ return;
29
35
  try {
30
36
  const journalDir = join(gsdRoot(basePath), "journal");
31
37
  mkdirSync(journalDir, { recursive: true });
32
38
  const dateStr = entry.ts.slice(0, 10);
33
39
  const filePath = join(journalDir, `${dateStr}.jsonl`);
34
- appendFileSync(filePath, JSON.stringify(entry) + "\n");
40
+ // Ensure file exists so proper-lockfile can acquire a lock against it.
41
+ if (!existsSync(filePath))
42
+ closeSync(openSync(filePath, "a"));
43
+ // onLocked: "skip" — journal writes are best-effort. POSIX O_APPEND
44
+ // atomicity still protects small entries; the lock mainly serializes
45
+ // larger writes and gives cross-process exclusivity on platforms where
46
+ // O_APPEND semantics are weaker (Windows).
47
+ withFileLockSync(filePath, () => {
48
+ appendFileSync(filePath, JSON.stringify(entry) + "\n");
49
+ }, { onLocked: "skip" });
35
50
  }
36
51
  catch {
37
52
  // Silent failure — journal must never break auto-mode
@@ -28,6 +28,8 @@ export const PROVIDER_REGISTRY = [
28
28
  { id: "xai", label: "xAI (Grok)", category: "llm", envVar: "XAI_API_KEY", dashboardUrl: "console.x.ai" },
29
29
  { id: "openrouter", label: "OpenRouter", category: "llm", envVar: "OPENROUTER_API_KEY", dashboardUrl: "openrouter.ai/keys" },
30
30
  { id: "mistral", label: "Mistral", category: "llm", envVar: "MISTRAL_API_KEY", dashboardUrl: "console.mistral.ai" },
31
+ { id: "minimax", label: "MiniMax", category: "llm", envVar: "MINIMAX_API_KEY", dashboardUrl: "platform.minimax.io" },
32
+ { id: "minimax-cn", label: "MiniMax CN", category: "llm", envVar: "MINIMAX_CN_API_KEY", dashboardUrl: "platform.minimax.io" },
31
33
  { id: "ollama-cloud", label: "Ollama Cloud", category: "llm", envVar: "OLLAMA_API_KEY" },
32
34
  { id: "custom-openai", label: "Custom (OpenAI-compat)", category: "llm", envVar: "CUSTOM_OPENAI_API_KEY" },
33
35
  { id: "cerebras", label: "Cerebras", category: "llm", envVar: "CEREBRAS_API_KEY" },
@@ -393,6 +395,26 @@ const TEST_ENDPOINTS = {
393
395
  url: "https://api.mistral.ai/v1/models",
394
396
  headers: (key) => ({ Authorization: `Bearer ${key}` }),
395
397
  },
398
+ minimax: {
399
+ url: "https://api.minimax.io/anthropic/v1/messages",
400
+ method: "POST",
401
+ headers: (key) => ({
402
+ "x-api-key": key,
403
+ "anthropic-version": "2023-06-01",
404
+ "content-type": "application/json",
405
+ }),
406
+ body: JSON.stringify({ model: "MiniMax-M2.7", max_tokens: 1, messages: [{ role: "user", content: "hi" }] }),
407
+ },
408
+ "minimax-cn": {
409
+ url: "https://api.minimaxi.com/anthropic/v1/messages",
410
+ method: "POST",
411
+ headers: (key) => ({
412
+ "x-api-key": key,
413
+ "anthropic-version": "2023-06-01",
414
+ "content-type": "application/json",
415
+ }),
416
+ body: JSON.stringify({ model: "MiniMax-M2.7", max_tokens: 1, messages: [{ role: "user", content: "hi" }] }),
417
+ },
396
418
  openrouter: {
397
419
  url: "https://openrouter.ai/api/v1/models",
398
420
  headers: (key) => ({ Authorization: `Bearer ${key}` }),
@@ -18,6 +18,18 @@ import { loadQueueOrder, saveQueueOrder } from "./queue-order.js";
18
18
  import { deleteMilestone, getMilestone, isDbAvailable, updateMilestoneStatus } from "./gsd-db.js";
19
19
  import { removeWorktree } from "./worktree-manager.js";
20
20
  import { logWarning } from "./workflow-logger.js";
21
+ import { isAutoActive } from "./auto.js";
22
+ /**
23
+ * Writer-side assert for mutations that race with auto-mode's squash merge (#4704).
24
+ * Auto-mode is confirmed not to call parkMilestone/discardMilestone/unparkMilestone
25
+ * internally — these throws only surface invariant violations from new or forgotten
26
+ * call sites, which is the correct failure mode to catch loudly.
27
+ */
28
+ function assertNotAutoActive(action) {
29
+ if (isAutoActive()) {
30
+ throw new Error(`${action} cannot run while auto-mode is active. Stop auto-mode first with /gsd stop.`);
31
+ }
32
+ }
21
33
  // ─── Park ──────────────────────────────────────────────────────────────────
22
34
  /**
23
35
  * Park a milestone — creates a PARKED.md marker file with reason and timestamp.
@@ -25,6 +37,7 @@ import { logWarning } from "./workflow-logger.js";
25
37
  * Returns true if successfully parked, false if milestone not found or already parked.
26
38
  */
27
39
  export function parkMilestone(basePath, milestoneId, reason) {
40
+ assertNotAutoActive("park milestone");
28
41
  const mDir = resolveMilestonePath(basePath, milestoneId);
29
42
  if (!mDir || !existsSync(mDir))
30
43
  return false;
@@ -65,6 +78,7 @@ export function parkMilestone(basePath, milestoneId, reason) {
65
78
  * Returns true if successfully unparked, false if milestone not found or not parked.
66
79
  */
67
80
  export function unparkMilestone(basePath, milestoneId) {
81
+ assertNotAutoActive("unpark milestone");
68
82
  const mDir = resolveMilestonePath(basePath, milestoneId);
69
83
  if (!mDir || !existsSync(mDir))
70
84
  return false;
@@ -97,6 +111,7 @@ export function unparkMilestone(basePath, milestoneId) {
97
111
  * Returns true if successfully discarded, false if milestone not found.
98
112
  */
99
113
  export function discardMilestone(basePath, milestoneId) {
114
+ assertNotAutoActive("discard milestone");
100
115
  const mDir = resolveMilestonePath(basePath, milestoneId);
101
116
  if (!mDir || !existsSync(mDir))
102
117
  return false;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Shared milestone SUMMARY classifier.
3
+ *
4
+ * SUMMARY presence alone is not enough to prove milestone completion: recovery
5
+ * and blocker paths also write SUMMARY files. Keep this leaf module free of
6
+ * state/auto imports so state derivation, dispatch guards, and recovery can
7
+ * share one definition without cycles.
8
+ */
9
+ import { splitFrontmatter, parseFrontmatterMap } from "../shared/frontmatter.js";
10
+ import { isClosedStatus } from "./status-guards.js";
11
+ export function classifyMilestoneSummaryContent(content) {
12
+ const [fmLines] = splitFrontmatter(content);
13
+ const fm = fmLines ? parseFrontmatterMap(fmLines) : null;
14
+ const rawStatus = typeof fm?.status === "string" ? fm.status.trim().toLowerCase() : "";
15
+ if (rawStatus) {
16
+ if (isClosedStatus(rawStatus))
17
+ return "success";
18
+ if (["active", "pending", "blocked", "failed", "failure", "incomplete"].includes(rawStatus)) {
19
+ return "failure";
20
+ }
21
+ }
22
+ const failureSignal = /(?:^|\n)\s*#\s*BLOCKER\b/i.test(content)
23
+ || /auto-mode recovery failed/i.test(content)
24
+ || /verification\s+failed/i.test(content)
25
+ || /(?:^|\n)\s*(?:status|verdict|outcome|result)\s*[:=-]\s*not complete\b/i.test(content);
26
+ if (failureSignal)
27
+ return "failure";
28
+ return "unknown";
29
+ }
30
+ /**
31
+ * Legacy-compatible terminal check for state derivation.
32
+ * Unknown summaries remain terminal to preserve old handwritten SUMMARY files;
33
+ * explicit failure summaries do not.
34
+ */
35
+ export function isTerminalMilestoneSummaryContent(content) {
36
+ return classifyMilestoneSummaryContent(content) !== "failure";
37
+ }
@@ -440,6 +440,20 @@ function getModelCost(modelId) {
440
440
  function bareModelId(modelId) {
441
441
  return modelId.includes("/") ? modelId.split("/").pop() : modelId;
442
442
  }
443
+ // ─── Provider-specific Tool Limits ─────────────────────────────────────────
444
+ /**
445
+ * Groq enforces a hard limit of 128 tools per request.
446
+ * Requests exceeding this limit receive a 400 error:
447
+ * "maximum number of items is 128"
448
+ * @see https://console.groq.com/docs/tool-use
449
+ */
450
+ export const GROQ_MAX_TOOLS = 128;
451
+ /**
452
+ * Provider IDs that map to the Groq API backend.
453
+ * Used to detect Groq at the GSD routing layer where only the provider string
454
+ * is available (the pi-ai openai-completions adapter is shared across providers).
455
+ */
456
+ const GROQ_PROVIDER_IDS = new Set(["groq"]);
443
457
  // ─── Tool Compatibility Filter (ADR-005 Phase 3) ───────────────────────────
444
458
  /**
445
459
  * Check if a tool is compatible with a provider's capabilities.
@@ -461,8 +475,14 @@ export function isToolCompatibleWithProvider(toolName, providerCaps) {
461
475
  /**
462
476
  * Filter a list of tool names to only those compatible with a provider.
463
477
  * Used by the routing pipeline to adjust tool sets when switching providers.
478
+ *
479
+ * @param toolNames - The full list of active tool names to filter.
480
+ * @param providerApi - The pi-ai API string (e.g. "openai-completions").
481
+ * @param provider - Optional provider ID (e.g. "groq"). Used to apply
482
+ * provider-specific limits that can't be expressed as API-level capabilities
483
+ * (e.g. Groq's 128-tool hard limit on the shared openai-completions adapter).
464
484
  */
465
- export function filterToolsForProvider(toolNames, providerApi) {
485
+ export function filterToolsForProvider(toolNames, providerApi, provider) {
466
486
  const providerCaps = getProviderCapabilities(providerApi);
467
487
  // Provider doesn't support tool calling at all
468
488
  if (!providerCaps.toolCalling) {
@@ -478,6 +498,14 @@ export function filterToolsForProvider(toolNames, providerApi) {
478
498
  filtered.push(name);
479
499
  }
480
500
  }
501
+ // Groq enforces a hard limit of 128 tools per request (#4376).
502
+ // Trim the compatible list to GROQ_MAX_TOOLS and move the excess to filtered.
503
+ if (provider && GROQ_PROVIDER_IDS.has(provider) && compatible.length > GROQ_MAX_TOOLS) {
504
+ const trimmed = compatible.splice(GROQ_MAX_TOOLS);
505
+ filtered.push(...trimmed);
506
+ console.warn(`[gsd] Groq tool limit: ${compatible.length + trimmed.length} tools active but Groq allows at most ${GROQ_MAX_TOOLS}. ` +
507
+ `Trimming to the first ${GROQ_MAX_TOOLS} tools. Removed: ${trimmed.join(", ")}`);
508
+ }
481
509
  return { compatible, filtered };
482
510
  }
483
511
  /**
@@ -486,8 +514,13 @@ export function filterToolsForProvider(toolNames, providerApi) {
486
514
  *
487
515
  * This is a hard filter only — it removes tools that would fail at the
488
516
  * provider level. It does NOT remove tools based on soft heuristics.
517
+ *
518
+ * @param activeToolNames - The full list of currently active tool names.
519
+ * @param selectedModelApi - The pi-ai API string for the selected model.
520
+ * @param provider - Optional provider ID (e.g. "groq") for provider-specific
521
+ * limits beyond what the API-level capability profile expresses.
489
522
  */
490
- export function adjustToolSet(activeToolNames, selectedModelApi) {
491
- const { compatible, filtered } = filterToolsForProvider(activeToolNames, selectedModelApi);
523
+ export function adjustToolSet(activeToolNames, selectedModelApi, provider) {
524
+ const { compatible, filtered } = filterToolsForProvider(activeToolNames, selectedModelApi, provider);
492
525
  return { toolNames: compatible, removedTools: filtered };
493
526
  }
@@ -2,7 +2,6 @@
2
2
  // Cross-platform desktop notifications for auto-mode events.
3
3
  import { execFileSync } from "node:child_process";
4
4
  import { loadEffectiveGSDPreferences } from "./preferences.js";
5
- import { CmuxClient, emitOsc777Notification, resolveCmuxConfig } from "../cmux/index.js";
6
5
  import { sendRemoteNotification } from "../remote-questions/notify.js";
7
6
  /**
8
7
  * Send a native desktop notification. Non-blocking, non-fatal.
@@ -20,22 +19,37 @@ export function sendDesktopNotification(title, message, level = "info", kind = "
20
19
  void sendRemoteNotification(title, message).catch(() => { });
21
20
  if (!shouldSendDesktopNotification(kind, loaded?.notifications))
22
21
  return;
23
- const cmux = resolveCmuxConfig(loaded);
24
- if (cmux.notifications) {
25
- const delivered = CmuxClient.fromPreferences(loaded).notify(title, message);
26
- if (delivered)
27
- return;
28
- emitOsc777Notification(title, message);
29
- }
30
- try {
31
- const command = buildDesktopNotificationCommand(process.platform, title, message, level);
32
- if (!command)
22
+ // cmux delivery and desktop delivery are independent — if cmux import or
23
+ // delivery fails, we must still attempt the native desktop notification.
24
+ const runCmux = async () => {
25
+ try {
26
+ const { CmuxClient, emitOsc777Notification, resolveCmuxConfig } = await import("../cmux/index.js");
27
+ const cmux = resolveCmuxConfig(loaded);
28
+ if (cmux.notifications) {
29
+ const delivered = CmuxClient.fromPreferences(loaded).notify(title, message);
30
+ if (delivered)
31
+ return true;
32
+ emitOsc777Notification(title, message);
33
+ }
34
+ }
35
+ catch {
36
+ // cmux unavailable — fall through to desktop notification
37
+ }
38
+ return false;
39
+ };
40
+ void runCmux().then((deliveredByCmux) => {
41
+ if (deliveredByCmux)
33
42
  return;
34
- execFileSync(command.file, command.args, { timeout: 3000, stdio: "ignore" });
35
- }
36
- catch {
37
- // Non-fatal — desktop notifications are best-effort
38
- }
43
+ try {
44
+ const command = buildDesktopNotificationCommand(process.platform, title, message, level);
45
+ if (!command)
46
+ return;
47
+ execFileSync(command.file, command.args, { timeout: 3000, stdio: "ignore" });
48
+ }
49
+ catch {
50
+ // Non-fatal — desktop notifications are best-effort
51
+ }
52
+ }).catch(() => { });
39
53
  }
40
54
  export function shouldSendDesktopNotification(kind, preferences = loadEffectiveGSDPreferences()?.preferences.notifications) {
41
55
  if (preferences?.enabled === false)
@@ -281,6 +281,15 @@ function extractPathFromAnnotation(raw) {
281
281
  if (backtickMatch) {
282
282
  return backtickMatch[2].trim();
283
283
  }
284
+ // Strip leading/trailing double or single quotes wrapping the whole value.
285
+ // Plan documents sometimes emit `"src/foo.ts"` or `'src/bar.ts'` as input
286
+ // annotations. Stripping the wrapper allows the inner path to be checked
287
+ // correctly instead of producing a false-positive "file not found" error
288
+ // for a literal string with quote characters in it (#3747).
289
+ const quoteMatch = trimmed.match(/^(["'])([^"']+)\1$/);
290
+ if (quoteMatch) {
291
+ return quoteMatch[2].trim();
292
+ }
284
293
  const annotatedMatch = trimmed.match(/^(.+?)\s+[—–-]\s+.+$/);
285
294
  if (annotatedMatch) {
286
295
  const prefix = annotatedMatch[1].trim();
@@ -343,13 +352,19 @@ function containsGlobPattern(candidate) {
343
352
  }
344
353
  /**
345
354
  * Build a set of files that will be created by tasks up to (but not including) taskIndex.
355
+ * Also includes outputs of completed tasks at any position — a completed task has already
356
+ * run and its outputs are available regardless of sequence position or disk state (#4071).
346
357
  * All paths are normalized for consistent comparison.
347
358
  */
348
359
  function getExpectedOutputsUpTo(tasks, taskIndex) {
349
360
  const outputs = new Set();
350
- for (let i = 0; i < taskIndex; i++) {
351
- for (const file of tasks[i].expected_output) {
352
- outputs.add(normalizeFilePath(file));
361
+ for (let i = 0; i < tasks.length; i++) {
362
+ const task = tasks[i];
363
+ // Include prior tasks (i < taskIndex) OR completed tasks at any position
364
+ if (i < taskIndex || task.status === "completed") {
365
+ for (const file of task.expected_output) {
366
+ outputs.add(normalizeFilePath(file));
367
+ }
353
368
  }
354
369
  }
355
370
  return outputs;
@@ -426,8 +441,14 @@ export function checkTaskOrdering(tasks, basePath) {
426
441
  const task = tasks[i];
427
442
  for (const file of task.expected_output) {
428
443
  const normalizedFile = normalizeFilePath(file);
429
- if (!fileCreators.has(normalizedFile)) {
430
- fileCreators.set(normalizedFile, { taskId: task.id, index: i, originalPath: file });
444
+ const existing = fileCreators.get(normalizedFile);
445
+ if (!existing || (!existing.completed && task.status === "completed")) {
446
+ fileCreators.set(normalizedFile, {
447
+ taskId: task.id,
448
+ index: i,
449
+ originalPath: file,
450
+ completed: task.status === "completed",
451
+ });
431
452
  }
432
453
  }
433
454
  }
@@ -451,7 +472,11 @@ export function checkTaskOrdering(tasks, basePath) {
451
472
  const creator = fileCreators.get(normalizedFile);
452
473
  const absolutePath = resolve(basePath, normalizedFile);
453
474
  const existsOnDisk = existsSync(absolutePath);
454
- if (creator && creator.index > i && !existsOnDisk) {
475
+ // Skip if the creating task has already completed its output is available
476
+ // regardless of disk state (e.g. file was a temp artifact cleaned up after
477
+ // the task ran, or a replan introduced a new earlier-sequence task that
478
+ // reads this pre-execution output). (#4071)
479
+ if (creator && creator.index > i && !existsOnDisk && !creator.completed) {
455
480
  // Task reads file that is created later — impossible ordering
456
481
  results.push({
457
482
  category: "file",