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/shell-app.js
CHANGED
|
@@ -8469,6 +8469,34 @@ var useInput = ink.useInput;
|
|
|
8469
8469
|
// src/react-ink/theme-adapter.ts
|
|
8470
8470
|
import chalk from "chalk";
|
|
8471
8471
|
import stripAnsi from "strip-ansi";
|
|
8472
|
+
var DEFAULT_ROLE_KEYS = {
|
|
8473
|
+
codeInline: "codeInline",
|
|
8474
|
+
heading: "heading",
|
|
8475
|
+
blockquoteBar: "blockquoteBar",
|
|
8476
|
+
diffAddedBg: "diffAddedBg",
|
|
8477
|
+
diffRemovedBg: "diffRemovedBg",
|
|
8478
|
+
diffAddedText: "diffAddedText",
|
|
8479
|
+
diffRemovedText: "diffRemovedText",
|
|
8480
|
+
synKeyword: "synKeyword",
|
|
8481
|
+
synString: "synString",
|
|
8482
|
+
synNumber: "synNumber",
|
|
8483
|
+
synComment: "synComment",
|
|
8484
|
+
synType: "synType"
|
|
8485
|
+
};
|
|
8486
|
+
var ROLE_FALLBACK_KEYS = {
|
|
8487
|
+
codeInline: "accent",
|
|
8488
|
+
heading: "accent",
|
|
8489
|
+
blockquoteBar: "muted",
|
|
8490
|
+
diffAddedBg: "success",
|
|
8491
|
+
diffRemovedBg: "error",
|
|
8492
|
+
diffAddedText: "success",
|
|
8493
|
+
diffRemovedText: "error",
|
|
8494
|
+
synKeyword: "accent",
|
|
8495
|
+
synString: "success",
|
|
8496
|
+
synNumber: "warning",
|
|
8497
|
+
synComment: "muted",
|
|
8498
|
+
synType: "info"
|
|
8499
|
+
};
|
|
8472
8500
|
function applyForeground(color, text) {
|
|
8473
8501
|
if (!color) return text;
|
|
8474
8502
|
try {
|
|
@@ -8495,15 +8523,27 @@ function applyBackground(background, foreground, text) {
|
|
|
8495
8523
|
return applyForeground(foreground, text);
|
|
8496
8524
|
}
|
|
8497
8525
|
}
|
|
8498
|
-
function createThemeAdapter(themeName, colors) {
|
|
8526
|
+
function createThemeAdapter(themeName, colors, roleOverrides) {
|
|
8499
8527
|
const fallback = colors.text ?? "#e5e5e7";
|
|
8528
|
+
const roles = { ...DEFAULT_ROLE_KEYS, ...roleOverrides };
|
|
8529
|
+
const resolveRoleColor = (role) => resolveColorToken(
|
|
8530
|
+
colors[roles[role]],
|
|
8531
|
+
resolveColorToken(colors[ROLE_FALLBACK_KEYS[role]], fallback)
|
|
8532
|
+
);
|
|
8500
8533
|
return {
|
|
8501
8534
|
name: themeName,
|
|
8502
8535
|
colors,
|
|
8536
|
+
roles,
|
|
8503
8537
|
color: (key, text) => applyForeground(resolveColorToken(colors[key], fallback), text),
|
|
8504
8538
|
background: (key, text, textKey = "text") => applyBackground(resolveColorToken(colors[key]), resolveColorToken(colors[textKey], fallback), ` ${stripAnsi(text)} `),
|
|
8505
8539
|
dim: (text) => applyForeground(resolveColorToken(colors.dim, "#666666"), text),
|
|
8506
|
-
muted: (text) => applyForeground(resolveColorToken(colors.muted, "#808080"), text)
|
|
8540
|
+
muted: (text) => applyForeground(resolveColorToken(colors.muted, "#808080"), text),
|
|
8541
|
+
role: (role, text) => applyForeground(resolveRoleColor(role), text),
|
|
8542
|
+
roleBackground: (role, text, foregroundRole) => applyBackground(
|
|
8543
|
+
resolveRoleColor(role),
|
|
8544
|
+
foregroundRole ? resolveRoleColor(foregroundRole) : void 0,
|
|
8545
|
+
text
|
|
8546
|
+
)
|
|
8507
8547
|
};
|
|
8508
8548
|
}
|
|
8509
8549
|
|
|
@@ -8888,8 +8928,1120 @@ function parseSkillInvocation(content) {
|
|
|
8888
8928
|
};
|
|
8889
8929
|
}
|
|
8890
8930
|
|
|
8931
|
+
// src/react-ink/markdown/format-token.ts
|
|
8932
|
+
import chalk2 from "chalk";
|
|
8933
|
+
import { marked } from "marked";
|
|
8934
|
+
import stripAnsi3 from "strip-ansi";
|
|
8935
|
+
|
|
8936
|
+
// src/ui/utils.ts
|
|
8937
|
+
import { eastAsianWidth } from "get-east-asian-width";
|
|
8938
|
+
var segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
8939
|
+
var TextWidthCalculator = class {
|
|
8940
|
+
getWidth(text) {
|
|
8941
|
+
return visibleWidth(text);
|
|
8942
|
+
}
|
|
8943
|
+
clearCache() {
|
|
8944
|
+
widthCache.clear();
|
|
8945
|
+
}
|
|
8946
|
+
};
|
|
8947
|
+
var textWidthCalculator = new TextWidthCalculator();
|
|
8948
|
+
function looksLikeEmojiCandidate(segment) {
|
|
8949
|
+
const cp = segment.codePointAt(0);
|
|
8950
|
+
return cp >= 126976 && cp <= 130047 || // pictographs and emoji proper
|
|
8951
|
+
cp >= 8960 && cp <= 9215 || // miscellaneous technical glyphs
|
|
8952
|
+
cp >= 9728 && cp <= 10175 || // assorted symbols and dingbats
|
|
8953
|
+
cp >= 11088 && cp <= 11093 || // a few star/circle characters
|
|
8954
|
+
segment.includes("\uFE0F") || // carries VS16, the emoji-presentation selector
|
|
8955
|
+
segment.length > 2;
|
|
8956
|
+
}
|
|
8957
|
+
function createUnicodeRegex(vPattern, uFallback) {
|
|
8958
|
+
try {
|
|
8959
|
+
return new RegExp(vPattern, "v");
|
|
8960
|
+
} catch {
|
|
8961
|
+
return new RegExp(uFallback, "u");
|
|
8962
|
+
}
|
|
8963
|
+
}
|
|
8964
|
+
var zeroWidthRegex = createUnicodeRegex(
|
|
8965
|
+
"^(?:\\p{Default_Ignorable_Code_Point}|\\p{Control}|\\p{Mark}|\\p{Surrogate})+$",
|
|
8966
|
+
"^(?:\\p{Default_Ignorable_Code_Point}|\\p{Control}|\\p{Mark}|\\p{Surrogate})+$"
|
|
8967
|
+
);
|
|
8968
|
+
var leadingNonPrintingRegex = createUnicodeRegex(
|
|
8969
|
+
"^[\\p{Default_Ignorable_Code_Point}\\p{Control}\\p{Format}\\p{Mark}\\p{Surrogate}]+",
|
|
8970
|
+
"^[\\p{Default_Ignorable_Code_Point}\\p{Control}\\p{Format}\\p{Mark}\\p{Surrogate}]+"
|
|
8971
|
+
);
|
|
8972
|
+
var rgiEmojiRegex = createUnicodeRegex("^\\p{RGI_Emoji}$", "^\\p{Extended_Pictographic}$");
|
|
8973
|
+
var AnsiStripper = {
|
|
8974
|
+
strip(text) {
|
|
8975
|
+
if (!text.includes("\x1B")) {
|
|
8976
|
+
return text;
|
|
8977
|
+
}
|
|
8978
|
+
let cleaned = text;
|
|
8979
|
+
cleaned = cleaned.replace(/\x1b\[[0-9;]*[mGKHJ]/g, "");
|
|
8980
|
+
cleaned = cleaned.replace(/\x1b\]8;;[^\x07]*\x07/g, "");
|
|
8981
|
+
cleaned = cleaned.replace(/\x1b_[^\x07\x1b]*(?:\x07|\x1b\\)/g, "");
|
|
8982
|
+
return cleaned;
|
|
8983
|
+
}
|
|
8984
|
+
};
|
|
8985
|
+
var WIDTH_CACHE_SIZE = 512;
|
|
8986
|
+
var widthCache = /* @__PURE__ */ new Map();
|
|
8987
|
+
function measureClusterWidth(segment) {
|
|
8988
|
+
if (zeroWidthRegex.test(segment)) {
|
|
8989
|
+
return 0;
|
|
8990
|
+
}
|
|
8991
|
+
if (looksLikeEmojiCandidate(segment) && rgiEmojiRegex.test(segment)) {
|
|
8992
|
+
return 2;
|
|
8993
|
+
}
|
|
8994
|
+
const base = segment.replace(leadingNonPrintingRegex, "");
|
|
8995
|
+
const cp = base.codePointAt(0);
|
|
8996
|
+
if (cp === void 0) {
|
|
8997
|
+
return 0;
|
|
8998
|
+
}
|
|
8999
|
+
let width = eastAsianWidth(cp);
|
|
9000
|
+
if (segment.length > 1) {
|
|
9001
|
+
for (const char of segment.slice(1)) {
|
|
9002
|
+
const c = char.codePointAt(0);
|
|
9003
|
+
if (c >= 65280 && c <= 65519) {
|
|
9004
|
+
width += eastAsianWidth(c);
|
|
9005
|
+
}
|
|
9006
|
+
}
|
|
9007
|
+
}
|
|
9008
|
+
return width;
|
|
9009
|
+
}
|
|
9010
|
+
function visibleWidth(str2) {
|
|
9011
|
+
if (str2.length === 0) {
|
|
9012
|
+
return 0;
|
|
9013
|
+
}
|
|
9014
|
+
let isPureAscii = true;
|
|
9015
|
+
for (let i = 0; i < str2.length; i++) {
|
|
9016
|
+
const code = str2.charCodeAt(i);
|
|
9017
|
+
if (code < 32 || code > 126) {
|
|
9018
|
+
isPureAscii = false;
|
|
9019
|
+
break;
|
|
9020
|
+
}
|
|
9021
|
+
}
|
|
9022
|
+
if (isPureAscii) {
|
|
9023
|
+
return str2.length;
|
|
9024
|
+
}
|
|
9025
|
+
const cached = widthCache.get(str2);
|
|
9026
|
+
if (cached !== void 0) {
|
|
9027
|
+
return cached;
|
|
9028
|
+
}
|
|
9029
|
+
let clean = str2;
|
|
9030
|
+
if (str2.includes(" ")) {
|
|
9031
|
+
clean = clean.replace(/\t/g, " ");
|
|
9032
|
+
}
|
|
9033
|
+
clean = AnsiStripper.strip(clean);
|
|
9034
|
+
let width = 0;
|
|
9035
|
+
for (const { segment } of segmenter.segment(clean)) {
|
|
9036
|
+
width += measureClusterWidth(segment);
|
|
9037
|
+
}
|
|
9038
|
+
if (widthCache.size >= WIDTH_CACHE_SIZE) {
|
|
9039
|
+
const firstKey = widthCache.keys().next().value;
|
|
9040
|
+
if (firstKey !== void 0) {
|
|
9041
|
+
widthCache.delete(firstKey);
|
|
9042
|
+
}
|
|
9043
|
+
}
|
|
9044
|
+
widthCache.set(str2, width);
|
|
9045
|
+
return width;
|
|
9046
|
+
}
|
|
9047
|
+
function extractAnsiCode(str2, pos) {
|
|
9048
|
+
if (pos >= str2.length || str2[pos] !== "\x1B") return null;
|
|
9049
|
+
const next = str2[pos + 1];
|
|
9050
|
+
if (next === "[") {
|
|
9051
|
+
let j = pos + 2;
|
|
9052
|
+
while (j < str2.length && !/[mGKHJ]/.test(str2[j])) j++;
|
|
9053
|
+
if (j < str2.length) return { code: str2.substring(pos, j + 1), length: j + 1 - pos };
|
|
9054
|
+
return null;
|
|
9055
|
+
}
|
|
9056
|
+
if (next === "]") {
|
|
9057
|
+
let j = pos + 2;
|
|
9058
|
+
while (j < str2.length) {
|
|
9059
|
+
if (str2[j] === "\x07") return { code: str2.substring(pos, j + 1), length: j + 1 - pos };
|
|
9060
|
+
if (str2[j] === "\x1B" && str2[j + 1] === "\\") return { code: str2.substring(pos, j + 2), length: j + 2 - pos };
|
|
9061
|
+
j++;
|
|
9062
|
+
}
|
|
9063
|
+
return null;
|
|
9064
|
+
}
|
|
9065
|
+
if (next === "_") {
|
|
9066
|
+
let j = pos + 2;
|
|
9067
|
+
while (j < str2.length) {
|
|
9068
|
+
if (str2[j] === "\x07") return { code: str2.substring(pos, j + 1), length: j + 1 - pos };
|
|
9069
|
+
if (str2[j] === "\x1B" && str2[j + 1] === "\\") return { code: str2.substring(pos, j + 2), length: j + 2 - pos };
|
|
9070
|
+
j++;
|
|
9071
|
+
}
|
|
9072
|
+
return null;
|
|
9073
|
+
}
|
|
9074
|
+
return null;
|
|
9075
|
+
}
|
|
9076
|
+
var AnsiStateTracker = class {
|
|
9077
|
+
// Each attribute is kept on its own flag, which lets us clear them one at a time.
|
|
9078
|
+
_bold = false;
|
|
9079
|
+
_dim = false;
|
|
9080
|
+
italic = false;
|
|
9081
|
+
underline = false;
|
|
9082
|
+
blink = false;
|
|
9083
|
+
inverse = false;
|
|
9084
|
+
hidden = false;
|
|
9085
|
+
strikethrough = false;
|
|
9086
|
+
_colors = { fg: null, bg: null };
|
|
9087
|
+
process(ansiCode) {
|
|
9088
|
+
if (!ansiCode.endsWith("m")) {
|
|
9089
|
+
return;
|
|
9090
|
+
}
|
|
9091
|
+
const match = ansiCode.match(/\x1b\[([\d;]*)m/);
|
|
9092
|
+
if (!match) return;
|
|
9093
|
+
const params = match[1];
|
|
9094
|
+
if (params === "" || params === "0") {
|
|
9095
|
+
this.reset();
|
|
9096
|
+
return;
|
|
9097
|
+
}
|
|
9098
|
+
const parts = params.split(";");
|
|
9099
|
+
let i = 0;
|
|
9100
|
+
while (i < parts.length) {
|
|
9101
|
+
const code = Number.parseInt(parts[i] ?? "", 10);
|
|
9102
|
+
if (Number.isNaN(code)) {
|
|
9103
|
+
i++;
|
|
9104
|
+
continue;
|
|
9105
|
+
}
|
|
9106
|
+
const consumed = this.tryConsumeColorCode(parts, i, code);
|
|
9107
|
+
if (consumed > 0) {
|
|
9108
|
+
i += consumed;
|
|
9109
|
+
continue;
|
|
9110
|
+
}
|
|
9111
|
+
this.applyStandardCode(code);
|
|
9112
|
+
i++;
|
|
9113
|
+
}
|
|
9114
|
+
}
|
|
9115
|
+
tryConsumeColorCode(parts, index, code) {
|
|
9116
|
+
if (code !== 38 && code !== 48) {
|
|
9117
|
+
return 0;
|
|
9118
|
+
}
|
|
9119
|
+
if (parts[index + 1] === "5" && parts[index + 2] !== void 0) {
|
|
9120
|
+
const colorCode = `${parts[index]};${parts[index + 1]};${parts[index + 2]}`;
|
|
9121
|
+
if (code === 38) {
|
|
9122
|
+
this._colors.fg = colorCode;
|
|
9123
|
+
} else {
|
|
9124
|
+
this._colors.bg = colorCode;
|
|
9125
|
+
}
|
|
9126
|
+
return 3;
|
|
9127
|
+
}
|
|
9128
|
+
if (parts[index + 1] === "2" && parts[index + 4] !== void 0) {
|
|
9129
|
+
const colorCode = `${parts[index]};${parts[index + 1]};${parts[index + 2]};${parts[index + 3]};${parts[index + 4]}`;
|
|
9130
|
+
if (code === 38) {
|
|
9131
|
+
this._colors.fg = colorCode;
|
|
9132
|
+
} else {
|
|
9133
|
+
this._colors.bg = colorCode;
|
|
9134
|
+
}
|
|
9135
|
+
return 5;
|
|
9136
|
+
}
|
|
9137
|
+
return 0;
|
|
9138
|
+
}
|
|
9139
|
+
applyStandardCode(code) {
|
|
9140
|
+
switch (code) {
|
|
9141
|
+
case 0:
|
|
9142
|
+
this.reset();
|
|
9143
|
+
return;
|
|
9144
|
+
case 1:
|
|
9145
|
+
this._bold = true;
|
|
9146
|
+
return;
|
|
9147
|
+
case 2:
|
|
9148
|
+
this._dim = true;
|
|
9149
|
+
return;
|
|
9150
|
+
case 3:
|
|
9151
|
+
this.italic = true;
|
|
9152
|
+
return;
|
|
9153
|
+
case 4:
|
|
9154
|
+
this.underline = true;
|
|
9155
|
+
return;
|
|
9156
|
+
case 5:
|
|
9157
|
+
this.blink = true;
|
|
9158
|
+
return;
|
|
9159
|
+
case 7:
|
|
9160
|
+
this.inverse = true;
|
|
9161
|
+
return;
|
|
9162
|
+
case 8:
|
|
9163
|
+
this.hidden = true;
|
|
9164
|
+
return;
|
|
9165
|
+
case 9:
|
|
9166
|
+
this.strikethrough = true;
|
|
9167
|
+
return;
|
|
9168
|
+
case 21:
|
|
9169
|
+
this._bold = false;
|
|
9170
|
+
return;
|
|
9171
|
+
case 22:
|
|
9172
|
+
this._bold = false;
|
|
9173
|
+
this._dim = false;
|
|
9174
|
+
return;
|
|
9175
|
+
case 23:
|
|
9176
|
+
this.italic = false;
|
|
9177
|
+
return;
|
|
9178
|
+
case 24:
|
|
9179
|
+
this.underline = false;
|
|
9180
|
+
return;
|
|
9181
|
+
case 25:
|
|
9182
|
+
this.blink = false;
|
|
9183
|
+
return;
|
|
9184
|
+
case 27:
|
|
9185
|
+
this.inverse = false;
|
|
9186
|
+
return;
|
|
9187
|
+
case 28:
|
|
9188
|
+
this.hidden = false;
|
|
9189
|
+
return;
|
|
9190
|
+
case 29:
|
|
9191
|
+
this.strikethrough = false;
|
|
9192
|
+
return;
|
|
9193
|
+
case 39:
|
|
9194
|
+
this._colors.fg = null;
|
|
9195
|
+
return;
|
|
9196
|
+
case 49:
|
|
9197
|
+
this._colors.bg = null;
|
|
9198
|
+
return;
|
|
9199
|
+
default:
|
|
9200
|
+
if (code >= 30 && code <= 37 || code >= 90 && code <= 97) {
|
|
9201
|
+
this._colors.fg = String(code);
|
|
9202
|
+
return;
|
|
9203
|
+
}
|
|
9204
|
+
if (code >= 40 && code <= 47 || code >= 100 && code <= 107) {
|
|
9205
|
+
this._colors.bg = String(code);
|
|
9206
|
+
}
|
|
9207
|
+
}
|
|
9208
|
+
}
|
|
9209
|
+
reset() {
|
|
9210
|
+
this._bold = false;
|
|
9211
|
+
this._dim = false;
|
|
9212
|
+
this.italic = false;
|
|
9213
|
+
this.underline = false;
|
|
9214
|
+
this.blink = false;
|
|
9215
|
+
this.inverse = false;
|
|
9216
|
+
this.hidden = false;
|
|
9217
|
+
this.strikethrough = false;
|
|
9218
|
+
this._colors.fg = null;
|
|
9219
|
+
this._colors.bg = null;
|
|
9220
|
+
}
|
|
9221
|
+
/** Wipe all tracked state so the instance can be reused. */
|
|
9222
|
+
clear() {
|
|
9223
|
+
this.reset();
|
|
9224
|
+
}
|
|
9225
|
+
getActiveCodes() {
|
|
9226
|
+
const codes = [];
|
|
9227
|
+
if (this._bold) codes.push("1");
|
|
9228
|
+
if (this._dim) codes.push("2");
|
|
9229
|
+
if (this.italic) codes.push("3");
|
|
9230
|
+
if (this.underline) codes.push("4");
|
|
9231
|
+
if (this.blink) codes.push("5");
|
|
9232
|
+
if (this.inverse) codes.push("7");
|
|
9233
|
+
if (this.hidden) codes.push("8");
|
|
9234
|
+
if (this.strikethrough) codes.push("9");
|
|
9235
|
+
if (this._colors.fg) codes.push(this._colors.fg);
|
|
9236
|
+
if (this._colors.bg) codes.push(this._colors.bg);
|
|
9237
|
+
if (codes.length === 0) return "";
|
|
9238
|
+
return `\x1B[${codes.join(";")}m`;
|
|
9239
|
+
}
|
|
9240
|
+
hasActiveCodes() {
|
|
9241
|
+
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;
|
|
9242
|
+
}
|
|
9243
|
+
/**
|
|
9244
|
+
* Produce the escape code needed to switch off any attribute that would
|
|
9245
|
+
* otherwise smear into the padding at the end of a line. In practice that
|
|
9246
|
+
* is just underline. Yields an empty string when nothing needs disabling.
|
|
9247
|
+
*/
|
|
9248
|
+
getLineEndReset() {
|
|
9249
|
+
if (this.underline) {
|
|
9250
|
+
return "\x1B[24m";
|
|
9251
|
+
}
|
|
9252
|
+
return "";
|
|
9253
|
+
}
|
|
9254
|
+
};
|
|
9255
|
+
function mergeTextIntoTracker(text, tracker) {
|
|
9256
|
+
let i = 0;
|
|
9257
|
+
while (i < text.length) {
|
|
9258
|
+
const ansiResult = extractAnsiCode(text, i);
|
|
9259
|
+
if (ansiResult) {
|
|
9260
|
+
tracker.process(ansiResult.code);
|
|
9261
|
+
i += ansiResult.length;
|
|
9262
|
+
} else {
|
|
9263
|
+
i++;
|
|
9264
|
+
}
|
|
9265
|
+
}
|
|
9266
|
+
}
|
|
9267
|
+
function tokenizeTextWithAnsi(text) {
|
|
9268
|
+
const tokens = [];
|
|
9269
|
+
let current = "";
|
|
9270
|
+
let pendingAnsi = "";
|
|
9271
|
+
let inWhitespace = false;
|
|
9272
|
+
let i = 0;
|
|
9273
|
+
while (i < text.length) {
|
|
9274
|
+
const ansiResult = extractAnsiCode(text, i);
|
|
9275
|
+
if (ansiResult) {
|
|
9276
|
+
pendingAnsi += ansiResult.code;
|
|
9277
|
+
i += ansiResult.length;
|
|
9278
|
+
continue;
|
|
9279
|
+
}
|
|
9280
|
+
const char = text[i];
|
|
9281
|
+
const charIsSpace = char === " ";
|
|
9282
|
+
if (charIsSpace !== inWhitespace && current) {
|
|
9283
|
+
tokens.push(current);
|
|
9284
|
+
current = "";
|
|
9285
|
+
}
|
|
9286
|
+
if (pendingAnsi) {
|
|
9287
|
+
current += pendingAnsi;
|
|
9288
|
+
pendingAnsi = "";
|
|
9289
|
+
}
|
|
9290
|
+
inWhitespace = charIsSpace;
|
|
9291
|
+
current += char;
|
|
9292
|
+
i++;
|
|
9293
|
+
}
|
|
9294
|
+
if (pendingAnsi) {
|
|
9295
|
+
current += pendingAnsi;
|
|
9296
|
+
}
|
|
9297
|
+
if (current) {
|
|
9298
|
+
tokens.push(current);
|
|
9299
|
+
}
|
|
9300
|
+
return tokens;
|
|
9301
|
+
}
|
|
9302
|
+
var TextWrapper = class {
|
|
9303
|
+
wrap(text, width) {
|
|
9304
|
+
return wrapTextWithAnsi(text, width);
|
|
9305
|
+
}
|
|
9306
|
+
};
|
|
9307
|
+
var textWrapper = new TextWrapper();
|
|
9308
|
+
var TokenWrapEngine = {
|
|
9309
|
+
wrap(tokens, width, tracker) {
|
|
9310
|
+
const wrapped = [];
|
|
9311
|
+
let currentLine = "";
|
|
9312
|
+
let currentVisibleLength = 0;
|
|
9313
|
+
for (const token of tokens) {
|
|
9314
|
+
const tokenVisibleLength = visibleWidth(token);
|
|
9315
|
+
const isWhitespace = token.trim() === "";
|
|
9316
|
+
if (tokenVisibleLength > width && !isWhitespace) {
|
|
9317
|
+
if (currentLine) {
|
|
9318
|
+
const lineEndReset = tracker.getLineEndReset();
|
|
9319
|
+
if (lineEndReset) {
|
|
9320
|
+
currentLine += lineEndReset;
|
|
9321
|
+
}
|
|
9322
|
+
wrapped.push(currentLine);
|
|
9323
|
+
currentLine = "";
|
|
9324
|
+
currentVisibleLength = 0;
|
|
9325
|
+
}
|
|
9326
|
+
const broken = splitLongToken(token, width, tracker);
|
|
9327
|
+
wrapped.push(...broken.slice(0, -1));
|
|
9328
|
+
currentLine = broken[broken.length - 1];
|
|
9329
|
+
currentVisibleLength = visibleWidth(currentLine);
|
|
9330
|
+
continue;
|
|
9331
|
+
}
|
|
9332
|
+
const totalNeeded = currentVisibleLength + tokenVisibleLength;
|
|
9333
|
+
if (totalNeeded > width && currentVisibleLength > 0) {
|
|
9334
|
+
let lineToWrap = currentLine.trimEnd();
|
|
9335
|
+
const lineEndReset = tracker.getLineEndReset();
|
|
9336
|
+
if (lineEndReset) {
|
|
9337
|
+
lineToWrap += lineEndReset;
|
|
9338
|
+
}
|
|
9339
|
+
wrapped.push(lineToWrap);
|
|
9340
|
+
if (isWhitespace) {
|
|
9341
|
+
currentLine = tracker.getActiveCodes();
|
|
9342
|
+
currentVisibleLength = 0;
|
|
9343
|
+
} else {
|
|
9344
|
+
currentLine = tracker.getActiveCodes() + token;
|
|
9345
|
+
currentVisibleLength = tokenVisibleLength;
|
|
9346
|
+
}
|
|
9347
|
+
} else {
|
|
9348
|
+
currentLine += token;
|
|
9349
|
+
currentVisibleLength += tokenVisibleLength;
|
|
9350
|
+
}
|
|
9351
|
+
mergeTextIntoTracker(token, tracker);
|
|
9352
|
+
}
|
|
9353
|
+
return { wrapped, currentLine, currentVisibleLength };
|
|
9354
|
+
}
|
|
9355
|
+
};
|
|
9356
|
+
function wrapTextWithAnsi(text, width) {
|
|
9357
|
+
if (!text) {
|
|
9358
|
+
return [""];
|
|
9359
|
+
}
|
|
9360
|
+
const inputLines = text.split("\n");
|
|
9361
|
+
const result = [];
|
|
9362
|
+
const tracker = new AnsiStateTracker();
|
|
9363
|
+
for (const inputLine of inputLines) {
|
|
9364
|
+
const prefix = result.length > 0 ? tracker.getActiveCodes() : "";
|
|
9365
|
+
result.push(...wrapLinePreservingAnsi(prefix + inputLine, width));
|
|
9366
|
+
mergeTextIntoTracker(inputLine, tracker);
|
|
9367
|
+
}
|
|
9368
|
+
return result.length > 0 ? result : [""];
|
|
9369
|
+
}
|
|
9370
|
+
function wrapLinePreservingAnsi(line, width) {
|
|
9371
|
+
if (!line) {
|
|
9372
|
+
return [""];
|
|
9373
|
+
}
|
|
9374
|
+
const visibleLength = visibleWidth(line);
|
|
9375
|
+
if (visibleLength <= width) {
|
|
9376
|
+
return [line];
|
|
9377
|
+
}
|
|
9378
|
+
const tracker = new AnsiStateTracker();
|
|
9379
|
+
const tokens = tokenizeTextWithAnsi(line);
|
|
9380
|
+
const { wrapped, currentLine } = TokenWrapEngine.wrap(tokens, width, tracker);
|
|
9381
|
+
if (currentLine) {
|
|
9382
|
+
wrapped.push(currentLine);
|
|
9383
|
+
}
|
|
9384
|
+
return wrapped.length > 0 ? wrapped.map((segmentLine) => segmentLine.trimEnd()) : [""];
|
|
9385
|
+
}
|
|
9386
|
+
function splitLongToken(word, width, tracker) {
|
|
9387
|
+
const lines = [];
|
|
9388
|
+
let currentLine = tracker.getActiveCodes();
|
|
9389
|
+
let currentWidth = 0;
|
|
9390
|
+
let i = 0;
|
|
9391
|
+
const segments = [];
|
|
9392
|
+
while (i < word.length) {
|
|
9393
|
+
const ansiResult = extractAnsiCode(word, i);
|
|
9394
|
+
if (ansiResult) {
|
|
9395
|
+
segments.push({ type: "ansi", value: ansiResult.code });
|
|
9396
|
+
i += ansiResult.length;
|
|
9397
|
+
} else {
|
|
9398
|
+
let end = i;
|
|
9399
|
+
while (end < word.length) {
|
|
9400
|
+
const nextAnsi = extractAnsiCode(word, end);
|
|
9401
|
+
if (nextAnsi) break;
|
|
9402
|
+
end++;
|
|
9403
|
+
}
|
|
9404
|
+
const textPortion = word.slice(i, end);
|
|
9405
|
+
for (const seg of segmenter.segment(textPortion)) {
|
|
9406
|
+
segments.push({ type: "grapheme", value: seg.segment });
|
|
9407
|
+
}
|
|
9408
|
+
i = end;
|
|
9409
|
+
}
|
|
9410
|
+
}
|
|
9411
|
+
for (const seg of segments) {
|
|
9412
|
+
if (seg.type === "ansi") {
|
|
9413
|
+
currentLine += seg.value;
|
|
9414
|
+
tracker.process(seg.value);
|
|
9415
|
+
continue;
|
|
9416
|
+
}
|
|
9417
|
+
const grapheme = seg.value;
|
|
9418
|
+
if (!grapheme) continue;
|
|
9419
|
+
const clusterWidth = visibleWidth(grapheme);
|
|
9420
|
+
if (currentWidth + clusterWidth > width) {
|
|
9421
|
+
const lineEndReset = tracker.getLineEndReset();
|
|
9422
|
+
if (lineEndReset) {
|
|
9423
|
+
currentLine += lineEndReset;
|
|
9424
|
+
}
|
|
9425
|
+
lines.push(currentLine);
|
|
9426
|
+
currentLine = tracker.getActiveCodes();
|
|
9427
|
+
currentWidth = 0;
|
|
9428
|
+
}
|
|
9429
|
+
currentLine += grapheme;
|
|
9430
|
+
currentWidth += clusterWidth;
|
|
9431
|
+
}
|
|
9432
|
+
if (currentLine) {
|
|
9433
|
+
lines.push(currentLine);
|
|
9434
|
+
}
|
|
9435
|
+
return lines.length > 0 ? lines : [""];
|
|
9436
|
+
}
|
|
9437
|
+
var pooledStyleTracker = new AnsiStateTracker();
|
|
9438
|
+
|
|
9439
|
+
// src/react-ink/markdown/format-token.ts
|
|
9440
|
+
var EOL = "\n";
|
|
9441
|
+
var BLOCKQUOTE_BAR = "\u2502";
|
|
9442
|
+
var markedConfigured = false;
|
|
9443
|
+
function configureMarked() {
|
|
9444
|
+
if (markedConfigured) {
|
|
9445
|
+
return;
|
|
9446
|
+
}
|
|
9447
|
+
markedConfigured = true;
|
|
9448
|
+
marked.use({
|
|
9449
|
+
tokenizer: {
|
|
9450
|
+
del() {
|
|
9451
|
+
return void 0;
|
|
9452
|
+
}
|
|
9453
|
+
}
|
|
9454
|
+
});
|
|
9455
|
+
}
|
|
9456
|
+
var TOKEN_CACHE_MAX = 500;
|
|
9457
|
+
var tokenCache = /* @__PURE__ */ new Map();
|
|
9458
|
+
var MD_SYNTAX_RE = /[#*`|[>\-_~]|\n\n|^\d+\. |\n\d+\. /;
|
|
9459
|
+
function hasMarkdownSyntax(text) {
|
|
9460
|
+
return MD_SYNTAX_RE.test(text.length > 500 ? text.slice(0, 500) : text);
|
|
9461
|
+
}
|
|
9462
|
+
function hashContent(content) {
|
|
9463
|
+
let hash = 2166136261;
|
|
9464
|
+
for (let i = 0; i < content.length; i++) {
|
|
9465
|
+
hash ^= content.charCodeAt(i);
|
|
9466
|
+
hash = Math.imul(hash, 16777619);
|
|
9467
|
+
}
|
|
9468
|
+
return (hash >>> 0).toString(36) + ":" + content.length.toString(36);
|
|
9469
|
+
}
|
|
9470
|
+
function cachedLexer(content) {
|
|
9471
|
+
configureMarked();
|
|
9472
|
+
if (!hasMarkdownSyntax(content)) {
|
|
9473
|
+
return [
|
|
9474
|
+
{
|
|
9475
|
+
type: "paragraph",
|
|
9476
|
+
raw: content,
|
|
9477
|
+
text: content,
|
|
9478
|
+
tokens: [{ type: "text", raw: content, text: content }]
|
|
9479
|
+
}
|
|
9480
|
+
];
|
|
9481
|
+
}
|
|
9482
|
+
const key = hashContent(content);
|
|
9483
|
+
const hit = tokenCache.get(key);
|
|
9484
|
+
if (hit) {
|
|
9485
|
+
tokenCache.delete(key);
|
|
9486
|
+
tokenCache.set(key, hit);
|
|
9487
|
+
return hit;
|
|
9488
|
+
}
|
|
9489
|
+
const tokens = marked.lexer(content);
|
|
9490
|
+
if (tokenCache.size >= TOKEN_CACHE_MAX) {
|
|
9491
|
+
const first = tokenCache.keys().next().value;
|
|
9492
|
+
if (first !== void 0) {
|
|
9493
|
+
tokenCache.delete(first);
|
|
9494
|
+
}
|
|
9495
|
+
}
|
|
9496
|
+
tokenCache.set(key, tokens);
|
|
9497
|
+
return tokens;
|
|
9498
|
+
}
|
|
9499
|
+
function formatToken(token, theme, highlight = null, listDepth = 0, orderedListNumber = null, parent = null) {
|
|
9500
|
+
switch (token.type) {
|
|
9501
|
+
case "blockquote": {
|
|
9502
|
+
const inner = (token.tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("");
|
|
9503
|
+
const bar = theme.dim(BLOCKQUOTE_BAR);
|
|
9504
|
+
return inner.split(EOL).map((line) => stripAnsi3(line).trim() ? `${bar} ${chalk2.italic(line)}` : line).join(EOL);
|
|
9505
|
+
}
|
|
9506
|
+
case "code": {
|
|
9507
|
+
const codeToken = token;
|
|
9508
|
+
if (!highlight) {
|
|
9509
|
+
return codeToken.text + EOL;
|
|
9510
|
+
}
|
|
9511
|
+
let language = "plaintext";
|
|
9512
|
+
if (codeToken.lang && highlight.supportsLanguage(codeToken.lang)) {
|
|
9513
|
+
language = codeToken.lang;
|
|
9514
|
+
}
|
|
9515
|
+
return highlight.highlight(codeToken.text, { language }) + EOL;
|
|
9516
|
+
}
|
|
9517
|
+
case "codespan":
|
|
9518
|
+
return theme.role("codeInline", token.text);
|
|
9519
|
+
case "em":
|
|
9520
|
+
return chalk2.italic(
|
|
9521
|
+
(token.tokens ?? []).map((child) => formatToken(child, theme, highlight, 0, null, parent)).join("")
|
|
9522
|
+
);
|
|
9523
|
+
case "strong":
|
|
9524
|
+
return chalk2.bold(
|
|
9525
|
+
(token.tokens ?? []).map((child) => formatToken(child, theme, highlight, 0, null, parent)).join("")
|
|
9526
|
+
);
|
|
9527
|
+
case "heading": {
|
|
9528
|
+
const headingToken = token;
|
|
9529
|
+
const inner = (headingToken.tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("");
|
|
9530
|
+
const colored = theme.role("heading", inner);
|
|
9531
|
+
if (headingToken.depth === 1) {
|
|
9532
|
+
return chalk2.bold.italic.underline(colored) + EOL + EOL;
|
|
9533
|
+
}
|
|
9534
|
+
return chalk2.bold(colored) + EOL + EOL;
|
|
9535
|
+
}
|
|
9536
|
+
case "hr":
|
|
9537
|
+
return "---";
|
|
9538
|
+
case "image":
|
|
9539
|
+
return token.href;
|
|
9540
|
+
case "link": {
|
|
9541
|
+
const linkToken = token;
|
|
9542
|
+
if (linkToken.href.startsWith("mailto:")) {
|
|
9543
|
+
return linkToken.href.replace(/^mailto:/, "");
|
|
9544
|
+
}
|
|
9545
|
+
const linkText = (linkToken.tokens ?? []).map((child) => formatToken(child, theme, highlight, 0, null, linkToken)).join("");
|
|
9546
|
+
const plainLinkText = stripAnsi3(linkText);
|
|
9547
|
+
const display = plainLinkText && plainLinkText !== linkToken.href ? linkText : linkToken.href;
|
|
9548
|
+
return `\x1B]8;;${linkToken.href}\x07${display}\x1B]8;;\x07`;
|
|
9549
|
+
}
|
|
9550
|
+
case "list": {
|
|
9551
|
+
const listToken = token;
|
|
9552
|
+
const start = typeof listToken.start === "number" ? listToken.start : Number(listToken.start) || 1;
|
|
9553
|
+
return listToken.items.map(
|
|
9554
|
+
(item, index) => formatToken(
|
|
9555
|
+
item,
|
|
9556
|
+
theme,
|
|
9557
|
+
highlight,
|
|
9558
|
+
listDepth,
|
|
9559
|
+
listToken.ordered ? start + index : null,
|
|
9560
|
+
listToken
|
|
9561
|
+
)
|
|
9562
|
+
).join("");
|
|
9563
|
+
}
|
|
9564
|
+
case "list_item":
|
|
9565
|
+
return (token.tokens ?? []).map(
|
|
9566
|
+
(child) => `${" ".repeat(listDepth)}${formatToken(child, theme, highlight, listDepth + 1, orderedListNumber, token)}`
|
|
9567
|
+
).join("");
|
|
9568
|
+
case "paragraph":
|
|
9569
|
+
return (token.tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("") + EOL;
|
|
9570
|
+
case "space":
|
|
9571
|
+
case "br":
|
|
9572
|
+
return EOL;
|
|
9573
|
+
case "text": {
|
|
9574
|
+
const textToken = token;
|
|
9575
|
+
if (parent?.type === "link") {
|
|
9576
|
+
return textToken.text;
|
|
9577
|
+
}
|
|
9578
|
+
if (parent?.type === "list_item") {
|
|
9579
|
+
const marker = orderedListNumber === null ? "-" : `${getListNumber(listDepth, orderedListNumber)}.`;
|
|
9580
|
+
const body = textToken.tokens ? textToken.tokens.map((child) => formatToken(child, theme, highlight, listDepth, orderedListNumber, token)).join("") : textToken.text;
|
|
9581
|
+
return `${marker} ${body}${EOL}`;
|
|
9582
|
+
}
|
|
9583
|
+
return textToken.text;
|
|
9584
|
+
}
|
|
9585
|
+
case "escape":
|
|
9586
|
+
return token.text;
|
|
9587
|
+
case "table":
|
|
9588
|
+
case "def":
|
|
9589
|
+
case "del":
|
|
9590
|
+
case "html":
|
|
9591
|
+
return "";
|
|
9592
|
+
default:
|
|
9593
|
+
return "";
|
|
9594
|
+
}
|
|
9595
|
+
}
|
|
9596
|
+
function numberToLetter(n) {
|
|
9597
|
+
let result = "";
|
|
9598
|
+
while (n > 0) {
|
|
9599
|
+
n--;
|
|
9600
|
+
result = String.fromCharCode(97 + n % 26) + result;
|
|
9601
|
+
n = Math.floor(n / 26);
|
|
9602
|
+
}
|
|
9603
|
+
return result;
|
|
9604
|
+
}
|
|
9605
|
+
var ROMAN_VALUES = [
|
|
9606
|
+
[1e3, "m"],
|
|
9607
|
+
[900, "cm"],
|
|
9608
|
+
[500, "d"],
|
|
9609
|
+
[400, "cd"],
|
|
9610
|
+
[100, "c"],
|
|
9611
|
+
[90, "xc"],
|
|
9612
|
+
[50, "l"],
|
|
9613
|
+
[40, "xl"],
|
|
9614
|
+
[10, "x"],
|
|
9615
|
+
[9, "ix"],
|
|
9616
|
+
[5, "v"],
|
|
9617
|
+
[4, "iv"],
|
|
9618
|
+
[1, "i"]
|
|
9619
|
+
];
|
|
9620
|
+
function numberToRoman(n) {
|
|
9621
|
+
let result = "";
|
|
9622
|
+
for (const [value, numeral] of ROMAN_VALUES) {
|
|
9623
|
+
while (n >= value) {
|
|
9624
|
+
result += numeral;
|
|
9625
|
+
n -= value;
|
|
9626
|
+
}
|
|
9627
|
+
}
|
|
9628
|
+
return result;
|
|
9629
|
+
}
|
|
9630
|
+
function getListNumber(listDepth, orderedListNumber) {
|
|
9631
|
+
switch (listDepth) {
|
|
9632
|
+
case 0:
|
|
9633
|
+
case 1:
|
|
9634
|
+
return orderedListNumber.toString();
|
|
9635
|
+
case 2:
|
|
9636
|
+
return numberToLetter(orderedListNumber);
|
|
9637
|
+
case 3:
|
|
9638
|
+
return numberToRoman(orderedListNumber);
|
|
9639
|
+
default:
|
|
9640
|
+
return orderedListNumber.toString();
|
|
9641
|
+
}
|
|
9642
|
+
}
|
|
9643
|
+
function padAligned(content, displayWidth, targetWidth, align) {
|
|
9644
|
+
const padding = Math.max(0, targetWidth - displayWidth);
|
|
9645
|
+
if (align === "center") {
|
|
9646
|
+
const leftPad = Math.floor(padding / 2);
|
|
9647
|
+
return " ".repeat(leftPad) + content + " ".repeat(padding - leftPad);
|
|
9648
|
+
}
|
|
9649
|
+
if (align === "right") {
|
|
9650
|
+
return " ".repeat(padding) + content;
|
|
9651
|
+
}
|
|
9652
|
+
return content + " ".repeat(padding);
|
|
9653
|
+
}
|
|
9654
|
+
function stringWidth(text) {
|
|
9655
|
+
return visibleWidth(text);
|
|
9656
|
+
}
|
|
9657
|
+
|
|
9658
|
+
// src/react-ink/markdown/highlight.ts
|
|
9659
|
+
import { extname } from "node:path";
|
|
9660
|
+
import hljs from "highlight.js";
|
|
9661
|
+
function scopeToRole(scope) {
|
|
9662
|
+
const head = scope.split(".")[0] ?? scope;
|
|
9663
|
+
switch (head) {
|
|
9664
|
+
case "keyword":
|
|
9665
|
+
case "built_in":
|
|
9666
|
+
case "literal":
|
|
9667
|
+
case "operator":
|
|
9668
|
+
return "synKeyword";
|
|
9669
|
+
case "string":
|
|
9670
|
+
case "regexp":
|
|
9671
|
+
case "symbol":
|
|
9672
|
+
case "char":
|
|
9673
|
+
case "meta":
|
|
9674
|
+
return "synString";
|
|
9675
|
+
case "number":
|
|
9676
|
+
return "synNumber";
|
|
9677
|
+
case "comment":
|
|
9678
|
+
case "quote":
|
|
9679
|
+
return "synComment";
|
|
9680
|
+
case "type":
|
|
9681
|
+
case "class":
|
|
9682
|
+
case "title":
|
|
9683
|
+
case "tag":
|
|
9684
|
+
case "name":
|
|
9685
|
+
case "attr":
|
|
9686
|
+
case "attribute":
|
|
9687
|
+
case "selector":
|
|
9688
|
+
return "synType";
|
|
9689
|
+
default:
|
|
9690
|
+
return null;
|
|
9691
|
+
}
|
|
9692
|
+
}
|
|
9693
|
+
var HTML_ENTITIES = {
|
|
9694
|
+
"&": "&",
|
|
9695
|
+
"<": "<",
|
|
9696
|
+
">": ">",
|
|
9697
|
+
""": '"',
|
|
9698
|
+
"'": "'",
|
|
9699
|
+
"'": "'"
|
|
9700
|
+
};
|
|
9701
|
+
function decodeEntities2(text) {
|
|
9702
|
+
return text.replace(/&(?:amp|lt|gt|quot|#x27|#39);/g, (match) => HTML_ENTITIES[match] ?? match);
|
|
9703
|
+
}
|
|
9704
|
+
function parseHljsHtml(html) {
|
|
9705
|
+
const nodes = [];
|
|
9706
|
+
const scopeStack = [];
|
|
9707
|
+
const tagRe = /<span class="hljs-([^"]+)">|<\/span>/g;
|
|
9708
|
+
let lastIndex = 0;
|
|
9709
|
+
let match;
|
|
9710
|
+
const pushText = (raw) => {
|
|
9711
|
+
if (!raw) return;
|
|
9712
|
+
const currentScope = scopeStack.length > 0 ? scopeStack[scopeStack.length - 1] : null;
|
|
9713
|
+
const scope = currentScope ? currentScope.split(/\s+/)[0].replace(/_$/, "") : null;
|
|
9714
|
+
nodes.push({ text: decodeEntities2(raw), scope });
|
|
9715
|
+
};
|
|
9716
|
+
while ((match = tagRe.exec(html)) !== null) {
|
|
9717
|
+
pushText(html.slice(lastIndex, match.index));
|
|
9718
|
+
lastIndex = tagRe.lastIndex;
|
|
9719
|
+
if (match[0] === "</span>") {
|
|
9720
|
+
scopeStack.pop();
|
|
9721
|
+
} else if (match[1]) {
|
|
9722
|
+
scopeStack.push(match[1]);
|
|
9723
|
+
}
|
|
9724
|
+
}
|
|
9725
|
+
pushText(html.slice(lastIndex));
|
|
9726
|
+
return nodes;
|
|
9727
|
+
}
|
|
9728
|
+
function createHighlighter(theme) {
|
|
9729
|
+
return {
|
|
9730
|
+
supportsLanguage: (language) => {
|
|
9731
|
+
if (!language || language === "plaintext" || language === "text") {
|
|
9732
|
+
return false;
|
|
9733
|
+
}
|
|
9734
|
+
try {
|
|
9735
|
+
return hljs.getLanguage(language) !== void 0;
|
|
9736
|
+
} catch {
|
|
9737
|
+
return false;
|
|
9738
|
+
}
|
|
9739
|
+
},
|
|
9740
|
+
highlight: (code, options) => {
|
|
9741
|
+
const language = options.language;
|
|
9742
|
+
if (!language || language === "plaintext" || language === "text") {
|
|
9743
|
+
return code;
|
|
9744
|
+
}
|
|
9745
|
+
try {
|
|
9746
|
+
if (hljs.getLanguage(language) === void 0) {
|
|
9747
|
+
return code;
|
|
9748
|
+
}
|
|
9749
|
+
const { value } = hljs.highlight(code, { language, ignoreIllegals: true });
|
|
9750
|
+
return parseHljsHtml(value).map((node) => {
|
|
9751
|
+
const role = node.scope ? scopeToRole(node.scope) : null;
|
|
9752
|
+
return role ? theme.role(role, node.text) : node.text;
|
|
9753
|
+
}).join("");
|
|
9754
|
+
} catch {
|
|
9755
|
+
return code;
|
|
9756
|
+
}
|
|
9757
|
+
}
|
|
9758
|
+
};
|
|
9759
|
+
}
|
|
9760
|
+
function highlightByPath(code, filePath, theme) {
|
|
9761
|
+
const language = languageFromPath(filePath);
|
|
9762
|
+
if (!language) {
|
|
9763
|
+
return code;
|
|
9764
|
+
}
|
|
9765
|
+
const highlighter = createHighlighter(theme);
|
|
9766
|
+
if (!highlighter.supportsLanguage(language)) {
|
|
9767
|
+
return code;
|
|
9768
|
+
}
|
|
9769
|
+
return highlighter.highlight(code, { language });
|
|
9770
|
+
}
|
|
9771
|
+
var EXTENSION_LANGUAGES = {
|
|
9772
|
+
ts: "typescript",
|
|
9773
|
+
tsx: "typescript",
|
|
9774
|
+
mts: "typescript",
|
|
9775
|
+
cts: "typescript",
|
|
9776
|
+
js: "javascript",
|
|
9777
|
+
jsx: "javascript",
|
|
9778
|
+
mjs: "javascript",
|
|
9779
|
+
cjs: "javascript",
|
|
9780
|
+
py: "python",
|
|
9781
|
+
rb: "ruby",
|
|
9782
|
+
rs: "rust",
|
|
9783
|
+
go: "go",
|
|
9784
|
+
java: "java",
|
|
9785
|
+
kt: "kotlin",
|
|
9786
|
+
c: "c",
|
|
9787
|
+
h: "c",
|
|
9788
|
+
cc: "cpp",
|
|
9789
|
+
cpp: "cpp",
|
|
9790
|
+
hpp: "cpp",
|
|
9791
|
+
cs: "csharp",
|
|
9792
|
+
sh: "bash",
|
|
9793
|
+
bash: "bash",
|
|
9794
|
+
zsh: "bash",
|
|
9795
|
+
yml: "yaml",
|
|
9796
|
+
yaml: "yaml",
|
|
9797
|
+
json: "json",
|
|
9798
|
+
md: "markdown",
|
|
9799
|
+
html: "xml",
|
|
9800
|
+
xml: "xml",
|
|
9801
|
+
css: "css",
|
|
9802
|
+
scss: "scss",
|
|
9803
|
+
sql: "sql",
|
|
9804
|
+
toml: "ini",
|
|
9805
|
+
ini: "ini",
|
|
9806
|
+
php: "php",
|
|
9807
|
+
swift: "swift"
|
|
9808
|
+
};
|
|
9809
|
+
function languageFromPath(filePath) {
|
|
9810
|
+
const ext = extname(filePath).slice(1).toLowerCase();
|
|
9811
|
+
if (!ext) {
|
|
9812
|
+
return null;
|
|
9813
|
+
}
|
|
9814
|
+
const mapped = EXTENSION_LANGUAGES[ext];
|
|
9815
|
+
if (mapped) {
|
|
9816
|
+
return mapped;
|
|
9817
|
+
}
|
|
9818
|
+
try {
|
|
9819
|
+
return hljs.getLanguage(ext) !== void 0 ? ext : null;
|
|
9820
|
+
} catch {
|
|
9821
|
+
return null;
|
|
9822
|
+
}
|
|
9823
|
+
}
|
|
9824
|
+
|
|
9825
|
+
// src/react-ink/markdown/MarkdownTable.tsx
|
|
9826
|
+
import chalk3 from "chalk";
|
|
9827
|
+
import stripAnsi4 from "strip-ansi";
|
|
9828
|
+
var MIN_COLUMN_WIDTH = 3;
|
|
9829
|
+
var COLUMN_GAP = 2;
|
|
9830
|
+
function MarkdownTable({ token, theme, highlight = null }) {
|
|
9831
|
+
const formatCell = (tokens) => (tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("");
|
|
9832
|
+
const displayWidth = (tokens) => stringWidth(stripAnsi4(formatCell(tokens)));
|
|
9833
|
+
const columnCount = token.header.length;
|
|
9834
|
+
const columnWidths = token.header.map((header, index) => {
|
|
9835
|
+
let max = displayWidth(header.tokens);
|
|
9836
|
+
for (const row of token.rows) {
|
|
9837
|
+
max = Math.max(max, displayWidth(row[index]?.tokens));
|
|
9838
|
+
}
|
|
9839
|
+
return Math.max(max, MIN_COLUMN_WIDTH);
|
|
9840
|
+
});
|
|
9841
|
+
const renderRow2 = (cells, key, bold) => /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: columnWidths.map((width, index) => {
|
|
9842
|
+
const cell = cells[index];
|
|
9843
|
+
const content = formatCell(cell?.tokens);
|
|
9844
|
+
const visible = stringWidth(stripAnsi4(content));
|
|
9845
|
+
const align = token.align?.[index];
|
|
9846
|
+
const padded = padAligned(content, visible, width, align ?? "left");
|
|
9847
|
+
const styled = bold ? chalk3.bold(padded) : padded;
|
|
9848
|
+
const gap = index < columnCount - 1 ? " ".repeat(COLUMN_GAP) : "";
|
|
9849
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
9850
|
+
styled,
|
|
9851
|
+
gap
|
|
9852
|
+
] }, index);
|
|
9853
|
+
}) }, key);
|
|
9854
|
+
const separator = /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: columnWidths.map((width, index) => {
|
|
9855
|
+
const gap = index < columnCount - 1 ? " ".repeat(COLUMN_GAP) : "";
|
|
9856
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
9857
|
+
theme.dim("-".repeat(width)),
|
|
9858
|
+
gap
|
|
9859
|
+
] }, index);
|
|
9860
|
+
}) });
|
|
9861
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
9862
|
+
renderRow2(token.header, "header", true),
|
|
9863
|
+
separator,
|
|
9864
|
+
token.rows.map((row, rowIndex) => renderRow2(row, `row-${rowIndex}`, false))
|
|
9865
|
+
] });
|
|
9866
|
+
}
|
|
9867
|
+
|
|
9868
|
+
// src/react-ink/markdown/Markdown.tsx
|
|
9869
|
+
function stripPromptXMLTags(text) {
|
|
9870
|
+
return text.replace(/<\/?(?:system-reminder|prompt|context)[^>]*>/g, "");
|
|
9871
|
+
}
|
|
9872
|
+
function Markdown({ children, theme, highlightCode = true, dim = false }) {
|
|
9873
|
+
const highlight = useMemo(
|
|
9874
|
+
() => highlightCode ? createHighlighter(theme) : null,
|
|
9875
|
+
[highlightCode, theme]
|
|
9876
|
+
);
|
|
9877
|
+
const elements = useMemo(() => {
|
|
9878
|
+
configureMarked();
|
|
9879
|
+
const tokens = cachedLexer(stripPromptXMLTags(children));
|
|
9880
|
+
const out = [];
|
|
9881
|
+
let buffer = "";
|
|
9882
|
+
const flush = () => {
|
|
9883
|
+
if (buffer) {
|
|
9884
|
+
const text = buffer.replace(/\n+$/, "");
|
|
9885
|
+
if (text) {
|
|
9886
|
+
out.push(
|
|
9887
|
+
/* @__PURE__ */ jsx(Text, { children: dim ? theme.dim(text) : text }, out.length)
|
|
9888
|
+
);
|
|
9889
|
+
}
|
|
9890
|
+
buffer = "";
|
|
9891
|
+
}
|
|
9892
|
+
};
|
|
9893
|
+
for (const token of tokens) {
|
|
9894
|
+
if (token.type === "table") {
|
|
9895
|
+
flush();
|
|
9896
|
+
out.push(
|
|
9897
|
+
/* @__PURE__ */ jsx(
|
|
9898
|
+
MarkdownTable,
|
|
9899
|
+
{
|
|
9900
|
+
token,
|
|
9901
|
+
theme,
|
|
9902
|
+
highlight
|
|
9903
|
+
},
|
|
9904
|
+
out.length
|
|
9905
|
+
)
|
|
9906
|
+
);
|
|
9907
|
+
} else {
|
|
9908
|
+
buffer += formatToken(token, theme, highlight);
|
|
9909
|
+
}
|
|
9910
|
+
}
|
|
9911
|
+
flush();
|
|
9912
|
+
return out;
|
|
9913
|
+
}, [children, dim, highlight, theme]);
|
|
9914
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: elements });
|
|
9915
|
+
}
|
|
9916
|
+
|
|
8891
9917
|
// src/react-ink/utils/tool-display.ts
|
|
8892
9918
|
import { homedir as homedir2 } from "node:os";
|
|
9919
|
+
|
|
9920
|
+
// src/react-ink/diff/structured.ts
|
|
9921
|
+
import { structuredPatch } from "diff";
|
|
9922
|
+
|
|
9923
|
+
// src/react-ink/diff/word-diff.ts
|
|
9924
|
+
import { diffWordsWithSpace } from "diff";
|
|
9925
|
+
var CHANGE_THRESHOLD = 0.4;
|
|
9926
|
+
function wordDiffLine(oldLine, newLine, side) {
|
|
9927
|
+
const lineText = side === "removed" ? oldLine : newLine;
|
|
9928
|
+
if (oldLine.length === 0 || newLine.length === 0) {
|
|
9929
|
+
return [{ text: lineText, changed: true }];
|
|
9930
|
+
}
|
|
9931
|
+
let changes;
|
|
9932
|
+
try {
|
|
9933
|
+
changes = diffWordsWithSpace(oldLine, newLine);
|
|
9934
|
+
} catch {
|
|
9935
|
+
return [{ text: lineText, changed: true }];
|
|
9936
|
+
}
|
|
9937
|
+
let changedChars = 0;
|
|
9938
|
+
let totalChars = 0;
|
|
9939
|
+
for (const change of changes) {
|
|
9940
|
+
totalChars += change.value.length;
|
|
9941
|
+
if (change.added || change.removed) {
|
|
9942
|
+
changedChars += change.value.length;
|
|
9943
|
+
}
|
|
9944
|
+
}
|
|
9945
|
+
const fraction = totalChars === 0 ? 0 : changedChars / totalChars;
|
|
9946
|
+
if (fraction > CHANGE_THRESHOLD) {
|
|
9947
|
+
return [{ text: lineText, changed: true }];
|
|
9948
|
+
}
|
|
9949
|
+
const spans = [];
|
|
9950
|
+
for (const change of changes) {
|
|
9951
|
+
const belongs = side === "removed" ? !change.added : !change.removed;
|
|
9952
|
+
if (!belongs) {
|
|
9953
|
+
continue;
|
|
9954
|
+
}
|
|
9955
|
+
spans.push({ text: change.value, changed: Boolean(change.added || change.removed) });
|
|
9956
|
+
}
|
|
9957
|
+
return spans.length > 0 ? spans : [{ text: lineText, changed: false }];
|
|
9958
|
+
}
|
|
9959
|
+
|
|
9960
|
+
// src/react-ink/diff/structured.ts
|
|
9961
|
+
var CONTEXT_LINES = 3;
|
|
9962
|
+
function buildStructuredDiff(oldStr, newStr, filePath = "") {
|
|
9963
|
+
if (oldStr === newStr) {
|
|
9964
|
+
return null;
|
|
9965
|
+
}
|
|
9966
|
+
let patch;
|
|
9967
|
+
try {
|
|
9968
|
+
patch = structuredPatch(filePath, filePath, oldStr, newStr, "", "", { context: CONTEXT_LINES });
|
|
9969
|
+
} catch {
|
|
9970
|
+
return null;
|
|
9971
|
+
}
|
|
9972
|
+
const hunks = [];
|
|
9973
|
+
let addedCount = 0;
|
|
9974
|
+
let removedCount = 0;
|
|
9975
|
+
for (const hunk of patch.hunks) {
|
|
9976
|
+
const lines = classifyHunkLines(hunk);
|
|
9977
|
+
for (const line of lines) {
|
|
9978
|
+
if (line.kind === "added") addedCount += 1;
|
|
9979
|
+
else if (line.kind === "removed") removedCount += 1;
|
|
9980
|
+
}
|
|
9981
|
+
if (lines.length > 0) {
|
|
9982
|
+
hunks.push({ oldStart: hunk.oldStart, newStart: hunk.newStart, lines });
|
|
9983
|
+
}
|
|
9984
|
+
}
|
|
9985
|
+
if (hunks.length === 0) {
|
|
9986
|
+
return null;
|
|
9987
|
+
}
|
|
9988
|
+
return { hunks, addedCount, removedCount };
|
|
9989
|
+
}
|
|
9990
|
+
function classifyHunkLines(hunk) {
|
|
9991
|
+
const out = [];
|
|
9992
|
+
let oldNum = hunk.oldStart;
|
|
9993
|
+
let newNum = hunk.newStart;
|
|
9994
|
+
const rawLines = hunk.lines.filter((line) => !line.startsWith("\\"));
|
|
9995
|
+
let removedRun = [];
|
|
9996
|
+
let removedRunStart = -1;
|
|
9997
|
+
const flushPairing = (addedRun2) => {
|
|
9998
|
+
const pairs = Math.min(removedRun.length, addedRun2.length);
|
|
9999
|
+
for (let i = 0; i < pairs; i += 1) {
|
|
10000
|
+
const removed = removedRun[i];
|
|
10001
|
+
const added = addedRun2[i];
|
|
10002
|
+
removed.spans = wordDiffLine(removed.text, added.text, "removed");
|
|
10003
|
+
added.spans = wordDiffLine(removed.text, added.text, "added");
|
|
10004
|
+
}
|
|
10005
|
+
removedRun = [];
|
|
10006
|
+
removedRunStart = -1;
|
|
10007
|
+
};
|
|
10008
|
+
let addedRun = [];
|
|
10009
|
+
for (const raw of rawLines) {
|
|
10010
|
+
const marker = raw[0];
|
|
10011
|
+
const text = raw.slice(1);
|
|
10012
|
+
if (marker === "-") {
|
|
10013
|
+
if (addedRun.length > 0) {
|
|
10014
|
+
addedRun = [];
|
|
10015
|
+
}
|
|
10016
|
+
const line = { kind: "removed", oldLine: oldNum, text };
|
|
10017
|
+
out.push(line);
|
|
10018
|
+
if (removedRunStart === -1) removedRunStart = out.length - 1;
|
|
10019
|
+
removedRun.push(line);
|
|
10020
|
+
oldNum += 1;
|
|
10021
|
+
} else if (marker === "+") {
|
|
10022
|
+
const line = { kind: "added", newLine: newNum, text };
|
|
10023
|
+
out.push(line);
|
|
10024
|
+
addedRun.push(line);
|
|
10025
|
+
newNum += 1;
|
|
10026
|
+
} else {
|
|
10027
|
+
if (removedRun.length > 0 && addedRun.length > 0) {
|
|
10028
|
+
flushPairing(addedRun);
|
|
10029
|
+
}
|
|
10030
|
+
removedRun = [];
|
|
10031
|
+
removedRunStart = -1;
|
|
10032
|
+
addedRun = [];
|
|
10033
|
+
out.push({ kind: "context", oldLine: oldNum, newLine: newNum, text });
|
|
10034
|
+
oldNum += 1;
|
|
10035
|
+
newNum += 1;
|
|
10036
|
+
}
|
|
10037
|
+
}
|
|
10038
|
+
if (removedRun.length > 0 && addedRun.length > 0) {
|
|
10039
|
+
flushPairing(addedRun);
|
|
10040
|
+
}
|
|
10041
|
+
return out;
|
|
10042
|
+
}
|
|
10043
|
+
|
|
10044
|
+
// src/react-ink/utils/tool-display.ts
|
|
8893
10045
|
function asRecord2(value) {
|
|
8894
10046
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
8895
10047
|
}
|
|
@@ -8972,6 +10124,12 @@ function clipBody(value, maxLines = 8, maxChars = 1400) {
|
|
|
8972
10124
|
}
|
|
8973
10125
|
return previewMultiline(value, { maxLines, maxChars });
|
|
8974
10126
|
}
|
|
10127
|
+
function highlightedBody(body, filePath, theme) {
|
|
10128
|
+
if (!body || !theme || !filePath || languageFromPath(filePath) === null) {
|
|
10129
|
+
return { body };
|
|
10130
|
+
}
|
|
10131
|
+
return { body: highlightByPath(body, filePath, theme), preformatted: true };
|
|
10132
|
+
}
|
|
8975
10133
|
function extractDetails(value) {
|
|
8976
10134
|
return asRecord2(asRecord2(value)?.details);
|
|
8977
10135
|
}
|
|
@@ -9038,7 +10196,7 @@ function fallbackBody(output, fallbackOutputText, showImages = false) {
|
|
|
9038
10196
|
return clipBody(fallbackOutputText);
|
|
9039
10197
|
}
|
|
9040
10198
|
function describeToolSource(source) {
|
|
9041
|
-
const { args, fallbackArgsText, fallbackOutputText, output, showImages = false, toolName } = source;
|
|
10199
|
+
const { args, fallbackArgsText, fallbackOutputText, output, showImages = false, theme, toolName } = source;
|
|
9042
10200
|
const argsRecord = asRecord2(args);
|
|
9043
10201
|
const details = extractDetails(output);
|
|
9044
10202
|
const outputText = toolText(output, showImages);
|
|
@@ -9056,10 +10214,12 @@ function describeToolSource(source) {
|
|
|
9056
10214
|
summary += `:${start}${end ? `-${end}` : ""}`;
|
|
9057
10215
|
}
|
|
9058
10216
|
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";
|
|
10217
|
+
const readBody = hasResult && !containsImage(output) ? highlightedBody(clipBody(outputText, 10, 1800), rawPath, theme) : { body: hasResult ? clipBody(outputText, 10, 1800) : void 0 };
|
|
9059
10218
|
return {
|
|
9060
10219
|
title,
|
|
9061
10220
|
summary: hasResult ? responseSummary : summary,
|
|
9062
|
-
body:
|
|
10221
|
+
body: readBody.body,
|
|
10222
|
+
preformatted: readBody.preformatted,
|
|
9063
10223
|
emptyText: "Reading file..."
|
|
9064
10224
|
};
|
|
9065
10225
|
}
|
|
@@ -9067,10 +10227,14 @@ function describeToolSource(source) {
|
|
|
9067
10227
|
const rawPath = asString(argsRecord?.file_path) ?? asString(argsRecord?.path) ?? "";
|
|
9068
10228
|
const content = asString(argsRecord?.content);
|
|
9069
10229
|
const responseSummary = firstMeaningfulLine(outputText) ?? "Wrote file";
|
|
10230
|
+
const writeDiff = !hasResult && content !== void 0 && content.length > 0 ? buildStructuredDiff("", content, rawPath) ?? void 0 : void 0;
|
|
10231
|
+
const writeBody = hasResult ? { body: clipBody(outputText, 8, 1500) } : highlightedBody(clipBody(content, 8, 1500), rawPath, theme);
|
|
9070
10232
|
return {
|
|
9071
10233
|
title,
|
|
9072
10234
|
summary: hasResult ? responseSummary : rawPath ? shortenPath2(rawPath) : void 0,
|
|
9073
|
-
body:
|
|
10235
|
+
body: writeDiff ? void 0 : writeBody.body,
|
|
10236
|
+
preformatted: writeDiff ? void 0 : writeBody.preformatted,
|
|
10237
|
+
diff: writeDiff,
|
|
9074
10238
|
emptyText: "Preparing file write..."
|
|
9075
10239
|
};
|
|
9076
10240
|
}
|
|
@@ -9087,10 +10251,15 @@ function describeToolSource(source) {
|
|
|
9087
10251
|
400
|
|
9088
10252
|
) : void 0;
|
|
9089
10253
|
const responseSummary = firstMeaningfulLine(outputText) ?? "Applied edit";
|
|
10254
|
+
const editDiff = oldText !== void 0 && newText !== void 0 ? buildStructuredDiff(oldText, newText, rawPath) ?? void 0 : void 0;
|
|
10255
|
+
const editBody = hasResult ? highlightedBody(clipBody(outputText, 8, 1500), rawPath, theme) : { body: replacementPreview };
|
|
10256
|
+
const editChangeSummary = editDiff ? `+${editDiff.addedCount} -${editDiff.removedCount}` : void 0;
|
|
9090
10257
|
return {
|
|
9091
10258
|
title,
|
|
9092
|
-
summary: hasResult ? responseSummary : rawPath ? shortenPath2(rawPath) : void 0,
|
|
9093
|
-
body:
|
|
10259
|
+
summary: hasResult ? editChangeSummary ?? responseSummary : editChangeSummary ?? (rawPath ? shortenPath2(rawPath) : void 0),
|
|
10260
|
+
body: editDiff ? void 0 : editBody.body,
|
|
10261
|
+
preformatted: editDiff ? void 0 : editBody.preformatted,
|
|
10262
|
+
diff: editDiff,
|
|
9094
10263
|
emptyText: "Applying edit..."
|
|
9095
10264
|
};
|
|
9096
10265
|
}
|
|
@@ -9187,7 +10356,7 @@ function describeToolCall(toolCall) {
|
|
|
9187
10356
|
args: toolCall.arguments
|
|
9188
10357
|
});
|
|
9189
10358
|
}
|
|
9190
|
-
function describeToolResult(message, showImages, args) {
|
|
10359
|
+
function describeToolResult(message, showImages, args, theme) {
|
|
9191
10360
|
return describeToolSource({
|
|
9192
10361
|
args,
|
|
9193
10362
|
toolName: message.toolName,
|
|
@@ -9195,12 +10364,13 @@ function describeToolResult(message, showImages, args) {
|
|
|
9195
10364
|
content: message.content,
|
|
9196
10365
|
details: message.details
|
|
9197
10366
|
},
|
|
9198
|
-
showImages
|
|
10367
|
+
showImages,
|
|
10368
|
+
theme
|
|
9199
10369
|
});
|
|
9200
10370
|
}
|
|
9201
10371
|
|
|
9202
10372
|
// src/react-ink/components/ToolEventBlock.tsx
|
|
9203
|
-
import
|
|
10373
|
+
import stripAnsi5 from "strip-ansi";
|
|
9204
10374
|
function statusMarker(status) {
|
|
9205
10375
|
switch (status) {
|
|
9206
10376
|
case "error":
|
|
@@ -9212,11 +10382,11 @@ function statusMarker(status) {
|
|
|
9212
10382
|
}
|
|
9213
10383
|
}
|
|
9214
10384
|
function plainToolText(text) {
|
|
9215
|
-
return
|
|
10385
|
+
return stripAnsi5(text);
|
|
9216
10386
|
}
|
|
9217
10387
|
function splitVisibleLines(text) {
|
|
9218
10388
|
return (text ?? "").split(/\r?\n/).map((line) => line.trimEnd()).filter((line, index, lines) => {
|
|
9219
|
-
if (line.length > 0) {
|
|
10389
|
+
if (stripAnsi5(line).length > 0) {
|
|
9220
10390
|
return true;
|
|
9221
10391
|
}
|
|
9222
10392
|
return index !== 0 && index !== lines.length - 1;
|
|
@@ -9247,6 +10417,7 @@ function ToolEventBlock({
|
|
|
9247
10417
|
indent = 0,
|
|
9248
10418
|
marginBottom = 1,
|
|
9249
10419
|
maxContentLines = 10,
|
|
10420
|
+
preformatted = false,
|
|
9250
10421
|
showSummaryInline = false,
|
|
9251
10422
|
showTitle = true,
|
|
9252
10423
|
status,
|
|
@@ -9275,9 +10446,9 @@ function ToolEventBlock({
|
|
|
9275
10446
|
Box,
|
|
9276
10447
|
{
|
|
9277
10448
|
marginLeft: line.kind === "response" ? showTitle ? 2 : 0 : showTitle ? 4 : 2,
|
|
9278
|
-
children: /* @__PURE__ */ jsx(Text, { color: "white", children: plainToolText(line.text) })
|
|
10449
|
+
children: preformatted ? /* @__PURE__ */ jsx(Text, { children: line.text }) : /* @__PURE__ */ jsx(Text, { color: "white", children: plainToolText(line.text) })
|
|
9279
10450
|
},
|
|
9280
|
-
`${line.kind}:${index}:${line.text}`
|
|
10451
|
+
`${line.kind}:${index}:${stripAnsi5(line.text)}`
|
|
9281
10452
|
)),
|
|
9282
10453
|
hiddenLineCount > 0 ? /* @__PURE__ */ jsx(Box, { marginLeft: showTitle ? 4 : 2, children: /* @__PURE__ */ jsx(Text, { color: "white", children: plainToolText(`... ${hiddenLineCount} more line(s)`) }) }) : null
|
|
9283
10454
|
] });
|
|
@@ -9302,17 +10473,100 @@ function ToolCallMessage({ theme, toolCall }) {
|
|
|
9302
10473
|
);
|
|
9303
10474
|
}
|
|
9304
10475
|
|
|
10476
|
+
// src/react-ink/diff/Diff.tsx
|
|
10477
|
+
import chalk4 from "chalk";
|
|
10478
|
+
function lineMarker(kind) {
|
|
10479
|
+
switch (kind) {
|
|
10480
|
+
case "added":
|
|
10481
|
+
return "+";
|
|
10482
|
+
case "removed":
|
|
10483
|
+
return "-";
|
|
10484
|
+
default:
|
|
10485
|
+
return " ";
|
|
10486
|
+
}
|
|
10487
|
+
}
|
|
10488
|
+
function gutterWidth(diff) {
|
|
10489
|
+
let max = 1;
|
|
10490
|
+
for (const hunk of diff.hunks) {
|
|
10491
|
+
for (const line of hunk.lines) {
|
|
10492
|
+
const num2 = line.kind === "removed" ? line.oldLine : line.newLine;
|
|
10493
|
+
if (num2 !== void 0) {
|
|
10494
|
+
max = Math.max(max, stringWidth(String(num2)));
|
|
10495
|
+
}
|
|
10496
|
+
}
|
|
10497
|
+
}
|
|
10498
|
+
return max;
|
|
10499
|
+
}
|
|
10500
|
+
function renderLineText(line, theme, bgRole, fgRole) {
|
|
10501
|
+
const paintSpan = (text, changed) => {
|
|
10502
|
+
const fg = theme.role(fgRole, text);
|
|
10503
|
+
return changed ? chalk4.bold(fg) : fg;
|
|
10504
|
+
};
|
|
10505
|
+
let body;
|
|
10506
|
+
if (line.spans && line.spans.length > 0) {
|
|
10507
|
+
body = line.spans.map((span) => paintSpan(span.text, span.changed)).join("");
|
|
10508
|
+
} else {
|
|
10509
|
+
body = theme.role(fgRole, line.text);
|
|
10510
|
+
}
|
|
10511
|
+
return bgRole ? theme.roleBackground(bgRole, body) : body;
|
|
10512
|
+
}
|
|
10513
|
+
function Diff({ diff, theme, indent = 0, marginBottom = 0 }) {
|
|
10514
|
+
const gutter = gutterWidth(diff);
|
|
10515
|
+
const renderLine = (line, key) => {
|
|
10516
|
+
const num2 = line.kind === "removed" ? line.oldLine : line.newLine;
|
|
10517
|
+
const gutterText = (num2 !== void 0 ? String(num2) : "").padStart(gutter);
|
|
10518
|
+
const marker = lineMarker(line.kind);
|
|
10519
|
+
const bgRole = line.kind === "added" ? "diffAddedBg" : line.kind === "removed" ? "diffRemovedBg" : null;
|
|
10520
|
+
const fgRole = line.kind === "added" ? "diffAddedText" : line.kind === "removed" ? "diffRemovedText" : "blockquoteBar";
|
|
10521
|
+
const gutterStyled = theme.dim(`${gutterText} `);
|
|
10522
|
+
const markerStyled = line.kind === "context" ? theme.dim(`${marker} `) : theme.role(fgRole, `${marker} `);
|
|
10523
|
+
const text = renderLineText(line, theme, bgRole, fgRole);
|
|
10524
|
+
return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
10525
|
+
gutterStyled,
|
|
10526
|
+
markerStyled,
|
|
10527
|
+
text
|
|
10528
|
+
] }) }, key);
|
|
10529
|
+
};
|
|
10530
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: indent, marginBottom, children: diff.hunks.map((hunk, hunkIndex) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
10531
|
+
hunkIndex > 0 ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { children: theme.dim("...") }) }) : null,
|
|
10532
|
+
hunk.lines.map((line, lineIndex) => renderLine(line, `${hunkIndex}-${lineIndex}`))
|
|
10533
|
+
] }, `hunk-${hunkIndex}`)) });
|
|
10534
|
+
}
|
|
10535
|
+
|
|
9305
10536
|
// src/react-ink/components/messages/ToolResultBlock.tsx
|
|
9306
10537
|
function ToolResultBlock({ expanded = false, message, nested = false, showImages, theme, toolCall }) {
|
|
9307
|
-
const descriptor = describeToolResult(message, showImages, toolCall?.arguments);
|
|
10538
|
+
const descriptor = describeToolResult(message, showImages, toolCall?.arguments, theme);
|
|
10539
|
+
const indent = nested ? 4 : 2;
|
|
10540
|
+
if (descriptor.diff) {
|
|
10541
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 0, children: [
|
|
10542
|
+
/* @__PURE__ */ jsx(
|
|
10543
|
+
ToolEventBlock,
|
|
10544
|
+
{
|
|
10545
|
+
detail: void 0,
|
|
10546
|
+
emptyText: descriptor.emptyText,
|
|
10547
|
+
indent,
|
|
10548
|
+
marginBottom: 0,
|
|
10549
|
+
maxContentLines: 0,
|
|
10550
|
+
showSummaryInline: false,
|
|
10551
|
+
showTitle: !nested,
|
|
10552
|
+
status: message.isError ? "error" : "success",
|
|
10553
|
+
summary: descriptor.summary,
|
|
10554
|
+
theme,
|
|
10555
|
+
title: descriptor.title
|
|
10556
|
+
}
|
|
10557
|
+
),
|
|
10558
|
+
/* @__PURE__ */ jsx(Diff, { diff: descriptor.diff, theme, indent: indent + 2 })
|
|
10559
|
+
] });
|
|
10560
|
+
}
|
|
9308
10561
|
return /* @__PURE__ */ jsx(
|
|
9309
10562
|
ToolEventBlock,
|
|
9310
10563
|
{
|
|
9311
10564
|
detail: descriptor.body,
|
|
9312
10565
|
emptyText: descriptor.emptyText,
|
|
9313
|
-
indent
|
|
10566
|
+
indent,
|
|
9314
10567
|
marginBottom: 0,
|
|
9315
10568
|
maxContentLines: expanded ? Number.MAX_SAFE_INTEGER : 10,
|
|
10569
|
+
preformatted: descriptor.preformatted,
|
|
9316
10570
|
showSummaryInline: false,
|
|
9317
10571
|
showTitle: !nested,
|
|
9318
10572
|
status: message.isError ? "error" : "success",
|
|
@@ -9337,7 +10591,7 @@ function AssistantMessageView({
|
|
|
9337
10591
|
const matchedToolResultIds = /* @__PURE__ */ new Set();
|
|
9338
10592
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
9339
10593
|
/* @__PURE__ */ jsx(Text, { children: theme.color("accent", `Assistant ${message.provider}/${message.model} ${formatMessageTimestamp(message.timestamp)}`) }),
|
|
9340
|
-
parts.text ? /* @__PURE__ */ jsx(
|
|
10594
|
+
parts.text ? /* @__PURE__ */ jsx(Markdown, { theme, children: parts.text }) : null,
|
|
9341
10595
|
parts.thinking.map((thinking, index) => /* @__PURE__ */ jsx(Text, { children: theme.muted(`[thinking] ${thinking}`) }, index)),
|
|
9342
10596
|
parts.toolCalls.map((toolCall) => {
|
|
9343
10597
|
const toolResult = toolResultsByCallId.get(toolCall.id);
|