gsd-pi 2.80.0-dev.8b3a59f5c → 2.80.0-dev.b2a374d5b

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 (222) 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/gsd/auto/loop.js +32 -1
  4. package/dist/resources/extensions/gsd/auto/phases.js +37 -30
  5. package/dist/resources/extensions/gsd/auto-dispatch.js +10 -0
  6. package/dist/resources/extensions/gsd/auto-post-unit.js +10 -10
  7. package/dist/resources/extensions/gsd/auto-prompts.js +111 -1
  8. package/dist/resources/extensions/gsd/auto-start.js +2 -3
  9. package/dist/resources/extensions/gsd/auto.js +16 -3
  10. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +21 -0
  11. package/dist/resources/extensions/gsd/clean-root-preflight.js +42 -4
  12. package/dist/resources/extensions/gsd/commands/dispatcher.js +5 -0
  13. package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
  14. package/dist/resources/extensions/gsd/detection.js +106 -0
  15. package/dist/resources/extensions/gsd/guided-flow.js +63 -12
  16. package/dist/resources/extensions/gsd/migrate/command.js +40 -1
  17. package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
  18. package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
  19. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +7 -8
  20. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  21. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
  22. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  23. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
  24. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  25. package/dist/resources/extensions/gsd/quick.js +34 -2
  26. package/dist/resources/extensions/gsd/safety/evidence-collector.js +10 -2
  27. package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
  28. package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
  29. package/dist/resources/extensions/gsd/unit-runtime.js +11 -0
  30. package/dist/resources/extensions/gsd/worktree-manager.js +16 -14
  31. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  32. package/dist/web/standalone/.next/BUILD_ID +1 -1
  33. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  34. package/dist/web/standalone/.next/build-manifest.json +2 -2
  35. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  36. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  37. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  41. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  42. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  44. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  45. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  47. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  52. package/dist/web/standalone/.next/server/app/index.html +1 -1
  53. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  55. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  56. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  57. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  60. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  61. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  62. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  63. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  64. package/package.json +4 -2
  65. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  66. package/packages/pi-coding-agent/dist/core/agent-session.js +3 -0
  67. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  68. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +32 -0
  69. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  70. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
  71. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  72. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
  73. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  74. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
  75. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
  76. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
  77. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
  78. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
  79. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
  80. package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
  81. package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
  82. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
  83. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
  84. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
  85. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
  86. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +3 -0
  87. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  88. package/packages/pi-coding-agent/dist/core/extensions/runner.js +17 -1
  89. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  90. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +99 -0
  91. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  92. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +7 -0
  93. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  94. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  95. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
  96. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  97. package/packages/pi-coding-agent/dist/core/settings-manager.js +25 -0
  98. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  99. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js +6 -4
  100. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js.map +1 -1
  101. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +25 -20
  102. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  103. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +2 -2
  104. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -1
  105. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  106. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  107. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  108. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +2 -1
  109. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  110. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +7 -6
  111. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
  112. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  113. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  114. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +26 -13
  115. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  116. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  117. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +15 -5
  118. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  119. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +53 -0
  120. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  121. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  122. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +3 -0
  123. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  124. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  125. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +36 -27
  126. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  127. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +21 -0
  128. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -1
  129. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
  130. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
  131. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +10 -0
  132. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
  133. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
  134. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
  135. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
  136. package/packages/pi-coding-agent/src/core/agent-session.ts +3 -0
  137. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +38 -0
  138. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
  139. package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
  140. package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
  141. package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
  142. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +110 -0
  143. package/packages/pi-coding-agent/src/core/extensions/runner.ts +19 -1
  144. package/packages/pi-coding-agent/src/core/extensions/types.ts +7 -0
  145. package/packages/pi-coding-agent/src/core/settings-manager.ts +39 -1
  146. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.ts +7 -5
  147. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +25 -20
  148. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +2 -2
  149. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +1 -0
  150. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +2 -1
  151. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +10 -9
  152. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +33 -13
  153. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +56 -0
  154. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +24 -7
  155. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +3 -0
  156. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +36 -27
  157. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +25 -0
  158. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +14 -0
  159. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
  160. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  161. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  162. package/packages/pi-tui/dist/tui.js +17 -7
  163. package/packages/pi-tui/dist/tui.js.map +1 -1
  164. package/packages/pi-tui/src/tui.ts +19 -7
  165. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  166. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  167. package/pkg/dist/modes/interactive/theme/themes.js +36 -27
  168. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  169. package/src/resources/GSD-WORKFLOW.md +2 -2
  170. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
  171. package/src/resources/extensions/gsd/auto/loop.ts +50 -8
  172. package/src/resources/extensions/gsd/auto/phases.ts +42 -28
  173. package/src/resources/extensions/gsd/auto-dispatch.ts +17 -0
  174. package/src/resources/extensions/gsd/auto-post-unit.ts +10 -10
  175. package/src/resources/extensions/gsd/auto-prompts.ts +116 -1
  176. package/src/resources/extensions/gsd/auto-start.ts +7 -6
  177. package/src/resources/extensions/gsd/auto.ts +23 -3
  178. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +22 -0
  179. package/src/resources/extensions/gsd/clean-root-preflight.ts +41 -3
  180. package/src/resources/extensions/gsd/commands/dispatcher.ts +6 -0
  181. package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
  182. package/src/resources/extensions/gsd/detection.ts +128 -0
  183. package/src/resources/extensions/gsd/guided-flow.ts +66 -12
  184. package/src/resources/extensions/gsd/migrate/command.ts +47 -1
  185. package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
  186. package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
  187. package/src/resources/extensions/gsd/prompts/complete-milestone.md +7 -8
  188. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  189. package/src/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
  190. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  191. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
  192. package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  193. package/src/resources/extensions/gsd/quick.ts +37 -2
  194. package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -2
  195. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +1 -1
  196. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +88 -2
  197. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +55 -0
  198. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
  199. package/src/resources/extensions/gsd/tests/detection.test.ts +140 -0
  200. package/src/resources/extensions/gsd/tests/has-pending-deep-stage.test.ts +33 -1
  201. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
  202. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
  203. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
  204. package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
  205. package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
  206. package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
  207. package/src/resources/extensions/gsd/tests/right-sized-workflow-prompts.test.ts +192 -0
  208. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +29 -0
  209. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +38 -0
  210. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +63 -2
  211. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +9 -0
  212. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +7 -0
  213. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +1 -1
  214. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +37 -6
  215. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +7 -0
  216. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +9 -2
  217. package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
  218. package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
  219. package/src/resources/extensions/gsd/unit-runtime.ts +14 -0
  220. package/src/resources/extensions/gsd/worktree-manager.ts +15 -4
  221. /package/dist/web/standalone/.next/static/{k-MDjzPMF62Rg1-FR437h → FU0iL9dhdc2IBzEYBDOlY}/_buildManifest.js +0 -0
  222. /package/dist/web/standalone/.next/static/{k-MDjzPMF62Rg1-FR437h → FU0iL9dhdc2IBzEYBDOlY}/_ssgManifest.js +0 -0
@@ -80,8 +80,8 @@ export class AdaptiveLayoutComponent {
80
80
  }
