@opengsd/gsd-pi 1.0.2-dev.e9a1b49 → 1.0.2-dev.fb7ddf1

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 (490) hide show
  1. package/README.md +63 -12
  2. package/dist/headless-answers.js +2 -1
  3. package/dist/headless-events.d.ts +1 -0
  4. package/dist/headless-events.js +8 -1
  5. package/dist/onboarding.js +22 -3
  6. package/dist/resource-loader.d.ts +7 -0
  7. package/dist/resource-loader.js +44 -9
  8. package/dist/resources/.managed-resources-content-hash +1 -1
  9. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +34 -11
  10. package/dist/resources/extensions/context7/index.js +12 -2
  11. package/dist/resources/extensions/get-secrets-from-user.js +16 -16
  12. package/dist/resources/extensions/google-cli/index.js +30 -0
  13. package/dist/resources/extensions/google-cli/models.js +55 -0
  14. package/dist/resources/extensions/google-cli/package.json +11 -0
  15. package/dist/resources/extensions/google-cli/readiness.js +12 -0
  16. package/dist/resources/extensions/google-cli/stream-adapter.js +191 -0
  17. package/dist/resources/extensions/gsd/auto/loop.js +81 -1
  18. package/dist/resources/extensions/gsd/auto/orchestrator.js +4 -2
  19. package/dist/resources/extensions/gsd/auto/phases.js +38 -1
  20. package/dist/resources/extensions/gsd/auto/run-unit.js +8 -0
  21. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  22. package/dist/resources/extensions/gsd/auto-dispatch.js +17 -7
  23. package/dist/resources/extensions/gsd/auto-post-unit.js +65 -16
  24. package/dist/resources/extensions/gsd/auto-prompts.js +5 -236
  25. package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
  26. package/dist/resources/extensions/gsd/auto-start.js +232 -49
  27. package/dist/resources/extensions/gsd/auto-tool-tracking.js +2 -1
  28. package/dist/resources/extensions/gsd/auto-verification.js +14 -2
  29. package/dist/resources/extensions/gsd/auto-worktree.js +36 -55
  30. package/dist/resources/extensions/gsd/auto.js +40 -2
  31. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +4 -3
  32. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +7 -2
  33. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +39 -5
  34. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +107 -27
  35. package/dist/resources/extensions/gsd/bootstrap/system-context.js +3 -27
  36. package/dist/resources/extensions/gsd/bootstrap/tool-search-shim.js +4 -4
  37. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +1 -1
  38. package/dist/resources/extensions/gsd/closeout-recovery.js +7 -1
  39. package/dist/resources/extensions/gsd/commands/handlers/auto.js +9 -1
  40. package/dist/resources/extensions/gsd/commands-handlers.js +3 -0
  41. package/dist/resources/extensions/gsd/commands-usage.js +105 -1
  42. package/dist/resources/extensions/gsd/config-overlay.js +20 -14
  43. package/dist/resources/extensions/gsd/context-overlay.js +22 -16
  44. package/dist/resources/extensions/gsd/dashboard-overlay.js +10 -23
  45. package/dist/resources/extensions/gsd/doctor-engine-checks.js +87 -0
  46. package/dist/resources/extensions/gsd/doctor-git-checks.js +70 -5
  47. package/dist/resources/extensions/gsd/doctor-providers.js +54 -24
  48. package/dist/resources/extensions/gsd/doctor.js +7 -2
  49. package/dist/resources/extensions/gsd/git-conflict-state.js +26 -1
  50. package/dist/resources/extensions/gsd/guided-flow.js +5 -6
  51. package/dist/resources/extensions/gsd/key-manager.js +45 -13
  52. package/dist/resources/extensions/gsd/mcp-filter.js +57 -18
  53. package/dist/resources/extensions/gsd/mcp-project-config.js +15 -9
  54. package/dist/resources/extensions/gsd/migration-auto-check.js +5 -1
  55. package/dist/resources/extensions/gsd/milestone-actions.js +3 -0
  56. package/dist/resources/extensions/gsd/milestone-reopen-events.js +28 -0
  57. package/dist/resources/extensions/gsd/notification-overlay.js +8 -9
  58. package/dist/resources/extensions/gsd/parallel-merge.js +6 -4
  59. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +15 -13
  60. package/dist/resources/extensions/gsd/post-execution-checks.js +5 -4
  61. package/dist/resources/extensions/gsd/preferences-skills.js +11 -4
  62. package/dist/resources/extensions/gsd/preferences.js +14 -2
  63. package/dist/resources/extensions/gsd/prompt-loader.js +2 -0
  64. package/dist/resources/extensions/gsd/prompts/discuss.md +4 -2
  65. package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
  66. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
  67. package/dist/resources/extensions/gsd/prompts/system.md +3 -20
  68. package/dist/resources/extensions/gsd/queue-reorder-ui.js +28 -18
  69. package/dist/resources/extensions/gsd/repo-identity.js +36 -6
  70. package/dist/resources/extensions/gsd/repository-registry.js +3 -1
  71. package/dist/resources/extensions/gsd/safety/evidence-collector.js +13 -6
  72. package/dist/resources/extensions/gsd/skill-activation.js +233 -0
  73. package/dist/resources/extensions/gsd/skill-catalog.data.js +820 -0
  74. package/dist/resources/extensions/gsd/skill-catalog.install.js +179 -0
  75. package/dist/resources/extensions/gsd/skill-catalog.js +5 -1028
  76. package/dist/resources/extensions/gsd/skill-discovery.js +121 -79
  77. package/dist/resources/extensions/gsd/skill-scope.js +52 -0
  78. package/dist/resources/extensions/gsd/skill-telemetry.js +6 -39
  79. package/dist/resources/extensions/gsd/skills/gsd-headless/SKILL.md +1 -1
  80. package/dist/resources/extensions/gsd/skills.js +60 -0
  81. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +351 -0
  82. package/dist/resources/extensions/gsd/state-reconciliation/index.js +41 -0
  83. package/dist/resources/extensions/gsd/state-reconciliation/registry.js +4 -0
  84. package/dist/resources/extensions/gsd/tools/complete-task.js +9 -0
  85. package/dist/resources/extensions/gsd/tools/exec-tool.js +42 -8
  86. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +63 -2
  87. package/dist/resources/extensions/gsd/tui/render-kit.js +51 -0
  88. package/dist/resources/extensions/gsd/unit-context-manifest.js +35 -26
  89. package/dist/resources/extensions/gsd/user-input-boundary.js +1 -1
  90. package/dist/resources/extensions/gsd/vision-ask.js +22 -0
  91. package/dist/resources/extensions/gsd/visualizer-overlay.js +8 -36
  92. package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -3
  93. package/dist/resources/extensions/gsd/worktree-post-create-hook.js +117 -0
  94. package/dist/resources/extensions/gsd/worktree-state-projection.js +29 -0
  95. package/dist/resources/extensions/search-the-web/native-search.js +57 -8
  96. package/dist/resources/extensions/shared/confirm-ui.js +9 -6
  97. package/dist/resources/extensions/shared/dialog-frame.js +42 -0
  98. package/dist/resources/extensions/shared/interview-ui.js +42 -30
  99. package/dist/resources/extensions/shared/next-action-ui.js +6 -6
  100. package/dist/resources/extensions/subagent/index.js +8 -15
  101. package/dist/resources/shared/package-manager-detection.js +36 -0
  102. package/dist/resources/skills/agent-browser/SKILL.md +1 -1
  103. package/dist/resources/skills/api-design/SKILL.md +1 -1
  104. package/dist/resources/skills/code-optimizer/SKILL.md +6 -11
  105. package/dist/resources/skills/create-gsd-extension/SKILL.md +1 -1
  106. package/dist/resources/skills/create-mcp-server/SKILL.md +1 -1
  107. package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +1 -1
  108. package/dist/resources/skills/create-skill/workflows/verify-skill.md +2 -10
  109. package/dist/resources/skills/debug-like-expert/references/when-to-research.md +1 -5
  110. package/dist/resources/skills/decompose-into-slices/SKILL.md +3 -3
  111. package/dist/resources/skills/dependency-upgrade/SKILL.md +1 -1
  112. package/dist/resources/skills/forensics/SKILL.md +2 -2
  113. package/dist/resources/skills/grill-me/SKILL.md +1 -1
  114. package/dist/resources/skills/handoff/SKILL.md +1 -1
  115. package/dist/resources/skills/make-interfaces-feel-better/SKILL.md +1 -1
  116. package/dist/resources/skills/observability/SKILL.md +1 -1
  117. package/dist/resources/skills/security-review/SKILL.md +1 -1
  118. package/dist/resources/skills/spike-wrap-up/SKILL.md +1 -1
  119. package/dist/resources/skills/tdd/SKILL.md +1 -1
  120. package/dist/resources/skills/write-docs/SKILL.md +1 -1
  121. package/dist/resources/skills/write-milestone-brief/SKILL.md +1 -1
  122. package/dist/update-check.d.ts +6 -2
  123. package/dist/update-check.js +7 -3
  124. package/dist/web/standalone/.next/BUILD_ID +1 -1
  125. package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
  126. package/dist/web/standalone/.next/build-manifest.json +2 -2
  127. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  128. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  129. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  130. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  131. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  132. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  134. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  135. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  136. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  137. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  139. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  140. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  141. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  142. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  143. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  144. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  145. package/dist/web/standalone/.next/server/app/index.html +1 -1
  146. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  147. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  148. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  149. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  150. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  151. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  152. package/dist/web/standalone/.next/server/app-paths-manifest.json +8 -8
  153. package/dist/web/standalone/.next/server/chunks/1834.js +2 -2
  154. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  156. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  157. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  158. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  159. package/dist/worktree-cli.d.ts +0 -2
  160. package/dist/worktree-cli.js +21 -9
  161. package/package.json +5 -2
  162. package/packages/cloud-mcp-gateway/bin/gsd-cloud-mcp-gateway.js +14 -0
  163. package/packages/cloud-mcp-gateway/package.json +4 -3
  164. package/packages/contracts/dist/rpc.test.js +5 -0
  165. package/packages/contracts/dist/rpc.test.js.map +1 -1
  166. package/packages/contracts/dist/workflow.d.ts +15 -0
  167. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  168. package/packages/contracts/dist/workflow.js +16 -0
  169. package/packages/contracts/dist/workflow.js.map +1 -1
  170. package/packages/contracts/dist/workflow.test.js +1 -0
  171. package/packages/contracts/dist/workflow.test.js.map +1 -1
  172. package/packages/contracts/package.json +1 -1
  173. package/packages/daemon/package.json +4 -4
  174. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +1 -0
  175. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
  176. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +22 -8
  177. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
  178. package/packages/gsd-agent-core/package.json +5 -5
  179. package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.d.ts +12 -0
  180. package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.d.ts.map +1 -0
  181. package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.js +45 -0
  182. package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.js.map +1 -0
  183. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.d.ts +3 -2
  184. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  185. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.js +11 -11
  186. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.js.map +1 -1
  187. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.d.ts +3 -3
  188. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  189. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.js +13 -11
  190. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.js.map +1 -1
  191. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.d.ts +3 -3
  192. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  193. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.js +12 -10
  194. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.js.map +1 -1
  195. package/packages/gsd-agent-modes/dist/modes/interactive/components/index.d.ts +1 -0
  196. package/packages/gsd-agent-modes/dist/modes/interactive/components/index.d.ts.map +1 -1
  197. package/packages/gsd-agent-modes/dist/modes/interactive/components/index.js +1 -0
  198. package/packages/gsd-agent-modes/dist/modes/interactive/components/index.js.map +1 -1
  199. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts +1 -1
  200. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  201. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js +2 -2
  202. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js.map +1 -1
  203. package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.d.ts +6 -1
  204. package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  205. package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.js +9 -6
  206. package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  207. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  208. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +3 -1
  209. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  210. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
  211. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +0 -2
  212. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
  213. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts +1 -0
  214. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts.map +1 -1
  215. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js +1 -0
  216. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js.map +1 -1
  217. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  218. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +2 -1
  219. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
  220. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts +3 -0
  221. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
  222. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +144 -2
  223. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
  224. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.d.ts.map +1 -1
  225. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.js +2 -14
  226. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.js.map +1 -1
  227. package/packages/gsd-agent-modes/package.json +7 -7
  228. package/packages/mcp-server/bin/gsd-mcp-server.js +14 -0
  229. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  230. package/packages/mcp-server/dist/server.js +7 -1
  231. package/packages/mcp-server/dist/server.js.map +1 -1
  232. package/packages/mcp-server/dist/workflow-tools.d.ts +13 -1
  233. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  234. package/packages/mcp-server/dist/workflow-tools.js +47 -8
  235. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  236. package/packages/mcp-server/package.json +5 -4
  237. package/packages/native/package.json +1 -1
  238. package/packages/pi-agent-core/dist/agent-loop.js +16 -14
  239. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  240. package/packages/pi-agent-core/dist/harness/skills.d.ts.map +1 -1
  241. package/packages/pi-agent-core/dist/harness/skills.js +6 -0
  242. package/packages/pi-agent-core/dist/harness/skills.js.map +1 -1
  243. package/packages/pi-agent-core/dist/harness/system-prompt.d.ts +7 -0
  244. package/packages/pi-agent-core/dist/harness/system-prompt.d.ts.map +1 -1
  245. package/packages/pi-agent-core/dist/harness/system-prompt.js +7 -0
  246. package/packages/pi-agent-core/dist/harness/system-prompt.js.map +1 -1
  247. package/packages/pi-agent-core/package.json +1 -1
  248. package/packages/pi-ai/bin/pi-ai.js +14 -0
  249. package/packages/pi-ai/dist/models.generated.d.ts +48 -206
  250. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  251. package/packages/pi-ai/dist/models.generated.js +73 -226
  252. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  253. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  254. package/packages/pi-ai/dist/providers/anthropic.js +50 -0
  255. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  256. package/packages/pi-ai/dist/providers/openai-responses-shared.d.ts.map +1 -1
  257. package/packages/pi-ai/dist/providers/openai-responses-shared.js +28 -4
  258. package/packages/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
  259. package/packages/pi-ai/dist/types.d.ts +2 -0
  260. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  261. package/packages/pi-ai/dist/types.js.map +1 -1
  262. package/packages/pi-ai/dist/utils/tests/tool-search-shim.test.js +29 -1
  263. package/packages/pi-ai/dist/utils/tests/tool-search-shim.test.js.map +1 -1
  264. package/packages/pi-ai/dist/utils/tool-search-shim.d.ts +4 -1
  265. package/packages/pi-ai/dist/utils/tool-search-shim.d.ts.map +1 -1
  266. package/packages/pi-ai/dist/utils/tool-search-shim.js +58 -10
  267. package/packages/pi-ai/dist/utils/tool-search-shim.js.map +1 -1
  268. package/packages/pi-ai/dist/utils/tool-shims.d.ts +1 -1
  269. package/packages/pi-ai/dist/utils/tool-shims.d.ts.map +1 -1
  270. package/packages/pi-ai/dist/utils/tool-shims.js.map +1 -1
  271. package/packages/pi-ai/package.json +3 -2
  272. package/packages/pi-coding-agent/README.md +1 -1
  273. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts +2 -2
  274. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts.map +1 -1
  275. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.js.map +1 -1
  276. package/packages/pi-coding-agent/dist/core/extensions/loader.js +1 -1
  277. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  278. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  279. package/packages/pi-coding-agent/dist/core/extensions/runner.js +8 -2
  280. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  281. package/packages/pi-coding-agent/dist/core/skills.d.ts +3 -0
  282. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  283. package/packages/pi-coding-agent/dist/core/skills.js +3 -0
  284. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  285. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  286. package/packages/pi-coding-agent/dist/core/tools/edit.js +5 -7
  287. package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  288. package/packages/pi-coding-agent/dist/core/tools/read.d.ts +2 -2
  289. package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
  290. package/packages/pi-coding-agent/dist/core/tools/read.js +5 -4
  291. package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
  292. package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  293. package/packages/pi-coding-agent/dist/core/tools/write.js +0 -1
  294. package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  295. package/packages/pi-coding-agent/package.json +8 -8
  296. package/packages/pi-tui/package.json +1 -1
  297. package/packages/rpc-client/package.json +2 -2
  298. package/pkg/package.json +1 -1
  299. package/scripts/install/deps.js +10 -0
  300. package/scripts/install/detect-existing.js +17 -3
  301. package/scripts/install/npm-global.js +103 -33
  302. package/scripts/install.js +1 -0
  303. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +36 -11
  304. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +86 -19
  305. package/src/resources/extensions/context7/index.ts +15 -2
  306. package/src/resources/extensions/get-secrets-from-user.ts +17 -16
  307. package/src/resources/extensions/google-cli/index.ts +34 -0
  308. package/src/resources/extensions/google-cli/models.ts +57 -0
  309. package/src/resources/extensions/google-cli/package.json +11 -0
  310. package/src/resources/extensions/google-cli/readiness.ts +15 -0
  311. package/src/resources/extensions/google-cli/stream-adapter.ts +245 -0
  312. package/src/resources/extensions/gsd/auto/loop.ts +96 -1
  313. package/src/resources/extensions/gsd/auto/orchestrator.ts +4 -2
  314. package/src/resources/extensions/gsd/auto/phases.ts +47 -1
  315. package/src/resources/extensions/gsd/auto/run-unit.ts +10 -0
  316. package/src/resources/extensions/gsd/auto/session.ts +3 -0
  317. package/src/resources/extensions/gsd/auto-dispatch.ts +31 -11
  318. package/src/resources/extensions/gsd/auto-post-unit.ts +101 -18
  319. package/src/resources/extensions/gsd/auto-prompts.ts +4 -284
  320. package/src/resources/extensions/gsd/auto-recovery.ts +10 -7
  321. package/src/resources/extensions/gsd/auto-start.ts +307 -56
  322. package/src/resources/extensions/gsd/auto-tool-tracking.ts +3 -1
  323. package/src/resources/extensions/gsd/auto-verification.ts +18 -2
  324. package/src/resources/extensions/gsd/auto-worktree.ts +47 -57
  325. package/src/resources/extensions/gsd/auto.ts +50 -2
  326. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +4 -3
  327. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +9 -4
  328. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +42 -5
  329. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +124 -25
  330. package/src/resources/extensions/gsd/bootstrap/system-context.ts +3 -28
  331. package/src/resources/extensions/gsd/bootstrap/tool-search-shim.ts +4 -4
  332. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +1 -1
  333. package/src/resources/extensions/gsd/closeout-recovery.ts +6 -1
  334. package/src/resources/extensions/gsd/commands/handlers/auto.ts +9 -1
  335. package/src/resources/extensions/gsd/commands-handlers.ts +2 -0
  336. package/src/resources/extensions/gsd/commands-usage.ts +110 -5
  337. package/src/resources/extensions/gsd/config-overlay.ts +19 -16
  338. package/src/resources/extensions/gsd/context-overlay.ts +24 -19
  339. package/src/resources/extensions/gsd/dashboard-overlay.ts +14 -27
  340. package/src/resources/extensions/gsd/doctor-engine-checks.ts +99 -0
  341. package/src/resources/extensions/gsd/doctor-git-checks.ts +72 -5
  342. package/src/resources/extensions/gsd/doctor-providers.ts +55 -27
  343. package/src/resources/extensions/gsd/doctor-types.ts +2 -0
  344. package/src/resources/extensions/gsd/doctor.ts +7 -2
  345. package/src/resources/extensions/gsd/git-conflict-state.ts +25 -1
  346. package/src/resources/extensions/gsd/guided-flow.ts +5 -6
  347. package/src/resources/extensions/gsd/key-manager.ts +57 -14
  348. package/src/resources/extensions/gsd/mcp-filter.ts +64 -17
  349. package/src/resources/extensions/gsd/mcp-project-config.ts +24 -9
  350. package/src/resources/extensions/gsd/migration-auto-check.ts +6 -0
  351. package/src/resources/extensions/gsd/milestone-actions.ts +2 -0
  352. package/src/resources/extensions/gsd/milestone-reopen-events.ts +28 -0
  353. package/src/resources/extensions/gsd/notification-overlay.ts +12 -11
  354. package/src/resources/extensions/gsd/parallel-merge.ts +6 -4
  355. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +16 -12
  356. package/src/resources/extensions/gsd/post-execution-checks.ts +7 -4
  357. package/src/resources/extensions/gsd/preferences-skills.ts +11 -4
  358. package/src/resources/extensions/gsd/preferences.ts +17 -2
  359. package/src/resources/extensions/gsd/prompt-loader.ts +2 -0
  360. package/src/resources/extensions/gsd/prompts/discuss.md +4 -2
  361. package/src/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
  362. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
  363. package/src/resources/extensions/gsd/prompts/system.md +3 -20
  364. package/src/resources/extensions/gsd/queue-reorder-ui.ts +29 -20
  365. package/src/resources/extensions/gsd/repo-identity.ts +35 -7
  366. package/src/resources/extensions/gsd/repository-registry.ts +3 -1
  367. package/src/resources/extensions/gsd/safety/evidence-collector.ts +13 -6
  368. package/src/resources/extensions/gsd/skill-activation.ts +292 -0
  369. package/src/resources/extensions/gsd/skill-catalog.data.ts +858 -0
  370. package/src/resources/extensions/gsd/skill-catalog.install.ts +205 -0
  371. package/src/resources/extensions/gsd/skill-catalog.ts +16 -1087
  372. package/src/resources/extensions/gsd/skill-discovery.ts +134 -78
  373. package/src/resources/extensions/gsd/skill-scope.ts +63 -0
  374. package/src/resources/extensions/gsd/skill-telemetry.ts +6 -40
  375. package/src/resources/extensions/gsd/skills/gsd-headless/SKILL.md +1 -1
  376. package/src/resources/extensions/gsd/skills.ts +75 -0
  377. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +499 -0
  378. package/src/resources/extensions/gsd/state-reconciliation/index.ts +40 -0
  379. package/src/resources/extensions/gsd/state-reconciliation/registry.ts +8 -0
  380. package/src/resources/extensions/gsd/state-reconciliation/types.ts +30 -0
  381. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +328 -2
  382. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +75 -0
  383. package/src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts +28 -2
  384. package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +30 -0
  385. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +41 -0
  386. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +24 -0
  387. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +436 -0
  388. package/src/resources/extensions/gsd/tests/auto-worktree-untracked-content.test.ts +53 -0
  389. package/src/resources/extensions/gsd/tests/closeout-recovery.test.ts +15 -0
  390. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +31 -0
  391. package/src/resources/extensions/gsd/tests/commands-context.test.ts +5 -3
  392. package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +15 -2
  393. package/src/resources/extensions/gsd/tests/commands-usage.test.ts +97 -0
  394. package/src/resources/extensions/gsd/tests/complete-slice-reopen-handoff.test.ts +40 -3
  395. package/src/resources/extensions/gsd/tests/context-chart.test.ts +9 -0
  396. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +64 -0
  397. package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +25 -0
  398. package/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +1 -0
  399. package/src/resources/extensions/gsd/tests/discuss-prompt.test.ts +4 -2
  400. package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +1 -1
  401. package/src/resources/extensions/gsd/tests/doctor-empty-worktree.test.ts +71 -1
  402. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +105 -0
  403. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +101 -1
  404. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +30 -0
  405. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +6 -0
  406. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +22 -3
  407. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +43 -0
  408. package/src/resources/extensions/gsd/tests/interactive-tool-idle-exemption.test.ts +8 -0
  409. package/src/resources/extensions/gsd/tests/key-manager.test.ts +23 -4
  410. package/src/resources/extensions/gsd/tests/mcp-filter.test.ts +19 -1
  411. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +24 -0
  412. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +56 -1
  413. package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +6 -1
  414. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +70 -10
  415. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +7 -1
  416. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +9 -0
  417. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +127 -10
  418. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +44 -0
  419. package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +93 -0
  420. package/src/resources/extensions/gsd/tests/project-relocation-recovery.test.ts +101 -0
  421. package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +46 -0
  422. package/src/resources/extensions/gsd/tests/register-extension-guard.test.ts +116 -11
  423. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +27 -0
  424. package/src/resources/extensions/gsd/tests/repository-registry.test.ts +30 -1
  425. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +4 -0
  426. package/src/resources/extensions/gsd/tests/skill-discovery.test.ts +111 -0
  427. package/src/resources/extensions/gsd/tests/skill-scope-auto.test.ts +67 -0
  428. package/src/resources/extensions/gsd/tests/skills.test.ts +55 -0
  429. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +13 -2
  430. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +303 -0
  431. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +67 -1
  432. package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +24 -1
  433. package/src/resources/extensions/gsd/tests/tui-border-assertions.ts +28 -0
  434. package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +14 -0
  435. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +18 -0
  436. package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +26 -0
  437. package/src/resources/extensions/gsd/tests/vision-ask.test.ts +23 -0
  438. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +6 -1
  439. package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +133 -0
  440. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +82 -0
  441. package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +16 -1
  442. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +28 -0
  443. package/src/resources/extensions/gsd/tests/worktree-post-create-hook.test.ts +141 -1
  444. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +38 -1
  445. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +10 -0
  446. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +45 -1
  447. package/src/resources/extensions/gsd/tools/complete-task.ts +9 -0
  448. package/src/resources/extensions/gsd/tools/exec-tool.ts +42 -10
  449. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +82 -5
  450. package/src/resources/extensions/gsd/tui/render-kit.ts +82 -0
  451. package/src/resources/extensions/gsd/unit-context-manifest.ts +37 -26
  452. package/src/resources/extensions/gsd/user-input-boundary.ts +1 -1
  453. package/src/resources/extensions/gsd/vision-ask.ts +28 -0
  454. package/src/resources/extensions/gsd/visualizer-overlay.ts +12 -40
  455. package/src/resources/extensions/gsd/worktree-lifecycle.ts +37 -2
  456. package/src/resources/extensions/gsd/worktree-post-create-hook.ts +127 -0
  457. package/src/resources/extensions/gsd/worktree-state-projection.ts +33 -0
  458. package/src/resources/extensions/search-the-web/native-search.ts +60 -8
  459. package/src/resources/extensions/shared/confirm-ui.ts +8 -12
  460. package/src/resources/extensions/shared/dialog-frame.ts +71 -0
  461. package/src/resources/extensions/shared/interview-ui.ts +43 -42
  462. package/src/resources/extensions/shared/next-action-ui.ts +6 -6
  463. package/src/resources/extensions/shared/tests/confirm-ui.test.ts +57 -0
  464. package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +163 -0
  465. package/src/resources/extensions/shared/tests/next-action-ui-hasui.test.ts +55 -0
  466. package/src/resources/extensions/subagent/index.ts +8 -15
  467. package/src/resources/shared/package-manager-detection.ts +39 -0
  468. package/src/resources/skills/agent-browser/SKILL.md +1 -1
  469. package/src/resources/skills/api-design/SKILL.md +1 -1
  470. package/src/resources/skills/code-optimizer/SKILL.md +6 -11
  471. package/src/resources/skills/create-gsd-extension/SKILL.md +1 -1
  472. package/src/resources/skills/create-mcp-server/SKILL.md +1 -1
  473. package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +1 -1
  474. package/src/resources/skills/create-skill/workflows/verify-skill.md +2 -10
  475. package/src/resources/skills/debug-like-expert/references/when-to-research.md +1 -5
  476. package/src/resources/skills/decompose-into-slices/SKILL.md +3 -3
  477. package/src/resources/skills/dependency-upgrade/SKILL.md +1 -1
  478. package/src/resources/skills/forensics/SKILL.md +2 -2
  479. package/src/resources/skills/grill-me/SKILL.md +1 -1
  480. package/src/resources/skills/handoff/SKILL.md +1 -1
  481. package/src/resources/skills/make-interfaces-feel-better/SKILL.md +1 -1
  482. package/src/resources/skills/observability/SKILL.md +1 -1
  483. package/src/resources/skills/security-review/SKILL.md +1 -1
  484. package/src/resources/skills/spike-wrap-up/SKILL.md +1 -1
  485. package/src/resources/skills/tdd/SKILL.md +1 -1
  486. package/src/resources/skills/write-docs/SKILL.md +1 -1
  487. package/src/resources/skills/write-milestone-brief/SKILL.md +1 -1
  488. package/dist/tsconfig.extensions.tsbuildinfo +0 -1
  489. /package/dist/web/standalone/.next/static/{BEjZM0MLHLibeMFbjtMol → tH1tnDYt1E0hK9Ien73Z0}/_buildManifest.js +0 -0
  490. /package/dist/web/standalone/.next/static/{BEjZM0MLHLibeMFbjtMol → tH1tnDYt1E0hK9Ien73Z0}/_ssgManifest.js +0 -0
