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

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 (328) hide show
  1. package/dist/onboarding.js +22 -3
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/context7/index.js +12 -2
  4. package/dist/resources/extensions/get-secrets-from-user.js +16 -16
  5. package/dist/resources/extensions/google-cli/index.js +30 -0
  6. package/dist/resources/extensions/google-cli/models.js +55 -0
  7. package/dist/resources/extensions/google-cli/package.json +11 -0
  8. package/dist/resources/extensions/google-cli/readiness.js +12 -0
  9. package/dist/resources/extensions/google-cli/stream-adapter.js +191 -0
  10. package/dist/resources/extensions/gsd/auto/loop.js +62 -1
  11. package/dist/resources/extensions/gsd/auto/orchestrator.js +4 -2
  12. package/dist/resources/extensions/gsd/auto/phases.js +37 -0
  13. package/dist/resources/extensions/gsd/auto/run-unit.js +8 -0
  14. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  15. package/dist/resources/extensions/gsd/auto-dispatch.js +17 -7
  16. package/dist/resources/extensions/gsd/auto-post-unit.js +21 -11
  17. package/dist/resources/extensions/gsd/auto-prompts.js +5 -236
  18. package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
  19. package/dist/resources/extensions/gsd/auto-start.js +232 -49
  20. package/dist/resources/extensions/gsd/auto.js +6 -1
  21. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +4 -3
  22. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +7 -2
  23. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +39 -5
  24. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +17 -7
  25. package/dist/resources/extensions/gsd/bootstrap/system-context.js +3 -27
  26. package/dist/resources/extensions/gsd/closeout-recovery.js +7 -1
  27. package/dist/resources/extensions/gsd/commands/handlers/auto.js +9 -1
  28. package/dist/resources/extensions/gsd/commands-usage.js +105 -1
  29. package/dist/resources/extensions/gsd/config-overlay.js +20 -14
  30. package/dist/resources/extensions/gsd/context-overlay.js +22 -16
  31. package/dist/resources/extensions/gsd/dashboard-overlay.js +10 -23
  32. package/dist/resources/extensions/gsd/doctor-engine-checks.js +87 -0
  33. package/dist/resources/extensions/gsd/doctor-providers.js +54 -24
  34. package/dist/resources/extensions/gsd/doctor.js +6 -1
  35. package/dist/resources/extensions/gsd/git-conflict-state.js +26 -1
  36. package/dist/resources/extensions/gsd/guided-flow.js +5 -6
  37. package/dist/resources/extensions/gsd/key-manager.js +45 -13
  38. package/dist/resources/extensions/gsd/milestone-reopen-events.js +28 -0
  39. package/dist/resources/extensions/gsd/notification-overlay.js +8 -9
  40. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +15 -13
  41. package/dist/resources/extensions/gsd/preferences-skills.js +11 -4
  42. package/dist/resources/extensions/gsd/preferences.js +14 -2
  43. package/dist/resources/extensions/gsd/prompt-loader.js +2 -0
  44. package/dist/resources/extensions/gsd/prompts/discuss.md +4 -2
  45. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
  46. package/dist/resources/extensions/gsd/prompts/system.md +1 -3
  47. package/dist/resources/extensions/gsd/queue-reorder-ui.js +28 -18
  48. package/dist/resources/extensions/gsd/repository-registry.js +3 -1
  49. package/dist/resources/extensions/gsd/safety/evidence-collector.js +11 -4
  50. package/dist/resources/extensions/gsd/skill-activation.js +233 -0
  51. package/dist/resources/extensions/gsd/skill-catalog.data.js +820 -0
  52. package/dist/resources/extensions/gsd/skill-catalog.install.js +179 -0
  53. package/dist/resources/extensions/gsd/skill-catalog.js +5 -1028
  54. package/dist/resources/extensions/gsd/skill-discovery.js +121 -79
  55. package/dist/resources/extensions/gsd/skill-scope.js +52 -0
  56. package/dist/resources/extensions/gsd/skill-telemetry.js +6 -39
  57. package/dist/resources/extensions/gsd/skills.js +60 -0
  58. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +351 -0
  59. package/dist/resources/extensions/gsd/state-reconciliation/index.js +41 -0
  60. package/dist/resources/extensions/gsd/state-reconciliation/registry.js +4 -0
  61. package/dist/resources/extensions/gsd/tools/complete-task.js +9 -0
  62. package/dist/resources/extensions/gsd/tools/exec-tool.js +42 -8
  63. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +63 -2
  64. package/dist/resources/extensions/gsd/tui/render-kit.js +51 -0
  65. package/dist/resources/extensions/gsd/unit-context-manifest.js +35 -26
  66. package/dist/resources/extensions/gsd/user-input-boundary.js +1 -1
  67. package/dist/resources/extensions/gsd/vision-ask.js +22 -0
  68. package/dist/resources/extensions/gsd/visualizer-overlay.js +8 -36
  69. package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -3
  70. package/dist/resources/extensions/search-the-web/native-search.js +57 -8
  71. package/dist/resources/extensions/shared/confirm-ui.js +9 -6
  72. package/dist/resources/extensions/shared/dialog-frame.js +42 -0
  73. package/dist/resources/extensions/shared/interview-ui.js +42 -30
  74. package/dist/resources/extensions/shared/next-action-ui.js +6 -6
  75. package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +1 -1
  76. package/dist/web/standalone/.next/BUILD_ID +1 -1
  77. package/dist/web/standalone/.next/app-path-routes-manifest.json +4 -4
  78. package/dist/web/standalone/.next/build-manifest.json +2 -2
  79. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  80. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  81. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  89. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/index.html +1 -1
  97. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app-paths-manifest.json +4 -4
  104. package/dist/web/standalone/.next/server/chunks/1834.js +2 -2
  105. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  106. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  107. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  108. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  109. package/package.json +1 -1
  110. package/packages/cloud-mcp-gateway/package.json +2 -2
  111. package/packages/contracts/package.json +1 -1
  112. package/packages/daemon/package.json +4 -4
  113. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +1 -0
  114. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
  115. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +22 -8
  116. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
  117. package/packages/gsd-agent-core/package.json +5 -5
  118. package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.d.ts +12 -0
  119. package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.d.ts.map +1 -0
  120. package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.js +45 -0
  121. package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.js.map +1 -0
  122. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.d.ts +3 -2
  123. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  124. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.js +11 -11
  125. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.js.map +1 -1
  126. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.d.ts +3 -3
  127. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  128. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.js +13 -11
  129. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.js.map +1 -1
  130. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.d.ts +3 -3
  131. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  132. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.js +12 -10
  133. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.js.map +1 -1
  134. package/packages/gsd-agent-modes/dist/modes/interactive/components/index.d.ts +1 -0
  135. package/packages/gsd-agent-modes/dist/modes/interactive/components/index.d.ts.map +1 -1
  136. package/packages/gsd-agent-modes/dist/modes/interactive/components/index.js +1 -0
  137. package/packages/gsd-agent-modes/dist/modes/interactive/components/index.js.map +1 -1
  138. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts +1 -1
  139. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  140. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js +2 -2
  141. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js.map +1 -1
  142. package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.d.ts +6 -1
  143. package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  144. package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.js +9 -6
  145. package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  146. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
  147. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +0 -1
  148. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
  149. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts +3 -0
  150. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
  151. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +144 -2
  152. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
  153. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.d.ts.map +1 -1
  154. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.js +2 -14
  155. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.js.map +1 -1
  156. package/packages/gsd-agent-modes/package.json +7 -7
  157. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  158. package/packages/mcp-server/dist/workflow-tools.js +10 -5
  159. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  160. package/packages/mcp-server/package.json +3 -3
  161. package/packages/native/package.json +1 -1
  162. package/packages/pi-agent-core/dist/harness/skills.d.ts.map +1 -1
  163. package/packages/pi-agent-core/dist/harness/skills.js +6 -0
  164. package/packages/pi-agent-core/dist/harness/skills.js.map +1 -1
  165. package/packages/pi-agent-core/dist/harness/system-prompt.d.ts +7 -0
  166. package/packages/pi-agent-core/dist/harness/system-prompt.d.ts.map +1 -1
  167. package/packages/pi-agent-core/dist/harness/system-prompt.js +7 -0
  168. package/packages/pi-agent-core/dist/harness/system-prompt.js.map +1 -1
  169. package/packages/pi-agent-core/package.json +1 -1
  170. package/packages/pi-ai/dist/models.generated.d.ts +8 -59
  171. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  172. package/packages/pi-ai/dist/models.generated.js +21 -72
  173. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  174. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  175. package/packages/pi-ai/dist/providers/anthropic.js +50 -0
  176. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  177. package/packages/pi-ai/dist/providers/openai-responses-shared.d.ts.map +1 -1
  178. package/packages/pi-ai/dist/providers/openai-responses-shared.js +28 -4
  179. package/packages/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
  180. package/packages/pi-ai/dist/types.d.ts +2 -0
  181. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  182. package/packages/pi-ai/dist/types.js.map +1 -1
  183. package/packages/pi-ai/package.json +1 -1
  184. package/packages/pi-coding-agent/README.md +1 -1
  185. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts +2 -2
  186. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts.map +1 -1
  187. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.js.map +1 -1
  188. package/packages/pi-coding-agent/dist/core/extensions/loader.js +1 -1
  189. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  190. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  191. package/packages/pi-coding-agent/dist/core/extensions/runner.js +8 -2
  192. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  193. package/packages/pi-coding-agent/dist/core/skills.d.ts +3 -0
  194. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  195. package/packages/pi-coding-agent/dist/core/skills.js +3 -0
  196. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  197. package/packages/pi-coding-agent/package.json +7 -7
  198. package/packages/pi-tui/package.json +1 -1
  199. package/packages/rpc-client/package.json +2 -2
  200. package/pkg/package.json +1 -1
  201. package/src/resources/extensions/context7/index.ts +15 -2
  202. package/src/resources/extensions/get-secrets-from-user.ts +17 -16
  203. package/src/resources/extensions/google-cli/index.ts +34 -0
  204. package/src/resources/extensions/google-cli/models.ts +57 -0
  205. package/src/resources/extensions/google-cli/package.json +11 -0
  206. package/src/resources/extensions/google-cli/readiness.ts +15 -0
  207. package/src/resources/extensions/google-cli/stream-adapter.ts +245 -0
  208. package/src/resources/extensions/gsd/auto/loop.ts +74 -1
  209. package/src/resources/extensions/gsd/auto/orchestrator.ts +4 -2
  210. package/src/resources/extensions/gsd/auto/phases.ts +46 -0
  211. package/src/resources/extensions/gsd/auto/run-unit.ts +10 -0
  212. package/src/resources/extensions/gsd/auto/session.ts +3 -0
  213. package/src/resources/extensions/gsd/auto-dispatch.ts +31 -11
  214. package/src/resources/extensions/gsd/auto-post-unit.ts +43 -14
  215. package/src/resources/extensions/gsd/auto-prompts.ts +4 -284
  216. package/src/resources/extensions/gsd/auto-recovery.ts +10 -7
  217. package/src/resources/extensions/gsd/auto-start.ts +307 -56
  218. package/src/resources/extensions/gsd/auto.ts +6 -1
  219. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +4 -3
  220. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +9 -4
  221. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +42 -5
  222. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +18 -6
  223. package/src/resources/extensions/gsd/bootstrap/system-context.ts +3 -28
  224. package/src/resources/extensions/gsd/closeout-recovery.ts +6 -1
  225. package/src/resources/extensions/gsd/commands/handlers/auto.ts +9 -1
  226. package/src/resources/extensions/gsd/commands-usage.ts +110 -5
  227. package/src/resources/extensions/gsd/config-overlay.ts +19 -16
  228. package/src/resources/extensions/gsd/context-overlay.ts +24 -19
  229. package/src/resources/extensions/gsd/dashboard-overlay.ts +14 -27
  230. package/src/resources/extensions/gsd/doctor-engine-checks.ts +99 -0
  231. package/src/resources/extensions/gsd/doctor-providers.ts +55 -27
  232. package/src/resources/extensions/gsd/doctor-types.ts +2 -0
  233. package/src/resources/extensions/gsd/doctor.ts +6 -1
  234. package/src/resources/extensions/gsd/git-conflict-state.ts +25 -1
  235. package/src/resources/extensions/gsd/guided-flow.ts +5 -6
  236. package/src/resources/extensions/gsd/key-manager.ts +57 -14
  237. package/src/resources/extensions/gsd/milestone-reopen-events.ts +28 -0
  238. package/src/resources/extensions/gsd/notification-overlay.ts +12 -11
  239. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +16 -12
  240. package/src/resources/extensions/gsd/preferences-skills.ts +11 -4
  241. package/src/resources/extensions/gsd/preferences.ts +17 -2
  242. package/src/resources/extensions/gsd/prompt-loader.ts +2 -0
  243. package/src/resources/extensions/gsd/prompts/discuss.md +4 -2
  244. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
  245. package/src/resources/extensions/gsd/prompts/system.md +1 -3
  246. package/src/resources/extensions/gsd/queue-reorder-ui.ts +29 -20
  247. package/src/resources/extensions/gsd/repository-registry.ts +3 -1
  248. package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -4
  249. package/src/resources/extensions/gsd/skill-activation.ts +292 -0
  250. package/src/resources/extensions/gsd/skill-catalog.data.ts +858 -0
  251. package/src/resources/extensions/gsd/skill-catalog.install.ts +205 -0
  252. package/src/resources/extensions/gsd/skill-catalog.ts +16 -1087
  253. package/src/resources/extensions/gsd/skill-discovery.ts +134 -78
  254. package/src/resources/extensions/gsd/skill-scope.ts +63 -0
  255. package/src/resources/extensions/gsd/skill-telemetry.ts +6 -40
  256. package/src/resources/extensions/gsd/skills.ts +75 -0
  257. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +499 -0
  258. package/src/resources/extensions/gsd/state-reconciliation/index.ts +40 -0
  259. package/src/resources/extensions/gsd/state-reconciliation/registry.ts +8 -0
  260. package/src/resources/extensions/gsd/state-reconciliation/types.ts +30 -0
  261. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +328 -2
  262. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +21 -0
  263. package/src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts +28 -2
  264. package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +30 -0
  265. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +41 -0
  266. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +12 -0
  267. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +436 -0
  268. package/src/resources/extensions/gsd/tests/closeout-recovery.test.ts +15 -0
  269. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +31 -0
  270. package/src/resources/extensions/gsd/tests/commands-context.test.ts +5 -3
  271. package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +15 -2
  272. package/src/resources/extensions/gsd/tests/commands-usage.test.ts +97 -0
  273. package/src/resources/extensions/gsd/tests/context-chart.test.ts +9 -0
  274. package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +25 -0
  275. package/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +1 -0
  276. package/src/resources/extensions/gsd/tests/discuss-prompt.test.ts +4 -2
  277. package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +1 -1
  278. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +105 -0
  279. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +101 -1
  280. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +30 -0
  281. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +6 -0
  282. package/src/resources/extensions/gsd/tests/key-manager.test.ts +23 -4
  283. package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +6 -1
  284. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +70 -10
  285. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +7 -1
  286. package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +93 -0
  287. package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +46 -0
  288. package/src/resources/extensions/gsd/tests/register-extension-guard.test.ts +116 -11
  289. package/src/resources/extensions/gsd/tests/repository-registry.test.ts +30 -1
  290. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +4 -0
  291. package/src/resources/extensions/gsd/tests/skill-discovery.test.ts +111 -0
  292. package/src/resources/extensions/gsd/tests/skill-scope-auto.test.ts +67 -0
  293. package/src/resources/extensions/gsd/tests/skills.test.ts +55 -0
  294. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +13 -2
  295. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +303 -0
  296. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +19 -0
  297. package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +24 -1
  298. package/src/resources/extensions/gsd/tests/tui-border-assertions.ts +28 -0
  299. package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +14 -0
  300. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +18 -0
  301. package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +26 -0
  302. package/src/resources/extensions/gsd/tests/vision-ask.test.ts +23 -0
  303. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +6 -1
  304. package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +74 -1
  305. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +82 -0
  306. package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +16 -1
  307. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +28 -0
  308. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +45 -1
  309. package/src/resources/extensions/gsd/tools/complete-task.ts +9 -0
  310. package/src/resources/extensions/gsd/tools/exec-tool.ts +42 -10
  311. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +82 -5
  312. package/src/resources/extensions/gsd/tui/render-kit.ts +82 -0
  313. package/src/resources/extensions/gsd/unit-context-manifest.ts +37 -26
  314. package/src/resources/extensions/gsd/user-input-boundary.ts +1 -1
  315. package/src/resources/extensions/gsd/vision-ask.ts +28 -0
  316. package/src/resources/extensions/gsd/visualizer-overlay.ts +12 -40
  317. package/src/resources/extensions/gsd/worktree-lifecycle.ts +37 -2
  318. package/src/resources/extensions/search-the-web/native-search.ts +60 -8
  319. package/src/resources/extensions/shared/confirm-ui.ts +8 -12
  320. package/src/resources/extensions/shared/dialog-frame.ts +71 -0
  321. package/src/resources/extensions/shared/interview-ui.ts +43 -42
  322. package/src/resources/extensions/shared/next-action-ui.ts +6 -6
  323. package/src/resources/extensions/shared/tests/confirm-ui.test.ts +57 -0
  324. package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +163 -0
  325. package/src/resources/extensions/shared/tests/next-action-ui-hasui.test.ts +55 -0
  326. package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +1 -1
  327. /package/dist/web/standalone/.next/static/{praHP_OATcjBkvAVejjGK → _LIEWYP8ISVAPKAEEXxFr}/_buildManifest.js +0 -0
  328. /package/dist/web/standalone/.next/static/{praHP_OATcjBkvAVejjGK → _LIEWYP8ISVAPKAEEXxFr}/_ssgManifest.js +0 -0
