@ashx-j/lunr 0.1.6 → 0.2.0

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 (149) hide show
  1. package/dist/builtin-extensions/index.d.ts.map +1 -1
  2. package/dist/builtin-extensions/index.js +3 -6
  3. package/dist/builtin-extensions/index.js.map +1 -1
  4. package/dist/builtin-extensions/lunr-todos.d.ts +7 -6
  5. package/dist/builtin-extensions/lunr-todos.d.ts.map +1 -1
  6. package/dist/builtin-extensions/lunr-todos.js +24 -11
  7. package/dist/builtin-extensions/lunr-todos.js.map +1 -1
  8. package/dist/builtin-extensions/narumiruna-pi-goal/src/commands.d.ts.map +1 -1
  9. package/dist/builtin-extensions/narumiruna-pi-goal/src/commands.js +9 -5
  10. package/dist/builtin-extensions/narumiruna-pi-goal/src/commands.js.map +1 -1
  11. package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.d.ts.map +1 -1
  12. package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.js +31 -3
  13. package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.js.map +1 -1
  14. package/dist/builtin-extensions/narumiruna-pi-goal/src/runtime.d.ts +1 -0
  15. package/dist/builtin-extensions/narumiruna-pi-goal/src/runtime.d.ts.map +1 -1
  16. package/dist/builtin-extensions/narumiruna-pi-goal/src/runtime.js +14 -4
  17. package/dist/builtin-extensions/narumiruna-pi-goal/src/runtime.js.map +1 -1
  18. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
  19. package/dist/builtin-extensions/pi-subagents/src/extension/index.js +4 -3
  20. package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
  21. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts.map +1 -1
  22. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js +12 -1
  23. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js.map +1 -1
  24. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +3 -0
  25. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
  26. package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
  27. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +8 -0
  28. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
  29. package/dist/builtin-extensions/pi-subagents/src/tui/render.js +22 -2
  30. package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
  31. package/dist/builtin-extensions/pi-web-access/index.d.ts.map +1 -1
  32. package/dist/builtin-extensions/pi-web-access/index.js +38 -230
  33. package/dist/builtin-extensions/pi-web-access/index.js.map +1 -1
  34. package/dist/builtin-extensions/pi-web-access/render-search-chrome.d.ts +35 -0
  35. package/dist/builtin-extensions/pi-web-access/render-search-chrome.d.ts.map +1 -0
  36. package/dist/builtin-extensions/pi-web-access/render-search-chrome.js +93 -0
  37. package/dist/builtin-extensions/pi-web-access/render-search-chrome.js.map +1 -0
  38. package/dist/bun/cli.d.ts.map +1 -1
  39. package/dist/bun/cli.js +1 -0
  40. package/dist/bun/cli.js.map +1 -1
  41. package/dist/catalog/models.json +1 -1
  42. package/dist/catalog/providers/cerebras.json +1 -1
  43. package/dist/catalog/providers/cloudflare-ai-gateway.json +1 -1
  44. package/dist/catalog/providers/cloudflare-workers-ai.json +1 -1
  45. package/dist/catalog/providers/huggingface.json +1 -1
  46. package/dist/catalog/providers/opencode-go.json +1 -1
  47. package/dist/catalog/providers/openrouter.json +1 -1
  48. package/dist/catalog/providers/vercel-ai-gateway.json +1 -1
  49. package/dist/catalog/publication.json +3 -3
  50. package/dist/cli.d.ts.map +1 -1
  51. package/dist/cli.js +4 -1
  52. package/dist/cli.js.map +1 -1
  53. package/dist/core/context-breakdown.d.ts +21 -1
  54. package/dist/core/context-breakdown.d.ts.map +1 -1
  55. package/dist/core/context-breakdown.js +58 -2
  56. package/dist/core/context-breakdown.js.map +1 -1
  57. package/dist/core/extensions/host-static.d.ts +2 -0
  58. package/dist/core/extensions/host-static.d.ts.map +1 -0
  59. package/dist/core/extensions/host-static.js +15 -0
  60. package/dist/core/extensions/host-static.js.map +1 -0
  61. package/dist/core/extensions/loader.d.ts +10 -0
  62. package/dist/core/extensions/loader.d.ts.map +1 -1
  63. package/dist/core/extensions/loader.js +75 -34
  64. package/dist/core/extensions/loader.js.map +1 -1
  65. package/dist/core/official-catalog.d.ts.map +1 -1
  66. package/dist/core/official-catalog.js +11 -4
  67. package/dist/core/official-catalog.js.map +1 -1
  68. package/dist/core/package-manager.d.ts +3 -0
  69. package/dist/core/package-manager.d.ts.map +1 -1
  70. package/dist/core/package-manager.js +11 -5
  71. package/dist/core/package-manager.js.map +1 -1
  72. package/dist/core/permission-mode-control.d.ts +27 -0
  73. package/dist/core/permission-mode-control.d.ts.map +1 -0
  74. package/dist/core/permission-mode-control.js +39 -0
  75. package/dist/core/permission-mode-control.js.map +1 -0
  76. package/dist/core/resource-loader.d.ts +4 -1
  77. package/dist/core/resource-loader.d.ts.map +1 -1
  78. package/dist/core/resource-loader.js +13 -5
  79. package/dist/core/resource-loader.js.map +1 -1
  80. package/dist/core/settings-manager.d.ts.map +1 -1
  81. package/dist/core/settings-manager.js.map +1 -1
  82. package/dist/core/slash-commands.d.ts.map +1 -1
  83. package/dist/core/slash-commands.js +0 -1
  84. package/dist/core/slash-commands.js.map +1 -1
  85. package/dist/core/timings.d.ts +1 -0
  86. package/dist/core/timings.d.ts.map +1 -1
  87. package/dist/core/timings.js +6 -1
  88. package/dist/core/timings.js.map +1 -1
  89. package/dist/core/tools/read.d.ts.map +1 -1
  90. package/dist/core/tools/read.js +14 -20
  91. package/dist/core/tools/read.js.map +1 -1
  92. package/dist/core/tools/render-utils.d.ts +2 -0
  93. package/dist/core/tools/render-utils.d.ts.map +1 -1
  94. package/dist/core/tools/render-utils.js +10 -0
  95. package/dist/core/tools/render-utils.js.map +1 -1
  96. package/dist/main.d.ts +8 -0
  97. package/dist/main.d.ts.map +1 -1
  98. package/dist/main.js +63 -16
  99. package/dist/main.js.map +1 -1
  100. package/dist/migrations.d.ts.map +1 -1
  101. package/dist/migrations.js +3 -0
  102. package/dist/migrations.js.map +1 -1
  103. package/dist/modes/interactive/components/assistant-message.d.ts +1 -0
  104. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  105. package/dist/modes/interactive/components/assistant-message.js +1 -0
  106. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  107. package/dist/modes/interactive/components/context-view.d.ts.map +1 -1
  108. package/dist/modes/interactive/components/context-view.js +3 -1
  109. package/dist/modes/interactive/components/context-view.js.map +1 -1
  110. package/dist/modes/interactive/components/plan-message.d.ts +17 -0
  111. package/dist/modes/interactive/components/plan-message.d.ts.map +1 -0
  112. package/dist/modes/interactive/components/plan-message.js +43 -0
  113. package/dist/modes/interactive/components/plan-message.js.map +1 -0
  114. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  115. package/dist/modes/interactive/components/settings-selector.js +1 -1
  116. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  117. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  118. package/dist/modes/interactive/components/tool-execution.js +3 -1
  119. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  120. package/dist/modes/interactive/components/usage-view.d.ts +4 -25
  121. package/dist/modes/interactive/components/usage-view.d.ts.map +1 -1
  122. package/dist/modes/interactive/components/usage-view.js +17 -69
  123. package/dist/modes/interactive/components/usage-view.js.map +1 -1
  124. package/dist/modes/interactive/components/user-message.d.ts +1 -0
  125. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  126. package/dist/modes/interactive/components/user-message.js +1 -0
  127. package/dist/modes/interactive/components/user-message.js.map +1 -1
  128. package/dist/modes/interactive/interactive-mode.d.ts +23 -6
  129. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  130. package/dist/modes/interactive/interactive-mode.js +267 -148
  131. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  132. package/dist/modes/interactive/smooth-streaming.d.ts +39 -6
  133. package/dist/modes/interactive/smooth-streaming.d.ts.map +1 -1
  134. package/dist/modes/interactive/smooth-streaming.js +160 -73
  135. package/dist/modes/interactive/smooth-streaming.js.map +1 -1
  136. package/dist/utils/clipboard-image.d.ts.map +1 -1
  137. package/dist/utils/clipboard-image.js +7 -3
  138. package/dist/utils/clipboard-image.js.map +1 -1
  139. package/docs/terminal-setup.md +13 -0
  140. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  141. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  142. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  143. package/examples/extensions/gondolin/package-lock.json +2 -2
  144. package/examples/extensions/gondolin/package.json +1 -1
  145. package/examples/extensions/sandbox/package-lock.json +2 -2
  146. package/examples/extensions/sandbox/package.json +1 -1
  147. package/examples/extensions/with-deps/package-lock.json +2 -2
  148. package/examples/extensions/with-deps/package.json +1 -1
  149. package/package.json +4 -4