@@ -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
+
@@ -36,6 +36,7 @@ import {
36
36
  truncateToWidth,
37
37
  type TUI,
38
38
  } from "@gsd/pi-tui";
39
+ import { renderSharedDialogFrame } from "./dialog-frame.js";
39
40
  import { mergeSideBySide } from "./layout-utils.js";
40
41
  import { makeUI, INDENT } from "./ui.js";
41
42
 
@@ -126,6 +127,10 @@ const DIVIDER_CHARS = " │ ";
126
127
  const DIVIDER_WIDTH = 3;
127
128
  const PREVIEW_MAX_LINES = 20; // hard cap — keeps total ≤ 24 rows for single-question
128
129
 
130
+ function dialogContentWidth(width: number): number {
131
+ return width < 4 ? Math.max(1, width) : Math.max(1, width - 4);
132
+ }
133
+
129
134
  // ─── Wrap-up screen ───────────────────────────────────────────────────────────
130
135
 
131
136
  export async function showWrapUpScreen(
@@ -157,11 +162,12 @@ export async function showWrapUpScreen(
157
162
 
158
163
  function render(width: number): string[] {
159
164
  if (cachedLines) return cachedLines;
160
- const ui = makeUI(theme, width);
165
+ const contentWidth = dialogContentWidth(width);
166
+ const ui = makeUI(theme, contentWidth);
161
167
  const lines: string[] = [];
162
168
  const push = (...rows: string[][]) => { for (const r of rows) lines.push(...r); };
163
169
 
164
- push(ui.bar(), ui.blank(), ui.header(` ${opts.headline}`), ui.blank());
170
+ push(ui.blank());
165
171
  if (opts.progress) push(ui.meta(` ${opts.progress}`), ui.blank());
166
172
 
167
173
  if (cursorIdx === 1) {
@@ -175,14 +181,11 @@ export async function showWrapUpScreen(
175
181
  } else {
176
182
  push(ui.actionUnselected(2, opts.keepGoingLabel, "Continue with another batch of questions."));
177
183
  }
178
- push(
179
- ui.blank(),
180
- ui.hints(["↑/↓ to choose", "1/2 to quick-select", "enter to confirm"]),
181
- ui.bar(),
182
- );
184
+ push(ui.blank());
183
185
 
184
- cachedLines = lines;
185
- return lines;
186
+ const footer = ui.hints(["↑/↓ to choose", "1/2 to quick-select", "enter to confirm"])[0] ?? "";
187
+ cachedLines = renderSharedDialogFrame(theme, opts.headline, lines, width, { footer });
188
+ return cachedLines;
186
189
  }
187
190
 
188
191
  return {
@@ -469,11 +472,13 @@ export async function showInterviewRound(
469
472
  // ── Review screen ────────────────────────────────────────────────
470
473
 
471
474
  function renderReviewScreen(width: number): string[] {
472
- const ui = makeUI(theme, width);
475
+ const contentWidth = dialogContentWidth(width);
476
+ const title = opts.reviewHeadline ?? "Review your answers";
477
+ const ui = makeUI(theme, contentWidth);
473
478
  const lines: string[] = [];
474
479
  const push = (...rows: string[][]) => { for (const r of rows) lines.push(...r); };
475
480
 
476
- push(ui.bar(), ui.blank(), ui.header(` ${opts.reviewHeadline ?? "Review your answers"}`), ui.blank());
481
+ push(ui.blank());
477
482
 
478
483
  for (let i = 0; i < questions.length; i++) {
479
484
  const q = questions[i];
@@ -500,24 +505,22 @@ export async function showInterviewRound(
500
505
  push(
501
506
  ui.actionSelected(0, "Submit answers"),
502
507
  ui.blank(),
503
- ui.hints(["← to go back and edit", "enter to submit", `esc to ${opts.exitLabel ?? "end interview"}`]),
504
- ui.bar(),
505
508
  );
506
509
 
507
- return lines;
510
+ const footer = ui.hints(["← to go back and edit", "enter to submit", `esc to ${opts.exitLabel ?? "end interview"}`])[0] ?? "";
511
+ return renderSharedDialogFrame(theme, title, lines, width, { footer });
508
512
  }
509
513
 
510
514
  // ── Exit confirm screen ──────────────────────────────────────────
511
515
 
512
516
  function renderExitConfirm(width: number): string[] {
513
- const ui = makeUI(theme, width);
517
+ const contentWidth = dialogContentWidth(width);
518
+ const title = opts.exitHeadline ?? "End interview?";
519
+ const ui = makeUI(theme, contentWidth);
514
520
  const lines: string[] = [];
515
521
  const push = (...rows: string[][]) => { for (const r of rows) lines.push(...r); };
516
522
 
517
523
  push(
518
- ui.bar(),
519
- ui.blank(),
520
- ui.header(` ${opts.exitHeadline ?? "End interview?"}`),
521
524
  ui.blank(),
522
525
  ui.subtitle(" Answers from this batch won't be saved."),
523
526
  ui.blank(),
@@ -538,13 +541,10 @@ export async function showInterviewRound(
538
541
  } else {
539
542
  push(ui.actionUnselected(2, exitActionLabel, "Exit and discard this batch of answers."));
540
543
  }
541
- push(
542
- ui.blank(),
543
- ui.hints(["↑/↓ to choose", "1/2 to quick-select", "enter to confirm"]),
544
- ui.bar(),
545
- );
544
+ push(ui.blank());
546
545
 
547
- return lines;
546
+ const footer = ui.hints(["↑/↓ to choose", "1/2 to quick-select", "enter to confirm"])[0] ?? "";
547
+ return renderSharedDialogFrame(theme, title, lines, width, { footer });
548
548
  }
549
549
 
550
550
  // ── Preview helpers ──────────────────────────────────────────────
@@ -648,17 +648,17 @@ export async function showInterviewRound(
648
648
  if (showingExitConfirm) { cachedLines = renderExitConfirm(width); return cachedLines; }
649
649
  if (showingReview) { cachedLines = renderReviewScreen(width); return cachedLines; }
650
650
 
651
+ const contentWidth = dialogContentWidth(width);
652
+ const title = questions[currentIdx]?.header || "GSD Interview";
651
653
  const useSideBySide = questionHasAnyPreview()
652
- && width >= (MIN_OPTIONS_WIDTH + MIN_PREVIEW_WIDTH + DIVIDER_WIDTH);
654
+ && contentWidth >= (MIN_OPTIONS_WIDTH + MIN_PREVIEW_WIDTH + DIVIDER_WIDTH);
653
655
 
654
656
  if (useSideBySide) {
655
657
  // ── Preview path ──────────────────────────────────────
656
- const ui = makeUI(theme, width);
658
+ const ui = makeUI(theme, contentWidth);
657
659
  const lines: string[] = [];
658
660
  const push = (...rows: string[][]) => { for (const r of rows) lines.push(...r); };
659
661
 
660
- push(ui.bar());
661
-
662
662
  if (isMultiQuestion) {
663
663
  const unanswered = questions.filter((_, i) => !isQuestionAnswered(i)).length;
664
664
  const answeredSet = new Set(questions.map((_, i) => i).filter(i => isQuestionAnswered(i)));
@@ -680,12 +680,15 @@ export async function showInterviewRound(
680
680
  // component: spinner/loader (1-2), status line (1), tool header (1),
681
681
  // plus a safety margin for future additions.
682
682
  const termRows = (typeof process !== "undefined" && process.stdout?.rows) || 24;
683
- const footerLines = 3; // blank + hints + bar
683
+ const footerLines = 5; // body spacer + frame top/footer/bottom chrome
684
684
  const tuiChrome = 5;
685
685
  const maxBody = Math.min(PREVIEW_MAX_LINES, Math.max(6, termRows - lines.length - footerLines - tuiChrome));
686
686
 
687
- const previewWidth = Math.max(MIN_PREVIEW_WIDTH, Math.floor(width * PREVIEW_RATIO));
688
- const leftWidth = Math.max(MIN_OPTIONS_WIDTH, width - previewWidth - DIVIDER_WIDTH);
687
+ const previewWidth = Math.max(
688
+ MIN_PREVIEW_WIDTH,
689
+ Math.min(contentWidth - MIN_OPTIONS_WIDTH - DIVIDER_WIDTH, Math.floor(contentWidth * PREVIEW_RATIO)),
690
+ );
691
+ const leftWidth = Math.max(MIN_OPTIONS_WIDTH, contentWidth - previewWidth - DIVIDER_WIDTH);
689
692
 
690
693
  const fullLeft = renderOptionsColumn(leftWidth);
691
694
  const leftLines = fullLeft.slice(0, maxBody);
@@ -709,7 +712,7 @@ export async function showInterviewRound(
709
712
  while (leftLines.length < maxBody) leftLines.push("");
710
713
  while (rightLines.length < maxBody) rightLines.push("");
711
714
  const divider = theme.fg("dim", DIVIDER_CHARS);
712
- lines.push(...mergeSideBySide(leftLines, rightLines, leftWidth, divider, width));
715
+ lines.push(...mergeSideBySide(leftLines, rightLines, leftWidth, divider, contentWidth));
713
716
 
714
717
  // Footer
715
718
  push(ui.blank());
@@ -729,15 +732,15 @@ export async function showInterviewRound(
729
732
  hints.push(isLast && allAnswered() ? "enter to review" : "enter to next");
730
733
  }
731
734
  hints.push("esc to exit");
732
- push(ui.hints(hints), ui.bar());
735
+ const footer = ui.hints(hints)[0] ?? "";
733
736
 
734
- cachedLines = lines;
735
- return lines;
737
+ cachedLines = renderSharedDialogFrame(theme, title, lines, width, { footer });
738
+ return cachedLines;
736
739
  }
737
740
 
738
741
  // ── Original path — no preview, untouched ────────────────
739
742
 
740
- const ui = makeUI(theme, width);
743
+ const ui = makeUI(theme, contentWidth);
741
744
  const lines: string[] = [];
742
745
  const push = (...rows: string[][]) => { for (const r of rows) lines.push(...r); };
743
746
 
@@ -745,8 +748,6 @@ export async function showInterviewRound(
745
748
  const st = states[currentIdx];
746
749
  const multiSel = isMultiSelect(currentIdx);
747
750
 
748
- push(ui.bar());
749
-
750
751
  // ── Progress header ────────────────────────────────────────────
751
752
  if (isMultiQuestion) {
752
753
  const unanswered = questions.filter((_, i) => !isQuestionAnswered(i)).length;
@@ -809,7 +810,7 @@ export async function showInterviewRound(
809
810
  if (st.notesVisible || focusNotes) {
810
811
  push(ui.blank(), ui.notesLabel(focusNotes));
811
812
  if (focusNotes) {
812
- for (const line of getEditor().render(width - 2)) lines.push(truncateToWidth(` ${line}`, width));
813
+ for (const line of getEditor().render(contentWidth - 2)) lines.push(truncateToWidth(` ${line}`, contentWidth));
813
814
  } else if (st.notes) {
814
815
  push(ui.notesText(st.notes));
815
816
  }
@@ -833,10 +834,10 @@ export async function showInterviewRound(
833
834
  hints.push(isLast && allAnswered() ? "enter to review" : "enter to next");
834
835
  }
835
836
  hints.push("esc to exit");
836
- push(ui.hints(hints), ui.bar());
837
+ const footer = ui.hints(hints)[0] ?? "";
837
838
 
838
- cachedLines = lines;
839
- return lines;
839
+ cachedLines = renderSharedDialogFrame(theme, title, lines, width, { footer });
840
+ return cachedLines;
840
841
  }
841
842
 
842
843
  return {
@@ -44,6 +44,7 @@
44
44
  import type { ExtensionCommandContext } from "@gsd/pi-coding-agent";
45
45
  import { type Theme } from "@gsd/pi-coding-agent";
46
46
  import { Key, matchesKey, type TUI } from "@gsd/pi-tui";
47
+ import { renderSharedDialogFrame } from "./dialog-frame.js";
47
48
  import { makeUI } from "./ui.js";
48
49
 
49
50
  // ─── Public API ───────────────────────────────────────────────────────────────
@@ -142,14 +143,14 @@ export async function showNextAction(
142
143
 
143
144
  function render(width: number): string[] {
144
145
  if (cachedLines) return cachedLines;
145
- const ui = makeUI(theme, width);
146
+ const contentWidth = Math.max(1, width - 4);
147
+ const ui = makeUI(theme, contentWidth);
146
148
  const lines: string[] = [];
147
149
  const push = (...rows: string[][]) => { for (const r of rows) lines.push(...r); };
148
150
 
149
151
  // ── Header — uses success colour to signal completion ────────────
150
152
  // Note: next-action intentionally uses "success" for its bar/title
151
153
  // to distinguish it from regular accent-coloured screens.
152
- push(ui.bar());
153
154
  push(ui.blank());
154
155
  push(ui.header(` ✓ ${opts.title}`));
155
156
 
@@ -192,11 +193,10 @@ export async function showNextAction(
192
193
 
193
194
  // ── Footer ────────────────────────────────────────────────────────
194
195
  const numHint = allActions.map((_, i) => `${i + 1}`).join("/");
195
- push(ui.hints([`↑/↓ to choose`, `${numHint} to quick-select`, `enter to confirm`]));
196
- push(ui.bar());
196
+ const footer = ui.hints([`↑/↓ to choose`, `${numHint} to quick-select`, `enter to confirm`])[0] ?? "";
197
197
 
198
- cachedLines = lines;
199
- return lines;
198
+ cachedLines = renderSharedDialogFrame(theme, "GSD Next Action", lines, width, { footer });
199
+ return cachedLines;
200
200
  }
201
201
 
202
202
  return { render, invalidate: () => { cachedLines = undefined; }, handleInput };
@@ -0,0 +1,57 @@
1
+ import { describe, it } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { stripVTControlCharacters } from "node:util";
4
+
5
+ import { visibleWidth } from "@gsd/pi-tui";
6
+
7
+ import { showConfirm } from "../confirm-ui.js";
8
+
9
+ function assertFullOuterBorder(lines: string[], width: number): void {
10
+ assert.ok(lines.length >= 2, "dialog must include top and bottom borders");
11
+ for (const [index, line] of lines.entries()) {
12
+ assert.equal(visibleWidth(line), width, `line ${index} must fill dialog width`);
13
+ }
14
+ const top = stripVTControlCharacters(lines[0] ?? "");
15
+ const bottom = stripVTControlCharacters(lines.at(-1) ?? "");
16
+ assert.match(top, /^[╭┌].*[╮┐]$/);
17
+ assert.match(bottom, /^[╰└].*[╯┘]$/);
18
+ for (let index = 1; index < lines.length - 1; index++) {
19
+ const line = stripVTControlCharacters(lines[index] ?? "");
20
+ assert.match(line, /^[│┃├]/, `line ${index} missing left border: ${line}`);
21
+ assert.match(line, /[│┃┤]$/, `line ${index} missing right border: ${line}`);
22
+ }
23
+ }
24
+
25
+ describe("showConfirm", () => {
26
+ it("renders the confirmation prompt inside a full border", async () => {
27
+ let rendered: string[] = [];
28
+ const theme = {
29
+ fg: (_color: string, text: string) => text,
30
+ bold: (text: string) => text,
31
+ };
32
+
33
+ const ctx = {
34
+ hasUI: true,
35
+ ui: {
36
+ custom: async (factory: any) => {
37
+ let resolved: boolean | undefined;
38
+ const component = factory({ requestRender() {} }, theme, null, (value: boolean) => {
39
+ resolved = value;
40
+ });
41
+ rendered = component.render(80);
42
+ component.handleInput("\r");
43
+ return resolved as never;
44
+ },
45
+ },
46
+ };
47
+
48
+ const result = await showConfirm(ctx as any, {
49
+ title: "Confirm action",
50
+ message: "Proceed with the change?",
51
+ });
52
+
53
+ assert.equal(result, true);
54
+ assertFullOuterBorder(rendered, 80);
55
+ assert.match(stripVTControlCharacters(rendered[0] ?? ""), /Confirm action/);
56
+ });
57
+ });