@caupulican/pi-adaptative 0.93.19 → 0.94.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.
- package/CHANGELOG.md +14 -0
- package/README.md +3 -2
- package/dist/core/extensions/loader.d.ts +0 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +0 -1
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +0 -4
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/tools/artifact-retrieve.d.ts.map +1 -1
- package/dist/core/tools/artifact-retrieve.js +0 -1
- package/dist/core/tools/artifact-retrieve.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +0 -7
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +0 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +0 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +0 -1
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/skill-audit.d.ts.map +1 -1
- package/dist/core/tools/skill-audit.js +0 -1
- package/dist/core/tools/skill-audit.js.map +1 -1
- package/dist/core/tools/skill.d.ts.map +1 -1
- package/dist/core/tools/skill.js +0 -1
- package/dist/core/tools/skill.js.map +1 -1
- package/dist/core/tools/skillify.d.ts.map +1 -1
- package/dist/core/tools/skillify.js +0 -1
- package/dist/core/tools/skillify.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +1 -2
- package/dist/core/tools/write.js.map +1 -1
- package/dist/modes/interactive/components/action-transcript.d.ts +24 -0
- package/dist/modes/interactive/components/action-transcript.d.ts.map +1 -0
- package/dist/modes/interactive/components/action-transcript.js +72 -0
- package/dist/modes/interactive/components/action-transcript.js.map +1 -0
- package/dist/modes/interactive/components/active-tool-call-registry.d.ts +12 -0
- package/dist/modes/interactive/components/active-tool-call-registry.d.ts.map +1 -0
- package/dist/modes/interactive/components/active-tool-call-registry.js +25 -0
- package/dist/modes/interactive/components/active-tool-call-registry.js.map +1 -0
- package/dist/modes/interactive/components/activity-lane.d.ts +1 -1
- package/dist/modes/interactive/components/activity-lane.d.ts.map +1 -1
- package/dist/modes/interactive/components/activity-lane.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +2 -0
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +7 -1
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +0 -2
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +0 -2
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +0 -7
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +2 -76
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/transcript-overlay.d.ts +3 -1
- package/dist/modes/interactive/components/transcript-overlay.d.ts.map +1 -1
- package/dist/modes/interactive/components/transcript-overlay.js +8 -5
- package/dist/modes/interactive/components/transcript-overlay.js.map +1 -1
- package/dist/modes/interactive/interactive-event-controller.d.ts +2 -3
- package/dist/modes/interactive/interactive-event-controller.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-event-controller.js +9 -9
- package/dist/modes/interactive/interactive-event-controller.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +6 -6
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +50 -100
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/settings-selector-flow.d.ts.map +1 -1
- package/dist/modes/interactive/settings-selector-flow.js +3 -4
- package/dist/modes/interactive/settings-selector-flow.js.map +1 -1
- package/docs/UI_POLISH_ORCHESTRATION.md +4 -4
- package/docs/extensions.md +4 -12
- package/docs/keybindings.md +2 -2
- package/docs/settings.md +1 -1
- package/docs/task-steps.md +3 -3
- package/docs/tool-repair.md +1 -1
- package/docs/usage.md +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
- package/dist/modes/interactive/components/tool-group.d.ts +0 -28
- package/dist/modes/interactive/components/tool-group.d.ts.map +0 -1
- package/dist/modes/interactive/components/tool-group.js +0 -200
- package/dist/modes/interactive/components/tool-group.js.map +0 -1
- package/dist/modes/interactive/components/tool-panel-registry.d.ts +0 -30
- package/dist/modes/interactive/components/tool-panel-registry.d.ts.map +0 -1
- package/dist/modes/interactive/components/tool-panel-registry.js +0 -145
- package/dist/modes/interactive/components/tool-panel-registry.js.map +0 -1
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
import { Box, truncateToWidth, visibleWidth } from "@caupulican/pi-tui";
|
|
2
|
-
import { shortenPath } from "../../../core/tools/render-utils.js";
|
|
3
|
-
import { theme } from "../theme/theme.js";
|
|
4
|
-
import { keyText } from "./keybinding-hints.js";
|
|
5
|
-
const COLLAPSED_FILE_SNIPPET = 3;
|
|
6
|
-
const MAX_COMPACT_COMMANDS = 32;
|
|
7
|
-
/** Human nouns for collapsed group headers. Keys are toolGroup ids, not raw tool names. */
|
|
8
|
-
const GROUP_NOUNS = {
|
|
9
|
-
task_steps: { singular: "Task Step", plural: "Task Steps" },
|
|
10
|
-
pipeline: { singular: "Pipeline", plural: "Pipelines" },
|
|
11
|
-
skills: { singular: "Skill", plural: "Skills" },
|
|
12
|
-
delegate: { singular: "Worker", plural: "Workers" },
|
|
13
|
-
explore: { singular: "Search", plural: "Searches" },
|
|
14
|
-
};
|
|
15
|
-
function plural(count, singular, pluralForm = `${singular}s`) {
|
|
16
|
-
return `${count} ${count === 1 ? singular : pluralForm}`;
|
|
17
|
-
}
|
|
18
|
-
function humanizeGroupKey(raw) {
|
|
19
|
-
const words = raw
|
|
20
|
-
.replace(/[_-]+/g, " ")
|
|
21
|
-
.trim()
|
|
22
|
-
.split(/\s+/)
|
|
23
|
-
.filter(Boolean)
|
|
24
|
-
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase());
|
|
25
|
-
const last = words.at(-1) ?? "Tool";
|
|
26
|
-
const lastSingular = last.endsWith("s") && last.length > 1 ? last.slice(0, -1) : last;
|
|
27
|
-
const lastPlural = last.endsWith("s") ? last : `${last}s`;
|
|
28
|
-
return {
|
|
29
|
-
singular: [...words.slice(0, -1), lastSingular].join(" "),
|
|
30
|
-
plural: [...words.slice(0, -1), lastPlural].join(" "),
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
function groupNoun(groupKey, tools) {
|
|
34
|
-
const mapped = GROUP_NOUNS[groupKey];
|
|
35
|
-
if (mapped)
|
|
36
|
-
return mapped;
|
|
37
|
-
const labels = [...new Set(tools.map((tool) => tool.getDisplayLabel()).filter((label) => label.length > 0))];
|
|
38
|
-
if (labels.length === 1)
|
|
39
|
-
return humanizeGroupKey(labels[0]);
|
|
40
|
-
if (groupKey)
|
|
41
|
-
return humanizeGroupKey(groupKey);
|
|
42
|
-
return { singular: "Tool", plural: "Tools" };
|
|
43
|
-
}
|
|
44
|
-
export class ToolGroupComponent {
|
|
45
|
-
constructor(toolGroup, tools = []) {
|
|
46
|
-
this.tools = [];
|
|
47
|
-
this.expanded = false;
|
|
48
|
-
this.toolGroup = toolGroup;
|
|
49
|
-
for (const tool of tools)
|
|
50
|
-
this.addTool(tool);
|
|
51
|
-
}
|
|
52
|
-
addTool(tool) {
|
|
53
|
-
tool.setExpanded(this.expanded);
|
|
54
|
-
this.tools.push(tool);
|
|
55
|
-
}
|
|
56
|
-
canAccept(tool) {
|
|
57
|
-
if (tool.toolGroup?.trim() !== this.toolGroup)
|
|
58
|
-
return false;
|
|
59
|
-
if (!this.isCommandGroup(tool))
|
|
60
|
-
return true;
|
|
61
|
-
return this.tools.length < MAX_COMPACT_COMMANDS;
|
|
62
|
-
}
|
|
63
|
-
removeTool(tool) {
|
|
64
|
-
const index = this.tools.indexOf(tool);
|
|
65
|
-
if (index === -1)
|
|
66
|
-
return false;
|
|
67
|
-
this.tools.splice(index, 1);
|
|
68
|
-
return true;
|
|
69
|
-
}
|
|
70
|
-
getToolCount() {
|
|
71
|
-
return this.tools.length;
|
|
72
|
-
}
|
|
73
|
-
getOnlyTool() {
|
|
74
|
-
return this.tools.length === 1 ? this.tools[0] : undefined;
|
|
75
|
-
}
|
|
76
|
-
setExpanded(expanded) {
|
|
77
|
-
this.expanded = expanded;
|
|
78
|
-
for (const tool of this.tools)
|
|
79
|
-
tool.setExpanded(expanded);
|
|
80
|
-
}
|
|
81
|
-
setShowImages(show) {
|
|
82
|
-
for (const tool of this.tools)
|
|
83
|
-
tool.setShowImages(show);
|
|
84
|
-
}
|
|
85
|
-
setImageWidthCells(width) {
|
|
86
|
-
for (const tool of this.tools)
|
|
87
|
-
tool.setImageWidthCells(width);
|
|
88
|
-
}
|
|
89
|
-
invalidate() {
|
|
90
|
-
for (const tool of this.tools)
|
|
91
|
-
tool.invalidate();
|
|
92
|
-
}
|
|
93
|
-
render(width) {
|
|
94
|
-
if (this.tools.length === 0)
|
|
95
|
-
return [];
|
|
96
|
-
const safeWidth = Math.max(1, width);
|
|
97
|
-
if (this.expanded)
|
|
98
|
-
return this.tools.flatMap((tool) => tool.render(safeWidth));
|
|
99
|
-
if (this.isCommandGroup())
|
|
100
|
-
return this.renderCommandGroup(safeWidth);
|
|
101
|
-
const collapsed = this.renderCollapsed(safeWidth);
|
|
102
|
-
if (collapsed.length === 0)
|
|
103
|
-
return [];
|
|
104
|
-
const box = new Box(1, 1, (text) => theme.bg(this.getBackgroundColor(), text));
|
|
105
|
-
box.addChild({ render: (contentWidth) => this.renderCollapsed(contentWidth), invalidate: () => { } });
|
|
106
|
-
return [" ".repeat(safeWidth), ...box.render(safeWidth)];
|
|
107
|
-
}
|
|
108
|
-
isCommandGroup(candidate) {
|
|
109
|
-
return (this.toolGroup === "bash" &&
|
|
110
|
-
this.tools.every((tool) => tool.getToolName() === "bash") &&
|
|
111
|
-
(candidate === undefined || candidate.getToolName() === "bash"));
|
|
112
|
-
}
|
|
113
|
-
renderCommandGroup(width) {
|
|
114
|
-
const total = this.tools.length;
|
|
115
|
-
const pending = this.tools.filter((tool) => tool.isToolPartial()).length;
|
|
116
|
-
const failed = this.tools.filter((tool) => tool.isToolError()).length;
|
|
117
|
-
const status = pending > 0 ? "Running" : "Ran";
|
|
118
|
-
const noun = total === 1 ? "command" : "commands";
|
|
119
|
-
const failureSuffix = failed > 0 ? ` · ${failed} failed` : "";
|
|
120
|
-
const summary = `${theme.fg(failed > 0 ? "error" : pending > 0 ? "accent" : "success", "•")} ${theme.bold(`${status} ${total} ${noun}`)}${theme.fg("dim", `${failureSuffix} · ${keyText("app.transcript.open")} to view transcript`)}`;
|
|
121
|
-
return [truncateToWidth(summary, width, "...")];
|
|
122
|
-
}
|
|
123
|
-
renderCollapsed(width) {
|
|
124
|
-
const safeWidth = Math.max(1, width);
|
|
125
|
-
const lines = [this.formatCountLine(), ...this.formatFileSnippet(), ...this.formatLastAction()].filter((line) => line.trim().length > 0);
|
|
126
|
-
if (lines.length === 0)
|
|
127
|
-
return [];
|
|
128
|
-
lines[lines.length - 1] = this.appendExpandHint(lines[lines.length - 1], safeWidth);
|
|
129
|
-
return lines.map((line) => truncateToWidth(line, safeWidth, "..."));
|
|
130
|
-
}
|
|
131
|
-
formatCountLine() {
|
|
132
|
-
const editCount = this.tools.filter((tool) => tool.getToolName() === "edit").length;
|
|
133
|
-
const writeCount = this.tools.filter((tool) => tool.getToolName() === "write").length;
|
|
134
|
-
const errorCount = this.tools.filter((tool) => tool.isToolError()).length;
|
|
135
|
-
const files = this.uniqueFiles();
|
|
136
|
-
const parts = [];
|
|
137
|
-
if (editCount > 0)
|
|
138
|
-
parts.push(plural(editCount, "edit"));
|
|
139
|
-
if (writeCount > 0)
|
|
140
|
-
parts.push(plural(writeCount, "write"));
|
|
141
|
-
if (parts.length === 0) {
|
|
142
|
-
const noun = groupNoun(this.toolGroup, this.tools);
|
|
143
|
-
parts.push(plural(this.tools.length, noun.singular, noun.plural));
|
|
144
|
-
}
|
|
145
|
-
if (files.length > 0)
|
|
146
|
-
parts.push(plural(files.length, "file"));
|
|
147
|
-
if (errorCount > 0)
|
|
148
|
-
parts.push(plural(errorCount, "error"));
|
|
149
|
-
return theme.bold(parts.join(" · "));
|
|
150
|
-
}
|
|
151
|
-
formatFileSnippet() {
|
|
152
|
-
const files = this.uniqueFiles();
|
|
153
|
-
if (files.length === 0)
|
|
154
|
-
return [];
|
|
155
|
-
const shown = files.slice(0, COLLAPSED_FILE_SNIPPET);
|
|
156
|
-
const extra = files.length - shown.length;
|
|
157
|
-
const list = shown.join(", ") + (extra > 0 ? `, +${extra}` : "");
|
|
158
|
-
return [theme.fg("dim", list)];
|
|
159
|
-
}
|
|
160
|
-
formatLastAction() {
|
|
161
|
-
const last = [...this.tools].reverse().find((tool) => tool.isToolSuccess()) ?? this.tools[this.tools.length - 1];
|
|
162
|
-
if (!last)
|
|
163
|
-
return [];
|
|
164
|
-
const path = last.getDisplayPath();
|
|
165
|
-
const name = last.getDisplayLabel();
|
|
166
|
-
const label = path ? `${name} ${shortenPath(path)}` : name;
|
|
167
|
-
return [`${theme.fg("dim", "last: ")}${label}`];
|
|
168
|
-
}
|
|
169
|
-
uniqueFiles() {
|
|
170
|
-
const seen = new Set();
|
|
171
|
-
const files = [];
|
|
172
|
-
for (const tool of this.tools) {
|
|
173
|
-
const path = tool.getDisplayPath();
|
|
174
|
-
if (!path)
|
|
175
|
-
continue;
|
|
176
|
-
const display = shortenPath(path);
|
|
177
|
-
if (seen.has(display))
|
|
178
|
-
continue;
|
|
179
|
-
seen.add(display);
|
|
180
|
-
files.push(display);
|
|
181
|
-
}
|
|
182
|
-
return files;
|
|
183
|
-
}
|
|
184
|
-
appendExpandHint(line, width) {
|
|
185
|
-
const hint = theme.fg("dim", ` (${keyText("app.tools.expand")} to expand)`);
|
|
186
|
-
const hintWidth = visibleWidth(hint);
|
|
187
|
-
if (hintWidth >= width)
|
|
188
|
-
return truncateToWidth(hint, width, "...");
|
|
189
|
-
return truncateToWidth(line, width - hintWidth, "") + hint;
|
|
190
|
-
}
|
|
191
|
-
getBackgroundColor() {
|
|
192
|
-
const colors = this.tools.map((tool) => tool.getBackgroundColor());
|
|
193
|
-
if (colors.includes("toolErrorBg"))
|
|
194
|
-
return "toolErrorBg";
|
|
195
|
-
if (colors.includes("toolPendingBg"))
|
|
196
|
-
return "toolPendingBg";
|
|
197
|
-
return "toolSuccessBg";
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
//# sourceMappingURL=tool-group.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tool-group.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-group.ts"],"names":[],"mappings":"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","sourcesContent":["import { Box, type Component, truncateToWidth, visibleWidth } from \"@caupulican/pi-tui\";\nimport { shortenPath } from \"../../../core/tools/render-utils.ts\";\nimport { type ThemeBg, theme } from \"../theme/theme.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\nimport type { ToolExecutionComponent } from \"./tool-execution.ts\";\n\nconst COLLAPSED_FILE_SNIPPET = 3;\nconst MAX_COMPACT_COMMANDS = 32;\n\n/** Human nouns for collapsed group headers. Keys are toolGroup ids, not raw tool names. */\nconst GROUP_NOUNS: Record<string, { singular: string; plural: string }> = {\n\ttask_steps: { singular: \"Task Step\", plural: \"Task Steps\" },\n\tpipeline: { singular: \"Pipeline\", plural: \"Pipelines\" },\n\tskills: { singular: \"Skill\", plural: \"Skills\" },\n\tdelegate: { singular: \"Worker\", plural: \"Workers\" },\n\texplore: { singular: \"Search\", plural: \"Searches\" },\n};\n\nfunction plural(count: number, singular: string, pluralForm = `${singular}s`): string {\n\treturn `${count} ${count === 1 ? singular : pluralForm}`;\n}\n\nfunction humanizeGroupKey(raw: string): { singular: string; plural: string } {\n\tconst words = raw\n\t\t.replace(/[_-]+/g, \" \")\n\t\t.trim()\n\t\t.split(/\\s+/)\n\t\t.filter(Boolean)\n\t\t.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase());\n\tconst last = words.at(-1) ?? \"Tool\";\n\tconst lastSingular = last.endsWith(\"s\") && last.length > 1 ? last.slice(0, -1) : last;\n\tconst lastPlural = last.endsWith(\"s\") ? last : `${last}s`;\n\treturn {\n\t\tsingular: [...words.slice(0, -1), lastSingular].join(\" \"),\n\t\tplural: [...words.slice(0, -1), lastPlural].join(\" \"),\n\t};\n}\n\nfunction groupNoun(groupKey: string, tools: readonly ToolExecutionComponent[]): { singular: string; plural: string } {\n\tconst mapped = GROUP_NOUNS[groupKey];\n\tif (mapped) return mapped;\n\tconst labels = [...new Set(tools.map((tool) => tool.getDisplayLabel()).filter((label) => label.length > 0))];\n\tif (labels.length === 1) return humanizeGroupKey(labels[0]);\n\tif (groupKey) return humanizeGroupKey(groupKey);\n\treturn { singular: \"Tool\", plural: \"Tools\" };\n}\n\nexport class ToolGroupComponent implements Component {\n\treadonly toolGroup: string;\n\tprivate readonly tools: ToolExecutionComponent[] = [];\n\tprivate expanded = false;\n\n\tconstructor(toolGroup: string, tools: ToolExecutionComponent[] = []) {\n\t\tthis.toolGroup = toolGroup;\n\t\tfor (const tool of tools) this.addTool(tool);\n\t}\n\n\taddTool(tool: ToolExecutionComponent): void {\n\t\ttool.setExpanded(this.expanded);\n\t\tthis.tools.push(tool);\n\t}\n\n\tcanAccept(tool: ToolExecutionComponent): boolean {\n\t\tif (tool.toolGroup?.trim() !== this.toolGroup) return false;\n\t\tif (!this.isCommandGroup(tool)) return true;\n\t\treturn this.tools.length < MAX_COMPACT_COMMANDS;\n\t}\n\n\tremoveTool(tool: ToolExecutionComponent): boolean {\n\t\tconst index = this.tools.indexOf(tool);\n\t\tif (index === -1) return false;\n\t\tthis.tools.splice(index, 1);\n\t\treturn true;\n\t}\n\n\tgetToolCount(): number {\n\t\treturn this.tools.length;\n\t}\n\n\tgetOnlyTool(): ToolExecutionComponent | undefined {\n\t\treturn this.tools.length === 1 ? this.tools[0] : undefined;\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tfor (const tool of this.tools) tool.setExpanded(expanded);\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tfor (const tool of this.tools) tool.setShowImages(show);\n\t}\n\n\tsetImageWidthCells(width: number): void {\n\t\tfor (const tool of this.tools) tool.setImageWidthCells(width);\n\t}\n\n\tinvalidate(): void {\n\t\tfor (const tool of this.tools) tool.invalidate();\n\t}\n\n\trender(width: number): string[] {\n\t\tif (this.tools.length === 0) return [];\n\t\tconst safeWidth = Math.max(1, width);\n\t\tif (this.expanded) return this.tools.flatMap((tool) => tool.render(safeWidth));\n\t\tif (this.isCommandGroup()) return this.renderCommandGroup(safeWidth);\n\n\t\tconst collapsed = this.renderCollapsed(safeWidth);\n\t\tif (collapsed.length === 0) return [];\n\t\tconst box = new Box(1, 1, (text) => theme.bg(this.getBackgroundColor(), text));\n\t\tbox.addChild({ render: (contentWidth) => this.renderCollapsed(contentWidth), invalidate: () => {} });\n\t\treturn [\" \".repeat(safeWidth), ...box.render(safeWidth)];\n\t}\n\n\tprivate isCommandGroup(candidate?: ToolExecutionComponent): boolean {\n\t\treturn (\n\t\t\tthis.toolGroup === \"bash\" &&\n\t\t\tthis.tools.every((tool) => tool.getToolName() === \"bash\") &&\n\t\t\t(candidate === undefined || candidate.getToolName() === \"bash\")\n\t\t);\n\t}\n\n\tprivate renderCommandGroup(width: number): string[] {\n\t\tconst total = this.tools.length;\n\t\tconst pending = this.tools.filter((tool) => tool.isToolPartial()).length;\n\t\tconst failed = this.tools.filter((tool) => tool.isToolError()).length;\n\t\tconst status = pending > 0 ? \"Running\" : \"Ran\";\n\t\tconst noun = total === 1 ? \"command\" : \"commands\";\n\t\tconst failureSuffix = failed > 0 ? ` · ${failed} failed` : \"\";\n\t\tconst summary = `${theme.fg(failed > 0 ? \"error\" : pending > 0 ? \"accent\" : \"success\", \"•\")} ${theme.bold(`${status} ${total} ${noun}`)}${theme.fg(\"dim\", `${failureSuffix} · ${keyText(\"app.transcript.open\")} to view transcript`)}`;\n\t\treturn [truncateToWidth(summary, width, \"...\")];\n\t}\n\n\tprivate renderCollapsed(width: number): string[] {\n\t\tconst safeWidth = Math.max(1, width);\n\t\tconst lines = [this.formatCountLine(), ...this.formatFileSnippet(), ...this.formatLastAction()].filter(\n\t\t\t(line) => line.trim().length > 0,\n\t\t);\n\t\tif (lines.length === 0) return [];\n\t\tlines[lines.length - 1] = this.appendExpandHint(lines[lines.length - 1], safeWidth);\n\t\treturn lines.map((line) => truncateToWidth(line, safeWidth, \"...\"));\n\t}\n\n\tprivate formatCountLine(): string {\n\t\tconst editCount = this.tools.filter((tool) => tool.getToolName() === \"edit\").length;\n\t\tconst writeCount = this.tools.filter((tool) => tool.getToolName() === \"write\").length;\n\t\tconst errorCount = this.tools.filter((tool) => tool.isToolError()).length;\n\t\tconst files = this.uniqueFiles();\n\t\tconst parts: string[] = [];\n\t\tif (editCount > 0) parts.push(plural(editCount, \"edit\"));\n\t\tif (writeCount > 0) parts.push(plural(writeCount, \"write\"));\n\t\tif (parts.length === 0) {\n\t\t\tconst noun = groupNoun(this.toolGroup, this.tools);\n\t\t\tparts.push(plural(this.tools.length, noun.singular, noun.plural));\n\t\t}\n\t\tif (files.length > 0) parts.push(plural(files.length, \"file\"));\n\t\tif (errorCount > 0) parts.push(plural(errorCount, \"error\"));\n\t\treturn theme.bold(parts.join(\" · \"));\n\t}\n\n\tprivate formatFileSnippet(): string[] {\n\t\tconst files = this.uniqueFiles();\n\t\tif (files.length === 0) return [];\n\t\tconst shown = files.slice(0, COLLAPSED_FILE_SNIPPET);\n\t\tconst extra = files.length - shown.length;\n\t\tconst list = shown.join(\", \") + (extra > 0 ? `, +${extra}` : \"\");\n\t\treturn [theme.fg(\"dim\", list)];\n\t}\n\n\tprivate formatLastAction(): string[] {\n\t\tconst last = [...this.tools].reverse().find((tool) => tool.isToolSuccess()) ?? this.tools[this.tools.length - 1];\n\t\tif (!last) return [];\n\t\tconst path = last.getDisplayPath();\n\t\tconst name = last.getDisplayLabel();\n\t\tconst label = path ? `${name} ${shortenPath(path)}` : name;\n\t\treturn [`${theme.fg(\"dim\", \"last: \")}${label}`];\n\t}\n\n\tprivate uniqueFiles(): string[] {\n\t\tconst seen = new Set<string>();\n\t\tconst files: string[] = [];\n\t\tfor (const tool of this.tools) {\n\t\t\tconst path = tool.getDisplayPath();\n\t\t\tif (!path) continue;\n\t\t\tconst display = shortenPath(path);\n\t\t\tif (seen.has(display)) continue;\n\t\t\tseen.add(display);\n\t\t\tfiles.push(display);\n\t\t}\n\t\treturn files;\n\t}\n\n\tprivate appendExpandHint(line: string, width: number): string {\n\t\tconst hint = theme.fg(\"dim\", ` (${keyText(\"app.tools.expand\")} to expand)`);\n\t\tconst hintWidth = visibleWidth(hint);\n\t\tif (hintWidth >= width) return truncateToWidth(hint, width, \"...\");\n\t\treturn truncateToWidth(line, width - hintWidth, \"\") + hint;\n\t}\n\n\tprivate getBackgroundColor(): ThemeBg {\n\t\tconst colors = this.tools.map((tool) => tool.getBackgroundColor());\n\t\tif (colors.includes(\"toolErrorBg\")) return \"toolErrorBg\";\n\t\tif (colors.includes(\"toolPendingBg\")) return \"toolPendingBg\";\n\t\treturn \"toolSuccessBg\";\n\t}\n}\n"]}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { ToolExecutionComponent } from "./tool-execution.ts";
|
|
2
|
-
export interface ToolPanelTenantScope {
|
|
3
|
-
sessionId?: string;
|
|
4
|
-
sessionFile?: string;
|
|
5
|
-
cwd: string;
|
|
6
|
-
}
|
|
7
|
-
export declare function createToolPanelTenantKey(scope: ToolPanelTenantScope): string;
|
|
8
|
-
export declare function getToolPanelActionKey(scope: ToolPanelTenantScope, toolName: string, args: unknown): string | undefined;
|
|
9
|
-
export declare function getToolPanelResultActionKeys(scope: ToolPanelTenantScope, toolName: string, result: unknown): string[];
|
|
10
|
-
export declare function shouldReuseToolPanelInPlace(toolName: string, args: unknown): boolean;
|
|
11
|
-
export declare class ToolPanelRegistry {
|
|
12
|
-
private readonly panelsByAction;
|
|
13
|
-
private readonly activeByCallId;
|
|
14
|
-
private readonly actionKeyByCallId;
|
|
15
|
-
getReusable(actionKey: string | undefined, options?: {
|
|
16
|
-
allowActive?: boolean;
|
|
17
|
-
}): ToolExecutionComponent | undefined;
|
|
18
|
-
private rememberAction;
|
|
19
|
-
replaceActiveForAction(toolCallId: string, panel: ToolExecutionComponent, actionKey: string): void;
|
|
20
|
-
register(toolCallId: string, panel: ToolExecutionComponent, actionKey?: string): void;
|
|
21
|
-
registerAliases(panel: ToolExecutionComponent, actionKeys: string[]): void;
|
|
22
|
-
hasActive(toolCallId: string): boolean;
|
|
23
|
-
getActive(toolCallId: string): ToolExecutionComponent | undefined;
|
|
24
|
-
activeEntries(): IterableIterator<[string, ToolExecutionComponent]>;
|
|
25
|
-
isActive(panel: ToolExecutionComponent): boolean;
|
|
26
|
-
finish(toolCallId: string): void;
|
|
27
|
-
clearActive(): void;
|
|
28
|
-
clearAll(): void;
|
|
29
|
-
}
|
|
30
|
-
//# sourceMappingURL=tool-panel-registry.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tool-panel-registry.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-panel-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAElE,MAAM,WAAW,oBAAoB;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,CAE5E;AA4BD,wBAAgB,qBAAqB,CACpC,KAAK,EAAE,oBAAoB,EAC3B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,GACX,MAAM,GAAG,SAAS,CAgBpB;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,EAAE,CAIrH;AAED,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAOpF;AAMD,qBAAa,iBAAiB;IAC7B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA6C;IAC5E,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA6C;IAC5E,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA6B;IAE/D,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,sBAAsB,GAAG,SAAS,CAQlH;IAED,OAAO,CAAC,cAAc;IAUtB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,sBAAsB,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAOjG;IAED,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,sBAAsB,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAMpF;IAED,eAAe,CAAC,KAAK,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,IAAI,CAIzE;IAED,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAErC;IAED,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,sBAAsB,GAAG,SAAS,CAEhE;IAED,aAAa,IAAI,gBAAgB,CAAC,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC,CAElE;IAED,QAAQ,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAK/C;IAED,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAG/B;IAED,WAAW,IAAI,IAAI,CAGlB;IAED,QAAQ,IAAI,IAAI,CAIf;CACD"}
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
export function createToolPanelTenantKey(scope) {
|
|
2
|
-
return [scope.sessionId || "no-session-id", scope.sessionFile || "no-session-file", scope.cwd].join("\0");
|
|
3
|
-
}
|
|
4
|
-
function backgroundScriptActionKey(tenantKey, selector) {
|
|
5
|
-
return `${tenantKey}\0background_script:${selector}`;
|
|
6
|
-
}
|
|
7
|
-
function backgroundScriptSelector(record) {
|
|
8
|
-
const action = String(record.action || "list");
|
|
9
|
-
if (action === "start" && typeof record.name === "string" && record.name.trim())
|
|
10
|
-
return record.name.trim();
|
|
11
|
-
if (["status", "logs", "stop"].includes(action) && typeof record.id === "string" && record.id.trim()) {
|
|
12
|
-
return record.id.trim();
|
|
13
|
-
}
|
|
14
|
-
return undefined;
|
|
15
|
-
}
|
|
16
|
-
function backgroundScriptResultSelectors(result) {
|
|
17
|
-
if (!result || typeof result !== "object")
|
|
18
|
-
return [];
|
|
19
|
-
const details = result.details;
|
|
20
|
-
if (!details || typeof details !== "object")
|
|
21
|
-
return [];
|
|
22
|
-
const job = details.job;
|
|
23
|
-
if (!job || typeof job !== "object")
|
|
24
|
-
return [];
|
|
25
|
-
const record = job;
|
|
26
|
-
const selectors = [record.id, record.name]
|
|
27
|
-
.filter((value) => typeof value === "string" && value.trim().length > 0)
|
|
28
|
-
.map((value) => value.trim());
|
|
29
|
-
return [...new Set(selectors)];
|
|
30
|
-
}
|
|
31
|
-
export function getToolPanelActionKey(scope, toolName, args) {
|
|
32
|
-
const tenantKey = createToolPanelTenantKey(scope);
|
|
33
|
-
if (!args || typeof args !== "object")
|
|
34
|
-
return toolName.endsWith("_status") ? `${tenantKey}\0${toolName}` : undefined;
|
|
35
|
-
const record = args;
|
|
36
|
-
const pathValue = record.path ?? record.file_path;
|
|
37
|
-
if (["read", "edit", "write"].includes(toolName) && typeof pathValue === "string" && pathValue.trim()) {
|
|
38
|
-
return `${tenantKey}\0${toolName}:${pathValue.trim()}`;
|
|
39
|
-
}
|
|
40
|
-
if (toolName === "background_script") {
|
|
41
|
-
const selector = backgroundScriptSelector(record);
|
|
42
|
-
return selector ? backgroundScriptActionKey(tenantKey, selector) : undefined;
|
|
43
|
-
}
|
|
44
|
-
if (toolName.endsWith("_status"))
|
|
45
|
-
return `${tenantKey}\0${toolName}`;
|
|
46
|
-
if (toolName === "learning_auto_learn_state")
|
|
47
|
-
return `${tenantKey}\0${toolName}:${String(record.action || "read")}`;
|
|
48
|
-
if (toolName === "task_steps")
|
|
49
|
-
return `${tenantKey}\0${toolName}:${String(record.action || "list")}`;
|
|
50
|
-
return undefined;
|
|
51
|
-
}
|
|
52
|
-
export function getToolPanelResultActionKeys(scope, toolName, result) {
|
|
53
|
-
if (toolName !== "background_script")
|
|
54
|
-
return [];
|
|
55
|
-
const tenantKey = createToolPanelTenantKey(scope);
|
|
56
|
-
return backgroundScriptResultSelectors(result).map((selector) => backgroundScriptActionKey(tenantKey, selector));
|
|
57
|
-
}
|
|
58
|
-
export function shouldReuseToolPanelInPlace(toolName, args) {
|
|
59
|
-
return (toolName === "background_script" &&
|
|
60
|
-
!!args &&
|
|
61
|
-
typeof args === "object" &&
|
|
62
|
-
!!backgroundScriptSelector(args));
|
|
63
|
-
}
|
|
64
|
-
// Reusable panels retain rendered arguments/results. Keep this aligned with the bounded live TUI
|
|
65
|
-
// scrollback rather than pinning one component for every unique file/status action in a long process.
|
|
66
|
-
const MAX_REUSABLE_TOOL_PANEL_ACTIONS = 256;
|
|
67
|
-
export class ToolPanelRegistry {
|
|
68
|
-
constructor() {
|
|
69
|
-
this.panelsByAction = new Map();
|
|
70
|
-
this.activeByCallId = new Map();
|
|
71
|
-
this.actionKeyByCallId = new Map();
|
|
72
|
-
}
|
|
73
|
-
getReusable(actionKey, options) {
|
|
74
|
-
if (!actionKey)
|
|
75
|
-
return undefined;
|
|
76
|
-
const panel = this.panelsByAction.get(actionKey);
|
|
77
|
-
if (!panel || (!options?.allowActive && this.isActive(panel)))
|
|
78
|
-
return undefined;
|
|
79
|
-
// Refresh insertion order so eviction follows recent reuse rather than original creation.
|
|
80
|
-
this.panelsByAction.delete(actionKey);
|
|
81
|
-
this.panelsByAction.set(actionKey, panel);
|
|
82
|
-
return panel;
|
|
83
|
-
}
|
|
84
|
-
rememberAction(actionKey, panel) {
|
|
85
|
-
this.panelsByAction.delete(actionKey);
|
|
86
|
-
this.panelsByAction.set(actionKey, panel);
|
|
87
|
-
while (this.panelsByAction.size > MAX_REUSABLE_TOOL_PANEL_ACTIONS) {
|
|
88
|
-
const oldest = this.panelsByAction.keys().next().value;
|
|
89
|
-
if (oldest === undefined)
|
|
90
|
-
break;
|
|
91
|
-
this.panelsByAction.delete(oldest);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
replaceActiveForAction(toolCallId, panel, actionKey) {
|
|
95
|
-
for (const [activeCallId, activeActionKey] of this.actionKeyByCallId.entries()) {
|
|
96
|
-
if (activeActionKey !== actionKey)
|
|
97
|
-
continue;
|
|
98
|
-
this.activeByCallId.delete(activeCallId);
|
|
99
|
-
this.actionKeyByCallId.delete(activeCallId);
|
|
100
|
-
}
|
|
101
|
-
this.register(toolCallId, panel, actionKey);
|
|
102
|
-
}
|
|
103
|
-
register(toolCallId, panel, actionKey) {
|
|
104
|
-
this.activeByCallId.set(toolCallId, panel);
|
|
105
|
-
if (actionKey) {
|
|
106
|
-
this.rememberAction(actionKey, panel);
|
|
107
|
-
this.actionKeyByCallId.set(toolCallId, actionKey);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
registerAliases(panel, actionKeys) {
|
|
111
|
-
for (const actionKey of actionKeys) {
|
|
112
|
-
this.rememberAction(actionKey, panel);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
hasActive(toolCallId) {
|
|
116
|
-
return this.activeByCallId.has(toolCallId);
|
|
117
|
-
}
|
|
118
|
-
getActive(toolCallId) {
|
|
119
|
-
return this.activeByCallId.get(toolCallId);
|
|
120
|
-
}
|
|
121
|
-
activeEntries() {
|
|
122
|
-
return this.activeByCallId.entries();
|
|
123
|
-
}
|
|
124
|
-
isActive(panel) {
|
|
125
|
-
for (const active of this.activeByCallId.values()) {
|
|
126
|
-
if (active === panel)
|
|
127
|
-
return true;
|
|
128
|
-
}
|
|
129
|
-
return false;
|
|
130
|
-
}
|
|
131
|
-
finish(toolCallId) {
|
|
132
|
-
this.activeByCallId.delete(toolCallId);
|
|
133
|
-
this.actionKeyByCallId.delete(toolCallId);
|
|
134
|
-
}
|
|
135
|
-
clearActive() {
|
|
136
|
-
this.activeByCallId.clear();
|
|
137
|
-
this.actionKeyByCallId.clear();
|
|
138
|
-
}
|
|
139
|
-
clearAll() {
|
|
140
|
-
this.activeByCallId.clear();
|
|
141
|
-
this.panelsByAction.clear();
|
|
142
|
-
this.actionKeyByCallId.clear();
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
//# sourceMappingURL=tool-panel-registry.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tool-panel-registry.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-panel-registry.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ToolExecutionComponent } from \"./tool-execution.ts\";\n\nexport interface ToolPanelTenantScope {\n\tsessionId?: string;\n\tsessionFile?: string;\n\tcwd: string;\n}\n\nexport function createToolPanelTenantKey(scope: ToolPanelTenantScope): string {\n\treturn [scope.sessionId || \"no-session-id\", scope.sessionFile || \"no-session-file\", scope.cwd].join(\"\\0\");\n}\n\nfunction backgroundScriptActionKey(tenantKey: string, selector: string): string {\n\treturn `${tenantKey}\\0background_script:${selector}`;\n}\n\nfunction backgroundScriptSelector(record: Record<string, unknown>): string | undefined {\n\tconst action = String(record.action || \"list\");\n\tif (action === \"start\" && typeof record.name === \"string\" && record.name.trim()) return record.name.trim();\n\tif ([\"status\", \"logs\", \"stop\"].includes(action) && typeof record.id === \"string\" && record.id.trim()) {\n\t\treturn record.id.trim();\n\t}\n\treturn undefined;\n}\n\nfunction backgroundScriptResultSelectors(result: unknown): string[] {\n\tif (!result || typeof result !== \"object\") return [];\n\tconst details = (result as Record<string, unknown>).details;\n\tif (!details || typeof details !== \"object\") return [];\n\tconst job = (details as Record<string, unknown>).job;\n\tif (!job || typeof job !== \"object\") return [];\n\tconst record = job as Record<string, unknown>;\n\tconst selectors = [record.id, record.name]\n\t\t.filter((value): value is string => typeof value === \"string\" && value.trim().length > 0)\n\t\t.map((value) => value.trim());\n\treturn [...new Set(selectors)];\n}\n\nexport function getToolPanelActionKey(\n\tscope: ToolPanelTenantScope,\n\ttoolName: string,\n\targs: unknown,\n): string | undefined {\n\tconst tenantKey = createToolPanelTenantKey(scope);\n\tif (!args || typeof args !== \"object\") return toolName.endsWith(\"_status\") ? `${tenantKey}\\0${toolName}` : undefined;\n\tconst record = args as Record<string, unknown>;\n\tconst pathValue = record.path ?? record.file_path;\n\tif ([\"read\", \"edit\", \"write\"].includes(toolName) && typeof pathValue === \"string\" && pathValue.trim()) {\n\t\treturn `${tenantKey}\\0${toolName}:${pathValue.trim()}`;\n\t}\n\tif (toolName === \"background_script\") {\n\t\tconst selector = backgroundScriptSelector(record);\n\t\treturn selector ? backgroundScriptActionKey(tenantKey, selector) : undefined;\n\t}\n\tif (toolName.endsWith(\"_status\")) return `${tenantKey}\\0${toolName}`;\n\tif (toolName === \"learning_auto_learn_state\") return `${tenantKey}\\0${toolName}:${String(record.action || \"read\")}`;\n\tif (toolName === \"task_steps\") return `${tenantKey}\\0${toolName}:${String(record.action || \"list\")}`;\n\treturn undefined;\n}\n\nexport function getToolPanelResultActionKeys(scope: ToolPanelTenantScope, toolName: string, result: unknown): string[] {\n\tif (toolName !== \"background_script\") return [];\n\tconst tenantKey = createToolPanelTenantKey(scope);\n\treturn backgroundScriptResultSelectors(result).map((selector) => backgroundScriptActionKey(tenantKey, selector));\n}\n\nexport function shouldReuseToolPanelInPlace(toolName: string, args: unknown): boolean {\n\treturn (\n\t\ttoolName === \"background_script\" &&\n\t\t!!args &&\n\t\ttypeof args === \"object\" &&\n\t\t!!backgroundScriptSelector(args as Record<string, unknown>)\n\t);\n}\n\n// Reusable panels retain rendered arguments/results. Keep this aligned with the bounded live TUI\n// scrollback rather than pinning one component for every unique file/status action in a long process.\nconst MAX_REUSABLE_TOOL_PANEL_ACTIONS = 256;\n\nexport class ToolPanelRegistry {\n\tprivate readonly panelsByAction = new Map<string, ToolExecutionComponent>();\n\tprivate readonly activeByCallId = new Map<string, ToolExecutionComponent>();\n\tprivate readonly actionKeyByCallId = new Map<string, string>();\n\n\tgetReusable(actionKey: string | undefined, options?: { allowActive?: boolean }): ToolExecutionComponent | undefined {\n\t\tif (!actionKey) return undefined;\n\t\tconst panel = this.panelsByAction.get(actionKey);\n\t\tif (!panel || (!options?.allowActive && this.isActive(panel))) return undefined;\n\t\t// Refresh insertion order so eviction follows recent reuse rather than original creation.\n\t\tthis.panelsByAction.delete(actionKey);\n\t\tthis.panelsByAction.set(actionKey, panel);\n\t\treturn panel;\n\t}\n\n\tprivate rememberAction(actionKey: string, panel: ToolExecutionComponent): void {\n\t\tthis.panelsByAction.delete(actionKey);\n\t\tthis.panelsByAction.set(actionKey, panel);\n\t\twhile (this.panelsByAction.size > MAX_REUSABLE_TOOL_PANEL_ACTIONS) {\n\t\t\tconst oldest = this.panelsByAction.keys().next().value;\n\t\t\tif (oldest === undefined) break;\n\t\t\tthis.panelsByAction.delete(oldest);\n\t\t}\n\t}\n\n\treplaceActiveForAction(toolCallId: string, panel: ToolExecutionComponent, actionKey: string): void {\n\t\tfor (const [activeCallId, activeActionKey] of this.actionKeyByCallId.entries()) {\n\t\t\tif (activeActionKey !== actionKey) continue;\n\t\t\tthis.activeByCallId.delete(activeCallId);\n\t\t\tthis.actionKeyByCallId.delete(activeCallId);\n\t\t}\n\t\tthis.register(toolCallId, panel, actionKey);\n\t}\n\n\tregister(toolCallId: string, panel: ToolExecutionComponent, actionKey?: string): void {\n\t\tthis.activeByCallId.set(toolCallId, panel);\n\t\tif (actionKey) {\n\t\t\tthis.rememberAction(actionKey, panel);\n\t\t\tthis.actionKeyByCallId.set(toolCallId, actionKey);\n\t\t}\n\t}\n\n\tregisterAliases(panel: ToolExecutionComponent, actionKeys: string[]): void {\n\t\tfor (const actionKey of actionKeys) {\n\t\t\tthis.rememberAction(actionKey, panel);\n\t\t}\n\t}\n\n\thasActive(toolCallId: string): boolean {\n\t\treturn this.activeByCallId.has(toolCallId);\n\t}\n\n\tgetActive(toolCallId: string): ToolExecutionComponent | undefined {\n\t\treturn this.activeByCallId.get(toolCallId);\n\t}\n\n\tactiveEntries(): IterableIterator<[string, ToolExecutionComponent]> {\n\t\treturn this.activeByCallId.entries();\n\t}\n\n\tisActive(panel: ToolExecutionComponent): boolean {\n\t\tfor (const active of this.activeByCallId.values()) {\n\t\t\tif (active === panel) return true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tfinish(toolCallId: string): void {\n\t\tthis.activeByCallId.delete(toolCallId);\n\t\tthis.actionKeyByCallId.delete(toolCallId);\n\t}\n\n\tclearActive(): void {\n\t\tthis.activeByCallId.clear();\n\t\tthis.actionKeyByCallId.clear();\n\t}\n\n\tclearAll(): void {\n\t\tthis.activeByCallId.clear();\n\t\tthis.panelsByAction.clear();\n\t\tthis.actionKeyByCallId.clear();\n\t}\n}\n"]}
|