@@ -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,uBAAuB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAY,KAAK,aAAa,EAAgB,MAAM,wBAAwB,CAAC;AAE/F,OAAO,EAGN,KAAK,iBAAiB,EAEtB,MAAM,uBAAuB,CAAC;AAO/B;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,SAAS;IACvD,OAAO,CAAC,gBAAgB,CAAY;IACpC,OAAO,CAAC,iBAAiB,CAAU;IAGnC,OAAO,CAAC,gBAAgB,CAAU;IAGlC,OAAO,CAAC,QAAQ,CAAS;IAGzB,OAAO,CAAC,eAAe,CAAC,CAAsB;IAC9C,OAAO,CAAC,aAAa,CAAgB;IAGrC,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAC,CAAmB;IACvC,OAAO,CAAC,YAAY,CAAS;IAG7B,OAAO,CAAC,UAAU,CAAU;IAE5B,YACC,OAAO,CAAC,EAAE,gBAAgB,EAC1B,iBAAiB,UAAQ,EACzB,aAAa,GAAE,aAAkC,EACjD,mBAAmB,SAAgB,EACnC,SAAS,SAAI,EACb,UAAU,UAAQ,EAClB,gBAAgB,UAAQ,EAkBxB;IAEQ,UAAU,IAAI,IAAI,CAK1B;IAED,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAKxC;IAGD,mBAAmB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAK3C;IAID,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAKnC;IAED,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,EAAE,GAAG,SAAS,GAAG,IAAI,CAEjE;IAGD,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAEpC;IAED,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAK1C;IAED,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAKlC;IAEQ,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA6BvC;IAED,aAAa,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAuJ7C;CACD","sourcesContent":["import type { AssistantMessage } from \"@ashx-j/lunr-ai\";\nimport { Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@ashx-j/lunr-tui\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport {\n\tformatThoughtDuration,\n\tisThinkingRunComplete,\n\ttype ThinkingRunTiming,\n\tthinkingSnippet,\n} from \"./thinking-summary.ts\";\nimport { ThinkingTailComponent } from \"./thinking-tail.ts\";\n\nconst OSC133_ZONE_START = \"\\x1b]133;A\\x07\";\nconst OSC133_ZONE_END = \"\\x1b]133;B\\x07\";\nconst OSC133_ZONE_FINAL = \"\\x1b]133;C\\x07\";\n\n/**\n * Component that renders a complete assistant message\n */\nexport class AssistantMessageComponent extends Container {\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\t// lunr: collapsible reasoning — when true, a completed thinking run renders as\n\t// \"✻ Thought for Xs\" + its first sentence instead of the full block.\n\tprivate thinkingCollapse: boolean;\n\t// lunr: ctrl+o expansion — when true, collapsed thinking runs render in full\n\t// (wired into the global app.tools.expand toggle via the Expandable interface).\n\tprivate expanded = false;\n\t// lunr: live per-run timings from interactive-mode; undefined = history message\n\t// (always treated as final, rendered without durations).\n\tprivate thinkingTimings?: ThinkingRunTiming[];\n\tprivate markdownTheme: MarkdownTheme;\n\t// lunr: kept for the deferred alternative hidden-thinking indicator (Phase 8 removed the label render).\n\t// biome-ignore lint/correctness/noUnusedPrivateClassMembers: retained for future use\n\tprivate hiddenThinkingLabel: string;\n\tprivate outputPad: number;\n\tprivate lastMessage?: AssistantMessage;\n\tprivate hasToolCalls = false;\n\t// lunr: gutter rail — prefix rendered lines with a dim │; the last line uses ╰\n\t// when this component closes the turn (no tool calls follow).\n\tprivate gutterRail: boolean;\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\thiddenThinkingLabel = \"Thinking...\",\n\t\toutputPad = 1,\n\t\tgutterRail = false,\n\t\tthinkingCollapse = false,\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.thinkingCollapse = thinkingCollapse;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.hiddenThinkingLabel = hiddenThinkingLabel;\n\t\tthis.outputPad = outputPad;\n\t\tthis.gutterRail = gutterRail;\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\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\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\t// lunr: collapsible reasoning toggles (live; re-render like setHideThinkingBlock).\n\tsetThinkingCollapse(collapse: boolean): void {\n\t\tthis.thinkingCollapse = collapse;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\t// lunr: ctrl+o expansion — Expandable interface hook; expanded collapsed thinking\n\t// runs render as full Markdown blocks again.\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetThinkingTimings(timings: ThinkingRunTiming[] | undefined): void {\n\t\tthis.thinkingTimings = timings;\n\t}\n\n\t// lunr: gutter rail toggle (live; applied on next render).\n\tsetGutterRail(enabled: boolean): void {\n\t\tthis.gutterRail = enabled;\n\t}\n\n\tsetHiddenThinkingLabel(label: string): void {\n\t\tthis.hiddenThinkingLabel = label;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetOutputPad(padding: number): void {\n\t\tthis.outputPad = padding;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\toverride render(width: number): string[] {\n\t\t// lunr: gutter rail — render content at width-2 and prefix each line with a\n\t\t// dim │; the last line uses ╰ when this assistant message closes the turn\n\t\t// (no tool calls follow). When tool calls are present the rail stays open (│)\n\t\t// because tool-execution components render their own borders below.\n\t\tconst railEnabled = this.gutterRail;\n\t\tconst contentWidth = railEnabled ? Math.max(1, width - 2) : width;\n\t\tconst lines = super.render(contentWidth);\n\t\tif (this.hasToolCalls || lines.length === 0) {\n\t\t\tif (railEnabled && lines.length > 0) {\n\t\t\t\tconst rail = theme.fg(\"dim\", \"│ \");\n\t\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\t\tlines[i] = rail + lines[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn lines;\n\t\t}\n\n\t\tlines[0] = OSC133_ZONE_START + lines[0];\n\t\tlines[lines.length - 1] = OSC133_ZONE_END + OSC133_ZONE_FINAL + lines[lines.length - 1];\n\n\t\tif (railEnabled) {\n\t\t\tconst rail = theme.fg(\"dim\", \"│ \");\n\t\t\tconst close = theme.fg(\"dim\", \"╰ \");\n\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\tlines[i] = (i === lines.length - 1 ? close : rail) + lines[i];\n\t\t\t}\n\t\t}\n\t\treturn lines;\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 hasVisibleContent = message.content.some(\n\t\t\t(c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()),\n\t\t);\n\n\t\tif (hasVisibleContent) {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t}\n\n\t\t// Render content in order\n\t\tlet isFirstTextBlock = true;\n\t\tlet thinkingRunIndex = -1;\n\t\tfor (let i = 0; i < message.content.length; i++) {\n\t\t\tconst content = message.content[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\t// lunr: leading ● marks the first text block (never thinking blocks). It rides\n\t\t\t\t// the defaultTextStyle below, so it renders bright white like the body.\n\t\t\t\tconst trimmed = content.text.trim();\n\t\t\t\tconst text = isFirstTextBlock ? `● ${trimmed}` : trimmed;\n\t\t\t\tisFirstTextBlock = false;\n\t\t\t\t// lunr: theme-polish — assistant message body renders bright white via the\n\t\t\t\t// shared userMessageText token (same knob as user messages).\n\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\tnew Markdown(text, this.outputPad, 0, this.markdownTheme, {\n\t\t\t\t\t\tcolor: (body: string) => theme.fg(\"userMessageText\", body),\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t} else if (content.type === \"thinking\") {\n\t\t\t\tthinkingRunIndex++;\n\t\t\t\tconst thinkingBlocks: string[] = [];\n\t\t\t\tfor (; i < message.content.length; i++) {\n\t\t\t\t\tconst thinkingContent = message.content[i];\n\t\t\t\t\tif (thinkingContent.type !== \"thinking\") {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\t\t\tif (thinking) {\n\t\t\t\t\t\tthinkingBlocks.push(thinking);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ti--;\n\n\t\t\t\tif (thinkingBlocks.length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\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 = message.content\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// lunr: thinking blocks are hidden — render nothing (the \"Thinking...\" label is\n\t\t\t\t\t// removed; an alternative hidden indicator will be designed separately).\n\t\t\t\t} else {\n\t\t\t\t\t// lunr: a run is complete when a block follows it, its timing closed, or no\n\t\t\t\t\t// timings are attached (history). Incomplete = still streaming.\n\t\t\t\t\tconst runComplete = isThinkingRunComplete(\n\t\t\t\t\t\ti < message.content.length - 1,\n\t\t\t\t\t\tthis.thinkingTimings?.[thinkingRunIndex],\n\t\t\t\t\t\tthis.thinkingTimings !== undefined,\n\t\t\t\t\t);\n\t\t\t\t\tif (this.thinkingCollapse && !this.expanded && runComplete) {\n\t\t\t\t\t\t// lunr: collapsible reasoning — a completed run collapses to\n\t\t\t\t\t\t// \"✻ Thought for Xs\" (duration only from live timings) + its first sentence.\n\t\t\t\t\t\tconst timing = this.thinkingTimings?.[thinkingRunIndex];\n\t\t\t\t\t\tconst label =\n\t\t\t\t\t\t\ttiming?.end !== undefined\n\t\t\t\t\t\t\t\t? `✻ Thought for ${formatThoughtDuration(timing.end - timing.start)}`\n\t\t\t\t\t\t\t\t: \"✻ Thought\";\n\t\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\t\tnew Text(theme.fg(\"thinkingText\", theme.italic(label)), this.outputPad, 0),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst snippet = thinkingSnippet(thinkingBlocks.join(\"\\n\\n\"));\n\t\t\t\t\t\tif (snippet) {\n\t\t\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\t\t\tnew Text(theme.fg(\"thinkingText\", theme.italic(snippet)), this.outputPad + 2, 0),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (!runComplete && !this.expanded) {\n\t\t\t\t\t\t// lunr: rolling window — a still-streaming run shows only its last\n\t\t\t\t\t\t// THINKING_TAIL_LINES rendered lines; older lines disappear as new\n\t\t\t\t\t\t// ones stream in. ctrl+o expand (or completion) renders in full.\n\t\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\t\tnew ThinkingTailComponent(thinkingBlocks.join(\"\\n\\n\"), this.outputPad, 0, this.markdownTheme, {\n\t\t\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\t\t\titalic: true,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Render each run of thinking blocks as one Markdown section.\n\t\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\t\tnew Markdown(thinkingBlocks.join(\"\\n\\n\"), this.outputPad, 0, this.markdownTheme, {\n\t\t\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\t\t\titalic: true,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t\t// lunr: only add the spacer when thinking is visible (avoids stray blank line when hidden).\n\t\t\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check if incomplete/failed - show after partial content.\n\t\t// For aborted/error tool calls, tool execution components show the error.\n\t\t// Length stops can happen before a tool call is complete, so surface them here too.\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tthis.hasToolCalls = hasToolCalls;\n\t\tif (message.stopReason === \"length\") {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\tthis.contentContainer.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\t\"Error: Model stopped because it reached the maximum output token limit. The response may be incomplete.\",\n\t\t\t\t\t),\n\t\t\t\t\tthis.outputPad,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t} else if (!hasToolCalls) {\n\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\tconst abortMessage =\n\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", abortMessage), this.outputPad, 0));\n\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\tconst errorMsg = message.errorMessage || \"Unknown error\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", `Error: ${errorMsg}`), this.outputPad, 0));\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
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,uBAAuB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAY,KAAK,aAAa,EAAgB,MAAM,wBAAwB,CAAC;AAE/F,OAAO,EAGN,KAAK,iBAAiB,EAEtB,MAAM,uBAAuB,CAAC;AAO/B;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,SAAS;IACvD,UAAU,UAAQ;IAClB,OAAO,CAAC,gBAAgB,CAAY;IACpC,OAAO,CAAC,iBAAiB,CAAU;IAGnC,OAAO,CAAC,gBAAgB,CAAU;IAGlC,OAAO,CAAC,QAAQ,CAAS;IAGzB,OAAO,CAAC,eAAe,CAAC,CAAsB;IAC9C,OAAO,CAAC,aAAa,CAAgB;IAGrC,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAC,CAAmB;IACvC,OAAO,CAAC,YAAY,CAAS;IAG7B,OAAO,CAAC,UAAU,CAAU;IAE5B,YACC,OAAO,CAAC,EAAE,gBAAgB,EAC1B,iBAAiB,UAAQ,EACzB,aAAa,GAAE,aAAkC,EACjD,mBAAmB,SAAgB,EACnC,SAAS,SAAI,EACb,UAAU,UAAQ,EAClB,gBAAgB,UAAQ,EAkBxB;IAEQ,UAAU,IAAI,IAAI,CAK1B;IAED,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAKxC;IAGD,mBAAmB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAK3C;IAID,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAKnC;IAED,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,EAAE,GAAG,SAAS,GAAG,IAAI,CAEjE;IAGD,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAEpC;IAED,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAK1C;IAED,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAKlC;IAEQ,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA6BvC;IAED,aAAa,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAuJ7C;CACD","sourcesContent":["import type { AssistantMessage } from \"@ashx-j/lunr-ai\";\nimport { Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@ashx-j/lunr-tui\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport {\n\tformatThoughtDuration,\n\tisThinkingRunComplete,\n\ttype ThinkingRunTiming,\n\tthinkingSnippet,\n} from \"./thinking-summary.ts\";\nimport { ThinkingTailComponent } from \"./thinking-tail.ts\";\n\nconst OSC133_ZONE_START = \"\\x1b]133;A\\x07\";\nconst OSC133_ZONE_END = \"\\x1b]133;B\\x07\";\nconst OSC133_ZONE_FINAL = \"\\x1b]133;C\\x07\";\n\n/**\n * Component that renders a complete assistant message\n */\nexport class AssistantMessageComponent extends Container {\n\tselectable = true;\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\t// lunr: collapsible reasoning — when true, a completed thinking run renders as\n\t// \"✻ Thought for Xs\" + its first sentence instead of the full block.\n\tprivate thinkingCollapse: boolean;\n\t// lunr: ctrl+o expansion — when true, collapsed thinking runs render in full\n\t// (wired into the global app.tools.expand toggle via the Expandable interface).\n\tprivate expanded = false;\n\t// lunr: live per-run timings from interactive-mode; undefined = history message\n\t// (always treated as final, rendered without durations).\n\tprivate thinkingTimings?: ThinkingRunTiming[];\n\tprivate markdownTheme: MarkdownTheme;\n\t// lunr: kept for the deferred alternative hidden-thinking indicator (Phase 8 removed the label render).\n\t// biome-ignore lint/correctness/noUnusedPrivateClassMembers: retained for future use\n\tprivate hiddenThinkingLabel: string;\n\tprivate outputPad: number;\n\tprivate lastMessage?: AssistantMessage;\n\tprivate hasToolCalls = false;\n\t// lunr: gutter rail — prefix rendered lines with a dim │; the last line uses ╰\n\t// when this component closes the turn (no tool calls follow).\n\tprivate gutterRail: boolean;\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\thiddenThinkingLabel = \"Thinking...\",\n\t\toutputPad = 1,\n\t\tgutterRail = false,\n\t\tthinkingCollapse = false,\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.thinkingCollapse = thinkingCollapse;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.hiddenThinkingLabel = hiddenThinkingLabel;\n\t\tthis.outputPad = outputPad;\n\t\tthis.gutterRail = gutterRail;\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\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\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\t// lunr: collapsible reasoning toggles (live; re-render like setHideThinkingBlock).\n\tsetThinkingCollapse(collapse: boolean): void {\n\t\tthis.thinkingCollapse = collapse;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\t// lunr: ctrl+o expansion — Expandable interface hook; expanded collapsed thinking\n\t// runs render as full Markdown blocks again.\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetThinkingTimings(timings: ThinkingRunTiming[] | undefined): void {\n\t\tthis.thinkingTimings = timings;\n\t}\n\n\t// lunr: gutter rail toggle (live; applied on next render).\n\tsetGutterRail(enabled: boolean): void {\n\t\tthis.gutterRail = enabled;\n\t}\n\n\tsetHiddenThinkingLabel(label: string): void {\n\t\tthis.hiddenThinkingLabel = label;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetOutputPad(padding: number): void {\n\t\tthis.outputPad = padding;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\toverride render(width: number): string[] {\n\t\t// lunr: gutter rail — render content at width-2 and prefix each line with a\n\t\t// dim │; the last line uses ╰ when this assistant message closes the turn\n\t\t// (no tool calls follow). When tool calls are present the rail stays open (│)\n\t\t// because tool-execution components render their own borders below.\n\t\tconst railEnabled = this.gutterRail;\n\t\tconst contentWidth = railEnabled ? Math.max(1, width - 2) : width;\n\t\tconst lines = super.render(contentWidth);\n\t\tif (this.hasToolCalls || lines.length === 0) {\n\t\t\tif (railEnabled && lines.length > 0) {\n\t\t\t\tconst rail = theme.fg(\"dim\", \"│ \");\n\t\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\t\tlines[i] = rail + lines[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn lines;\n\t\t}\n\n\t\tlines[0] = OSC133_ZONE_START + lines[0];\n\t\tlines[lines.length - 1] = OSC133_ZONE_END + OSC133_ZONE_FINAL + lines[lines.length - 1];\n\n\t\tif (railEnabled) {\n\t\t\tconst rail = theme.fg(\"dim\", \"│ \");\n\t\t\tconst close = theme.fg(\"dim\", \"╰ \");\n\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\tlines[i] = (i === lines.length - 1 ? close : rail) + lines[i];\n\t\t\t}\n\t\t}\n\t\treturn lines;\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 hasVisibleContent = message.content.some(\n\t\t\t(c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()),\n\t\t);\n\n\t\tif (hasVisibleContent) {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t}\n\n\t\t// Render content in order\n\t\tlet isFirstTextBlock = true;\n\t\tlet thinkingRunIndex = -1;\n\t\tfor (let i = 0; i < message.content.length; i++) {\n\t\t\tconst content = message.content[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\t// lunr: leading ● marks the first text block (never thinking blocks). It rides\n\t\t\t\t// the defaultTextStyle below, so it renders bright white like the body.\n\t\t\t\tconst trimmed = content.text.trim();\n\t\t\t\tconst text = isFirstTextBlock ? `● ${trimmed}` : trimmed;\n\t\t\t\tisFirstTextBlock = false;\n\t\t\t\t// lunr: theme-polish — assistant message body renders bright white via the\n\t\t\t\t// shared userMessageText token (same knob as user messages).\n\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\tnew Markdown(text, this.outputPad, 0, this.markdownTheme, {\n\t\t\t\t\t\tcolor: (body: string) => theme.fg(\"userMessageText\", body),\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t} else if (content.type === \"thinking\") {\n\t\t\t\tthinkingRunIndex++;\n\t\t\t\tconst thinkingBlocks: string[] = [];\n\t\t\t\tfor (; i < message.content.length; i++) {\n\t\t\t\t\tconst thinkingContent = message.content[i];\n\t\t\t\t\tif (thinkingContent.type !== \"thinking\") {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\t\t\tif (thinking) {\n\t\t\t\t\t\tthinkingBlocks.push(thinking);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ti--;\n\n\t\t\t\tif (thinkingBlocks.length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\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 = message.content\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// lunr: thinking blocks are hidden — render nothing (the \"Thinking...\" label is\n\t\t\t\t\t// removed; an alternative hidden indicator will be designed separately).\n\t\t\t\t} else {\n\t\t\t\t\t// lunr: a run is complete when a block follows it, its timing closed, or no\n\t\t\t\t\t// timings are attached (history). Incomplete = still streaming.\n\t\t\t\t\tconst runComplete = isThinkingRunComplete(\n\t\t\t\t\t\ti < message.content.length - 1,\n\t\t\t\t\t\tthis.thinkingTimings?.[thinkingRunIndex],\n\t\t\t\t\t\tthis.thinkingTimings !== undefined,\n\t\t\t\t\t);\n\t\t\t\t\tif (this.thinkingCollapse && !this.expanded && runComplete) {\n\t\t\t\t\t\t// lunr: collapsible reasoning — a completed run collapses to\n\t\t\t\t\t\t// \"✻ Thought for Xs\" (duration only from live timings) + its first sentence.\n\t\t\t\t\t\tconst timing = this.thinkingTimings?.[thinkingRunIndex];\n\t\t\t\t\t\tconst label =\n\t\t\t\t\t\t\ttiming?.end !== undefined\n\t\t\t\t\t\t\t\t? `✻ Thought for ${formatThoughtDuration(timing.end - timing.start)}`\n\t\t\t\t\t\t\t\t: \"✻ Thought\";\n\t\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\t\tnew Text(theme.fg(\"thinkingText\", theme.italic(label)), this.outputPad, 0),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst snippet = thinkingSnippet(thinkingBlocks.join(\"\\n\\n\"));\n\t\t\t\t\t\tif (snippet) {\n\t\t\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\t\t\tnew Text(theme.fg(\"thinkingText\", theme.italic(snippet)), this.outputPad + 2, 0),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (!runComplete && !this.expanded) {\n\t\t\t\t\t\t// lunr: rolling window — a still-streaming run shows only its last\n\t\t\t\t\t\t// THINKING_TAIL_LINES rendered lines; older lines disappear as new\n\t\t\t\t\t\t// ones stream in. ctrl+o expand (or completion) renders in full.\n\t\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\t\tnew ThinkingTailComponent(thinkingBlocks.join(\"\\n\\n\"), this.outputPad, 0, this.markdownTheme, {\n\t\t\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\t\t\titalic: true,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Render each run of thinking blocks as one Markdown section.\n\t\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\t\tnew Markdown(thinkingBlocks.join(\"\\n\\n\"), this.outputPad, 0, this.markdownTheme, {\n\t\t\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\t\t\titalic: true,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t\t// lunr: only add the spacer when thinking is visible (avoids stray blank line when hidden).\n\t\t\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check if incomplete/failed - show after partial content.\n\t\t// For aborted/error tool calls, tool execution components show the error.\n\t\t// Length stops can happen before a tool call is complete, so surface them here too.\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tthis.hasToolCalls = hasToolCalls;\n\t\tif (message.stopReason === \"length\") {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\tthis.contentContainer.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\t\"Error: Model stopped because it reached the maximum output token limit. The response may be incomplete.\",\n\t\t\t\t\t),\n\t\t\t\t\tthis.outputPad,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t} else if (!hasToolCalls) {\n\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\tconst abortMessage =\n\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", abortMessage), this.outputPad, 0));\n\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\tconst errorMsg = message.errorMessage || \"Unknown error\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", `Error: ${errorMsg}`), this.outputPad, 0));\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
@@ -9,6 +9,7 @@ const OSC133_ZONE_FINAL = "\x1b]133;C\x07";
9
9
  * Component that renders a complete assistant message
