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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (337) hide show
  1. package/dist/onboarding.js +22 -3
  2. package/dist/resource-loader.js +3 -1
  3. package/dist/resources/.managed-resources-content-hash +1 -1
  4. package/dist/resources/extensions/context7/index.js +12 -2
  5. package/dist/resources/extensions/get-secrets-from-user.js +16 -16
  6. package/dist/resources/extensions/google-cli/index.js +30 -0
  7. package/dist/resources/extensions/google-cli/models.js +55 -0
  8. package/dist/resources/extensions/google-cli/package.json +11 -0
  9. package/dist/resources/extensions/google-cli/readiness.js +12 -0
  10. package/dist/resources/extensions/google-cli/stream-adapter.js +191 -0
  11. package/dist/resources/extensions/gsd/auto/loop.js +62 -1
  12. package/dist/resources/extensions/gsd/auto/orchestrator.js +4 -2
  13. package/dist/resources/extensions/gsd/auto/phases.js +37 -0
  14. package/dist/resources/extensions/gsd/auto/run-unit.js +8 -0
  15. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  16. package/dist/resources/extensions/gsd/auto-dispatch.js +17 -7
  17. package/dist/resources/extensions/gsd/auto-post-unit.js +21 -11
  18. package/dist/resources/extensions/gsd/auto-prompts.js +5 -236
  19. package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
  20. package/dist/resources/extensions/gsd/auto-start.js +232 -49
  21. package/dist/resources/extensions/gsd/auto.js +6 -1
  22. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +4 -3
  23. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +7 -2
  24. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +39 -5
  25. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +17 -7
  26. package/dist/resources/extensions/gsd/bootstrap/system-context.js +3 -27
  27. package/dist/resources/extensions/gsd/closeout-recovery.js +7 -1
  28. package/dist/resources/extensions/gsd/commands/handlers/auto.js +9 -1
  29. package/dist/resources/extensions/gsd/commands-usage.js +105 -1
  30. package/dist/resources/extensions/gsd/config-overlay.js +20 -14
  31. package/dist/resources/extensions/gsd/context-overlay.js +22 -16
  32. package/dist/resources/extensions/gsd/dashboard-overlay.js +10 -23
  33. package/dist/resources/extensions/gsd/doctor-engine-checks.js +87 -0
  34. package/dist/resources/extensions/gsd/doctor-providers.js +54 -24
  35. package/dist/resources/extensions/gsd/doctor.js +6 -1
  36. package/dist/resources/extensions/gsd/git-conflict-state.js +26 -1
  37. package/dist/resources/extensions/gsd/guided-flow.js +5 -6
  38. package/dist/resources/extensions/gsd/key-manager.js +45 -13
  39. package/dist/resources/extensions/gsd/milestone-reopen-events.js +28 -0
  40. package/dist/resources/extensions/gsd/notification-overlay.js +8 -9
  41. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +15 -13
  42. package/dist/resources/extensions/gsd/preferences-skills.js +11 -4
  43. package/dist/resources/extensions/gsd/preferences.js +14 -2
  44. package/dist/resources/extensions/gsd/prompt-loader.js +2 -0
  45. package/dist/resources/extensions/gsd/prompts/discuss.md +4 -2
  46. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
  47. package/dist/resources/extensions/gsd/prompts/system.md +1 -3
  48. package/dist/resources/extensions/gsd/queue-reorder-ui.js +28 -18
  49. package/dist/resources/extensions/gsd/repository-registry.js +3 -1
  50. package/dist/resources/extensions/gsd/safety/evidence-collector.js +11 -4
  51. package/dist/resources/extensions/gsd/skill-activation.js +233 -0
  52. package/dist/resources/extensions/gsd/skill-catalog.data.js +820 -0
  53. package/dist/resources/extensions/gsd/skill-catalog.install.js +179 -0
  54. package/dist/resources/extensions/gsd/skill-catalog.js +5 -1028
  55. package/dist/resources/extensions/gsd/skill-discovery.js +121 -79
  56. package/dist/resources/extensions/gsd/skill-scope.js +52 -0
  57. package/dist/resources/extensions/gsd/skill-telemetry.js +6 -39
  58. package/dist/resources/extensions/gsd/skills.js +60 -0
  59. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +351 -0
  60. package/dist/resources/extensions/gsd/state-reconciliation/index.js +41 -0
  61. package/dist/resources/extensions/gsd/state-reconciliation/registry.js +4 -0
  62. package/dist/resources/extensions/gsd/tools/complete-task.js +9 -0
  63. package/dist/resources/extensions/gsd/tools/exec-tool.js +42 -8
  64. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +63 -2
  65. package/dist/resources/extensions/gsd/tui/render-kit.js +51 -0
  66. package/dist/resources/extensions/gsd/unit-context-manifest.js +35 -26
  67. package/dist/resources/extensions/gsd/user-input-boundary.js +1 -1
  68. package/dist/resources/extensions/gsd/vision-ask.js +22 -0
  69. package/dist/resources/extensions/gsd/visualizer-overlay.js +8 -36
  70. package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -3
  71. package/dist/resources/extensions/search-the-web/native-search.js +57 -8
  72. package/dist/resources/extensions/shared/confirm-ui.js +9 -6
  73. package/dist/resources/extensions/shared/dialog-frame.js +42 -0
  74. package/dist/resources/extensions/shared/interview-ui.js +42 -30
  75. package/dist/resources/extensions/shared/next-action-ui.js +6 -6
  76. package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +1 -1
  77. package/dist/web/standalone/.next/BUILD_ID +1 -1
  78. package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
  79. package/dist/web/standalone/.next/build-manifest.json +2 -2
  80. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  81. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  82. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  90. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/index.html +1 -1
  98. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app-paths-manifest.json +6 -6
  105. package/dist/web/standalone/.next/server/chunks/1834.js +2 -2
  106. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  108. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  109. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  110. package/package.json +1 -1
  111. package/packages/cloud-mcp-gateway/package.json +2 -2
  112. package/packages/contracts/dist/rpc.test.js +5 -0
  113. package/packages/contracts/dist/rpc.test.js.map +1 -1
  114. package/packages/contracts/dist/workflow.d.ts +7 -0
  115. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  116. package/packages/contracts/dist/workflow.js +8 -0
  117. package/packages/contracts/dist/workflow.js.map +1 -1
  118. package/packages/contracts/dist/workflow.test.js +1 -0
  119. package/packages/contracts/dist/workflow.test.js.map +1 -1
  120. package/packages/contracts/package.json +1 -1
  121. package/packages/daemon/package.json +4 -4
  122. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +1 -0
  123. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
  124. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +22 -8
  125. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
  126. package/packages/gsd-agent-core/package.json +5 -5
  127. package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.d.ts +12 -0
  128. package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.d.ts.map +1 -0
  129. package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.js +45 -0
  130. package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.js.map +1 -0
  131. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.d.ts +3 -2
  132. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  133. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.js +11 -11
  134. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.js.map +1 -1
  135. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.d.ts +3 -3
  136. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  137. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.js +13 -11
  138. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.js.map +1 -1
  139. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.d.ts +3 -3
  140. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  141. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.js +12 -10
  142. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.js.map +1 -1
  143. package/packages/gsd-agent-modes/dist/modes/interactive/components/index.d.ts +1 -0
  144. package/packages/gsd-agent-modes/dist/modes/interactive/components/index.d.ts.map +1 -1
  145. package/packages/gsd-agent-modes/dist/modes/interactive/components/index.js +1 -0
  146. package/packages/gsd-agent-modes/dist/modes/interactive/components/index.js.map +1 -1
  147. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts +1 -1
  148. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  149. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js +2 -2
  150. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js.map +1 -1
  151. package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.d.ts +6 -1
  152. package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  153. package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.js +9 -6
  154. package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  155. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
  156. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +0 -1
  157. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
  158. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts +3 -0
  159. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
  160. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +144 -2
  161. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
  162. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.d.ts.map +1 -1
  163. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.js +2 -14
  164. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.js.map +1 -1
  165. package/packages/gsd-agent-modes/package.json +7 -7
  166. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  167. package/packages/mcp-server/dist/workflow-tools.js +28 -5
  168. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  169. package/packages/mcp-server/package.json +3 -3
  170. package/packages/native/package.json +1 -1
  171. package/packages/pi-agent-core/dist/harness/skills.d.ts.map +1 -1
  172. package/packages/pi-agent-core/dist/harness/skills.js +6 -0
  173. package/packages/pi-agent-core/dist/harness/skills.js.map +1 -1
  174. package/packages/pi-agent-core/dist/harness/system-prompt.d.ts +7 -0
  175. package/packages/pi-agent-core/dist/harness/system-prompt.d.ts.map +1 -1
  176. package/packages/pi-agent-core/dist/harness/system-prompt.js +7 -0
  177. package/packages/pi-agent-core/dist/harness/system-prompt.js.map +1 -1
  178. package/packages/pi-agent-core/package.json +1 -1
  179. package/packages/pi-ai/dist/models.generated.d.ts +8 -59
  180. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  181. package/packages/pi-ai/dist/models.generated.js +21 -72
  182. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  183. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  184. package/packages/pi-ai/dist/providers/anthropic.js +50 -0
  185. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  186. package/packages/pi-ai/dist/providers/openai-responses-shared.d.ts.map +1 -1
  187. package/packages/pi-ai/dist/providers/openai-responses-shared.js +28 -4
  188. package/packages/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
  189. package/packages/pi-ai/dist/types.d.ts +2 -0
  190. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  191. package/packages/pi-ai/dist/types.js.map +1 -1
  192. package/packages/pi-ai/package.json +1 -1
  193. package/packages/pi-coding-agent/README.md +1 -1
  194. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts +2 -2
  195. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts.map +1 -1
  196. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.js.map +1 -1
  197. package/packages/pi-coding-agent/dist/core/extensions/loader.js +1 -1
  198. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  199. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  200. package/packages/pi-coding-agent/dist/core/extensions/runner.js +8 -2
  201. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  202. package/packages/pi-coding-agent/dist/core/skills.d.ts +3 -0
  203. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  204. package/packages/pi-coding-agent/dist/core/skills.js +3 -0
  205. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  206. package/packages/pi-coding-agent/package.json +7 -7
  207. package/packages/pi-tui/package.json +1 -1
  208. package/packages/rpc-client/package.json +2 -2
  209. package/pkg/package.json +1 -1
  210. package/src/resources/extensions/context7/index.ts +15 -2
  211. package/src/resources/extensions/get-secrets-from-user.ts +17 -16
  212. package/src/resources/extensions/google-cli/index.ts +34 -0
  213. package/src/resources/extensions/google-cli/models.ts +57 -0
  214. package/src/resources/extensions/google-cli/package.json +11 -0
  215. package/src/resources/extensions/google-cli/readiness.ts +15 -0
  216. package/src/resources/extensions/google-cli/stream-adapter.ts +245 -0
  217. package/src/resources/extensions/gsd/auto/loop.ts +74 -1
  218. package/src/resources/extensions/gsd/auto/orchestrator.ts +4 -2
  219. package/src/resources/extensions/gsd/auto/phases.ts +46 -0
  220. package/src/resources/extensions/gsd/auto/run-unit.ts +10 -0
  221. package/src/resources/extensions/gsd/auto/session.ts +3 -0
  222. package/src/resources/extensions/gsd/auto-dispatch.ts +31 -11
  223. package/src/resources/extensions/gsd/auto-post-unit.ts +43 -14
  224. package/src/resources/extensions/gsd/auto-prompts.ts +4 -284
  225. package/src/resources/extensions/gsd/auto-recovery.ts +10 -7
  226. package/src/resources/extensions/gsd/auto-start.ts +307 -56
  227. package/src/resources/extensions/gsd/auto.ts +6 -1
  228. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +4 -3
  229. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +9 -4
  230. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +42 -5
  231. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +18 -6
  232. package/src/resources/extensions/gsd/bootstrap/system-context.ts +3 -28
  233. package/src/resources/extensions/gsd/closeout-recovery.ts +6 -1
  234. package/src/resources/extensions/gsd/commands/handlers/auto.ts +9 -1
  235. package/src/resources/extensions/gsd/commands-usage.ts +110 -5
  236. package/src/resources/extensions/gsd/config-overlay.ts +19 -16
  237. package/src/resources/extensions/gsd/context-overlay.ts +24 -19
  238. package/src/resources/extensions/gsd/dashboard-overlay.ts +14 -27
  239. package/src/resources/extensions/gsd/doctor-engine-checks.ts +99 -0
  240. package/src/resources/extensions/gsd/doctor-providers.ts +55 -27
  241. package/src/resources/extensions/gsd/doctor-types.ts +2 -0
  242. package/src/resources/extensions/gsd/doctor.ts +6 -1
  243. package/src/resources/extensions/gsd/git-conflict-state.ts +25 -1
  244. package/src/resources/extensions/gsd/guided-flow.ts +5 -6
  245. package/src/resources/extensions/gsd/key-manager.ts +57 -14
  246. package/src/resources/extensions/gsd/milestone-reopen-events.ts +28 -0
  247. package/src/resources/extensions/gsd/notification-overlay.ts +12 -11
  248. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +16 -12
  249. package/src/resources/extensions/gsd/preferences-skills.ts +11 -4
  250. package/src/resources/extensions/gsd/preferences.ts +17 -2
  251. package/src/resources/extensions/gsd/prompt-loader.ts +2 -0
  252. package/src/resources/extensions/gsd/prompts/discuss.md +4 -2
  253. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
  254. package/src/resources/extensions/gsd/prompts/system.md +1 -3
  255. package/src/resources/extensions/gsd/queue-reorder-ui.ts +29 -20
  256. package/src/resources/extensions/gsd/repository-registry.ts +3 -1
  257. package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -4
  258. package/src/resources/extensions/gsd/skill-activation.ts +292 -0
  259. package/src/resources/extensions/gsd/skill-catalog.data.ts +858 -0
  260. package/src/resources/extensions/gsd/skill-catalog.install.ts +205 -0
  261. package/src/resources/extensions/gsd/skill-catalog.ts +16 -1087
  262. package/src/resources/extensions/gsd/skill-discovery.ts +134 -78
  263. package/src/resources/extensions/gsd/skill-scope.ts +63 -0
  264. package/src/resources/extensions/gsd/skill-telemetry.ts +6 -40
  265. package/src/resources/extensions/gsd/skills.ts +75 -0
  266. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +499 -0
  267. package/src/resources/extensions/gsd/state-reconciliation/index.ts +40 -0
  268. package/src/resources/extensions/gsd/state-reconciliation/registry.ts +8 -0
  269. package/src/resources/extensions/gsd/state-reconciliation/types.ts +30 -0
  270. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +328 -2
  271. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +21 -0
  272. package/src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts +28 -2
  273. package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +30 -0
  274. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +41 -0
  275. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +12 -0
  276. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +436 -0
  277. package/src/resources/extensions/gsd/tests/closeout-recovery.test.ts +15 -0
  278. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +31 -0
  279. package/src/resources/extensions/gsd/tests/commands-context.test.ts +5 -3
  280. package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +15 -2
  281. package/src/resources/extensions/gsd/tests/commands-usage.test.ts +97 -0
  282. package/src/resources/extensions/gsd/tests/context-chart.test.ts +9 -0
  283. package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +25 -0
  284. package/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +1 -0
  285. package/src/resources/extensions/gsd/tests/discuss-prompt.test.ts +4 -2
  286. package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +1 -1
  287. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +105 -0
  288. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +101 -1
  289. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +30 -0
  290. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +6 -0
  291. package/src/resources/extensions/gsd/tests/key-manager.test.ts +23 -4
  292. package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +6 -1
  293. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +70 -10
  294. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +7 -1
  295. package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +93 -0
  296. package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +46 -0
  297. package/src/resources/extensions/gsd/tests/register-extension-guard.test.ts +116 -11
  298. package/src/resources/extensions/gsd/tests/repository-registry.test.ts +30 -1
  299. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +4 -0
  300. package/src/resources/extensions/gsd/tests/skill-discovery.test.ts +111 -0
  301. package/src/resources/extensions/gsd/tests/skill-scope-auto.test.ts +67 -0
  302. package/src/resources/extensions/gsd/tests/skills.test.ts +55 -0
  303. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +13 -2
  304. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +303 -0
  305. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +19 -0
  306. package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +24 -1
  307. package/src/resources/extensions/gsd/tests/tui-border-assertions.ts +28 -0
  308. package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +14 -0
  309. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +18 -0
  310. package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +26 -0
  311. package/src/resources/extensions/gsd/tests/vision-ask.test.ts +23 -0
  312. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +6 -1
  313. package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +74 -1
  314. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +82 -0
  315. package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +16 -1
  316. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +28 -0
  317. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +45 -1
  318. package/src/resources/extensions/gsd/tools/complete-task.ts +9 -0
  319. package/src/resources/extensions/gsd/tools/exec-tool.ts +42 -10
  320. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +82 -5
  321. package/src/resources/extensions/gsd/tui/render-kit.ts +82 -0
  322. package/src/resources/extensions/gsd/unit-context-manifest.ts +37 -26
  323. package/src/resources/extensions/gsd/user-input-boundary.ts +1 -1
  324. package/src/resources/extensions/gsd/vision-ask.ts +28 -0
  325. package/src/resources/extensions/gsd/visualizer-overlay.ts +12 -40
  326. package/src/resources/extensions/gsd/worktree-lifecycle.ts +37 -2
  327. package/src/resources/extensions/search-the-web/native-search.ts +60 -8
  328. package/src/resources/extensions/shared/confirm-ui.ts +8 -12
  329. package/src/resources/extensions/shared/dialog-frame.ts +71 -0
  330. package/src/resources/extensions/shared/interview-ui.ts +43 -42
  331. package/src/resources/extensions/shared/next-action-ui.ts +6 -6
  332. package/src/resources/extensions/shared/tests/confirm-ui.test.ts +57 -0
  333. package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +163 -0
  334. package/src/resources/extensions/shared/tests/next-action-ui-hasui.test.ts +55 -0
  335. package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +1 -1
  336. /package/dist/web/standalone/.next/static/{praHP_OATcjBkvAVejjGK → QKed8_bmMc7zc3WLM7MW9}/_buildManifest.js +0 -0
  337. /package/dist/web/standalone/.next/static/{praHP_OATcjBkvAVejjGK → QKed8_bmMc7zc3WLM7MW9}/_ssgManifest.js +0 -0
