@opengsd/gsd-pi 1.0.2-dev.867e002 → 1.0.2-dev.a271e2d

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 (337) hide show
  1. package/dist/onboarding.js +22 -3
  2. package/dist/resource-loader.js +3 -1
  3. package/dist/resources/.managed-resources-content-hash +1 -1
  4. package/dist/resources/extensions/context7/index.js +12 -2
  5. package/dist/resources/extensions/get-secrets-from-user.js +16 -16
  6. package/dist/resources/extensions/google-cli/index.js +30 -0
  7. package/dist/resources/extensions/google-cli/models.js +55 -0
  8. package/dist/resources/extensions/google-cli/package.json +11 -0
  9. package/dist/resources/extensions/google-cli/readiness.js +12 -0
  10. package/dist/resources/extensions/google-cli/stream-adapter.js +191 -0
  11. package/dist/resources/extensions/gsd/auto/loop.js +62 -1
  12. package/dist/resources/extensions/gsd/auto/orchestrator.js +4 -2
  13. package/dist/resources/extensions/gsd/auto/phases.js +37 -0
  14. package/dist/resources/extensions/gsd/auto/run-unit.js +8 -0
  15. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  16. package/dist/resources/extensions/gsd/auto-dispatch.js +17 -7
  17. package/dist/resources/extensions/gsd/auto-post-unit.js +21 -11
  18. package/dist/resources/extensions/gsd/auto-prompts.js +5 -236
  19. package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
  20. package/dist/resources/extensions/gsd/auto-start.js +232 -49
  21. package/dist/resources/extensions/gsd/auto.js +6 -1
  22. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +4 -3
  23. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +7 -2
  24. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +39 -5
  25. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +17 -7
  26. package/dist/resources/extensions/gsd/bootstrap/system-context.js +3 -27
  27. package/dist/resources/extensions/gsd/closeout-recovery.js +7 -1
  28. package/dist/resources/extensions/gsd/commands/handlers/auto.js +9 -1
  29. package/dist/resources/extensions/gsd/commands-usage.js +105 -1
  30. package/dist/resources/extensions/gsd/config-overlay.js +20 -14
  31. package/dist/resources/extensions/gsd/context-overlay.js +22 -16
  32. package/dist/resources/extensions/gsd/dashboard-overlay.js +10 -23
  33. package/dist/resources/extensions/gsd/doctor-engine-checks.js +87 -0
  34. package/dist/resources/extensions/gsd/doctor-providers.js +54 -24
  35. package/dist/resources/extensions/gsd/doctor.js +6 -1
  36. package/dist/resources/extensions/gsd/git-conflict-state.js +26 -1
  37. package/dist/resources/extensions/gsd/guided-flow.js +5 -6
  38. package/dist/resources/extensions/gsd/key-manager.js +45 -13
  39. package/dist/resources/extensions/gsd/milestone-reopen-events.js +28 -0
  40. package/dist/resources/extensions/gsd/notification-overlay.js +8 -9
  41. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +15 -13
  42. package/dist/resources/extensions/gsd/preferences-skills.js +11 -4
  43. package/dist/resources/extensions/gsd/preferences.js +14 -2
  44. package/dist/resources/extensions/gsd/prompt-loader.js +2 -0
  45. package/dist/resources/extensions/gsd/prompts/discuss.md +4 -2
  46. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
  47. package/dist/resources/extensions/gsd/prompts/system.md +1 -3
  48. package/dist/resources/extensions/gsd/queue-reorder-ui.js +28 -18
  49. package/dist/resources/extensions/gsd/repository-registry.js +3 -1
  50. package/dist/resources/extensions/gsd/safety/evidence-collector.js +11 -4
  51. package/dist/resources/extensions/gsd/skill-activation.js +233 -0
  52. package/dist/resources/extensions/gsd/skill-catalog.data.js +820 -0
  53. package/dist/resources/extensions/gsd/skill-catalog.install.js +179 -0
  54. package/dist/resources/extensions/gsd/skill-catalog.js +5 -1028
  55. package/dist/resources/extensions/gsd/skill-discovery.js +121 -79
  56. package/dist/resources/extensions/gsd/skill-scope.js +52 -0
  57. package/dist/resources/extensions/gsd/skill-telemetry.js +6 -39
  58. package/dist/resources/extensions/gsd/skills.js +60 -0
  59. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +351 -0
  60. package/dist/resources/extensions/gsd/state-reconciliation/index.js +41 -0
  61. package/dist/resources/extensions/gsd/state-reconciliation/registry.js +4 -0
  62. package/dist/resources/extensions/gsd/tools/complete-task.js +9 -0
  63. package/dist/resources/extensions/gsd/tools/exec-tool.js +42 -8
  64. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +63 -2
  65. package/dist/resources/extensions/gsd/tui/render-kit.js +51 -0
  66. package/dist/resources/extensions/gsd/unit-context-manifest.js +35 -26
  67. package/dist/resources/extensions/gsd/user-input-boundary.js +1 -1
  68. package/dist/resources/extensions/gsd/vision-ask.js +22 -0
  69. package/dist/resources/extensions/gsd/visualizer-overlay.js +8 -36
  70. package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -3
  71. package/dist/resources/extensions/search-the-web/native-search.js +57 -8
  72. package/dist/resources/extensions/shared/confirm-ui.js +9 -6
  73. package/dist/resources/extensions/shared/dialog-frame.js +42 -0
  74. package/dist/resources/extensions/shared/interview-ui.js +42 -30
  75. package/dist/resources/extensions/shared/next-action-ui.js +6 -6
  76. package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +1 -1
  77. package/dist/web/standalone/.next/BUILD_ID +1 -1
  78. package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
  79. package/dist/web/standalone/.next/build-manifest.json +2 -2
  80. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  81. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  82. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  90. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/index.html +1 -1
  98. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app-paths-manifest.json +6 -6
  105. package/dist/web/standalone/.next/server/chunks/1834.js +2 -2
  106. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  108. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  109. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  110. package/package.json +1 -1
  111. package/packages/cloud-mcp-gateway/package.json +2 -2
  112. package/packages/contracts/dist/rpc.test.js +5 -0
  113. package/packages/contracts/dist/rpc.test.js.map +1 -1
  114. package/packages/contracts/dist/workflow.d.ts +7 -0
  115. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  116. package/packages/contracts/dist/workflow.js +8 -0
  117. package/packages/contracts/dist/workflow.js.map +1 -1
  118. package/packages/contracts/dist/workflow.test.js +1 -0
  119. package/packages/contracts/dist/workflow.test.js.map +1 -1
  120. package/packages/contracts/package.json +1 -1
  121. package/packages/daemon/package.json +4 -4
  122. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +1 -0
  123. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
  124. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +22 -8
  125. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
  126. package/packages/gsd-agent-core/package.json +5 -5
  127. package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.d.ts +12 -0
  128. package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.d.ts.map +1 -0
  129. package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.js +45 -0
  130. package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.js.map +1 -0
  131. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.d.ts +3 -2
  132. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  133. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.js +11 -11
  134. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.js.map +1 -1
  135. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.d.ts +3 -3
  136. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  137. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.js +13 -11
  138. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.js.map +1 -1
  139. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.d.ts +3 -3
  140. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  141. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.js +12 -10
  142. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.js.map +1 -1
  143. package/packages/gsd-agent-modes/dist/modes/interactive/components/index.d.ts +1 -0
  144. package/packages/gsd-agent-modes/dist/modes/interactive/components/index.d.ts.map +1 -1
  145. package/packages/gsd-agent-modes/dist/modes/interactive/components/index.js +1 -0
  146. package/packages/gsd-agent-modes/dist/modes/interactive/components/index.js.map +1 -1
  147. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts +1 -1
  148. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  149. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js +2 -2
  150. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js.map +1 -1
  151. package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.d.ts +6 -1
  152. package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  153. package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.js +9 -6
  154. package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  155. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
  156. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +0 -1
  157. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
  158. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts +3 -0
  159. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
  160. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +144 -2
  161. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
  162. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.d.ts.map +1 -1
  163. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.js +2 -14
  164. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.js.map +1 -1
  165. package/packages/gsd-agent-modes/package.json +7 -7
  166. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  167. package/packages/mcp-server/dist/workflow-tools.js +28 -5
  168. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  169. package/packages/mcp-server/package.json +3 -3
  170. package/packages/native/package.json +1 -1
  171. package/packages/pi-agent-core/dist/harness/skills.d.ts.map +1 -1
  172. package/packages/pi-agent-core/dist/harness/skills.js +6 -0
  173. package/packages/pi-agent-core/dist/harness/skills.js.map +1 -1
  174. package/packages/pi-agent-core/dist/harness/system-prompt.d.ts +7 -0
  175. package/packages/pi-agent-core/dist/harness/system-prompt.d.ts.map +1 -1
  176. package/packages/pi-agent-core/dist/harness/system-prompt.js +7 -0
  177. package/packages/pi-agent-core/dist/harness/system-prompt.js.map +1 -1
  178. package/packages/pi-agent-core/package.json +1 -1
  179. package/packages/pi-ai/dist/models.generated.d.ts +8 -59
  180. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  181. package/packages/pi-ai/dist/models.generated.js +21 -72
  182. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  183. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  184. package/packages/pi-ai/dist/providers/anthropic.js +50 -0
  185. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  186. package/packages/pi-ai/dist/providers/openai-responses-shared.d.ts.map +1 -1
  187. package/packages/pi-ai/dist/providers/openai-responses-shared.js +28 -4
  188. package/packages/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
  189. package/packages/pi-ai/dist/types.d.ts +2 -0
  190. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  191. package/packages/pi-ai/dist/types.js.map +1 -1
  192. package/packages/pi-ai/package.json +1 -1
  193. package/packages/pi-coding-agent/README.md +1 -1
  194. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts +2 -2
  195. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts.map +1 -1
  196. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.js.map +1 -1
  197. package/packages/pi-coding-agent/dist/core/extensions/loader.js +1 -1
  198. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  199. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  200. package/packages/pi-coding-agent/dist/core/extensions/runner.js +8 -2
  201. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  202. package/packages/pi-coding-agent/dist/core/skills.d.ts +3 -0
  203. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  204. package/packages/pi-coding-agent/dist/core/skills.js +3 -0
  205. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  206. package/packages/pi-coding-agent/package.json +7 -7
  207. package/packages/pi-tui/package.json +1 -1
  208. package/packages/rpc-client/package.json +2 -2
  209. package/pkg/package.json +1 -1
  210. package/src/resources/extensions/context7/index.ts +15 -2
  211. package/src/resources/extensions/get-secrets-from-user.ts +17 -16
  212. package/src/resources/extensions/google-cli/index.ts +34 -0
  213. package/src/resources/extensions/google-cli/models.ts +57 -0
  214. package/src/resources/extensions/google-cli/package.json +11 -0
  215. package/src/resources/extensions/google-cli/readiness.ts +15 -0
  216. package/src/resources/extensions/google-cli/stream-adapter.ts +245 -0
  217. package/src/resources/extensions/gsd/auto/loop.ts +74 -1
  218. package/src/resources/extensions/gsd/auto/orchestrator.ts +4 -2
  219. package/src/resources/extensions/gsd/auto/phases.ts +46 -0
  220. package/src/resources/extensions/gsd/auto/run-unit.ts +10 -0
  221. package/src/resources/extensions/gsd/auto/session.ts +3 -0
  222. package/src/resources/extensions/gsd/auto-dispatch.ts +31 -11
  223. package/src/resources/extensions/gsd/auto-post-unit.ts +43 -14
  224. package/src/resources/extensions/gsd/auto-prompts.ts +4 -284
  225. package/src/resources/extensions/gsd/auto-recovery.ts +10 -7
  226. package/src/resources/extensions/gsd/auto-start.ts +307 -56
  227. package/src/resources/extensions/gsd/auto.ts +6 -1
  228. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +4 -3
  229. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +9 -4
  230. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +42 -5
  231. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +18 -6
  232. package/src/resources/extensions/gsd/bootstrap/system-context.ts +3 -28
  233. package/src/resources/extensions/gsd/closeout-recovery.ts +6 -1
  234. package/src/resources/extensions/gsd/commands/handlers/auto.ts +9 -1
  235. package/src/resources/extensions/gsd/commands-usage.ts +110 -5
  236. package/src/resources/extensions/gsd/config-overlay.ts +19 -16
  237. package/src/resources/extensions/gsd/context-overlay.ts +24 -19
  238. package/src/resources/extensions/gsd/dashboard-overlay.ts +14 -27
  239. package/src/resources/extensions/gsd/doctor-engine-checks.ts +99 -0
  240. package/src/resources/extensions/gsd/doctor-providers.ts +55 -27
  241. package/src/resources/extensions/gsd/doctor-types.ts +2 -0
  242. package/src/resources/extensions/gsd/doctor.ts +6 -1
  243. package/src/resources/extensions/gsd/git-conflict-state.ts +25 -1
  244. package/src/resources/extensions/gsd/guided-flow.ts +5 -6
  245. package/src/resources/extensions/gsd/key-manager.ts +57 -14
  246. package/src/resources/extensions/gsd/milestone-reopen-events.ts +28 -0
  247. package/src/resources/extensions/gsd/notification-overlay.ts +12 -11
  248. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +16 -12
  249. package/src/resources/extensions/gsd/preferences-skills.ts +11 -4
  250. package/src/resources/extensions/gsd/preferences.ts +17 -2
  251. package/src/resources/extensions/gsd/prompt-loader.ts +2 -0
  252. package/src/resources/extensions/gsd/prompts/discuss.md +4 -2
  253. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
  254. package/src/resources/extensions/gsd/prompts/system.md +1 -3
  255. package/src/resources/extensions/gsd/queue-reorder-ui.ts +29 -20
  256. package/src/resources/extensions/gsd/repository-registry.ts +3 -1
  257. package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -4
  258. package/src/resources/extensions/gsd/skill-activation.ts +292 -0
  259. package/src/resources/extensions/gsd/skill-catalog.data.ts +858 -0
  260. package/src/resources/extensions/gsd/skill-catalog.install.ts +205 -0
  261. package/src/resources/extensions/gsd/skill-catalog.ts +16 -1087
  262. package/src/resources/extensions/gsd/skill-discovery.ts +134 -78
  263. package/src/resources/extensions/gsd/skill-scope.ts +63 -0
  264. package/src/resources/extensions/gsd/skill-telemetry.ts +6 -40
  265. package/src/resources/extensions/gsd/skills.ts +75 -0
  266. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +499 -0
  267. package/src/resources/extensions/gsd/state-reconciliation/index.ts +40 -0
  268. package/src/resources/extensions/gsd/state-reconciliation/registry.ts +8 -0
  269. package/src/resources/extensions/gsd/state-reconciliation/types.ts +30 -0
  270. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +328 -2
  271. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +21 -0
  272. package/src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts +28 -2
  273. package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +30 -0
  274. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +41 -0
  275. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +12 -0
  276. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +436 -0
  277. package/src/resources/extensions/gsd/tests/closeout-recovery.test.ts +15 -0
  278. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +31 -0
  279. package/src/resources/extensions/gsd/tests/commands-context.test.ts +5 -3
  280. package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +15 -2
  281. package/src/resources/extensions/gsd/tests/commands-usage.test.ts +97 -0
  282. package/src/resources/extensions/gsd/tests/context-chart.test.ts +9 -0
  283. package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +25 -0
  284. package/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +1 -0
  285. package/src/resources/extensions/gsd/tests/discuss-prompt.test.ts +4 -2
  286. package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +1 -1
  287. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +105 -0
  288. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +101 -1
  289. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +30 -0
  290. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +6 -0
  291. package/src/resources/extensions/gsd/tests/key-manager.test.ts +23 -4
  292. package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +6 -1
  293. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +70 -10
  294. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +7 -1
  295. package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +93 -0
  296. package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +46 -0
  297. package/src/resources/extensions/gsd/tests/register-extension-guard.test.ts +116 -11
  298. package/src/resources/extensions/gsd/tests/repository-registry.test.ts +30 -1
  299. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +4 -0
  300. package/src/resources/extensions/gsd/tests/skill-discovery.test.ts +111 -0
  301. package/src/resources/extensions/gsd/tests/skill-scope-auto.test.ts +67 -0
  302. package/src/resources/extensions/gsd/tests/skills.test.ts +55 -0
  303. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +13 -2
  304. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +303 -0
  305. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +19 -0
  306. package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +24 -1
  307. package/src/resources/extensions/gsd/tests/tui-border-assertions.ts +28 -0
  308. package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +14 -0
  309. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +18 -0
  310. package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +26 -0
  311. package/src/resources/extensions/gsd/tests/vision-ask.test.ts +23 -0
  312. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +6 -1
  313. package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +74 -1
  314. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +82 -0
  315. package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +16 -1
  316. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +28 -0
  317. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +45 -1
  318. package/src/resources/extensions/gsd/tools/complete-task.ts +9 -0
  319. package/src/resources/extensions/gsd/tools/exec-tool.ts +42 -10
  320. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +82 -5
  321. package/src/resources/extensions/gsd/tui/render-kit.ts +82 -0
  322. package/src/resources/extensions/gsd/unit-context-manifest.ts +37 -26
  323. package/src/resources/extensions/gsd/user-input-boundary.ts +1 -1
  324. package/src/resources/extensions/gsd/vision-ask.ts +28 -0
  325. package/src/resources/extensions/gsd/visualizer-overlay.ts +12 -40
  326. package/src/resources/extensions/gsd/worktree-lifecycle.ts +37 -2
  327. package/src/resources/extensions/search-the-web/native-search.ts +60 -8
  328. package/src/resources/extensions/shared/confirm-ui.ts +8 -12
  329. package/src/resources/extensions/shared/dialog-frame.ts +71 -0
  330. package/src/resources/extensions/shared/interview-ui.ts +43 -42
  331. package/src/resources/extensions/shared/next-action-ui.ts +6 -6
  332. package/src/resources/extensions/shared/tests/confirm-ui.test.ts +57 -0
  333. package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +163 -0
  334. package/src/resources/extensions/shared/tests/next-action-ui-hasui.test.ts +55 -0
  335. package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +1 -1
  336. /package/dist/web/standalone/.next/static/{praHP_OATcjBkvAVejjGK → QKed8_bmMc7zc3WLM7MW9}/_buildManifest.js +0 -0
  337. /package/dist/web/standalone/.next/static/{praHP_OATcjBkvAVejjGK → QKed8_bmMc7zc3WLM7MW9}/_ssgManifest.js +0 -0