10
10
  */
11
11
  export class AssistantMessageComponent extends Container {
12
+ selectable = true;
12
13
  contentContainer;
13
14
  hideThinkingBlock;
14
15
  // lunr: collapsible reasoning — when true, a completed thinking run renders as
@@ -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 \"@ashx-j/lunr-ai\";\nimport { Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@ashx-j/lunr-tui\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport {\n\tformatThoughtDuration,\n\tisThinkingRunComplete,\n\ttype ThinkingRunTiming,\n\tthinkingSnippet,\n} from \"./thinking-summary.ts\";\nimport { ThinkingTailComponent } from \"./thinking-tail.ts\";\n\nconst OSC133_ZONE_START = \"\\x1b]133;A\\x07\";\nconst OSC133_ZONE_END = \"\\x1b]133;B\\x07\";\nconst OSC133_ZONE_FINAL = \"\\x1b]133;C\\x07\";\n\n/**\n * Component that renders a complete assistant message\n */\nexport class AssistantMessageComponent extends Container {\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\t// lunr: collapsible reasoning — when true, a completed thinking run renders as\n\t// \"✻ Thought for Xs\" + its first sentence instead of the full block.\n\tprivate thinkingCollapse: boolean;\n\t// lunr: ctrl+o expansion — when true, collapsed thinking runs render in full\n\t// (wired into the global app.tools.expand toggle via the Expandable interface).\n\tprivate expanded = false;\n\t// lunr: live per-run timings from interactive-mode; undefined = history message\n\t// (always treated as final, rendered without durations).\n\tprivate thinkingTimings?: ThinkingRunTiming[];\n\tprivate markdownTheme: MarkdownTheme;\n\t// lunr: kept for the deferred alternative hidden-thinking indicator (Phase 8 removed the label render).\n\t// biome-ignore lint/correctness/noUnusedPrivateClassMembers: retained for future use\n\tprivate hiddenThinkingLabel: string;\n\tprivate outputPad: number;\n\tprivate lastMessage?: AssistantMessage;\n\tprivate hasToolCalls = false;\n\t// lunr: gutter rail — prefix rendered lines with a dim │; the last line uses ╰\n\t// when this component closes the turn (no tool calls follow).\n\tprivate gutterRail: boolean;\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\thiddenThinkingLabel = \"Thinking...\",\n\t\toutputPad = 1,\n\t\tgutterRail = false,\n\t\tthinkingCollapse = false,\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.thinkingCollapse = thinkingCollapse;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.hiddenThinkingLabel = hiddenThinkingLabel;\n\t\tthis.outputPad = outputPad;\n\t\tthis.gutterRail = gutterRail;\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\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\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\t// lunr: collapsible reasoning toggles (live; re-render like setHideThinkingBlock).\n\tsetThinkingCollapse(collapse: boolean): void {\n\t\tthis.thinkingCollapse = collapse;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\t// lunr: ctrl+o expansion — Expandable interface hook; expanded collapsed thinking\n\t// runs render as full Markdown blocks again.\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetThinkingTimings(timings: ThinkingRunTiming[] | undefined): void {\n\t\tthis.thinkingTimings = timings;\n\t}\n\n\t// lunr: gutter rail toggle (live; applied on next render).\n\tsetGutterRail(enabled: boolean): void {\n\t\tthis.gutterRail = enabled;\n\t}\n\n\tsetHiddenThinkingLabel(label: string): void {\n\t\tthis.hiddenThinkingLabel = label;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetOutputPad(padding: number): void {\n\t\tthis.outputPad = padding;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\toverride render(width: number): string[] {\n\t\t// lunr: gutter rail — render content at width-2 and prefix each line with a\n\t\t// dim │; the last line uses ╰ when this assistant message closes the turn\n\t\t// (no tool calls follow). When tool calls are present the rail stays open (│)\n\t\t// because tool-execution components render their own borders below.\n\t\tconst railEnabled = this.gutterRail;\n\t\tconst contentWidth = railEnabled ? Math.max(1, width - 2) : width;\n\t\tconst lines = super.render(contentWidth);\n\t\tif (this.hasToolCalls || lines.length === 0) {\n\t\t\tif (railEnabled && lines.length > 0) {\n\t\t\t\tconst rail = theme.fg(\"dim\", \"│ \");\n\t\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\t\tlines[i] = rail + lines[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn lines;\n\t\t}\n\n\t\tlines[0] = OSC133_ZONE_START + lines[0];\n\t\tlines[lines.length - 1] = OSC133_ZONE_END + OSC133_ZONE_FINAL + lines[lines.length - 1];\n\n\t\tif (railEnabled) {\n\t\t\tconst rail = theme.fg(\"dim\", \"│ \");\n\t\t\tconst close = theme.fg(\"dim\", \"╰ \");\n\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\tlines[i] = (i === lines.length - 1 ? close : rail) + lines[i];\n\t\t\t}\n\t\t}\n\t\treturn lines;\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 hasVisibleContent = message.content.some(\n\t\t\t(c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()),\n\t\t);\n\n\t\tif (hasVisibleContent) {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t}\n\n\t\t// Render content in order\n\t\tlet isFirstTextBlock = true;\n\t\tlet thinkingRunIndex = -1;\n\t\tfor (let i = 0; i < message.content.length; i++) {\n\t\t\tconst content = message.content[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\t// lunr: leading ● marks the first text block (never thinking blocks). It rides\n\t\t\t\t// the defaultTextStyle below, so it renders bright white like the body.\n\t\t\t\tconst trimmed = content.text.trim();\n\t\t\t\tconst text = isFirstTextBlock ? `● ${trimmed}` : trimmed;\n\t\t\t\tisFirstTextBlock = false;\n\t\t\t\t// lunr: theme-polish — assistant message body renders bright white via the\n\t\t\t\t// shared userMessageText token (same knob as user messages).\n\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\tnew Markdown(text, this.outputPad, 0, this.markdownTheme, {\n\t\t\t\t\t\tcolor: (body: string) => theme.fg(\"userMessageText\", body),\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t} else if (content.type === \"thinking\") {\n\t\t\t\tthinkingRunIndex++;\n\t\t\t\tconst thinkingBlocks: string[] = [];\n\t\t\t\tfor (; i < message.content.length; i++) {\n\t\t\t\t\tconst thinkingContent = message.content[i];\n\t\t\t\t\tif (thinkingContent.type !== \"thinking\") {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\t\t\tif (thinking) {\n\t\t\t\t\t\tthinkingBlocks.push(thinking);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ti--;\n\n\t\t\t\tif (thinkingBlocks.length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\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 = message.content\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// lunr: thinking blocks are hidden — render nothing (the \"Thinking...\" label is\n\t\t\t\t\t// removed; an alternative hidden indicator will be designed separately).\n\t\t\t\t} else {\n\t\t\t\t\t// lunr: a run is complete when a block follows it, its timing closed, or no\n\t\t\t\t\t// timings are attached (history). Incomplete = still streaming.\n\t\t\t\t\tconst runComplete = isThinkingRunComplete(\n\t\t\t\t\t\ti < message.content.length - 1,\n\t\t\t\t\t\tthis.thinkingTimings?.[thinkingRunIndex],\n\t\t\t\t\t\tthis.thinkingTimings !== undefined,\n\t\t\t\t\t);\n\t\t\t\t\tif (this.thinkingCollapse && !this.expanded && runComplete) {\n\t\t\t\t\t\t// lunr: collapsible reasoning — a completed run collapses to\n\t\t\t\t\t\t// \"✻ Thought for Xs\" (duration only from live timings) + its first sentence.\n\t\t\t\t\t\tconst timing = this.thinkingTimings?.[thinkingRunIndex];\n\t\t\t\t\t\tconst label =\n\t\t\t\t\t\t\ttiming?.end !== undefined\n\t\t\t\t\t\t\t\t? `✻ Thought for ${formatThoughtDuration(timing.end - timing.start)}`\n\t\t\t\t\t\t\t\t: \"✻ Thought\";\n\t\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\t\tnew Text(theme.fg(\"thinkingText\", theme.italic(label)), this.outputPad, 0),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst snippet = thinkingSnippet(thinkingBlocks.join(\"\\n\\n\"));\n\t\t\t\t\t\tif (snippet) {\n\t\t\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\t\t\tnew Text(theme.fg(\"thinkingText\", theme.italic(snippet)), this.outputPad + 2, 0),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (!runComplete && !this.expanded) {\n\t\t\t\t\t\t// lunr: rolling window — a still-streaming run shows only its last\n\t\t\t\t\t\t// THINKING_TAIL_LINES rendered lines; older lines disappear as new\n\t\t\t\t\t\t// ones stream in. ctrl+o expand (or completion) renders in full.\n\t\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\t\tnew ThinkingTailComponent(thinkingBlocks.join(\"\\n\\n\"), this.outputPad, 0, this.markdownTheme, {\n\t\t\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\t\t\titalic: true,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Render each run of thinking blocks as one Markdown section.\n\t\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\t\tnew Markdown(thinkingBlocks.join(\"\\n\\n\"), this.outputPad, 0, this.markdownTheme, {\n\t\t\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\t\t\titalic: true,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t\t// lunr: only add the spacer when thinking is visible (avoids stray blank line when hidden).\n\t\t\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check if incomplete/failed - show after partial content.\n\t\t// For aborted/error tool calls, tool execution components show the error.\n\t\t// Length stops can happen before a tool call is complete, so surface them here too.\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tthis.hasToolCalls = hasToolCalls;\n\t\tif (message.stopReason === \"length\") {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\tthis.contentContainer.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\t\"Error: Model stopped because it reached the maximum output token limit. The response may be incomplete.\",\n\t\t\t\t\t),\n\t\t\t\t\tthis.outputPad,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t} else if (!hasToolCalls) {\n\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\tconst abortMessage =\n\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", abortMessage), this.outputPad, 0));\n\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\tconst errorMsg = message.errorMessage || \"Unknown error\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", `Error: ${errorMsg}`), this.outputPad, 0));\n\t\t\t}\n\t\t}\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":["import type { AssistantMessage } from \"@ashx-j/lunr-ai\";\nimport { Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@ashx-j/lunr-tui\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport {\n\tformatThoughtDuration,\n\tisThinkingRunComplete,\n\ttype ThinkingRunTiming,\n\tthinkingSnippet,\n} from \"./thinking-summary.ts\";\nimport { ThinkingTailComponent } from \"./thinking-tail.ts\";\n\nconst OSC133_ZONE_START = \"\\x1b]133;A\\x07\";\nconst OSC133_ZONE_END = \"\\x1b]133;B\\x07\";\nconst OSC133_ZONE_FINAL = \"\\x1b]133;C\\x07\";\n\n/**\n * Component that renders a complete assistant message\n */\nexport class AssistantMessageComponent extends Container {\n\tselectable = true;\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\t// lunr: collapsible reasoning — when true, a completed thinking run renders as\n\t// \"✻ Thought for Xs\" + its first sentence instead of the full block.\n\tprivate thinkingCollapse: boolean;\n\t// lunr: ctrl+o expansion — when true, collapsed thinking runs render in full\n\t// (wired into the global app.tools.expand toggle via the Expandable interface).\n\tprivate expanded = false;\n\t// lunr: live per-run timings from interactive-mode; undefined = history message\n\t// (always treated as final, rendered without durations).\n\tprivate thinkingTimings?: ThinkingRunTiming[];\n\tprivate markdownTheme: MarkdownTheme;\n\t// lunr: kept for the deferred alternative hidden-thinking indicator (Phase 8 removed the label render).\n\t// biome-ignore lint/correctness/noUnusedPrivateClassMembers: retained for future use\n\tprivate hiddenThinkingLabel: string;\n\tprivate outputPad: number;\n\tprivate lastMessage?: AssistantMessage;\n\tprivate hasToolCalls = false;\n\t// lunr: gutter rail — prefix rendered lines with a dim │; the last line uses ╰\n\t// when this component closes the turn (no tool calls follow).\n\tprivate gutterRail: boolean;\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\thiddenThinkingLabel = \"Thinking...\",\n\t\toutputPad = 1,\n\t\tgutterRail = false,\n\t\tthinkingCollapse = false,\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.thinkingCollapse = thinkingCollapse;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.hiddenThinkingLabel = hiddenThinkingLabel;\n\t\tthis.outputPad = outputPad;\n\t\tthis.gutterRail = gutterRail;\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\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\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\t// lunr: collapsible reasoning toggles (live; re-render like setHideThinkingBlock).\n\tsetThinkingCollapse(collapse: boolean): void {\n\t\tthis.thinkingCollapse = collapse;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\t// lunr: ctrl+o expansion — Expandable interface hook; expanded collapsed thinking\n\t// runs render as full Markdown blocks again.\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetThinkingTimings(timings: ThinkingRunTiming[] | undefined): void {\n\t\tthis.thinkingTimings = timings;\n\t}\n\n\t// lunr: gutter rail toggle (live; applied on next render).\n\tsetGutterRail(enabled: boolean): void {\n\t\tthis.gutterRail = enabled;\n\t}\n\n\tsetHiddenThinkingLabel(label: string): void {\n\t\tthis.hiddenThinkingLabel = label;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetOutputPad(padding: number): void {\n\t\tthis.outputPad = padding;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\toverride render(width: number): string[] {\n\t\t// lunr: gutter rail — render content at width-2 and prefix each line with a\n\t\t// dim │; the last line uses ╰ when this assistant message closes the turn\n\t\t// (no tool calls follow). When tool calls are present the rail stays open (│)\n\t\t// because tool-execution components render their own borders below.\n\t\tconst railEnabled = this.gutterRail;\n\t\tconst contentWidth = railEnabled ? Math.max(1, width - 2) : width;\n\t\tconst lines = super.render(contentWidth);\n\t\tif (this.hasToolCalls || lines.length === 0) {\n\t\t\tif (railEnabled && lines.length > 0) {\n\t\t\t\tconst rail = theme.fg(\"dim\", \"│ \");\n\t\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\t\tlines[i] = rail + lines[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn lines;\n\t\t}\n\n\t\tlines[0] = OSC133_ZONE_START + lines[0];\n\t\tlines[lines.length - 1] = OSC133_ZONE_END + OSC133_ZONE_FINAL + lines[lines.length - 1];\n\n\t\tif (railEnabled) {\n\t\t\tconst rail = theme.fg(\"dim\", \"│ \");\n\t\t\tconst close = theme.fg(\"dim\", \"╰ \");\n\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\tlines[i] = (i === lines.length - 1 ? close : rail) + lines[i];\n\t\t\t}\n\t\t}\n\t\treturn lines;\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 hasVisibleContent = message.content.some(\n\t\t\t(c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()),\n\t\t);\n\n\t\tif (hasVisibleContent) {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t}\n\n\t\t// Render content in order\n\t\tlet isFirstTextBlock = true;\n\t\tlet thinkingRunIndex = -1;\n\t\tfor (let i = 0; i < message.content.length; i++) {\n\t\t\tconst content = message.content[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\t// lunr: leading ● marks the first text block (never thinking blocks). It rides\n\t\t\t\t// the defaultTextStyle below, so it renders bright white like the body.\n\t\t\t\tconst trimmed = content.text.trim();\n\t\t\t\tconst text = isFirstTextBlock ? `● ${trimmed}` : trimmed;\n\t\t\t\tisFirstTextBlock = false;\n\t\t\t\t// lunr: theme-polish — assistant message body renders bright white via the\n\t\t\t\t// shared userMessageText token (same knob as user messages).\n\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\tnew Markdown(text, this.outputPad, 0, this.markdownTheme, {\n\t\t\t\t\t\tcolor: (body: string) => theme.fg(\"userMessageText\", body),\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t} else if (content.type === \"thinking\") {\n\t\t\t\tthinkingRunIndex++;\n\t\t\t\tconst thinkingBlocks: string[] = [];\n\t\t\t\tfor (; i < message.content.length; i++) {\n\t\t\t\t\tconst thinkingContent = message.content[i];\n\t\t\t\t\tif (thinkingContent.type !== \"thinking\") {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\t\t\tif (thinking) {\n\t\t\t\t\t\tthinkingBlocks.push(thinking);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ti--;\n\n\t\t\t\tif (thinkingBlocks.length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\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 = message.content\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// lunr: thinking blocks are hidden — render nothing (the \"Thinking...\" label is\n\t\t\t\t\t// removed; an alternative hidden indicator will be designed separately).\n\t\t\t\t} else {\n\t\t\t\t\t// lunr: a run is complete when a block follows it, its timing closed, or no\n\t\t\t\t\t// timings are attached (history). Incomplete = still streaming.\n\t\t\t\t\tconst runComplete = isThinkingRunComplete(\n\t\t\t\t\t\ti < message.content.length - 1,\n\t\t\t\t\t\tthis.thinkingTimings?.[thinkingRunIndex],\n\t\t\t\t\t\tthis.thinkingTimings !== undefined,\n\t\t\t\t\t);\n\t\t\t\t\tif (this.thinkingCollapse && !this.expanded && runComplete) {\n\t\t\t\t\t\t// lunr: collapsible reasoning — a completed run collapses to\n\t\t\t\t\t\t// \"✻ Thought for Xs\" (duration only from live timings) + its first sentence.\n\t\t\t\t\t\tconst timing = this.thinkingTimings?.[thinkingRunIndex];\n\t\t\t\t\t\tconst label =\n\t\t\t\t\t\t\ttiming?.end !== undefined\n\t\t\t\t\t\t\t\t? `✻ Thought for ${formatThoughtDuration(timing.end - timing.start)}`\n\t\t\t\t\t\t\t\t: \"✻ Thought\";\n\t\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\t\tnew Text(theme.fg(\"thinkingText\", theme.italic(label)), this.outputPad, 0),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst snippet = thinkingSnippet(thinkingBlocks.join(\"\\n\\n\"));\n\t\t\t\t\t\tif (snippet) {\n\t\t\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\t\t\tnew Text(theme.fg(\"thinkingText\", theme.italic(snippet)), this.outputPad + 2, 0),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (!runComplete && !this.expanded) {\n\t\t\t\t\t\t// lunr: rolling window — a still-streaming run shows only its last\n\t\t\t\t\t\t// THINKING_TAIL_LINES rendered lines; older lines disappear as new\n\t\t\t\t\t\t// ones stream in. ctrl+o expand (or completion) renders in full.\n\t\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\t\tnew ThinkingTailComponent(thinkingBlocks.join(\"\\n\\n\"), this.outputPad, 0, this.markdownTheme, {\n\t\t\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\t\t\titalic: true,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Render each run of thinking blocks as one Markdown section.\n\t\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\t\tnew Markdown(thinkingBlocks.join(\"\\n\\n\"), this.outputPad, 0, this.markdownTheme, {\n\t\t\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\t\t\titalic: true,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t\t// lunr: only add the spacer when thinking is visible (avoids stray blank line when hidden).\n\t\t\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check if incomplete/failed - show after partial content.\n\t\t// For aborted/error tool calls, tool execution components show the error.\n\t\t// Length stops can happen before a tool call is complete, so surface them here too.\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tthis.hasToolCalls = hasToolCalls;\n\t\tif (message.stopReason === \"length\") {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\tthis.contentContainer.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\t\"Error: Model stopped because it reached the maximum output token limit. The response may be incomplete.\",\n\t\t\t\t\t),\n\t\t\t\t\tthis.outputPad,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t} else if (!hasToolCalls) {\n\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\tconst abortMessage =\n\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", abortMessage), this.outputPad, 0));\n\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\tconst errorMsg = message.errorMessage || \"Unknown error\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", `Error: ${errorMsg}`), this.outputPad, 0));\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"context-view.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/context-view.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAK3E,MAAM,WAAW,eAAe;IAC/B,SAAS,EAAE,gBAAgB,CAAC;IAC5B,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAiBD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CA+BlF","sourcesContent":["import type { ContextBreakdown } from \"../../../core/context-breakdown.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { formatTokens } from \"./footer.ts\";\nimport { renderThemedBox, usageBar } from \"./usage-view.ts\";\n\nexport interface ContextViewData {\n\tbreakdown: ContextBreakdown;\n\t/** provider/model id shown in the box, when known. */\n\tmodel?: string;\n}\n\ninterface BreakdownRow {\n\tlabel: string;\n\ttokens: number;\n\tcount?: number;\n}\n\nfunction renderRowLabel(row: BreakdownRow): string {\n\treturn row.count !== undefined && row.count > 0 ? `${row.label} (${row.count})` : row.label;\n}\n\nfunction rowLine(row: BreakdownRow, labelWidth: number): string {\n\tconst label = renderRowLabel(row);\n\treturn ` ${label.padEnd(labelWidth)} ${formatTokens(row.tokens)}`;\n}\n\n/**\n * Render the /context bordered box: an estimated breakdown of what consumes\n * the context window. Category rows are counts only; the estimated-total\n * row keeps the shared 20-cell usage bar.\n */\nexport function renderContextBox(data: ContextViewData, maxWidth: number): string[] {\n\tconst { breakdown } = data;\n\tconst content: string[] = [];\n\n\tif (data.model) content.push(data.model);\n\tcontent.push(theme.fg(\"dim\", \"Estimated (chars/4), current session only — actual token counts may differ.\"));\n\tcontent.push(\"\");\n\n\tconst rows: BreakdownRow[] = [\n\t\t{ label: \"System prompt + files\", tokens: breakdown.systemPrompt },\n\t\t{ label: \"Tool definitions\", tokens: breakdown.toolDefinitions },\n\t\t{ label: \"User messages\", tokens: breakdown.user, count: breakdown.counts.user },\n\t\t{ label: \"Assistant text\", tokens: breakdown.assistantText, count: breakdown.counts.assistantText },\n\t\t{ label: \"Thinking\", tokens: breakdown.thinking, count: breakdown.counts.thinking },\n\t\t{ label: \"Tool calls\", tokens: breakdown.toolCalls, count: breakdown.counts.toolCalls },\n\t\t{ label: \"Tool results\", tokens: breakdown.toolResults, count: breakdown.counts.toolResults },\n\t\t{ label: \"Summaries\", tokens: breakdown.summaries, count: breakdown.counts.summaries },\n\t].filter((row) => row.tokens > 0);\n\n\tconst labelWidth = Math.max(...rows.map((row) => renderRowLabel(row).length), \"Estimated total\".length);\n\tfor (const row of rows) {\n\t\tcontent.push(rowLine(row, labelWidth));\n\t}\n\n\tcontent.push(\"\");\n\tconst usedPercent = breakdown.contextWindow > 0 ? (breakdown.total / breakdown.contextWindow) * 100 : 0;\n\tcontent.push(\n\t\t` ${\"Estimated total\".padEnd(labelWidth)} ${usageBar(usedPercent)} ${formatTokens(breakdown.total)} / ${formatTokens(breakdown.contextWindow)} (${Math.round(usedPercent)}%)`,\n\t);\n\n\treturn renderThemedBox(\" Context \", content, maxWidth);\n}\n"]}
1
+ {"version":3,"file":"context-view.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/context-view.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAK3E,MAAM,WAAW,eAAe;IAC/B,SAAS,EAAE,gBAAgB,CAAC;IAC5B,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAiBD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAiClF","sourcesContent":["import type { ContextBreakdown } from \"../../../core/context-breakdown.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { formatTokens } from \"./footer.ts\";\nimport { renderThemedBox, usageBar } from \"./usage-view.ts\";\n\nexport interface ContextViewData {\n\tbreakdown: ContextBreakdown;\n\t/** provider/model id shown in the box, when known. */\n\tmodel?: string;\n}\n\ninterface BreakdownRow {\n\tlabel: string;\n\ttokens: number;\n\tcount?: number;\n}\n\nfunction renderRowLabel(row: BreakdownRow): string {\n\treturn row.count !== undefined && row.count > 0 ? `${row.label} (${row.count})` : row.label;\n}\n\nfunction rowLine(row: BreakdownRow, labelWidth: number): string {\n\tconst label = renderRowLabel(row);\n\treturn ` ${label.padEnd(labelWidth)} ${formatTokens(row.tokens)}`;\n}\n\n/**\n * Render the /context bordered box: an estimated breakdown of what consumes\n * the context window. Category rows are counts only; the estimated-total\n * row keeps the shared 20-cell usage bar.\n */\nexport function renderContextBox(data: ContextViewData, maxWidth: number): string[] {\n\tconst { breakdown } = data;\n\tconst content: string[] = [];\n\n\tif (data.model) content.push(data.model);\n\tcontent.push(theme.fg(\"dim\", \"Estimated (chars/4), current session only — actual token counts may differ.\"));\n\tcontent.push(\"\");\n\n\tconst rows: BreakdownRow[] = [\n\t\t{ label: \"System prompt\", tokens: breakdown.systemPrompt },\n\t\t...breakdown.contextFiles.map((file) => ({ label: file.label, tokens: file.tokens })),\n\t\t{ label: \"Skills\", tokens: breakdown.skills },\n\t\t{ label: \"Tool definitions\", tokens: breakdown.toolDefinitions },\n\t\t{ label: \"User messages\", tokens: breakdown.user, count: breakdown.counts.user },\n\t\t{ label: \"Assistant text\", tokens: breakdown.assistantText, count: breakdown.counts.assistantText },\n\t\t{ label: \"Thinking\", tokens: breakdown.thinking, count: breakdown.counts.thinking },\n\t\t{ label: \"Tool calls\", tokens: breakdown.toolCalls, count: breakdown.counts.toolCalls },\n\t\t{ label: \"Tool results\", tokens: breakdown.toolResults, count: breakdown.counts.toolResults },\n\t\t{ label: \"Summaries\", tokens: breakdown.summaries, count: breakdown.counts.summaries },\n\t].filter((row) => row.tokens > 0);\n\n\tconst labelWidth = Math.max(...rows.map((row) => renderRowLabel(row).length), \"Estimated total\".length);\n\tfor (const row of rows) {\n\t\tcontent.push(rowLine(row, labelWidth));\n\t}\n\n\tcontent.push(\"\");\n\tconst usedPercent = breakdown.contextWindow > 0 ? (breakdown.total / breakdown.contextWindow) * 100 : 0;\n\tcontent.push(\n\t\t` ${\"Estimated total\".padEnd(labelWidth)} ${usageBar(usedPercent)} ${formatTokens(breakdown.total)} / ${formatTokens(breakdown.contextWindow)} (${Math.round(usedPercent)}%)`,\n\t);\n\n\treturn renderThemedBox(\" Context \", content, maxWidth);\n}\n"]}
@@ -21,7 +21,9 @@ export function renderContextBox(data, maxWidth) {
21
21
  content.push(theme.fg("dim", "Estimated (chars/4), current session only — actual token counts may differ."));
22
22
  content.push("");
23
23
  const rows = [
24
- { label: "System prompt + files", tokens: breakdown.systemPrompt },
24
+ { label: "System prompt", tokens: breakdown.systemPrompt },
25
+ ...breakdown.contextFiles.map((file) => ({ label: file.label, tokens: file.tokens })),
26
+ { label: "Skills", tokens: breakdown.skills },
25
27
  { label: "Tool definitions", tokens: breakdown.toolDefinitions },
26
28
  { label: "User messages", tokens: breakdown.user, count: breakdown.counts.user },
27
29
  { label: "Assistant text", tokens: breakdown.assistantText, count: breakdown.counts.assistantText },
@@ -1 +1 @@
1
- {"version":3,"file":"context-view.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/context-view.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContextBreakdown } from \"../../../core/context-breakdown.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { formatTokens } from \"./footer.ts\";\nimport { renderThemedBox, usageBar } from \"./usage-view.ts\";\n\nexport interface ContextViewData {\n\tbreakdown: ContextBreakdown;\n\t/** provider/model id shown in the box, when known. */\n\tmodel?: string;\n}\n\ninterface BreakdownRow {\n\tlabel: string;\n\ttokens: number;\n\tcount?: number;\n}\n\nfunction renderRowLabel(row: BreakdownRow): string {\n\treturn row.count !== undefined && row.count > 0 ? `${row.label} (${row.count})` : row.label;\n}\n\nfunction rowLine(row: BreakdownRow, labelWidth: number): string {\n\tconst label = renderRowLabel(row);\n\treturn ` ${label.padEnd(labelWidth)} ${formatTokens(row.tokens)}`;\n}\n\n/**\n * Render the /context bordered box: an estimated breakdown of what consumes\n * the context window. Category rows are counts only; the estimated-total\n * row keeps the shared 20-cell usage bar.\n */\nexport function renderContextBox(data: ContextViewData, maxWidth: number): string[] {\n\tconst { breakdown } = data;\n\tconst content: string[] = [];\n\n\tif (data.model) content.push(data.model);\n\tcontent.push(theme.fg(\"dim\", \"Estimated (chars/4), current session only — actual token counts may differ.\"));\n\tcontent.push(\"\");\n\n\tconst rows: BreakdownRow[] = [\n\t\t{ label: \"System prompt + files\", tokens: breakdown.systemPrompt },\n\t\t{ label: \"Tool definitions\", tokens: breakdown.toolDefinitions },\n\t\t{ label: \"User messages\", tokens: breakdown.user, count: breakdown.counts.user },\n\t\t{ label: \"Assistant text\", tokens: breakdown.assistantText, count: breakdown.counts.assistantText },\n\t\t{ label: \"Thinking\", tokens: breakdown.thinking, count: breakdown.counts.thinking },\n\t\t{ label: \"Tool calls\", tokens: breakdown.toolCalls, count: breakdown.counts.toolCalls },\n\t\t{ label: \"Tool results\", tokens: breakdown.toolResults, count: breakdown.counts.toolResults },\n\t\t{ label: \"Summaries\", tokens: breakdown.summaries, count: breakdown.counts.summaries },\n\t].filter((row) => row.tokens > 0);\n\n\tconst labelWidth = Math.max(...rows.map((row) => renderRowLabel(row).length), \"Estimated total\".length);\n\tfor (const row of rows) {\n\t\tcontent.push(rowLine(row, labelWidth));\n\t}\n\n\tcontent.push(\"\");\n\tconst usedPercent = breakdown.contextWindow > 0 ? (breakdown.total / breakdown.contextWindow) * 100 : 0;\n\tcontent.push(\n\t\t` ${\"Estimated total\".padEnd(labelWidth)} ${usageBar(usedPercent)} ${formatTokens(breakdown.total)} / ${formatTokens(breakdown.contextWindow)} (${Math.round(usedPercent)}%)`,\n\t);\n\n\treturn renderThemedBox(\" Context \", content, maxWidth);\n}\n"]}
1
+ {"version":3,"file":"context-view.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/context-view.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAc5D,SAAS,cAAc,CAAC,GAAiB,EAAU;IAClD,OAAO,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;AAAA,CAC5F;AAED,SAAS,OAAO,CAAC,GAAiB,EAAE,UAAkB,EAAU;IAC/D,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,KAAK,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;AAAA,CACpE;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAqB,EAAE,QAAgB,EAAY;IACnF,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;IAC3B,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,IAAI,IAAI,CAAC,KAAK;QAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,+EAA6E,CAAC,CAAC,CAAC;IAC7G,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEjB,MAAM,IAAI,GAAmB;QAC5B,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,SAAS,CAAC,YAAY,EAAE;QAC1D,GAAG,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACrF,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE;QAC7C,EAAE,KAAK,EAAE,kBAAkB,EAAE,MAAM,EAAE,SAAS,CAAC,eAAe,EAAE;QAChE,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE;QAChF,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,CAAC,aAAa,EAAE,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,aAAa,EAAE;QACnG,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,QAAQ,EAAE;QACnF,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,CAAC,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,SAAS,EAAE;QACvF,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,CAAC,WAAW,EAAE,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,WAAW,EAAE;QAC7F,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,SAAS,EAAE;KACtF,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAElC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACxG,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,MAAM,WAAW,GAAG,SAAS,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,GAAG,SAAS,CAAC,aAAa,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACxG,OAAO,CAAC,IAAI,CACX,KAAK,iBAAiB,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,QAAQ,CAAC,WAAW,CAAC,KAAK,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,YAAY,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAChL,CAAC;IAEF,OAAO,eAAe,CAAC,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;AAAA,CACvD","sourcesContent":["import type { ContextBreakdown } from \"../../../core/context-breakdown.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { formatTokens } from \"./footer.ts\";\nimport { renderThemedBox, usageBar } from \"./usage-view.ts\";\n\nexport interface ContextViewData {\n\tbreakdown: ContextBreakdown;\n\t/** provider/model id shown in the box, when known. */\n\tmodel?: string;\n}\n\ninterface BreakdownRow {\n\tlabel: string;\n\ttokens: number;\n\tcount?: number;\n}\n\nfunction renderRowLabel(row: BreakdownRow): string {\n\treturn row.count !== undefined && row.count > 0 ? `${row.label} (${row.count})` : row.label;\n}\n\nfunction rowLine(row: BreakdownRow, labelWidth: number): string {\n\tconst label = renderRowLabel(row);\n\treturn ` ${label.padEnd(labelWidth)} ${formatTokens(row.tokens)}`;\n}\n\n/**\n * Render the /context bordered box: an estimated breakdown of what consumes\n * the context window. Category rows are counts only; the estimated-total\n * row keeps the shared 20-cell usage bar.\n */\nexport function renderContextBox(data: ContextViewData, maxWidth: number): string[] {\n\tconst { breakdown } = data;\n\tconst content: string[] = [];\n\n\tif (data.model) content.push(data.model);\n\tcontent.push(theme.fg(\"dim\", \"Estimated (chars/4), current session only — actual token counts may differ.\"));\n\tcontent.push(\"\");\n\n\tconst rows: BreakdownRow[] = [\n\t\t{ label: \"System prompt\", tokens: breakdown.systemPrompt },\n\t\t...breakdown.contextFiles.map((file) => ({ label: file.label, tokens: file.tokens })),\n\t\t{ label: \"Skills\", tokens: breakdown.skills },\n\t\t{ label: \"Tool definitions\", tokens: breakdown.toolDefinitions },\n\t\t{ label: \"User messages\", tokens: breakdown.user, count: breakdown.counts.user },\n\t\t{ label: \"Assistant text\", tokens: breakdown.assistantText, count: breakdown.counts.assistantText },\n\t\t{ label: \"Thinking\", tokens: breakdown.thinking, count: breakdown.counts.thinking },\n\t\t{ label: \"Tool calls\", tokens: breakdown.toolCalls, count: breakdown.counts.toolCalls },\n\t\t{ label: \"Tool results\", tokens: breakdown.toolResults, count: breakdown.counts.toolResults },\n\t\t{ label: \"Summaries\", tokens: breakdown.summaries, count: breakdown.counts.summaries },\n\t].filter((row) => row.tokens > 0);\n\n\tconst labelWidth = Math.max(...rows.map((row) => renderRowLabel(row).length), \"Estimated total\".length);\n\tfor (const row of rows) {\n\t\tcontent.push(rowLine(row, labelWidth));\n\t}\n\n\tcontent.push(\"\");\n\tconst usedPercent = breakdown.contextWindow > 0 ? (breakdown.total / breakdown.contextWindow) * 100 : 0;\n\tcontent.push(\n\t\t` ${\"Estimated total\".padEnd(labelWidth)} ${usageBar(usedPercent)} ${formatTokens(breakdown.total)} / ${formatTokens(breakdown.contextWindow)} (${Math.round(usedPercent)}%)`,\n\t);\n\n\treturn renderThemedBox(\" Context \", content, maxWidth);\n}\n"]}
@@ -0,0 +1,17 @@
1
+ import { Container, type MarkdownTheme } from "@ashx-j/lunr-tui";
2
+ /** Markdown source for the live plan chat card. Full summary, no 500-char slice. */
3
+ export declare function planMessageMarkdown(summary: string): string;
4
+ /**
5
+ * Chat card for present_plan. Lives in the transcript so the dock dialog
6
+ * can stay a short Approve / Decline chooser.
7
+ */
8
+ export declare class PlanMessageComponent extends Container {
9
+ private summary;
10
+ private markdownTheme;
11
+ private outputPad;
12
+ private gutterRail;
13
+ constructor(summary: string, markdownTheme?: MarkdownTheme, outputPad?: number, gutterRail?: boolean);
14
+ private rebuild;
15
+ render(width: number): string[];
16
+ }
17
+ //# sourceMappingURL=plan-message.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/plan-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAY,KAAK,aAAa,EAAQ,MAAM,wBAAwB,CAAC;AAGvF,oFAAoF;AACpF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;;GAGG;AACH,qBAAa,oBAAqB,SAAQ,SAAS;IAClD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAU;IAE5B,YAAY,OAAO,EAAE,MAAM,EAAE,aAAa,GAAE,aAAkC,EAAE,SAAS,SAAI,EAAE,UAAU,UAAQ,EAOhH;IAED,OAAO,CAAC,OAAO;IAMN,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAWvC;CACD","sourcesContent":["import { Container, Markdown, type MarkdownTheme, Text } from \"@ashx-j/lunr-tui\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\n\n/** Markdown source for the live plan chat card. Full summary, no 500-char slice. */\nexport function planMessageMarkdown(summary: string): string {\n\treturn summary;\n}\n\n/**\n * Chat card for present_plan. Lives in the transcript so the dock dialog\n * can stay a short Approve / Decline chooser.\n */\nexport class PlanMessageComponent extends Container {\n\tprivate summary: string;\n\tprivate markdownTheme: MarkdownTheme;\n\tprivate outputPad: number;\n\tprivate gutterRail: boolean;\n\n\tconstructor(summary: string, markdownTheme: MarkdownTheme = getMarkdownTheme(), outputPad = 1, gutterRail = false) {\n\t\tsuper();\n\t\tthis.summary = summary;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.outputPad = outputPad;\n\t\tthis.gutterRail = gutterRail;\n\t\tthis.rebuild();\n\t}\n\n\tprivate rebuild(): void {\n\t\tthis.clear();\n\t\tthis.addChild(new Text(theme.fg(\"accent\", theme.bold(\"Plan\")), this.outputPad, 0));\n\t\tthis.addChild(new Markdown(planMessageMarkdown(this.summary), this.outputPad, 0, this.markdownTheme));\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst railEnabled = this.gutterRail;\n\t\tconst contentWidth = railEnabled ? Math.max(1, width - 2) : width;\n\t\tconst lines = super.render(contentWidth);\n\t\tif (!railEnabled || lines.length === 0) return lines;\n\t\tconst rail = theme.fg(\"dim\", \"│ \");\n\t\tconst close = theme.fg(\"dim\", \"╰ \");\n\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\tlines[i] = (i === lines.length - 1 ? close : rail) + lines[i];\n\t\t}\n\t\treturn lines;\n\t}\n}\n"]}
@@ -0,0 +1,43 @@
1
+ import { Container, Markdown, Text } from "@ashx-j/lunr-tui";
2
+ import { getMarkdownTheme, theme } from "../theme/theme.js";
3
+ /** Markdown source for the live plan chat card. Full summary, no 500-char slice. */
4
+ export function planMessageMarkdown(summary) {
5
+ return summary;
6
+ }
7
+ /**
8
+ * Chat card for present_plan. Lives in the transcript so the dock dialog
9
+ * can stay a short Approve / Decline chooser.
10
+ */
11
+ export class PlanMessageComponent extends Container {
12
+ summary;
13
+ markdownTheme;
14
+ outputPad;
15
+ gutterRail;
16
+ constructor(summary, markdownTheme = getMarkdownTheme(), outputPad = 1, gutterRail = false) {
17
+ super();
18
+ this.summary = summary;
19
+ this.markdownTheme = markdownTheme;
20
+ this.outputPad = outputPad;
21
+ this.gutterRail = gutterRail;
22
+ this.rebuild();
23
+ }
24
+ rebuild() {
25
+ this.clear();
26
+ this.addChild(new Text(theme.fg("accent", theme.bold("Plan")), this.outputPad, 0));
27
+ this.addChild(new Markdown(planMessageMarkdown(this.summary), this.outputPad, 0, this.markdownTheme));
28
+ }
29
+ render(width) {
30
+ const railEnabled = this.gutterRail;
31
+ const contentWidth = railEnabled ? Math.max(1, width - 2) : width;
32
+ const lines = super.render(contentWidth);
33
+ if (!railEnabled || lines.length === 0)
34
+ return lines;
35
+ const rail = theme.fg("dim", "│ ");
36
+ const close = theme.fg("dim", "╰ ");
37
+ for (let i = 0; i < lines.length; i++) {
38
+ lines[i] = (i === lines.length - 1 ? close : rail) + lines[i];
39
+ }
40
+ return lines;
41
+ }
42
+ }
43
+ //# sourceMappingURL=plan-message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/plan-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAsB,IAAI,EAAE,MAAM,wBAAwB,CAAC;AACvF,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE5D,oFAAoF;AACpF,MAAM,UAAU,mBAAmB,CAAC,OAAe,EAAU;IAC5D,OAAO,OAAO,CAAC;AAAA,CACf;AAED;;;GAGG;AACH,MAAM,OAAO,oBAAqB,SAAQ,SAAS;IAC1C,OAAO,CAAS;IAChB,aAAa,CAAgB;IAC7B,SAAS,CAAS;IAClB,UAAU,CAAU;IAE5B,YAAY,OAAe,EAAE,aAAa,GAAkB,gBAAgB,EAAE,EAAE,SAAS,GAAG,CAAC,EAAE,UAAU,GAAG,KAAK,EAAE;QAClH,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,OAAO,EAAE,CAAC;IAAA,CACf;IAEO,OAAO,GAAS;QACvB,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;QACnF,IAAI,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;IAAA,CACtG;IAEQ,MAAM,CAAC,KAAa,EAAY;QACxC,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC;QACpC,MAAM,YAAY,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAClE,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QACzC,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QACrD,MAAM,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAI,CAAC,CAAC;QACnC,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAI,CAAC,CAAC;QACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/D,CAAC;QACD,OAAO,KAAK,CAAC;IAAA,CACb;CACD","sourcesContent":["import { Container, Markdown, type MarkdownTheme, Text } from \"@ashx-j/lunr-tui\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\n\n/** Markdown source for the live plan chat card. Full summary, no 500-char slice. */\nexport function planMessageMarkdown(summary: string): string {\n\treturn summary;\n}\n\n/**\n * Chat card for present_plan. Lives in the transcript so the dock dialog\n * can stay a short Approve / Decline chooser.\n */\nexport class PlanMessageComponent extends Container {\n\tprivate summary: string;\n\tprivate markdownTheme: MarkdownTheme;\n\tprivate outputPad: number;\n\tprivate gutterRail: boolean;\n\n\tconstructor(summary: string, markdownTheme: MarkdownTheme = getMarkdownTheme(), outputPad = 1, gutterRail = false) {\n\t\tsuper();\n\t\tthis.summary = summary;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.outputPad = outputPad;\n\t\tthis.gutterRail = gutterRail;\n\t\tthis.rebuild();\n\t}\n\n\tprivate rebuild(): void {\n\t\tthis.clear();\n\t\tthis.addChild(new Text(theme.fg(\"accent\", theme.bold(\"Plan\")), this.outputPad, 0));\n\t\tthis.addChild(new Markdown(planMessageMarkdown(this.summary), this.outputPad, 0, this.markdownTheme));\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst railEnabled = this.gutterRail;\n\t\tconst contentWidth = railEnabled ? Math.max(1, width - 2) : width;\n\t\tconst lines = super.render(contentWidth);\n\t\tif (!railEnabled || lines.length === 0) return lines;\n\t\tconst rail = theme.fg(\"dim\", \"│ \");\n\t\tconst close = theme.fg(\"dim\", \"╰ \");\n\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\tlines[i] = (i === lines.length - 1 ? close : rail) + lines[i];\n\t\t}\n\t\treturn lines;\n\t}\n}\n"]}