indusagi 0.12.33 → 0.12.34
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/cli.js +1271 -17
- package/dist/index.js +1271 -17
- package/dist/react-ink.js +1377 -31
- package/dist/shell-app.js +1271 -17
- package/dist/types/react-ink/components/ToolEventBlock.d.ts +8 -1
- package/dist/types/react-ink/components/dialogs/SelectableDialog.d.ts +7 -1
- package/dist/types/react-ink/components/dialogs/ThemeDialog.d.ts +21 -2
- package/dist/types/react-ink/diff/Diff.d.ts +22 -0
- package/dist/types/react-ink/diff/diff.test.d.ts +1 -0
- package/dist/types/react-ink/diff/structured.d.ts +41 -0
- package/dist/types/react-ink/diff/word-diff.d.ts +27 -0
- package/dist/types/react-ink/index.d.ts +8 -0
- package/dist/types/react-ink/markdown/Markdown.d.ts +23 -0
- package/dist/types/react-ink/markdown/MarkdownTable.d.ts +19 -0
- package/dist/types/react-ink/markdown/StreamingMarkdown.d.ts +34 -0
- package/dist/types/react-ink/markdown/format-token.d.ts +39 -0
- package/dist/types/react-ink/markdown/highlight.d.ts +31 -0
- package/dist/types/react-ink/theme-adapter.d.ts +58 -1
- package/dist/types/react-ink/utils/tool-display.d.ts +17 -1
- package/package.json +5 -1
package/dist/index.js
CHANGED
|
@@ -12790,6 +12790,34 @@ var useInput = ink.useInput;
|
|
|
12790
12790
|
// src/react-ink/theme-adapter.ts
|
|
12791
12791
|
import chalk from "chalk";
|
|
12792
12792
|
import stripAnsi from "strip-ansi";
|
|
12793
|
+
var DEFAULT_ROLE_KEYS = {
|
|
12794
|
+
codeInline: "codeInline",
|
|
12795
|
+
heading: "heading",
|
|
12796
|
+
blockquoteBar: "blockquoteBar",
|
|
12797
|
+
diffAddedBg: "diffAddedBg",
|
|
12798
|
+
diffRemovedBg: "diffRemovedBg",
|
|
12799
|
+
diffAddedText: "diffAddedText",
|
|
12800
|
+
diffRemovedText: "diffRemovedText",
|
|
12801
|
+
synKeyword: "synKeyword",
|
|
12802
|
+
synString: "synString",
|
|
12803
|
+
synNumber: "synNumber",
|
|
12804
|
+
synComment: "synComment",
|
|
12805
|
+
synType: "synType"
|
|
12806
|
+
};
|
|
12807
|
+
var ROLE_FALLBACK_KEYS = {
|
|
12808
|
+
codeInline: "accent",
|
|
12809
|
+
heading: "accent",
|
|
12810
|
+
blockquoteBar: "muted",
|
|
12811
|
+
diffAddedBg: "success",
|
|
12812
|
+
diffRemovedBg: "error",
|
|
12813
|
+
diffAddedText: "success",
|
|
12814
|
+
diffRemovedText: "error",
|
|
12815
|
+
synKeyword: "accent",
|
|
12816
|
+
synString: "success",
|
|
12817
|
+
synNumber: "warning",
|
|
12818
|
+
synComment: "muted",
|
|
12819
|
+
synType: "info"
|
|
12820
|
+
};
|
|
12793
12821
|
function applyForeground(color, text) {
|
|
12794
12822
|
if (!color) return text;
|
|
12795
12823
|
try {
|
|
@@ -12816,15 +12844,27 @@ function applyBackground(background, foreground, text) {
|
|
|
12816
12844
|
return applyForeground(foreground, text);
|
|
12817
12845
|
}
|
|
12818
12846
|
}
|
|
12819
|
-
function createThemeAdapter(themeName, colors) {
|
|
12847
|
+
function createThemeAdapter(themeName, colors, roleOverrides) {
|
|
12820
12848
|
const fallback = colors.text ?? "#e5e5e7";
|
|
12849
|
+
const roles = { ...DEFAULT_ROLE_KEYS, ...roleOverrides };
|
|
12850
|
+
const resolveRoleColor = (role) => resolveColorToken(
|
|
12851
|
+
colors[roles[role]],
|
|
12852
|
+
resolveColorToken(colors[ROLE_FALLBACK_KEYS[role]], fallback)
|
|
12853
|
+
);
|
|
12821
12854
|
return {
|
|
12822
12855
|
name: themeName,
|
|
12823
12856
|
colors,
|
|
12857
|
+
roles,
|
|
12824
12858
|
color: (key, text) => applyForeground(resolveColorToken(colors[key], fallback), text),
|
|
12825
12859
|
background: (key, text, textKey = "text") => applyBackground(resolveColorToken(colors[key]), resolveColorToken(colors[textKey], fallback), ` ${stripAnsi(text)} `),
|
|
12826
12860
|
dim: (text) => applyForeground(resolveColorToken(colors.dim, "#666666"), text),
|
|
12827
|
-
muted: (text) => applyForeground(resolveColorToken(colors.muted, "#808080"), text)
|
|
12861
|
+
muted: (text) => applyForeground(resolveColorToken(colors.muted, "#808080"), text),
|
|
12862
|
+
role: (role, text) => applyForeground(resolveRoleColor(role), text),
|
|
12863
|
+
roleBackground: (role, text, foregroundRole) => applyBackground(
|
|
12864
|
+
resolveRoleColor(role),
|
|
12865
|
+
foregroundRole ? resolveRoleColor(foregroundRole) : void 0,
|
|
12866
|
+
text
|
|
12867
|
+
)
|
|
12828
12868
|
};
|
|
12829
12869
|
}
|
|
12830
12870
|
|
|
@@ -13209,8 +13249,1120 @@ function parseSkillInvocation(content) {
|
|
|
13209
13249
|
};
|
|
13210
13250
|
}
|
|
13211
13251
|
|
|
13252
|
+
// src/react-ink/markdown/format-token.ts
|
|
13253
|
+
import chalk2 from "chalk";
|
|
13254
|
+
import { marked } from "marked";
|
|
13255
|
+
import stripAnsi3 from "strip-ansi";
|
|
13256
|
+
|
|
13257
|
+
// src/ui/utils.ts
|
|
13258
|
+
import { eastAsianWidth } from "get-east-asian-width";
|
|
13259
|
+
var segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
13260
|
+
var TextWidthCalculator = class {
|
|
13261
|
+
getWidth(text) {
|
|
13262
|
+
return visibleWidth(text);
|
|
13263
|
+
}
|
|
13264
|
+
clearCache() {
|
|
13265
|
+
widthCache.clear();
|
|
13266
|
+
}
|
|
13267
|
+
};
|
|
13268
|
+
var textWidthCalculator = new TextWidthCalculator();
|
|
13269
|
+
function looksLikeEmojiCandidate(segment) {
|
|
13270
|
+
const cp = segment.codePointAt(0);
|
|
13271
|
+
return cp >= 126976 && cp <= 130047 || // pictographs and emoji proper
|
|
13272
|
+
cp >= 8960 && cp <= 9215 || // miscellaneous technical glyphs
|
|
13273
|
+
cp >= 9728 && cp <= 10175 || // assorted symbols and dingbats
|
|
13274
|
+
cp >= 11088 && cp <= 11093 || // a few star/circle characters
|
|
13275
|
+
segment.includes("\uFE0F") || // carries VS16, the emoji-presentation selector
|
|
13276
|
+
segment.length > 2;
|
|
13277
|
+
}
|
|
13278
|
+
function createUnicodeRegex(vPattern, uFallback) {
|
|
13279
|
+
try {
|
|
13280
|
+
return new RegExp(vPattern, "v");
|
|
13281
|
+
} catch {
|
|
13282
|
+
return new RegExp(uFallback, "u");
|
|
13283
|
+
}
|
|
13284
|
+
}
|
|
13285
|
+
var zeroWidthRegex = createUnicodeRegex(
|
|
13286
|
+
"^(?:\\p{Default_Ignorable_Code_Point}|\\p{Control}|\\p{Mark}|\\p{Surrogate})+$",
|
|
13287
|
+
"^(?:\\p{Default_Ignorable_Code_Point}|\\p{Control}|\\p{Mark}|\\p{Surrogate})+$"
|
|
13288
|
+
);
|
|
13289
|
+
var leadingNonPrintingRegex = createUnicodeRegex(
|
|
13290
|
+
"^[\\p{Default_Ignorable_Code_Point}\\p{Control}\\p{Format}\\p{Mark}\\p{Surrogate}]+",
|
|
13291
|
+
"^[\\p{Default_Ignorable_Code_Point}\\p{Control}\\p{Format}\\p{Mark}\\p{Surrogate}]+"
|
|
13292
|
+
);
|
|
13293
|
+
var rgiEmojiRegex = createUnicodeRegex("^\\p{RGI_Emoji}$", "^\\p{Extended_Pictographic}$");
|
|
13294
|
+
var AnsiStripper = {
|
|
13295
|
+
strip(text) {
|
|
13296
|
+
if (!text.includes("\x1B")) {
|
|
13297
|
+
return text;
|
|
13298
|
+
}
|
|
13299
|
+
let cleaned = text;
|
|
13300
|
+
cleaned = cleaned.replace(/\x1b\[[0-9;]*[mGKHJ]/g, "");
|
|
13301
|
+
cleaned = cleaned.replace(/\x1b\]8;;[^\x07]*\x07/g, "");
|
|
13302
|
+
cleaned = cleaned.replace(/\x1b_[^\x07\x1b]*(?:\x07|\x1b\\)/g, "");
|
|
13303
|
+
return cleaned;
|
|
13304
|
+
}
|
|
13305
|
+
};
|
|
13306
|
+
var WIDTH_CACHE_SIZE = 512;
|
|
13307
|
+
var widthCache = /* @__PURE__ */ new Map();
|
|
13308
|
+
function measureClusterWidth(segment) {
|
|
13309
|
+
if (zeroWidthRegex.test(segment)) {
|
|
13310
|
+
return 0;
|
|
13311
|
+
}
|
|
13312
|
+
if (looksLikeEmojiCandidate(segment) && rgiEmojiRegex.test(segment)) {
|
|
13313
|
+
return 2;
|
|
13314
|
+
}
|
|
13315
|
+
const base = segment.replace(leadingNonPrintingRegex, "");
|
|
13316
|
+
const cp = base.codePointAt(0);
|
|
13317
|
+
if (cp === void 0) {
|
|
13318
|
+
return 0;
|
|
13319
|
+
}
|
|
13320
|
+
let width = eastAsianWidth(cp);
|
|
13321
|
+
if (segment.length > 1) {
|
|
13322
|
+
for (const char of segment.slice(1)) {
|
|
13323
|
+
const c = char.codePointAt(0);
|
|
13324
|
+
if (c >= 65280 && c <= 65519) {
|
|
13325
|
+
width += eastAsianWidth(c);
|
|
13326
|
+
}
|
|
13327
|
+
}
|
|
13328
|
+
}
|
|
13329
|
+
return width;
|
|
13330
|
+
}
|
|
13331
|
+
function visibleWidth(str2) {
|
|
13332
|
+
if (str2.length === 0) {
|
|
13333
|
+
return 0;
|
|
13334
|
+
}
|
|
13335
|
+
let isPureAscii = true;
|
|
13336
|
+
for (let i = 0; i < str2.length; i++) {
|
|
13337
|
+
const code = str2.charCodeAt(i);
|
|
13338
|
+
if (code < 32 || code > 126) {
|
|
13339
|
+
isPureAscii = false;
|
|
13340
|
+
break;
|
|
13341
|
+
}
|
|
13342
|
+
}
|
|
13343
|
+
if (isPureAscii) {
|
|
13344
|
+
return str2.length;
|
|
13345
|
+
}
|
|
13346
|
+
const cached = widthCache.get(str2);
|
|
13347
|
+
if (cached !== void 0) {
|
|
13348
|
+
return cached;
|
|
13349
|
+
}
|
|
13350
|
+
let clean = str2;
|
|
13351
|
+
if (str2.includes(" ")) {
|
|
13352
|
+
clean = clean.replace(/\t/g, " ");
|
|
13353
|
+
}
|
|
13354
|
+
clean = AnsiStripper.strip(clean);
|
|
13355
|
+
let width = 0;
|
|
13356
|
+
for (const { segment } of segmenter.segment(clean)) {
|
|
13357
|
+
width += measureClusterWidth(segment);
|
|
13358
|
+
}
|
|
13359
|
+
if (widthCache.size >= WIDTH_CACHE_SIZE) {
|
|
13360
|
+
const firstKey = widthCache.keys().next().value;
|
|
13361
|
+
if (firstKey !== void 0) {
|
|
13362
|
+
widthCache.delete(firstKey);
|
|
13363
|
+
}
|
|
13364
|
+
}
|
|
13365
|
+
widthCache.set(str2, width);
|
|
13366
|
+
return width;
|
|
13367
|
+
}
|
|
13368
|
+
function extractAnsiCode(str2, pos) {
|
|
13369
|
+
if (pos >= str2.length || str2[pos] !== "\x1B") return null;
|
|
13370
|
+
const next = str2[pos + 1];
|
|
13371
|
+
if (next === "[") {
|
|
13372
|
+
let j = pos + 2;
|
|
13373
|
+
while (j < str2.length && !/[mGKHJ]/.test(str2[j])) j++;
|
|
13374
|
+
if (j < str2.length) return { code: str2.substring(pos, j + 1), length: j + 1 - pos };
|
|
13375
|
+
return null;
|
|
13376
|
+
}
|
|
13377
|
+
if (next === "]") {
|
|
13378
|
+
let j = pos + 2;
|
|
13379
|
+
while (j < str2.length) {
|
|
13380
|
+
if (str2[j] === "\x07") return { code: str2.substring(pos, j + 1), length: j + 1 - pos };
|
|
13381
|
+
if (str2[j] === "\x1B" && str2[j + 1] === "\\") return { code: str2.substring(pos, j + 2), length: j + 2 - pos };
|
|
13382
|
+
j++;
|
|
13383
|
+
}
|
|
13384
|
+
return null;
|
|
13385
|
+
}
|
|
13386
|
+
if (next === "_") {
|
|
13387
|
+
let j = pos + 2;
|
|
13388
|
+
while (j < str2.length) {
|
|
13389
|
+
if (str2[j] === "\x07") return { code: str2.substring(pos, j + 1), length: j + 1 - pos };
|
|
13390
|
+
if (str2[j] === "\x1B" && str2[j + 1] === "\\") return { code: str2.substring(pos, j + 2), length: j + 2 - pos };
|
|
13391
|
+
j++;
|
|
13392
|
+
}
|
|
13393
|
+
return null;
|
|
13394
|
+
}
|
|
13395
|
+
return null;
|
|
13396
|
+
}
|
|
13397
|
+
var AnsiStateTracker = class {
|
|
13398
|
+
// Each attribute is kept on its own flag, which lets us clear them one at a time.
|
|
13399
|
+
_bold = false;
|
|
13400
|
+
_dim = false;
|
|
13401
|
+
italic = false;
|
|
13402
|
+
underline = false;
|
|
13403
|
+
blink = false;
|
|
13404
|
+
inverse = false;
|
|
13405
|
+
hidden = false;
|
|
13406
|
+
strikethrough = false;
|
|
13407
|
+
_colors = { fg: null, bg: null };
|
|
13408
|
+
process(ansiCode) {
|
|
13409
|
+
if (!ansiCode.endsWith("m")) {
|
|
13410
|
+
return;
|
|
13411
|
+
}
|
|
13412
|
+
const match = ansiCode.match(/\x1b\[([\d;]*)m/);
|
|
13413
|
+
if (!match) return;
|
|
13414
|
+
const params = match[1];
|
|
13415
|
+
if (params === "" || params === "0") {
|
|
13416
|
+
this.reset();
|
|
13417
|
+
return;
|
|
13418
|
+
}
|
|
13419
|
+
const parts = params.split(";");
|
|
13420
|
+
let i = 0;
|
|
13421
|
+
while (i < parts.length) {
|
|
13422
|
+
const code = Number.parseInt(parts[i] ?? "", 10);
|
|
13423
|
+
if (Number.isNaN(code)) {
|
|
13424
|
+
i++;
|
|
13425
|
+
continue;
|
|
13426
|
+
}
|
|
13427
|
+
const consumed = this.tryConsumeColorCode(parts, i, code);
|
|
13428
|
+
if (consumed > 0) {
|
|
13429
|
+
i += consumed;
|
|
13430
|
+
continue;
|
|
13431
|
+
}
|
|
13432
|
+
this.applyStandardCode(code);
|
|
13433
|
+
i++;
|
|
13434
|
+
}
|
|
13435
|
+
}
|
|
13436
|
+
tryConsumeColorCode(parts, index, code) {
|
|
13437
|
+
if (code !== 38 && code !== 48) {
|
|
13438
|
+
return 0;
|
|
13439
|
+
}
|
|
13440
|
+
if (parts[index + 1] === "5" && parts[index + 2] !== void 0) {
|
|
13441
|
+
const colorCode = `${parts[index]};${parts[index + 1]};${parts[index + 2]}`;
|
|
13442
|
+
if (code === 38) {
|
|
13443
|
+
this._colors.fg = colorCode;
|
|
13444
|
+
} else {
|
|
13445
|
+
this._colors.bg = colorCode;
|
|
13446
|
+
}
|
|
13447
|
+
return 3;
|
|
13448
|
+
}
|
|
13449
|
+
if (parts[index + 1] === "2" && parts[index + 4] !== void 0) {
|
|
13450
|
+
const colorCode = `${parts[index]};${parts[index + 1]};${parts[index + 2]};${parts[index + 3]};${parts[index + 4]}`;
|
|
13451
|
+
if (code === 38) {
|
|
13452
|
+
this._colors.fg = colorCode;
|
|
13453
|
+
} else {
|
|
13454
|
+
this._colors.bg = colorCode;
|
|
13455
|
+
}
|
|
13456
|
+
return 5;
|
|
13457
|
+
}
|
|
13458
|
+
return 0;
|
|
13459
|
+
}
|
|
13460
|
+
applyStandardCode(code) {
|
|
13461
|
+
switch (code) {
|
|
13462
|
+
case 0:
|
|
13463
|
+
this.reset();
|
|
13464
|
+
return;
|
|
13465
|
+
case 1:
|
|
13466
|
+
this._bold = true;
|
|
13467
|
+
return;
|
|
13468
|
+
case 2:
|
|
13469
|
+
this._dim = true;
|
|
13470
|
+
return;
|
|
13471
|
+
case 3:
|
|
13472
|
+
this.italic = true;
|
|
13473
|
+
return;
|
|
13474
|
+
case 4:
|
|
13475
|
+
this.underline = true;
|
|
13476
|
+
return;
|
|
13477
|
+
case 5:
|
|
13478
|
+
this.blink = true;
|
|
13479
|
+
return;
|
|
13480
|
+
case 7:
|
|
13481
|
+
this.inverse = true;
|
|
13482
|
+
return;
|
|
13483
|
+
case 8:
|
|
13484
|
+
this.hidden = true;
|
|
13485
|
+
return;
|
|
13486
|
+
case 9:
|
|
13487
|
+
this.strikethrough = true;
|
|
13488
|
+
return;
|
|
13489
|
+
case 21:
|
|
13490
|
+
this._bold = false;
|
|
13491
|
+
return;
|
|
13492
|
+
case 22:
|
|
13493
|
+
this._bold = false;
|
|
13494
|
+
this._dim = false;
|
|
13495
|
+
return;
|
|
13496
|
+
case 23:
|
|
13497
|
+
this.italic = false;
|
|
13498
|
+
return;
|
|
13499
|
+
case 24:
|
|
13500
|
+
this.underline = false;
|
|
13501
|
+
return;
|
|
13502
|
+
case 25:
|
|
13503
|
+
this.blink = false;
|
|
13504
|
+
return;
|
|
13505
|
+
case 27:
|
|
13506
|
+
this.inverse = false;
|
|
13507
|
+
return;
|
|
13508
|
+
case 28:
|
|
13509
|
+
this.hidden = false;
|
|
13510
|
+
return;
|
|
13511
|
+
case 29:
|
|
13512
|
+
this.strikethrough = false;
|
|
13513
|
+
return;
|
|
13514
|
+
case 39:
|
|
13515
|
+
this._colors.fg = null;
|
|
13516
|
+
return;
|
|
13517
|
+
case 49:
|
|
13518
|
+
this._colors.bg = null;
|
|
13519
|
+
return;
|
|
13520
|
+
default:
|
|
13521
|
+
if (code >= 30 && code <= 37 || code >= 90 && code <= 97) {
|
|
13522
|
+
this._colors.fg = String(code);
|
|
13523
|
+
return;
|
|
13524
|
+
}
|
|
13525
|
+
if (code >= 40 && code <= 47 || code >= 100 && code <= 107) {
|
|
13526
|
+
this._colors.bg = String(code);
|
|
13527
|
+
}
|
|
13528
|
+
}
|
|
13529
|
+
}
|
|
13530
|
+
reset() {
|
|
13531
|
+
this._bold = false;
|
|
13532
|
+
this._dim = false;
|
|
13533
|
+
this.italic = false;
|
|
13534
|
+
this.underline = false;
|
|
13535
|
+
this.blink = false;
|
|
13536
|
+
this.inverse = false;
|
|
13537
|
+
this.hidden = false;
|
|
13538
|
+
this.strikethrough = false;
|
|
13539
|
+
this._colors.fg = null;
|
|
13540
|
+
this._colors.bg = null;
|
|
13541
|
+
}
|
|
13542
|
+
/** Wipe all tracked state so the instance can be reused. */
|
|
13543
|
+
clear() {
|
|
13544
|
+
this.reset();
|
|
13545
|
+
}
|
|
13546
|
+
getActiveCodes() {
|
|
13547
|
+
const codes = [];
|
|
13548
|
+
if (this._bold) codes.push("1");
|
|
13549
|
+
if (this._dim) codes.push("2");
|
|
13550
|
+
if (this.italic) codes.push("3");
|
|
13551
|
+
if (this.underline) codes.push("4");
|
|
13552
|
+
if (this.blink) codes.push("5");
|
|
13553
|
+
if (this.inverse) codes.push("7");
|
|
13554
|
+
if (this.hidden) codes.push("8");
|
|
13555
|
+
if (this.strikethrough) codes.push("9");
|
|
13556
|
+
if (this._colors.fg) codes.push(this._colors.fg);
|
|
13557
|
+
if (this._colors.bg) codes.push(this._colors.bg);
|
|
13558
|
+
if (codes.length === 0) return "";
|
|
13559
|
+
return `\x1B[${codes.join(";")}m`;
|
|
13560
|
+
}
|
|
13561
|
+
hasActiveCodes() {
|
|
13562
|
+
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;
|
|
13563
|
+
}
|
|
13564
|
+
/**
|
|
13565
|
+
* Produce the escape code needed to switch off any attribute that would
|
|
13566
|
+
* otherwise smear into the padding at the end of a line. In practice that
|
|
13567
|
+
* is just underline. Yields an empty string when nothing needs disabling.
|
|
13568
|
+
*/
|
|
13569
|
+
getLineEndReset() {
|
|
13570
|
+
if (this.underline) {
|
|
13571
|
+
return "\x1B[24m";
|
|
13572
|
+
}
|
|
13573
|
+
return "";
|
|
13574
|
+
}
|
|
13575
|
+
};
|
|
13576
|
+
function mergeTextIntoTracker(text, tracker) {
|
|
13577
|
+
let i = 0;
|
|
13578
|
+
while (i < text.length) {
|
|
13579
|
+
const ansiResult = extractAnsiCode(text, i);
|
|
13580
|
+
if (ansiResult) {
|
|
13581
|
+
tracker.process(ansiResult.code);
|
|
13582
|
+
i += ansiResult.length;
|
|
13583
|
+
} else {
|
|
13584
|
+
i++;
|
|
13585
|
+
}
|
|
13586
|
+
}
|
|
13587
|
+
}
|
|
13588
|
+
function tokenizeTextWithAnsi(text) {
|
|
13589
|
+
const tokens = [];
|
|
13590
|
+
let current = "";
|
|
13591
|
+
let pendingAnsi = "";
|
|
13592
|
+
let inWhitespace = false;
|
|
13593
|
+
let i = 0;
|
|
13594
|
+
while (i < text.length) {
|
|
13595
|
+
const ansiResult = extractAnsiCode(text, i);
|
|
13596
|
+
if (ansiResult) {
|
|
13597
|
+
pendingAnsi += ansiResult.code;
|
|
13598
|
+
i += ansiResult.length;
|
|
13599
|
+
continue;
|
|
13600
|
+
}
|
|
13601
|
+
const char = text[i];
|
|
13602
|
+
const charIsSpace = char === " ";
|
|
13603
|
+
if (charIsSpace !== inWhitespace && current) {
|
|
13604
|
+
tokens.push(current);
|
|
13605
|
+
current = "";
|
|
13606
|
+
}
|
|
13607
|
+
if (pendingAnsi) {
|
|
13608
|
+
current += pendingAnsi;
|
|
13609
|
+
pendingAnsi = "";
|
|
13610
|
+
}
|
|
13611
|
+
inWhitespace = charIsSpace;
|
|
13612
|
+
current += char;
|
|
13613
|
+
i++;
|
|
13614
|
+
}
|
|
13615
|
+
if (pendingAnsi) {
|
|
13616
|
+
current += pendingAnsi;
|
|
13617
|
+
}
|
|
13618
|
+
if (current) {
|
|
13619
|
+
tokens.push(current);
|
|
13620
|
+
}
|
|
13621
|
+
return tokens;
|
|
13622
|
+
}
|
|
13623
|
+
var TextWrapper = class {
|
|
13624
|
+
wrap(text, width) {
|
|
13625
|
+
return wrapTextWithAnsi(text, width);
|
|
13626
|
+
}
|
|
13627
|
+
};
|
|
13628
|
+
var textWrapper = new TextWrapper();
|
|
13629
|
+
var TokenWrapEngine = {
|
|
13630
|
+
wrap(tokens, width, tracker) {
|
|
13631
|
+
const wrapped = [];
|
|
13632
|
+
let currentLine = "";
|
|
13633
|
+
let currentVisibleLength = 0;
|
|
13634
|
+
for (const token of tokens) {
|
|
13635
|
+
const tokenVisibleLength = visibleWidth(token);
|
|
13636
|
+
const isWhitespace = token.trim() === "";
|
|
13637
|
+
if (tokenVisibleLength > width && !isWhitespace) {
|
|
13638
|
+
if (currentLine) {
|
|
13639
|
+
const lineEndReset = tracker.getLineEndReset();
|
|
13640
|
+
if (lineEndReset) {
|
|
13641
|
+
currentLine += lineEndReset;
|
|
13642
|
+
}
|
|
13643
|
+
wrapped.push(currentLine);
|
|
13644
|
+
currentLine = "";
|
|
13645
|
+
currentVisibleLength = 0;
|
|
13646
|
+
}
|
|
13647
|
+
const broken = splitLongToken(token, width, tracker);
|
|
13648
|
+
wrapped.push(...broken.slice(0, -1));
|
|
13649
|
+
currentLine = broken[broken.length - 1];
|
|
13650
|
+
currentVisibleLength = visibleWidth(currentLine);
|
|
13651
|
+
continue;
|
|
13652
|
+
}
|
|
13653
|
+
const totalNeeded = currentVisibleLength + tokenVisibleLength;
|
|
13654
|
+
if (totalNeeded > width && currentVisibleLength > 0) {
|
|
13655
|
+
let lineToWrap = currentLine.trimEnd();
|
|
13656
|
+
const lineEndReset = tracker.getLineEndReset();
|
|
13657
|
+
if (lineEndReset) {
|
|
13658
|
+
lineToWrap += lineEndReset;
|
|
13659
|
+
}
|
|
13660
|
+
wrapped.push(lineToWrap);
|
|
13661
|
+
if (isWhitespace) {
|
|
13662
|
+
currentLine = tracker.getActiveCodes();
|
|
13663
|
+
currentVisibleLength = 0;
|
|
13664
|
+
} else {
|
|
13665
|
+
currentLine = tracker.getActiveCodes() + token;
|
|
13666
|
+
currentVisibleLength = tokenVisibleLength;
|
|
13667
|
+
}
|
|
13668
|
+
} else {
|
|
13669
|
+
currentLine += token;
|
|
13670
|
+
currentVisibleLength += tokenVisibleLength;
|
|
13671
|
+
}
|
|
13672
|
+
mergeTextIntoTracker(token, tracker);
|
|
13673
|
+
}
|
|
13674
|
+
return { wrapped, currentLine, currentVisibleLength };
|
|
13675
|
+
}
|
|
13676
|
+
};
|
|
13677
|
+
function wrapTextWithAnsi(text, width) {
|
|
13678
|
+
if (!text) {
|
|
13679
|
+
return [""];
|
|
13680
|
+
}
|
|
13681
|
+
const inputLines = text.split("\n");
|
|
13682
|
+
const result = [];
|
|
13683
|
+
const tracker = new AnsiStateTracker();
|
|
13684
|
+
for (const inputLine of inputLines) {
|
|
13685
|
+
const prefix = result.length > 0 ? tracker.getActiveCodes() : "";
|
|
13686
|
+
result.push(...wrapLinePreservingAnsi(prefix + inputLine, width));
|
|
13687
|
+
mergeTextIntoTracker(inputLine, tracker);
|
|
13688
|
+
}
|
|
13689
|
+
return result.length > 0 ? result : [""];
|
|
13690
|
+
}
|
|
13691
|
+
function wrapLinePreservingAnsi(line4, width) {
|
|
13692
|
+
if (!line4) {
|
|
13693
|
+
return [""];
|
|
13694
|
+
}
|
|
13695
|
+
const visibleLength = visibleWidth(line4);
|
|
13696
|
+
if (visibleLength <= width) {
|
|
13697
|
+
return [line4];
|
|
13698
|
+
}
|
|
13699
|
+
const tracker = new AnsiStateTracker();
|
|
13700
|
+
const tokens = tokenizeTextWithAnsi(line4);
|
|
13701
|
+
const { wrapped, currentLine } = TokenWrapEngine.wrap(tokens, width, tracker);
|
|
13702
|
+
if (currentLine) {
|
|
13703
|
+
wrapped.push(currentLine);
|
|
13704
|
+
}
|
|
13705
|
+
return wrapped.length > 0 ? wrapped.map((segmentLine) => segmentLine.trimEnd()) : [""];
|
|
13706
|
+
}
|
|
13707
|
+
function splitLongToken(word, width, tracker) {
|
|
13708
|
+
const lines = [];
|
|
13709
|
+
let currentLine = tracker.getActiveCodes();
|
|
13710
|
+
let currentWidth = 0;
|
|
13711
|
+
let i = 0;
|
|
13712
|
+
const segments = [];
|
|
13713
|
+
while (i < word.length) {
|
|
13714
|
+
const ansiResult = extractAnsiCode(word, i);
|
|
13715
|
+
if (ansiResult) {
|
|
13716
|
+
segments.push({ type: "ansi", value: ansiResult.code });
|
|
13717
|
+
i += ansiResult.length;
|
|
13718
|
+
} else {
|
|
13719
|
+
let end = i;
|
|
13720
|
+
while (end < word.length) {
|
|
13721
|
+
const nextAnsi = extractAnsiCode(word, end);
|
|
13722
|
+
if (nextAnsi) break;
|
|
13723
|
+
end++;
|
|
13724
|
+
}
|
|
13725
|
+
const textPortion = word.slice(i, end);
|
|
13726
|
+
for (const seg of segmenter.segment(textPortion)) {
|
|
13727
|
+
segments.push({ type: "grapheme", value: seg.segment });
|
|
13728
|
+
}
|
|
13729
|
+
i = end;
|
|
13730
|
+
}
|
|
13731
|
+
}
|
|
13732
|
+
for (const seg of segments) {
|
|
13733
|
+
if (seg.type === "ansi") {
|
|
13734
|
+
currentLine += seg.value;
|
|
13735
|
+
tracker.process(seg.value);
|
|
13736
|
+
continue;
|
|
13737
|
+
}
|
|
13738
|
+
const grapheme = seg.value;
|
|
13739
|
+
if (!grapheme) continue;
|
|
13740
|
+
const clusterWidth = visibleWidth(grapheme);
|
|
13741
|
+
if (currentWidth + clusterWidth > width) {
|
|
13742
|
+
const lineEndReset = tracker.getLineEndReset();
|
|
13743
|
+
if (lineEndReset) {
|
|
13744
|
+
currentLine += lineEndReset;
|
|
13745
|
+
}
|
|
13746
|
+
lines.push(currentLine);
|
|
13747
|
+
currentLine = tracker.getActiveCodes();
|
|
13748
|
+
currentWidth = 0;
|
|
13749
|
+
}
|
|
13750
|
+
currentLine += grapheme;
|
|
13751
|
+
currentWidth += clusterWidth;
|
|
13752
|
+
}
|
|
13753
|
+
if (currentLine) {
|
|
13754
|
+
lines.push(currentLine);
|
|
13755
|
+
}
|
|
13756
|
+
return lines.length > 0 ? lines : [""];
|
|
13757
|
+
}
|
|
13758
|
+
var pooledStyleTracker = new AnsiStateTracker();
|
|
13759
|
+
|
|
13760
|
+
// src/react-ink/markdown/format-token.ts
|
|
13761
|
+
var EOL = "\n";
|
|
13762
|
+
var BLOCKQUOTE_BAR = "\u2502";
|
|
13763
|
+
var markedConfigured = false;
|
|
13764
|
+
function configureMarked() {
|
|
13765
|
+
if (markedConfigured) {
|
|
13766
|
+
return;
|
|
13767
|
+
}
|
|
13768
|
+
markedConfigured = true;
|
|
13769
|
+
marked.use({
|
|
13770
|
+
tokenizer: {
|
|
13771
|
+
del() {
|
|
13772
|
+
return void 0;
|
|
13773
|
+
}
|
|
13774
|
+
}
|
|
13775
|
+
});
|
|
13776
|
+
}
|
|
13777
|
+
var TOKEN_CACHE_MAX = 500;
|
|
13778
|
+
var tokenCache = /* @__PURE__ */ new Map();
|
|
13779
|
+
var MD_SYNTAX_RE = /[#*`|[>\-_~]|\n\n|^\d+\. |\n\d+\. /;
|
|
13780
|
+
function hasMarkdownSyntax(text) {
|
|
13781
|
+
return MD_SYNTAX_RE.test(text.length > 500 ? text.slice(0, 500) : text);
|
|
13782
|
+
}
|
|
13783
|
+
function hashContent(content) {
|
|
13784
|
+
let hash = 2166136261;
|
|
13785
|
+
for (let i = 0; i < content.length; i++) {
|
|
13786
|
+
hash ^= content.charCodeAt(i);
|
|
13787
|
+
hash = Math.imul(hash, 16777619);
|
|
13788
|
+
}
|
|
13789
|
+
return (hash >>> 0).toString(36) + ":" + content.length.toString(36);
|
|
13790
|
+
}
|
|
13791
|
+
function cachedLexer(content) {
|
|
13792
|
+
configureMarked();
|
|
13793
|
+
if (!hasMarkdownSyntax(content)) {
|
|
13794
|
+
return [
|
|
13795
|
+
{
|
|
13796
|
+
type: "paragraph",
|
|
13797
|
+
raw: content,
|
|
13798
|
+
text: content,
|
|
13799
|
+
tokens: [{ type: "text", raw: content, text: content }]
|
|
13800
|
+
}
|
|
13801
|
+
];
|
|
13802
|
+
}
|
|
13803
|
+
const key = hashContent(content);
|
|
13804
|
+
const hit = tokenCache.get(key);
|
|
13805
|
+
if (hit) {
|
|
13806
|
+
tokenCache.delete(key);
|
|
13807
|
+
tokenCache.set(key, hit);
|
|
13808
|
+
return hit;
|
|
13809
|
+
}
|
|
13810
|
+
const tokens = marked.lexer(content);
|
|
13811
|
+
if (tokenCache.size >= TOKEN_CACHE_MAX) {
|
|
13812
|
+
const first = tokenCache.keys().next().value;
|
|
13813
|
+
if (first !== void 0) {
|
|
13814
|
+
tokenCache.delete(first);
|
|
13815
|
+
}
|
|
13816
|
+
}
|
|
13817
|
+
tokenCache.set(key, tokens);
|
|
13818
|
+
return tokens;
|
|
13819
|
+
}
|
|
13820
|
+
function formatToken(token, theme, highlight = null, listDepth = 0, orderedListNumber = null, parent = null) {
|
|
13821
|
+
switch (token.type) {
|
|
13822
|
+
case "blockquote": {
|
|
13823
|
+
const inner = (token.tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("");
|
|
13824
|
+
const bar = theme.dim(BLOCKQUOTE_BAR);
|
|
13825
|
+
return inner.split(EOL).map((line4) => stripAnsi3(line4).trim() ? `${bar} ${chalk2.italic(line4)}` : line4).join(EOL);
|
|
13826
|
+
}
|
|
13827
|
+
case "code": {
|
|
13828
|
+
const codeToken = token;
|
|
13829
|
+
if (!highlight) {
|
|
13830
|
+
return codeToken.text + EOL;
|
|
13831
|
+
}
|
|
13832
|
+
let language = "plaintext";
|
|
13833
|
+
if (codeToken.lang && highlight.supportsLanguage(codeToken.lang)) {
|
|
13834
|
+
language = codeToken.lang;
|
|
13835
|
+
}
|
|
13836
|
+
return highlight.highlight(codeToken.text, { language }) + EOL;
|
|
13837
|
+
}
|
|
13838
|
+
case "codespan":
|
|
13839
|
+
return theme.role("codeInline", token.text);
|
|
13840
|
+
case "em":
|
|
13841
|
+
return chalk2.italic(
|
|
13842
|
+
(token.tokens ?? []).map((child) => formatToken(child, theme, highlight, 0, null, parent)).join("")
|
|
13843
|
+
);
|
|
13844
|
+
case "strong":
|
|
13845
|
+
return chalk2.bold(
|
|
13846
|
+
(token.tokens ?? []).map((child) => formatToken(child, theme, highlight, 0, null, parent)).join("")
|
|
13847
|
+
);
|
|
13848
|
+
case "heading": {
|
|
13849
|
+
const headingToken = token;
|
|
13850
|
+
const inner = (headingToken.tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("");
|
|
13851
|
+
const colored = theme.role("heading", inner);
|
|
13852
|
+
if (headingToken.depth === 1) {
|
|
13853
|
+
return chalk2.bold.italic.underline(colored) + EOL + EOL;
|
|
13854
|
+
}
|
|
13855
|
+
return chalk2.bold(colored) + EOL + EOL;
|
|
13856
|
+
}
|
|
13857
|
+
case "hr":
|
|
13858
|
+
return "---";
|
|
13859
|
+
case "image":
|
|
13860
|
+
return token.href;
|
|
13861
|
+
case "link": {
|
|
13862
|
+
const linkToken = token;
|
|
13863
|
+
if (linkToken.href.startsWith("mailto:")) {
|
|
13864
|
+
return linkToken.href.replace(/^mailto:/, "");
|
|
13865
|
+
}
|
|
13866
|
+
const linkText = (linkToken.tokens ?? []).map((child) => formatToken(child, theme, highlight, 0, null, linkToken)).join("");
|
|
13867
|
+
const plainLinkText = stripAnsi3(linkText);
|
|
13868
|
+
const display = plainLinkText && plainLinkText !== linkToken.href ? linkText : linkToken.href;
|
|
13869
|
+
return `\x1B]8;;${linkToken.href}\x07${display}\x1B]8;;\x07`;
|
|
13870
|
+
}
|
|
13871
|
+
case "list": {
|
|
13872
|
+
const listToken = token;
|
|
13873
|
+
const start = typeof listToken.start === "number" ? listToken.start : Number(listToken.start) || 1;
|
|
13874
|
+
return listToken.items.map(
|
|
13875
|
+
(item, index) => formatToken(
|
|
13876
|
+
item,
|
|
13877
|
+
theme,
|
|
13878
|
+
highlight,
|
|
13879
|
+
listDepth,
|
|
13880
|
+
listToken.ordered ? start + index : null,
|
|
13881
|
+
listToken
|
|
13882
|
+
)
|
|
13883
|
+
).join("");
|
|
13884
|
+
}
|
|
13885
|
+
case "list_item":
|
|
13886
|
+
return (token.tokens ?? []).map(
|
|
13887
|
+
(child) => `${" ".repeat(listDepth)}${formatToken(child, theme, highlight, listDepth + 1, orderedListNumber, token)}`
|
|
13888
|
+
).join("");
|
|
13889
|
+
case "paragraph":
|
|
13890
|
+
return (token.tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("") + EOL;
|
|
13891
|
+
case "space":
|
|
13892
|
+
case "br":
|
|
13893
|
+
return EOL;
|
|
13894
|
+
case "text": {
|
|
13895
|
+
const textToken = token;
|
|
13896
|
+
if (parent?.type === "link") {
|
|
13897
|
+
return textToken.text;
|
|
13898
|
+
}
|
|
13899
|
+
if (parent?.type === "list_item") {
|
|
13900
|
+
const marker = orderedListNumber === null ? "-" : `${getListNumber(listDepth, orderedListNumber)}.`;
|
|
13901
|
+
const body = textToken.tokens ? textToken.tokens.map((child) => formatToken(child, theme, highlight, listDepth, orderedListNumber, token)).join("") : textToken.text;
|
|
13902
|
+
return `${marker} ${body}${EOL}`;
|
|
13903
|
+
}
|
|
13904
|
+
return textToken.text;
|
|
13905
|
+
}
|
|
13906
|
+
case "escape":
|
|
13907
|
+
return token.text;
|
|
13908
|
+
case "table":
|
|
13909
|
+
case "def":
|
|
13910
|
+
case "del":
|
|
13911
|
+
case "html":
|
|
13912
|
+
return "";
|
|
13913
|
+
default:
|
|
13914
|
+
return "";
|
|
13915
|
+
}
|
|
13916
|
+
}
|
|
13917
|
+
function numberToLetter(n) {
|
|
13918
|
+
let result = "";
|
|
13919
|
+
while (n > 0) {
|
|
13920
|
+
n--;
|
|
13921
|
+
result = String.fromCharCode(97 + n % 26) + result;
|
|
13922
|
+
n = Math.floor(n / 26);
|
|
13923
|
+
}
|
|
13924
|
+
return result;
|
|
13925
|
+
}
|
|
13926
|
+
var ROMAN_VALUES = [
|
|
13927
|
+
[1e3, "m"],
|
|
13928
|
+
[900, "cm"],
|
|
13929
|
+
[500, "d"],
|
|
13930
|
+
[400, "cd"],
|
|
13931
|
+
[100, "c"],
|
|
13932
|
+
[90, "xc"],
|
|
13933
|
+
[50, "l"],
|
|
13934
|
+
[40, "xl"],
|
|
13935
|
+
[10, "x"],
|
|
13936
|
+
[9, "ix"],
|
|
13937
|
+
[5, "v"],
|
|
13938
|
+
[4, "iv"],
|
|
13939
|
+
[1, "i"]
|
|
13940
|
+
];
|
|
13941
|
+
function numberToRoman(n) {
|
|
13942
|
+
let result = "";
|
|
13943
|
+
for (const [value, numeral] of ROMAN_VALUES) {
|
|
13944
|
+
while (n >= value) {
|
|
13945
|
+
result += numeral;
|
|
13946
|
+
n -= value;
|
|
13947
|
+
}
|
|
13948
|
+
}
|
|
13949
|
+
return result;
|
|
13950
|
+
}
|
|
13951
|
+
function getListNumber(listDepth, orderedListNumber) {
|
|
13952
|
+
switch (listDepth) {
|
|
13953
|
+
case 0:
|
|
13954
|
+
case 1:
|
|
13955
|
+
return orderedListNumber.toString();
|
|
13956
|
+
case 2:
|
|
13957
|
+
return numberToLetter(orderedListNumber);
|
|
13958
|
+
case 3:
|
|
13959
|
+
return numberToRoman(orderedListNumber);
|
|
13960
|
+
default:
|
|
13961
|
+
return orderedListNumber.toString();
|
|
13962
|
+
}
|
|
13963
|
+
}
|
|
13964
|
+
function padAligned(content, displayWidth, targetWidth, align) {
|
|
13965
|
+
const padding = Math.max(0, targetWidth - displayWidth);
|
|
13966
|
+
if (align === "center") {
|
|
13967
|
+
const leftPad = Math.floor(padding / 2);
|
|
13968
|
+
return " ".repeat(leftPad) + content + " ".repeat(padding - leftPad);
|
|
13969
|
+
}
|
|
13970
|
+
if (align === "right") {
|
|
13971
|
+
return " ".repeat(padding) + content;
|
|
13972
|
+
}
|
|
13973
|
+
return content + " ".repeat(padding);
|
|
13974
|
+
}
|
|
13975
|
+
function stringWidth(text) {
|
|
13976
|
+
return visibleWidth(text);
|
|
13977
|
+
}
|
|
13978
|
+
|
|
13979
|
+
// src/react-ink/markdown/highlight.ts
|
|
13980
|
+
import { extname } from "node:path";
|
|
13981
|
+
import hljs from "highlight.js";
|
|
13982
|
+
function scopeToRole(scope) {
|
|
13983
|
+
const head = scope.split(".")[0] ?? scope;
|
|
13984
|
+
switch (head) {
|
|
13985
|
+
case "keyword":
|
|
13986
|
+
case "built_in":
|
|
13987
|
+
case "literal":
|
|
13988
|
+
case "operator":
|
|
13989
|
+
return "synKeyword";
|
|
13990
|
+
case "string":
|
|
13991
|
+
case "regexp":
|
|
13992
|
+
case "symbol":
|
|
13993
|
+
case "char":
|
|
13994
|
+
case "meta":
|
|
13995
|
+
return "synString";
|
|
13996
|
+
case "number":
|
|
13997
|
+
return "synNumber";
|
|
13998
|
+
case "comment":
|
|
13999
|
+
case "quote":
|
|
14000
|
+
return "synComment";
|
|
14001
|
+
case "type":
|
|
14002
|
+
case "class":
|
|
14003
|
+
case "title":
|
|
14004
|
+
case "tag":
|
|
14005
|
+
case "name":
|
|
14006
|
+
case "attr":
|
|
14007
|
+
case "attribute":
|
|
14008
|
+
case "selector":
|
|
14009
|
+
return "synType";
|
|
14010
|
+
default:
|
|
14011
|
+
return null;
|
|
14012
|
+
}
|
|
14013
|
+
}
|
|
14014
|
+
var HTML_ENTITIES = {
|
|
14015
|
+
"&": "&",
|
|
14016
|
+
"<": "<",
|
|
14017
|
+
">": ">",
|
|
14018
|
+
""": '"',
|
|
14019
|
+
"'": "'",
|
|
14020
|
+
"'": "'"
|
|
14021
|
+
};
|
|
14022
|
+
function decodeEntities2(text) {
|
|
14023
|
+
return text.replace(/&(?:amp|lt|gt|quot|#x27|#39);/g, (match) => HTML_ENTITIES[match] ?? match);
|
|
14024
|
+
}
|
|
14025
|
+
function parseHljsHtml(html) {
|
|
14026
|
+
const nodes = [];
|
|
14027
|
+
const scopeStack = [];
|
|
14028
|
+
const tagRe = /<span class="hljs-([^"]+)">|<\/span>/g;
|
|
14029
|
+
let lastIndex = 0;
|
|
14030
|
+
let match;
|
|
14031
|
+
const pushText = (raw) => {
|
|
14032
|
+
if (!raw) return;
|
|
14033
|
+
const currentScope = scopeStack.length > 0 ? scopeStack[scopeStack.length - 1] : null;
|
|
14034
|
+
const scope = currentScope ? currentScope.split(/\s+/)[0].replace(/_$/, "") : null;
|
|
14035
|
+
nodes.push({ text: decodeEntities2(raw), scope });
|
|
14036
|
+
};
|
|
14037
|
+
while ((match = tagRe.exec(html)) !== null) {
|
|
14038
|
+
pushText(html.slice(lastIndex, match.index));
|
|
14039
|
+
lastIndex = tagRe.lastIndex;
|
|
14040
|
+
if (match[0] === "</span>") {
|
|
14041
|
+
scopeStack.pop();
|
|
14042
|
+
} else if (match[1]) {
|
|
14043
|
+
scopeStack.push(match[1]);
|
|
14044
|
+
}
|
|
14045
|
+
}
|
|
14046
|
+
pushText(html.slice(lastIndex));
|
|
14047
|
+
return nodes;
|
|
14048
|
+
}
|
|
14049
|
+
function createHighlighter(theme) {
|
|
14050
|
+
return {
|
|
14051
|
+
supportsLanguage: (language) => {
|
|
14052
|
+
if (!language || language === "plaintext" || language === "text") {
|
|
14053
|
+
return false;
|
|
14054
|
+
}
|
|
14055
|
+
try {
|
|
14056
|
+
return hljs.getLanguage(language) !== void 0;
|
|
14057
|
+
} catch {
|
|
14058
|
+
return false;
|
|
14059
|
+
}
|
|
14060
|
+
},
|
|
14061
|
+
highlight: (code, options) => {
|
|
14062
|
+
const language = options.language;
|
|
14063
|
+
if (!language || language === "plaintext" || language === "text") {
|
|
14064
|
+
return code;
|
|
14065
|
+
}
|
|
14066
|
+
try {
|
|
14067
|
+
if (hljs.getLanguage(language) === void 0) {
|
|
14068
|
+
return code;
|
|
14069
|
+
}
|
|
14070
|
+
const { value } = hljs.highlight(code, { language, ignoreIllegals: true });
|
|
14071
|
+
return parseHljsHtml(value).map((node) => {
|
|
14072
|
+
const role = node.scope ? scopeToRole(node.scope) : null;
|
|
14073
|
+
return role ? theme.role(role, node.text) : node.text;
|
|
14074
|
+
}).join("");
|
|
14075
|
+
} catch {
|
|
14076
|
+
return code;
|
|
14077
|
+
}
|
|
14078
|
+
}
|
|
14079
|
+
};
|
|
14080
|
+
}
|
|
14081
|
+
function highlightByPath(code, filePath, theme) {
|
|
14082
|
+
const language = languageFromPath(filePath);
|
|
14083
|
+
if (!language) {
|
|
14084
|
+
return code;
|
|
14085
|
+
}
|
|
14086
|
+
const highlighter = createHighlighter(theme);
|
|
14087
|
+
if (!highlighter.supportsLanguage(language)) {
|
|
14088
|
+
return code;
|
|
14089
|
+
}
|
|
14090
|
+
return highlighter.highlight(code, { language });
|
|
14091
|
+
}
|
|
14092
|
+
var EXTENSION_LANGUAGES = {
|
|
14093
|
+
ts: "typescript",
|
|
14094
|
+
tsx: "typescript",
|
|
14095
|
+
mts: "typescript",
|
|
14096
|
+
cts: "typescript",
|
|
14097
|
+
js: "javascript",
|
|
14098
|
+
jsx: "javascript",
|
|
14099
|
+
mjs: "javascript",
|
|
14100
|
+
cjs: "javascript",
|
|
14101
|
+
py: "python",
|
|
14102
|
+
rb: "ruby",
|
|
14103
|
+
rs: "rust",
|
|
14104
|
+
go: "go",
|
|
14105
|
+
java: "java",
|
|
14106
|
+
kt: "kotlin",
|
|
14107
|
+
c: "c",
|
|
14108
|
+
h: "c",
|
|
14109
|
+
cc: "cpp",
|
|
14110
|
+
cpp: "cpp",
|
|
14111
|
+
hpp: "cpp",
|
|
14112
|
+
cs: "csharp",
|
|
14113
|
+
sh: "bash",
|
|
14114
|
+
bash: "bash",
|
|
14115
|
+
zsh: "bash",
|
|
14116
|
+
yml: "yaml",
|
|
14117
|
+
yaml: "yaml",
|
|
14118
|
+
json: "json",
|
|
14119
|
+
md: "markdown",
|
|
14120
|
+
html: "xml",
|
|
14121
|
+
xml: "xml",
|
|
14122
|
+
css: "css",
|
|
14123
|
+
scss: "scss",
|
|
14124
|
+
sql: "sql",
|
|
14125
|
+
toml: "ini",
|
|
14126
|
+
ini: "ini",
|
|
14127
|
+
php: "php",
|
|
14128
|
+
swift: "swift"
|
|
14129
|
+
};
|
|
14130
|
+
function languageFromPath(filePath) {
|
|
14131
|
+
const ext = extname(filePath).slice(1).toLowerCase();
|
|
14132
|
+
if (!ext) {
|
|
14133
|
+
return null;
|
|
14134
|
+
}
|
|
14135
|
+
const mapped = EXTENSION_LANGUAGES[ext];
|
|
14136
|
+
if (mapped) {
|
|
14137
|
+
return mapped;
|
|
14138
|
+
}
|
|
14139
|
+
try {
|
|
14140
|
+
return hljs.getLanguage(ext) !== void 0 ? ext : null;
|
|
14141
|
+
} catch {
|
|
14142
|
+
return null;
|
|
14143
|
+
}
|
|
14144
|
+
}
|
|
14145
|
+
|
|
14146
|
+
// src/react-ink/markdown/MarkdownTable.tsx
|
|
14147
|
+
import chalk3 from "chalk";
|
|
14148
|
+
import stripAnsi4 from "strip-ansi";
|
|
14149
|
+
var MIN_COLUMN_WIDTH = 3;
|
|
14150
|
+
var COLUMN_GAP = 2;
|
|
14151
|
+
function MarkdownTable({ token, theme, highlight = null }) {
|
|
14152
|
+
const formatCell = (tokens) => (tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("");
|
|
14153
|
+
const displayWidth = (tokens) => stringWidth(stripAnsi4(formatCell(tokens)));
|
|
14154
|
+
const columnCount = token.header.length;
|
|
14155
|
+
const columnWidths = token.header.map((header, index) => {
|
|
14156
|
+
let max = displayWidth(header.tokens);
|
|
14157
|
+
for (const row of token.rows) {
|
|
14158
|
+
max = Math.max(max, displayWidth(row[index]?.tokens));
|
|
14159
|
+
}
|
|
14160
|
+
return Math.max(max, MIN_COLUMN_WIDTH);
|
|
14161
|
+
});
|
|
14162
|
+
const renderRow2 = (cells, key, bold) => /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: columnWidths.map((width, index) => {
|
|
14163
|
+
const cell = cells[index];
|
|
14164
|
+
const content = formatCell(cell?.tokens);
|
|
14165
|
+
const visible = stringWidth(stripAnsi4(content));
|
|
14166
|
+
const align = token.align?.[index];
|
|
14167
|
+
const padded = padAligned(content, visible, width, align ?? "left");
|
|
14168
|
+
const styled = bold ? chalk3.bold(padded) : padded;
|
|
14169
|
+
const gap = index < columnCount - 1 ? " ".repeat(COLUMN_GAP) : "";
|
|
14170
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
14171
|
+
styled,
|
|
14172
|
+
gap
|
|
14173
|
+
] }, index);
|
|
14174
|
+
}) }, key);
|
|
14175
|
+
const separator = /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: columnWidths.map((width, index) => {
|
|
14176
|
+
const gap = index < columnCount - 1 ? " ".repeat(COLUMN_GAP) : "";
|
|
14177
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
14178
|
+
theme.dim("-".repeat(width)),
|
|
14179
|
+
gap
|
|
14180
|
+
] }, index);
|
|
14181
|
+
}) });
|
|
14182
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
14183
|
+
renderRow2(token.header, "header", true),
|
|
14184
|
+
separator,
|
|
14185
|
+
token.rows.map((row, rowIndex) => renderRow2(row, `row-${rowIndex}`, false))
|
|
14186
|
+
] });
|
|
14187
|
+
}
|
|
14188
|
+
|
|
14189
|
+
// src/react-ink/markdown/Markdown.tsx
|
|
14190
|
+
function stripPromptXMLTags(text) {
|
|
14191
|
+
return text.replace(/<\/?(?:system-reminder|prompt|context)[^>]*>/g, "");
|
|
14192
|
+
}
|
|
14193
|
+
function Markdown({ children, theme, highlightCode = true, dim = false }) {
|
|
14194
|
+
const highlight = useMemo(
|
|
14195
|
+
() => highlightCode ? createHighlighter(theme) : null,
|
|
14196
|
+
[highlightCode, theme]
|
|
14197
|
+
);
|
|
14198
|
+
const elements = useMemo(() => {
|
|
14199
|
+
configureMarked();
|
|
14200
|
+
const tokens = cachedLexer(stripPromptXMLTags(children));
|
|
14201
|
+
const out = [];
|
|
14202
|
+
let buffer = "";
|
|
14203
|
+
const flush = () => {
|
|
14204
|
+
if (buffer) {
|
|
14205
|
+
const text = buffer.replace(/\n+$/, "");
|
|
14206
|
+
if (text) {
|
|
14207
|
+
out.push(
|
|
14208
|
+
/* @__PURE__ */ jsx(Text, { children: dim ? theme.dim(text) : text }, out.length)
|
|
14209
|
+
);
|
|
14210
|
+
}
|
|
14211
|
+
buffer = "";
|
|
14212
|
+
}
|
|
14213
|
+
};
|
|
14214
|
+
for (const token of tokens) {
|
|
14215
|
+
if (token.type === "table") {
|
|
14216
|
+
flush();
|
|
14217
|
+
out.push(
|
|
14218
|
+
/* @__PURE__ */ jsx(
|
|
14219
|
+
MarkdownTable,
|
|
14220
|
+
{
|
|
14221
|
+
token,
|
|
14222
|
+
theme,
|
|
14223
|
+
highlight
|
|
14224
|
+
},
|
|
14225
|
+
out.length
|
|
14226
|
+
)
|
|
14227
|
+
);
|
|
14228
|
+
} else {
|
|
14229
|
+
buffer += formatToken(token, theme, highlight);
|
|
14230
|
+
}
|
|
14231
|
+
}
|
|
14232
|
+
flush();
|
|
14233
|
+
return out;
|
|
14234
|
+
}, [children, dim, highlight, theme]);
|
|
14235
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: elements });
|
|
14236
|
+
}
|
|
14237
|
+
|
|
13212
14238
|
// src/react-ink/utils/tool-display.ts
|
|
13213
14239
|
import { homedir as homedir2 } from "node:os";
|
|
14240
|
+
|
|
14241
|
+
// src/react-ink/diff/structured.ts
|
|
14242
|
+
import { structuredPatch } from "diff";
|
|
14243
|
+
|
|
14244
|
+
// src/react-ink/diff/word-diff.ts
|
|
14245
|
+
import { diffWordsWithSpace } from "diff";
|
|
14246
|
+
var CHANGE_THRESHOLD = 0.4;
|
|
14247
|
+
function wordDiffLine(oldLine, newLine, side) {
|
|
14248
|
+
const lineText = side === "removed" ? oldLine : newLine;
|
|
14249
|
+
if (oldLine.length === 0 || newLine.length === 0) {
|
|
14250
|
+
return [{ text: lineText, changed: true }];
|
|
14251
|
+
}
|
|
14252
|
+
let changes;
|
|
14253
|
+
try {
|
|
14254
|
+
changes = diffWordsWithSpace(oldLine, newLine);
|
|
14255
|
+
} catch {
|
|
14256
|
+
return [{ text: lineText, changed: true }];
|
|
14257
|
+
}
|
|
14258
|
+
let changedChars = 0;
|
|
14259
|
+
let totalChars = 0;
|
|
14260
|
+
for (const change of changes) {
|
|
14261
|
+
totalChars += change.value.length;
|
|
14262
|
+
if (change.added || change.removed) {
|
|
14263
|
+
changedChars += change.value.length;
|
|
14264
|
+
}
|
|
14265
|
+
}
|
|
14266
|
+
const fraction = totalChars === 0 ? 0 : changedChars / totalChars;
|
|
14267
|
+
if (fraction > CHANGE_THRESHOLD) {
|
|
14268
|
+
return [{ text: lineText, changed: true }];
|
|
14269
|
+
}
|
|
14270
|
+
const spans = [];
|
|
14271
|
+
for (const change of changes) {
|
|
14272
|
+
const belongs = side === "removed" ? !change.added : !change.removed;
|
|
14273
|
+
if (!belongs) {
|
|
14274
|
+
continue;
|
|
14275
|
+
}
|
|
14276
|
+
spans.push({ text: change.value, changed: Boolean(change.added || change.removed) });
|
|
14277
|
+
}
|
|
14278
|
+
return spans.length > 0 ? spans : [{ text: lineText, changed: false }];
|
|
14279
|
+
}
|
|
14280
|
+
|
|
14281
|
+
// src/react-ink/diff/structured.ts
|
|
14282
|
+
var CONTEXT_LINES = 3;
|
|
14283
|
+
function buildStructuredDiff(oldStr, newStr, filePath = "") {
|
|
14284
|
+
if (oldStr === newStr) {
|
|
14285
|
+
return null;
|
|
14286
|
+
}
|
|
14287
|
+
let patch;
|
|
14288
|
+
try {
|
|
14289
|
+
patch = structuredPatch(filePath, filePath, oldStr, newStr, "", "", { context: CONTEXT_LINES });
|
|
14290
|
+
} catch {
|
|
14291
|
+
return null;
|
|
14292
|
+
}
|
|
14293
|
+
const hunks = [];
|
|
14294
|
+
let addedCount = 0;
|
|
14295
|
+
let removedCount = 0;
|
|
14296
|
+
for (const hunk of patch.hunks) {
|
|
14297
|
+
const lines = classifyHunkLines(hunk);
|
|
14298
|
+
for (const line4 of lines) {
|
|
14299
|
+
if (line4.kind === "added") addedCount += 1;
|
|
14300
|
+
else if (line4.kind === "removed") removedCount += 1;
|
|
14301
|
+
}
|
|
14302
|
+
if (lines.length > 0) {
|
|
14303
|
+
hunks.push({ oldStart: hunk.oldStart, newStart: hunk.newStart, lines });
|
|
14304
|
+
}
|
|
14305
|
+
}
|
|
14306
|
+
if (hunks.length === 0) {
|
|
14307
|
+
return null;
|
|
14308
|
+
}
|
|
14309
|
+
return { hunks, addedCount, removedCount };
|
|
14310
|
+
}
|
|
14311
|
+
function classifyHunkLines(hunk) {
|
|
14312
|
+
const out = [];
|
|
14313
|
+
let oldNum = hunk.oldStart;
|
|
14314
|
+
let newNum = hunk.newStart;
|
|
14315
|
+
const rawLines = hunk.lines.filter((line4) => !line4.startsWith("\\"));
|
|
14316
|
+
let removedRun = [];
|
|
14317
|
+
let removedRunStart = -1;
|
|
14318
|
+
const flushPairing = (addedRun2) => {
|
|
14319
|
+
const pairs = Math.min(removedRun.length, addedRun2.length);
|
|
14320
|
+
for (let i = 0; i < pairs; i += 1) {
|
|
14321
|
+
const removed = removedRun[i];
|
|
14322
|
+
const added = addedRun2[i];
|
|
14323
|
+
removed.spans = wordDiffLine(removed.text, added.text, "removed");
|
|
14324
|
+
added.spans = wordDiffLine(removed.text, added.text, "added");
|
|
14325
|
+
}
|
|
14326
|
+
removedRun = [];
|
|
14327
|
+
removedRunStart = -1;
|
|
14328
|
+
};
|
|
14329
|
+
let addedRun = [];
|
|
14330
|
+
for (const raw of rawLines) {
|
|
14331
|
+
const marker = raw[0];
|
|
14332
|
+
const text = raw.slice(1);
|
|
14333
|
+
if (marker === "-") {
|
|
14334
|
+
if (addedRun.length > 0) {
|
|
14335
|
+
addedRun = [];
|
|
14336
|
+
}
|
|
14337
|
+
const line4 = { kind: "removed", oldLine: oldNum, text };
|
|
14338
|
+
out.push(line4);
|
|
14339
|
+
if (removedRunStart === -1) removedRunStart = out.length - 1;
|
|
14340
|
+
removedRun.push(line4);
|
|
14341
|
+
oldNum += 1;
|
|
14342
|
+
} else if (marker === "+") {
|
|
14343
|
+
const line4 = { kind: "added", newLine: newNum, text };
|
|
14344
|
+
out.push(line4);
|
|
14345
|
+
addedRun.push(line4);
|
|
14346
|
+
newNum += 1;
|
|
14347
|
+
} else {
|
|
14348
|
+
if (removedRun.length > 0 && addedRun.length > 0) {
|
|
14349
|
+
flushPairing(addedRun);
|
|
14350
|
+
}
|
|
14351
|
+
removedRun = [];
|
|
14352
|
+
removedRunStart = -1;
|
|
14353
|
+
addedRun = [];
|
|
14354
|
+
out.push({ kind: "context", oldLine: oldNum, newLine: newNum, text });
|
|
14355
|
+
oldNum += 1;
|
|
14356
|
+
newNum += 1;
|
|
14357
|
+
}
|
|
14358
|
+
}
|
|
14359
|
+
if (removedRun.length > 0 && addedRun.length > 0) {
|
|
14360
|
+
flushPairing(addedRun);
|
|
14361
|
+
}
|
|
14362
|
+
return out;
|
|
14363
|
+
}
|
|
14364
|
+
|
|
14365
|
+
// src/react-ink/utils/tool-display.ts
|
|
13214
14366
|
function asRecord2(value) {
|
|
13215
14367
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
13216
14368
|
}
|
|
@@ -13293,6 +14445,12 @@ function clipBody(value, maxLines = 8, maxChars = 1400) {
|
|
|
13293
14445
|
}
|
|
13294
14446
|
return previewMultiline(value, { maxLines, maxChars });
|
|
13295
14447
|
}
|
|
14448
|
+
function highlightedBody(body, filePath, theme) {
|
|
14449
|
+
if (!body || !theme || !filePath || languageFromPath(filePath) === null) {
|
|
14450
|
+
return { body };
|
|
14451
|
+
}
|
|
14452
|
+
return { body: highlightByPath(body, filePath, theme), preformatted: true };
|
|
14453
|
+
}
|
|
13296
14454
|
function extractDetails(value) {
|
|
13297
14455
|
return asRecord2(asRecord2(value)?.details);
|
|
13298
14456
|
}
|
|
@@ -13359,7 +14517,7 @@ function fallbackBody(output, fallbackOutputText, showImages = false) {
|
|
|
13359
14517
|
return clipBody(fallbackOutputText);
|
|
13360
14518
|
}
|
|
13361
14519
|
function describeToolSource(source) {
|
|
13362
|
-
const { args, fallbackArgsText, fallbackOutputText, output, showImages = false, toolName } = source;
|
|
14520
|
+
const { args, fallbackArgsText, fallbackOutputText, output, showImages = false, theme, toolName } = source;
|
|
13363
14521
|
const argsRecord = asRecord2(args);
|
|
13364
14522
|
const details = extractDetails(output);
|
|
13365
14523
|
const outputText = toolText(output, showImages);
|
|
@@ -13377,10 +14535,12 @@ function describeToolSource(source) {
|
|
|
13377
14535
|
summary += `:${start}${end ? `-${end}` : ""}`;
|
|
13378
14536
|
}
|
|
13379
14537
|
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";
|
|
14538
|
+
const readBody = hasResult && !containsImage(output) ? highlightedBody(clipBody(outputText, 10, 1800), rawPath, theme) : { body: hasResult ? clipBody(outputText, 10, 1800) : void 0 };
|
|
13380
14539
|
return {
|
|
13381
14540
|
title,
|
|
13382
14541
|
summary: hasResult ? responseSummary : summary,
|
|
13383
|
-
body:
|
|
14542
|
+
body: readBody.body,
|
|
14543
|
+
preformatted: readBody.preformatted,
|
|
13384
14544
|
emptyText: "Reading file..."
|
|
13385
14545
|
};
|
|
13386
14546
|
}
|
|
@@ -13388,10 +14548,14 @@ function describeToolSource(source) {
|
|
|
13388
14548
|
const rawPath = asString(argsRecord?.file_path) ?? asString(argsRecord?.path) ?? "";
|
|
13389
14549
|
const content = asString(argsRecord?.content);
|
|
13390
14550
|
const responseSummary = firstMeaningfulLine(outputText) ?? "Wrote file";
|
|
14551
|
+
const writeDiff = !hasResult && content !== void 0 && content.length > 0 ? buildStructuredDiff("", content, rawPath) ?? void 0 : void 0;
|
|
14552
|
+
const writeBody = hasResult ? { body: clipBody(outputText, 8, 1500) } : highlightedBody(clipBody(content, 8, 1500), rawPath, theme);
|
|
13391
14553
|
return {
|
|
13392
14554
|
title,
|
|
13393
14555
|
summary: hasResult ? responseSummary : rawPath ? shortenPath2(rawPath) : void 0,
|
|
13394
|
-
body:
|
|
14556
|
+
body: writeDiff ? void 0 : writeBody.body,
|
|
14557
|
+
preformatted: writeDiff ? void 0 : writeBody.preformatted,
|
|
14558
|
+
diff: writeDiff,
|
|
13395
14559
|
emptyText: "Preparing file write..."
|
|
13396
14560
|
};
|
|
13397
14561
|
}
|
|
@@ -13408,10 +14572,15 @@ function describeToolSource(source) {
|
|
|
13408
14572
|
400
|
|
13409
14573
|
) : void 0;
|
|
13410
14574
|
const responseSummary = firstMeaningfulLine(outputText) ?? "Applied edit";
|
|
14575
|
+
const editDiff = oldText !== void 0 && newText !== void 0 ? buildStructuredDiff(oldText, newText, rawPath) ?? void 0 : void 0;
|
|
14576
|
+
const editBody = hasResult ? highlightedBody(clipBody(outputText, 8, 1500), rawPath, theme) : { body: replacementPreview };
|
|
14577
|
+
const editChangeSummary = editDiff ? `+${editDiff.addedCount} -${editDiff.removedCount}` : void 0;
|
|
13411
14578
|
return {
|
|
13412
14579
|
title,
|
|
13413
|
-
summary: hasResult ? responseSummary : rawPath ? shortenPath2(rawPath) : void 0,
|
|
13414
|
-
body:
|
|
14580
|
+
summary: hasResult ? editChangeSummary ?? responseSummary : editChangeSummary ?? (rawPath ? shortenPath2(rawPath) : void 0),
|
|
14581
|
+
body: editDiff ? void 0 : editBody.body,
|
|
14582
|
+
preformatted: editDiff ? void 0 : editBody.preformatted,
|
|
14583
|
+
diff: editDiff,
|
|
13415
14584
|
emptyText: "Applying edit..."
|
|
13416
14585
|
};
|
|
13417
14586
|
}
|
|
@@ -13508,7 +14677,7 @@ function describeToolCall(toolCall) {
|
|
|
13508
14677
|
args: toolCall.arguments
|
|
13509
14678
|
});
|
|
13510
14679
|
}
|
|
13511
|
-
function describeToolResult(message, showImages, args) {
|
|
14680
|
+
function describeToolResult(message, showImages, args, theme) {
|
|
13512
14681
|
return describeToolSource({
|
|
13513
14682
|
args,
|
|
13514
14683
|
toolName: message.toolName,
|
|
@@ -13516,12 +14685,13 @@ function describeToolResult(message, showImages, args) {
|
|
|
13516
14685
|
content: message.content,
|
|
13517
14686
|
details: message.details
|
|
13518
14687
|
},
|
|
13519
|
-
showImages
|
|
14688
|
+
showImages,
|
|
14689
|
+
theme
|
|
13520
14690
|
});
|
|
13521
14691
|
}
|
|
13522
14692
|
|
|
13523
14693
|
// src/react-ink/components/ToolEventBlock.tsx
|
|
13524
|
-
import
|
|
14694
|
+
import stripAnsi5 from "strip-ansi";
|
|
13525
14695
|
function statusMarker(status) {
|
|
13526
14696
|
switch (status) {
|
|
13527
14697
|
case "error":
|
|
@@ -13533,11 +14703,11 @@ function statusMarker(status) {
|
|
|
13533
14703
|
}
|
|
13534
14704
|
}
|
|
13535
14705
|
function plainToolText(text) {
|
|
13536
|
-
return
|
|
14706
|
+
return stripAnsi5(text);
|
|
13537
14707
|
}
|
|
13538
14708
|
function splitVisibleLines(text) {
|
|
13539
14709
|
return (text ?? "").split(/\r?\n/).map((line4) => line4.trimEnd()).filter((line4, index, lines) => {
|
|
13540
|
-
if (line4.length > 0) {
|
|
14710
|
+
if (stripAnsi5(line4).length > 0) {
|
|
13541
14711
|
return true;
|
|
13542
14712
|
}
|
|
13543
14713
|
return index !== 0 && index !== lines.length - 1;
|
|
@@ -13568,6 +14738,7 @@ function ToolEventBlock({
|
|
|
13568
14738
|
indent = 0,
|
|
13569
14739
|
marginBottom = 1,
|
|
13570
14740
|
maxContentLines = 10,
|
|
14741
|
+
preformatted = false,
|
|
13571
14742
|
showSummaryInline = false,
|
|
13572
14743
|
showTitle = true,
|
|
13573
14744
|
status,
|
|
@@ -13596,9 +14767,9 @@ function ToolEventBlock({
|
|
|
13596
14767
|
Box,
|
|
13597
14768
|
{
|
|
13598
14769
|
marginLeft: line4.kind === "response" ? showTitle ? 2 : 0 : showTitle ? 4 : 2,
|
|
13599
|
-
children: /* @__PURE__ */ jsx(Text, { color: "white", children: plainToolText(line4.text) })
|
|
14770
|
+
children: preformatted ? /* @__PURE__ */ jsx(Text, { children: line4.text }) : /* @__PURE__ */ jsx(Text, { color: "white", children: plainToolText(line4.text) })
|
|
13600
14771
|
},
|
|
13601
|
-
`${line4.kind}:${index}:${line4.text}`
|
|
14772
|
+
`${line4.kind}:${index}:${stripAnsi5(line4.text)}`
|
|
13602
14773
|
)),
|
|
13603
14774
|
hiddenLineCount > 0 ? /* @__PURE__ */ jsx(Box, { marginLeft: showTitle ? 4 : 2, children: /* @__PURE__ */ jsx(Text, { color: "white", children: plainToolText(`... ${hiddenLineCount} more line(s)`) }) }) : null
|
|
13604
14775
|
] });
|
|
@@ -13623,17 +14794,100 @@ function ToolCallMessage({ theme, toolCall }) {
|
|
|
13623
14794
|
);
|
|
13624
14795
|
}
|
|
13625
14796
|
|
|
14797
|
+
// src/react-ink/diff/Diff.tsx
|
|
14798
|
+
import chalk4 from "chalk";
|
|
14799
|
+
function lineMarker(kind) {
|
|
14800
|
+
switch (kind) {
|
|
14801
|
+
case "added":
|
|
14802
|
+
return "+";
|
|
14803
|
+
case "removed":
|
|
14804
|
+
return "-";
|
|
14805
|
+
default:
|
|
14806
|
+
return " ";
|
|
14807
|
+
}
|
|
14808
|
+
}
|
|
14809
|
+
function gutterWidth(diff) {
|
|
14810
|
+
let max = 1;
|
|
14811
|
+
for (const hunk of diff.hunks) {
|
|
14812
|
+
for (const line4 of hunk.lines) {
|
|
14813
|
+
const num2 = line4.kind === "removed" ? line4.oldLine : line4.newLine;
|
|
14814
|
+
if (num2 !== void 0) {
|
|
14815
|
+
max = Math.max(max, stringWidth(String(num2)));
|
|
14816
|
+
}
|
|
14817
|
+
}
|
|
14818
|
+
}
|
|
14819
|
+
return max;
|
|
14820
|
+
}
|
|
14821
|
+
function renderLineText(line4, theme, bgRole, fgRole) {
|
|
14822
|
+
const paintSpan = (text, changed) => {
|
|
14823
|
+
const fg = theme.role(fgRole, text);
|
|
14824
|
+
return changed ? chalk4.bold(fg) : fg;
|
|
14825
|
+
};
|
|
14826
|
+
let body;
|
|
14827
|
+
if (line4.spans && line4.spans.length > 0) {
|
|
14828
|
+
body = line4.spans.map((span) => paintSpan(span.text, span.changed)).join("");
|
|
14829
|
+
} else {
|
|
14830
|
+
body = theme.role(fgRole, line4.text);
|
|
14831
|
+
}
|
|
14832
|
+
return bgRole ? theme.roleBackground(bgRole, body) : body;
|
|
14833
|
+
}
|
|
14834
|
+
function Diff({ diff, theme, indent = 0, marginBottom = 0 }) {
|
|
14835
|
+
const gutter = gutterWidth(diff);
|
|
14836
|
+
const renderLine = (line4, key) => {
|
|
14837
|
+
const num2 = line4.kind === "removed" ? line4.oldLine : line4.newLine;
|
|
14838
|
+
const gutterText = (num2 !== void 0 ? String(num2) : "").padStart(gutter);
|
|
14839
|
+
const marker = lineMarker(line4.kind);
|
|
14840
|
+
const bgRole = line4.kind === "added" ? "diffAddedBg" : line4.kind === "removed" ? "diffRemovedBg" : null;
|
|
14841
|
+
const fgRole = line4.kind === "added" ? "diffAddedText" : line4.kind === "removed" ? "diffRemovedText" : "blockquoteBar";
|
|
14842
|
+
const gutterStyled = theme.dim(`${gutterText} `);
|
|
14843
|
+
const markerStyled = line4.kind === "context" ? theme.dim(`${marker} `) : theme.role(fgRole, `${marker} `);
|
|
14844
|
+
const text = renderLineText(line4, theme, bgRole, fgRole);
|
|
14845
|
+
return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
14846
|
+
gutterStyled,
|
|
14847
|
+
markerStyled,
|
|
14848
|
+
text
|
|
14849
|
+
] }) }, key);
|
|
14850
|
+
};
|
|
14851
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: indent, marginBottom, children: diff.hunks.map((hunk, hunkIndex) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
14852
|
+
hunkIndex > 0 ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { children: theme.dim("...") }) }) : null,
|
|
14853
|
+
hunk.lines.map((line4, lineIndex) => renderLine(line4, `${hunkIndex}-${lineIndex}`))
|
|
14854
|
+
] }, `hunk-${hunkIndex}`)) });
|
|
14855
|
+
}
|
|
14856
|
+
|
|
13626
14857
|
// src/react-ink/components/messages/ToolResultBlock.tsx
|
|
13627
14858
|
function ToolResultBlock({ expanded = false, message, nested = false, showImages, theme, toolCall }) {
|
|
13628
|
-
const descriptor = describeToolResult(message, showImages, toolCall?.arguments);
|
|
14859
|
+
const descriptor = describeToolResult(message, showImages, toolCall?.arguments, theme);
|
|
14860
|
+
const indent = nested ? 4 : 2;
|
|
14861
|
+
if (descriptor.diff) {
|
|
14862
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 0, children: [
|
|
14863
|
+
/* @__PURE__ */ jsx(
|
|
14864
|
+
ToolEventBlock,
|
|
14865
|
+
{
|
|
14866
|
+
detail: void 0,
|
|
14867
|
+
emptyText: descriptor.emptyText,
|
|
14868
|
+
indent,
|
|
14869
|
+
marginBottom: 0,
|
|
14870
|
+
maxContentLines: 0,
|
|
14871
|
+
showSummaryInline: false,
|
|
14872
|
+
showTitle: !nested,
|
|
14873
|
+
status: message.isError ? "error" : "success",
|
|
14874
|
+
summary: descriptor.summary,
|
|
14875
|
+
theme,
|
|
14876
|
+
title: descriptor.title
|
|
14877
|
+
}
|
|
14878
|
+
),
|
|
14879
|
+
/* @__PURE__ */ jsx(Diff, { diff: descriptor.diff, theme, indent: indent + 2 })
|
|
14880
|
+
] });
|
|
14881
|
+
}
|
|
13629
14882
|
return /* @__PURE__ */ jsx(
|
|
13630
14883
|
ToolEventBlock,
|
|
13631
14884
|
{
|
|
13632
14885
|
detail: descriptor.body,
|
|
13633
14886
|
emptyText: descriptor.emptyText,
|
|
13634
|
-
indent
|
|
14887
|
+
indent,
|
|
13635
14888
|
marginBottom: 0,
|
|
13636
14889
|
maxContentLines: expanded ? Number.MAX_SAFE_INTEGER : 10,
|
|
14890
|
+
preformatted: descriptor.preformatted,
|
|
13637
14891
|
showSummaryInline: false,
|
|
13638
14892
|
showTitle: !nested,
|
|
13639
14893
|
status: message.isError ? "error" : "success",
|
|
@@ -13658,7 +14912,7 @@ function AssistantMessageView({
|
|
|
13658
14912
|
const matchedToolResultIds = /* @__PURE__ */ new Set();
|
|
13659
14913
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
13660
14914
|
/* @__PURE__ */ jsx(Text, { children: theme.color("accent", `Assistant ${message.provider}/${message.model} ${formatMessageTimestamp(message.timestamp)}`) }),
|
|
13661
|
-
parts.text ? /* @__PURE__ */ jsx(
|
|
14915
|
+
parts.text ? /* @__PURE__ */ jsx(Markdown, { theme, children: parts.text }) : null,
|
|
13662
14916
|
parts.thinking.map((thinking, index) => /* @__PURE__ */ jsx(Text, { children: theme.muted(`[thinking] ${thinking}`) }, index)),
|
|
13663
14917
|
parts.toolCalls.map((toolCall) => {
|
|
13664
14918
|
const toolResult = toolResultsByCallId.get(toolCall.id);
|