indusagi 0.12.33 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/agent.js +1247 -184
- package/dist/ai.js +72 -4
- package/dist/capabilities.js +69 -2
- package/dist/cli.js +1353 -29
- package/dist/connectors-saas.js +66 -0
- package/dist/index.js +1353 -29
- package/dist/interop.js +66 -0
- package/dist/mcp.js +270 -363
- package/dist/react-ink.js +1391 -41
- package/dist/shell-app.js +1353 -29
- package/dist/smithy.js +69 -2
- package/dist/swarm.js +69 -2
- package/dist/types/capabilities/backends/node-backends.d.ts +3 -1
- package/dist/types/capabilities/files/read-state-gate.d.ts +69 -0
- package/dist/types/capabilities/files/read-state-gate.test.d.ts +14 -0
- package/dist/types/capabilities/kernel/context.d.ts +4 -0
- package/dist/types/capabilities/kernel/index.d.ts +2 -2
- package/dist/types/capabilities/kernel/spec.d.ts +55 -0
- package/dist/types/facade/bot/actions/bash.d.ts +15 -0
- package/dist/types/facade/bot/actions/bash.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/checkpoint.d.ts +49 -0
- package/dist/types/facade/bot/actions/checkpoint.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/edit-utils.d.ts +86 -0
- package/dist/types/facade/bot/actions/edit.d.ts +18 -0
- package/dist/types/facade/bot/actions/edit.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/find.d.ts +2 -0
- package/dist/types/facade/bot/actions/find.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/grep.d.ts +10 -0
- package/dist/types/facade/bot/actions/grep.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/index.d.ts +16 -0
- package/dist/types/facade/bot/actions/read-state.d.ts +83 -0
- package/dist/types/facade/bot/actions/read-state.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/read.d.ts +7 -0
- package/dist/types/facade/bot/actions/read.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/sandbox-backend.d.ts +99 -0
- package/dist/types/facade/bot/actions/sandbox-backend.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/websearch.d.ts +5 -2
- package/dist/types/facade/bot/actions/websearch.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/write.d.ts +15 -0
- package/dist/types/facade/bot/agent-loop.d.ts +10 -0
- package/dist/types/facade/bot/agent-loop.test.d.ts +1 -0
- package/dist/types/facade/bot/agent.d.ts +9 -1
- package/dist/types/facade/bot/permission-gate.test.d.ts +1 -0
- package/dist/types/facade/bot/types.d.ts +60 -0
- package/dist/types/facade/mcp-core/client.d.ts +71 -15
- package/dist/types/facade/mcp-core/client.test.d.ts +18 -0
- package/dist/types/facade/mcp-core/types.d.ts +10 -0
- package/dist/types/facade/ml/adapters/anthropic-retry.test.d.ts +1 -0
- package/dist/types/facade/ml/adapters/anthropic.d.ts +17 -0
- package/dist/types/facade/ml/adapters/simple-options.d.ts +13 -0
- package/dist/types/facade/ml/adapters/simple-options.test.d.ts +1 -0
- package/dist/types/react-ink/components/StatusLine.d.ts +10 -1
- package/dist/types/react-ink/components/ToolEventBlock.d.ts +9 -1
- package/dist/types/react-ink/components/ToolEventBlock.test.d.ts +1 -0
- package/dist/types/react-ink/components/dialogs/SelectableDialog.d.ts +7 -1
- package/dist/types/react-ink/components/dialogs/ThemeDialog.d.ts +21 -2
- package/dist/types/react-ink/diff/Diff.d.ts +22 -0
- package/dist/types/react-ink/diff/diff.test.d.ts +1 -0
- package/dist/types/react-ink/diff/structured.d.ts +41 -0
- package/dist/types/react-ink/diff/word-diff.d.ts +27 -0
- package/dist/types/react-ink/index.d.ts +8 -0
- package/dist/types/react-ink/markdown/Markdown.d.ts +23 -0
- package/dist/types/react-ink/markdown/MarkdownTable.d.ts +19 -0
- package/dist/types/react-ink/markdown/StreamingMarkdown.d.ts +34 -0
- package/dist/types/react-ink/markdown/format-token.d.ts +39 -0
- package/dist/types/react-ink/markdown/highlight.d.ts +31 -0
- package/dist/types/react-ink/theme-adapter.d.ts +58 -1
- package/dist/types/react-ink/utils/tool-display.d.ts +17 -1
- package/package.json +5 -1
package/dist/index.js
CHANGED
|
@@ -4512,6 +4512,7 @@ __export(capabilities_exports, {
|
|
|
4512
4512
|
});
|
|
4513
4513
|
|
|
4514
4514
|
// src/capabilities/kernel/spec.ts
|
|
4515
|
+
var READ_STATE_HANDLE_KEY = "readState";
|
|
4515
4516
|
function coerceInput(raw) {
|
|
4516
4517
|
if (typeof raw === "string") {
|
|
4517
4518
|
const trimmed = raw.trim();
|
|
@@ -4965,7 +4966,7 @@ var standardBudget = {
|
|
|
4965
4966
|
[${omitted} bytes elided to stay within the output ceiling]
|
|
4966
4967
|
`
|
|
4967
4968
|
};
|
|
4968
|
-
function makeNodeContext(cwd, signal, budget) {
|
|
4969
|
+
function makeNodeContext(cwd, signal, budget, framework) {
|
|
4969
4970
|
if (typeof cwd !== "string" || cwd.length === 0) {
|
|
4970
4971
|
throw new Error("makeNodeContext requires a non-empty working directory.");
|
|
4971
4972
|
}
|
|
@@ -4974,10 +4975,60 @@ function makeNodeContext(cwd, signal, budget) {
|
|
|
4974
4975
|
fs: nodeFs,
|
|
4975
4976
|
shell: nodeShell,
|
|
4976
4977
|
signal: signal ?? neverAborts(),
|
|
4977
|
-
budget: budget ?? standardBudget
|
|
4978
|
+
budget: budget ?? standardBudget,
|
|
4979
|
+
...framework ? { framework } : {}
|
|
4978
4980
|
};
|
|
4979
4981
|
}
|
|
4980
4982
|
|
|
4983
|
+
// src/capabilities/files/read-state-gate.ts
|
|
4984
|
+
var READ_BEFORE_EDIT_MESSAGE = "File has not been read yet. Read it first before writing to it.";
|
|
4985
|
+
var MODIFIED_SINCE_READ_MESSAGE = "File has been modified since read, either by the user or by a linter. Read it again before attempting to write it.";
|
|
4986
|
+
function getReadStateHandle(ctx) {
|
|
4987
|
+
const bag = ctx.framework;
|
|
4988
|
+
if (!bag || typeof bag !== "object") return void 0;
|
|
4989
|
+
const candidate = bag[READ_STATE_HANDLE_KEY];
|
|
4990
|
+
if (!candidate || typeof candidate !== "object") return void 0;
|
|
4991
|
+
const handle = candidate;
|
|
4992
|
+
if (typeof handle.get !== "function" || typeof handle.set !== "function" || typeof handle.has !== "function") {
|
|
4993
|
+
return void 0;
|
|
4994
|
+
}
|
|
4995
|
+
return handle;
|
|
4996
|
+
}
|
|
4997
|
+
async function recordReadState(ctx, absPath, handle) {
|
|
4998
|
+
if (!handle) return;
|
|
4999
|
+
try {
|
|
5000
|
+
const info = await ctx.fs.stat(absPath);
|
|
5001
|
+
const record = {
|
|
5002
|
+
mtimeMs: Math.floor(info.modifiedMs),
|
|
5003
|
+
size: info.size,
|
|
5004
|
+
readAt: Date.now()
|
|
5005
|
+
};
|
|
5006
|
+
handle.set(absPath, record);
|
|
5007
|
+
} catch {
|
|
5008
|
+
}
|
|
5009
|
+
}
|
|
5010
|
+
async function enforceReadGate(ctx, absPath, handle) {
|
|
5011
|
+
if (!handle) return { ok: true };
|
|
5012
|
+
if (!handle.has(absPath)) {
|
|
5013
|
+
return { ok: false, message: READ_BEFORE_EDIT_MESSAGE };
|
|
5014
|
+
}
|
|
5015
|
+
const recorded = handle.get(absPath);
|
|
5016
|
+
if (!recorded) {
|
|
5017
|
+
return { ok: false, message: READ_BEFORE_EDIT_MESSAGE };
|
|
5018
|
+
}
|
|
5019
|
+
let info;
|
|
5020
|
+
try {
|
|
5021
|
+
info = await ctx.fs.stat(absPath);
|
|
5022
|
+
} catch {
|
|
5023
|
+
return { ok: true };
|
|
5024
|
+
}
|
|
5025
|
+
const currentMtime = Math.floor(info.modifiedMs);
|
|
5026
|
+
if (currentMtime > recorded.mtimeMs || info.size !== recorded.size) {
|
|
5027
|
+
return { ok: false, message: MODIFIED_SINCE_READ_MESSAGE };
|
|
5028
|
+
}
|
|
5029
|
+
return { ok: true };
|
|
5030
|
+
}
|
|
5031
|
+
|
|
4981
5032
|
// src/capabilities/files/read.ts
|
|
4982
5033
|
var GUTTER_WIDTH = 6;
|
|
4983
5034
|
var DESCRIPTION = [
|
|
@@ -5080,6 +5131,7 @@ var readTool = defineTool({
|
|
|
5080
5131
|
const detail = err instanceof Error ? err.message : String(err);
|
|
5081
5132
|
return failure(`Could not read ${path2}: ${detail}`);
|
|
5082
5133
|
}
|
|
5134
|
+
await recordReadState(ctx, path2, getReadStateHandle(ctx));
|
|
5083
5135
|
const allLines = toLines(text);
|
|
5084
5136
|
const totalLines = allLines.length;
|
|
5085
5137
|
if (totalLines === 0) {
|
|
@@ -5187,11 +5239,19 @@ var writeTool = defineTool({
|
|
|
5187
5239
|
async run(input, ctx) {
|
|
5188
5240
|
const path2 = readPath(input?.path);
|
|
5189
5241
|
const content = readContent(input?.content);
|
|
5242
|
+
const handle = getReadStateHandle(ctx);
|
|
5243
|
+
if (handle && await ctx.fs.exists(path2)) {
|
|
5244
|
+
const gate = await enforceReadGate(ctx, path2, handle);
|
|
5245
|
+
if (!gate.ok) {
|
|
5246
|
+
return asText(gate.message, true);
|
|
5247
|
+
}
|
|
5248
|
+
}
|
|
5190
5249
|
const folder = parentDir(path2);
|
|
5191
5250
|
if (folder.length > 0) {
|
|
5192
5251
|
await ctx.fs.mkdir(folder, { recursive: true });
|
|
5193
5252
|
}
|
|
5194
5253
|
await ctx.fs.writeFile(path2, content, "utf8");
|
|
5254
|
+
await recordReadState(ctx, path2, handle);
|
|
5195
5255
|
const bytes = Buffer.byteLength(content, "utf8");
|
|
5196
5256
|
const unit = bytes === 1 ? "byte" : "bytes";
|
|
5197
5257
|
return asText(`Saved ${bytes} ${unit} to ${path2}.`);
|
|
@@ -5481,6 +5541,11 @@ async function runEdit(input, ctx) {
|
|
|
5481
5541
|
if (!info.isFile) {
|
|
5482
5542
|
return failure2(`${path2} is not a regular file, so it cannot be edited.`);
|
|
5483
5543
|
}
|
|
5544
|
+
const handle = getReadStateHandle(ctx);
|
|
5545
|
+
const gate = await enforceReadGate(ctx, path2, handle);
|
|
5546
|
+
if (!gate.ok) {
|
|
5547
|
+
return failure2(gate.message);
|
|
5548
|
+
}
|
|
5484
5549
|
const before = await ctx.fs.readFile(path2, "utf8");
|
|
5485
5550
|
const literalHits = countLiteral(before, oldText);
|
|
5486
5551
|
if (literalHits > 0) {
|
|
@@ -5494,6 +5559,7 @@ async function runEdit(input, ctx) {
|
|
|
5494
5559
|
return failure2(`The replacement left ${path2} unchanged.`);
|
|
5495
5560
|
}
|
|
5496
5561
|
await ctx.fs.writeFile(path2, after2, "utf8");
|
|
5562
|
+
await recordReadState(ctx, path2, handle);
|
|
5497
5563
|
return success(path2, before, after2, replaceAll ? literalHits : 1);
|
|
5498
5564
|
}
|
|
5499
5565
|
const spans = findFuzzySpans(before, oldText);
|
|
@@ -5517,6 +5583,7 @@ async function runEdit(input, ctx) {
|
|
|
5517
5583
|
return failure2(`The fuzzy replacement left ${path2} unchanged.`);
|
|
5518
5584
|
}
|
|
5519
5585
|
await ctx.fs.writeFile(path2, after, "utf8");
|
|
5586
|
+
await recordReadState(ctx, path2, handle);
|
|
5520
5587
|
return success(path2, before, after, targets.length);
|
|
5521
5588
|
}
|
|
5522
5589
|
var editTool = defineTool({
|
|
@@ -12790,6 +12857,34 @@ var useInput = ink.useInput;
|
|
|
12790
12857
|
// src/react-ink/theme-adapter.ts
|
|
12791
12858
|
import chalk from "chalk";
|
|
12792
12859
|
import stripAnsi from "strip-ansi";
|
|
12860
|
+
var DEFAULT_ROLE_KEYS = {
|
|
12861
|
+
codeInline: "codeInline",
|
|
12862
|
+
heading: "heading",
|
|
12863
|
+
blockquoteBar: "blockquoteBar",
|
|
12864
|
+
diffAddedBg: "diffAddedBg",
|
|
12865
|
+
diffRemovedBg: "diffRemovedBg",
|
|
12866
|
+
diffAddedText: "diffAddedText",
|
|
12867
|
+
diffRemovedText: "diffRemovedText",
|
|
12868
|
+
synKeyword: "synKeyword",
|
|
12869
|
+
synString: "synString",
|
|
12870
|
+
synNumber: "synNumber",
|
|
12871
|
+
synComment: "synComment",
|
|
12872
|
+
synType: "synType"
|
|
12873
|
+
};
|
|
12874
|
+
var ROLE_FALLBACK_KEYS = {
|
|
12875
|
+
codeInline: "accent",
|
|
12876
|
+
heading: "accent",
|
|
12877
|
+
blockquoteBar: "muted",
|
|
12878
|
+
diffAddedBg: "success",
|
|
12879
|
+
diffRemovedBg: "error",
|
|
12880
|
+
diffAddedText: "success",
|
|
12881
|
+
diffRemovedText: "error",
|
|
12882
|
+
synKeyword: "accent",
|
|
12883
|
+
synString: "success",
|
|
12884
|
+
synNumber: "warning",
|
|
12885
|
+
synComment: "muted",
|
|
12886
|
+
synType: "info"
|
|
12887
|
+
};
|
|
12793
12888
|
function applyForeground(color, text) {
|
|
12794
12889
|
if (!color) return text;
|
|
12795
12890
|
try {
|
|
@@ -12816,15 +12911,27 @@ function applyBackground(background, foreground, text) {
|
|
|
12816
12911
|
return applyForeground(foreground, text);
|
|
12817
12912
|
}
|
|
12818
12913
|
}
|
|
12819
|
-
function createThemeAdapter(themeName, colors) {
|
|
12914
|
+
function createThemeAdapter(themeName, colors, roleOverrides) {
|
|
12820
12915
|
const fallback = colors.text ?? "#e5e5e7";
|
|
12916
|
+
const roles = { ...DEFAULT_ROLE_KEYS, ...roleOverrides };
|
|
12917
|
+
const resolveRoleColor = (role) => resolveColorToken(
|
|
12918
|
+
colors[roles[role]],
|
|
12919
|
+
resolveColorToken(colors[ROLE_FALLBACK_KEYS[role]], fallback)
|
|
12920
|
+
);
|
|
12821
12921
|
return {
|
|
12822
12922
|
name: themeName,
|
|
12823
12923
|
colors,
|
|
12924
|
+
roles,
|
|
12824
12925
|
color: (key, text) => applyForeground(resolveColorToken(colors[key], fallback), text),
|
|
12825
12926
|
background: (key, text, textKey = "text") => applyBackground(resolveColorToken(colors[key]), resolveColorToken(colors[textKey], fallback), ` ${stripAnsi(text)} `),
|
|
12826
12927
|
dim: (text) => applyForeground(resolveColorToken(colors.dim, "#666666"), text),
|
|
12827
|
-
muted: (text) => applyForeground(resolveColorToken(colors.muted, "#808080"), text)
|
|
12928
|
+
muted: (text) => applyForeground(resolveColorToken(colors.muted, "#808080"), text),
|
|
12929
|
+
role: (role, text) => applyForeground(resolveRoleColor(role), text),
|
|
12930
|
+
roleBackground: (role, text, foregroundRole) => applyBackground(
|
|
12931
|
+
resolveRoleColor(role),
|
|
12932
|
+
foregroundRole ? resolveRoleColor(foregroundRole) : void 0,
|
|
12933
|
+
text
|
|
12934
|
+
)
|
|
12828
12935
|
};
|
|
12829
12936
|
}
|
|
12830
12937
|
|
|
@@ -13209,8 +13316,1120 @@ function parseSkillInvocation(content) {
|
|
|
13209
13316
|
};
|
|
13210
13317
|
}
|
|
13211
13318
|
|
|
13319
|
+
// src/react-ink/markdown/format-token.ts
|
|
13320
|
+
import chalk2 from "chalk";
|
|
13321
|
+
import { marked } from "marked";
|
|
13322
|
+
import stripAnsi3 from "strip-ansi";
|
|
13323
|
+
|
|
13324
|
+
// src/ui/utils.ts
|
|
13325
|
+
import { eastAsianWidth } from "get-east-asian-width";
|
|
13326
|
+
var segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
13327
|
+
var TextWidthCalculator = class {
|
|
13328
|
+
getWidth(text) {
|
|
13329
|
+
return visibleWidth(text);
|
|
13330
|
+
}
|
|
13331
|
+
clearCache() {
|
|
13332
|
+
widthCache.clear();
|
|
13333
|
+
}
|
|
13334
|
+
};
|
|
13335
|
+
var textWidthCalculator = new TextWidthCalculator();
|
|
13336
|
+
function looksLikeEmojiCandidate(segment) {
|
|
13337
|
+
const cp = segment.codePointAt(0);
|
|
13338
|
+
return cp >= 126976 && cp <= 130047 || // pictographs and emoji proper
|
|
13339
|
+
cp >= 8960 && cp <= 9215 || // miscellaneous technical glyphs
|
|
13340
|
+
cp >= 9728 && cp <= 10175 || // assorted symbols and dingbats
|
|
13341
|
+
cp >= 11088 && cp <= 11093 || // a few star/circle characters
|
|
13342
|
+
segment.includes("\uFE0F") || // carries VS16, the emoji-presentation selector
|
|
13343
|
+
segment.length > 2;
|
|
13344
|
+
}
|
|
13345
|
+
function createUnicodeRegex(vPattern, uFallback) {
|
|
13346
|
+
try {
|
|
13347
|
+
return new RegExp(vPattern, "v");
|
|
13348
|
+
} catch {
|
|
13349
|
+
return new RegExp(uFallback, "u");
|
|
13350
|
+
}
|
|
13351
|
+
}
|
|
13352
|
+
var zeroWidthRegex = createUnicodeRegex(
|
|
13353
|
+
"^(?:\\p{Default_Ignorable_Code_Point}|\\p{Control}|\\p{Mark}|\\p{Surrogate})+$",
|
|
13354
|
+
"^(?:\\p{Default_Ignorable_Code_Point}|\\p{Control}|\\p{Mark}|\\p{Surrogate})+$"
|
|
13355
|
+
);
|
|
13356
|
+
var leadingNonPrintingRegex = createUnicodeRegex(
|
|
13357
|
+
"^[\\p{Default_Ignorable_Code_Point}\\p{Control}\\p{Format}\\p{Mark}\\p{Surrogate}]+",
|
|
13358
|
+
"^[\\p{Default_Ignorable_Code_Point}\\p{Control}\\p{Format}\\p{Mark}\\p{Surrogate}]+"
|
|
13359
|
+
);
|
|
13360
|
+
var rgiEmojiRegex = createUnicodeRegex("^\\p{RGI_Emoji}$", "^\\p{Extended_Pictographic}$");
|
|
13361
|
+
var AnsiStripper = {
|
|
13362
|
+
strip(text) {
|
|
13363
|
+
if (!text.includes("\x1B")) {
|
|
13364
|
+
return text;
|
|
13365
|
+
}
|
|
13366
|
+
let cleaned = text;
|
|
13367
|
+
cleaned = cleaned.replace(/\x1b\[[0-9;]*[mGKHJ]/g, "");
|
|
13368
|
+
cleaned = cleaned.replace(/\x1b\]8;;[^\x07]*\x07/g, "");
|
|
13369
|
+
cleaned = cleaned.replace(/\x1b_[^\x07\x1b]*(?:\x07|\x1b\\)/g, "");
|
|
13370
|
+
return cleaned;
|
|
13371
|
+
}
|
|
13372
|
+
};
|
|
13373
|
+
var WIDTH_CACHE_SIZE = 512;
|
|
13374
|
+
var widthCache = /* @__PURE__ */ new Map();
|
|
13375
|
+
function measureClusterWidth(segment) {
|
|
13376
|
+
if (zeroWidthRegex.test(segment)) {
|
|
13377
|
+
return 0;
|
|
13378
|
+
}
|
|
13379
|
+
if (looksLikeEmojiCandidate(segment) && rgiEmojiRegex.test(segment)) {
|
|
13380
|
+
return 2;
|
|
13381
|
+
}
|
|
13382
|
+
const base = segment.replace(leadingNonPrintingRegex, "");
|
|
13383
|
+
const cp = base.codePointAt(0);
|
|
13384
|
+
if (cp === void 0) {
|
|
13385
|
+
return 0;
|
|
13386
|
+
}
|
|
13387
|
+
let width = eastAsianWidth(cp);
|
|
13388
|
+
if (segment.length > 1) {
|
|
13389
|
+
for (const char of segment.slice(1)) {
|
|
13390
|
+
const c = char.codePointAt(0);
|
|
13391
|
+
if (c >= 65280 && c <= 65519) {
|
|
13392
|
+
width += eastAsianWidth(c);
|
|
13393
|
+
}
|
|
13394
|
+
}
|
|
13395
|
+
}
|
|
13396
|
+
return width;
|
|
13397
|
+
}
|
|
13398
|
+
function visibleWidth(str2) {
|
|
13399
|
+
if (str2.length === 0) {
|
|
13400
|
+
return 0;
|
|
13401
|
+
}
|
|
13402
|
+
let isPureAscii = true;
|
|
13403
|
+
for (let i = 0; i < str2.length; i++) {
|
|
13404
|
+
const code = str2.charCodeAt(i);
|
|
13405
|
+
if (code < 32 || code > 126) {
|
|
13406
|
+
isPureAscii = false;
|
|
13407
|
+
break;
|
|
13408
|
+
}
|
|
13409
|
+
}
|
|
13410
|
+
if (isPureAscii) {
|
|
13411
|
+
return str2.length;
|
|
13412
|
+
}
|
|
13413
|
+
const cached = widthCache.get(str2);
|
|
13414
|
+
if (cached !== void 0) {
|
|
13415
|
+
return cached;
|
|
13416
|
+
}
|
|
13417
|
+
let clean = str2;
|
|
13418
|
+
if (str2.includes(" ")) {
|
|
13419
|
+
clean = clean.replace(/\t/g, " ");
|
|
13420
|
+
}
|
|
13421
|
+
clean = AnsiStripper.strip(clean);
|
|
13422
|
+
let width = 0;
|
|
13423
|
+
for (const { segment } of segmenter.segment(clean)) {
|
|
13424
|
+
width += measureClusterWidth(segment);
|
|
13425
|
+
}
|
|
13426
|
+
if (widthCache.size >= WIDTH_CACHE_SIZE) {
|
|
13427
|
+
const firstKey = widthCache.keys().next().value;
|
|
13428
|
+
if (firstKey !== void 0) {
|
|
13429
|
+
widthCache.delete(firstKey);
|
|
13430
|
+
}
|
|
13431
|
+
}
|
|
13432
|
+
widthCache.set(str2, width);
|
|
13433
|
+
return width;
|
|
13434
|
+
}
|
|
13435
|
+
function extractAnsiCode(str2, pos) {
|
|
13436
|
+
if (pos >= str2.length || str2[pos] !== "\x1B") return null;
|
|
13437
|
+
const next = str2[pos + 1];
|
|
13438
|
+
if (next === "[") {
|
|
13439
|
+
let j = pos + 2;
|
|
13440
|
+
while (j < str2.length && !/[mGKHJ]/.test(str2[j])) j++;
|
|
13441
|
+
if (j < str2.length) return { code: str2.substring(pos, j + 1), length: j + 1 - pos };
|
|
13442
|
+
return null;
|
|
13443
|
+
}
|
|
13444
|
+
if (next === "]") {
|
|
13445
|
+
let j = pos + 2;
|
|
13446
|
+
while (j < str2.length) {
|
|
13447
|
+
if (str2[j] === "\x07") return { code: str2.substring(pos, j + 1), length: j + 1 - pos };
|
|
13448
|
+
if (str2[j] === "\x1B" && str2[j + 1] === "\\") return { code: str2.substring(pos, j + 2), length: j + 2 - pos };
|
|
13449
|
+
j++;
|
|
13450
|
+
}
|
|
13451
|
+
return null;
|
|
13452
|
+
}
|
|
13453
|
+
if (next === "_") {
|
|
13454
|
+
let j = pos + 2;
|
|
13455
|
+
while (j < str2.length) {
|
|
13456
|
+
if (str2[j] === "\x07") return { code: str2.substring(pos, j + 1), length: j + 1 - pos };
|
|
13457
|
+
if (str2[j] === "\x1B" && str2[j + 1] === "\\") return { code: str2.substring(pos, j + 2), length: j + 2 - pos };
|
|
13458
|
+
j++;
|
|
13459
|
+
}
|
|
13460
|
+
return null;
|
|
13461
|
+
}
|
|
13462
|
+
return null;
|
|
13463
|
+
}
|
|
13464
|
+
var AnsiStateTracker = class {
|
|
13465
|
+
// Each attribute is kept on its own flag, which lets us clear them one at a time.
|
|
13466
|
+
_bold = false;
|
|
13467
|
+
_dim = false;
|
|
13468
|
+
italic = false;
|
|
13469
|
+
underline = false;
|
|
13470
|
+
blink = false;
|
|
13471
|
+
inverse = false;
|
|
13472
|
+
hidden = false;
|
|
13473
|
+
strikethrough = false;
|
|
13474
|
+
_colors = { fg: null, bg: null };
|
|
13475
|
+
process(ansiCode) {
|
|
13476
|
+
if (!ansiCode.endsWith("m")) {
|
|
13477
|
+
return;
|
|
13478
|
+
}
|
|
13479
|
+
const match = ansiCode.match(/\x1b\[([\d;]*)m/);
|
|
13480
|
+
if (!match) return;
|
|
13481
|
+
const params = match[1];
|
|
13482
|
+
if (params === "" || params === "0") {
|
|
13483
|
+
this.reset();
|
|
13484
|
+
return;
|
|
13485
|
+
}
|
|
13486
|
+
const parts = params.split(";");
|
|
13487
|
+
let i = 0;
|
|
13488
|
+
while (i < parts.length) {
|
|
13489
|
+
const code = Number.parseInt(parts[i] ?? "", 10);
|
|
13490
|
+
if (Number.isNaN(code)) {
|
|
13491
|
+
i++;
|
|
13492
|
+
continue;
|
|
13493
|
+
}
|
|
13494
|
+
const consumed = this.tryConsumeColorCode(parts, i, code);
|
|
13495
|
+
if (consumed > 0) {
|
|
13496
|
+
i += consumed;
|
|
13497
|
+
continue;
|
|
13498
|
+
}
|
|
13499
|
+
this.applyStandardCode(code);
|
|
13500
|
+
i++;
|
|
13501
|
+
}
|
|
13502
|
+
}
|
|
13503
|
+
tryConsumeColorCode(parts, index, code) {
|
|
13504
|
+
if (code !== 38 && code !== 48) {
|
|
13505
|
+
return 0;
|
|
13506
|
+
}
|
|
13507
|
+
if (parts[index + 1] === "5" && parts[index + 2] !== void 0) {
|
|
13508
|
+
const colorCode = `${parts[index]};${parts[index + 1]};${parts[index + 2]}`;
|
|
13509
|
+
if (code === 38) {
|
|
13510
|
+
this._colors.fg = colorCode;
|
|
13511
|
+
} else {
|
|
13512
|
+
this._colors.bg = colorCode;
|
|
13513
|
+
}
|
|
13514
|
+
return 3;
|
|
13515
|
+
}
|
|
13516
|
+
if (parts[index + 1] === "2" && parts[index + 4] !== void 0) {
|
|
13517
|
+
const colorCode = `${parts[index]};${parts[index + 1]};${parts[index + 2]};${parts[index + 3]};${parts[index + 4]}`;
|
|
13518
|
+
if (code === 38) {
|
|
13519
|
+
this._colors.fg = colorCode;
|
|
13520
|
+
} else {
|
|
13521
|
+
this._colors.bg = colorCode;
|
|
13522
|
+
}
|
|
13523
|
+
return 5;
|
|
13524
|
+
}
|
|
13525
|
+
return 0;
|
|
13526
|
+
}
|
|
13527
|
+
applyStandardCode(code) {
|
|
13528
|
+
switch (code) {
|
|
13529
|
+
case 0:
|
|
13530
|
+
this.reset();
|
|
13531
|
+
return;
|
|
13532
|
+
case 1:
|
|
13533
|
+
this._bold = true;
|
|
13534
|
+
return;
|
|
13535
|
+
case 2:
|
|
13536
|
+
this._dim = true;
|
|
13537
|
+
return;
|
|
13538
|
+
case 3:
|
|
13539
|
+
this.italic = true;
|
|
13540
|
+
return;
|
|
13541
|
+
case 4:
|
|
13542
|
+
this.underline = true;
|
|
13543
|
+
return;
|
|
13544
|
+
case 5:
|
|
13545
|
+
this.blink = true;
|
|
13546
|
+
return;
|
|
13547
|
+
case 7:
|
|
13548
|
+
this.inverse = true;
|
|
13549
|
+
return;
|
|
13550
|
+
case 8:
|
|
13551
|
+
this.hidden = true;
|
|
13552
|
+
return;
|
|
13553
|
+
case 9:
|
|
13554
|
+
this.strikethrough = true;
|
|
13555
|
+
return;
|
|
13556
|
+
case 21:
|
|
13557
|
+
this._bold = false;
|
|
13558
|
+
return;
|
|
13559
|
+
case 22:
|
|
13560
|
+
this._bold = false;
|
|
13561
|
+
this._dim = false;
|
|
13562
|
+
return;
|
|
13563
|
+
case 23:
|
|
13564
|
+
this.italic = false;
|
|
13565
|
+
return;
|
|
13566
|
+
case 24:
|
|
13567
|
+
this.underline = false;
|
|
13568
|
+
return;
|
|
13569
|
+
case 25:
|
|
13570
|
+
this.blink = false;
|
|
13571
|
+
return;
|
|
13572
|
+
case 27:
|
|
13573
|
+
this.inverse = false;
|
|
13574
|
+
return;
|
|
13575
|
+
case 28:
|
|
13576
|
+
this.hidden = false;
|
|
13577
|
+
return;
|
|
13578
|
+
case 29:
|
|
13579
|
+
this.strikethrough = false;
|
|
13580
|
+
return;
|
|
13581
|
+
case 39:
|
|
13582
|
+
this._colors.fg = null;
|
|
13583
|
+
return;
|
|
13584
|
+
case 49:
|
|
13585
|
+
this._colors.bg = null;
|
|
13586
|
+
return;
|
|
13587
|
+
default:
|
|
13588
|
+
if (code >= 30 && code <= 37 || code >= 90 && code <= 97) {
|
|
13589
|
+
this._colors.fg = String(code);
|
|
13590
|
+
return;
|
|
13591
|
+
}
|
|
13592
|
+
if (code >= 40 && code <= 47 || code >= 100 && code <= 107) {
|
|
13593
|
+
this._colors.bg = String(code);
|
|
13594
|
+
}
|
|
13595
|
+
}
|
|
13596
|
+
}
|
|
13597
|
+
reset() {
|
|
13598
|
+
this._bold = false;
|
|
13599
|
+
this._dim = false;
|
|
13600
|
+
this.italic = false;
|
|
13601
|
+
this.underline = false;
|
|
13602
|
+
this.blink = false;
|
|
13603
|
+
this.inverse = false;
|
|
13604
|
+
this.hidden = false;
|
|
13605
|
+
this.strikethrough = false;
|
|
13606
|
+
this._colors.fg = null;
|
|
13607
|
+
this._colors.bg = null;
|
|
13608
|
+
}
|
|
13609
|
+
/** Wipe all tracked state so the instance can be reused. */
|
|
13610
|
+
clear() {
|
|
13611
|
+
this.reset();
|
|
13612
|
+
}
|
|
13613
|
+
getActiveCodes() {
|
|
13614
|
+
const codes = [];
|
|
13615
|
+
if (this._bold) codes.push("1");
|
|
13616
|
+
if (this._dim) codes.push("2");
|
|
13617
|
+
if (this.italic) codes.push("3");
|
|
13618
|
+
if (this.underline) codes.push("4");
|
|
13619
|
+
if (this.blink) codes.push("5");
|
|
13620
|
+
if (this.inverse) codes.push("7");
|
|
13621
|
+
if (this.hidden) codes.push("8");
|
|
13622
|
+
if (this.strikethrough) codes.push("9");
|
|
13623
|
+
if (this._colors.fg) codes.push(this._colors.fg);
|
|
13624
|
+
if (this._colors.bg) codes.push(this._colors.bg);
|
|
13625
|
+
if (codes.length === 0) return "";
|
|
13626
|
+
return `\x1B[${codes.join(";")}m`;
|
|
13627
|
+
}
|
|
13628
|
+
hasActiveCodes() {
|
|
13629
|
+
return this._bold || this._dim || this.italic || this.underline || this.blink || this.inverse || this.hidden || this.strikethrough || this._colors.fg !== null || this._colors.bg !== null;
|
|
13630
|
+
}
|
|
13631
|
+
/**
|
|
13632
|
+
* Produce the escape code needed to switch off any attribute that would
|
|
13633
|
+
* otherwise smear into the padding at the end of a line. In practice that
|
|
13634
|
+
* is just underline. Yields an empty string when nothing needs disabling.
|
|
13635
|
+
*/
|
|
13636
|
+
getLineEndReset() {
|
|
13637
|
+
if (this.underline) {
|
|
13638
|
+
return "\x1B[24m";
|
|
13639
|
+
}
|
|
13640
|
+
return "";
|
|
13641
|
+
}
|
|
13642
|
+
};
|
|
13643
|
+
function mergeTextIntoTracker(text, tracker) {
|
|
13644
|
+
let i = 0;
|
|
13645
|
+
while (i < text.length) {
|
|
13646
|
+
const ansiResult = extractAnsiCode(text, i);
|
|
13647
|
+
if (ansiResult) {
|
|
13648
|
+
tracker.process(ansiResult.code);
|
|
13649
|
+
i += ansiResult.length;
|
|
13650
|
+
} else {
|
|
13651
|
+
i++;
|
|
13652
|
+
}
|
|
13653
|
+
}
|
|
13654
|
+
}
|
|
13655
|
+
function tokenizeTextWithAnsi(text) {
|
|
13656
|
+
const tokens = [];
|
|
13657
|
+
let current = "";
|
|
13658
|
+
let pendingAnsi = "";
|
|
13659
|
+
let inWhitespace = false;
|
|
13660
|
+
let i = 0;
|
|
13661
|
+
while (i < text.length) {
|
|
13662
|
+
const ansiResult = extractAnsiCode(text, i);
|
|
13663
|
+
if (ansiResult) {
|
|
13664
|
+
pendingAnsi += ansiResult.code;
|
|
13665
|
+
i += ansiResult.length;
|
|
13666
|
+
continue;
|
|
13667
|
+
}
|
|
13668
|
+
const char = text[i];
|
|
13669
|
+
const charIsSpace = char === " ";
|
|
13670
|
+
if (charIsSpace !== inWhitespace && current) {
|
|
13671
|
+
tokens.push(current);
|
|
13672
|
+
current = "";
|
|
13673
|
+
}
|
|
13674
|
+
if (pendingAnsi) {
|
|
13675
|
+
current += pendingAnsi;
|
|
13676
|
+
pendingAnsi = "";
|
|
13677
|
+
}
|
|
13678
|
+
inWhitespace = charIsSpace;
|
|
13679
|
+
current += char;
|
|
13680
|
+
i++;
|
|
13681
|
+
}
|
|
13682
|
+
if (pendingAnsi) {
|
|
13683
|
+
current += pendingAnsi;
|
|
13684
|
+
}
|
|
13685
|
+
if (current) {
|
|
13686
|
+
tokens.push(current);
|
|
13687
|
+
}
|
|
13688
|
+
return tokens;
|
|
13689
|
+
}
|
|
13690
|
+
var TextWrapper = class {
|
|
13691
|
+
wrap(text, width) {
|
|
13692
|
+
return wrapTextWithAnsi(text, width);
|
|
13693
|
+
}
|
|
13694
|
+
};
|
|
13695
|
+
var textWrapper = new TextWrapper();
|
|
13696
|
+
var TokenWrapEngine = {
|
|
13697
|
+
wrap(tokens, width, tracker) {
|
|
13698
|
+
const wrapped = [];
|
|
13699
|
+
let currentLine = "";
|
|
13700
|
+
let currentVisibleLength = 0;
|
|
13701
|
+
for (const token of tokens) {
|
|
13702
|
+
const tokenVisibleLength = visibleWidth(token);
|
|
13703
|
+
const isWhitespace = token.trim() === "";
|
|
13704
|
+
if (tokenVisibleLength > width && !isWhitespace) {
|
|
13705
|
+
if (currentLine) {
|
|
13706
|
+
const lineEndReset = tracker.getLineEndReset();
|
|
13707
|
+
if (lineEndReset) {
|
|
13708
|
+
currentLine += lineEndReset;
|
|
13709
|
+
}
|
|
13710
|
+
wrapped.push(currentLine);
|
|
13711
|
+
currentLine = "";
|
|
13712
|
+
currentVisibleLength = 0;
|
|
13713
|
+
}
|
|
13714
|
+
const broken = splitLongToken(token, width, tracker);
|
|
13715
|
+
wrapped.push(...broken.slice(0, -1));
|
|
13716
|
+
currentLine = broken[broken.length - 1];
|
|
13717
|
+
currentVisibleLength = visibleWidth(currentLine);
|
|
13718
|
+
continue;
|
|
13719
|
+
}
|
|
13720
|
+
const totalNeeded = currentVisibleLength + tokenVisibleLength;
|
|
13721
|
+
if (totalNeeded > width && currentVisibleLength > 0) {
|
|
13722
|
+
let lineToWrap = currentLine.trimEnd();
|
|
13723
|
+
const lineEndReset = tracker.getLineEndReset();
|
|
13724
|
+
if (lineEndReset) {
|
|
13725
|
+
lineToWrap += lineEndReset;
|
|
13726
|
+
}
|
|
13727
|
+
wrapped.push(lineToWrap);
|
|
13728
|
+
if (isWhitespace) {
|
|
13729
|
+
currentLine = tracker.getActiveCodes();
|
|
13730
|
+
currentVisibleLength = 0;
|
|
13731
|
+
} else {
|
|
13732
|
+
currentLine = tracker.getActiveCodes() + token;
|
|
13733
|
+
currentVisibleLength = tokenVisibleLength;
|
|
13734
|
+
}
|
|
13735
|
+
} else {
|
|
13736
|
+
currentLine += token;
|
|
13737
|
+
currentVisibleLength += tokenVisibleLength;
|
|
13738
|
+
}
|
|
13739
|
+
mergeTextIntoTracker(token, tracker);
|
|
13740
|
+
}
|
|
13741
|
+
return { wrapped, currentLine, currentVisibleLength };
|
|
13742
|
+
}
|
|
13743
|
+
};
|
|
13744
|
+
function wrapTextWithAnsi(text, width) {
|
|
13745
|
+
if (!text) {
|
|
13746
|
+
return [""];
|
|
13747
|
+
}
|
|
13748
|
+
const inputLines = text.split("\n");
|
|
13749
|
+
const result = [];
|
|
13750
|
+
const tracker = new AnsiStateTracker();
|
|
13751
|
+
for (const inputLine of inputLines) {
|
|
13752
|
+
const prefix = result.length > 0 ? tracker.getActiveCodes() : "";
|
|
13753
|
+
result.push(...wrapLinePreservingAnsi(prefix + inputLine, width));
|
|
13754
|
+
mergeTextIntoTracker(inputLine, tracker);
|
|
13755
|
+
}
|
|
13756
|
+
return result.length > 0 ? result : [""];
|
|
13757
|
+
}
|
|
13758
|
+
function wrapLinePreservingAnsi(line4, width) {
|
|
13759
|
+
if (!line4) {
|
|
13760
|
+
return [""];
|
|
13761
|
+
}
|
|
13762
|
+
const visibleLength = visibleWidth(line4);
|
|
13763
|
+
if (visibleLength <= width) {
|
|
13764
|
+
return [line4];
|
|
13765
|
+
}
|
|
13766
|
+
const tracker = new AnsiStateTracker();
|
|
13767
|
+
const tokens = tokenizeTextWithAnsi(line4);
|
|
13768
|
+
const { wrapped, currentLine } = TokenWrapEngine.wrap(tokens, width, tracker);
|
|
13769
|
+
if (currentLine) {
|
|
13770
|
+
wrapped.push(currentLine);
|
|
13771
|
+
}
|
|
13772
|
+
return wrapped.length > 0 ? wrapped.map((segmentLine) => segmentLine.trimEnd()) : [""];
|
|
13773
|
+
}
|
|
13774
|
+
function splitLongToken(word, width, tracker) {
|
|
13775
|
+
const lines = [];
|
|
13776
|
+
let currentLine = tracker.getActiveCodes();
|
|
13777
|
+
let currentWidth = 0;
|
|
13778
|
+
let i = 0;
|
|
13779
|
+
const segments = [];
|
|
13780
|
+
while (i < word.length) {
|
|
13781
|
+
const ansiResult = extractAnsiCode(word, i);
|
|
13782
|
+
if (ansiResult) {
|
|
13783
|
+
segments.push({ type: "ansi", value: ansiResult.code });
|
|
13784
|
+
i += ansiResult.length;
|
|
13785
|
+
} else {
|
|
13786
|
+
let end = i;
|
|
13787
|
+
while (end < word.length) {
|
|
13788
|
+
const nextAnsi = extractAnsiCode(word, end);
|
|
13789
|
+
if (nextAnsi) break;
|
|
13790
|
+
end++;
|
|
13791
|
+
}
|
|
13792
|
+
const textPortion = word.slice(i, end);
|
|
13793
|
+
for (const seg of segmenter.segment(textPortion)) {
|
|
13794
|
+
segments.push({ type: "grapheme", value: seg.segment });
|
|
13795
|
+
}
|
|
13796
|
+
i = end;
|
|
13797
|
+
}
|
|
13798
|
+
}
|
|
13799
|
+
for (const seg of segments) {
|
|
13800
|
+
if (seg.type === "ansi") {
|
|
13801
|
+
currentLine += seg.value;
|
|
13802
|
+
tracker.process(seg.value);
|
|
13803
|
+
continue;
|
|
13804
|
+
}
|
|
13805
|
+
const grapheme = seg.value;
|
|
13806
|
+
if (!grapheme) continue;
|
|
13807
|
+
const clusterWidth = visibleWidth(grapheme);
|
|
13808
|
+
if (currentWidth + clusterWidth > width) {
|
|
13809
|
+
const lineEndReset = tracker.getLineEndReset();
|
|
13810
|
+
if (lineEndReset) {
|
|
13811
|
+
currentLine += lineEndReset;
|
|
13812
|
+
}
|
|
13813
|
+
lines.push(currentLine);
|
|
13814
|
+
currentLine = tracker.getActiveCodes();
|
|
13815
|
+
currentWidth = 0;
|
|
13816
|
+
}
|
|
13817
|
+
currentLine += grapheme;
|
|
13818
|
+
currentWidth += clusterWidth;
|
|
13819
|
+
}
|
|
13820
|
+
if (currentLine) {
|
|
13821
|
+
lines.push(currentLine);
|
|
13822
|
+
}
|
|
13823
|
+
return lines.length > 0 ? lines : [""];
|
|
13824
|
+
}
|
|
13825
|
+
var pooledStyleTracker = new AnsiStateTracker();
|
|
13826
|
+
|
|
13827
|
+
// src/react-ink/markdown/format-token.ts
|
|
13828
|
+
var EOL = "\n";
|
|
13829
|
+
var BLOCKQUOTE_BAR = "\u2502";
|
|
13830
|
+
var markedConfigured = false;
|
|
13831
|
+
function configureMarked() {
|
|
13832
|
+
if (markedConfigured) {
|
|
13833
|
+
return;
|
|
13834
|
+
}
|
|
13835
|
+
markedConfigured = true;
|
|
13836
|
+
marked.use({
|
|
13837
|
+
tokenizer: {
|
|
13838
|
+
del() {
|
|
13839
|
+
return void 0;
|
|
13840
|
+
}
|
|
13841
|
+
}
|
|
13842
|
+
});
|
|
13843
|
+
}
|
|
13844
|
+
var TOKEN_CACHE_MAX = 500;
|
|
13845
|
+
var tokenCache = /* @__PURE__ */ new Map();
|
|
13846
|
+
var MD_SYNTAX_RE = /[#*`|[>\-_~]|\n\n|^\d+\. |\n\d+\. /;
|
|
13847
|
+
function hasMarkdownSyntax(text) {
|
|
13848
|
+
return MD_SYNTAX_RE.test(text.length > 500 ? text.slice(0, 500) : text);
|
|
13849
|
+
}
|
|
13850
|
+
function hashContent(content) {
|
|
13851
|
+
let hash = 2166136261;
|
|
13852
|
+
for (let i = 0; i < content.length; i++) {
|
|
13853
|
+
hash ^= content.charCodeAt(i);
|
|
13854
|
+
hash = Math.imul(hash, 16777619);
|
|
13855
|
+
}
|
|
13856
|
+
return (hash >>> 0).toString(36) + ":" + content.length.toString(36);
|
|
13857
|
+
}
|
|
13858
|
+
function cachedLexer(content) {
|
|
13859
|
+
configureMarked();
|
|
13860
|
+
if (!hasMarkdownSyntax(content)) {
|
|
13861
|
+
return [
|
|
13862
|
+
{
|
|
13863
|
+
type: "paragraph",
|
|
13864
|
+
raw: content,
|
|
13865
|
+
text: content,
|
|
13866
|
+
tokens: [{ type: "text", raw: content, text: content }]
|
|
13867
|
+
}
|
|
13868
|
+
];
|
|
13869
|
+
}
|
|
13870
|
+
const key = hashContent(content);
|
|
13871
|
+
const hit = tokenCache.get(key);
|
|
13872
|
+
if (hit) {
|
|
13873
|
+
tokenCache.delete(key);
|
|
13874
|
+
tokenCache.set(key, hit);
|
|
13875
|
+
return hit;
|
|
13876
|
+
}
|
|
13877
|
+
const tokens = marked.lexer(content);
|
|
13878
|
+
if (tokenCache.size >= TOKEN_CACHE_MAX) {
|
|
13879
|
+
const first = tokenCache.keys().next().value;
|
|
13880
|
+
if (first !== void 0) {
|
|
13881
|
+
tokenCache.delete(first);
|
|
13882
|
+
}
|
|
13883
|
+
}
|
|
13884
|
+
tokenCache.set(key, tokens);
|
|
13885
|
+
return tokens;
|
|
13886
|
+
}
|
|
13887
|
+
function formatToken(token, theme, highlight = null, listDepth = 0, orderedListNumber = null, parent = null) {
|
|
13888
|
+
switch (token.type) {
|
|
13889
|
+
case "blockquote": {
|
|
13890
|
+
const inner = (token.tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("");
|
|
13891
|
+
const bar = theme.dim(BLOCKQUOTE_BAR);
|
|
13892
|
+
return inner.split(EOL).map((line4) => stripAnsi3(line4).trim() ? `${bar} ${chalk2.italic(line4)}` : line4).join(EOL);
|
|
13893
|
+
}
|
|
13894
|
+
case "code": {
|
|
13895
|
+
const codeToken = token;
|
|
13896
|
+
if (!highlight) {
|
|
13897
|
+
return codeToken.text + EOL;
|
|
13898
|
+
}
|
|
13899
|
+
let language = "plaintext";
|
|
13900
|
+
if (codeToken.lang && highlight.supportsLanguage(codeToken.lang)) {
|
|
13901
|
+
language = codeToken.lang;
|
|
13902
|
+
}
|
|
13903
|
+
return highlight.highlight(codeToken.text, { language }) + EOL;
|
|
13904
|
+
}
|
|
13905
|
+
case "codespan":
|
|
13906
|
+
return theme.role("codeInline", token.text);
|
|
13907
|
+
case "em":
|
|
13908
|
+
return chalk2.italic(
|
|
13909
|
+
(token.tokens ?? []).map((child) => formatToken(child, theme, highlight, 0, null, parent)).join("")
|
|
13910
|
+
);
|
|
13911
|
+
case "strong":
|
|
13912
|
+
return chalk2.bold(
|
|
13913
|
+
(token.tokens ?? []).map((child) => formatToken(child, theme, highlight, 0, null, parent)).join("")
|
|
13914
|
+
);
|
|
13915
|
+
case "heading": {
|
|
13916
|
+
const headingToken = token;
|
|
13917
|
+
const inner = (headingToken.tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("");
|
|
13918
|
+
const colored = theme.role("heading", inner);
|
|
13919
|
+
if (headingToken.depth === 1) {
|
|
13920
|
+
return chalk2.bold.italic.underline(colored) + EOL + EOL;
|
|
13921
|
+
}
|
|
13922
|
+
return chalk2.bold(colored) + EOL + EOL;
|
|
13923
|
+
}
|
|
13924
|
+
case "hr":
|
|
13925
|
+
return "---";
|
|
13926
|
+
case "image":
|
|
13927
|
+
return token.href;
|
|
13928
|
+
case "link": {
|
|
13929
|
+
const linkToken = token;
|
|
13930
|
+
if (linkToken.href.startsWith("mailto:")) {
|
|
13931
|
+
return linkToken.href.replace(/^mailto:/, "");
|
|
13932
|
+
}
|
|
13933
|
+
const linkText = (linkToken.tokens ?? []).map((child) => formatToken(child, theme, highlight, 0, null, linkToken)).join("");
|
|
13934
|
+
const plainLinkText = stripAnsi3(linkText);
|
|
13935
|
+
const display = plainLinkText && plainLinkText !== linkToken.href ? linkText : linkToken.href;
|
|
13936
|
+
return `\x1B]8;;${linkToken.href}\x07${display}\x1B]8;;\x07`;
|
|
13937
|
+
}
|
|
13938
|
+
case "list": {
|
|
13939
|
+
const listToken = token;
|
|
13940
|
+
const start = typeof listToken.start === "number" ? listToken.start : Number(listToken.start) || 1;
|
|
13941
|
+
return listToken.items.map(
|
|
13942
|
+
(item, index) => formatToken(
|
|
13943
|
+
item,
|
|
13944
|
+
theme,
|
|
13945
|
+
highlight,
|
|
13946
|
+
listDepth,
|
|
13947
|
+
listToken.ordered ? start + index : null,
|
|
13948
|
+
listToken
|
|
13949
|
+
)
|
|
13950
|
+
).join("");
|
|
13951
|
+
}
|
|
13952
|
+
case "list_item":
|
|
13953
|
+
return (token.tokens ?? []).map(
|
|
13954
|
+
(child) => `${" ".repeat(listDepth)}${formatToken(child, theme, highlight, listDepth + 1, orderedListNumber, token)}`
|
|
13955
|
+
).join("");
|
|
13956
|
+
case "paragraph":
|
|
13957
|
+
return (token.tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("") + EOL;
|
|
13958
|
+
case "space":
|
|
13959
|
+
case "br":
|
|
13960
|
+
return EOL;
|
|
13961
|
+
case "text": {
|
|
13962
|
+
const textToken = token;
|
|
13963
|
+
if (parent?.type === "link") {
|
|
13964
|
+
return textToken.text;
|
|
13965
|
+
}
|
|
13966
|
+
if (parent?.type === "list_item") {
|
|
13967
|
+
const marker = orderedListNumber === null ? "-" : `${getListNumber(listDepth, orderedListNumber)}.`;
|
|
13968
|
+
const body = textToken.tokens ? textToken.tokens.map((child) => formatToken(child, theme, highlight, listDepth, orderedListNumber, token)).join("") : textToken.text;
|
|
13969
|
+
return `${marker} ${body}${EOL}`;
|
|
13970
|
+
}
|
|
13971
|
+
return textToken.text;
|
|
13972
|
+
}
|
|
13973
|
+
case "escape":
|
|
13974
|
+
return token.text;
|
|
13975
|
+
case "table":
|
|
13976
|
+
case "def":
|
|
13977
|
+
case "del":
|
|
13978
|
+
case "html":
|
|
13979
|
+
return "";
|
|
13980
|
+
default:
|
|
13981
|
+
return "";
|
|
13982
|
+
}
|
|
13983
|
+
}
|
|
13984
|
+
function numberToLetter(n) {
|
|
13985
|
+
let result = "";
|
|
13986
|
+
while (n > 0) {
|
|
13987
|
+
n--;
|
|
13988
|
+
result = String.fromCharCode(97 + n % 26) + result;
|
|
13989
|
+
n = Math.floor(n / 26);
|
|
13990
|
+
}
|
|
13991
|
+
return result;
|
|
13992
|
+
}
|
|
13993
|
+
var ROMAN_VALUES = [
|
|
13994
|
+
[1e3, "m"],
|
|
13995
|
+
[900, "cm"],
|
|
13996
|
+
[500, "d"],
|
|
13997
|
+
[400, "cd"],
|
|
13998
|
+
[100, "c"],
|
|
13999
|
+
[90, "xc"],
|
|
14000
|
+
[50, "l"],
|
|
14001
|
+
[40, "xl"],
|
|
14002
|
+
[10, "x"],
|
|
14003
|
+
[9, "ix"],
|
|
14004
|
+
[5, "v"],
|
|
14005
|
+
[4, "iv"],
|
|
14006
|
+
[1, "i"]
|
|
14007
|
+
];
|
|
14008
|
+
function numberToRoman(n) {
|
|
14009
|
+
let result = "";
|
|
14010
|
+
for (const [value, numeral] of ROMAN_VALUES) {
|
|
14011
|
+
while (n >= value) {
|
|
14012
|
+
result += numeral;
|
|
14013
|
+
n -= value;
|
|
14014
|
+
}
|
|
14015
|
+
}
|
|
14016
|
+
return result;
|
|
14017
|
+
}
|
|
14018
|
+
function getListNumber(listDepth, orderedListNumber) {
|
|
14019
|
+
switch (listDepth) {
|
|
14020
|
+
case 0:
|
|
14021
|
+
case 1:
|
|
14022
|
+
return orderedListNumber.toString();
|
|
14023
|
+
case 2:
|
|
14024
|
+
return numberToLetter(orderedListNumber);
|
|
14025
|
+
case 3:
|
|
14026
|
+
return numberToRoman(orderedListNumber);
|
|
14027
|
+
default:
|
|
14028
|
+
return orderedListNumber.toString();
|
|
14029
|
+
}
|
|
14030
|
+
}
|
|
14031
|
+
function padAligned(content, displayWidth, targetWidth, align) {
|
|
14032
|
+
const padding = Math.max(0, targetWidth - displayWidth);
|
|
14033
|
+
if (align === "center") {
|
|
14034
|
+
const leftPad = Math.floor(padding / 2);
|
|
14035
|
+
return " ".repeat(leftPad) + content + " ".repeat(padding - leftPad);
|
|
14036
|
+
}
|
|
14037
|
+
if (align === "right") {
|
|
14038
|
+
return " ".repeat(padding) + content;
|
|
14039
|
+
}
|
|
14040
|
+
return content + " ".repeat(padding);
|
|
14041
|
+
}
|
|
14042
|
+
function stringWidth(text) {
|
|
14043
|
+
return visibleWidth(text);
|
|
14044
|
+
}
|
|
14045
|
+
|
|
14046
|
+
// src/react-ink/markdown/highlight.ts
|
|
14047
|
+
import { extname } from "node:path";
|
|
14048
|
+
import hljs from "highlight.js";
|
|
14049
|
+
function scopeToRole(scope) {
|
|
14050
|
+
const head = scope.split(".")[0] ?? scope;
|
|
14051
|
+
switch (head) {
|
|
14052
|
+
case "keyword":
|
|
14053
|
+
case "built_in":
|
|
14054
|
+
case "literal":
|
|
14055
|
+
case "operator":
|
|
14056
|
+
return "synKeyword";
|
|
14057
|
+
case "string":
|
|
14058
|
+
case "regexp":
|
|
14059
|
+
case "symbol":
|
|
14060
|
+
case "char":
|
|
14061
|
+
case "meta":
|
|
14062
|
+
return "synString";
|
|
14063
|
+
case "number":
|
|
14064
|
+
return "synNumber";
|
|
14065
|
+
case "comment":
|
|
14066
|
+
case "quote":
|
|
14067
|
+
return "synComment";
|
|
14068
|
+
case "type":
|
|
14069
|
+
case "class":
|
|
14070
|
+
case "title":
|
|
14071
|
+
case "tag":
|
|
14072
|
+
case "name":
|
|
14073
|
+
case "attr":
|
|
14074
|
+
case "attribute":
|
|
14075
|
+
case "selector":
|
|
14076
|
+
return "synType";
|
|
14077
|
+
default:
|
|
14078
|
+
return null;
|
|
14079
|
+
}
|
|
14080
|
+
}
|
|
14081
|
+
var HTML_ENTITIES = {
|
|
14082
|
+
"&": "&",
|
|
14083
|
+
"<": "<",
|
|
14084
|
+
">": ">",
|
|
14085
|
+
""": '"',
|
|
14086
|
+
"'": "'",
|
|
14087
|
+
"'": "'"
|
|
14088
|
+
};
|
|
14089
|
+
function decodeEntities2(text) {
|
|
14090
|
+
return text.replace(/&(?:amp|lt|gt|quot|#x27|#39);/g, (match) => HTML_ENTITIES[match] ?? match);
|
|
14091
|
+
}
|
|
14092
|
+
function parseHljsHtml(html) {
|
|
14093
|
+
const nodes = [];
|
|
14094
|
+
const scopeStack = [];
|
|
14095
|
+
const tagRe = /<span class="hljs-([^"]+)">|<\/span>/g;
|
|
14096
|
+
let lastIndex = 0;
|
|
14097
|
+
let match;
|
|
14098
|
+
const pushText = (raw) => {
|
|
14099
|
+
if (!raw) return;
|
|
14100
|
+
const currentScope = scopeStack.length > 0 ? scopeStack[scopeStack.length - 1] : null;
|
|
14101
|
+
const scope = currentScope ? currentScope.split(/\s+/)[0].replace(/_$/, "") : null;
|
|
14102
|
+
nodes.push({ text: decodeEntities2(raw), scope });
|
|
14103
|
+
};
|
|
14104
|
+
while ((match = tagRe.exec(html)) !== null) {
|
|
14105
|
+
pushText(html.slice(lastIndex, match.index));
|
|
14106
|
+
lastIndex = tagRe.lastIndex;
|
|
14107
|
+
if (match[0] === "</span>") {
|
|
14108
|
+
scopeStack.pop();
|
|
14109
|
+
} else if (match[1]) {
|
|
14110
|
+
scopeStack.push(match[1]);
|
|
14111
|
+
}
|
|
14112
|
+
}
|
|
14113
|
+
pushText(html.slice(lastIndex));
|
|
14114
|
+
return nodes;
|
|
14115
|
+
}
|
|
14116
|
+
function createHighlighter(theme) {
|
|
14117
|
+
return {
|
|
14118
|
+
supportsLanguage: (language) => {
|
|
14119
|
+
if (!language || language === "plaintext" || language === "text") {
|
|
14120
|
+
return false;
|
|
14121
|
+
}
|
|
14122
|
+
try {
|
|
14123
|
+
return hljs.getLanguage(language) !== void 0;
|
|
14124
|
+
} catch {
|
|
14125
|
+
return false;
|
|
14126
|
+
}
|
|
14127
|
+
},
|
|
14128
|
+
highlight: (code, options) => {
|
|
14129
|
+
const language = options.language;
|
|
14130
|
+
if (!language || language === "plaintext" || language === "text") {
|
|
14131
|
+
return code;
|
|
14132
|
+
}
|
|
14133
|
+
try {
|
|
14134
|
+
if (hljs.getLanguage(language) === void 0) {
|
|
14135
|
+
return code;
|
|
14136
|
+
}
|
|
14137
|
+
const { value } = hljs.highlight(code, { language, ignoreIllegals: true });
|
|
14138
|
+
return parseHljsHtml(value).map((node) => {
|
|
14139
|
+
const role = node.scope ? scopeToRole(node.scope) : null;
|
|
14140
|
+
return role ? theme.role(role, node.text) : node.text;
|
|
14141
|
+
}).join("");
|
|
14142
|
+
} catch {
|
|
14143
|
+
return code;
|
|
14144
|
+
}
|
|
14145
|
+
}
|
|
14146
|
+
};
|
|
14147
|
+
}
|
|
14148
|
+
function highlightByPath(code, filePath, theme) {
|
|
14149
|
+
const language = languageFromPath(filePath);
|
|
14150
|
+
if (!language) {
|
|
14151
|
+
return code;
|
|
14152
|
+
}
|
|
14153
|
+
const highlighter = createHighlighter(theme);
|
|
14154
|
+
if (!highlighter.supportsLanguage(language)) {
|
|
14155
|
+
return code;
|
|
14156
|
+
}
|
|
14157
|
+
return highlighter.highlight(code, { language });
|
|
14158
|
+
}
|
|
14159
|
+
var EXTENSION_LANGUAGES = {
|
|
14160
|
+
ts: "typescript",
|
|
14161
|
+
tsx: "typescript",
|
|
14162
|
+
mts: "typescript",
|
|
14163
|
+
cts: "typescript",
|
|
14164
|
+
js: "javascript",
|
|
14165
|
+
jsx: "javascript",
|
|
14166
|
+
mjs: "javascript",
|
|
14167
|
+
cjs: "javascript",
|
|
14168
|
+
py: "python",
|
|
14169
|
+
rb: "ruby",
|
|
14170
|
+
rs: "rust",
|
|
14171
|
+
go: "go",
|
|
14172
|
+
java: "java",
|
|
14173
|
+
kt: "kotlin",
|
|
14174
|
+
c: "c",
|
|
14175
|
+
h: "c",
|
|
14176
|
+
cc: "cpp",
|
|
14177
|
+
cpp: "cpp",
|
|
14178
|
+
hpp: "cpp",
|
|
14179
|
+
cs: "csharp",
|
|
14180
|
+
sh: "bash",
|
|
14181
|
+
bash: "bash",
|
|
14182
|
+
zsh: "bash",
|
|
14183
|
+
yml: "yaml",
|
|
14184
|
+
yaml: "yaml",
|
|
14185
|
+
json: "json",
|
|
14186
|
+
md: "markdown",
|
|
14187
|
+
html: "xml",
|
|
14188
|
+
xml: "xml",
|
|
14189
|
+
css: "css",
|
|
14190
|
+
scss: "scss",
|
|
14191
|
+
sql: "sql",
|
|
14192
|
+
toml: "ini",
|
|
14193
|
+
ini: "ini",
|
|
14194
|
+
php: "php",
|
|
14195
|
+
swift: "swift"
|
|
14196
|
+
};
|
|
14197
|
+
function languageFromPath(filePath) {
|
|
14198
|
+
const ext = extname(filePath).slice(1).toLowerCase();
|
|
14199
|
+
if (!ext) {
|
|
14200
|
+
return null;
|
|
14201
|
+
}
|
|
14202
|
+
const mapped = EXTENSION_LANGUAGES[ext];
|
|
14203
|
+
if (mapped) {
|
|
14204
|
+
return mapped;
|
|
14205
|
+
}
|
|
14206
|
+
try {
|
|
14207
|
+
return hljs.getLanguage(ext) !== void 0 ? ext : null;
|
|
14208
|
+
} catch {
|
|
14209
|
+
return null;
|
|
14210
|
+
}
|
|
14211
|
+
}
|
|
14212
|
+
|
|
14213
|
+
// src/react-ink/markdown/MarkdownTable.tsx
|
|
14214
|
+
import chalk3 from "chalk";
|
|
14215
|
+
import stripAnsi4 from "strip-ansi";
|
|
14216
|
+
var MIN_COLUMN_WIDTH = 3;
|
|
14217
|
+
var COLUMN_GAP = 2;
|
|
14218
|
+
function MarkdownTable({ token, theme, highlight = null }) {
|
|
14219
|
+
const formatCell = (tokens) => (tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("");
|
|
14220
|
+
const displayWidth = (tokens) => stringWidth(stripAnsi4(formatCell(tokens)));
|
|
14221
|
+
const columnCount = token.header.length;
|
|
14222
|
+
const columnWidths = token.header.map((header, index) => {
|
|
14223
|
+
let max = displayWidth(header.tokens);
|
|
14224
|
+
for (const row of token.rows) {
|
|
14225
|
+
max = Math.max(max, displayWidth(row[index]?.tokens));
|
|
14226
|
+
}
|
|
14227
|
+
return Math.max(max, MIN_COLUMN_WIDTH);
|
|
14228
|
+
});
|
|
14229
|
+
const renderRow2 = (cells, key, bold) => /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: columnWidths.map((width, index) => {
|
|
14230
|
+
const cell = cells[index];
|
|
14231
|
+
const content = formatCell(cell?.tokens);
|
|
14232
|
+
const visible = stringWidth(stripAnsi4(content));
|
|
14233
|
+
const align = token.align?.[index];
|
|
14234
|
+
const padded = padAligned(content, visible, width, align ?? "left");
|
|
14235
|
+
const styled = bold ? chalk3.bold(padded) : padded;
|
|
14236
|
+
const gap = index < columnCount - 1 ? " ".repeat(COLUMN_GAP) : "";
|
|
14237
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
14238
|
+
styled,
|
|
14239
|
+
gap
|
|
14240
|
+
] }, index);
|
|
14241
|
+
}) }, key);
|
|
14242
|
+
const separator = /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: columnWidths.map((width, index) => {
|
|
14243
|
+
const gap = index < columnCount - 1 ? " ".repeat(COLUMN_GAP) : "";
|
|
14244
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
14245
|
+
theme.dim("-".repeat(width)),
|
|
14246
|
+
gap
|
|
14247
|
+
] }, index);
|
|
14248
|
+
}) });
|
|
14249
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
14250
|
+
renderRow2(token.header, "header", true),
|
|
14251
|
+
separator,
|
|
14252
|
+
token.rows.map((row, rowIndex) => renderRow2(row, `row-${rowIndex}`, false))
|
|
14253
|
+
] });
|
|
14254
|
+
}
|
|
14255
|
+
|
|
14256
|
+
// src/react-ink/markdown/Markdown.tsx
|
|
14257
|
+
function stripPromptXMLTags(text) {
|
|
14258
|
+
return text.replace(/<\/?(?:system-reminder|prompt|context)[^>]*>/g, "");
|
|
14259
|
+
}
|
|
14260
|
+
function Markdown({ children, theme, highlightCode = true, dim = false }) {
|
|
14261
|
+
const highlight = useMemo(
|
|
14262
|
+
() => highlightCode ? createHighlighter(theme) : null,
|
|
14263
|
+
[highlightCode, theme]
|
|
14264
|
+
);
|
|
14265
|
+
const elements = useMemo(() => {
|
|
14266
|
+
configureMarked();
|
|
14267
|
+
const tokens = cachedLexer(stripPromptXMLTags(children));
|
|
14268
|
+
const out = [];
|
|
14269
|
+
let buffer = "";
|
|
14270
|
+
const flush = () => {
|
|
14271
|
+
if (buffer) {
|
|
14272
|
+
const text = buffer.replace(/\n+$/, "");
|
|
14273
|
+
if (text) {
|
|
14274
|
+
out.push(
|
|
14275
|
+
/* @__PURE__ */ jsx(Text, { children: dim ? theme.dim(text) : text }, out.length)
|
|
14276
|
+
);
|
|
14277
|
+
}
|
|
14278
|
+
buffer = "";
|
|
14279
|
+
}
|
|
14280
|
+
};
|
|
14281
|
+
for (const token of tokens) {
|
|
14282
|
+
if (token.type === "table") {
|
|
14283
|
+
flush();
|
|
14284
|
+
out.push(
|
|
14285
|
+
/* @__PURE__ */ jsx(
|
|
14286
|
+
MarkdownTable,
|
|
14287
|
+
{
|
|
14288
|
+
token,
|
|
14289
|
+
theme,
|
|
14290
|
+
highlight
|
|
14291
|
+
},
|
|
14292
|
+
out.length
|
|
14293
|
+
)
|
|
14294
|
+
);
|
|
14295
|
+
} else {
|
|
14296
|
+
buffer += formatToken(token, theme, highlight);
|
|
14297
|
+
}
|
|
14298
|
+
}
|
|
14299
|
+
flush();
|
|
14300
|
+
return out;
|
|
14301
|
+
}, [children, dim, highlight, theme]);
|
|
14302
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: elements });
|
|
14303
|
+
}
|
|
14304
|
+
|
|
13212
14305
|
// src/react-ink/utils/tool-display.ts
|
|
13213
14306
|
import { homedir as homedir2 } from "node:os";
|
|
14307
|
+
|
|
14308
|
+
// src/react-ink/diff/structured.ts
|
|
14309
|
+
import { structuredPatch } from "diff";
|
|
14310
|
+
|
|
14311
|
+
// src/react-ink/diff/word-diff.ts
|
|
14312
|
+
import { diffWordsWithSpace } from "diff";
|
|
14313
|
+
var CHANGE_THRESHOLD = 0.4;
|
|
14314
|
+
function wordDiffLine(oldLine, newLine, side) {
|
|
14315
|
+
const lineText = side === "removed" ? oldLine : newLine;
|
|
14316
|
+
if (oldLine.length === 0 || newLine.length === 0) {
|
|
14317
|
+
return [{ text: lineText, changed: true }];
|
|
14318
|
+
}
|
|
14319
|
+
let changes;
|
|
14320
|
+
try {
|
|
14321
|
+
changes = diffWordsWithSpace(oldLine, newLine);
|
|
14322
|
+
} catch {
|
|
14323
|
+
return [{ text: lineText, changed: true }];
|
|
14324
|
+
}
|
|
14325
|
+
let changedChars = 0;
|
|
14326
|
+
let totalChars = 0;
|
|
14327
|
+
for (const change of changes) {
|
|
14328
|
+
totalChars += change.value.length;
|
|
14329
|
+
if (change.added || change.removed) {
|
|
14330
|
+
changedChars += change.value.length;
|
|
14331
|
+
}
|
|
14332
|
+
}
|
|
14333
|
+
const fraction = totalChars === 0 ? 0 : changedChars / totalChars;
|
|
14334
|
+
if (fraction > CHANGE_THRESHOLD) {
|
|
14335
|
+
return [{ text: lineText, changed: true }];
|
|
14336
|
+
}
|
|
14337
|
+
const spans = [];
|
|
14338
|
+
for (const change of changes) {
|
|
14339
|
+
const belongs = side === "removed" ? !change.added : !change.removed;
|
|
14340
|
+
if (!belongs) {
|
|
14341
|
+
continue;
|
|
14342
|
+
}
|
|
14343
|
+
spans.push({ text: change.value, changed: Boolean(change.added || change.removed) });
|
|
14344
|
+
}
|
|
14345
|
+
return spans.length > 0 ? spans : [{ text: lineText, changed: false }];
|
|
14346
|
+
}
|
|
14347
|
+
|
|
14348
|
+
// src/react-ink/diff/structured.ts
|
|
14349
|
+
var CONTEXT_LINES = 3;
|
|
14350
|
+
function buildStructuredDiff(oldStr, newStr, filePath = "") {
|
|
14351
|
+
if (oldStr === newStr) {
|
|
14352
|
+
return null;
|
|
14353
|
+
}
|
|
14354
|
+
let patch;
|
|
14355
|
+
try {
|
|
14356
|
+
patch = structuredPatch(filePath, filePath, oldStr, newStr, "", "", { context: CONTEXT_LINES });
|
|
14357
|
+
} catch {
|
|
14358
|
+
return null;
|
|
14359
|
+
}
|
|
14360
|
+
const hunks = [];
|
|
14361
|
+
let addedCount = 0;
|
|
14362
|
+
let removedCount = 0;
|
|
14363
|
+
for (const hunk of patch.hunks) {
|
|
14364
|
+
const lines = classifyHunkLines(hunk);
|
|
14365
|
+
for (const line4 of lines) {
|
|
14366
|
+
if (line4.kind === "added") addedCount += 1;
|
|
14367
|
+
else if (line4.kind === "removed") removedCount += 1;
|
|
14368
|
+
}
|
|
14369
|
+
if (lines.length > 0) {
|
|
14370
|
+
hunks.push({ oldStart: hunk.oldStart, newStart: hunk.newStart, lines });
|
|
14371
|
+
}
|
|
14372
|
+
}
|
|
14373
|
+
if (hunks.length === 0) {
|
|
14374
|
+
return null;
|
|
14375
|
+
}
|
|
14376
|
+
return { hunks, addedCount, removedCount };
|
|
14377
|
+
}
|
|
14378
|
+
function classifyHunkLines(hunk) {
|
|
14379
|
+
const out = [];
|
|
14380
|
+
let oldNum = hunk.oldStart;
|
|
14381
|
+
let newNum = hunk.newStart;
|
|
14382
|
+
const rawLines = hunk.lines.filter((line4) => !line4.startsWith("\\"));
|
|
14383
|
+
let removedRun = [];
|
|
14384
|
+
let removedRunStart = -1;
|
|
14385
|
+
const flushPairing = (addedRun2) => {
|
|
14386
|
+
const pairs = Math.min(removedRun.length, addedRun2.length);
|
|
14387
|
+
for (let i = 0; i < pairs; i += 1) {
|
|
14388
|
+
const removed = removedRun[i];
|
|
14389
|
+
const added = addedRun2[i];
|
|
14390
|
+
removed.spans = wordDiffLine(removed.text, added.text, "removed");
|
|
14391
|
+
added.spans = wordDiffLine(removed.text, added.text, "added");
|
|
14392
|
+
}
|
|
14393
|
+
removedRun = [];
|
|
14394
|
+
removedRunStart = -1;
|
|
14395
|
+
};
|
|
14396
|
+
let addedRun = [];
|
|
14397
|
+
for (const raw of rawLines) {
|
|
14398
|
+
const marker = raw[0];
|
|
14399
|
+
const text = raw.slice(1);
|
|
14400
|
+
if (marker === "-") {
|
|
14401
|
+
if (addedRun.length > 0) {
|
|
14402
|
+
addedRun = [];
|
|
14403
|
+
}
|
|
14404
|
+
const line4 = { kind: "removed", oldLine: oldNum, text };
|
|
14405
|
+
out.push(line4);
|
|
14406
|
+
if (removedRunStart === -1) removedRunStart = out.length - 1;
|
|
14407
|
+
removedRun.push(line4);
|
|
14408
|
+
oldNum += 1;
|
|
14409
|
+
} else if (marker === "+") {
|
|
14410
|
+
const line4 = { kind: "added", newLine: newNum, text };
|
|
14411
|
+
out.push(line4);
|
|
14412
|
+
addedRun.push(line4);
|
|
14413
|
+
newNum += 1;
|
|
14414
|
+
} else {
|
|
14415
|
+
if (removedRun.length > 0 && addedRun.length > 0) {
|
|
14416
|
+
flushPairing(addedRun);
|
|
14417
|
+
}
|
|
14418
|
+
removedRun = [];
|
|
14419
|
+
removedRunStart = -1;
|
|
14420
|
+
addedRun = [];
|
|
14421
|
+
out.push({ kind: "context", oldLine: oldNum, newLine: newNum, text });
|
|
14422
|
+
oldNum += 1;
|
|
14423
|
+
newNum += 1;
|
|
14424
|
+
}
|
|
14425
|
+
}
|
|
14426
|
+
if (removedRun.length > 0 && addedRun.length > 0) {
|
|
14427
|
+
flushPairing(addedRun);
|
|
14428
|
+
}
|
|
14429
|
+
return out;
|
|
14430
|
+
}
|
|
14431
|
+
|
|
14432
|
+
// src/react-ink/utils/tool-display.ts
|
|
13214
14433
|
function asRecord2(value) {
|
|
13215
14434
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
13216
14435
|
}
|
|
@@ -13293,6 +14512,12 @@ function clipBody(value, maxLines = 8, maxChars = 1400) {
|
|
|
13293
14512
|
}
|
|
13294
14513
|
return previewMultiline(value, { maxLines, maxChars });
|
|
13295
14514
|
}
|
|
14515
|
+
function highlightedBody(body, filePath, theme) {
|
|
14516
|
+
if (!body || !theme || !filePath || languageFromPath(filePath) === null) {
|
|
14517
|
+
return { body };
|
|
14518
|
+
}
|
|
14519
|
+
return { body: highlightByPath(body, filePath, theme), preformatted: true };
|
|
14520
|
+
}
|
|
13296
14521
|
function extractDetails(value) {
|
|
13297
14522
|
return asRecord2(asRecord2(value)?.details);
|
|
13298
14523
|
}
|
|
@@ -13359,7 +14584,7 @@ function fallbackBody(output, fallbackOutputText, showImages = false) {
|
|
|
13359
14584
|
return clipBody(fallbackOutputText);
|
|
13360
14585
|
}
|
|
13361
14586
|
function describeToolSource(source) {
|
|
13362
|
-
const { args, fallbackArgsText, fallbackOutputText, output, showImages = false, toolName } = source;
|
|
14587
|
+
const { args, fallbackArgsText, fallbackOutputText, output, showImages = false, theme, toolName } = source;
|
|
13363
14588
|
const argsRecord = asRecord2(args);
|
|
13364
14589
|
const details = extractDetails(output);
|
|
13365
14590
|
const outputText = toolText(output, showImages);
|
|
@@ -13377,10 +14602,12 @@ function describeToolSource(source) {
|
|
|
13377
14602
|
summary += `:${start}${end ? `-${end}` : ""}`;
|
|
13378
14603
|
}
|
|
13379
14604
|
const responseSummary = containsImage(output) ? firstMeaningfulLine(outputText) ?? "Read image" : /unchanged/i.test(outputText) ? "Unchanged since last read" : countMeaningfulLines(outputText) > 0 ? `Read ${countMeaningfulLines(outputText)} ${countMeaningfulLines(outputText) === 1 ? "line" : "lines"}` : "Read file";
|
|
14605
|
+
const readBody = hasResult && !containsImage(output) ? highlightedBody(clipBody(outputText, 10, 1800), rawPath, theme) : { body: hasResult ? clipBody(outputText, 10, 1800) : void 0 };
|
|
13380
14606
|
return {
|
|
13381
14607
|
title,
|
|
13382
14608
|
summary: hasResult ? responseSummary : summary,
|
|
13383
|
-
body:
|
|
14609
|
+
body: readBody.body,
|
|
14610
|
+
preformatted: readBody.preformatted,
|
|
13384
14611
|
emptyText: "Reading file..."
|
|
13385
14612
|
};
|
|
13386
14613
|
}
|
|
@@ -13388,10 +14615,14 @@ function describeToolSource(source) {
|
|
|
13388
14615
|
const rawPath = asString(argsRecord?.file_path) ?? asString(argsRecord?.path) ?? "";
|
|
13389
14616
|
const content = asString(argsRecord?.content);
|
|
13390
14617
|
const responseSummary = firstMeaningfulLine(outputText) ?? "Wrote file";
|
|
14618
|
+
const writeDiff = !hasResult && content !== void 0 && content.length > 0 ? buildStructuredDiff("", content, rawPath) ?? void 0 : void 0;
|
|
14619
|
+
const writeBody = hasResult ? { body: clipBody(outputText, 8, 1500) } : highlightedBody(clipBody(content, 8, 1500), rawPath, theme);
|
|
13391
14620
|
return {
|
|
13392
14621
|
title,
|
|
13393
14622
|
summary: hasResult ? responseSummary : rawPath ? shortenPath2(rawPath) : void 0,
|
|
13394
|
-
body:
|
|
14623
|
+
body: writeDiff ? void 0 : writeBody.body,
|
|
14624
|
+
preformatted: writeDiff ? void 0 : writeBody.preformatted,
|
|
14625
|
+
diff: writeDiff,
|
|
13395
14626
|
emptyText: "Preparing file write..."
|
|
13396
14627
|
};
|
|
13397
14628
|
}
|
|
@@ -13408,10 +14639,15 @@ function describeToolSource(source) {
|
|
|
13408
14639
|
400
|
|
13409
14640
|
) : void 0;
|
|
13410
14641
|
const responseSummary = firstMeaningfulLine(outputText) ?? "Applied edit";
|
|
14642
|
+
const editDiff = oldText !== void 0 && newText !== void 0 ? buildStructuredDiff(oldText, newText, rawPath) ?? void 0 : void 0;
|
|
14643
|
+
const editBody = hasResult ? highlightedBody(clipBody(outputText, 8, 1500), rawPath, theme) : { body: replacementPreview };
|
|
14644
|
+
const editChangeSummary = editDiff ? `+${editDiff.addedCount} -${editDiff.removedCount}` : void 0;
|
|
13411
14645
|
return {
|
|
13412
14646
|
title,
|
|
13413
|
-
summary: hasResult ? responseSummary : rawPath ? shortenPath2(rawPath) : void 0,
|
|
13414
|
-
body:
|
|
14647
|
+
summary: hasResult ? editChangeSummary ?? responseSummary : editChangeSummary ?? (rawPath ? shortenPath2(rawPath) : void 0),
|
|
14648
|
+
body: editDiff ? void 0 : editBody.body,
|
|
14649
|
+
preformatted: editDiff ? void 0 : editBody.preformatted,
|
|
14650
|
+
diff: editDiff,
|
|
13415
14651
|
emptyText: "Applying edit..."
|
|
13416
14652
|
};
|
|
13417
14653
|
}
|
|
@@ -13508,7 +14744,7 @@ function describeToolCall(toolCall) {
|
|
|
13508
14744
|
args: toolCall.arguments
|
|
13509
14745
|
});
|
|
13510
14746
|
}
|
|
13511
|
-
function describeToolResult(message, showImages, args) {
|
|
14747
|
+
function describeToolResult(message, showImages, args, theme) {
|
|
13512
14748
|
return describeToolSource({
|
|
13513
14749
|
args,
|
|
13514
14750
|
toolName: message.toolName,
|
|
@@ -13516,12 +14752,13 @@ function describeToolResult(message, showImages, args) {
|
|
|
13516
14752
|
content: message.content,
|
|
13517
14753
|
details: message.details
|
|
13518
14754
|
},
|
|
13519
|
-
showImages
|
|
14755
|
+
showImages,
|
|
14756
|
+
theme
|
|
13520
14757
|
});
|
|
13521
14758
|
}
|
|
13522
14759
|
|
|
13523
14760
|
// src/react-ink/components/ToolEventBlock.tsx
|
|
13524
|
-
import
|
|
14761
|
+
import stripAnsi5 from "strip-ansi";
|
|
13525
14762
|
function statusMarker(status) {
|
|
13526
14763
|
switch (status) {
|
|
13527
14764
|
case "error":
|
|
@@ -13532,12 +14769,15 @@ function statusMarker(status) {
|
|
|
13532
14769
|
return ">";
|
|
13533
14770
|
}
|
|
13534
14771
|
}
|
|
14772
|
+
function statusColorKey(status) {
|
|
14773
|
+
return status === "error" ? "error" : "text";
|
|
14774
|
+
}
|
|
13535
14775
|
function plainToolText(text) {
|
|
13536
|
-
return
|
|
14776
|
+
return stripAnsi5(text);
|
|
13537
14777
|
}
|
|
13538
14778
|
function splitVisibleLines(text) {
|
|
13539
14779
|
return (text ?? "").split(/\r?\n/).map((line4) => line4.trimEnd()).filter((line4, index, lines) => {
|
|
13540
|
-
if (line4.length > 0) {
|
|
14780
|
+
if (stripAnsi5(line4).length > 0) {
|
|
13541
14781
|
return true;
|
|
13542
14782
|
}
|
|
13543
14783
|
return index !== 0 && index !== lines.length - 1;
|
|
@@ -13568,11 +14808,12 @@ function ToolEventBlock({
|
|
|
13568
14808
|
indent = 0,
|
|
13569
14809
|
marginBottom = 1,
|
|
13570
14810
|
maxContentLines = 10,
|
|
14811
|
+
preformatted = false,
|
|
13571
14812
|
showSummaryInline = false,
|
|
13572
14813
|
showTitle = true,
|
|
13573
14814
|
status,
|
|
13574
14815
|
summary,
|
|
13575
|
-
theme
|
|
14816
|
+
theme,
|
|
13576
14817
|
title
|
|
13577
14818
|
}) {
|
|
13578
14819
|
const normalizedSummary = summary?.trim();
|
|
@@ -13588,19 +14829,19 @@ function ToolEventBlock({
|
|
|
13588
14829
|
const { visibleLines, hiddenLineCount } = clampContentLines(combinedLines, maxContentLines);
|
|
13589
14830
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom, marginLeft: indent, children: [
|
|
13590
14831
|
showTitle ? /* @__PURE__ */ jsxs(Box, { children: [
|
|
13591
|
-
/* @__PURE__ */ jsx(Text, {
|
|
13592
|
-
/* @__PURE__ */ jsx(Text, {
|
|
13593
|
-
showSummaryInline && normalizedSummary ? /* @__PURE__ */ jsx(Text, {
|
|
14832
|
+
/* @__PURE__ */ jsx(Text, { children: theme.color(statusColorKey(status), plainToolText(`${statusMarker(status)} `)) }),
|
|
14833
|
+
/* @__PURE__ */ jsx(Text, { children: theme.color(statusColorKey(status), plainToolText(title)) }),
|
|
14834
|
+
showSummaryInline && normalizedSummary ? /* @__PURE__ */ jsx(Text, { children: theme.muted(plainToolText(` (${normalizedSummary})`)) }) : null
|
|
13594
14835
|
] }) : null,
|
|
13595
14836
|
visibleLines.map((line4, index) => /* @__PURE__ */ jsx(
|
|
13596
14837
|
Box,
|
|
13597
14838
|
{
|
|
13598
14839
|
marginLeft: line4.kind === "response" ? showTitle ? 2 : 0 : showTitle ? 4 : 2,
|
|
13599
|
-
children: /* @__PURE__ */ jsx(Text, {
|
|
14840
|
+
children: preformatted ? /* @__PURE__ */ jsx(Text, { children: line4.text }) : /* @__PURE__ */ jsx(Text, { children: theme.color("text", plainToolText(line4.text)) })
|
|
13600
14841
|
},
|
|
13601
|
-
`${line4.kind}:${index}:${line4.text}`
|
|
14842
|
+
`${line4.kind}:${index}:${stripAnsi5(line4.text)}`
|
|
13602
14843
|
)),
|
|
13603
|
-
hiddenLineCount > 0 ? /* @__PURE__ */ jsx(Box, { marginLeft: showTitle ? 4 : 2, children: /* @__PURE__ */ jsx(Text, {
|
|
14844
|
+
hiddenLineCount > 0 ? /* @__PURE__ */ jsx(Box, { marginLeft: showTitle ? 4 : 2, children: /* @__PURE__ */ jsx(Text, { children: theme.muted(plainToolText(`... ${hiddenLineCount} more line(s)`)) }) }) : null
|
|
13604
14845
|
] });
|
|
13605
14846
|
}
|
|
13606
14847
|
|
|
@@ -13623,17 +14864,100 @@ function ToolCallMessage({ theme, toolCall }) {
|
|
|
13623
14864
|
);
|
|
13624
14865
|
}
|
|
13625
14866
|
|
|
14867
|
+
// src/react-ink/diff/Diff.tsx
|
|
14868
|
+
import chalk4 from "chalk";
|
|
14869
|
+
function lineMarker(kind) {
|
|
14870
|
+
switch (kind) {
|
|
14871
|
+
case "added":
|
|
14872
|
+
return "+";
|
|
14873
|
+
case "removed":
|
|
14874
|
+
return "-";
|
|
14875
|
+
default:
|
|
14876
|
+
return " ";
|
|
14877
|
+
}
|
|
14878
|
+
}
|
|
14879
|
+
function gutterWidth(diff) {
|
|
14880
|
+
let max = 1;
|
|
14881
|
+
for (const hunk of diff.hunks) {
|
|
14882
|
+
for (const line4 of hunk.lines) {
|
|
14883
|
+
const num2 = line4.kind === "removed" ? line4.oldLine : line4.newLine;
|
|
14884
|
+
if (num2 !== void 0) {
|
|
14885
|
+
max = Math.max(max, stringWidth(String(num2)));
|
|
14886
|
+
}
|
|
14887
|
+
}
|
|
14888
|
+
}
|
|
14889
|
+
return max;
|
|
14890
|
+
}
|
|
14891
|
+
function renderLineText(line4, theme, bgRole, fgRole) {
|
|
14892
|
+
const paintSpan = (text, changed) => {
|
|
14893
|
+
const fg = theme.role(fgRole, text);
|
|
14894
|
+
return changed ? chalk4.bold(fg) : fg;
|
|
14895
|
+
};
|
|
14896
|
+
let body;
|
|
14897
|
+
if (line4.spans && line4.spans.length > 0) {
|
|
14898
|
+
body = line4.spans.map((span) => paintSpan(span.text, span.changed)).join("");
|
|
14899
|
+
} else {
|
|
14900
|
+
body = theme.role(fgRole, line4.text);
|
|
14901
|
+
}
|
|
14902
|
+
return bgRole ? theme.roleBackground(bgRole, body) : body;
|
|
14903
|
+
}
|
|
14904
|
+
function Diff({ diff, theme, indent = 0, marginBottom = 0 }) {
|
|
14905
|
+
const gutter = gutterWidth(diff);
|
|
14906
|
+
const renderLine = (line4, key) => {
|
|
14907
|
+
const num2 = line4.kind === "removed" ? line4.oldLine : line4.newLine;
|
|
14908
|
+
const gutterText = (num2 !== void 0 ? String(num2) : "").padStart(gutter);
|
|
14909
|
+
const marker = lineMarker(line4.kind);
|
|
14910
|
+
const bgRole = line4.kind === "added" ? "diffAddedBg" : line4.kind === "removed" ? "diffRemovedBg" : null;
|
|
14911
|
+
const fgRole = line4.kind === "added" ? "diffAddedText" : line4.kind === "removed" ? "diffRemovedText" : "blockquoteBar";
|
|
14912
|
+
const gutterStyled = theme.dim(`${gutterText} `);
|
|
14913
|
+
const markerStyled = line4.kind === "context" ? theme.dim(`${marker} `) : theme.role(fgRole, `${marker} `);
|
|
14914
|
+
const text = renderLineText(line4, theme, bgRole, fgRole);
|
|
14915
|
+
return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
14916
|
+
gutterStyled,
|
|
14917
|
+
markerStyled,
|
|
14918
|
+
text
|
|
14919
|
+
] }) }, key);
|
|
14920
|
+
};
|
|
14921
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: indent, marginBottom, children: diff.hunks.map((hunk, hunkIndex) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
14922
|
+
hunkIndex > 0 ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { children: theme.dim("...") }) }) : null,
|
|
14923
|
+
hunk.lines.map((line4, lineIndex) => renderLine(line4, `${hunkIndex}-${lineIndex}`))
|
|
14924
|
+
] }, `hunk-${hunkIndex}`)) });
|
|
14925
|
+
}
|
|
14926
|
+
|
|
13626
14927
|
// src/react-ink/components/messages/ToolResultBlock.tsx
|
|
13627
14928
|
function ToolResultBlock({ expanded = false, message, nested = false, showImages, theme, toolCall }) {
|
|
13628
|
-
const descriptor = describeToolResult(message, showImages, toolCall?.arguments);
|
|
14929
|
+
const descriptor = describeToolResult(message, showImages, toolCall?.arguments, theme);
|
|
14930
|
+
const indent = nested ? 4 : 2;
|
|
14931
|
+
if (descriptor.diff) {
|
|
14932
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 0, children: [
|
|
14933
|
+
/* @__PURE__ */ jsx(
|
|
14934
|
+
ToolEventBlock,
|
|
14935
|
+
{
|
|
14936
|
+
detail: void 0,
|
|
14937
|
+
emptyText: descriptor.emptyText,
|
|
14938
|
+
indent,
|
|
14939
|
+
marginBottom: 0,
|
|
14940
|
+
maxContentLines: 0,
|
|
14941
|
+
showSummaryInline: false,
|
|
14942
|
+
showTitle: !nested,
|
|
14943
|
+
status: message.isError ? "error" : "success",
|
|
14944
|
+
summary: descriptor.summary,
|
|
14945
|
+
theme,
|
|
14946
|
+
title: descriptor.title
|
|
14947
|
+
}
|
|
14948
|
+
),
|
|
14949
|
+
/* @__PURE__ */ jsx(Diff, { diff: descriptor.diff, theme, indent: indent + 2 })
|
|
14950
|
+
] });
|
|
14951
|
+
}
|
|
13629
14952
|
return /* @__PURE__ */ jsx(
|
|
13630
14953
|
ToolEventBlock,
|
|
13631
14954
|
{
|
|
13632
14955
|
detail: descriptor.body,
|
|
13633
14956
|
emptyText: descriptor.emptyText,
|
|
13634
|
-
indent
|
|
14957
|
+
indent,
|
|
13635
14958
|
marginBottom: 0,
|
|
13636
14959
|
maxContentLines: expanded ? Number.MAX_SAFE_INTEGER : 10,
|
|
14960
|
+
preformatted: descriptor.preformatted,
|
|
13637
14961
|
showSummaryInline: false,
|
|
13638
14962
|
showTitle: !nested,
|
|
13639
14963
|
status: message.isError ? "error" : "success",
|
|
@@ -13658,7 +14982,7 @@ function AssistantMessageView({
|
|
|
13658
14982
|
const matchedToolResultIds = /* @__PURE__ */ new Set();
|
|
13659
14983
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
13660
14984
|
/* @__PURE__ */ jsx(Text, { children: theme.color("accent", `Assistant ${message.provider}/${message.model} ${formatMessageTimestamp(message.timestamp)}`) }),
|
|
13661
|
-
parts.text ? /* @__PURE__ */ jsx(
|
|
14985
|
+
parts.text ? /* @__PURE__ */ jsx(Markdown, { theme, children: parts.text }) : null,
|
|
13662
14986
|
parts.thinking.map((thinking, index) => /* @__PURE__ */ jsx(Text, { children: theme.muted(`[thinking] ${thinking}`) }, index)),
|
|
13663
14987
|
parts.toolCalls.map((toolCall) => {
|
|
13664
14988
|
const toolResult = toolResultsByCallId.get(toolCall.id);
|
|
@@ -13860,20 +15184,20 @@ function MessageList({
|
|
|
13860
15184
|
}
|
|
13861
15185
|
|
|
13862
15186
|
// src/react-ink/components/StatusLine.tsx
|
|
13863
|
-
function StatusLine({ snapshot, status, theme }) {
|
|
15187
|
+
function StatusLine({ snapshot, status, theme, showBusyText = true }) {
|
|
13864
15188
|
let text = status?.text;
|
|
13865
15189
|
let tone = status?.kind ?? "info";
|
|
13866
15190
|
if (!text) {
|
|
13867
|
-
if (snapshot.isCompacting) {
|
|
15191
|
+
if (showBusyText && snapshot.isCompacting) {
|
|
13868
15192
|
text = "Compacting conversation context...";
|
|
13869
15193
|
tone = "busy";
|
|
13870
|
-
} else if (snapshot.isBashRunning) {
|
|
15194
|
+
} else if (showBusyText && snapshot.isBashRunning) {
|
|
13871
15195
|
text = "Running bash command...";
|
|
13872
15196
|
tone = "busy";
|
|
13873
|
-
} else if (snapshot.pendingToolCallCount > 0 || snapshot.pendingMessageCount > 0) {
|
|
15197
|
+
} else if (showBusyText && (snapshot.pendingToolCallCount > 0 || snapshot.pendingMessageCount > 0)) {
|
|
13874
15198
|
text = "Agent working...";
|
|
13875
15199
|
tone = "busy";
|
|
13876
|
-
} else if (snapshot.isStreaming) {
|
|
15200
|
+
} else if (showBusyText && snapshot.isStreaming) {
|
|
13877
15201
|
text = "Agent working...";
|
|
13878
15202
|
tone = "busy";
|
|
13879
15203
|
} else if (snapshot.error) {
|