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/shell-app.js
CHANGED
|
@@ -4635,6 +4635,7 @@ function runErrorThrowable(kind, message) {
|
|
|
4635
4635
|
}
|
|
4636
4636
|
|
|
4637
4637
|
// src/capabilities/kernel/spec.ts
|
|
4638
|
+
var READ_STATE_HANDLE_KEY = "readState";
|
|
4638
4639
|
function coerceInput(raw) {
|
|
4639
4640
|
if (typeof raw === "string") {
|
|
4640
4641
|
const trimmed = raw.trim();
|
|
@@ -5088,7 +5089,7 @@ var standardBudget = {
|
|
|
5088
5089
|
[${omitted} bytes elided to stay within the output ceiling]
|
|
5089
5090
|
`
|
|
5090
5091
|
};
|
|
5091
|
-
function makeNodeContext(cwd, signal, budget) {
|
|
5092
|
+
function makeNodeContext(cwd, signal, budget, framework) {
|
|
5092
5093
|
if (typeof cwd !== "string" || cwd.length === 0) {
|
|
5093
5094
|
throw new Error("makeNodeContext requires a non-empty working directory.");
|
|
5094
5095
|
}
|
|
@@ -5097,10 +5098,60 @@ function makeNodeContext(cwd, signal, budget) {
|
|
|
5097
5098
|
fs: nodeFs,
|
|
5098
5099
|
shell: nodeShell,
|
|
5099
5100
|
signal: signal ?? neverAborts(),
|
|
5100
|
-
budget: budget ?? standardBudget
|
|
5101
|
+
budget: budget ?? standardBudget,
|
|
5102
|
+
...framework ? { framework } : {}
|
|
5101
5103
|
};
|
|
5102
5104
|
}
|
|
5103
5105
|
|
|
5106
|
+
// src/capabilities/files/read-state-gate.ts
|
|
5107
|
+
var READ_BEFORE_EDIT_MESSAGE = "File has not been read yet. Read it first before writing to it.";
|
|
5108
|
+
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.";
|
|
5109
|
+
function getReadStateHandle(ctx) {
|
|
5110
|
+
const bag = ctx.framework;
|
|
5111
|
+
if (!bag || typeof bag !== "object") return void 0;
|
|
5112
|
+
const candidate = bag[READ_STATE_HANDLE_KEY];
|
|
5113
|
+
if (!candidate || typeof candidate !== "object") return void 0;
|
|
5114
|
+
const handle = candidate;
|
|
5115
|
+
if (typeof handle.get !== "function" || typeof handle.set !== "function" || typeof handle.has !== "function") {
|
|
5116
|
+
return void 0;
|
|
5117
|
+
}
|
|
5118
|
+
return handle;
|
|
5119
|
+
}
|
|
5120
|
+
async function recordReadState(ctx, absPath, handle) {
|
|
5121
|
+
if (!handle) return;
|
|
5122
|
+
try {
|
|
5123
|
+
const info = await ctx.fs.stat(absPath);
|
|
5124
|
+
const record = {
|
|
5125
|
+
mtimeMs: Math.floor(info.modifiedMs),
|
|
5126
|
+
size: info.size,
|
|
5127
|
+
readAt: Date.now()
|
|
5128
|
+
};
|
|
5129
|
+
handle.set(absPath, record);
|
|
5130
|
+
} catch {
|
|
5131
|
+
}
|
|
5132
|
+
}
|
|
5133
|
+
async function enforceReadGate(ctx, absPath, handle) {
|
|
5134
|
+
if (!handle) return { ok: true };
|
|
5135
|
+
if (!handle.has(absPath)) {
|
|
5136
|
+
return { ok: false, message: READ_BEFORE_EDIT_MESSAGE };
|
|
5137
|
+
}
|
|
5138
|
+
const recorded = handle.get(absPath);
|
|
5139
|
+
if (!recorded) {
|
|
5140
|
+
return { ok: false, message: READ_BEFORE_EDIT_MESSAGE };
|
|
5141
|
+
}
|
|
5142
|
+
let info;
|
|
5143
|
+
try {
|
|
5144
|
+
info = await ctx.fs.stat(absPath);
|
|
5145
|
+
} catch {
|
|
5146
|
+
return { ok: true };
|
|
5147
|
+
}
|
|
5148
|
+
const currentMtime = Math.floor(info.modifiedMs);
|
|
5149
|
+
if (currentMtime > recorded.mtimeMs || info.size !== recorded.size) {
|
|
5150
|
+
return { ok: false, message: MODIFIED_SINCE_READ_MESSAGE };
|
|
5151
|
+
}
|
|
5152
|
+
return { ok: true };
|
|
5153
|
+
}
|
|
5154
|
+
|
|
5104
5155
|
// src/capabilities/files/read.ts
|
|
5105
5156
|
var GUTTER_WIDTH = 6;
|
|
5106
5157
|
var DESCRIPTION = [
|
|
@@ -5203,6 +5254,7 @@ var readTool = defineTool({
|
|
|
5203
5254
|
const detail = err instanceof Error ? err.message : String(err);
|
|
5204
5255
|
return failure(`Could not read ${path2}: ${detail}`);
|
|
5205
5256
|
}
|
|
5257
|
+
await recordReadState(ctx, path2, getReadStateHandle(ctx));
|
|
5206
5258
|
const allLines = toLines(text);
|
|
5207
5259
|
const totalLines = allLines.length;
|
|
5208
5260
|
if (totalLines === 0) {
|
|
@@ -5310,11 +5362,19 @@ var writeTool = defineTool({
|
|
|
5310
5362
|
async run(input, ctx) {
|
|
5311
5363
|
const path2 = readPath(input?.path);
|
|
5312
5364
|
const content = readContent(input?.content);
|
|
5365
|
+
const handle = getReadStateHandle(ctx);
|
|
5366
|
+
if (handle && await ctx.fs.exists(path2)) {
|
|
5367
|
+
const gate = await enforceReadGate(ctx, path2, handle);
|
|
5368
|
+
if (!gate.ok) {
|
|
5369
|
+
return asText(gate.message, true);
|
|
5370
|
+
}
|
|
5371
|
+
}
|
|
5313
5372
|
const folder = parentDir(path2);
|
|
5314
5373
|
if (folder.length > 0) {
|
|
5315
5374
|
await ctx.fs.mkdir(folder, { recursive: true });
|
|
5316
5375
|
}
|
|
5317
5376
|
await ctx.fs.writeFile(path2, content, "utf8");
|
|
5377
|
+
await recordReadState(ctx, path2, handle);
|
|
5318
5378
|
const bytes = Buffer.byteLength(content, "utf8");
|
|
5319
5379
|
const unit = bytes === 1 ? "byte" : "bytes";
|
|
5320
5380
|
return asText(`Saved ${bytes} ${unit} to ${path2}.`);
|
|
@@ -5604,6 +5664,11 @@ async function runEdit(input, ctx) {
|
|
|
5604
5664
|
if (!info.isFile) {
|
|
5605
5665
|
return failure2(`${path2} is not a regular file, so it cannot be edited.`);
|
|
5606
5666
|
}
|
|
5667
|
+
const handle = getReadStateHandle(ctx);
|
|
5668
|
+
const gate = await enforceReadGate(ctx, path2, handle);
|
|
5669
|
+
if (!gate.ok) {
|
|
5670
|
+
return failure2(gate.message);
|
|
5671
|
+
}
|
|
5607
5672
|
const before = await ctx.fs.readFile(path2, "utf8");
|
|
5608
5673
|
const literalHits = countLiteral(before, oldText);
|
|
5609
5674
|
if (literalHits > 0) {
|
|
@@ -5617,6 +5682,7 @@ async function runEdit(input, ctx) {
|
|
|
5617
5682
|
return failure2(`The replacement left ${path2} unchanged.`);
|
|
5618
5683
|
}
|
|
5619
5684
|
await ctx.fs.writeFile(path2, after2, "utf8");
|
|
5685
|
+
await recordReadState(ctx, path2, handle);
|
|
5620
5686
|
return success(path2, before, after2, replaceAll ? literalHits : 1);
|
|
5621
5687
|
}
|
|
5622
5688
|
const spans = findFuzzySpans(before, oldText);
|
|
@@ -5640,6 +5706,7 @@ async function runEdit(input, ctx) {
|
|
|
5640
5706
|
return failure2(`The fuzzy replacement left ${path2} unchanged.`);
|
|
5641
5707
|
}
|
|
5642
5708
|
await ctx.fs.writeFile(path2, after, "utf8");
|
|
5709
|
+
await recordReadState(ctx, path2, handle);
|
|
5643
5710
|
return success(path2, before, after, targets.length);
|
|
5644
5711
|
}
|
|
5645
5712
|
var editTool = defineTool({
|
|
@@ -8469,6 +8536,34 @@ var useInput = ink.useInput;
|
|
|
8469
8536
|
// src/react-ink/theme-adapter.ts
|
|
8470
8537
|
import chalk from "chalk";
|
|
8471
8538
|
import stripAnsi from "strip-ansi";
|
|
8539
|
+
var DEFAULT_ROLE_KEYS = {
|
|
8540
|
+
codeInline: "codeInline",
|
|
8541
|
+
heading: "heading",
|
|
8542
|
+
blockquoteBar: "blockquoteBar",
|
|
8543
|
+
diffAddedBg: "diffAddedBg",
|
|
8544
|
+
diffRemovedBg: "diffRemovedBg",
|
|
8545
|
+
diffAddedText: "diffAddedText",
|
|
8546
|
+
diffRemovedText: "diffRemovedText",
|
|
8547
|
+
synKeyword: "synKeyword",
|
|
8548
|
+
synString: "synString",
|
|
8549
|
+
synNumber: "synNumber",
|
|
8550
|
+
synComment: "synComment",
|
|
8551
|
+
synType: "synType"
|
|
8552
|
+
};
|
|
8553
|
+
var ROLE_FALLBACK_KEYS = {
|
|
8554
|
+
codeInline: "accent",
|
|
8555
|
+
heading: "accent",
|
|
8556
|
+
blockquoteBar: "muted",
|
|
8557
|
+
diffAddedBg: "success",
|
|
8558
|
+
diffRemovedBg: "error",
|
|
8559
|
+
diffAddedText: "success",
|
|
8560
|
+
diffRemovedText: "error",
|
|
8561
|
+
synKeyword: "accent",
|
|
8562
|
+
synString: "success",
|
|
8563
|
+
synNumber: "warning",
|
|
8564
|
+
synComment: "muted",
|
|
8565
|
+
synType: "info"
|
|
8566
|
+
};
|
|
8472
8567
|
function applyForeground(color, text) {
|
|
8473
8568
|
if (!color) return text;
|
|
8474
8569
|
try {
|
|
@@ -8495,15 +8590,27 @@ function applyBackground(background, foreground, text) {
|
|
|
8495
8590
|
return applyForeground(foreground, text);
|
|
8496
8591
|
}
|
|
8497
8592
|
}
|
|
8498
|
-
function createThemeAdapter(themeName, colors) {
|
|
8593
|
+
function createThemeAdapter(themeName, colors, roleOverrides) {
|
|
8499
8594
|
const fallback = colors.text ?? "#e5e5e7";
|
|
8595
|
+
const roles = { ...DEFAULT_ROLE_KEYS, ...roleOverrides };
|
|
8596
|
+
const resolveRoleColor = (role) => resolveColorToken(
|
|
8597
|
+
colors[roles[role]],
|
|
8598
|
+
resolveColorToken(colors[ROLE_FALLBACK_KEYS[role]], fallback)
|
|
8599
|
+
);
|
|
8500
8600
|
return {
|
|
8501
8601
|
name: themeName,
|
|
8502
8602
|
colors,
|
|
8603
|
+
roles,
|
|
8503
8604
|
color: (key, text) => applyForeground(resolveColorToken(colors[key], fallback), text),
|
|
8504
8605
|
background: (key, text, textKey = "text") => applyBackground(resolveColorToken(colors[key]), resolveColorToken(colors[textKey], fallback), ` ${stripAnsi(text)} `),
|
|
8505
8606
|
dim: (text) => applyForeground(resolveColorToken(colors.dim, "#666666"), text),
|
|
8506
|
-
muted: (text) => applyForeground(resolveColorToken(colors.muted, "#808080"), text)
|
|
8607
|
+
muted: (text) => applyForeground(resolveColorToken(colors.muted, "#808080"), text),
|
|
8608
|
+
role: (role, text) => applyForeground(resolveRoleColor(role), text),
|
|
8609
|
+
roleBackground: (role, text, foregroundRole) => applyBackground(
|
|
8610
|
+
resolveRoleColor(role),
|
|
8611
|
+
foregroundRole ? resolveRoleColor(foregroundRole) : void 0,
|
|
8612
|
+
text
|
|
8613
|
+
)
|
|
8507
8614
|
};
|
|
8508
8615
|
}
|
|
8509
8616
|
|
|
@@ -8888,8 +8995,1120 @@ function parseSkillInvocation(content) {
|
|
|
8888
8995
|
};
|
|
8889
8996
|
}
|
|
8890
8997
|
|
|
8998
|
+
// src/react-ink/markdown/format-token.ts
|
|
8999
|
+
import chalk2 from "chalk";
|
|
9000
|
+
import { marked } from "marked";
|
|
9001
|
+
import stripAnsi3 from "strip-ansi";
|
|
9002
|
+
|
|
9003
|
+
// src/ui/utils.ts
|
|
9004
|
+
import { eastAsianWidth } from "get-east-asian-width";
|
|
9005
|
+
var segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
9006
|
+
var TextWidthCalculator = class {
|
|
9007
|
+
getWidth(text) {
|
|
9008
|
+
return visibleWidth(text);
|
|
9009
|
+
}
|
|
9010
|
+
clearCache() {
|
|
9011
|
+
widthCache.clear();
|
|
9012
|
+
}
|
|
9013
|
+
};
|
|
9014
|
+
var textWidthCalculator = new TextWidthCalculator();
|
|
9015
|
+
function looksLikeEmojiCandidate(segment) {
|
|
9016
|
+
const cp = segment.codePointAt(0);
|
|
9017
|
+
return cp >= 126976 && cp <= 130047 || // pictographs and emoji proper
|
|
9018
|
+
cp >= 8960 && cp <= 9215 || // miscellaneous technical glyphs
|
|
9019
|
+
cp >= 9728 && cp <= 10175 || // assorted symbols and dingbats
|
|
9020
|
+
cp >= 11088 && cp <= 11093 || // a few star/circle characters
|
|
9021
|
+
segment.includes("\uFE0F") || // carries VS16, the emoji-presentation selector
|
|
9022
|
+
segment.length > 2;
|
|
9023
|
+
}
|
|
9024
|
+
function createUnicodeRegex(vPattern, uFallback) {
|
|
9025
|
+
try {
|
|
9026
|
+
return new RegExp(vPattern, "v");
|
|
9027
|
+
} catch {
|
|
9028
|
+
return new RegExp(uFallback, "u");
|
|
9029
|
+
}
|
|
9030
|
+
}
|
|
9031
|
+
var zeroWidthRegex = createUnicodeRegex(
|
|
9032
|
+
"^(?:\\p{Default_Ignorable_Code_Point}|\\p{Control}|\\p{Mark}|\\p{Surrogate})+$",
|
|
9033
|
+
"^(?:\\p{Default_Ignorable_Code_Point}|\\p{Control}|\\p{Mark}|\\p{Surrogate})+$"
|
|
9034
|
+
);
|
|
9035
|
+
var leadingNonPrintingRegex = createUnicodeRegex(
|
|
9036
|
+
"^[\\p{Default_Ignorable_Code_Point}\\p{Control}\\p{Format}\\p{Mark}\\p{Surrogate}]+",
|
|
9037
|
+
"^[\\p{Default_Ignorable_Code_Point}\\p{Control}\\p{Format}\\p{Mark}\\p{Surrogate}]+"
|
|
9038
|
+
);
|
|
9039
|
+
var rgiEmojiRegex = createUnicodeRegex("^\\p{RGI_Emoji}$", "^\\p{Extended_Pictographic}$");
|
|
9040
|
+
var AnsiStripper = {
|
|
9041
|
+
strip(text) {
|
|
9042
|
+
if (!text.includes("\x1B")) {
|
|
9043
|
+
return text;
|
|
9044
|
+
}
|
|
9045
|
+
let cleaned = text;
|
|
9046
|
+
cleaned = cleaned.replace(/\x1b\[[0-9;]*[mGKHJ]/g, "");
|
|
9047
|
+
cleaned = cleaned.replace(/\x1b\]8;;[^\x07]*\x07/g, "");
|
|
9048
|
+
cleaned = cleaned.replace(/\x1b_[^\x07\x1b]*(?:\x07|\x1b\\)/g, "");
|
|
9049
|
+
return cleaned;
|
|
9050
|
+
}
|
|
9051
|
+
};
|
|
9052
|
+
var WIDTH_CACHE_SIZE = 512;
|
|
9053
|
+
var widthCache = /* @__PURE__ */ new Map();
|
|
9054
|
+
function measureClusterWidth(segment) {
|
|
9055
|
+
if (zeroWidthRegex.test(segment)) {
|
|
9056
|
+
return 0;
|
|
9057
|
+
}
|
|
9058
|
+
if (looksLikeEmojiCandidate(segment) && rgiEmojiRegex.test(segment)) {
|
|
9059
|
+
return 2;
|
|
9060
|
+
}
|
|
9061
|
+
const base = segment.replace(leadingNonPrintingRegex, "");
|
|
9062
|
+
const cp = base.codePointAt(0);
|
|
9063
|
+
if (cp === void 0) {
|
|
9064
|
+
return 0;
|
|
9065
|
+
}
|
|
9066
|
+
let width = eastAsianWidth(cp);
|
|
9067
|
+
if (segment.length > 1) {
|
|
9068
|
+
for (const char of segment.slice(1)) {
|
|
9069
|
+
const c = char.codePointAt(0);
|
|
9070
|
+
if (c >= 65280 && c <= 65519) {
|
|
9071
|
+
width += eastAsianWidth(c);
|
|
9072
|
+
}
|
|
9073
|
+
}
|
|
9074
|
+
}
|
|
9075
|
+
return width;
|
|
9076
|
+
}
|
|
9077
|
+
function visibleWidth(str2) {
|
|
9078
|
+
if (str2.length === 0) {
|
|
9079
|
+
return 0;
|
|
9080
|
+
}
|
|
9081
|
+
let isPureAscii = true;
|
|
9082
|
+
for (let i = 0; i < str2.length; i++) {
|
|
9083
|
+
const code = str2.charCodeAt(i);
|
|
9084
|
+
if (code < 32 || code > 126) {
|
|
9085
|
+
isPureAscii = false;
|
|
9086
|
+
break;
|
|
9087
|
+
}
|
|
9088
|
+
}
|
|
9089
|
+
if (isPureAscii) {
|
|
9090
|
+
return str2.length;
|
|
9091
|
+
}
|
|
9092
|
+
const cached = widthCache.get(str2);
|
|
9093
|
+
if (cached !== void 0) {
|
|
9094
|
+
return cached;
|
|
9095
|
+
}
|
|
9096
|
+
let clean = str2;
|
|
9097
|
+
if (str2.includes(" ")) {
|
|
9098
|
+
clean = clean.replace(/\t/g, " ");
|
|
9099
|
+
}
|
|
9100
|
+
clean = AnsiStripper.strip(clean);
|
|
9101
|
+
let width = 0;
|
|
9102
|
+
for (const { segment } of segmenter.segment(clean)) {
|
|
9103
|
+
width += measureClusterWidth(segment);
|
|
9104
|
+
}
|
|
9105
|
+
if (widthCache.size >= WIDTH_CACHE_SIZE) {
|
|
9106
|
+
const firstKey = widthCache.keys().next().value;
|
|
9107
|
+
if (firstKey !== void 0) {
|
|
9108
|
+
widthCache.delete(firstKey);
|
|
9109
|
+
}
|
|
9110
|
+
}
|
|
9111
|
+
widthCache.set(str2, width);
|
|
9112
|
+
return width;
|
|
9113
|
+
}
|
|
9114
|
+
function extractAnsiCode(str2, pos) {
|
|
9115
|
+
if (pos >= str2.length || str2[pos] !== "\x1B") return null;
|
|
9116
|
+
const next = str2[pos + 1];
|
|
9117
|
+
if (next === "[") {
|
|
9118
|
+
let j = pos + 2;
|
|
9119
|
+
while (j < str2.length && !/[mGKHJ]/.test(str2[j])) j++;
|
|
9120
|
+
if (j < str2.length) return { code: str2.substring(pos, j + 1), length: j + 1 - pos };
|
|
9121
|
+
return null;
|
|
9122
|
+
}
|
|
9123
|
+
if (next === "]") {
|
|
9124
|
+
let j = pos + 2;
|
|
9125
|
+
while (j < str2.length) {
|
|
9126
|
+
if (str2[j] === "\x07") return { code: str2.substring(pos, j + 1), length: j + 1 - pos };
|
|
9127
|
+
if (str2[j] === "\x1B" && str2[j + 1] === "\\") return { code: str2.substring(pos, j + 2), length: j + 2 - pos };
|
|
9128
|
+
j++;
|
|
9129
|
+
}
|
|
9130
|
+
return null;
|
|
9131
|
+
}
|
|
9132
|
+
if (next === "_") {
|
|
9133
|
+
let j = pos + 2;
|
|
9134
|
+
while (j < str2.length) {
|
|
9135
|
+
if (str2[j] === "\x07") return { code: str2.substring(pos, j + 1), length: j + 1 - pos };
|
|
9136
|
+
if (str2[j] === "\x1B" && str2[j + 1] === "\\") return { code: str2.substring(pos, j + 2), length: j + 2 - pos };
|
|
9137
|
+
j++;
|
|
9138
|
+
}
|
|
9139
|
+
return null;
|
|
9140
|
+
}
|
|
9141
|
+
return null;
|
|
9142
|
+
}
|
|
9143
|
+
var AnsiStateTracker = class {
|
|
9144
|
+
// Each attribute is kept on its own flag, which lets us clear them one at a time.
|
|
9145
|
+
_bold = false;
|
|
9146
|
+
_dim = false;
|
|
9147
|
+
italic = false;
|
|
9148
|
+
underline = false;
|
|
9149
|
+
blink = false;
|
|
9150
|
+
inverse = false;
|
|
9151
|
+
hidden = false;
|
|
9152
|
+
strikethrough = false;
|
|
9153
|
+
_colors = { fg: null, bg: null };
|
|
9154
|
+
process(ansiCode) {
|
|
9155
|
+
if (!ansiCode.endsWith("m")) {
|
|
9156
|
+
return;
|
|
9157
|
+
}
|
|
9158
|
+
const match = ansiCode.match(/\x1b\[([\d;]*)m/);
|
|
9159
|
+
if (!match) return;
|
|
9160
|
+
const params = match[1];
|
|
9161
|
+
if (params === "" || params === "0") {
|
|
9162
|
+
this.reset();
|
|
9163
|
+
return;
|
|
9164
|
+
}
|
|
9165
|
+
const parts = params.split(";");
|
|
9166
|
+
let i = 0;
|
|
9167
|
+
while (i < parts.length) {
|
|
9168
|
+
const code = Number.parseInt(parts[i] ?? "", 10);
|
|
9169
|
+
if (Number.isNaN(code)) {
|
|
9170
|
+
i++;
|
|
9171
|
+
continue;
|
|
9172
|
+
}
|
|
9173
|
+
const consumed = this.tryConsumeColorCode(parts, i, code);
|
|
9174
|
+
if (consumed > 0) {
|
|
9175
|
+
i += consumed;
|
|
9176
|
+
continue;
|
|
9177
|
+
}
|
|
9178
|
+
this.applyStandardCode(code);
|
|
9179
|
+
i++;
|
|
9180
|
+
}
|
|
9181
|
+
}
|
|
9182
|
+
tryConsumeColorCode(parts, index, code) {
|
|
9183
|
+
if (code !== 38 && code !== 48) {
|
|
9184
|
+
return 0;
|
|
9185
|
+
}
|
|
9186
|
+
if (parts[index + 1] === "5" && parts[index + 2] !== void 0) {
|
|
9187
|
+
const colorCode = `${parts[index]};${parts[index + 1]};${parts[index + 2]}`;
|
|
9188
|
+
if (code === 38) {
|
|
9189
|
+
this._colors.fg = colorCode;
|
|
9190
|
+
} else {
|
|
9191
|
+
this._colors.bg = colorCode;
|
|
9192
|
+
}
|
|
9193
|
+
return 3;
|
|
9194
|
+
}
|
|
9195
|
+
if (parts[index + 1] === "2" && parts[index + 4] !== void 0) {
|
|
9196
|
+
const colorCode = `${parts[index]};${parts[index + 1]};${parts[index + 2]};${parts[index + 3]};${parts[index + 4]}`;
|
|
9197
|
+
if (code === 38) {
|
|
9198
|
+
this._colors.fg = colorCode;
|
|
9199
|
+
} else {
|
|
9200
|
+
this._colors.bg = colorCode;
|
|
9201
|
+
}
|
|
9202
|
+
return 5;
|
|
9203
|
+
}
|
|
9204
|
+
return 0;
|
|
9205
|
+
}
|
|
9206
|
+
applyStandardCode(code) {
|
|
9207
|
+
switch (code) {
|
|
9208
|
+
case 0:
|
|
9209
|
+
this.reset();
|
|
9210
|
+
return;
|
|
9211
|
+
case 1:
|
|
9212
|
+
this._bold = true;
|
|
9213
|
+
return;
|
|
9214
|
+
case 2:
|
|
9215
|
+
this._dim = true;
|
|
9216
|
+
return;
|
|
9217
|
+
case 3:
|
|
9218
|
+
this.italic = true;
|
|
9219
|
+
return;
|
|
9220
|
+
case 4:
|
|
9221
|
+
this.underline = true;
|
|
9222
|
+
return;
|
|
9223
|
+
case 5:
|
|
9224
|
+
this.blink = true;
|
|
9225
|
+
return;
|
|
9226
|
+
case 7:
|
|
9227
|
+
this.inverse = true;
|
|
9228
|
+
return;
|
|
9229
|
+
case 8:
|
|
9230
|
+
this.hidden = true;
|
|
9231
|
+
return;
|
|
9232
|
+
case 9:
|
|
9233
|
+
this.strikethrough = true;
|
|
9234
|
+
return;
|
|
9235
|
+
case 21:
|
|
9236
|
+
this._bold = false;
|
|
9237
|
+
return;
|
|
9238
|
+
case 22:
|
|
9239
|
+
this._bold = false;
|
|
9240
|
+
this._dim = false;
|
|
9241
|
+
return;
|
|
9242
|
+
case 23:
|
|
9243
|
+
this.italic = false;
|
|
9244
|
+
return;
|
|
9245
|
+
case 24:
|
|
9246
|
+
this.underline = false;
|
|
9247
|
+
return;
|
|
9248
|
+
case 25:
|
|
9249
|
+
this.blink = false;
|
|
9250
|
+
return;
|
|
9251
|
+
case 27:
|
|
9252
|
+
this.inverse = false;
|
|
9253
|
+
return;
|
|
9254
|
+
case 28:
|
|
9255
|
+
this.hidden = false;
|
|
9256
|
+
return;
|
|
9257
|
+
case 29:
|
|
9258
|
+
this.strikethrough = false;
|
|
9259
|
+
return;
|
|
9260
|
+
case 39:
|
|
9261
|
+
this._colors.fg = null;
|
|
9262
|
+
return;
|
|
9263
|
+
case 49:
|
|
9264
|
+
this._colors.bg = null;
|
|
9265
|
+
return;
|
|
9266
|
+
default:
|
|
9267
|
+
if (code >= 30 && code <= 37 || code >= 90 && code <= 97) {
|
|
9268
|
+
this._colors.fg = String(code);
|
|
9269
|
+
return;
|
|
9270
|
+
}
|
|
9271
|
+
if (code >= 40 && code <= 47 || code >= 100 && code <= 107) {
|
|
9272
|
+
this._colors.bg = String(code);
|
|
9273
|
+
}
|
|
9274
|
+
}
|
|
9275
|
+
}
|
|
9276
|
+
reset() {
|
|
9277
|
+
this._bold = false;
|
|
9278
|
+
this._dim = false;
|
|
9279
|
+
this.italic = false;
|
|
9280
|
+
this.underline = false;
|
|
9281
|
+
this.blink = false;
|
|
9282
|
+
this.inverse = false;
|
|
9283
|
+
this.hidden = false;
|
|
9284
|
+
this.strikethrough = false;
|
|
9285
|
+
this._colors.fg = null;
|
|
9286
|
+
this._colors.bg = null;
|
|
9287
|
+
}
|
|
9288
|
+
/** Wipe all tracked state so the instance can be reused. */
|
|
9289
|
+
clear() {
|
|
9290
|
+
this.reset();
|
|
9291
|
+
}
|
|
9292
|
+
getActiveCodes() {
|
|
9293
|
+
const codes = [];
|
|
9294
|
+
if (this._bold) codes.push("1");
|
|
9295
|
+
if (this._dim) codes.push("2");
|
|
9296
|
+
if (this.italic) codes.push("3");
|
|
9297
|
+
if (this.underline) codes.push("4");
|
|
9298
|
+
if (this.blink) codes.push("5");
|
|
9299
|
+
if (this.inverse) codes.push("7");
|
|
9300
|
+
if (this.hidden) codes.push("8");
|
|
9301
|
+
if (this.strikethrough) codes.push("9");
|
|
9302
|
+
if (this._colors.fg) codes.push(this._colors.fg);
|
|
9303
|
+
if (this._colors.bg) codes.push(this._colors.bg);
|
|
9304
|
+
if (codes.length === 0) return "";
|
|
9305
|
+
return `\x1B[${codes.join(";")}m`;
|
|
9306
|
+
}
|
|
9307
|
+
hasActiveCodes() {
|
|
9308
|
+
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;
|
|
9309
|
+
}
|
|
9310
|
+
/**
|
|
9311
|
+
* Produce the escape code needed to switch off any attribute that would
|
|
9312
|
+
* otherwise smear into the padding at the end of a line. In practice that
|
|
9313
|
+
* is just underline. Yields an empty string when nothing needs disabling.
|
|
9314
|
+
*/
|
|
9315
|
+
getLineEndReset() {
|
|
9316
|
+
if (this.underline) {
|
|
9317
|
+
return "\x1B[24m";
|
|
9318
|
+
}
|
|
9319
|
+
return "";
|
|
9320
|
+
}
|
|
9321
|
+
};
|
|
9322
|
+
function mergeTextIntoTracker(text, tracker) {
|
|
9323
|
+
let i = 0;
|
|
9324
|
+
while (i < text.length) {
|
|
9325
|
+
const ansiResult = extractAnsiCode(text, i);
|
|
9326
|
+
if (ansiResult) {
|
|
9327
|
+
tracker.process(ansiResult.code);
|
|
9328
|
+
i += ansiResult.length;
|
|
9329
|
+
} else {
|
|
9330
|
+
i++;
|
|
9331
|
+
}
|
|
9332
|
+
}
|
|
9333
|
+
}
|
|
9334
|
+
function tokenizeTextWithAnsi(text) {
|
|
9335
|
+
const tokens = [];
|
|
9336
|
+
let current = "";
|
|
9337
|
+
let pendingAnsi = "";
|
|
9338
|
+
let inWhitespace = false;
|
|
9339
|
+
let i = 0;
|
|
9340
|
+
while (i < text.length) {
|
|
9341
|
+
const ansiResult = extractAnsiCode(text, i);
|
|
9342
|
+
if (ansiResult) {
|
|
9343
|
+
pendingAnsi += ansiResult.code;
|
|
9344
|
+
i += ansiResult.length;
|
|
9345
|
+
continue;
|
|
9346
|
+
}
|
|
9347
|
+
const char = text[i];
|
|
9348
|
+
const charIsSpace = char === " ";
|
|
9349
|
+
if (charIsSpace !== inWhitespace && current) {
|
|
9350
|
+
tokens.push(current);
|
|
9351
|
+
current = "";
|
|
9352
|
+
}
|
|
9353
|
+
if (pendingAnsi) {
|
|
9354
|
+
current += pendingAnsi;
|
|
9355
|
+
pendingAnsi = "";
|
|
9356
|
+
}
|
|
9357
|
+
inWhitespace = charIsSpace;
|
|
9358
|
+
current += char;
|
|
9359
|
+
i++;
|
|
9360
|
+
}
|
|
9361
|
+
if (pendingAnsi) {
|
|
9362
|
+
current += pendingAnsi;
|
|
9363
|
+
}
|
|
9364
|
+
if (current) {
|
|
9365
|
+
tokens.push(current);
|
|
9366
|
+
}
|
|
9367
|
+
return tokens;
|
|
9368
|
+
}
|
|
9369
|
+
var TextWrapper = class {
|
|
9370
|
+
wrap(text, width) {
|
|
9371
|
+
return wrapTextWithAnsi(text, width);
|
|
9372
|
+
}
|
|
9373
|
+
};
|
|
9374
|
+
var textWrapper = new TextWrapper();
|
|
9375
|
+
var TokenWrapEngine = {
|
|
9376
|
+
wrap(tokens, width, tracker) {
|
|
9377
|
+
const wrapped = [];
|
|
9378
|
+
let currentLine = "";
|
|
9379
|
+
let currentVisibleLength = 0;
|
|
9380
|
+
for (const token of tokens) {
|
|
9381
|
+
const tokenVisibleLength = visibleWidth(token);
|
|
9382
|
+
const isWhitespace = token.trim() === "";
|
|
9383
|
+
if (tokenVisibleLength > width && !isWhitespace) {
|
|
9384
|
+
if (currentLine) {
|
|
9385
|
+
const lineEndReset = tracker.getLineEndReset();
|
|
9386
|
+
if (lineEndReset) {
|
|
9387
|
+
currentLine += lineEndReset;
|
|
9388
|
+
}
|
|
9389
|
+
wrapped.push(currentLine);
|
|
9390
|
+
currentLine = "";
|
|
9391
|
+
currentVisibleLength = 0;
|
|
9392
|
+
}
|
|
9393
|
+
const broken = splitLongToken(token, width, tracker);
|
|
9394
|
+
wrapped.push(...broken.slice(0, -1));
|
|
9395
|
+
currentLine = broken[broken.length - 1];
|
|
9396
|
+
currentVisibleLength = visibleWidth(currentLine);
|
|
9397
|
+
continue;
|
|
9398
|
+
}
|
|
9399
|
+
const totalNeeded = currentVisibleLength + tokenVisibleLength;
|
|
9400
|
+
if (totalNeeded > width && currentVisibleLength > 0) {
|
|
9401
|
+
let lineToWrap = currentLine.trimEnd();
|
|
9402
|
+
const lineEndReset = tracker.getLineEndReset();
|
|
9403
|
+
if (lineEndReset) {
|
|
9404
|
+
lineToWrap += lineEndReset;
|
|
9405
|
+
}
|
|
9406
|
+
wrapped.push(lineToWrap);
|
|
9407
|
+
if (isWhitespace) {
|
|
9408
|
+
currentLine = tracker.getActiveCodes();
|
|
9409
|
+
currentVisibleLength = 0;
|
|
9410
|
+
} else {
|
|
9411
|
+
currentLine = tracker.getActiveCodes() + token;
|
|
9412
|
+
currentVisibleLength = tokenVisibleLength;
|
|
9413
|
+
}
|
|
9414
|
+
} else {
|
|
9415
|
+
currentLine += token;
|
|
9416
|
+
currentVisibleLength += tokenVisibleLength;
|
|
9417
|
+
}
|
|
9418
|
+
mergeTextIntoTracker(token, tracker);
|
|
9419
|
+
}
|
|
9420
|
+
return { wrapped, currentLine, currentVisibleLength };
|
|
9421
|
+
}
|
|
9422
|
+
};
|
|
9423
|
+
function wrapTextWithAnsi(text, width) {
|
|
9424
|
+
if (!text) {
|
|
9425
|
+
return [""];
|
|
9426
|
+
}
|
|
9427
|
+
const inputLines = text.split("\n");
|
|
9428
|
+
const result = [];
|
|
9429
|
+
const tracker = new AnsiStateTracker();
|
|
9430
|
+
for (const inputLine of inputLines) {
|
|
9431
|
+
const prefix = result.length > 0 ? tracker.getActiveCodes() : "";
|
|
9432
|
+
result.push(...wrapLinePreservingAnsi(prefix + inputLine, width));
|
|
9433
|
+
mergeTextIntoTracker(inputLine, tracker);
|
|
9434
|
+
}
|
|
9435
|
+
return result.length > 0 ? result : [""];
|
|
9436
|
+
}
|
|
9437
|
+
function wrapLinePreservingAnsi(line, width) {
|
|
9438
|
+
if (!line) {
|
|
9439
|
+
return [""];
|
|
9440
|
+
}
|
|
9441
|
+
const visibleLength = visibleWidth(line);
|
|
9442
|
+
if (visibleLength <= width) {
|
|
9443
|
+
return [line];
|
|
9444
|
+
}
|
|
9445
|
+
const tracker = new AnsiStateTracker();
|
|
9446
|
+
const tokens = tokenizeTextWithAnsi(line);
|
|
9447
|
+
const { wrapped, currentLine } = TokenWrapEngine.wrap(tokens, width, tracker);
|
|
9448
|
+
if (currentLine) {
|
|
9449
|
+
wrapped.push(currentLine);
|
|
9450
|
+
}
|
|
9451
|
+
return wrapped.length > 0 ? wrapped.map((segmentLine) => segmentLine.trimEnd()) : [""];
|
|
9452
|
+
}
|
|
9453
|
+
function splitLongToken(word, width, tracker) {
|
|
9454
|
+
const lines = [];
|
|
9455
|
+
let currentLine = tracker.getActiveCodes();
|
|
9456
|
+
let currentWidth = 0;
|
|
9457
|
+
let i = 0;
|
|
9458
|
+
const segments = [];
|
|
9459
|
+
while (i < word.length) {
|
|
9460
|
+
const ansiResult = extractAnsiCode(word, i);
|
|
9461
|
+
if (ansiResult) {
|
|
9462
|
+
segments.push({ type: "ansi", value: ansiResult.code });
|
|
9463
|
+
i += ansiResult.length;
|
|
9464
|
+
} else {
|
|
9465
|
+
let end = i;
|
|
9466
|
+
while (end < word.length) {
|
|
9467
|
+
const nextAnsi = extractAnsiCode(word, end);
|
|
9468
|
+
if (nextAnsi) break;
|
|
9469
|
+
end++;
|
|
9470
|
+
}
|
|
9471
|
+
const textPortion = word.slice(i, end);
|
|
9472
|
+
for (const seg of segmenter.segment(textPortion)) {
|
|
9473
|
+
segments.push({ type: "grapheme", value: seg.segment });
|
|
9474
|
+
}
|
|
9475
|
+
i = end;
|
|
9476
|
+
}
|
|
9477
|
+
}
|
|
9478
|
+
for (const seg of segments) {
|
|
9479
|
+
if (seg.type === "ansi") {
|
|
9480
|
+
currentLine += seg.value;
|
|
9481
|
+
tracker.process(seg.value);
|
|
9482
|
+
continue;
|
|
9483
|
+
}
|
|
9484
|
+
const grapheme = seg.value;
|
|
9485
|
+
if (!grapheme) continue;
|
|
9486
|
+
const clusterWidth = visibleWidth(grapheme);
|
|
9487
|
+
if (currentWidth + clusterWidth > width) {
|
|
9488
|
+
const lineEndReset = tracker.getLineEndReset();
|
|
9489
|
+
if (lineEndReset) {
|
|
9490
|
+
currentLine += lineEndReset;
|
|
9491
|
+
}
|
|
9492
|
+
lines.push(currentLine);
|
|
9493
|
+
currentLine = tracker.getActiveCodes();
|
|
9494
|
+
currentWidth = 0;
|
|
9495
|
+
}
|
|
9496
|
+
currentLine += grapheme;
|
|
9497
|
+
currentWidth += clusterWidth;
|
|
9498
|
+
}
|
|
9499
|
+
if (currentLine) {
|
|
9500
|
+
lines.push(currentLine);
|
|
9501
|
+
}
|
|
9502
|
+
return lines.length > 0 ? lines : [""];
|
|
9503
|
+
}
|
|
9504
|
+
var pooledStyleTracker = new AnsiStateTracker();
|
|
9505
|
+
|
|
9506
|
+
// src/react-ink/markdown/format-token.ts
|
|
9507
|
+
var EOL = "\n";
|
|
9508
|
+
var BLOCKQUOTE_BAR = "\u2502";
|
|
9509
|
+
var markedConfigured = false;
|
|
9510
|
+
function configureMarked() {
|
|
9511
|
+
if (markedConfigured) {
|
|
9512
|
+
return;
|
|
9513
|
+
}
|
|
9514
|
+
markedConfigured = true;
|
|
9515
|
+
marked.use({
|
|
9516
|
+
tokenizer: {
|
|
9517
|
+
del() {
|
|
9518
|
+
return void 0;
|
|
9519
|
+
}
|
|
9520
|
+
}
|
|
9521
|
+
});
|
|
9522
|
+
}
|
|
9523
|
+
var TOKEN_CACHE_MAX = 500;
|
|
9524
|
+
var tokenCache = /* @__PURE__ */ new Map();
|
|
9525
|
+
var MD_SYNTAX_RE = /[#*`|[>\-_~]|\n\n|^\d+\. |\n\d+\. /;
|
|
9526
|
+
function hasMarkdownSyntax(text) {
|
|
9527
|
+
return MD_SYNTAX_RE.test(text.length > 500 ? text.slice(0, 500) : text);
|
|
9528
|
+
}
|
|
9529
|
+
function hashContent(content) {
|
|
9530
|
+
let hash = 2166136261;
|
|
9531
|
+
for (let i = 0; i < content.length; i++) {
|
|
9532
|
+
hash ^= content.charCodeAt(i);
|
|
9533
|
+
hash = Math.imul(hash, 16777619);
|
|
9534
|
+
}
|
|
9535
|
+
return (hash >>> 0).toString(36) + ":" + content.length.toString(36);
|
|
9536
|
+
}
|
|
9537
|
+
function cachedLexer(content) {
|
|
9538
|
+
configureMarked();
|
|
9539
|
+
if (!hasMarkdownSyntax(content)) {
|
|
9540
|
+
return [
|
|
9541
|
+
{
|
|
9542
|
+
type: "paragraph",
|
|
9543
|
+
raw: content,
|
|
9544
|
+
text: content,
|
|
9545
|
+
tokens: [{ type: "text", raw: content, text: content }]
|
|
9546
|
+
}
|
|
9547
|
+
];
|
|
9548
|
+
}
|
|
9549
|
+
const key = hashContent(content);
|
|
9550
|
+
const hit = tokenCache.get(key);
|
|
9551
|
+
if (hit) {
|
|
9552
|
+
tokenCache.delete(key);
|
|
9553
|
+
tokenCache.set(key, hit);
|
|
9554
|
+
return hit;
|
|
9555
|
+
}
|
|
9556
|
+
const tokens = marked.lexer(content);
|
|
9557
|
+
if (tokenCache.size >= TOKEN_CACHE_MAX) {
|
|
9558
|
+
const first = tokenCache.keys().next().value;
|
|
9559
|
+
if (first !== void 0) {
|
|
9560
|
+
tokenCache.delete(first);
|
|
9561
|
+
}
|
|
9562
|
+
}
|
|
9563
|
+
tokenCache.set(key, tokens);
|
|
9564
|
+
return tokens;
|
|
9565
|
+
}
|
|
9566
|
+
function formatToken(token, theme, highlight = null, listDepth = 0, orderedListNumber = null, parent = null) {
|
|
9567
|
+
switch (token.type) {
|
|
9568
|
+
case "blockquote": {
|
|
9569
|
+
const inner = (token.tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("");
|
|
9570
|
+
const bar = theme.dim(BLOCKQUOTE_BAR);
|
|
9571
|
+
return inner.split(EOL).map((line) => stripAnsi3(line).trim() ? `${bar} ${chalk2.italic(line)}` : line).join(EOL);
|
|
9572
|
+
}
|
|
9573
|
+
case "code": {
|
|
9574
|
+
const codeToken = token;
|
|
9575
|
+
if (!highlight) {
|
|
9576
|
+
return codeToken.text + EOL;
|
|
9577
|
+
}
|
|
9578
|
+
let language = "plaintext";
|
|
9579
|
+
if (codeToken.lang && highlight.supportsLanguage(codeToken.lang)) {
|
|
9580
|
+
language = codeToken.lang;
|
|
9581
|
+
}
|
|
9582
|
+
return highlight.highlight(codeToken.text, { language }) + EOL;
|
|
9583
|
+
}
|
|
9584
|
+
case "codespan":
|
|
9585
|
+
return theme.role("codeInline", token.text);
|
|
9586
|
+
case "em":
|
|
9587
|
+
return chalk2.italic(
|
|
9588
|
+
(token.tokens ?? []).map((child) => formatToken(child, theme, highlight, 0, null, parent)).join("")
|
|
9589
|
+
);
|
|
9590
|
+
case "strong":
|
|
9591
|
+
return chalk2.bold(
|
|
9592
|
+
(token.tokens ?? []).map((child) => formatToken(child, theme, highlight, 0, null, parent)).join("")
|
|
9593
|
+
);
|
|
9594
|
+
case "heading": {
|
|
9595
|
+
const headingToken = token;
|
|
9596
|
+
const inner = (headingToken.tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("");
|
|
9597
|
+
const colored = theme.role("heading", inner);
|
|
9598
|
+
if (headingToken.depth === 1) {
|
|
9599
|
+
return chalk2.bold.italic.underline(colored) + EOL + EOL;
|
|
9600
|
+
}
|
|
9601
|
+
return chalk2.bold(colored) + EOL + EOL;
|
|
9602
|
+
}
|
|
9603
|
+
case "hr":
|
|
9604
|
+
return "---";
|
|
9605
|
+
case "image":
|
|
9606
|
+
return token.href;
|
|
9607
|
+
case "link": {
|
|
9608
|
+
const linkToken = token;
|
|
9609
|
+
if (linkToken.href.startsWith("mailto:")) {
|
|
9610
|
+
return linkToken.href.replace(/^mailto:/, "");
|
|
9611
|
+
}
|
|
9612
|
+
const linkText = (linkToken.tokens ?? []).map((child) => formatToken(child, theme, highlight, 0, null, linkToken)).join("");
|
|
9613
|
+
const plainLinkText = stripAnsi3(linkText);
|
|
9614
|
+
const display = plainLinkText && plainLinkText !== linkToken.href ? linkText : linkToken.href;
|
|
9615
|
+
return `\x1B]8;;${linkToken.href}\x07${display}\x1B]8;;\x07`;
|
|
9616
|
+
}
|
|
9617
|
+
case "list": {
|
|
9618
|
+
const listToken = token;
|
|
9619
|
+
const start = typeof listToken.start === "number" ? listToken.start : Number(listToken.start) || 1;
|
|
9620
|
+
return listToken.items.map(
|
|
9621
|
+
(item, index) => formatToken(
|
|
9622
|
+
item,
|
|
9623
|
+
theme,
|
|
9624
|
+
highlight,
|
|
9625
|
+
listDepth,
|
|
9626
|
+
listToken.ordered ? start + index : null,
|
|
9627
|
+
listToken
|
|
9628
|
+
)
|
|
9629
|
+
).join("");
|
|
9630
|
+
}
|
|
9631
|
+
case "list_item":
|
|
9632
|
+
return (token.tokens ?? []).map(
|
|
9633
|
+
(child) => `${" ".repeat(listDepth)}${formatToken(child, theme, highlight, listDepth + 1, orderedListNumber, token)}`
|
|
9634
|
+
).join("");
|
|
9635
|
+
case "paragraph":
|
|
9636
|
+
return (token.tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("") + EOL;
|
|
9637
|
+
case "space":
|
|
9638
|
+
case "br":
|
|
9639
|
+
return EOL;
|
|
9640
|
+
case "text": {
|
|
9641
|
+
const textToken = token;
|
|
9642
|
+
if (parent?.type === "link") {
|
|
9643
|
+
return textToken.text;
|
|
9644
|
+
}
|
|
9645
|
+
if (parent?.type === "list_item") {
|
|
9646
|
+
const marker = orderedListNumber === null ? "-" : `${getListNumber(listDepth, orderedListNumber)}.`;
|
|
9647
|
+
const body = textToken.tokens ? textToken.tokens.map((child) => formatToken(child, theme, highlight, listDepth, orderedListNumber, token)).join("") : textToken.text;
|
|
9648
|
+
return `${marker} ${body}${EOL}`;
|
|
9649
|
+
}
|
|
9650
|
+
return textToken.text;
|
|
9651
|
+
}
|
|
9652
|
+
case "escape":
|
|
9653
|
+
return token.text;
|
|
9654
|
+
case "table":
|
|
9655
|
+
case "def":
|
|
9656
|
+
case "del":
|
|
9657
|
+
case "html":
|
|
9658
|
+
return "";
|
|
9659
|
+
default:
|
|
9660
|
+
return "";
|
|
9661
|
+
}
|
|
9662
|
+
}
|
|
9663
|
+
function numberToLetter(n) {
|
|
9664
|
+
let result = "";
|
|
9665
|
+
while (n > 0) {
|
|
9666
|
+
n--;
|
|
9667
|
+
result = String.fromCharCode(97 + n % 26) + result;
|
|
9668
|
+
n = Math.floor(n / 26);
|
|
9669
|
+
}
|
|
9670
|
+
return result;
|
|
9671
|
+
}
|
|
9672
|
+
var ROMAN_VALUES = [
|
|
9673
|
+
[1e3, "m"],
|
|
9674
|
+
[900, "cm"],
|
|
9675
|
+
[500, "d"],
|
|
9676
|
+
[400, "cd"],
|
|
9677
|
+
[100, "c"],
|
|
9678
|
+
[90, "xc"],
|
|
9679
|
+
[50, "l"],
|
|
9680
|
+
[40, "xl"],
|
|
9681
|
+
[10, "x"],
|
|
9682
|
+
[9, "ix"],
|
|
9683
|
+
[5, "v"],
|
|
9684
|
+
[4, "iv"],
|
|
9685
|
+
[1, "i"]
|
|
9686
|
+
];
|
|
9687
|
+
function numberToRoman(n) {
|
|
9688
|
+
let result = "";
|
|
9689
|
+
for (const [value, numeral] of ROMAN_VALUES) {
|
|
9690
|
+
while (n >= value) {
|
|
9691
|
+
result += numeral;
|
|
9692
|
+
n -= value;
|
|
9693
|
+
}
|
|
9694
|
+
}
|
|
9695
|
+
return result;
|
|
9696
|
+
}
|
|
9697
|
+
function getListNumber(listDepth, orderedListNumber) {
|
|
9698
|
+
switch (listDepth) {
|
|
9699
|
+
case 0:
|
|
9700
|
+
case 1:
|
|
9701
|
+
return orderedListNumber.toString();
|
|
9702
|
+
case 2:
|
|
9703
|
+
return numberToLetter(orderedListNumber);
|
|
9704
|
+
case 3:
|
|
9705
|
+
return numberToRoman(orderedListNumber);
|
|
9706
|
+
default:
|
|
9707
|
+
return orderedListNumber.toString();
|
|
9708
|
+
}
|
|
9709
|
+
}
|
|
9710
|
+
function padAligned(content, displayWidth, targetWidth, align) {
|
|
9711
|
+
const padding = Math.max(0, targetWidth - displayWidth);
|
|
9712
|
+
if (align === "center") {
|
|
9713
|
+
const leftPad = Math.floor(padding / 2);
|
|
9714
|
+
return " ".repeat(leftPad) + content + " ".repeat(padding - leftPad);
|
|
9715
|
+
}
|
|
9716
|
+
if (align === "right") {
|
|
9717
|
+
return " ".repeat(padding) + content;
|
|
9718
|
+
}
|
|
9719
|
+
return content + " ".repeat(padding);
|
|
9720
|
+
}
|
|
9721
|
+
function stringWidth(text) {
|
|
9722
|
+
return visibleWidth(text);
|
|
9723
|
+
}
|
|
9724
|
+
|
|
9725
|
+
// src/react-ink/markdown/highlight.ts
|
|
9726
|
+
import { extname } from "node:path";
|
|
9727
|
+
import hljs from "highlight.js";
|
|
9728
|
+
function scopeToRole(scope) {
|
|
9729
|
+
const head = scope.split(".")[0] ?? scope;
|
|
9730
|
+
switch (head) {
|
|
9731
|
+
case "keyword":
|
|
9732
|
+
case "built_in":
|
|
9733
|
+
case "literal":
|
|
9734
|
+
case "operator":
|
|
9735
|
+
return "synKeyword";
|
|
9736
|
+
case "string":
|
|
9737
|
+
case "regexp":
|
|
9738
|
+
case "symbol":
|
|
9739
|
+
case "char":
|
|
9740
|
+
case "meta":
|
|
9741
|
+
return "synString";
|
|
9742
|
+
case "number":
|
|
9743
|
+
return "synNumber";
|
|
9744
|
+
case "comment":
|
|
9745
|
+
case "quote":
|
|
9746
|
+
return "synComment";
|
|
9747
|
+
case "type":
|
|
9748
|
+
case "class":
|
|
9749
|
+
case "title":
|
|
9750
|
+
case "tag":
|
|
9751
|
+
case "name":
|
|
9752
|
+
case "attr":
|
|
9753
|
+
case "attribute":
|
|
9754
|
+
case "selector":
|
|
9755
|
+
return "synType";
|
|
9756
|
+
default:
|
|
9757
|
+
return null;
|
|
9758
|
+
}
|
|
9759
|
+
}
|
|
9760
|
+
var HTML_ENTITIES = {
|
|
9761
|
+
"&": "&",
|
|
9762
|
+
"<": "<",
|
|
9763
|
+
">": ">",
|
|
9764
|
+
""": '"',
|
|
9765
|
+
"'": "'",
|
|
9766
|
+
"'": "'"
|
|
9767
|
+
};
|
|
9768
|
+
function decodeEntities2(text) {
|
|
9769
|
+
return text.replace(/&(?:amp|lt|gt|quot|#x27|#39);/g, (match) => HTML_ENTITIES[match] ?? match);
|
|
9770
|
+
}
|
|
9771
|
+
function parseHljsHtml(html) {
|
|
9772
|
+
const nodes = [];
|
|
9773
|
+
const scopeStack = [];
|
|
9774
|
+
const tagRe = /<span class="hljs-([^"]+)">|<\/span>/g;
|
|
9775
|
+
let lastIndex = 0;
|
|
9776
|
+
let match;
|
|
9777
|
+
const pushText = (raw) => {
|
|
9778
|
+
if (!raw) return;
|
|
9779
|
+
const currentScope = scopeStack.length > 0 ? scopeStack[scopeStack.length - 1] : null;
|
|
9780
|
+
const scope = currentScope ? currentScope.split(/\s+/)[0].replace(/_$/, "") : null;
|
|
9781
|
+
nodes.push({ text: decodeEntities2(raw), scope });
|
|
9782
|
+
};
|
|
9783
|
+
while ((match = tagRe.exec(html)) !== null) {
|
|
9784
|
+
pushText(html.slice(lastIndex, match.index));
|
|
9785
|
+
lastIndex = tagRe.lastIndex;
|
|
9786
|
+
if (match[0] === "</span>") {
|
|
9787
|
+
scopeStack.pop();
|
|
9788
|
+
} else if (match[1]) {
|
|
9789
|
+
scopeStack.push(match[1]);
|
|
9790
|
+
}
|
|
9791
|
+
}
|
|
9792
|
+
pushText(html.slice(lastIndex));
|
|
9793
|
+
return nodes;
|
|
9794
|
+
}
|
|
9795
|
+
function createHighlighter(theme) {
|
|
9796
|
+
return {
|
|
9797
|
+
supportsLanguage: (language) => {
|
|
9798
|
+
if (!language || language === "plaintext" || language === "text") {
|
|
9799
|
+
return false;
|
|
9800
|
+
}
|
|
9801
|
+
try {
|
|
9802
|
+
return hljs.getLanguage(language) !== void 0;
|
|
9803
|
+
} catch {
|
|
9804
|
+
return false;
|
|
9805
|
+
}
|
|
9806
|
+
},
|
|
9807
|
+
highlight: (code, options) => {
|
|
9808
|
+
const language = options.language;
|
|
9809
|
+
if (!language || language === "plaintext" || language === "text") {
|
|
9810
|
+
return code;
|
|
9811
|
+
}
|
|
9812
|
+
try {
|
|
9813
|
+
if (hljs.getLanguage(language) === void 0) {
|
|
9814
|
+
return code;
|
|
9815
|
+
}
|
|
9816
|
+
const { value } = hljs.highlight(code, { language, ignoreIllegals: true });
|
|
9817
|
+
return parseHljsHtml(value).map((node) => {
|
|
9818
|
+
const role = node.scope ? scopeToRole(node.scope) : null;
|
|
9819
|
+
return role ? theme.role(role, node.text) : node.text;
|
|
9820
|
+
}).join("");
|
|
9821
|
+
} catch {
|
|
9822
|
+
return code;
|
|
9823
|
+
}
|
|
9824
|
+
}
|
|
9825
|
+
};
|
|
9826
|
+
}
|
|
9827
|
+
function highlightByPath(code, filePath, theme) {
|
|
9828
|
+
const language = languageFromPath(filePath);
|
|
9829
|
+
if (!language) {
|
|
9830
|
+
return code;
|
|
9831
|
+
}
|
|
9832
|
+
const highlighter = createHighlighter(theme);
|
|
9833
|
+
if (!highlighter.supportsLanguage(language)) {
|
|
9834
|
+
return code;
|
|
9835
|
+
}
|
|
9836
|
+
return highlighter.highlight(code, { language });
|
|
9837
|
+
}
|
|
9838
|
+
var EXTENSION_LANGUAGES = {
|
|
9839
|
+
ts: "typescript",
|
|
9840
|
+
tsx: "typescript",
|
|
9841
|
+
mts: "typescript",
|
|
9842
|
+
cts: "typescript",
|
|
9843
|
+
js: "javascript",
|
|
9844
|
+
jsx: "javascript",
|
|
9845
|
+
mjs: "javascript",
|
|
9846
|
+
cjs: "javascript",
|
|
9847
|
+
py: "python",
|
|
9848
|
+
rb: "ruby",
|
|
9849
|
+
rs: "rust",
|
|
9850
|
+
go: "go",
|
|
9851
|
+
java: "java",
|
|
9852
|
+
kt: "kotlin",
|
|
9853
|
+
c: "c",
|
|
9854
|
+
h: "c",
|
|
9855
|
+
cc: "cpp",
|
|
9856
|
+
cpp: "cpp",
|
|
9857
|
+
hpp: "cpp",
|
|
9858
|
+
cs: "csharp",
|
|
9859
|
+
sh: "bash",
|
|
9860
|
+
bash: "bash",
|
|
9861
|
+
zsh: "bash",
|
|
9862
|
+
yml: "yaml",
|
|
9863
|
+
yaml: "yaml",
|
|
9864
|
+
json: "json",
|
|
9865
|
+
md: "markdown",
|
|
9866
|
+
html: "xml",
|
|
9867
|
+
xml: "xml",
|
|
9868
|
+
css: "css",
|
|
9869
|
+
scss: "scss",
|
|
9870
|
+
sql: "sql",
|
|
9871
|
+
toml: "ini",
|
|
9872
|
+
ini: "ini",
|
|
9873
|
+
php: "php",
|
|
9874
|
+
swift: "swift"
|
|
9875
|
+
};
|
|
9876
|
+
function languageFromPath(filePath) {
|
|
9877
|
+
const ext = extname(filePath).slice(1).toLowerCase();
|
|
9878
|
+
if (!ext) {
|
|
9879
|
+
return null;
|
|
9880
|
+
}
|
|
9881
|
+
const mapped = EXTENSION_LANGUAGES[ext];
|
|
9882
|
+
if (mapped) {
|
|
9883
|
+
return mapped;
|
|
9884
|
+
}
|
|
9885
|
+
try {
|
|
9886
|
+
return hljs.getLanguage(ext) !== void 0 ? ext : null;
|
|
9887
|
+
} catch {
|
|
9888
|
+
return null;
|
|
9889
|
+
}
|
|
9890
|
+
}
|
|
9891
|
+
|
|
9892
|
+
// src/react-ink/markdown/MarkdownTable.tsx
|
|
9893
|
+
import chalk3 from "chalk";
|
|
9894
|
+
import stripAnsi4 from "strip-ansi";
|
|
9895
|
+
var MIN_COLUMN_WIDTH = 3;
|
|
9896
|
+
var COLUMN_GAP = 2;
|
|
9897
|
+
function MarkdownTable({ token, theme, highlight = null }) {
|
|
9898
|
+
const formatCell = (tokens) => (tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("");
|
|
9899
|
+
const displayWidth = (tokens) => stringWidth(stripAnsi4(formatCell(tokens)));
|
|
9900
|
+
const columnCount = token.header.length;
|
|
9901
|
+
const columnWidths = token.header.map((header, index) => {
|
|
9902
|
+
let max = displayWidth(header.tokens);
|
|
9903
|
+
for (const row of token.rows) {
|
|
9904
|
+
max = Math.max(max, displayWidth(row[index]?.tokens));
|
|
9905
|
+
}
|
|
9906
|
+
return Math.max(max, MIN_COLUMN_WIDTH);
|
|
9907
|
+
});
|
|
9908
|
+
const renderRow2 = (cells, key, bold) => /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: columnWidths.map((width, index) => {
|
|
9909
|
+
const cell = cells[index];
|
|
9910
|
+
const content = formatCell(cell?.tokens);
|
|
9911
|
+
const visible = stringWidth(stripAnsi4(content));
|
|
9912
|
+
const align = token.align?.[index];
|
|
9913
|
+
const padded = padAligned(content, visible, width, align ?? "left");
|
|
9914
|
+
const styled = bold ? chalk3.bold(padded) : padded;
|
|
9915
|
+
const gap = index < columnCount - 1 ? " ".repeat(COLUMN_GAP) : "";
|
|
9916
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
9917
|
+
styled,
|
|
9918
|
+
gap
|
|
9919
|
+
] }, index);
|
|
9920
|
+
}) }, key);
|
|
9921
|
+
const separator = /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: columnWidths.map((width, index) => {
|
|
9922
|
+
const gap = index < columnCount - 1 ? " ".repeat(COLUMN_GAP) : "";
|
|
9923
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
9924
|
+
theme.dim("-".repeat(width)),
|
|
9925
|
+
gap
|
|
9926
|
+
] }, index);
|
|
9927
|
+
}) });
|
|
9928
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
9929
|
+
renderRow2(token.header, "header", true),
|
|
9930
|
+
separator,
|
|
9931
|
+
token.rows.map((row, rowIndex) => renderRow2(row, `row-${rowIndex}`, false))
|
|
9932
|
+
] });
|
|
9933
|
+
}
|
|
9934
|
+
|
|
9935
|
+
// src/react-ink/markdown/Markdown.tsx
|
|
9936
|
+
function stripPromptXMLTags(text) {
|
|
9937
|
+
return text.replace(/<\/?(?:system-reminder|prompt|context)[^>]*>/g, "");
|
|
9938
|
+
}
|
|
9939
|
+
function Markdown({ children, theme, highlightCode = true, dim = false }) {
|
|
9940
|
+
const highlight = useMemo(
|
|
9941
|
+
() => highlightCode ? createHighlighter(theme) : null,
|
|
9942
|
+
[highlightCode, theme]
|
|
9943
|
+
);
|
|
9944
|
+
const elements = useMemo(() => {
|
|
9945
|
+
configureMarked();
|
|
9946
|
+
const tokens = cachedLexer(stripPromptXMLTags(children));
|
|
9947
|
+
const out = [];
|
|
9948
|
+
let buffer = "";
|
|
9949
|
+
const flush = () => {
|
|
9950
|
+
if (buffer) {
|
|
9951
|
+
const text = buffer.replace(/\n+$/, "");
|
|
9952
|
+
if (text) {
|
|
9953
|
+
out.push(
|
|
9954
|
+
/* @__PURE__ */ jsx(Text, { children: dim ? theme.dim(text) : text }, out.length)
|
|
9955
|
+
);
|
|
9956
|
+
}
|
|
9957
|
+
buffer = "";
|
|
9958
|
+
}
|
|
9959
|
+
};
|
|
9960
|
+
for (const token of tokens) {
|
|
9961
|
+
if (token.type === "table") {
|
|
9962
|
+
flush();
|
|
9963
|
+
out.push(
|
|
9964
|
+
/* @__PURE__ */ jsx(
|
|
9965
|
+
MarkdownTable,
|
|
9966
|
+
{
|
|
9967
|
+
token,
|
|
9968
|
+
theme,
|
|
9969
|
+
highlight
|
|
9970
|
+
},
|
|
9971
|
+
out.length
|
|
9972
|
+
)
|
|
9973
|
+
);
|
|
9974
|
+
} else {
|
|
9975
|
+
buffer += formatToken(token, theme, highlight);
|
|
9976
|
+
}
|
|
9977
|
+
}
|
|
9978
|
+
flush();
|
|
9979
|
+
return out;
|
|
9980
|
+
}, [children, dim, highlight, theme]);
|
|
9981
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: elements });
|
|
9982
|
+
}
|
|
9983
|
+
|
|
8891
9984
|
// src/react-ink/utils/tool-display.ts
|
|
8892
9985
|
import { homedir as homedir2 } from "node:os";
|
|
9986
|
+
|
|
9987
|
+
// src/react-ink/diff/structured.ts
|
|
9988
|
+
import { structuredPatch } from "diff";
|
|
9989
|
+
|
|
9990
|
+
// src/react-ink/diff/word-diff.ts
|
|
9991
|
+
import { diffWordsWithSpace } from "diff";
|
|
9992
|
+
var CHANGE_THRESHOLD = 0.4;
|
|
9993
|
+
function wordDiffLine(oldLine, newLine, side) {
|
|
9994
|
+
const lineText = side === "removed" ? oldLine : newLine;
|
|
9995
|
+
if (oldLine.length === 0 || newLine.length === 0) {
|
|
9996
|
+
return [{ text: lineText, changed: true }];
|
|
9997
|
+
}
|
|
9998
|
+
let changes;
|
|
9999
|
+
try {
|
|
10000
|
+
changes = diffWordsWithSpace(oldLine, newLine);
|
|
10001
|
+
} catch {
|
|
10002
|
+
return [{ text: lineText, changed: true }];
|
|
10003
|
+
}
|
|
10004
|
+
let changedChars = 0;
|
|
10005
|
+
let totalChars = 0;
|
|
10006
|
+
for (const change of changes) {
|
|
10007
|
+
totalChars += change.value.length;
|
|
10008
|
+
if (change.added || change.removed) {
|
|
10009
|
+
changedChars += change.value.length;
|
|
10010
|
+
}
|
|
10011
|
+
}
|
|
10012
|
+
const fraction = totalChars === 0 ? 0 : changedChars / totalChars;
|
|
10013
|
+
if (fraction > CHANGE_THRESHOLD) {
|
|
10014
|
+
return [{ text: lineText, changed: true }];
|
|
10015
|
+
}
|
|
10016
|
+
const spans = [];
|
|
10017
|
+
for (const change of changes) {
|
|
10018
|
+
const belongs = side === "removed" ? !change.added : !change.removed;
|
|
10019
|
+
if (!belongs) {
|
|
10020
|
+
continue;
|
|
10021
|
+
}
|
|
10022
|
+
spans.push({ text: change.value, changed: Boolean(change.added || change.removed) });
|
|
10023
|
+
}
|
|
10024
|
+
return spans.length > 0 ? spans : [{ text: lineText, changed: false }];
|
|
10025
|
+
}
|
|
10026
|
+
|
|
10027
|
+
// src/react-ink/diff/structured.ts
|
|
10028
|
+
var CONTEXT_LINES = 3;
|
|
10029
|
+
function buildStructuredDiff(oldStr, newStr, filePath = "") {
|
|
10030
|
+
if (oldStr === newStr) {
|
|
10031
|
+
return null;
|
|
10032
|
+
}
|
|
10033
|
+
let patch;
|
|
10034
|
+
try {
|
|
10035
|
+
patch = structuredPatch(filePath, filePath, oldStr, newStr, "", "", { context: CONTEXT_LINES });
|
|
10036
|
+
} catch {
|
|
10037
|
+
return null;
|
|
10038
|
+
}
|
|
10039
|
+
const hunks = [];
|
|
10040
|
+
let addedCount = 0;
|
|
10041
|
+
let removedCount = 0;
|
|
10042
|
+
for (const hunk of patch.hunks) {
|
|
10043
|
+
const lines = classifyHunkLines(hunk);
|
|
10044
|
+
for (const line of lines) {
|
|
10045
|
+
if (line.kind === "added") addedCount += 1;
|
|
10046
|
+
else if (line.kind === "removed") removedCount += 1;
|
|
10047
|
+
}
|
|
10048
|
+
if (lines.length > 0) {
|
|
10049
|
+
hunks.push({ oldStart: hunk.oldStart, newStart: hunk.newStart, lines });
|
|
10050
|
+
}
|
|
10051
|
+
}
|
|
10052
|
+
if (hunks.length === 0) {
|
|
10053
|
+
return null;
|
|
10054
|
+
}
|
|
10055
|
+
return { hunks, addedCount, removedCount };
|
|
10056
|
+
}
|
|
10057
|
+
function classifyHunkLines(hunk) {
|
|
10058
|
+
const out = [];
|
|
10059
|
+
let oldNum = hunk.oldStart;
|
|
10060
|
+
let newNum = hunk.newStart;
|
|
10061
|
+
const rawLines = hunk.lines.filter((line) => !line.startsWith("\\"));
|
|
10062
|
+
let removedRun = [];
|
|
10063
|
+
let removedRunStart = -1;
|
|
10064
|
+
const flushPairing = (addedRun2) => {
|
|
10065
|
+
const pairs = Math.min(removedRun.length, addedRun2.length);
|
|
10066
|
+
for (let i = 0; i < pairs; i += 1) {
|
|
10067
|
+
const removed = removedRun[i];
|
|
10068
|
+
const added = addedRun2[i];
|
|
10069
|
+
removed.spans = wordDiffLine(removed.text, added.text, "removed");
|
|
10070
|
+
added.spans = wordDiffLine(removed.text, added.text, "added");
|
|
10071
|
+
}
|
|
10072
|
+
removedRun = [];
|
|
10073
|
+
removedRunStart = -1;
|
|
10074
|
+
};
|
|
10075
|
+
let addedRun = [];
|
|
10076
|
+
for (const raw of rawLines) {
|
|
10077
|
+
const marker = raw[0];
|
|
10078
|
+
const text = raw.slice(1);
|
|
10079
|
+
if (marker === "-") {
|
|
10080
|
+
if (addedRun.length > 0) {
|
|
10081
|
+
addedRun = [];
|
|
10082
|
+
}
|
|
10083
|
+
const line = { kind: "removed", oldLine: oldNum, text };
|
|
10084
|
+
out.push(line);
|
|
10085
|
+
if (removedRunStart === -1) removedRunStart = out.length - 1;
|
|
10086
|
+
removedRun.push(line);
|
|
10087
|
+
oldNum += 1;
|
|
10088
|
+
} else if (marker === "+") {
|
|
10089
|
+
const line = { kind: "added", newLine: newNum, text };
|
|
10090
|
+
out.push(line);
|
|
10091
|
+
addedRun.push(line);
|
|
10092
|
+
newNum += 1;
|
|
10093
|
+
} else {
|
|
10094
|
+
if (removedRun.length > 0 && addedRun.length > 0) {
|
|
10095
|
+
flushPairing(addedRun);
|
|
10096
|
+
}
|
|
10097
|
+
removedRun = [];
|
|
10098
|
+
removedRunStart = -1;
|
|
10099
|
+
addedRun = [];
|
|
10100
|
+
out.push({ kind: "context", oldLine: oldNum, newLine: newNum, text });
|
|
10101
|
+
oldNum += 1;
|
|
10102
|
+
newNum += 1;
|
|
10103
|
+
}
|
|
10104
|
+
}
|
|
10105
|
+
if (removedRun.length > 0 && addedRun.length > 0) {
|
|
10106
|
+
flushPairing(addedRun);
|
|
10107
|
+
}
|
|
10108
|
+
return out;
|
|
10109
|
+
}
|
|
10110
|
+
|
|
10111
|
+
// src/react-ink/utils/tool-display.ts
|
|
8893
10112
|
function asRecord2(value) {
|
|
8894
10113
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
8895
10114
|
}
|
|
@@ -8972,6 +10191,12 @@ function clipBody(value, maxLines = 8, maxChars = 1400) {
|
|
|
8972
10191
|
}
|
|
8973
10192
|
return previewMultiline(value, { maxLines, maxChars });
|
|
8974
10193
|
}
|
|
10194
|
+
function highlightedBody(body, filePath, theme) {
|
|
10195
|
+
if (!body || !theme || !filePath || languageFromPath(filePath) === null) {
|
|
10196
|
+
return { body };
|
|
10197
|
+
}
|
|
10198
|
+
return { body: highlightByPath(body, filePath, theme), preformatted: true };
|
|
10199
|
+
}
|
|
8975
10200
|
function extractDetails(value) {
|
|
8976
10201
|
return asRecord2(asRecord2(value)?.details);
|
|
8977
10202
|
}
|
|
@@ -9038,7 +10263,7 @@ function fallbackBody(output, fallbackOutputText, showImages = false) {
|
|
|
9038
10263
|
return clipBody(fallbackOutputText);
|
|
9039
10264
|
}
|
|
9040
10265
|
function describeToolSource(source) {
|
|
9041
|
-
const { args, fallbackArgsText, fallbackOutputText, output, showImages = false, toolName } = source;
|
|
10266
|
+
const { args, fallbackArgsText, fallbackOutputText, output, showImages = false, theme, toolName } = source;
|
|
9042
10267
|
const argsRecord = asRecord2(args);
|
|
9043
10268
|
const details = extractDetails(output);
|
|
9044
10269
|
const outputText = toolText(output, showImages);
|
|
@@ -9056,10 +10281,12 @@ function describeToolSource(source) {
|
|
|
9056
10281
|
summary += `:${start}${end ? `-${end}` : ""}`;
|
|
9057
10282
|
}
|
|
9058
10283
|
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";
|
|
10284
|
+
const readBody = hasResult && !containsImage(output) ? highlightedBody(clipBody(outputText, 10, 1800), rawPath, theme) : { body: hasResult ? clipBody(outputText, 10, 1800) : void 0 };
|
|
9059
10285
|
return {
|
|
9060
10286
|
title,
|
|
9061
10287
|
summary: hasResult ? responseSummary : summary,
|
|
9062
|
-
body:
|
|
10288
|
+
body: readBody.body,
|
|
10289
|
+
preformatted: readBody.preformatted,
|
|
9063
10290
|
emptyText: "Reading file..."
|
|
9064
10291
|
};
|
|
9065
10292
|
}
|
|
@@ -9067,10 +10294,14 @@ function describeToolSource(source) {
|
|
|
9067
10294
|
const rawPath = asString(argsRecord?.file_path) ?? asString(argsRecord?.path) ?? "";
|
|
9068
10295
|
const content = asString(argsRecord?.content);
|
|
9069
10296
|
const responseSummary = firstMeaningfulLine(outputText) ?? "Wrote file";
|
|
10297
|
+
const writeDiff = !hasResult && content !== void 0 && content.length > 0 ? buildStructuredDiff("", content, rawPath) ?? void 0 : void 0;
|
|
10298
|
+
const writeBody = hasResult ? { body: clipBody(outputText, 8, 1500) } : highlightedBody(clipBody(content, 8, 1500), rawPath, theme);
|
|
9070
10299
|
return {
|
|
9071
10300
|
title,
|
|
9072
10301
|
summary: hasResult ? responseSummary : rawPath ? shortenPath2(rawPath) : void 0,
|
|
9073
|
-
body:
|
|
10302
|
+
body: writeDiff ? void 0 : writeBody.body,
|
|
10303
|
+
preformatted: writeDiff ? void 0 : writeBody.preformatted,
|
|
10304
|
+
diff: writeDiff,
|
|
9074
10305
|
emptyText: "Preparing file write..."
|
|
9075
10306
|
};
|
|
9076
10307
|
}
|
|
@@ -9087,10 +10318,15 @@ function describeToolSource(source) {
|
|
|
9087
10318
|
400
|
|
9088
10319
|
) : void 0;
|
|
9089
10320
|
const responseSummary = firstMeaningfulLine(outputText) ?? "Applied edit";
|
|
10321
|
+
const editDiff = oldText !== void 0 && newText !== void 0 ? buildStructuredDiff(oldText, newText, rawPath) ?? void 0 : void 0;
|
|
10322
|
+
const editBody = hasResult ? highlightedBody(clipBody(outputText, 8, 1500), rawPath, theme) : { body: replacementPreview };
|
|
10323
|
+
const editChangeSummary = editDiff ? `+${editDiff.addedCount} -${editDiff.removedCount}` : void 0;
|
|
9090
10324
|
return {
|
|
9091
10325
|
title,
|
|
9092
|
-
summary: hasResult ? responseSummary : rawPath ? shortenPath2(rawPath) : void 0,
|
|
9093
|
-
body:
|
|
10326
|
+
summary: hasResult ? editChangeSummary ?? responseSummary : editChangeSummary ?? (rawPath ? shortenPath2(rawPath) : void 0),
|
|
10327
|
+
body: editDiff ? void 0 : editBody.body,
|
|
10328
|
+
preformatted: editDiff ? void 0 : editBody.preformatted,
|
|
10329
|
+
diff: editDiff,
|
|
9094
10330
|
emptyText: "Applying edit..."
|
|
9095
10331
|
};
|
|
9096
10332
|
}
|
|
@@ -9187,7 +10423,7 @@ function describeToolCall(toolCall) {
|
|
|
9187
10423
|
args: toolCall.arguments
|
|
9188
10424
|
});
|
|
9189
10425
|
}
|
|
9190
|
-
function describeToolResult(message, showImages, args) {
|
|
10426
|
+
function describeToolResult(message, showImages, args, theme) {
|
|
9191
10427
|
return describeToolSource({
|
|
9192
10428
|
args,
|
|
9193
10429
|
toolName: message.toolName,
|
|
@@ -9195,12 +10431,13 @@ function describeToolResult(message, showImages, args) {
|
|
|
9195
10431
|
content: message.content,
|
|
9196
10432
|
details: message.details
|
|
9197
10433
|
},
|
|
9198
|
-
showImages
|
|
10434
|
+
showImages,
|
|
10435
|
+
theme
|
|
9199
10436
|
});
|
|
9200
10437
|
}
|
|
9201
10438
|
|
|
9202
10439
|
// src/react-ink/components/ToolEventBlock.tsx
|
|
9203
|
-
import
|
|
10440
|
+
import stripAnsi5 from "strip-ansi";
|
|
9204
10441
|
function statusMarker(status) {
|
|
9205
10442
|
switch (status) {
|
|
9206
10443
|
case "error":
|
|
@@ -9211,12 +10448,15 @@ function statusMarker(status) {
|
|
|
9211
10448
|
return ">";
|
|
9212
10449
|
}
|
|
9213
10450
|
}
|
|
10451
|
+
function statusColorKey(status) {
|
|
10452
|
+
return status === "error" ? "error" : "text";
|
|
10453
|
+
}
|
|
9214
10454
|
function plainToolText(text) {
|
|
9215
|
-
return
|
|
10455
|
+
return stripAnsi5(text);
|
|
9216
10456
|
}
|
|
9217
10457
|
function splitVisibleLines(text) {
|
|
9218
10458
|
return (text ?? "").split(/\r?\n/).map((line) => line.trimEnd()).filter((line, index, lines) => {
|
|
9219
|
-
if (line.length > 0) {
|
|
10459
|
+
if (stripAnsi5(line).length > 0) {
|
|
9220
10460
|
return true;
|
|
9221
10461
|
}
|
|
9222
10462
|
return index !== 0 && index !== lines.length - 1;
|
|
@@ -9247,11 +10487,12 @@ function ToolEventBlock({
|
|
|
9247
10487
|
indent = 0,
|
|
9248
10488
|
marginBottom = 1,
|
|
9249
10489
|
maxContentLines = 10,
|
|
10490
|
+
preformatted = false,
|
|
9250
10491
|
showSummaryInline = false,
|
|
9251
10492
|
showTitle = true,
|
|
9252
10493
|
status,
|
|
9253
10494
|
summary,
|
|
9254
|
-
theme
|
|
10495
|
+
theme,
|
|
9255
10496
|
title
|
|
9256
10497
|
}) {
|
|
9257
10498
|
const normalizedSummary = summary?.trim();
|
|
@@ -9267,19 +10508,19 @@ function ToolEventBlock({
|
|
|
9267
10508
|
const { visibleLines, hiddenLineCount } = clampContentLines(combinedLines, maxContentLines);
|
|
9268
10509
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom, marginLeft: indent, children: [
|
|
9269
10510
|
showTitle ? /* @__PURE__ */ jsxs(Box, { children: [
|
|
9270
|
-
/* @__PURE__ */ jsx(Text, {
|
|
9271
|
-
/* @__PURE__ */ jsx(Text, {
|
|
9272
|
-
showSummaryInline && normalizedSummary ? /* @__PURE__ */ jsx(Text, {
|
|
10511
|
+
/* @__PURE__ */ jsx(Text, { children: theme.color(statusColorKey(status), plainToolText(`${statusMarker(status)} `)) }),
|
|
10512
|
+
/* @__PURE__ */ jsx(Text, { children: theme.color(statusColorKey(status), plainToolText(title)) }),
|
|
10513
|
+
showSummaryInline && normalizedSummary ? /* @__PURE__ */ jsx(Text, { children: theme.muted(plainToolText(` (${normalizedSummary})`)) }) : null
|
|
9273
10514
|
] }) : null,
|
|
9274
10515
|
visibleLines.map((line, index) => /* @__PURE__ */ jsx(
|
|
9275
10516
|
Box,
|
|
9276
10517
|
{
|
|
9277
10518
|
marginLeft: line.kind === "response" ? showTitle ? 2 : 0 : showTitle ? 4 : 2,
|
|
9278
|
-
children: /* @__PURE__ */ jsx(Text, {
|
|
10519
|
+
children: preformatted ? /* @__PURE__ */ jsx(Text, { children: line.text }) : /* @__PURE__ */ jsx(Text, { children: theme.color("text", plainToolText(line.text)) })
|
|
9279
10520
|
},
|
|
9280
|
-
`${line.kind}:${index}:${line.text}`
|
|
10521
|
+
`${line.kind}:${index}:${stripAnsi5(line.text)}`
|
|
9281
10522
|
)),
|
|
9282
|
-
hiddenLineCount > 0 ? /* @__PURE__ */ jsx(Box, { marginLeft: showTitle ? 4 : 2, children: /* @__PURE__ */ jsx(Text, {
|
|
10523
|
+
hiddenLineCount > 0 ? /* @__PURE__ */ jsx(Box, { marginLeft: showTitle ? 4 : 2, children: /* @__PURE__ */ jsx(Text, { children: theme.muted(plainToolText(`... ${hiddenLineCount} more line(s)`)) }) }) : null
|
|
9283
10524
|
] });
|
|
9284
10525
|
}
|
|
9285
10526
|
|
|
@@ -9302,17 +10543,100 @@ function ToolCallMessage({ theme, toolCall }) {
|
|
|
9302
10543
|
);
|
|
9303
10544
|
}
|
|
9304
10545
|
|
|
10546
|
+
// src/react-ink/diff/Diff.tsx
|
|
10547
|
+
import chalk4 from "chalk";
|
|
10548
|
+
function lineMarker(kind) {
|
|
10549
|
+
switch (kind) {
|
|
10550
|
+
case "added":
|
|
10551
|
+
return "+";
|
|
10552
|
+
case "removed":
|
|
10553
|
+
return "-";
|
|
10554
|
+
default:
|
|
10555
|
+
return " ";
|
|
10556
|
+
}
|
|
10557
|
+
}
|
|
10558
|
+
function gutterWidth(diff) {
|
|
10559
|
+
let max = 1;
|
|
10560
|
+
for (const hunk of diff.hunks) {
|
|
10561
|
+
for (const line of hunk.lines) {
|
|
10562
|
+
const num2 = line.kind === "removed" ? line.oldLine : line.newLine;
|
|
10563
|
+
if (num2 !== void 0) {
|
|
10564
|
+
max = Math.max(max, stringWidth(String(num2)));
|
|
10565
|
+
}
|
|
10566
|
+
}
|
|
10567
|
+
}
|
|
10568
|
+
return max;
|
|
10569
|
+
}
|
|
10570
|
+
function renderLineText(line, theme, bgRole, fgRole) {
|
|
10571
|
+
const paintSpan = (text, changed) => {
|
|
10572
|
+
const fg = theme.role(fgRole, text);
|
|
10573
|
+
return changed ? chalk4.bold(fg) : fg;
|
|
10574
|
+
};
|
|
10575
|
+
let body;
|
|
10576
|
+
if (line.spans && line.spans.length > 0) {
|
|
10577
|
+
body = line.spans.map((span) => paintSpan(span.text, span.changed)).join("");
|
|
10578
|
+
} else {
|
|
10579
|
+
body = theme.role(fgRole, line.text);
|
|
10580
|
+
}
|
|
10581
|
+
return bgRole ? theme.roleBackground(bgRole, body) : body;
|
|
10582
|
+
}
|
|
10583
|
+
function Diff({ diff, theme, indent = 0, marginBottom = 0 }) {
|
|
10584
|
+
const gutter = gutterWidth(diff);
|
|
10585
|
+
const renderLine = (line, key) => {
|
|
10586
|
+
const num2 = line.kind === "removed" ? line.oldLine : line.newLine;
|
|
10587
|
+
const gutterText = (num2 !== void 0 ? String(num2) : "").padStart(gutter);
|
|
10588
|
+
const marker = lineMarker(line.kind);
|
|
10589
|
+
const bgRole = line.kind === "added" ? "diffAddedBg" : line.kind === "removed" ? "diffRemovedBg" : null;
|
|
10590
|
+
const fgRole = line.kind === "added" ? "diffAddedText" : line.kind === "removed" ? "diffRemovedText" : "blockquoteBar";
|
|
10591
|
+
const gutterStyled = theme.dim(`${gutterText} `);
|
|
10592
|
+
const markerStyled = line.kind === "context" ? theme.dim(`${marker} `) : theme.role(fgRole, `${marker} `);
|
|
10593
|
+
const text = renderLineText(line, theme, bgRole, fgRole);
|
|
10594
|
+
return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
10595
|
+
gutterStyled,
|
|
10596
|
+
markerStyled,
|
|
10597
|
+
text
|
|
10598
|
+
] }) }, key);
|
|
10599
|
+
};
|
|
10600
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: indent, marginBottom, children: diff.hunks.map((hunk, hunkIndex) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
10601
|
+
hunkIndex > 0 ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { children: theme.dim("...") }) }) : null,
|
|
10602
|
+
hunk.lines.map((line, lineIndex) => renderLine(line, `${hunkIndex}-${lineIndex}`))
|
|
10603
|
+
] }, `hunk-${hunkIndex}`)) });
|
|
10604
|
+
}
|
|
10605
|
+
|
|
9305
10606
|
// src/react-ink/components/messages/ToolResultBlock.tsx
|
|
9306
10607
|
function ToolResultBlock({ expanded = false, message, nested = false, showImages, theme, toolCall }) {
|
|
9307
|
-
const descriptor = describeToolResult(message, showImages, toolCall?.arguments);
|
|
10608
|
+
const descriptor = describeToolResult(message, showImages, toolCall?.arguments, theme);
|
|
10609
|
+
const indent = nested ? 4 : 2;
|
|
10610
|
+
if (descriptor.diff) {
|
|
10611
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 0, children: [
|
|
10612
|
+
/* @__PURE__ */ jsx(
|
|
10613
|
+
ToolEventBlock,
|
|
10614
|
+
{
|
|
10615
|
+
detail: void 0,
|
|
10616
|
+
emptyText: descriptor.emptyText,
|
|
10617
|
+
indent,
|
|
10618
|
+
marginBottom: 0,
|
|
10619
|
+
maxContentLines: 0,
|
|
10620
|
+
showSummaryInline: false,
|
|
10621
|
+
showTitle: !nested,
|
|
10622
|
+
status: message.isError ? "error" : "success",
|
|
10623
|
+
summary: descriptor.summary,
|
|
10624
|
+
theme,
|
|
10625
|
+
title: descriptor.title
|
|
10626
|
+
}
|
|
10627
|
+
),
|
|
10628
|
+
/* @__PURE__ */ jsx(Diff, { diff: descriptor.diff, theme, indent: indent + 2 })
|
|
10629
|
+
] });
|
|
10630
|
+
}
|
|
9308
10631
|
return /* @__PURE__ */ jsx(
|
|
9309
10632
|
ToolEventBlock,
|
|
9310
10633
|
{
|
|
9311
10634
|
detail: descriptor.body,
|
|
9312
10635
|
emptyText: descriptor.emptyText,
|
|
9313
|
-
indent
|
|
10636
|
+
indent,
|
|
9314
10637
|
marginBottom: 0,
|
|
9315
10638
|
maxContentLines: expanded ? Number.MAX_SAFE_INTEGER : 10,
|
|
10639
|
+
preformatted: descriptor.preformatted,
|
|
9316
10640
|
showSummaryInline: false,
|
|
9317
10641
|
showTitle: !nested,
|
|
9318
10642
|
status: message.isError ? "error" : "success",
|
|
@@ -9337,7 +10661,7 @@ function AssistantMessageView({
|
|
|
9337
10661
|
const matchedToolResultIds = /* @__PURE__ */ new Set();
|
|
9338
10662
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
9339
10663
|
/* @__PURE__ */ jsx(Text, { children: theme.color("accent", `Assistant ${message.provider}/${message.model} ${formatMessageTimestamp(message.timestamp)}`) }),
|
|
9340
|
-
parts.text ? /* @__PURE__ */ jsx(
|
|
10664
|
+
parts.text ? /* @__PURE__ */ jsx(Markdown, { theme, children: parts.text }) : null,
|
|
9341
10665
|
parts.thinking.map((thinking, index) => /* @__PURE__ */ jsx(Text, { children: theme.muted(`[thinking] ${thinking}`) }, index)),
|
|
9342
10666
|
parts.toolCalls.map((toolCall) => {
|
|
9343
10667
|
const toolResult = toolResultsByCallId.get(toolCall.id);
|
|
@@ -9539,20 +10863,20 @@ function MessageList({
|
|
|
9539
10863
|
}
|
|
9540
10864
|
|
|
9541
10865
|
// src/react-ink/components/StatusLine.tsx
|
|
9542
|
-
function StatusLine({ snapshot, status, theme }) {
|
|
10866
|
+
function StatusLine({ snapshot, status, theme, showBusyText = true }) {
|
|
9543
10867
|
let text = status?.text;
|
|
9544
10868
|
let tone = status?.kind ?? "info";
|
|
9545
10869
|
if (!text) {
|
|
9546
|
-
if (snapshot.isCompacting) {
|
|
10870
|
+
if (showBusyText && snapshot.isCompacting) {
|
|
9547
10871
|
text = "Compacting conversation context...";
|
|
9548
10872
|
tone = "busy";
|
|
9549
|
-
} else if (snapshot.isBashRunning) {
|
|
10873
|
+
} else if (showBusyText && snapshot.isBashRunning) {
|
|
9550
10874
|
text = "Running bash command...";
|
|
9551
10875
|
tone = "busy";
|
|
9552
|
-
} else if (snapshot.pendingToolCallCount > 0 || snapshot.pendingMessageCount > 0) {
|
|
10876
|
+
} else if (showBusyText && (snapshot.pendingToolCallCount > 0 || snapshot.pendingMessageCount > 0)) {
|
|
9553
10877
|
text = "Agent working...";
|
|
9554
10878
|
tone = "busy";
|
|
9555
|
-
} else if (snapshot.isStreaming) {
|
|
10879
|
+
} else if (showBusyText && snapshot.isStreaming) {
|
|
9556
10880
|
text = "Agent working...";
|
|
9557
10881
|
tone = "busy";
|
|
9558
10882
|
} else if (snapshot.error) {
|