scream-code 0.16.2 → 0.16.3
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/{app-V7s7I7Nr.mjs → app-C1foLjDE.mjs} +38 -151
- package/dist/{dispatch-BRkUiHzo.mjs → dispatch-BGLqpKHG.mjs} +1 -1
- package/dist/{dispatch-D0mYcf1X.mjs → dispatch-ChDxIz0h.mjs} +671 -485
- package/dist/main.mjs +1 -1
- package/dist/{text-input-dialog-Dp2TUSjQ.mjs → text-input-dialog-DAQfJdHu.mjs} +1 -1
- package/dist/{text-input-dialog-CzJKBIoN.mjs → text-input-dialog-GajpxjyL.mjs} +32 -14
- package/package.json +1 -1
|
@@ -4,9 +4,9 @@ import { dirname as __cjsShimDirname } from 'node:path';
|
|
|
4
4
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
5
5
|
const __dirname = __cjsShimDirname(__filename);
|
|
6
6
|
import { i as __require, o as __toESM, r as __exportAll, t as __commonJSMin } from "./chunk-D90kvbyJ.mjs";
|
|
7
|
-
import { C as join$1, D as resolve$
|
|
7
|
+
import { C as join$1, D as resolve$2, E as relative$1, S as isAbsolute$1, T as parse$7, a as isSupportedFile, b as basename$1, i as ingestFile, r as ingestDirectory, t as multiSearch, w as normalize$1, x as dirname$2, y as KnowledgeStore } from "./src-tDEINaMV.mjs";
|
|
8
8
|
import { t as require_base64_js } from "./base64-js-DzVmk6Nb.mjs";
|
|
9
|
-
import { a as setLocale, i as getLocale, n as assertScreamHostIdentity, o as t, r as createScreamDefaultHeaders, t as TextInputDialogComponent } from "./text-input-dialog-
|
|
9
|
+
import { a as setLocale, i as getLocale, n as assertScreamHostIdentity, o as t, r as createScreamDefaultHeaders, t as TextInputDialogComponent } from "./text-input-dialog-GajpxjyL.mjs";
|
|
10
10
|
import { createRequire } from "node:module";
|
|
11
11
|
import { createHash, randomBytes, randomInt, randomUUID } from "node:crypto";
|
|
12
12
|
import * as fs$1 from "node:fs/promises";
|
|
@@ -50779,7 +50779,7 @@ function canonicalizePath(path, cwd, pathClass = DEFAULT_PATH_CLASS) {
|
|
|
50779
50779
|
const normalizedPath = normalizeUserPath(path, pathClass);
|
|
50780
50780
|
if (pathClass === "win32" && isWin32DriveRelative(normalizedPath)) throw new PathSecurityError("PATH_INVALID", path, normalizedPath, `"${path}" is a drive-relative Windows path. Use an absolute path like C:\\path or a path relative to the working directory.`);
|
|
50781
50781
|
if (!isAbsolute$1(normalizedPath) && !isAbsolute$1(cwd)) throw new PathSecurityError("PATH_INVALID", path, normalizedPath, `Cannot resolve "${path}" against non-absolute cwd "${cwd}".`);
|
|
50782
|
-
return normalize$1(isAbsolute$1(normalizedPath) ? normalizedPath : resolve$
|
|
50782
|
+
return normalize$1(isAbsolute$1(normalizedPath) ? normalizedPath : resolve$2(cwd, normalizedPath));
|
|
50783
50783
|
}
|
|
50784
50784
|
/**
|
|
50785
50785
|
* True iff `candidate` is `base` itself or a descendant of it, compared
|
|
@@ -58452,7 +58452,7 @@ function dump$1(input, options) {
|
|
|
58452
58452
|
return "";
|
|
58453
58453
|
}
|
|
58454
58454
|
var dumper = { dump: dump$1 };
|
|
58455
|
-
var load = loader.load;
|
|
58455
|
+
var load$2 = loader.load;
|
|
58456
58456
|
loader.loadAll;
|
|
58457
58457
|
dumper.dump;
|
|
58458
58458
|
//#endregion
|
|
@@ -60001,7 +60001,7 @@ function parseFrontmatter(text) {
|
|
|
60001
60001
|
};
|
|
60002
60002
|
try {
|
|
60003
60003
|
return {
|
|
60004
|
-
data: load(yamlText) ?? {},
|
|
60004
|
+
data: load$2(yamlText) ?? {},
|
|
60005
60005
|
body
|
|
60006
60006
|
};
|
|
60007
60007
|
} catch (error) {
|
|
@@ -60025,7 +60025,7 @@ function parseSkillText(options) {
|
|
|
60025
60025
|
const name = nonEmptyString$1(metadata.name);
|
|
60026
60026
|
const description = nonEmptyString$1(metadata.description);
|
|
60027
60027
|
if (isDirectorySkill && (name === void 0 || description === void 0)) throw new SkillParseError(`Missing required frontmatter field ${name === void 0 ? "\"name\"" : "\"description\""} in ${options.skillMdPath}`);
|
|
60028
|
-
const skillPath = resolve$
|
|
60028
|
+
const skillPath = resolve$2(options.skillMdPath);
|
|
60029
60029
|
const content = parsed.body.trim();
|
|
60030
60030
|
return {
|
|
60031
60031
|
name: name ?? options.skillDirName,
|
|
@@ -60407,7 +60407,7 @@ async function defaultIsFile(p) {
|
|
|
60407
60407
|
}
|
|
60408
60408
|
}
|
|
60409
60409
|
async function findProjectRoot$2(workDir) {
|
|
60410
|
-
const start = resolve$
|
|
60410
|
+
const start = resolve$2(workDir);
|
|
60411
60411
|
let current = start;
|
|
60412
60412
|
while (true) {
|
|
60413
60413
|
if (await exists(join$1(current, ".git"))) return current;
|
|
@@ -60428,7 +60428,7 @@ function resolveConfiguredDir(dir, projectRoot, userHomeDir) {
|
|
|
60428
60428
|
if (dir === "~") return userHomeDir;
|
|
60429
60429
|
if (dir.startsWith("~/")) return join$1(userHomeDir, dir.slice(2));
|
|
60430
60430
|
if (isAbsolute$1(dir)) return dir;
|
|
60431
|
-
return resolve$
|
|
60431
|
+
return resolve$2(projectRoot, dir);
|
|
60432
60432
|
}
|
|
60433
60433
|
function isWithin$1(child, parent) {
|
|
60434
60434
|
const rel = relative$1(parent, child);
|
|
@@ -78140,7 +78140,7 @@ const McpJsonFileSchema = z.object({ mcpServers: z.record(z.string(), McpServerC
|
|
|
78140
78140
|
/** Maximum number of parent directories to walk when discovering mcp.json. */
|
|
78141
78141
|
const MAX_PARENT_WALK = 20;
|
|
78142
78142
|
function resolveMcpJsonPaths(input) {
|
|
78143
|
-
const cwd = resolve$
|
|
78143
|
+
const cwd = resolve$2(input.cwd);
|
|
78144
78144
|
return {
|
|
78145
78145
|
user: join$1(resolveScreamHome(input.homeDir), "mcp.json"),
|
|
78146
78146
|
project: join$1(cwd, ".scream-code", "mcp.json"),
|
|
@@ -99461,7 +99461,7 @@ function finalizeRawAgentProfileSource(content, profilePath, sources) {
|
|
|
99461
99461
|
function parseAgentProfileYaml(content, profilePath) {
|
|
99462
99462
|
let parsed;
|
|
99463
99463
|
try {
|
|
99464
|
-
parsed = load(content);
|
|
99464
|
+
parsed = load$2(content);
|
|
99465
99465
|
} catch (error) {
|
|
99466
99466
|
throw new Error(`Invalid agent profile YAML at ${profilePath}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
99467
99467
|
}
|
|
@@ -123105,7 +123105,7 @@ async function exportSessionDirectory(input) {
|
|
|
123105
123105
|
installSource: input.request.installSource,
|
|
123106
123106
|
shellEnv: input.request.shellEnv
|
|
123107
123107
|
});
|
|
123108
|
-
const outputPath = input.request.outputPath !== void 0 ? resolve$
|
|
123108
|
+
const outputPath = input.request.outputPath !== void 0 ? resolve$2(input.request.outputPath) : resolve$2(`${input.summary.id}.zip`);
|
|
123109
123109
|
return {
|
|
123110
123110
|
zipPath: outputPath,
|
|
123111
123111
|
entries: await writeExportZip({
|
|
@@ -123633,7 +123633,7 @@ async function readSessionIndex(homeDir, sessionsDir) {
|
|
|
123633
123633
|
if (trimmed === "") continue;
|
|
123634
123634
|
const entry = parseIndexLine(trimmed);
|
|
123635
123635
|
if (entry === void 0) continue;
|
|
123636
|
-
const sessionDir = resolve$
|
|
123636
|
+
const sessionDir = resolve$2(entry.sessionDir);
|
|
123637
123637
|
if (!isAbsolute$1(entry.sessionDir)) continue;
|
|
123638
123638
|
if (!isAbsolute$1(entry.workDir)) continue;
|
|
123639
123639
|
if (!isPathInside(sessionsDir, sessionDir)) continue;
|
|
@@ -123641,7 +123641,7 @@ async function readSessionIndex(homeDir, sessionsDir) {
|
|
|
123641
123641
|
result.set(entry.sessionId, {
|
|
123642
123642
|
sessionId: entry.sessionId,
|
|
123643
123643
|
sessionDir,
|
|
123644
|
-
workDir: resolve$
|
|
123644
|
+
workDir: resolve$2(entry.workDir)
|
|
123645
123645
|
});
|
|
123646
123646
|
}
|
|
123647
123647
|
return result;
|
|
@@ -123682,7 +123682,7 @@ function parseIndexLine(line) {
|
|
|
123682
123682
|
}
|
|
123683
123683
|
}
|
|
123684
123684
|
function isPathInside(parent, child) {
|
|
123685
|
-
const rel = relative$1(resolve$
|
|
123685
|
+
const rel = relative$1(resolve$2(parent), resolve$2(child));
|
|
123686
123686
|
return rel !== "" && !rel.startsWith("..") && !isAbsolute$1(rel);
|
|
123687
123687
|
}
|
|
123688
123688
|
//#endregion
|
|
@@ -123697,7 +123697,7 @@ function slugifyWorkDirName(name) {
|
|
|
123697
123697
|
const WORKDIR_KEY_PREFIX = "wd_";
|
|
123698
123698
|
const HASH_LENGTH = 12;
|
|
123699
123699
|
function normalizeWorkDir(workDir) {
|
|
123700
|
-
const resolved = resolve$
|
|
123700
|
+
const resolved = resolve$2(workDir);
|
|
123701
123701
|
let dir = resolved;
|
|
123702
123702
|
while (dir !== dirname$2(dir)) {
|
|
123703
123703
|
if (existsSync(join$1(dir, ".git")) || existsSync(join$1(dir, "package.json"))) return dir;
|
|
@@ -127996,6 +127996,20 @@ const BUILTIN_SLASH_COMMANDS = [
|
|
|
127996
127996
|
priority: 178,
|
|
127997
127997
|
availability: "always"
|
|
127998
127998
|
},
|
|
127999
|
+
{
|
|
128000
|
+
name: "blockrows",
|
|
128001
|
+
aliases: ["rows"],
|
|
128002
|
+
description: "registry.blockrows_desc",
|
|
128003
|
+
priority: 179,
|
|
128004
|
+
availability: "always"
|
|
128005
|
+
},
|
|
128006
|
+
{
|
|
128007
|
+
name: "codebg",
|
|
128008
|
+
aliases: ["codeblock"],
|
|
128009
|
+
description: "registry.codebg_desc",
|
|
128010
|
+
priority: 180,
|
|
128011
|
+
availability: "always"
|
|
128012
|
+
},
|
|
127999
128013
|
{
|
|
128000
128014
|
name: "like",
|
|
128001
128015
|
aliases: [],
|
|
@@ -128578,6 +128592,7 @@ var ApiKeyInputDialogComponent = class extends Container {
|
|
|
128578
128592
|
const STATUS_BULLET = "■ ";
|
|
128579
128593
|
const USER_MESSAGE_BULLET = "■ ";
|
|
128580
128594
|
const FAILURE_MARK = "✗ ";
|
|
128595
|
+
const DONE_MARK = "✓ ";
|
|
128581
128596
|
const INTERJECTION_BULLET = "▸ ";
|
|
128582
128597
|
//#endregion
|
|
128583
128598
|
//#region src/tui/utils/printable-key.ts
|
|
@@ -131783,7 +131798,7 @@ const darkColors = {
|
|
|
131783
131798
|
mdLink: "#56B6C2",
|
|
131784
131799
|
mdCodeBlock: "#9CDCFE",
|
|
131785
131800
|
mdCodeBlockBorder: "#5C6370",
|
|
131786
|
-
mdCodeBlockBg: "#
|
|
131801
|
+
mdCodeBlockBg: "#16191f",
|
|
131787
131802
|
mdQuote: "#7F848E",
|
|
131788
131803
|
border: dark.gray700,
|
|
131789
131804
|
borderFocus: dark.yellowGreenLight,
|
|
@@ -131817,7 +131832,7 @@ const lightColors = {
|
|
|
131817
131832
|
mdLink: "#007A8A",
|
|
131818
131833
|
mdCodeBlock: "#1565C0",
|
|
131819
131834
|
mdCodeBlockBorder: "#848484",
|
|
131820
|
-
mdCodeBlockBg: "#
|
|
131835
|
+
mdCodeBlockBg: "#f7f9fb",
|
|
131821
131836
|
mdQuote: "#616161",
|
|
131822
131837
|
border: light.gray500,
|
|
131823
131838
|
borderFocus: light.yellowGreen700,
|
|
@@ -131886,6 +131901,113 @@ function createThemeStyles(colors) {
|
|
|
131886
131901
|
};
|
|
131887
131902
|
}
|
|
131888
131903
|
//#endregion
|
|
131904
|
+
//#region src/tui/utils/ui-preferences.ts
|
|
131905
|
+
/**
|
|
131906
|
+
* TUI-local UI preferences persisted to `<dataDir>/ui-preferences.json`.
|
|
131907
|
+
* Distinct from agent/SDK config files (which are owned by core) — this file
|
|
131908
|
+
* stores lightweight view-state knobs owned by the TUI itself, e.g. whether
|
|
131909
|
+
* the empty-session provider hint has been dismissed by the user.
|
|
131910
|
+
*/
|
|
131911
|
+
const EMPTY = {};
|
|
131912
|
+
function getUiPreferencesPath() {
|
|
131913
|
+
return join(getDataDir(), SCREAM_CODE_UI_PREFERENCES_FILE_NAME);
|
|
131914
|
+
}
|
|
131915
|
+
function readUiPreferences() {
|
|
131916
|
+
try {
|
|
131917
|
+
const file = getUiPreferencesPath();
|
|
131918
|
+
if (!existsSync(file)) return { ...EMPTY };
|
|
131919
|
+
const raw = readFileSync(file, "utf8");
|
|
131920
|
+
const parsed = JSON.parse(raw);
|
|
131921
|
+
return {
|
|
131922
|
+
...EMPTY,
|
|
131923
|
+
...parsed
|
|
131924
|
+
};
|
|
131925
|
+
} catch {
|
|
131926
|
+
return { ...EMPTY };
|
|
131927
|
+
}
|
|
131928
|
+
}
|
|
131929
|
+
function writeUiPreferences(prefs) {
|
|
131930
|
+
try {
|
|
131931
|
+
const file = getUiPreferencesPath();
|
|
131932
|
+
mkdirSync(dirname$1(file), { recursive: true });
|
|
131933
|
+
writeFileSync(file, JSON.stringify(prefs, null, 2), "utf8");
|
|
131934
|
+
} catch {}
|
|
131935
|
+
}
|
|
131936
|
+
function isEmptySessionHintDismissed() {
|
|
131937
|
+
return readUiPreferences().emptySessionHintDismissed === true;
|
|
131938
|
+
}
|
|
131939
|
+
/** Toggle the empty-session hint on/off (Ctrl+B). Returns the new state:
|
|
131940
|
+
* true = hidden, false = shown. Persisted immediately. */
|
|
131941
|
+
function toggleEmptySessionHint() {
|
|
131942
|
+
const prefs = readUiPreferences();
|
|
131943
|
+
const dismissed = prefs.emptySessionHintDismissed !== true;
|
|
131944
|
+
prefs.emptySessionHintDismissed = dismissed;
|
|
131945
|
+
writeUiPreferences(prefs);
|
|
131946
|
+
return dismissed;
|
|
131947
|
+
}
|
|
131948
|
+
/** Whether the per-turn elapsed marker is enabled (default on). */
|
|
131949
|
+
function isTurnElapsedEnabled() {
|
|
131950
|
+
return readUiPreferences().turnElapsedEnabled !== false;
|
|
131951
|
+
}
|
|
131952
|
+
/** Toggle the per-turn elapsed marker via /snaptimer. Returns the new state:
|
|
131953
|
+
* true = shown, false = hidden. Persisted immediately. */
|
|
131954
|
+
function toggleTurnElapsed() {
|
|
131955
|
+
const prefs = readUiPreferences();
|
|
131956
|
+
const enabled = prefs.turnElapsedEnabled !== false;
|
|
131957
|
+
prefs.turnElapsedEnabled = !enabled;
|
|
131958
|
+
writeUiPreferences(prefs);
|
|
131959
|
+
return !enabled;
|
|
131960
|
+
}
|
|
131961
|
+
/** Row budgets of the activity block as stored, without clamping (see
|
|
131962
|
+
* `utils/activity-lines.ts`, which owns the ranges and defaults). */
|
|
131963
|
+
function readActivityLinePrefs() {
|
|
131964
|
+
const prefs = readUiPreferences();
|
|
131965
|
+
return {
|
|
131966
|
+
activityCollapsedLines: prefs.activityCollapsedLines,
|
|
131967
|
+
activityExpandedToolLines: prefs.activityExpandedToolLines,
|
|
131968
|
+
activityExpandedThinkingLines: prefs.activityExpandedThinkingLines
|
|
131969
|
+
};
|
|
131970
|
+
}
|
|
131971
|
+
/** Persist one activity row budget. Persisted immediately. */
|
|
131972
|
+
function writeActivityLinePref(key, value) {
|
|
131973
|
+
const prefs = readUiPreferences();
|
|
131974
|
+
prefs[key] = value;
|
|
131975
|
+
writeUiPreferences(prefs);
|
|
131976
|
+
}
|
|
131977
|
+
/**
|
|
131978
|
+
* Whether fenced code blocks render as a background panel (default on).
|
|
131979
|
+
*
|
|
131980
|
+
* Cached: the markdown renderer asks once per code line, and reading the file
|
|
131981
|
+
* each time would hit the disk on every frame. `/codebg` updates the cache.
|
|
131982
|
+
*/
|
|
131983
|
+
let codeBlockPanelCache;
|
|
131984
|
+
function isCodeBlockPanelEnabled() {
|
|
131985
|
+
codeBlockPanelCache ??= readUiPreferences().codeBlockPanelEnabled !== false;
|
|
131986
|
+
return codeBlockPanelCache;
|
|
131987
|
+
}
|
|
131988
|
+
/** Toggle the code-block panel via /codebg. Returns the new state. */
|
|
131989
|
+
function toggleCodeBlockPanel() {
|
|
131990
|
+
const prefs = readUiPreferences();
|
|
131991
|
+
const enabled = prefs.codeBlockPanelEnabled !== false;
|
|
131992
|
+
prefs.codeBlockPanelEnabled = !enabled;
|
|
131993
|
+
writeUiPreferences(prefs);
|
|
131994
|
+
codeBlockPanelCache = !enabled;
|
|
131995
|
+
return !enabled;
|
|
131996
|
+
}
|
|
131997
|
+
/** Whether user messages render with a highlight background block (default on). */
|
|
131998
|
+
function isUserMessageHighlightEnabled() {
|
|
131999
|
+
return readUiPreferences().userMessageHighlightEnabled !== false;
|
|
132000
|
+
}
|
|
132001
|
+
/** Toggle the user-message highlight block via /hl. Returns the new state:
|
|
132002
|
+
* true = highlighted, false = default (no background). Persisted immediately. */
|
|
132003
|
+
function toggleUserMessageHighlight() {
|
|
132004
|
+
const prefs = readUiPreferences();
|
|
132005
|
+
const enabled = prefs.userMessageHighlightEnabled !== false;
|
|
132006
|
+
prefs.userMessageHighlightEnabled = !enabled;
|
|
132007
|
+
writeUiPreferences(prefs);
|
|
132008
|
+
return !enabled;
|
|
132009
|
+
}
|
|
132010
|
+
//#endregion
|
|
131889
132011
|
//#region src/tui/theme/pi-tui-theme.ts
|
|
131890
132012
|
const HEADING_HASH_PREFIX = /^((?:\u001B\[[0-9;]*m)*)#{1,6}[ \t]+/;
|
|
131891
132013
|
/**
|
|
@@ -131962,8 +132084,6 @@ function createMarkdownTheme(colors) {
|
|
|
131962
132084
|
codeBlockBorder: () => null,
|
|
131963
132085
|
codeBlockIndent: " ",
|
|
131964
132086
|
codeBlockLine: (line, { index, lang, width }) => {
|
|
131965
|
-
const panel = chalk.bgHex(colors.mdCodeBlockBg);
|
|
131966
|
-
const labelPaint = chalk.bgHex(colors.mdCodeBlockBg).hex(colors.mdCodeBlock);
|
|
131967
132087
|
const content = visibleWidth(line) > width - 1 ? truncateToWidth(line, Math.max(1, width - 1), "…") : line;
|
|
131968
132088
|
const contentCells = visibleWidth(content);
|
|
131969
132089
|
const rawLabel = index === 0 && lang !== void 0 && lang.length > 0 ? ` ${lang}` : "";
|
|
@@ -131971,8 +132091,11 @@ function createMarkdownTheme(colors) {
|
|
|
131971
132091
|
const showLabel = labelCells > 0 && 1 + contentCells + labelCells + 1 <= width;
|
|
131972
132092
|
const filler = showLabel ? Math.max(0, width - contentCells - labelCells - 2) : 0;
|
|
131973
132093
|
const padCells = showLabel ? 1 : Math.max(0, width - contentCells - 1);
|
|
132094
|
+
const panelled = isCodeBlockPanelEnabled();
|
|
132095
|
+
const paint = panelled ? chalk.bgHex(colors.mdCodeBlockBg) : (text) => text;
|
|
132096
|
+
const labelPaint = panelled ? chalk.bgHex(colors.mdCodeBlockBg).hex(colors.mdCodeBlock) : chalk.hex(colors.mdCodeBlock);
|
|
131974
132097
|
const label = showLabel ? chalk.italic(labelPaint(rawLabel)) : "";
|
|
131975
|
-
return `${
|
|
132098
|
+
return `${paint(" ")}${paint(content)}${paint(" ".repeat(filler))}${label}${paint(" ".repeat(padCells))}`;
|
|
131976
132099
|
},
|
|
131977
132100
|
quote: (text) => chalk.hex(colors.mdQuote)(text),
|
|
131978
132101
|
quoteBorder: (text) => chalk.hex(colors.mdQuote)(text),
|
|
@@ -132441,7 +132564,7 @@ async function loadManagedUsageReport(host) {
|
|
|
132441
132564
|
* not hammer the vendor endpoint.
|
|
132442
132565
|
*/
|
|
132443
132566
|
const BALANCE_CACHE_MS = 6e4;
|
|
132444
|
-
const cache = /* @__PURE__ */ new Map();
|
|
132567
|
+
const cache$1 = /* @__PURE__ */ new Map();
|
|
132445
132568
|
/** Monotonic id so an out-of-order lookup can never overwrite a newer one. */
|
|
132446
132569
|
let latestRequestId = 0;
|
|
132447
132570
|
function resolveApiKey(providerName) {
|
|
@@ -132484,10 +132607,10 @@ async function loadBalance(providerName) {
|
|
|
132484
132607
|
async function getProviderBalanceForModel(model) {
|
|
132485
132608
|
const providerName = model.split("/")[0] ?? "";
|
|
132486
132609
|
if (providerName.length === 0) return null;
|
|
132487
|
-
const cached = cache.get(providerName);
|
|
132610
|
+
const cached = cache$1.get(providerName);
|
|
132488
132611
|
if (cached !== void 0 && Date.now() - cached.at < BALANCE_CACHE_MS) return cached.balance;
|
|
132489
132612
|
const balance = await loadBalance(providerName);
|
|
132490
|
-
cache.set(providerName, {
|
|
132613
|
+
cache$1.set(providerName, {
|
|
132491
132614
|
balance,
|
|
132492
132615
|
at: Date.now()
|
|
132493
132616
|
});
|
|
@@ -133931,7 +134054,7 @@ async function guidedGoalSetup(host) {
|
|
|
133931
134054
|
host.showNotice(t("goal.storm_breaker"), t("goal.conflict_loop"));
|
|
133932
134055
|
return;
|
|
133933
134056
|
}
|
|
133934
|
-
const { TextInputDialogComponent } = await import("./text-input-dialog-
|
|
134057
|
+
const { TextInputDialogComponent } = await import("./text-input-dialog-DAQfJdHu.mjs");
|
|
133935
134058
|
const initialDesc = await promptText(host, TextInputDialogComponent, {
|
|
133936
134059
|
title: t("goal.setup_title_initial"),
|
|
133937
134060
|
subtitle: t("goal.setup_desc_hint"),
|
|
@@ -133952,7 +134075,7 @@ async function guidedGoalSetup(host) {
|
|
|
133952
134075
|
await showGoalConfigWizard(host, session, confirmed.trim() || objective, false);
|
|
133953
134076
|
}
|
|
133954
134077
|
async function showGoalConfigWizard(host, session, objective, replace) {
|
|
133955
|
-
const { TextInputDialogComponent } = await import("./text-input-dialog-
|
|
134078
|
+
const { TextInputDialogComponent } = await import("./text-input-dialog-DAQfJdHu.mjs");
|
|
133956
134079
|
const turnInput = await promptNumber(host, TextInputDialogComponent, {
|
|
133957
134080
|
title: t("goal.wizard_title", { objective }),
|
|
133958
134081
|
subtitle: t("goal.budget_turns_hint"),
|
|
@@ -134618,7 +134741,7 @@ var WrappedLine = class {
|
|
|
134618
134741
|
};
|
|
134619
134742
|
//#endregion
|
|
134620
134743
|
//#region src/tui/components/messages/agent-group.ts
|
|
134621
|
-
const THROTTLE_MS$
|
|
134744
|
+
const THROTTLE_MS$1 = 200;
|
|
134622
134745
|
var AgentGroupComponent = class extends Container {
|
|
134623
134746
|
colors;
|
|
134624
134747
|
ui;
|
|
@@ -134679,7 +134802,7 @@ var AgentGroupComponent = class extends Container {
|
|
|
134679
134802
|
this.throttleTimer = setTimeout(() => {
|
|
134680
134803
|
this.throttleTimer = null;
|
|
134681
134804
|
this.flushRender();
|
|
134682
|
-
}, THROTTLE_MS$
|
|
134805
|
+
}, THROTTLE_MS$1);
|
|
134683
134806
|
}
|
|
134684
134807
|
/**
|
|
134685
134808
|
* Compares each child's current phase with the phase captured at the last
|
|
@@ -134801,6 +134924,140 @@ function formatTokens$1(n) {
|
|
|
134801
134924
|
return `${String(n)} tok`;
|
|
134802
134925
|
}
|
|
134803
134926
|
//#endregion
|
|
134927
|
+
//#region src/tui/components/messages/background-agent-status.ts
|
|
134928
|
+
/**
|
|
134929
|
+
* Builds the bullet + text of a background task notice. Shared by the standalone
|
|
134930
|
+
* card and the activity block row so a notice looks the same in both places.
|
|
134931
|
+
*/
|
|
134932
|
+
function renderBackgroundStatus(data, colors, maxCells) {
|
|
134933
|
+
const tone = data.phase === "started" ? colors.primary : data.phase === "completed" ? colors.success : colors.error;
|
|
134934
|
+
const bullet = data.phase === "completed" ? chalk.hex(colors.success)(DONE_MARK) : data.phase === "failed" ? chalk.hex(colors.error)(FAILURE_MARK) : chalk.hex(colors.textDim)(`${BRAILLE_SPINNER_FRAMES[0] ?? "⠋"} `);
|
|
134935
|
+
const hasDetail = data.detail !== void 0 && data.detail.length > 0;
|
|
134936
|
+
const plain = hasDetail ? `${data.headline} (${data.detail ?? ""})` : data.headline;
|
|
134937
|
+
if (maxCells !== void 0 && visibleWidth(plain) > maxCells) return {
|
|
134938
|
+
bullet,
|
|
134939
|
+
text: chalk.hex(tone)(truncateToWidth(plain, maxCells, "…"))
|
|
134940
|
+
};
|
|
134941
|
+
return {
|
|
134942
|
+
bullet,
|
|
134943
|
+
text: chalk.hex(tone)(data.headline) + (hasDetail ? chalk.hex(colors.textDim)(` (${data.detail ?? ""})`) : "")
|
|
134944
|
+
};
|
|
134945
|
+
}
|
|
134946
|
+
var BackgroundAgentStatusComponent = class {
|
|
134947
|
+
data;
|
|
134948
|
+
colors;
|
|
134949
|
+
bullet;
|
|
134950
|
+
textComponent;
|
|
134951
|
+
cachedWidth;
|
|
134952
|
+
cachedLines;
|
|
134953
|
+
constructor(data, colors) {
|
|
134954
|
+
this.data = data;
|
|
134955
|
+
this.colors = colors;
|
|
134956
|
+
const view = renderBackgroundStatus(data, colors);
|
|
134957
|
+
this.bullet = view.bullet;
|
|
134958
|
+
this.textComponent = new Text(view.text, 0, 0);
|
|
134959
|
+
}
|
|
134960
|
+
invalidate() {
|
|
134961
|
+
this.cachedWidth = void 0;
|
|
134962
|
+
this.cachedLines = void 0;
|
|
134963
|
+
}
|
|
134964
|
+
render(width) {
|
|
134965
|
+
if (this.cachedLines !== void 0 && this.cachedWidth === width) return this.cachedLines;
|
|
134966
|
+
const contentWidth = Math.max(1, width - 2);
|
|
134967
|
+
const lines = ["", ...this.textComponent.render(contentWidth).map((line, index) => (index === 0 ? this.bullet : " ") + line)];
|
|
134968
|
+
this.cachedWidth = width;
|
|
134969
|
+
this.cachedLines = lines;
|
|
134970
|
+
return lines;
|
|
134971
|
+
}
|
|
134972
|
+
};
|
|
134973
|
+
//#endregion
|
|
134974
|
+
//#region src/tui/utils/activity-lines.ts
|
|
134975
|
+
/**
|
|
134976
|
+
* Row budgets of the activity block.
|
|
134977
|
+
*
|
|
134978
|
+
* The defaults are the constants in `constant/rendering.ts`; `/blockrows` writes
|
|
134979
|
+
* overrides into ui-preferences.json so the block can be tuned without a rebuild.
|
|
134980
|
+
* Values are cached in memory because a block reads them on every rebuild — and
|
|
134981
|
+
* rebuilds happen on every throttled streaming tick — while the file only changes
|
|
134982
|
+
* when the user runs the command.
|
|
134983
|
+
*
|
|
134984
|
+
* Anything out of range (hand-edited file, stale value, non-number) falls back to
|
|
134985
|
+
* the default rather than changing how much content a row may occupy.
|
|
134986
|
+
*/
|
|
134987
|
+
const ACTIVITY_LINE_SETTINGS = [
|
|
134988
|
+
{
|
|
134989
|
+
key: "activityCollapsedLines",
|
|
134990
|
+
label: "blockrows.item_collapsed",
|
|
134991
|
+
values: [
|
|
134992
|
+
2,
|
|
134993
|
+
3,
|
|
134994
|
+
4,
|
|
134995
|
+
5
|
|
134996
|
+
],
|
|
134997
|
+
fallback: 3
|
|
134998
|
+
},
|
|
134999
|
+
{
|
|
135000
|
+
key: "activityExpandedToolLines",
|
|
135001
|
+
label: "blockrows.item_tool",
|
|
135002
|
+
values: [
|
|
135003
|
+
5,
|
|
135004
|
+
10,
|
|
135005
|
+
15,
|
|
135006
|
+
20,
|
|
135007
|
+
30
|
|
135008
|
+
],
|
|
135009
|
+
fallback: 15
|
|
135010
|
+
},
|
|
135011
|
+
{
|
|
135012
|
+
key: "activityExpandedThinkingLines",
|
|
135013
|
+
label: "blockrows.item_thinking",
|
|
135014
|
+
values: [
|
|
135015
|
+
5,
|
|
135016
|
+
10,
|
|
135017
|
+
15,
|
|
135018
|
+
20
|
|
135019
|
+
],
|
|
135020
|
+
fallback: 10
|
|
135021
|
+
}
|
|
135022
|
+
];
|
|
135023
|
+
let cache;
|
|
135024
|
+
function isActivityLineKey(value) {
|
|
135025
|
+
return ACTIVITY_LINE_SETTINGS.some((setting) => setting.key === value);
|
|
135026
|
+
}
|
|
135027
|
+
function findActivityLineSetting(key) {
|
|
135028
|
+
return ACTIVITY_LINE_SETTINGS.find((candidate) => candidate.key === key) ?? ACTIVITY_LINE_SETTINGS[0];
|
|
135029
|
+
}
|
|
135030
|
+
function resolve$1(stored, setting) {
|
|
135031
|
+
if (typeof stored !== "number" || !Number.isFinite(stored)) return setting.fallback;
|
|
135032
|
+
return setting.values.includes(stored) ? stored : setting.fallback;
|
|
135033
|
+
}
|
|
135034
|
+
function load() {
|
|
135035
|
+
const stored = readActivityLinePrefs();
|
|
135036
|
+
const settings = ACTIVITY_LINE_SETTINGS;
|
|
135037
|
+
return {
|
|
135038
|
+
collapsed: resolve$1(stored.activityCollapsedLines, settings[0]),
|
|
135039
|
+
expandedTool: resolve$1(stored.activityExpandedToolLines, settings[1]),
|
|
135040
|
+
expandedThinking: resolve$1(stored.activityExpandedThinkingLines, settings[2])
|
|
135041
|
+
};
|
|
135042
|
+
}
|
|
135043
|
+
/** Current row budgets. Cached: call `refreshActivityLines` after a change. */
|
|
135044
|
+
function getActivityLines() {
|
|
135045
|
+
cache ??= load();
|
|
135046
|
+
return cache;
|
|
135047
|
+
}
|
|
135048
|
+
/** Value currently in effect for one budget (never undefined). */
|
|
135049
|
+
function getActivityLineValue(key) {
|
|
135050
|
+
const lines = getActivityLines();
|
|
135051
|
+
if (key === "activityCollapsedLines") return lines.collapsed;
|
|
135052
|
+
if (key === "activityExpandedToolLines") return lines.expandedTool;
|
|
135053
|
+
return lines.expandedThinking;
|
|
135054
|
+
}
|
|
135055
|
+
/** Persist one budget and drop the cache so the next render picks it up. */
|
|
135056
|
+
function setActivityLineValue(key, value) {
|
|
135057
|
+
writeActivityLinePref(key, value);
|
|
135058
|
+
cache = void 0;
|
|
135059
|
+
}
|
|
135060
|
+
//#endregion
|
|
134804
135061
|
//#region src/tui/utils/speed-tracker.ts
|
|
134805
135062
|
/**
|
|
134806
135063
|
* Streaming-speed gauge for the live thinking indicator.
|
|
@@ -134957,7 +135214,9 @@ const BRANCH_LAST = " └─ ";
|
|
|
134957
135214
|
const BRANCH_PIPE = " │ ";
|
|
134958
135215
|
const TREE_PIPE_ROW = " │";
|
|
134959
135216
|
const THINKING_BODY_PREFIX = " ";
|
|
134960
|
-
|
|
135217
|
+
/** Cells of a background task notice bullet (`⠋ ` / `✓ ` / `✗ `). */
|
|
135218
|
+
const NOTICE_BULLET_WIDTH = 2;
|
|
135219
|
+
const THROTTLE_MS = 200;
|
|
134961
135220
|
/** Rates below this are noise: the live badge stays hidden until tokens flow. */
|
|
134962
135221
|
const MIN_RATE = .05;
|
|
134963
135222
|
const SEPARATOR = " · ";
|
|
@@ -134978,6 +135237,10 @@ const CARD_INDENT_RE = /^(\u001B\[[0-9;]*m)*( {2})/;
|
|
|
134978
135237
|
function countTokens(text) {
|
|
134979
135238
|
return text.trim().length === 0 ? 0 : estimateTokens(text);
|
|
134980
135239
|
}
|
|
135240
|
+
/** Non-empty, trimmed lines of one reasoning run. */
|
|
135241
|
+
function thinkingLines(text) {
|
|
135242
|
+
return text.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
135243
|
+
}
|
|
134981
135244
|
/**
|
|
134982
135245
|
* Drops the card's own two-cell status marker so a row prefix can take its
|
|
134983
135246
|
* place without shifting the row.
|
|
@@ -135119,10 +135382,8 @@ function condenseRowLabel(header, toolName, args, budget) {
|
|
|
135119
135382
|
var ActivityGroupComponent = class extends Container {
|
|
135120
135383
|
colors;
|
|
135121
135384
|
ui;
|
|
135122
|
-
|
|
135385
|
+
segments = [];
|
|
135123
135386
|
steps = /* @__PURE__ */ new Set();
|
|
135124
|
-
thinkingText = "";
|
|
135125
|
-
thinkingLive = false;
|
|
135126
135387
|
running = true;
|
|
135127
135388
|
expanded = false;
|
|
135128
135389
|
headerText;
|
|
@@ -135134,7 +135395,10 @@ var ActivityGroupComponent = class extends Container {
|
|
|
135134
135395
|
renderedWidth;
|
|
135135
135396
|
/** Token estimates per borrowed card, keyed by the result text they counted. */
|
|
135136
135397
|
toolTokenCache = /* @__PURE__ */ new WeakMap();
|
|
135137
|
-
|
|
135398
|
+
/** Token estimates per reasoning run, keyed by the segment they counted. */
|
|
135399
|
+
thinkingTokenCache = /* @__PURE__ */ new WeakMap();
|
|
135400
|
+
/** Reasoning text already shown when a notice interrupted the newest run. */
|
|
135401
|
+
interruptedThinking;
|
|
135138
135402
|
constructor(colors, ui) {
|
|
135139
135403
|
super();
|
|
135140
135404
|
this.colors = colors;
|
|
@@ -135148,7 +135412,7 @@ var ActivityGroupComponent = class extends Container {
|
|
|
135148
135412
|
}
|
|
135149
135413
|
/** True when the group owns neither reasoning nor tool calls. */
|
|
135150
135414
|
isEmpty() {
|
|
135151
|
-
return this.
|
|
135415
|
+
return this.segments.every((segment) => segment.kind === "thinking" && segment.text.trim().length === 0);
|
|
135152
135416
|
}
|
|
135153
135417
|
isExpanded() {
|
|
135154
135418
|
return this.expanded;
|
|
@@ -135158,8 +135422,9 @@ var ActivityGroupComponent = class extends Container {
|
|
|
135158
135422
|
* card is a no-op.
|
|
135159
135423
|
*/
|
|
135160
135424
|
attachTool(tc, step) {
|
|
135161
|
-
if (this.
|
|
135162
|
-
this.
|
|
135425
|
+
if (this.segments.some((segment) => segment.kind === "tool" && segment.tc === tc)) return;
|
|
135426
|
+
this.segments.push({
|
|
135427
|
+
kind: "tool",
|
|
135163
135428
|
tc,
|
|
135164
135429
|
step
|
|
135165
135430
|
});
|
|
@@ -135170,18 +135435,55 @@ var ActivityGroupComponent = class extends Container {
|
|
|
135170
135435
|
});
|
|
135171
135436
|
this.flushNow();
|
|
135172
135437
|
}
|
|
135173
|
-
/**
|
|
135174
|
-
|
|
135175
|
-
|
|
135176
|
-
|
|
135177
|
-
|
|
135178
|
-
|
|
135179
|
-
|
|
135180
|
-
|
|
135438
|
+
/** Adds a background task notice as the newest step of the timeline. */
|
|
135439
|
+
attachNotice(data) {
|
|
135440
|
+
const last = this.segments.at(-1);
|
|
135441
|
+
if (last !== void 0 && last.kind === "thinking" && last.live) {
|
|
135442
|
+
last.live = false;
|
|
135443
|
+
this.interruptedThinking = {
|
|
135444
|
+
text: last.text,
|
|
135445
|
+
length: last.text.length
|
|
135446
|
+
};
|
|
135447
|
+
}
|
|
135448
|
+
this.segments.push({
|
|
135449
|
+
kind: "notice",
|
|
135450
|
+
data
|
|
135451
|
+
});
|
|
135452
|
+
this.flushNow();
|
|
135453
|
+
}
|
|
135454
|
+
/**
|
|
135455
|
+
* Appends to the reasoning run streaming right now, opening a new step of the
|
|
135456
|
+
* timeline when the last step is a tool call or a reasoning run that already
|
|
135457
|
+
* ended. `live` drives the streaming rate in the header.
|
|
135458
|
+
*/
|
|
135459
|
+
appendThinking(text, live) {
|
|
135460
|
+
const interrupted = this.interruptedThinking;
|
|
135461
|
+
const split = interrupted !== void 0 && text.startsWith(interrupted.text);
|
|
135462
|
+
if (interrupted !== void 0 && !split) this.interruptedThinking = void 0;
|
|
135463
|
+
const body = split && interrupted !== void 0 ? text.slice(interrupted.length) : text;
|
|
135464
|
+
const last = this.segments.at(-1);
|
|
135465
|
+
if (last !== void 0 && last.kind === "thinking" && (last.live || last.text.trim().length === 0)) {
|
|
135466
|
+
if (last.text === body && last.live === live) return;
|
|
135467
|
+
const structureChanged = body.length === 0 !== (last.text.length === 0);
|
|
135468
|
+
last.text = body;
|
|
135469
|
+
last.live = live;
|
|
135470
|
+
if (structureChanged) this.flushNow();
|
|
135471
|
+
else this.scheduleFlush();
|
|
135472
|
+
return;
|
|
135473
|
+
}
|
|
135474
|
+
if (body.trim().length === 0) return;
|
|
135475
|
+
this.segments.push({
|
|
135476
|
+
kind: "thinking",
|
|
135477
|
+
text: body,
|
|
135478
|
+
live
|
|
135479
|
+
});
|
|
135480
|
+
this.flushNow();
|
|
135181
135481
|
}
|
|
135182
135482
|
endThinking() {
|
|
135183
|
-
|
|
135184
|
-
|
|
135483
|
+
this.interruptedThinking = void 0;
|
|
135484
|
+
const last = this.segments.at(-1);
|
|
135485
|
+
if (last === void 0 || last.kind !== "thinking" || !last.live) return;
|
|
135486
|
+
last.live = false;
|
|
135185
135487
|
this.flushNow();
|
|
135186
135488
|
}
|
|
135187
135489
|
/** Marks the producing turn as finished: the header stops spinning. */
|
|
@@ -135189,13 +135491,18 @@ var ActivityGroupComponent = class extends Container {
|
|
|
135189
135491
|
if (this.running === running) return;
|
|
135190
135492
|
this.running = running;
|
|
135191
135493
|
if (running) this.startSpinner();
|
|
135192
|
-
else
|
|
135494
|
+
else {
|
|
135495
|
+
this.stopSpinner();
|
|
135496
|
+
this.interruptedThinking = void 0;
|
|
135497
|
+
const last = this.segments.at(-1);
|
|
135498
|
+
if (last !== void 0 && last.kind === "thinking") last.live = false;
|
|
135499
|
+
}
|
|
135193
135500
|
this.flushNow();
|
|
135194
135501
|
}
|
|
135195
135502
|
setExpanded(expanded) {
|
|
135196
135503
|
if (this.expanded === expanded) return;
|
|
135197
135504
|
this.expanded = expanded;
|
|
135198
|
-
for (const
|
|
135505
|
+
for (const segment of this.segments) if (segment.kind === "tool") segment.tc.setExpanded(expanded);
|
|
135199
135506
|
this.flushNow();
|
|
135200
135507
|
}
|
|
135201
135508
|
/** Repaints after a borrowed card changed (results land via setResult). */
|
|
@@ -135224,7 +135531,7 @@ var ActivityGroupComponent = class extends Container {
|
|
|
135224
135531
|
*/
|
|
135225
135532
|
invalidate() {
|
|
135226
135533
|
this.renderedWidth = void 0;
|
|
135227
|
-
for (const
|
|
135534
|
+
for (const segment of this.segments) if (segment.kind === "tool") segment.tc.invalidate();
|
|
135228
135535
|
super.invalidate();
|
|
135229
135536
|
}
|
|
135230
135537
|
scheduleFlush() {
|
|
@@ -135233,7 +135540,7 @@ var ActivityGroupComponent = class extends Container {
|
|
|
135233
135540
|
this.throttleTimer = null;
|
|
135234
135541
|
this.rebuild(this.renderedWidth ?? 80);
|
|
135235
135542
|
this.ui?.requestRender();
|
|
135236
|
-
}, THROTTLE_MS
|
|
135543
|
+
}, THROTTLE_MS);
|
|
135237
135544
|
}
|
|
135238
135545
|
flushNow() {
|
|
135239
135546
|
if (this.throttleTimer !== null) {
|
|
@@ -135257,11 +135564,12 @@ var ActivityGroupComponent = class extends Container {
|
|
|
135257
135564
|
const marker = this.running ? chalk.hex(colors.roleThinking)(`${frame} `) : chalk.hex(colors.success)(STATUS_BULLET);
|
|
135258
135565
|
const label = this.running ? t("activitygroup.running") : t("activitygroup.done");
|
|
135259
135566
|
const parts = [];
|
|
135567
|
+
const toolCount = this.toolCount();
|
|
135260
135568
|
if (this.steps.size > 0) parts.push(t("activitygroup.steps", { count: String(this.steps.size) }));
|
|
135261
|
-
if (
|
|
135569
|
+
if (toolCount > 0) parts.push(t("activitygroup.tools", { count: String(toolCount) }));
|
|
135262
135570
|
parts.push(t("activitygroup.tokens", { tok: this.formatTokens(this.blockTokens()) }));
|
|
135263
135571
|
const stats = chalk.dim(SEPARATOR + parts.join(SEPARATOR));
|
|
135264
|
-
const speed = this.
|
|
135572
|
+
const speed = this.liveThinking() ? getSharedSpeedTracker().getSpeed() : 0;
|
|
135265
135573
|
const rate = speed > MIN_RATE ? chalk.hex(lerpHex(colors.textDim, colors.primary, easeSpeedRatio(speed / 200)))(t("activitygroup.rate", { rate: speed.toFixed(1) })) : chalk.dim(t("activitygroup.rate", { rate: "-" }));
|
|
135266
135574
|
const hint = chalk.dim(this.expanded ? t("activitygroup.hint_collapse") : t("activitygroup.hint_expand"));
|
|
135267
135575
|
const head = `${marker}${chalk.hex(colors.primary).bold(label)}${stats}`;
|
|
@@ -135274,68 +135582,126 @@ var ActivityGroupComponent = class extends Container {
|
|
|
135274
135582
|
if (visibleWidth(bare) <= width) return bare;
|
|
135275
135583
|
return chalk.hex(colors.primary).bold(truncateToWidth(label, Math.max(1, width - 2), "…"));
|
|
135276
135584
|
}
|
|
135277
|
-
/**
|
|
135585
|
+
/**
|
|
135586
|
+
* Collapsed state: the newest steps of the timeline, kept in chronological
|
|
135587
|
+
* order so the block still reads top-down. Reasoning runs and tool calls share
|
|
135588
|
+
* the same row budget — by default the newest step plus the reasoning run that
|
|
135589
|
+
* led to it.
|
|
135590
|
+
*/
|
|
135278
135591
|
buildCollapsedRows(width) {
|
|
135279
|
-
const
|
|
135280
|
-
const
|
|
135281
|
-
|
|
135282
|
-
const
|
|
135283
|
-
|
|
135284
|
-
|
|
135285
|
-
|
|
135286
|
-
|
|
135592
|
+
const budget = Math.max(1, getActivityLines().collapsed - 1);
|
|
135593
|
+
const shown = this.segments.slice(Math.max(0, this.segments.length - budget));
|
|
135594
|
+
shown.forEach((segment, index) => {
|
|
135595
|
+
const isLast = index === shown.length - 1;
|
|
135596
|
+
if (segment.kind === "tool") {
|
|
135597
|
+
const row = this.toolRow(segment.tc, width, 3);
|
|
135598
|
+
this.bodyContainer.addChild(new Text(`${isLast ? BRANCH_LAST : BRANCH_FIRST}${this.statusGlyph(row)} ${row.header}`, 0, 0));
|
|
135599
|
+
return;
|
|
135600
|
+
}
|
|
135601
|
+
if (segment.kind === "notice") {
|
|
135602
|
+
this.bodyContainer.addChild(this.noticeRow(segment.data, width, isLast));
|
|
135603
|
+
return;
|
|
135604
|
+
}
|
|
135605
|
+
this.bodyContainer.addChild(this.thinkingSummaryRow(segment, width, isLast));
|
|
135606
|
+
});
|
|
135287
135607
|
}
|
|
135288
|
-
/**
|
|
135608
|
+
/**
|
|
135609
|
+
* Expanded state: the whole timeline in order. Rows are budgeted for the block
|
|
135610
|
+
* as a whole, so a turn with dozens of steps cannot expand into hundreds of
|
|
135611
|
+
* rows; whatever does not fit is summarised in one row at the end.
|
|
135612
|
+
*/
|
|
135289
135613
|
buildExpandedRows(width) {
|
|
135290
|
-
const colors = this.colors;
|
|
135291
|
-
const hasThinking = this.thinkingText.trim().length > 0;
|
|
135292
135614
|
this.bodyContainer.addChild(new Text(TREE_PIPE_ROW, 0, 0));
|
|
135293
|
-
const toolRows = this.tools.map((entry) => ({ row: this.toolRow(entry.tc, width, 15) }));
|
|
135294
135615
|
let used = 1;
|
|
135295
|
-
let
|
|
135296
|
-
let
|
|
135297
|
-
|
|
135298
|
-
const
|
|
135299
|
-
|
|
135300
|
-
|
|
135301
|
-
|
|
135616
|
+
let hidden = 0;
|
|
135617
|
+
for (let index = 0; index < this.segments.length; index += 1) {
|
|
135618
|
+
const segment = this.segments[index];
|
|
135619
|
+
const isLastStep = index === this.segments.length - 1;
|
|
135620
|
+
const rows = this.segmentRows(segment, width, isLastStep);
|
|
135621
|
+
const budget = 60 - (isLastStep ? 0 : 1);
|
|
135622
|
+
if (index > 0 && used + rows.cost > budget) {
|
|
135623
|
+
hidden = this.segments.length - index;
|
|
135624
|
+
break;
|
|
135302
135625
|
}
|
|
135303
|
-
const
|
|
135304
|
-
|
|
135626
|
+
for (const component of rows.components) this.bodyContainer.addChild(component);
|
|
135627
|
+
used += rows.cost;
|
|
135628
|
+
}
|
|
135629
|
+
if (hidden > 0) {
|
|
135630
|
+
const summary = t("activitygroup.segments_hidden", { count: String(hidden) });
|
|
135631
|
+
this.bodyContainer.addChild(new Text(`${BRANCH_PIPE}${chalk.dim(summary)}`, 0, 0));
|
|
135632
|
+
}
|
|
135633
|
+
}
|
|
135634
|
+
/** Renders one step of the timeline: its branch row plus its own body rows. */
|
|
135635
|
+
segmentRows(segment, width, isLast) {
|
|
135636
|
+
if (segment.kind === "tool") {
|
|
135637
|
+
const row = this.toolRow(segment.tc, width, getActivityLines().expandedTool);
|
|
135638
|
+
const components = [new Text(`${isLast ? BRANCH_LAST : BRANCH_FIRST}${this.statusGlyph(row)} ${row.header}`, 0, 0)];
|
|
135305
135639
|
const continuation = isLast ? THINKING_BODY_PREFIX : BRANCH_PIPE;
|
|
135306
|
-
for (const line of row.body)
|
|
135307
|
-
|
|
135308
|
-
|
|
135309
|
-
|
|
135310
|
-
|
|
135311
|
-
|
|
135312
|
-
|
|
135313
|
-
this.
|
|
135314
|
-
|
|
135315
|
-
}
|
|
135316
|
-
|
|
135317
|
-
|
|
135318
|
-
|
|
135319
|
-
|
|
135320
|
-
|
|
135321
|
-
|
|
135322
|
-
|
|
135323
|
-
|
|
135324
|
-
|
|
135325
|
-
|
|
135326
|
-
|
|
135640
|
+
for (const line of row.body) components.push(new Text(`${continuation}${line}`, 0, 0));
|
|
135641
|
+
return {
|
|
135642
|
+
components,
|
|
135643
|
+
cost: 1 + row.body.length
|
|
135644
|
+
};
|
|
135645
|
+
}
|
|
135646
|
+
if (segment.kind === "notice") return {
|
|
135647
|
+
components: [this.noticeRow(segment.data, width, isLast)],
|
|
135648
|
+
cost: 1
|
|
135649
|
+
};
|
|
135650
|
+
return this.thinkingSegmentRows(segment, width, isLast);
|
|
135651
|
+
}
|
|
135652
|
+
/** One background task notice, kept to a single row. */
|
|
135653
|
+
noticeRow(data, width, isLast) {
|
|
135654
|
+
const prefix = isLast ? BRANCH_LAST : BRANCH_FIRST;
|
|
135655
|
+
const view = renderBackgroundStatus(data, this.colors, Math.max(1, width - visibleWidth(prefix) - NOTICE_BULLET_WIDTH));
|
|
135656
|
+
return new Text(`${prefix}${view.bullet}${view.text}`, 0, 0);
|
|
135657
|
+
}
|
|
135658
|
+
/**
|
|
135659
|
+
* One reasoning run: a label row plus as many of its lines as its own budget
|
|
135660
|
+
* allows. Lines keep their order; the oldest end of a live run (or the newest
|
|
135661
|
+
* end of a finished one) is dropped until the budget fits.
|
|
135662
|
+
*/
|
|
135663
|
+
thinkingSegmentRows(segment, width, isLast) {
|
|
135664
|
+
const colors = this.colors;
|
|
135665
|
+
const lines = thinkingLines(segment.text);
|
|
135666
|
+
if (lines.length === 0) return {
|
|
135667
|
+
components: [],
|
|
135668
|
+
cost: 0
|
|
135669
|
+
};
|
|
135670
|
+
const continuation = isLast ? THINKING_BODY_PREFIX : BRANCH_PIPE;
|
|
135671
|
+
const components = [new Text(`${isLast ? BRANCH_LAST : BRANCH_FIRST}${chalk.hex(colors.roleThinking)(t("activitygroup.thinking_label"))}`, 0, 0)];
|
|
135672
|
+
let cost = 1;
|
|
135673
|
+
const budget = getActivityLines().expandedThinking;
|
|
135674
|
+
const inner = Math.max(1, width - visibleWidth(continuation));
|
|
135675
|
+
const height = (line) => new WrappedLine(continuation, continuation, line).render(inner).length;
|
|
135676
|
+
let selected = segment.live ? lines.slice(-budget) : lines.slice(0, budget);
|
|
135677
|
+
while (selected.length > 1 && selected.reduce((sum, line) => sum + height(line), 0) > budget) selected = segment.live ? selected.slice(1) : selected.slice(0, -1);
|
|
135327
135678
|
const first = selected[0];
|
|
135328
|
-
if (selected.length === 1 && first !== void 0 && height(first) >
|
|
135679
|
+
if (selected.length === 1 && first !== void 0 && height(first) > budget) selected = [truncateToWidth(first, inner * budget, "…")];
|
|
135329
135680
|
for (const line of selected) {
|
|
135330
|
-
|
|
135331
|
-
|
|
135332
|
-
used += height(line);
|
|
135681
|
+
components.push(new WrappedLine(continuation, continuation, chalk.hex(colors.roleThinking)(line)));
|
|
135682
|
+
cost += height(line);
|
|
135333
135683
|
}
|
|
135334
|
-
const
|
|
135335
|
-
if (
|
|
135336
|
-
const hint =
|
|
135337
|
-
|
|
135684
|
+
const hiddenLines = lines.length - selected.length;
|
|
135685
|
+
if (hiddenLines > 0) {
|
|
135686
|
+
const hint = segment.live ? t("activitygroup.thinking_earlier", { count: String(hiddenLines) }) : t("activitygroup.thinking_more", { count: String(hiddenLines) });
|
|
135687
|
+
components.push(new Text(`${continuation}${chalk.dim(hint)}`, 0, 0));
|
|
135688
|
+
cost += 1;
|
|
135338
135689
|
}
|
|
135690
|
+
return {
|
|
135691
|
+
components,
|
|
135692
|
+
cost
|
|
135693
|
+
};
|
|
135694
|
+
}
|
|
135695
|
+
/** Number of tool calls on the timeline. */
|
|
135696
|
+
toolCount() {
|
|
135697
|
+
let count = 0;
|
|
135698
|
+
for (const segment of this.segments) if (segment.kind === "tool") count += 1;
|
|
135699
|
+
return count;
|
|
135700
|
+
}
|
|
135701
|
+
/** True while the newest step of the timeline is a reasoning run still streaming. */
|
|
135702
|
+
liveThinking() {
|
|
135703
|
+
const last = this.segments.at(-1);
|
|
135704
|
+
return last !== void 0 && last.kind === "thinking" && last.live;
|
|
135339
135705
|
}
|
|
135340
135706
|
/**
|
|
135341
135707
|
* Renders one borrowed card at the width left over by the row prefix and
|
|
@@ -135373,29 +135739,27 @@ var ActivityGroupComponent = class extends Container {
|
|
|
135373
135739
|
}
|
|
135374
135740
|
return chalk.hex(this.colors.success)("✓");
|
|
135375
135741
|
}
|
|
135376
|
-
thinkingLines() {
|
|
135377
|
-
return this.thinkingText.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
135378
|
-
}
|
|
135379
135742
|
/**
|
|
135380
|
-
* Collapsed reasoning row: the first
|
|
135381
|
-
*
|
|
135382
|
-
*
|
|
135743
|
+
* Collapsed reasoning row: the run's first line clipped to whatever space the
|
|
135744
|
+
* row can still hold at this width, so a narrow terminal cannot wrap the block
|
|
135745
|
+
* past its height. The token estimate lives in the block header only.
|
|
135383
135746
|
*/
|
|
135384
|
-
|
|
135385
|
-
const first =
|
|
135747
|
+
thinkingSummaryRow(segment, width, isLast) {
|
|
135748
|
+
const first = thinkingLines(segment.text)[0] ?? "";
|
|
135386
135749
|
const label = t("activitygroup.thinking_summary", { summary: "" });
|
|
135387
|
-
const
|
|
135388
|
-
const cells = Math.max(1,
|
|
135750
|
+
const used = visibleWidth(isLast ? BRANCH_LAST : BRANCH_FIRST) + visibleWidth(label);
|
|
135751
|
+
const cells = Math.max(1, width - used);
|
|
135389
135752
|
const summary = chalk.hex(this.colors.roleThinking)(t("activitygroup.thinking_summary", { summary: truncateToWidth(first, cells, "…") }));
|
|
135390
|
-
return `${BRANCH_LAST
|
|
135753
|
+
return new Text(`${isLast ? BRANCH_LAST : BRANCH_FIRST}${summary}`, 0, 0);
|
|
135391
135754
|
}
|
|
135392
135755
|
/**
|
|
135393
135756
|
* Token estimate for the whole block: the reasoning text plus every result the
|
|
135394
135757
|
* block owns, i.e. how much material this stretch of work moved through.
|
|
135395
135758
|
*/
|
|
135396
135759
|
blockTokens() {
|
|
135397
|
-
let tokens =
|
|
135398
|
-
for (const
|
|
135760
|
+
let tokens = 0;
|
|
135761
|
+
for (const segment of this.segments) if (segment.kind === "tool") tokens += this.toolTokens(segment.tc);
|
|
135762
|
+
else if (segment.kind === "thinking") tokens += this.thinkingTokens(segment);
|
|
135399
135763
|
return tokens;
|
|
135400
135764
|
}
|
|
135401
135765
|
/** Result tokens of one card, counted once per distinct result text. */
|
|
@@ -135416,14 +135780,14 @@ var ActivityGroupComponent = class extends Container {
|
|
|
135416
135780
|
* the streaming speed gauge so both numbers agree. Empty reasoning counts as
|
|
135417
135781
|
* zero: the estimator's floor of one token is for per-delta rates.
|
|
135418
135782
|
*/
|
|
135419
|
-
thinkingTokens() {
|
|
135420
|
-
const cached = this.thinkingTokenCache;
|
|
135421
|
-
if (cached !== void 0 && cached.text ===
|
|
135422
|
-
const tokens = countTokens(
|
|
135423
|
-
this.thinkingTokenCache
|
|
135424
|
-
text:
|
|
135783
|
+
thinkingTokens(segment) {
|
|
135784
|
+
const cached = this.thinkingTokenCache.get(segment);
|
|
135785
|
+
if (cached !== void 0 && cached.text === segment.text) return cached.tokens;
|
|
135786
|
+
const tokens = countTokens(segment.text);
|
|
135787
|
+
this.thinkingTokenCache.set(segment, {
|
|
135788
|
+
text: segment.text,
|
|
135425
135789
|
tokens
|
|
135426
|
-
};
|
|
135790
|
+
});
|
|
135427
135791
|
return tokens;
|
|
135428
135792
|
}
|
|
135429
135793
|
formatTokens(tokens) {
|
|
@@ -135442,7 +135806,7 @@ var ActivityGroupComponent = class extends Container {
|
|
|
135442
135806
|
this.spinnerFrame = (this.spinnerFrame + steps) % BRAILLE_SPINNER_FRAMES.length;
|
|
135443
135807
|
this.lastSpinnerTickAt += steps * 80;
|
|
135444
135808
|
const width = this.renderedWidth ?? 80;
|
|
135445
|
-
if (!this.expanded && this.
|
|
135809
|
+
if (!this.expanded && this.segments.some((segment) => segment.kind === "tool" && segment.tc.resultView === void 0)) this.rebuild(width);
|
|
135446
135810
|
else this.headerText.setText(this.buildHeader(width));
|
|
135447
135811
|
this.ui?.requestRender();
|
|
135448
135812
|
}
|
|
@@ -135666,244 +136030,6 @@ var AssistantMessageComponent = class {
|
|
|
135666
136030
|
}
|
|
135667
136031
|
};
|
|
135668
136032
|
//#endregion
|
|
135669
|
-
//#region src/tui/components/messages/background-agent-status.ts
|
|
135670
|
-
var BackgroundAgentStatusComponent = class {
|
|
135671
|
-
data;
|
|
135672
|
-
colors;
|
|
135673
|
-
bullet;
|
|
135674
|
-
textComponent;
|
|
135675
|
-
cachedWidth;
|
|
135676
|
-
cachedLines;
|
|
135677
|
-
constructor(data, colors) {
|
|
135678
|
-
this.data = data;
|
|
135679
|
-
this.colors = colors;
|
|
135680
|
-
const tone = data.phase === "started" ? colors.primary : data.phase === "completed" ? colors.success : colors.error;
|
|
135681
|
-
this.bullet = data.phase === "failed" ? chalk.hex(tone)(FAILURE_MARK) : chalk.hex(tone)(STATUS_BULLET);
|
|
135682
|
-
const text = chalk.hex(tone)(data.headline) + (data.detail !== void 0 && data.detail.length > 0 ? chalk.hex(colors.textDim)(` (${data.detail})`) : "");
|
|
135683
|
-
this.textComponent = new Text(text, 0, 0);
|
|
135684
|
-
}
|
|
135685
|
-
invalidate() {
|
|
135686
|
-
this.cachedWidth = void 0;
|
|
135687
|
-
this.cachedLines = void 0;
|
|
135688
|
-
}
|
|
135689
|
-
render(width) {
|
|
135690
|
-
if (this.cachedLines !== void 0 && this.cachedWidth === width) return this.cachedLines;
|
|
135691
|
-
const contentWidth = Math.max(1, width - 2);
|
|
135692
|
-
const lines = ["", ...this.textComponent.render(contentWidth).map((line, index) => (index === 0 ? this.bullet : " ") + line)];
|
|
135693
|
-
this.cachedWidth = width;
|
|
135694
|
-
this.cachedLines = lines;
|
|
135695
|
-
return lines;
|
|
135696
|
-
}
|
|
135697
|
-
};
|
|
135698
|
-
//#endregion
|
|
135699
|
-
//#region src/tui/components/messages/read-group.ts
|
|
135700
|
-
const THROTTLE_MS = 200;
|
|
135701
|
-
const CONFLICT_MARKER_RE = /^(<<<<<<<|=======|>>>>>>>)/;
|
|
135702
|
-
function detectConflictMarkers(contentLines) {
|
|
135703
|
-
for (const raw of contentLines) {
|
|
135704
|
-
const tabIdx = raw.indexOf(" ");
|
|
135705
|
-
const line = tabIdx >= 0 ? raw.slice(tabIdx + 1) : raw;
|
|
135706
|
-
if (CONFLICT_MARKER_RE.test(line)) return true;
|
|
135707
|
-
}
|
|
135708
|
-
return false;
|
|
135709
|
-
}
|
|
135710
|
-
function parseReadGroupOutput(output) {
|
|
135711
|
-
const results = [];
|
|
135712
|
-
const lines = output.split("\n");
|
|
135713
|
-
let currentPath;
|
|
135714
|
-
let currentLines = [];
|
|
135715
|
-
const finishSection = (path, contentLines) => {
|
|
135716
|
-
if (path === void 0) return;
|
|
135717
|
-
const text = contentLines.join("\n");
|
|
135718
|
-
if (text.trimStart().startsWith("[ERROR]")) {
|
|
135719
|
-
results.push({
|
|
135720
|
-
filePath: path,
|
|
135721
|
-
lines: 0,
|
|
135722
|
-
failed: true
|
|
135723
|
-
});
|
|
135724
|
-
return;
|
|
135725
|
-
}
|
|
135726
|
-
const systemMatch = text.match(/<system>([\s\S]*?)<\/system>\s*$/);
|
|
135727
|
-
let lineCount = 0;
|
|
135728
|
-
if (systemMatch !== null) {
|
|
135729
|
-
const systemBody = systemMatch[1];
|
|
135730
|
-
if (systemBody !== void 0) {
|
|
135731
|
-
const lineMatch = systemBody.match(/(\d+)\s+lines?\s+read\s+from\s+file/);
|
|
135732
|
-
if (lineMatch !== null) {
|
|
135733
|
-
const count = lineMatch[1];
|
|
135734
|
-
if (count !== void 0) lineCount = parseInt(count, 10);
|
|
135735
|
-
}
|
|
135736
|
-
}
|
|
135737
|
-
}
|
|
135738
|
-
const hasConflicts = detectConflictMarkers(contentLines);
|
|
135739
|
-
results.push({
|
|
135740
|
-
filePath: path,
|
|
135741
|
-
lines: lineCount,
|
|
135742
|
-
failed: false,
|
|
135743
|
-
hasConflicts
|
|
135744
|
-
});
|
|
135745
|
-
};
|
|
135746
|
-
for (const line of lines) {
|
|
135747
|
-
const match = line.match(/^---\s+(.+?)\s+---$/);
|
|
135748
|
-
if (match !== null) {
|
|
135749
|
-
finishSection(currentPath, currentLines);
|
|
135750
|
-
currentPath = match[1];
|
|
135751
|
-
currentLines = [];
|
|
135752
|
-
} else if (currentPath !== void 0) currentLines.push(line);
|
|
135753
|
-
}
|
|
135754
|
-
finishSection(currentPath, currentLines);
|
|
135755
|
-
return results;
|
|
135756
|
-
}
|
|
135757
|
-
var ReadGroupComponent = class extends Container {
|
|
135758
|
-
colors;
|
|
135759
|
-
ui;
|
|
135760
|
-
entries = [];
|
|
135761
|
-
directResults;
|
|
135762
|
-
headerText;
|
|
135763
|
-
bodyContainer;
|
|
135764
|
-
throttleTimer = null;
|
|
135765
|
-
lastFlushPhases = /* @__PURE__ */ new Map();
|
|
135766
|
-
constructor(colors, ui) {
|
|
135767
|
-
super();
|
|
135768
|
-
this.colors = colors;
|
|
135769
|
-
this.ui = ui;
|
|
135770
|
-
this.addChild(new Spacer(1));
|
|
135771
|
-
this.headerText = new Text("", 0, 0);
|
|
135772
|
-
this.addChild(this.headerText);
|
|
135773
|
-
this.bodyContainer = new Container();
|
|
135774
|
-
this.addChild(this.bodyContainer);
|
|
135775
|
-
}
|
|
135776
|
-
size() {
|
|
135777
|
-
return this.directResults?.length ?? this.entries.length;
|
|
135778
|
-
}
|
|
135779
|
-
setResults(results) {
|
|
135780
|
-
this.directResults = results;
|
|
135781
|
-
this.flushRender();
|
|
135782
|
-
}
|
|
135783
|
-
/**
|
|
135784
|
-
* Borrows a standalone `ToolCallComponent` into the group as a hidden state
|
|
135785
|
-
* container. Snapshot changes trigger throttled refreshes. Re-attaching the
|
|
135786
|
-
* same toolCallId is a no-op.
|
|
135787
|
-
*/
|
|
135788
|
-
attach(toolCallId, tc) {
|
|
135789
|
-
if (this.entries.some((e) => e.toolCallId === toolCallId)) return;
|
|
135790
|
-
this.entries.push({
|
|
135791
|
-
toolCallId,
|
|
135792
|
-
tc
|
|
135793
|
-
});
|
|
135794
|
-
tc.setSnapshotListener(() => {
|
|
135795
|
-
this.scheduleRender();
|
|
135796
|
-
});
|
|
135797
|
-
this.flushRender();
|
|
135798
|
-
}
|
|
135799
|
-
/**
|
|
135800
|
-
* The pending -> done/failed transition is the important visible change, so
|
|
135801
|
-
* it refreshes immediately. Other changes are throttled.
|
|
135802
|
-
*/
|
|
135803
|
-
scheduleRender() {
|
|
135804
|
-
if (this.detectPhaseTransition()) {
|
|
135805
|
-
this.flushRender();
|
|
135806
|
-
return;
|
|
135807
|
-
}
|
|
135808
|
-
if (this.throttleTimer !== null) return;
|
|
135809
|
-
this.throttleTimer = setTimeout(() => {
|
|
135810
|
-
this.throttleTimer = null;
|
|
135811
|
-
this.flushRender();
|
|
135812
|
-
}, THROTTLE_MS);
|
|
135813
|
-
}
|
|
135814
|
-
detectPhaseTransition() {
|
|
135815
|
-
for (const e of this.entries) {
|
|
135816
|
-
const phase = e.tc.getReadSnapshot().phase;
|
|
135817
|
-
if (this.lastFlushPhases.get(e.toolCallId) !== phase) return true;
|
|
135818
|
-
}
|
|
135819
|
-
return false;
|
|
135820
|
-
}
|
|
135821
|
-
flushRender() {
|
|
135822
|
-
if (this.throttleTimer !== null) {
|
|
135823
|
-
clearTimeout(this.throttleTimer);
|
|
135824
|
-
this.throttleTimer = null;
|
|
135825
|
-
}
|
|
135826
|
-
if (this.directResults !== void 0) {
|
|
135827
|
-
this.renderDirectResults();
|
|
135828
|
-
return;
|
|
135829
|
-
}
|
|
135830
|
-
const snapshots = this.entries.map((e) => e.tc.getReadSnapshot());
|
|
135831
|
-
let pending = 0;
|
|
135832
|
-
let failed = 0;
|
|
135833
|
-
let totalLines = 0;
|
|
135834
|
-
for (const snap of snapshots) if (snap.phase === "pending") pending += 1;
|
|
135835
|
-
else if (snap.phase === "failed") failed += 1;
|
|
135836
|
-
else totalLines += snap.lines;
|
|
135837
|
-
this.headerText.setText(this.buildHeader(snapshots.length, pending, failed, totalLines));
|
|
135838
|
-
this.bodyContainer.clear();
|
|
135839
|
-
const visibleSnapshots = snapshots.filter((snap) => snap.filePath !== void 0 && snap.filePath.length > 0);
|
|
135840
|
-
visibleSnapshots.forEach((snap, idx) => {
|
|
135841
|
-
const isLast = idx === visibleSnapshots.length - 1;
|
|
135842
|
-
this.addBodyBranch(snap.filePath ?? "", isLast, this.buildBodyTail(snap));
|
|
135843
|
-
});
|
|
135844
|
-
this.lastFlushPhases.clear();
|
|
135845
|
-
this.entries.forEach((entry, i) => {
|
|
135846
|
-
const snap = snapshots[i];
|
|
135847
|
-
if (snap !== void 0) this.lastFlushPhases.set(entry.toolCallId, snap.phase);
|
|
135848
|
-
});
|
|
135849
|
-
this.invalidate();
|
|
135850
|
-
this.ui?.requestRender();
|
|
135851
|
-
}
|
|
135852
|
-
renderDirectResults() {
|
|
135853
|
-
const results = this.directResults ?? [];
|
|
135854
|
-
let failed = 0;
|
|
135855
|
-
let totalLines = 0;
|
|
135856
|
-
for (const r of results) if (r.failed) failed += 1;
|
|
135857
|
-
else totalLines += r.lines;
|
|
135858
|
-
this.headerText.setText(this.buildHeader(results.length, 0, failed, totalLines));
|
|
135859
|
-
this.bodyContainer.clear();
|
|
135860
|
-
results.forEach((r, idx) => {
|
|
135861
|
-
const isLast = idx === results.length - 1;
|
|
135862
|
-
this.addBodyBranch(r.filePath, isLast, this.buildDirectBodyTail(r));
|
|
135863
|
-
});
|
|
135864
|
-
this.invalidate();
|
|
135865
|
-
this.ui?.requestRender();
|
|
135866
|
-
}
|
|
135867
|
-
buildHeader(total, pending, failed, totalLines) {
|
|
135868
|
-
const colors = this.colors;
|
|
135869
|
-
const dim = chalk.dim;
|
|
135870
|
-
if (pending > 0) return `${chalk.hex(colors.roleAssistant)(STATUS_BULLET)}${chalk.hex(colors.primary).bold(t("readgroup.reading", { count: total }))}`;
|
|
135871
|
-
if (failed === total) return `${chalk.hex(colors.error)("✗ ")}${chalk.hex(colors.error).bold(t("readgroup.read", { count: total }))}${chalk.hex(colors.error)(t("readgroup.failed_suffix"))}`;
|
|
135872
|
-
return `${chalk.hex(colors.success)(STATUS_BULLET)}${chalk.hex(colors.primary).bold(t("readgroup.read", { count: total }))}${dim(t("readgroup.lines_suffix", { count: totalLines }))}${failed > 0 ? chalk.hex(colors.error)(t("readgroup.failed_count", { count: failed })) : ""}`;
|
|
135873
|
-
}
|
|
135874
|
-
/**
|
|
135875
|
-
* Renders one tree-branch body line with a hanging-indent continuation,
|
|
135876
|
-
* so a path longer than the viewport keeps its branch connector instead
|
|
135877
|
-
* of breaking the tree.
|
|
135878
|
-
*/
|
|
135879
|
-
addBodyBranch(path, isLast, tail) {
|
|
135880
|
-
const prefix = ` ${isLast ? "└─" : "├─"} `;
|
|
135881
|
-
const continuation = isLast ? " " : " │ ";
|
|
135882
|
-
this.bodyContainer.addChild(new WrappedLine(prefix, continuation, `${chalk.hex(this.colors.text)(path)}${tail}`));
|
|
135883
|
-
}
|
|
135884
|
-
buildBodyTail(snap) {
|
|
135885
|
-
const dim = chalk.dim;
|
|
135886
|
-
if (snap.phase === "pending") return dim(t("readgroup.reading_suffix"));
|
|
135887
|
-
if (snap.phase === "failed") return chalk.hex(this.colors.error)(t("readgroup.failed_suffix"));
|
|
135888
|
-
return dim(t("readgroup.lines_suffix", { count: snap.lines }));
|
|
135889
|
-
}
|
|
135890
|
-
buildDirectBodyTail(result) {
|
|
135891
|
-
const dim = chalk.dim;
|
|
135892
|
-
if (result.failed) return chalk.hex(this.colors.error)(t("readgroup.failed_suffix"));
|
|
135893
|
-
let tail = dim(t("readgroup.lines_suffix", { count: result.lines }));
|
|
135894
|
-
if (result.hasConflicts) tail = `${tail}${chalk.hex(this.colors.warning)(` ⚠ ${t("readgroup.conflict_suffix")}`)}`;
|
|
135895
|
-
return tail;
|
|
135896
|
-
}
|
|
135897
|
-
/** Releases throttle timers so destroyed components cannot refresh later. */
|
|
135898
|
-
dispose() {
|
|
135899
|
-
if (this.throttleTimer !== null) {
|
|
135900
|
-
clearTimeout(this.throttleTimer);
|
|
135901
|
-
this.throttleTimer = null;
|
|
135902
|
-
}
|
|
135903
|
-
for (const e of this.entries) e.tc.setSnapshotListener(void 0);
|
|
135904
|
-
}
|
|
135905
|
-
};
|
|
135906
|
-
//#endregion
|
|
135907
136033
|
//#region src/tui/components/messages/skill-activation.ts
|
|
135908
136034
|
/**
|
|
135909
136035
|
* Skill activation card.
|
|
@@ -137058,6 +137184,76 @@ const readMediaSummary = (toolCall, result, ctx) => {
|
|
|
137058
137184
|
return out;
|
|
137059
137185
|
};
|
|
137060
137186
|
//#endregion
|
|
137187
|
+
//#region src/tui/components/messages/tool-renderers/read-group-list.ts
|
|
137188
|
+
const CONFLICT_MARKER_RE = /^(<<<<<<<|=======|>>>>>>>)/;
|
|
137189
|
+
function detectConflictMarkers(contentLines) {
|
|
137190
|
+
for (const raw of contentLines) {
|
|
137191
|
+
const tabIdx = raw.indexOf(" ");
|
|
137192
|
+
const line = tabIdx >= 0 ? raw.slice(tabIdx + 1) : raw;
|
|
137193
|
+
if (CONFLICT_MARKER_RE.test(line)) return true;
|
|
137194
|
+
}
|
|
137195
|
+
return false;
|
|
137196
|
+
}
|
|
137197
|
+
/** Parses the `--- path ---` sections of the batch reader's output. */
|
|
137198
|
+
function parseReadGroupOutput(output) {
|
|
137199
|
+
const results = [];
|
|
137200
|
+
const lines = output.split("\n");
|
|
137201
|
+
let currentPath;
|
|
137202
|
+
let currentLines = [];
|
|
137203
|
+
const finishSection = (path, contentLines) => {
|
|
137204
|
+
if (path === void 0) return;
|
|
137205
|
+
const text = contentLines.join("\n");
|
|
137206
|
+
if (text.trimStart().startsWith("[ERROR]")) {
|
|
137207
|
+
results.push({
|
|
137208
|
+
filePath: path,
|
|
137209
|
+
lines: 0,
|
|
137210
|
+
failed: true,
|
|
137211
|
+
hasConflicts: false
|
|
137212
|
+
});
|
|
137213
|
+
return;
|
|
137214
|
+
}
|
|
137215
|
+
let lineCount = 0;
|
|
137216
|
+
for (const match of text.matchAll(/(\d+)\s+lines?\s+read\s+from\s+file/g)) {
|
|
137217
|
+
const count = match[1];
|
|
137218
|
+
if (count !== void 0) lineCount = parseInt(count, 10);
|
|
137219
|
+
}
|
|
137220
|
+
const hasConflicts = detectConflictMarkers(contentLines);
|
|
137221
|
+
results.push({
|
|
137222
|
+
filePath: path,
|
|
137223
|
+
lines: lineCount,
|
|
137224
|
+
failed: false,
|
|
137225
|
+
hasConflicts
|
|
137226
|
+
});
|
|
137227
|
+
};
|
|
137228
|
+
for (const line of lines) {
|
|
137229
|
+
const match = line.match(/^---\s+(.+?)\s+---$/);
|
|
137230
|
+
if (match !== null) {
|
|
137231
|
+
finishSection(currentPath, currentLines);
|
|
137232
|
+
currentPath = match[1];
|
|
137233
|
+
currentLines = [];
|
|
137234
|
+
} else if (currentPath !== void 0) currentLines.push(line);
|
|
137235
|
+
}
|
|
137236
|
+
finishSection(currentPath, currentLines);
|
|
137237
|
+
return results;
|
|
137238
|
+
}
|
|
137239
|
+
const readGroupListSummary = (toolCall, result, ctx) => {
|
|
137240
|
+
if (result.is_error) return renderTruncated(toolCall, result, ctx);
|
|
137241
|
+
if (!ctx.expanded) return [];
|
|
137242
|
+
const entries = parseReadGroupOutput(result.output);
|
|
137243
|
+
if (entries.length === 0) return renderTruncated(toolCall, result, ctx);
|
|
137244
|
+
const shown = entries.slice(0, 15);
|
|
137245
|
+
const rows = shown.map((entry) => {
|
|
137246
|
+
const path = chalk.hex(ctx.colors.text)(entry.filePath);
|
|
137247
|
+
if (entry.failed) return `${path}${chalk.hex(ctx.colors.error)(t("readgroup.failed_suffix"))}`;
|
|
137248
|
+
let tail = chalk.dim(t("readgroup.lines_suffix", { count: String(entry.lines) }));
|
|
137249
|
+
if (entry.hasConflicts) tail += chalk.hex(ctx.colors.warning)(` ⚠ ${t("readgroup.conflict_suffix")}`);
|
|
137250
|
+
return `${path}${tail}`;
|
|
137251
|
+
});
|
|
137252
|
+
const remaining = entries.length - shown.length;
|
|
137253
|
+
if (remaining > 0) rows.push(chalk.dim(t("readgroup.more_files", { count: String(remaining) })));
|
|
137254
|
+
return [new Text(rows.map((row) => ` ${row}`).join("\n"), 0, 0)];
|
|
137255
|
+
};
|
|
137256
|
+
//#endregion
|
|
137061
137257
|
//#region src/tui/components/messages/tool-renderers/chip.ts
|
|
137062
137258
|
/**
|
|
137063
137259
|
* Header chip providers — produce a short "stat" suffix appended to the
|
|
@@ -137120,6 +137316,18 @@ const editChip = (toolCall) => {
|
|
|
137120
137316
|
};
|
|
137121
137317
|
const writeChip = (toolCall) => formatWriteChip(computeWriteStats(toolCall.args));
|
|
137122
137318
|
const readChip = (_toolCall, result) => pluralize(countNonEmptyLines(result.output), "line");
|
|
137319
|
+
const readGroupChip = (_toolCall, result) => {
|
|
137320
|
+
const entries = parseReadGroupOutput(result.output);
|
|
137321
|
+
if (entries.length === 0) return "";
|
|
137322
|
+
const failed = entries.filter((entry) => entry.failed).length;
|
|
137323
|
+
const files = pluralize(entries.length, "file");
|
|
137324
|
+
if (failed === entries.length) return `${files} · failed`;
|
|
137325
|
+
const lines = entries.reduce((sum, entry) => entry.failed ? sum : sum + entry.lines, 0);
|
|
137326
|
+
const parts = [files];
|
|
137327
|
+
if (lines > 0) parts.push(pluralize(lines, "line"));
|
|
137328
|
+
if (failed > 0) parts.push(`${String(failed)} failed`);
|
|
137329
|
+
return parts.join(" · ");
|
|
137330
|
+
};
|
|
137123
137331
|
const grepChip = (_toolCall, result) => {
|
|
137124
137332
|
const matches = countNonEmptyLines(result.output);
|
|
137125
137333
|
if (matches === 0) return "no matches";
|
|
@@ -137142,6 +137350,7 @@ const REGISTRY = {
|
|
|
137142
137350
|
Edit: editChip,
|
|
137143
137351
|
Write: writeChip,
|
|
137144
137352
|
Read: readChip,
|
|
137353
|
+
ReadGroup: readGroupChip,
|
|
137145
137354
|
ReadMediaFile: readMediaChip,
|
|
137146
137355
|
Grep: grepChip,
|
|
137147
137356
|
Glob: globChip,
|
|
@@ -137397,6 +137606,7 @@ const globSummary = withGlance(globGlance);
|
|
|
137397
137606
|
function pickResultRenderer(toolName) {
|
|
137398
137607
|
switch (toolName) {
|
|
137399
137608
|
case "Read": return readSummary;
|
|
137609
|
+
case "ReadGroup": return readGroupListSummary;
|
|
137400
137610
|
case "ReadMediaFile": return readMediaSummary;
|
|
137401
137611
|
case "Grep": return grepSummary;
|
|
137402
137612
|
case "Glob": return globSummary;
|
|
@@ -137741,12 +137951,12 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
137741
137951
|
writeStreamLang;
|
|
137742
137952
|
static WRITE_STREAM_TAIL_RAW_CHARS = 4096;
|
|
137743
137953
|
/**
|
|
137744
|
-
* Registered by a group container (`AgentGroupComponent
|
|
137745
|
-
*
|
|
137746
|
-
*
|
|
137747
|
-
*
|
|
137748
|
-
*
|
|
137749
|
-
*
|
|
137954
|
+
* Registered by a group container (`AgentGroupComponent`, the activity block)
|
|
137955
|
+
* when this component is borrowed as a hidden state container. Any state
|
|
137956
|
+
* change (subagent meta, phase, sub-tool, result, etc.) triggers a throttled
|
|
137957
|
+
* group re-render. `undefined` means no group is subscribed and standalone
|
|
137958
|
+
* rendering is unaffected. A ToolCallComponent can only belong to one group at
|
|
137959
|
+
* a time, so one listener slot is enough.
|
|
137750
137960
|
*/
|
|
137751
137961
|
onSnapshotChange;
|
|
137752
137962
|
static HEADER_END_INDEX = 2;
|
|
@@ -137922,10 +138132,10 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
137922
138132
|
this.ui?.requestRender();
|
|
137923
138133
|
}
|
|
137924
138134
|
/**
|
|
137925
|
-
* Lets group containers (
|
|
137926
|
-
* state changes. Registration immediately calls back so the group
|
|
137927
|
-
* the current
|
|
137928
|
-
*
|
|
138135
|
+
* Lets group containers (the agent group, the activity block) subscribe to
|
|
138136
|
+
* this card's state changes. Registration immediately calls back so the group
|
|
138137
|
+
* receives the current state without separately calling
|
|
138138
|
+
* getSubagentSnapshot. Pass `undefined` to unsubscribe.
|
|
137929
138139
|
*/
|
|
137930
138140
|
setSnapshotListener(cb) {
|
|
137931
138141
|
this.onSnapshotChange = cb;
|
|
@@ -137952,35 +138162,6 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
137952
138162
|
latestActivity
|
|
137953
138163
|
};
|
|
137954
138164
|
}
|
|
137955
|
-
/**
|
|
137956
|
-
* Used by `ReadGroupComponent` to sum line counts across same-step Read
|
|
137957
|
-
* cards. `lines` matches the single-card chip
|
|
137958
|
-
* (`pluralize(countNonEmptyLines(...), 'line')`) so group and card counts do
|
|
137959
|
-
* not drift.
|
|
137960
|
-
*/
|
|
137961
|
-
getReadSnapshot() {
|
|
137962
|
-
const args = this.toolCall.args;
|
|
137963
|
-
const filePathRaw = args["file_path"] ?? args["path"];
|
|
137964
|
-
const filePath = typeof filePathRaw === "string" ? makeWorkspaceRelativePath(filePathRaw, this.workspaceDir) : void 0;
|
|
137965
|
-
if (this.result === void 0) return {
|
|
137966
|
-
toolCallId: this.toolCall.id,
|
|
137967
|
-
filePath,
|
|
137968
|
-
phase: "pending",
|
|
137969
|
-
lines: 0
|
|
137970
|
-
};
|
|
137971
|
-
if (this.result.is_error === true) return {
|
|
137972
|
-
toolCallId: this.toolCall.id,
|
|
137973
|
-
filePath,
|
|
137974
|
-
phase: "failed",
|
|
137975
|
-
lines: 0
|
|
137976
|
-
};
|
|
137977
|
-
return {
|
|
137978
|
-
toolCallId: this.toolCall.id,
|
|
137979
|
-
filePath,
|
|
137980
|
-
phase: "done",
|
|
137981
|
-
lines: countNonEmptyLines(this.result.output)
|
|
137982
|
-
};
|
|
137983
|
-
}
|
|
137984
138165
|
get toolCallView() {
|
|
137985
138166
|
return this.toolCall;
|
|
137986
138167
|
}
|
|
@@ -138791,77 +138972,6 @@ function formatActivityLine(verb, toolName, args, workspaceDir) {
|
|
|
138791
138972
|
return keyArg ? `${verb} ${toolName} (${keyArg})` : `${verb} ${toolName}`;
|
|
138792
138973
|
}
|
|
138793
138974
|
//#endregion
|
|
138794
|
-
//#region src/tui/utils/ui-preferences.ts
|
|
138795
|
-
/**
|
|
138796
|
-
* TUI-local UI preferences persisted to `<dataDir>/ui-preferences.json`.
|
|
138797
|
-
* Distinct from agent/SDK config files (which are owned by core) — this file
|
|
138798
|
-
* stores lightweight view-state knobs owned by the TUI itself, e.g. whether
|
|
138799
|
-
* the empty-session provider hint has been dismissed by the user.
|
|
138800
|
-
*/
|
|
138801
|
-
const EMPTY = {};
|
|
138802
|
-
function getUiPreferencesPath() {
|
|
138803
|
-
return join(getDataDir(), SCREAM_CODE_UI_PREFERENCES_FILE_NAME);
|
|
138804
|
-
}
|
|
138805
|
-
function readUiPreferences() {
|
|
138806
|
-
try {
|
|
138807
|
-
const file = getUiPreferencesPath();
|
|
138808
|
-
if (!existsSync(file)) return { ...EMPTY };
|
|
138809
|
-
const raw = readFileSync(file, "utf8");
|
|
138810
|
-
const parsed = JSON.parse(raw);
|
|
138811
|
-
return {
|
|
138812
|
-
...EMPTY,
|
|
138813
|
-
...parsed
|
|
138814
|
-
};
|
|
138815
|
-
} catch {
|
|
138816
|
-
return { ...EMPTY };
|
|
138817
|
-
}
|
|
138818
|
-
}
|
|
138819
|
-
function writeUiPreferences(prefs) {
|
|
138820
|
-
try {
|
|
138821
|
-
const file = getUiPreferencesPath();
|
|
138822
|
-
mkdirSync(dirname$1(file), { recursive: true });
|
|
138823
|
-
writeFileSync(file, JSON.stringify(prefs, null, 2), "utf8");
|
|
138824
|
-
} catch {}
|
|
138825
|
-
}
|
|
138826
|
-
function isEmptySessionHintDismissed() {
|
|
138827
|
-
return readUiPreferences().emptySessionHintDismissed === true;
|
|
138828
|
-
}
|
|
138829
|
-
/** Toggle the empty-session hint on/off (Ctrl+B). Returns the new state:
|
|
138830
|
-
* true = hidden, false = shown. Persisted immediately. */
|
|
138831
|
-
function toggleEmptySessionHint() {
|
|
138832
|
-
const prefs = readUiPreferences();
|
|
138833
|
-
const dismissed = prefs.emptySessionHintDismissed !== true;
|
|
138834
|
-
prefs.emptySessionHintDismissed = dismissed;
|
|
138835
|
-
writeUiPreferences(prefs);
|
|
138836
|
-
return dismissed;
|
|
138837
|
-
}
|
|
138838
|
-
/** Whether the per-turn elapsed marker is enabled (default on). */
|
|
138839
|
-
function isTurnElapsedEnabled() {
|
|
138840
|
-
return readUiPreferences().turnElapsedEnabled !== false;
|
|
138841
|
-
}
|
|
138842
|
-
/** Toggle the per-turn elapsed marker via /snaptimer. Returns the new state:
|
|
138843
|
-
* true = shown, false = hidden. Persisted immediately. */
|
|
138844
|
-
function toggleTurnElapsed() {
|
|
138845
|
-
const prefs = readUiPreferences();
|
|
138846
|
-
const enabled = prefs.turnElapsedEnabled !== false;
|
|
138847
|
-
prefs.turnElapsedEnabled = !enabled;
|
|
138848
|
-
writeUiPreferences(prefs);
|
|
138849
|
-
return !enabled;
|
|
138850
|
-
}
|
|
138851
|
-
/** Whether user messages render with a highlight background block (default on). */
|
|
138852
|
-
function isUserMessageHighlightEnabled() {
|
|
138853
|
-
return readUiPreferences().userMessageHighlightEnabled !== false;
|
|
138854
|
-
}
|
|
138855
|
-
/** Toggle the user-message highlight block via /hl. Returns the new state:
|
|
138856
|
-
* true = highlighted, false = default (no background). Persisted immediately. */
|
|
138857
|
-
function toggleUserMessageHighlight() {
|
|
138858
|
-
const prefs = readUiPreferences();
|
|
138859
|
-
const enabled = prefs.userMessageHighlightEnabled !== false;
|
|
138860
|
-
prefs.userMessageHighlightEnabled = !enabled;
|
|
138861
|
-
writeUiPreferences(prefs);
|
|
138862
|
-
return !enabled;
|
|
138863
|
-
}
|
|
138864
|
-
//#endregion
|
|
138865
138975
|
//#region src/tui/components/messages/user-message.ts
|
|
138866
138976
|
var UserMessageComponent = class {
|
|
138867
138977
|
color;
|
|
@@ -139052,7 +139162,7 @@ function isRevokeAnchorComponent(child) {
|
|
|
139052
139162
|
return child instanceof UserMessageComponent || child instanceof SkillActivationComponent;
|
|
139053
139163
|
}
|
|
139054
139164
|
function isRevokeContextComponent(child) {
|
|
139055
|
-
return child instanceof UserMessageComponent || child instanceof AssistantMessageComponent || child instanceof ThinkingComponent || child instanceof ToolCallComponent || child instanceof ActivityGroupComponent || child instanceof AgentGroupComponent || child instanceof
|
|
139165
|
+
return child instanceof UserMessageComponent || child instanceof AssistantMessageComponent || child instanceof ThinkingComponent || child instanceof ToolCallComponent || child instanceof ActivityGroupComponent || child instanceof AgentGroupComponent || child instanceof SkillActivationComponent || child instanceof BackgroundAgentStatusComponent || child instanceof StatusMessageComponent || child instanceof CompactionComponent;
|
|
139056
139166
|
}
|
|
139057
139167
|
function renderWelcome(host) {
|
|
139058
139168
|
if (host.state.transcriptContainer.children.some((child) => child instanceof WelcomeComponent)) return;
|
|
@@ -141021,18 +141131,6 @@ function isExpandable(obj) {
|
|
|
141021
141131
|
function isPlanExpandable(obj) {
|
|
141022
141132
|
return typeof obj === "object" && obj !== null && "setPlanExpanded" in obj && typeof obj.setPlanExpanded === "function";
|
|
141023
141133
|
}
|
|
141024
|
-
/**
|
|
141025
|
-
* Reads a component's current expansion state. Components that only accept
|
|
141026
|
-
* `setExpanded` (or that return something other than a boolean) yield
|
|
141027
|
-
* undefined, so callers fall back to their own last value instead of guessing.
|
|
141028
|
-
*/
|
|
141029
|
-
function readExpanded(obj) {
|
|
141030
|
-
if (typeof obj !== "object" || obj === null || !("isExpanded" in obj)) return void 0;
|
|
141031
|
-
const reader = obj.isExpanded;
|
|
141032
|
-
if (typeof reader !== "function") return void 0;
|
|
141033
|
-
const value = reader.call(obj);
|
|
141034
|
-
return typeof value === "boolean" ? value : void 0;
|
|
141035
|
-
}
|
|
141036
141134
|
function hasDispose(value) {
|
|
141037
141135
|
return typeof value === "object" && value !== null && "dispose" in value && typeof value.dispose === "function";
|
|
141038
141136
|
}
|
|
@@ -141602,6 +141700,88 @@ async function handleHighlightCommand(host, _args) {
|
|
|
141602
141700
|
host.state.ui.requestRender();
|
|
141603
141701
|
}
|
|
141604
141702
|
//#endregion
|
|
141703
|
+
//#region src/tui/utils/transcript-repaint.ts
|
|
141704
|
+
function repaintTranscript(host) {
|
|
141705
|
+
for (const child of host.state.transcriptContainer.children) {
|
|
141706
|
+
const repaintable = child;
|
|
141707
|
+
if (typeof repaintable.invalidate === "function") repaintable.invalidate();
|
|
141708
|
+
}
|
|
141709
|
+
host.state.ui.requestRender();
|
|
141710
|
+
}
|
|
141711
|
+
//#endregion
|
|
141712
|
+
//#region src/tui/commands/blockrows.ts
|
|
141713
|
+
/**
|
|
141714
|
+
* /blockrows — Tune the activity block's row budgets: how tall a collapsed block
|
|
141715
|
+
* is, how much of a tool result and of a reasoning run an expanded block shows.
|
|
141716
|
+
*
|
|
141717
|
+
* Two steps: pick the budget, then pick the value. Choices are persisted to
|
|
141718
|
+
* ui-preferences.json (so they survive restarts) and applied to the transcript
|
|
141719
|
+
* that is already on screen, not just to blocks created afterwards.
|
|
141720
|
+
*/
|
|
141721
|
+
function showSettingPicker(host) {
|
|
141722
|
+
host.mountEditorReplacement(new ChoicePickerComponent({
|
|
141723
|
+
title: t("blockrows.title"),
|
|
141724
|
+
hint: t("blockrows.hint"),
|
|
141725
|
+
colors: host.state.theme.colors,
|
|
141726
|
+
options: ACTIVITY_LINE_SETTINGS.map((setting) => ({
|
|
141727
|
+
value: setting.key,
|
|
141728
|
+
label: t(setting.label),
|
|
141729
|
+
description: t("blockrows.current", { value: String(getActivityLineValue(setting.key)) })
|
|
141730
|
+
})),
|
|
141731
|
+
onSelect: (value) => {
|
|
141732
|
+
if (isActivityLineKey(value)) showValuePicker(host, value);
|
|
141733
|
+
},
|
|
141734
|
+
onCancel: () => {
|
|
141735
|
+
host.restoreEditor();
|
|
141736
|
+
}
|
|
141737
|
+
}));
|
|
141738
|
+
}
|
|
141739
|
+
function showValuePicker(host, key) {
|
|
141740
|
+
const setting = findActivityLineSetting(key);
|
|
141741
|
+
host.mountEditorReplacement(new ChoicePickerComponent({
|
|
141742
|
+
title: t(setting.label),
|
|
141743
|
+
hint: t("blockrows.value_hint"),
|
|
141744
|
+
currentValue: String(getActivityLineValue(key)),
|
|
141745
|
+
colors: host.state.theme.colors,
|
|
141746
|
+
options: setting.values.map((value) => ({
|
|
141747
|
+
value: String(value),
|
|
141748
|
+
label: String(value)
|
|
141749
|
+
})),
|
|
141750
|
+
onSelect: (value) => {
|
|
141751
|
+
const parsed = Number(value);
|
|
141752
|
+
if (!Number.isFinite(parsed)) return;
|
|
141753
|
+
setActivityLineValue(key, parsed);
|
|
141754
|
+
host.restoreEditor();
|
|
141755
|
+
host.showStatus(t("blockrows.saved", {
|
|
141756
|
+
label: t(setting.label),
|
|
141757
|
+
value: String(parsed)
|
|
141758
|
+
}), host.state.theme.colors.success);
|
|
141759
|
+
repaintTranscript(host);
|
|
141760
|
+
},
|
|
141761
|
+
onCancel: () => {
|
|
141762
|
+
showSettingPicker(host);
|
|
141763
|
+
}
|
|
141764
|
+
}));
|
|
141765
|
+
}
|
|
141766
|
+
async function handleBlockRowsCommand(host, _args) {
|
|
141767
|
+
showSettingPicker(host);
|
|
141768
|
+
}
|
|
141769
|
+
//#endregion
|
|
141770
|
+
//#region src/tui/commands/codebg.ts
|
|
141771
|
+
/**
|
|
141772
|
+
* /codebg — Toggle the background panel behind fenced code blocks.
|
|
141773
|
+
*
|
|
141774
|
+
* On (default): each code line is painted as a full-width band, which separates
|
|
141775
|
+
* code from prose at a glance. Off: the band disappears and code is set apart by
|
|
141776
|
+
* its own colour, the one-cell gutter and the language label only.
|
|
141777
|
+
* Persisted to ui-preferences.json, so it survives restarts.
|
|
141778
|
+
*/
|
|
141779
|
+
async function handleCodeBgCommand(host, _args) {
|
|
141780
|
+
const enabled = toggleCodeBlockPanel();
|
|
141781
|
+
host.showStatus(enabled ? t("codebg.enabled") : t("codebg.disabled"), enabled ? host.state.theme.colors.success : host.state.theme.colors.textDim);
|
|
141782
|
+
repaintTranscript(host);
|
|
141783
|
+
}
|
|
141784
|
+
//#endregion
|
|
141605
141785
|
//#region src/tui/commands/like.ts
|
|
141606
141786
|
function promptTextInput$1(host, title, opts) {
|
|
141607
141787
|
const { promise, resolve } = Promise.withResolvers();
|
|
@@ -144446,6 +144626,12 @@ async function handleBuiltInSlashCommand(host, name, args) {
|
|
|
144446
144626
|
case "hl":
|
|
144447
144627
|
await handleHighlightCommand(host, args);
|
|
144448
144628
|
return;
|
|
144629
|
+
case "blockrows":
|
|
144630
|
+
await handleBlockRowsCommand(host, args);
|
|
144631
|
+
return;
|
|
144632
|
+
case "codebg":
|
|
144633
|
+
await handleCodeBgCommand(host, args);
|
|
144634
|
+
return;
|
|
144449
144635
|
case "mcp":
|
|
144450
144636
|
await handleMcpCommand(host, args);
|
|
144451
144637
|
return;
|
|
@@ -144579,4 +144765,4 @@ async function handleBuiltInSlashCommand(host, name, args) {
|
|
|
144579
144765
|
}
|
|
144580
144766
|
}
|
|
144581
144767
|
//#endregion
|
|
144582
|
-
export {
|
|
144768
|
+
export { handleExportMdCommand as $, readSessionIndex as $n, SubagentSlots as $t, langFromPath as A, startManualEmbeddingDownload as An, toggleEmptySessionHint as At, charsForTokenBudget as B, getLogDir as Bn, OSC11_QUERY as Bt, getDaemonInstructions as C, buildSkillSlashCommands as Cn, showStatusReport as Ct, renderDiffLines as D, setExperimentalFlags as Dn, createMarkdownTheme as Dt, ToolCallComponent as E, isExperimentalFlagEnabled as En, createEditorTheme as Et, replaceTabs as F, loadTuiConfig as Fn, parseOsc11BackgroundTheme as Ft, WelcomeComponent as G, PRODUCT_NAME as Gn, TERMINAL_FOCUS_IN as Gt, getSharedSpeedTracker as H, CLI_COMMAND_NAME as Hn, OSC11_RESPONSE_PREFIX as Ht, sanitizeShellOutput as I, saveTuiConfig as In, DISABLE_TERMINAL_FOCUS_REPORTING as It, resetBreathingClock as J, saveCatalogCache as Jn, TERMINAL_THEME_LIGHT as Jt, BREATHE_CYCLE_MS as K, DEFAULT_CATALOG_URL as Kn, TERMINAL_FOCUS_OUT as Kt, SkillActivationComponent as L, detectShellEnvironment as Ln, DISABLE_TERMINAL_THEME_REPORTING as Lt, ThinkingComponent as M, PULSE_WAVE_FRAMES as Mn, contrastTextHex as Mt, NoticeMessageComponent as N, TuiConfigParseError as Nn, getColorPalette as Nt, renderDiffLinesClustered as O, getKnowledgeStore as On, isEmptySessionHintDismissed as Ot, StatusMessageComponent as P, TuiLikePreferencesSchema as Pn, detectTerminalTheme as Pt, handleExportDebugZipCommand as Q, appendSessionIndexEntry as Qn, lerpGradient as Qt, AssistantMessageComponent as R, getDataDir as Rn, ENABLE_TERMINAL_FOCUS_REPORTING as Rt, handleCcCommand as S, getNoActiveSessionMessage as Sn, clearInfoPanelState as St, UserMessageComponent as T, sortSlashCommands as Tn, resolveThemeSync as Tt, BackgroundAgentStatusComponent as U, CLI_UI_MODE as Un, OSC11_RESPONSE_PREFIX_NO_ESC as Ut, estimateTokens as V, detectInstallSource as Vn, OSC11_RESPONSE as Vt, AgentGroupComponent as W, CLI_USER_AGENT_PRODUCT as Wn, QUERY_TERMINAL_THEME as Wt, clearGoalState as X, encodeWorkDirKey as Xn, isStreaming as Xt, CompactionComponent as Y, ScreamHarness as Yn, isBusy as Yt, refineGoal as Z, normalizeWorkDir as Zn, FooterComponent as Zt, selectUpdateTarget as _, SESSION_TIPS as _n, showModelPicker as _t, handleExtensionCommand as a, STATUS_BULLET as an, log as ar, changeThinkingLevel as at, appendJsonlLine as b, getCtrlDHint as bn, refreshProviderBalance as bt, hasDispose as c, formatErrorMessage as cn, isOrphanedToolCallError as cr, handleBotCommand as ct, MoonLoader as d, serializeToolResultOutput as dn, handleFusionPlanCommand as dt, handleTraceCommand as en, removeSessionIndexEntry as er, handleForkCommand as et, formatMemoryMemoForInjection as f, stringValue as fn, handleModelCommand as ft, handleUpdateCommand as g, MAIN_AGENT_ID$1 as gn, handleYoloCommand as gt, handleMcpCommand as h, EXIT_CONFIRM_WINDOW_MS as hn, handleWolfpackCommand as ht, buildRoleAdditionalText as i, printableChar as in, flushDiagnosticLogs as ir, toTerminalHyperlink as it, CachedContainer as j, PIXEL_PULSE_FRAMES as jn, createThemeStyles as jt, highlightLines as k, isEmbeddingModelCached as kn, isTurnElapsedEnabled as kt, isExpandable as l, isTodoItemShape as ln, ErrorCodes as lr, handleCompactCommand as lt, handleChannelCommand as m, EMPTY_SESSION_HINT_URL as mn, handleThemeCommand as mt, clearEvalPanelState as n, handleConnectCommand as nn, resolveScreamHome as nr, handleTitleCommand as nt, handleSkillCommand as o, appendStreamingArgsPreview as on, resolveGlobalLogPath as or, getModelCycleLevel as ot, handleMemoryCommand as p, truncateErrorMessage as pn, handlePlanCommand as pt, getBreathingFrame as q, fetchCatalog as qn, TERMINAL_THEME_DARK as qt, openUrl as r, handleLogoutCommand as rn, MemoryMemoStore as rr, isInternalMessage as rt, disposeChildren as s, argsRecord as sn, isScreamError as sr, handleAutoCommand as st, dispatchInput as t, handleSearchCommand as tn, MCP_OAUTH_AUTHORIZATION_URL_TOOL_UPDATE as tr, handleInitCommand as tt, isPlanExpandable as u, parseStreamingArgs as un, SCREAM_ERROR_INFO as ur, handleEditorCommand as ut, refreshUpdateCache as v, TIP_ROTATION_INTERVAL_MS as vn, showPermissionPicker as vt, handleRevokeCommand as w, BUILTIN_SLASH_COMMANDS as wn, showUsage as wt, readJsonlFile as x, getLlmNotSetMessage as xn, supportsBalance as xt, readUpdateCache as y, getCtrlCHint as yn, showSettingsSelector as yt, ActivityGroupComponent as z, getInputHistoryFile as zn, ENABLE_TERMINAL_THEME_REPORTING as zt };
|