mastracode 0.45.0 → 0.46.0-alpha.1
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/dist/cli.cjs +7 -2
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +7 -2
- package/dist/cli.js.map +1 -1
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/tui/commands/think.d.ts.map +1 -1
- package/dist/tui/components/account-switch-notice.d.ts +1 -1
- package/dist/tui/components/ask-question-inline.d.ts +15 -0
- package/dist/tui/components/ask-question-inline.d.ts.map +1 -1
- package/dist/tui/components/banner.d.ts +32 -5
- package/dist/tui/components/banner.d.ts.map +1 -1
- package/dist/tui/components/custom-editor.d.ts +0 -4
- package/dist/tui/components/custom-editor.d.ts.map +1 -1
- package/dist/tui/components/error-display.d.ts.map +1 -1
- package/dist/tui/components/idle-counter.d.ts +5 -1
- package/dist/tui/components/idle-counter.d.ts.map +1 -1
- package/dist/tui/components/judge-display.d.ts +1 -0
- package/dist/tui/components/judge-display.d.ts.map +1 -1
- package/dist/tui/components/notification.d.ts.map +1 -1
- package/dist/tui/components/om-output.d.ts +2 -2
- package/dist/tui/components/om-output.d.ts.map +1 -1
- package/dist/tui/components/plan-approval-inline.d.ts +2 -0
- package/dist/tui/components/plan-approval-inline.d.ts.map +1 -1
- package/dist/tui/components/shell-output.d.ts +1 -1
- package/dist/tui/components/shell-output.d.ts.map +1 -1
- package/dist/tui/components/slash-command.d.ts +2 -2
- package/dist/tui/components/slash-command.d.ts.map +1 -1
- package/dist/tui/components/subagent-execution.d.ts.map +1 -1
- package/dist/tui/components/surface.d.ts +30 -0
- package/dist/tui/components/surface.d.ts.map +1 -0
- package/dist/tui/components/system-reminder.d.ts.map +1 -1
- package/dist/tui/components/task-progress.d.ts.map +1 -1
- package/dist/tui/components/thinking-settings.d.ts.map +1 -1
- package/dist/tui/components/tool-approval-dialog.d.ts +36 -15
- package/dist/tui/components/tool-approval-dialog.d.ts.map +1 -1
- package/dist/tui/components/tool-execution-enhanced.d.ts +16 -4
- package/dist/tui/components/tool-execution-enhanced.d.ts.map +1 -1
- package/dist/tui/components/tool-execution-interface.d.ts +5 -0
- package/dist/tui/components/tool-execution-interface.d.ts.map +1 -1
- package/dist/tui/components/user-message.d.ts +3 -2
- package/dist/tui/components/user-message.d.ts.map +1 -1
- package/dist/tui/components/wrapping-select-list.d.ts +13 -1
- package/dist/tui/components/wrapping-select-list.d.ts.map +1 -1
- package/dist/tui/handlers/agent-lifecycle.d.ts +1 -0
- package/dist/tui/handlers/agent-lifecycle.d.ts.map +1 -1
- package/dist/tui/handlers/message.d.ts.map +1 -1
- package/dist/tui/handlers/tool.d.ts.map +1 -1
- package/dist/tui/mastra-tui.d.ts.map +1 -1
- package/dist/tui/onboarding-inline.d.ts +6 -0
- package/dist/tui/onboarding-inline.d.ts.map +1 -1
- package/dist/tui/render-messages.d.ts +1 -1
- package/dist/tui/render-messages.d.ts.map +1 -1
- package/dist/tui/setup.d.ts.map +1 -1
- package/dist/tui/state.d.ts +9 -13
- package/dist/tui/state.d.ts.map +1 -1
- package/dist/tui/status-line.d.ts +8 -2
- package/dist/tui/status-line.d.ts.map +1 -1
- package/dist/tui/theme.d.ts +19 -1
- package/dist/tui/theme.d.ts.map +1 -1
- package/dist/{tui-CDdSkr_Q.js → tui-5IfsALo2.js} +1338 -1137
- package/dist/tui-5IfsALo2.js.map +1 -0
- package/dist/{tui-BsLtXA9y.cjs → tui-jrSC6Hge.cjs} +1337 -1136
- package/dist/tui-jrSC6Hge.cjs.map +1 -0
- package/dist/tui.cjs +1 -1
- package/dist/tui.js +1 -1
- package/package.json +12 -12
- package/dist/tui-BsLtXA9y.cjs.map +0 -1
- package/dist/tui-CDdSkr_Q.js.map +0 -1
|
@@ -23,7 +23,8 @@ import { DEFAULT_STT_MODEL, defaultModelForProvider, resolveSTTModel, sttModelsF
|
|
|
23
23
|
import { Readable } from "stream";
|
|
24
24
|
import { DeepgramVoice } from "@mastra/voice-deepgram";
|
|
25
25
|
import { OpenAIVoice } from "@mastra/voice-openai";
|
|
26
|
-
import { THINK_COMMAND_DESCRIPTOR,
|
|
26
|
+
import { THINK_COMMAND_DESCRIPTOR, isThinkingLevelSetting, parseThinkCommand } from "@mastra/code-sdk/thinking";
|
|
27
|
+
import { getCatalogThinkingLevels, runCatalogThinkingLevel } from "@mastra/code-sdk/thinking-catalog";
|
|
27
28
|
import { VALID_EVENTS } from "@mastra/code-sdk/hooks/index";
|
|
28
29
|
import { openUrlInBrowser } from "@mastra/code-sdk/utils/open-url";
|
|
29
30
|
import { parseError } from "@mastra/code-sdk/utils/errors";
|
|
@@ -138,6 +139,7 @@ const textThemeKeys = [
|
|
|
138
139
|
"muted",
|
|
139
140
|
"dim",
|
|
140
141
|
"text",
|
|
142
|
+
"secondary",
|
|
141
143
|
"thinkingText",
|
|
142
144
|
"userMessageText",
|
|
143
145
|
"toolTitle",
|
|
@@ -171,6 +173,60 @@ const mastra = new Proxy({}, { get(_target, prop) {
|
|
|
171
173
|
const surface = getSurface();
|
|
172
174
|
if (prop in surface) return surface[prop];
|
|
173
175
|
} });
|
|
176
|
+
/**
|
|
177
|
+
* A surface shade derived from the terminal's own background (detected via OSC 11), so panels match the
|
|
178
|
+
* user's theme instead of a fixed grey. Same idea as opencode's "system" theme: each step moves the
|
|
179
|
+
* background's luminance 1/30 of the way toward white (dark) or black (light) while keeping its hue.
|
|
180
|
+
* Step 1 = tool output panels, step 2 = the prompt and sent messages.
|
|
181
|
+
*/
|
|
182
|
+
function surfaceShade(step) {
|
|
183
|
+
const bg = getContrastBg();
|
|
184
|
+
const [r, g, b] = [
|
|
185
|
+
1,
|
|
186
|
+
3,
|
|
187
|
+
5
|
|
188
|
+
].map((i) => parseInt(bg.slice(i, i + 2), 16));
|
|
189
|
+
const lum = .299 * r + .587 * g + .114 * b;
|
|
190
|
+
const f = step / 12 * .4;
|
|
191
|
+
let out;
|
|
192
|
+
if (currentThemeMode === "light") out = [
|
|
193
|
+
r,
|
|
194
|
+
g,
|
|
195
|
+
b
|
|
196
|
+
].map((c) => c * (1 - f));
|
|
197
|
+
else if (lum < 10) {
|
|
198
|
+
const lift = Math.min(255, step * 18);
|
|
199
|
+
out = [
|
|
200
|
+
lift,
|
|
201
|
+
lift,
|
|
202
|
+
lift
|
|
203
|
+
];
|
|
204
|
+
} else {
|
|
205
|
+
const ratio = (lum + (255 - lum) * f) / lum;
|
|
206
|
+
out = [
|
|
207
|
+
r,
|
|
208
|
+
g,
|
|
209
|
+
b
|
|
210
|
+
].map((c) => Math.min(255, c * ratio));
|
|
211
|
+
}
|
|
212
|
+
return `#${out.map((c) => Math.floor(c).toString(16).padStart(2, "0")).join("")}`;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Mode colors (build / plan / fast) as displayed. On dark backgrounds the deep brand colors are lifted
|
|
216
|
+
* toward white the same way the accent is (brand green maps exactly to the accent), so mode-colored text
|
|
217
|
+
* never reads darker than the accent. On light backgrounds brand green maps to the light accent and the
|
|
218
|
+
* others are darkened just enough to read.
|
|
219
|
+
*/
|
|
220
|
+
function displayModeColor(hex) {
|
|
221
|
+
const isBrandGreen = hex.toLowerCase() === mastraBrand.green.toLowerCase();
|
|
222
|
+
if (currentThemeMode === "light") return isBrandGreen ? lightTheme.accent : ensureContrast(hex, getContrastBg());
|
|
223
|
+
if (isBrandGreen) return darkTheme.accent;
|
|
224
|
+
const mix = (i) => {
|
|
225
|
+
const c = parseInt(hex.slice(i, i + 2), 16);
|
|
226
|
+
return Math.round(c + (255 - c) * .35).toString(16).padStart(2, "0");
|
|
227
|
+
};
|
|
228
|
+
return `#${mix(1)}${mix(3)}${mix(5)}`;
|
|
229
|
+
}
|
|
174
230
|
/** Tint a hex color by a brightness factor (0–1). e.g. tintHex("#ff8800", 0.15) → near-black orange */
|
|
175
231
|
function tintHex(hex, factor) {
|
|
176
232
|
const r = Math.floor(parseInt(hex.slice(1, 3), 16) * factor);
|
|
@@ -179,16 +235,17 @@ function tintHex(hex, factor) {
|
|
|
179
235
|
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
|
180
236
|
}
|
|
181
237
|
const darkTheme = {
|
|
182
|
-
accent: "#
|
|
238
|
+
accent: "#62f69d",
|
|
183
239
|
border: "#3f3f46",
|
|
184
|
-
borderAccent: "#
|
|
240
|
+
borderAccent: "#62f69d",
|
|
185
241
|
borderMuted: "#27272a",
|
|
186
|
-
success: "#
|
|
242
|
+
success: "#62f69d",
|
|
187
243
|
error: "#ef4444",
|
|
188
244
|
warning: "#f59e0b",
|
|
189
245
|
muted: "#8c8c94",
|
|
190
246
|
dim: "#84848c",
|
|
191
247
|
text: "#fafafa",
|
|
248
|
+
secondary: "#d9d9dc",
|
|
192
249
|
thinkingText: "#a1a1aa",
|
|
193
250
|
userMessageBg: "#0f172a",
|
|
194
251
|
userMessageText: "#fafafa",
|
|
@@ -199,8 +256,8 @@ const darkTheme = {
|
|
|
199
256
|
toolBorderPending: "#52525b",
|
|
200
257
|
toolBorderSuccess: "#52525b",
|
|
201
258
|
toolBorderError: "#ef4444",
|
|
202
|
-
toolTitle: "#
|
|
203
|
-
toolArgs: "#
|
|
259
|
+
toolTitle: "#d9d9dc",
|
|
260
|
+
toolArgs: "#d9d9dc",
|
|
204
261
|
toolOutput: "#d4d4d8",
|
|
205
262
|
textHighlight: "#c084fc",
|
|
206
263
|
errorBg: "#291415",
|
|
@@ -215,12 +272,13 @@ const lightTheme = {
|
|
|
215
272
|
border: "#d4d4d8",
|
|
216
273
|
borderAccent: "#0d8020",
|
|
217
274
|
borderMuted: "#e4e4e7",
|
|
218
|
-
success: "#
|
|
275
|
+
success: "#0d8020",
|
|
219
276
|
error: "#dc2626",
|
|
220
277
|
warning: "#d97706",
|
|
221
278
|
muted: "#595961",
|
|
222
279
|
dim: "#67676f",
|
|
223
280
|
text: "#18181b",
|
|
281
|
+
secondary: "#38383e",
|
|
224
282
|
thinkingText: "#595961",
|
|
225
283
|
userMessageBg: "#f0fdf4",
|
|
226
284
|
userMessageText: "#18181b",
|
|
@@ -231,8 +289,8 @@ const lightTheme = {
|
|
|
231
289
|
toolBorderPending: "#a1a1aa",
|
|
232
290
|
toolBorderSuccess: "#a1a1aa",
|
|
233
291
|
toolBorderError: "#dc2626",
|
|
234
|
-
toolTitle: "#
|
|
235
|
-
toolArgs: "#
|
|
292
|
+
toolTitle: "#38383e",
|
|
293
|
+
toolArgs: "#38383e",
|
|
236
294
|
toolOutput: "#3f3f46",
|
|
237
295
|
textHighlight: "#7c3aed",
|
|
238
296
|
errorBg: "#fef2f2",
|
|
@@ -3191,12 +3249,18 @@ var WrappingSelectList = class {
|
|
|
3191
3249
|
onSelectionChange;
|
|
3192
3250
|
/** Called when the user confirms a multi-select list with Enter; receives all checked items in display order. */
|
|
3193
3251
|
onConfirmMulti;
|
|
3194
|
-
|
|
3252
|
+
/**
|
|
3253
|
+
* `card` style (inline prompts): an accent ❯ cursor and a bold label instead of a highlighted row,
|
|
3254
|
+
* and ●/○ instead of [x]/[ ] in multi-select mode.
|
|
3255
|
+
*/
|
|
3256
|
+
cardStyle;
|
|
3257
|
+
constructor(items, maxVisible, theme, multiSelect = false, cardStyle) {
|
|
3195
3258
|
this.items = items;
|
|
3196
3259
|
this.filteredItems = items;
|
|
3197
3260
|
this.maxVisible = maxVisible;
|
|
3198
3261
|
this.theme = theme;
|
|
3199
3262
|
this.multiSelect = multiSelect;
|
|
3263
|
+
this.cardStyle = cardStyle;
|
|
3200
3264
|
}
|
|
3201
3265
|
setFilter(filter) {
|
|
3202
3266
|
this.filteredItems = this.items.filter((item) => item.value.toLowerCase().startsWith(filter.toLowerCase()));
|
|
@@ -3253,6 +3317,14 @@ var WrappingSelectList = class {
|
|
|
3253
3317
|
const checkboxWidth = this.multiSelect ? CHECKBOX_WIDTH : 0;
|
|
3254
3318
|
const wrapped = wrapTextWithAnsi(labelText, Math.max(1, width - PREFIX_WIDTH - checkboxWidth));
|
|
3255
3319
|
const checkbox = this.multiSelect ? this.checkedValues.has(item.value) ? CHECKBOX_CHECKED : CHECKBOX_UNCHECKED : "";
|
|
3320
|
+
if (this.cardStyle) {
|
|
3321
|
+
const style = this.cardStyle;
|
|
3322
|
+
const box = this.multiSelect ? this.checkedValues.has(item.value) ? style.checked : style.unchecked : "";
|
|
3323
|
+
return (wrapped.length === 0 ? [""] : wrapped).map((chunk, index) => {
|
|
3324
|
+
if (index > 0) return `${" ".repeat(PREFIX_WIDTH + (this.multiSelect ? CHECKBOX_WIDTH : 0))}${chunk}`;
|
|
3325
|
+
return `${isSelected ? style.cursor : UNSELECTED_PREFIX}${box}${isSelected ? style.selectedLabel(chunk) : chunk}`;
|
|
3326
|
+
});
|
|
3327
|
+
}
|
|
3256
3328
|
if (wrapped.length === 0) {
|
|
3257
3329
|
const rendered = `${isSelected ? SELECTED_PREFIX : UNSELECTED_PREFIX}${checkbox}`;
|
|
3258
3330
|
return [isSelected ? this.theme.selectedText(rendered) : rendered];
|
|
@@ -3833,11 +3905,11 @@ const BASE_THINKING_LEVELS = [
|
|
|
3833
3905
|
id: "max",
|
|
3834
3906
|
label: "Max",
|
|
3835
3907
|
providerValue: "max",
|
|
3836
|
-
description: "Unbounded reasoning
|
|
3908
|
+
description: "Unbounded reasoning"
|
|
3837
3909
|
}
|
|
3838
3910
|
];
|
|
3839
3911
|
function getThinkingLevelsForModel(modelId) {
|
|
3840
|
-
const availableLevels =
|
|
3912
|
+
const availableLevels = getCatalogThinkingLevels(modelId);
|
|
3841
3913
|
const levels = BASE_THINKING_LEVELS.filter((level) => availableLevels.some((available) => available === level.id));
|
|
3842
3914
|
if (!modelId.startsWith("openai/")) return [...levels];
|
|
3843
3915
|
return levels.map((level) => ({
|
|
@@ -3894,6 +3966,7 @@ async function handleThinkCommand(ctx, args = []) {
|
|
|
3894
3966
|
const modelId = ctx.state.session.model.get() ?? "";
|
|
3895
3967
|
const thinkingLevels = getThinkingLevelsForModel(modelId);
|
|
3896
3968
|
const override = getSessionOverride(ctx);
|
|
3969
|
+
const runningOverride = override && runCatalogThinkingLevel(modelId, override);
|
|
3897
3970
|
const configuredDefault = getConfiguredDefault(ctx);
|
|
3898
3971
|
const rawArguments = args.join(" ");
|
|
3899
3972
|
if (rawArguments) {
|
|
@@ -3923,7 +3996,7 @@ async function handleThinkCommand(ctx, args = []) {
|
|
|
3923
3996
|
label: ` Default ${theme.fg("dim", defaultDescription)}${override === void 0 ? theme.fg("dim", " (current)") : ""}`
|
|
3924
3997
|
}, ...thinkingLevels.map((l) => ({
|
|
3925
3998
|
value: l.id,
|
|
3926
|
-
label: ` ${l.label} ${theme.fg("dim", l.description)}${l.id ===
|
|
3999
|
+
label: ` ${l.label} ${theme.fg("dim", l.description)}${l.id === runningOverride ? theme.fg("dim", " (current)") : ""}`
|
|
3927
4000
|
}))];
|
|
3928
4001
|
const modelNote = getModelNote(ctx);
|
|
3929
4002
|
return new Promise((resolve) => {
|
|
@@ -3947,7 +4020,7 @@ async function handleThinkCommand(ctx, args = []) {
|
|
|
3947
4020
|
} else if (isThinkingLevelSetting(selectedValue)) {
|
|
3948
4021
|
await ctx.state.session.state.set({ thinkingLevel: selectedValue });
|
|
3949
4022
|
const selectedLabel = getThinkingLevelForModel(modelId, selectedValue).label;
|
|
3950
|
-
ctx.showInfo(`Thinking → ${selectedValue ===
|
|
4023
|
+
ctx.showInfo(`Thinking → ${selectedValue === runningOverride ? `${selectedLabel} (unchanged)` : `${selectedLabel} (session override)`}`);
|
|
3951
4024
|
}
|
|
3952
4025
|
} catch {} finally {
|
|
3953
4026
|
resolve();
|
|
@@ -3960,7 +4033,7 @@ async function handleThinkCommand(ctx, args = []) {
|
|
|
3960
4033
|
container.addChild(selectList);
|
|
3961
4034
|
container.addChild(new Spacer(1));
|
|
3962
4035
|
container.addChild(new Text(theme.fg("dim", "↑↓ navigate · Enter select · Esc cancel"), 0, 0));
|
|
3963
|
-
const currentIdx = override === void 0 ? 0 : thinkingLevels.findIndex((l) => l.id ===
|
|
4036
|
+
const currentIdx = override === void 0 ? 0 : thinkingLevels.findIndex((l) => l.id === runningOverride) + 1;
|
|
3964
4037
|
if (currentIdx > 0) selectList.setSelectedIndex(currentIdx);
|
|
3965
4038
|
const modal = container;
|
|
3966
4039
|
modal.handleInput = (data) => selectList.handleInput(data);
|
|
@@ -5358,6 +5431,227 @@ async function handleModeCommand(ctx, args) {
|
|
|
5358
5431
|
}
|
|
5359
5432
|
}
|
|
5360
5433
|
//#endregion
|
|
5434
|
+
//#region src/tui/components/ansi.ts
|
|
5435
|
+
/**
|
|
5436
|
+
* Shared ANSI text-handling helpers for TUI components.
|
|
5437
|
+
*/
|
|
5438
|
+
const ANSI_CLOSERS = "\x1B]8;;\x07\x1B[0m";
|
|
5439
|
+
const ELLIPSIS = "…";
|
|
5440
|
+
const ELLIPSIS_WIDTH = visibleWidth(ELLIPSIS);
|
|
5441
|
+
const graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
5442
|
+
function fitVisibleText(text, maxWidth) {
|
|
5443
|
+
if (maxWidth <= 0) return {
|
|
5444
|
+
text: "",
|
|
5445
|
+
width: 0,
|
|
5446
|
+
truncated: text.length > 0
|
|
5447
|
+
};
|
|
5448
|
+
const targetWidth = Math.max(0, maxWidth - ELLIPSIS_WIDTH);
|
|
5449
|
+
let width = 0;
|
|
5450
|
+
let result = "";
|
|
5451
|
+
let resultWidth = 0;
|
|
5452
|
+
for (const { segment: char } of graphemeSegmenter.segment(text)) {
|
|
5453
|
+
const charWidth = visibleWidth(char);
|
|
5454
|
+
if (width + charWidth > maxWidth) return {
|
|
5455
|
+
text: `${result}${ELLIPSIS}`,
|
|
5456
|
+
width: resultWidth + ELLIPSIS_WIDTH,
|
|
5457
|
+
truncated: true
|
|
5458
|
+
};
|
|
5459
|
+
if (width + charWidth <= targetWidth) {
|
|
5460
|
+
result += char;
|
|
5461
|
+
resultWidth += charWidth;
|
|
5462
|
+
}
|
|
5463
|
+
width += charWidth;
|
|
5464
|
+
}
|
|
5465
|
+
return {
|
|
5466
|
+
text,
|
|
5467
|
+
width,
|
|
5468
|
+
truncated: false
|
|
5469
|
+
};
|
|
5470
|
+
}
|
|
5471
|
+
/** Truncate a string with ANSI codes to a visible width.
|
|
5472
|
+
* Handles both SGR sequences (\x1b[...m) and OSC 8 hyperlinks (\x1b]8;...;\x07).
|
|
5473
|
+
*/
|
|
5474
|
+
function truncateAnsi(str, maxWidth) {
|
|
5475
|
+
if (maxWidth <= 0) return "";
|
|
5476
|
+
const ansiRegex = /\x1b\[[0-9;]{0,32}m|\x1b\]8;[^\x07\x1b]{0,8192}\x07/g;
|
|
5477
|
+
let visibleLength = 0;
|
|
5478
|
+
let result = "";
|
|
5479
|
+
let lastIndex = 0;
|
|
5480
|
+
let match;
|
|
5481
|
+
while ((match = ansiRegex.exec(str)) !== null) {
|
|
5482
|
+
const fitted = fitVisibleText(str.slice(lastIndex, match.index), maxWidth - visibleLength);
|
|
5483
|
+
if (fitted.truncated) {
|
|
5484
|
+
result += fitted.text;
|
|
5485
|
+
result += ANSI_CLOSERS;
|
|
5486
|
+
return result;
|
|
5487
|
+
}
|
|
5488
|
+
result += fitted.text;
|
|
5489
|
+
visibleLength += fitted.width;
|
|
5490
|
+
result += match[0];
|
|
5491
|
+
lastIndex = match.index + match[0].length;
|
|
5492
|
+
}
|
|
5493
|
+
const fitted = fitVisibleText(str.slice(lastIndex), maxWidth - visibleLength);
|
|
5494
|
+
result += fitted.text;
|
|
5495
|
+
if (fitted.truncated) result += ANSI_CLOSERS;
|
|
5496
|
+
return result;
|
|
5497
|
+
}
|
|
5498
|
+
//#endregion
|
|
5499
|
+
//#region src/tui/components/surface.ts
|
|
5500
|
+
/**
|
|
5501
|
+
* Shared drawing primitives for the borderless TUI design: half-block panels (prompt, sent messages,
|
|
5502
|
+
* tool output), the colored left bar for prompts that wait on the user, and soft keycaps for key hints.
|
|
5503
|
+
*/
|
|
5504
|
+
/** The xterm-256 gray ramp (232-255) plus black (16) and white (231). */
|
|
5505
|
+
const GRAYS_256 = [
|
|
5506
|
+
[16, 0],
|
|
5507
|
+
...Array.from({ length: 24 }, (_, i) => [232 + i, 8 + i * 10]),
|
|
5508
|
+
[231, 255]
|
|
5509
|
+
];
|
|
5510
|
+
/**
|
|
5511
|
+
* Nearest xterm-256 gray. Panel shades are a step off the background, and the nearest color of the 6×6×6 cube
|
|
5512
|
+
* is often a saturated one (peach on a cream background, teal on Solarized), so panels stay neutral instead.
|
|
5513
|
+
*/
|
|
5514
|
+
function nearestGray256(rgb) {
|
|
5515
|
+
const luma = .299 * rgb[0] + .587 * rgb[1] + .114 * rgb[2];
|
|
5516
|
+
let best = GRAYS_256[0];
|
|
5517
|
+
for (const gray of GRAYS_256) if (Math.abs(gray[1] - luma) < Math.abs(best[1] - luma)) best = gray;
|
|
5518
|
+
return best[0];
|
|
5519
|
+
}
|
|
5520
|
+
/** SGR opening a panel color at the terminal's color depth, so panel bodies and their half-block edges match. */
|
|
5521
|
+
function surfaceOpen(hex, layer) {
|
|
5522
|
+
const rgb = [
|
|
5523
|
+
1,
|
|
5524
|
+
3,
|
|
5525
|
+
5
|
|
5526
|
+
].map((i) => parseInt(hex.slice(i, i + 2), 16));
|
|
5527
|
+
if (chalk.level === 0) return "";
|
|
5528
|
+
if (chalk.level === 2) return `\x1b[${layer};5;${nearestGray256(rgb)}m`;
|
|
5529
|
+
return `\x1b[${layer};2;${rgb.join(";")}m`;
|
|
5530
|
+
}
|
|
5531
|
+
const bgOpen = (hex) => surfaceOpen(hex, 48);
|
|
5532
|
+
/** Fill a line with `bg` across `width` columns, re-applying it after any reset inside the line. */
|
|
5533
|
+
function fillBg(line, width, bg) {
|
|
5534
|
+
const open = bgOpen(bg);
|
|
5535
|
+
const pad = Math.max(0, width - visibleWidth(line));
|
|
5536
|
+
return open + line.replace(/\x1b\[(?:0|49)?m/g, (m) => m + open) + " ".repeat(pad) + "\x1B[49m";
|
|
5537
|
+
}
|
|
5538
|
+
/**
|
|
5539
|
+
* Rows on a solid background framed by half blocks (▄ above, ▀ below), so the panel reads as starting and
|
|
5540
|
+
* ending mid-row instead of using a border.
|
|
5541
|
+
*/
|
|
5542
|
+
function halfBlockPanel(rows, width, bg) {
|
|
5543
|
+
return [
|
|
5544
|
+
panelEdge("▄", width, bg),
|
|
5545
|
+
...rows.map((r) => fillBg(r, width, bg)),
|
|
5546
|
+
panelEdge("▀", width, bg)
|
|
5547
|
+
];
|
|
5548
|
+
}
|
|
5549
|
+
/** A panel's ▄ or ▀ edge in the panel color. Without colors there's no panel background, so it's blank. */
|
|
5550
|
+
function panelEdge(ch, width, bg) {
|
|
5551
|
+
const open = surfaceOpen(bg, 38);
|
|
5552
|
+
const n = Math.max(0, width);
|
|
5553
|
+
return open ? `${open}${ch.repeat(n)}\x1b[39m` : " ".repeat(n);
|
|
5554
|
+
}
|
|
5555
|
+
const ESCAPE_TOKEN_RE = /(\x1b(?:\[[0-?]*[ -/]*[@-~]|[\]_][^\x07\x1b]*(?:\x07|\x1b\\)))/;
|
|
5556
|
+
const RESET_RE = /^\x1b\[(?:0|49)?m$/;
|
|
5557
|
+
const graphemes = new Intl.Segmenter();
|
|
5558
|
+
/** Higher = the shade stays strong farther right before fading. 1 is a straight linear fade. */
|
|
5559
|
+
const FADE_CURVE = 3;
|
|
5560
|
+
function fadeShades(width, step) {
|
|
5561
|
+
const last = Math.max(1, width - 1);
|
|
5562
|
+
return Array.from({ length: Math.max(0, width) }, (_, col) => surfaceShade(step * (1 - (col / last) ** FADE_CURVE)));
|
|
5563
|
+
}
|
|
5564
|
+
function fadeRow(line, shades) {
|
|
5565
|
+
let out = "";
|
|
5566
|
+
let col = 0;
|
|
5567
|
+
let current = "";
|
|
5568
|
+
const cell = (text) => {
|
|
5569
|
+
const hex = shades[Math.min(col, shades.length - 1)] ?? "";
|
|
5570
|
+
if (hex !== current) {
|
|
5571
|
+
current = hex;
|
|
5572
|
+
out += bgOpen(hex);
|
|
5573
|
+
}
|
|
5574
|
+
out += text;
|
|
5575
|
+
col += visibleWidth(text);
|
|
5576
|
+
};
|
|
5577
|
+
for (const part of line.split(ESCAPE_TOKEN_RE)) {
|
|
5578
|
+
if (!part) continue;
|
|
5579
|
+
if (part.startsWith("\x1B")) {
|
|
5580
|
+
out += part;
|
|
5581
|
+
if (RESET_RE.test(part) && current) out += bgOpen(current);
|
|
5582
|
+
continue;
|
|
5583
|
+
}
|
|
5584
|
+
for (const { segment } of graphemes.segment(part)) cell(segment);
|
|
5585
|
+
}
|
|
5586
|
+
while (col < shades.length) cell(" ");
|
|
5587
|
+
return `${out}\x1b[49m`;
|
|
5588
|
+
}
|
|
5589
|
+
function fadeEdge(ch, shades) {
|
|
5590
|
+
if (chalk.level === 0) return " ".repeat(shades.length);
|
|
5591
|
+
let out = "";
|
|
5592
|
+
let current = "";
|
|
5593
|
+
for (const hex of shades) {
|
|
5594
|
+
if (hex !== current) {
|
|
5595
|
+
current = hex;
|
|
5596
|
+
out += surfaceOpen(hex, 38);
|
|
5597
|
+
}
|
|
5598
|
+
out += ch;
|
|
5599
|
+
}
|
|
5600
|
+
return `${out}\x1b[39m`;
|
|
5601
|
+
}
|
|
5602
|
+
/** Like halfBlockPanel, but the shade fades out toward the right edge. */
|
|
5603
|
+
function fadePanel(rows, width, step) {
|
|
5604
|
+
if (chalk.level === 2) return halfBlockPanel(rows, width, surfaceShade(step));
|
|
5605
|
+
const shades = fadeShades(width, step);
|
|
5606
|
+
return [
|
|
5607
|
+
fadeEdge("▄", shades),
|
|
5608
|
+
...rows.map((r) => fadeRow(r, shades)),
|
|
5609
|
+
fadeEdge("▀", shades)
|
|
5610
|
+
];
|
|
5611
|
+
}
|
|
5612
|
+
/** Background of the prompt and sent messages. */
|
|
5613
|
+
const promptSurface = () => surfaceShade(2);
|
|
5614
|
+
/** Tool blocks with output: the title band is a step lighter than the output panel under it. */
|
|
5615
|
+
const toolTitleSurface = () => surfaceShade(2);
|
|
5616
|
+
const toolOutputSurface = () => surfaceShade(1);
|
|
5617
|
+
/** Status dot in front of a tool-style row: grey while running, green when done, red on failure. */
|
|
5618
|
+
function statusDot(status) {
|
|
5619
|
+
return status === "running" ? theme.fg("muted", "•") : theme.fg(status === "error" ? "error" : "success", "•");
|
|
5620
|
+
}
|
|
5621
|
+
/**
|
|
5622
|
+
* Tool-style block: a "• title" row (further title rows indented under it). With output, the title rows sit
|
|
5623
|
+
* on a lighter band directly above the output panel, the output lined up under the title text. Without output
|
|
5624
|
+
* it's just the title rows, so runs of quiet calls stay one row each.
|
|
5625
|
+
*/
|
|
5626
|
+
function toolBlock(dot, title, output, width) {
|
|
5627
|
+
const [first = "", ...rest] = Array.isArray(title) ? title : [title];
|
|
5628
|
+
const titleRows = [`${dot} ${first}`, ...rest.map((line) => ` ${line}`)];
|
|
5629
|
+
if (output.length === 0) return titleRows;
|
|
5630
|
+
const contentWidth = Math.max(1, width - 3);
|
|
5631
|
+
const titleBg = toolTitleSurface();
|
|
5632
|
+
const outputBg = toolOutputSurface();
|
|
5633
|
+
return [
|
|
5634
|
+
panelEdge("▄", width, titleBg),
|
|
5635
|
+
...titleRows.map((line) => fillBg(line, width, titleBg)),
|
|
5636
|
+
...output.map((line) => fillBg(` ${truncateAnsi(line, contentWidth)}`, width, outputBg)),
|
|
5637
|
+
panelEdge("▀", width, outputBg)
|
|
5638
|
+
];
|
|
5639
|
+
}
|
|
5640
|
+
/** Left-bar card for inline prompts: accent = waiting on you, warning = approval, border = answered. */
|
|
5641
|
+
function card(color, lines) {
|
|
5642
|
+
const bar = chalk.hex(color)("▎");
|
|
5643
|
+
return lines.map((l) => l === "" ? bar : `${bar} ${l}`);
|
|
5644
|
+
}
|
|
5645
|
+
/** Soft keycap: key text between the description grey and full white, on a chip one shade up. */
|
|
5646
|
+
function keycap(key) {
|
|
5647
|
+
const fg = theme.getTheme().secondary;
|
|
5648
|
+
return fillBg(chalk.hex(fg)(` ${key} `), visibleWidth(key) + 2, surfaceShade(2));
|
|
5649
|
+
}
|
|
5650
|
+
/** "key description" hint, e.g. keyHint('/help', 'info & shortcuts'). */
|
|
5651
|
+
function keyHint(key, description) {
|
|
5652
|
+
return `${keycap(key)} ${theme.fg("muted", description)}`;
|
|
5653
|
+
}
|
|
5654
|
+
//#endregion
|
|
5361
5655
|
//#region src/tui/components/width-aware-container.ts
|
|
5362
5656
|
/** Rebuilds width-derived children only when state or the received render width changes. */
|
|
5363
5657
|
var WidthAwareContainer = class extends Container {
|
|
@@ -5379,12 +5673,10 @@ var WidthAwareContainer = class extends Container {
|
|
|
5379
5673
|
//#endregion
|
|
5380
5674
|
//#region src/tui/components/slash-command.ts
|
|
5381
5675
|
/**
|
|
5382
|
-
* SlashCommandComponent - renders a
|
|
5383
|
-
* showing the command name as a heading
|
|
5676
|
+
* SlashCommandComponent - renders a "• skill /name" or "• command /name" block for slash command messages
|
|
5677
|
+
* showing the command name as a heading; the content stays hidden until
|
|
5384
5678
|
* expanded with ctrl+e. The full content is still sent to the assistant.
|
|
5385
5679
|
*/
|
|
5386
|
-
const MAX_COLLAPSED_LINES$1 = 3;
|
|
5387
|
-
const getBorderColor = () => mastra.green;
|
|
5388
5680
|
var SlashCommandComponent = class extends WidthAwareContainer {
|
|
5389
5681
|
commandName;
|
|
5390
5682
|
contentLines;
|
|
@@ -5405,14 +5697,17 @@ var SlashCommandComponent = class extends WidthAwareContainer {
|
|
|
5405
5697
|
}
|
|
5406
5698
|
rebuildForWidth(termWidth) {
|
|
5407
5699
|
this.clear();
|
|
5408
|
-
const
|
|
5409
|
-
const maxLineWidth = Math.max(1,
|
|
5410
|
-
const
|
|
5411
|
-
|
|
5412
|
-
|
|
5700
|
+
const width = Math.max(1, termWidth - 0);
|
|
5701
|
+
const maxLineWidth = Math.max(1, width - 3);
|
|
5702
|
+
const dot = statusDot("done");
|
|
5703
|
+
const isSkill = this.commandName.startsWith("skill/");
|
|
5704
|
+
const name = isSkill ? this.commandName.slice(6) : this.commandName;
|
|
5705
|
+
const heading = `${theme.bold(theme.fg("success", isSkill ? "skill" : "command"))} ${theme.fg("muted", `/${name}`)}`;
|
|
5706
|
+
const block = (output) => this.addChild(new Text(toolBlock(dot, heading, output, width).join("\n"), 0, 0));
|
|
5707
|
+
if (this.contentLines.length === 0 || !this.expanded) {
|
|
5708
|
+
block([]);
|
|
5413
5709
|
return;
|
|
5414
5710
|
}
|
|
5415
|
-
this.addChild(new Text(`${border("╭──")}`, 0, 0));
|
|
5416
5711
|
const wrappedLines = [];
|
|
5417
5712
|
for (const line of this.contentLines) if (line.length > maxLineWidth) {
|
|
5418
5713
|
let remaining = line;
|
|
@@ -5424,14 +5719,7 @@ var SlashCommandComponent = class extends WidthAwareContainer {
|
|
|
5424
5719
|
}
|
|
5425
5720
|
if (remaining) wrappedLines.push(remaining);
|
|
5426
5721
|
} else wrappedLines.push(line);
|
|
5427
|
-
|
|
5428
|
-
const contentText = (truncated ? wrappedLines.slice(0, MAX_COLLAPSED_LINES$1) : wrappedLines).map((line) => `${border("│")} ${chalk.hex(mastra.mainGray)(line.length > maxLineWidth ? line.slice(0, maxLineWidth - 1) + "…" : line)}`).join("\n");
|
|
5429
|
-
this.addChild(new Text(contentText, 0, 0));
|
|
5430
|
-
if (truncated) {
|
|
5431
|
-
const moreText = chalk.hex(mastra.darkGray)(`... ${wrappedLines.length - MAX_COLLAPSED_LINES$1} more lines (ctrl+e to expand)`);
|
|
5432
|
-
this.addChild(new Text(`${border("│")} ${moreText}`, 0, 0));
|
|
5433
|
-
}
|
|
5434
|
-
this.addChild(new Text(`${border("╰──")} ${heading}`, 0, 0));
|
|
5722
|
+
block(wrappedLines.map((line) => chalk.hex(mastra.mainGray)(line.length > maxLineWidth ? line.slice(0, maxLineWidth - 1) + "…" : line)));
|
|
5435
5723
|
}
|
|
5436
5724
|
getChatSpacingKind() {
|
|
5437
5725
|
return "other";
|
|
@@ -5441,7 +5729,7 @@ var SlashCommandComponent = class extends WidthAwareContainer {
|
|
|
5441
5729
|
//#region src/tui/components/account-switch-notice.ts
|
|
5442
5730
|
/**
|
|
5443
5731
|
* One-line transcript notice for persisted `data-mastracode-account-switch`
|
|
5444
|
-
* parts: account rotations
|
|
5732
|
+
* parts: account rotations and pool exhaustion.
|
|
5445
5733
|
* Modeled on OMMarkerComponent (single themed Text row). The copy comes from
|
|
5446
5734
|
* the SDK's shared formatter so live `info`-event lines and history-reloaded
|
|
5447
5735
|
* part lines read identically.
|
|
@@ -5510,6 +5798,8 @@ var AskQuestionBorderedBox = class {
|
|
|
5510
5798
|
answerIsNegative = false;
|
|
5511
5799
|
/** True when created during streaming, before activate() is called */
|
|
5512
5800
|
streaming = false;
|
|
5801
|
+
/** Rows the card last took while waiting for an answer; the settled card keeps this height. */
|
|
5802
|
+
liveHeight = 0;
|
|
5513
5803
|
constructor(questionLines, hintText, items, selectList, input, streaming) {
|
|
5514
5804
|
this.questionLines = questionLines;
|
|
5515
5805
|
this.hintText = hintText;
|
|
@@ -5558,99 +5848,95 @@ var AskQuestionBorderedBox = class {
|
|
|
5558
5848
|
if (this.answered) {
|
|
5559
5849
|
if (this.cachedLines && this.cachedWidth === width && this.cachedThemeGeneration === getThemeGeneration()) return this.cachedLines;
|
|
5560
5850
|
const result = this.renderSafe(width);
|
|
5851
|
+
while (result.length < this.liveHeight) result.push("");
|
|
5561
5852
|
this.cachedLines = result;
|
|
5562
5853
|
this.cachedWidth = width;
|
|
5563
5854
|
this.cachedThemeGeneration = getThemeGeneration();
|
|
5564
5855
|
return result;
|
|
5565
5856
|
}
|
|
5566
|
-
|
|
5857
|
+
const result = this.renderSafe(width);
|
|
5858
|
+
this.liveHeight = result.length;
|
|
5859
|
+
return result;
|
|
5567
5860
|
}
|
|
5568
5861
|
renderSafe(width) {
|
|
5569
5862
|
try {
|
|
5570
5863
|
return this._render(width);
|
|
5571
5864
|
} catch {
|
|
5572
|
-
return [
|
|
5573
|
-
"" + theme.fg("dim", "╭──── Question ────╮"),
|
|
5574
|
-
"" + theme.fg("dim", "│ (render error) │"),
|
|
5575
|
-
"" + theme.fg("dim", "╰──────────────────╯")
|
|
5576
|
-
];
|
|
5865
|
+
return card(theme.getTheme().dim, [theme.fg("dim", "(render error)")]);
|
|
5577
5866
|
}
|
|
5578
5867
|
}
|
|
5868
|
+
/**
|
|
5869
|
+
* Borderless card with a colored left bar (▎):
|
|
5870
|
+
* - waiting for an answer: accent bar, bold question, ❯ options, hint
|
|
5871
|
+
* - answered: muted question with the options frozen (✓ on the chosen ones), or "✓ answer" for
|
|
5872
|
+
* free text; a card answered live keeps the height it had while waiting (see render)
|
|
5873
|
+
*/
|
|
5579
5874
|
_render(width) {
|
|
5580
|
-
const
|
|
5581
|
-
const innerWidth = Math.max(1, width - 0 -
|
|
5582
|
-
const
|
|
5583
|
-
const
|
|
5584
|
-
lines.
|
|
5585
|
-
const
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
addLine(cancelLine, visibleWidth(cancelLine));
|
|
5622
|
-
} else {
|
|
5623
|
-
const text = (s) => theme.fg("text", s);
|
|
5624
|
-
for (const item of this.items) if (this.selectedValues ? this.selectedValues.includes(item.label) : item.label === this.selectedValue) addWrappedOptionLine(`${this.answerIsNegative ? theme.fg("error", "✗") : theme.fg("success", "✓")} `, item.label, text);
|
|
5625
|
-
else addWrappedOptionLine(continuationPrefix, item.label, dim);
|
|
5626
|
-
}
|
|
5627
|
-
addLine("", 0);
|
|
5628
|
-
} else if (this.answered && this.selectedValue != null) {
|
|
5629
|
-
const iconPrefix = `${this.answerIsNegative ? theme.fg("error", "✗") : theme.fg("success", "✓")} `;
|
|
5630
|
-
const continuationPrefix = " ";
|
|
5631
|
-
wrapTextWithAnsi(this.selectedValue, Math.max(1, innerWidth - visibleWidth(iconPrefix))).forEach((line, index) => {
|
|
5632
|
-
const prefix = index === 0 ? iconPrefix : continuationPrefix;
|
|
5633
|
-
const content = `${prefix}${theme.fg("text", line)}`;
|
|
5634
|
-
addLine(content, visibleWidth(prefix) + visibleWidth(line));
|
|
5635
|
-
});
|
|
5636
|
-
} else if (this.answered && this.cancelled) {
|
|
5637
|
-
const cancelLine = `${theme.fg("error", "✗")} ${theme.fg("dim", "(cancelled)")}`;
|
|
5638
|
-
addLine(cancelLine, visibleWidth(cancelLine));
|
|
5639
|
-
} else {
|
|
5640
|
-
if (this.selectList) {
|
|
5641
|
-
const selectLines = this.selectList.render(innerWidth);
|
|
5642
|
-
for (const sLine of selectLines) addLine(sLine, visibleWidth(sLine));
|
|
5643
|
-
} else if (this.input) {
|
|
5644
|
-
const inputLines = this.input.render(innerWidth);
|
|
5645
|
-
for (const iLine of inputLines) addLine(iLine, visibleWidth(iLine));
|
|
5646
|
-
}
|
|
5647
|
-
const hint = theme.fg("dim", this.hintText);
|
|
5648
|
-
addLine(hint, visibleWidth(hint));
|
|
5875
|
+
const t = theme.getTheme();
|
|
5876
|
+
const innerWidth = Math.max(1, width - 0 - 2);
|
|
5877
|
+
const wrap = (text, style) => wrapTextWithAnsi(text, innerWidth).map((line) => style(line));
|
|
5878
|
+
const question = (style) => this.questionLines.flatMap((line) => line ? wrap(line, style) : [""]);
|
|
5879
|
+
const out = (color, lines) => card(color, lines.map((line) => truncateToWidth(line, innerWidth))).map((line) => "" + line);
|
|
5880
|
+
const icon = this.answerIsNegative ? theme.fg("error", "✗") : theme.fg("success", "✓");
|
|
5881
|
+
if (this.streaming) return out(t.dim, [
|
|
5882
|
+
...question((s) => theme.bold(theme.fg("text", s))),
|
|
5883
|
+
"",
|
|
5884
|
+
...this.items.flatMap((item) => wrap(item.label, (s) => theme.fg("dim", ` ${s}`))),
|
|
5885
|
+
theme.fg("dim", "…")
|
|
5886
|
+
]);
|
|
5887
|
+
if (this.answered) {
|
|
5888
|
+
const asked = question((s) => theme.fg("muted", s));
|
|
5889
|
+
const cancelledLine = `${theme.fg("error", "✗")} ${theme.fg("dim", "(cancelled)")}`;
|
|
5890
|
+
if (this.items.length > 0) {
|
|
5891
|
+
const chosen = new Set(this.selectedValues ?? (this.selectedValue != null ? [this.selectedValue] : []));
|
|
5892
|
+
const optionLines = this.items.flatMap((item) => {
|
|
5893
|
+
const picked = !this.cancelled && chosen.has(item.label);
|
|
5894
|
+
return wrapTextWithAnsi(item.label, Math.max(1, innerWidth - 2)).map((line, j) => `${picked && j === 0 ? icon : " "} ${theme.fg(picked ? "secondary" : "dim", line)}`);
|
|
5895
|
+
});
|
|
5896
|
+
return out(t.border, [
|
|
5897
|
+
...asked,
|
|
5898
|
+
"",
|
|
5899
|
+
...optionLines,
|
|
5900
|
+
...this.cancelled ? [cancelledLine] : []
|
|
5901
|
+
]);
|
|
5902
|
+
}
|
|
5903
|
+
if (this.cancelled) return out(t.border, [
|
|
5904
|
+
...asked,
|
|
5905
|
+
"",
|
|
5906
|
+
cancelledLine
|
|
5907
|
+
]);
|
|
5908
|
+
const answers = this.selectedValues ?? (this.selectedValue != null ? [this.selectedValue] : []);
|
|
5909
|
+
if (answers.length === 0) return out(t.border, asked);
|
|
5910
|
+
const answerLines = answers.flatMap((answer, i) => wrapTextWithAnsi(answer, Math.max(1, innerWidth - 2)).map((line, j) => `${j === 0 ? icon : " "} ${theme.fg("secondary", line)}`));
|
|
5911
|
+
return out(t.border, [
|
|
5912
|
+
...asked,
|
|
5913
|
+
"",
|
|
5914
|
+
...answerLines
|
|
5915
|
+
]);
|
|
5649
5916
|
}
|
|
5650
|
-
|
|
5651
|
-
return
|
|
5917
|
+
const body = this.selectList ? this.selectList.render(innerWidth) : this.input ? this.input.render(innerWidth) : [];
|
|
5918
|
+
return out(t.accent, [
|
|
5919
|
+
...question((s) => theme.bold(theme.fg("text", s))),
|
|
5920
|
+
"",
|
|
5921
|
+
...body,
|
|
5922
|
+
"",
|
|
5923
|
+
theme.fg("dim", this.hintText)
|
|
5924
|
+
]);
|
|
5652
5925
|
}
|
|
5653
5926
|
};
|
|
5927
|
+
/** Option list styling shared by inline prompts: accent ❯ cursor, bold selected label, ●/○ toggles. */
|
|
5928
|
+
const INLINE_CARD_LIST_STYLE = {
|
|
5929
|
+
get cursor() {
|
|
5930
|
+
return theme.fg("accent", "❯ ");
|
|
5931
|
+
},
|
|
5932
|
+
get checked() {
|
|
5933
|
+
return theme.fg("accent", "●") + " ";
|
|
5934
|
+
},
|
|
5935
|
+
get unchecked() {
|
|
5936
|
+
return theme.fg("dim", "○") + " ";
|
|
5937
|
+
},
|
|
5938
|
+
selectedLabel: (label) => theme.bold(label)
|
|
5939
|
+
};
|
|
5654
5940
|
var AskQuestionInlineComponent = class AskQuestionInlineComponent extends Container {
|
|
5655
5941
|
borderedBox;
|
|
5656
5942
|
selectList;
|
|
@@ -5789,7 +6075,7 @@ var AskQuestionInlineComponent = class AskQuestionInlineComponent extends Contai
|
|
|
5789
6075
|
value: AskQuestionInlineComponent.CUSTOM_RESPONSE_VALUE,
|
|
5790
6076
|
label: theme.fg("dim", "✎ Custom response...")
|
|
5791
6077
|
});
|
|
5792
|
-
this.selectList = new WrappingSelectList(items, Math.min(items.length, 8), getSelectListTheme(), this.multiSelect);
|
|
6078
|
+
this.selectList = new WrappingSelectList(items, Math.min(items.length, 8), getSelectListTheme(), this.multiSelect, INLINE_CARD_LIST_STYLE);
|
|
5793
6079
|
if (this.multiSelect) this.selectList.onConfirmMulti = (selected) => {
|
|
5794
6080
|
this.handleMultiAnswer(selected.map((item) => item.value));
|
|
5795
6081
|
};
|
|
@@ -5945,16 +6231,13 @@ var JudgeDisplayComponent = class extends WidthAwareContainer {
|
|
|
5945
6231
|
this.clear();
|
|
5946
6232
|
const border = (char) => chalk.hex(JUDGE_COLOR)(char);
|
|
5947
6233
|
const title = chalk.hex(JUDGE_COLOR).bold("Goal");
|
|
5948
|
-
const innerWidth = Math.max(20, termWidth - 0 -
|
|
5949
|
-
const horizontal = "─".repeat(innerWidth + 1);
|
|
5950
|
-
this.addChild(new Text(`${border("╭")}${border(horizontal)}${border("╮")}`, 0, 0));
|
|
6234
|
+
const innerWidth = Math.max(20, termWidth - 0 - 2);
|
|
5951
6235
|
this.addChild(new Text(this.renderRow(this.renderHeader(title), innerWidth, border), 0, 0));
|
|
5952
6236
|
if (!this.result && this.activity.length === 0 && !this.streamingReason) this.addChild(new Text(this.renderRow(chalk.dim("evaluating…"), innerWidth, border), 0, 0));
|
|
5953
6237
|
for (const line of this.activity) this.addChild(new Text(this.renderRow(this.renderActivityLine(line), innerWidth, border), 0, 0));
|
|
5954
6238
|
if (this.activity.length > 0 && (this.result || this.streamingReason)) this.addChild(new Text(this.renderRow("", innerWidth, border), 0, 0));
|
|
5955
6239
|
const reason = stripControlChars(this.result?.reason ?? this.streamingReason);
|
|
5956
6240
|
if (reason) for (const line of this.wrapLine(reason, innerWidth)) this.addChild(new Text(this.renderRow(chalk.dim(line), innerWidth, border), 0, 0));
|
|
5957
|
-
this.addChild(new Text(`${border("╰")}${border(horizontal)}${border("╯")}`, 0, 0));
|
|
5958
6241
|
}
|
|
5959
6242
|
renderActivityLine(line) {
|
|
5960
6243
|
const toolName = getActivityToolName(line);
|
|
@@ -5969,9 +6252,9 @@ var JudgeDisplayComponent = class extends WidthAwareContainer {
|
|
|
5969
6252
|
const turnInfo = this.maxTurns > 0 ? chalk.hex(MUTED_COLOR)(`(${this.turnsUsed}/${this.maxTurns})`) : "";
|
|
5970
6253
|
return `${title} ${decisionIcon} ${decisionText}${turnInfo ? ` ${turnInfo}` : ""}`;
|
|
5971
6254
|
}
|
|
6255
|
+
/** A row of the left-bar card (`width` is the room for text after the bar). */
|
|
5972
6256
|
renderRow(text, width, border) {
|
|
5973
|
-
|
|
5974
|
-
return `${border("│")} ${content}${border("│")}`;
|
|
6257
|
+
return text ? `${border("▎")} ${this.padLine(text, width)}` : border("▎");
|
|
5975
6258
|
}
|
|
5976
6259
|
wrapLine(text, width) {
|
|
5977
6260
|
const lines = [];
|
|
@@ -6047,9 +6330,6 @@ function priorityColor(priority) {
|
|
|
6047
6330
|
}
|
|
6048
6331
|
const MAX_NOTIFICATION_CONTENT_WIDTH = 100;
|
|
6049
6332
|
const MIN_NOTIFICATION_CONTENT_WIDTH = 24;
|
|
6050
|
-
function padLine$1(value, width) {
|
|
6051
|
-
return value + " ".repeat(Math.max(0, width - visibleWidth(value)));
|
|
6052
|
-
}
|
|
6053
6333
|
function splitLongWord(word, maxWidth) {
|
|
6054
6334
|
const segments = [];
|
|
6055
6335
|
let current = "";
|
|
@@ -6131,7 +6411,7 @@ var NotificationComponent = class extends WidthAwareContainer {
|
|
|
6131
6411
|
options.status
|
|
6132
6412
|
].filter(Boolean).join(" · ");
|
|
6133
6413
|
const message = options.message.trim();
|
|
6134
|
-
const maxContentWidth = Math.max(MIN_NOTIFICATION_CONTENT_WIDTH, Math.min(MAX_NOTIFICATION_CONTENT_WIDTH, width - 0 -
|
|
6414
|
+
const maxContentWidth = Math.max(MIN_NOTIFICATION_CONTENT_WIDTH, Math.min(MAX_NOTIFICATION_CONTENT_WIDTH, width - 0 - 2));
|
|
6135
6415
|
const titleLines = wrapText(titleText, maxContentWidth);
|
|
6136
6416
|
const detailLines = details ? wrapText(details, maxContentWidth) : [];
|
|
6137
6417
|
const messageLines = message ? this.limitMessageLines(wrapText(message, maxContentWidth), quiet, maxContentWidth) : [];
|
|
@@ -6140,22 +6420,13 @@ var NotificationComponent = class extends WidthAwareContainer {
|
|
|
6140
6420
|
options.backgroundCompletion.argsSummary ? `invocation · ${options.backgroundCompletion.argsSummary}` : void 0,
|
|
6141
6421
|
options.backgroundCompletion.errorSummary ? `failure · ${options.backgroundCompletion.errorSummary}` : void 0
|
|
6142
6422
|
].filter((line) => Boolean(line)).flatMap((line) => wrapText(line, maxContentWidth)) : [];
|
|
6143
|
-
const
|
|
6144
|
-
...titleLines,
|
|
6145
|
-
...detailLines,
|
|
6146
|
-
...messageLines,
|
|
6147
|
-
...backgroundDetailLines
|
|
6423
|
+
const lines = [
|
|
6424
|
+
...titleLines.map((line) => chalk.hex(priorityColor(options.priority)).bold(line)),
|
|
6425
|
+
...detailLines.map((line) => theme.fg("dim", line)),
|
|
6426
|
+
...messageLines.map((line) => theme.fg("thinkingText", line)),
|
|
6427
|
+
...backgroundDetailLines.map((line) => theme.fg("dim", line))
|
|
6148
6428
|
];
|
|
6149
|
-
|
|
6150
|
-
const borderColor = chalk.hex(mastra.blue);
|
|
6151
|
-
const top = `╭${"─".repeat(contentWidth + 2)}╮`;
|
|
6152
|
-
const bottom = `╰${"─".repeat(contentWidth + 2)}╯`;
|
|
6153
|
-
this.addChild(new Text(borderColor(top), 0, 0));
|
|
6154
|
-
for (const line of titleLines) this.addChild(new Text(`${borderColor("│")} ${chalk.hex(priorityColor(options.priority)).bold(padLine$1(line, contentWidth))} ${borderColor("│")}`, 0, 0));
|
|
6155
|
-
for (const line of detailLines) this.addChild(new Text(`${borderColor("│")} ${theme.fg("dim", padLine$1(line, contentWidth))} ${borderColor("│")}`, 0, 0));
|
|
6156
|
-
for (const line of messageLines) this.addChild(new Text(`${borderColor("│")} ${padLine$1(line, contentWidth)} ${borderColor("│")}`, 0, 0));
|
|
6157
|
-
for (const line of backgroundDetailLines) this.addChild(new Text(`${borderColor("│")} ${theme.fg("dim", padLine$1(line, contentWidth))} ${borderColor("│")}`, 0, 0));
|
|
6158
|
-
this.addChild(new Text(borderColor(bottom), 0, 0));
|
|
6429
|
+
this.addChild(new Text(card(mastra.blue, lines).join("\n"), 0, 0));
|
|
6159
6430
|
}
|
|
6160
6431
|
limitMessageLines(lines, quiet, maxWidth) {
|
|
6161
6432
|
if (!quiet || lines.length <= this.quietPreviewLineLimit) return lines;
|
|
@@ -6267,10 +6538,10 @@ function formatMarker(data) {
|
|
|
6267
6538
|
//#endregion
|
|
6268
6539
|
//#region src/tui/components/om-output.ts
|
|
6269
6540
|
/**
|
|
6270
|
-
* TUI component for rendering OM observation/reflection output
|
|
6541
|
+
* TUI component for rendering OM observation/reflection output as a tool-style block.
|
|
6271
6542
|
* Uses observer (amber) color for observations and reflector (red) color for reflections.
|
|
6272
6543
|
* Collapsed to COLLAPSED_LINES by default, expandable with ctrl+e.
|
|
6273
|
-
*
|
|
6544
|
+
* The title row carries the compression stats; the observations sit on a panel below.
|
|
6274
6545
|
*/
|
|
6275
6546
|
const getObserverColor$1 = () => mastra.orange;
|
|
6276
6547
|
const getReflectorColor$1 = () => mastra.red;
|
|
@@ -6280,33 +6551,6 @@ function formatTokens$1(tokens) {
|
|
|
6280
6551
|
const k = tokens / 1e3;
|
|
6281
6552
|
return k % 1 === 0 ? `${k}k` : `${k.toFixed(1)}k`;
|
|
6282
6553
|
}
|
|
6283
|
-
/** Truncate a string with ANSI codes to a visible width */
|
|
6284
|
-
function truncateAnsi$1(str, maxWidth) {
|
|
6285
|
-
const ansiRegex = /\x1b\[[0-9;]{0,32}m/g;
|
|
6286
|
-
let visibleLength = 0;
|
|
6287
|
-
let result = "";
|
|
6288
|
-
let lastIndex = 0;
|
|
6289
|
-
let match;
|
|
6290
|
-
while ((match = ansiRegex.exec(str)) !== null) {
|
|
6291
|
-
const textBefore = str.slice(lastIndex, match.index);
|
|
6292
|
-
for (const char of textBefore) {
|
|
6293
|
-
if (visibleLength >= maxWidth) break;
|
|
6294
|
-
result += char;
|
|
6295
|
-
visibleLength++;
|
|
6296
|
-
}
|
|
6297
|
-
if (visibleLength >= maxWidth) break;
|
|
6298
|
-
result += match[0];
|
|
6299
|
-
lastIndex = match.index + match[0].length;
|
|
6300
|
-
}
|
|
6301
|
-
const remaining = str.slice(lastIndex);
|
|
6302
|
-
for (const char of remaining) {
|
|
6303
|
-
if (visibleLength >= maxWidth) break;
|
|
6304
|
-
result += char;
|
|
6305
|
-
visibleLength++;
|
|
6306
|
-
}
|
|
6307
|
-
if (visibleLength >= maxWidth) result += "\x1B[0m";
|
|
6308
|
-
return result;
|
|
6309
|
-
}
|
|
6310
6554
|
/**
|
|
6311
6555
|
* Soft-wrap an array of lines to fit within maxWidth, preserving words where possible.
|
|
6312
6556
|
* Returns groups where each group corresponds to one original line split into wrapped segments.
|
|
@@ -6359,14 +6603,13 @@ var OMOutputComponent = class extends WidthAwareContainer {
|
|
|
6359
6603
|
rebuildForWidth(termWidth) {
|
|
6360
6604
|
this.clear();
|
|
6361
6605
|
const color = this.data.type === "reflection" ? getReflectorColor$1() : getObserverColor$1();
|
|
6362
|
-
const
|
|
6363
|
-
const maxLineWidth =
|
|
6606
|
+
const width = Math.max(1, termWidth - 0);
|
|
6607
|
+
const maxLineWidth = width - 4;
|
|
6364
6608
|
const originalLines = this.data.observations.split("\n");
|
|
6365
6609
|
const { groups, flat: wrappedLines } = softWrapLines(originalLines, maxLineWidth);
|
|
6366
6610
|
const originalLineCount = originalLines.length;
|
|
6367
6611
|
const wrappedLineCount = wrappedLines.length;
|
|
6368
6612
|
const footerText = this.buildFooterText(color);
|
|
6369
|
-
this.addChild(new Text(border("╭──"), 0, 0));
|
|
6370
6613
|
let truncated = false;
|
|
6371
6614
|
const borderedLines = [];
|
|
6372
6615
|
if (!this.expanded && wrappedLineCount > 11) {
|
|
@@ -6388,40 +6631,31 @@ var OMOutputComponent = class extends WidthAwareContainer {
|
|
|
6388
6631
|
}
|
|
6389
6632
|
truncated = tailGroupStart - headGroupCount > 0;
|
|
6390
6633
|
if (truncated) {
|
|
6391
|
-
for (const line of headLines) borderedLines.push(
|
|
6392
|
-
borderedLines.push(
|
|
6393
|
-
for (const line of tailLines) borderedLines.push(
|
|
6394
|
-
} else for (const line of wrappedLines) borderedLines.push(
|
|
6395
|
-
} else for (const line of wrappedLines) borderedLines.push(
|
|
6396
|
-
|
|
6397
|
-
if (
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
this.addChild(new Text(truncateAnsi$1(taskLine, termWidth - 2 - 0), 0, 0));
|
|
6401
|
-
}
|
|
6402
|
-
if (this.data.suggestedResponse && (this.expanded || !truncated)) {
|
|
6403
|
-
const sugLine = border("│") + " " + chalk.hex(color).bold("Suggested response: ") + chalk.hex(mastra.specialGray)(this.data.suggestedResponse);
|
|
6404
|
-
this.addChild(new Text(truncateAnsi$1(sugLine, termWidth - 2 - 0), 0, 0));
|
|
6405
|
-
}
|
|
6406
|
-
this.addChild(new Text(`${border("╰──")} ${footerText}`, 0, 0));
|
|
6634
|
+
for (const line of headLines) borderedLines.push(chalk.hex(mastra.specialGray)(line));
|
|
6635
|
+
borderedLines.push(chalk.hex(mastra.mainGray)(`... ${originalLineCount} lines total (ctrl+e to expand)`));
|
|
6636
|
+
for (const line of tailLines) borderedLines.push(chalk.hex(mastra.specialGray)(line));
|
|
6637
|
+
} else for (const line of wrappedLines) borderedLines.push(chalk.hex(mastra.specialGray)(line));
|
|
6638
|
+
} else for (const line of wrappedLines) borderedLines.push(chalk.hex(mastra.specialGray)(line));
|
|
6639
|
+
if (this.data.currentTask && (this.expanded || !truncated)) borderedLines.push(chalk.hex(color).bold("Current task: ") + chalk.hex(mastra.specialGray)(this.data.currentTask));
|
|
6640
|
+
if (this.data.suggestedResponse && (this.expanded || !truncated)) borderedLines.push(chalk.hex(color).bold("Suggested response: ") + chalk.hex(mastra.specialGray)(this.data.suggestedResponse));
|
|
6641
|
+
const output = borderedLines.some((line) => line.trim()) ? borderedLines : [];
|
|
6642
|
+
this.addChild(new Text(toolBlock(chalk.hex(color)("•"), footerText, output, width).join("\n"), 0, 0));
|
|
6407
6643
|
}
|
|
6408
6644
|
buildFooterText(color) {
|
|
6409
|
-
|
|
6410
|
-
const emoji = "🧠";
|
|
6411
|
-
if (isReflection) {
|
|
6645
|
+
if (this.data.type === "reflection") {
|
|
6412
6646
|
const observed = formatTokens$1(this.data.tokensObserved ?? 0);
|
|
6413
6647
|
const compressed = formatTokens$1(this.data.compressedTokens ?? this.data.observationTokens ?? 0);
|
|
6414
6648
|
const ratio = (this.data.tokensObserved ?? 0) > 0 && (this.data.compressedTokens ?? this.data.observationTokens ?? 0) > 0 ? `${Math.round((this.data.tokensObserved ?? 0) / (this.data.compressedTokens ?? this.data.observationTokens ?? 1))}x` : "";
|
|
6415
6649
|
const durationStr = this.data.durationMs ? ` in ${(this.data.durationMs / 1e3).toFixed(1)}s` : "";
|
|
6416
6650
|
const ratioStr = ratio ? ` (${ratio} compression)` : "";
|
|
6417
|
-
return `${
|
|
6651
|
+
return `${chalk.hex(color)(`Reflected: ${observed} → ${compressed} tokens${ratioStr}${durationStr}`)}`;
|
|
6418
6652
|
} else {
|
|
6419
6653
|
const observed = formatTokens$1(this.data.tokensObserved ?? 0);
|
|
6420
6654
|
const compressed = formatTokens$1(this.data.observationTokens ?? 0);
|
|
6421
6655
|
const ratio = (this.data.tokensObserved ?? 0) > 0 && (this.data.observationTokens ?? 0) > 0 ? `${Math.round((this.data.tokensObserved ?? 0) / (this.data.observationTokens ?? 1))}x` : "";
|
|
6422
6656
|
const durationStr = this.data.durationMs ? ` in ${(this.data.durationMs / 1e3).toFixed(1)}s` : "";
|
|
6423
6657
|
const ratioStr = ratio ? ` (${ratio} compression)` : "";
|
|
6424
|
-
return `${
|
|
6658
|
+
return `${chalk.hex(color)(`Observed: ${observed} → ${compressed} tokens${ratioStr}${durationStr}`)}`;
|
|
6425
6659
|
}
|
|
6426
6660
|
}
|
|
6427
6661
|
getChatSpacingKind() {
|
|
@@ -6454,26 +6688,11 @@ var PlanContentBox = class {
|
|
|
6454
6688
|
}
|
|
6455
6689
|
render(width) {
|
|
6456
6690
|
if (this.cachedLines && this.cachedWidth === width && this.cachedThemeGeneration === getThemeGeneration()) return this.cachedLines;
|
|
6457
|
-
const
|
|
6458
|
-
const innerWidth = Math.max(20, availableWidth - 4);
|
|
6691
|
+
const innerWidth = Math.max(20, width - 0);
|
|
6459
6692
|
const rendered = new Markdown(this.plan, 0, 0, getMarkdownTheme(), { color: (text) => theme.fg("text", text) }).render(innerWidth).flatMap((line) => line.length > 0 ? [line] : [""]);
|
|
6460
|
-
const border = (text) => chalk.hex(mastra.purple)(text);
|
|
6461
|
-
const top = `${border("╭")}${border("─".repeat(innerWidth + 2))}${border("╮")}`;
|
|
6462
|
-
const bottom = `${border("╰")}${border("─".repeat(innerWidth + 2))}${border("╯")}`;
|
|
6463
6693
|
const body = [];
|
|
6464
|
-
for (const line of rendered)
|
|
6465
|
-
|
|
6466
|
-
for (const chunk of wrapped) {
|
|
6467
|
-
const chunkVis = visibleWidth(chunk);
|
|
6468
|
-
const padding = " ".repeat(Math.max(0, innerWidth - chunkVis));
|
|
6469
|
-
body.push(`${border("│")} ${chunk}${padding} ${border("│")}`);
|
|
6470
|
-
}
|
|
6471
|
-
}
|
|
6472
|
-
this.cachedLines = [
|
|
6473
|
-
top,
|
|
6474
|
-
...body,
|
|
6475
|
-
bottom
|
|
6476
|
-
];
|
|
6694
|
+
for (const line of rendered) body.push(...wrapTextWithAnsi(line, innerWidth).map((chunk) => chunk.replace(/\s+$/, "")));
|
|
6695
|
+
this.cachedLines = body;
|
|
6477
6696
|
this.cachedWidth = width;
|
|
6478
6697
|
this.cachedThemeGeneration = getThemeGeneration();
|
|
6479
6698
|
return this.cachedLines;
|
|
@@ -6498,11 +6717,7 @@ var PlanDiffBox = class {
|
|
|
6498
6717
|
}
|
|
6499
6718
|
render(width) {
|
|
6500
6719
|
if (this.cachedLines && this.cachedWidth === width && this.cachedThemeGeneration === getThemeGeneration()) return this.cachedLines;
|
|
6501
|
-
const
|
|
6502
|
-
const innerWidth = Math.max(20, availableWidth - 4);
|
|
6503
|
-
const border = (text) => chalk.hex(mastra.purple)(text);
|
|
6504
|
-
const top = `${border("╭")}${border("─".repeat(innerWidth + 2))}${border("╮")}`;
|
|
6505
|
-
const bottom = `${border("╰")}${border("─".repeat(innerWidth + 2))}${border("╯")}`;
|
|
6720
|
+
const innerWidth = Math.max(20, width - 0);
|
|
6506
6721
|
const removedColor = chalk.hex(mastra.red);
|
|
6507
6722
|
const addedColor = chalk.hex(theme.getTheme().success);
|
|
6508
6723
|
const body = [];
|
|
@@ -6513,23 +6728,25 @@ var PlanDiffBox = class {
|
|
|
6513
6728
|
const wrappedChunks = wrapTextWithAnsi(entry.text, textWidth);
|
|
6514
6729
|
for (let ci = 0; ci < wrappedChunks.length; ci++) {
|
|
6515
6730
|
const content = colorFn(`${ci === 0 ? prefix : " "}${wrappedChunks[ci]}`);
|
|
6516
|
-
|
|
6517
|
-
const padding = " ".repeat(Math.max(0, innerWidth - contentVis));
|
|
6518
|
-
body.push(`${border("│")} ${content}${padding} ${border("│")}`);
|
|
6731
|
+
body.push(content);
|
|
6519
6732
|
}
|
|
6520
6733
|
}
|
|
6521
|
-
this.cachedLines =
|
|
6522
|
-
top,
|
|
6523
|
-
...body,
|
|
6524
|
-
bottom
|
|
6525
|
-
];
|
|
6734
|
+
this.cachedLines = body;
|
|
6526
6735
|
this.cachedWidth = width;
|
|
6527
6736
|
this.cachedThemeGeneration = getThemeGeneration();
|
|
6528
6737
|
return this.cachedLines;
|
|
6529
6738
|
}
|
|
6530
6739
|
};
|
|
6740
|
+
/** Plan prompts sit inside a left bar in the plan-mode color, like the other inline prompts. */
|
|
6741
|
+
function withPlanBar(lines) {
|
|
6742
|
+
const bar = chalk.hex(displayModeColor(mastra.purple))("▎");
|
|
6743
|
+
return lines.map((line) => line.replace(/\x1b\[[0-9;]*m/g, "").trim() === "" ? bar : `${bar} ${line}`);
|
|
6744
|
+
}
|
|
6531
6745
|
var PlanApprovalInlineComponent = class PlanApprovalInlineComponent extends Container {
|
|
6532
6746
|
ui;
|
|
6747
|
+
render(width) {
|
|
6748
|
+
return withPlanBar(super.render(Math.max(1, width - 2)));
|
|
6749
|
+
}
|
|
6533
6750
|
contentBox;
|
|
6534
6751
|
selectList;
|
|
6535
6752
|
onApprove;
|
|
@@ -6607,15 +6824,15 @@ var PlanApprovalInlineComponent = class PlanApprovalInlineComponent extends Cont
|
|
|
6607
6824
|
const items = [
|
|
6608
6825
|
{
|
|
6609
6826
|
value: "approve",
|
|
6610
|
-
label:
|
|
6827
|
+
label: `${theme.fg("text", "Approve")} ${theme.fg("dim", "switch to Build mode and implement")}`
|
|
6611
6828
|
},
|
|
6612
6829
|
{
|
|
6613
6830
|
value: "goal",
|
|
6614
|
-
label:
|
|
6831
|
+
label: `${theme.fg("text", "Use as /goal")} ${theme.fg("dim", "switch to Build mode and pursue this plan")}`
|
|
6615
6832
|
},
|
|
6616
6833
|
{
|
|
6617
6834
|
value: "changes",
|
|
6618
|
-
label:
|
|
6835
|
+
label: `${theme.fg("text", "Request changes")} ${theme.fg("dim", "reject and give feedback in chat")}`
|
|
6619
6836
|
}
|
|
6620
6837
|
];
|
|
6621
6838
|
this.selectList = new SelectList(items, items.length, getSelectListTheme());
|
|
@@ -6627,7 +6844,7 @@ var PlanApprovalInlineComponent = class PlanApprovalInlineComponent extends Cont
|
|
|
6627
6844
|
};
|
|
6628
6845
|
this.contentBox.addChild(this.selectList);
|
|
6629
6846
|
this.contentBox.addChild(new Spacer(1));
|
|
6630
|
-
this.contentBox.addChild(new Text(theme.fg("dim", "
|
|
6847
|
+
this.contentBox.addChild(new Text(theme.fg("dim", "↑↓ select · Enter confirm · Esc reject"), 0, 0));
|
|
6631
6848
|
}
|
|
6632
6849
|
renderStreaming() {
|
|
6633
6850
|
this.contentBox.clear();
|
|
@@ -6637,7 +6854,8 @@ var PlanApprovalInlineComponent = class PlanApprovalInlineComponent extends Cont
|
|
|
6637
6854
|
this.contentBox.addChild(new Text(theme.fg("dim", "Submitting plan…"), 0, 0));
|
|
6638
6855
|
}
|
|
6639
6856
|
renderPlanHeader(prefix = "") {
|
|
6640
|
-
|
|
6857
|
+
const plan = chalk.bold.hex(displayModeColor(mastra.purple));
|
|
6858
|
+
this.contentBox.addChild(new Text(`${prefix}${plan("Plan:")} ${theme.bold(theme.fg("text", this.planTitle))}`, 0, 0));
|
|
6641
6859
|
if (this.planFilename) this.contentBox.addChild(new Text(theme.fg("dim", this.planFilename), 0, 0));
|
|
6642
6860
|
this.contentBox.addChild(new Spacer(1));
|
|
6643
6861
|
}
|
|
@@ -6695,6 +6913,9 @@ var PlanApprovalInlineComponent = class PlanApprovalInlineComponent extends Cont
|
|
|
6695
6913
|
}
|
|
6696
6914
|
};
|
|
6697
6915
|
var PlanResultComponent = class extends Container {
|
|
6916
|
+
render(width) {
|
|
6917
|
+
return withPlanBar(super.render(Math.max(1, width - 2)));
|
|
6918
|
+
}
|
|
6698
6919
|
getChatSpacingKind() {
|
|
6699
6920
|
return "plan";
|
|
6700
6921
|
}
|
|
@@ -6704,7 +6925,7 @@ var PlanResultComponent = class extends Container {
|
|
|
6704
6925
|
this.addChild(contentBox);
|
|
6705
6926
|
const icon = options.isApproved ? theme.fg("success", "✓") : theme.fg("error", "✗");
|
|
6706
6927
|
const status = options.isApproved ? "Approved" : options.feedback ? "Changes requested" : "Rejected";
|
|
6707
|
-
contentBox.addChild(new Text(theme.bold(theme.fg("
|
|
6928
|
+
contentBox.addChild(new Text(`${chalk.bold.hex(displayModeColor(mastra.purple))("Plan:")} ${theme.bold(theme.fg("text", options.title))}`, 0, 0));
|
|
6708
6929
|
if (options.planFilename) contentBox.addChild(new Text(theme.fg("dim", options.planFilename), 0, 0));
|
|
6709
6930
|
contentBox.addChild(new Spacer(1));
|
|
6710
6931
|
contentBox.addChild(new PlanContentBox(options.plan));
|
|
@@ -6962,21 +7183,25 @@ var SubagentExecutionComponent = class extends WidthAwareContainer {
|
|
|
6962
7183
|
}
|
|
6963
7184
|
rebuildForWidth(termWidth) {
|
|
6964
7185
|
this.clear();
|
|
6965
|
-
const
|
|
6966
|
-
const maxLineWidth = Math.max(1,
|
|
7186
|
+
const width = Math.max(1, termWidth - 0);
|
|
7187
|
+
const maxLineWidth = Math.max(1, width - 3);
|
|
6967
7188
|
const typeLabelText = this.forked ? "fork" : this.agentType;
|
|
6968
7189
|
const typeLabel = theme.bold(colorText(this.colors.agentType, typeLabelText, (text) => theme.fg("accent", text)));
|
|
6969
7190
|
const modelLabel = this.modelId ? theme.fg("muted", ` ${this.modelId}`) : "";
|
|
6970
|
-
const statusIcon = this.backgroundTaskId ? this.done ? this.cancelled ? theme.fg("muted", ` ■ background · ${this.backgroundTaskId}`) : this.isError ? theme.fg("error", ` ✗ background · ${this.backgroundTaskId}`) : theme.fg("success", ` ✓ background · ${this.backgroundTaskId}`) : theme.fg("warning", ` ◌ background · ${this.backgroundTaskId}`) : this.done
|
|
7191
|
+
const statusIcon = this.backgroundTaskId ? this.done ? this.cancelled ? theme.fg("muted", ` ■ background · ${this.backgroundTaskId}`) : this.isError ? theme.fg("error", ` ✗ background · ${this.backgroundTaskId}`) : theme.fg("success", ` ✓ background · ${this.backgroundTaskId}`) : theme.fg("warning", ` ◌ background · ${this.backgroundTaskId}`) : this.done && this.isError ? colorText(this.colors.icon, ` ${this.icons.error}`, (text) => theme.fg("error", text)) : "";
|
|
7192
|
+
const dot = statusDot(this.done ? this.isError ? "error" : "done" : "running");
|
|
7193
|
+
const output = [];
|
|
7194
|
+
const emit = () => {
|
|
7195
|
+
this.addChild(new Text(toolBlock(dot, footerText, output, width).join("\n"), 0, 0));
|
|
7196
|
+
this.invalidate();
|
|
7197
|
+
this.ui.requestRender();
|
|
7198
|
+
};
|
|
6971
7199
|
const durationStr = this.done ? theme.fg("muted", ` ${formatDuration$1(this.durationMs)}`) : "";
|
|
6972
7200
|
const footerText = `${theme.bold(colorText(this.colors.label, this.label, (text) => theme.fg("toolTitle", text)))} ${typeLabel}${modelLabel}${durationStr}${statusIcon}`;
|
|
6973
7201
|
if ((this.collapseOnComplete || this.backgroundTaskId) && this.done && !this.expanded) {
|
|
6974
|
-
|
|
6975
|
-
this.invalidate();
|
|
6976
|
-
this.ui.requestRender();
|
|
7202
|
+
emit();
|
|
6977
7203
|
return;
|
|
6978
7204
|
}
|
|
6979
|
-
this.addChild(new Text(border("╭──"), 0, 0));
|
|
6980
7205
|
const taskLines = this.task.split("\n");
|
|
6981
7206
|
const wrappedTaskLines = [];
|
|
6982
7207
|
for (const line of taskLines) if (line.length > maxLineWidth) {
|
|
@@ -6991,14 +7216,11 @@ var SubagentExecutionComponent = class extends WidthAwareContainer {
|
|
|
6991
7216
|
} else wrappedTaskLines.push(line);
|
|
6992
7217
|
const maxTaskLines = 5;
|
|
6993
7218
|
const taskTruncated = !this.expanded && wrappedTaskLines.length > 6;
|
|
6994
|
-
const
|
|
6995
|
-
|
|
6996
|
-
if (taskTruncated) {
|
|
6997
|
-
const moreText = theme.fg("muted", `... ${wrappedTaskLines.length - maxTaskLines} more lines (ctrl+e to expand)`);
|
|
6998
|
-
this.addChild(new Text(`${border("│")} ${moreText}`, 0, 0));
|
|
6999
|
-
}
|
|
7219
|
+
const displayTaskLines = taskTruncated ? wrappedTaskLines.slice(0, maxTaskLines) : wrappedTaskLines;
|
|
7220
|
+
output.push(...displayTaskLines);
|
|
7221
|
+
if (taskTruncated) output.push(theme.fg("muted", `... ${wrappedTaskLines.length - maxTaskLines} more lines (ctrl+e to expand)`));
|
|
7000
7222
|
if (this.activity.length > 0) {
|
|
7001
|
-
|
|
7223
|
+
output.push(theme.fg("muted", "───"));
|
|
7002
7224
|
const activityLines = this.activity.flatMap((item) => formatActivityLine(item, maxLineWidth, this.icons, this.colors.icon));
|
|
7003
7225
|
const cap = this.done ? this.collapsedLines : this.maxActivityLines;
|
|
7004
7226
|
let displayLines = activityLines;
|
|
@@ -7010,22 +7232,15 @@ var SubagentExecutionComponent = class extends WidthAwareContainer {
|
|
|
7010
7232
|
}
|
|
7011
7233
|
if (hiddenCount > 0) {
|
|
7012
7234
|
const hiddenText = theme.fg("muted", ` ... ${hiddenCount} more above${this.done ? " (ctrl+e to expand)" : ""}`);
|
|
7013
|
-
|
|
7235
|
+
output.push(hiddenText);
|
|
7014
7236
|
}
|
|
7015
|
-
|
|
7016
|
-
this.addChild(new Text(activityContent, 0, 0));
|
|
7237
|
+
output.push(...displayLines);
|
|
7017
7238
|
}
|
|
7018
7239
|
if (this.done && this.finalResult && this.expanded) {
|
|
7019
|
-
|
|
7020
|
-
const
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
}).join("\n");
|
|
7024
|
-
if (resultContent.trim()) this.addChild(new Text(resultContent, 0, 0));
|
|
7025
|
-
}
|
|
7026
|
-
this.addChild(new Text(`${border("╰──")} ${footerText}`, 0, 0));
|
|
7027
|
-
this.invalidate();
|
|
7028
|
-
this.ui.requestRender();
|
|
7240
|
+
output.push(theme.fg("muted", "───"));
|
|
7241
|
+
for (const line of this.finalResult.split("\n")) output.push(theme.fg("muted", line.length > maxLineWidth ? line.slice(0, maxLineWidth - 1) + "…" : line));
|
|
7242
|
+
}
|
|
7243
|
+
emit();
|
|
7029
7244
|
}
|
|
7030
7245
|
};
|
|
7031
7246
|
function clampPositiveInt(value, fallback) {
|
|
@@ -7217,13 +7432,11 @@ var SystemReminderComponent = class extends WidthAwareContainer {
|
|
|
7217
7432
|
const metadataColor = (text) => theme.fg("dim", text);
|
|
7218
7433
|
const bodyColor = (text) => theme.fg("text", text);
|
|
7219
7434
|
const hintColor = (text) => theme.fg("dim", text);
|
|
7220
|
-
const innerWidth = Math.max(20, termWidth - 0 -
|
|
7221
|
-
const horizontal = "─".repeat(innerWidth + 1);
|
|
7435
|
+
const innerWidth = Math.max(20, termWidth - 0 - 2);
|
|
7222
7436
|
const metadataLines = [this.path ? formatReminderPath(this.path) : void 0].filter((line) => Boolean(line));
|
|
7223
7437
|
const wrappedMessageLines = wrapLines(this.messageLines, innerWidth);
|
|
7224
7438
|
const shouldCollapse = wrappedMessageLines.length > MAX_COLLAPSED_LINES;
|
|
7225
7439
|
const visibleMessageLines = shouldCollapse && !this.expanded ? wrappedMessageLines.slice(0, MAX_COLLAPSED_LINES) : wrappedMessageLines;
|
|
7226
|
-
this.addChild(new Text(`${border("╭")}${border(horizontal)}${border("╮")}`, 0, 0));
|
|
7227
7440
|
this.addChild(new Text(renderRow(title, innerWidth, border), 0, 0));
|
|
7228
7441
|
for (const line of metadataLines) this.addChild(new Text(renderRow(metadataColor(line), innerWidth, border), 0, 0));
|
|
7229
7442
|
if (metadataLines.length > 0 && visibleMessageLines.length > 0) this.addChild(new Text(renderRow("", innerWidth, border), 0, 0));
|
|
@@ -7232,13 +7445,11 @@ var SystemReminderComponent = class extends WidthAwareContainer {
|
|
|
7232
7445
|
const hint = hintColor(`... ${wrappedMessageLines.length - visibleMessageLines.length} more lines (ctrl+e to expand)`);
|
|
7233
7446
|
this.addChild(new Text(renderRow(hint, innerWidth, border), 0, 0));
|
|
7234
7447
|
}
|
|
7235
|
-
this.addChild(new Text(`${border("╰")}${border(horizontal)}${border("╯")}`, 0, 0));
|
|
7236
7448
|
}
|
|
7237
7449
|
};
|
|
7450
|
+
/** A row of the left-bar card (`width` is the room for text after the bar). */
|
|
7238
7451
|
function renderRow(text, width, border) {
|
|
7239
|
-
|
|
7240
|
-
const rightPadding = hasWideGlyph(stripAnsi(text)) ? " " : "";
|
|
7241
|
-
return `${border("│")} ${content}${rightPadding}${border("│")}`;
|
|
7452
|
+
return text ? `${border("▎")} ${padLine(text, width)}` : border("▎");
|
|
7242
7453
|
}
|
|
7243
7454
|
function splitMessageLines(message) {
|
|
7244
7455
|
return message.split("\n").map((line) => line.trimEnd()).filter((line) => line.length > 0);
|
|
@@ -7270,9 +7481,6 @@ function formatReminderPath(path) {
|
|
|
7270
7481
|
const cwdPrefix = `${cwd}/`;
|
|
7271
7482
|
return path.startsWith(cwdPrefix) ? path.slice(cwdPrefix.length) : path;
|
|
7272
7483
|
}
|
|
7273
|
-
function hasWideGlyph(text) {
|
|
7274
|
-
return [...text].some((char) => /[\p{Extended_Pictographic}\u1100-\u115F\u2329\u232A\u2E80-\uA4CF\uAC00-\uD7A3\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE6F\uFF00-\uFF60\uFFE0-\uFFE6]/u.test(char));
|
|
7275
|
-
}
|
|
7276
7484
|
function wrapLines(lines, maxLineWidth) {
|
|
7277
7485
|
if (lines.length === 0) return [""];
|
|
7278
7486
|
const wrappedLines = [];
|
|
@@ -7303,71 +7511,6 @@ function truncateLine(text, width) {
|
|
|
7303
7511
|
return plain.length <= width ? text : plain.slice(0, Math.max(0, width - 1)) + "…";
|
|
7304
7512
|
}
|
|
7305
7513
|
//#endregion
|
|
7306
|
-
//#region src/tui/components/ansi.ts
|
|
7307
|
-
/**
|
|
7308
|
-
* Shared ANSI text-handling helpers for TUI components.
|
|
7309
|
-
*/
|
|
7310
|
-
const ANSI_CLOSERS = "\x1B]8;;\x07\x1B[0m";
|
|
7311
|
-
const ELLIPSIS = "…";
|
|
7312
|
-
const ELLIPSIS_WIDTH = visibleWidth(ELLIPSIS);
|
|
7313
|
-
const graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
7314
|
-
function fitVisibleText(text, maxWidth) {
|
|
7315
|
-
if (maxWidth <= 0) return {
|
|
7316
|
-
text: "",
|
|
7317
|
-
width: 0,
|
|
7318
|
-
truncated: text.length > 0
|
|
7319
|
-
};
|
|
7320
|
-
const targetWidth = Math.max(0, maxWidth - ELLIPSIS_WIDTH);
|
|
7321
|
-
let width = 0;
|
|
7322
|
-
let result = "";
|
|
7323
|
-
let resultWidth = 0;
|
|
7324
|
-
for (const { segment: char } of graphemeSegmenter.segment(text)) {
|
|
7325
|
-
const charWidth = visibleWidth(char);
|
|
7326
|
-
if (width + charWidth > maxWidth) return {
|
|
7327
|
-
text: `${result}${ELLIPSIS}`,
|
|
7328
|
-
width: resultWidth + ELLIPSIS_WIDTH,
|
|
7329
|
-
truncated: true
|
|
7330
|
-
};
|
|
7331
|
-
if (width + charWidth <= targetWidth) {
|
|
7332
|
-
result += char;
|
|
7333
|
-
resultWidth += charWidth;
|
|
7334
|
-
}
|
|
7335
|
-
width += charWidth;
|
|
7336
|
-
}
|
|
7337
|
-
return {
|
|
7338
|
-
text,
|
|
7339
|
-
width,
|
|
7340
|
-
truncated: false
|
|
7341
|
-
};
|
|
7342
|
-
}
|
|
7343
|
-
/** Truncate a string with ANSI codes to a visible width.
|
|
7344
|
-
* Handles both SGR sequences (\x1b[...m) and OSC 8 hyperlinks (\x1b]8;...;\x07).
|
|
7345
|
-
*/
|
|
7346
|
-
function truncateAnsi(str, maxWidth) {
|
|
7347
|
-
if (maxWidth <= 0) return "";
|
|
7348
|
-
const ansiRegex = /\x1b\[[0-9;]{0,32}m|\x1b\]8;[^\x07\x1b]{0,8192}\x07/g;
|
|
7349
|
-
let visibleLength = 0;
|
|
7350
|
-
let result = "";
|
|
7351
|
-
let lastIndex = 0;
|
|
7352
|
-
let match;
|
|
7353
|
-
while ((match = ansiRegex.exec(str)) !== null) {
|
|
7354
|
-
const fitted = fitVisibleText(str.slice(lastIndex, match.index), maxWidth - visibleLength);
|
|
7355
|
-
if (fitted.truncated) {
|
|
7356
|
-
result += fitted.text;
|
|
7357
|
-
result += ANSI_CLOSERS;
|
|
7358
|
-
return result;
|
|
7359
|
-
}
|
|
7360
|
-
result += fitted.text;
|
|
7361
|
-
visibleLength += fitted.width;
|
|
7362
|
-
result += match[0];
|
|
7363
|
-
lastIndex = match.index + match[0].length;
|
|
7364
|
-
}
|
|
7365
|
-
const fitted = fitVisibleText(str.slice(lastIndex), maxWidth - visibleLength);
|
|
7366
|
-
result += fitted.text;
|
|
7367
|
-
if (fitted.truncated) result += ANSI_CLOSERS;
|
|
7368
|
-
return result;
|
|
7369
|
-
}
|
|
7370
|
-
//#endregion
|
|
7371
7514
|
//#region src/tui/components/task-progress.ts
|
|
7372
7515
|
/**
|
|
7373
7516
|
* Task progress component for the TUI.
|
|
@@ -7410,10 +7553,7 @@ var TaskProgressComponent = class extends WidthAwareContainer {
|
|
|
7410
7553
|
this.clear();
|
|
7411
7554
|
const completed = this.tasks.filter((t) => t.status === "completed").length;
|
|
7412
7555
|
const total = this.tasks.length;
|
|
7413
|
-
if (!(total > 0 && completed !== total))
|
|
7414
|
-
this.addChild(new Spacer(1));
|
|
7415
|
-
return;
|
|
7416
|
-
}
|
|
7556
|
+
if (!(total > 0 && completed !== total)) return;
|
|
7417
7557
|
this.addChild(new Spacer(1));
|
|
7418
7558
|
if (this.quietMode) {
|
|
7419
7559
|
for (const line of this.formatQuietTaskLines(completed, total, width)) this.addChild(new Text(line, 0, 0));
|
|
@@ -7565,12 +7705,6 @@ var CollapsibleComponent = class extends Container {
|
|
|
7565
7705
|
* Enhanced error display component with collapsible stack traces,
|
|
7566
7706
|
* syntax highlighting, and smart summarization.
|
|
7567
7707
|
*/
|
|
7568
|
-
/** A single-width box-drawing border sized to `width`, truncating from the right when the corners don't fit. */
|
|
7569
|
-
function fitBorder(width, left, right, fill = "─") {
|
|
7570
|
-
const inner = Math.max(0, width - left.length - right.length);
|
|
7571
|
-
const line = left + fill.repeat(inner) + right;
|
|
7572
|
-
return line.length <= width ? line : line.slice(0, Math.max(0, width));
|
|
7573
|
-
}
|
|
7574
7708
|
/**
|
|
7575
7709
|
* Parse error information from various error formats
|
|
7576
7710
|
*/
|
|
@@ -7660,38 +7794,21 @@ var ErrorDisplayComponent = class extends WidthAwareContainer {
|
|
|
7660
7794
|
rebuildForWidth(width) {
|
|
7661
7795
|
this.clear();
|
|
7662
7796
|
const info = parseErrorInfo(this.error);
|
|
7663
|
-
const
|
|
7664
|
-
|
|
7665
|
-
const borderWidth = Math.max(0, width - 0);
|
|
7666
|
-
const borderTop = new Text(theme.fg("error", fitBorder(borderWidth, "╭─ Error ", "╮")), 0, 0);
|
|
7667
|
-
box.addChild(borderTop);
|
|
7668
|
-
const errorContainer = new Container();
|
|
7669
|
-
const errorBg = (text) => theme.bg("errorBg", text);
|
|
7670
|
-
if (info.name && info.name !== "Error") {
|
|
7671
|
-
const typeLine = new Container();
|
|
7672
|
-
typeLine.addChild(new Text("│ ", 0, 0));
|
|
7673
|
-
typeLine.addChild(new Text(errorBg(` ${theme.bold(theme.fg("error", info.name))} `), 0, 0));
|
|
7674
|
-
errorContainer.addChild(typeLine);
|
|
7675
|
-
}
|
|
7676
|
-
const msgLine = new Container();
|
|
7677
|
-
msgLine.addChild(new Text("│ ", 0, 0));
|
|
7678
|
-
msgLine.addChild(new Text(theme.bold(info.message), 0, 0));
|
|
7679
|
-
errorContainer.addChild(msgLine);
|
|
7797
|
+
const room = Math.max(10, width - 0 - 2);
|
|
7798
|
+
const lines = [theme.bold(theme.fg("error", info.name && info.name !== "Error" ? info.name : "Error")), ...wrapTextWithAnsi(theme.fg("text", info.message), room)];
|
|
7680
7799
|
if (info.file && info.line) {
|
|
7681
7800
|
const location = `${info.file}:${info.line}${info.column ? `:${info.column}` : ""}`;
|
|
7682
|
-
|
|
7801
|
+
lines.push(theme.fg("muted", `at ${location}`));
|
|
7683
7802
|
}
|
|
7684
|
-
|
|
7803
|
+
this.addChild(new Text(card(theme.getTheme().error, lines).join("\n"), 0, 0));
|
|
7685
7804
|
if (this.options.showContext && info.context) {
|
|
7686
|
-
|
|
7687
|
-
|
|
7805
|
+
this.addChild(new Spacer(1));
|
|
7806
|
+
this.addChild(this.createCodeContext(info.context, info.line));
|
|
7688
7807
|
}
|
|
7689
7808
|
if (this.options.showStack && info.stack) {
|
|
7690
|
-
|
|
7691
|
-
|
|
7809
|
+
this.addChild(new Spacer(1));
|
|
7810
|
+
this.addChild(new CollapsibleStackTrace(info.stack, { expanded: this.options.expanded }, this.ui));
|
|
7692
7811
|
}
|
|
7693
|
-
const borderBottom = new Text(theme.fg("error", fitBorder(borderWidth, "╰", "╯")), 0, 0);
|
|
7694
|
-
box.addChild(borderBottom);
|
|
7695
7812
|
}
|
|
7696
7813
|
getChatSpacingKind() {
|
|
7697
7814
|
return "other";
|
|
@@ -7889,6 +8006,28 @@ const QUIET_CODE_HIGHLIGHT_THEME = {
|
|
|
7889
8006
|
tag: chalk.hex("#c4b5fd"),
|
|
7890
8007
|
name: chalk.hex("#c4b5fd")
|
|
7891
8008
|
};
|
|
8009
|
+
/** The same roles in darker tones that read on light backgrounds. */
|
|
8010
|
+
const LIGHT_CODE_HIGHLIGHT_THEME = {
|
|
8011
|
+
default: (text) => theme.fg("toolArgs", text),
|
|
8012
|
+
keyword: chalk.hex("#7e22ce"),
|
|
8013
|
+
built_in: chalk.hex("#1d4ed8"),
|
|
8014
|
+
type: chalk.hex("#1d4ed8"),
|
|
8015
|
+
literal: chalk.hex("#b91c1c"),
|
|
8016
|
+
number: chalk.hex("#b45309"),
|
|
8017
|
+
string: chalk.hex("#15803d"),
|
|
8018
|
+
regexp: chalk.hex("#b91c1c"),
|
|
8019
|
+
title: chalk.hex("#1d4ed8"),
|
|
8020
|
+
function: chalk.hex("#1d4ed8"),
|
|
8021
|
+
params: chalk.hex("#3f3f46"),
|
|
8022
|
+
comment: chalk.hex("#71717a"),
|
|
8023
|
+
meta: chalk.hex("#52525b"),
|
|
8024
|
+
attr: chalk.hex("#b45309"),
|
|
8025
|
+
variable: chalk.hex("#3f3f46"),
|
|
8026
|
+
tag: chalk.hex("#7e22ce"),
|
|
8027
|
+
name: chalk.hex("#7e22ce")
|
|
8028
|
+
};
|
|
8029
|
+
const codeHighlightTheme = () => getThemeMode() === "light" ? LIGHT_CODE_HIGHLIGHT_THEME : CODE_HIGHLIGHT_THEME;
|
|
8030
|
+
const quietCodeHighlightTheme = () => getThemeMode() === "light" ? LIGHT_CODE_HIGHLIGHT_THEME : QUIET_CODE_HIGHLIGHT_THEME;
|
|
7892
8031
|
const SHELL_CONTROL_WORDS = /* @__PURE__ */ new Set([
|
|
7893
8032
|
"if",
|
|
7894
8033
|
"then",
|
|
@@ -7999,6 +8138,8 @@ function extractContent(text) {
|
|
|
7999
8138
|
/**
|
|
8000
8139
|
* Enhanced tool execution component with collapsible sections
|
|
8001
8140
|
*/
|
|
8141
|
+
/** Shell output lines shown before the rest is folded behind ctrl+e. */
|
|
8142
|
+
const SHELL_OUTPUT_LINES = 8;
|
|
8002
8143
|
var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
8003
8144
|
contentBox;
|
|
8004
8145
|
toolName;
|
|
@@ -8121,6 +8262,12 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
8121
8262
|
this.quietShellPreviewRowFloor = Math.min(this.quietShellPreviewRowFloor, this.quietPreviewLineLimit);
|
|
8122
8263
|
this.rebuild();
|
|
8123
8264
|
}
|
|
8265
|
+
getToolCall() {
|
|
8266
|
+
return {
|
|
8267
|
+
toolName: this.toolName,
|
|
8268
|
+
args: this.args
|
|
8269
|
+
};
|
|
8270
|
+
}
|
|
8124
8271
|
setCompactToolModeColor(color) {
|
|
8125
8272
|
const nextColor = normalizeHexColor(color);
|
|
8126
8273
|
if (this.compactToolModeColor === nextColor) return;
|
|
@@ -8402,7 +8549,7 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
8402
8549
|
return highlight(preview, {
|
|
8403
8550
|
language: getLanguageFromPath(path),
|
|
8404
8551
|
ignoreIllegals: true,
|
|
8405
|
-
theme:
|
|
8552
|
+
theme: quietCodeHighlightTheme()
|
|
8406
8553
|
});
|
|
8407
8554
|
} catch {
|
|
8408
8555
|
return theme.fg("toolArgs", preview);
|
|
@@ -8551,9 +8698,6 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
8551
8698
|
getQuietToolCircleColor(color) {
|
|
8552
8699
|
return ensureTerminalGlyphContrast(color);
|
|
8553
8700
|
}
|
|
8554
|
-
formatToolBorder(char) {
|
|
8555
|
-
return theme.bold(chalk.hex(ensureTerminalGlyphContrast(theme.getTheme().toolBorderSuccess))(char));
|
|
8556
|
-
}
|
|
8557
8701
|
getCompactToolLabelColor() {
|
|
8558
8702
|
if (this.compactToolGroupLabelColor) return this.compactToolGroupLabelColor;
|
|
8559
8703
|
return this.getOwnCompactToolLabelColor();
|
|
@@ -8947,14 +9091,13 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
8947
9091
|
const to = limit ? from + limit - 1 : void 0;
|
|
8948
9092
|
rangeDisplay = theme.fg("muted", to ? `:${from}-${to}` : `:${from}`);
|
|
8949
9093
|
}
|
|
8950
|
-
const border = (char) => this.formatToolBorder(char);
|
|
8951
9094
|
if (!this.result || this.isPartial) {
|
|
8952
9095
|
const path = argsObj?.path ? shortenPath(String(argsObj.path)) : "...";
|
|
8953
9096
|
const status = this.getStatusIndicator();
|
|
8954
9097
|
const pathDisplay = fullPath ? fileLink(theme.fg("toolArgs", path), fullPath, startLine) : theme.fg("toolArgs", path);
|
|
8955
9098
|
const footerText = `${theme.bold(theme.fg("toolTitle", "view"))} ${pathDisplay}${rangeDisplay}${status}`;
|
|
8956
|
-
this.
|
|
8957
|
-
this.
|
|
9099
|
+
this.startBlock();
|
|
9100
|
+
this.endBlock(footerText);
|
|
8958
9101
|
return;
|
|
8959
9102
|
}
|
|
8960
9103
|
const status = this.getStatusIndicator();
|
|
@@ -8964,7 +9107,7 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
8964
9107
|
const pathDisplay = fullPath ? fileLink(theme.fg("toolArgs", path), fullPath, startLine) : theme.fg("toolArgs", path);
|
|
8965
9108
|
const footerText = `${theme.bold(theme.fg("toolTitle", "view"))} ${pathDisplay}${rangeDisplay}${status}`;
|
|
8966
9109
|
this.addLeadingPadding();
|
|
8967
|
-
this.
|
|
9110
|
+
this.startBlock();
|
|
8968
9111
|
const output = this.getFormattedOutput();
|
|
8969
9112
|
if (output) {
|
|
8970
9113
|
const maxLineWidth = this.renderWidth - 4 - 0;
|
|
@@ -8975,15 +9118,15 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
8975
9118
|
if (hasMore) lines = lines.slice(0, collapsedLines);
|
|
8976
9119
|
const borderedLines = lines.map((line) => {
|
|
8977
9120
|
const truncated = truncateAnsi(line, maxLineWidth);
|
|
8978
|
-
return
|
|
9121
|
+
return theme.fg("toolOutput", truncated);
|
|
8979
9122
|
});
|
|
8980
|
-
this.
|
|
9123
|
+
this.blockLines(borderedLines);
|
|
8981
9124
|
if (hasMore) {
|
|
8982
9125
|
const remaining = totalLines - collapsedLines;
|
|
8983
|
-
this.
|
|
9126
|
+
this.blockLine(theme.fg("muted", `... ${remaining} more lines (ctrl+e to expand)`));
|
|
8984
9127
|
}
|
|
8985
9128
|
}
|
|
8986
|
-
this.
|
|
9129
|
+
this.endBlock(footerText);
|
|
8987
9130
|
}
|
|
8988
9131
|
renderBashToolEnhanced() {
|
|
8989
9132
|
const argsObj = this.args;
|
|
@@ -9002,37 +9145,26 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9002
9145
|
const timeoutSuffix = timeout ? theme.fg("muted", ` (timeout ${timeout}s)`) : "";
|
|
9003
9146
|
const cwdSuffix = cwd ? theme.fg("muted", ` in ${cwd}`) : "";
|
|
9004
9147
|
const timeSuffix = this.isPartial ? timeoutSuffix : this.getDurationSuffix();
|
|
9005
|
-
const
|
|
9006
|
-
const
|
|
9007
|
-
const
|
|
9008
|
-
const
|
|
9009
|
-
const
|
|
9010
|
-
const
|
|
9011
|
-
const
|
|
9012
|
-
|
|
9013
|
-
|
|
9014
|
-
|
|
9015
|
-
|
|
9016
|
-
|
|
9017
|
-
|
|
9018
|
-
|
|
9019
|
-
|
|
9020
|
-
|
|
9021
|
-
|
|
9022
|
-
|
|
9023
|
-
|
|
9024
|
-
|
|
9025
|
-
const footerWrapWidth = Math.max(1, contentWidth - 2 - footerPromptWidth);
|
|
9026
|
-
const footerLines = this.wrapQuietShellCommand(command, footerWrapWidth);
|
|
9027
|
-
const footerSuffixWidth = visibleWidth(footerSuffix);
|
|
9028
|
-
const continuationIndent = " ".repeat(footerPromptWidth);
|
|
9029
|
-
footerLines.forEach((footerLine, index) => {
|
|
9030
|
-
const prefix = index === 0 ? footerPrompt : continuationIndent;
|
|
9031
|
-
const suffix = index === footerLines.length - 1 && visibleWidth(footerLine) + footerSuffixWidth <= footerWrapWidth ? footerSuffix : "";
|
|
9032
|
-
this.contentBox.addChild(new Text(renderLine(`${prefix}${footerLine}${suffix}`, (value) => value), 0, 0));
|
|
9033
|
-
});
|
|
9034
|
-
if (visibleWidth(footerLines[footerLines.length - 1] ?? "") + footerSuffixWidth > footerWrapWidth) this.contentBox.addChild(new Text(renderLine(`${continuationIndent}${footerSuffix}`, (value) => value), 0, 0));
|
|
9035
|
-
this.contentBox.addChild(new Text(`${border("╰")}${border(horizontal)}${border("╯")}`, 0, 0));
|
|
9148
|
+
const renderShellBlock = (status, outputLines, failed) => {
|
|
9149
|
+
const prompt = `${theme.bold(theme.fg("toolTitle", "$"))} `;
|
|
9150
|
+
const suffix = `${cwdSuffix}${timeSuffix}${status}`;
|
|
9151
|
+
const titleWidth = Math.max(1, this.renderWidth - 0 - 2 - visibleWidth(prompt));
|
|
9152
|
+
const commandLines = this.wrapQuietShellCommand(command, titleWidth);
|
|
9153
|
+
const title = commandLines.map((line, i) => (i === 0 ? prompt : " ".repeat(visibleWidth(prompt))) + line);
|
|
9154
|
+
const last = title.length - 1;
|
|
9155
|
+
if (visibleWidth(commandLines[last] ?? "") + visibleWidth(suffix) <= titleWidth) title[last] += suffix;
|
|
9156
|
+
else title.push(" ".repeat(visibleWidth(prompt)) + suffix);
|
|
9157
|
+
let shown = outputLines;
|
|
9158
|
+
let hiddenNote;
|
|
9159
|
+
if (!this.expanded && outputLines.length > SHELL_OUTPUT_LINES) {
|
|
9160
|
+
const hidden = outputLines.length - SHELL_OUTPUT_LINES;
|
|
9161
|
+
shown = outputLines.slice(-8);
|
|
9162
|
+
hiddenNote = this.isPartial ? theme.fg("dim", `… ${hidden} earlier lines`) : theme.fg("dim", `… ${hidden} more lines · `) + theme.fg("muted", "ctrl+e") + theme.fg("dim", " to expand");
|
|
9163
|
+
}
|
|
9164
|
+
this.startBlock();
|
|
9165
|
+
if (hiddenNote) this.blockLine(hiddenNote);
|
|
9166
|
+
this.blockLines(shown.map((line) => theme.fg("toolOutput", line)));
|
|
9167
|
+
this.endBlock(title, failed);
|
|
9036
9168
|
};
|
|
9037
9169
|
if (!this.result || this.isPartial) {
|
|
9038
9170
|
const status = this.getStatusIndicator();
|
|
@@ -9040,7 +9172,7 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9040
9172
|
while (lines.length > 0 && lines[0] === "") lines.shift();
|
|
9041
9173
|
while (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
|
|
9042
9174
|
if (maxStreamLines && lines.length > maxStreamLines) lines = lines.slice(-maxStreamLines);
|
|
9043
|
-
|
|
9175
|
+
renderShellBlock(status, lines);
|
|
9044
9176
|
return;
|
|
9045
9177
|
}
|
|
9046
9178
|
const prepareOutputLines = (output) => {
|
|
@@ -9052,17 +9184,17 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9052
9184
|
};
|
|
9053
9185
|
const failed = this.getShellFailureLine() !== void 0;
|
|
9054
9186
|
const output = this.streamingOutput.trim() || this.getFormattedOutput();
|
|
9055
|
-
|
|
9187
|
+
renderShellBlock(this.getStatusIndicator(failed), prepareOutputLines(output), failed);
|
|
9056
9188
|
}
|
|
9057
9189
|
/**
|
|
9058
9190
|
* One call's slice of a shared quiet shell box. The first call in a run opens the box with a
|
|
9059
9191
|
* `$ <path>` header, a call in a new directory adds another header, and the last call closes it.
|
|
9060
9192
|
*/
|
|
9061
9193
|
renderQuietShellGroupRow() {
|
|
9062
|
-
const border = (char) => this.formatToolBorder(char);
|
|
9063
9194
|
const fullWidth = Math.max(20, this.renderWidth - 0 - 4);
|
|
9064
9195
|
const naturalWidth = this.quietShellGroupWidth ?? this.getQuietShellNaturalWidth() ?? 0;
|
|
9065
9196
|
const contentWidth = Math.min(fullWidth, Math.max(QUIET_SHELL_MIN_CONTENT_WIDTH, naturalWidth));
|
|
9197
|
+
const border = (char) => theme.bold(chalk.hex(ensureTerminalGlyphContrast(theme.getTheme().toolBorderSuccess))(char));
|
|
9066
9198
|
const rule = (left, right) => `${border(left)}${border("─".repeat(contentWidth + 2))}${border(right)}`;
|
|
9067
9199
|
const singleLine = (text) => text.replace(TERMINAL_SEQUENCE_RE, "").replace(/[\t\n\r\v\f]/g, " ").replace(/[\x00-\x08\x0e-\x1f\x7f-\x9f]/g, "");
|
|
9068
9200
|
const row = (left, right = "") => {
|
|
@@ -9172,16 +9304,15 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9172
9304
|
const timeSuffix = this.isPartial ? "" : this.getDurationSuffix();
|
|
9173
9305
|
const label = isKill ? "kill" : isWait ? "wait" : "output";
|
|
9174
9306
|
const renderBorderedProcess = (status, outputLines) => {
|
|
9175
|
-
const border = (char) => this.formatToolBorder(char);
|
|
9176
9307
|
const footerText = `${theme.bold(theme.fg("toolTitle", label))} ${theme.fg("toolArgs", `PID ${pid}`)}${timeSuffix}${status}`;
|
|
9177
|
-
this.
|
|
9308
|
+
this.startBlock();
|
|
9178
9309
|
const maxLineWidth = this.renderWidth - 4 - 0;
|
|
9179
|
-
const
|
|
9310
|
+
const borderedLines = outputLines.map((line) => {
|
|
9180
9311
|
const truncated = truncateAnsi(line, maxLineWidth);
|
|
9181
|
-
return
|
|
9182
|
-
})
|
|
9183
|
-
if (
|
|
9184
|
-
this.
|
|
9312
|
+
return theme.fg("toolOutput", truncated);
|
|
9313
|
+
});
|
|
9314
|
+
if (borderedLines.join("\n").trim()) this.blockLines(borderedLines);
|
|
9315
|
+
this.endBlock(footerText);
|
|
9185
9316
|
};
|
|
9186
9317
|
const prepareOutputLines = (output) => {
|
|
9187
9318
|
let lines = output.split("\n");
|
|
@@ -9211,11 +9342,10 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9211
9342
|
const oldStr = argsObj?.old_str ?? argsObj?.old_string;
|
|
9212
9343
|
const newStr = argsObj?.new_str ?? argsObj?.new_string;
|
|
9213
9344
|
if (oldStr != null && newStr != null) {
|
|
9214
|
-
const border = (char) => this.formatToolBorder(char);
|
|
9215
9345
|
const maxLineWidth = this.renderWidth - 4 - 0;
|
|
9216
9346
|
const footerText = `${theme.bold(theme.fg("toolTitle", "edit"))} ${pathDisplay}${theme.fg("muted", startLine)}${status}`;
|
|
9217
9347
|
this.addLeadingPadding();
|
|
9218
|
-
this.
|
|
9348
|
+
this.startBlock();
|
|
9219
9349
|
const { lines: diffLines } = this.generateDiffLines(String(oldStr), String(newStr));
|
|
9220
9350
|
const collapsedLines = this.getCollapsedLineLimit(15);
|
|
9221
9351
|
const totalLines = diffLines.length;
|
|
@@ -9226,22 +9356,20 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9226
9356
|
skippedAbove = totalLines - collapsedLines;
|
|
9227
9357
|
linesToShow = diffLines.slice(-collapsedLines);
|
|
9228
9358
|
}
|
|
9229
|
-
if (skippedAbove > 0) this.
|
|
9359
|
+
if (skippedAbove > 0) this.blockLine(theme.fg("muted", `... ${skippedAbove} lines above (ctrl+e to expand)`));
|
|
9230
9360
|
const borderedLines = linesToShow.map((line) => {
|
|
9231
9361
|
const truncated = truncateAnsi(line, maxLineWidth);
|
|
9232
|
-
return
|
|
9362
|
+
return theme.fg("toolOutput", truncated);
|
|
9233
9363
|
});
|
|
9234
|
-
this.
|
|
9235
|
-
this.
|
|
9364
|
+
this.blockLines(borderedLines);
|
|
9365
|
+
this.endBlock(footerText);
|
|
9236
9366
|
return;
|
|
9237
9367
|
}
|
|
9238
|
-
const editBorder = (char) => this.formatToolBorder(char);
|
|
9239
9368
|
const headerText = `${theme.bold(theme.fg("toolTitle", "edit"))} ${pathDisplay}${theme.fg("muted", startLine)}${status}`;
|
|
9240
|
-
this.
|
|
9241
|
-
this.
|
|
9369
|
+
this.startBlock();
|
|
9370
|
+
this.endBlock(headerText);
|
|
9242
9371
|
return;
|
|
9243
9372
|
}
|
|
9244
|
-
const border = (char) => this.formatToolBorder(char);
|
|
9245
9373
|
const status = this.getStatusIndicator();
|
|
9246
9374
|
const termWidth = this.renderWidth;
|
|
9247
9375
|
const availableForPath = termWidth - ("╰── edit " + startLine + " ✓").length - 6 - 0;
|
|
@@ -9250,7 +9378,7 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9250
9378
|
const pathDisplay = fullPath ? fileLink(theme.fg("toolArgs", path), fullPath, startLineNum) : theme.fg("toolArgs", path);
|
|
9251
9379
|
const footerText = `${theme.bold(theme.fg("toolTitle", "edit"))} ${pathDisplay}${theme.fg("muted", startLine)}${status}`;
|
|
9252
9380
|
this.addLeadingPadding();
|
|
9253
|
-
this.
|
|
9381
|
+
this.startBlock();
|
|
9254
9382
|
const finalOldStr = argsObj?.old_str ?? argsObj?.old_string;
|
|
9255
9383
|
const finalNewStr = argsObj?.new_str ?? argsObj?.new_string;
|
|
9256
9384
|
if (finalOldStr != null && finalNewStr != null && !this.result.isError) {
|
|
@@ -9266,15 +9394,15 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9266
9394
|
skippedBefore = start;
|
|
9267
9395
|
}
|
|
9268
9396
|
const maxLineWidth = termWidth - 4 - 0;
|
|
9269
|
-
if (skippedBefore > 0) this.
|
|
9397
|
+
if (skippedBefore > 0) this.blockLine(theme.fg("muted", `... ${skippedBefore} lines above`));
|
|
9270
9398
|
const borderedLines = linesToShow.map((line) => {
|
|
9271
9399
|
const truncated = truncateAnsi(line, maxLineWidth);
|
|
9272
|
-
return
|
|
9400
|
+
return theme.fg("toolOutput", truncated);
|
|
9273
9401
|
});
|
|
9274
|
-
this.
|
|
9402
|
+
this.blockLines(borderedLines);
|
|
9275
9403
|
if (hasMore) {
|
|
9276
9404
|
const remaining = totalLines - (skippedBefore + linesToShow.length);
|
|
9277
|
-
if (remaining > 0) this.
|
|
9405
|
+
if (remaining > 0) this.blockLine(theme.fg("muted", `... ${remaining} more lines (ctrl+e to expand)`));
|
|
9278
9406
|
}
|
|
9279
9407
|
} else if (this.result.isError) {
|
|
9280
9408
|
const output = this.getFormattedOutput();
|
|
@@ -9282,12 +9410,12 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9282
9410
|
const maxLineWidth = termWidth - 4 - 0;
|
|
9283
9411
|
const lines = output.split("\n").map((line) => {
|
|
9284
9412
|
const truncated = truncateAnsi(line, maxLineWidth);
|
|
9285
|
-
return
|
|
9413
|
+
return theme.fg("error", truncated);
|
|
9286
9414
|
});
|
|
9287
|
-
this.
|
|
9415
|
+
this.blockLines(lines);
|
|
9288
9416
|
}
|
|
9289
9417
|
}
|
|
9290
|
-
this.
|
|
9418
|
+
this.endBlock(footerText);
|
|
9291
9419
|
const diagnostics = this.parseLSPDiagnostics();
|
|
9292
9420
|
if (diagnostics && !diagnostics.hasIssues) this.contentBox.addChild(new Text(theme.fg("muted", ` ✓ No LSP issues`), 0, 0));
|
|
9293
9421
|
else if (diagnostics && diagnostics.hasIssues) {
|
|
@@ -9371,16 +9499,14 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9371
9499
|
const content = argsObj?.content ? String(argsObj.content) : "";
|
|
9372
9500
|
if (!this.result || this.isPartial) {
|
|
9373
9501
|
if (!content) {
|
|
9374
|
-
const writeBorder = (char) => this.formatToolBorder(char);
|
|
9375
9502
|
const path = argsObj?.path ? shortenPath(String(argsObj.path)) : "...";
|
|
9376
9503
|
const status = this.getStatusIndicator();
|
|
9377
9504
|
const pathDisplay = fullPath ? fileLink(theme.fg("toolArgs", path), fullPath) : theme.fg("toolArgs", path);
|
|
9378
9505
|
const footerText = `${theme.bold(theme.fg("toolTitle", "write"))} ${pathDisplay}${status}`;
|
|
9379
|
-
this.
|
|
9380
|
-
this.
|
|
9506
|
+
this.startBlock();
|
|
9507
|
+
this.endBlock(footerText);
|
|
9381
9508
|
return;
|
|
9382
9509
|
}
|
|
9383
|
-
const border = (char) => this.formatToolBorder(char);
|
|
9384
9510
|
const status = this.getStatusIndicator();
|
|
9385
9511
|
const termWidth = this.renderWidth;
|
|
9386
9512
|
const maxLineWidth = termWidth - 4 - 0;
|
|
@@ -9390,8 +9516,8 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9390
9516
|
const pathDisplay = fullPath ? fileLink(theme.fg("toolArgs", path), fullPath) : theme.fg("toolArgs", path);
|
|
9391
9517
|
const footerText = `${theme.bold(theme.fg("toolTitle", "write"))} ${pathDisplay}${status}`;
|
|
9392
9518
|
this.addLeadingPadding();
|
|
9393
|
-
this.
|
|
9394
|
-
let lines = highlightCode(content, fullPath).split("\n");
|
|
9519
|
+
this.startBlock();
|
|
9520
|
+
let lines = highlightCode(content, fullPath, void 0, false).split("\n");
|
|
9395
9521
|
const collapsedLines = this.getCollapsedLineLimit(20);
|
|
9396
9522
|
const totalLines = lines.length;
|
|
9397
9523
|
const hasMore = !this.expanded && totalLines > collapsedLines + 1;
|
|
@@ -9400,16 +9526,15 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9400
9526
|
skippedAbove = totalLines - collapsedLines;
|
|
9401
9527
|
lines = lines.slice(-collapsedLines);
|
|
9402
9528
|
}
|
|
9403
|
-
if (skippedAbove > 0) this.
|
|
9529
|
+
if (skippedAbove > 0) this.blockLine(theme.fg("muted", `... ${skippedAbove} lines above (ctrl+e to expand)`));
|
|
9404
9530
|
const borderedLines = lines.map((line) => {
|
|
9405
9531
|
const truncated = truncateAnsi(line, maxLineWidth);
|
|
9406
|
-
return
|
|
9532
|
+
return theme.fg("toolOutput", truncated);
|
|
9407
9533
|
});
|
|
9408
|
-
this.
|
|
9409
|
-
this.
|
|
9534
|
+
this.blockLines(borderedLines);
|
|
9535
|
+
this.endBlock(footerText);
|
|
9410
9536
|
return;
|
|
9411
9537
|
}
|
|
9412
|
-
const border = (char) => this.formatToolBorder(char);
|
|
9413
9538
|
const status = this.getStatusIndicator();
|
|
9414
9539
|
const termWidth = this.renderWidth;
|
|
9415
9540
|
const maxLineWidth = termWidth - 4 - 0;
|
|
@@ -9419,18 +9544,18 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9419
9544
|
const pathDisplay = fullPath ? fileLink(theme.fg("toolArgs", path), fullPath) : theme.fg("toolArgs", path);
|
|
9420
9545
|
const footerText = `${theme.bold(theme.fg("toolTitle", "write"))} ${pathDisplay}${status}`;
|
|
9421
9546
|
this.addLeadingPadding();
|
|
9422
|
-
this.
|
|
9547
|
+
this.startBlock();
|
|
9423
9548
|
if (this.result.isError) {
|
|
9424
9549
|
const output = this.getFormattedOutput();
|
|
9425
9550
|
if (output) {
|
|
9426
9551
|
const lines = output.split("\n").map((line) => {
|
|
9427
9552
|
const truncated = truncateAnsi(line, maxLineWidth);
|
|
9428
|
-
return
|
|
9553
|
+
return theme.fg("error", truncated);
|
|
9429
9554
|
});
|
|
9430
|
-
this.
|
|
9555
|
+
this.blockLines(lines);
|
|
9431
9556
|
}
|
|
9432
9557
|
} else if (content) {
|
|
9433
|
-
let lines = highlightCode(content, fullPath).split("\n");
|
|
9558
|
+
let lines = highlightCode(content, fullPath, void 0, false).split("\n");
|
|
9434
9559
|
const collapsedLines = this.getCollapsedLineLimit(20);
|
|
9435
9560
|
const totalLines = lines.length;
|
|
9436
9561
|
const hasMore = !this.expanded && totalLines > collapsedLines + 1;
|
|
@@ -9439,14 +9564,14 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9439
9564
|
skippedAbove = totalLines - collapsedLines;
|
|
9440
9565
|
lines = lines.slice(-collapsedLines);
|
|
9441
9566
|
}
|
|
9442
|
-
if (skippedAbove > 0) this.
|
|
9567
|
+
if (skippedAbove > 0) this.blockLine(theme.fg("muted", `... ${skippedAbove} lines above (ctrl+e to expand)`));
|
|
9443
9568
|
const borderedLines = lines.map((line) => {
|
|
9444
9569
|
const truncated = truncateAnsi(line, maxLineWidth);
|
|
9445
|
-
return
|
|
9570
|
+
return theme.fg("toolOutput", truncated);
|
|
9446
9571
|
});
|
|
9447
|
-
this.
|
|
9572
|
+
this.blockLines(borderedLines);
|
|
9448
9573
|
}
|
|
9449
|
-
this.
|
|
9574
|
+
this.endBlock(footerText);
|
|
9450
9575
|
}
|
|
9451
9576
|
renderListFilesEnhanced() {
|
|
9452
9577
|
const argsObj = this.args;
|
|
@@ -9454,14 +9579,13 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9454
9579
|
const path = argsObj?.path ? shortenPath(String(argsObj.path)) : "/";
|
|
9455
9580
|
const pattern = argsObj?.pattern ? String(argsObj.pattern) : "";
|
|
9456
9581
|
const patternDisplay = pattern ? " " + theme.fg("muted", pattern) : "";
|
|
9457
|
-
const border = (char) => this.formatToolBorder(char);
|
|
9458
9582
|
const status = this.getStatusIndicator();
|
|
9459
9583
|
const maxLineWidth = this.renderWidth - 4 - 0;
|
|
9460
9584
|
if (!this.result || this.isPartial) {
|
|
9461
9585
|
const pathDisplay = fullPath ? fileLink(theme.fg("toolArgs", path), fullPath) : theme.fg("toolArgs", path);
|
|
9462
9586
|
const footerText = `${theme.bold(theme.fg("toolTitle", "list"))} ${pathDisplay}${patternDisplay}${status}`;
|
|
9463
|
-
this.
|
|
9464
|
-
this.
|
|
9587
|
+
this.startBlock();
|
|
9588
|
+
this.endBlock(footerText);
|
|
9465
9589
|
return;
|
|
9466
9590
|
}
|
|
9467
9591
|
const output = this.getFormattedOutput();
|
|
@@ -9481,18 +9605,17 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9481
9605
|
}
|
|
9482
9606
|
const pathDisplay = fullPath ? fileLink(theme.fg("toolArgs", path), fullPath) : theme.fg("toolArgs", path);
|
|
9483
9607
|
const footerText = `${theme.bold(theme.fg("toolTitle", "list"))} ${pathDisplay}${patternDisplay}${summaryDisplay}${status}`;
|
|
9484
|
-
this.
|
|
9485
|
-
if (skippedAbove > 0) this.
|
|
9608
|
+
this.startBlock();
|
|
9609
|
+
if (skippedAbove > 0) this.blockLine(theme.fg("muted", `... ${skippedAbove} lines above (ctrl+e to expand)`));
|
|
9486
9610
|
const borderedLines = lines.map((line) => {
|
|
9487
9611
|
const truncated = truncateAnsi(line, maxLineWidth);
|
|
9488
|
-
return
|
|
9612
|
+
return theme.fg("toolOutput", truncated);
|
|
9489
9613
|
});
|
|
9490
|
-
this.
|
|
9491
|
-
this.
|
|
9614
|
+
this.blockLines(borderedLines);
|
|
9615
|
+
this.endBlock(footerText);
|
|
9492
9616
|
}
|
|
9493
9617
|
}
|
|
9494
9618
|
renderLspInspectEnhanced() {
|
|
9495
|
-
const border = (char) => this.formatToolBorder(char);
|
|
9496
9619
|
const status = this.getStatusIndicator();
|
|
9497
9620
|
const maxLineWidth = this.renderWidth - 4 - 0;
|
|
9498
9621
|
const argsObj = this.args;
|
|
@@ -9506,17 +9629,17 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9506
9629
|
].filter(Boolean).join(" ");
|
|
9507
9630
|
if (!this.result || this.isPartial) {
|
|
9508
9631
|
const footerText = `${theme.bold(theme.fg("toolTitle", "lsp_inspect"))}${argsSummary ? " " + theme.fg("toolArgs", argsSummary) : ""}${status}`;
|
|
9509
|
-
this.
|
|
9510
|
-
this.
|
|
9632
|
+
this.startBlock();
|
|
9633
|
+
this.endBlock(footerText);
|
|
9511
9634
|
return;
|
|
9512
9635
|
}
|
|
9513
9636
|
const rawText = this.result.content.filter((c) => c.type === "text" && c.text).map((c) => c.text).join("\n");
|
|
9514
9637
|
if (this.result.isError || !rawText.trim()) {
|
|
9515
9638
|
const footerText = `${theme.bold(theme.fg("toolTitle", "lsp_inspect"))}${argsSummary ? " " + theme.fg("toolArgs", argsSummary) : ""}${status}`;
|
|
9516
9639
|
const output = this.getFormattedOutput();
|
|
9517
|
-
this.
|
|
9518
|
-
if (output) this.
|
|
9519
|
-
this.
|
|
9640
|
+
this.startBlock();
|
|
9641
|
+
if (output) this.blockLine(theme.fg("error", output));
|
|
9642
|
+
this.endBlock(footerText);
|
|
9520
9643
|
return;
|
|
9521
9644
|
}
|
|
9522
9645
|
let parsed;
|
|
@@ -9528,67 +9651,64 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9528
9651
|
}
|
|
9529
9652
|
if (parsed.error) {
|
|
9530
9653
|
const footerText = `${theme.bold(theme.fg("toolTitle", "lsp_inspect"))}${argsSummary ? " " + theme.fg("toolArgs", argsSummary) : ""}${status}`;
|
|
9531
|
-
this.
|
|
9532
|
-
this.
|
|
9533
|
-
this.
|
|
9654
|
+
this.startBlock();
|
|
9655
|
+
this.blockLine(theme.fg("error", parsed.error));
|
|
9656
|
+
this.endBlock(footerText);
|
|
9534
9657
|
return;
|
|
9535
9658
|
}
|
|
9536
9659
|
const footerText = `${theme.bold(theme.fg("toolTitle", "lsp_inspect"))}${argsSummary ? " " + theme.fg("toolArgs", argsSummary) : ""}${status}`;
|
|
9537
|
-
this.
|
|
9660
|
+
this.startBlock();
|
|
9538
9661
|
if (parsed.hover) {
|
|
9539
9662
|
const hoverLines = (parsed.hover.value || "").split("\n").filter((line) => line.trim() !== "");
|
|
9540
|
-
if (hoverLines.length > 0) this.
|
|
9663
|
+
if (hoverLines.length > 0) this.blockLine(theme.fg("toolArgs", "hover:"));
|
|
9541
9664
|
for (const line of hoverLines) {
|
|
9542
9665
|
const truncated = truncateAnsi(line, maxLineWidth - 2);
|
|
9543
|
-
|
|
9544
|
-
this.contentBox.addChild(new Text(prefix + theme.fg("text", truncated), 0, 0));
|
|
9666
|
+
this.blockLine(theme.fg("text", truncated));
|
|
9545
9667
|
}
|
|
9546
9668
|
}
|
|
9547
9669
|
if (parsed.diagnostics && parsed.diagnostics.length > 0) {
|
|
9548
|
-
this.
|
|
9549
|
-
this.
|
|
9670
|
+
this.blockLine("");
|
|
9671
|
+
this.blockLine(theme.fg("toolArgs", "diagnostics:"));
|
|
9550
9672
|
for (const diagnostic of parsed.diagnostics) {
|
|
9551
9673
|
const diagLine = `${diagnostic.source ? `${diagnostic.severity} (${diagnostic.source})` : diagnostic.severity}: ${diagnostic.message}`;
|
|
9552
|
-
this.
|
|
9674
|
+
this.blockLine(theme.fg(diagnostic.severity === "error" ? "error" : "text", truncateAnsi(diagLine, maxLineWidth - 2)));
|
|
9553
9675
|
}
|
|
9554
9676
|
}
|
|
9555
9677
|
if (parsed.definition && parsed.definition.length > 0) {
|
|
9556
|
-
this.
|
|
9557
|
-
this.
|
|
9678
|
+
this.blockLine("");
|
|
9679
|
+
this.blockLine(theme.fg("toolArgs", "definition:"));
|
|
9558
9680
|
for (const def of parsed.definition) {
|
|
9559
9681
|
const location = def.location || "";
|
|
9560
9682
|
const preview = def.preview || "";
|
|
9561
9683
|
const parsedLoc = this.parseLspLocation(location);
|
|
9562
|
-
const
|
|
9563
|
-
|
|
9564
|
-
this.contentBox.addChild(new Text(truncateAnsi(defLine, maxLineWidth), 0, 0));
|
|
9684
|
+
const defLine = parsedLoc ? fileLink(theme.fg("toolOutput", parsedLoc.shortPath + ":" + parsedLoc.lineCol), parsedLoc.absPath, parsedLoc.line) : theme.fg("toolOutput", location);
|
|
9685
|
+
this.blockLine(truncateAnsi(defLine, maxLineWidth));
|
|
9565
9686
|
if (preview) {
|
|
9566
|
-
const previewLine =
|
|
9567
|
-
this.
|
|
9687
|
+
const previewLine = " " + theme.fg("text", truncateAnsi(preview, maxLineWidth - 3));
|
|
9688
|
+
this.blockLine(previewLine);
|
|
9568
9689
|
}
|
|
9569
9690
|
}
|
|
9570
9691
|
}
|
|
9571
9692
|
if (parsed.implementation && parsed.implementation.length > 0) {
|
|
9572
9693
|
const implCount = parsed.implementation.length;
|
|
9573
9694
|
const implLabel = implCount === 1 ? "implementation:" : `implementations (${implCount}):`;
|
|
9574
|
-
this.
|
|
9695
|
+
this.blockLine("");
|
|
9575
9696
|
const maxShow = this.expanded ? parsed.implementation.length : 5;
|
|
9576
9697
|
const shown = parsed.implementation.slice(0, maxShow);
|
|
9577
9698
|
const remaining = parsed.implementation.length - maxShow;
|
|
9578
|
-
this.
|
|
9699
|
+
this.blockLine(theme.fg("toolArgs", implLabel));
|
|
9579
9700
|
for (const loc of shown) {
|
|
9580
9701
|
const parsedLoc = this.parseLspLocation(loc);
|
|
9581
|
-
const
|
|
9582
|
-
|
|
9583
|
-
this.contentBox.addChild(new Text(truncateAnsi(implLine, maxLineWidth), 0, 0));
|
|
9702
|
+
const implLine = parsedLoc ? fileLink(theme.fg("toolOutput", parsedLoc.shortPath + ":" + parsedLoc.lineCol), parsedLoc.absPath, parsedLoc.line) : theme.fg("toolOutput", loc);
|
|
9703
|
+
this.blockLine(truncateAnsi(implLine, maxLineWidth));
|
|
9584
9704
|
}
|
|
9585
9705
|
if (remaining > 0 && !this.expanded) {
|
|
9586
|
-
const moreLine =
|
|
9587
|
-
this.
|
|
9706
|
+
const moreLine = theme.fg("toolOutput", `... ${remaining} more (ctrl+e to expand)`);
|
|
9707
|
+
this.blockLine(moreLine);
|
|
9588
9708
|
}
|
|
9589
9709
|
}
|
|
9590
|
-
if (!parsed.hover && !parsed.diagnostics?.length && !parsed.definition?.length && !parsed.implementation?.length) this.
|
|
9591
|
-
this.
|
|
9710
|
+
if (!parsed.hover && !parsed.diagnostics?.length && !parsed.definition?.length && !parsed.implementation?.length) this.blockLine(theme.fg("muted", "No hover, diagnostics, definition, or implementation results"));
|
|
9711
|
+
this.endBlock(footerText);
|
|
9592
9712
|
}
|
|
9593
9713
|
/**
|
|
9594
9714
|
* Parse an LSP location string like "$cwd/path:Lline:Cchar" into components.
|
|
@@ -9624,16 +9744,15 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9624
9744
|
renderTaskWriteEnhanced() {
|
|
9625
9745
|
const tasks = this.args?.tasks;
|
|
9626
9746
|
const status = this.getStatusIndicator();
|
|
9627
|
-
const border = (char) => this.formatToolBorder(char);
|
|
9628
9747
|
const count = tasks?.length ?? 0;
|
|
9629
9748
|
const countSuffix = count > 0 ? theme.fg("muted", ` (${count} tasks)`) : "";
|
|
9630
9749
|
const footerText = `${theme.bold(theme.fg("toolTitle", "task_write"))}${countSuffix}${status}`;
|
|
9631
|
-
this.
|
|
9750
|
+
this.startBlock();
|
|
9632
9751
|
if (!this.isPartial && this.result?.isError) {
|
|
9633
9752
|
const output = this.getFormattedOutput();
|
|
9634
|
-
if (output) this.
|
|
9753
|
+
if (output) this.blockLine(theme.fg("error", output));
|
|
9635
9754
|
}
|
|
9636
|
-
this.
|
|
9755
|
+
this.endBlock(footerText);
|
|
9637
9756
|
}
|
|
9638
9757
|
renderWebSearchEnhanced() {
|
|
9639
9758
|
const argsObj = this.args;
|
|
@@ -9647,10 +9766,9 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9647
9766
|
const status = this.getStatusIndicator();
|
|
9648
9767
|
const queryDisplay = query ? ` ${theme.fg("toolArgs", `"${query}"`)}` : "";
|
|
9649
9768
|
const footerText = `${theme.bold(theme.fg("toolTitle", "web_search"))}${queryDisplay}${status}`;
|
|
9650
|
-
const border = (char) => this.formatToolBorder(char);
|
|
9651
9769
|
if (!this.result || this.isPartial) {
|
|
9652
|
-
this.
|
|
9653
|
-
this.
|
|
9770
|
+
this.startBlock();
|
|
9771
|
+
this.endBlock(footerText);
|
|
9654
9772
|
return;
|
|
9655
9773
|
}
|
|
9656
9774
|
if (this.result.isError) {
|
|
@@ -9661,7 +9779,7 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9661
9779
|
if (output) {
|
|
9662
9780
|
const maxLineWidth = this.renderWidth - 4 - 0;
|
|
9663
9781
|
this.addLeadingPadding();
|
|
9664
|
-
this.
|
|
9782
|
+
this.startBlock();
|
|
9665
9783
|
let lines = output.split("\n");
|
|
9666
9784
|
const collapsedLines = this.getCollapsedLineLimit(10);
|
|
9667
9785
|
const totalLines = lines.length;
|
|
@@ -9669,15 +9787,18 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9669
9787
|
if (hasMore) lines = lines.slice(0, collapsedLines);
|
|
9670
9788
|
const borderedLines = lines.map((line) => {
|
|
9671
9789
|
const truncated = truncateAnsi(line, maxLineWidth);
|
|
9672
|
-
return
|
|
9790
|
+
return theme.fg("toolOutput", truncated);
|
|
9673
9791
|
});
|
|
9674
|
-
this.
|
|
9792
|
+
this.blockLines(borderedLines);
|
|
9675
9793
|
if (hasMore) {
|
|
9676
9794
|
const remaining = totalLines - collapsedLines;
|
|
9677
|
-
this.
|
|
9795
|
+
this.blockLine(theme.fg("muted", `... ${remaining} more lines (ctrl+e to expand)`));
|
|
9678
9796
|
}
|
|
9679
|
-
this.
|
|
9680
|
-
} else
|
|
9797
|
+
this.endBlock(footerText);
|
|
9798
|
+
} else {
|
|
9799
|
+
this.startBlock();
|
|
9800
|
+
this.endBlock(footerText);
|
|
9801
|
+
}
|
|
9681
9802
|
}
|
|
9682
9803
|
/**
|
|
9683
9804
|
* Format web search results as a clean list of titles + URLs.
|
|
@@ -9738,8 +9859,7 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9738
9859
|
return outcome ? `Outcome: ${outcome}` : "";
|
|
9739
9860
|
}
|
|
9740
9861
|
renderAgentSignalSendEnhanced() {
|
|
9741
|
-
const
|
|
9742
|
-
const maxLineWidth = Math.max(10, this.renderWidth - 0 - 4);
|
|
9862
|
+
const maxLineWidth = Math.max(10, this.renderWidth - 0 - 6);
|
|
9743
9863
|
const args = this.args;
|
|
9744
9864
|
const target = sanitizeAnsiForRendering(typeof args?.targetId === "string" ? args.targetId : "unknown peer");
|
|
9745
9865
|
const priority = sanitizeAnsiForRendering(typeof args?.priority === "string" ? args.priority : "medium");
|
|
@@ -9751,34 +9871,33 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9751
9871
|
const renderField = (label, value, preserveMessageFormatting = false) => {
|
|
9752
9872
|
const displayValue = value || "—";
|
|
9753
9873
|
const lines = preserveMessageFormatting ? this.wrapAgentSignalMessageLines(displayValue, maxLineWidth) : this.wrapPreviewLines(displayValue, maxLineWidth, maxLineWidth);
|
|
9754
|
-
this.
|
|
9755
|
-
for (const line of lines) this.
|
|
9874
|
+
this.blockLine(`${theme.fg("toolArgs", `${label}:`)}`);
|
|
9875
|
+
for (const line of lines) this.blockLine(` ${theme.fg("text", line)}`);
|
|
9756
9876
|
};
|
|
9757
|
-
this.
|
|
9877
|
+
this.startBlock();
|
|
9758
9878
|
renderField("target", target);
|
|
9759
|
-
this.
|
|
9760
|
-
this.
|
|
9879
|
+
this.blockLine(`${theme.fg("toolArgs", "priority:")} ${theme.fg("text", priority)} ${theme.fg("toolArgs", "expects reply:")} ${theme.fg("text", expectsReply)}`);
|
|
9880
|
+
this.blockLine("");
|
|
9761
9881
|
renderField("message", message, true);
|
|
9762
9882
|
if (outcome) {
|
|
9763
|
-
this.
|
|
9883
|
+
this.blockLine("");
|
|
9764
9884
|
renderField("outcome", outcome);
|
|
9765
9885
|
}
|
|
9766
|
-
this.
|
|
9886
|
+
this.endBlock(footerText);
|
|
9767
9887
|
}
|
|
9768
9888
|
renderGenericToolEnhanced() {
|
|
9769
|
-
const border = (char) => this.formatToolBorder(char);
|
|
9770
9889
|
const status = this.getStatusIndicator();
|
|
9771
9890
|
const argsSummary = this.formatArgsSummary();
|
|
9772
9891
|
const footerText = `${theme.bold(theme.fg("toolTitle", this.toolName))}${argsSummary}${status}`;
|
|
9773
9892
|
if (!this.result || this.isPartial) {
|
|
9774
9893
|
const partialOutput = this.result ? this.getFormattedOutput() : "";
|
|
9775
9894
|
const preview = partialOutput ? partialOutput.split("\n") : this.formatArgsPreview();
|
|
9776
|
-
this.
|
|
9895
|
+
this.startBlock();
|
|
9777
9896
|
if (preview.length > 0) {
|
|
9778
|
-
const previewLines = preview.map((line) =>
|
|
9779
|
-
this.
|
|
9897
|
+
const previewLines = preview.map((line) => theme.fg("toolOutput", line));
|
|
9898
|
+
this.blockLines(previewLines);
|
|
9780
9899
|
}
|
|
9781
|
-
this.
|
|
9900
|
+
this.endBlock(footerText);
|
|
9782
9901
|
return;
|
|
9783
9902
|
}
|
|
9784
9903
|
if (this.result.isError) {
|
|
@@ -9789,7 +9908,7 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9789
9908
|
if (output) {
|
|
9790
9909
|
const maxLineWidth = this.renderWidth - 4 - 0;
|
|
9791
9910
|
this.addLeadingPadding();
|
|
9792
|
-
this.
|
|
9911
|
+
this.startBlock();
|
|
9793
9912
|
let lines = output.split("\n");
|
|
9794
9913
|
const collapsedLines = this.getCollapsedLineLimit(10);
|
|
9795
9914
|
const totalLines = lines.length;
|
|
@@ -9797,15 +9916,18 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9797
9916
|
if (hasMore) lines = lines.slice(0, collapsedLines);
|
|
9798
9917
|
const borderedLines = lines.map((line) => {
|
|
9799
9918
|
const truncated = truncateAnsi(line, maxLineWidth);
|
|
9800
|
-
return
|
|
9919
|
+
return theme.fg("toolOutput", truncated);
|
|
9801
9920
|
});
|
|
9802
|
-
this.
|
|
9921
|
+
this.blockLines(borderedLines);
|
|
9803
9922
|
if (hasMore) {
|
|
9804
9923
|
const remaining = totalLines - collapsedLines;
|
|
9805
|
-
this.
|
|
9924
|
+
this.blockLine(theme.fg("muted", `... ${remaining} more lines (ctrl+e to expand)`));
|
|
9806
9925
|
}
|
|
9807
|
-
this.
|
|
9808
|
-
} else
|
|
9926
|
+
this.endBlock(footerText);
|
|
9927
|
+
} else {
|
|
9928
|
+
this.startBlock();
|
|
9929
|
+
this.endBlock(footerText);
|
|
9930
|
+
}
|
|
9809
9931
|
}
|
|
9810
9932
|
/**
|
|
9811
9933
|
* Format a compact args preview as key="value" pairs.
|
|
@@ -9885,10 +10007,35 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
|
|
|
9885
10007
|
if (this.isPartial) return theme.fg("warning", ` ◌ background · ${this.backgroundTaskId}`);
|
|
9886
10008
|
return isError ? theme.fg("error", ` ✗ background · ${this.backgroundTaskId}`) : theme.fg("success", ` ✓ background · ${this.backgroundTaskId}`);
|
|
9887
10009
|
}
|
|
10010
|
+
/** Output lines of the block being built (see startBlock / endBlock). */
|
|
10011
|
+
pendingBlock = null;
|
|
10012
|
+
/** Start a tool block: collect output lines until endBlock prints the title and the panel. */
|
|
10013
|
+
startBlock() {
|
|
10014
|
+
this.pendingBlock = [];
|
|
10015
|
+
}
|
|
10016
|
+
blockLine(line) {
|
|
10017
|
+
(this.pendingBlock ??= []).push(line);
|
|
10018
|
+
}
|
|
10019
|
+
blockLines(lines) {
|
|
10020
|
+
for (const line of lines) this.blockLine(line);
|
|
10021
|
+
}
|
|
10022
|
+
/**
|
|
10023
|
+
* Finish the block: a "● title" row (the dot carries the status: green done, red failed, grey
|
|
10024
|
+
* running), then any collected output on a shaded half-block panel, indented under the title.
|
|
10025
|
+
*/
|
|
10026
|
+
endBlock(title, isError = this.isErrorResult()) {
|
|
10027
|
+
const output = this.pendingBlock ?? [];
|
|
10028
|
+
this.pendingBlock = null;
|
|
10029
|
+
const width = Math.max(1, this.renderWidth - 0);
|
|
10030
|
+
this.contentBox.addChild(new Text(toolBlock(this.getStatusDot(isError), title, output, width).join("\n"), 0, 0));
|
|
10031
|
+
}
|
|
10032
|
+
getStatusDot(isError = this.isErrorResult()) {
|
|
10033
|
+
return statusDot(this.isPartial ? "running" : isError ? "error" : "done");
|
|
10034
|
+
}
|
|
9888
10035
|
getStatusIndicator(isError = this.isErrorResult()) {
|
|
9889
10036
|
const backgroundStatus = this.getBackgroundStatusIndicator(isError);
|
|
9890
10037
|
if (backgroundStatus) return backgroundStatus;
|
|
9891
|
-
return this.isPartial
|
|
10038
|
+
return !this.isPartial && isError ? theme.fg("error", " ✗") : "";
|
|
9892
10039
|
}
|
|
9893
10040
|
getDurationSuffix() {
|
|
9894
10041
|
const duration = this.formatDuration();
|
|
@@ -10010,13 +10157,13 @@ function getPlainCodeFromViewOutput(content, startLine) {
|
|
|
10010
10157
|
return codeLines.join("\n");
|
|
10011
10158
|
}
|
|
10012
10159
|
/** Strip line number formatting (cat -n or workspace →) and apply syntax highlighting */
|
|
10013
|
-
function highlightCode(content, path, startLine) {
|
|
10014
|
-
const code = getPlainCodeFromViewOutput(content, startLine);
|
|
10160
|
+
function highlightCode(content, path, startLine, hasLineNumbers = true) {
|
|
10161
|
+
const code = hasLineNumbers ? getPlainCodeFromViewOutput(content, startLine) : content.replace(/\n+$/, "");
|
|
10015
10162
|
try {
|
|
10016
10163
|
return highlight(code, {
|
|
10017
10164
|
language: getLanguageFromPath(path),
|
|
10018
10165
|
ignoreIllegals: true,
|
|
10019
|
-
theme:
|
|
10166
|
+
theme: codeHighlightTheme()
|
|
10020
10167
|
});
|
|
10021
10168
|
} catch {
|
|
10022
10169
|
return code;
|
|
@@ -10042,8 +10189,10 @@ function parseErrorFromContent(content) {
|
|
|
10042
10189
|
//#endregion
|
|
10043
10190
|
//#region src/tui/components/user-message.ts
|
|
10044
10191
|
/**
|
|
10045
|
-
* Component that renders a user message
|
|
10192
|
+
* Component that renders a sent user message on the same half-block panel as the prompt.
|
|
10046
10193
|
*/
|
|
10194
|
+
/** Columns of shaded padding on each side of a sent message's text. */
|
|
10195
|
+
const PAD = 2;
|
|
10047
10196
|
/**
|
|
10048
10197
|
* Strip ANSI escape sequences from a string.
|
|
10049
10198
|
*/
|
|
@@ -10051,7 +10200,8 @@ function stripAnsi$1(s) {
|
|
|
10051
10200
|
return s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
10052
10201
|
}
|
|
10053
10202
|
/**
|
|
10054
|
-
* A renderable wrapper that
|
|
10203
|
+
* A renderable wrapper that puts content on the prompt's half-block panel (full width, shaded, no border).
|
|
10204
|
+
* `label` (e.g. "steer") is shown before the text.
|
|
10055
10205
|
*/
|
|
10056
10206
|
var BorderedBox = class {
|
|
10057
10207
|
child;
|
|
@@ -10082,52 +10232,18 @@ var BorderedBox = class {
|
|
|
10082
10232
|
return result;
|
|
10083
10233
|
}
|
|
10084
10234
|
renderUncached(width) {
|
|
10085
|
-
const
|
|
10086
|
-
const
|
|
10087
|
-
const
|
|
10235
|
+
const prefix = this.label ? theme.fg("dim", `${this.label} · `) : "";
|
|
10236
|
+
const prefixWidth = this.label ? visibleWidth(this.label) + 3 : 0;
|
|
10237
|
+
const contentWidth = Math.max(1, width - 0 - prefixWidth - PAD * 2);
|
|
10238
|
+
const childLines = this.child.render(contentWidth);
|
|
10088
10239
|
if (childLines.length === 0) return [];
|
|
10089
|
-
const
|
|
10090
|
-
|
|
10091
|
-
|
|
10092
|
-
|
|
10093
|
-
|
|
10094
|
-
|
|
10095
|
-
|
|
10096
|
-
}
|
|
10097
|
-
maxContentWidth = Math.min(maxContentWidth, maxInnerWidth);
|
|
10098
|
-
let boxInner = maxContentWidth + 2;
|
|
10099
|
-
if (this.label) {
|
|
10100
|
-
const labelOverhead = ` ${this.label} `.length + 2;
|
|
10101
|
-
boxInner = Math.max(boxInner + 4, labelOverhead) - 4;
|
|
10102
|
-
}
|
|
10103
|
-
const boxWidth = boxInner + 4;
|
|
10104
|
-
const lines = [];
|
|
10105
|
-
const promptPrefix = chalk.hex(tintHex(mastra.green, 1))("»") + " ";
|
|
10106
|
-
const promptWidth = 2;
|
|
10107
|
-
if (this.label) {
|
|
10108
|
-
const labelText = ` ${this.label} `;
|
|
10109
|
-
const labelLen = labelText.length;
|
|
10110
|
-
const remaining = Math.max(0, boxWidth - 2 - labelLen);
|
|
10111
|
-
lines.push(borderColor("╭") + chalk.hex(theme.getTheme().dim)(labelText) + borderColor(`${"─".repeat(remaining)}╮`));
|
|
10112
|
-
} else lines.push(borderColor(`╭${"─".repeat(boxWidth - 2)}╮`));
|
|
10113
|
-
for (let i = 0; i < trimmedLines.length; i++) {
|
|
10114
|
-
let trimmed = trimmedLines[i];
|
|
10115
|
-
let vis = visibleWidth(stripAnsi$1(trimmed));
|
|
10116
|
-
const lineMaxWidth = i === 0 ? boxInner - promptWidth : boxInner;
|
|
10117
|
-
if (vis > lineMaxWidth) {
|
|
10118
|
-
trimmed = truncateToWidth(trimmed, lineMaxWidth);
|
|
10119
|
-
vis = visibleWidth(stripAnsi$1(trimmed));
|
|
10120
|
-
}
|
|
10121
|
-
if (i === 0) {
|
|
10122
|
-
const padNeeded = Math.max(0, boxInner - vis - promptWidth);
|
|
10123
|
-
lines.push(borderColor("│") + " " + promptPrefix + trimmed + " ".repeat(padNeeded) + " " + borderColor("│"));
|
|
10124
|
-
} else {
|
|
10125
|
-
const padNeeded = Math.max(0, boxInner - vis);
|
|
10126
|
-
lines.push(borderColor("│") + " " + trimmed + " ".repeat(padNeeded) + " " + borderColor("│"));
|
|
10127
|
-
}
|
|
10128
|
-
}
|
|
10129
|
-
lines.push(borderColor(`╰${"─".repeat(boxWidth - 2)}╯`));
|
|
10130
|
-
return lines.map((l) => "" + l);
|
|
10240
|
+
const rows = childLines.map((line, i) => {
|
|
10241
|
+
let content = line.replace(/\s+$/, "");
|
|
10242
|
+
if (visibleWidth(stripAnsi$1(content)) > contentWidth) content = truncateToWidth(content, contentWidth);
|
|
10243
|
+
return `${" ".repeat(PAD)}${i === 0 ? prefix : " ".repeat(prefixWidth)}${content}`;
|
|
10244
|
+
});
|
|
10245
|
+
const fitWidth = Math.max(...rows.map((r) => visibleWidth(stripAnsi$1(r)))) + PAD;
|
|
10246
|
+
return halfBlockPanel(rows, Math.min(width - 0, fitWidth), promptSurface()).map((l) => "" + l);
|
|
10131
10247
|
}
|
|
10132
10248
|
};
|
|
10133
10249
|
var UserMessageComponent = class extends Container {
|
|
@@ -10160,20 +10276,33 @@ var PendingUserMessageComponent = class extends Container {
|
|
|
10160
10276
|
//#endregion
|
|
10161
10277
|
//#region src/tui/components/tool-approval-dialog.ts
|
|
10162
10278
|
/**
|
|
10163
|
-
* Tool approval
|
|
10164
|
-
* Shows tool details and prompts user to approve or decline execution.
|
|
10279
|
+
* Tool approval prompt: one inline row in the chat, directly under the pending tool call.
|
|
10165
10280
|
*
|
|
10166
10281
|
* Keyboard shortcuts:
|
|
10167
10282
|
* y — approve this one call
|
|
10168
10283
|
* n / Esc — decline this call
|
|
10169
10284
|
* a — always allow this category for this thread
|
|
10170
10285
|
* Y — switch to YOLO mode (approve all)
|
|
10286
|
+
* Ctrl+E — show / hide long arguments in full (when the card lists them)
|
|
10287
|
+
*/
|
|
10288
|
+
/** Long argument values (e.g. file contents) stop after this many lines until expanded with Ctrl+E. */
|
|
10289
|
+
const TARGET_MAX_LINES = 40;
|
|
10290
|
+
/**
|
|
10291
|
+
* Arguments come from the model, so control characters must not reach the terminal: escape sequences could
|
|
10292
|
+
* restyle, move or clear what the card shows. They're shown as visible \xNN escapes (the card shows exactly
|
|
10293
|
+
* what gets approved); newlines stay, CRLF becomes a newline and tabs become spaces.
|
|
10171
10294
|
*/
|
|
10172
|
-
|
|
10295
|
+
function escapeControls(text) {
|
|
10296
|
+
return text.replace(/\r\n/g, "\n").replace(/\t/g, " ").replace(/[\u0000-\u0009\u000b-\u001f\u007f-\u009f]/g, (c) => `\\x${c.charCodeAt(0).toString(16).padStart(2, "0")}`);
|
|
10297
|
+
}
|
|
10298
|
+
var ToolApprovalDialogComponent = class {
|
|
10173
10299
|
toolName;
|
|
10174
10300
|
args;
|
|
10175
10301
|
categoryLabel;
|
|
10302
|
+
showTarget;
|
|
10176
10303
|
onAction;
|
|
10304
|
+
requestRender;
|
|
10305
|
+
expanded = false;
|
|
10177
10306
|
resolved = false;
|
|
10178
10307
|
_focused = false;
|
|
10179
10308
|
get focused() {
|
|
@@ -10183,28 +10312,84 @@ var ToolApprovalDialogComponent = class extends Box {
|
|
|
10183
10312
|
this._focused = value;
|
|
10184
10313
|
}
|
|
10185
10314
|
constructor(options) {
|
|
10186
|
-
super(2, 1, (text) => theme.bg("overlayBg", text));
|
|
10187
10315
|
this.toolName = options.toolName;
|
|
10188
10316
|
this.args = options.args;
|
|
10189
10317
|
this.categoryLabel = options.categoryLabel;
|
|
10318
|
+
this.showTarget = options.showTarget ?? false;
|
|
10190
10319
|
this.onAction = options.onAction;
|
|
10191
|
-
this.
|
|
10320
|
+
this.requestRender = options.requestRender;
|
|
10192
10321
|
}
|
|
10193
|
-
|
|
10194
|
-
|
|
10195
|
-
|
|
10196
|
-
|
|
10197
|
-
|
|
10198
|
-
|
|
10199
|
-
|
|
10200
|
-
|
|
10201
|
-
|
|
10202
|
-
|
|
10203
|
-
|
|
10204
|
-
const
|
|
10205
|
-
const
|
|
10206
|
-
const
|
|
10207
|
-
|
|
10322
|
+
invalidate() {}
|
|
10323
|
+
/**
|
|
10324
|
+
* One inline row under the pending tool call (which already shows the command / path):
|
|
10325
|
+
* ▎ Allow? y yes · a always allow Execute · Y YOLO · n no
|
|
10326
|
+
* On narrow terminals the options wrap under "Allow?".
|
|
10327
|
+
* When no visible row shows this exact call (`showTarget`), the card names the tool and lists its arguments:
|
|
10328
|
+
* ▎ Allow write_file?
|
|
10329
|
+
* ▎ path: src/auth.ts
|
|
10330
|
+
* ▎ y yes · a always allow Edit · Y YOLO · n no
|
|
10331
|
+
*/
|
|
10332
|
+
render(width) {
|
|
10333
|
+
const warning = theme.getTheme().warning;
|
|
10334
|
+
const key = (k, label) => `${chalk.bold.hex(warning)(k)} ${theme.fg("muted", label)}`;
|
|
10335
|
+
const always = this.categoryLabel ? `always allow ${this.categoryLabel}` : "always allow category";
|
|
10336
|
+
const options = [
|
|
10337
|
+
key("y", "yes"),
|
|
10338
|
+
key("a", always),
|
|
10339
|
+
key("Y", "YOLO"),
|
|
10340
|
+
key("n", "no")
|
|
10341
|
+
];
|
|
10342
|
+
const sep = theme.fg("dim", " · ");
|
|
10343
|
+
const room = width - 2;
|
|
10344
|
+
if (!this.showTarget) {
|
|
10345
|
+
const line = `${theme.bold(theme.fg("text", "Allow?"))} ${options.join(sep)}`;
|
|
10346
|
+
if (visibleWidth(line) <= room) return card(warning, [line]);
|
|
10347
|
+
}
|
|
10348
|
+
const rows = [this.showTarget ? theme.bold(theme.fg("text", `Allow ${this.toolName}?`)) : theme.bold(theme.fg("text", "Allow?")), ...this.showTarget ? this.targetArgRows(room - 2).map((row) => theme.fg("muted", ` ${row}`)) : []];
|
|
10349
|
+
let row = "";
|
|
10350
|
+
for (const option of options) {
|
|
10351
|
+
const next = row ? `${row}${sep}${option}` : option;
|
|
10352
|
+
if (row && visibleWidth(next) > room) {
|
|
10353
|
+
rows.push(row);
|
|
10354
|
+
row = option;
|
|
10355
|
+
} else row = next;
|
|
10356
|
+
}
|
|
10357
|
+
rows.push(row);
|
|
10358
|
+
return card(warning, rows).map((l) => truncateToWidth(l, width));
|
|
10359
|
+
}
|
|
10360
|
+
/**
|
|
10361
|
+
* Every argument in full, wrapped to `width`: this is what gets approved, so nothing is cut to one line.
|
|
10362
|
+
* Very long values (file contents and the like) stop after TARGET_MAX_LINES until Ctrl+E shows the rest.
|
|
10363
|
+
*/
|
|
10364
|
+
targetArgRows(width) {
|
|
10365
|
+
const args = this.args;
|
|
10366
|
+
if (args === null || args === void 0 || typeof args !== "object") return [escapeControls(String(args ?? "(none)"))];
|
|
10367
|
+
const entries = Object.entries(args).filter(([, v]) => v !== null && v !== void 0);
|
|
10368
|
+
if (entries.length === 0) return ["(none)"];
|
|
10369
|
+
const rows = [];
|
|
10370
|
+
for (const [key, value] of entries) {
|
|
10371
|
+
const wrapped = escapeControls(`${key}: ${typeof value === "string" ? value : safeStringify(value)}`).split("\n").flatMap((line) => line ? wrapTextWithAnsi(line, Math.max(10, width)) : [""]);
|
|
10372
|
+
if (this.expanded || wrapped.length <= TARGET_MAX_LINES) rows.push(...wrapped);
|
|
10373
|
+
else {
|
|
10374
|
+
rows.push(...wrapped.slice(0, TARGET_MAX_LINES));
|
|
10375
|
+
rows.push(`… ${wrapped.length - TARGET_MAX_LINES} more lines · ctrl+e to show all`);
|
|
10376
|
+
}
|
|
10377
|
+
}
|
|
10378
|
+
return rows;
|
|
10379
|
+
}
|
|
10380
|
+
/**
|
|
10381
|
+
* Whether Ctrl+E belongs to the card (it lists the arguments). Otherwise Ctrl+E keeps its usual job of
|
|
10382
|
+
* expanding the tool row above, so a collapsed preview can be read in full before approving.
|
|
10383
|
+
*/
|
|
10384
|
+
handlesExpand() {
|
|
10385
|
+
return this.showTarget;
|
|
10386
|
+
}
|
|
10387
|
+
/** Arguments as "key: value" lines (used by tests and for tools without a call row). */
|
|
10388
|
+
describeArgs() {
|
|
10389
|
+
return this.formatArgs(this.args);
|
|
10390
|
+
}
|
|
10391
|
+
get tool() {
|
|
10392
|
+
return this.toolName;
|
|
10208
10393
|
}
|
|
10209
10394
|
formatArgs(args) {
|
|
10210
10395
|
if (args === null || args === void 0) return "(none)";
|
|
@@ -10236,6 +10421,11 @@ var ToolApprovalDialogComponent = class extends Box {
|
|
|
10236
10421
|
this.emit({ type: "decline" });
|
|
10237
10422
|
return;
|
|
10238
10423
|
}
|
|
10424
|
+
if (data === "" && this.showTarget) {
|
|
10425
|
+
this.expanded = !this.expanded;
|
|
10426
|
+
this.requestRender?.();
|
|
10427
|
+
return;
|
|
10428
|
+
}
|
|
10239
10429
|
switch (decodePrintableShortcut(data)) {
|
|
10240
10430
|
case "y":
|
|
10241
10431
|
this.emit({ type: "approve" });
|
|
@@ -10251,9 +10441,6 @@ var ToolApprovalDialogComponent = class extends Box {
|
|
|
10251
10441
|
break;
|
|
10252
10442
|
}
|
|
10253
10443
|
}
|
|
10254
|
-
render(maxWidth) {
|
|
10255
|
-
return super.render(maxWidth);
|
|
10256
|
-
}
|
|
10257
10444
|
};
|
|
10258
10445
|
var RenderScheduler = class {
|
|
10259
10446
|
render;
|
|
@@ -10639,13 +10826,18 @@ function handleToolApprovalRequired(ctx, toolCallId, toolName, args) {
|
|
|
10639
10826
|
const firePermissionResult = (decision) => {
|
|
10640
10827
|
state.hookManager?.runPermissionResult("tool_approval", toolCallId, toolName, decision, args).catch(() => {});
|
|
10641
10828
|
};
|
|
10829
|
+
const askPreview = toolName === "ask_user" ? state.pendingAskUserComponents.get(toolCallId) : void 0;
|
|
10830
|
+
askPreview?.updateArgs(args);
|
|
10831
|
+
const visibleCall = state.pendingTools.get(toolCallId)?.getToolCall?.();
|
|
10642
10832
|
const dialog = new ToolApprovalDialogComponent({
|
|
10643
10833
|
toolCallId,
|
|
10644
10834
|
toolName,
|
|
10645
10835
|
args,
|
|
10646
10836
|
categoryLabel,
|
|
10837
|
+
showTarget: !askPreview && (state.quietMode || !visibleCall || visibleCall.toolName !== toolName || safeStringify(visibleCall.args) !== safeStringify(args)),
|
|
10838
|
+
requestRender: () => state.ui.requestRender(),
|
|
10647
10839
|
onAction: (action) => {
|
|
10648
|
-
|
|
10840
|
+
removeApproval();
|
|
10649
10841
|
state.pendingApprovalDismiss = null;
|
|
10650
10842
|
if (action.type === "approve") {
|
|
10651
10843
|
firePermissionResult("approved");
|
|
@@ -10675,8 +10867,13 @@ function handleToolApprovalRequired(ctx, toolCallId, toolName, args) {
|
|
|
10675
10867
|
}
|
|
10676
10868
|
}
|
|
10677
10869
|
});
|
|
10870
|
+
const removeApproval = () => {
|
|
10871
|
+
if (state.activeInlineApproval === dialog) state.activeInlineApproval = void 0;
|
|
10872
|
+
state.chatContainer.removeChild(dialog);
|
|
10873
|
+
state.ui.requestRender();
|
|
10874
|
+
};
|
|
10678
10875
|
state.pendingApprovalDismiss = (declineContext) => {
|
|
10679
|
-
|
|
10876
|
+
removeApproval();
|
|
10680
10877
|
state.pendingApprovalDismiss = null;
|
|
10681
10878
|
firePermissionResult("dismissed");
|
|
10682
10879
|
state.session.respondToToolApproval({
|
|
@@ -10685,7 +10882,8 @@ function handleToolApprovalRequired(ctx, toolCallId, toolName, args) {
|
|
|
10685
10882
|
declineContext
|
|
10686
10883
|
});
|
|
10687
10884
|
};
|
|
10688
|
-
|
|
10885
|
+
ctx.addChildBeforeFollowUps(dialog);
|
|
10886
|
+
state.activeInlineApproval = dialog;
|
|
10689
10887
|
dialog.focused = true;
|
|
10690
10888
|
flushRender(state);
|
|
10691
10889
|
}
|
|
@@ -11246,9 +11444,12 @@ function removePendingUserMessage(state, messageId) {
|
|
|
11246
11444
|
state.pendingSignalMessageComponentsById.delete(messageId);
|
|
11247
11445
|
state.ui.requestRender();
|
|
11248
11446
|
}
|
|
11249
|
-
function clearPendingUserMessages(state) {
|
|
11250
|
-
for (const pending of state.pendingSignalMessageComponentsById
|
|
11251
|
-
|
|
11447
|
+
function clearPendingUserMessages(state, keepIds = []) {
|
|
11448
|
+
for (const [id, pending] of state.pendingSignalMessageComponentsById) {
|
|
11449
|
+
if (keepIds.includes(id)) continue;
|
|
11450
|
+
state.chatContainer.removeChild(pending.component);
|
|
11451
|
+
state.pendingSignalMessageComponentsById.delete(id);
|
|
11452
|
+
}
|
|
11252
11453
|
state.ui.requestRender();
|
|
11253
11454
|
}
|
|
11254
11455
|
function confirmMatchingPendingUserMessage(state, messageId, text, attachments) {
|
|
@@ -11554,14 +11755,6 @@ function addUserMessage(state, message, options) {
|
|
|
11554
11755
|
return;
|
|
11555
11756
|
}
|
|
11556
11757
|
if (confirmMatchingPendingUserMessage(state, message.id, displayText, attachments)) return;
|
|
11557
|
-
const dedupKey = displayText.trim();
|
|
11558
|
-
const pendingEchoCounts = state.firedQueuedMessageTexts;
|
|
11559
|
-
const dedupCount = pendingEchoCounts?.get(dedupKey) ?? 0;
|
|
11560
|
-
if (dedupCount > 0) {
|
|
11561
|
-
if (dedupCount === 1) pendingEchoCounts.delete(dedupKey);
|
|
11562
|
-
else pendingEchoCounts.set(dedupKey, dedupCount - 1);
|
|
11563
|
-
return;
|
|
11564
|
-
}
|
|
11565
11758
|
const legacyReminderMatch = exactDisplayText.match(/^<system-reminder(?<attrs>\s+[^>]*)?>(?<body>[\s\S]*?)<\/system-reminder>$/);
|
|
11566
11759
|
if (legacyReminderMatch?.groups?.body) {
|
|
11567
11760
|
const attrs = legacyReminderMatch.groups.attrs ?? "";
|
|
@@ -13453,56 +13646,90 @@ function formatGoalDuration(goal) {
|
|
|
13453
13646
|
if (hours > 0) return minutes > 0 ? `${hours}hr${minutes}m` : `${hours}hr`;
|
|
13454
13647
|
return `${minutes}m`;
|
|
13455
13648
|
}
|
|
13649
|
+
/** Shorten a path under the home directory to ~/… */
|
|
13650
|
+
function shortPath(path) {
|
|
13651
|
+
const home = process.env.HOME;
|
|
13652
|
+
return home && (path === home || path.startsWith(`${home}/`)) ? `~${path.slice(home.length)}` : path;
|
|
13653
|
+
}
|
|
13654
|
+
/**
|
|
13655
|
+
* The path, then shorter forms that keep the last directories, like zsh's prompt truncation:
|
|
13656
|
+
* ~/dev/mastra/mastracode/tui → ~/…/mastracode/tui → ~/…/tui
|
|
13657
|
+
*/
|
|
13658
|
+
function compactPaths(path) {
|
|
13659
|
+
const isHome = path.startsWith("~/");
|
|
13660
|
+
const isAbsolute = path.startsWith("/");
|
|
13661
|
+
const segments = (isHome ? path.slice(2) : isAbsolute ? path.slice(1) : path).split("/").filter(Boolean);
|
|
13662
|
+
const prefix = isHome ? "~/…/" : isAbsolute ? "/…/" : "…/";
|
|
13663
|
+
const paths = [path];
|
|
13664
|
+
for (const keep of [2, 1]) if (segments.length > keep) paths.push(prefix + segments.slice(-keep).join("/"));
|
|
13665
|
+
return paths;
|
|
13666
|
+
}
|
|
13667
|
+
function truncateEnd(value, maxWidth) {
|
|
13668
|
+
return [...value].slice(0, Math.max(0, maxWidth - 1)).join("") + "…";
|
|
13669
|
+
}
|
|
13670
|
+
/** ~/…/a-very-long-directory-name → ~/…/a-very-l…ry-name */
|
|
13671
|
+
function truncateLastSegment(path, maxWidth) {
|
|
13672
|
+
if (visibleWidth(path) <= maxWidth) return path;
|
|
13673
|
+
const slash = path.lastIndexOf("/");
|
|
13674
|
+
const head = path.slice(0, slash + 1);
|
|
13675
|
+
const name = [...path.slice(slash + 1)];
|
|
13676
|
+
const room = maxWidth - visibleWidth(head) - 1;
|
|
13677
|
+
if (room < 2) return truncateEnd(path, maxWidth);
|
|
13678
|
+
const start = Math.ceil(room * .6);
|
|
13679
|
+
return head + name.slice(0, start).join("") + "…" + name.slice(name.length - (room - start)).join("");
|
|
13680
|
+
}
|
|
13681
|
+
const PULSE_PERIOD_MS = 1600;
|
|
13682
|
+
/** How far the dot fades at its dimmest: 0 = no fade, 1 = disappears into the background. */
|
|
13683
|
+
const PULSE_DEPTH = 1;
|
|
13684
|
+
/** Terminal width at which the footer last needed two rows (see updateStatusLine). */
|
|
13685
|
+
const twoRowFooterWidth = /* @__PURE__ */ new WeakMap();
|
|
13686
|
+
function pulseDot(color, now) {
|
|
13687
|
+
const wave = (Math.cos(now / PULSE_PERIOD_MS * Math.PI * 2) + 1) / 2;
|
|
13688
|
+
const fade = PULSE_DEPTH * (1 - wave);
|
|
13689
|
+
const bg = getContrastBg();
|
|
13690
|
+
const channel = (i) => {
|
|
13691
|
+
const fg = parseInt(color.slice(i, i + 2), 16);
|
|
13692
|
+
return Math.round(fg + (parseInt(bg.slice(i, i + 2), 16) - fg) * fade);
|
|
13693
|
+
};
|
|
13694
|
+
return chalk.rgb(channel(1), channel(3), channel(5))("•");
|
|
13695
|
+
}
|
|
13456
13696
|
/**
|
|
13457
|
-
* Update the status line
|
|
13458
|
-
*
|
|
13697
|
+
* Update the status line under the prompt and the Working row above it.
|
|
13698
|
+
*
|
|
13699
|
+
* Status line: " · "-separated parts, left-aligned with one column of padding:
|
|
13700
|
+
* mode · model · [fallback] · [goal] · [queued] · context · location
|
|
13701
|
+
* A long path shortens like zsh (~/…/parent/dir) to stay on one row; only when even that doesn't fit does
|
|
13702
|
+
* the location move to a second row.
|
|
13703
|
+
* It never changes while the agent runs; run progress (spinner, elapsed time, throughput) lives in the
|
|
13704
|
+
* Working row instead. Parts are dropped or shortened from the right until the first row fits.
|
|
13459
13705
|
*/
|
|
13460
13706
|
function updateStatusLine(state) {
|
|
13461
13707
|
if (!state.statusLine) return;
|
|
13462
|
-
const termWidth =
|
|
13463
|
-
const
|
|
13708
|
+
const termWidth = state.ui.terminal?.columns || process.stdout.columns || 80;
|
|
13709
|
+
const PAD = 1;
|
|
13710
|
+
const SEP = theme.fg("dim", " · ");
|
|
13711
|
+
const SEP_WIDTH = 3;
|
|
13712
|
+
const now = Date.now();
|
|
13464
13713
|
const displayState = state.session.displayState.get();
|
|
13465
13714
|
const omStatus = displayState.omProgress.status;
|
|
13466
13715
|
const isJudging = Boolean(state.activeGoalJudge);
|
|
13467
13716
|
const isObserving = omStatus === "observing";
|
|
13468
13717
|
const showOMMode = !isJudging && (isObserving || omStatus === "reflecting");
|
|
13469
|
-
let modeBadge = "";
|
|
13470
|
-
let modeBadgeWidth = 0;
|
|
13471
13718
|
const modes = state.controller.listModes();
|
|
13472
13719
|
const configuredMode = state.session.mode.resolve();
|
|
13473
13720
|
const currentMode = modes.length > 1 ? configuredMode : void 0;
|
|
13474
|
-
const judgeModeColor = mastra.blue;
|
|
13475
13721
|
const currentModeColor = currentMode?.metadata?.color;
|
|
13476
|
-
const
|
|
13477
|
-
const
|
|
13478
|
-
const
|
|
13479
|
-
const
|
|
13480
|
-
|
|
13481
|
-
|
|
13482
|
-
|
|
13483
|
-
|
|
13484
|
-
|
|
13485
|
-
|
|
13486
|
-
|
|
13487
|
-
];
|
|
13488
|
-
let badgeBrightness = .9;
|
|
13489
|
-
if (state.gradientAnimator?.isRunning()) {
|
|
13490
|
-
const fade = state.gradientAnimator.getFadeProgress();
|
|
13491
|
-
const easedFade = fade * fade * (3 - 2 * fade);
|
|
13492
|
-
const offset = state.gradientAnimator.getOffset() % 1;
|
|
13493
|
-
const animBrightness = .65 + .3 * (.5 + .5 * Math.sin(offset * Math.PI * 2 + Math.PI));
|
|
13494
|
-
badgeBrightness = animBrightness + (.9 - animBrightness) * easedFade;
|
|
13495
|
-
}
|
|
13496
|
-
const mr = Math.floor(mcr * badgeBrightness);
|
|
13497
|
-
const mg = Math.floor(mcg * badgeBrightness);
|
|
13498
|
-
const mb = Math.floor(mcb * badgeBrightness);
|
|
13499
|
-
const rightHalf = tintBg ? chalk.rgb(mr, mg, mb).bgHex(tintBg)("▌") : chalk.rgb(mr, mg, mb)("▌");
|
|
13500
|
-
modeBadge = chalk.rgb(mr, mg, mb)("▐") + chalk.bgRgb(mr, mg, mb).hex("#000000").bold(badgeName.toLowerCase()) + rightHalf;
|
|
13501
|
-
modeBadgeWidth = badgeName.length + 2;
|
|
13502
|
-
} else if (badgeName) {
|
|
13503
|
-
modeBadge = " " + theme.fg("dim", badgeName) + " ";
|
|
13504
|
-
modeBadgeWidth = badgeName.length + 2;
|
|
13505
|
-
}
|
|
13722
|
+
const rawModeColor = isJudging ? mastra.blue : showOMMode ? isObserving ? getObserverColor() : getReflectorColor() : typeof currentModeColor === "string" ? currentModeColor : void 0;
|
|
13723
|
+
const modeColor = rawModeColor ? displayModeColor(rawModeColor) : void 0;
|
|
13724
|
+
const modeName = isJudging ? "judge" : showOMMode ? isObserving ? "observe" : "reflect" : currentMode ? (currentMode.name || currentMode.id || "unknown").toLowerCase() : void 0;
|
|
13725
|
+
const modeInitial = modeName ? {
|
|
13726
|
+
plain: modeName.charAt(0),
|
|
13727
|
+
styled: modeColor ? chalk.bold.hex(modeColor)(modeName.charAt(0)) : theme.fg("dim", modeName.charAt(0))
|
|
13728
|
+
} : null;
|
|
13729
|
+
const modePart = modeName ? {
|
|
13730
|
+
plain: modeName,
|
|
13731
|
+
styled: modeColor ? chalk.bold.hex(modeColor)(modeName) : theme.fg("dim", modeName)
|
|
13732
|
+
} : null;
|
|
13506
13733
|
const rawModelId = (isJudging ? state.activeGoalJudge?.modelId : showOMMode ? isObserving ? state.session.om.observer.modelId() : state.session.om.reflector.modelId() : state.session.model.get()) ?? "";
|
|
13507
13734
|
let fullModelId = rawModelId.startsWith("fireworks-ai/accounts/fireworks/models/") ? "fireworks/" + rawModelId.slice(39) : rawModelId;
|
|
13508
13735
|
fullModelId = fullModelId.replace(/\b([a-z]+-[a-z])(\d+)p(\d+)\b/g, "$1$2.$3");
|
|
@@ -13514,246 +13741,191 @@ function updateStatusLine(state) {
|
|
|
13514
13741
|
};
|
|
13515
13742
|
const shortModelId = compactModelId(fullModelId);
|
|
13516
13743
|
const tinyModelId = shortModelId.includes("/") ? shortModelId : shortModelId.replace(/^claude-/, "").replace(/^(\w+)-(\d+)-(\d{1,2})$/, "$1 $2.$3");
|
|
13517
|
-
const
|
|
13518
|
-
const threadTitle = state.currentThreadTitle && !isGenericTitle(state.currentThreadTitle) ? state.currentThreadTitle : null;
|
|
13519
|
-
const activeGithubPrSubscriptions = state.activeGithubPrSubscriptions ?? [];
|
|
13520
|
-
const githubPrLabel = activeGithubPrSubscriptions.length > 0 ? formatGithubPrLabel(state, activeGithubPrSubscriptions) : null;
|
|
13521
|
-
const centerText = threadTitle || branch || (githubPrLabel ? "" : null);
|
|
13522
|
-
const centerTextShort = centerText && centerText.length > 24 ? centerText.slice(0, 12) + ".." + centerText.slice(-8) : centerText;
|
|
13523
|
-
const now = Date.now();
|
|
13524
|
-
const queuedCount = state.pendingQueuedActions.length + displayState.queuedFollowUps;
|
|
13525
|
-
const queuedLabel = queuedCount > 0 ? `${queuedCount} queued` : null;
|
|
13526
|
-
const goalState = state.goalManager?.getGoal();
|
|
13527
|
-
const goalDuration = !isJudging && goalState?.status === "active" ? formatGoalDuration(goalState) : null;
|
|
13528
|
-
const goalMatchesActiveRun = goalState?.status === "active" && goalDuration !== null && state.agentRunStartedAt !== void 0 && Math.floor(getGoalDurationMs(goalState, now) / 6e4) === Math.floor((now - state.agentRunStartedAt) / 6e4);
|
|
13529
|
-
const goalLabel = goalDuration ? goalMatchesActiveRun ? "goal" : `goal ${goalDuration}` : null;
|
|
13530
|
-
const fallbackLabel = !isJudging && !showOMMode && state.fallbackStatus ? `Using fallback ${state.fallbackStatus.usingPack} (${state.fallbackStatus.failedPack} failed)` : null;
|
|
13531
|
-
const formatDirPart = (value) => {
|
|
13532
|
-
const separator = githubPrLabel && value ? " " : "";
|
|
13533
|
-
return {
|
|
13534
|
-
plain: githubPrLabel ? `${githubPrLabel.plain}${separator}${value}` : value,
|
|
13535
|
-
styled: githubPrLabel ? `${githubPrLabel.styled}${separator}${theme.fg("thinkingText", value)}` : theme.fg("thinkingText", value)
|
|
13536
|
-
};
|
|
13537
|
-
};
|
|
13538
|
-
const modelTrail = tintBg ? chalk.hex(tintBg)("▌") : "";
|
|
13539
|
-
const styleModelId = (id) => {
|
|
13744
|
+
const modelPart = (id) => {
|
|
13540
13745
|
if (!state.modelAuthStatus.hasAuth) {
|
|
13541
13746
|
const envVar = state.modelAuthStatus.apiKeyEnvVar;
|
|
13542
|
-
|
|
13543
|
-
|
|
13544
|
-
|
|
13545
|
-
|
|
13546
|
-
|
|
13547
|
-
const text = applyGradientSweep(id, state.gradientAnimator.getOffset(), modeColor, easedFade);
|
|
13548
|
-
const styled = chalk.italic(text);
|
|
13549
|
-
return (tintBg ? chalk.bgHex(tintBg)(styled) : styled) + modelTrail;
|
|
13550
|
-
}
|
|
13551
|
-
if (modeColor) {
|
|
13552
|
-
const [cr, cg, cb] = [
|
|
13553
|
-
parseInt(modeColor.slice(1, 3), 16),
|
|
13554
|
-
parseInt(modeColor.slice(3, 5), 16),
|
|
13555
|
-
parseInt(modeColor.slice(5, 7), 16)
|
|
13556
|
-
];
|
|
13557
|
-
const idleBright = .8;
|
|
13558
|
-
const fgStyled = chalk.rgb(Math.floor(cr * idleBright), Math.floor(cg * idleBright), Math.floor(cb * idleBright)).bold.italic(id);
|
|
13559
|
-
return (tintBg ? chalk.bgHex(tintBg)(fgStyled) : fgStyled) + modelTrail;
|
|
13747
|
+
const hint = envVar ? ` (${envVar})` : " (no key)";
|
|
13748
|
+
return {
|
|
13749
|
+
plain: `${id} ✗${hint}`,
|
|
13750
|
+
styled: theme.fg("dim", id) + theme.fg("error", " ✗") + theme.fg("muted", hint)
|
|
13751
|
+
};
|
|
13560
13752
|
}
|
|
13561
|
-
|
|
13753
|
+
const lastRun = state.agentRunStartedAt === void 0 && state.lastAgentRunDurationMs !== void 0 ? formatStatusDuration(state.lastAgentRunDurationMs, { includeSeconds: true }) : "";
|
|
13754
|
+
if (!lastRun) return {
|
|
13755
|
+
plain: id,
|
|
13756
|
+
styled: theme.fg("secondary", id)
|
|
13757
|
+
};
|
|
13758
|
+
const reason = state.lastAgentRunEndReason;
|
|
13759
|
+
const icon = reason === "error" ? " ×" : reason === "aborted" ? "" : " ✓";
|
|
13760
|
+
const tone = reason === "error" ? "error" : reason === "aborted" ? "warning" : "success";
|
|
13761
|
+
return {
|
|
13762
|
+
plain: `${id} ${lastRun}${icon}`,
|
|
13763
|
+
styled: theme.fg("secondary", id) + " " + theme.fg(tone, lastRun + icon)
|
|
13764
|
+
};
|
|
13562
13765
|
};
|
|
13563
|
-
|
|
13564
|
-
|
|
13565
|
-
if (badgeName && modeColor) {
|
|
13566
|
-
const shortName = badgeName.toLowerCase().charAt(0);
|
|
13567
|
-
const [mcr, mcg, mcb] = [
|
|
13568
|
-
parseInt(modeColor.slice(1, 3), 16),
|
|
13569
|
-
parseInt(modeColor.slice(3, 5), 16),
|
|
13570
|
-
parseInt(modeColor.slice(5, 7), 16)
|
|
13571
|
-
];
|
|
13572
|
-
let sBadgeBrightness = .9;
|
|
13573
|
-
if (state.gradientAnimator?.isRunning()) {
|
|
13574
|
-
const fade = state.gradientAnimator.getFadeProgress();
|
|
13575
|
-
if (fade < 1) {
|
|
13576
|
-
const offset = state.gradientAnimator.getOffset() % 1;
|
|
13577
|
-
const animBrightness = .65 + .3 * (.5 + .5 * Math.sin(offset * Math.PI * 2 + Math.PI));
|
|
13578
|
-
sBadgeBrightness = animBrightness + (.9 - animBrightness) * fade;
|
|
13579
|
-
}
|
|
13580
|
-
}
|
|
13581
|
-
const sr = Math.floor(mcr * sBadgeBrightness);
|
|
13582
|
-
const sg = Math.floor(mcg * sBadgeBrightness);
|
|
13583
|
-
const sb = Math.floor(mcb * sBadgeBrightness);
|
|
13584
|
-
const shortRightHalf = tintBg ? chalk.rgb(sr, sg, sb).bgHex(tintBg)("▌") : chalk.rgb(sr, sg, sb)("▌");
|
|
13585
|
-
shortModeBadge = chalk.rgb(sr, sg, sb)("▐") + chalk.bgRgb(sr, sg, sb).hex("#000000").bold(shortName) + shortRightHalf;
|
|
13586
|
-
shortModeBadgeWidth = shortName.length + 2;
|
|
13587
|
-
} else if (badgeName) {
|
|
13588
|
-
const shortName = badgeName.toLowerCase().charAt(0);
|
|
13589
|
-
shortModeBadge = " " + theme.fg("dim", shortName) + " ";
|
|
13590
|
-
shortModeBadgeWidth = shortName.length + 2;
|
|
13591
|
-
}
|
|
13592
|
-
const activeTimingLabel = state.agentRunStartedAt !== void 0 ? formatStatusDuration(now - state.agentRunStartedAt, { includeSeconds: true }) : "";
|
|
13593
|
-
const activeTimingIsStale = state.agentRunStartedAt !== void 0 && state.agentRunLastStreamPartAt !== void 0 && now - state.agentRunLastStreamPartAt > 3 * 6e4;
|
|
13594
|
-
const completedTimingLabel = !activeTimingLabel && state.lastAgentRunDurationMs !== void 0 ? formatStatusDuration(state.lastAgentRunDurationMs, { includeSeconds: true }) : "";
|
|
13595
|
-
const completedTimingIcon = state.lastAgentRunEndReason === "error" ? "×" : completedTimingLabel && state.lastAgentRunEndReason !== "aborted" ? "✓" : "";
|
|
13596
|
-
const timingLabel = activeTimingLabel || completedTimingLabel;
|
|
13597
|
-
const buildLine = (opts) => {
|
|
13598
|
-
const parts = [];
|
|
13599
|
-
const timingPlain = timingLabel ? ` ${timingLabel}${completedTimingIcon ? ` ${completedTimingIcon}` : ""}` : "";
|
|
13600
|
-
const timingColor = activeTimingIsStale ? theme.fg("error", timingLabel) : activeTimingLabel ? modeColor ? chalk.hex(modeColor)(timingLabel) : theme.fg("dim", timingLabel) : state.lastAgentRunEndReason === "aborted" ? theme.fg("warning", timingLabel) : state.lastAgentRunEndReason === "error" ? theme.fg("error", timingLabel) : theme.fg("success", timingLabel);
|
|
13601
|
-
const timingIconColor = state.lastAgentRunEndReason === "aborted" ? "warning" : state.lastAgentRunEndReason === "error" ? "error" : "success";
|
|
13602
|
-
const timingStyled = timingLabel ? ` ${timingColor}${completedTimingIcon ? ` ${theme.fg(timingIconColor, completedTimingIcon)}` : ""}` : "";
|
|
13603
|
-
parts.push({
|
|
13604
|
-
plain: `${opts.modelId}${tintBg ? " " : ""}${timingPlain}`,
|
|
13605
|
-
styled: styleModelId(opts.modelId) + timingStyled
|
|
13606
|
-
});
|
|
13607
|
-
const visibleFallbackLabel = opts.showFallback === false ? null : fallbackLabel;
|
|
13608
|
-
if (visibleFallbackLabel) parts.push({
|
|
13609
|
-
plain: visibleFallbackLabel,
|
|
13610
|
-
styled: theme.fg("warning", visibleFallbackLabel)
|
|
13611
|
-
});
|
|
13612
|
-
const useBadge = opts.badge === "short" ? shortModeBadge : modeBadge;
|
|
13613
|
-
const useBadgeWidth = opts.badge === "short" ? shortModeBadgeWidth : modeBadgeWidth;
|
|
13614
|
-
const ds = displayState;
|
|
13615
|
-
const messageColor = contextIndicatorColor;
|
|
13616
|
-
const memoryColor = mastraBrand.blue;
|
|
13617
|
-
const unusedColor = "#3f3f46";
|
|
13618
|
-
const messageSegmentStyler = ds.bufferingMessages && state.gradientAnimator?.isRunning() ? (segment) => applyGradientSweep(segment, state.gradientAnimator.getOffset(), messageColor, state.gradientAnimator.getFadeProgress()) : (segment) => chalk.hex(messageColor)(segment);
|
|
13619
|
-
const memorySegmentStyler = ds.bufferingObservations && state.gradientAnimator?.isRunning() ? (segment) => applyGradientSweep(segment, state.gradientAnimator.getOffset(), memoryColor, state.gradientAnimator.getFadeProgress()) : (segment) => chalk.hex(memoryColor)(segment);
|
|
13620
|
-
const unusedSegmentStyler = (segment) => chalk.hex(unusedColor)(segment);
|
|
13621
|
-
const indicatorPart = !isJudging && opts.showOM !== false ? formatOMContextIndicator(ds.omProgress, {
|
|
13622
|
-
messages: messageSegmentStyler,
|
|
13623
|
-
memory: memorySegmentStyler,
|
|
13624
|
-
unused: unusedSegmentStyler,
|
|
13625
|
-
showBar: opts.showOMBar
|
|
13626
|
-
}) : null;
|
|
13627
|
-
if (opts.showQueue && goalLabel) parts.push({
|
|
13628
|
-
plain: goalLabel,
|
|
13629
|
-
styled: theme.fg("success", goalLabel)
|
|
13630
|
-
});
|
|
13631
|
-
if (opts.showQueue && queuedLabel) parts.push({
|
|
13632
|
-
plain: queuedLabel,
|
|
13633
|
-
styled: theme.fg("warning", queuedLabel)
|
|
13634
|
-
});
|
|
13635
|
-
const tpsLabel = state.tokensPerSec > 0 ? `${String(state.tokensPerSec).padStart(3)} t/s` : null;
|
|
13636
|
-
const tpsPart = tpsLabel ? {
|
|
13637
|
-
plain: tpsLabel,
|
|
13638
|
-
styled: theme.fg("text", tpsLabel)
|
|
13639
|
-
} : null;
|
|
13640
|
-
let dirText = opts.dir !== void 0 ? opts.dir : opts.showDir ? centerText : null;
|
|
13641
|
-
const rightParts = indicatorPart ? [tpsPart, indicatorPart].filter((part) => part !== null) : [];
|
|
13642
|
-
const nonDirWidth = useBadgeWidth + [...parts, ...rightParts].reduce((sum, p, i) => sum + visibleWidth(p.plain) + (i > 0 ? 2 : 0), 0);
|
|
13643
|
-
if (dirText !== null) {
|
|
13644
|
-
const dirPart = formatDirPart(dirText);
|
|
13645
|
-
const availableForDir = termWidth - nonDirWidth - 2 - 1;
|
|
13646
|
-
const dirWidth = visibleWidth(dirPart.plain);
|
|
13647
|
-
const availableForText = availableForDir - (githubPrLabel ? visibleWidth(githubPrLabel.plain) + (dirText ? 1 : 0) : 0);
|
|
13648
|
-
const MIN_TRUNCATED_DIR = 10;
|
|
13649
|
-
if (dirWidth > availableForDir && opts.allowDirTruncation === false) return null;
|
|
13650
|
-
if (dirWidth > availableForDir && availableForText >= MIN_TRUNCATED_DIR) dirText = availableForText > 1 ? dirText.slice(0, availableForText - 1) + "…" : null;
|
|
13651
|
-
else if (dirWidth > availableForDir) dirText = githubPrLabel && visibleWidth(githubPrLabel.plain) <= availableForDir ? "" : null;
|
|
13652
|
-
}
|
|
13653
|
-
if (dirText !== null) parts.push(formatDirPart(dirText));
|
|
13654
|
-
if (indicatorPart) parts.push(...rightParts);
|
|
13655
|
-
else if (tpsPart) parts.push(tpsPart);
|
|
13656
|
-
const totalPlain = useBadgeWidth + parts.reduce((sum, p, i) => sum + visibleWidth(p.plain) + (i > 0 ? 2 : 0), 0);
|
|
13657
|
-
if (totalPlain + 1 > termWidth) return null;
|
|
13658
|
-
let styledLine;
|
|
13659
|
-
const hasDir = dirText !== null;
|
|
13660
|
-
if (indicatorPart && parts.length >= 2) {
|
|
13661
|
-
const leftPartCount = 1 + (visibleFallbackLabel ? 1 : 0) + (opts.showQueue && goalLabel ? 1 : 0);
|
|
13662
|
-
const leftParts = parts.slice(0, leftPartCount);
|
|
13663
|
-
const centerParts = parts.slice(leftPartCount, -rightParts.length);
|
|
13664
|
-
const leftSeparatorPlain = timingLabel ? " · " : " ";
|
|
13665
|
-
const leftSeparatorStyled = timingLabel ? ` ${theme.fg("success", "·")} ` : " ";
|
|
13666
|
-
const leftWidth = useBadgeWidth + leftParts.reduce((sum, p, i) => sum + visibleWidth(p.plain) + (i > 0 ? leftSeparatorPlain.length : 0), 0);
|
|
13667
|
-
const centerWidth = centerParts.reduce((sum, p, i) => sum + visibleWidth(p.plain) + (i > 0 ? 2 : 0), 0);
|
|
13668
|
-
const rightWidth = rightParts.reduce((sum, p, i) => sum + visibleWidth(p.plain) + (i > 0 ? 2 : 0), 0);
|
|
13669
|
-
const totalContent = leftWidth + centerWidth + rightWidth;
|
|
13670
|
-
const freeSpace = termWidth - totalContent;
|
|
13671
|
-
const gapLeft = Math.floor(freeSpace / 2);
|
|
13672
|
-
const gapRight = freeSpace - gapLeft;
|
|
13673
|
-
styledLine = useBadge + leftParts.map((p) => p.styled).join(leftSeparatorStyled) + " ".repeat(Math.max(gapLeft, 1)) + centerParts.map((p) => p.styled).join(SEP) + " ".repeat(Math.max(gapRight, 1)) + rightParts.map((p) => p.styled).join(SEP);
|
|
13674
|
-
} else if (hasDir && parts.length === 2) {
|
|
13675
|
-
const mainStr = useBadge + parts[0].styled;
|
|
13676
|
-
const dirPart = parts[parts.length - 1];
|
|
13677
|
-
const gap = termWidth - totalPlain;
|
|
13678
|
-
styledLine = mainStr + " ".repeat(gap + 2) + dirPart.styled;
|
|
13679
|
-
} else styledLine = useBadge + parts.map((p) => p.styled).join(SEP);
|
|
13766
|
+
const fallbackPart = !isJudging && !showOMMode && state.fallbackStatus ? (() => {
|
|
13767
|
+
const label = `Using fallback ${state.fallbackStatus.usingPack} (${state.fallbackStatus.failedPack} failed)`;
|
|
13680
13768
|
return {
|
|
13681
|
-
plain:
|
|
13682
|
-
styled:
|
|
13769
|
+
plain: label,
|
|
13770
|
+
styled: theme.fg("warning", label)
|
|
13683
13771
|
};
|
|
13772
|
+
})() : null;
|
|
13773
|
+
const goalState = state.goalManager?.getGoal();
|
|
13774
|
+
const goalDuration = !isJudging && goalState?.status === "active" ? formatGoalDuration(goalState) : null;
|
|
13775
|
+
const goalMatchesActiveRun = goalState?.status === "active" && goalDuration !== null && state.agentRunStartedAt !== void 0 && Math.floor(getGoalDurationMs(goalState, now) / 6e4) === Math.floor((now - state.agentRunStartedAt) / 6e4);
|
|
13776
|
+
const goalLabel = goalDuration ? goalMatchesActiveRun ? "goal" : `goal ${goalDuration}` : null;
|
|
13777
|
+
const goalPart = goalLabel ? {
|
|
13778
|
+
plain: goalLabel,
|
|
13779
|
+
styled: theme.fg("success", goalLabel)
|
|
13780
|
+
} : null;
|
|
13781
|
+
const queuedCount = state.pendingSlashCommands.length + displayState.queuedFollowUps;
|
|
13782
|
+
const queuedPart = queuedCount > 0 ? {
|
|
13783
|
+
plain: `${queuedCount} queued`,
|
|
13784
|
+
styled: theme.fg("warning", `${queuedCount} queued`)
|
|
13785
|
+
} : null;
|
|
13786
|
+
const om = displayState.omProgress;
|
|
13787
|
+
const used = Math.max(0, om.pendingTokens) + Math.max(0, om.observationTokens);
|
|
13788
|
+
const capacity = Math.max(0, om.threshold) + Math.max(0, om.reflectionThreshold);
|
|
13789
|
+
const indicator = !isJudging ? formatOMContextIndicator(om, { showBar: false }) : null;
|
|
13790
|
+
const pct = capacity > 0 ? ` ${Math.round(used / capacity * 100)}%` : "";
|
|
13791
|
+
const sweep = (displayState.bufferingMessages || displayState.bufferingObservations) && state.gradientAnimator?.isRunning() ? state.gradientAnimator : void 0;
|
|
13792
|
+
const contextPart = indicator ? {
|
|
13793
|
+
plain: indicator.plain.trimEnd() + pct,
|
|
13794
|
+
styled: (sweep ? applyGradientSweep(indicator.plain.trimEnd(), sweep.getOffset(), displayState.bufferingMessages ? modeColor ?? theme.getTheme().accent : mastra.blue, sweep.getFadeProgress()) : indicator.styled.trimEnd()) + theme.fg("dim", pct)
|
|
13795
|
+
} : null;
|
|
13796
|
+
const branch = state.projectInfo.gitBranch;
|
|
13797
|
+
const threadTitle = state.currentThreadTitle && !isGenericTitle(state.currentThreadTitle) ? state.currentThreadTitle : null;
|
|
13798
|
+
const activeGithubPrSubscriptions = state.activeGithubPrSubscriptions ?? [];
|
|
13799
|
+
const githubPrLabel = activeGithubPrSubscriptions.length > 0 ? formatGithubPrLabel(state, activeGithubPrSubscriptions) : null;
|
|
13800
|
+
const locationPart = (maxWidth, fit) => {
|
|
13801
|
+
const prefix = githubPrLabel ? {
|
|
13802
|
+
plain: `${githubPrLabel.plain} `,
|
|
13803
|
+
styled: `${githubPrLabel.styled} `
|
|
13804
|
+
} : null;
|
|
13805
|
+
const room = maxWidth - (prefix ? visibleWidth(prefix.plain) : 0);
|
|
13806
|
+
const fits = (value) => visibleWidth(value) <= room;
|
|
13807
|
+
let text = null;
|
|
13808
|
+
if (threadTitle) {
|
|
13809
|
+
const title = fits(threadTitle) ? threadTitle : fit === "any" && room >= 10 ? truncateEnd(threadTitle, room) : null;
|
|
13810
|
+
if (title) text = {
|
|
13811
|
+
plain: title,
|
|
13812
|
+
styled: theme.fg("muted", title)
|
|
13813
|
+
};
|
|
13814
|
+
} else {
|
|
13815
|
+
const withBranch = (path) => ({
|
|
13816
|
+
plain: branch ? `${path} (${branch})` : path,
|
|
13817
|
+
styled: theme.fg("muted", path) + (branch ? theme.fg("dim", ` (${branch})`) : "")
|
|
13818
|
+
});
|
|
13819
|
+
const path = shortPath(state.projectInfo.rootPath ?? process.cwd());
|
|
13820
|
+
text = (fit === "full" ? [withBranch(path)] : compactPaths(path).map(withBranch)).find((candidate) => fits(candidate.plain)) ?? null;
|
|
13821
|
+
if (!text && fit === "any" && room >= 10) {
|
|
13822
|
+
const value = branch ? fits(branch) ? branch : truncateEnd(branch, room) : truncateLastSegment(compactPaths(path).at(-1), room);
|
|
13823
|
+
text = {
|
|
13824
|
+
plain: value,
|
|
13825
|
+
styled: theme.fg(branch ? "dim" : "muted", value)
|
|
13826
|
+
};
|
|
13827
|
+
}
|
|
13828
|
+
}
|
|
13829
|
+
if (!text) return prefix && visibleWidth(prefix.plain) - 1 <= maxWidth ? {
|
|
13830
|
+
plain: githubPrLabel.plain,
|
|
13831
|
+
styled: githubPrLabel.styled
|
|
13832
|
+
} : null;
|
|
13833
|
+
return prefix ? {
|
|
13834
|
+
plain: prefix.plain + text.plain,
|
|
13835
|
+
styled: prefix.styled + text.styled
|
|
13836
|
+
} : text;
|
|
13684
13837
|
};
|
|
13685
|
-
const
|
|
13686
|
-
|
|
13687
|
-
|
|
13688
|
-
|
|
13689
|
-
|
|
13690
|
-
|
|
13691
|
-
|
|
13692
|
-
|
|
13693
|
-
|
|
13694
|
-
|
|
13695
|
-
|
|
13696
|
-
|
|
13697
|
-
|
|
13698
|
-
|
|
13699
|
-
|
|
13700
|
-
|
|
13701
|
-
|
|
13702
|
-
|
|
13703
|
-
|
|
13704
|
-
|
|
13705
|
-
|
|
13706
|
-
|
|
13707
|
-
|
|
13708
|
-
|
|
13709
|
-
|
|
13710
|
-
|
|
13711
|
-
|
|
13712
|
-
|
|
13713
|
-
|
|
13714
|
-
|
|
13715
|
-
|
|
13716
|
-
|
|
13717
|
-
|
|
13718
|
-
|
|
13719
|
-
|
|
13720
|
-
|
|
13721
|
-
|
|
13722
|
-
|
|
13723
|
-
|
|
13724
|
-
|
|
13725
|
-
|
|
13726
|
-
|
|
13727
|
-
|
|
13728
|
-
|
|
13729
|
-
|
|
13730
|
-
|
|
13731
|
-
|
|
13732
|
-
|
|
13733
|
-
|
|
13734
|
-
|
|
13735
|
-
|
|
13736
|
-
|
|
13737
|
-
|
|
13738
|
-
|
|
13739
|
-
|
|
13740
|
-
|
|
13741
|
-
|
|
13742
|
-
|
|
13743
|
-
|
|
13744
|
-
|
|
13745
|
-
|
|
13746
|
-
|
|
13747
|
-
|
|
13748
|
-
|
|
13749
|
-
|
|
13750
|
-
|
|
13751
|
-
|
|
13752
|
-
|
|
13753
|
-
state
|
|
13754
|
-
if (state.memoryStatusLine) state.memoryStatusLine.setText("");
|
|
13838
|
+
const width = (parts) => PAD + parts.reduce((sum, p, i) => sum + visibleWidth(p.plain) + (i > 0 ? SEP_WIDTH : 0), 0) + 1;
|
|
13839
|
+
const fitsRow = (parts) => {
|
|
13840
|
+
const present = parts.filter((p) => p !== null);
|
|
13841
|
+
return width(present) <= termWidth ? present : null;
|
|
13842
|
+
};
|
|
13843
|
+
const withLocation = (parts, fit) => {
|
|
13844
|
+
const present = parts.filter((p) => p !== null);
|
|
13845
|
+
const location = locationPart(termWidth - width(present) - SEP_WIDTH, fit);
|
|
13846
|
+
return location ? fitsRow([...present, location]) : null;
|
|
13847
|
+
};
|
|
13848
|
+
const transient = [
|
|
13849
|
+
fallbackPart,
|
|
13850
|
+
goalPart,
|
|
13851
|
+
queuedPart
|
|
13852
|
+
];
|
|
13853
|
+
const oneRow = twoRowFooterWidth.get(state) === termWidth ? null : withLocation([
|
|
13854
|
+
modePart,
|
|
13855
|
+
modelPart(fullModelId),
|
|
13856
|
+
...transient,
|
|
13857
|
+
contextPart
|
|
13858
|
+
], "full") ?? withLocation([
|
|
13859
|
+
modePart,
|
|
13860
|
+
modelPart(shortModelId),
|
|
13861
|
+
...transient,
|
|
13862
|
+
contextPart
|
|
13863
|
+
], "full") ?? withLocation([
|
|
13864
|
+
modePart,
|
|
13865
|
+
modelPart(fullModelId),
|
|
13866
|
+
...transient,
|
|
13867
|
+
contextPart
|
|
13868
|
+
], "compact") ?? withLocation([
|
|
13869
|
+
modePart,
|
|
13870
|
+
modelPart(shortModelId),
|
|
13871
|
+
...transient,
|
|
13872
|
+
contextPart
|
|
13873
|
+
], "compact");
|
|
13874
|
+
const row = oneRow ?? fitsRow([
|
|
13875
|
+
modePart,
|
|
13876
|
+
modelPart(fullModelId),
|
|
13877
|
+
...transient,
|
|
13878
|
+
contextPart
|
|
13879
|
+
]) ?? fitsRow([
|
|
13880
|
+
modePart,
|
|
13881
|
+
modelPart(shortModelId),
|
|
13882
|
+
...transient,
|
|
13883
|
+
contextPart
|
|
13884
|
+
]) ?? fitsRow([
|
|
13885
|
+
modePart,
|
|
13886
|
+
modelPart(tinyModelId),
|
|
13887
|
+
...transient,
|
|
13888
|
+
contextPart
|
|
13889
|
+
]) ?? fitsRow([
|
|
13890
|
+
modePart,
|
|
13891
|
+
modelPart(tinyModelId),
|
|
13892
|
+
goalPart,
|
|
13893
|
+
queuedPart,
|
|
13894
|
+
contextPart
|
|
13895
|
+
]) ?? fitsRow([
|
|
13896
|
+
modePart,
|
|
13897
|
+
modelPart(tinyModelId),
|
|
13898
|
+
goalPart,
|
|
13899
|
+
queuedPart
|
|
13900
|
+
]) ?? fitsRow([modePart, modelPart(tinyModelId)]) ?? fitsRow([modeInitial, modelPart(tinyModelId)]) ?? fitsRow([modePart]) ?? [];
|
|
13901
|
+
const secondRow = oneRow ? null : locationPart(termWidth - PAD - 1, "any");
|
|
13902
|
+
if (secondRow) twoRowFooterWidth.set(state, termWidth);
|
|
13903
|
+
else twoRowFooterWidth.delete(state);
|
|
13904
|
+
state.statusLine.setText(" ".repeat(PAD) + row.map((p) => p.styled).join(SEP));
|
|
13905
|
+
if (state.memoryStatusLine) state.memoryStatusLine.setText(secondRow ? " ".repeat(PAD) + secondRow.styled : "");
|
|
13906
|
+
updateActivityLine(state, modeColor, now);
|
|
13755
13907
|
state.ui.requestRender();
|
|
13756
13908
|
}
|
|
13909
|
+
/**
|
|
13910
|
+
* Working row above the prompt while the agent runs: spinner, elapsed time, throughput, interrupt hint.
|
|
13911
|
+
* Empty (renders nothing) when idle.
|
|
13912
|
+
*/
|
|
13913
|
+
function updateActivityLine(state, modeColor, now) {
|
|
13914
|
+
if (!state.idleCounter) return;
|
|
13915
|
+
if (state.agentRunStartedAt === void 0) {
|
|
13916
|
+
state.idleCounter.setActivity("");
|
|
13917
|
+
return;
|
|
13918
|
+
}
|
|
13919
|
+
const spinner = pulseDot(modeColor ?? theme.getTheme().accent, now);
|
|
13920
|
+
const elapsed = formatStatusDuration(now - state.agentRunStartedAt, { includeSeconds: true });
|
|
13921
|
+
const stale = state.agentRunLastStreamPartAt !== void 0 && now - state.agentRunLastStreamPartAt > 3 * 6e4 ? formatStatusDuration(now - state.agentRunLastStreamPartAt, { includeSeconds: false }) : null;
|
|
13922
|
+
const parts = [theme.fg(stale ? "error" : "dim", elapsed)];
|
|
13923
|
+
if (stale) parts.push(theme.fg("warning", `no output for ${stale}`));
|
|
13924
|
+
if (state.tokensPerSec > 0) parts.push(theme.fg("dim", `${state.tokensPerSec} tok/s`));
|
|
13925
|
+
parts.push(`${theme.fg("muted", "esc")}${theme.fg("dim", " to interrupt")}`);
|
|
13926
|
+
const label = state.idleCounter.isThinking() ? "thinking" : "working ";
|
|
13927
|
+
state.idleCounter.setActivity(` ${spinner} ${theme.bold(theme.fg("secondary", label))} ${parts.join(theme.fg("dim", " · "))}`);
|
|
13928
|
+
}
|
|
13757
13929
|
//#endregion
|
|
13758
13930
|
//#region src/tui/commands/models-pack.ts
|
|
13759
13931
|
const SHARE_PREFIX = "mastra-pack:";
|
|
@@ -21558,47 +21730,22 @@ function handleAgentEnd(ctx) {
|
|
|
21558
21730
|
}
|
|
21559
21731
|
function drainQueuedAction(ctx) {
|
|
21560
21732
|
const { state } = ctx;
|
|
21561
|
-
if (state.session.displayState.get().queuedFollowUps > 0) return
|
|
21562
|
-
const nextAction = state.pendingQueuedActions.shift();
|
|
21563
|
-
ctx.updateStatusLine();
|
|
21564
|
-
if (!nextAction) return false;
|
|
21565
|
-
if (nextAction === "message") {
|
|
21566
|
-
const nextMessage = state.pendingFollowUpMessages.shift();
|
|
21567
|
-
if (!nextMessage) return true;
|
|
21568
|
-
ctx.addUserMessage({
|
|
21569
|
-
id: `user-${Date.now()}`,
|
|
21570
|
-
role: "user",
|
|
21571
|
-
content: {
|
|
21572
|
-
format: 2,
|
|
21573
|
-
parts: [{
|
|
21574
|
-
type: "text",
|
|
21575
|
-
text: nextMessage.content
|
|
21576
|
-
}, ...nextMessage.images?.map((img) => ({
|
|
21577
|
-
type: "file",
|
|
21578
|
-
data: img.data,
|
|
21579
|
-
mimeType: img.mimeType
|
|
21580
|
-
})) ?? []]
|
|
21581
|
-
},
|
|
21582
|
-
createdAt: /* @__PURE__ */ new Date()
|
|
21583
|
-
});
|
|
21584
|
-
const key = nextMessage.content.trim();
|
|
21585
|
-
const counts = state.firedQueuedMessageTexts ??= /* @__PURE__ */ new Map();
|
|
21586
|
-
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
21587
|
-
flushRender(state);
|
|
21588
|
-
ctx.fireMessage(nextMessage.content, nextMessage.images);
|
|
21589
|
-
return true;
|
|
21590
|
-
}
|
|
21733
|
+
if (state.session.displayState.get().queuedFollowUps > 0 || state.pendingQueueSubmissions > 0) return;
|
|
21591
21734
|
const nextCommand = state.pendingSlashCommands.shift();
|
|
21592
21735
|
const pendingMessageId = state.pendingSlashCommandMessageIds.shift();
|
|
21736
|
+
ctx.updateStatusLine();
|
|
21593
21737
|
if (!nextCommand) {
|
|
21594
21738
|
if (pendingMessageId) removePendingUserMessage(state, pendingMessageId);
|
|
21595
|
-
return
|
|
21739
|
+
return;
|
|
21596
21740
|
}
|
|
21597
21741
|
if (pendingMessageId) removePendingUserMessage(state, pendingMessageId);
|
|
21598
21742
|
ctx.handleSlashCommand(nextCommand).catch((error) => {
|
|
21599
21743
|
ctx.showError(error instanceof Error ? error.message : "Queued slash command failed");
|
|
21600
21744
|
});
|
|
21601
|
-
|
|
21745
|
+
}
|
|
21746
|
+
function drainQueuedActionIfIdle(ctx) {
|
|
21747
|
+
if (ctx.state.session.stream.isActive()) return;
|
|
21748
|
+
drainQueuedAction(ctx);
|
|
21602
21749
|
}
|
|
21603
21750
|
function handleAgentAborted(ctx) {
|
|
21604
21751
|
const { state } = ctx;
|
|
@@ -21624,11 +21771,7 @@ function handleAgentAborted(ctx) {
|
|
|
21624
21771
|
state.activeGoalJudge = void 0;
|
|
21625
21772
|
}
|
|
21626
21773
|
state.followUpComponents = [];
|
|
21627
|
-
state.
|
|
21628
|
-
state.pendingQueuedActions = [];
|
|
21629
|
-
state.pendingSlashCommands = [];
|
|
21630
|
-
state.pendingSlashCommandMessageIds = [];
|
|
21631
|
-
clearPendingUserMessages(state);
|
|
21774
|
+
clearPendingUserMessages(state, state.pendingSlashCommandMessageIds);
|
|
21632
21775
|
for (const tool of state.pendingTools.values()) tool.stopLiveUpdates?.();
|
|
21633
21776
|
state.idleCounter?.setThinking(false);
|
|
21634
21777
|
state.pendingTools.clear();
|
|
@@ -21636,6 +21779,7 @@ function handleAgentAborted(ctx) {
|
|
|
21636
21779
|
pruneChatContainer(state);
|
|
21637
21780
|
ctx.updateStatusLine();
|
|
21638
21781
|
flushRender(state);
|
|
21782
|
+
drainQueuedActionIfIdle(ctx);
|
|
21639
21783
|
}
|
|
21640
21784
|
function handleAgentError(ctx) {
|
|
21641
21785
|
const { state } = ctx;
|
|
@@ -21646,11 +21790,7 @@ function handleAgentError(ctx) {
|
|
|
21646
21790
|
state.activeGoalJudge = void 0;
|
|
21647
21791
|
}
|
|
21648
21792
|
state.followUpComponents = [];
|
|
21649
|
-
state.
|
|
21650
|
-
state.pendingQueuedActions = [];
|
|
21651
|
-
state.pendingSlashCommands = [];
|
|
21652
|
-
state.pendingSlashCommandMessageIds = [];
|
|
21653
|
-
clearPendingUserMessages(state);
|
|
21793
|
+
clearPendingUserMessages(state, state.pendingSlashCommandMessageIds);
|
|
21654
21794
|
for (const tool of state.pendingTools.values()) tool.stopLiveUpdates?.();
|
|
21655
21795
|
state.idleCounter?.setThinking(false);
|
|
21656
21796
|
state.pendingTools.clear();
|
|
@@ -21658,6 +21798,7 @@ function handleAgentError(ctx) {
|
|
|
21658
21798
|
pruneChatContainer(state);
|
|
21659
21799
|
ctx.updateStatusLine();
|
|
21660
21800
|
flushRender(state);
|
|
21801
|
+
drainQueuedActionIfIdle(ctx);
|
|
21661
21802
|
}
|
|
21662
21803
|
/** Remove the judge display component from the chat container if present. */
|
|
21663
21804
|
function removeJudgeComponent(state, component) {
|
|
@@ -21735,7 +21876,9 @@ function syncQuietThinkingStatus(ctx, message) {
|
|
|
21735
21876
|
const { state } = ctx;
|
|
21736
21877
|
const latest = message ? getRawParts(message).findLast((part) => part.type === "text" || part.type === "reasoning" || part.type === "tool-invocation") : void 0;
|
|
21737
21878
|
const thinking = state.quietMode && state.hideThinkingBlock && latest?.type === "reasoning";
|
|
21738
|
-
state.idleCounter
|
|
21879
|
+
if (!state.idleCounter || state.idleCounter.isThinking() === thinking) return;
|
|
21880
|
+
state.idleCounter.setThinking(thinking);
|
|
21881
|
+
ctx.updateStatusLine();
|
|
21739
21882
|
}
|
|
21740
21883
|
function isToolPart(part) {
|
|
21741
21884
|
return part.type === "tool-invocation";
|
|
@@ -22855,44 +22998,12 @@ const VOICE_WAVE_BARS = [
|
|
|
22855
22998
|
"▇",
|
|
22856
22999
|
"█"
|
|
22857
23000
|
];
|
|
22858
|
-
const DEFAULT_PROMPT_ICON = "•";
|
|
22859
|
-
const PROMPT_ICON_CHOICES = [
|
|
22860
|
-
"☯",
|
|
22861
|
-
"✺",
|
|
22862
|
-
"☻",
|
|
22863
|
-
"✿",
|
|
22864
|
-
"◒",
|
|
22865
|
-
"◓",
|
|
22866
|
-
"♞",
|
|
22867
|
-
"☘",
|
|
22868
|
-
"☸",
|
|
22869
|
-
"❂",
|
|
22870
|
-
"❁",
|
|
22871
|
-
"✽",
|
|
22872
|
-
"❉",
|
|
22873
|
-
"✹",
|
|
22874
|
-
"❨",
|
|
22875
|
-
"❩",
|
|
22876
|
-
"✚",
|
|
22877
|
-
"⚉",
|
|
22878
|
-
"❣",
|
|
22879
|
-
"❥",
|
|
22880
|
-
"♫",
|
|
22881
|
-
"❤"
|
|
22882
|
-
];
|
|
22883
|
-
function getRandomPromptIcon(currentIcon) {
|
|
22884
|
-
if (Math.random() < .99) return DEFAULT_PROMPT_ICON;
|
|
22885
|
-
const nextChoices = PROMPT_ICON_CHOICES.filter((icon) => icon !== currentIcon);
|
|
22886
|
-
const choices = nextChoices.length > 0 ? nextChoices : PROMPT_ICON_CHOICES;
|
|
22887
|
-
return choices[Math.floor(Math.random() * choices.length)];
|
|
22888
|
-
}
|
|
22889
23001
|
var CustomEditor = class extends Editor {
|
|
22890
23002
|
actionHandlers = /* @__PURE__ */ new Map();
|
|
22891
23003
|
onCtrlD;
|
|
22892
23004
|
escapeEnabled = true;
|
|
22893
23005
|
onImagePaste;
|
|
22894
23006
|
getModeColor;
|
|
22895
|
-
getPromptAnimator;
|
|
22896
23007
|
requestRender;
|
|
22897
23008
|
pendingBracketedPaste = null;
|
|
22898
23009
|
/**
|
|
@@ -22914,8 +23025,6 @@ var CustomEditor = class extends Editor {
|
|
|
22914
23025
|
voiceDictationActive = false;
|
|
22915
23026
|
_cachedModeColorHex;
|
|
22916
23027
|
_cachedColorFn;
|
|
22917
|
-
promptIcon = DEFAULT_PROMPT_ICON;
|
|
22918
|
-
lastPromptWasInvisible = false;
|
|
22919
23028
|
requestEditorRender() {
|
|
22920
23029
|
if (this.requestRender) {
|
|
22921
23030
|
this.requestRender();
|
|
@@ -22953,27 +23062,8 @@ var CustomEditor = class extends Editor {
|
|
|
22953
23062
|
const isSlash = text.startsWith("/");
|
|
22954
23063
|
const isAt = text.startsWith("@");
|
|
22955
23064
|
const isBang = text.startsWith("!");
|
|
22956
|
-
const color = this.getModeColor?.() || mastra.green;
|
|
22957
|
-
const
|
|
22958
|
-
const isPromptAnimated = !isSlash && !isAt && !isBang && Boolean(promptAnimator?.isRunning());
|
|
22959
|
-
const fadeProgress = isPromptAnimated ? promptAnimator.getFadeProgress() : 1;
|
|
22960
|
-
const isTransitioningIn = isPromptAnimated && promptAnimator.isFadingIn();
|
|
22961
|
-
const isTransitioningOut = isPromptAnimated && promptAnimator.isFadingOut();
|
|
22962
|
-
const promptOffset = isPromptAnimated ? promptAnimator.getOffset() : 0;
|
|
22963
|
-
const pulseWave = isPromptAnimated ? (Math.sin(promptOffset * Math.PI * 2) + 1) / 2 : 0;
|
|
22964
|
-
const transitionPhase = isTransitioningIn || isTransitioningOut ? 1 - fadeProgress : 1;
|
|
22965
|
-
const chevronBrightness = isPromptAnimated ? isTransitioningIn ? transitionPhase < .5 ? Math.max(0, 1 - transitionPhase * 2) : 0 : isTransitioningOut ? transitionPhase <= .5 ? Math.max(0, 1 - transitionPhase * 2) : 0 : 0 : 1;
|
|
22966
|
-
const dotBrightness = isPromptAnimated ? isTransitioningIn ? transitionPhase <= .5 ? 0 : Math.max(0, (transitionPhase - .5) * 2) : isTransitioningOut ? transitionPhase < .5 ? 0 : Math.max(0, (transitionPhase - .5) * 2) : pulseWave : 0;
|
|
22967
|
-
const isSteadyPulse = isPromptAnimated && !isTransitioningIn && !isTransitioningOut;
|
|
22968
|
-
if (!isPromptAnimated) {
|
|
22969
|
-
this.promptIcon = DEFAULT_PROMPT_ICON;
|
|
22970
|
-
this.lastPromptWasInvisible = false;
|
|
22971
|
-
} else if (!isSteadyPulse) this.lastPromptWasInvisible = false;
|
|
22972
|
-
const promptIsInvisible = isSteadyPulse && dotBrightness <= .05;
|
|
22973
|
-
if (promptIsInvisible && !this.lastPromptWasInvisible) this.promptIcon = getRandomPromptIcon(this.promptIcon);
|
|
22974
|
-
this.lastPromptWasInvisible = promptIsInvisible;
|
|
22975
|
-
const promptChar = isSlash ? "/" : isAt ? "@" : isBang ? "!" : chevronBrightness > .05 ? "›" : dotBrightness > .05 ? this.promptIcon : " ";
|
|
22976
|
-
const promptBrightness = isPromptAnimated ? Math.max(chevronBrightness, dotBrightness) : 1;
|
|
23065
|
+
const color = displayModeColor(this.getModeColor?.() || mastra.green);
|
|
23066
|
+
const promptChar = isSlash ? "/" : isAt ? "@" : isBang ? "!" : "→";
|
|
22977
23067
|
if (this._cachedModeColorHex !== color) {
|
|
22978
23068
|
this._cachedModeColorHex = color;
|
|
22979
23069
|
this._cachedColorFn = chalk.hex(color);
|
|
@@ -22986,9 +23076,9 @@ var CustomEditor = class extends Editor {
|
|
|
22986
23076
|
const bar = VOICE_WAVE_BARS[Math.round(wave * (VOICE_WAVE_BARS.length - 1))];
|
|
22987
23077
|
const brightness = .5 + wave * .5;
|
|
22988
23078
|
prompt = chalk.bold.rgb(Math.round(r * brightness), Math.round(g * brightness), Math.round(bValue * brightness))(bar);
|
|
22989
|
-
} else prompt = chalk.bold.rgb(
|
|
22990
|
-
const promptWidth =
|
|
22991
|
-
const contentWidth = width -
|
|
23079
|
+
} else prompt = chalk.bold.rgb(r, g, bValue)(promptChar);
|
|
23080
|
+
const promptWidth = 3;
|
|
23081
|
+
const contentWidth = width - 4;
|
|
22992
23082
|
const editorState = this.state;
|
|
22993
23083
|
const decorativePrompt = isSlash ? "/" : isAt ? "@" : isBang ? "!" : void 0;
|
|
22994
23084
|
const firstLine = editorState.lines[0];
|
|
@@ -23030,14 +23120,8 @@ var CustomEditor = class extends Editor {
|
|
|
23030
23120
|
contentLines.push(line);
|
|
23031
23121
|
}
|
|
23032
23122
|
const result = [];
|
|
23033
|
-
const hBarLen = width - 2;
|
|
23034
|
-
const top = b("╭") + b("─").repeat(hBarLen) + b("╮");
|
|
23035
|
-
const leftBorder = b("│");
|
|
23036
|
-
const rightBorder = b("│");
|
|
23037
|
-
const bottom = b("╰") + b("─").repeat(hBarLen) + b("╯");
|
|
23038
23123
|
const textColorOpen = `\x1b[38;2;${parseHex(theme.getTheme().text).join(";")}m`;
|
|
23039
23124
|
const textColorClose = "\x1B[39m";
|
|
23040
|
-
result.push(top);
|
|
23041
23125
|
const fullText = this.getText();
|
|
23042
23126
|
let greyRemaining = this.voiceTranscriptText.length > 0 && fullText.endsWith(this.voiceTranscriptText) ? [...this.voiceTranscriptText].length : 0;
|
|
23043
23127
|
const greyOpen = `\x1b[38;2;${parseHex(theme.getTheme().muted).join(";")}m`;
|
|
@@ -23046,12 +23130,11 @@ var CustomEditor = class extends Editor {
|
|
|
23046
23130
|
contentLines[i] = line;
|
|
23047
23131
|
greyRemaining -= consumed;
|
|
23048
23132
|
}
|
|
23049
|
-
|
|
23050
|
-
const line = `${textColorOpen}${
|
|
23051
|
-
|
|
23052
|
-
|
|
23053
|
-
|
|
23054
|
-
result.push(bottom);
|
|
23133
|
+
const rows = contentLines.map((content, i) => {
|
|
23134
|
+
const line = `${textColorOpen}${content}${textColorClose}`;
|
|
23135
|
+
return i === 0 ? ` ${prompt} ${line}` : `${" ".repeat(promptWidth)}${line}`;
|
|
23136
|
+
});
|
|
23137
|
+
result.push(...fadePanel(rows, width, 1.5));
|
|
23055
23138
|
for (const ind of scrollIndicators) result.push(ind);
|
|
23056
23139
|
return result;
|
|
23057
23140
|
}
|
|
@@ -24881,12 +24964,11 @@ function createTUIState(options) {
|
|
|
24881
24964
|
pendingAskUserComponents: /* @__PURE__ */ new Map(),
|
|
24882
24965
|
pendingSubmitPlanComponents: /* @__PURE__ */ new Map(),
|
|
24883
24966
|
pendingInlineQuestions: [],
|
|
24884
|
-
pendingFollowUpMessages: [],
|
|
24885
|
-
pendingQueuedActions: [],
|
|
24886
24967
|
followUpComponents: [],
|
|
24887
24968
|
pendingSignalMessageComponentsById: /* @__PURE__ */ new Map(),
|
|
24888
24969
|
pendingSlashCommands: [],
|
|
24889
24970
|
pendingSlashCommandMessageIds: [],
|
|
24971
|
+
pendingQueueSubmissions: 0,
|
|
24890
24972
|
pendingApprovalDismiss: null,
|
|
24891
24973
|
projectInfo: detectProject(process.cwd()),
|
|
24892
24974
|
modelAuthStatus: { hasAuth: true },
|
|
@@ -25386,6 +25468,77 @@ async function dispatchEvent(event, ectx, state) {
|
|
|
25386
25468
|
}
|
|
25387
25469
|
}
|
|
25388
25470
|
//#endregion
|
|
25471
|
+
//#region src/tui/components/banner.ts
|
|
25472
|
+
/** 16 columns × 5 rows: the header logo. */
|
|
25473
|
+
const LOGO_HEADER = [
|
|
25474
|
+
" ⣠⣶⣶⣄ ⣠⣶⣶⣄",
|
|
25475
|
+
" ⢻⣿⣿⣿ ⣿⣿⣿⡟",
|
|
25476
|
+
" ⢀⣀ ⠈⠻⣿⣄⣠⣿⠟⢻⣷⣀⡀",
|
|
25477
|
+
"⢰⣿⣿⣿⡄ ⣿⣿⣿⣿ ⢸⣿⣿⣿⡆",
|
|
25478
|
+
"⠈⠻⠿⠟⠁ ⠙⠿⠿⠋ ⠈⠻⠿⠟⠁"
|
|
25479
|
+
];
|
|
25480
|
+
/** 24 columns × 7 rows: setup screens. */
|
|
25481
|
+
const LOGO_LARGE = [
|
|
25482
|
+
" ⣴⣾⣿⣷⣦⡀ ⢀⣴⣾⣿⣷⣦",
|
|
25483
|
+
" ⢸⣿⣿⣿⣿⣿⡇ ⢸⣿⣿⣿⣿⣿⡇",
|
|
25484
|
+
" ⠻⢿⣿⣿⣿⡇ ⢸⣿⣿⣿⣿⣿",
|
|
25485
|
+
" ⠈⢻⣿⣷⡀⢀⣾⣿⡟⠙⢿⣿⣆",
|
|
25486
|
+
" ⣴⣾⣿⣿⣶⡀ ⣿⣿⣿⣿⣿⣿ ⢸⣿⣿⣿⣷⣦",
|
|
25487
|
+
"⠸⣿⣿⣿⣿⣿⡇ ⣿⣿⣿⣿⣿⣿ ⢸⣿⣿⣿⣿⣿⠇",
|
|
25488
|
+
" ⠹⢿⣿⡿⠟⠁ ⠘⠿⣿⣿⠿⠃ ⠈⠻⢿⣿⡿⠏"
|
|
25489
|
+
];
|
|
25490
|
+
/** Logo rows in the accent color, padded to a common width. */
|
|
25491
|
+
function renderLogo(rows = LOGO_HEADER) {
|
|
25492
|
+
const w = Math.max(...rows.map((r) => visibleWidth(r)));
|
|
25493
|
+
return rows.map((r) => theme.fg("accent", r) + " ".repeat(w - visibleWidth(r)));
|
|
25494
|
+
}
|
|
25495
|
+
const LOGO_GAP = 3;
|
|
25496
|
+
/**
|
|
25497
|
+
* Header lines for a given width:
|
|
25498
|
+
* - wide: logo, then title + info beside it (the info block is padded to the logo's 5 rows)
|
|
25499
|
+
* - narrow: logo stacked above title + info
|
|
25500
|
+
* - very narrow or a custom app name: one text line
|
|
25501
|
+
*/
|
|
25502
|
+
function renderHeader(width, { version, appName, info }) {
|
|
25503
|
+
const name = appName || "Mastra Code";
|
|
25504
|
+
const compact = theme.fg("accent", "◆") + " " + theme.bold(theme.fg("accent", name)) + theme.fg("dim", ` v${version}`);
|
|
25505
|
+
if (name !== "Mastra Code" || width < 30) return [compact];
|
|
25506
|
+
const title = theme.bold(theme.fg("text", name)) + theme.fg("dim", ` v${version}`);
|
|
25507
|
+
const fit = (room) => info.map((l) => theme.fg("muted", visibleWidth(l) <= room ? l : [...l].slice(0, Math.max(0, room - 1)).join("") + "…"));
|
|
25508
|
+
const logo = renderLogo();
|
|
25509
|
+
const room = width - visibleWidth(logo[0]) - LOGO_GAP;
|
|
25510
|
+
if (visibleWidth(title) <= room) {
|
|
25511
|
+
const infoLines = fit(room);
|
|
25512
|
+
const block = infoLines.length + 1 < logo.length ? [
|
|
25513
|
+
title,
|
|
25514
|
+
"",
|
|
25515
|
+
...infoLines
|
|
25516
|
+
] : [title, ...infoLines];
|
|
25517
|
+
const top = Math.floor((logo.length - block.length) / 2);
|
|
25518
|
+
return logo.map((row, i) => row + " ".repeat(LOGO_GAP) + (block[i - top] ?? ""));
|
|
25519
|
+
}
|
|
25520
|
+
return [
|
|
25521
|
+
...logo,
|
|
25522
|
+
"",
|
|
25523
|
+
title,
|
|
25524
|
+
...fit(width)
|
|
25525
|
+
];
|
|
25526
|
+
}
|
|
25527
|
+
/** Startup header component; re-lays out on resize. */
|
|
25528
|
+
var HeaderComponent = class {
|
|
25529
|
+
options;
|
|
25530
|
+
paddingX;
|
|
25531
|
+
constructor(options, paddingX = 1) {
|
|
25532
|
+
this.options = options;
|
|
25533
|
+
this.paddingX = paddingX;
|
|
25534
|
+
}
|
|
25535
|
+
invalidate() {}
|
|
25536
|
+
render(width) {
|
|
25537
|
+
const pad = " ".repeat(this.paddingX);
|
|
25538
|
+
return renderHeader(width - this.paddingX * 2, this.options).map((l) => pad + l);
|
|
25539
|
+
}
|
|
25540
|
+
};
|
|
25541
|
+
//#endregion
|
|
25389
25542
|
//#region src/tui/onboarding-inline.ts
|
|
25390
25543
|
/**
|
|
25391
25544
|
* Setup onboarding component.
|
|
@@ -25400,6 +25553,25 @@ async function dispatchEvent(event, ectx, state) {
|
|
|
25400
25553
|
* The component renders as a settings overlay. On completion it fires
|
|
25401
25554
|
* `onComplete` with the collected choices.
|
|
25402
25555
|
*/
|
|
25556
|
+
const STEP_LABELS = [
|
|
25557
|
+
"Welcome",
|
|
25558
|
+
"Sign in",
|
|
25559
|
+
"Models",
|
|
25560
|
+
"Memory",
|
|
25561
|
+
"Approval"
|
|
25562
|
+
];
|
|
25563
|
+
const STEP_INDEX = {
|
|
25564
|
+
welcome: 0,
|
|
25565
|
+
auth: 1,
|
|
25566
|
+
modePack: 2,
|
|
25567
|
+
omPack: 3,
|
|
25568
|
+
yolo: 4,
|
|
25569
|
+
done: 5
|
|
25570
|
+
};
|
|
25571
|
+
/** "✓ Welcome ● Sign in ○ Models …": done steps checked, the current one bold. */
|
|
25572
|
+
function renderStepper(current) {
|
|
25573
|
+
return STEP_LABELS.map((label, i) => i < current ? `${theme.fg("success", "✓")} ${theme.fg("muted", label)}` : i === current ? `${theme.fg("accent", "●")} ${theme.bold(theme.fg("text", label))}` : theme.fg("dim", `○ ${label}`)).join(" ");
|
|
25574
|
+
}
|
|
25403
25575
|
var OnboardingInlineComponent = class extends Box {
|
|
25404
25576
|
tui;
|
|
25405
25577
|
options;
|
|
@@ -25421,7 +25593,7 @@ var OnboardingInlineComponent = class extends Box {
|
|
|
25421
25593
|
this._focused = value;
|
|
25422
25594
|
}
|
|
25423
25595
|
constructor(options) {
|
|
25424
|
-
super(4, 2, (text) =>
|
|
25596
|
+
super(4, 2, (text) => text);
|
|
25425
25597
|
this.tui = options.tui;
|
|
25426
25598
|
this.options = options;
|
|
25427
25599
|
const prevModePack = options.previous?.modePackId ? options.modePacks.find((p) => p.id === options.previous.modePackId) : void 0;
|
|
@@ -25437,6 +25609,60 @@ var OnboardingInlineComponent = class extends Box {
|
|
|
25437
25609
|
if (options.previous?.yolo != null) this.selectedYolo = options.previous.yolo;
|
|
25438
25610
|
this.renderStep("welcome");
|
|
25439
25611
|
}
|
|
25612
|
+
/**
|
|
25613
|
+
* Full-screen setup: the large logo, a step indicator and the current step, centered. Earlier steps
|
|
25614
|
+
* are not repeated (the indicator shows progress). On short terminals the gaps tighten, then the logo
|
|
25615
|
+
* shrinks, then it is dropped, so the step itself is never cut off.
|
|
25616
|
+
*/
|
|
25617
|
+
render(width) {
|
|
25618
|
+
const rows = this.tui.terminal?.rows ?? 40;
|
|
25619
|
+
const contentWidth = Math.max(20, Math.min(width - 8, 80));
|
|
25620
|
+
const body = (this.stepBox ? this.stepBox.render(contentWidth) : []).map((line) => line.replace(/\s+$/, ""));
|
|
25621
|
+
while (body.length && body[0] === "") body.shift();
|
|
25622
|
+
while (body.length && body.at(-1) === "") body.pop();
|
|
25623
|
+
const center = (lines) => {
|
|
25624
|
+
const blockWidth = Math.max(0, ...lines.map((line) => visibleWidth(line)));
|
|
25625
|
+
const pad = " ".repeat(Math.max(0, Math.floor((width - blockWidth) / 2)));
|
|
25626
|
+
return lines.map((line) => line ? pad + line : "");
|
|
25627
|
+
};
|
|
25628
|
+
const stepper = center([renderStepper(STEP_INDEX[this.currentStep])]);
|
|
25629
|
+
const layouts = [
|
|
25630
|
+
[
|
|
25631
|
+
...center(renderLogo(LOGO_LARGE)),
|
|
25632
|
+
"",
|
|
25633
|
+
"",
|
|
25634
|
+
...stepper,
|
|
25635
|
+
"",
|
|
25636
|
+
"",
|
|
25637
|
+
...center(body)
|
|
25638
|
+
],
|
|
25639
|
+
[
|
|
25640
|
+
...center(renderLogo(LOGO_LARGE)),
|
|
25641
|
+
"",
|
|
25642
|
+
...stepper,
|
|
25643
|
+
"",
|
|
25644
|
+
...center(body)
|
|
25645
|
+
],
|
|
25646
|
+
[
|
|
25647
|
+
...center(renderLogo(LOGO_HEADER)),
|
|
25648
|
+
"",
|
|
25649
|
+
...stepper,
|
|
25650
|
+
"",
|
|
25651
|
+
...center(body)
|
|
25652
|
+
],
|
|
25653
|
+
[
|
|
25654
|
+
...stepper,
|
|
25655
|
+
"",
|
|
25656
|
+
...center(body)
|
|
25657
|
+
],
|
|
25658
|
+
center(body)
|
|
25659
|
+
];
|
|
25660
|
+
const content = layouts.find((layout) => layout.length <= rows) ?? layouts.at(-1);
|
|
25661
|
+
const top = Math.max(0, Math.floor((rows - content.length) / 2));
|
|
25662
|
+
const screen = [...Array.from({ length: top }, () => ""), ...content];
|
|
25663
|
+
while (screen.length < rows) screen.push("");
|
|
25664
|
+
return screen.map((line) => line + " ".repeat(Math.max(0, width - visibleWidth(line))));
|
|
25665
|
+
}
|
|
25440
25666
|
get finished() {
|
|
25441
25667
|
return this._finished;
|
|
25442
25668
|
}
|
|
@@ -25487,7 +25713,7 @@ var OnboardingInlineComponent = class extends Box {
|
|
|
25487
25713
|
stepCount = 0;
|
|
25488
25714
|
makeBox() {
|
|
25489
25715
|
this.clearStep();
|
|
25490
|
-
this.stepBox = new Box(0, 1, (text) =>
|
|
25716
|
+
this.stepBox = new Box(0, 1, (text) => text);
|
|
25491
25717
|
if (this.stepCount > 0) this.addChild(new Spacer(1));
|
|
25492
25718
|
this.stepCount++;
|
|
25493
25719
|
this.addChild(this.stepBox);
|
|
@@ -25495,7 +25721,7 @@ var OnboardingInlineComponent = class extends Box {
|
|
|
25495
25721
|
}
|
|
25496
25722
|
renderWelcome() {
|
|
25497
25723
|
const box = this.makeBox();
|
|
25498
|
-
box.addChild(new Text(theme.bold(theme.fg("
|
|
25724
|
+
box.addChild(new Text(theme.bold(theme.fg("text", "Welcome to Mastra Code")), 0, 0));
|
|
25499
25725
|
box.addChild(new Spacer(1));
|
|
25500
25726
|
box.addChild(new Text(theme.fg("text", "Let's configure your models and preferences."), 0, 0));
|
|
25501
25727
|
box.addChild(new Text(chalk.white("You can re-run this anytime with /setup."), 0, 0));
|
|
@@ -25527,7 +25753,7 @@ var OnboardingInlineComponent = class extends Box {
|
|
|
25527
25753
|
}
|
|
25528
25754
|
renderAuth() {
|
|
25529
25755
|
const box = this.makeBox();
|
|
25530
|
-
box.addChild(new Text(theme.bold(theme.fg("
|
|
25756
|
+
box.addChild(new Text(theme.bold(theme.fg("text", "Authentication")), 0, 0));
|
|
25531
25757
|
box.addChild(new Spacer(1));
|
|
25532
25758
|
const providers = this.options.authProviders;
|
|
25533
25759
|
if (providers.length === 0) {
|
|
@@ -25580,7 +25806,7 @@ var OnboardingInlineComponent = class extends Box {
|
|
|
25580
25806
|
box.addChild(new Text(theme.fg("dim", "Run /connect to configure an API key or authenticate with an account."), 0, 0));
|
|
25581
25807
|
box.addChild(new Spacer(1));
|
|
25582
25808
|
}
|
|
25583
|
-
box.addChild(new Text(theme.bold(theme.fg("
|
|
25809
|
+
box.addChild(new Text(theme.bold(theme.fg("text", "Model Packs")), 0, 0));
|
|
25584
25810
|
box.addChild(new Spacer(1));
|
|
25585
25811
|
box.addChild(new Text(theme.fg("text", "Choose default models for each mode (build / plan / fast):"), 0, 0));
|
|
25586
25812
|
box.addChild(new Spacer(1));
|
|
@@ -25726,7 +25952,7 @@ var OnboardingInlineComponent = class extends Box {
|
|
|
25726
25952
|
return;
|
|
25727
25953
|
}
|
|
25728
25954
|
const box = this.makeBox();
|
|
25729
|
-
box.addChild(new Text(theme.bold(theme.fg("
|
|
25955
|
+
box.addChild(new Text(theme.bold(theme.fg("text", "Observational Memory")), 0, 0));
|
|
25730
25956
|
box.addChild(new Spacer(1));
|
|
25731
25957
|
box.addChild(new Text(theme.fg("text", "Choose the model for observational memory:"), 0, 0));
|
|
25732
25958
|
box.addChild(new Text(theme.fg("dim", "https://mastra.ai/docs/memory/observational-memory"), 0, 0));
|
|
@@ -25781,7 +26007,7 @@ var OnboardingInlineComponent = class extends Box {
|
|
|
25781
26007
|
}
|
|
25782
26008
|
renderYolo() {
|
|
25783
26009
|
const box = this.makeBox();
|
|
25784
|
-
box.addChild(new Text(theme.bold(theme.fg("
|
|
26010
|
+
box.addChild(new Text(theme.bold(theme.fg("text", "Tool Approval")), 0, 0));
|
|
25785
26011
|
box.addChild(new Spacer(1));
|
|
25786
26012
|
box.addChild(new Text(theme.fg("text", "YOLO mode auto-approves all tool calls (edits, commands, etc)."), 0, 0));
|
|
25787
26013
|
box.addChild(new Text(theme.fg("text", "You can toggle this anytime with Ctrl+Y or /yolo."), 0, 0));
|
|
@@ -25839,7 +26065,7 @@ var OnboardingInlineComponent = class extends Box {
|
|
|
25839
26065
|
collapseStep(summary) {
|
|
25840
26066
|
if (!this.stepBox) return;
|
|
25841
26067
|
this.stepBox.clear();
|
|
25842
|
-
this.stepBox.setBgFn((text) =>
|
|
26068
|
+
this.stepBox.setBgFn((text) => text);
|
|
25843
26069
|
this.stepBox.addChild(new Text(`${theme.fg("success", "✓")} ${theme.fg("text", summary)}`, 0, 0));
|
|
25844
26070
|
this.selectList = void 0;
|
|
25845
26071
|
this.activeInlineQuestion = void 0;
|
|
@@ -25866,80 +26092,6 @@ function showSessionError(state, error) {
|
|
|
25866
26092
|
showError(state, error instanceof Error ? error.message : "Unknown error");
|
|
25867
26093
|
}
|
|
25868
26094
|
//#endregion
|
|
25869
|
-
//#region src/tui/components/banner.ts
|
|
25870
|
-
/**
|
|
25871
|
-
* ASCII art banner for the Mastra Code TUI header.
|
|
25872
|
-
* Renders "MASTRA CODE" or "MASTRA" in block-letter art with a green gradient.
|
|
25873
|
-
*/
|
|
25874
|
-
const GRADIENT_STOPS = [
|
|
25875
|
-
"#085314",
|
|
25876
|
-
"#0d8020",
|
|
25877
|
-
"#16c858",
|
|
25878
|
-
"#62f69d",
|
|
25879
|
-
"#a1fac7"
|
|
25880
|
-
];
|
|
25881
|
-
const FULL_ART = [
|
|
25882
|
-
"█▀▄▀█ ▄▀█ █▀ ▀█▀ █▀█ ▄▀█ █▀▀ █▀█ █▀▄ █▀▀",
|
|
25883
|
-
"█ ▀ █ █▀█ ▀█ █ █▀▄ █▀█ █ █ █ █ █ █▀▀",
|
|
25884
|
-
"▀ ▀ ▀ ▀ ▀▀ ▀ ▀ ▀ ▀ ▀ ▀▀▀ ▀▀▀ ▀▀ ▀▀▀"
|
|
25885
|
-
];
|
|
25886
|
-
const SHORT_ART = [
|
|
25887
|
-
"█▀▄▀█ ▄▀█ █▀ ▀█▀ █▀█ ▄▀█",
|
|
25888
|
-
"█ ▀ █ █▀█ ▀█ █ █▀▄ █▀█",
|
|
25889
|
-
"▀ ▀ ▀ ▀ ▀▀ ▀ ▀ ▀ ▀ ▀"
|
|
25890
|
-
];
|
|
25891
|
-
/**
|
|
25892
|
-
* Interpolate between two hex colors.
|
|
25893
|
-
*/
|
|
25894
|
-
function lerpColor(hex1, hex2, t) {
|
|
25895
|
-
const r1 = parseInt(hex1.slice(1, 3), 16);
|
|
25896
|
-
const g1 = parseInt(hex1.slice(3, 5), 16);
|
|
25897
|
-
const b1 = parseInt(hex1.slice(5, 7), 16);
|
|
25898
|
-
const r2 = parseInt(hex2.slice(1, 3), 16);
|
|
25899
|
-
const g2 = parseInt(hex2.slice(3, 5), 16);
|
|
25900
|
-
const b2 = parseInt(hex2.slice(5, 7), 16);
|
|
25901
|
-
return [
|
|
25902
|
-
Math.round(r1 + (r2 - r1) * t),
|
|
25903
|
-
Math.round(g1 + (g2 - g1) * t),
|
|
25904
|
-
Math.round(b1 + (b2 - b1) * t)
|
|
25905
|
-
];
|
|
25906
|
-
}
|
|
25907
|
-
/**
|
|
25908
|
-
* Color a single character based on its horizontal position in the gradient.
|
|
25909
|
-
*/
|
|
25910
|
-
function gradientChar(ch, colIdx, totalCols) {
|
|
25911
|
-
if (ch === " ") return " ";
|
|
25912
|
-
const t = totalCols <= 1 ? .5 : colIdx / (totalCols - 1);
|
|
25913
|
-
const segmentCount = GRADIENT_STOPS.length - 1;
|
|
25914
|
-
const segment = Math.min(Math.floor(t * segmentCount), segmentCount - 1);
|
|
25915
|
-
const frac = t * segmentCount - segment;
|
|
25916
|
-
const [r, g, b] = lerpColor(GRADIENT_STOPS[segment], GRADIENT_STOPS[segment + 1], frac);
|
|
25917
|
-
return chalk.rgb(r, g, b)(ch);
|
|
25918
|
-
}
|
|
25919
|
-
/**
|
|
25920
|
-
* Apply left-to-right purple gradient to a line of text.
|
|
25921
|
-
*/
|
|
25922
|
-
function colorLine(line) {
|
|
25923
|
-
const chars = [...line];
|
|
25924
|
-
return chars.map((ch, i) => gradientChar(ch, i, chars.length)).join("");
|
|
25925
|
-
}
|
|
25926
|
-
/**
|
|
25927
|
-
* Render the banner header for the TUI.
|
|
25928
|
-
*
|
|
25929
|
-
* @param version - App version string (e.g. "0.2.0")
|
|
25930
|
-
* @param appName - App name. Block art is only used for "Mastra Code" (default).
|
|
25931
|
-
* @returns Styled multi-line string ready for display.
|
|
25932
|
-
*/
|
|
25933
|
-
function renderBanner(version, appName) {
|
|
25934
|
-
const name = appName || "Mastra Code";
|
|
25935
|
-
if (name !== "Mastra Code") return theme.fg("accent", "◆") + " " + theme.bold(theme.fg("accent", name)) + theme.fg("dim", ` v${version}`);
|
|
25936
|
-
const cols = process.stdout.columns || 80;
|
|
25937
|
-
if (cols < 30) return theme.fg("accent", "◆") + " " + theme.bold(theme.fg("accent", "Mastra Code")) + theme.fg("dim", ` v${version}`);
|
|
25938
|
-
const coloredLines = (cols >= 50 ? FULL_ART : SHORT_ART).map((line) => colorLine(line));
|
|
25939
|
-
coloredLines.push(theme.fg("dim", `v${version}`));
|
|
25940
|
-
return coloredLines.join("\n");
|
|
25941
|
-
}
|
|
25942
|
-
//#endregion
|
|
25943
26095
|
//#region src/tui/components/idle-counter.ts
|
|
25944
26096
|
/**
|
|
25945
26097
|
* Live work/idle-time indicator shown above the user input.
|
|
@@ -25949,6 +26101,7 @@ var IdleCounterComponent = class extends Container {
|
|
|
25949
26101
|
timingState;
|
|
25950
26102
|
textChild;
|
|
25951
26103
|
thinking = false;
|
|
26104
|
+
activity = "";
|
|
25952
26105
|
constructor() {
|
|
25953
26106
|
super();
|
|
25954
26107
|
this.textChild = new Text("", 0, 0);
|
|
@@ -25958,17 +26111,18 @@ var IdleCounterComponent = class extends Container {
|
|
|
25958
26111
|
this.timingState = timingState;
|
|
25959
26112
|
this.update(now);
|
|
25960
26113
|
}
|
|
25961
|
-
/** Quiet mode
|
|
26114
|
+
/** Quiet mode's live thinking state; status-line.ts swaps the Working row's label while it is set. */
|
|
25962
26115
|
setThinking(thinking) {
|
|
25963
|
-
if (this.thinking === thinking) return;
|
|
25964
26116
|
this.thinking = thinking;
|
|
25965
|
-
|
|
26117
|
+
}
|
|
26118
|
+
isThinking() {
|
|
26119
|
+
return this.thinking;
|
|
26120
|
+
}
|
|
26121
|
+
/** The Working row (built in status-line.ts) shares this slot; empty when idle. */
|
|
26122
|
+
setActivity(text) {
|
|
26123
|
+
this.activity = text;
|
|
25966
26124
|
}
|
|
25967
26125
|
update(now = Date.now()) {
|
|
25968
|
-
if (this.thinking) {
|
|
25969
|
-
this.textChild.setText(` ${theme.italic(theme.fg("thinkingText", "Thinking..."))}`);
|
|
25970
|
-
return;
|
|
25971
|
-
}
|
|
25972
26126
|
const segments = this.timingState ? formatIdleStatusTimingSegments(this.timingState, now) : null;
|
|
25973
26127
|
if (!segments) {
|
|
25974
26128
|
this.textChild.setText("");
|
|
@@ -25978,8 +26132,8 @@ var IdleCounterComponent = class extends Container {
|
|
|
25978
26132
|
this.textChild.setText(idle ? ` ${idle}` : "");
|
|
25979
26133
|
}
|
|
25980
26134
|
render(width) {
|
|
25981
|
-
|
|
25982
|
-
return
|
|
26135
|
+
if (this.activity) return ["", truncateToWidth(this.activity, width)];
|
|
26136
|
+
return ["", super.render(width)[0] ?? ""];
|
|
25983
26137
|
}
|
|
25984
26138
|
};
|
|
25985
26139
|
function formatIdleStatusTimingSegments(state, now = Date.now()) {
|
|
@@ -26156,24 +26310,39 @@ function abortActiveGoalJudge(state) {
|
|
|
26156
26310
|
}
|
|
26157
26311
|
function buildLayout(state, refreshModelAuthStatus) {
|
|
26158
26312
|
const appName = state.options.appName || "Mastra Code";
|
|
26159
|
-
const
|
|
26160
|
-
const
|
|
26313
|
+
const version = state.options.version || "0.1.0";
|
|
26314
|
+
const info = [
|
|
26161
26315
|
`Project: ${state.projectInfo.name}`,
|
|
26162
26316
|
`Resource ID: ${state.projectInfo.resourceId}`,
|
|
26163
26317
|
state.projectInfo.gitBranch ? `Branch: ${state.projectInfo.gitBranch}` : null,
|
|
26164
26318
|
state.projectInfo.isWorktree ? `Worktree of: ${state.projectInfo.mainRepoPath}` : null
|
|
26165
|
-
].filter(
|
|
26319
|
+
].filter((line) => Boolean(line));
|
|
26166
26320
|
const sep = theme.fg("dim", " · ");
|
|
26167
26321
|
const hintParts = [];
|
|
26168
|
-
if (state.controller.listModes().length > 1) hintParts.push(
|
|
26169
|
-
hintParts.push(
|
|
26170
|
-
const
|
|
26171
|
-
|
|
26172
|
-
|
|
26173
|
-
|
|
26322
|
+
if (state.controller.listModes().length > 1) hintParts.push(keyHint("shift+tab", "cycle modes"));
|
|
26323
|
+
hintParts.push(keyHint("/help", "info & shortcuts"));
|
|
26324
|
+
const renderHints = (width) => {
|
|
26325
|
+
for (let count = hintParts.length; count > 0; count--) {
|
|
26326
|
+
const row = ` ${hintParts.slice(0, count).join(sep)}`;
|
|
26327
|
+
if (visibleWidth(row) <= width) return [row];
|
|
26328
|
+
}
|
|
26329
|
+
return [];
|
|
26330
|
+
};
|
|
26174
26331
|
state.ui.addChild(new Spacer(1));
|
|
26175
|
-
state.ui.addChild(new
|
|
26332
|
+
state.ui.addChild(new HeaderComponent({
|
|
26333
|
+
version,
|
|
26334
|
+
appName,
|
|
26335
|
+
info
|
|
26336
|
+
}));
|
|
26176
26337
|
state.ui.addChild(new Spacer(1));
|
|
26338
|
+
state.ui.addChild({
|
|
26339
|
+
render: renderHints,
|
|
26340
|
+
invalidate: () => {}
|
|
26341
|
+
});
|
|
26342
|
+
state.ui.addChild({
|
|
26343
|
+
render: () => state.chatContainer.children.length > 0 ? [""] : [],
|
|
26344
|
+
invalidate: () => {}
|
|
26345
|
+
});
|
|
26177
26346
|
state.ui.addChild(state.chatContainer);
|
|
26178
26347
|
state.taskProgress = new TaskProgressComponent();
|
|
26179
26348
|
state.taskProgress.setQuietMode(state.quietMode);
|
|
@@ -26189,6 +26358,15 @@ function buildLayout(state, refreshModelAuthStatus) {
|
|
|
26189
26358
|
state.footer.addChild(state.memoryStatusLine);
|
|
26190
26359
|
state.ui.addChild(state.footer);
|
|
26191
26360
|
updateStatusLine(state);
|
|
26361
|
+
let statusWidth = 0;
|
|
26362
|
+
const renderFooter = state.footer.render.bind(state.footer);
|
|
26363
|
+
state.footer.render = (width) => {
|
|
26364
|
+
if (width !== statusWidth) {
|
|
26365
|
+
statusWidth = width;
|
|
26366
|
+
updateStatusLine(state);
|
|
26367
|
+
}
|
|
26368
|
+
return renderFooter(width);
|
|
26369
|
+
};
|
|
26192
26370
|
refreshModelAuthStatus();
|
|
26193
26371
|
state.ui.setFocus(state.editor);
|
|
26194
26372
|
installOverlayFocusHandoff(state.ui, state);
|
|
@@ -26713,7 +26891,7 @@ async function renderExistingTasks(state) {
|
|
|
26713
26891
|
//#region src/tui/components/shell-output.ts
|
|
26714
26892
|
/**
|
|
26715
26893
|
* Streaming shell output component for the shell passthrough (! command).
|
|
26716
|
-
*
|
|
26894
|
+
* A tool-style block: "● $ command" with live stdout/stderr on a shaded panel below.
|
|
26717
26895
|
*/
|
|
26718
26896
|
const MAX_LINES = 200;
|
|
26719
26897
|
const COLLAPSED_LINES = 20;
|
|
@@ -26759,33 +26937,25 @@ var ShellStreamComponent = class extends WidthAwareContainer {
|
|
|
26759
26937
|
}
|
|
26760
26938
|
rebuildForWidth(termWidth) {
|
|
26761
26939
|
this.clear();
|
|
26762
|
-
const border = (char) => theme.bold(theme.fg("accent", char));
|
|
26763
|
-
const maxLineWidth = termWidth - 6;
|
|
26764
26940
|
const done = this.exitCode !== void 0;
|
|
26765
|
-
const
|
|
26941
|
+
const failed = done && this.exitCode !== 0;
|
|
26766
26942
|
const durationStr = done ? theme.fg("muted", ` ${formatDuration(Date.now() - this.startTime)}`) : "";
|
|
26767
|
-
const
|
|
26768
|
-
this.addChild(new Text(border("╭──"), 0, 0));
|
|
26943
|
+
const title = `${theme.bold(theme.fg("toolTitle", "$"))} ${theme.fg("toolArgs", this.command)}${durationStr}${failed ? theme.fg("error", " ✗") : ""}`;
|
|
26769
26944
|
const displayLines = [...this.lines];
|
|
26770
26945
|
if (this.trailingPartial && !done) displayLines.push(this.trailingPartial);
|
|
26771
26946
|
while (displayLines.length > 0 && displayLines[0] === "") displayLines.shift();
|
|
26772
|
-
|
|
26773
|
-
|
|
26774
|
-
|
|
26775
|
-
|
|
26776
|
-
|
|
26777
|
-
|
|
26778
|
-
});
|
|
26779
|
-
if (truncated) {
|
|
26780
|
-
const remaining = displayLines.length - maxVisible;
|
|
26781
|
-
const action = this.expanded ? "collapse" : "expand";
|
|
26782
|
-
borderedLines.push(border("│") + " " + theme.fg("muted", `... ${remaining} more lines (Ctrl+E to ${action})`));
|
|
26783
|
-
}
|
|
26784
|
-
const displayOutput = borderedLines.join("\n");
|
|
26785
|
-
if (displayOutput.trim()) this.addChild(new Text(displayOutput, 0, 0));
|
|
26947
|
+
const maxVisible = this.expanded ? MAX_LINES : COLLAPSED_LINES;
|
|
26948
|
+
const truncated = displayLines.length > maxVisible;
|
|
26949
|
+
const output = (truncated ? displayLines.slice(-maxVisible) : displayLines).map((line) => theme.fg("toolOutput", line));
|
|
26950
|
+
if (truncated) {
|
|
26951
|
+
const remaining = displayLines.length - maxVisible;
|
|
26952
|
+
const action = this.expanded ? "collapse" : "expand";
|
|
26953
|
+
output.unshift(theme.fg("dim", `… ${remaining} earlier lines · `) + theme.fg("muted", "ctrl+e") + theme.fg("dim", ` to ${action}`));
|
|
26786
26954
|
}
|
|
26787
|
-
|
|
26788
|
-
|
|
26955
|
+
if (failed) output.push(theme.fg("error", `Exit code: ${this.exitCode}`));
|
|
26956
|
+
const dot = statusDot(done ? failed ? "error" : "done" : "running");
|
|
26957
|
+
const hasOutput = output.some((line) => line.trim());
|
|
26958
|
+
this.addChild(new Text(toolBlock(dot, title, hasOutput ? output : [], termWidth).join("\n"), 0, 0));
|
|
26789
26959
|
this.invalidate();
|
|
26790
26960
|
}
|
|
26791
26961
|
getChatSpacingKind() {
|
|
@@ -27224,7 +27394,21 @@ var MastraTUI = class MastraTUI {
|
|
|
27224
27394
|
this.state.quietModeMaxToolPreviewLines = savedSettings.preferences.quietModeMaxToolPreviewLines;
|
|
27225
27395
|
const originalHandleInput = this.state.editor.handleInput.bind(this.state.editor);
|
|
27226
27396
|
this.state.editor.handleInput = (data) => {
|
|
27227
|
-
if (this.state.
|
|
27397
|
+
if (this.state.activeOnboarding) {
|
|
27398
|
+
if (data === "") {
|
|
27399
|
+
this.state.activeOnboarding.cancel();
|
|
27400
|
+
this.state.activeOnboarding = void 0;
|
|
27401
|
+
originalHandleInput(data);
|
|
27402
|
+
} else this.state.activeOnboarding.handleInput(data);
|
|
27403
|
+
return;
|
|
27404
|
+
}
|
|
27405
|
+
if (this.state.activeInlineApproval) {
|
|
27406
|
+
const expandsRow = data === "" && !this.state.activeInlineApproval.handlesExpand?.();
|
|
27407
|
+
if (data !== "" && !expandsRow) {
|
|
27408
|
+
this.state.activeInlineApproval.handleInput(data);
|
|
27409
|
+
return;
|
|
27410
|
+
}
|
|
27411
|
+
} else if (this.state.activeInlinePlanApproval) {
|
|
27228
27412
|
if (data !== "") {
|
|
27229
27413
|
this.state.activeInlinePlanApproval.handleInput(data);
|
|
27230
27414
|
return;
|
|
@@ -27235,13 +27419,6 @@ var MastraTUI = class MastraTUI {
|
|
|
27235
27419
|
return;
|
|
27236
27420
|
}
|
|
27237
27421
|
}
|
|
27238
|
-
if (this.state.activeOnboarding) if (data === "") {
|
|
27239
|
-
this.state.activeOnboarding.cancel();
|
|
27240
|
-
this.state.activeOnboarding = void 0;
|
|
27241
|
-
} else {
|
|
27242
|
-
this.state.activeOnboarding.handleInput(data);
|
|
27243
|
-
return;
|
|
27244
|
-
}
|
|
27245
27422
|
originalHandleInput(data);
|
|
27246
27423
|
};
|
|
27247
27424
|
this.state.editor.onImagePaste = (image) => {
|
|
@@ -27249,7 +27426,6 @@ var MastraTUI = class MastraTUI {
|
|
|
27249
27426
|
this.state.editor.insertTextAtCursor?.("[image] ");
|
|
27250
27427
|
flushRender(this.state);
|
|
27251
27428
|
};
|
|
27252
|
-
this.state.editor.getPromptAnimator = () => this.state.gradientAnimator;
|
|
27253
27429
|
setupKeyboardShortcuts(this.state, {
|
|
27254
27430
|
stop: () => this.stop(),
|
|
27255
27431
|
exit: (exitCode) => this.exit(exitCode),
|
|
@@ -27435,9 +27611,19 @@ var MastraTUI = class MastraTUI {
|
|
|
27435
27611
|
this.state.messageComponentsById.set(signalId, component);
|
|
27436
27612
|
}
|
|
27437
27613
|
createPendingNewThread() {
|
|
27614
|
+
if (this.state.pendingNewThreadCreation) return this.state.pendingNewThreadCreation;
|
|
27438
27615
|
if (!this.state.pendingNewThread) return void 0;
|
|
27439
27616
|
this.state.pendingNewThread = false;
|
|
27440
|
-
|
|
27617
|
+
const creation = this.state.session.thread.create().then(() => void 0, (error) => {
|
|
27618
|
+
this.state.pendingNewThread = true;
|
|
27619
|
+
throw error;
|
|
27620
|
+
});
|
|
27621
|
+
this.state.pendingNewThreadCreation = creation;
|
|
27622
|
+
const clear = () => {
|
|
27623
|
+
if (this.state.pendingNewThreadCreation === creation) this.state.pendingNewThreadCreation = void 0;
|
|
27624
|
+
};
|
|
27625
|
+
creation.then(clear, clear);
|
|
27626
|
+
return creation;
|
|
27441
27627
|
}
|
|
27442
27628
|
sendOptimisticSignal(content, images, optimisticMessageId, pendingNewThread) {
|
|
27443
27629
|
const send = () => {
|
|
@@ -27495,18 +27681,28 @@ var MastraTUI = class MastraTUI {
|
|
|
27495
27681
|
const messageId = `queued-slash-${Date.now()}-${this.state.pendingSlashCommands.length}`;
|
|
27496
27682
|
this.state.pendingSlashCommands.push(text);
|
|
27497
27683
|
this.state.pendingSlashCommandMessageIds.push(messageId);
|
|
27498
|
-
this.state.pendingQueuedActions.push("slash");
|
|
27499
27684
|
addPendingUserMessage(this.state, messageId, text);
|
|
27500
27685
|
updateStatusLine(this.state);
|
|
27501
27686
|
return;
|
|
27502
27687
|
}
|
|
27503
27688
|
const { content, images } = consumePendingImages(text, this.state.pendingImages);
|
|
27504
27689
|
this.state.pendingImages = [];
|
|
27505
|
-
|
|
27690
|
+
const files = images?.map((img) => ({
|
|
27691
|
+
data: img.data,
|
|
27692
|
+
mediaType: img.mimeType
|
|
27693
|
+
}));
|
|
27694
|
+
const queue = () => this.state.session.queueMessage({
|
|
27506
27695
|
content,
|
|
27507
|
-
|
|
27696
|
+
files
|
|
27697
|
+
});
|
|
27698
|
+
const pendingThread = this.createPendingNewThread();
|
|
27699
|
+
this.state.pendingQueueSubmissions++;
|
|
27700
|
+
(pendingThread ? pendingThread.then(queue) : queue()).catch((error) => {
|
|
27701
|
+
showSessionError(this.state, error);
|
|
27702
|
+
}).finally(() => {
|
|
27703
|
+
this.state.pendingQueueSubmissions--;
|
|
27704
|
+
if (this.state.pendingQueueSubmissions === 0) drainQueuedActionIfIdle(this.getEventContext());
|
|
27508
27705
|
});
|
|
27509
|
-
this.state.pendingQueuedActions.push("message");
|
|
27510
27706
|
updateStatusLine(this.state);
|
|
27511
27707
|
flushRender(this.state);
|
|
27512
27708
|
}
|
|
@@ -28174,7 +28370,12 @@ var MastraTUI = class MastraTUI {
|
|
|
28174
28370
|
}
|
|
28175
28371
|
});
|
|
28176
28372
|
this.state.activeOnboarding = component;
|
|
28177
|
-
showModalOverlay(this.state.ui, component, {
|
|
28373
|
+
showModalOverlay(this.state.ui, component, {
|
|
28374
|
+
widthPercent: 1,
|
|
28375
|
+
maxWidth: 1e4,
|
|
28376
|
+
maxHeight: "100%",
|
|
28377
|
+
minHeightPercent: 1
|
|
28378
|
+
});
|
|
28178
28379
|
component.focused = true;
|
|
28179
28380
|
});
|
|
28180
28381
|
}
|
|
@@ -28383,4 +28584,4 @@ var MastraTUI = class MastraTUI {
|
|
|
28383
28584
|
//#endregion
|
|
28384
28585
|
export { mastraBrand as _, OMProgressComponent as a, TUI_CO_AUTHOR as b, ToolExecutionComponentEnhanced as c, detectTerminalTheme as d, applyThemeMode as f, mastra as g, getThemeMode as h, LoginDialogComponent as i, ModelSelectorComponent as l, getMarkdownTheme as m, createTUIState as n, formatOMStatus as o, getEditorTheme as p, LoginSelectorComponent as r, UserMessageComponent as s, MastraTUI as t, AssistantMessageComponent as u, restoreTerminalForeground as v, theme as y };
|
|
28385
28586
|
|
|
28386
|
-
//# sourceMappingURL=tui-
|
|
28587
|
+
//# sourceMappingURL=tui-5IfsALo2.js.map
|