@@ -13,6 +13,8 @@
13
13
  //
14
14
  // Phased rollout tracking:
15
15
  // - Phase 1 (this PR): schema + manifests + coverage test.
16
+ // - Phase 1b (skill token savings): skills policy wired via skill-scope.ts
17
+ // and setVisibleSkills(); allowlists derived from skill-manifest.ts.
16
18
  // - Phase 2: add composeSystemPromptForUnit(); migrate one low-risk
17
19
  // unit type (e.g. reassess-roadmap) as the pilot.
18
20
  // - Phase 3: migrate remaining unit types, tighten manifests per
@@ -277,11 +279,20 @@ export interface UnitContextManifest {
277
279
 
278
280
  // ─── Manifests ────────────────────────────────────────────────────────────
279
281
 
280
- // Phase 1 policy: every manifest encodes today's behavior. Skills = "all"
281
- // unless the unit type was already narrowed via the existing skill-manifest
282
- // resolver (#4779). Memory/knowledge policies reflect the defaults in
283
- // `bootstrap/system-context.ts`. Artifact classifications follow what
284
- // `auto-prompts.ts` inlines today for each unit type.
282
+ // Phase 1 policy: skills policy is derived from skill-manifest.ts allowlists
283
+ // via `skillPolicyForUnit()`; units without an allowlist keep mode "all".
284
+ // Explicit mode "none" remains for lightweight config units.
285
+
286
+ import { resolveSkillManifest } from "./skill-manifest.js";
287
+
288
+ /** Derive skills policy from skill-manifest allowlists; default to full catalog. */
289
+ function skillPolicyForUnit(unitType: string): SkillsPolicy {
290
+ const allowlist = resolveSkillManifest(unitType);
291
+ if (allowlist) {
292
+ return { mode: "allowlist", skills: allowlist };
293
+ }
294
+ return { mode: "all" };
295
+ }
285
296
 
286
297
  const COMMON_BUDGET_LARGE = 1_500_000; // ~400K tokens
287
298
  const COMMON_BUDGET_MEDIUM = 750_000; // ~200K tokens
@@ -360,7 +371,7 @@ export type UnitType = typeof KNOWN_UNIT_TYPES[number];
360
371
  export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
361
372
  // ─── Milestone-scoped ────────────────────────────────────────────────
362
373
  "research-milestone": {
363
- skills: { mode: "all" },
374
+ skills: skillPolicyForUnit("research-milestone"),
364
375
  knowledge: "full",
365
376
  memory: "prompt-relevant",
366
377
  codebaseMap: true,
@@ -377,7 +388,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
377
388
  maxSystemPromptChars: COMMON_BUDGET_MEDIUM,
378
389
  },
379
390
  "plan-milestone": {
380
- skills: { mode: "all" },
391
+ skills: skillPolicyForUnit("plan-milestone"),
381
392
  knowledge: "full",
382
393
  memory: "prompt-relevant",
383
394
  codebaseMap: true,
@@ -392,7 +403,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
392
403
  maxSystemPromptChars: COMMON_BUDGET_LARGE,
393
404
  },
394
405
  "discuss-milestone": {
395
- skills: { mode: "all" },
406
+ skills: skillPolicyForUnit("discuss-milestone"),
396
407
  knowledge: "full",
397
408
  memory: "prompt-relevant",
398
409
  codebaseMap: true,
@@ -407,7 +418,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
407
418
  maxSystemPromptChars: COMMON_BUDGET_MEDIUM,
408
419
  },
409
420
  "validate-milestone": {
410
- skills: { mode: "all" },
421
+ skills: skillPolicyForUnit("validate-milestone"),
411
422
  knowledge: "scoped",
412
423
  memory: "prompt-relevant",
413
424
  codebaseMap: false,
@@ -424,7 +435,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
424
435
  maxSystemPromptChars: COMMON_BUDGET_LARGE,
425
436
  },
426
437
  "complete-milestone": {
427
- skills: { mode: "all" },
438
+ skills: skillPolicyForUnit("complete-milestone"),
428
439
  knowledge: "scoped",
429
440
  memory: "prompt-relevant",
430
441
  codebaseMap: false,
@@ -446,7 +457,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
446
457
 
447
458
  // ─── Slice-scoped ────────────────────────────────────────────────────
448
459
  "research-slice": {
449
- skills: { mode: "all" },
460
+ skills: skillPolicyForUnit("research-slice"),
450
461
  knowledge: "full",
451
462
  memory: "prompt-relevant",
452
463
  codebaseMap: true,
@@ -463,7 +474,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
463
474
  maxSystemPromptChars: COMMON_BUDGET_MEDIUM,
464
475
  },
465
476
  "plan-slice": {
466
- skills: { mode: "all" },
477
+ skills: skillPolicyForUnit("plan-slice"),
467
478
  knowledge: "full",
468
479
  memory: "prompt-relevant",
469
480
  codebaseMap: true,
@@ -481,7 +492,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
481
492
  maxSystemPromptChars: COMMON_BUDGET_LARGE,
482
493
  },
483
494
  "refine-slice": {
484
- skills: { mode: "all" },
495
+ skills: skillPolicyForUnit("refine-slice"),
485
496
  knowledge: "scoped",
486
497
  memory: "prompt-relevant",
487
498
  codebaseMap: true,
@@ -499,7 +510,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
499
510
  maxSystemPromptChars: COMMON_BUDGET_MEDIUM,
500
511
  },
501
512
  "replan-slice": {
502
- skills: { mode: "all" },
513
+ skills: skillPolicyForUnit("replan-slice"),
503
514
  knowledge: "scoped",
504
515
  memory: "prompt-relevant",
505
516
  codebaseMap: true,
@@ -514,7 +525,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
514
525
  maxSystemPromptChars: COMMON_BUDGET_MEDIUM,
515
526
  },
516
527
  "complete-slice": {
517
- skills: { mode: "all" },
528
+ skills: skillPolicyForUnit("complete-slice"),
518
529
  knowledge: "scoped",
519
530
  memory: "prompt-relevant",
520
531
  codebaseMap: false,
@@ -535,7 +546,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
535
546
  maxSystemPromptChars: COMMON_BUDGET_LARGE,
536
547
  },
537
548
  "reassess-roadmap": {
538
- skills: { mode: "all" },
549
+ skills: skillPolicyForUnit("reassess-roadmap"),
539
550
  knowledge: "scoped",
540
551
  memory: "critical-only",
541
552
  codebaseMap: false,
@@ -552,7 +563,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
552
563
 
553
564
  // ─── Task-scoped ─────────────────────────────────────────────────────
554
565
  "execute-task": {
555
- skills: { mode: "all" },
566
+ skills: skillPolicyForUnit("execute-task"),
556
567
  knowledge: "scoped",
557
568
  memory: "prompt-relevant",
558
569
  codebaseMap: true,
@@ -567,7 +578,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
567
578
  maxSystemPromptChars: COMMON_BUDGET_LARGE,
568
579
  },
569
580
  "reactive-execute": {
570
- skills: { mode: "all" },
581
+ skills: skillPolicyForUnit("reactive-execute"),
571
582
  knowledge: "scoped",
572
583
  memory: "prompt-relevant",
573
584
  codebaseMap: true,
@@ -584,7 +595,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
584
595
 
585
596
  // ─── Ancillary units ─────────────────────────────────────────────────
586
597
  "run-uat": {
587
- skills: { mode: "all" },
598
+ skills: skillPolicyForUnit("run-uat"),
588
599
  knowledge: "critical-only",
589
600
  memory: "critical-only",
590
601
  codebaseMap: false,
@@ -599,7 +610,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
599
610
  maxSystemPromptChars: COMMON_BUDGET_SMALL,
600
611
  },
601
612
  "gate-evaluate": {
602
- skills: { mode: "all" },
613
+ skills: skillPolicyForUnit("gate-evaluate"),
603
614
  knowledge: "critical-only",
604
615
  memory: "critical-only",
605
616
  codebaseMap: false,
@@ -616,7 +627,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
616
627
  maxSystemPromptChars: COMMON_BUDGET_SMALL,
617
628
  },
618
629
  "rewrite-docs": {
619
- skills: { mode: "all" },
630
+ skills: skillPolicyForUnit("rewrite-docs"),
620
631
  knowledge: "scoped",
621
632
  memory: "prompt-relevant",
622
633
  codebaseMap: true,
@@ -631,7 +642,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
631
642
  maxSystemPromptChars: COMMON_BUDGET_MEDIUM,
632
643
  },
633
644
  "triage-captures": {
634
- skills: { mode: "all" },
645
+ skills: skillPolicyForUnit("triage-captures"),
635
646
  knowledge: "scoped",
636
647
  memory: "prompt-relevant",
637
648
  codebaseMap: false,
@@ -646,7 +657,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
646
657
  maxSystemPromptChars: COMMON_BUDGET_MEDIUM,
647
658
  },
648
659
  "quick-task": {
649
- skills: { mode: "all" },
660
+ skills: skillPolicyForUnit("quick-task"),
650
661
  knowledge: "full",
651
662
  memory: "prompt-relevant",
652
663
  codebaseMap: true,
@@ -684,7 +695,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
684
695
  // discussion runs before any milestone exists, so milestone artifacts are
685
696
  // not loaded. Keeps templates available for PROJECT.md scaffolding.
686
697
  "discuss-project": {
687
- skills: { mode: "all" },
698
+ skills: skillPolicyForUnit("discuss-project"),
688
699
  knowledge: "scoped",
689
700
  memory: "prompt-relevant",
690
701
  codebaseMap: true,
@@ -701,7 +712,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
701
712
  // discuss-requirements: REQUIREMENTS.md interview. PROJECT.md is the
702
713
  // primary context input; templates carry the requirements format.
703
714
  "discuss-requirements": {
704
- skills: { mode: "all" },
715
+ skills: skillPolicyForUnit("discuss-requirements"),
705
716
  knowledge: "scoped",
706
717
  memory: "prompt-relevant",
707
718
  codebaseMap: true,
@@ -737,7 +748,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
737
748
  // planning-dispatch policy to dispatch them. PROJECT.md + REQUIREMENTS.md
738
749
  // give the orchestrator the framing context.
739
750
  "research-project": {
740
- skills: { mode: "all" },
751
+ skills: skillPolicyForUnit("research-project"),
741
752
  knowledge: "scoped",
742
753
  memory: "prompt-relevant",
743
754
  codebaseMap: true,
@@ -39,7 +39,7 @@ function extractTextFromMessage(msg: unknown): string {
39
39
  return parts.join("\n");
40
40
  }
41
41
 
42
- function lastAssistantText(messages: unknown[] | undefined): string {
42
+ export function lastAssistantText(messages: unknown[] | null | undefined): string {
43
43
  if (!Array.isArray(messages)) return "";
44
44
  for (let i = messages.length - 1; i >= 0; i--) {
45
45
  const msg = messages[i];
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Natural-language openers for milestone discussion.
3
+ *
4
+ * Keep these short and conversational. They are often the user's first prompt
5
+ * when GSD starts shaping a project or milestone, so they should feel like a
6
+ * collaborator starting a working session rather than a form field.
7
+ */
8
+ import { randomInt } from "node:crypto";
9
+
10
+ export const VISION_ASK_VARIANTS = [
11
+ "What are we building?",
12
+ "What do you want to make next?",
13
+ "What should this become?",
14
+ "What are you picturing?",
15
+ "Where should we take this?",
16
+ "What should this milestone unlock?",
17
+ "Tell me what you want to build.",
18
+ "What should GSD help you shape?",
19
+ ] as const;
20
+
21
+ export type VisionAskVariant = typeof VISION_ASK_VARIANTS[number];
22
+
23
+ export function chooseVisionAskVariant(
24
+ pickIndex: (exclusiveMax: number) => number = randomInt,
25
+ ): VisionAskVariant {
26
+ const index = pickIndex(VISION_ASK_VARIANTS.length);
27
+ return VISION_ASK_VARIANTS[index] ?? VISION_ASK_VARIANTS[0];
28
+ }
@@ -1,5 +1,5 @@
1
1
  import type { Theme } from "@gsd/pi-coding-agent";
2
- import { truncateToWidth, visibleWidth, matchesKey, Key } from "@gsd/pi-tui";
2
+ import { visibleWidth, matchesKey, Key } from "@gsd/pi-tui";
3
3
  import { loadVisualizerData, type VisualizerData } from "./visualizer-data.js";
4
4
  import {
5
5
  renderProgressView,
@@ -19,6 +19,7 @@ import { join } from "node:path";
19
19
  import { writeExportFile } from "./export.js";
20
20
  import { gsdRoot } from "./paths.js";
21
21
  import { stripAnsi } from "../shared/mod.js";
22
+ import { renderDialogFrame, renderKeyHints } from "./tui/render-kit.js";
22
23
 
23
24
  export const TAB_COUNT = 10;
24
25
  const TAB_LABELS = [
@@ -500,8 +501,7 @@ export class GSDVisualizerOverlay {
500
501
 
501
502
  // Apply scroll
502
503
  const viewportHeight = Math.max(5, process.stdout.rows ? process.stdout.rows - 8 : 24);
503
- const chromeHeight = 2;
504
- const visibleContentRows = Math.max(1, viewportHeight - chromeHeight);
504
+ const visibleContentRows = Math.max(1, viewportHeight - 4);
505
505
  this.lastVisibleRows = visibleContentRows;
506
506
  const totalLines = content.length;
507
507
  const maxScroll = Math.max(0, content.length - visibleContentRows);
@@ -509,49 +509,21 @@ export class GSDVisualizerOverlay {
509
509
  const offset = this.scrollOffsets[this.activeTab];
510
510
  const visibleContent = content.slice(offset, offset + visibleContentRows);
511
511
 
512
- const lines = this.wrapInBox(visibleContent, width, offset, visibleContentRows, totalLines);
513
-
514
- // Footer hint
515
- const hint = th.fg("dim", "Tab/Shift+Tab/1-9,0 switch \u00b7 / filter \u00b7 PgUp/PgDn scroll \u00b7 ? help \u00b7 esc close");
516
- const hintVis = visibleWidth(hint);
517
- const hintPad = Math.max(0, Math.floor((width - hintVis) / 2));
518
- lines.push(" ".repeat(hintPad) + hint);
512
+ const footer = renderKeyHints(
513
+ th,
514
+ ["Tab/Shift+Tab/1-9,0 switch", "/ filter", "PgUp/PgDn scroll", "? help", "esc close"],
515
+ Math.max(1, width - 4),
516
+ );
517
+ const lines = renderDialogFrame(th, "GSD Visualizer", visibleContent, width, {
518
+ footer,
519
+ scroll: { offset, visibleRows: visibleContentRows, totalRows: totalLines },
520
+ });
519
521
 
520
522
  this.cachedWidth = width;
521
523
  this.cachedLines = lines;
522
524
  return lines;
523
525
  }
524
526
 
525
- private wrapInBox(inner: string[], width: number, offset?: number, visibleRows?: number, totalLines?: number): string[] {
526
- const th = this.theme;
527
- const border = (s: string) => th.fg("borderAccent", s);
528
- const innerWidth = width - 4;
529
- const lines: string[] = [];
530
- lines.push(border("\u256d" + "\u2500".repeat(width - 2) + "\u256e"));
531
-
532
- // Compute scroll indicator positions
533
- const scrollable = totalLines !== undefined && visibleRows !== undefined && totalLines > visibleRows;
534
- let thumbStart = -1;
535
- let thumbLen = 0;
536
- const innerRows = inner.length;
537
- if (scrollable && innerRows > 0 && totalLines! > 0) {
538
- thumbStart = Math.round(((offset ?? 0) / totalLines!) * innerRows);
539
- thumbLen = Math.max(1, Math.round((visibleRows! / totalLines!) * innerRows));
540
- }
541
-
542
- for (let i = 0; i < inner.length; i++) {
543
- const line = inner[i];
544
- const truncated = truncateToWidth(line, innerWidth);
545
- const padWidth = Math.max(0, innerWidth - visibleWidth(truncated));
546
- const rightBorder = scrollable && i >= thumbStart && i < thumbStart + thumbLen
547
- ? border("\u2503")
548
- : border("\u2502");
549
- lines.push(border("\u2502") + " " + truncated + " ".repeat(padWidth) + " " + rightBorder);
550
- }
551
- lines.push(border("\u2570" + "\u2500".repeat(width - 2) + "\u256f"));
552
- return lines;
553
- }
554
-
555
527
  invalidate(): void {
556
528
  this.cachedWidth = undefined;
557
529
  this.cachedLines = undefined;
@@ -216,6 +216,10 @@ export type EnterResult =
216
216
  cause?: unknown;
217
217
  };
218
218
 
219
+ export interface StrandedMilestoneAdoptionOptions {
220
+ mode: "worktree" | "branch";
221
+ }
222
+
219
223
  export type ExitResult =
220
224
  | { ok: true; merged: boolean; codeFilesChanged: boolean }
221
225
  | { ok: false; reason: "merge-conflict" | "teardown-failed"; cause?: unknown };
@@ -237,6 +241,8 @@ export interface MergeContext {
237
241
  */
238
242
  worktreeBasePath: string;
239
243
  milestoneId: string;
244
+ /** Temporary override used while recovering stranded work. */
245
+ isolationModeOverride?: "worktree" | "branch" | "none";
240
246
  /**
241
247
  * When true, `mergeMilestoneStandalone` returns `{ merged: false,
242
248
  * mode: "skipped" }` immediately (mirrors the single-loop guard). Default
@@ -533,6 +539,7 @@ export function _enterMilestoneCore(
533
539
  deps: WorktreeLifecycleDeps,
534
540
  milestoneId: string,
535
541
  ctx: NotifyCtx,
542
+ opts: { modeOverride?: "worktree" | "branch" } = {},
536
543
  ): EnterResult {
537
544
  if (!isValidMilestoneId(milestoneId)) {
538
545
  debugLog("WorktreeLifecycle", {
@@ -653,7 +660,7 @@ export function _enterMilestoneCore(
653
660
  // Handles the case where originalBasePath is falsy and basePath is itself
654
661
  // a worktree path — prevents double-nested worktree paths (#3729).
655
662
  const basePath = resolveWorktreeProjectRoot(s.basePath, s.originalBasePath);
656
- const mode = getIsolationMode(basePath);
663
+ const mode = opts.modeOverride ?? getIsolationMode(basePath);
657
664
 
658
665
  if (s.isolationDegraded) {
659
666
  if (mode === "worktree") {
@@ -1298,7 +1305,9 @@ export function mergeMilestoneStandalone(
1298
1305
  };
1299
1306
  }
1300
1307
 
1301
- const mode = getIsolationMode(originalBasePath || worktreeBasePath);
1308
+ const mode =
1309
+ mctx.isolationModeOverride ??
1310
+ getIsolationMode(originalBasePath || worktreeBasePath);
1302
1311
  debugLog("WorktreeLifecycle", {
1303
1312
  action: "mergeAndExit",
1304
1313
  milestoneId,
@@ -1637,6 +1646,7 @@ export class WorktreeLifecycle {
1637
1646
  originalBasePath: this.s.originalBasePath,
1638
1647
  worktreeBasePath: this.s.basePath,
1639
1648
  milestoneId,
1649
+ isolationModeOverride: this.s.strandedRecoveryIsolationMode ?? undefined,
1640
1650
  isolationDegraded: this.s.isolationDegraded,
1641
1651
  notify: ctx.notify,
1642
1652
  });
@@ -1740,6 +1750,7 @@ export class WorktreeLifecycle {
1740
1750
  // Rebuild GitService after merge (branch HEAD changed)
1741
1751
  rebuildGitService(this.s, this.deps);
1742
1752
  }
1753
+ this.s.strandedRecoveryIsolationMode = null;
1743
1754
  return result;
1744
1755
  }
1745
1756
 
@@ -1876,6 +1887,30 @@ export class WorktreeLifecycle {
1876
1887
  this.s.basePath = resolvePausedResumeBasePath(base, persistedWorktreePath);
1877
1888
  }
1878
1889
 
1890
+ /**
1891
+ * Adopt in-progress stranded work during bootstrap.
1892
+ *
1893
+ * Unlike completed-orphan recovery, this does not merge, delete, or commit.
1894
+ * It only moves the live session onto the branch/worktree proven by the
1895
+ * audit evidence, while preserving that mode for the eventual merge.
1896
+ */
1897
+ adoptStrandedMilestone(
1898
+ milestoneId: string,
1899
+ base: string,
1900
+ ctx: NotifyCtx,
1901
+ opts: StrandedMilestoneAdoptionOptions,
1902
+ ): EnterResult {
1903
+ this.adoptSessionRoot(base);
1904
+ this.s.strandedRecoveryIsolationMode = opts.mode;
1905
+ const result = _enterMilestoneCore(this.s, this.deps, milestoneId, ctx, {
1906
+ modeOverride: opts.mode,
1907
+ });
1908
+ if (!result.ok) {
1909
+ this.s.strandedRecoveryIsolationMode = null;
1910
+ }
1911
+ return result;
1912
+ }
1913
+
1879
1914
  /**
1880
1915
  * Adopt an orphan worktree for a bootstrap-time merge (ADR-016 phase 2 / B4,
1881
1916
  * issue #5622).
@@ -16,6 +16,47 @@ export const CUSTOM_SEARCH_TOOL_NAMES = ["search-the-web", "search_and_read", "g
16
16
 
17
17
  /** Thinking block types that require signature validation by the API */
18
18
  const THINKING_TYPES = new Set(["thinking", "redacted_thinking"]);
19
+ const NATIVE_SERVER_TOOL_USE_TYPES = new Set([
20
+ "server_tool_use",
21
+ "serverToolUse",
22
+ ]);
23
+ const NATIVE_WEB_SEARCH_RESULT_TYPES = new Set([
24
+ "web_search_tool_result",
25
+ "webSearchResult",
26
+ ]);
27
+
28
+ function nativeServerToolId(block: any): string | undefined {
29
+ if (!NATIVE_SERVER_TOOL_USE_TYPES.has(block?.type)) return undefined;
30
+ return typeof block.id === "string" ? block.id : undefined;
31
+ }
32
+
33
+ function nativeWebSearchResultId(block: any): string | undefined {
34
+ if (!NATIVE_WEB_SEARCH_RESULT_TYPES.has(block?.type)) return undefined;
35
+ const id = block.type === "webSearchResult" ? block.toolUseId : block.tool_use_id;
36
+ return typeof id === "string" ? id : undefined;
37
+ }
38
+
39
+ function hasCompleteNativeServerToolReplay(content: any[]): boolean {
40
+ const pendingToolUseIds = new Set<string>();
41
+ let sawNativeServerToolUse = false;
42
+
43
+ for (const block of content) {
44
+ const toolUseId = nativeServerToolId(block);
45
+ if (toolUseId !== undefined) {
46
+ if (pendingToolUseIds.has(toolUseId)) return false;
47
+ sawNativeServerToolUse = true;
48
+ pendingToolUseIds.add(toolUseId);
49
+ continue;
50
+ }
51
+
52
+ const resultId = nativeWebSearchResultId(block);
53
+ if (resultId !== undefined) {
54
+ if (!pendingToolUseIds.delete(resultId)) return false;
55
+ }
56
+ }
57
+
58
+ return sawNativeServerToolUse && pendingToolUseIds.size === 0;
59
+ }
19
60
 
20
61
  /**
21
62
  * Providers whose Anthropic-Messages endpoint is known to accept the native
@@ -36,6 +77,11 @@ const NATIVE_WEB_SEARCH_PROVIDERS = new Set([
36
77
  "vercel-ai-gateway",
37
78
  ]);
38
79
 
80
+ function looksLikeAnthropicModelName(modelName: string): boolean {
81
+ const normalized = modelName.trim().toLowerCase();
82
+ return normalized.startsWith("claude-") || normalized.startsWith("anthropic/claude-");
83
+ }
84
+
39
85
  /**
40
86
  * True when the model is an Anthropic-shaped transport AND the provider is
41
87
  * known to accept the native `web_search_20250305` tool. Gate both on api
@@ -89,11 +135,10 @@ export interface NativeSearchPI {
89
135
  * those blocks. The Anthropic API detects the modification and rejects the
90
136
  * request with "thinking blocks cannot be modified."
91
137
  *
92
- * Fix: Remove thinking blocks from all assistant messages in the history.
93
- * In Anthropic's Messages API, the messages array always ends with a user
94
- * message, so every assistant message is from a previous turn that has been
95
- * through a store/replay cycle. The model generates fresh thinking for the
96
- * current turn regardless.
138
+ * Fix: Remove thinking blocks only from assistant messages that do not carry
139
+ * native server-tool blocks. Complete native server-tool histories can be
140
+ * replayed as-is; stripping thinking from those messages is itself a latest
141
+ * assistant message modification.
97
142
  */
98
143
  export function stripThinkingFromHistory(
99
144
  messages: Array<Record<string, unknown>>
@@ -103,6 +148,9 @@ export function stripThinkingFromHistory(
103
148
 
104
149
  const content = msg.content;
105
150
  if (!Array.isArray(content)) continue;
151
+ if (hasCompleteNativeServerToolReplay(content)) {
152
+ continue;
153
+ }
106
154
 
107
155
  msg.content = content.filter(
108
156
  (block: any) => !THINKING_TYPES.has(block?.type)
@@ -180,6 +228,8 @@ export function registerNativeSearchHooks(pi: NativeSearchPI): { getIsAnthropic:
180
228
  // The model name heuristic is needed for session restores where
181
229
  // modelsAreEqual suppresses model_select AND the SDK doesn't pass model.
182
230
  const eventModel = event.model as { provider?: string; api?: string } | undefined;
231
+ const payloadModelName = typeof payload.model === "string" ? payload.model : "";
232
+ const payloadLooksAnthropic = payloadModelName ? looksLikeAnthropicModelName(payloadModelName) : undefined;
183
233
  let isAnthropic: boolean;
184
234
  if (eventModel?.api || eventModel?.provider) {
185
235
  // Preferred path: gate on api shape + provider allowlist. Both fields
@@ -188,12 +238,14 @@ export function registerNativeSearchHooks(pi: NativeSearchPI): { getIsAnthropic:
188
238
  // (#444 regression) or minimax-served Claude-compat as Anthropic (#4492).
189
239
  isAnthropic = supportsNativeWebSearch(eventModel);
190
240
  } else if (modelSelectFired) {
191
- isAnthropic = isAnthropicProvider;
241
+ // The model_select flag can be stale if the next request omits event.model
242
+ // after a provider switch. A concrete non-Claude payload must win so an
243
+ // Anthropic-only tool never leaks into OpenAI Responses requests.
244
+ isAnthropic = isAnthropicProvider && payloadLooksAnthropic !== false;
192
245
  } else {
193
246
  // Last resort: session-restore paths where the SDK doesn't pass model.
194
247
  // The model-name prefix is best-effort and assumes direct Anthropic.
195
- const modelName = typeof payload.model === "string" ? payload.model : "";
196
- isAnthropic = modelName.startsWith("claude-");
248
+ isAnthropic = payloadLooksAnthropic === true;
197
249
  }
198
250
  if (!isAnthropic) return;
199
251
 
@@ -18,6 +18,7 @@
18
18
  import type { ExtensionContext } from "@gsd/pi-coding-agent";
19
19
  import { type Theme } from "@gsd/pi-coding-agent";
20
20
  import { Key, matchesKey, truncateToWidth, type TUI } from "@gsd/pi-tui";
21
+ import { renderSharedDialogFrame } from "./dialog-frame.js";
21
22
  import { makeUI, GLYPH } from "./ui.js";
22
23
 
23
24
  export interface ConfirmOptions {
@@ -83,20 +84,18 @@ export async function showConfirm(
83
84
  function render(width: number): string[] {
84
85
  if (cachedLines) return cachedLines;
85
86
 
86
- const ui = makeUI(theme, width);
87
+ const contentWidth = Math.max(1, width - 4);
88
+ const ui = makeUI(theme, contentWidth);
87
89
  const lines: string[] = [];
88
90
  const push = (...rows: string[][]) => { for (const r of rows) lines.push(...r); };
89
91
 
90
92
  push(
91
- ui.bar(),
92
- ui.blank(),
93
- ui.header(` ${opts.title}`),
94
93
  ui.blank(),
95
94
  ui.subtitle(` ${opts.message}`),
96
95
  ui.blank(),
97
96
  );
98
97
 
99
- const add = (s: string) => truncateToWidth(s, width);
98
+ const add = (s: string) => truncateToWidth(s, contentWidth);
100
99
  const option = (num: number, label: string, selected: boolean) => {
101
100
  if (selected) {
102
101
  return add(` ${theme.fg("accent", GLYPH.cursor)} ${theme.fg("accent", `${num}. ${label}`)}`);
@@ -107,14 +106,11 @@ export async function showConfirm(
107
106
  lines.push(option(1, yesLabel, cursor === 0));
108
107
  lines.push(option(2, noLabel, cursor === 1));
109
108
 
110
- push(
111
- ui.blank(),
112
- ui.hints(["↑/↓ to choose", "y/n to quick-select", "enter to confirm"]),
113
- ui.bar(),
114
- );
109
+ push(ui.blank());
110
+ const footer = ui.hints(["↑/↓ to choose", "y/n to quick-select", "enter to confirm"])[0] ?? "";
115
111
 
116
- cachedLines = lines;
117
- return lines;
112
+ cachedLines = renderSharedDialogFrame(theme, opts.title, lines, width, { footer });
113
+ return cachedLines;
118
114
  }
119
115
 
120
116
  return {
@@ -0,0 +1,71 @@
1
+ import { type Theme } from "@gsd/pi-coding-agent";
2
+ import { truncateToWidth, visibleWidth } from "@gsd/pi-tui";
3
+
4
+ type ThemeColor = Parameters<Theme["fg"]>[0];
5
+
6
+ export interface SharedDialogFrameOptions {
7
+ borderColor?: ThemeColor;
8
+ footer?: string | string[];
9
+ paddingX?: number;
10
+ }
11
+
12
+ function safeLine(text: string, width: number): string {
13
+ return truncateToWidth(text, width, "");
14
+ }
15
+
16
+ function padVisible(text: string, width: number): string {
17
+ const clipped = safeLine(text, width);
18
+ return clipped + " ".repeat(Math.max(0, width - visibleWidth(clipped)));
19
+ }
20
+
21
+ function renderTopBorder(
22
+ theme: Theme,
23
+ title: string,
24
+ width: number,
25
+ border: (text: string) => string,
26
+ ): string {
27
+ const trimmedTitle = title.trim();
28
+ if (!trimmedTitle || width < 10) {
29
+ return border("╭" + "─".repeat(width - 2) + "╮");
30
+ }
31
+
32
+ const safeTitle = safeLine(trimmedTitle, Math.max(0, width - 7));
33
+ const fill = Math.max(0, width - visibleWidth(safeTitle) - 5);
34
+ return border("╭─ ") + theme.bold(theme.fg("accent", safeTitle)) + border(" " + "─".repeat(fill) + "╮");
35
+ }
36
+
37
+ export function renderSharedDialogFrame(
38
+ theme: Theme,
39
+ title: string,
40
+ inner: string[],
41
+ width: number,
42
+ options: SharedDialogFrameOptions = {},
43
+ ): string[] {
44
+ if (width < 4) return inner.map((line) => safeLine(line, width));
45
+
46
+ const paddingX = Math.max(0, options.paddingX ?? 1);
47
+ const contentWidth = Math.max(0, width - 2 - paddingX * 2);
48
+ const border = (text: string) => theme.fg(options.borderColor ?? "borderAccent", text);
49
+ const pad = " ".repeat(paddingX);
50
+ const lines = [renderTopBorder(theme, title, width, border)];
51
+
52
+ for (const line of inner) {
53
+ lines.push(border("│") + pad + padVisible(line, contentWidth) + pad + border("│"));
54
+ }
55
+
56
+ const footer = Array.isArray(options.footer)
57
+ ? options.footer
58
+ : options.footer
59
+ ? [options.footer]
60
+ : [];
61
+ if (footer.length > 0) {
62
+ lines.push(border("├" + "─".repeat(width - 2) + "┤"));
63
+ for (const line of footer) {
64
+ lines.push(border("│") + pad + padVisible(line, contentWidth) + pad + border("│"));
65
+ }
66
+ }
67
+
68
+ lines.push(border("╰" + "─".repeat(width - 2) + "╯"));
69
+ return lines;
70
+ }
71
+