81
81
  frame(lines, width, title, rightTitle, accent) {
82
82
  return style()
83
- .border("rounded")
84
- .density("comfortable")
83
+ .border("rule")
84
+ .density("compact")
85
85
  .toneColor((text) => theme.fg("surfaceMuted", text))
86
86
  .borderColor((text) => theme.fg("surfaceBorder", text))
87
87
  .title(theme.fg("surfaceTitle", title))
@@ -1 +1 @@
1
- {"version":3,"file":"adaptive-layout.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/adaptive-layout.ts"],"names":[],"mappings":"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","sourcesContent":["// GSD2 - Adaptive terminal mode dashboard for the interactive TUI\n\nimport { style, truncateToWidth, visibleWidth, type Component } from \"@gsd/pi-tui\";\nimport type { TuiAdaptiveMode, TuiMode } from \"../tui-mode.js\";\nimport { resolveTuiMode } from \"../tui-mode.js\";\nimport { theme, type ThemeColor } from \"../theme/theme.js\";\n\nexport interface AdaptiveLayoutState {\n\toverride: TuiAdaptiveMode;\n\tactiveToolCount: number;\n\tgsdPhase?: string;\n\tlastError?: string;\n\tsessionName?: string;\n\tcwd: string;\n}\n\nexport class AdaptiveLayoutComponent implements Component {\n\tconstructor(private readonly getState: () => AdaptiveLayoutState) {}\n\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\tconst state = this.getState();\n\t\tconst mode = resolveTuiMode({\n\t\t\tterminalWidth: width,\n\t\t\toverride: state.override,\n\t\t\tactiveToolCount: state.activeToolCount,\n\t\t\tgsdPhase: state.gsdPhase,\n\t\t\thasBlockingError: !!state.lastError,\n\t\t});\n\n\t\tif (state.override === \"auto\" && mode === \"chat\" && !state.gsdPhase && !state.lastError && state.activeToolCount === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tif (mode === \"compact\" || width < 72) return this.renderCompact(width, mode, state);\n\t\tif (mode === \"debug\") return this.renderDebug(width, state);\n\t\tif (mode === \"validation\") return this.renderValidation(width, state);\n\t\tif (mode === \"workflow\") return this.renderWorkflow(width, state);\n\t\treturn this.renderChat(width, state);\n\t}\n\n\tprivate renderWorkflow(width: number, state: AdaptiveLayoutState): string[] {\n\t\tif (width < 112) return this.renderCompact(width, \"workflow\", state);\n\n\t\tconst leftWidth = Math.max(44, Math.floor(width * 0.56));\n\t\tconst rightWidth = Math.max(32, width - leftWidth - 2);\n\t\tconst phase = state.gsdPhase ?? \"Ready\";\n\t\tconst left = this.frame(\n\t\t\t[\n\t\t\t\tthis.metric(\"Active\", phase, \"modeWorkflow\"),\n\t\t\t\tthis.metric(\"Tools\", state.activeToolCount > 0 ? `${state.activeToolCount} running` : \"idle\", \"toolRunning\"),\n\t\t\t\tthis.metric(\"Mode\", state.override === \"auto\" ? \"auto workflow\" : state.override, \"modeWorkflow\"),\n\t\t\t],\n\t\t\tleftWidth,\n\t\t\t\"GSD Command Center\",\n\t\t\t\"workflow\",\n\t\t\t\"modeWorkflow\",\n\t\t);\n\t\tconst right = this.frame(\n\t\t\t[\n\t\t\t\t`Session ${state.sessionName ?? \"current\"}`,\n\t\t\t\t`Path ${this.basename(state.cwd)}`,\n\t\t\t\t`Next ${state.activeToolCount > 0 ? \"watch tool output\" : \"continue from prompt\"}`,\n\t\t\t],\n\t\t\trightWidth,\n\t\t\t\"signals\",\n\t\t\t\"inspector\",\n\t\t\t\"surfaceAccent\",\n\t\t);\n\t\treturn this.columns(left, right, leftWidth);\n\t}\n\n\tprivate renderValidation(width: number, state: AdaptiveLayoutState): string[] {\n\t\tconst phase = state.gsdPhase ?? \"Validation pending\";\n\t\treturn this.frame(\n\t\t\t[\n\t\t\t\tthis.metric(\"Focus\", phase, \"modeValidation\"),\n\t\t\t\tthis.metric(\"Checks\", state.activeToolCount > 0 ? `${state.activeToolCount} active` : \"waiting\", \"toolRunning\"),\n\t\t\t\tthis.metric(\"Timeline\", state.lastError ? \"blocked\" : \"ready for completion evidence\", state.lastError ? \"toolError\" : \"toolSuccess\"),\n\t\t\t],\n\t\t\twidth,\n\t\t\t\"validation\",\n\t\t\tstate.override === \"auto\" ? \"auto\" : state.override,\n\t\t\t\"modeValidation\",\n\t\t);\n\t}\n\n\tprivate renderDebug(width: number, state: AdaptiveLayoutState): string[] {\n\t\tconst error = state.lastError ?? \"Blocking error detected\";\n\t\treturn this.frame(\n\t\t\t[\n\t\t\t\tthis.metric(\"Failure\", truncateToWidth(error, Math.max(20, width - 20), \"\"), \"toolError\"),\n\t\t\t\tthis.metric(\"Tools\", state.activeToolCount > 0 ? `${state.activeToolCount} still running` : \"none running\", \"toolRunning\"),\n\t\t\t\tthis.metric(\"Next\", \"inspect the failed output, then retry the smallest step\", \"modeDebug\"),\n\t\t\t],\n\t\t\twidth,\n\t\t\t\"blocking failure\",\n\t\t\t\"debug\",\n\t\t\t\"modeDebug\",\n\t\t);\n\t}\n\n\tprivate renderChat(width: number, state: AdaptiveLayoutState): string[] {\n\t\treturn this.frame(\n\t\t\t[\n\t\t\t\tthis.metric(\"Mode\", state.override === \"auto\" ? \"auto chat\" : state.override, \"surfaceAccent\"),\n\t\t\t\tthis.metric(\"Tools\", state.activeToolCount > 0 ? `${state.activeToolCount} active` : \"compact rows\", \"toolMuted\"),\n\t\t\t],\n\t\t\twidth,\n\t\t\t\"chat\",\n\t\t\tstate.sessionName ?? \"conversation\",\n\t\t\t\"surfaceAccent\",\n\t\t);\n\t}\n\n\tprivate renderCompact(width: number, mode: TuiMode, state: AdaptiveLayoutState): string[] {\n\t\tconst phase = state.lastError ?? state.gsdPhase ?? (state.activeToolCount > 0 ? `${state.activeToolCount} tools` : \"ready\");\n\t\tconst line = `${theme.fg(\"modeCompact\", \"GSD compact\")} ${theme.fg(\"surfaceMuted\", `${mode} · ${phase}`)}`;\n\t\treturn style()\n\t\t\t.border(\"minimal\")\n\t\t\t.borderColor((text) => theme.fg(\"surfaceBorder\", text))\n\t\t\t.bodyGutter(\" \")\n\t\t\t.render([line], width);\n\t}\n\n\tprivate frame(lines: string[], width: number, title: string, rightTitle: string, accent: ThemeColor): string[] {\n\t\treturn style()\n\t\t\t.border(\"rounded\")\n\t\t\t.density(\"comfortable\")\n\t\t\t.toneColor((text) => theme.fg(\"surfaceMuted\", text))\n\t\t\t.borderColor((text) => theme.fg(\"surfaceBorder\", text))\n\t\t\t.title(theme.fg(\"surfaceTitle\", title))\n\t\t\t.rightTitle(theme.fg(accent, rightTitle))\n\t\t\t.bodyGutter(theme.fg(accent, \"│ \"))\n\t\t\t.render(lines, width);\n\t}\n\n\tprivate metric(label: string, value: string, color: ThemeColor): string {\n\t\treturn `${theme.fg(\"surfaceMuted\", `${label.padEnd(8)} `)}${theme.fg(color, value)}`;\n\t}\n\n\tprivate columns(left: string[], right: string[], leftWidth: number): string[] {\n\t\tconst rows = Math.max(left.length, right.length);\n\t\tconst output: string[] = [];\n\t\tfor (let i = 0; i < rows; i++) {\n\t\t\tconst leftLine = left[i] ?? \"\";\n\t\t\tconst rightLine = right[i] ?? \"\";\n\t\t\tconst gap = \" \".repeat(Math.max(2, leftWidth - visibleWidth(leftLine) + 2));\n\t\t\toutput.push(`${leftLine}${gap}${rightLine}`);\n\t\t}\n\t\treturn output;\n\t}\n\n\tprivate basename(cwd: string): string {\n\t\tconst trimmed = cwd.replace(/\\/+$/, \"\");\n\t\tconst slash = trimmed.lastIndexOf(\"/\");\n\t\treturn slash === -1 ? trimmed : trimmed.slice(slash + 1);\n\t}\n}\n"]}
1
+ {"version":3,"file":"adaptive-layout.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/adaptive-layout.ts"],"names":[],"mappings":"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","sourcesContent":["// GSD2 - Adaptive terminal mode dashboard for the interactive TUI\n\nimport { style, truncateToWidth, visibleWidth, type Component } from \"@gsd/pi-tui\";\nimport type { TuiAdaptiveMode, TuiMode } from \"../tui-mode.js\";\nimport { resolveTuiMode } from \"../tui-mode.js\";\nimport { theme, type ThemeColor } from \"../theme/theme.js\";\n\nexport interface AdaptiveLayoutState {\n\toverride: TuiAdaptiveMode;\n\tactiveToolCount: number;\n\tgsdPhase?: string;\n\tlastError?: string;\n\tsessionName?: string;\n\tcwd: string;\n}\n\nexport class AdaptiveLayoutComponent implements Component {\n\tconstructor(private readonly getState: () => AdaptiveLayoutState) {}\n\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\tconst state = this.getState();\n\t\tconst mode = resolveTuiMode({\n\t\t\tterminalWidth: width,\n\t\t\toverride: state.override,\n\t\t\tactiveToolCount: state.activeToolCount,\n\t\t\tgsdPhase: state.gsdPhase,\n\t\t\thasBlockingError: !!state.lastError,\n\t\t});\n\n\t\tif (state.override === \"auto\" && mode === \"chat\" && !state.gsdPhase && !state.lastError && state.activeToolCount === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tif (mode === \"compact\" || width < 72) return this.renderCompact(width, mode, state);\n\t\tif (mode === \"debug\") return this.renderDebug(width, state);\n\t\tif (mode === \"validation\") return this.renderValidation(width, state);\n\t\tif (mode === \"workflow\") return this.renderWorkflow(width, state);\n\t\treturn this.renderChat(width, state);\n\t}\n\n\tprivate renderWorkflow(width: number, state: AdaptiveLayoutState): string[] {\n\t\tif (width < 112) return this.renderCompact(width, \"workflow\", state);\n\n\t\tconst leftWidth = Math.max(44, Math.floor(width * 0.56));\n\t\tconst rightWidth = Math.max(32, width - leftWidth - 2);\n\t\tconst phase = state.gsdPhase ?? \"Ready\";\n\t\tconst left = this.frame(\n\t\t\t[\n\t\t\t\tthis.metric(\"Active\", phase, \"modeWorkflow\"),\n\t\t\t\tthis.metric(\"Tools\", state.activeToolCount > 0 ? `${state.activeToolCount} running` : \"idle\", \"toolRunning\"),\n\t\t\t\tthis.metric(\"Mode\", state.override === \"auto\" ? \"auto workflow\" : state.override, \"modeWorkflow\"),\n\t\t\t],\n\t\t\tleftWidth,\n\t\t\t\"GSD Command Center\",\n\t\t\t\"workflow\",\n\t\t\t\"modeWorkflow\",\n\t\t);\n\t\tconst right = this.frame(\n\t\t\t[\n\t\t\t\t`Session ${state.sessionName ?? \"current\"}`,\n\t\t\t\t`Path ${this.basename(state.cwd)}`,\n\t\t\t\t`Next ${state.activeToolCount > 0 ? \"watch tool output\" : \"continue from prompt\"}`,\n\t\t\t],\n\t\t\trightWidth,\n\t\t\t\"signals\",\n\t\t\t\"inspector\",\n\t\t\t\"surfaceAccent\",\n\t\t);\n\t\treturn this.columns(left, right, leftWidth);\n\t}\n\n\tprivate renderValidation(width: number, state: AdaptiveLayoutState): string[] {\n\t\tconst phase = state.gsdPhase ?? \"Validation pending\";\n\t\treturn this.frame(\n\t\t\t[\n\t\t\t\tthis.metric(\"Focus\", phase, \"modeValidation\"),\n\t\t\t\tthis.metric(\"Checks\", state.activeToolCount > 0 ? `${state.activeToolCount} active` : \"waiting\", \"toolRunning\"),\n\t\t\t\tthis.metric(\"Timeline\", state.lastError ? \"blocked\" : \"ready for completion evidence\", state.lastError ? \"toolError\" : \"toolSuccess\"),\n\t\t\t],\n\t\t\twidth,\n\t\t\t\"validation\",\n\t\t\tstate.override === \"auto\" ? \"auto\" : state.override,\n\t\t\t\"modeValidation\",\n\t\t);\n\t}\n\n\tprivate renderDebug(width: number, state: AdaptiveLayoutState): string[] {\n\t\tconst error = state.lastError ?? \"Blocking error detected\";\n\t\treturn this.frame(\n\t\t\t[\n\t\t\t\tthis.metric(\"Failure\", truncateToWidth(error, Math.max(20, width - 20), \"\"), \"toolError\"),\n\t\t\t\tthis.metric(\"Tools\", state.activeToolCount > 0 ? `${state.activeToolCount} still running` : \"none running\", \"toolRunning\"),\n\t\t\t\tthis.metric(\"Next\", \"inspect the failed output, then retry the smallest step\", \"modeDebug\"),\n\t\t\t],\n\t\t\twidth,\n\t\t\t\"blocking failure\",\n\t\t\t\"debug\",\n\t\t\t\"modeDebug\",\n\t\t);\n\t}\n\n\tprivate renderChat(width: number, state: AdaptiveLayoutState): string[] {\n\t\treturn this.frame(\n\t\t\t[\n\t\t\t\tthis.metric(\"Mode\", state.override === \"auto\" ? \"auto chat\" : state.override, \"surfaceAccent\"),\n\t\t\t\tthis.metric(\"Tools\", state.activeToolCount > 0 ? `${state.activeToolCount} active` : \"compact rows\", \"toolMuted\"),\n\t\t\t],\n\t\t\twidth,\n\t\t\t\"chat\",\n\t\t\tstate.sessionName ?? \"conversation\",\n\t\t\t\"surfaceAccent\",\n\t\t);\n\t}\n\n\tprivate renderCompact(width: number, mode: TuiMode, state: AdaptiveLayoutState): string[] {\n\t\tconst phase = state.lastError ?? state.gsdPhase ?? (state.activeToolCount > 0 ? `${state.activeToolCount} tools` : \"ready\");\n\t\tconst line = `${theme.fg(\"modeCompact\", \"GSD compact\")} ${theme.fg(\"surfaceMuted\", `${mode} · ${phase}`)}`;\n\t\treturn style()\n\t\t\t.border(\"minimal\")\n\t\t\t.borderColor((text) => theme.fg(\"surfaceBorder\", text))\n\t\t\t.bodyGutter(\" \")\n\t\t\t.render([line], width);\n\t}\n\n\tprivate frame(lines: string[], width: number, title: string, rightTitle: string, accent: ThemeColor): string[] {\n\t\treturn style()\n\t\t\t.border(\"rule\")\n\t\t\t.density(\"compact\")\n\t\t\t.toneColor((text) => theme.fg(\"surfaceMuted\", text))\n\t\t\t.borderColor((text) => theme.fg(\"surfaceBorder\", text))\n\t\t\t.title(theme.fg(\"surfaceTitle\", title))\n\t\t\t.rightTitle(theme.fg(accent, rightTitle))\n\t\t\t.bodyGutter(theme.fg(accent, \"│ \"))\n\t\t\t.render(lines, width);\n\t}\n\n\tprivate metric(label: string, value: string, color: ThemeColor): string {\n\t\treturn `${theme.fg(\"surfaceMuted\", `${label.padEnd(8)} `)}${theme.fg(color, value)}`;\n\t}\n\n\tprivate columns(left: string[], right: string[], leftWidth: number): string[] {\n\t\tconst rows = Math.max(left.length, right.length);\n\t\tconst output: string[] = [];\n\t\tfor (let i = 0; i < rows; i++) {\n\t\t\tconst leftLine = left[i] ?? \"\";\n\t\t\tconst rightLine = right[i] ?? \"\";\n\t\t\tconst gap = \" \".repeat(Math.max(2, leftWidth - visibleWidth(leftLine) + 2));\n\t\t\toutput.push(`${leftLine}${gap}${rightLine}`);\n\t\t}\n\t\treturn output;\n\t}\n\n\tprivate basename(cwd: string): string {\n\t\tconst trimmed = cwd.replace(/\\/+$/, \"\");\n\t\tconst slash = trimmed.lastIndexOf(\"/\");\n\t\treturn slash === -1 ? trimmed : trimmed.slice(slash + 1);\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"assistant-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,SAAS,EAAY,KAAK,aAAa,EAAgB,MAAM,aAAa,CAAC;AAEpF,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGtD,MAAM,WAAW,YAAY;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,qBAAa,yBAA0B,SAAQ,SAAS;IACvD,OAAO,CAAC,gBAAgB,CAAY;IACpC,OAAO,CAAC,iBAAiB,CAAU;IACnC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,WAAW,CAAC,CAAmB;IACvC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,KAAK,CAAC,CAAe;IAC7B,OAAO,CAAC,YAAY,CAAU;gBAG7B,OAAO,CAAC,EAAE,gBAAgB,EAC1B,iBAAiB,UAAQ,EACzB,aAAa,GAAE,aAAkC,EACjD,eAAe,GAAE,eAAiC,EAClD,KAAK,CAAC,EAAE,YAAY;IAsBrB,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,GAAG,IAAI;IAO/C,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAO3B,UAAU,IAAI,IAAI;IAO3B,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAIzC,aAAa,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAqFrC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;CAiBxC"}
1
+ {"version":3,"file":"assistant-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,SAAS,EAAY,KAAK,aAAa,EAAgB,MAAM,aAAa,CAAC;AAEpF,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGtD,MAAM,WAAW,YAAY;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,qBAAa,yBAA0B,SAAQ,SAAS;IACvD,OAAO,CAAC,gBAAgB,CAAY;IACpC,OAAO,CAAC,iBAAiB,CAAU;IACnC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,WAAW,CAAC,CAAmB;IACvC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,KAAK,CAAC,CAAe;IAC7B,OAAO,CAAC,YAAY,CAAU;gBAG7B,OAAO,CAAC,EAAE,gBAAgB,EAC1B,iBAAiB,UAAQ,EACzB,aAAa,GAAE,aAAkC,EACjD,eAAe,GAAE,eAAiC,EAClD,KAAK,CAAC,EAAE,YAAY;IAsBrB,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,GAAG,IAAI;IAO/C,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAO3B,UAAU,IAAI,IAAI;IAO3B,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAIzC,aAAa,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAqFrC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;CAiBxC"}
@@ -1 +1 @@
1
- {"version":3,"file":"assistant-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssistantMessage } from \"@gsd/pi-ai\";\nimport { Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@gsd/pi-tui\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.js\";\nimport { type TimestampFormat } from \"./timestamp.js\";\nimport { renderChatFrame } from \"./chat-frame.js\";\n\nexport interface ContentRange {\n\tstartIndex: number;\n\tendIndex: number;\n}\n\n/**\n * Component that renders a complete assistant message, or a sub-range of its content[].\n * When `range` is provided, only content[startIndex..endIndex] (inclusive) is rendered.\n * Non-text/thinking blocks within the range are silently skipped.\n */\nexport class AssistantMessageComponent extends Container {\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\tprivate markdownTheme: MarkdownTheme;\n\tprivate lastMessage?: AssistantMessage;\n\tprivate timestampFormat: TimestampFormat;\n\tprivate range?: ContentRange;\n\tprivate showMetadata: boolean;\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\ttimestampFormat: TimestampFormat = \"date-time-iso\",\n\t\trange?: ContentRange,\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.timestampFormat = timestampFormat;\n\t\tthis.range = range;\n\t\t// No range = legacy full-message rendering; show metadata by default.\n\t\t// Ranged (interleaved) instances start with metadata hidden; chat-controller\n\t\t// calls setShowMetadata(true) on the last segment at message_end.\n\t\tthis.showMetadata = !range;\n\n\t\t// Container for text/thinking content\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\tif (message) {\n\t\t\tthis.updateContent(message);\n\t\t}\n\t}\n\n\tsetRange(range: ContentRange | undefined): void {\n\t\tthis.range = range;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetShowMetadata(show: boolean): void {\n\t\tthis.showMetadata = show;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.hideThinkingBlock = hide;\n\t}\n\n\tupdateContent(message: AssistantMessage): void {\n\t\tthis.lastMessage = message;\n\n\t\t// Clear content container\n\t\tthis.contentContainer.clear();\n\n\t\tconst start = this.range?.startIndex ?? 0;\n\t\tconst end = this.range?.endIndex ?? message.content.length - 1;\n\t\tconst slice = message.content.slice(start, end + 1);\n\n\t\tconst hasVisibleContent = slice.some(\n\t\t\t(c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()),\n\t\t);\n\t\tconst hasTextContent = message.content.some((c) => c.type === \"text\" && c.text.trim().length > 0);\n\t\tconst hasToolContent = message.content.some((c) => c.type === \"toolCall\" || c.type === \"serverToolUse\");\n\t\t// Claude Code often emits long reasoning blocks ahead of user-visible text/tool\n\t\t// output in the same lifecycle. Keep chat output visible without requiring a\n\t\t// manual thinking toggle every turn.\n\t\tconst shouldCapThinking = hasTextContent || hasToolContent || message.provider === \"claude-code\";\n\n\t\t// Render content in order; non-text/thinking blocks are silently skipped\n\t\tfor (let i = 0; i < slice.length; i++) {\n\t\t\tconst content = slice[i];\n\t\t\tif (content.type === \"text\" && content.text.trim()) {\n\t\t\t\t// Assistant text messages with no background - trim the text\n\t\t\t\t// Set paddingY=0 to avoid extra spacing before tool executions\n\t\t\t\tthis.contentContainer.addChild(new Markdown(content.text.trim(), 1, 0, this.markdownTheme));\n\t\t\t} else if (content.type === \"thinking\" && content.thinking.trim()) {\n\t\t\t\t// Add spacing only when another visible assistant content block follows.\n\t\t\t\t// This avoids a superfluous blank line before separately-rendered tool execution blocks.\n\t\t\t\tconst hasVisibleContentAfter = slice\n\t\t\t\t\t.slice(i + 1)\n\t\t\t\t\t.some((c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()));\n\n\t\t\t\tif (this.hideThinkingBlock) {\n\t\t\t\t\t// Show static \"Thinking...\" label when hidden\n\t\t\t\t\tthis.contentContainer.addChild(new Text(theme.italic(theme.fg(\"thinkingText\", \"Thinking...\")), 1, 0));\n\t\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Thinking traces in thinkingText color, italic\n\t\t\t\t\tconst thinkingMarkdown = new Markdown(content.thinking.trim(), 1, 0, this.markdownTheme, {\n\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\titalic: true,\n\t\t\t\t\t});\n\t\t\t\t\t// Keep visible chat output readable when thinking traces are long.\n\t\t\t\t\t// Tool-bearing turns can stream text in a later assistant message.\n\t\t\t\t\tif (shouldCapThinking) {\n\t\t\t\t\t\tthinkingMarkdown.maxLines = 8;\n\t\t\t\t\t}\n\t\t\t\t\tthis.contentContainer.addChild(thinkingMarkdown);\n\t\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Metadata (errors, timestamp): gated on showMetadata so ranged instances stay clean\n\t\t// until chat-controller explicitly enables it on the last segment at message_end.\n\t\tif (this.showMetadata) {\n\t\t\t// Check if aborted - show after partial content\n\t\t\t// But only if there are no tool calls (tool execution components will show the error)\n\t\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\t\tif (!hasToolCalls) {\n\t\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\t\tconst abortMessage =\n\t\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\t\tif (hasVisibleContent) {\n\t\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\t}\n\t\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", abortMessage), 1, 0));\n\t\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\t\tconst errorMsg = message.errorMessage || \"Unknown error\";\n\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", `Error: ${errorMsg}`), 1, 0));\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst frameWidth = Math.max(20, width);\n\t\tconst contentWidth = Math.max(1, frameWidth - 4);\n\t\tconst lines = super.render(contentWidth);\n\t\tconst headerLabel = this.lastMessage?.model ? `GSD - ${this.lastMessage.model}` : \"GSD\";\n\t\tconst framed = renderChatFrame(lines, frameWidth, {\n\t\t\tlabel: headerLabel,\n\t\t\ttone: \"assistant\",\n\t\t\ttimestamp: this.lastMessage?.timestamp,\n\t\t\ttimestampFormat: this.timestampFormat,\n\t\t\tshowTimestamp: this.showMetadata,\n\t\t});\n\t\tif (framed.length === 0) {\n\t\t\treturn framed;\n\t\t}\n\t\treturn [\"\", ...framed];\n\t}\n}\n"]}
1
+ {"version":3,"file":"assistant-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"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","sourcesContent":["// GSD2 TUI - Assistant message card renderer for interactive terminal sessions.\nimport type { AssistantMessage } from \"@gsd/pi-ai\";\nimport { Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@gsd/pi-tui\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.js\";\nimport { type TimestampFormat } from \"./timestamp.js\";\nimport { renderChatFrame } from \"./chat-frame.js\";\n\nexport interface ContentRange {\n\tstartIndex: number;\n\tendIndex: number;\n}\n\n/**\n * Component that renders a complete assistant message, or a sub-range of its content[].\n * When `range` is provided, only content[startIndex..endIndex] (inclusive) is rendered.\n * Non-text/thinking blocks within the range are silently skipped.\n */\nexport class AssistantMessageComponent extends Container {\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\tprivate markdownTheme: MarkdownTheme;\n\tprivate lastMessage?: AssistantMessage;\n\tprivate timestampFormat: TimestampFormat;\n\tprivate range?: ContentRange;\n\tprivate showMetadata: boolean;\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\ttimestampFormat: TimestampFormat = \"date-time-iso\",\n\t\trange?: ContentRange,\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.timestampFormat = timestampFormat;\n\t\tthis.range = range;\n\t\t// No range = legacy full-message rendering; show metadata by default.\n\t\t// Ranged (interleaved) instances start with metadata hidden; chat-controller\n\t\t// calls setShowMetadata(true) on the last segment at message_end.\n\t\tthis.showMetadata = !range;\n\n\t\t// Container for text/thinking content\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\tif (message) {\n\t\t\tthis.updateContent(message);\n\t\t}\n\t}\n\n\tsetRange(range: ContentRange | undefined): void {\n\t\tthis.range = range;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetShowMetadata(show: boolean): void {\n\t\tthis.showMetadata = show;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.hideThinkingBlock = hide;\n\t}\n\n\tupdateContent(message: AssistantMessage): void {\n\t\tthis.lastMessage = message;\n\n\t\t// Clear content container\n\t\tthis.contentContainer.clear();\n\n\t\tconst start = this.range?.startIndex ?? 0;\n\t\tconst end = this.range?.endIndex ?? message.content.length - 1;\n\t\tconst slice = message.content.slice(start, end + 1);\n\n\t\tconst hasVisibleContent = slice.some(\n\t\t\t(c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()),\n\t\t);\n\t\tconst hasTextContent = message.content.some((c) => c.type === \"text\" && c.text.trim().length > 0);\n\t\tconst hasToolContent = message.content.some((c) => c.type === \"toolCall\" || c.type === \"serverToolUse\");\n\t\t// Claude Code often emits long reasoning blocks ahead of user-visible text/tool\n\t\t// output in the same lifecycle. Keep chat output visible without requiring a\n\t\t// manual thinking toggle every turn.\n\t\tconst shouldCapThinking = hasTextContent || hasToolContent || message.provider === \"claude-code\";\n\n\t\t// Render content in order; non-text/thinking blocks are silently skipped\n\t\tfor (let i = 0; i < slice.length; i++) {\n\t\t\tconst content = slice[i];\n\t\t\tif (content.type === \"text\" && content.text.trim()) {\n\t\t\t\t// Assistant text messages with no background - trim the text\n\t\t\t\t// Set paddingY=0 to avoid extra spacing before tool executions\n\t\t\t\tthis.contentContainer.addChild(new Markdown(content.text.trim(), 1, 0, this.markdownTheme));\n\t\t\t} else if (content.type === \"thinking\" && content.thinking.trim()) {\n\t\t\t\t// Add spacing only when another visible assistant content block follows.\n\t\t\t\t// This avoids a superfluous blank line before separately-rendered tool execution blocks.\n\t\t\t\tconst hasVisibleContentAfter = slice\n\t\t\t\t\t.slice(i + 1)\n\t\t\t\t\t.some((c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()));\n\n\t\t\t\tif (this.hideThinkingBlock) {\n\t\t\t\t\t// Show static \"Thinking...\" label when hidden\n\t\t\t\t\tthis.contentContainer.addChild(new Text(theme.italic(theme.fg(\"thinkingText\", \"Thinking...\")), 1, 0));\n\t\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Thinking traces in thinkingText color, italic\n\t\t\t\t\tconst thinkingMarkdown = new Markdown(content.thinking.trim(), 1, 0, this.markdownTheme, {\n\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\titalic: true,\n\t\t\t\t\t});\n\t\t\t\t\t// Keep visible chat output readable when thinking traces are long.\n\t\t\t\t\t// Tool-bearing turns can stream text in a later assistant message.\n\t\t\t\t\tif (shouldCapThinking) {\n\t\t\t\t\t\tthinkingMarkdown.maxLines = 8;\n\t\t\t\t\t}\n\t\t\t\t\tthis.contentContainer.addChild(thinkingMarkdown);\n\t\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Metadata (errors, timestamp): gated on showMetadata so ranged instances stay clean\n\t\t// until chat-controller explicitly enables it on the last segment at message_end.\n\t\tif (this.showMetadata) {\n\t\t\t// Check if aborted - show after partial content\n\t\t\t// But only if there are no tool calls (tool execution components will show the error)\n\t\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\t\tif (!hasToolCalls) {\n\t\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\t\tconst abortMessage =\n\t\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\t\tif (hasVisibleContent) {\n\t\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\t}\n\t\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", abortMessage), 1, 0));\n\t\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\t\tconst errorMsg = message.errorMessage || \"Unknown error\";\n\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", `Error: ${errorMsg}`), 1, 0));\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst frameWidth = Math.max(20, width);\n\t\tconst contentWidth = Math.max(1, frameWidth - 4);\n\t\tconst lines = super.render(contentWidth);\n\t\tconst headerLabel = this.lastMessage?.model ? `GSD - ${this.lastMessage.model}` : \"GSD\";\n\t\tconst framed = renderChatFrame(lines, frameWidth, {\n\t\t\tlabel: headerLabel,\n\t\t\ttone: \"assistant\",\n\t\t\ttimestamp: this.lastMessage?.timestamp,\n\t\t\ttimestampFormat: this.timestampFormat,\n\t\t\tshowTimestamp: this.showMetadata,\n\t\t});\n\t\tif (framed.length === 0) {\n\t\t\treturn framed;\n\t\t}\n\t\treturn [\"\", ...framed];\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-frame.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-frame.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEvE,KAAK,SAAS,GAAG,WAAW,GAAG,MAAM,GAAG,YAAY,GAAG,OAAO,CAAC;AAU/D,wBAAgB,eAAe,CAC9B,YAAY,EAAE,MAAM,EAAE,EACtB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE;IACL,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,eAAe,CAAC;IACjC,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB,GACC,MAAM,EAAE,CA8DV"}
1
+ {"version":3,"file":"chat-frame.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-frame.ts"],"names":[],"mappings":"AAGA,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEvE,KAAK,SAAS,GAAG,WAAW,GAAG,MAAM,GAAG,YAAY,GAAG,OAAO,CAAC;AAU/D,wBAAgB,eAAe,CAC9B,YAAY,EAAE,MAAM,EAAE,EACtB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE;IACL,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,eAAe,CAAC;IACjC,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB,GACC,MAAM,EAAE,CA8DV"}
@@ -1,3 +1,4 @@
1
+ // GSD2 TUI - Shared chat frame renderer for assistant, user, and system cards.
1
2
  import { style, truncateToWidth, visibleWidth } from "@gsd/pi-tui";