@@ -15,6 +15,7 @@ import { dirname, join } from 'node:path';
15
15
  import { renderGsdPiLogo, GSD_PI_BRAND, GSD_WEBSITE } from './logo.js';
16
16
  import { agentDir } from './app-paths.js';
17
17
  import { isClaudeCliReady } from './claude-cli-check.js';
18
+ import { isAntigravityCliReady, isGeminiCliReady } from './resources/extensions/google-cli/readiness.js';
18
19
  import { markOnboardingComplete, markStepCompleted, markStepSkipped, isOnboardingComplete, } from './resources/extensions/gsd/onboarding-state.js';
19
20
  import { getLlmProviderIds } from './resources/extensions/gsd/setup-catalog.js';
20
21
  // ─── Constants ────────────────────────────────────────────────────────────────
@@ -358,7 +359,13 @@ export async function runLlmStep(p, pc, authStorage) {
358
359
  if (isClaudeCliReady()) {
359
360
  authOptions.push({ value: 'claude-cli', label: 'Use Claude Code CLI', hint: 'recommended — uses your existing Claude subscription' });
360
361
  }
361
- authOptions.push({ value: 'browser', label: 'Sign in with your browser', hint: 'GitHub Copilot, ChatGPT, Google, etc.' }, { value: 'api-key', label: 'Paste an API key', hint: 'from your provider dashboard' }, { value: 'skip', label: 'Skip for now', hint: 'use /login inside GSD later' });
362
+ if (isGeminiCliReady()) {
363
+ authOptions.push({ value: 'gemini-cli', label: 'Use Google Gemini CLI', hint: 'uses your existing Gemini CLI session' });
364
+ }
365
+ if (isAntigravityCliReady()) {
366
+ authOptions.push({ value: 'antigravity-cli', label: 'Use Antigravity CLI', hint: 'uses your existing Antigravity session' });
367
+ }
368
+ authOptions.push({ value: 'browser', label: 'Sign in with your browser', hint: 'GitHub Copilot or ChatGPT/Codex' }, { value: 'api-key', label: 'Paste an API key', hint: 'from your provider dashboard' }, { value: 'skip', label: 'Skip for now', hint: 'use /login inside GSD later' });
362
369
  const method = await p.select({
363
370
  message: existingAuth ? `LLM provider: ${existingAuth} — change it?` : 'How do you want to sign in?',
364
371
  options: authOptions,
@@ -377,6 +384,20 @@ export async function runLlmStep(p, pc, authStorage) {
377
384
  persistDefaultProvider('claude-code');
378
385
  return true;
379
386
  }
387
+ if (method === 'gemini-cli') {
388
+ p.log.success('Google Gemini CLI detected — routing through local CLI');
389
+ p.log.info('Your Gemini CLI session will be used for inference. No API key needed.');
390
+ authStorage.set('google-gemini-cli', { type: 'api_key', key: 'cli' });
391
+ persistDefaultProvider('google-gemini-cli');
392
+ return true;
393
+ }
394
+ if (method === 'antigravity-cli') {
395
+ p.log.success('Antigravity CLI detected — routing through local CLI');
396
+ p.log.info('Your Antigravity session will be used for inference. No API key needed.');
397
+ authStorage.set('google-antigravity', { type: 'api_key', key: 'cli' });
398
+ persistDefaultProvider('google-antigravity');
399
+ return true;
400
+ }
380
401
  // ── Step 2: Which provider? ──────────────────────────────────────────────
381
402
  if (method === 'browser') {
382
403
  // Anthropic OAuth is removed from browser auth — it violates Anthropic TOS for
@@ -387,8 +408,6 @@ export async function runLlmStep(p, pc, authStorage) {
387
408
  options: [
388
409
  { value: 'github-copilot', label: 'GitHub Copilot' },
389
410
  { value: 'openai-codex', label: 'ChatGPT Plus/Pro (Codex)' },
390
- { value: 'google-gemini-cli', label: 'Google Gemini CLI' },
391
- { value: 'google-antigravity', label: 'Antigravity (Gemini 3, Claude, GPT-OSS)' },
392
411
  ],
393
412
  });
394
413
  if (p.isCancel(provider))
@@ -602,10 +602,12 @@ export function initResources(agentDir, skillsDir = join(agentDir, 'skills')) {
602
602
  const currentHash = getCurrentResourceFingerprint();
603
603
  const hasStaleExtensionFiles = hasStaleCompiledExtensionSiblings(extensionsDir, bundledExtensionsDir);
604
604
  const hasMissingSharedFiles = hasMissingBundledResourceFiles(join(agentDir, 'shared'), join(resourcesDir, 'shared'));
605
+ const hasMissingSkillFiles = hasMissingBundledResourceFiles(skillsDir, join(resourcesDir, 'skills'));
605
606
  if (manifest.contentHash &&
606
607
  manifest.contentHash === currentHash &&
607
608
  !hasStaleExtensionFiles &&
608
- !hasMissingSharedFiles) {
609
+ !hasMissingSharedFiles &&
610
+ !hasMissingSkillFiles) {
609
611
  return;
610
612
  }
611
613
  }
@@ -1 +1 @@
1
- 9d6ff59a3cc348a6
1
+ 679e72aa2db909a2
@@ -92,6 +92,16 @@ function formatLibraryList(libs, query) {
92
92
  lines.push("\nUse the ID (e.g. /websites/react_dev) with get_library_docs to fetch documentation.");
93
93
  return lines.join("\n");
94
94
  }
95
+ function getFirstTextContent(result) {
96
+ const content = result.content;
97
+ if (!Array.isArray(content))
98
+ return undefined;
99
+ const textBlock = content.find((block) => typeof block === "object" &&
100
+ block !== null &&
101
+ block.type === "text" &&
102
+ typeof block.text === "string");
103
+ return textBlock?.text.trim() || undefined;
104
+ }
95
105
  // ─── Extension ───────────────────────────────────────────────────────────────
96
106
  export default function (pi) {
97
107
  // ── resolve_library ──────────────────────────────────────────────────────
@@ -164,7 +174,7 @@ export default function (pi) {
164
174
  if (isPartial)
165
175
  return new Text(theme.fg("warning", "Searching Context7..."), 0, 0);
166
176
  if (result.isError || d?.error) {
167
- return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
177
+ return new Text(theme.fg("error", `Error: ${d?.error ?? getFirstTextContent(result) ?? "unknown"}`), 0, 0);
168
178
  }
169
179
  let text = theme.fg("success", `${d?.resultCount ?? 0} ${d?.resultCount === 1 ? "library" : "libraries"} found`);
170
180
  if (d?.cached)
@@ -303,7 +313,7 @@ export default function (pi) {
303
313
  if (isPartial)
304
314
  return new Text(theme.fg("warning", "Fetching documentation..."), 0, 0);
305
315
  if (result.isError || d?.error) {
306
- return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
316
+ return new Text(theme.fg("error", `Error: ${d?.error ?? getFirstTextContent(result) ?? "unknown"}`), 0, 0);
307
317
  }
308
318
  let text = theme.fg("success", `${(d?.charCount ?? 0).toLocaleString()} chars`);
309
319
  text += theme.fg("dim", ` · ${d?.tokens ?? 5000} token budget`);
@@ -10,6 +10,7 @@ import { existsSync, statSync } from "node:fs";
10
10
  import { resolve } from "node:path";
11
11
  import { Editor, Key, matchesKey, Text, truncateToWidth, wrapTextWithAnsi } from "@gsd/pi-tui";
12
12
  import { Type } from "@sinclair/typebox";
13
+ import { renderSharedDialogFrame } from "./shared/dialog-frame.js";
13
14
  import { makeUI } from "./shared/tui.js";
14
15
  import { maskEditorLine } from "./shared/mod.js";
15
16
  import { parseSecretsManifest, formatSecretsManifest } from "./gsd/files.js";
@@ -22,6 +23,9 @@ function maskPreview(value) {
22
23
  return "*".repeat(value.length);
23
24
  return `${value.slice(0, 4)}${"*".repeat(Math.max(4, value.length - 8))}${value.slice(-4)}`;
24
25
  }
26
+ function dialogContentWidth(width) {
27
+ return width < 4 ? Math.max(1, width) : Math.max(1, width - 4);
28
+ }
25
29
  function shellEscapeSingle(value) {
26
30
  return `'${value.replace(/'/g, `'\\''`)}'`;
27
31
  }
@@ -132,9 +136,9 @@ async function collectOneSecret(ctx, pageIndex, totalPages, keyName, hint, guida
132
136
  function render(width) {
133
137
  if (cachedLines)
134
138
  return cachedLines;
139
+ const contentWidth = dialogContentWidth(width);
135
140
  const lines = [];
136
- const add = (s) => lines.push(truncateToWidth(s, width));
137
- add(theme.fg("accent", "─".repeat(width)));
141
+ const add = (s) => lines.push(truncateToWidth(s, contentWidth));
138
142
  add(theme.fg("dim", ` Page ${pageIndex + 1}/${totalPages} · Secure Env Setup`));
139
143
  lines.push("");
140
144
  // Key name as big header
@@ -148,7 +152,7 @@ async function collectOneSecret(ctx, pageIndex, totalPages, keyName, hint, guida
148
152
  for (let g = 0; g < guidance.length; g++) {
149
153
  const prefix = ` ${g + 1}. `;
150
154
  const step = guidance[g];
151
- const wrappedLines = wrapTextWithAnsi(step, width - 4);
155
+ const wrappedLines = wrapTextWithAnsi(step, Math.max(1, contentWidth - 4));
152
156
  for (let w = 0; w < wrappedLines.length; w++) {
153
157
  const indent = w === 0 ? prefix : " ".repeat(prefix.length);
154
158
  lines.push(theme.fg("dim", `${indent}${wrappedLines[w]}`));
@@ -163,14 +167,13 @@ async function collectOneSecret(ctx, pageIndex, totalPages, keyName, hint, guida
163
167
  lines.push("");
164
168
  // Editor
165
169
  add(theme.fg("muted", " Enter value:"));
166
- for (const line of editor.render(width - 2)) {
170
+ for (const line of editor.render(Math.max(1, contentWidth - 2))) {
167
171
  add(theme.fg("text", maskEditorLine(line)));
168
172
  }
169
173
  lines.push("");
170
- add(theme.fg("dim", ` enter to confirm | ctrl+s or esc to skip | esc cancels`));
171
- add(theme.fg("accent", "─".repeat(width)));
172
- cachedLines = lines;
173
- return lines;
174
+ const footer = theme.fg("dim", " enter to confirm | ctrl+s or esc to skip | esc cancels");
175
+ cachedLines = renderSharedDialogFrame(theme, "Secure Env Setup", lines, width, { footer });
176
+ return cachedLines;
174
177
  }
175
178
  return {
176
179
  render,
@@ -224,13 +227,11 @@ export async function showSecretsSummary(ctx, entries, existingKeys) {
224
227
  function render(width) {
225
228
  if (cachedLines)
226
229
  return cachedLines;
227
- const ui = makeUI(theme, width);
230
+ const contentWidth = dialogContentWidth(width);
231
+ const ui = makeUI(theme, contentWidth);
228
232
  const lines = [];
229
233
  const push = (...rows) => { for (const r of rows)
230
234
  lines.push(...r); };
231
- push(ui.bar());
232
- push(ui.blank());
233
- push(ui.header(" Secrets Summary"));
234
235
  push(ui.blank());
235
236
  for (const entry of entries) {
236
237
  let status;
@@ -251,10 +252,9 @@ export async function showSecretsSummary(ctx, entries, existingKeys) {
251
252
  push(ui.progressItem(entry.key, status, { detail }));
252
253
  }
253
254
  push(ui.blank());
254
- push(ui.hints(["any key to continue"]));
255
- push(ui.bar());
256
- cachedLines = lines;
257
- return lines;
255
+ const footer = ui.hints(["any key to continue"])[0] ?? "";
256
+ cachedLines = renderSharedDialogFrame(theme, "Secrets Summary", lines, width, { footer });
257
+ return cachedLines;
258
258
  }
259
259
  return {
260
260
  render,
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Google local CLI providers.
3
+ *
4
+ * These deliberately use authMode "externalCli": GSD never owns the browser
5
+ * OAuth flow or cached tokens. Users authenticate with the official CLI, then
6
+ * /login activates the provider once the local binary is available.
7
+ */
8
+ import { GOOGLE_ANTIGRAVITY_MODELS, GOOGLE_GEMINI_CLI_MODELS } from "./models.js";
9
+ import { isAntigravityCliReady, isGeminiCliReady } from "./readiness.js";
10
+ import { streamViaGoogleCli } from "./stream-adapter.js";
11
+ export default function googleCli(pi) {
12
+ pi.registerProvider("google-gemini-cli", {
13
+ name: "Google Gemini CLI",
14
+ authMode: "externalCli",
15
+ api: "google-gemini-cli",
16
+ baseUrl: "local://google-gemini-cli",
17
+ isReady: isGeminiCliReady,
18
+ streamSimple: streamViaGoogleCli,
19
+ models: GOOGLE_GEMINI_CLI_MODELS,
20
+ });
21
+ pi.registerProvider("google-antigravity", {
22
+ name: "Google Antigravity",
23
+ authMode: "externalCli",
24
+ api: "google-antigravity",
25
+ baseUrl: "local://google-antigravity",
26
+ isReady: isAntigravityCliReady,
27
+ streamSimple: streamViaGoogleCli,
28
+ models: GOOGLE_ANTIGRAVITY_MODELS,
29
+ });
30
+ }
@@ -0,0 +1,55 @@
1
+ const ZERO_COST = {
2
+ input: 0,
3
+ output: 0,
4
+ cacheRead: 0,
5
+ cacheWrite: 0,
6
+ };
7
+ export const GOOGLE_GEMINI_CLI_MODELS = [
8
+ {
9
+ id: "gemini-2.5-flash",
10
+ name: "Gemini 2.5 Flash",
11
+ reasoning: true,
12
+ input: ["text"],
13
+ cost: ZERO_COST,
14
+ contextWindow: 1_000_000,
15
+ maxTokens: 65_536,
16
+ },
17
+ {
18
+ id: "gemini-2.5-pro",
19
+ name: "Gemini 2.5 Pro",
20
+ reasoning: true,
21
+ input: ["text"],
22
+ cost: ZERO_COST,
23
+ contextWindow: 1_000_000,
24
+ maxTokens: 65_536,
25
+ },
26
+ {
27
+ id: "gemini-3-flash-preview",
28
+ name: "Gemini 3 Flash Preview",
29
+ reasoning: true,
30
+ input: ["text"],
31
+ cost: ZERO_COST,
32
+ contextWindow: 1_000_000,
33
+ maxTokens: 65_536,
34
+ },
35
+ {
36
+ id: "gemini-3.1-pro-preview",
37
+ name: "Gemini 3.1 Pro Preview",
38
+ reasoning: true,
39
+ input: ["text"],
40
+ cost: ZERO_COST,
41
+ contextWindow: 1_000_000,
42
+ maxTokens: 65_536,
43
+ },
44
+ ];
45
+ export const GOOGLE_ANTIGRAVITY_MODELS = [
46
+ {
47
+ id: "default",
48
+ name: "Antigravity Default",
49
+ reasoning: true,
50
+ input: ["text"],
51
+ cost: ZERO_COST,
52
+ contextWindow: 1_000_000,
53
+ maxTokens: 65_536,
54
+ },
55
+ ];
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "@gsd/google-cli",
3
+ "private": true,
4
+ "version": "1.0.0",
5
+ "type": "module",
6
+ "pi": {
7
+ "extensions": [
8
+ "./index.js"
9
+ ]
10
+ }
11
+ }
@@ -0,0 +1,12 @@
1
+ import { spawnSync } from "node:child_process";
2
+ function isCommandInPath(command) {
3
+ const resolver = process.platform === "win32" ? "where" : "which";
4
+ const result = spawnSync(resolver, [command], { stdio: "ignore" });
5
+ return result.status === 0;
6
+ }
7
+ export function isGeminiCliReady() {
8
+ return isCommandInPath("gemini");
9
+ }
10
+ export function isAntigravityCliReady() {
11
+ return isCommandInPath("agy");
12
+ }
@@ -0,0 +1,191 @@
1
+ import { spawn } from "node:child_process";
2
+ import { createAssistantMessageEventStream } from "@gsd/pi-ai";
3
+ const ZERO_USAGE = {
4
+ input: 0,
5
+ output: 0,
6
+ cacheRead: 0,
7
+ cacheWrite: 0,
8
+ totalTokens: 0,
9
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
10
+ };
11
+ function textBlocks(content) {
12
+ return content
13
+ .map((block) => block.type === "text" ? block.text : `[${block.type} omitted]`)
14
+ .join("\n");
15
+ }
16
+ function messageToText(message) {
17
+ if (message.role === "user") {
18
+ const content = typeof message.content === "string" ? message.content : textBlocks(message.content);
19
+ return `User:\n${content}`;
20
+ }
21
+ if (message.role === "assistant") {
22
+ const text = message.content
23
+ .map((block) => {
24
+ if (block.type === "text")
25
+ return block.text;
26
+ if (block.type === "thinking")
27
+ return `[thinking omitted]`;
28
+ if (block.type === "toolCall")
29
+ return `[tool call: ${block.name}]`;
30
+ if (block.type === "serverToolUse")
31
+ return `[server tool: ${block.name}]`;
32
+ if (block.type === "webSearchResult")
33
+ return `[web search result omitted]`;
34
+ return `[${block.type} omitted]`;
35
+ })
36
+ .join("\n");
37
+ return `Assistant:\n${text}`;
38
+ }
39
+ return `Tool result (${message.toolName}):\n${textBlocks(message.content)}`;
40
+ }
41
+ export function buildGoogleCliPrompt(context) {
42
+ const parts = [];
43
+ if (context.systemPrompt?.trim()) {
44
+ parts.push(`System instructions:\n${context.systemPrompt.trim()}`);
45
+ }
46
+ if (context.messages.length > 0) {
47
+ parts.push(context.messages.map(messageToText).join("\n\n"));
48
+ }
49
+ if (context.tools?.length) {
50
+ const names = context.tools.map((tool) => tool.name).join(", ");
51
+ parts.push(`Available local GSD tools were not forwarded to this external CLI bridge. ` +
52
+ `If you need to act, use the CLI's own tools or ask the user to switch to a provider with native tool-call support. ` +
53
+ `Requested GSD tools: ${names}`);
54
+ }
55
+ return parts.join("\n\n").trim();
56
+ }
57
+ function buildAssistantMessage(model, text, stopReason = "stop", errorMessage) {
58
+ return {
59
+ role: "assistant",
60
+ content: text ? [{ type: "text", text }] : [],
61
+ api: model.api,
62
+ provider: model.provider,
63
+ model: model.id,
64
+ usage: { ...ZERO_USAGE, cost: { ...ZERO_USAGE.cost } },
65
+ stopReason,
66
+ ...(errorMessage ? { errorMessage } : {}),
67
+ timestamp: Date.now(),
68
+ };
69
+ }
70
+ function extractGeminiJsonResponse(raw) {
71
+ const trimmed = raw.trim();
72
+ if (!trimmed)
73
+ return "";
74
+ try {
75
+ const parsed = JSON.parse(trimmed);
76
+ for (const key of ["response", "text", "content", "message"]) {
77
+ const value = parsed[key];
78
+ if (typeof value === "string")
79
+ return value;
80
+ }
81
+ return JSON.stringify(parsed, null, 2);
82
+ }
83
+ catch {
84
+ return trimmed;
85
+ }
86
+ }
87
+ function commandForProvider(provider) {
88
+ return provider === "google-gemini-cli" ? "gemini" : "agy";
89
+ }
90
+ function argsForProvider(provider, model, prompt) {
91
+ if (provider === "google-gemini-cli") {
92
+ const args = ["-p", prompt, "--output-format", "json"];
93
+ if (model.id !== "default")
94
+ args.unshift("-m", model.id);
95
+ return args;
96
+ }
97
+ const args = ["-p", prompt];
98
+ if (model.id !== "default")
99
+ args.unshift("-m", model.id);
100
+ return args;
101
+ }
102
+ export function buildGoogleCliSpawnInvocation(command, args, platform = process.platform) {
103
+ if (platform === "win32") {
104
+ return { command: "cmd", args: ["/c", command, ...args] };
105
+ }
106
+ return { command, args };
107
+ }
108
+ function runCli(command, args, options) {
109
+ return new Promise((resolve, reject) => {
110
+ const invocation = buildGoogleCliSpawnInvocation(command, args);
111
+ const child = spawn(invocation.command, invocation.args, {
112
+ cwd: options?.cwd || process.cwd(),
113
+ env: process.env,
114
+ stdio: ["ignore", "pipe", "pipe"],
115
+ });
116
+ let stdout = "";
117
+ let stderr = "";
118
+ let settled = false;
119
+ const settle = (fn) => {
120
+ if (settled)
121
+ return;
122
+ settled = true;
123
+ options?.signal?.removeEventListener("abort", onAbort);
124
+ fn();
125
+ };
126
+ const onAbort = () => {
127
+ child.kill("SIGTERM");
128
+ settle(() => reject(new Error("Request was aborted")));
129
+ };
130
+ if (options?.signal?.aborted) {
131
+ onAbort();
132
+ return;
133
+ }
134
+ options?.signal?.addEventListener("abort", onAbort);
135
+ child.stdout.setEncoding("utf8");
136
+ child.stderr.setEncoding("utf8");
137
+ child.stdout.on("data", (chunk) => {
138
+ stdout += chunk;
139
+ });
140
+ child.stderr.on("data", (chunk) => {
141
+ stderr += chunk;
142
+ });
143
+ child.on("error", (error) => {
144
+ settle(() => reject(error));
145
+ });
146
+ child.on("close", (code, signal) => {
147
+ settle(() => resolve({ stdout, stderr, code, signal }));
148
+ });
149
+ });
150
+ }
151
+ function emitText(stream, message, text) {
152
+ stream.push({ type: "start", partial: { ...message, content: [] } });
153
+ if (text) {
154
+ stream.push({ type: "text_start", contentIndex: 0, partial: message });
155
+ stream.push({ type: "text_delta", contentIndex: 0, delta: text, partial: message });
156
+ stream.push({ type: "text_end", contentIndex: 0, content: text, partial: message });
157
+ }
158
+ stream.push({ type: "done", reason: "stop", message });
159
+ stream.end(message);
160
+ }
161
+ function emitError(stream, model, error) {
162
+ const message = error instanceof Error ? error.message : String(error);
163
+ const output = buildAssistantMessage(model, "", "error", message);
164
+ stream.push({ type: "error", reason: "error", error: output });
165
+ stream.end(output);
166
+ }
167
+ export function streamViaGoogleCli(model, context, options) {
168
+ const stream = createAssistantMessageEventStream();
169
+ const provider = model.provider;
170
+ queueMicrotask(async () => {
171
+ try {
172
+ const prompt = buildGoogleCliPrompt(context);
173
+ const command = commandForProvider(provider);
174
+ const args = argsForProvider(provider, model, prompt);
175
+ const result = await runCli(command, args, options);
176
+ if (result.code !== 0) {
177
+ const detail = (result.stderr || result.stdout || `CLI exited with code ${result.code}`).trim();
178
+ throw new Error(detail);
179
+ }
180
+ const text = provider === "google-gemini-cli"
181
+ ? extractGeminiJsonResponse(result.stdout)
182
+ : result.stdout.trim();
183
+ const message = buildAssistantMessage(model, text);
184
+ emitText(stream, message, text);
185
+ }
186
+ catch (error) {
187
+ emitError(stream, model, error);
188
+ }
189
+ });
190
+ return stream;
191
+ }
@@ -732,11 +732,36 @@ export async function autoLoop(ctx, pi, s, deps, options) {
732
732
  message: orchestrationResult.reason,
733
733
  category: "unknown",
734
734
  });
735
+ finishTurn("paused", "manual-attention", "orchestration-blocked");
735
736
  }
736
737
  else {
737
738
  await deps.stopAuto(ctx, pi, orchestrationResult.reason);
739
+ finishTurn("stopped", "manual-attention", "orchestration-blocked");
738
740
  }
739
- finishTurn("stopped", "manual-attention", "orchestration-blocked");
741
+ finishIncompleteIteration({
742
+ status: orchestrationResult.action === "pause" ? "paused" : "stopped",
743
+ reason: orchestrationResult.reason,
744
+ failureClass: "manual-attention",
745
+ });
746
+ break;
747
+ }
748
+ if (orchestrationResult.kind === "paused") {
749
+ s.pendingOrchestrationDispatch = null;
750
+ finishTurn("skipped");
751
+ continue;
752
+ }
753
+ if (orchestrationResult.kind === "error") {
754
+ s.pendingOrchestrationDispatch = null;
755
+ await deps.pauseAuto(ctx, pi, {
756
+ message: orchestrationResult.reason,
757
+ category: "unknown",
758
+ });
759
+ finishTurn("paused", "manual-attention", `orchestration-${orchestrationResult.kind}`);
760
+ finishIncompleteIteration({
761
+ status: "paused",
762
+ reason: orchestrationResult.reason,
763
+ failureClass: "manual-attention",
764
+ });
740
765
  break;
741
766
  }
742
767
  if (orchestrationResult.kind === "stopped") {
@@ -769,6 +794,42 @@ export async function autoLoop(ctx, pi, s, deps, options) {
769
794
  isRetry: false,
770
795
  previousTier: undefined,
771
796
  };
797
+ const preDispatchResult = deps.runPreDispatchHooks(iterData.unitType, iterData.unitId, iterData.prompt, s.basePath);
798
+ if (preDispatchResult.firedHooks.length > 0) {
799
+ ctx.ui.notify(`Pre-dispatch hook${preDispatchResult.firedHooks.length > 1 ? "s" : ""}: ${preDispatchResult.firedHooks.join(", ")}`, "info");
800
+ deps.emitJournalEvent({
801
+ ts: new Date().toISOString(),
802
+ flowId: ic.flowId,
803
+ seq: ic.nextSeq(),
804
+ eventType: "pre-dispatch-hook",
805
+ data: {
806
+ firedHooks: preDispatchResult.firedHooks,
807
+ action: preDispatchResult.action,
808
+ },
809
+ });
810
+ }
811
+ if (preDispatchResult.action === "skip") {
812
+ ctx.ui.notify(`Skipping ${iterData.unitType} ${iterData.unitId} (pre-dispatch hook).`, "info");
813
+ s.pendingOrchestrationDispatch = null;
814
+ emitIterationEnd({ skipped: true });
815
+ completeIteration();
816
+ finishTurn("skipped");
817
+ continue;
818
+ }
819
+ if (preDispatchResult.action === "replace") {
820
+ iterData.prompt = preDispatchResult.prompt ?? iterData.prompt;
821
+ iterData.finalPrompt = iterData.prompt;
822
+ if (preDispatchResult.unitType) {
823
+ iterData.unitType = preDispatchResult.unitType;
824
+ }
825
+ }
826
+ else if (preDispatchResult.prompt) {
827
+ iterData.prompt = preDispatchResult.prompt;
828
+ iterData.finalPrompt = preDispatchResult.prompt;
829
+ }
830
+ if (preDispatchResult.model) {
831
+ iterData.hookModelOverride = preDispatchResult.model;
832
+ }
772
833
  s.pendingOrchestrationDispatch = null;
773
834
  phaseReporter.report("dispatch", "next", {
774
835
  unitType: iterData.unitType,
@@ -369,9 +369,11 @@ export class AutoOrchestrator {
369
369
  const activeUnitKey = this.status.activeUnit
370
370
  ? `${this.status.activeUnit.unitType}:${this.status.activeUnit.unitId}`
371
371
  : null;
372
- if (activeUnitKey !== unitKey)
372
+ if (activeUnitKey !== unitKey && this.lastFinalizedUnitKey !== unitKey)
373
373
  return;
374
- this.status.activeUnit = undefined;
374
+ if (activeUnitKey === unitKey) {
375
+ this.status.activeUnit = undefined;
376
+ }
375
377
  this.lastAdvanceKey = null;
376
378
  this.lastFinalizedUnitKey = null;
377
379
  this.bumpTransition();
@@ -10,6 +10,7 @@
10
10
  */
11
11
  import { importExtensionModule } from "@gsd/pi-coding-agent";
12
12
  import { USER_DRIVEN_DEEP_UNITS, isAwaitingUserInput, } from "../auto-post-unit.js";
13
+ import { lastAssistantText } from "../user-input-boundary.js";
13
14
  import { MAX_RECOVERY_CHARS, BUDGET_THRESHOLDS, MAX_FINALIZE_TIMEOUTS, } from "./types.js";
14
15
  import { detectStuck } from "./detect-stuck.js";
15
16
  import { runUnit } from "./run-unit.js";
@@ -52,8 +53,19 @@ import { decideVerificationRetry, verificationRetryKey } from "./verification-re
52
53
  import { buildPhaseHandoffOutcome, setAutoOutcomeWidget } from "../auto-dashboard.js";
53
54
  import { getConsecutiveDispatchBlocker } from "../dispatch-guard.js";
54
55
  import { captureRootDirtySnapshot, detectRootWriteLeak, formatRootWriteLeakMessage, } from "../root-write-leak-guard.js";
56
+ import { classifyError, isTransient } from "../error-classifier.js";
55
57
  export const STUCK_WINDOW_SIZE = 6;
56
58
  const STUCK_RECOVERY_ATTEMPTS_KEY = "stuck_recovery_attempts";
59
+ const ZERO_TOOL_PROVIDER_ERROR_PREFIX_RE = /^(?:api error(?::|$|\s*\()|provider error(?::|$|\s*\()|request failed\b|(?:http\s*)?(?:429|500|502|503)\b|\b(?:econnreset|etimedout|econnrefused|epipe)\b|socket hang up\b|fetch failed\b|(?:network|connection|server) error(?::|$)|connection (?:reset|refused)(?::|$|\s+by\b)|dns\b.*(?:fail|error|timeout)|unexpected eof\b|stream idle timeout\b|partial response received\b|stream_exhausted\b|terminated(?::|$)|(?:connection|stream|request)\b.{0,40}\bterminated\b|other side closed\b|rate.?limit(?:ed| exceeded| reached| error)|too many requests\b|you(?:'ve| have) hit your limit\b|usage limit\b|out of extra usage\b|service.?unavailable\b|internal(?: server)? error(?::|$)|internal(?:[_-]server)?[_-]error\b|server[_-]error\b|(?:provider|server|api|model|codex|claude|openai|anthropic|gemini)\b.{0,80}\boverloaded\b|overloaded\b.{0,80}\b(?:provider|server|api|model)\b|context (?:window|length) exceed|context window exceed)/i;
60
+ const ZERO_TOOL_PROVIDER_ERROR_SIGNAL_RE = /(?:\b(?:http|status(?: code)?|code|error:)\s*(?:429|500|502|503)\b|\b(?:api|provider) error\s*[:(]?\s*(?:429|500|502|503)\b|\b(?:typeerror|error):\s*(?:fetch failed\b|socket hang up\b|terminated(?::|$)|connection (?:reset|refused)(?::|$|\s+by\b)|(?:network|connection|server) error(?::|$)|stream idle timeout\b|partial response received\b|unexpected eof\b)|\b(?:server_error|api_error|stream_exhausted(?:_without_result)?)\b|\b(?:econnreset|etimedout|econnrefused|epipe)\b|context (?:window|length) exceed|context window exceed)/i;
61
+ function classifyZeroToolProviderMessage(message) {
62
+ const firstLine = message.trim().split(/\r?\n/, 1)[0]?.trim() ?? "";
63
+ if (!firstLine ||
64
+ (!ZERO_TOOL_PROVIDER_ERROR_PREFIX_RE.test(firstLine) &&
65
+ !ZERO_TOOL_PROVIDER_ERROR_SIGNAL_RE.test(firstLine)))
66
+ return null;
67
+ return classifyError(firstLine);
68
+ }
57
69
  export function resolveDispatchRecoveryAttempts(unitRecoveryCount, unitType, unitId) {
58
70
  return (unitRecoveryCount.get(`${unitType}/${unitId}`) ?? 0) > 0
59
71
  ? 0
@@ -1999,6 +2011,31 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
1999
2011
  if (currentLedger?.units) {
2000
2012
  const lastUnit = [...currentLedger.units].reverse().find((u) => u.type === unitType && u.id === unitId && u.startedAt === _resolveCurrentUnitStartedAtForTest(s.currentUnit));
2001
2013
  if (lastUnit && lastUnit.toolCalls === 0) {
2014
+ const lastAssistantMessage = lastAssistantText(s.lastUnitAgentEndMessages);
2015
+ const providerMessageClass = classifyZeroToolProviderMessage(lastAssistantMessage);
2016
+ if (providerMessageClass && isTransient(providerMessageClass)) {
2017
+ const retryAfterMs = "retryAfterMs" in providerMessageClass ? providerMessageClass.retryAfterMs : 15_000;
2018
+ await pauseAutoForProviderError(ctx.ui, ` for ${unitType} ${unitId}`, () => deps.pauseAuto(ctx, pi), {
2019
+ isRateLimit: providerMessageClass.kind === "rate-limit",
2020
+ isTransient: true,
2021
+ retryAfterMs,
2022
+ resume: () => {
2023
+ void resumeAutoAfterProviderDelay(pi, ctx).catch((err) => {
2024
+ logWarning("engine", `Provider error auto-resume failed: ${err instanceof Error ? err.message : String(err)}`);
2025
+ });
2026
+ },
2027
+ });
2028
+ await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, {
2029
+ message: lastAssistantMessage.slice(0, 200),
2030
+ category: "provider",
2031
+ isTransient: true,
2032
+ retryAfterMs,
2033
+ });
2034
+ return {
2035
+ action: "break",
2036
+ reason: providerMessageClass.kind === "rate-limit" ? "rate-limit" : "api-timeout",
2037
+ };
2038
+ }
2002
2039
  if (USER_DRIVEN_DEEP_UNITS.has(unitType) && isAwaitingUserInput(s.lastUnitAgentEndMessages ?? undefined)) {
2003
2040
  debugLog("runUnitPhase", {
2004
2041
  phase: "zero-tool-calls-awaiting-user-input",