@@ -25,7 +25,7 @@ import { initNotificationWidget } from "../notification-widget.js";
25
25
  import { resolveWorktreeProjectRoot } from "../worktree-root.js";
26
26
  import { extractSubagentAgentClasses } from "./subagent-input.js";
27
27
  import { approvalGateIdForUnit, isExplicitApprovalResponse, shouldPauseForUserApprovalQuestion } from "../user-input-boundary.js";
28
- import { resolveSkillManifest } from "../skill-manifest.js";
28
+ import { applyUnitSkillVisibility, unitHasSkillManifest } from "../skill-scope.js";
29
29
  import { getGuidedUnitContext } from "../guided-unit-context.js";
30
30
  import { registerPlanMilestoneSchemaRecovery } from "./plan-milestone-schema-recovery.js";
31
31
  let approvalQuestionAbortInFlight = false;
@@ -285,8 +285,7 @@ export function scopeGsdWorkflowToolsForDispatch(pi, unitType) {
285
285
  ? buildMinimalAutoGsdToolSet(current, unitType, registeredToolNames)
286
286
  : buildMinimalGsdWorkflowToolSet(current, registeredToolNames);
287
287
  const toolsChanged = !(scoped.length === current.length && scoped.every((name, index) => name === current[index]));
288
- const skillManifest = resolveSkillManifest(unitType);
289
- const canScopeSkills = skillManifest !== null && pi.getVisibleSkills && pi.setVisibleSkills;
288
+ const canScopeSkills = unitHasSkillManifest(unitType) && pi.getVisibleSkills && pi.setVisibleSkills;
290
289
  if (!toolsChanged && !canScopeSkills) {
291
290
  return null;
292
291
  }
@@ -294,8 +293,8 @@ export function scopeGsdWorkflowToolsForDispatch(pi, unitType) {
294
293
  pi.setActiveTools(scoped);
295
294
  }
296
295
  const visibleSkills = canScopeSkills ? pi.getVisibleSkills() : undefined;
297
- if (canScopeSkills) {
298
- pi.setVisibleSkills(skillManifest);
296
+ if (canScopeSkills && pi.setVisibleSkills) {
297
+ applyUnitSkillVisibility({ setVisibleSkills: pi.setVisibleSkills }, unitType);
299
298
  }
300
299
  return {
301
300
  tools: toolsChanged ? current : null,
@@ -513,9 +512,20 @@ export function registerHooks(pi, ecosystemHandlers) {
513
512
  // before_agent_start, Claude Code CLI sessions should get the same
514
513
  // project MCP config that /gsd mcp init would write.
515
514
  await prepareWorkflowMcpForHookContext(ctx, beforeAgentBasePath);
515
+ let systemPrompt = event.systemPrompt;
516
+ const { appendDiscoveredSkillsFallback, hasSkillSnapshot, refreshCatalogForNewSkills } = await import("../skill-discovery.js");
517
+ if (hasSkillSnapshot()) {
518
+ const loadedSkills = await refreshCatalogForNewSkills({
519
+ reload: () => ctx.reload(),
520
+ notify: (message, level) => ctx.ui.notify(message, level),
521
+ });
522
+ if (loadedSkills.length > 0) {
523
+ systemPrompt = appendDiscoveredSkillsFallback(ctx.getSystemPrompt(), loadedSkills);
524
+ }
525
+ }
516
526
  // GSD's own context injection (existing behavior — unchanged).
517
527
  const { buildBeforeAgentStartResult } = await import("./system-context.js");
518
- const gsdResult = await buildBeforeAgentStartResult(event, ctx);
528
+ const gsdResult = await buildBeforeAgentStartResult({ ...event, systemPrompt }, ctx);
519
529
  // Refresh the snapshot used by ecosystem getPhase()/getActiveUnit().
520
530
  // deriveState has its own ~100ms cache so this is cheap on repeat calls.
521
531
  try {
@@ -527,7 +537,7 @@ export function registerHooks(pi, ecosystemHandlers) {
527
537
  }
528
538
  // Chain ecosystem handlers using pi's runner.ts chaining protocol:
529
539
  // each handler sees the systemPrompt mutated by prior handlers.
530
- let currentSystemPrompt = gsdResult?.systemPrompt ?? event.systemPrompt;
540
+ let currentSystemPrompt = gsdResult?.systemPrompt ?? systemPrompt;
531
541
  // `any` because pi's BeforeAgentStartEventResult.message uses an internal
532
542
  // CustomMessage type that's not re-exported (see ecosystem/gsd-extension-api.ts).
533
543
  let lastMessage = gsdResult?.message;
@@ -8,11 +8,9 @@ import { loadPrompt, getTemplatesDir } from "../prompt-loader.js";
8
8
  import { readForensicsMarker } from "../forensics.js";
9
9
  import { resolveAllSkillReferences, renderPreferencesForSystemPrompt, loadEffectiveGSDPreferences } from "../preferences.js";
10
10
  import { resolveModelWithFallbacksForUnit } from "../preferences-models.js";
11
- import { resolveSkillReference } from "../preferences-skills.js";
12
11
  import { resolveGsdRootFile, resolveSliceFile, resolveSlicePath, resolveTaskFile, resolveTaskFiles, resolveTasksDir, relSliceFile, relSlicePath, relTaskFile } from "../paths.js";
13
12
  import { extractIntroAndRules } from "../knowledge-parser.js";
14
13
  import { ensureCodebaseMapFresh, readCodebaseMap } from "../codebase-generator.js";
15
- import { hasSkillSnapshot, detectNewSkills, formatSkillsXml } from "../skill-discovery.js";
16
14
  import { getActiveAutoWorktreeContext } from "../auto-worktree.js";
17
15
  import { getActiveWorktreeName, getWorktreeOriginalCwd } from "../worktree-session-state.js";
18
16
  import { deriveState } from "../state.js";
@@ -66,20 +64,6 @@ export const BUNDLED_SKILL_TRIGGERS = [
66
64
  { trigger: "Author a YAML workflow definition — steps, triggers, and templates", skill: "create-workflow" },
67
65
  { 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" },
68
66
  ];
69
- function buildBundledSkillsTable() {
70
- const cwd = process.cwd();
71
- const rows = [];
72
- for (const { trigger, skill } of BUNDLED_SKILL_TRIGGERS) {
73
- const resolution = resolveSkillReference(skill, cwd);
74
- if (resolution.method === "unresolved")
75
- continue; // skill not installed — omit from prompt
76
- rows.push(`| ${trigger} | \`${resolution.resolvedPath}\` |`);
77
- }
78
- if (rows.length === 0) {
79
- return "*No bundled skills found. Install or sync skills to `~/.gsd/agent/skills/`, `~/.agents/skills/`, or `~/.claude/skills/`.*";
80
- }
81
- return `| Trigger | Skill to load |\n|---|---|\n${rows.join("\n")}`;
82
- }
83
67
  function warnDeprecatedAgentInstructions() {
84
68
  const paths = [
85
69
  join(gsdHome(), "agent-instructions.md"),
@@ -98,7 +82,6 @@ export async function buildBeforeAgentStartResult(event, ctx) {
98
82
  return undefined;
99
83
  const stopContextTimer = debugTime("context-inject");
100
84
  const systemContent = loadPrompt("system", {
101
- bundledSkillsTable: buildBundledSkillsTable(),
102
85
  templatesDir: getTemplatesDir(),
103
86
  shortcutDashboard: formatShortcut("Ctrl+Alt+G"),
104
87
  shortcutShell: formatShortcut("Ctrl+Alt+B"),
@@ -125,7 +108,7 @@ export async function buildBeforeAgentStartResult(event, ctx) {
125
108
  if (loadedPreferences) {
126
109
  const cwd = basePath;
127
110
  const report = resolveAllSkillReferences(loadedPreferences.preferences, cwd);
128
- preferenceBlock = `\n\n${renderPreferencesForSystemPrompt(loadedPreferences.preferences, report.resolutions)}`;
111
+ preferenceBlock = `\n\n${renderPreferencesForSystemPrompt(loadedPreferences.preferences, report.resolutions, { includeResolvedPaths: false })}`;
129
112
  if (report.warnings.length > 0) {
130
113
  ctx.ui.notify(`GSD skill preferences: ${report.warnings.length} unresolved skill${report.warnings.length === 1 ? "" : "s"}: ${report.warnings.join(", ")}`, "warning");
131
114
  }
@@ -178,13 +161,6 @@ export async function buildBeforeAgentStartResult(event, ctx) {
178
161
  if (globalSizeKb > 4) {
179
162
  ctx.ui.notify(`GSD: ~/.gsd/agent/KNOWLEDGE.md is ${globalSizeKb.toFixed(1)}KB — consider trimming to keep system prompt lean.`, "warning");
180
163
  }
181
- let newSkillsBlock = "";
182
- if (hasSkillSnapshot()) {
183
- const newSkills = detectNewSkills();
184
- if (newSkills.length > 0) {
185
- newSkillsBlock = formatSkillsXml(newSkills);
186
- }
187
- }
188
164
  let codebaseBlock = "";
189
165
  try {
190
166
  const codebaseOptions = loadedPreferences?.preferences?.codebase
@@ -235,12 +211,12 @@ export async function buildBeforeAgentStartResult(event, ctx) {
235
211
  // Keeping it out of `fullSystem` preserves provider prompt-cache stability
236
212
  // for the static system/tool prefix. The dynamic memory block rides the
237
213
  // volatile context message instead. (#5019)
238
- const fullSystem = `${event.systemPrompt}\n\n[SYSTEM CONTEXT — GSD]\n\n${systemContent}${preferenceBlock}${knowledgeBlock}${codebaseBlock}${newSkillsBlock}${worktreeBlock}${subagentModelBlock}`;
214
+ const fullSystem = `${event.systemPrompt}\n\n[SYSTEM CONTEXT — GSD]\n\n${systemContent}${preferenceBlock}${knowledgeBlock}${codebaseBlock}${worktreeBlock}${subagentModelBlock}`;
239
215
  stopContextTimer({
240
216
  systemPromptSize: fullSystem.length,
241
217
  injectionSize: injection?.length ?? forensicsInjection?.length ?? 0,
242
218
  hasPreferences: preferenceBlock.length > 0,
243
- hasNewSkills: newSkillsBlock.length > 0,
219
+ hasNewSkills: false,
244
220
  });
245
221
  const contextMessage = buildContextMessage({ memoryBlock, injection, forensicsInjection });
246
222
  return {
@@ -167,7 +167,13 @@ export function getCloseoutManualResolveBlocker(basePath) {
167
167
  if (conflictProbe.status === "dirty" && conflictProbe.unmerged.length > 0) {
168
168
  return `Unmerged paths remain in ${basePath}: ${conflictProbe.unmerged.slice(0, 5).join(", ")}`;
169
169
  }
170
- const status = runGit(basePath, ["status", "--porcelain"]);
170
+ let status;
171
+ try {
172
+ status = runGit(basePath, ["status", "--porcelain"]);
173
+ }
174
+ catch {
175
+ return `Could not inspect git status in ${basePath}.`;
176
+ }
171
177
  if (status) {
172
178
  return `Working tree still has uncommitted changes in ${basePath}. Commit, stash, or run /gsd closeout retry first.`;
173
179
  }
@@ -197,7 +197,15 @@ export async function handleAutoCommand(trimmed, ctx, pi) {
197
197
  if (trimmed === "") {
198
198
  if (!(await guardRemoteSession(ctx, pi)))
199
199
  return true;
200
- if (await hasUnresolvedCloseoutBlocker(ctx, projectRoot()))
200
+ const basePath = projectRoot();
201
+ const { hasGsdBootstrapArtifacts } = await import("../../detection.js");
202
+ const { gsdRoot } = await import("../../paths.js");
203
+ if (!hasGsdBootstrapArtifacts(gsdRoot(basePath))) {
204
+ const { showSmartEntry } = await import("../../guided-flow.js");
205
+ await showSmartEntry(ctx, pi, basePath, { step: true });
206
+ return true;
207
+ }
208
+ if (await hasUnresolvedCloseoutBlocker(ctx, basePath))
201
209
  return true;
202
210
  const { showGsdHome } = await import("../../gsd-command-home.js");
203
211
  await showGsdHome(ctx, pi, projectRoot());
@@ -3,8 +3,10 @@
3
3
  *
4
4
  * Shows current LLM context window usage and session token totals.
5
5
  */
6
+ import { Key, matchesKey } from "@gsd/pi-tui";
6
7
  import { formatCost, formatPercent, formatTokenCount } from "./metrics.js";
7
8
  import { loadEffectiveGSDPreferences } from "./preferences.js";
9
+ import { renderDialogFrame, renderKeyHints } from "./tui/render-kit.js";
8
10
  export function scanSessionTokenTotals(entries) {
9
11
  const totals = {
10
12
  input: 0,
@@ -115,6 +117,97 @@ export function formatUsageReport(options) {
115
117
  }
116
118
  return lines.join("\n");
117
119
  }
120
+ async function showUsageDialog(ctx, reportText) {
121
+ return ctx.ui.custom((tui, theme, _kb, done) => {
122
+ let cachedLines;
123
+ let cachedWidth;
124
+ let cachedRows;
125
+ let cachedScrollOffset;
126
+ let scrollOffset = 0;
127
+ let lastMaxScroll = 0;
128
+ let lastVisibleRows = 1;
129
+ function render(width) {
130
+ const terminalRows = process.stdout.rows || 0;
131
+ if (cachedLines &&
132
+ cachedWidth === width &&
133
+ cachedRows === terminalRows &&
134
+ cachedScrollOffset === scrollOffset) {
135
+ return cachedLines;
136
+ }
137
+ const contentWidth = Math.max(1, width - 4);
138
+ const body = reportText.split("\n");
139
+ if (body[0] === "Context Usage")
140
+ body.shift();
141
+ while (body[0] === "")
142
+ body.shift();
143
+ const maxOverlayRows = terminalRows > 0 ? Math.max(5, Math.floor(terminalRows * 0.8)) : 24;
144
+ const frameRows = 4;
145
+ const visibleRows = Math.max(1, maxOverlayRows - frameRows);
146
+ const maxScroll = Math.max(0, body.length - visibleRows);
147
+ scrollOffset = Math.min(Math.max(scrollOffset, 0), maxScroll);
148
+ lastMaxScroll = maxScroll;
149
+ lastVisibleRows = visibleRows;
150
+ const visible = body.slice(scrollOffset, scrollOffset + visibleRows);
151
+ const scrollable = body.length > visibleRows;
152
+ cachedLines = renderDialogFrame(theme, "Context Usage", visible, width, {
153
+ footer: renderKeyHints(theme, scrollable ? ["↑↓ scroll", "any key close"] : ["any key close"], contentWidth),
154
+ scroll: { offset: scrollOffset, visibleRows, totalRows: body.length },
155
+ });
156
+ cachedWidth = width;
157
+ cachedRows = terminalRows;
158
+ cachedScrollOffset = scrollOffset;
159
+ return cachedLines;
160
+ }
161
+ function scrollBy(delta) {
162
+ if (lastMaxScroll <= 0)
163
+ return false;
164
+ const nextOffset = Math.min(Math.max(scrollOffset + delta, 0), lastMaxScroll);
165
+ if (nextOffset !== scrollOffset) {
166
+ scrollOffset = nextOffset;
167
+ cachedLines = undefined;
168
+ cachedScrollOffset = undefined;
169
+ tui.requestRender();
170
+ }
171
+ return true;
172
+ }
173
+ return {
174
+ render,
175
+ invalidate: () => {
176
+ cachedLines = undefined;
177
+ cachedWidth = undefined;
178
+ cachedRows = undefined;
179
+ cachedScrollOffset = undefined;
180
+ },
181
+ handleInput: (data) => {
182
+ if (matchesKey(data, Key.down) || matchesKey(data, "j")) {
183
+ if (scrollBy(1))
184
+ return;
185
+ }
186
+ if (matchesKey(data, Key.up) || matchesKey(data, "k")) {
187
+ if (scrollBy(-1))
188
+ return;
189
+ }
190
+ if (matchesKey(data, Key.pageDown)) {
191
+ if (scrollBy(lastVisibleRows))
192
+ return;
193
+ }
194
+ if (matchesKey(data, Key.pageUp)) {
195
+ if (scrollBy(-lastVisibleRows))
196
+ return;
197
+ }
198
+ done(true);
199
+ },
200
+ };
201
+ }, {
202
+ overlay: true,
203
+ overlayOptions: {
204
+ width: "70%",
205
+ minWidth: 64,
206
+ maxHeight: "80%",
207
+ anchor: "center",
208
+ },
209
+ });
210
+ }
118
211
  export async function handleUsage(args, ctx) {
119
212
  const contextUsage = ctx.getContextUsage?.();
120
213
  const sessionTotals = scanSessionTokenTotals(ctx.sessionManager.getEntries());
@@ -133,5 +226,16 @@ export async function handleUsage(args, ctx) {
133
226
  }, null, 2), "info");
134
227
  return;
135
228
  }
136
- ctx.ui.notify(formatUsageReport({ modelLabel, contextUsage, sessionTotals }), "info");
229
+ const reportText = formatUsageReport({ modelLabel, contextUsage, sessionTotals });
230
+ if (ctx.hasUI) {
231
+ try {
232
+ const result = await showUsageDialog(ctx, reportText);
233
+ if (result !== undefined)
234
+ return;
235
+ }
236
+ catch {
237
+ // Fall back to text notify below when custom overlays are unavailable.
238
+ }
239
+ }
240
+ ctx.ui.notify(reportText, "info");
137
241
  }
@@ -7,6 +7,7 @@
7
7
  * Opened via `/gsd show-config` or `/gsd config`.
8
8
  */
9
9
  import { matchesKey, Key, truncateToWidth } from "@gsd/pi-tui";
10
+ import { renderDialogFrame, renderKeyHints } from "./tui/render-kit.js";
10
11
  import { loadEffectiveGSDPreferences, loadGlobalGSDPreferences, loadProjectGSDPreferences, getGlobalGSDPreferencesPath, getProjectGSDPreferencesPath, resolveDynamicRoutingConfig, resolveEffectiveProfile, resolveModelWithFallbacksForUnit, resolveAutoSupervisorConfig, } from "./preferences.js";
11
12
  function collectConfigSections() {
12
13
  const sections = [];
@@ -227,6 +228,7 @@ export class GSDConfigOverlay {
227
228
  onClose;
228
229
  sections;
229
230
  cachedLines;
231
+ cachedWidth;
230
232
  scrollOffset = 0;
231
233
  disposed = false;
232
234
  constructor(tui, theme, onClose) {
@@ -237,6 +239,7 @@ export class GSDConfigOverlay {
237
239
  }
238
240
  invalidate() {
239
241
  this.cachedLines = undefined;
242
+ this.cachedWidth = undefined;
240
243
  }
241
244
  dispose() {
242
245
  this.disposed = true;
@@ -273,14 +276,12 @@ export class GSDConfigOverlay {
273
276
  }
274
277
  }
275
278
  render(width) {
276
- if (this.cachedLines)
279
+ if (this.cachedLines && this.cachedWidth === width)
277
280
  return this.cachedLines;
278
281
  const t = this.theme;
279
- const w = Math.max(width, 50);
282
+ const w = Math.max(1, width);
283
+ const contentWidth = Math.max(1, w - 4);
280
284
  const allLines = [];
281
- // Header
282
- allLines.push(t.bold(t.fg("accent", " GSD Configuration ")));
283
- allLines.push(t.fg("muted", "\u2500".repeat(w)));
284
285
  // Find max label width for alignment
285
286
  let maxLabel = 0;
286
287
  for (const section of this.sections) {
@@ -291,22 +292,27 @@ export class GSDConfigOverlay {
291
292
  }
292
293
  const labelPad = Math.min(maxLabel + 2, 24);
293
294
  for (const section of this.sections) {
294
- allLines.push("");
295
+ if (allLines.length > 0)
296
+ allLines.push("");
295
297
  allLines.push(t.bold(t.fg("accent", ` ${section.title}`)));
296
298
  for (const row of section.rows) {
297
299
  const label = t.fg("muted", ` ${row.label.padEnd(labelPad)}`);
298
300
  const value = row.accent ? t.bold(row.value) : row.value;
299
- allLines.push(truncateToWidth(`${label}${value}`, w));
301
+ allLines.push(truncateToWidth(`${label}${value}`, contentWidth));
300
302
  }
301
303
  }
302
- allLines.push("");
303
- allLines.push(t.fg("muted", ` ${"\u2500".repeat(w - 4)}`));
304
- allLines.push(t.fg("muted", " esc/q close \u2502 \u2191\u2193/jk scroll \u2502 /gsd prefs to edit"));
305
304
  // Apply scroll
306
- const maxScroll = Math.max(0, allLines.length - 20);
305
+ const terminalRows = process.stdout.rows || 32;
306
+ const maxBodyRows = Math.max(1, Math.min(allLines.length, terminalRows - 12));
307
+ const maxScroll = Math.max(0, allLines.length - maxBodyRows);
307
308
  this.scrollOffset = Math.min(this.scrollOffset, maxScroll);
308
- const visible = allLines.slice(this.scrollOffset);
309
- this.cachedLines = visible;
310
- return visible;
309
+ const visible = allLines.slice(this.scrollOffset, this.scrollOffset + maxBodyRows);
310
+ const footer = renderKeyHints(t, ["esc/q close", "\u2191\u2193/jk scroll", "/gsd prefs to edit"], contentWidth);
311
+ this.cachedLines = renderDialogFrame(t, "GSD Configuration", visible, w, {
312
+ footer,
313
+ scroll: { offset: this.scrollOffset, visibleRows: maxBodyRows, totalRows: allLines.length },
314
+ });
315
+ this.cachedWidth = width;
316
+ return this.cachedLines;
311
317
  }
312
318
  }
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { matchesKey, Key, truncateToWidth } from "@gsd/pi-tui";
5
5
  import { formatTokenCount } from "./metrics.js";
6
- import { renderProgressBar, rightAlign } from "./tui/render-kit.js";
6
+ import { renderDialogFrame, renderKeyHints, renderProgressBar, rightAlign } from "./tui/render-kit.js";
7
7
  const SECTION_COLORS = ["accent", "success", "warning", "borderAccent", "text"];
8
8
  export function getContextChartTotals(report) {
9
9
  const systemTokens = report.systemSections.reduce((sum, section) => sum + section.tokens, 0);
@@ -47,6 +47,7 @@ export class GSDContextOverlay {
47
47
  onClose;
48
48
  report;
49
49
  cachedLines;
50
+ cachedWidth;
50
51
  scrollOffset = 0;
51
52
  disposed = false;
52
53
  constructor(tui, theme, report, onClose) {
@@ -57,6 +58,7 @@ export class GSDContextOverlay {
57
58
  }
58
59
  invalidate() {
59
60
  this.cachedLines = undefined;
61
+ this.cachedWidth = undefined;
60
62
  }
61
63
  dispose() {
62
64
  this.disposed = true;
@@ -92,21 +94,20 @@ export class GSDContextOverlay {
92
94
  }
93
95
  }
94
96
  render(width) {
95
- if (this.cachedLines)
97
+ if (this.cachedLines && this.cachedWidth === width)
96
98
  return this.cachedLines;
97
99
  const theme = this.theme;
98
- const w = Math.max(width, 60);
100
+ const w = Math.max(1, width);
101
+ const contentWidth = Math.max(1, w - 4);
99
102
  const totals = getContextChartTotals(this.report);
100
103
  const chartTotal = Math.max(totals.inContext, totals.estimated, 1);
101
104
  const lines = [];
102
- lines.push(theme.bold(theme.fg("accent", " Context Breakdown ")));
103
- lines.push(theme.fg("muted", "─".repeat(w)));
104
105
  if (this.report.modelLabel) {
105
- lines.push(rightAlign(theme.fg("muted", "Model"), theme.fg("text", this.report.modelLabel), w));
106
+ lines.push(rightAlign(theme.fg("muted", "Model"), theme.fg("text", this.report.modelLabel), contentWidth));
106
107
  }
107
108
  lines.push("");
108
109
  if (totals.window != null) {
109
- const usageBarWidth = Math.max(20, w - 28);
110
+ const usageBarWidth = Math.max(8, contentWidth - 28);
110
111
  const usageBar = renderProgressBar(theme, totals.inContext, totals.window, usageBarWidth, {
111
112
  filledColor: totals.inContext / totals.window > 0.85 ? "warning" : "accent",
112
113
  });
@@ -115,7 +116,7 @@ export class GSDContextOverlay {
115
116
  else {
116
117
  lines.push(` ${theme.fg("muted", "Estimated")} ${theme.fg("text", formatTokenCount(chartTotal))}`);
117
118
  }
118
- const splitWidth = Math.max(16, Math.floor((w - 8) / 2));
119
+ const splitWidth = Math.max(8, Math.floor((contentWidth - 8) / 2));
119
120
  const systemBar = renderProgressBar(theme, totals.systemTokens, chartTotal, splitWidth, { filledColor: "accent" });
120
121
  const convBar = renderProgressBar(theme, totals.conversationTokens, chartTotal, splitWidth, { filledColor: "success" });
121
122
  lines.push("");
@@ -123,17 +124,17 @@ export class GSDContextOverlay {
123
124
  lines.push(` ${theme.fg("success", "History")} ${convBar} ${theme.fg("muted", formatPct(totals.conversationTokens, chartTotal))}`);
124
125
  lines.push("");
125
126
  lines.push(theme.bold(theme.fg("accent", " System prompt")));
126
- lines.push(...renderSectionBars(theme, this.report.systemSections, chartTotal, w, 22));
127
+ lines.push(...renderSectionBars(theme, this.report.systemSections, chartTotal, contentWidth, 22));
127
128
  lines.push("");
128
129
  lines.push(theme.bold(theme.fg("accent", " Conversation")));
129
- lines.push(...renderSectionBars(theme, this.report.conversationSections, chartTotal, w, 22));
130
+ lines.push(...renderSectionBars(theme, this.report.conversationSections, chartTotal, contentWidth, 22));
130
131
  lines.push("");
131
132
  lines.push(theme.bold(theme.fg("accent", " Skills")));
132
133
  const { skills } = this.report;
133
134
  if (skills.available.length > 0) {
134
135
  lines.push(` ${theme.fg("muted", "Available")} ${theme.fg("text", `${skills.available.length}`)}`);
135
136
  const preview = skills.available.slice(0, 8).join(", ");
136
- lines.push(truncateToWidth(` ${preview}${skills.available.length > 8 ? "…" : ""}`, w));
137
+ lines.push(truncateToWidth(` ${preview}${skills.available.length > 8 ? "…" : ""}`, contentWidth));
137
138
  }
138
139
  else {
139
140
  lines.push(theme.fg("dim", " none in prompt"));
@@ -147,12 +148,17 @@ export class GSDContextOverlay {
147
148
  lines.push("");
148
149
  lines.push(theme.bold(theme.fg("accent", " Agents")));
149
150
  lines.push(` ${theme.fg("muted", "Subagent spawns")} ${theme.fg("text", String(this.report.subagentSpawns))}`);
150
- lines.push("");
151
- lines.push(theme.fg("muted", ` ${"─".repeat(Math.max(0, w - 4))}`));
152
- lines.push(theme.fg("muted", " esc/q close │ ↑↓ scroll │ /gsd context --open for browser chart"));
153
- const maxScroll = Math.max(0, lines.length - 24);
151
+ const terminalRows = process.stdout.rows || 32;
152
+ const maxBodyRows = Math.max(1, Math.min(lines.length, terminalRows - 12));
153
+ const maxScroll = Math.max(0, lines.length - maxBodyRows);
154
154
  this.scrollOffset = Math.min(this.scrollOffset, maxScroll);
155
- this.cachedLines = lines.slice(this.scrollOffset);
155
+ const visible = lines.slice(this.scrollOffset, this.scrollOffset + maxBodyRows);
156
+ const footer = renderKeyHints(theme, ["esc/q close", "↑↓ scroll", "/gsd context --open"], contentWidth);
157
+ this.cachedLines = renderDialogFrame(theme, "Context Breakdown", visible, w, {
158
+ footer,
159
+ scroll: { offset: this.scrollOffset, visibleRows: maxBodyRows, totalRows: lines.length },
160
+ });
161
+ this.cachedWidth = width;
156
162
  return this.cachedLines;
157
163
  }
158
164
  }
@@ -6,7 +6,7 @@
6
6
  * Toggled with Ctrl+Alt+G (⌃⌥G on macOS), Ctrl+Shift+G fallback,
7
7
  * or opened from /gsd status.
8
8
  */
9
- import { truncateToWidth, visibleWidth, matchesKey, Key } from "@gsd/pi-tui";
9
+ import { truncateToWidth, matchesKey, Key } from "@gsd/pi-tui";
10
10
  import { deriveState } from "./state.js";
11
11
  import { loadFile } from "./files.js";
12
12
  import { isDbAvailable, getMilestoneSlices, getSliceTasks } from "./gsd-db.js";
@@ -21,6 +21,7 @@ import { estimateTimeRemaining } from "./auto-dashboard.js";
21
21
  import { computeProgressScore } from "./progress-score.js";
22
22
  import { runEnvironmentChecks } from "./doctor-environment.js";
23
23
  import { formattedShortcutPair } from "./shortcut-defs.js";
24
+ import { renderDialogFrame, renderKeyHints } from "./tui/render-kit.js";
24
25
  export function unitLabel(type) {
25
26
  switch (type) {
26
27
  case "discuss-milestone":
@@ -222,30 +223,20 @@ export class GSDDashboardOverlay {
222
223
  }
223
224
  const content = this.buildContentLines(width);
224
225
  const viewportHeight = Math.max(5, process.stdout.rows ? process.stdout.rows - 8 : 24);
225
- const chromeHeight = 2;
226
- const visibleContentRows = Math.max(1, viewportHeight - chromeHeight);
226
+ const visibleContentRows = Math.max(1, viewportHeight - 4);
227
227
  const maxScroll = Math.max(0, content.length - visibleContentRows);
228
228
  this.scrollOffset = Math.min(this.scrollOffset, maxScroll);
229
229
  const visibleContent = content.slice(this.scrollOffset, this.scrollOffset + visibleContentRows);
230
- const lines = this.wrapInBox(visibleContent, width);
230
+ const contentWidth = Math.max(1, width - 4);
231
+ const footer = renderKeyHints(this.theme, ["↑↓ scroll", "g/G top/end", `Esc/${formattedShortcutPair("dashboard")} close`], contentWidth);
232
+ const lines = renderDialogFrame(this.theme, "GSD Dashboard", visibleContent, width, {
233
+ footer,
234
+ scroll: { offset: this.scrollOffset, visibleRows: visibleContentRows, totalRows: content.length },
235
+ });
231
236
  this.cachedWidth = width;
232
237
  this.cachedLines = lines;
233
238
  return lines;
234
239
  }
235
- wrapInBox(inner, width) {
236
- const th = this.theme;
237
- const border = (s) => th.fg("borderAccent", s);
238
- const innerWidth = width - 4;
239
- const lines = [];
240
- lines.push(border("╭" + "─".repeat(width - 2) + "╮"));
241
- for (const line of inner) {
242
- const truncated = truncateToWidth(line, innerWidth);
243
- const padWidth = Math.max(0, innerWidth - visibleWidth(truncated));
244
- lines.push(border("│") + " " + truncated + " ".repeat(padWidth) + " " + border("│"));
245
- }
246
- lines.push(border("╰" + "─".repeat(width - 2) + "╯"));
247
- return lines;
248
- }
249
240
  buildContentLines(width) {
250
241
  const th = this.theme;
251
242
  const shellWidth = width - 4;
@@ -260,7 +251,6 @@ export class GSDDashboardOverlay {
260
251
  const blank = () => row("");
261
252
  const hr = () => row(th.fg("dim", "─".repeat(contentWidth)));
262
253
  const centered = (content) => row(centerLine(content, contentWidth));
263
- const title = th.fg("accent", th.bold("GSD Dashboard"));
264
254
  const isRemote = !!this.dashData.remoteSession;
265
255
  const status = this.dashData.active
266
256
  ? `${Date.now() % 2000 < 1000 ? th.fg("success", "●") : th.fg("dim", "○")} ${th.fg("success", "AUTO")}`
@@ -287,7 +277,7 @@ export class GSDDashboardOverlay {
287
277
  else if (isRemote) {
288
278
  elapsedParts = th.fg("dim", `since ${this.dashData.remoteSession.startedAt.replace("T", " ").slice(0, 19)}`);
289
279
  }
290
- lines.push(row(joinColumns(`${title} ${status}${worktreeTag}`, elapsedParts, contentWidth)));
280
+ lines.push(row(joinColumns(`${status}${worktreeTag}`, elapsedParts, contentWidth)));
291
281
  // Progress score — traffic light indicator (#1221)
292
282
  if (this.dashData.active || this.dashData.paused) {
293
283
  const progressScore = computeProgressScore();
@@ -528,9 +518,6 @@ export class GSDDashboardOverlay {
528
518
  }
529
519
  }
530
520
  }
531
- lines.push(blank());
532
- lines.push(hr());
533
- lines.push(centered(th.fg("dim", `↑↓ scroll · g/G top/end · Esc/${formattedShortcutPair("dashboard")} close`)));
534
521
  return lines;
535
522
  }
536
523
  renderProgressRow(label, done, total, color, width) {