2
3
  import { theme } from "../theme/theme.js";
3
4
  import { formatTimestamp } from "./timestamp.js";
@@ -21,7 +22,7 @@ export function renderChatFrame(contentLines, width, opts) {
21
22
  : "borderAccent";
22
23
  const borderMuted = isPurple ? "customMessageLabel" : "borderMuted";
23
24
  const border = (s) => theme.fg(borderColor, s);
24
- const leftRaw = `• ${opts.label}`;
25
+ const leftRaw = opts.label;
25
26
  const rightRaw = opts.showTimestamp === false || !opts.timestamp
26
27
  ? ""
27
28
  : formatTimestamp(opts.timestamp, opts.timestampFormat);
@@ -1 +1 @@
1
- {"version":3,"file":"chat-frame.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-frame.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAwB,MAAM,gBAAgB,CAAC;AAIvE,SAAS,mBAAmB,CAAC,KAAe;IAC3C,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC;IACvB,OAAO,KAAK,GAAG,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,KAAK,EAAE,CAAC;IAChE,OAAO,GAAG,GAAG,KAAK,IAAI,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,GAAG,EAAE,CAAC;IAChE,OAAO,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,eAAe,CAC9B,YAAsB,EACtB,KAAa,EACb,IAMC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IACvC,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB;IACnE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC;IACrE,MAAM,WAAW,GAChB,IAAI,CAAC,IAAI,KAAK,MAAM;QACnB,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,QAAQ;YACT,CAAC,CAAC,oBAAoB;YACtB,CAAC,CAAC,cAAc,CAAC;IACpB,MAAM,WAAW,GAAG,QAAQ,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,aAAa,CAAC;IACpE,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;IAClC,MAAM,QAAQ,GACb,IAAI,CAAC,aAAa,KAAK,KAAK,IAAI,CAAC,IAAI,CAAC,SAAS;QAC9C,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;IAE1D,MAAM,UAAU,GAAG,QAAQ;QAC1B,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QACtD,CAAC,CAAC,UAAU,CAAC;IACd,MAAM,IAAI,GAAG,eAAe,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;IACtD,MAAM,UAAU,GACf,IAAI,CAAC,IAAI,KAAK,MAAM;QACnB,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,QAAQ;YACT,CAAC,CAAC,oBAAoB;YACtB,CAAC,CAAC,cAAc,CAAC;IACpB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACpC,MAAM,UAAU,GACf,OAAO,IAAI,CAAC;QACX,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;YACzD,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3C,MAAM,WAAW,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9D,MAAM,GAAG,GACR,QAAQ,CAAC,MAAM,GAAG,CAAC;QAClB,CAAC,CAAC,IAAI,CAAC,GAAG,CACR,CAAC,EACD,UAAU,GAAG,YAAY,CAAC,UAAU,CAAC,GAAG,YAAY,CAAC,WAAW,CAAC,CACjE;QACF,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,GAAG,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,WAAW,EAAE,CAAC;IAClE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC;IAEpE,MAAM,SAAS,GACd,IAAI,CAAC,IAAI,KAAK,MAAM;QACnB,CAAC,CAAC,iBAAiB;QACnB,CAAC,CAAC,QAAQ;YACT,CAAC,CAAC,mBAAmB;YACrB,CAAC,CAAC,sBAAsB,CAAC;IAC5B,MAAM,WAAW,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAC5E,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;QACxD,OAAO,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,OAAO,KAAK,EAAE;SACZ,MAAM,CAAC,MAAM,CAAC;SACd,WAAW,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;SAC1F,KAAK,CAAC,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;SACxC,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;AACjC,CAAC","sourcesContent":["import { style, truncateToWidth, visibleWidth } from \"@gsd/pi-tui\";\nimport { theme } from \"../theme/theme.js\";\nimport { formatTimestamp, type TimestampFormat } from \"./timestamp.js\";\n\ntype FrameTone = \"assistant\" | \"user\" | \"compaction\" | \"skill\";\n\nfunction trimOuterBlankLines(lines: string[]): string[] {\n\tlet start = 0;\n\tlet end = lines.length;\n\twhile (start < end && lines[start].trim().length === 0) start++;\n\twhile (end > start && lines[end - 1].trim().length === 0) end--;\n\treturn lines.slice(start, end);\n}\n\nexport function renderChatFrame(\n\tcontentLines: string[],\n\twidth: number,\n\topts: {\n\t\tlabel: string;\n\t\ttone: FrameTone;\n\t\ttimestamp?: number;\n\t\ttimestampFormat: TimestampFormat;\n\t\tshowTimestamp?: boolean;\n\t},\n): string[] {\n\tconst outerWidth = Math.max(20, width);\n\tconst contentWidth = Math.max(1, outerWidth - 2); // \"│ \" + content\n\tconst isPurple = opts.tone === \"compaction\" || opts.tone === \"skill\";\n\tconst borderColor =\n\t\topts.tone === \"user\"\n\t\t\t? \"border\"\n\t\t\t: isPurple\n\t\t\t\t? \"customMessageLabel\"\n\t\t\t\t: \"borderAccent\";\n\tconst borderMuted = isPurple ? \"customMessageLabel\" : \"borderMuted\";\n\tconst border = (s: string) => theme.fg(borderColor, s);\n\tconst leftRaw = `• ${opts.label}`;\n\tconst rightRaw =\n\t\topts.showTimestamp === false || !opts.timestamp\n\t\t\t? \"\"\n\t\t\t: formatTimestamp(opts.timestamp, opts.timestampFormat);\n\n\tconst leftBudget = rightRaw\n\t\t? Math.max(1, outerWidth - visibleWidth(rightRaw) - 1)\n\t\t: outerWidth;\n\tconst left = truncateToWidth(leftRaw, leftBudget, \"\");\n\tconst labelColor =\n\t\topts.tone === \"user\"\n\t\t\t? \"border\"\n\t\t\t: isPurple\n\t\t\t\t? \"customMessageLabel\"\n\t\t\t\t: \"borderAccent\";\n\tconst dashIdx = left.indexOf(\" - \");\n\tconst leftStyled =\n\t\tdashIdx >= 0\n\t\t\t? theme.fg(labelColor, theme.bold(left.slice(0, dashIdx))) +\n\t\t\t\ttheme.fg(\"dim\", left.slice(dashIdx))\n\t\t\t: theme.fg(labelColor, theme.bold(left));\n\tconst rightStyled = rightRaw ? theme.fg(\"dim\", rightRaw) : \"\";\n\tconst gap =\n\t\trightRaw.length > 0\n\t\t\t? Math.max(\n\t\t\t\t\t1,\n\t\t\t\t\touterWidth - visibleWidth(leftStyled) - visibleWidth(rightStyled),\n\t\t\t\t)\n\t\t\t: Math.max(0, outerWidth - visibleWidth(leftStyled));\n\tconst headerRow = `${leftStyled}${\" \".repeat(gap)}${rightStyled}`;\n\tconst headerPad = Math.max(0, outerWidth - visibleWidth(headerRow));\n\n\tconst bodyColor =\n\t\topts.tone === \"user\"\n\t\t\t? \"userMessageText\"\n\t\t\t: isPurple\n\t\t\t\t? \"customMessageText\"\n\t\t\t\t: \"assistantMessageText\";\n\tconst sourceLines = trimOuterBlankLines(contentLines);\n\tconst bodyLines = (sourceLines.length > 0 ? sourceLines : [\"\"]).map((line) => {\n\t\tconst clipped = truncateToWidth(line, contentWidth, \"\");\n\t\treturn theme.fg(bodyColor, clipped);\n\t});\n\n\treturn style()\n\t\t.border(\"rule\")\n\t\t.borderColor((line) => (line.startsWith(\"─\") ? theme.fg(borderMuted, line) : border(line)))\n\t\t.title(headerRow + \" \".repeat(headerPad))\n\t\t.render(bodyLines, outerWidth);\n}\n"]}
1
+ {"version":3,"file":"chat-frame.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-frame.ts"],"names":[],"mappings":"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","sourcesContent":["// GSD2 TUI - Shared chat frame renderer for assistant, user, and system cards.\nimport { style, truncateToWidth, visibleWidth } from \"@gsd/pi-tui\";\nimport { theme } from \"../theme/theme.js\";\nimport { formatTimestamp, type TimestampFormat } from \"./timestamp.js\";\n\ntype FrameTone = \"assistant\" | \"user\" | \"compaction\" | \"skill\";\n\nfunction trimOuterBlankLines(lines: string[]): string[] {\n\tlet start = 0;\n\tlet end = lines.length;\n\twhile (start < end && lines[start].trim().length === 0) start++;\n\twhile (end > start && lines[end - 1].trim().length === 0) end--;\n\treturn lines.slice(start, end);\n}\n\nexport function renderChatFrame(\n\tcontentLines: string[],\n\twidth: number,\n\topts: {\n\t\tlabel: string;\n\t\ttone: FrameTone;\n\t\ttimestamp?: number;\n\t\ttimestampFormat: TimestampFormat;\n\t\tshowTimestamp?: boolean;\n\t},\n): string[] {\n\tconst outerWidth = Math.max(20, width);\n\tconst contentWidth = Math.max(1, outerWidth - 2); // \"│ \" + content\n\tconst isPurple = opts.tone === \"compaction\" || opts.tone === \"skill\";\n\tconst borderColor =\n\t\topts.tone === \"user\"\n\t\t\t? \"border\"\n\t\t\t: isPurple\n\t\t\t\t? \"customMessageLabel\"\n\t\t\t\t: \"borderAccent\";\n\tconst borderMuted = isPurple ? \"customMessageLabel\" : \"borderMuted\";\n\tconst border = (s: string) => theme.fg(borderColor, s);\n\tconst leftRaw = opts.label;\n\tconst rightRaw =\n\t\topts.showTimestamp === false || !opts.timestamp\n\t\t\t? \"\"\n\t\t\t: formatTimestamp(opts.timestamp, opts.timestampFormat);\n\n\tconst leftBudget = rightRaw\n\t\t? Math.max(1, outerWidth - visibleWidth(rightRaw) - 1)\n\t\t: outerWidth;\n\tconst left = truncateToWidth(leftRaw, leftBudget, \"\");\n\tconst labelColor =\n\t\topts.tone === \"user\"\n\t\t\t? \"border\"\n\t\t\t: isPurple\n\t\t\t\t? \"customMessageLabel\"\n\t\t\t\t: \"borderAccent\";\n\tconst dashIdx = left.indexOf(\" - \");\n\tconst leftStyled =\n\t\tdashIdx >= 0\n\t\t\t? theme.fg(labelColor, theme.bold(left.slice(0, dashIdx))) +\n\t\t\t\ttheme.fg(\"dim\", left.slice(dashIdx))\n\t\t\t: theme.fg(labelColor, theme.bold(left));\n\tconst rightStyled = rightRaw ? theme.fg(\"dim\", rightRaw) : \"\";\n\tconst gap =\n\t\trightRaw.length > 0\n\t\t\t? Math.max(\n\t\t\t\t\t1,\n\t\t\t\t\touterWidth - visibleWidth(leftStyled) - visibleWidth(rightStyled),\n\t\t\t\t)\n\t\t\t: Math.max(0, outerWidth - visibleWidth(leftStyled));\n\tconst headerRow = `${leftStyled}${\" \".repeat(gap)}${rightStyled}`;\n\tconst headerPad = Math.max(0, outerWidth - visibleWidth(headerRow));\n\n\tconst bodyColor =\n\t\topts.tone === \"user\"\n\t\t\t? \"userMessageText\"\n\t\t\t: isPurple\n\t\t\t\t? \"customMessageText\"\n\t\t\t\t: \"assistantMessageText\";\n\tconst sourceLines = trimOuterBlankLines(contentLines);\n\tconst bodyLines = (sourceLines.length > 0 ? sourceLines : [\"\"]).map((line) => {\n\t\tconst clipped = truncateToWidth(line, contentWidth, \"\");\n\t\treturn theme.fg(bodyColor, clipped);\n\t});\n\n\treturn style()\n\t\t.border(\"rule\")\n\t\t.borderColor((line) => (line.startsWith(\"─\") ? theme.fg(borderMuted, line) : border(line)))\n\t\t.title(headerRow + \" \".repeat(headerPad))\n\t\t.render(bodyLines, outerWidth);\n}\n"]}
@@ -1,3 +1,4 @@
1
+ // GSD2 TUI Tests - Runtime coverage for tool-card cleanup and success notification rendering.
1
2
  // Runtime regression tests for the post-compaction tool-card cleanup and the
