lsd-pi 1.3.7 → 1.3.10

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 (92) hide show
  1. package/README.md +82 -0
  2. package/dist/resources/extensions/mcp-client/index.js +230 -54
  3. package/dist/resources/extensions/mcp-client/mcp-manager-component.js +220 -0
  4. package/dist/resources/extensions/slash-commands/plan.js +72 -18
  5. package/dist/resources/extensions/subagent/agents.js +7 -0
  6. package/dist/resources/extensions/subagent/index.js +25 -8
  7. package/dist/resources/extensions/subagent/model-resolution.js +1 -0
  8. package/dist/resources/extensions/usage/index.js +34 -2
  9. package/dist/resources/extensions/voice/index.js +1 -0
  10. package/dist/resources/extensions/voice/push-to-talk.js +2 -0
  11. package/package.json +1 -1
  12. package/packages/pi-coding-agent/dist/core/agent-session.context-usage.test.d.ts +2 -0
  13. package/packages/pi-coding-agent/dist/core/agent-session.context-usage.test.d.ts.map +1 -0
  14. package/packages/pi-coding-agent/dist/core/agent-session.context-usage.test.js +72 -0
  15. package/packages/pi-coding-agent/dist/core/agent-session.context-usage.test.js.map +1 -0
  16. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +4 -0
  17. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  18. package/packages/pi-coding-agent/dist/core/agent-session.js +29 -2
  19. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  20. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  21. package/packages/pi-coding-agent/dist/core/extensions/runner.js +1 -0
  22. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  23. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -0
  24. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  25. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  26. package/packages/pi-coding-agent/dist/core/tool-priority.js +1 -1
  27. package/packages/pi-coding-agent/dist/core/tool-priority.js.map +1 -1
  28. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  29. package/packages/pi-coding-agent/dist/main.js +1 -0
  30. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  31. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-summary-line.test.js +104 -2
  32. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-summary-line.test.js.map +1 -1
  33. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +39 -2
  34. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  35. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +135 -18
  36. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  37. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +2 -0
  38. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  39. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +17 -1
  40. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  41. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.d.ts +21 -2
  42. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.d.ts.map +1 -1
  43. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.js +147 -9
  44. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.js.map +1 -1
  45. package/packages/pi-coding-agent/dist/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.js +51 -13
  46. package/packages/pi-coding-agent/dist/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.js.map +1 -1
  47. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  48. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +112 -18
  49. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  50. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts.map +1 -1
  51. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js +1 -0
  52. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js.map +1 -1
  53. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +4 -0
  54. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  55. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  56. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
  57. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  58. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +34 -4
  59. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  60. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  61. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +3 -0
  62. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  63. package/packages/pi-coding-agent/package.json +1 -1
  64. package/packages/pi-coding-agent/src/core/agent-session.context-usage.test.ts +87 -0
  65. package/packages/pi-coding-agent/src/core/agent-session.ts +40 -2
  66. package/packages/pi-coding-agent/src/core/extensions/runner.ts +1 -0
  67. package/packages/pi-coding-agent/src/core/extensions/types.ts +3 -0
  68. package/packages/pi-coding-agent/src/core/tool-priority.ts +1 -1
  69. package/packages/pi-coding-agent/src/main.ts +1 -0
  70. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-summary-line.test.ts +129 -2
  71. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +158 -18
  72. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +18 -1
  73. package/packages/pi-coding-agent/src/modes/interactive/components/tool-summary-line.ts +164 -10
  74. package/packages/pi-coding-agent/src/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.ts +60 -13
  75. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +123 -20
  76. package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts +1 -0
  77. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -0
  78. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +34 -4
  79. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +4 -0
  80. package/pkg/package.json +1 -1
  81. package/src/resources/extensions/mcp-client/index.ts +259 -58
  82. package/src/resources/extensions/mcp-client/mcp-manager-component.ts +256 -0
  83. package/src/resources/extensions/mcp-client/tests/mcp-manager-component.test.ts +141 -0
  84. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +32 -0
  85. package/src/resources/extensions/slash-commands/plan.ts +76 -19
  86. package/src/resources/extensions/subagent/agents.ts +9 -0
  87. package/src/resources/extensions/subagent/index.ts +30 -8
  88. package/src/resources/extensions/subagent/model-resolution.ts +1 -0
  89. package/src/resources/extensions/usage/index.ts +40 -2
  90. package/src/resources/extensions/voice/index.ts +1 -0
  91. package/src/resources/extensions/voice/push-to-talk.ts +3 -0
  92. package/src/resources/extensions/voice/tests/push-to-talk.test.ts +6 -0
@@ -1,3 +1,4 @@
1
+ import { basename } from "node:path";
1
2
  import { Container, Text } from "@gsd/pi-tui";
2
3
  import { theme } from "../theme/theme.js";
3
4
  // Tools that can be mixed together in one summary line
@@ -22,6 +23,8 @@ const TOOL_SUMMARY_DESCRIPTORS = {
22
23
  search_and_read: { action: "researching", singular: "topic", plural: "topics" },
23
24
  google_search: { action: "searching web for", singular: "query", plural: "queries" },
24
25
  };
26
+ const SPINNER_FRAMES = ["◯", "◔", "◑", "◕", "●"];
27
+ const SPINNER_INTERVAL_MS = 150;
25
28
  function formatCount(count, singular, plural) {
26
29
  return `${count} ${count === 1 ? singular : plural}`;
27
30
  }
@@ -35,23 +38,137 @@ function summarizeToolGroup(name, count) {
35
38
  }
36
39
  return `${descriptor.action} ${formatCount(count, descriptor.singular, descriptor.plural)}`;
37
40
  }
