gsd-pi 2.80.0-dev.c5f2443b3 → 2.80.0-dev.f55d16d13

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 (303) hide show
  1. package/dist/resources/.managed-resources-content-hash +1 -1
  2. package/dist/resources/GSD-WORKFLOW.md +2 -2
  3. package/dist/resources/extensions/github-sync/templates.js +39 -8
  4. package/dist/resources/extensions/gsd/auto/loop.js +16 -9
  5. package/dist/resources/extensions/gsd/auto/phases.js +37 -30
  6. package/dist/resources/extensions/gsd/auto/run-unit.js +19 -15
  7. package/dist/resources/extensions/gsd/auto-dashboard.js +51 -15
  8. package/dist/resources/extensions/gsd/auto-dispatch.js +10 -0
  9. package/dist/resources/extensions/gsd/auto-post-unit.js +10 -10
  10. package/dist/resources/extensions/gsd/auto-prompts.js +111 -1
  11. package/dist/resources/extensions/gsd/auto-recovery.js +154 -8
  12. package/dist/resources/extensions/gsd/auto-start.js +2 -3
  13. package/dist/resources/extensions/gsd/auto.js +9 -1
  14. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +15 -1
  15. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +11 -1
  16. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +129 -1
  17. package/dist/resources/extensions/gsd/clean-root-preflight.js +42 -4
  18. package/dist/resources/extensions/gsd/commands-extract-learnings.js +17 -12
  19. package/dist/resources/extensions/gsd/custom-workflow-engine.js +22 -2
  20. package/dist/resources/extensions/gsd/db-base-schema.js +14 -0
  21. package/dist/resources/extensions/gsd/db-migration-steps.js +16 -0
  22. package/dist/resources/extensions/gsd/detection.js +106 -0
  23. package/dist/resources/extensions/gsd/graph.js +9 -3
  24. package/dist/resources/extensions/gsd/gsd-db.js +102 -2
  25. package/dist/resources/extensions/gsd/guided-flow.js +2 -2
  26. package/dist/resources/extensions/gsd/pr-evidence.js +57 -16
  27. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +7 -8
  28. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
  29. package/dist/resources/extensions/gsd/safety/evidence-collector.js +10 -2
  30. package/dist/resources/extensions/gsd/working-output-messages.js +64 -0
  31. package/dist/resources/extensions/gsd/worktree-manager.js +16 -14
  32. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  33. package/dist/web/standalone/.next/BUILD_ID +1 -1
  34. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  35. package/dist/web/standalone/.next/build-manifest.json +3 -3
  36. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  37. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  38. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  39. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  41. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  42. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  44. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  47. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  52. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  53. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  55. package/dist/web/standalone/.next/server/app/index.html +1 -1
  56. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  57. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  63. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  64. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  65. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  66. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  67. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  68. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  69. package/dist/web/standalone/.next/static/chunks/{8336.6f6f30e410419aff.js → 8336.631939fb583761fa.js} +1 -1
  70. package/dist/web/standalone/.next/static/chunks/{webpack-d82dbee6356c1733.js → webpack-0481f1221120a7c6.js} +1 -1
  71. package/package.json +10 -6
  72. package/packages/contracts/package.json +1 -1
  73. package/packages/pi-ai/dist/models/fake-model.d.ts +12 -0
  74. package/packages/pi-ai/dist/models/fake-model.d.ts.map +1 -0
  75. package/packages/pi-ai/dist/models/fake-model.js +27 -0
  76. package/packages/pi-ai/dist/models/fake-model.js.map +1 -0
  77. package/packages/pi-ai/dist/models/index.d.ts.map +1 -1
  78. package/packages/pi-ai/dist/models/index.js +8 -0
  79. package/packages/pi-ai/dist/models/index.js.map +1 -1
  80. package/packages/pi-ai/dist/providers/fake.d.ts +42 -0
  81. package/packages/pi-ai/dist/providers/fake.d.ts.map +1 -0
  82. package/packages/pi-ai/dist/providers/fake.js +319 -0
  83. package/packages/pi-ai/dist/providers/fake.js.map +1 -0
  84. package/packages/pi-ai/dist/providers/register-builtins.d.ts.map +1 -1
  85. package/packages/pi-ai/dist/providers/register-builtins.js +24 -0
  86. package/packages/pi-ai/dist/providers/register-builtins.js.map +1 -1
  87. package/packages/pi-ai/src/models/fake-model.ts +30 -0
  88. package/packages/pi-ai/src/models/index.ts +9 -0
  89. package/packages/pi-ai/src/providers/fake.ts +376 -0
  90. package/packages/pi-ai/src/providers/register-builtins.ts +23 -0
  91. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  92. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +74 -0
  93. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  94. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -0
  95. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  96. package/packages/pi-coding-agent/dist/core/extensions/runner.js +14 -1
  97. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  98. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +97 -0
  99. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  100. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  101. package/packages/pi-coding-agent/dist/core/model-registry.js +5 -0
  102. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  103. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +4 -0
  104. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  105. package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
  106. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  107. package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
  108. package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -0
  109. package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
  110. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js +6 -4
  111. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js.map +1 -1
  112. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +54 -15
  113. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  114. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +26 -0
  115. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -0
  116. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +112 -0
  117. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -0
  118. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts +2 -0
  119. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts.map +1 -0
  120. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +51 -0
  121. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -0
  122. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  123. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  124. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  125. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +10 -9
  126. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  127. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +3 -0
  128. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  129. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +11 -0
  130. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  131. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +7 -6
  132. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
  133. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +16 -0
  134. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  135. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +106 -17
  136. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  137. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  138. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +60 -1
  139. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  140. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +40 -1
  141. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  142. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +1 -0
  143. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  144. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +1 -0
  145. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  146. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  147. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +3 -0
  148. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  149. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +23 -0
  150. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  151. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
  152. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +20 -0
  153. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
  154. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts +2 -0
  155. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts.map +1 -0
  156. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js +79 -0
  157. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js.map +1 -0
  158. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
  159. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
  160. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js +13 -0
  161. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js.map +1 -1
  162. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +1 -1
  163. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  164. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +18 -1
  165. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  166. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  167. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +36 -27
  168. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  169. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts +11 -0
  170. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts.map +1 -0
  171. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js +18 -0
  172. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js.map +1 -0
  173. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts +2 -0
  174. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts.map +1 -0
  175. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +48 -0
  176. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -0
  177. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +87 -0
  178. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +108 -0
  179. package/packages/pi-coding-agent/src/core/extensions/runner.ts +16 -1
  180. package/packages/pi-coding-agent/src/core/model-registry.ts +4 -0
  181. package/packages/pi-coding-agent/src/core/settings-manager.ts +12 -0
  182. package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -0
  183. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.ts +7 -5
  184. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +78 -15
  185. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +59 -0
  186. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +160 -0
  187. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +1 -0
  188. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +10 -9
  189. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
  190. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +10 -9
  191. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +118 -17
  192. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +43 -1
  193. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +75 -1
  194. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +1 -0
  195. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -1
  196. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +25 -0
  197. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.test.ts +95 -0
  198. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +24 -1
  199. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-schema.ts +13 -0
  200. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +32 -2
  201. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +36 -27
  202. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +65 -0
  203. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.ts +29 -0
  204. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  205. package/packages/pi-tui/dist/__tests__/style.test.d.ts +2 -0
  206. package/packages/pi-tui/dist/__tests__/style.test.d.ts.map +1 -0
  207. package/packages/pi-tui/dist/__tests__/style.test.js +63 -0
  208. package/packages/pi-tui/dist/__tests__/style.test.js.map +1 -0
  209. package/packages/pi-tui/dist/__tests__/tui.test.js +24 -3
  210. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  211. package/packages/pi-tui/dist/index.d.ts +1 -0
  212. package/packages/pi-tui/dist/index.d.ts.map +1 -1
  213. package/packages/pi-tui/dist/index.js +2 -0
  214. package/packages/pi-tui/dist/index.js.map +1 -1
  215. package/packages/pi-tui/dist/style.d.ts +41 -0
  216. package/packages/pi-tui/dist/style.d.ts.map +1 -0
  217. package/packages/pi-tui/dist/style.js +158 -0
  218. package/packages/pi-tui/dist/style.js.map +1 -0
  219. package/packages/pi-tui/dist/tui.d.ts +0 -1
  220. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  221. package/packages/pi-tui/dist/tui.js +3 -8
  222. package/packages/pi-tui/dist/tui.js.map +1 -1
  223. package/packages/pi-tui/src/__tests__/style.test.ts +76 -0
  224. package/packages/pi-tui/src/__tests__/tui.test.ts +29 -3
  225. package/packages/pi-tui/src/index.ts +9 -0
  226. package/packages/pi-tui/src/style.ts +225 -0
  227. package/packages/pi-tui/src/tui.ts +3 -8
  228. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  229. package/pkg/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
  230. package/pkg/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
  231. package/pkg/dist/modes/interactive/theme/theme-schema.js +13 -0
  232. package/pkg/dist/modes/interactive/theme/theme-schema.js.map +1 -1
  233. package/pkg/dist/modes/interactive/theme/theme.d.ts +1 -1
  234. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  235. package/pkg/dist/modes/interactive/theme/theme.js +18 -1
  236. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  237. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  238. package/pkg/dist/modes/interactive/theme/themes.js +36 -27
  239. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  240. package/src/resources/GSD-WORKFLOW.md +2 -2
  241. package/src/resources/extensions/github-sync/templates.ts +38 -8
  242. package/src/resources/extensions/github-sync/tests/inline-code.test.ts +66 -0
  243. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
  244. package/src/resources/extensions/gsd/auto/loop.ts +17 -10
  245. package/src/resources/extensions/gsd/auto/phases.ts +42 -28
  246. package/src/resources/extensions/gsd/auto/run-unit.ts +24 -14
  247. package/src/resources/extensions/gsd/auto-dashboard.ts +57 -8
  248. package/src/resources/extensions/gsd/auto-dispatch.ts +17 -0
  249. package/src/resources/extensions/gsd/auto-post-unit.ts +10 -10
  250. package/src/resources/extensions/gsd/auto-prompts.ts +116 -1
  251. package/src/resources/extensions/gsd/auto-recovery.ts +153 -7
  252. package/src/resources/extensions/gsd/auto-start.ts +7 -6
  253. package/src/resources/extensions/gsd/auto.ts +12 -1
  254. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +16 -1
  255. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +17 -1
  256. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +135 -1
  257. package/src/resources/extensions/gsd/clean-root-preflight.ts +41 -3
  258. package/src/resources/extensions/gsd/commands-extract-learnings.ts +17 -12
  259. package/src/resources/extensions/gsd/custom-workflow-engine.ts +24 -1
  260. package/src/resources/extensions/gsd/db-base-schema.ts +15 -0
  261. package/src/resources/extensions/gsd/db-migration-steps.ts +17 -0
  262. package/src/resources/extensions/gsd/detection.ts +128 -0
  263. package/src/resources/extensions/gsd/graph.ts +12 -5
  264. package/src/resources/extensions/gsd/gsd-db.ts +119 -1
  265. package/src/resources/extensions/gsd/guided-flow.ts +2 -2
  266. package/src/resources/extensions/gsd/pr-evidence.ts +63 -5
  267. package/src/resources/extensions/gsd/prompts/complete-milestone.md +7 -8
  268. package/src/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
  269. package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -2
  270. package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +7 -1
  271. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +33 -0
  272. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +84 -5
  273. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +170 -1
  274. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +88 -2
  275. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +9 -0
  276. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +112 -6
  277. package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +40 -2
  278. package/src/resources/extensions/gsd/tests/db-migration-steps.integration.test.ts +428 -0
  279. package/src/resources/extensions/gsd/tests/db-schema-metadata.test.ts +2 -2
  280. package/src/resources/extensions/gsd/tests/detection.test.ts +140 -0
  281. package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-basic.md +52 -0
  282. package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-empty-optionals.md +42 -0
  283. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +55 -0
  284. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +60 -0
  285. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +10 -0
  286. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +44 -0
  287. package/src/resources/extensions/gsd/tests/has-pending-deep-stage.test.ts +33 -1
  288. package/src/resources/extensions/gsd/tests/pr-evidence-equivalence.test.ts +102 -0
  289. package/src/resources/extensions/gsd/tests/pr-evidence-hardening.test.ts +165 -0
  290. package/src/resources/extensions/gsd/tests/right-sized-workflow-prompts.test.ts +192 -0
  291. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +29 -0
  292. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +46 -2
  293. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +1 -1
  294. package/src/resources/extensions/gsd/tests/working-output-messages.test.ts +93 -0
  295. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +37 -6
  296. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +7 -0
  297. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +9 -2
  298. package/src/resources/extensions/gsd/tests/worktree-write-gate.test.ts +179 -0
  299. package/src/resources/extensions/gsd/working-output-messages.ts +120 -0
  300. package/src/resources/extensions/gsd/worktree-manager.ts +15 -4
  301. package/packages/contracts/tsconfig.tsbuildinfo +0 -1
  302. /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → mPZbi5BH9dwokaPZlrYuQ}/_buildManifest.js +0 -0
  303. /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → mPZbi5BH9dwokaPZlrYuQ}/_ssgManifest.js +0 -0