2
3
  // green-bordered success-notification rendering. Replaces the source-grep
3
4
  // `src/tests/tui-running-and-success-box.test.ts` that was deleted in #4875
@@ -51,16 +52,16 @@ function makeMockTUI() {
51
52
  }
52
53
  // ─── Bug 1: tool cards stuck in "Running" after compaction ──────────────
53
54
  describe("ToolExecutionComponent post-compaction cleanup", () => {
54
- it("renders 'Running' status while the tool call has no result", () => {
55
+ it("renders 'running' status while the tool call has no result", () => {
55
56
  // Baseline: a freshly-constructed component (mid-stream) must show
56
57
  // the running badge — this is the state we need to flip OUT of when
57
58
  // compaction removes the result message.
58
59
  const ui = makeMockTUI();
59
60
  const c = new ToolExecutionComponent("read_file", { path: "/tmp/x.txt" }, {}, undefined, ui);
60
61
  const rendered = c.render(60).map(stripAnsi).join("\n");
61
- assert.ok(rendered.includes("Running"), "freshly constructed component should render 'Running' badge");
62
+ assert.ok(rendered.includes("running"), "freshly constructed component should render 'running' badge");
62
63
  });
63
- it("markHistoricalNoResult flips a stuck tool card OUT of 'Running'", () => {
64
+ it("markHistoricalNoResult flips a stuck tool card OUT of 'running'", () => {
64
65
  // Real bug: after session-history replay (post-compaction or session
65
66
  // switch), tool calls without matching tool_result messages stay in
66
67
  // isPartial = true forever. markHistoricalNoResult must produce a
@@ -69,9 +70,9 @@ describe("ToolExecutionComponent post-compaction cleanup", () => {
69
70
  const c = new ToolExecutionComponent("read_file", { path: "/tmp/x.txt" }, {}, undefined, ui);
70
71
  c.markHistoricalNoResult();
71
72
  const rendered = c.render(60).map(stripAnsi).join("\n");
72
- assert.ok(!rendered.includes("Running"), "after markHistoricalNoResult, the tool card must NOT render 'Running' got:\n" +
73
+ assert.ok(!rendered.includes("running"), "after markHistoricalNoResult, the tool card must NOT render 'running' -- got:\n" +
73
74
  rendered);
74
- assert.ok(rendered.includes("Done"), "flipped card should render 'Done' status (no-result success)");
75
+ assert.ok(rendered.includes("success"), "flipped card should render 'success' status (no-result success)");
75
76
  });
76
77
  it("markHistoricalNoResult is idempotent when a real result already exists", () => {
77
78
  // Late-arriving stream events must not clobber legitimate results.
@@ -86,7 +87,7 @@ describe("ToolExecutionComponent post-compaction cleanup", () => {
86
87
  isError: false,
87
88
  }, false);
88
89
  const before = c.render(60).map(stripAnsi).join("\n");
89
- assert.ok(before.includes("Done"), "after complete(), card shows 'Done'");
90
+ assert.ok(before.includes("success"), "after complete(), card shows 'success'");
90
91
  c.markHistoricalNoResult(); // must early-return
91
92
  const after = c.render(60).map(stripAnsi).join("\n");
92
93
  assert.equal(after, before, "markHistoricalNoResult must NOT mutate state when a real result is already present");
@@ -1 +1 @@
1
- {"version":3,"file":"tool-card-cleanup-and-success-runtime.test.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts"],"names":[],"mappings":"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","sourcesContent":["// Runtime regression tests for the post-compaction tool-card cleanup and the\n// green-bordered success-notification rendering. Replaces the source-grep\n// `src/tests/tui-running-and-success-box.test.ts` that was deleted in #4875\n// (tracked as #4872).\n//\n// The previous tests asserted on identifier presence and method signature\n// shape via regex. A regression that routed `success` notifications through\n// `showStatus` (dim text) by accident would not have failed because the\n// `showSuccess` method would still exist and still match the regex. These\n// tests instead drive the components through the actual scenario and assert\n// on rendered output.\n\nimport assert from \"node:assert/strict\";\nimport { describe, it, before } from \"node:test\";\n\nimport { Container, Text } from \"@gsd/pi-tui\";\nimport stripAnsi from \"strip-ansi\";\n\nimport { initTheme, theme } from \"../theme/theme.js\";\nimport { renderExtensionNotifyInChat, shouldRenderExtensionNotifyInChat } from \"../interactive-mode.js\";\nimport { DynamicBorder } from \"./dynamic-border.js\";\nimport { ToolExecutionComponent } from \"./tool-execution.js\";\n\n// Theme is a globalThis-shared singleton that throws if not initialized.\n// Initialize once before any test that exercises themed rendering.\nbefore(() => {\n\tinitTheme(\"dark\");\n});\n\ndescribe(\"Extension warning notifications\", () => {\n\tit(\"do not render into chat output\", () => {\n\t\tassert.equal(shouldRenderExtensionNotifyInChat(\"warning\"), false);\n\t\tassert.equal(shouldRenderExtensionNotifyInChat(\"error\"), true);\n\t\tassert.equal(shouldRenderExtensionNotifyInChat(\"success\"), true);\n\t\tassert.equal(shouldRenderExtensionNotifyInChat(\"info\"), true);\n\t\tassert.equal(shouldRenderExtensionNotifyInChat(undefined), true);\n\n\t\tconst warningChat = new Container();\n\t\tconst warningResult = renderExtensionNotifyInChat(warningChat, \"extension warning\", \"warning\");\n\t\tassert.equal(warningResult.rendered, false);\n\t\tassert.equal(\n\t\t\twarningChat.render(80).map(stripAnsi).join(\"\\n\"),\n\t\t\t\"\",\n\t\t\t\"warning notifications must not add chat output\",\n\t\t);\n\n\t\tfor (const type of [\"error\", \"success\", \"info\"] as const) {\n\t\t\tconst chat = new Container();\n\t\t\tconst result = renderExtensionNotifyInChat(chat, `${type} notification`, type);\n\t\t\tassert.equal(result.rendered, true, `${type} notification should render`);\n\t\t\tassert.match(\n\t\t\t\tchat.render(80).map(stripAnsi).join(\"\\n\"),\n\t\t\t\tnew RegExp(`${type} notification`),\n\t\t\t\t`${type} notification text should appear in chat output`,\n\t\t\t);\n\t\t}\n\t});\n});\n\ninterface MockTui {\n\trenderCount: number;\n\trequestRender(): void;\n}\n\nfunction makeMockTUI(): MockTui {\n\treturn {\n\t\trenderCount: 0,\n\t\trequestRender() {\n\t\t\tthis.renderCount++;\n\t\t},\n\t};\n}\n\n// ─── Bug 1: tool cards stuck in \"Running\" after compaction ──────────────\n\ndescribe(\"ToolExecutionComponent post-compaction cleanup\", () => {\n\tit(\"renders 'Running' status while the tool call has no result\", () => {\n\t\t// Baseline: a freshly-constructed component (mid-stream) must show\n\t\t// the running badge — this is the state we need to flip OUT of when\n\t\t// compaction removes the result message.\n\t\tconst ui = makeMockTUI();\n\t\tconst c = new ToolExecutionComponent(\n\t\t\t\"read_file\",\n\t\t\t{ path: \"/tmp/x.txt\" },\n\t\t\t{},\n\t\t\tundefined,\n\t\t\tui as never,\n\t\t);\n\t\tconst rendered = c.render(60).map(stripAnsi).join(\"\\n\");\n\t\tassert.ok(\n\t\t\trendered.includes(\"Running\"),\n\t\t\t\"freshly constructed component should render 'Running' badge\",\n\t\t);\n\t});\n\n\tit(\"markHistoricalNoResult flips a stuck tool card OUT of 'Running'\", () => {\n\t\t// Real bug: after session-history replay (post-compaction or session\n\t\t// switch), tool calls without matching tool_result messages stay in\n\t\t// isPartial = true forever. markHistoricalNoResult must produce a\n\t\t// rendered output that no longer reads \"Running\".\n\t\tconst ui = makeMockTUI();\n\t\tconst c = new ToolExecutionComponent(\n\t\t\t\"read_file\",\n\t\t\t{ path: \"/tmp/x.txt\" },\n\t\t\t{},\n\t\t\tundefined,\n\t\t\tui as never,\n\t\t);\n\n\t\tc.markHistoricalNoResult();\n\n\t\tconst rendered = c.render(60).map(stripAnsi).join(\"\\n\");\n\t\tassert.ok(\n\t\t\t!rendered.includes(\"Running\"),\n\t\t\t\"after markHistoricalNoResult, the tool card must NOT render 'Running' — got:\\n\" +\n\t\t\t\trendered,\n\t\t);\n\t\tassert.ok(\n\t\t\trendered.includes(\"Done\"),\n\t\t\t\"flipped card should render 'Done' status (no-result success)\",\n\t\t);\n\t});\n\n\tit(\"markHistoricalNoResult is idempotent when a real result already exists\", () => {\n\t\t// Late-arriving stream events must not clobber legitimate results.\n\t\t// We observe the no-clobber via behaviour: a card that completed\n\t\t// with a real result keeps its \"Done\" badge and content even if\n\t\t// markHistoricalNoResult fires again afterwards.\n\t\tconst ui = makeMockTUI();\n\t\tconst c = new ToolExecutionComponent(\n\t\t\t\"read_file\",\n\t\t\t{ path: \"/tmp/x.txt\" },\n\t\t\t{},\n\t\t\tundefined,\n\t\t\tui as never,\n\t\t);\n\n\t\t// Use the public completion path the runtime calls.\n\t\tc.updateResult(\n\t\t\t{\n\t\t\t\tcontent: [{ type: \"text\", text: \"real-result-payload\" }],\n\t\t\t\tisError: false,\n\t\t\t},\n\t\t\tfalse, // isPartial = false → \"Done\"\n\t\t);\n\n\t\tconst before = c.render(60).map(stripAnsi).join(\"\\n\");\n\t\tassert.ok(before.includes(\"Done\"), \"after complete(), card shows 'Done'\");\n\n\t\tc.markHistoricalNoResult(); // must early-return\n\t\tconst after = c.render(60).map(stripAnsi).join(\"\\n\");\n\t\tassert.equal(\n\t\t\tafter,\n\t\t\tbefore,\n\t\t\t\"markHistoricalNoResult must NOT mutate state when a real result is already present\",\n\t\t);\n\t});\n});\n\n// ─── Bug 2: success notifications render as a green bordered box ────────\n\ndescribe(\"Success-notification rendering — DynamicBorder + success theme\", () => {\n\t// We drive the same component composition that interactive-mode.showSuccess\n\t// builds (DynamicBorder + Text + DynamicBorder, all themed with\n\t// theme.fg(\"success\", …)) and assert on the rendered output, rather than\n\t// trying to instantiate the full InteractiveMode (which requires a real\n\t// session, bridge, and TUI runtime).\n\tfunction buildSuccessNotification(message: string): Container {\n\t\tconst c = new Container();\n\t\tconst successColor = (text: string) => theme.fg(\"success\", text);\n\t\tc.addChild(new DynamicBorder(successColor));\n\t\tc.addChild(new Text(theme.fg(\"success\", message), 1, 0));\n\t\tc.addChild(new DynamicBorder(successColor));\n\t\treturn c;\n\t}\n\n\tit(\"renders a top and bottom horizontal border framing the message\", () => {\n\t\tconst c = buildSuccessNotification(\"Milestone M042 ready.\");\n\t\tconst lines = c.render(40);\n\n\t\t// First and last lines should be horizontal-rule borders\n\t\t// (DynamicBorder renders a row of \"─\" characters).\n\t\tconst firstStripped = stripAnsi(lines[0]);\n\t\tconst lastStripped = stripAnsi(lines[lines.length - 1]);\n\n\t\tassert.ok(\n\t\t\tfirstStripped.includes(\"─\"),\n\t\t\t`first line should be a border (got: ${JSON.stringify(firstStripped)})`,\n\t\t);\n\t\tassert.ok(\n\t\t\tlastStripped.includes(\"─\"),\n\t\t\t`last line should be a border (got: ${JSON.stringify(lastStripped)})`,\n\t\t);\n\t\tassert.ok(\n\t\t\tlines.length >= 3,\n\t\t\t`success notification must have at least 3 lines (top border, message, bottom border) — got ${lines.length}`,\n\t\t);\n\t});\n\n\tit(\"the message text appears between the two borders\", () => {\n\t\tconst c = buildSuccessNotification(\"Milestone M042 ready.\");\n\t\tconst lines = c.render(40);\n\n\t\tconst messageRow = lines.findIndex((l) => stripAnsi(l).includes(\"Milestone M042 ready.\"));\n\t\tassert.ok(messageRow > 0, \"message must appear after the top border\");\n\t\tassert.ok(\n\t\t\tmessageRow < lines.length - 1,\n\t\t\t\"message must appear before the bottom border\",\n\t\t);\n\t});\n\n\tit(\"borders carry ANSI styling (not plain dim text like showStatus)\", () => {\n\t\t// Goodhart-resistant: if a regression routed success through\n\t\t// showStatus, the borders would be missing AND the rendered text\n\t\t// would be plain (or only dim-styled, not success-colored). We\n\t\t// observe the border lines carry ANSI escape codes — the literal\n\t\t// foreground color depends on the theme (which is system-dependent\n\t\t// in CI), so we don't pin a specific code but DO require styling\n\t\t// to be present.\n\t\tconst c = buildSuccessNotification(\"ok\");\n\t\tconst lines = c.render(40);\n\t\tconst top = lines[0];\n\t\tassert.ok(\n\t\t\ttop !== stripAnsi(top),\n\t\t\t\"top border must contain ANSI styling — a plain unstyled border \" +\n\t\t\t\t\"would indicate the rendering bypassed theme.fg('success', ...)\",\n\t\t);\n\t});\n\n\tit(\"plain Text status (the showStatus path) does NOT produce a bordered box\", () => {\n\t\t// Counter-test: this is what the bug looked like — a single dim Text\n\t\t// with no surrounding border. If anyone ever \"fixes\" the showSuccess\n\t\t// regression by also adding borders to showStatus, this test will\n\t\t// surface the conflation.\n\t\tconst plain = new Text(theme.fg(\"dim\", \"Milestone M042 ready.\"), 1, 0);\n\t\tconst lines = plain.render(40);\n\t\tconst joined = lines.map(stripAnsi).join(\"\\n\");\n\t\tassert.ok(\n\t\t\t!joined.includes(\"─\"),\n\t\t\t\"plain Text (showStatus path) must NOT contain border characters\",\n\t\t);\n\t});\n});\n"]}
1
+ {"version":3,"file":"tool-card-cleanup-and-success-runtime.test.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts"],"names":[],"mappings":"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","sourcesContent":["// GSD2 TUI Tests - Runtime coverage for tool-card cleanup and success notification rendering.\n// Runtime regression tests for the post-compaction tool-card cleanup and the\n// green-bordered success-notification rendering. Replaces the source-grep\n// `src/tests/tui-running-and-success-box.test.ts` that was deleted in #4875\n// (tracked as #4872).\n//\n// The previous tests asserted on identifier presence and method signature\n// shape via regex. A regression that routed `success` notifications through\n// `showStatus` (dim text) by accident would not have failed because the\n// `showSuccess` method would still exist and still match the regex. These\n// tests instead drive the components through the actual scenario and assert\n// on rendered output.\n\nimport assert from \"node:assert/strict\";\nimport { describe, it, before } from \"node:test\";\n\nimport { Container, Text } from \"@gsd/pi-tui\";\nimport stripAnsi from \"strip-ansi\";\n\nimport { initTheme, theme } from \"../theme/theme.js\";\nimport { renderExtensionNotifyInChat, shouldRenderExtensionNotifyInChat } from \"../interactive-mode.js\";\nimport { DynamicBorder } from \"./dynamic-border.js\";\nimport { ToolExecutionComponent } from \"./tool-execution.js\";\n\n// Theme is a globalThis-shared singleton that throws if not initialized.\n// Initialize once before any test that exercises themed rendering.\nbefore(() => {\n\tinitTheme(\"dark\");\n});\n\ndescribe(\"Extension warning notifications\", () => {\n\tit(\"do not render into chat output\", () => {\n\t\tassert.equal(shouldRenderExtensionNotifyInChat(\"warning\"), false);\n\t\tassert.equal(shouldRenderExtensionNotifyInChat(\"error\"), true);\n\t\tassert.equal(shouldRenderExtensionNotifyInChat(\"success\"), true);\n\t\tassert.equal(shouldRenderExtensionNotifyInChat(\"info\"), true);\n\t\tassert.equal(shouldRenderExtensionNotifyInChat(undefined), true);\n\n\t\tconst warningChat = new Container();\n\t\tconst warningResult = renderExtensionNotifyInChat(warningChat, \"extension warning\", \"warning\");\n\t\tassert.equal(warningResult.rendered, false);\n\t\tassert.equal(\n\t\t\twarningChat.render(80).map(stripAnsi).join(\"\\n\"),\n\t\t\t\"\",\n\t\t\t\"warning notifications must not add chat output\",\n\t\t);\n\n\t\tfor (const type of [\"error\", \"success\", \"info\"] as const) {\n\t\t\tconst chat = new Container();\n\t\t\tconst result = renderExtensionNotifyInChat(chat, `${type} notification`, type);\n\t\t\tassert.equal(result.rendered, true, `${type} notification should render`);\n\t\t\tassert.match(\n\t\t\t\tchat.render(80).map(stripAnsi).join(\"\\n\"),\n\t\t\t\tnew RegExp(`${type} notification`),\n\t\t\t\t`${type} notification text should appear in chat output`,\n\t\t\t);\n\t\t}\n\t});\n});\n\ninterface MockTui {\n\trenderCount: number;\n\trequestRender(): void;\n}\n\nfunction makeMockTUI(): MockTui {\n\treturn {\n\t\trenderCount: 0,\n\t\trequestRender() {\n\t\t\tthis.renderCount++;\n\t\t},\n\t};\n}\n\n// ─── Bug 1: tool cards stuck in \"Running\" after compaction ──────────────\n\ndescribe(\"ToolExecutionComponent post-compaction cleanup\", () => {\n\tit(\"renders 'running' status while the tool call has no result\", () => {\n\t\t// Baseline: a freshly-constructed component (mid-stream) must show\n\t\t// the running badge — this is the state we need to flip OUT of when\n\t\t// compaction removes the result message.\n\t\tconst ui = makeMockTUI();\n\t\tconst c = new ToolExecutionComponent(\n\t\t\t\"read_file\",\n\t\t\t{ path: \"/tmp/x.txt\" },\n\t\t\t{},\n\t\t\tundefined,\n\t\t\tui as never,\n\t\t);\n\t\tconst rendered = c.render(60).map(stripAnsi).join(\"\\n\");\n\t\tassert.ok(\n\t\t\trendered.includes(\"running\"),\n\t\t\t\"freshly constructed component should render 'running' badge\",\n\t\t);\n\t});\n\n\tit(\"markHistoricalNoResult flips a stuck tool card OUT of 'running'\", () => {\n\t\t// Real bug: after session-history replay (post-compaction or session\n\t\t// switch), tool calls without matching tool_result messages stay in\n\t\t// isPartial = true forever. markHistoricalNoResult must produce a\n\t\t// rendered output that no longer reads \"Running\".\n\t\tconst ui = makeMockTUI();\n\t\tconst c = new ToolExecutionComponent(\n\t\t\t\"read_file\",\n\t\t\t{ path: \"/tmp/x.txt\" },\n\t\t\t{},\n\t\t\tundefined,\n\t\t\tui as never,\n\t\t);\n\n\t\tc.markHistoricalNoResult();\n\n\t\tconst rendered = c.render(60).map(stripAnsi).join(\"\\n\");\n\t\tassert.ok(\n\t\t\t!rendered.includes(\"running\"),\n\t\t\t\"after markHistoricalNoResult, the tool card must NOT render 'running' -- got:\\n\" +\n\t\t\t\trendered,\n\t\t);\n\t\tassert.ok(\n\t\t\trendered.includes(\"success\"),\n\t\t\t\"flipped card should render 'success' status (no-result success)\",\n\t\t);\n\t});\n\n\tit(\"markHistoricalNoResult is idempotent when a real result already exists\", () => {\n\t\t// Late-arriving stream events must not clobber legitimate results.\n\t\t// We observe the no-clobber via behaviour: a card that completed\n\t\t// with a real result keeps its \"Done\" badge and content even if\n\t\t// markHistoricalNoResult fires again afterwards.\n\t\tconst ui = makeMockTUI();\n\t\tconst c = new ToolExecutionComponent(\n\t\t\t\"read_file\",\n\t\t\t{ path: \"/tmp/x.txt\" },\n\t\t\t{},\n\t\t\tundefined,\n\t\t\tui as never,\n\t\t);\n\n\t\t// Use the public completion path the runtime calls.\n\t\tc.updateResult(\n\t\t\t{\n\t\t\t\tcontent: [{ type: \"text\", text: \"real-result-payload\" }],\n\t\t\t\tisError: false,\n\t\t\t},\n\t\t\tfalse, // isPartial = false → \"Done\"\n\t\t);\n\n\t\tconst before = c.render(60).map(stripAnsi).join(\"\\n\");\n\t\tassert.ok(before.includes(\"success\"), \"after complete(), card shows 'success'\");\n\n\t\tc.markHistoricalNoResult(); // must early-return\n\t\tconst after = c.render(60).map(stripAnsi).join(\"\\n\");\n\t\tassert.equal(\n\t\t\tafter,\n\t\t\tbefore,\n\t\t\t\"markHistoricalNoResult must NOT mutate state when a real result is already present\",\n\t\t);\n\t});\n});\n\n// ─── Bug 2: success notifications render as a green bordered box ────────\n\ndescribe(\"Success-notification rendering — DynamicBorder + success theme\", () => {\n\t// We drive the same component composition that interactive-mode.showSuccess\n\t// builds (DynamicBorder + Text + DynamicBorder, all themed with\n\t// theme.fg(\"success\", …)) and assert on the rendered output, rather than\n\t// trying to instantiate the full InteractiveMode (which requires a real\n\t// session, bridge, and TUI runtime).\n\tfunction buildSuccessNotification(message: string): Container {\n\t\tconst c = new Container();\n\t\tconst successColor = (text: string) => theme.fg(\"success\", text);\n\t\tc.addChild(new DynamicBorder(successColor));\n\t\tc.addChild(new Text(theme.fg(\"success\", message), 1, 0));\n\t\tc.addChild(new DynamicBorder(successColor));\n\t\treturn c;\n\t}\n\n\tit(\"renders a top and bottom horizontal border framing the message\", () => {\n\t\tconst c = buildSuccessNotification(\"Milestone M042 ready.\");\n\t\tconst lines = c.render(40);\n\n\t\t// First and last lines should be horizontal-rule borders\n\t\t// (DynamicBorder renders a row of \"─\" characters).\n\t\tconst firstStripped = stripAnsi(lines[0]);\n\t\tconst lastStripped = stripAnsi(lines[lines.length - 1]);\n\n\t\tassert.ok(\n\t\t\tfirstStripped.includes(\"─\"),\n\t\t\t`first line should be a border (got: ${JSON.stringify(firstStripped)})`,\n\t\t);\n\t\tassert.ok(\n\t\t\tlastStripped.includes(\"─\"),\n\t\t\t`last line should be a border (got: ${JSON.stringify(lastStripped)})`,\n\t\t);\n\t\tassert.ok(\n\t\t\tlines.length >= 3,\n\t\t\t`success notification must have at least 3 lines (top border, message, bottom border) — got ${lines.length}`,\n\t\t);\n\t});\n\n\tit(\"the message text appears between the two borders\", () => {\n\t\tconst c = buildSuccessNotification(\"Milestone M042 ready.\");\n\t\tconst lines = c.render(40);\n\n\t\tconst messageRow = lines.findIndex((l) => stripAnsi(l).includes(\"Milestone M042 ready.\"));\n\t\tassert.ok(messageRow > 0, \"message must appear after the top border\");\n\t\tassert.ok(\n\t\t\tmessageRow < lines.length - 1,\n\t\t\t\"message must appear before the bottom border\",\n\t\t);\n\t});\n\n\tit(\"borders carry ANSI styling (not plain dim text like showStatus)\", () => {\n\t\t// Goodhart-resistant: if a regression routed success through\n\t\t// showStatus, the borders would be missing AND the rendered text\n\t\t// would be plain (or only dim-styled, not success-colored). We\n\t\t// observe the border lines carry ANSI escape codes — the literal\n\t\t// foreground color depends on the theme (which is system-dependent\n\t\t// in CI), so we don't pin a specific code but DO require styling\n\t\t// to be present.\n\t\tconst c = buildSuccessNotification(\"ok\");\n\t\tconst lines = c.render(40);\n\t\tconst top = lines[0];\n\t\tassert.ok(\n\t\t\ttop !== stripAnsi(top),\n\t\t\t\"top border must contain ANSI styling — a plain unstyled border \" +\n\t\t\t\t\"would indicate the rendering bypassed theme.fg('success', ...)\",\n\t\t);\n\t});\n\n\tit(\"plain Text status (the showStatus path) does NOT produce a bordered box\", () => {\n\t\t// Counter-test: this is what the bug looked like — a single dim Text\n\t\t// with no surrounding border. If anyone ever \"fixes\" the showSuccess\n\t\t// regression by also adding borders to showStatus, this test will\n\t\t// surface the conflation.\n\t\tconst plain = new Text(theme.fg(\"dim\", \"Milestone M042 ready.\"), 1, 0);\n\t\tconst lines = plain.render(40);\n\t\tconst joined = lines.map(stripAnsi).join(\"\\n\");\n\t\tassert.ok(\n\t\t\t!joined.includes(\"─\"),\n\t\t\t\"plain Text (showStatus path) must NOT contain border characters\",\n\t\t);\n\t});\n});\n"]}
@@ -103,6 +103,7 @@ export declare class ToolExecutionComponent extends Container {
103
103
  export declare class ToolPhaseSummaryComponent extends Container {
104
104
  private readonly phases;
105
105
  constructor(phases: ToolExecutionPhase[]);
106
+ getPhases(): ToolExecutionPhase[];
106
107
  render(width: number): string[];
107
108
  }
108
109
  //# sourceMappingURL=tool-execution.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tool-execution.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-execution.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tool-execution.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-execution.ts"],"names":[],"mappings":"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"}
@@ -82,9 +82,9 @@ function renderToolFrame(contentLines, width, opts) {
82
82
  const contentWidth = Math.max(1, outerWidth - 2); // "│ " + content
83
83
  const borderColor = opts.tone === "error" ? "toolError" : opts.tone === "pending" ? "toolRunning" : "toolSuccess";
84
84
  const topColor = borderColor;
85
- const labelColor = opts.tone === "error" ? "toolError" : "surfaceTitle";
85
+ const labelColor = opts.tone === "error" ? "toolError" : opts.tone === "pending" ? "toolRunning" : "toolSuccess";
86
86
  const statusColor = opts.tone === "error" ? "toolError" : opts.tone === "pending" ? "toolRunning" : "toolSuccess";
87
- const leftStyled = theme.fg(labelColor, theme.bold(`• ${opts.label}`));
87
+ const leftStyled = theme.fg(labelColor, theme.bold(opts.label));
88
88
  const rightStyled = theme.fg(statusColor, opts.status);
89
89
  const gap = Math.max(1, outerWidth - visibleWidth(leftStyled) - visibleWidth(rightStyled));
90
90
  const headerRow = `${leftStyled}${" ".repeat(gap)}${rightStyled}`;
@@ -100,6 +100,21 @@ function renderToolFrame(contentLines, width, opts) {
100
100
  .title(headerRow + " ".repeat(headerPad))
101
101
  .render(bodyLines, outerWidth);
102
102
  }
103
+ function renderCollapsedToolRow(label, status, width, tone) {
104
+ const outerWidth = Math.max(20, width);
105
+ const contentWidth = Math.max(1, outerWidth - 2);
106
+ const statusColor = tone === "success" ? "toolSuccess" : "toolMuted";
107
+ const labelStyled = theme.fg(statusColor, label);
108
+ const statusStyled = theme.fg(statusColor, status);
109
+ const labelWidth = Math.max(1, contentWidth - visibleWidth(statusStyled) - 1);
110
+ const clippedLabel = truncateToWidth(labelStyled, labelWidth, "");
111
+ const gap = Math.max(1, contentWidth - visibleWidth(clippedLabel) - visibleWidth(statusStyled));
112
+ const line = `${clippedLabel}${" ".repeat(gap)}${statusStyled}`;
113
+ return style()
114
+ .border("minimal")
115
+ .borderColor((text) => theme.fg(statusColor, text))
116
+ .render([line], outerWidth);
117
+ }
103
118
  const COMPACT_ARG_VALUE_LIMIT = 60;
104
119
  const GENERIC_OUTPUT_PREVIEW_LINES = 10;
105
120
  const GENERIC_ARGS_JSON_PREVIEW_LINES = 10;
@@ -445,18 +460,13 @@ export class ToolExecutionComponent extends Container {
445
460
  const contentWidth = Math.max(1, frameWidth - 4);
446
461
  const frameTone = this.result?.isError ? "error" : this.isPartial || !this.result ? "pending" : "success";
447
462
  const elapsed = formatElapsed((this.endedAt ?? Date.now()) - this.startedAt);
448
- const frameStatus = `${this.isPartial || !this.result ? "Running" : this.result.isError ? "Error" : "Done"} · ${elapsed}`;
463
+ const frameStatus = `${this.isPartial || !this.result ? "running" : this.result.isError ? "failed" : "success"} · ${elapsed}`;
449
464
  const parsed = parseMcpToolName(this.toolName);
450
465
  const frameLabel = parsed
451
- ? `Tool ${parsed.server}·${parsed.tool}`
452
- : `Tool ${prettifyToolName(this.toolName, this.toolDefinition?.label) || "unknown"}`;
466
+ ? `${parsed.server}·${parsed.tool}`
467
+ : prettifyToolName(this.toolName, this.toolDefinition?.label) || "unknown";
453
468
  if (this.shouldRenderCompactSuccess()) {
454
- const availableWidth = Math.max(1, frameWidth - 2);
455
- const summaryWidth = Math.max(1, availableWidth - visibleWidth(frameStatus) - 1);
456
- const summary = truncateToWidth(this.getCompactSummary(frameLabel), summaryWidth, "");
457
- const gap = Math.max(1, availableWidth - visibleWidth(summary) - visibleWidth(frameStatus));
458
- const line = `${theme.fg("toolSuccess", summary)}${" ".repeat(gap)}${theme.fg("toolSuccess", frameStatus)}`;
459
- return ["", ...style().border("minimal").borderColor((text) => theme.fg("toolSuccess", text)).render([line], frameWidth)];
469
+ return ["", ...renderCollapsedToolRow(this.getCompactSummary(frameLabel), frameStatus, frameWidth, "success")];
460
470
  }
461
471
  const lines = super.render(contentWidth);
462
472
  const framed = renderToolFrame(lines, frameWidth, {
@@ -470,7 +480,7 @@ export class ToolExecutionComponent extends Container {
470
480
  if (this.expanded || this.isPartial || !this.result || this.result.isError)
471
481
  return false;
472
482
  const hasImages = this.result.content?.some((block) => block.type === "image") ?? false;
473
- return !hasImages && this.getTextOutput().trim().length === 0;
483
+ return !hasImages;
474
484
  }
475
485
  getRollupPhase() {
476
486
  if (!this.shouldRenderCompactSuccess())
@@ -504,7 +514,7 @@ export class ToolExecutionComponent extends Container {
504
514
  return "Other tool actions";
505
515
  }
506
516
  getCompactSummary(frameLabel) {
507
- return `${frameLabel} Completed`;
517
+ return frameLabel;
508
518
  }
509
519
  updateDisplay() {
510
520
  // Tool body now uses transparent background; status is conveyed in the frame header.
@@ -1082,6 +1092,9 @@ export class ToolPhaseSummaryComponent extends Container {
1082
1092
  super();
1083
1093
  this.phases = phases;
1084
1094
  }
1095
+ getPhases() {
1096
+ return this.phases.map((phase) => ({ ...phase }));
1097
+ }
1085
1098
  render(width) {
1086
1099
  const frameWidth = Math.max(20, width);
1087
1100
  const rows = this.phases.map((phase) => {