indusagi 0.12.33 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/agent.js +1247 -184
- package/dist/ai.js +72 -4
- package/dist/capabilities.js +69 -2
- package/dist/cli.js +1353 -29
- package/dist/connectors-saas.js +66 -0
- package/dist/index.js +1353 -29
- package/dist/interop.js +66 -0
- package/dist/mcp.js +270 -363
- package/dist/react-ink.js +1391 -41
- package/dist/shell-app.js +1353 -29
- package/dist/smithy.js +69 -2
- package/dist/swarm.js +69 -2
- package/dist/types/capabilities/backends/node-backends.d.ts +3 -1
- package/dist/types/capabilities/files/read-state-gate.d.ts +69 -0
- package/dist/types/capabilities/files/read-state-gate.test.d.ts +14 -0
- package/dist/types/capabilities/kernel/context.d.ts +4 -0
- package/dist/types/capabilities/kernel/index.d.ts +2 -2
- package/dist/types/capabilities/kernel/spec.d.ts +55 -0
- package/dist/types/facade/bot/actions/bash.d.ts +15 -0
- package/dist/types/facade/bot/actions/bash.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/checkpoint.d.ts +49 -0
- package/dist/types/facade/bot/actions/checkpoint.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/edit-utils.d.ts +86 -0
- package/dist/types/facade/bot/actions/edit.d.ts +18 -0
- package/dist/types/facade/bot/actions/edit.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/find.d.ts +2 -0
- package/dist/types/facade/bot/actions/find.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/grep.d.ts +10 -0
- package/dist/types/facade/bot/actions/grep.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/index.d.ts +16 -0
- package/dist/types/facade/bot/actions/read-state.d.ts +83 -0
- package/dist/types/facade/bot/actions/read-state.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/read.d.ts +7 -0
- package/dist/types/facade/bot/actions/read.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/sandbox-backend.d.ts +99 -0
- package/dist/types/facade/bot/actions/sandbox-backend.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/websearch.d.ts +5 -2
- package/dist/types/facade/bot/actions/websearch.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/write.d.ts +15 -0
- package/dist/types/facade/bot/agent-loop.d.ts +10 -0
- package/dist/types/facade/bot/agent-loop.test.d.ts +1 -0
- package/dist/types/facade/bot/agent.d.ts +9 -1
- package/dist/types/facade/bot/permission-gate.test.d.ts +1 -0
- package/dist/types/facade/bot/types.d.ts +60 -0
- package/dist/types/facade/mcp-core/client.d.ts +71 -15
- package/dist/types/facade/mcp-core/client.test.d.ts +18 -0
- package/dist/types/facade/mcp-core/types.d.ts +10 -0
- package/dist/types/facade/ml/adapters/anthropic-retry.test.d.ts +1 -0
- package/dist/types/facade/ml/adapters/anthropic.d.ts +17 -0
- package/dist/types/facade/ml/adapters/simple-options.d.ts +13 -0
- package/dist/types/facade/ml/adapters/simple-options.test.d.ts +1 -0
- package/dist/types/react-ink/components/StatusLine.d.ts +10 -1
- package/dist/types/react-ink/components/ToolEventBlock.d.ts +9 -1
- package/dist/types/react-ink/components/ToolEventBlock.test.d.ts +1 -0
- package/dist/types/react-ink/components/dialogs/SelectableDialog.d.ts +7 -1
- package/dist/types/react-ink/components/dialogs/ThemeDialog.d.ts +21 -2
- package/dist/types/react-ink/diff/Diff.d.ts +22 -0
- package/dist/types/react-ink/diff/diff.test.d.ts +1 -0
- package/dist/types/react-ink/diff/structured.d.ts +41 -0
- package/dist/types/react-ink/diff/word-diff.d.ts +27 -0
- package/dist/types/react-ink/index.d.ts +8 -0
- package/dist/types/react-ink/markdown/Markdown.d.ts +23 -0
- package/dist/types/react-ink/markdown/MarkdownTable.d.ts +19 -0
- package/dist/types/react-ink/markdown/StreamingMarkdown.d.ts +34 -0
- package/dist/types/react-ink/markdown/format-token.d.ts +39 -0
- package/dist/types/react-ink/markdown/highlight.d.ts +31 -0
- package/dist/types/react-ink/theme-adapter.d.ts +58 -1
- package/dist/types/react-ink/utils/tool-display.d.ts +17 -1
- package/package.json +5 -1
package/dist/react-ink.js
CHANGED
|
@@ -1,6 +1,34 @@
|
|
|
1
1
|
// src/react-ink/theme-adapter.ts
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import stripAnsi from "strip-ansi";
|
|
4
|
+
var DEFAULT_ROLE_KEYS = {
|
|
5
|
+
codeInline: "codeInline",
|
|
6
|
+
heading: "heading",
|
|
7
|
+
blockquoteBar: "blockquoteBar",
|
|
8
|
+
diffAddedBg: "diffAddedBg",
|
|
9
|
+
diffRemovedBg: "diffRemovedBg",
|
|
10
|
+
diffAddedText: "diffAddedText",
|
|
11
|
+
diffRemovedText: "diffRemovedText",
|
|
12
|
+
synKeyword: "synKeyword",
|
|
13
|
+
synString: "synString",
|
|
14
|
+
synNumber: "synNumber",
|
|
15
|
+
synComment: "synComment",
|
|
16
|
+
synType: "synType"
|
|
17
|
+
};
|
|
18
|
+
var ROLE_FALLBACK_KEYS = {
|
|
19
|
+
codeInline: "accent",
|
|
20
|
+
heading: "accent",
|
|
21
|
+
blockquoteBar: "muted",
|
|
22
|
+
diffAddedBg: "success",
|
|
23
|
+
diffRemovedBg: "error",
|
|
24
|
+
diffAddedText: "success",
|
|
25
|
+
diffRemovedText: "error",
|
|
26
|
+
synKeyword: "accent",
|
|
27
|
+
synString: "success",
|
|
28
|
+
synNumber: "warning",
|
|
29
|
+
synComment: "muted",
|
|
30
|
+
synType: "info"
|
|
31
|
+
};
|
|
4
32
|
function applyForeground(color, text) {
|
|
5
33
|
if (!color) return text;
|
|
6
34
|
try {
|
|
@@ -27,15 +55,27 @@ function applyBackground(background, foreground, text) {
|
|
|
27
55
|
return applyForeground(foreground, text);
|
|
28
56
|
}
|
|
29
57
|
}
|
|
30
|
-
function createThemeAdapter(themeName, colors) {
|
|
58
|
+
function createThemeAdapter(themeName, colors, roleOverrides) {
|
|
31
59
|
const fallback = colors.text ?? "#e5e5e7";
|
|
60
|
+
const roles = { ...DEFAULT_ROLE_KEYS, ...roleOverrides };
|
|
61
|
+
const resolveRoleColor = (role) => resolveColorToken(
|
|
62
|
+
colors[roles[role]],
|
|
63
|
+
resolveColorToken(colors[ROLE_FALLBACK_KEYS[role]], fallback)
|
|
64
|
+
);
|
|
32
65
|
return {
|
|
33
66
|
name: themeName,
|
|
34
67
|
colors,
|
|
68
|
+
roles,
|
|
35
69
|
color: (key, text) => applyForeground(resolveColorToken(colors[key], fallback), text),
|
|
36
70
|
background: (key, text, textKey = "text") => applyBackground(resolveColorToken(colors[key]), resolveColorToken(colors[textKey], fallback), ` ${stripAnsi(text)} `),
|
|
37
71
|
dim: (text) => applyForeground(resolveColorToken(colors.dim, "#666666"), text),
|
|
38
|
-
muted: (text) => applyForeground(resolveColorToken(colors.muted, "#808080"), text)
|
|
72
|
+
muted: (text) => applyForeground(resolveColorToken(colors.muted, "#808080"), text),
|
|
73
|
+
role: (role, text) => applyForeground(resolveRoleColor(role), text),
|
|
74
|
+
roleBackground: (role, text, foregroundRole) => applyBackground(
|
|
75
|
+
resolveRoleColor(role),
|
|
76
|
+
foregroundRole ? resolveRoleColor(foregroundRole) : void 0,
|
|
77
|
+
text
|
|
78
|
+
)
|
|
39
79
|
};
|
|
40
80
|
}
|
|
41
81
|
|
|
@@ -560,8 +600,1128 @@ function parseSkillInvocation(content) {
|
|
|
560
600
|
};
|
|
561
601
|
}
|
|
562
602
|
|
|
603
|
+
// src/react-host/index.ts
|
|
604
|
+
var React = await loadHostReact();
|
|
605
|
+
var Fragment2 = React.Fragment;
|
|
606
|
+
var createElement = React.createElement;
|
|
607
|
+
var useEffect = React.useEffect;
|
|
608
|
+
var useMemo = React.useMemo;
|
|
609
|
+
var useState = React.useState;
|
|
610
|
+
|
|
611
|
+
// src/react-ink/markdown/format-token.ts
|
|
612
|
+
import chalk2 from "chalk";
|
|
613
|
+
import { marked } from "marked";
|
|
614
|
+
import stripAnsi3 from "strip-ansi";
|
|
615
|
+
|
|
616
|
+
// src/ui/utils.ts
|
|
617
|
+
import { eastAsianWidth } from "get-east-asian-width";
|
|
618
|
+
var segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
619
|
+
var TextWidthCalculator = class {
|
|
620
|
+
getWidth(text) {
|
|
621
|
+
return visibleWidth(text);
|
|
622
|
+
}
|
|
623
|
+
clearCache() {
|
|
624
|
+
widthCache.clear();
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
var textWidthCalculator = new TextWidthCalculator();
|
|
628
|
+
function looksLikeEmojiCandidate(segment) {
|
|
629
|
+
const cp = segment.codePointAt(0);
|
|
630
|
+
return cp >= 126976 && cp <= 130047 || // pictographs and emoji proper
|
|
631
|
+
cp >= 8960 && cp <= 9215 || // miscellaneous technical glyphs
|
|
632
|
+
cp >= 9728 && cp <= 10175 || // assorted symbols and dingbats
|
|
633
|
+
cp >= 11088 && cp <= 11093 || // a few star/circle characters
|
|
634
|
+
segment.includes("\uFE0F") || // carries VS16, the emoji-presentation selector
|
|
635
|
+
segment.length > 2;
|
|
636
|
+
}
|
|
637
|
+
function createUnicodeRegex(vPattern, uFallback) {
|
|
638
|
+
try {
|
|
639
|
+
return new RegExp(vPattern, "v");
|
|
640
|
+
} catch {
|
|
641
|
+
return new RegExp(uFallback, "u");
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
var zeroWidthRegex = createUnicodeRegex(
|
|
645
|
+
"^(?:\\p{Default_Ignorable_Code_Point}|\\p{Control}|\\p{Mark}|\\p{Surrogate})+$",
|
|
646
|
+
"^(?:\\p{Default_Ignorable_Code_Point}|\\p{Control}|\\p{Mark}|\\p{Surrogate})+$"
|
|
647
|
+
);
|
|
648
|
+
var leadingNonPrintingRegex = createUnicodeRegex(
|
|
649
|
+
"^[\\p{Default_Ignorable_Code_Point}\\p{Control}\\p{Format}\\p{Mark}\\p{Surrogate}]+",
|
|
650
|
+
"^[\\p{Default_Ignorable_Code_Point}\\p{Control}\\p{Format}\\p{Mark}\\p{Surrogate}]+"
|
|
651
|
+
);
|
|
652
|
+
var rgiEmojiRegex = createUnicodeRegex("^\\p{RGI_Emoji}$", "^\\p{Extended_Pictographic}$");
|
|
653
|
+
var AnsiStripper = {
|
|
654
|
+
strip(text) {
|
|
655
|
+
if (!text.includes("\x1B")) {
|
|
656
|
+
return text;
|
|
657
|
+
}
|
|
658
|
+
let cleaned = text;
|
|
659
|
+
cleaned = cleaned.replace(/\x1b\[[0-9;]*[mGKHJ]/g, "");
|
|
660
|
+
cleaned = cleaned.replace(/\x1b\]8;;[^\x07]*\x07/g, "");
|
|
661
|
+
cleaned = cleaned.replace(/\x1b_[^\x07\x1b]*(?:\x07|\x1b\\)/g, "");
|
|
662
|
+
return cleaned;
|
|
663
|
+
}
|
|
664
|
+
};
|
|
665
|
+
var WIDTH_CACHE_SIZE = 512;
|
|
666
|
+
var widthCache = /* @__PURE__ */ new Map();
|
|
667
|
+
function measureClusterWidth(segment) {
|
|
668
|
+
if (zeroWidthRegex.test(segment)) {
|
|
669
|
+
return 0;
|
|
670
|
+
}
|
|
671
|
+
if (looksLikeEmojiCandidate(segment) && rgiEmojiRegex.test(segment)) {
|
|
672
|
+
return 2;
|
|
673
|
+
}
|
|
674
|
+
const base = segment.replace(leadingNonPrintingRegex, "");
|
|
675
|
+
const cp = base.codePointAt(0);
|
|
676
|
+
if (cp === void 0) {
|
|
677
|
+
return 0;
|
|
678
|
+
}
|
|
679
|
+
let width = eastAsianWidth(cp);
|
|
680
|
+
if (segment.length > 1) {
|
|
681
|
+
for (const char of segment.slice(1)) {
|
|
682
|
+
const c = char.codePointAt(0);
|
|
683
|
+
if (c >= 65280 && c <= 65519) {
|
|
684
|
+
width += eastAsianWidth(c);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
return width;
|
|
689
|
+
}
|
|
690
|
+
function visibleWidth(str) {
|
|
691
|
+
if (str.length === 0) {
|
|
692
|
+
return 0;
|
|
693
|
+
}
|
|
694
|
+
let isPureAscii = true;
|
|
695
|
+
for (let i = 0; i < str.length; i++) {
|
|
696
|
+
const code = str.charCodeAt(i);
|
|
697
|
+
if (code < 32 || code > 126) {
|
|
698
|
+
isPureAscii = false;
|
|
699
|
+
break;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
if (isPureAscii) {
|
|
703
|
+
return str.length;
|
|
704
|
+
}
|
|
705
|
+
const cached = widthCache.get(str);
|
|
706
|
+
if (cached !== void 0) {
|
|
707
|
+
return cached;
|
|
708
|
+
}
|
|
709
|
+
let clean = str;
|
|
710
|
+
if (str.includes(" ")) {
|
|
711
|
+
clean = clean.replace(/\t/g, " ");
|
|
712
|
+
}
|
|
713
|
+
clean = AnsiStripper.strip(clean);
|
|
714
|
+
let width = 0;
|
|
715
|
+
for (const { segment } of segmenter.segment(clean)) {
|
|
716
|
+
width += measureClusterWidth(segment);
|
|
717
|
+
}
|
|
718
|
+
if (widthCache.size >= WIDTH_CACHE_SIZE) {
|
|
719
|
+
const firstKey = widthCache.keys().next().value;
|
|
720
|
+
if (firstKey !== void 0) {
|
|
721
|
+
widthCache.delete(firstKey);
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
widthCache.set(str, width);
|
|
725
|
+
return width;
|
|
726
|
+
}
|
|
727
|
+
function extractAnsiCode(str, pos) {
|
|
728
|
+
if (pos >= str.length || str[pos] !== "\x1B") return null;
|
|
729
|
+
const next = str[pos + 1];
|
|
730
|
+
if (next === "[") {
|
|
731
|
+
let j = pos + 2;
|
|
732
|
+
while (j < str.length && !/[mGKHJ]/.test(str[j])) j++;
|
|
733
|
+
if (j < str.length) return { code: str.substring(pos, j + 1), length: j + 1 - pos };
|
|
734
|
+
return null;
|
|
735
|
+
}
|
|
736
|
+
if (next === "]") {
|
|
737
|
+
let j = pos + 2;
|
|
738
|
+
while (j < str.length) {
|
|
739
|
+
if (str[j] === "\x07") return { code: str.substring(pos, j + 1), length: j + 1 - pos };
|
|
740
|
+
if (str[j] === "\x1B" && str[j + 1] === "\\") return { code: str.substring(pos, j + 2), length: j + 2 - pos };
|
|
741
|
+
j++;
|
|
742
|
+
}
|
|
743
|
+
return null;
|
|
744
|
+
}
|
|
745
|
+
if (next === "_") {
|
|
746
|
+
let j = pos + 2;
|
|
747
|
+
while (j < str.length) {
|
|
748
|
+
if (str[j] === "\x07") return { code: str.substring(pos, j + 1), length: j + 1 - pos };
|
|
749
|
+
if (str[j] === "\x1B" && str[j + 1] === "\\") return { code: str.substring(pos, j + 2), length: j + 2 - pos };
|
|
750
|
+
j++;
|
|
751
|
+
}
|
|
752
|
+
return null;
|
|
753
|
+
}
|
|
754
|
+
return null;
|
|
755
|
+
}
|
|
756
|
+
var AnsiStateTracker = class {
|
|
757
|
+
// Each attribute is kept on its own flag, which lets us clear them one at a time.
|
|
758
|
+
_bold = false;
|
|
759
|
+
_dim = false;
|
|
760
|
+
italic = false;
|
|
761
|
+
underline = false;
|
|
762
|
+
blink = false;
|
|
763
|
+
inverse = false;
|
|
764
|
+
hidden = false;
|
|
765
|
+
strikethrough = false;
|
|
766
|
+
_colors = { fg: null, bg: null };
|
|
767
|
+
process(ansiCode) {
|
|
768
|
+
if (!ansiCode.endsWith("m")) {
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
const match = ansiCode.match(/\x1b\[([\d;]*)m/);
|
|
772
|
+
if (!match) return;
|
|
773
|
+
const params = match[1];
|
|
774
|
+
if (params === "" || params === "0") {
|
|
775
|
+
this.reset();
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
const parts = params.split(";");
|
|
779
|
+
let i = 0;
|
|
780
|
+
while (i < parts.length) {
|
|
781
|
+
const code = Number.parseInt(parts[i] ?? "", 10);
|
|
782
|
+
if (Number.isNaN(code)) {
|
|
783
|
+
i++;
|
|
784
|
+
continue;
|
|
785
|
+
}
|
|
786
|
+
const consumed = this.tryConsumeColorCode(parts, i, code);
|
|
787
|
+
if (consumed > 0) {
|
|
788
|
+
i += consumed;
|
|
789
|
+
continue;
|
|
790
|
+
}
|
|
791
|
+
this.applyStandardCode(code);
|
|
792
|
+
i++;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
tryConsumeColorCode(parts, index, code) {
|
|
796
|
+
if (code !== 38 && code !== 48) {
|
|
797
|
+
return 0;
|
|
798
|
+
}
|
|
799
|
+
if (parts[index + 1] === "5" && parts[index + 2] !== void 0) {
|
|
800
|
+
const colorCode = `${parts[index]};${parts[index + 1]};${parts[index + 2]}`;
|
|
801
|
+
if (code === 38) {
|
|
802
|
+
this._colors.fg = colorCode;
|
|
803
|
+
} else {
|
|
804
|
+
this._colors.bg = colorCode;
|
|
805
|
+
}
|
|
806
|
+
return 3;
|
|
807
|
+
}
|
|
808
|
+
if (parts[index + 1] === "2" && parts[index + 4] !== void 0) {
|
|
809
|
+
const colorCode = `${parts[index]};${parts[index + 1]};${parts[index + 2]};${parts[index + 3]};${parts[index + 4]}`;
|
|
810
|
+
if (code === 38) {
|
|
811
|
+
this._colors.fg = colorCode;
|
|
812
|
+
} else {
|
|
813
|
+
this._colors.bg = colorCode;
|
|
814
|
+
}
|
|
815
|
+
return 5;
|
|
816
|
+
}
|
|
817
|
+
return 0;
|
|
818
|
+
}
|
|
819
|
+
applyStandardCode(code) {
|
|
820
|
+
switch (code) {
|
|
821
|
+
case 0:
|
|
822
|
+
this.reset();
|
|
823
|
+
return;
|
|
824
|
+
case 1:
|
|
825
|
+
this._bold = true;
|
|
826
|
+
return;
|
|
827
|
+
case 2:
|
|
828
|
+
this._dim = true;
|
|
829
|
+
return;
|
|
830
|
+
case 3:
|
|
831
|
+
this.italic = true;
|
|
832
|
+
return;
|
|
833
|
+
case 4:
|
|
834
|
+
this.underline = true;
|
|
835
|
+
return;
|
|
836
|
+
case 5:
|
|
837
|
+
this.blink = true;
|
|
838
|
+
return;
|
|
839
|
+
case 7:
|
|
840
|
+
this.inverse = true;
|
|
841
|
+
return;
|
|
842
|
+
case 8:
|
|
843
|
+
this.hidden = true;
|
|
844
|
+
return;
|
|
845
|
+
case 9:
|
|
846
|
+
this.strikethrough = true;
|
|
847
|
+
return;
|
|
848
|
+
case 21:
|
|
849
|
+
this._bold = false;
|
|
850
|
+
return;
|
|
851
|
+
case 22:
|
|
852
|
+
this._bold = false;
|
|
853
|
+
this._dim = false;
|
|
854
|
+
return;
|
|
855
|
+
case 23:
|
|
856
|
+
this.italic = false;
|
|
857
|
+
return;
|
|
858
|
+
case 24:
|
|
859
|
+
this.underline = false;
|
|
860
|
+
return;
|
|
861
|
+
case 25:
|
|
862
|
+
this.blink = false;
|
|
863
|
+
return;
|
|
864
|
+
case 27:
|
|
865
|
+
this.inverse = false;
|
|
866
|
+
return;
|
|
867
|
+
case 28:
|
|
868
|
+
this.hidden = false;
|
|
869
|
+
return;
|
|
870
|
+
case 29:
|
|
871
|
+
this.strikethrough = false;
|
|
872
|
+
return;
|
|
873
|
+
case 39:
|
|
874
|
+
this._colors.fg = null;
|
|
875
|
+
return;
|
|
876
|
+
case 49:
|
|
877
|
+
this._colors.bg = null;
|
|
878
|
+
return;
|
|
879
|
+
default:
|
|
880
|
+
if (code >= 30 && code <= 37 || code >= 90 && code <= 97) {
|
|
881
|
+
this._colors.fg = String(code);
|
|
882
|
+
return;
|
|
883
|
+
}
|
|
884
|
+
if (code >= 40 && code <= 47 || code >= 100 && code <= 107) {
|
|
885
|
+
this._colors.bg = String(code);
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
reset() {
|
|
890
|
+
this._bold = false;
|
|
891
|
+
this._dim = false;
|
|
892
|
+
this.italic = false;
|
|
893
|
+
this.underline = false;
|
|
894
|
+
this.blink = false;
|
|
895
|
+
this.inverse = false;
|
|
896
|
+
this.hidden = false;
|
|
897
|
+
this.strikethrough = false;
|
|
898
|
+
this._colors.fg = null;
|
|
899
|
+
this._colors.bg = null;
|
|
900
|
+
}
|
|
901
|
+
/** Wipe all tracked state so the instance can be reused. */
|
|
902
|
+
clear() {
|
|
903
|
+
this.reset();
|
|
904
|
+
}
|
|
905
|
+
getActiveCodes() {
|
|
906
|
+
const codes = [];
|
|
907
|
+
if (this._bold) codes.push("1");
|
|
908
|
+
if (this._dim) codes.push("2");
|
|
909
|
+
if (this.italic) codes.push("3");
|
|
910
|
+
if (this.underline) codes.push("4");
|
|
911
|
+
if (this.blink) codes.push("5");
|
|
912
|
+
if (this.inverse) codes.push("7");
|
|
913
|
+
if (this.hidden) codes.push("8");
|
|
914
|
+
if (this.strikethrough) codes.push("9");
|
|
915
|
+
if (this._colors.fg) codes.push(this._colors.fg);
|
|
916
|
+
if (this._colors.bg) codes.push(this._colors.bg);
|
|
917
|
+
if (codes.length === 0) return "";
|
|
918
|
+
return `\x1B[${codes.join(";")}m`;
|
|
919
|
+
}
|
|
920
|
+
hasActiveCodes() {
|
|
921
|
+
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;
|
|
922
|
+
}
|
|
923
|
+
/**
|
|
924
|
+
* Produce the escape code needed to switch off any attribute that would
|
|
925
|
+
* otherwise smear into the padding at the end of a line. In practice that
|
|
926
|
+
* is just underline. Yields an empty string when nothing needs disabling.
|
|
927
|
+
*/
|
|
928
|
+
getLineEndReset() {
|
|
929
|
+
if (this.underline) {
|
|
930
|
+
return "\x1B[24m";
|
|
931
|
+
}
|
|
932
|
+
return "";
|
|
933
|
+
}
|
|
934
|
+
};
|
|
935
|
+
function mergeTextIntoTracker(text, tracker) {
|
|
936
|
+
let i = 0;
|
|
937
|
+
while (i < text.length) {
|
|
938
|
+
const ansiResult = extractAnsiCode(text, i);
|
|
939
|
+
if (ansiResult) {
|
|
940
|
+
tracker.process(ansiResult.code);
|
|
941
|
+
i += ansiResult.length;
|
|
942
|
+
} else {
|
|
943
|
+
i++;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
function tokenizeTextWithAnsi(text) {
|
|
948
|
+
const tokens = [];
|
|
949
|
+
let current = "";
|
|
950
|
+
let pendingAnsi = "";
|
|
951
|
+
let inWhitespace = false;
|
|
952
|
+
let i = 0;
|
|
953
|
+
while (i < text.length) {
|
|
954
|
+
const ansiResult = extractAnsiCode(text, i);
|
|
955
|
+
if (ansiResult) {
|
|
956
|
+
pendingAnsi += ansiResult.code;
|
|
957
|
+
i += ansiResult.length;
|
|
958
|
+
continue;
|
|
959
|
+
}
|
|
960
|
+
const char = text[i];
|
|
961
|
+
const charIsSpace = char === " ";
|
|
962
|
+
if (charIsSpace !== inWhitespace && current) {
|
|
963
|
+
tokens.push(current);
|
|
964
|
+
current = "";
|
|
965
|
+
}
|
|
966
|
+
if (pendingAnsi) {
|
|
967
|
+
current += pendingAnsi;
|
|
968
|
+
pendingAnsi = "";
|
|
969
|
+
}
|
|
970
|
+
inWhitespace = charIsSpace;
|
|
971
|
+
current += char;
|
|
972
|
+
i++;
|
|
973
|
+
}
|
|
974
|
+
if (pendingAnsi) {
|
|
975
|
+
current += pendingAnsi;
|
|
976
|
+
}
|
|
977
|
+
if (current) {
|
|
978
|
+
tokens.push(current);
|
|
979
|
+
}
|
|
980
|
+
return tokens;
|
|
981
|
+
}
|
|
982
|
+
var TextWrapper = class {
|
|
983
|
+
wrap(text, width) {
|
|
984
|
+
return wrapTextWithAnsi(text, width);
|
|
985
|
+
}
|
|
986
|
+
};
|
|
987
|
+
var textWrapper = new TextWrapper();
|
|
988
|
+
var TokenWrapEngine = {
|
|
989
|
+
wrap(tokens, width, tracker) {
|
|
990
|
+
const wrapped = [];
|
|
991
|
+
let currentLine = "";
|
|
992
|
+
let currentVisibleLength = 0;
|
|
993
|
+
for (const token of tokens) {
|
|
994
|
+
const tokenVisibleLength = visibleWidth(token);
|
|
995
|
+
const isWhitespace = token.trim() === "";
|
|
996
|
+
if (tokenVisibleLength > width && !isWhitespace) {
|
|
997
|
+
if (currentLine) {
|
|
998
|
+
const lineEndReset = tracker.getLineEndReset();
|
|
999
|
+
if (lineEndReset) {
|
|
1000
|
+
currentLine += lineEndReset;
|
|
1001
|
+
}
|
|
1002
|
+
wrapped.push(currentLine);
|
|
1003
|
+
currentLine = "";
|
|
1004
|
+
currentVisibleLength = 0;
|
|
1005
|
+
}
|
|
1006
|
+
const broken = splitLongToken(token, width, tracker);
|
|
1007
|
+
wrapped.push(...broken.slice(0, -1));
|
|
1008
|
+
currentLine = broken[broken.length - 1];
|
|
1009
|
+
currentVisibleLength = visibleWidth(currentLine);
|
|
1010
|
+
continue;
|
|
1011
|
+
}
|
|
1012
|
+
const totalNeeded = currentVisibleLength + tokenVisibleLength;
|
|
1013
|
+
if (totalNeeded > width && currentVisibleLength > 0) {
|
|
1014
|
+
let lineToWrap = currentLine.trimEnd();
|
|
1015
|
+
const lineEndReset = tracker.getLineEndReset();
|
|
1016
|
+
if (lineEndReset) {
|
|
1017
|
+
lineToWrap += lineEndReset;
|
|
1018
|
+
}
|
|
1019
|
+
wrapped.push(lineToWrap);
|
|
1020
|
+
if (isWhitespace) {
|
|
1021
|
+
currentLine = tracker.getActiveCodes();
|
|
1022
|
+
currentVisibleLength = 0;
|
|
1023
|
+
} else {
|
|
1024
|
+
currentLine = tracker.getActiveCodes() + token;
|
|
1025
|
+
currentVisibleLength = tokenVisibleLength;
|
|
1026
|
+
}
|
|
1027
|
+
} else {
|
|
1028
|
+
currentLine += token;
|
|
1029
|
+
currentVisibleLength += tokenVisibleLength;
|
|
1030
|
+
}
|
|
1031
|
+
mergeTextIntoTracker(token, tracker);
|
|
1032
|
+
}
|
|
1033
|
+
return { wrapped, currentLine, currentVisibleLength };
|
|
1034
|
+
}
|
|
1035
|
+
};
|
|
1036
|
+
function wrapTextWithAnsi(text, width) {
|
|
1037
|
+
if (!text) {
|
|
1038
|
+
return [""];
|
|
1039
|
+
}
|
|
1040
|
+
const inputLines = text.split("\n");
|
|
1041
|
+
const result = [];
|
|
1042
|
+
const tracker = new AnsiStateTracker();
|
|
1043
|
+
for (const inputLine of inputLines) {
|
|
1044
|
+
const prefix = result.length > 0 ? tracker.getActiveCodes() : "";
|
|
1045
|
+
result.push(...wrapLinePreservingAnsi(prefix + inputLine, width));
|
|
1046
|
+
mergeTextIntoTracker(inputLine, tracker);
|
|
1047
|
+
}
|
|
1048
|
+
return result.length > 0 ? result : [""];
|
|
1049
|
+
}
|
|
1050
|
+
function wrapLinePreservingAnsi(line, width) {
|
|
1051
|
+
if (!line) {
|
|
1052
|
+
return [""];
|
|
1053
|
+
}
|
|
1054
|
+
const visibleLength = visibleWidth(line);
|
|
1055
|
+
if (visibleLength <= width) {
|
|
1056
|
+
return [line];
|
|
1057
|
+
}
|
|
1058
|
+
const tracker = new AnsiStateTracker();
|
|
1059
|
+
const tokens = tokenizeTextWithAnsi(line);
|
|
1060
|
+
const { wrapped, currentLine } = TokenWrapEngine.wrap(tokens, width, tracker);
|
|
1061
|
+
if (currentLine) {
|
|
1062
|
+
wrapped.push(currentLine);
|
|
1063
|
+
}
|
|
1064
|
+
return wrapped.length > 0 ? wrapped.map((segmentLine) => segmentLine.trimEnd()) : [""];
|
|
1065
|
+
}
|
|
1066
|
+
function splitLongToken(word, width, tracker) {
|
|
1067
|
+
const lines = [];
|
|
1068
|
+
let currentLine = tracker.getActiveCodes();
|
|
1069
|
+
let currentWidth = 0;
|
|
1070
|
+
let i = 0;
|
|
1071
|
+
const segments = [];
|
|
1072
|
+
while (i < word.length) {
|
|
1073
|
+
const ansiResult = extractAnsiCode(word, i);
|
|
1074
|
+
if (ansiResult) {
|
|
1075
|
+
segments.push({ type: "ansi", value: ansiResult.code });
|
|
1076
|
+
i += ansiResult.length;
|
|
1077
|
+
} else {
|
|
1078
|
+
let end = i;
|
|
1079
|
+
while (end < word.length) {
|
|
1080
|
+
const nextAnsi = extractAnsiCode(word, end);
|
|
1081
|
+
if (nextAnsi) break;
|
|
1082
|
+
end++;
|
|
1083
|
+
}
|
|
1084
|
+
const textPortion = word.slice(i, end);
|
|
1085
|
+
for (const seg of segmenter.segment(textPortion)) {
|
|
1086
|
+
segments.push({ type: "grapheme", value: seg.segment });
|
|
1087
|
+
}
|
|
1088
|
+
i = end;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
for (const seg of segments) {
|
|
1092
|
+
if (seg.type === "ansi") {
|
|
1093
|
+
currentLine += seg.value;
|
|
1094
|
+
tracker.process(seg.value);
|
|
1095
|
+
continue;
|
|
1096
|
+
}
|
|
1097
|
+
const grapheme = seg.value;
|
|
1098
|
+
if (!grapheme) continue;
|
|
1099
|
+
const clusterWidth = visibleWidth(grapheme);
|
|
1100
|
+
if (currentWidth + clusterWidth > width) {
|
|
1101
|
+
const lineEndReset = tracker.getLineEndReset();
|
|
1102
|
+
if (lineEndReset) {
|
|
1103
|
+
currentLine += lineEndReset;
|
|
1104
|
+
}
|
|
1105
|
+
lines.push(currentLine);
|
|
1106
|
+
currentLine = tracker.getActiveCodes();
|
|
1107
|
+
currentWidth = 0;
|
|
1108
|
+
}
|
|
1109
|
+
currentLine += grapheme;
|
|
1110
|
+
currentWidth += clusterWidth;
|
|
1111
|
+
}
|
|
1112
|
+
if (currentLine) {
|
|
1113
|
+
lines.push(currentLine);
|
|
1114
|
+
}
|
|
1115
|
+
return lines.length > 0 ? lines : [""];
|
|
1116
|
+
}
|
|
1117
|
+
var pooledStyleTracker = new AnsiStateTracker();
|
|
1118
|
+
|
|
1119
|
+
// src/react-ink/markdown/format-token.ts
|
|
1120
|
+
var EOL = "\n";
|
|
1121
|
+
var BLOCKQUOTE_BAR = "\u2502";
|
|
1122
|
+
var markedConfigured = false;
|
|
1123
|
+
function configureMarked() {
|
|
1124
|
+
if (markedConfigured) {
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
markedConfigured = true;
|
|
1128
|
+
marked.use({
|
|
1129
|
+
tokenizer: {
|
|
1130
|
+
del() {
|
|
1131
|
+
return void 0;
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
});
|
|
1135
|
+
}
|
|
1136
|
+
var TOKEN_CACHE_MAX = 500;
|
|
1137
|
+
var tokenCache = /* @__PURE__ */ new Map();
|
|
1138
|
+
var MD_SYNTAX_RE = /[#*`|[>\-_~]|\n\n|^\d+\. |\n\d+\. /;
|
|
1139
|
+
function hasMarkdownSyntax(text) {
|
|
1140
|
+
return MD_SYNTAX_RE.test(text.length > 500 ? text.slice(0, 500) : text);
|
|
1141
|
+
}
|
|
1142
|
+
function hashContent(content) {
|
|
1143
|
+
let hash = 2166136261;
|
|
1144
|
+
for (let i = 0; i < content.length; i++) {
|
|
1145
|
+
hash ^= content.charCodeAt(i);
|
|
1146
|
+
hash = Math.imul(hash, 16777619);
|
|
1147
|
+
}
|
|
1148
|
+
return (hash >>> 0).toString(36) + ":" + content.length.toString(36);
|
|
1149
|
+
}
|
|
1150
|
+
function cachedLexer(content) {
|
|
1151
|
+
configureMarked();
|
|
1152
|
+
if (!hasMarkdownSyntax(content)) {
|
|
1153
|
+
return [
|
|
1154
|
+
{
|
|
1155
|
+
type: "paragraph",
|
|
1156
|
+
raw: content,
|
|
1157
|
+
text: content,
|
|
1158
|
+
tokens: [{ type: "text", raw: content, text: content }]
|
|
1159
|
+
}
|
|
1160
|
+
];
|
|
1161
|
+
}
|
|
1162
|
+
const key = hashContent(content);
|
|
1163
|
+
const hit = tokenCache.get(key);
|
|
1164
|
+
if (hit) {
|
|
1165
|
+
tokenCache.delete(key);
|
|
1166
|
+
tokenCache.set(key, hit);
|
|
1167
|
+
return hit;
|
|
1168
|
+
}
|
|
1169
|
+
const tokens = marked.lexer(content);
|
|
1170
|
+
if (tokenCache.size >= TOKEN_CACHE_MAX) {
|
|
1171
|
+
const first = tokenCache.keys().next().value;
|
|
1172
|
+
if (first !== void 0) {
|
|
1173
|
+
tokenCache.delete(first);
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
tokenCache.set(key, tokens);
|
|
1177
|
+
return tokens;
|
|
1178
|
+
}
|
|
1179
|
+
function formatToken(token, theme, highlight = null, listDepth = 0, orderedListNumber = null, parent = null) {
|
|
1180
|
+
switch (token.type) {
|
|
1181
|
+
case "blockquote": {
|
|
1182
|
+
const inner = (token.tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("");
|
|
1183
|
+
const bar = theme.dim(BLOCKQUOTE_BAR);
|
|
1184
|
+
return inner.split(EOL).map((line) => stripAnsi3(line).trim() ? `${bar} ${chalk2.italic(line)}` : line).join(EOL);
|
|
1185
|
+
}
|
|
1186
|
+
case "code": {
|
|
1187
|
+
const codeToken = token;
|
|
1188
|
+
if (!highlight) {
|
|
1189
|
+
return codeToken.text + EOL;
|
|
1190
|
+
}
|
|
1191
|
+
let language = "plaintext";
|
|
1192
|
+
if (codeToken.lang && highlight.supportsLanguage(codeToken.lang)) {
|
|
1193
|
+
language = codeToken.lang;
|
|
1194
|
+
}
|
|
1195
|
+
return highlight.highlight(codeToken.text, { language }) + EOL;
|
|
1196
|
+
}
|
|
1197
|
+
case "codespan":
|
|
1198
|
+
return theme.role("codeInline", token.text);
|
|
1199
|
+
case "em":
|
|
1200
|
+
return chalk2.italic(
|
|
1201
|
+
(token.tokens ?? []).map((child) => formatToken(child, theme, highlight, 0, null, parent)).join("")
|
|
1202
|
+
);
|
|
1203
|
+
case "strong":
|
|
1204
|
+
return chalk2.bold(
|
|
1205
|
+
(token.tokens ?? []).map((child) => formatToken(child, theme, highlight, 0, null, parent)).join("")
|
|
1206
|
+
);
|
|
1207
|
+
case "heading": {
|
|
1208
|
+
const headingToken = token;
|
|
1209
|
+
const inner = (headingToken.tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("");
|
|
1210
|
+
const colored = theme.role("heading", inner);
|
|
1211
|
+
if (headingToken.depth === 1) {
|
|
1212
|
+
return chalk2.bold.italic.underline(colored) + EOL + EOL;
|
|
1213
|
+
}
|
|
1214
|
+
return chalk2.bold(colored) + EOL + EOL;
|
|
1215
|
+
}
|
|
1216
|
+
case "hr":
|
|
1217
|
+
return "---";
|
|
1218
|
+
case "image":
|
|
1219
|
+
return token.href;
|
|
1220
|
+
case "link": {
|
|
1221
|
+
const linkToken = token;
|
|
1222
|
+
if (linkToken.href.startsWith("mailto:")) {
|
|
1223
|
+
return linkToken.href.replace(/^mailto:/, "");
|
|
1224
|
+
}
|
|
1225
|
+
const linkText = (linkToken.tokens ?? []).map((child) => formatToken(child, theme, highlight, 0, null, linkToken)).join("");
|
|
1226
|
+
const plainLinkText = stripAnsi3(linkText);
|
|
1227
|
+
const display = plainLinkText && plainLinkText !== linkToken.href ? linkText : linkToken.href;
|
|
1228
|
+
return `\x1B]8;;${linkToken.href}\x07${display}\x1B]8;;\x07`;
|
|
1229
|
+
}
|
|
1230
|
+
case "list": {
|
|
1231
|
+
const listToken = token;
|
|
1232
|
+
const start = typeof listToken.start === "number" ? listToken.start : Number(listToken.start) || 1;
|
|
1233
|
+
return listToken.items.map(
|
|
1234
|
+
(item, index) => formatToken(
|
|
1235
|
+
item,
|
|
1236
|
+
theme,
|
|
1237
|
+
highlight,
|
|
1238
|
+
listDepth,
|
|
1239
|
+
listToken.ordered ? start + index : null,
|
|
1240
|
+
listToken
|
|
1241
|
+
)
|
|
1242
|
+
).join("");
|
|
1243
|
+
}
|
|
1244
|
+
case "list_item":
|
|
1245
|
+
return (token.tokens ?? []).map(
|
|
1246
|
+
(child) => `${" ".repeat(listDepth)}${formatToken(child, theme, highlight, listDepth + 1, orderedListNumber, token)}`
|
|
1247
|
+
).join("");
|
|
1248
|
+
case "paragraph":
|
|
1249
|
+
return (token.tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("") + EOL;
|
|
1250
|
+
case "space":
|
|
1251
|
+
case "br":
|
|
1252
|
+
return EOL;
|
|
1253
|
+
case "text": {
|
|
1254
|
+
const textToken = token;
|
|
1255
|
+
if (parent?.type === "link") {
|
|
1256
|
+
return textToken.text;
|
|
1257
|
+
}
|
|
1258
|
+
if (parent?.type === "list_item") {
|
|
1259
|
+
const marker = orderedListNumber === null ? "-" : `${getListNumber(listDepth, orderedListNumber)}.`;
|
|
1260
|
+
const body = textToken.tokens ? textToken.tokens.map((child) => formatToken(child, theme, highlight, listDepth, orderedListNumber, token)).join("") : textToken.text;
|
|
1261
|
+
return `${marker} ${body}${EOL}`;
|
|
1262
|
+
}
|
|
1263
|
+
return textToken.text;
|
|
1264
|
+
}
|
|
1265
|
+
case "escape":
|
|
1266
|
+
return token.text;
|
|
1267
|
+
case "table":
|
|
1268
|
+
case "def":
|
|
1269
|
+
case "del":
|
|
1270
|
+
case "html":
|
|
1271
|
+
return "";
|
|
1272
|
+
default:
|
|
1273
|
+
return "";
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
function numberToLetter(n) {
|
|
1277
|
+
let result = "";
|
|
1278
|
+
while (n > 0) {
|
|
1279
|
+
n--;
|
|
1280
|
+
result = String.fromCharCode(97 + n % 26) + result;
|
|
1281
|
+
n = Math.floor(n / 26);
|
|
1282
|
+
}
|
|
1283
|
+
return result;
|
|
1284
|
+
}
|
|
1285
|
+
var ROMAN_VALUES = [
|
|
1286
|
+
[1e3, "m"],
|
|
1287
|
+
[900, "cm"],
|
|
1288
|
+
[500, "d"],
|
|
1289
|
+
[400, "cd"],
|
|
1290
|
+
[100, "c"],
|
|
1291
|
+
[90, "xc"],
|
|
1292
|
+
[50, "l"],
|
|
1293
|
+
[40, "xl"],
|
|
1294
|
+
[10, "x"],
|
|
1295
|
+
[9, "ix"],
|
|
1296
|
+
[5, "v"],
|
|
1297
|
+
[4, "iv"],
|
|
1298
|
+
[1, "i"]
|
|
1299
|
+
];
|
|
1300
|
+
function numberToRoman(n) {
|
|
1301
|
+
let result = "";
|
|
1302
|
+
for (const [value, numeral] of ROMAN_VALUES) {
|
|
1303
|
+
while (n >= value) {
|
|
1304
|
+
result += numeral;
|
|
1305
|
+
n -= value;
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
return result;
|
|
1309
|
+
}
|
|
1310
|
+
function getListNumber(listDepth, orderedListNumber) {
|
|
1311
|
+
switch (listDepth) {
|
|
1312
|
+
case 0:
|
|
1313
|
+
case 1:
|
|
1314
|
+
return orderedListNumber.toString();
|
|
1315
|
+
case 2:
|
|
1316
|
+
return numberToLetter(orderedListNumber);
|
|
1317
|
+
case 3:
|
|
1318
|
+
return numberToRoman(orderedListNumber);
|
|
1319
|
+
default:
|
|
1320
|
+
return orderedListNumber.toString();
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
function padAligned(content, displayWidth, targetWidth, align) {
|
|
1324
|
+
const padding = Math.max(0, targetWidth - displayWidth);
|
|
1325
|
+
if (align === "center") {
|
|
1326
|
+
const leftPad = Math.floor(padding / 2);
|
|
1327
|
+
return " ".repeat(leftPad) + content + " ".repeat(padding - leftPad);
|
|
1328
|
+
}
|
|
1329
|
+
if (align === "right") {
|
|
1330
|
+
return " ".repeat(padding) + content;
|
|
1331
|
+
}
|
|
1332
|
+
return content + " ".repeat(padding);
|
|
1333
|
+
}
|
|
1334
|
+
function stringWidth(text) {
|
|
1335
|
+
return visibleWidth(text);
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
// src/react-ink/markdown/highlight.ts
|
|
1339
|
+
import { extname } from "node:path";
|
|
1340
|
+
import hljs from "highlight.js";
|
|
1341
|
+
function scopeToRole(scope) {
|
|
1342
|
+
const head = scope.split(".")[0] ?? scope;
|
|
1343
|
+
switch (head) {
|
|
1344
|
+
case "keyword":
|
|
1345
|
+
case "built_in":
|
|
1346
|
+
case "literal":
|
|
1347
|
+
case "operator":
|
|
1348
|
+
return "synKeyword";
|
|
1349
|
+
case "string":
|
|
1350
|
+
case "regexp":
|
|
1351
|
+
case "symbol":
|
|
1352
|
+
case "char":
|
|
1353
|
+
case "meta":
|
|
1354
|
+
return "synString";
|
|
1355
|
+
case "number":
|
|
1356
|
+
return "synNumber";
|
|
1357
|
+
case "comment":
|
|
1358
|
+
case "quote":
|
|
1359
|
+
return "synComment";
|
|
1360
|
+
case "type":
|
|
1361
|
+
case "class":
|
|
1362
|
+
case "title":
|
|
1363
|
+
case "tag":
|
|
1364
|
+
case "name":
|
|
1365
|
+
case "attr":
|
|
1366
|
+
case "attribute":
|
|
1367
|
+
case "selector":
|
|
1368
|
+
return "synType";
|
|
1369
|
+
default:
|
|
1370
|
+
return null;
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
var HTML_ENTITIES = {
|
|
1374
|
+
"&": "&",
|
|
1375
|
+
"<": "<",
|
|
1376
|
+
">": ">",
|
|
1377
|
+
""": '"',
|
|
1378
|
+
"'": "'",
|
|
1379
|
+
"'": "'"
|
|
1380
|
+
};
|
|
1381
|
+
function decodeEntities(text) {
|
|
1382
|
+
return text.replace(/&(?:amp|lt|gt|quot|#x27|#39);/g, (match) => HTML_ENTITIES[match] ?? match);
|
|
1383
|
+
}
|
|
1384
|
+
function parseHljsHtml(html) {
|
|
1385
|
+
const nodes = [];
|
|
1386
|
+
const scopeStack = [];
|
|
1387
|
+
const tagRe = /<span class="hljs-([^"]+)">|<\/span>/g;
|
|
1388
|
+
let lastIndex = 0;
|
|
1389
|
+
let match;
|
|
1390
|
+
const pushText = (raw) => {
|
|
1391
|
+
if (!raw) return;
|
|
1392
|
+
const currentScope = scopeStack.length > 0 ? scopeStack[scopeStack.length - 1] : null;
|
|
1393
|
+
const scope = currentScope ? currentScope.split(/\s+/)[0].replace(/_$/, "") : null;
|
|
1394
|
+
nodes.push({ text: decodeEntities(raw), scope });
|
|
1395
|
+
};
|
|
1396
|
+
while ((match = tagRe.exec(html)) !== null) {
|
|
1397
|
+
pushText(html.slice(lastIndex, match.index));
|
|
1398
|
+
lastIndex = tagRe.lastIndex;
|
|
1399
|
+
if (match[0] === "</span>") {
|
|
1400
|
+
scopeStack.pop();
|
|
1401
|
+
} else if (match[1]) {
|
|
1402
|
+
scopeStack.push(match[1]);
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
pushText(html.slice(lastIndex));
|
|
1406
|
+
return nodes;
|
|
1407
|
+
}
|
|
1408
|
+
function createHighlighter(theme) {
|
|
1409
|
+
return {
|
|
1410
|
+
supportsLanguage: (language) => {
|
|
1411
|
+
if (!language || language === "plaintext" || language === "text") {
|
|
1412
|
+
return false;
|
|
1413
|
+
}
|
|
1414
|
+
try {
|
|
1415
|
+
return hljs.getLanguage(language) !== void 0;
|
|
1416
|
+
} catch {
|
|
1417
|
+
return false;
|
|
1418
|
+
}
|
|
1419
|
+
},
|
|
1420
|
+
highlight: (code, options) => {
|
|
1421
|
+
const language = options.language;
|
|
1422
|
+
if (!language || language === "plaintext" || language === "text") {
|
|
1423
|
+
return code;
|
|
1424
|
+
}
|
|
1425
|
+
try {
|
|
1426
|
+
if (hljs.getLanguage(language) === void 0) {
|
|
1427
|
+
return code;
|
|
1428
|
+
}
|
|
1429
|
+
const { value } = hljs.highlight(code, { language, ignoreIllegals: true });
|
|
1430
|
+
return parseHljsHtml(value).map((node) => {
|
|
1431
|
+
const role = node.scope ? scopeToRole(node.scope) : null;
|
|
1432
|
+
return role ? theme.role(role, node.text) : node.text;
|
|
1433
|
+
}).join("");
|
|
1434
|
+
} catch {
|
|
1435
|
+
return code;
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
};
|
|
1439
|
+
}
|
|
1440
|
+
function highlightByPath(code, filePath, theme) {
|
|
1441
|
+
const language = languageFromPath(filePath);
|
|
1442
|
+
if (!language) {
|
|
1443
|
+
return code;
|
|
1444
|
+
}
|
|
1445
|
+
const highlighter = createHighlighter(theme);
|
|
1446
|
+
if (!highlighter.supportsLanguage(language)) {
|
|
1447
|
+
return code;
|
|
1448
|
+
}
|
|
1449
|
+
return highlighter.highlight(code, { language });
|
|
1450
|
+
}
|
|
1451
|
+
var EXTENSION_LANGUAGES = {
|
|
1452
|
+
ts: "typescript",
|
|
1453
|
+
tsx: "typescript",
|
|
1454
|
+
mts: "typescript",
|
|
1455
|
+
cts: "typescript",
|
|
1456
|
+
js: "javascript",
|
|
1457
|
+
jsx: "javascript",
|
|
1458
|
+
mjs: "javascript",
|
|
1459
|
+
cjs: "javascript",
|
|
1460
|
+
py: "python",
|
|
1461
|
+
rb: "ruby",
|
|
1462
|
+
rs: "rust",
|
|
1463
|
+
go: "go",
|
|
1464
|
+
java: "java",
|
|
1465
|
+
kt: "kotlin",
|
|
1466
|
+
c: "c",
|
|
1467
|
+
h: "c",
|
|
1468
|
+
cc: "cpp",
|
|
1469
|
+
cpp: "cpp",
|
|
1470
|
+
hpp: "cpp",
|
|
1471
|
+
cs: "csharp",
|
|
1472
|
+
sh: "bash",
|
|
1473
|
+
bash: "bash",
|
|
1474
|
+
zsh: "bash",
|
|
1475
|
+
yml: "yaml",
|
|
1476
|
+
yaml: "yaml",
|
|
1477
|
+
json: "json",
|
|
1478
|
+
md: "markdown",
|
|
1479
|
+
html: "xml",
|
|
1480
|
+
xml: "xml",
|
|
1481
|
+
css: "css",
|
|
1482
|
+
scss: "scss",
|
|
1483
|
+
sql: "sql",
|
|
1484
|
+
toml: "ini",
|
|
1485
|
+
ini: "ini",
|
|
1486
|
+
php: "php",
|
|
1487
|
+
swift: "swift"
|
|
1488
|
+
};
|
|
1489
|
+
function languageFromPath(filePath) {
|
|
1490
|
+
const ext = extname(filePath).slice(1).toLowerCase();
|
|
1491
|
+
if (!ext) {
|
|
1492
|
+
return null;
|
|
1493
|
+
}
|
|
1494
|
+
const mapped = EXTENSION_LANGUAGES[ext];
|
|
1495
|
+
if (mapped) {
|
|
1496
|
+
return mapped;
|
|
1497
|
+
}
|
|
1498
|
+
try {
|
|
1499
|
+
return hljs.getLanguage(ext) !== void 0 ? ext : null;
|
|
1500
|
+
} catch {
|
|
1501
|
+
return null;
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
// src/react-ink/markdown/MarkdownTable.tsx
|
|
1506
|
+
import chalk3 from "chalk";
|
|
1507
|
+
import stripAnsi4 from "strip-ansi";
|
|
1508
|
+
var MIN_COLUMN_WIDTH = 3;
|
|
1509
|
+
var COLUMN_GAP = 2;
|
|
1510
|
+
function MarkdownTable({ token, theme, highlight = null }) {
|
|
1511
|
+
const formatCell = (tokens) => (tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("");
|
|
1512
|
+
const displayWidth = (tokens) => stringWidth(stripAnsi4(formatCell(tokens)));
|
|
1513
|
+
const columnCount = token.header.length;
|
|
1514
|
+
const columnWidths = token.header.map((header, index) => {
|
|
1515
|
+
let max = displayWidth(header.tokens);
|
|
1516
|
+
for (const row of token.rows) {
|
|
1517
|
+
max = Math.max(max, displayWidth(row[index]?.tokens));
|
|
1518
|
+
}
|
|
1519
|
+
return Math.max(max, MIN_COLUMN_WIDTH);
|
|
1520
|
+
});
|
|
1521
|
+
const renderRow = (cells, key, bold) => /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: columnWidths.map((width, index) => {
|
|
1522
|
+
const cell = cells[index];
|
|
1523
|
+
const content = formatCell(cell?.tokens);
|
|
1524
|
+
const visible = stringWidth(stripAnsi4(content));
|
|
1525
|
+
const align = token.align?.[index];
|
|
1526
|
+
const padded = padAligned(content, visible, width, align ?? "left");
|
|
1527
|
+
const styled = bold ? chalk3.bold(padded) : padded;
|
|
1528
|
+
const gap = index < columnCount - 1 ? " ".repeat(COLUMN_GAP) : "";
|
|
1529
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
1530
|
+
styled,
|
|
1531
|
+
gap
|
|
1532
|
+
] }, index);
|
|
1533
|
+
}) }, key);
|
|
1534
|
+
const separator = /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: columnWidths.map((width, index) => {
|
|
1535
|
+
const gap = index < columnCount - 1 ? " ".repeat(COLUMN_GAP) : "";
|
|
1536
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
1537
|
+
theme.dim("-".repeat(width)),
|
|
1538
|
+
gap
|
|
1539
|
+
] }, index);
|
|
1540
|
+
}) });
|
|
1541
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
1542
|
+
renderRow(token.header, "header", true),
|
|
1543
|
+
separator,
|
|
1544
|
+
token.rows.map((row, rowIndex) => renderRow(row, `row-${rowIndex}`, false))
|
|
1545
|
+
] });
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
// src/react-ink/markdown/Markdown.tsx
|
|
1549
|
+
function stripPromptXMLTags(text) {
|
|
1550
|
+
return text.replace(/<\/?(?:system-reminder|prompt|context)[^>]*>/g, "");
|
|
1551
|
+
}
|
|
1552
|
+
function Markdown({ children, theme, highlightCode = true, dim = false }) {
|
|
1553
|
+
const highlight = useMemo(
|
|
1554
|
+
() => highlightCode ? createHighlighter(theme) : null,
|
|
1555
|
+
[highlightCode, theme]
|
|
1556
|
+
);
|
|
1557
|
+
const elements = useMemo(() => {
|
|
1558
|
+
configureMarked();
|
|
1559
|
+
const tokens = cachedLexer(stripPromptXMLTags(children));
|
|
1560
|
+
const out = [];
|
|
1561
|
+
let buffer = "";
|
|
1562
|
+
const flush = () => {
|
|
1563
|
+
if (buffer) {
|
|
1564
|
+
const text = buffer.replace(/\n+$/, "");
|
|
1565
|
+
if (text) {
|
|
1566
|
+
out.push(
|
|
1567
|
+
/* @__PURE__ */ jsx(Text, { children: dim ? theme.dim(text) : text }, out.length)
|
|
1568
|
+
);
|
|
1569
|
+
}
|
|
1570
|
+
buffer = "";
|
|
1571
|
+
}
|
|
1572
|
+
};
|
|
1573
|
+
for (const token of tokens) {
|
|
1574
|
+
if (token.type === "table") {
|
|
1575
|
+
flush();
|
|
1576
|
+
out.push(
|
|
1577
|
+
/* @__PURE__ */ jsx(
|
|
1578
|
+
MarkdownTable,
|
|
1579
|
+
{
|
|
1580
|
+
token,
|
|
1581
|
+
theme,
|
|
1582
|
+
highlight
|
|
1583
|
+
},
|
|
1584
|
+
out.length
|
|
1585
|
+
)
|
|
1586
|
+
);
|
|
1587
|
+
} else {
|
|
1588
|
+
buffer += formatToken(token, theme, highlight);
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
flush();
|
|
1592
|
+
return out;
|
|
1593
|
+
}, [children, dim, highlight, theme]);
|
|
1594
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: elements });
|
|
1595
|
+
}
|
|
1596
|
+
|
|
563
1597
|
// src/react-ink/utils/tool-display.ts
|
|
564
1598
|
import { homedir } from "node:os";
|
|
1599
|
+
|
|
1600
|
+
// src/react-ink/diff/structured.ts
|
|
1601
|
+
import { structuredPatch } from "diff";
|
|
1602
|
+
|
|
1603
|
+
// src/react-ink/diff/word-diff.ts
|
|
1604
|
+
import { diffWordsWithSpace } from "diff";
|
|
1605
|
+
var CHANGE_THRESHOLD = 0.4;
|
|
1606
|
+
function wordDiffLine(oldLine, newLine, side) {
|
|
1607
|
+
const lineText = side === "removed" ? oldLine : newLine;
|
|
1608
|
+
if (oldLine.length === 0 || newLine.length === 0) {
|
|
1609
|
+
return [{ text: lineText, changed: true }];
|
|
1610
|
+
}
|
|
1611
|
+
let changes;
|
|
1612
|
+
try {
|
|
1613
|
+
changes = diffWordsWithSpace(oldLine, newLine);
|
|
1614
|
+
} catch {
|
|
1615
|
+
return [{ text: lineText, changed: true }];
|
|
1616
|
+
}
|
|
1617
|
+
let changedChars = 0;
|
|
1618
|
+
let totalChars = 0;
|
|
1619
|
+
for (const change of changes) {
|
|
1620
|
+
totalChars += change.value.length;
|
|
1621
|
+
if (change.added || change.removed) {
|
|
1622
|
+
changedChars += change.value.length;
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
const fraction = totalChars === 0 ? 0 : changedChars / totalChars;
|
|
1626
|
+
if (fraction > CHANGE_THRESHOLD) {
|
|
1627
|
+
return [{ text: lineText, changed: true }];
|
|
1628
|
+
}
|
|
1629
|
+
const spans = [];
|
|
1630
|
+
for (const change of changes) {
|
|
1631
|
+
const belongs = side === "removed" ? !change.added : !change.removed;
|
|
1632
|
+
if (!belongs) {
|
|
1633
|
+
continue;
|
|
1634
|
+
}
|
|
1635
|
+
spans.push({ text: change.value, changed: Boolean(change.added || change.removed) });
|
|
1636
|
+
}
|
|
1637
|
+
return spans.length > 0 ? spans : [{ text: lineText, changed: false }];
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
// src/react-ink/diff/structured.ts
|
|
1641
|
+
var CONTEXT_LINES = 3;
|
|
1642
|
+
function buildStructuredDiff(oldStr, newStr, filePath = "") {
|
|
1643
|
+
if (oldStr === newStr) {
|
|
1644
|
+
return null;
|
|
1645
|
+
}
|
|
1646
|
+
let patch;
|
|
1647
|
+
try {
|
|
1648
|
+
patch = structuredPatch(filePath, filePath, oldStr, newStr, "", "", { context: CONTEXT_LINES });
|
|
1649
|
+
} catch {
|
|
1650
|
+
return null;
|
|
1651
|
+
}
|
|
1652
|
+
const hunks = [];
|
|
1653
|
+
let addedCount = 0;
|
|
1654
|
+
let removedCount = 0;
|
|
1655
|
+
for (const hunk of patch.hunks) {
|
|
1656
|
+
const lines = classifyHunkLines(hunk);
|
|
1657
|
+
for (const line of lines) {
|
|
1658
|
+
if (line.kind === "added") addedCount += 1;
|
|
1659
|
+
else if (line.kind === "removed") removedCount += 1;
|
|
1660
|
+
}
|
|
1661
|
+
if (lines.length > 0) {
|
|
1662
|
+
hunks.push({ oldStart: hunk.oldStart, newStart: hunk.newStart, lines });
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
if (hunks.length === 0) {
|
|
1666
|
+
return null;
|
|
1667
|
+
}
|
|
1668
|
+
return { hunks, addedCount, removedCount };
|
|
1669
|
+
}
|
|
1670
|
+
function classifyHunkLines(hunk) {
|
|
1671
|
+
const out = [];
|
|
1672
|
+
let oldNum = hunk.oldStart;
|
|
1673
|
+
let newNum = hunk.newStart;
|
|
1674
|
+
const rawLines = hunk.lines.filter((line) => !line.startsWith("\\"));
|
|
1675
|
+
let removedRun = [];
|
|
1676
|
+
let removedRunStart = -1;
|
|
1677
|
+
const flushPairing = (addedRun2) => {
|
|
1678
|
+
const pairs = Math.min(removedRun.length, addedRun2.length);
|
|
1679
|
+
for (let i = 0; i < pairs; i += 1) {
|
|
1680
|
+
const removed = removedRun[i];
|
|
1681
|
+
const added = addedRun2[i];
|
|
1682
|
+
removed.spans = wordDiffLine(removed.text, added.text, "removed");
|
|
1683
|
+
added.spans = wordDiffLine(removed.text, added.text, "added");
|
|
1684
|
+
}
|
|
1685
|
+
removedRun = [];
|
|
1686
|
+
removedRunStart = -1;
|
|
1687
|
+
};
|
|
1688
|
+
let addedRun = [];
|
|
1689
|
+
for (const raw of rawLines) {
|
|
1690
|
+
const marker = raw[0];
|
|
1691
|
+
const text = raw.slice(1);
|
|
1692
|
+
if (marker === "-") {
|
|
1693
|
+
if (addedRun.length > 0) {
|
|
1694
|
+
addedRun = [];
|
|
1695
|
+
}
|
|
1696
|
+
const line = { kind: "removed", oldLine: oldNum, text };
|
|
1697
|
+
out.push(line);
|
|
1698
|
+
if (removedRunStart === -1) removedRunStart = out.length - 1;
|
|
1699
|
+
removedRun.push(line);
|
|
1700
|
+
oldNum += 1;
|
|
1701
|
+
} else if (marker === "+") {
|
|
1702
|
+
const line = { kind: "added", newLine: newNum, text };
|
|
1703
|
+
out.push(line);
|
|
1704
|
+
addedRun.push(line);
|
|
1705
|
+
newNum += 1;
|
|
1706
|
+
} else {
|
|
1707
|
+
if (removedRun.length > 0 && addedRun.length > 0) {
|
|
1708
|
+
flushPairing(addedRun);
|
|
1709
|
+
}
|
|
1710
|
+
removedRun = [];
|
|
1711
|
+
removedRunStart = -1;
|
|
1712
|
+
addedRun = [];
|
|
1713
|
+
out.push({ kind: "context", oldLine: oldNum, newLine: newNum, text });
|
|
1714
|
+
oldNum += 1;
|
|
1715
|
+
newNum += 1;
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
if (removedRun.length > 0 && addedRun.length > 0) {
|
|
1719
|
+
flushPairing(addedRun);
|
|
1720
|
+
}
|
|
1721
|
+
return out;
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
// src/react-ink/utils/tool-display.ts
|
|
565
1725
|
function asRecord(value) {
|
|
566
1726
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
567
1727
|
}
|
|
@@ -644,6 +1804,12 @@ function clipBody(value, maxLines = 8, maxChars = 1400) {
|
|
|
644
1804
|
}
|
|
645
1805
|
return previewMultiline(value, { maxLines, maxChars });
|
|
646
1806
|
}
|
|
1807
|
+
function highlightedBody(body, filePath, theme) {
|
|
1808
|
+
if (!body || !theme || !filePath || languageFromPath(filePath) === null) {
|
|
1809
|
+
return { body };
|
|
1810
|
+
}
|
|
1811
|
+
return { body: highlightByPath(body, filePath, theme), preformatted: true };
|
|
1812
|
+
}
|
|
647
1813
|
function extractDetails(value) {
|
|
648
1814
|
return asRecord(asRecord(value)?.details);
|
|
649
1815
|
}
|
|
@@ -710,7 +1876,7 @@ function fallbackBody(output, fallbackOutputText, showImages = false) {
|
|
|
710
1876
|
return clipBody(fallbackOutputText);
|
|
711
1877
|
}
|
|
712
1878
|
function describeToolSource(source) {
|
|
713
|
-
const { args, fallbackArgsText, fallbackOutputText, output, showImages = false, toolName } = source;
|
|
1879
|
+
const { args, fallbackArgsText, fallbackOutputText, output, showImages = false, theme, toolName } = source;
|
|
714
1880
|
const argsRecord = asRecord(args);
|
|
715
1881
|
const details = extractDetails(output);
|
|
716
1882
|
const outputText = toolText(output, showImages);
|
|
@@ -728,10 +1894,12 @@ function describeToolSource(source) {
|
|
|
728
1894
|
summary += `:${start}${end ? `-${end}` : ""}`;
|
|
729
1895
|
}
|
|
730
1896
|
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";
|
|
1897
|
+
const readBody = hasResult && !containsImage(output) ? highlightedBody(clipBody(outputText, 10, 1800), rawPath, theme) : { body: hasResult ? clipBody(outputText, 10, 1800) : void 0 };
|
|
731
1898
|
return {
|
|
732
1899
|
title,
|
|
733
1900
|
summary: hasResult ? responseSummary : summary,
|
|
734
|
-
body:
|
|
1901
|
+
body: readBody.body,
|
|
1902
|
+
preformatted: readBody.preformatted,
|
|
735
1903
|
emptyText: "Reading file..."
|
|
736
1904
|
};
|
|
737
1905
|
}
|
|
@@ -739,10 +1907,14 @@ function describeToolSource(source) {
|
|
|
739
1907
|
const rawPath = asString(argsRecord?.file_path) ?? asString(argsRecord?.path) ?? "";
|
|
740
1908
|
const content = asString(argsRecord?.content);
|
|
741
1909
|
const responseSummary = firstMeaningfulLine(outputText) ?? "Wrote file";
|
|
1910
|
+
const writeDiff = !hasResult && content !== void 0 && content.length > 0 ? buildStructuredDiff("", content, rawPath) ?? void 0 : void 0;
|
|
1911
|
+
const writeBody = hasResult ? { body: clipBody(outputText, 8, 1500) } : highlightedBody(clipBody(content, 8, 1500), rawPath, theme);
|
|
742
1912
|
return {
|
|
743
1913
|
title,
|
|
744
1914
|
summary: hasResult ? responseSummary : rawPath ? shortenPath2(rawPath) : void 0,
|
|
745
|
-
body:
|
|
1915
|
+
body: writeDiff ? void 0 : writeBody.body,
|
|
1916
|
+
preformatted: writeDiff ? void 0 : writeBody.preformatted,
|
|
1917
|
+
diff: writeDiff,
|
|
746
1918
|
emptyText: "Preparing file write..."
|
|
747
1919
|
};
|
|
748
1920
|
}
|
|
@@ -759,10 +1931,15 @@ function describeToolSource(source) {
|
|
|
759
1931
|
400
|
|
760
1932
|
) : void 0;
|
|
761
1933
|
const responseSummary = firstMeaningfulLine(outputText) ?? "Applied edit";
|
|
1934
|
+
const editDiff = oldText !== void 0 && newText !== void 0 ? buildStructuredDiff(oldText, newText, rawPath) ?? void 0 : void 0;
|
|
1935
|
+
const editBody = hasResult ? highlightedBody(clipBody(outputText, 8, 1500), rawPath, theme) : { body: replacementPreview };
|
|
1936
|
+
const editChangeSummary = editDiff ? `+${editDiff.addedCount} -${editDiff.removedCount}` : void 0;
|
|
762
1937
|
return {
|
|
763
1938
|
title,
|
|
764
|
-
summary: hasResult ? responseSummary : rawPath ? shortenPath2(rawPath) : void 0,
|
|
765
|
-
body:
|
|
1939
|
+
summary: hasResult ? editChangeSummary ?? responseSummary : editChangeSummary ?? (rawPath ? shortenPath2(rawPath) : void 0),
|
|
1940
|
+
body: editDiff ? void 0 : editBody.body,
|
|
1941
|
+
preformatted: editDiff ? void 0 : editBody.preformatted,
|
|
1942
|
+
diff: editDiff,
|
|
766
1943
|
emptyText: "Applying edit..."
|
|
767
1944
|
};
|
|
768
1945
|
}
|
|
@@ -859,7 +2036,7 @@ function describeToolCall(toolCall) {
|
|
|
859
2036
|
args: toolCall.arguments
|
|
860
2037
|
});
|
|
861
2038
|
}
|
|
862
|
-
function describeToolResult(message, showImages, args) {
|
|
2039
|
+
function describeToolResult(message, showImages, args, theme) {
|
|
863
2040
|
return describeToolSource({
|
|
864
2041
|
args,
|
|
865
2042
|
toolName: message.toolName,
|
|
@@ -867,12 +2044,13 @@ function describeToolResult(message, showImages, args) {
|
|
|
867
2044
|
content: message.content,
|
|
868
2045
|
details: message.details
|
|
869
2046
|
},
|
|
870
|
-
showImages
|
|
2047
|
+
showImages,
|
|
2048
|
+
theme
|
|
871
2049
|
});
|
|
872
2050
|
}
|
|
873
2051
|
|
|
874
2052
|
// src/react-ink/components/ToolEventBlock.tsx
|
|
875
|
-
import
|
|
2053
|
+
import stripAnsi5 from "strip-ansi";
|
|
876
2054
|
function statusMarker(status) {
|
|
877
2055
|
switch (status) {
|
|
878
2056
|
case "error":
|
|
@@ -883,12 +2061,15 @@ function statusMarker(status) {
|
|
|
883
2061
|
return ">";
|
|
884
2062
|
}
|
|
885
2063
|
}
|
|
2064
|
+
function statusColorKey(status) {
|
|
2065
|
+
return status === "error" ? "error" : "text";
|
|
2066
|
+
}
|
|
886
2067
|
function plainToolText(text) {
|
|
887
|
-
return
|
|
2068
|
+
return stripAnsi5(text);
|
|
888
2069
|
}
|
|
889
2070
|
function splitVisibleLines(text) {
|
|
890
2071
|
return (text ?? "").split(/\r?\n/).map((line) => line.trimEnd()).filter((line, index, lines) => {
|
|
891
|
-
if (line.length > 0) {
|
|
2072
|
+
if (stripAnsi5(line).length > 0) {
|
|
892
2073
|
return true;
|
|
893
2074
|
}
|
|
894
2075
|
return index !== 0 && index !== lines.length - 1;
|
|
@@ -919,11 +2100,12 @@ function ToolEventBlock({
|
|
|
919
2100
|
indent = 0,
|
|
920
2101
|
marginBottom = 1,
|
|
921
2102
|
maxContentLines = 10,
|
|
2103
|
+
preformatted = false,
|
|
922
2104
|
showSummaryInline = false,
|
|
923
2105
|
showTitle = true,
|
|
924
2106
|
status,
|
|
925
2107
|
summary,
|
|
926
|
-
theme
|
|
2108
|
+
theme,
|
|
927
2109
|
title
|
|
928
2110
|
}) {
|
|
929
2111
|
const normalizedSummary = summary?.trim();
|
|
@@ -939,19 +2121,19 @@ function ToolEventBlock({
|
|
|
939
2121
|
const { visibleLines, hiddenLineCount } = clampContentLines(combinedLines, maxContentLines);
|
|
940
2122
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom, marginLeft: indent, children: [
|
|
941
2123
|
showTitle ? /* @__PURE__ */ jsxs(Box, { children: [
|
|
942
|
-
/* @__PURE__ */ jsx(Text, {
|
|
943
|
-
/* @__PURE__ */ jsx(Text, {
|
|
944
|
-
showSummaryInline && normalizedSummary ? /* @__PURE__ */ jsx(Text, {
|
|
2124
|
+
/* @__PURE__ */ jsx(Text, { children: theme.color(statusColorKey(status), plainToolText(`${statusMarker(status)} `)) }),
|
|
2125
|
+
/* @__PURE__ */ jsx(Text, { children: theme.color(statusColorKey(status), plainToolText(title)) }),
|
|
2126
|
+
showSummaryInline && normalizedSummary ? /* @__PURE__ */ jsx(Text, { children: theme.muted(plainToolText(` (${normalizedSummary})`)) }) : null
|
|
945
2127
|
] }) : null,
|
|
946
2128
|
visibleLines.map((line, index) => /* @__PURE__ */ jsx(
|
|
947
2129
|
Box,
|
|
948
2130
|
{
|
|
949
2131
|
marginLeft: line.kind === "response" ? showTitle ? 2 : 0 : showTitle ? 4 : 2,
|
|
950
|
-
children: /* @__PURE__ */ jsx(Text, {
|
|
2132
|
+
children: preformatted ? /* @__PURE__ */ jsx(Text, { children: line.text }) : /* @__PURE__ */ jsx(Text, { children: theme.color("text", plainToolText(line.text)) })
|
|
951
2133
|
},
|
|
952
|
-
`${line.kind}:${index}:${line.text}`
|
|
2134
|
+
`${line.kind}:${index}:${stripAnsi5(line.text)}`
|
|
953
2135
|
)),
|
|
954
|
-
hiddenLineCount > 0 ? /* @__PURE__ */ jsx(Box, { marginLeft: showTitle ? 4 : 2, children: /* @__PURE__ */ jsx(Text, {
|
|
2136
|
+
hiddenLineCount > 0 ? /* @__PURE__ */ jsx(Box, { marginLeft: showTitle ? 4 : 2, children: /* @__PURE__ */ jsx(Text, { children: theme.muted(plainToolText(`... ${hiddenLineCount} more line(s)`)) }) }) : null
|
|
955
2137
|
] });
|
|
956
2138
|
}
|
|
957
2139
|
|
|
@@ -974,17 +2156,100 @@ function ToolCallMessage({ theme, toolCall }) {
|
|
|
974
2156
|
);
|
|
975
2157
|
}
|
|
976
2158
|
|
|
2159
|
+
// src/react-ink/diff/Diff.tsx
|
|
2160
|
+
import chalk4 from "chalk";
|
|
2161
|
+
function lineMarker(kind) {
|
|
2162
|
+
switch (kind) {
|
|
2163
|
+
case "added":
|
|
2164
|
+
return "+";
|
|
2165
|
+
case "removed":
|
|
2166
|
+
return "-";
|
|
2167
|
+
default:
|
|
2168
|
+
return " ";
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
function gutterWidth(diff) {
|
|
2172
|
+
let max = 1;
|
|
2173
|
+
for (const hunk of diff.hunks) {
|
|
2174
|
+
for (const line of hunk.lines) {
|
|
2175
|
+
const num = line.kind === "removed" ? line.oldLine : line.newLine;
|
|
2176
|
+
if (num !== void 0) {
|
|
2177
|
+
max = Math.max(max, stringWidth(String(num)));
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
return max;
|
|
2182
|
+
}
|
|
2183
|
+
function renderLineText(line, theme, bgRole, fgRole) {
|
|
2184
|
+
const paintSpan = (text, changed) => {
|
|
2185
|
+
const fg = theme.role(fgRole, text);
|
|
2186
|
+
return changed ? chalk4.bold(fg) : fg;
|
|
2187
|
+
};
|
|
2188
|
+
let body;
|
|
2189
|
+
if (line.spans && line.spans.length > 0) {
|
|
2190
|
+
body = line.spans.map((span) => paintSpan(span.text, span.changed)).join("");
|
|
2191
|
+
} else {
|
|
2192
|
+
body = theme.role(fgRole, line.text);
|
|
2193
|
+
}
|
|
2194
|
+
return bgRole ? theme.roleBackground(bgRole, body) : body;
|
|
2195
|
+
}
|
|
2196
|
+
function Diff({ diff, theme, indent = 0, marginBottom = 0 }) {
|
|
2197
|
+
const gutter = gutterWidth(diff);
|
|
2198
|
+
const renderLine = (line, key) => {
|
|
2199
|
+
const num = line.kind === "removed" ? line.oldLine : line.newLine;
|
|
2200
|
+
const gutterText = (num !== void 0 ? String(num) : "").padStart(gutter);
|
|
2201
|
+
const marker = lineMarker(line.kind);
|
|
2202
|
+
const bgRole = line.kind === "added" ? "diffAddedBg" : line.kind === "removed" ? "diffRemovedBg" : null;
|
|
2203
|
+
const fgRole = line.kind === "added" ? "diffAddedText" : line.kind === "removed" ? "diffRemovedText" : "blockquoteBar";
|
|
2204
|
+
const gutterStyled = theme.dim(`${gutterText} `);
|
|
2205
|
+
const markerStyled = line.kind === "context" ? theme.dim(`${marker} `) : theme.role(fgRole, `${marker} `);
|
|
2206
|
+
const text = renderLineText(line, theme, bgRole, fgRole);
|
|
2207
|
+
return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
2208
|
+
gutterStyled,
|
|
2209
|
+
markerStyled,
|
|
2210
|
+
text
|
|
2211
|
+
] }) }, key);
|
|
2212
|
+
};
|
|
2213
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: indent, marginBottom, children: diff.hunks.map((hunk, hunkIndex) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
2214
|
+
hunkIndex > 0 ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { children: theme.dim("...") }) }) : null,
|
|
2215
|
+
hunk.lines.map((line, lineIndex) => renderLine(line, `${hunkIndex}-${lineIndex}`))
|
|
2216
|
+
] }, `hunk-${hunkIndex}`)) });
|
|
2217
|
+
}
|
|
2218
|
+
|
|
977
2219
|
// src/react-ink/components/messages/ToolResultBlock.tsx
|
|
978
2220
|
function ToolResultBlock({ expanded = false, message, nested = false, showImages, theme, toolCall }) {
|
|
979
|
-
const descriptor = describeToolResult(message, showImages, toolCall?.arguments);
|
|
2221
|
+
const descriptor = describeToolResult(message, showImages, toolCall?.arguments, theme);
|
|
2222
|
+
const indent = nested ? 4 : 2;
|
|
2223
|
+
if (descriptor.diff) {
|
|
2224
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 0, children: [
|
|
2225
|
+
/* @__PURE__ */ jsx(
|
|
2226
|
+
ToolEventBlock,
|
|
2227
|
+
{
|
|
2228
|
+
detail: void 0,
|
|
2229
|
+
emptyText: descriptor.emptyText,
|
|
2230
|
+
indent,
|
|
2231
|
+
marginBottom: 0,
|
|
2232
|
+
maxContentLines: 0,
|
|
2233
|
+
showSummaryInline: false,
|
|
2234
|
+
showTitle: !nested,
|
|
2235
|
+
status: message.isError ? "error" : "success",
|
|
2236
|
+
summary: descriptor.summary,
|
|
2237
|
+
theme,
|
|
2238
|
+
title: descriptor.title
|
|
2239
|
+
}
|
|
2240
|
+
),
|
|
2241
|
+
/* @__PURE__ */ jsx(Diff, { diff: descriptor.diff, theme, indent: indent + 2 })
|
|
2242
|
+
] });
|
|
2243
|
+
}
|
|
980
2244
|
return /* @__PURE__ */ jsx(
|
|
981
2245
|
ToolEventBlock,
|
|
982
2246
|
{
|
|
983
2247
|
detail: descriptor.body,
|
|
984
2248
|
emptyText: descriptor.emptyText,
|
|
985
|
-
indent
|
|
2249
|
+
indent,
|
|
986
2250
|
marginBottom: 0,
|
|
987
2251
|
maxContentLines: expanded ? Number.MAX_SAFE_INTEGER : 10,
|
|
2252
|
+
preformatted: descriptor.preformatted,
|
|
988
2253
|
showSummaryInline: false,
|
|
989
2254
|
showTitle: !nested,
|
|
990
2255
|
status: message.isError ? "error" : "success",
|
|
@@ -1009,7 +2274,7 @@ function AssistantMessageView({
|
|
|
1009
2274
|
const matchedToolResultIds = /* @__PURE__ */ new Set();
|
|
1010
2275
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
1011
2276
|
/* @__PURE__ */ jsx(Text, { children: theme.color("accent", `Assistant ${message.provider}/${message.model} ${formatMessageTimestamp(message.timestamp)}`) }),
|
|
1012
|
-
parts.text ? /* @__PURE__ */ jsx(
|
|
2277
|
+
parts.text ? /* @__PURE__ */ jsx(Markdown, { theme, children: parts.text }) : null,
|
|
1013
2278
|
parts.thinking.map((thinking, index) => /* @__PURE__ */ jsx(Text, { children: theme.muted(`[thinking] ${thinking}`) }, index)),
|
|
1014
2279
|
parts.toolCalls.map((toolCall) => {
|
|
1015
2280
|
const toolResult = toolResultsByCallId.get(toolCall.id);
|
|
@@ -1211,20 +2476,20 @@ function MessageList({
|
|
|
1211
2476
|
}
|
|
1212
2477
|
|
|
1213
2478
|
// src/react-ink/components/StatusLine.tsx
|
|
1214
|
-
function StatusLine({ snapshot, status, theme }) {
|
|
2479
|
+
function StatusLine({ snapshot, status, theme, showBusyText = true }) {
|
|
1215
2480
|
let text = status?.text;
|
|
1216
2481
|
let tone = status?.kind ?? "info";
|
|
1217
2482
|
if (!text) {
|
|
1218
|
-
if (snapshot.isCompacting) {
|
|
2483
|
+
if (showBusyText && snapshot.isCompacting) {
|
|
1219
2484
|
text = "Compacting conversation context...";
|
|
1220
2485
|
tone = "busy";
|
|
1221
|
-
} else if (snapshot.isBashRunning) {
|
|
2486
|
+
} else if (showBusyText && snapshot.isBashRunning) {
|
|
1222
2487
|
text = "Running bash command...";
|
|
1223
2488
|
tone = "busy";
|
|
1224
|
-
} else if (snapshot.pendingToolCallCount > 0 || snapshot.pendingMessageCount > 0) {
|
|
2489
|
+
} else if (showBusyText && (snapshot.pendingToolCallCount > 0 || snapshot.pendingMessageCount > 0)) {
|
|
1225
2490
|
text = "Agent working...";
|
|
1226
2491
|
tone = "busy";
|
|
1227
|
-
} else if (snapshot.isStreaming) {
|
|
2492
|
+
} else if (showBusyText && snapshot.isStreaming) {
|
|
1228
2493
|
text = "Agent working...";
|
|
1229
2494
|
tone = "busy";
|
|
1230
2495
|
} else if (snapshot.error) {
|
|
@@ -1289,14 +2554,6 @@ function DialogFrame({ children, footer, subtitle, title }) {
|
|
|
1289
2554
|
] });
|
|
1290
2555
|
}
|
|
1291
2556
|
|
|
1292
|
-
// src/react-host/index.ts
|
|
1293
|
-
var React = await loadHostReact();
|
|
1294
|
-
var Fragment2 = React.Fragment;
|
|
1295
|
-
var createElement = React.createElement;
|
|
1296
|
-
var useEffect = React.useEffect;
|
|
1297
|
-
var useMemo = React.useMemo;
|
|
1298
|
-
var useState = React.useState;
|
|
1299
|
-
|
|
1300
2557
|
// src/react-ink/utils/selection-dialog.ts
|
|
1301
2558
|
function matchesSearchQuery(value, query) {
|
|
1302
2559
|
if (!query.trim()) {
|
|
@@ -1323,6 +2580,7 @@ function SelectableDialog({
|
|
|
1323
2580
|
noSearchResultsText = "No options matched the current search.",
|
|
1324
2581
|
onClose,
|
|
1325
2582
|
onSelect,
|
|
2583
|
+
onHighlight,
|
|
1326
2584
|
getSearchText,
|
|
1327
2585
|
renderItem
|
|
1328
2586
|
}) {
|
|
@@ -1342,6 +2600,12 @@ function SelectableDialog({
|
|
|
1342
2600
|
setSelectedIndex(0);
|
|
1343
2601
|
}
|
|
1344
2602
|
}, [filteredItems.length, selectedIndex]);
|
|
2603
|
+
const highlighted = filteredItems[selectedIndex];
|
|
2604
|
+
useEffect(() => {
|
|
2605
|
+
if (isActive && onHighlight && highlighted !== void 0) {
|
|
2606
|
+
onHighlight(highlighted, selectedIndex);
|
|
2607
|
+
}
|
|
2608
|
+
}, [highlighted, isActive]);
|
|
1345
2609
|
const maxVisible = useMemo(() => Math.max(8, (process.stdout.rows ?? 24) - 16), []);
|
|
1346
2610
|
const windowStart = Math.max(
|
|
1347
2611
|
0,
|
|
@@ -2368,18 +3632,30 @@ function StartupSessionPicker({ onClose, onSelect, sessions, totalCount }) {
|
|
|
2368
3632
|
}
|
|
2369
3633
|
|
|
2370
3634
|
// src/react-ink/components/dialogs/ThemeDialog.tsx
|
|
2371
|
-
function
|
|
3635
|
+
function toItem(entry) {
|
|
3636
|
+
return typeof entry === "string" ? { id: entry, label: entry } : entry;
|
|
3637
|
+
}
|
|
3638
|
+
function ThemeDialog({ themes, onClose, onSelect, onHighlight }) {
|
|
3639
|
+
const items = themes.map(toItem);
|
|
2372
3640
|
return /* @__PURE__ */ jsx(
|
|
2373
3641
|
SelectableDialog,
|
|
2374
3642
|
{
|
|
2375
3643
|
title: "Themes",
|
|
2376
|
-
items
|
|
3644
|
+
items,
|
|
2377
3645
|
emptyText: "No themes are available.",
|
|
2378
3646
|
onClose,
|
|
2379
|
-
onSelect,
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
3647
|
+
onSelect: (item) => onSelect(item.id),
|
|
3648
|
+
onHighlight: onHighlight ? (item) => onHighlight(item.id) : void 0,
|
|
3649
|
+
getSearchText: (item) => `${item.label} ${item.description ?? ""}`,
|
|
3650
|
+
renderItem: (item, selected) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
3651
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
3652
|
+
selected ? "> " : " ",
|
|
3653
|
+
item.label
|
|
3654
|
+
] }),
|
|
3655
|
+
item.description ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
3656
|
+
" ",
|
|
3657
|
+
item.description
|
|
3658
|
+
] }) : null
|
|
2383
3659
|
] })
|
|
2384
3660
|
}
|
|
2385
3661
|
);
|
|
@@ -2423,17 +3699,77 @@ function UserMessageDialog({ items, onClose, onSelect }) {
|
|
|
2423
3699
|
}
|
|
2424
3700
|
);
|
|
2425
3701
|
}
|
|
3702
|
+
|
|
3703
|
+
// src/react-ink/markdown/StreamingMarkdown.tsx
|
|
3704
|
+
function lastStableBoundary(content) {
|
|
3705
|
+
let boundary = 0;
|
|
3706
|
+
let inFence = false;
|
|
3707
|
+
let lineStart = 0;
|
|
3708
|
+
let sawBlankRun = false;
|
|
3709
|
+
for (let i = 0; i <= content.length; i++) {
|
|
3710
|
+
const atEnd = i === content.length;
|
|
3711
|
+
const ch = atEnd ? "\n" : content[i];
|
|
3712
|
+
if (ch !== "\n" && !atEnd) {
|
|
3713
|
+
continue;
|
|
3714
|
+
}
|
|
3715
|
+
const line = content.slice(lineStart, i);
|
|
3716
|
+
if (line.trimStart().startsWith("```")) {
|
|
3717
|
+
inFence = !inFence;
|
|
3718
|
+
sawBlankRun = false;
|
|
3719
|
+
} else if (line.trim() === "") {
|
|
3720
|
+
if (!inFence) {
|
|
3721
|
+
sawBlankRun = true;
|
|
3722
|
+
}
|
|
3723
|
+
} else {
|
|
3724
|
+
if (sawBlankRun && !inFence) {
|
|
3725
|
+
boundary = lineStart;
|
|
3726
|
+
}
|
|
3727
|
+
sawBlankRun = false;
|
|
3728
|
+
}
|
|
3729
|
+
lineStart = i + 1;
|
|
3730
|
+
if (atEnd) {
|
|
3731
|
+
break;
|
|
3732
|
+
}
|
|
3733
|
+
}
|
|
3734
|
+
return boundary;
|
|
3735
|
+
}
|
|
3736
|
+
function StreamingMarkdown({
|
|
3737
|
+
children,
|
|
3738
|
+
theme,
|
|
3739
|
+
highlightCode = true,
|
|
3740
|
+
dim = false
|
|
3741
|
+
}) {
|
|
3742
|
+
const boundary = useMemo(() => lastStableBoundary(children), [children]);
|
|
3743
|
+
const stablePrefix = useMemo(
|
|
3744
|
+
() => children.slice(0, boundary).replace(/\n+$/, ""),
|
|
3745
|
+
[children, boundary]
|
|
3746
|
+
);
|
|
3747
|
+
const unstableSuffix = useMemo(() => children.slice(boundary), [children, boundary]);
|
|
3748
|
+
const stableNode = useMemo(
|
|
3749
|
+
() => stablePrefix ? /* @__PURE__ */ jsx(Markdown, { theme, highlightCode, dim, children: stablePrefix }) : null,
|
|
3750
|
+
[stablePrefix, theme, highlightCode, dim]
|
|
3751
|
+
);
|
|
3752
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3753
|
+
stableNode,
|
|
3754
|
+
unstableSuffix ? /* @__PURE__ */ jsx(Markdown, { theme, highlightCode, dim, children: unstableSuffix }) : null
|
|
3755
|
+
] });
|
|
3756
|
+
}
|
|
2426
3757
|
export {
|
|
2427
3758
|
AssistantMessageView,
|
|
2428
3759
|
BashMessageView,
|
|
2429
3760
|
BranchSummaryMessageView,
|
|
3761
|
+
CHANGE_THRESHOLD,
|
|
3762
|
+
CONTEXT_LINES,
|
|
2430
3763
|
ChangelogBlock,
|
|
2431
3764
|
CompactionMessageView,
|
|
2432
3765
|
CustomMessageView,
|
|
2433
3766
|
DialogFrame,
|
|
3767
|
+
Diff,
|
|
2434
3768
|
DisplayBlockView,
|
|
2435
3769
|
Footer,
|
|
2436
3770
|
LoginDialog,
|
|
3771
|
+
Markdown,
|
|
3772
|
+
MarkdownTable,
|
|
2437
3773
|
MessageList,
|
|
2438
3774
|
MessageRow,
|
|
2439
3775
|
ModelDialog,
|
|
@@ -2445,6 +3781,7 @@ export {
|
|
|
2445
3781
|
SkillInvocationMessage,
|
|
2446
3782
|
StartupSessionPicker,
|
|
2447
3783
|
StatusLine,
|
|
3784
|
+
StreamingMarkdown,
|
|
2448
3785
|
TaskPanel,
|
|
2449
3786
|
ThemeDialog,
|
|
2450
3787
|
ToolCallMessage,
|
|
@@ -2453,6 +3790,10 @@ export {
|
|
|
2453
3790
|
TreeDialog,
|
|
2454
3791
|
UserMessageDialog,
|
|
2455
3792
|
UserMessageView,
|
|
3793
|
+
buildStructuredDiff,
|
|
3794
|
+
cachedLexer,
|
|
3795
|
+
configureMarked,
|
|
3796
|
+
createHighlighter,
|
|
2456
3797
|
createThemeAdapter,
|
|
2457
3798
|
describeToolCall,
|
|
2458
3799
|
describeToolExecution,
|
|
@@ -2462,14 +3803,23 @@ export {
|
|
|
2462
3803
|
extractToolText,
|
|
2463
3804
|
formatCustomContent,
|
|
2464
3805
|
formatMessageTimestamp,
|
|
3806
|
+
formatToken,
|
|
2465
3807
|
formatToolCall,
|
|
2466
3808
|
formatToolResult,
|
|
2467
3809
|
formatUserContent,
|
|
3810
|
+
getListNumber,
|
|
3811
|
+
hasMarkdownSyntax,
|
|
3812
|
+
highlightByPath,
|
|
3813
|
+
languageFromPath,
|
|
2468
3814
|
matchesSearchQuery,
|
|
3815
|
+
padAligned,
|
|
2469
3816
|
parseSkillInvocation,
|
|
2470
3817
|
previewMultiline,
|
|
2471
3818
|
previewText,
|
|
2472
3819
|
safeStringify,
|
|
2473
3820
|
splitAssistantMessage,
|
|
3821
|
+
statusColorKey,
|
|
3822
|
+
stringWidth,
|
|
3823
|
+
wordDiffLine,
|
|
2474
3824
|
wrapSelectionIndex
|
|
2475
3825
|
};
|