@@ -1,9 +1,14 @@
1
+ // GSD-2 Interactive Chat Controller
1
2
  import { Loader, Markdown, Spacer, Text } from "@gsd/pi-tui";
2
3
 
3
4
  import type { InteractiveModeEvent, InteractiveModeStateHost } from "../interactive-mode-state.js";
4
5
  import { theme } from "../theme/theme.js";
5
6
  import { AssistantMessageComponent } from "../components/assistant-message.js";
6
- import { ToolExecutionComponent } from "../components/tool-execution.js";
7
+ import {
8
+ ToolExecutionComponent,
9
+ ToolPhaseSummaryComponent,
10
+ type ToolExecutionPhase,
11
+ } from "../components/tool-execution.js";
7
12
  import { DynamicBorder } from "../components/dynamic-border.js";
8
13
  import { appKey } from "../components/keybinding-hints.js";
9
14
 
@@ -100,6 +105,71 @@ let pinnedBorder: DynamicBorder | undefined;
100
105
  // Reference to the pinned markdown component below the border
101
106
  let pinnedTextComponent: Markdown | undefined;
102
107
 
108
+ function mergeToolPhases(phases: ToolExecutionPhase[]): ToolExecutionPhase[] {
109
+ const merged: ToolExecutionPhase[] = [];
110
+ for (const phase of phases) {
111
+ const previous = merged[merged.length - 1];
112
+ if (previous?.label === phase.label) {
113
+ previous.count += phase.count;
114
+ previous.durationMs += phase.durationMs;
115
+ } else {
116
+ merged.push({ ...phase });
117
+ }
118
+ }
119
+ return merged;
120
+ }
121
+
122
+ function replaceCompactToolRowsWithPhaseSummary(
123
+ host: InteractiveModeStateHost & { ui: { requestRender: () => void } },
124
+ ): void {
125
+ let changed = false;
126
+ const nextRenderedSegments: RenderedSegment[] = [];
127
+ let rollupRun: Array<{ seg: Extract<RenderedSegment, { kind: "tool" }>; phase: ToolExecutionPhase }> = [];
128
+
129
+ const flushRollupRun = () => {
130
+ if (rollupRun.length < 2) {
131
+ nextRenderedSegments.push(...rollupRun.map((item) => item.seg));
132
+ rollupRun = [];
133
+ return;
134
+ }
135
+
136
+ const firstIndex = Math.max(0, host.chatContainer.children.indexOf(rollupRun[0].seg.component));
137
+ const summary = new ToolPhaseSummaryComponent(mergeToolPhases(rollupRun.map((item) => item.phase)));
138
+
139
+ for (const { seg } of rollupRun) {
140
+ host.chatContainer.removeChild(seg.component);
141
+ }
142
+
143
+ host.chatContainer.addChild(summary);
144
+ const summaryIndex = host.chatContainer.children.indexOf(summary);
145
+ if (summaryIndex !== -1 && summaryIndex !== firstIndex) {
146
+ host.chatContainer.children.splice(summaryIndex, 1);
147
+ host.chatContainer.children.splice(firstIndex, 0, summary);
148
+ (host.chatContainer as unknown as { _prevRender: string[] | null })._prevRender = null;
149
+ }
150
+
151
+ changed = true;
152
+ rollupRun = [];
153
+ };
154
+
155
+ for (const seg of renderedSegments) {
156
+ const phase = seg.kind === "tool" ? seg.component.getRollupPhase() : null;
157
+ if (seg.kind === "tool" && phase) {
158
+ rollupRun.push({ seg, phase });
159
+ continue;
160
+ }
161
+
162
+ flushRollupRun();
163
+ nextRenderedSegments.push(seg);
164
+ }
165
+ flushRollupRun();
166
+
167
+ if (changed) {
168
+ renderedSegments = nextRenderedSegments;
169
+ host.ui.requestRender();
170
+ }
171
+ }
172
+
103
173
  export async function handleAgentEvent(host: InteractiveModeStateHost & {
104
174
  init: () => Promise<void>;
105
175
  getMarkdownThemeWithSettings: () => any;
@@ -177,6 +247,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
177
247
  return;
178
248
  }
179
249
  case "agent_start":
250
+ host.clearBlockingError();
180
251
  if (host.retryEscapeHandler) {
181
252
  host.defaultEditor.onEscape = host.retryEscapeHandler;
182
253
  host.retryEscapeHandler = undefined;
@@ -772,6 +843,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
772
843
  host.streamingComponent.setShowMetadata(true);
773
844
  host.streamingComponent.updateContent(host.streamingMessage);
774
845
  }
846
+ replaceCompactToolRowsWithPhaseSummary(host);
775
847
 
776
848
  if (host.streamingMessage.stopReason === "aborted" || host.streamingMessage.stopReason === "error") {
777
849
  if (!errorMessage) {
@@ -822,6 +894,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
822
894
  component.setExpanded(host.toolOutputExpanded);
823
895
  host.chatContainer.addChild(component);
824
896
  host.pendingTools.set(event.toolCallId, component);
897
+ renderedSegments.push({ kind: "tool", contentIndex: Number.MAX_SAFE_INTEGER, component });
825
898
  host.ui.requestRender();
826
899
  }
827
900
  break;
@@ -855,6 +928,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
855
928
  host.streamingComponent.setShowMetadata(true);
856
929
  host.streamingComponent.updateContent(host.streamingMessage);
857
930
  }
931
+ replaceCompactToolRowsWithPhaseSummary(host);
858
932
  host.streamingComponent = undefined;
859
933
  host.streamingMessage = undefined;
860
934
  renderedSegments = [];
@@ -49,6 +49,7 @@ function createMockHost() {
49
49
  isInitialized: true,
50
50
  loadingAnimation: undefined,
51
51
  pendingWorkingMessage: undefined,
52
+ clearBlockingError: () => {},
52
53
  defaultWorkingMessage: "Working...",
53
54
  streamingComponent: undefined,
54
55
  streamingMessage: undefined,
@@ -20,6 +20,7 @@ export interface InteractiveModeStateHost {
20
20
  isInitialized: boolean;
21
21
  loadingAnimation?: any;
22
22
  pendingWorkingMessage?: string;
23
+ clearBlockingError(): void;
23
24
  defaultWorkingMessage: string;
24
25
  streamingComponent?: any;
25
26
  streamingMessage?: any;
@@ -37,4 +38,3 @@ export interface InteractiveModeStateHost {
37
38
  }
38
39
 
39
40
  export type InteractiveModeEvent = AgentSessionEvent;
40
-
@@ -64,6 +64,7 @@ import { getChangelogPath, getNewEntries, parseChangelog } from "../../utils/cha
64
64
  import { readClipboardImage } from "../../utils/clipboard-image.js";
65
65
  import { ensureTool } from "../../utils/tools-manager.js";
66
66
  import { AssistantMessageComponent } from "./components/assistant-message.js";
67
+ import { AdaptiveLayoutComponent } from "./components/adaptive-layout.js";
67
68
  import { BashExecutionComponent } from "./components/bash-execution.js";
68
69
  import { BorderedLoader } from "./components/bordered-loader.js";
69
70
  import { BranchSummaryMessageComponent } from "./components/branch-summary-message.js";
@@ -246,6 +247,7 @@ export class InteractiveMode {
246
247
  private ui: TUI;
247
248
  private chatContainer: Container;
248
249
  private pendingMessagesContainer: Container;
250
+ private adaptiveLayout: AdaptiveLayoutComponent;
249
251
  private statusContainer: Container;
250
252
  private pinnedMessageContainer: Container;
251
253
  private defaultEditor: CustomEditor;
@@ -261,6 +263,7 @@ export class InteractiveMode {
261
263
  private loadingAnimation: Loader | undefined = undefined;
262
264
  private pendingWorkingMessage: string | undefined = undefined;
263
265
  private readonly defaultWorkingMessage = "Working...";
266
+ private lastBlockingError: string | undefined = undefined;
264
267
 
265
268
  private lastSigintTime = 0;
266
269
  private lastEscapeTime = 0;
@@ -367,6 +370,14 @@ export class InteractiveMode {
367
370
  this.headerContainer = new Container();
368
371
  this.chatContainer = new Container();
369
372
  this.pendingMessagesContainer = new Container();
373
+ this.adaptiveLayout = new AdaptiveLayoutComponent(() => ({
374
+ override: this.settingsManager.getAdaptiveMode(),
375
+ activeToolCount: this.pendingTools.size,
376
+ gsdPhase: this.pendingWorkingMessage,
377
+ lastError: this.lastBlockingError,
378
+ sessionName: this.sessionManager.getSessionName(),
379
+ cwd: process.cwd(),
380
+ }));
370
381
  this.statusContainer = new Container();
371
382
  this.pinnedMessageContainer = new Container();
372
383
  this.widgetContainerAbove = new Container();
@@ -571,6 +582,7 @@ export class InteractiveMode {
571
582
  }
572
583
  }
573
584
 
585
+ this.ui.addChild(this.adaptiveLayout);
574
586
  this.ui.addChild(this.chatContainer);
575
587
  this.ui.addChild(this.pendingMessagesContainer);
576
588
  this.ui.addChild(this.statusContainer);
@@ -1221,6 +1233,7 @@ export class InteractiveMode {
1221
1233
  this.streamingComponent = undefined;
1222
1234
  this.streamingMessage = undefined;
1223
1235
  this.pendingTools.clear();
1236
+ this.clearBlockingError();
1224
1237
 
1225
1238
  // Render any messages added via setup, or show empty session
1226
1239
  this.renderInitialMessages();
@@ -2880,11 +2893,16 @@ export class InteractiveMode {
2880
2893
  }
2881
2894
 
2882
2895
  showError(errorMessage: string): void {
2896
+ this.lastBlockingError = errorMessage;
2883
2897
  this.chatContainer.addChild(new Spacer(1));
2884
2898
  this.chatContainer.addChild(new Text(theme.fg("error", `Error: ${errorMessage}`), 1, 0));
2885
2899
  this.ui.requestRender();
2886
2900
  }
2887
2901
 
2902
+ clearBlockingError(): void {
2903
+ this.lastBlockingError = undefined;
2904
+ }
2905
+
2888
2906
  showWarning(warningMessage: string): void {
2889
2907
  this.chatContainer.addChild(new Spacer(1));
2890
2908
  this.chatContainer.addChild(new Text(theme.fg("warning", `Warning: ${warningMessage}`), 1, 0));
@@ -3195,6 +3213,7 @@ export class InteractiveMode {
3195
3213
  quietStartup: this.settingsManager.getQuietStartup(),
3196
3214
  clearOnShrink: this.settingsManager.getClearOnShrink(),
3197
3215
  timestampFormat: this.settingsManager.getTimestampFormat(),
3216
+ adaptiveMode: this.settingsManager.getAdaptiveMode(),
3198
3217
  },
3199
3218
  {
3200
3219
  onAutoCompactChange: (enabled) => {
@@ -3301,6 +3320,10 @@ export class InteractiveMode {
3301
3320
  onTimestampFormatChange: (format) => {
3302
3321
  this.settingsManager.setTimestampFormat(format);
3303
3322
  },
3323
+ onAdaptiveModeChange: (mode) => {
3324
+ this.settingsManager.setAdaptiveMode(mode);
3325
+ this.ui.requestRender();
3326
+ },
3304
3327
  onCancel: () => {
3305
3328
  done();
3306
3329
  this.ui.requestRender();
@@ -3689,6 +3712,7 @@ export class InteractiveMode {
3689
3712
  this.streamingComponent = undefined;
3690
3713
  this.streamingMessage = undefined;
3691
3714
  this.pendingTools.clear();
3715
+ this.clearBlockingError();
3692
3716
 
3693
3717
  // Switch session via AgentSession (emits extension session events)
3694
3718
  await this.session.switchSession(sessionPath);
@@ -4010,6 +4034,7 @@ export class InteractiveMode {
4010
4034
  this.streamingMessage = undefined;
4011
4035
  this.pendingTools.clear();
4012
4036
  this.pendingImages.length = 0;
4037
+ this.clearBlockingError();
4013
4038
 
4014
4039
  // Reset contextual tips for the new session
4015
4040
  this.contextualTips.reset();
@@ -0,0 +1,95 @@
1
+ // GSD2 - Slash command tests for interactive TUI settings commands
2
+
3
+ import assert from "node:assert/strict";
4
+ import { describe, it } from "node:test";
5
+ import { Container } from "@gsd/pi-tui";
6
+ import { SettingsManager } from "../../core/settings-manager.js";
7
+ import { dispatchSlashCommand, type SlashCommandContext } from "./slash-command-handlers.js";
8
+
9
+ function makeContext(settingsManager = SettingsManager.inMemory()): SlashCommandContext {
10
+ const statuses: string[] = [];
11
+ const warnings: string[] = [];
12
+ const renders: string[] = [];
13
+ return {
14
+ session: {} as never,
15
+ ui: {} as never,
16
+ keybindings: {} as never,
17
+ chatContainer: new Container(),
18
+ statusContainer: new Container(),
19
+ editorContainer: new Container(),
20
+ headerContainer: new Container(),
21
+ pendingMessagesContainer: new Container(),
22
+ editor: {} as never,
23
+ defaultEditor: {} as never,
24
+ sessionManager: {} as never,
25
+ settingsManager,
26
+ invalidateFooter() {},
27
+ showStatus(message: string) {
28
+ statuses.push(message);
29
+ },
30
+ showError(message: string) {
31
+ throw new Error(message);
32
+ },
33
+ showWarning(message: string) {
34
+ warnings.push(message);
35
+ },
36
+ showSelector() {},
37
+ updateEditorBorderColor() {},
38
+ getMarkdownThemeWithSettings: () => ({} as never),
39
+ requestRender() {
40
+ renders.push("render");
41
+ },
42
+ updateTerminalTitle() {},
43
+ showSettingsSelector() {},
44
+ showModelsSelector: async () => {},
45
+ handleModelCommand: async () => {},
46
+ showUserMessageSelector() {},
47
+ showTreeSelector() {},
48
+ showProviderManager() {},
49
+ showOAuthSelector: async () => {},
50
+ showSessionSelector() {},
51
+ handleClearCommand: async () => {},
52
+ handleReloadCommand: async () => {},
53
+ handleDebugCommand() {},
54
+ shutdown: async () => {},
55
+ executeCompaction: async () => undefined,
56
+ handleBashCommand: async () => {},
57
+ _testStatuses: statuses,
58
+ _testWarnings: warnings,
59
+ _testRenders: renders,
60
+ } as SlashCommandContext & {
61
+ _testStatuses: string[];
62
+ _testWarnings: string[];
63
+ _testRenders: string[];
64
+ };
65
+ }
66
+
67
+ describe("dispatchSlashCommand /tui", () => {
68
+ it("persists /tui mode validation to terminal adaptive mode", async () => {
69
+ const settingsManager = SettingsManager.inMemory();
70
+ const ctx = makeContext(settingsManager) as SlashCommandContext & {
71
+ _testStatuses: string[];
72
+ _testRenders: string[];
73
+ };
74
+
75
+ const handled = await dispatchSlashCommand("/tui mode validation", ctx);
76
+
77
+ assert.equal(handled, true);
78
+ assert.equal(settingsManager.getAdaptiveMode(), "validation");
79
+ assert.deepEqual(ctx._testStatuses, ["TUI mode: validation"]);
80
+ assert.equal(ctx._testRenders.length, 1);
81
+ });
82
+
83
+ it("rejects unknown TUI modes without changing settings", async () => {
84
+ const settingsManager = SettingsManager.inMemory({ terminal: { adaptiveMode: "workflow" } });
85
+ const ctx = makeContext(settingsManager) as SlashCommandContext & {
86
+ _testWarnings: string[];
87
+ };
88
+
89
+ const handled = await dispatchSlashCommand("/tui mode poster", ctx);
90
+
91
+ assert.equal(handled, true);
92
+ assert.equal(settingsManager.getAdaptiveMode(), "workflow");
93
+ assert.match(ctx._testWarnings[0], /Usage: \/tui mode/);
94
+ });
95
+ });
@@ -31,7 +31,7 @@ import {
31
31
  import type { AgentSession } from "../../core/agent-session.js";
32
32
  import type { AppAction, KeybindingsManager } from "../../core/keybindings.js";
33
33
  import type { SessionManager } from "../../core/session-manager.js";
34
- import type { SettingsManager } from "../../core/settings-manager.js";
34
+ import type { AdaptiveTuiMode, SettingsManager } from "../../core/settings-manager.js";
35
35
  import { copyToClipboard } from "../../utils/clipboard.js";
36
36
  import { getChangelogPath, parseChangelog } from "../../utils/changelog.js";
37
37
  import { ArminComponent } from "./components/armin.js";
@@ -235,6 +235,10 @@ export async function dispatchSlashCommand(
235
235
  await ctx.handleBashCommand(command, { loginShell: true });
236
236
  return true;
237
237
  }
238
+ if (text === "/tui" || text.startsWith("/tui ")) {
239
+ handleTuiCommand(text, ctx);
240
+ return true;
241
+ }
238
242
 
239
243
  return false;
240
244
  }
@@ -665,6 +669,25 @@ function handleEditModeCommand(arg: string | undefined, ctx: SlashCommandContext
665
669
  ctx.showStatus(`Edit mode: ${next}${next === "hashline" ? " (LINE#ID anchored edits)" : " (text-match edits)"}`);
666
670
  }
667
671
 
672
+ function handleTuiCommand(text: string, ctx: SlashCommandContext): void {
673
+ const parts = text.trim().split(/\s+/);
674
+ const mode = parts[1] === "mode" ? parts[2] : parts[1];
675
+ const valid: AdaptiveTuiMode[] = ["auto", "chat", "workflow", "validation", "debug", "compact"];
676
+
677
+ if (!mode) {
678
+ ctx.showStatus(`TUI mode: ${ctx.settingsManager.getAdaptiveMode()}`);
679
+ return;
680
+ }
681
+ if (!valid.includes(mode as AdaptiveTuiMode)) {
682
+ ctx.showWarning(`Usage: /tui mode ${valid.join("|")}`);
683
+ return;
684
+ }
685
+
686
+ ctx.settingsManager.setAdaptiveMode(mode as AdaptiveTuiMode);
687
+ ctx.showStatus(`TUI mode: ${mode}`);
688
+ ctx.requestRender();
689
+ }
690
+
668
691
  function handleArminSaysHi(ctx: SlashCommandContext): void {
669
692
  ctx.chatContainer.addChild(new Spacer(1));
670
693
  ctx.chatContainer.addChild(new ArminComponent(ctx.ui));
@@ -70,6 +70,19 @@ export const ThemeJsonSchema = Type.Object({
70
70
  thinkingXhigh: ColorValueSchema,
71
71
  // Bash Mode (1 color)
72
72
  bashMode: ColorValueSchema,
73
+ // Adaptive TUI semantic tokens (optional; defaults are derived from core colors)
74
+ surfaceBorder: Type.Optional(ColorValueSchema),
75
+ surfaceMuted: Type.Optional(ColorValueSchema),
76
+ surfaceTitle: Type.Optional(ColorValueSchema),
77
+ surfaceAccent: Type.Optional(ColorValueSchema),
78
+ toolRunning: Type.Optional(ColorValueSchema),
79
+ toolSuccess: Type.Optional(ColorValueSchema),
80
+ toolError: Type.Optional(ColorValueSchema),
81
+ toolMuted: Type.Optional(ColorValueSchema),
82
+ modeWorkflow: Type.Optional(ColorValueSchema),
83
+ modeValidation: Type.Optional(ColorValueSchema),
84
+ modeDebug: Type.Optional(ColorValueSchema),
85
+ modeCompact: Type.Optional(ColorValueSchema),
73
86
  }),
74
87
  export: Type.Optional(
75
88
  Type.Object({
@@ -69,7 +69,19 @@ export type ThemeColor =
69
69
  | "thinkingMedium"
70
70
  | "thinkingHigh"
71
71
  | "thinkingXhigh"
72
- | "bashMode";
72
+ | "bashMode"
73
+ | "surfaceBorder"
74
+ | "surfaceMuted"
75
+ | "surfaceTitle"
76
+ | "surfaceAccent"
77
+ | "toolRunning"
78
+ | "toolSuccess"
79
+ | "toolError"
80
+ | "toolMuted"
81
+ | "modeWorkflow"
82
+ | "modeValidation"
83
+ | "modeDebug"
84
+ | "modeCompact";
73
85
 
74
86
  export type ThemeBg =
75
87
  | "selectedBg"
@@ -374,6 +386,24 @@ function getBuiltinThemes(): Record<string, ThemeJson> {
374
386
  return builtinThemes;
375
387
  }
376
388
 
389
+ function withSemanticColorDefaults(colors: ThemeJson["colors"]): ThemeJson["colors"] {
390
+ return {
391
+ ...colors,
392
+ surfaceBorder: colors.surfaceBorder ?? colors.border,
393
+ surfaceMuted: colors.surfaceMuted ?? colors.borderMuted,
394
+ surfaceTitle: colors.surfaceTitle ?? colors.toolTitle,
395
+ surfaceAccent: colors.surfaceAccent ?? colors.borderAccent,
396
+ toolRunning: colors.toolRunning ?? colors.warning,
397
+ toolSuccess: colors.toolSuccess ?? colors.success,
398
+ toolError: colors.toolError ?? colors.error,
399
+ toolMuted: colors.toolMuted ?? colors.muted,
400
+ modeWorkflow: colors.modeWorkflow ?? colors.accent,
401
+ modeValidation: colors.modeValidation ?? colors.warning,
402
+ modeDebug: colors.modeDebug ?? colors.error,
403
+ modeCompact: colors.modeCompact ?? colors.muted,
404
+ };
405
+ }
406
+
377
407
  export function getAvailableThemes(): string[] {
378
408
  const themes = new Set<string>(Object.keys(getBuiltinThemes()));
379
409
  const customThemesDir = getCustomThemesDir();
@@ -493,7 +523,7 @@ function loadThemeJson(name: string): ThemeJson {
493
523
 
494
524
  function createTheme(themeJson: ThemeJson, mode?: ColorMode, sourcePath?: string): Theme {
495
525
  const colorMode = mode ?? detectColorMode();
496
- const resolvedColors = resolveThemeColors(themeJson.colors, themeJson.vars);
526
+ const resolvedColors = resolveThemeColors(withSemanticColorDefaults(themeJson.colors), themeJson.vars);
497
527
  const fgColors: Record<ThemeColor, string | number> = {} as Record<ThemeColor, string | number>;
498
528
  const bgColors: Record<ThemeBg, string | number> = {} as Record<ThemeBg, string | number>;
499
529
  const bgColorKeys: Set<string> = new Set([
@@ -1,3 +1,4 @@
1
+ // GSD2 TUI - Built-in terminal theme definitions.
1
2
  /**
2
3
  * Built-in theme definitions.
3
4
  *
@@ -18,27 +19,30 @@ import type { ThemeJson } from "./theme-schema.js";
18
19
  const dark: ThemeJson = {
19
20
  name: "dark",
20
21
  vars: {
21
- cyan: "#22d3ee",
22
- blue: "#60a5fa",
23
- green: "#34d399",
24
- red: "#fb7185",
25
- yellow: "#facc15",
26
- gray: "#a1a1aa",
27
- dimGray: "#8b93a7",
28
- darkGray: "#4b5563",
29
- accent: "#2dd4bf",
30
- selectedBg: "#1f2a44",
31
- userMsgBg: "#1e2535",
32
- toolPendingBg: "#1f2330",
33
- toolSuccessBg: "#1f3128",
34
- toolErrorBg: "#3a202a",
35
- customMsgBg: "#2a2140",
22
+ cyan: "#5cc8c8",
23
+ blue: "#79b8ff",
24
+ green: "#7ad38b",
25
+ red: "#f27b7b",
26
+ yellow: "#d6b85f",
27
+ gray: "#87949b",
28
+ dimGray: "#657178",
29
+ darkGray: "#303a40",
30
+ line: "#52616a",
31
+ lineSoft: "#303a40",
32
+ textSoft: "#cbd6dc",
33
+ accent: "#5cc8c8",
34
+ selectedBg: "#1d282a",
35
+ userMsgBg: "#202a2f",
36
+ toolPendingBg: "#252721",
37
+ toolSuccessBg: "#1c251f",
38
+ toolErrorBg: "#251e20",
39
+ customMsgBg: "#202a2f",
36
40
  },
37
41
  colors: {
38
42
  accent: "accent",
39
- border: "blue",
40
- borderAccent: "cyan",
41
- borderMuted: "darkGray",
43
+ border: "line",
44
+ borderAccent: "accent",
45
+ borderMuted: "lineSoft",
42
46
  success: "green",
43
47
  error: "red",
44
48
  warning: "yellow",
@@ -49,16 +53,21 @@ const dark: ThemeJson = {
49
53
 
50
54
  selectedBg: "selectedBg",
51
55
  userMessageBg: "userMsgBg",
52
- userMessageText: "gray",
53
- assistantMessageText: "",
56
+ userMessageText: "textSoft",
57
+ assistantMessageText: "textSoft",
54
58
  customMessageBg: "customMsgBg",
55
- customMessageText: "",
56
- customMessageLabel: "#c084fc",
59
+ customMessageText: "textSoft",
60
+ customMessageLabel: "blue",
57
61
  toolPendingBg: "toolPendingBg",
58
62
  toolSuccessBg: "toolSuccessBg",
59
63
  toolErrorBg: "toolErrorBg",
60
- toolTitle: "#8a8a8a",
61
- toolOutput: "#6e6e6e",
64
+ toolTitle: "gray",
65
+ toolOutput: "textSoft",
66
+ surfaceTitle: "accent",
67
+ surfaceAccent: "accent",
68
+ toolRunning: "yellow",
69
+ toolSuccess: "green",
70
+ toolError: "red",
62
71
 
63
72
  mdHeading: "#fbbf24",
64
73
  mdLink: "#93c5fd",
@@ -95,9 +104,9 @@ const dark: ThemeJson = {
95
104
  bashMode: "green",
96
105
  },
97
106
  export: {
98
- pageBg: "#101522",
99
- cardBg: "#171f33",
100
- infoBg: "#3b321d",
107
+ pageBg: "#111416",
108
+ cardBg: "#1e2529",
109
+ infoBg: "#252721",
101
110
  },
102
111
  };
103
112
 
@@ -0,0 +1,65 @@
1
+ // GSD2 - Tests for adaptive TUI mode selection
2
+
3
+ import assert from "node:assert/strict";
4
+ import { describe, test } from "node:test";
5
+ import stripAnsi from "strip-ansi";
6
+
7
+ import { AdaptiveLayoutComponent } from "./components/adaptive-layout.js";
8
+ import { initTheme } from "./theme/theme.js";
9
+ import { resolveTuiMode } from "./tui-mode.js";
10
+
11
+ initTheme("dark", false);
12
+
13
+ describe("resolveTuiMode", () => {
14
+ test("explicit overrides beat auto selection", () => {
15
+ assert.equal(
16
+ resolveTuiMode({ terminalWidth: 60, override: "debug", gsdPhase: "validating-milestone" }),
17
+ "debug",
18
+ );
19
+ });
20
+
21
+ test("prioritizes compact layouts on narrow terminals", () => {
22
+ assert.equal(
23
+ resolveTuiMode({ terminalWidth: 60, override: "auto", hasBlockingError: true, gsdPhase: "validating-milestone" }),
24
+ "compact",
25
+ );
26
+ });
27
+
28
+ test("uses debug mode for blocking errors on roomy terminals", () => {
29
+ assert.equal(resolveTuiMode({ terminalWidth: 100, hasBlockingError: true }), "debug");
30
+ });
31
+
32
+ test("uses validation mode for validation and completion phases", () => {
33
+ assert.equal(resolveTuiMode({ terminalWidth: 100, gsdPhase: "validating-milestone" }), "validation");
34
+ assert.equal(resolveTuiMode({ terminalWidth: 100, gsdPhase: "complete-milestone" }), "validation");
35
+ });
36
+
37
+ test("uses workflow mode when tools or non-validation phases are active", () => {
38
+ assert.equal(resolveTuiMode({ terminalWidth: 100, activeToolCount: 1 }), "workflow");
39
+ assert.equal(resolveTuiMode({ terminalWidth: 100, gsdPhase: "execute-phase" }), "workflow");
40
+ });
41
+
42
+ test("falls back to chat mode for plain conversation", () => {
43
+ assert.equal(resolveTuiMode({ terminalWidth: 100 }), "chat");
44
+ });
45
+ });
46
+
47
+ describe("AdaptiveLayoutComponent", () => {
48
+ test("renders workflow layout with prototype rule frames", () => {
49
+ const layout = new AdaptiveLayoutComponent(() => ({
50
+ override: "workflow",
51
+ activeToolCount: 2,
52
+ gsdPhase: "execute-task",
53
+ sessionName: "main",
54
+ cwd: "/Users/example/project",
55
+ }));
56
+
57
+ const plain = layout.render(120).map(stripAnsi);
58
+
59
+ assert.match(plain[0], /^─+/, "workflow layout should start with a rule frame");
60
+ assert.ok(plain.some((line) => line.includes("GSD Command Center")), "workflow title should render");
61
+ assert.ok(plain.some((line) => line.includes("signals")), "inspector title should render");
62
+ assert.ok(plain.some((line) => line.includes("│ Active")), "body rows should keep prototype gutter");
63
+ assert.ok(!plain.some((line) => /[╭╮╰╯]/.test(line)), "workflow layout should not use rounded box corners");
64
+ });
65
+ });
@@ -0,0 +1,29 @@
1
+ // GSD2 - Adaptive mode selection for the interactive terminal UI
2
+
3
+ export type TuiMode = "chat" | "workflow" | "validation" | "debug" | "compact";
4
+ export type TuiAdaptiveMode = "auto" | TuiMode;
5
+
6
+ export interface TuiModeContext {
7
+ terminalWidth: number;
8
+ override?: TuiAdaptiveMode;
9
+ gsdPhase?: string;
10
+ activeToolCount?: number;
11
+ hasBlockingError?: boolean;
12
+ }
13
+
14
+ export function resolveTuiMode(context: TuiModeContext): TuiMode {
15
+ if (context.override && context.override !== "auto") return context.override;
16
+ if (context.terminalWidth < 72) return "compact";
17
+ if (context.hasBlockingError) return "debug";
18
+
19
+ const phase = context.gsdPhase?.toLowerCase() ?? "";
20
+ if (phase.includes("validat") || phase.includes("complete") || phase.includes("review")) {
21
+ return "validation";
22
+ }
23
+
24
+ if ((context.activeToolCount ?? 0) > 0 || phase.length > 0) {
25
+ return "workflow";
26
+ }
27
+
28
+ return "chat";
29
+ }