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