@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
@@ -27,6 +27,32 @@ import { initCmuxEventListeners } from "../../cmux/index.js";
27
27
 
28
28
  export { writeCrashLog } from "./crash-log.js";
29
29
 
30
+ // Pipe-closed storm guard. #99/#101 stopped EPIPE from flooding ~/.gsd/crash,
31
+ // but a persistently-broken output pipe whose `destroyed`/`writableEnded` flags
32
+ // never flip is still swallowed on every write — a tight, progress-free CPU
33
+ // spin. If the pipe-closed error fires in a tight loop the pipe is gone for
34
+ // good; exit cleanly instead.
35
+ const EPIPE_STORM_THRESHOLD = 100;
36
+ const EPIPE_STORM_WINDOW_MS = 10_000;
37
+ let epipeCount = 0;
38
+ let epipeWindowStart = 0;
39
+
40
+ /** Write to stderr without ever re-throwing — stderr can EPIPE too, which would
41
+ * re-enter this handler and re-loop. */
42
+ function safeStderr(msg: string): void {
43
+ try {
44
+ process.stderr.write(msg);
45
+ } catch { /* stderr is also broken; nothing we can do */ }
46
+ }
47
+
48
+ /** A peer closing the read end of a pipe mid-write surfaces differently per
49
+ * platform: POSIX throws `EPIPE`; Windows throws `Error: write EOF` (or
50
+ * `read EOF`) with no `code` set, from node:internal/stream_base_commons.
51
+ * Both are the same logical condition and must be treated as recoverable —
52
+ * otherwise the Windows EOF variant escapes to the uncaught-exception path
53
+ * and crashes auto-mode workers mid-iteration (#181). ECONNRESET is NOT
54
+ * included here: it commonly comes from network sockets (#182 follow-up) and
55
+ * is a real error that should surface rather than be silently swallowed. */
30
56
  function isPipeClosedError(err: Error): boolean {
31
57
  const errno = (err as NodeJS.ErrnoException).code;
32
58
  if (errno === "EPIPE") return true;
@@ -36,7 +62,7 @@ function isPipeClosedError(err: Error): boolean {
36
62
 
37
63
  export function handleRecoverableExtensionProcessError(err: Error): boolean {
38
64
  if (err.message.includes("ProcessTransport is not ready for writing")) {
39
- process.stderr.write(`[gsd] swallowed dead transport control write: ${err.message}\n`);
65
+ safeStderr(`[gsd] swallowed dead transport control write: ${err.message}\n`);
40
66
  return true;
41
67
  }
42
68
  if (isPipeClosedError(err)) {
@@ -46,7 +72,18 @@ export function handleRecoverableExtensionProcessError(err: Error): boolean {
46
72
  if (stdoutGone) {
47
73
  process.exit(0);
48
74
  }
49
- process.stderr.write(
75
+ const now = Date.now();
76
+ if (now - epipeWindowStart > EPIPE_STORM_WINDOW_MS) {
77
+ epipeWindowStart = now;
78
+ epipeCount = 0;
79
+ }
80
+ if (++epipeCount > EPIPE_STORM_THRESHOLD) {
81
+ safeStderr(
82
+ `[gsd] ${tag} storm (${epipeCount} within ${EPIPE_STORM_WINDOW_MS}ms) — output pipe is gone; exiting.\n`,
83
+ );
84
+ process.exit(0);
85
+ }
86
+ safeStderr(
50
87
  `[gsd] swallowed ${tag} (syscall=${(err as NodeJS.ErrnoException).syscall ?? "?"})\n`,
51
88
  );
52
89
  return true;
@@ -54,18 +91,18 @@ export function handleRecoverableExtensionProcessError(err: Error): boolean {
54
91
  if ((err as NodeJS.ErrnoException).code === "EIO") {
55
92
  const syscall = (err as NodeJS.ErrnoException).syscall;
56
93
  if (syscall === "read") {
57
- process.stderr.write(`[gsd] EIO: ${err.message}\n`);
94
+ safeStderr(`[gsd] EIO: ${err.message}\n`);
58
95
  return true;
59
96
  }
60
97
  }
61
98
  if ((err as NodeJS.ErrnoException).code === "ENOENT") {
62
99
  const syscall = (err as NodeJS.ErrnoException).syscall;
63
100
  if (syscall?.startsWith("spawn")) {
64
- process.stderr.write(`[gsd] spawn ENOENT: ${(err as any).path ?? "unknown"} — command not found\n`);
101
+ safeStderr(`[gsd] spawn ENOENT: ${(err as any).path ?? "unknown"} — command not found\n`);
65
102
  return true;
66
103
  }
67
104
  if (syscall === "uv_cwd") {
68
- process.stderr.write(`[gsd] ENOENT (${syscall}): ${err.message}\n`);
105
+ safeStderr(`[gsd] ENOENT (${syscall}): ${err.message}\n`);
69
106
  return true;
70
107
  }
71
108
  }
@@ -33,6 +33,7 @@ import { resolveWorktreeProjectRoot } from "../worktree-root.js";
33
33
  import { extractSubagentAgentClasses } from "./subagent-input.js";
34
34
  import { approvalGateIdForUnit, isExplicitApprovalResponse, shouldPauseForUserApprovalQuestion } from "../user-input-boundary.js";
35
35
  import { resolveSkillManifest } from "../skill-manifest.js";
36
+ import { applyUnitSkillVisibility, unitHasSkillManifest } from "../skill-scope.js";
36
37
  import { getGuidedUnitContext } from "../guided-unit-context.js";
37
38
  import { registerPlanMilestoneSchemaRecovery } from "./plan-milestone-schema-recovery.js";
38
39
 
@@ -357,8 +358,7 @@ export function scopeGsdWorkflowToolsForDispatch(
357
358
  ? buildMinimalAutoGsdToolSet(current, unitType, registeredToolNames)
358
359
  : buildMinimalGsdWorkflowToolSet(current, registeredToolNames);
359
360
  const toolsChanged = !(scoped.length === current.length && scoped.every((name, index) => name === current[index]));
360
- const skillManifest = resolveSkillManifest(unitType);
361
- const canScopeSkills = skillManifest !== null && pi.getVisibleSkills && pi.setVisibleSkills;
361
+ const canScopeSkills = unitHasSkillManifest(unitType) && pi.getVisibleSkills && pi.setVisibleSkills;
362
362
  if (!toolsChanged && !canScopeSkills) {
363
363
  return null;
364
364
  }
@@ -366,8 +366,8 @@ export function scopeGsdWorkflowToolsForDispatch(
366
366
  pi.setActiveTools(scoped);
367
367
  }
368
368
  const visibleSkills = canScopeSkills ? pi.getVisibleSkills!() : undefined;
369
- if (canScopeSkills) {
370
- pi.setVisibleSkills!(skillManifest);
369
+ if (canScopeSkills && pi.setVisibleSkills) {
370
+ applyUnitSkillVisibility({ setVisibleSkills: pi.setVisibleSkills }, unitType);
371
371
  }
372
372
  return {
373
373
  tools: toolsChanged ? current : null,
@@ -615,9 +615,21 @@ export function registerHooks(
615
615
  // project MCP config that /gsd mcp init would write.
616
616
  await prepareWorkflowMcpForHookContext(ctx, beforeAgentBasePath);
617
617
 
618
+ let systemPrompt = event.systemPrompt;
619
+ const { appendDiscoveredSkillsFallback, hasSkillSnapshot, refreshCatalogForNewSkills } = await import("../skill-discovery.js");
620
+ if (hasSkillSnapshot()) {
621
+ const loadedSkills = await refreshCatalogForNewSkills({
622
+ reload: () => (ctx as ExtensionContext & { reload: () => Promise<void> }).reload(),
623
+ notify: (message, level) => ctx.ui.notify(message, level),
624
+ });
625
+ if (loadedSkills.length > 0) {
626
+ systemPrompt = appendDiscoveredSkillsFallback(ctx.getSystemPrompt(), loadedSkills);
627
+ }
628
+ }
629
+
618
630
  // GSD's own context injection (existing behavior — unchanged).
619
631
  const { buildBeforeAgentStartResult } = await import("./system-context.js");
620
- const gsdResult = await buildBeforeAgentStartResult(event, ctx);
632
+ const gsdResult = await buildBeforeAgentStartResult({ ...event, systemPrompt }, ctx);
621
633
 
622
634
  // Refresh the snapshot used by ecosystem getPhase()/getActiveUnit().
623
635
  // deriveState has its own ~100ms cache so this is cheap on repeat calls.
@@ -630,7 +642,7 @@ export function registerHooks(
630
642
 
631
643
  // Chain ecosystem handlers using pi's runner.ts chaining protocol:
632
644
  // each handler sees the systemPrompt mutated by prior handlers.
633
- let currentSystemPrompt = gsdResult?.systemPrompt ?? event.systemPrompt;
645
+ let currentSystemPrompt = gsdResult?.systemPrompt ?? systemPrompt;
634
646
  // `any` because pi's BeforeAgentStartEventResult.message uses an internal
635
647
  // CustomMessage type that's not re-exported (see ecosystem/gsd-extension-api.ts).
636
648
  let lastMessage: any = gsdResult?.message;
@@ -11,11 +11,9 @@ import { loadPrompt, getTemplatesDir } from "../prompt-loader.js";
11
11
  import { readForensicsMarker } from "../forensics.js";
12
12
  import { resolveAllSkillReferences, renderPreferencesForSystemPrompt, loadEffectiveGSDPreferences } from "../preferences.js";
13
13
  import { resolveModelWithFallbacksForUnit } from "../preferences-models.js";
14
- import { resolveSkillReference } from "../preferences-skills.js";
15
14
  import { resolveGsdRootFile, resolveSliceFile, resolveSlicePath, resolveTaskFile, resolveTaskFiles, resolveTasksDir, relSliceFile, relSlicePath, relTaskFile } from "../paths.js";
16
15
  import { extractIntroAndRules } from "../knowledge-parser.js";
17
16
  import { ensureCodebaseMapFresh, readCodebaseMap } from "../codebase-generator.js";
18
- import { hasSkillSnapshot, detectNewSkills, formatSkillsXml } from "../skill-discovery.js";
19
17
  import { getActiveAutoWorktreeContext } from "../auto-worktree.js";
20
18
  import { getActiveWorktreeName, getWorktreeOriginalCwd } from "../worktree-session-state.js";
21
19
  import { deriveState } from "../state.js";
@@ -72,20 +70,6 @@ export const BUNDLED_SKILL_TRIGGERS: Array<{ trigger: string; skill: string }> =
72
70
  { trigger: "Deep code optimization audit — perf anti-patterns, memory leaks, algorithmic complexity, bundle size, I/O, caching, dead code (parallel pattern-based hunt)", skill: "code-optimizer" },
73
71
  ];
74
72
 
75
- function buildBundledSkillsTable(): string {
76
- const cwd = process.cwd();
77
- const rows: string[] = [];
78
- for (const { trigger, skill } of BUNDLED_SKILL_TRIGGERS) {
79
- const resolution = resolveSkillReference(skill, cwd);
80
- if (resolution.method === "unresolved") continue; // skill not installed — omit from prompt
81
- rows.push(`| ${trigger} | \`${resolution.resolvedPath}\` |`);
82
- }
83
- if (rows.length === 0) {
84
- return "*No bundled skills found. Install or sync skills to `~/.gsd/agent/skills/`, `~/.agents/skills/`, or `~/.claude/skills/`.*";
85
- }
86
- return `| Trigger | Skill to load |\n|---|---|\n${rows.join("\n")}`;
87
- }
88
-
89
73
  function warnDeprecatedAgentInstructions(): void {
90
74
  const paths = [
91
75
  join(gsdHome(), "agent-instructions.md"),
@@ -110,7 +94,6 @@ export async function buildBeforeAgentStartResult(
110
94
 
111
95
  const stopContextTimer = debugTime("context-inject");
112
96
  const systemContent = loadPrompt("system", {
113
- bundledSkillsTable: buildBundledSkillsTable(),
114
97
  templatesDir: getTemplatesDir(),
115
98
  shortcutDashboard: formatShortcut("Ctrl+Alt+G"),
116
99
  shortcutShell: formatShortcut("Ctrl+Alt+B"),
@@ -141,7 +124,7 @@ export async function buildBeforeAgentStartResult(
141
124
  if (loadedPreferences) {
142
125
  const cwd = basePath;
143
126
  const report = resolveAllSkillReferences(loadedPreferences.preferences, cwd);
144
- preferenceBlock = `\n\n${renderPreferencesForSystemPrompt(loadedPreferences.preferences, report.resolutions)}`;
127
+ preferenceBlock = `\n\n${renderPreferencesForSystemPrompt(loadedPreferences.preferences, report.resolutions, { includeResolvedPaths: false })}`;
145
128
  if (report.warnings.length > 0) {
146
129
  ctx.ui.notify(
147
130
  `GSD skill preferences: ${report.warnings.length} unresolved skill${report.warnings.length === 1 ? "" : "s"}: ${report.warnings.join(", ")}`,
@@ -201,14 +184,6 @@ export async function buildBeforeAgentStartResult(
201
184
  );
202
185
  }
203
186
 
204
- let newSkillsBlock = "";
205
- if (hasSkillSnapshot()) {
206
- const newSkills = detectNewSkills();
207
- if (newSkills.length > 0) {
208
- newSkillsBlock = formatSkillsXml(newSkills);
209
- }
210
- }
211
-
212
187
  let codebaseBlock = "";
213
188
  try {
214
189
  const codebaseOptions = loadedPreferences?.preferences?.codebase
@@ -264,13 +239,13 @@ export async function buildBeforeAgentStartResult(
264
239
  // Keeping it out of `fullSystem` preserves provider prompt-cache stability
265
240
  // for the static system/tool prefix. The dynamic memory block rides the
266
241
  // volatile context message instead. (#5019)
267
- const fullSystem = `${event.systemPrompt}\n\n[SYSTEM CONTEXT — GSD]\n\n${systemContent}${preferenceBlock}${knowledgeBlock}${codebaseBlock}${newSkillsBlock}${worktreeBlock}${subagentModelBlock}`;
242
+ const fullSystem = `${event.systemPrompt}\n\n[SYSTEM CONTEXT — GSD]\n\n${systemContent}${preferenceBlock}${knowledgeBlock}${codebaseBlock}${worktreeBlock}${subagentModelBlock}`;
268
243
 
269
244
  stopContextTimer({
270
245
  systemPromptSize: fullSystem.length,
271
246
  injectionSize: injection?.length ?? forensicsInjection?.length ?? 0,
272
247
  hasPreferences: preferenceBlock.length > 0,
273
- hasNewSkills: newSkillsBlock.length > 0,
248
+ hasNewSkills: false,
274
249
  });
275
250
 
276
251
  const contextMessage = buildContextMessage({ memoryBlock, injection, forensicsInjection });
@@ -205,7 +205,12 @@ export function getCloseoutManualResolveBlocker(basePath: string): string | null
205
205
  return `Unmerged paths remain in ${basePath}: ${conflictProbe.unmerged.slice(0, 5).join(", ")}`;
206
206
  }
207
207
 
208
- const status = runGit(basePath, ["status", "--porcelain"]);
208
+ let status: string;
209
+ try {
210
+ status = runGit(basePath, ["status", "--porcelain"]);
211
+ } catch {
212
+ return `Could not inspect git status in ${basePath}.`;
213
+ }
209
214
  if (status) {
210
215
  return `Working tree still has uncommitted changes in ${basePath}. Commit, stash, or run /gsd closeout retry first.`;
211
216
  }
@@ -208,7 +208,15 @@ export async function handleAutoCommand(trimmed: string, ctx: ExtensionCommandCo
208
208
 
209
209
  if (trimmed === "") {
210
210
  if (!(await guardRemoteSession(ctx, pi))) return true;
211
- if (await hasUnresolvedCloseoutBlocker(ctx, projectRoot())) return true;
211
+ const basePath = projectRoot();
212
+ const { hasGsdBootstrapArtifacts } = await import("../../detection.js");
213
+ const { gsdRoot } = await import("../../paths.js");
214
+ if (!hasGsdBootstrapArtifacts(gsdRoot(basePath))) {
215
+ const { showSmartEntry } = await import("../../guided-flow.js");
216
+ await showSmartEntry(ctx, pi, basePath, { step: true });
217
+ return true;
218
+ }
219
+ if (await hasUnresolvedCloseoutBlocker(ctx, basePath)) return true;
212
220
  const { showGsdHome } = await import("../../gsd-command-home.js");
213
221
  await showGsdHome(ctx, pi, projectRoot());
214
222
  return true;
@@ -4,10 +4,12 @@
4
4
  * Shows current LLM context window usage and session token totals.
5
5
  */
6
6
 
7
- import type { ExtensionCommandContext, ContextUsage, SessionEntry } from "@gsd/pi-coding-agent";
7
+ import type { ExtensionCommandContext, ContextUsage, SessionEntry, Theme } from "@gsd/pi-coding-agent";
8
+ import { Key, matchesKey } from "@gsd/pi-tui";
8
9
 
9
10
  import { formatCost, formatPercent, formatTokenCount } from "./metrics.js";
10
11
  import { loadEffectiveGSDPreferences } from "./preferences.js";
12
+ import { renderDialogFrame, renderKeyHints } from "./tui/render-kit.js";
11
13
 
12
14
  export interface SessionTokenTotals {
13
15
  input: number;
@@ -160,6 +162,101 @@ export function formatUsageReport(options: {
160
162
  return lines.join("\n");
161
163
  }
162
164
 
165
+ async function showUsageDialog(
166
+ ctx: ExtensionCommandContext,
167
+ reportText: string,
168
+ ): Promise<boolean | undefined> {
169
+ return ctx.ui.custom<boolean>((tui, theme: Theme, _kb, done) => {
170
+ let cachedLines: string[] | undefined;
171
+ let cachedWidth: number | undefined;
172
+ let cachedRows: number | undefined;
173
+ let cachedScrollOffset: number | undefined;
174
+ let scrollOffset = 0;
175
+ let lastMaxScroll = 0;
176
+ let lastVisibleRows = 1;
177
+
178
+ function render(width: number): string[] {
179
+ const terminalRows = process.stdout.rows || 0;
180
+ if (
181
+ cachedLines &&
182
+ cachedWidth === width &&
183
+ cachedRows === terminalRows &&
184
+ cachedScrollOffset === scrollOffset
185
+ ) {
186
+ return cachedLines;
187
+ }
188
+
189
+ const contentWidth = Math.max(1, width - 4);
190
+ const body = reportText.split("\n");
191
+ if (body[0] === "Context Usage") body.shift();
192
+ while (body[0] === "") body.shift();
193
+ const maxOverlayRows = terminalRows > 0 ? Math.max(5, Math.floor(terminalRows * 0.8)) : 24;
194
+ const frameRows = 4;
195
+ const visibleRows = Math.max(1, maxOverlayRows - frameRows);
196
+ const maxScroll = Math.max(0, body.length - visibleRows);
197
+ scrollOffset = Math.min(Math.max(scrollOffset, 0), maxScroll);
198
+ lastMaxScroll = maxScroll;
199
+ lastVisibleRows = visibleRows;
200
+ const visible = body.slice(scrollOffset, scrollOffset + visibleRows);
201
+ const scrollable = body.length > visibleRows;
202
+
203
+ cachedLines = renderDialogFrame(theme, "Context Usage", visible, width, {
204
+ footer: renderKeyHints(theme, scrollable ? ["↑↓ scroll", "any key close"] : ["any key close"], contentWidth),
205
+ scroll: { offset: scrollOffset, visibleRows, totalRows: body.length },
206
+ });
207
+ cachedWidth = width;
208
+ cachedRows = terminalRows;
209
+ cachedScrollOffset = scrollOffset;
210
+ return cachedLines;
211
+ }
212
+
213
+ function scrollBy(delta: number): boolean {
214
+ if (lastMaxScroll <= 0) return false;
215
+ const nextOffset = Math.min(Math.max(scrollOffset + delta, 0), lastMaxScroll);
216
+ if (nextOffset !== scrollOffset) {
217
+ scrollOffset = nextOffset;
218
+ cachedLines = undefined;
219
+ cachedScrollOffset = undefined;
220
+ tui.requestRender();
221
+ }
222
+ return true;
223
+ }
224
+
225
+ return {
226
+ render,
227
+ invalidate: () => {
228
+ cachedLines = undefined;
229
+ cachedWidth = undefined;
230
+ cachedRows = undefined;
231
+ cachedScrollOffset = undefined;
232
+ },
233
+ handleInput: (data: string) => {
234
+ if (matchesKey(data, Key.down) || matchesKey(data, "j")) {
235
+ if (scrollBy(1)) return;
236
+ }
237
+ if (matchesKey(data, Key.up) || matchesKey(data, "k")) {
238
+ if (scrollBy(-1)) return;
239
+ }
240
+ if (matchesKey(data, Key.pageDown)) {
241
+ if (scrollBy(lastVisibleRows)) return;
242
+ }
243
+ if (matchesKey(data, Key.pageUp)) {
244
+ if (scrollBy(-lastVisibleRows)) return;
245
+ }
246
+ done(true);
247
+ },
248
+ };
249
+ }, {
250
+ overlay: true,
251
+ overlayOptions: {
252
+ width: "70%",
253
+ minWidth: 64,
254
+ maxHeight: "80%",
255
+ anchor: "center",
256
+ },
257
+ });
258
+ }
259
+
163
260
  export async function handleUsage(args: string, ctx: ExtensionCommandContext): Promise<void> {
164
261
  const contextUsage = ctx.getContextUsage?.();
165
262
  const sessionTotals = scanSessionTokenTotals(ctx.sessionManager.getEntries());
@@ -187,8 +284,16 @@ export async function handleUsage(args: string, ctx: ExtensionCommandContext): P
187
284
  return;
188
285
  }
189
286
 
190
- ctx.ui.notify(
191
- formatUsageReport({ modelLabel, contextUsage, sessionTotals }),
192
- "info",
193
- );
287
+ const reportText = formatUsageReport({ modelLabel, contextUsage, sessionTotals });
288
+
289
+ if (ctx.hasUI) {
290
+ try {
291
+ const result = await showUsageDialog(ctx, reportText);
292
+ if (result !== undefined) return;
293
+ } catch {
294
+ // Fall back to text notify below when custom overlays are unavailable.
295
+ }
296
+ }
297
+
298
+ ctx.ui.notify(reportText, "info");
194
299
  }
@@ -10,6 +10,7 @@
10
10
  import type { Theme } from "@gsd/pi-coding-agent";
11
11
  import { matchesKey, Key, truncateToWidth } from "@gsd/pi-tui";
12
12
 
13
+ import { renderDialogFrame, renderKeyHints } from "./tui/render-kit.js";
13
14
  import {
14
15
  loadEffectiveGSDPreferences,
15
16
  loadGlobalGSDPreferences,
@@ -231,6 +232,7 @@ export class GSDConfigOverlay {
231
232
  private onClose: () => void;
232
233
  private sections: ConfigSection[];
233
234
  private cachedLines?: string[];
235
+ private cachedWidth?: number;
234
236
  private scrollOffset = 0;
235
237
  private disposed = false;
236
238
 
@@ -247,6 +249,7 @@ export class GSDConfigOverlay {
247
249
 
248
250
  invalidate(): void {
249
251
  this.cachedLines = undefined;
252
+ this.cachedWidth = undefined;
250
253
  }
251
254
 
252
255
  dispose(): void {
@@ -286,16 +289,13 @@ export class GSDConfigOverlay {
286
289
  }
287
290
 
288
291
  render(width: number): string[] {
289
- if (this.cachedLines) return this.cachedLines;
292
+ if (this.cachedLines && this.cachedWidth === width) return this.cachedLines;
290
293
 
291
294
  const t = this.theme;
292
- const w = Math.max(width, 50);
295
+ const w = Math.max(1, width);
296
+ const contentWidth = Math.max(1, w - 4);
293
297
  const allLines: string[] = [];
294
298
 
295
- // Header
296
- allLines.push(t.bold(t.fg("accent", " GSD Configuration ")));
297
- allLines.push(t.fg("muted", "\u2500".repeat(w)));
298
-
299
299
  // Find max label width for alignment
300
300
  let maxLabel = 0;
301
301
  for (const section of this.sections) {
@@ -306,26 +306,29 @@ export class GSDConfigOverlay {
306
306
  const labelPad = Math.min(maxLabel + 2, 24);
307
307
 
308
308
  for (const section of this.sections) {
309
- allLines.push("");
309
+ if (allLines.length > 0) allLines.push("");
310
310
  allLines.push(t.bold(t.fg("accent", ` ${section.title}`)));
311
311
 
312
312
  for (const row of section.rows) {
313
313
  const label = t.fg("muted", ` ${row.label.padEnd(labelPad)}`);
314
314
  const value = row.accent ? t.bold(row.value) : row.value;
315
- allLines.push(truncateToWidth(`${label}${value}`, w));
315
+ allLines.push(truncateToWidth(`${label}${value}`, contentWidth));
316
316
  }
317
317
  }
318
318
 
319
- allLines.push("");
320
- allLines.push(t.fg("muted", ` ${"\u2500".repeat(w - 4)}`));
321
- allLines.push(t.fg("muted", " esc/q close \u2502 \u2191\u2193/jk scroll \u2502 /gsd prefs to edit"));
322
-
323
319
  // Apply scroll
324
- const maxScroll = Math.max(0, allLines.length - 20);
320
+ const terminalRows = process.stdout.rows || 32;
321
+ const maxBodyRows = Math.max(1, Math.min(allLines.length, terminalRows - 12));
322
+ const maxScroll = Math.max(0, allLines.length - maxBodyRows);
325
323
  this.scrollOffset = Math.min(this.scrollOffset, maxScroll);
326
- const visible = allLines.slice(this.scrollOffset);
324
+ const visible = allLines.slice(this.scrollOffset, this.scrollOffset + maxBodyRows);
325
+ const footer = renderKeyHints(t, ["esc/q close", "\u2191\u2193/jk scroll", "/gsd prefs to edit"], contentWidth);
327
326
 
328
- this.cachedLines = visible;
329
- return visible;
327
+ this.cachedLines = renderDialogFrame(t, "GSD Configuration", visible, w, {
328
+ footer,
329
+ scroll: { offset: this.scrollOffset, visibleRows: maxBodyRows, totalRows: allLines.length },
330
+ });
331
+ this.cachedWidth = width;
332
+ return this.cachedLines;
330
333
  }
331
334
  }
@@ -3,11 +3,11 @@
3
3
  */
4
4
 
5
5
  import type { Theme, ThemeColor } from "@gsd/pi-coding-agent";
6
- import { matchesKey, Key, truncateToWidth, visibleWidth } from "@gsd/pi-tui";
6
+ import { matchesKey, Key, truncateToWidth } from "@gsd/pi-tui";
7
7
 
8
8
  import type { ContextBreakdownReport, ContextSectionBreakdown } from "./commands-context.js";
9
9
  import { formatTokenCount } from "./metrics.js";
10
- import { renderProgressBar, rightAlign } from "./tui/render-kit.js";
10
+ import { renderDialogFrame, renderKeyHints, renderProgressBar, rightAlign } from "./tui/render-kit.js";
11
11
 
12
12
  const SECTION_COLORS: ThemeColor[] = ["accent", "success", "warning", "borderAccent", "text"];
13
13
 
@@ -70,6 +70,7 @@ export class GSDContextOverlay {
70
70
  private onClose: () => void;
71
71
  private report: ContextBreakdownReport;
72
72
  private cachedLines?: string[];
73
+ private cachedWidth?: number;
73
74
  private scrollOffset = 0;
74
75
  private disposed = false;
75
76
 
@@ -87,6 +88,7 @@ export class GSDContextOverlay {
87
88
 
88
89
  invalidate(): void {
89
90
  this.cachedLines = undefined;
91
+ this.cachedWidth = undefined;
90
92
  }
91
93
 
92
94
  dispose(): void {
@@ -125,24 +127,22 @@ export class GSDContextOverlay {
125
127
  }
126
128
 
127
129
  render(width: number): string[] {
128
- if (this.cachedLines) return this.cachedLines;
130
+ if (this.cachedLines && this.cachedWidth === width) return this.cachedLines;
129
131
 
130
132
  const theme = this.theme;
131
- const w = Math.max(width, 60);
133
+ const w = Math.max(1, width);
134
+ const contentWidth = Math.max(1, w - 4);
132
135
  const totals = getContextChartTotals(this.report);
133
136
  const chartTotal = Math.max(totals.inContext, totals.estimated, 1);
134
137
  const lines: string[] = [];
135
138
 
136
- lines.push(theme.bold(theme.fg("accent", " Context Breakdown ")));
137
- lines.push(theme.fg("muted", "─".repeat(w)));
138
-
139
139
  if (this.report.modelLabel) {
140
- lines.push(rightAlign(theme.fg("muted", "Model"), theme.fg("text", this.report.modelLabel), w));
140
+ lines.push(rightAlign(theme.fg("muted", "Model"), theme.fg("text", this.report.modelLabel), contentWidth));
141
141
  }
142
142
 
143
143
  lines.push("");
144
144
  if (totals.window != null) {
145
- const usageBarWidth = Math.max(20, w - 28);
145
+ const usageBarWidth = Math.max(8, contentWidth - 28);
146
146
  const usageBar = renderProgressBar(theme, totals.inContext, totals.window, usageBarWidth, {
147
147
  filledColor: totals.inContext / totals.window > 0.85 ? "warning" : "accent",
148
148
  });
@@ -151,7 +151,7 @@ export class GSDContextOverlay {
151
151
  lines.push(` ${theme.fg("muted", "Estimated")} ${theme.fg("text", formatTokenCount(chartTotal))}`);
152
152
  }
153
153
 
154
- const splitWidth = Math.max(16, Math.floor((w - 8) / 2));
154
+ const splitWidth = Math.max(8, Math.floor((contentWidth - 8) / 2));
155
155
  const systemBar = renderProgressBar(theme, totals.systemTokens, chartTotal, splitWidth, { filledColor: "accent" });
156
156
  const convBar = renderProgressBar(theme, totals.conversationTokens, chartTotal, splitWidth, { filledColor: "success" });
157
157
  lines.push("");
@@ -160,11 +160,11 @@ export class GSDContextOverlay {
160
160
 
161
161
  lines.push("");
162
162
  lines.push(theme.bold(theme.fg("accent", " System prompt")));
163
- lines.push(...renderSectionBars(theme, this.report.systemSections, chartTotal, w, 22));
163
+ lines.push(...renderSectionBars(theme, this.report.systemSections, chartTotal, contentWidth, 22));
164
164
 
165
165
  lines.push("");
166
166
  lines.push(theme.bold(theme.fg("accent", " Conversation")));
167
- lines.push(...renderSectionBars(theme, this.report.conversationSections, chartTotal, w, 22));
167
+ lines.push(...renderSectionBars(theme, this.report.conversationSections, chartTotal, contentWidth, 22));
168
168
 
169
169
  lines.push("");
170
170
  lines.push(theme.bold(theme.fg("accent", " Skills")));
@@ -172,7 +172,7 @@ export class GSDContextOverlay {
172
172
  if (skills.available.length > 0) {
173
173
  lines.push(` ${theme.fg("muted", "Available")} ${theme.fg("text", `${skills.available.length}`)}`);
174
174
  const preview = skills.available.slice(0, 8).join(", ");
175
- lines.push(truncateToWidth(` ${preview}${skills.available.length > 8 ? "…" : ""}`, w));
175
+ lines.push(truncateToWidth(` ${preview}${skills.available.length > 8 ? "…" : ""}`, contentWidth));
176
176
  } else {
177
177
  lines.push(theme.fg("dim", " none in prompt"));
178
178
  }
@@ -187,13 +187,18 @@ export class GSDContextOverlay {
187
187
  lines.push(theme.bold(theme.fg("accent", " Agents")));
188
188
  lines.push(` ${theme.fg("muted", "Subagent spawns")} ${theme.fg("text", String(this.report.subagentSpawns))}`);
189
189
 
190
- lines.push("");
191
- lines.push(theme.fg("muted", ` ${"─".repeat(Math.max(0, w - 4))}`));
192
- lines.push(theme.fg("muted", " esc/q close │ ↑↓ scroll │ /gsd context --open for browser chart"));
193
-
194
- const maxScroll = Math.max(0, lines.length - 24);
190
+ const terminalRows = process.stdout.rows || 32;
191
+ const maxBodyRows = Math.max(1, Math.min(lines.length, terminalRows - 12));
192
+ const maxScroll = Math.max(0, lines.length - maxBodyRows);
195
193
  this.scrollOffset = Math.min(this.scrollOffset, maxScroll);
196
- this.cachedLines = lines.slice(this.scrollOffset);
194
+ const visible = lines.slice(this.scrollOffset, this.scrollOffset + maxBodyRows);
195
+ const footer = renderKeyHints(theme, ["esc/q close", "↑↓ scroll", "/gsd context --open"], contentWidth);
196
+
197
+ this.cachedLines = renderDialogFrame(theme, "Context Breakdown", visible, w, {
198
+ footer,
199
+ scroll: { offset: this.scrollOffset, visibleRows: maxBodyRows, totalRows: lines.length },
200
+ });
201
+ this.cachedWidth = width;
197
202
  return this.cachedLines;
198
203
  }
199
204
  }