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