41
+ function capitalize(s) {
42
+ if (!s)
43
+ return s;
44
+ return s.charAt(0).toUpperCase() + s.slice(1);
45
+ }
46
+ export function extractToolLabel(toolName, args) {
47
+ switch (toolName) {
48
+ case "read": {
49
+ const path = (args.path ?? args.file_path);
50
+ return path ? basename(path) : toolName;
51
+ }
52
+ case "grep":
53
+ case "find": {
54
+ const pattern = args.pattern;
55
+ return pattern ?? toolName;
56
+ }
57
+ case "ls": {
58
+ const path = args.path;
59
+ return path ? basename(path) || path : ".";
60
+ }
61
+ case "lsp": {
62
+ const symbol = args.symbol;
63
+ const file = args.file;
64
+ if (symbol)
65
+ return symbol;
66
+ if (file)
67
+ return basename(file);
68
+ return toolName;
69
+ }
70
+ default:
71
+ return toolName;
72
+ }
73
+ }
38
74
  export class ToolSummaryLine extends Container {
39
75
  canGroupWith(toolName) {
40
- if (this.tools.length === 0)
76
+ if (this.tools.length === 0 && this.pendingTools.size === 0)
41
77
  return true;
42
- // Mixed-groupable tools can share a summary line regardless of order
43
- if (MIXED_GROUPABLE_TOOLS.has(toolName) && this.tools.every((t) => MIXED_GROUPABLE_TOOLS.has(t.name))) {
78
+ const allCompletedMixed = this.tools.every((t) => MIXED_GROUPABLE_TOOLS.has(t.name));
79
+ const allPendingMixed = [...this.pendingTools.values()].every((t) => MIXED_GROUPABLE_TOOLS.has(t.name));
80
+ if (MIXED_GROUPABLE_TOOLS.has(toolName) && allCompletedMixed && allPendingMixed) {
44
81
  return true;
45
82
  }
46
- // Otherwise only same-tool grouping
47
- return this.tools.every((tool) => tool.name === toolName);
83
+ return this.tools.every((tool) => tool.name === toolName)
84
+ && [...this.pendingTools.values()].every((tool) => tool.name === toolName);
48
85
  }
49
- constructor() {
86
+ constructor(ui) {
50
87
  super();
51
88
  this.tools = [];
89
+ this.pendingTools = new Map();
52
90
  this.hidden = false;
91
+ this.expandHint = "";
92
+ this.spinnerTimer = null;
93
+ this.spinnerFrame = 0;
94
+ this.lastToolLabel = "";
95
+ this.ui = ui;
53
96
  this.contentText = new Text("", 1, 0);
97
+ this.labelText = new Text("", 1, 0);
54
98
  this.addChild(this.contentText);
99
+ this.addChild(this.labelText);
100
+ }
101
+ setUI(ui) {
102
+ this.ui = ui;
103
+ }
104
+ setExpandHint(hint) {
105
+ this.expandHint = hint;
106
+ this.updateDisplay();
107
+ }
108
+ addPendingTool(toolCallId, name, args) {
109
+ const label = extractToolLabel(name, args);
110
+ this.pendingTools.set(toolCallId, { name, label });
111
+ this.lastToolLabel = label;
112
+ this.startSpinner();
113
+ this.updateDisplay();
114
+ }
115
+ removePendingTool(toolCallId) {
116
+ const removed = this.pendingTools.get(toolCallId);
117
+ this.pendingTools.delete(toolCallId);
118
+ if (removed) {
119
+ this.lastToolLabel = removed.label;
120
+ }
121
+ if (this.pendingTools.size === 0) {
122
+ this.stopSpinner();
123
+ }
124
+ else {
125
+ const lastPending = [...this.pendingTools.values()].at(-1);
126
+ if (lastPending)
127
+ this.lastToolLabel = lastPending.label;
128
+ }
129
+ this.updateDisplay();
130
+ }
131
+ hasPendingTools() {
132
+ return this.pendingTools.size > 0;
133
+ }
134
+ hasPendingTool(toolCallId) {
135
+ return this.pendingTools.has(toolCallId);
136
+ }
137
+ clearPendingTools() {
138
+ const lastPending = [...this.pendingTools.values()].at(-1);
139
+ if (lastPending) {
140
+ this.lastToolLabel = lastPending.label;
141
+ }
142
+ this.pendingTools.clear();
143
+ this.stopSpinner();
144
+ this.updateDisplay();
145
+ }
146
+ updatePendingToolArgs(toolCallId, args) {
147
+ const pending = this.pendingTools.get(toolCallId);
148
+ if (!pending)
149
+ return;
150
+ pending.label = extractToolLabel(pending.name, args);
151
+ this.lastToolLabel = pending.label;
152
+ this.updateDisplay();
153
+ }
154
+ startSpinner() {
155
+ if (this.spinnerTimer)
156
+ return;
157
+ this.spinnerTimer = setInterval(() => {
158
+ this.spinnerFrame = (this.spinnerFrame + 1) % SPINNER_FRAMES.length;
159
+ this.updateDisplay();
160
+ this.ui?.requestRender();
161
+ }, SPINNER_INTERVAL_MS);
162
+ this.spinnerTimer.unref?.();
163
+ }
164
+ stopSpinner() {
165
+ if (!this.spinnerTimer)
166
+ return;
167
+ clearInterval(this.spinnerTimer);
168
+ this.spinnerTimer = null;
169
+ }
170
+ dispose() {
171
+ this.stopSpinner();
55
172
  }
56
173
  addTool(name, elapsed) {
57
174
  this.tools.push({ name, elapsed });
@@ -65,16 +182,37 @@ export class ToolSummaryLine extends Container {
65
182
  this.updateDisplay();
66
183
  }
67
184
  render(width) {
68
- if (this.hidden || this.tools.length === 0) {
185
+ if (this.hidden || (this.tools.length === 0 && this.pendingTools.size === 0)) {
69
186
  return [];
70
187
  }
71
188
  return super.render(width);
72
189
  }
73
190
  updateDisplay() {
74
- if (this.tools.length === 0) {
191
+ if (this.tools.length === 0 && this.pendingTools.size === 0) {
75
192
  this.contentText.setText("");
193
+ this.labelText.setText("");
194
+ return;
195
+ }
196
+ if (this.pendingTools.size > 0) {
197
+ const counts = new Map();
198
+ for (const tool of this.tools) {
199
+ counts.set(tool.name, (counts.get(tool.name) ?? 0) + 1);
200
+ }
201
+ for (const tool of this.pendingTools.values()) {
202
+ counts.set(tool.name, (counts.get(tool.name) ?? 0) + 1);
203
+ }
204
+ const groupedTools = [...counts.entries()]
205
+ .map(([name, count]) => summarizeToolGroup(name, count))
206
+ .map((value, index) => index === 0 ? capitalize(value) : value)
207
+ .join(", ");
208
+ const spinner = theme.fg("accent", SPINNER_FRAMES[this.spinnerFrame]);
209
+ const hint = this.expandHint ? theme.fg("muted", ` ${this.expandHint}`) : "";
210
+ this.contentText.setText(`${spinner} ${theme.fg("text", groupedTools)}${theme.fg("muted", "…")}${hint}`);
211
+ const lastPending = [...this.pendingTools.values()].at(-1);
212
+ this.labelText.setText(lastPending ? theme.fg("muted", ` └ ${lastPending.label}`) : "");
76
213
  return;
77
214
  }
215
+ this.labelText.setText(this.lastToolLabel ? theme.fg("muted", ` └ ${this.lastToolLabel}`) : "");
78
216
  const counts = new Map();
79
217
  let totalElapsed = 0;
80
218
  for (const tool of this.tools) {
@@ -86,7 +224,7 @@ export class ToolSummaryLine extends Container {
86
224
  .join(" · ");
87
225
  const elapsed = (totalElapsed / 1000).toFixed(1);
88
226
  const indicator = theme.fg("success", "●");
89
- const details = theme.fg("muted", `${groupedTools} · ${elapsed}s`);
227
+ const details = theme.fg("text", groupedTools) + theme.fg("muted", ` · ${elapsed}s`);
90
228
  this.contentText.setText(`${indicator} ${details}`);
91
229
  }
92
230
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tool-summary-line.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-summary-line.ts"],"names":[],"mappings":"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","sourcesContent":["import { Container, Text } from \"@gsd/pi-tui\";\n\nimport { theme } from \"../theme/theme.js\";\n\ninterface CollapsedTool {\n\tname: string;\n\telapsed: number;\n}\n\n// Tools that can be mixed together in one summary line\nconst MIXED_GROUPABLE_TOOLS = new Set([\n\t\"read\", \"find\", \"ls\", \"grep\", \"lsp\",\n]);\n\ntype SummaryDescriptor = {\n\taction: string;\n\tsingular: string;\n\tplural: string;\n};\n\nconst TOOL_SUMMARY_DESCRIPTORS: Record<string, SummaryDescriptor> = {\n\tread: { action: \"reading\", singular: \"file\", plural: \"files\" },\n\twrite: { action: \"editing\", singular: \"file\", plural: \"files\" },\n\tedit: { action: \"editing\", singular: \"file\", plural: \"files\" },\n\tgrep: { action: \"searching for\", singular: \"pattern\", plural: \"patterns\" },\n\tfind: { action: \"finding\", singular: \"path\", plural: \"paths\" },\n\tls: { action: \"listing\", singular: \"directory\", plural: \"directories\" },\n\tlsp: { action: \"looking up\", singular: \"symbol\", plural: \"symbols\" },\n\tbash: { action: \"running\", singular: \"command\", plural: \"commands\" },\n\tbg_shell: { action: \"running\", singular: \"background command\", plural: \"background commands\" },\n\tfetch_page: { action: \"reading\", singular: \"page\", plural: \"pages\" },\n\tresolve_library: { action: \"searching for\", singular: \"library\", plural: \"libraries\" },\n\tget_library_docs: { action: \"reading\", singular: \"doc\", plural: \"docs\" },\n\tweb_search: { action: \"searching web for\", singular: \"query\", plural: \"queries\" },\n\t\"search-the-web\": { action: \"searching web for\", singular: \"query\", plural: \"queries\" },\n\tsearch_and_read: { action: \"researching\", singular: \"topic\", plural: \"topics\" },\n\tgoogle_search: { action: \"searching web for\", singular: \"query\", plural: \"queries\" },\n};\n\nfunction formatCount(count: number, singular: string, plural: string): string {\n\treturn `${count} ${count === 1 ? singular : plural}`;\n}\n\nfunction summarizeToolGroup(name: string, count: number): string {\n\tif (name.startsWith(\"browser_\")) {\n\t\treturn `using browser for ${formatCount(count, \"step\", \"steps\")}`;\n\t}\n\n\tconst descriptor = TOOL_SUMMARY_DESCRIPTORS[name];\n\tif (!descriptor) {\n\t\treturn count > 1 ? `${name} ×${count}` : name;\n\t}\n\n\treturn `${descriptor.action} ${formatCount(count, descriptor.singular, descriptor.plural)}`;\n}\n\nexport class ToolSummaryLine extends Container {\n\tprivate tools: CollapsedTool[] = [];\n\tprivate hidden = false;\n\tprivate contentText: Text;\n\n\tcanGroupWith(toolName: string): boolean {\n\t\tif (this.tools.length === 0) return true;\n\t\t// Mixed-groupable tools can share a summary line regardless of order\n\t\tif (MIXED_GROUPABLE_TOOLS.has(toolName) && this.tools.every((t) => MIXED_GROUPABLE_TOOLS.has(t.name))) {\n\t\t\treturn true;\n\t\t}\n\t\t// Otherwise only same-tool grouping\n\t\treturn this.tools.every((tool) => tool.name === toolName);\n\t}\n\n\tconstructor() {\n\t\tsuper();\n\t\tthis.contentText = new Text(\"\", 1, 0);\n\t\tthis.addChild(this.contentText);\n\t}\n\n\taddTool(name: string, elapsed: number): void {\n\t\tthis.tools.push({ name, elapsed });\n\t\tthis.updateDisplay();\n\t}\n\n\tsetHidden(hidden: boolean): void {\n\t\tthis.hidden = hidden;\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\toverride render(width: number): string[] {\n\t\tif (this.hidden || this.tools.length === 0) {\n\t\t\treturn [];\n\t\t}\n\t\treturn super.render(width);\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tif (this.tools.length === 0) {\n\t\t\tthis.contentText.setText(\"\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst counts = new Map<string, number>();\n\t\tlet totalElapsed = 0;\n\t\tfor (const tool of this.tools) {\n\t\t\tcounts.set(tool.name, (counts.get(tool.name) ?? 0) + 1);\n\t\t\ttotalElapsed += tool.elapsed;\n\t\t}\n\n\t\tconst groupedTools = [...counts.entries()]\n\t\t\t.map(([name, count]) => summarizeToolGroup(name, count))\n\t\t\t.join(\" · \");\n\t\tconst elapsed = (totalElapsed / 1000).toFixed(1);\n\t\tconst indicator = theme.fg(\"success\", \"●\");\n\t\tconst details = theme.fg(\"muted\", `${groupedTools} · ${elapsed}s`);\n\t\tthis.contentText.setText(`${indicator} ${details}`);\n\t}\n}\n"]}
1
+ {"version":3,"file":"tool-summary-line.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-summary-line.ts"],"names":[],"mappings":"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","sourcesContent":["import { basename } from \"node:path\";\nimport { Container, Text, type TUI } from \"@gsd/pi-tui\";\n\nimport { theme } from \"../theme/theme.js\";\n\ninterface CollapsedTool {\n\tname: string;\n\telapsed: number;\n}\n\ninterface PendingTool {\n\tname: string;\n\tlabel: string;\n}\n\n// Tools that can be mixed together in one summary line\nconst MIXED_GROUPABLE_TOOLS = new Set([\n\t\"read\", \"find\", \"ls\", \"grep\", \"lsp\",\n]);\n\ntype SummaryDescriptor = {\n\taction: string;\n\tsingular: string;\n\tplural: string;\n};\n\nconst TOOL_SUMMARY_DESCRIPTORS: Record<string, SummaryDescriptor> = {\n\tread: { action: \"reading\", singular: \"file\", plural: \"files\" },\n\twrite: { action: \"editing\", singular: \"file\", plural: \"files\" },\n\tedit: { action: \"editing\", singular: \"file\", plural: \"files\" },\n\tgrep: { action: \"searching for\", singular: \"pattern\", plural: \"patterns\" },\n\tfind: { action: \"finding\", singular: \"path\", plural: \"paths\" },\n\tls: { action: \"listing\", singular: \"directory\", plural: \"directories\" },\n\tlsp: { action: \"looking up\", singular: \"symbol\", plural: \"symbols\" },\n\tbash: { action: \"running\", singular: \"command\", plural: \"commands\" },\n\tbg_shell: { action: \"running\", singular: \"background command\", plural: \"background commands\" },\n\tfetch_page: { action: \"reading\", singular: \"page\", plural: \"pages\" },\n\tresolve_library: { action: \"searching for\", singular: \"library\", plural: \"libraries\" },\n\tget_library_docs: { action: \"reading\", singular: \"doc\", plural: \"docs\" },\n\tweb_search: { action: \"searching web for\", singular: \"query\", plural: \"queries\" },\n\t\"search-the-web\": { action: \"searching web for\", singular: \"query\", plural: \"queries\" },\n\tsearch_and_read: { action: \"researching\", singular: \"topic\", plural: \"topics\" },\n\tgoogle_search: { action: \"searching web for\", singular: \"query\", plural: \"queries\" },\n};\n\nconst SPINNER_FRAMES = [\"◯\", \"◔\", \"◑\", \"◕\", \"●\"];\nconst SPINNER_INTERVAL_MS = 150;\n\nfunction formatCount(count: number, singular: string, plural: string): string {\n\treturn `${count} ${count === 1 ? singular : plural}`;\n}\n\nfunction summarizeToolGroup(name: string, count: number): string {\n\tif (name.startsWith(\"browser_\")) {\n\t\treturn `using browser for ${formatCount(count, \"step\", \"steps\")}`;\n\t}\n\n\tconst descriptor = TOOL_SUMMARY_DESCRIPTORS[name];\n\tif (!descriptor) {\n\t\treturn count > 1 ? `${name} ×${count}` : name;\n\t}\n\n\treturn `${descriptor.action} ${formatCount(count, descriptor.singular, descriptor.plural)}`;\n}\n\nfunction capitalize(s: string): string {\n\tif (!s) return s;\n\treturn s.charAt(0).toUpperCase() + s.slice(1);\n}\n\nexport function extractToolLabel(toolName: string, args: Record<string, unknown>): string {\n\tswitch (toolName) {\n\t\tcase \"read\": {\n\t\t\tconst path = (args.path ?? args.file_path) as string | undefined;\n\t\t\treturn path ? basename(path) : toolName;\n\t\t}\n\t\tcase \"grep\":\n\t\tcase \"find\": {\n\t\t\tconst pattern = args.pattern as string | undefined;\n\t\t\treturn pattern ?? toolName;\n\t\t}\n\t\tcase \"ls\": {\n\t\t\tconst path = args.path as string | undefined;\n\t\t\treturn path ? basename(path) || path : \".\";\n\t\t}\n\t\tcase \"lsp\": {\n\t\t\tconst symbol = args.symbol as string | undefined;\n\t\t\tconst file = args.file as string | undefined;\n\t\t\tif (symbol) return symbol;\n\t\t\tif (file) return basename(file);\n\t\t\treturn toolName;\n\t\t}\n\t\tdefault:\n\t\t\treturn toolName;\n\t}\n}\n\nexport class ToolSummaryLine extends Container {\n\tprivate tools: CollapsedTool[] = [];\n\tprivate pendingTools: Map<string, PendingTool> = new Map();\n\tprivate hidden = false;\n\tprivate contentText: Text;\n\tprivate labelText: Text;\n\tprivate expandHint = \"\";\n\tprivate ui?: TUI;\n\tprivate spinnerTimer: NodeJS.Timeout | null = null;\n\tprivate spinnerFrame = 0;\n\tprivate lastToolLabel = \"\";\n\n\tcanGroupWith(toolName: string): boolean {\n\t\tif (this.tools.length === 0 && this.pendingTools.size === 0) return true;\n\t\tconst allCompletedMixed = this.tools.every((t) => MIXED_GROUPABLE_TOOLS.has(t.name));\n\t\tconst allPendingMixed = [...this.pendingTools.values()].every((t) => MIXED_GROUPABLE_TOOLS.has(t.name));\n\t\tif (MIXED_GROUPABLE_TOOLS.has(toolName) && allCompletedMixed && allPendingMixed) {\n\t\t\treturn true;\n\t\t}\n\t\treturn this.tools.every((tool) => tool.name === toolName)\n\t\t\t&& [...this.pendingTools.values()].every((tool) => tool.name === toolName);\n\t}\n\n\tconstructor(ui?: TUI) {\n\t\tsuper();\n\t\tthis.ui = ui;\n\t\tthis.contentText = new Text(\"\", 1, 0);\n\t\tthis.labelText = new Text(\"\", 1, 0);\n\t\tthis.addChild(this.contentText);\n\t\tthis.addChild(this.labelText);\n\t}\n\n\tsetUI(ui: TUI): void {\n\t\tthis.ui = ui;\n\t}\n\n\tsetExpandHint(hint: string): void {\n\t\tthis.expandHint = hint;\n\t\tthis.updateDisplay();\n\t}\n\n\taddPendingTool(toolCallId: string, name: string, args: Record<string, unknown>): void {\n\t\tconst label = extractToolLabel(name, args);\n\t\tthis.pendingTools.set(toolCallId, { name, label });\n\t\tthis.lastToolLabel = label;\n\t\tthis.startSpinner();\n\t\tthis.updateDisplay();\n\t}\n\n\tremovePendingTool(toolCallId: string): void {\n\t\tconst removed = this.pendingTools.get(toolCallId);\n\t\tthis.pendingTools.delete(toolCallId);\n\t\tif (removed) {\n\t\t\tthis.lastToolLabel = removed.label;\n\t\t}\n\t\tif (this.pendingTools.size === 0) {\n\t\t\tthis.stopSpinner();\n\t\t} else {\n\t\t\tconst lastPending = [...this.pendingTools.values()].at(-1);\n\t\t\tif (lastPending) this.lastToolLabel = lastPending.label;\n\t\t}\n\t\tthis.updateDisplay();\n\t}\n\n\thasPendingTools(): boolean {\n\t\treturn this.pendingTools.size > 0;\n\t}\n\n\thasPendingTool(toolCallId: string): boolean {\n\t\treturn this.pendingTools.has(toolCallId);\n\t}\n\n\tclearPendingTools(): void {\n\t\tconst lastPending = [...this.pendingTools.values()].at(-1);\n\t\tif (lastPending) {\n\t\t\tthis.lastToolLabel = lastPending.label;\n\t\t}\n\t\tthis.pendingTools.clear();\n\t\tthis.stopSpinner();\n\t\tthis.updateDisplay();\n\t}\n\n\tupdatePendingToolArgs(toolCallId: string, args: Record<string, unknown>): void {\n\t\tconst pending = this.pendingTools.get(toolCallId);\n\t\tif (!pending) return;\n\t\tpending.label = extractToolLabel(pending.name, args);\n\t\tthis.lastToolLabel = pending.label;\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate startSpinner(): void {\n\t\tif (this.spinnerTimer) return;\n\t\tthis.spinnerTimer = setInterval(() => {\n\t\t\tthis.spinnerFrame = (this.spinnerFrame + 1) % SPINNER_FRAMES.length;\n\t\t\tthis.updateDisplay();\n\t\t\tthis.ui?.requestRender();\n\t\t}, SPINNER_INTERVAL_MS);\n\t\tthis.spinnerTimer.unref?.();\n\t}\n\n\tprivate stopSpinner(): void {\n\t\tif (!this.spinnerTimer) return;\n\t\tclearInterval(this.spinnerTimer);\n\t\tthis.spinnerTimer = null;\n\t}\n\n\tdispose(): void {\n\t\tthis.stopSpinner();\n\t}\n\n\taddTool(name: string, elapsed: number): void {\n\t\tthis.tools.push({ name, elapsed });\n\t\tthis.updateDisplay();\n\t}\n\n\tsetHidden(hidden: boolean): void {\n\t\tthis.hidden = hidden;\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\toverride render(width: number): string[] {\n\t\tif (this.hidden || (this.tools.length === 0 && this.pendingTools.size === 0)) {\n\t\t\treturn [];\n\t\t}\n\t\treturn super.render(width);\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tif (this.tools.length === 0 && this.pendingTools.size === 0) {\n\t\t\tthis.contentText.setText(\"\");\n\t\t\tthis.labelText.setText(\"\");\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.pendingTools.size > 0) {\n\t\t\tconst counts = new Map<string, number>();\n\t\t\tfor (const tool of this.tools) {\n\t\t\t\tcounts.set(tool.name, (counts.get(tool.name) ?? 0) + 1);\n\t\t\t}\n\t\t\tfor (const tool of this.pendingTools.values()) {\n\t\t\t\tcounts.set(tool.name, (counts.get(tool.name) ?? 0) + 1);\n\t\t\t}\n\n\t\t\tconst groupedTools = [...counts.entries()]\n\t\t\t\t.map(([name, count]) => summarizeToolGroup(name, count))\n\t\t\t\t.map((value, index) => index === 0 ? capitalize(value) : value)\n\t\t\t\t.join(\", \");\n\t\t\tconst spinner = theme.fg(\"accent\", SPINNER_FRAMES[this.spinnerFrame]);\n\t\t\tconst hint = this.expandHint ? theme.fg(\"muted\", ` ${this.expandHint}`) : \"\";\n\t\t\tthis.contentText.setText(`${spinner} ${theme.fg(\"text\", groupedTools)}${theme.fg(\"muted\", \"…\")}${hint}`);\n\n\t\t\tconst lastPending = [...this.pendingTools.values()].at(-1);\n\t\t\tthis.labelText.setText(lastPending ? theme.fg(\"muted\", ` └ ${lastPending.label}`) : \"\");\n\t\t\treturn;\n\t\t}\n\n\t\tthis.labelText.setText(this.lastToolLabel ? theme.fg(\"muted\", ` └ ${this.lastToolLabel}`) : \"\");\n\t\tconst counts = new Map<string, number>();\n\t\tlet totalElapsed = 0;\n\t\tfor (const tool of this.tools) {\n\t\t\tcounts.set(tool.name, (counts.get(tool.name) ?? 0) + 1);\n\t\t\ttotalElapsed += tool.elapsed;\n\t\t}\n\n\t\tconst groupedTools = [...counts.entries()]\n\t\t\t.map(([name, count]) => summarizeToolGroup(name, count))\n\t\t\t.join(\" · \");\n\t\tconst elapsed = (totalElapsed / 1000).toFixed(1);\n\t\tconst indicator = theme.fg(\"success\", \"●\");\n\t\tconst details = theme.fg(\"text\", groupedTools) + theme.fg(\"muted\", ` · ${elapsed}s`);\n\t\tthis.contentText.setText(`${indicator} ${details}`);\n\t}\n}\n"]}
@@ -105,15 +105,19 @@ function createHost(options = {}) {
105
105
  };
106
106
  }
107
107
  function addPendingTool(host, toolCallId, elapsed) {
108
- const state = { hidden: false, component: undefined };
108
+ const state = { hidden: false, component: undefined, indented: false };
109
109
  const component = {
110
110
  render: () => (state.hidden ? [] : ["tool"]),
111
111
  updateResult: () => { },
112
+ updateArgs: () => { },
112
113
  setHidden: (hidden) => {
113
114
  state.hidden = hidden;
114
115
  },
115
116
  isHidden: () => !!state.hidden,
116
117
  setArgsComplete: () => { },
118
+ setIndented: (indented) => {
119
+ state.indented = indented;
120
+ },
117
121
  getElapsed: () => elapsed,
118
122
  };
119
123
  state.component = component;
@@ -156,7 +160,7 @@ describe("chat-controller collapsed tool summary lifecycle", () => {
156
160
  await handleAgentEvent(host, toolEndEvent("tool-1", "read"));
157
161
  assert.equal(summaryLines(host).length, 1);
158
162
  });
159
- it("reveals initially hidden on-error tools when they fail", async () => {
163
+ it("keeps on-error tools visible when they fail", async () => {
160
164
  const host = createHost();
161
165
  await handleAgentEvent(host, {
162
166
  type: "message_start",
@@ -165,7 +169,7 @@ describe("chat-controller collapsed tool summary lifecycle", () => {
165
169
  await handleAgentEvent(host, toolStartEvent("tool-1", "bash", { command: "exit 1" }));
166
170
  const pending = host.pendingTools.get("tool-1");
167
171
  assert.ok(pending);
168
- assert.equal(pending.isHidden(), true);
172
+ assert.equal(pending.isHidden(), false);
169
173
  await handleAgentEvent(host, {
170
174
  type: "tool_execution_end",
171
175
  toolCallId: "tool-1",
@@ -198,22 +202,34 @@ describe("chat-controller collapsed tool summary lifecycle", () => {
198
202
  assert.equal(summaries.length, 1);
199
203
  assert.ok(stripAnsi(summaries[0].render(160).join("\n")).includes("reading 2 files · 1.0s"));
200
204
  });
201
- it("does not group web fetches", async () => {
205
+ it("keeps last grouped tool label visible after completion", async () => {
202
206
  const host = createHost();
203
207
  await handleAgentEvent(host, {
204
208
  type: "message_start",
205
209
  message: assistantMessage(),
206
210
  });
207
- addPendingTool(host, "tool-1", 200);
211
+ await handleAgentEvent(host, toolStartEvent("tool-1", "read", { path: "README.md" }));
212
+ await handleAgentEvent(host, toolEndEvent("tool-1", "read"));
213
+ const summaries = summaryLines(host);
214
+ assert.equal(summaries.length, 1);
215
+ assert.ok(stripAnsi(summaries[0].render(160).join("\n")).includes("└ README.md"));
216
+ });
217
+ it("keeps non-groupable web fetches visible", async () => {
218
+ const host = createHost();
219
+ await handleAgentEvent(host, {
220
+ type: "message_start",
221
+ message: assistantMessage(),
222
+ });
223
+ const first = addPendingTool(host, "tool-1", 200);
208
224
  await handleAgentEvent(host, toolEndEvent("tool-1", "fetch_page"));
209
- addPendingTool(host, "tool-2", 300);
225
+ const second = addPendingTool(host, "tool-2", 300);
210
226
  await handleAgentEvent(host, toolEndEvent("tool-2", "fetch_page"));
211
227
  const summaries = summaryLines(host);
212
- assert.equal(summaries.length, 2);
213
- assert.ok(stripAnsi(summaries[0].render(160).join("\n")).includes("reading 1 page · 0.2s"));
214
- assert.ok(stripAnsi(summaries[1].render(160).join("\n")).includes("reading 1 page · 0.3s"));
228
+ assert.equal(summaries.length, 0);
229
+ assert.equal(first.hidden, false);
230
+ assert.equal(second.hidden, false);
215
231
  });
216
- it("keeps different collapsed tool types in separate summaries", async () => {
232
+ it("groups mixed collapsed file/nav tools into one summary", async () => {
217
233
  const host = createHost();
218
234
  await handleAgentEvent(host, {
219
235
  type: "message_start",
@@ -224,9 +240,10 @@ describe("chat-controller collapsed tool summary lifecycle", () => {
224
240
  addPendingTool(host, "tool-2", 300);
225
241
  await handleAgentEvent(host, toolEndEvent("tool-2", "find"));
226
242
  const summaries = summaryLines(host);
227
- assert.equal(summaries.length, 2);
228
- assert.ok(stripAnsi(summaries[0].render(160).join("\n")).includes("reading 1 file · 0.2s"));
229
- assert.ok(stripAnsi(summaries[1].render(160).join("\n")).includes("finding 1 path · 0.3s"));
243
+ assert.equal(summaries.length, 1);
244
+ const rendered = stripAnsi(summaries[0].render(160).join("\n"));
245
+ assert.ok(rendered.includes("reading 1 file"));
246
+ assert.ok(rendered.includes("finding 1 path"));
230
247
  });
231
248
  it("resets grouping after visible tool result", async () => {
232
249
  const host = createHost();
@@ -287,6 +304,27 @@ describe("chat-controller collapsed tool summary lifecycle", () => {
287
304
  assert.ok(stripAnsi(summaries[0].render(160).join("\n")).includes("0.3s"));
288
305
  assert.ok(stripAnsi(summaries[1].render(160).join("\n")).includes("0.4s"));
289
306
  });
307
+ it("stops grouped spinner on aborted assistant message", async () => {
308
+ const host = createHost();
309
+ await handleAgentEvent(host, {
310
+ type: "message_start",
311
+ message: assistantMessage(),
312
+ });
313
+ await handleAgentEvent(host, toolStartEvent("tool-1", "read", { path: "README.md" }));
314
+ await handleAgentEvent(host, {
315
+ type: "message_end",
316
+ message: {
317
+ ...assistantMessage(),
318
+ stopReason: "aborted",
319
+ errorMessage: "Operation aborted",
320
+ },
321
+ });
322
+ const summaries = summaryLines(host);
323
+ assert.equal(summaries.length, 1);
324
+ const rendered = stripAnsi(summaries[0].render(160).join("\n"));
325
+ assert.ok(!rendered.includes("…"));
326
+ assert.ok(rendered.includes("README.md") || rendered === "");
327
+ });
290
328
  it("keeps collapsed tool calls visible in intermediate mode", async () => {
291
329
  const host = createHost({ collapseToolCalls: true, collapsedToolCallsExpanded: true });
292
330
  await handleAgentEvent(host, {
@@ -1 +1 @@
1
- {"version":3,"file":"chat-controller.collapsed-tool-summary.test.js","sourceRoot":"","sources":["../../../../../src/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport stripAnsi from \"strip-ansi\";\n\nimport { handleAgentEvent } from \"../chat-controller.js\";\nimport { ToolSummaryLine } from \"../../components/tool-summary-line.js\";\nimport { getMarkdownTheme, initTheme } from \"../../theme/theme.js\";\n\ninitTheme(\"dark\");\n\nfunction assistantMessage(content: any[] = []): any {\n return {\n role: \"assistant\",\n content,\n timestamp: Date.now(),\n };\n}\n\nfunction toolStartEvent(toolCallId: string, toolName: string, args: Record<string, unknown> = {}): any {\n return {\n type: \"tool_execution_start\",\n toolCallId,\n toolName,\n args,\n };\n}\n\nfunction toolEndEvent(toolCallId: string, toolName: string): any {\n return {\n type: \"tool_execution_end\",\n toolCallId,\n toolName,\n isError: false,\n result: {\n content: [],\n details: {},\n },\n };\n}\n\nfunction createChatContainer() {\n return {\n children: [] as any[],\n addChild(child: any) {\n this.children.push(child);\n },\n removeChild(child: any) {\n this.children = this.children.filter((c) => c !== child);\n },\n clear() {\n this.children = [];\n },\n };\n}\n\nfunction createHost(options: { collapseToolCalls?: boolean; collapsedToolCallsExpanded?: boolean; toolOutputExpanded?: boolean } = {}): any {\n const chatContainer = createChatContainer();\n return {\n isInitialized: true,\n init: async () => { },\n ui: {\n requestRender: () => { },\n terminal: { write: () => { } },\n },\n footer: { invalidate: () => { } },\n statusContainer: { clear: () => { }, addChild: () => { } },\n chatContainer,\n settingsManager: {\n getTimestampFormat: () => \"date-time-iso\",\n getShowImages: () => true,\n getToolOutputMode: () => \"normal\",\n getEditorScheme: () => \"auto\",\n getCollapseToolCalls: () => options.collapseToolCalls ?? true,\n },\n pendingTools: new Map(),\n collapsedToolSummaryLine: undefined,\n collapsedToolCallsExpanded: options.collapsedToolCallsExpanded ?? options.toolOutputExpanded ?? false,\n toolOutputExpanded: options.toolOutputExpanded ?? false,\n hideThinkingBlock: false,\n notificationSoundEnabled: false,\n defaultEditor: { onEscape: undefined, bottomHint: \"\" },\n session: {\n thinkingLevel: \"off\",\n retryAttempt: 0,\n abortCompaction: () => { },\n abortRetry: () => { },\n },\n keybindings: {},\n pendingMessagesContainer: { clear: () => { } },\n compactionQueuedMessages: [],\n defaultWorkingMessage: \"\",\n workingMessages: [],\n startLoadingTips: () => { },\n stopLoadingTips: () => { },\n getMarkdownThemeWithSettings: () => getMarkdownTheme(),\n addMessageToChat: () => { },\n formatWebSearchResult: () => \"\",\n getRegisteredToolDefinition: () => undefined,\n checkShutdownRequested: async () => { },\n rebuildChatFromMessages: () => { },\n flushCompactionQueue: async () => { },\n showStatus: () => { },\n showError: () => { },\n updatePendingMessagesDisplay: () => { },\n updateTerminalTitle: () => { },\n updateEditorBorderColor: () => { },\n updateEditorExpandHint: () => { },\n getAgentPtyComponent: () => undefined,\n ensureAgentPtyComponent: () => undefined,\n updateAgentPtyComponent: () => { },\n clearAgentPtyComponents: () => { },\n };\n}\n\nfunction addPendingTool(host: any, toolCallId: string, elapsed: number): { hidden?: boolean; component: any } {\n const state: { hidden?: boolean; component: any } = { hidden: false, component: undefined };\n const component = {\n render: () => (state.hidden ? [] : [\"tool\"]),\n updateResult: () => { },\n setHidden: (hidden: boolean) => {\n state.hidden = hidden;\n },\n isHidden: () => !!state.hidden,\n setArgsComplete: () => { },\n getElapsed: () => elapsed,\n };\n state.component = component;\n host.chatContainer.addChild(component);\n host.pendingTools.set(toolCallId, component);\n return state;\n}\n\nfunction summaryLines(host: any): ToolSummaryLine[] {\n return host.chatContainer.children.filter((child: any) => child instanceof ToolSummaryLine);\n}\n\ndescribe(\"chat-controller collapsed tool summary lifecycle\", () => {\n it(\"hides collapsible tool calls immediately to avoid blink before grouping\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n await handleAgentEvent(host, toolStartEvent(\"tool-1\", \"read\", { path: \"README.md\" }));\n const pending = host.pendingTools.get(\"tool-1\");\n assert.ok(pending);\n assert.equal(pending.isHidden(), true);\n\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n assert.equal(summaryLines(host).length, 1);\n });\n\n it(\"hides streamed tool-call blocks immediately to avoid blink before grouping\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n await handleAgentEvent(host, {\n type: \"message_update\",\n message: assistantMessage([\n { type: \"toolCall\", id: \"tool-1\", name: \"read\", arguments: { path: \"README.md\" } },\n ]),\n } as any);\n\n const pending = host.pendingTools.get(\"tool-1\");\n assert.ok(pending);\n assert.equal(pending.isHidden(), true);\n\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n assert.equal(summaryLines(host).length, 1);\n });\n\n it(\"reveals initially hidden on-error tools when they fail\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n await handleAgentEvent(host, toolStartEvent(\"tool-1\", \"bash\", { command: \"exit 1\" }));\n const pending = host.pendingTools.get(\"tool-1\");\n assert.ok(pending);\n assert.equal(pending.isHidden(), true);\n\n await handleAgentEvent(host, {\n type: \"tool_execution_end\",\n toolCallId: \"tool-1\",\n toolName: \"bash\",\n isError: true,\n result: {\n content: [{ type: \"text\", text: \"failed\" }],\n details: {},\n },\n });\n\n assert.equal(summaryLines(host).length, 0);\n assert.equal(pending.isHidden(), false);\n });\n\n it(\"groups consecutive identical collapsed tools\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n const first = addPendingTool(host, \"tool-1\", 400);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n assert.equal(host.chatContainer.children.indexOf(summaryLines(host)[0]), host.chatContainer.children.indexOf(first.component) - 1);\n\n await handleAgentEvent(host, {\n type: \"message_update\",\n message: assistantMessage([{ type: \"text\", text: \"streaming text\" }]),\n } as any);\n\n addPendingTool(host, \"tool-2\", 600);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 1);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"reading 2 files · 1.0s\"));\n });\n\n it(\"does not group web fetches\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-1\", 200);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"fetch_page\"));\n\n addPendingTool(host, \"tool-2\", 300);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"fetch_page\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 2);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"reading 1 page · 0.2s\"));\n assert.ok(stripAnsi(summaries[1].render(160).join(\"\\n\")).includes(\"reading 1 page · 0.3s\"));\n });\n\n it(\"keeps different collapsed tool types in separate summaries\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-1\", 200);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n addPendingTool(host, \"tool-2\", 300);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"find\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 2);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"reading 1 file · 0.2s\"));\n assert.ok(stripAnsi(summaries[1].render(160).join(\"\\n\")).includes(\"finding 1 path · 0.3s\"));\n });\n\n it(\"resets grouping after visible tool result\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-1\", 200);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n const visibleTool = addPendingTool(host, \"tool-2\", 300);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"write\"));\n assert.equal(visibleTool.hidden, false);\n\n addPendingTool(host, \"tool-3\", 400);\n await handleAgentEvent(host, toolEndEvent(\"tool-3\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 2);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"0.2s\"));\n assert.ok(stripAnsi(summaries[1].render(160).join(\"\\n\")).includes(\"0.4s\"));\n });\n\n it(\"groups identical collapsed tools across empty assistant message boundaries\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-1\", 300);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-2\", 400);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 1);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"reading 2 files · 0.7s\"));\n });\n\n it(\"starts new collapsed group after visible assistant content\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-1\", 300);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n await handleAgentEvent(host, {\n type: \"message_update\",\n message: assistantMessage([{ type: \"text\", text: \"visible reply\" }]),\n } as any);\n\n addPendingTool(host, \"tool-2\", 400);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 2);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"0.3s\"));\n assert.ok(stripAnsi(summaries[1].render(160).join(\"\\n\")).includes(\"0.4s\"));\n });\n\n it(\"keeps collapsed tool calls visible in intermediate mode\", async () => {\n const host = createHost({ collapseToolCalls: true, collapsedToolCallsExpanded: true });\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n const tool = addPendingTool(host, \"tool-1\", 250);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(tool.hidden, false);\n assert.equal(summaries.length, 1);\n assert.deepEqual(summaries[0].render(160), []);\n });\n\n it(\"keeps collapsed tools visible when verbose mode is active\", async () => {\n const host = createHost({ collapseToolCalls: true, toolOutputExpanded: true });\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n const tool = addPendingTool(host, \"tool-1\", 250);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(tool.hidden, false);\n assert.equal(summaries.length, 1);\n assert.deepEqual(summaries[0].render(160), []);\n });\n\n it(\"does not collapse tool calls when setting is disabled\", async () => {\n const host = createHost({ collapseToolCalls: false });\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n const tool = addPendingTool(host, \"tool-1\", 250);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n assert.equal(tool.hidden, false);\n assert.equal(summaryLines(host).length, 0);\n });\n});\n"]}
1
+ {"version":3,"file":"chat-controller.collapsed-tool-summary.test.js","sourceRoot":"","sources":["../../../../../src/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport stripAnsi from \"strip-ansi\";\n\nimport { handleAgentEvent } from \"../chat-controller.js\";\nimport { ToolSummaryLine } from \"../../components/tool-summary-line.js\";\nimport { getMarkdownTheme, initTheme } from \"../../theme/theme.js\";\n\ninitTheme(\"dark\");\n\nfunction assistantMessage(content: any[] = []): any {\n return {\n role: \"assistant\",\n content,\n timestamp: Date.now(),\n };\n}\n\nfunction toolStartEvent(toolCallId: string, toolName: string, args: Record<string, unknown> = {}): any {\n return {\n type: \"tool_execution_start\",\n toolCallId,\n toolName,\n args,\n };\n}\n\nfunction toolEndEvent(toolCallId: string, toolName: string): any {\n return {\n type: \"tool_execution_end\",\n toolCallId,\n toolName,\n isError: false,\n result: {\n content: [],\n details: {},\n },\n };\n}\n\nfunction createChatContainer() {\n return {\n children: [] as any[],\n addChild(child: any) {\n this.children.push(child);\n },\n removeChild(child: any) {\n this.children = this.children.filter((c) => c !== child);\n },\n clear() {\n this.children = [];\n },\n };\n}\n\nfunction createHost(options: { collapseToolCalls?: boolean; collapsedToolCallsExpanded?: boolean; toolOutputExpanded?: boolean } = {}): any {\n const chatContainer = createChatContainer();\n return {\n isInitialized: true,\n init: async () => { },\n ui: {\n requestRender: () => { },\n terminal: { write: () => { } },\n },\n footer: { invalidate: () => { } },\n statusContainer: { clear: () => { }, addChild: () => { } },\n chatContainer,\n settingsManager: {\n getTimestampFormat: () => \"date-time-iso\",\n getShowImages: () => true,\n getToolOutputMode: () => \"normal\",\n getEditorScheme: () => \"auto\",\n getCollapseToolCalls: () => options.collapseToolCalls ?? true,\n },\n pendingTools: new Map(),\n collapsedToolSummaryLine: undefined,\n collapsedToolCallsExpanded: options.collapsedToolCallsExpanded ?? options.toolOutputExpanded ?? false,\n toolOutputExpanded: options.toolOutputExpanded ?? false,\n hideThinkingBlock: false,\n notificationSoundEnabled: false,\n defaultEditor: { onEscape: undefined, bottomHint: \"\" },\n session: {\n thinkingLevel: \"off\",\n retryAttempt: 0,\n abortCompaction: () => { },\n abortRetry: () => { },\n },\n keybindings: {},\n pendingMessagesContainer: { clear: () => { } },\n compactionQueuedMessages: [],\n defaultWorkingMessage: \"\",\n workingMessages: [],\n startLoadingTips: () => { },\n stopLoadingTips: () => { },\n getMarkdownThemeWithSettings: () => getMarkdownTheme(),\n addMessageToChat: () => { },\n formatWebSearchResult: () => \"\",\n getRegisteredToolDefinition: () => undefined,\n checkShutdownRequested: async () => { },\n rebuildChatFromMessages: () => { },\n flushCompactionQueue: async () => { },\n showStatus: () => { },\n showError: () => { },\n updatePendingMessagesDisplay: () => { },\n updateTerminalTitle: () => { },\n updateEditorBorderColor: () => { },\n updateEditorExpandHint: () => { },\n getAgentPtyComponent: () => undefined,\n ensureAgentPtyComponent: () => undefined,\n updateAgentPtyComponent: () => { },\n clearAgentPtyComponents: () => { },\n };\n}\n\nfunction addPendingTool(host: any, toolCallId: string, elapsed: number): { hidden?: boolean; component: any } {\n const state: { hidden?: boolean; component: any; indented?: boolean } = { hidden: false, component: undefined, indented: false };\n const component = {\n render: () => (state.hidden ? [] : [\"tool\"]),\n updateResult: () => { },\n updateArgs: () => { },\n setHidden: (hidden: boolean) => {\n state.hidden = hidden;\n },\n isHidden: () => !!state.hidden,\n setArgsComplete: () => { },\n setIndented: (indented: boolean) => {\n state.indented = indented;\n },\n getElapsed: () => elapsed,\n };\n state.component = component;\n host.chatContainer.addChild(component);\n host.pendingTools.set(toolCallId, component);\n return state;\n}\n\nfunction summaryLines(host: any): ToolSummaryLine[] {\n return host.chatContainer.children.filter((child: any) => child instanceof ToolSummaryLine);\n}\n\ndescribe(\"chat-controller collapsed tool summary lifecycle\", () => {\n it(\"hides collapsible tool calls immediately to avoid blink before grouping\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n await handleAgentEvent(host, toolStartEvent(\"tool-1\", \"read\", { path: \"README.md\" }));\n const pending = host.pendingTools.get(\"tool-1\");\n assert.ok(pending);\n assert.equal(pending.isHidden(), true);\n\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n assert.equal(summaryLines(host).length, 1);\n });\n\n it(\"hides streamed tool-call blocks immediately to avoid blink before grouping\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n await handleAgentEvent(host, {\n type: \"message_update\",\n message: assistantMessage([\n { type: \"toolCall\", id: \"tool-1\", name: \"read\", arguments: { path: \"README.md\" } },\n ]),\n } as any);\n\n const pending = host.pendingTools.get(\"tool-1\");\n assert.ok(pending);\n assert.equal(pending.isHidden(), true);\n\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n assert.equal(summaryLines(host).length, 1);\n });\n\n it(\"keeps on-error tools visible when they fail\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n await handleAgentEvent(host, toolStartEvent(\"tool-1\", \"bash\", { command: \"exit 1\" }));\n const pending = host.pendingTools.get(\"tool-1\");\n assert.ok(pending);\n assert.equal(pending.isHidden(), false);\n\n await handleAgentEvent(host, {\n type: \"tool_execution_end\",\n toolCallId: \"tool-1\",\n toolName: \"bash\",\n isError: true,\n result: {\n content: [{ type: \"text\", text: \"failed\" }],\n details: {},\n },\n });\n\n assert.equal(summaryLines(host).length, 0);\n assert.equal(pending.isHidden(), false);\n });\n\n it(\"groups consecutive identical collapsed tools\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n const first = addPendingTool(host, \"tool-1\", 400);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n assert.equal(host.chatContainer.children.indexOf(summaryLines(host)[0]), host.chatContainer.children.indexOf(first.component) - 1);\n\n await handleAgentEvent(host, {\n type: \"message_update\",\n message: assistantMessage([{ type: \"text\", text: \"streaming text\" }]),\n } as any);\n\n addPendingTool(host, \"tool-2\", 600);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 1);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"reading 2 files · 1.0s\"));\n });\n\n it(\"keeps last grouped tool label visible after completion\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n await handleAgentEvent(host, toolStartEvent(\"tool-1\", \"read\", { path: \"README.md\" }));\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 1);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"└ README.md\"));\n });\n\n it(\"keeps non-groupable web fetches visible\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n const first = addPendingTool(host, \"tool-1\", 200);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"fetch_page\"));\n\n const second = addPendingTool(host, \"tool-2\", 300);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"fetch_page\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 0);\n assert.equal(first.hidden, false);\n assert.equal(second.hidden, false);\n });\n\n it(\"groups mixed collapsed file/nav tools into one summary\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-1\", 200);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n addPendingTool(host, \"tool-2\", 300);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"find\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 1);\n const rendered = stripAnsi(summaries[0].render(160).join(\"\\n\"));\n assert.ok(rendered.includes(\"reading 1 file\"));\n assert.ok(rendered.includes(\"finding 1 path\"));\n });\n\n it(\"resets grouping after visible tool result\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-1\", 200);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n const visibleTool = addPendingTool(host, \"tool-2\", 300);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"write\"));\n assert.equal(visibleTool.hidden, false);\n\n addPendingTool(host, \"tool-3\", 400);\n await handleAgentEvent(host, toolEndEvent(\"tool-3\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 2);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"0.2s\"));\n assert.ok(stripAnsi(summaries[1].render(160).join(\"\\n\")).includes(\"0.4s\"));\n });\n\n it(\"groups identical collapsed tools across empty assistant message boundaries\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-1\", 300);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-2\", 400);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 1);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"reading 2 files · 0.7s\"));\n });\n\n it(\"starts new collapsed group after visible assistant content\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-1\", 300);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n await handleAgentEvent(host, {\n type: \"message_update\",\n message: assistantMessage([{ type: \"text\", text: \"visible reply\" }]),\n } as any);\n\n addPendingTool(host, \"tool-2\", 400);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 2);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"0.3s\"));\n assert.ok(stripAnsi(summaries[1].render(160).join(\"\\n\")).includes(\"0.4s\"));\n });\n\n it(\"stops grouped spinner on aborted assistant message\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n await handleAgentEvent(host, toolStartEvent(\"tool-1\", \"read\", { path: \"README.md\" }));\n\n await handleAgentEvent(host, {\n type: \"message_end\",\n message: {\n ...assistantMessage(),\n stopReason: \"aborted\",\n errorMessage: \"Operation aborted\",\n },\n } as any);\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 1);\n const rendered = stripAnsi(summaries[0].render(160).join(\"\\n\"));\n assert.ok(!rendered.includes(\"…\"));\n assert.ok(rendered.includes(\"README.md\") || rendered === \"\");\n });\n\n it(\"keeps collapsed tool calls visible in intermediate mode\", async () => {\n const host = createHost({ collapseToolCalls: true, collapsedToolCallsExpanded: true });\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n const tool = addPendingTool(host, \"tool-1\", 250);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(tool.hidden, false);\n assert.equal(summaries.length, 1);\n assert.deepEqual(summaries[0].render(160), []);\n });\n\n it(\"keeps collapsed tools visible when verbose mode is active\", async () => {\n const host = createHost({ collapseToolCalls: true, toolOutputExpanded: true });\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n const tool = addPendingTool(host, \"tool-1\", 250);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(tool.hidden, false);\n assert.equal(summaries.length, 1);\n assert.deepEqual(summaries[0].render(160), []);\n });\n\n it(\"does not collapse tool calls when setting is disabled\", async () => {\n const host = createHost({ collapseToolCalls: false });\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n const tool = addPendingTool(host, \"tool-1\", 250);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n assert.equal(tool.hidden, false);\n assert.equal(summaryLines(host).length, 0);\n });\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-controller.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/controllers/chat-controller.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAiBnG,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,wBAAwB,GAAG;IACpE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,4BAA4B,EAAE,MAAM,GAAG,CAAC;IACxC,gBAAgB,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACxD,qBAAqB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;IACpD,2BAA2B,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,CAAC;IACvD,sBAAsB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,oBAAoB,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,4BAA4B,EAAE,MAAM,IAAI,CAAC;IACzC,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,sBAAsB,EAAE,MAAM,IAAI,CAAC;IACnC,oBAAoB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,GAAG,CAAC;IACjD,uBAAuB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,GAAG,CAAC;IACtE,uBAAuB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACvK,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,wBAAwB,EAAE;QAAE,KAAK,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;IAChD,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,IAAI,CAAC;CAC/B,EAAE,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmgB7C"}
1
+ {"version":3,"file":"chat-controller.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/controllers/chat-controller.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAiBnG,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,wBAAwB,GAAG;IACpE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,4BAA4B,EAAE,MAAM,GAAG,CAAC;IACxC,gBAAgB,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACxD,qBAAqB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;IACpD,2BAA2B,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,CAAC;IACvD,sBAAsB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,oBAAoB,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,4BAA4B,EAAE,MAAM,IAAI,CAAC;IACzC,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,sBAAsB,EAAE,MAAM,IAAI,CAAC;IACnC,oBAAoB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,GAAG,CAAC;IACjD,uBAAuB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,GAAG,CAAC;IACtE,uBAAuB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACvK,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,wBAAwB,EAAE;QAAE,KAAK,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;IAChD,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,IAAI,CAAC;CAC/B,EAAE,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0mB7C"}