@quandev104/pi-style 0.2.1 → 0.2.2
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 +10 -0
- package/README.md +1 -1
- package/dist/extensions/pi-style.js +632 -262
- package/dist/extensions/pi-style.js.map +1 -1
- package/extension-src/pi-style/app/runtime.ts +29 -4
- package/extension-src/pi-style/domain/status-renderer.ts +40 -8
- package/extension-src/pi-style/domain/status.ts +15 -5
- package/extension-src/pi-style/domain/theme.ts +32 -1
- package/extension-src/pi-style/features/editor/index.ts +17 -5
- package/extension-src/pi-style/features/messages/index.ts +302 -61
- package/extension-src/pi-style/features/status-line/index.ts +41 -11
- package/extension-src/pi-style/features/tools/boxed/bash.ts +101 -40
- package/extension-src/pi-style/features/tools/boxed/batch.ts +17 -1
- package/extension-src/pi-style/features/tools/boxed/edit.ts +20 -15
- package/extension-src/pi-style/features/tools/boxed/find.ts +9 -4
- package/extension-src/pi-style/features/tools/boxed/git.ts +46 -2
- package/extension-src/pi-style/features/tools/boxed/grep.ts +9 -2
- package/extension-src/pi-style/features/tools/boxed/ls.ts +9 -4
- package/extension-src/pi-style/features/tools/boxed/quick-edit.ts +18 -11
- package/extension-src/pi-style/features/tools/boxed/read.ts +4 -2
- package/extension-src/pi-style/features/tools/boxed/shared.ts +27 -1
- package/extension-src/pi-style/features/tools/boxed/turn-summary.ts +12 -0
- package/extension-src/pi-style/pi/index.ts +2 -0
- package/extension-src/pi-style/shared/ansi.ts +17 -5
- package/extension-src/pi-style/shared/box.ts +70 -4
- package/extension-src/pi-style/shared/split-diff.ts +8 -5
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// extension-src/pi-style/shared/ansi.ts
|
|
2
|
+
import { visibleWidth as tuiVisibleWidth } from "@earendil-works/pi-tui";
|
|
2
3
|
function isFinal(byte) {
|
|
3
4
|
return byte >= "@" && byte <= "~";
|
|
4
5
|
}
|
|
@@ -82,7 +83,7 @@ function stripAnsi(value) {
|
|
|
82
83
|
return output;
|
|
83
84
|
}
|
|
84
85
|
function visibleWidth(value) {
|
|
85
|
-
return
|
|
86
|
+
return tuiVisibleWidth(value);
|
|
86
87
|
}
|
|
87
88
|
function resetAnsi(value) {
|
|
88
89
|
return `${value}\x1B[0m`;
|
|
@@ -93,9 +94,10 @@ function fitAnsiWidth(value, width, ellipsis = "\u2026") {
|
|
|
93
94
|
function truncateAnsi(value, width, ellipsis = "\u2026") {
|
|
94
95
|
if (width <= 0) return "";
|
|
95
96
|
if (visibleWidth(value) <= width) return resetAnsi(value);
|
|
97
|
+
const ellipsisWidth = visibleWidth(ellipsis);
|
|
96
98
|
let output = "";
|
|
97
99
|
let visible = 0;
|
|
98
|
-
for (let i = 0; i < value.length && visible < width -
|
|
100
|
+
for (let i = 0; i < value.length && visible < width - ellipsisWidth; i++) {
|
|
99
101
|
if (value.charCodeAt(i) === 27) {
|
|
100
102
|
const start = i;
|
|
101
103
|
i++;
|
|
@@ -233,7 +235,7 @@ function getElapsedMs(result) {
|
|
|
233
235
|
// extension-src/pi-style/shared/render-budget.ts
|
|
234
236
|
import {
|
|
235
237
|
truncateToWidth as tuiTruncateToWidth,
|
|
236
|
-
visibleWidth as
|
|
238
|
+
visibleWidth as tuiVisibleWidth2,
|
|
237
239
|
wrapTextWithAnsi
|
|
238
240
|
} from "@earendil-works/pi-tui";
|
|
239
241
|
var MAX_RENDER_LINE_CHARS = 2e3;
|
|
@@ -455,7 +457,7 @@ function safeVisibleWidth(text) {
|
|
|
455
457
|
const fastWidth = knownVisibleWidth(text);
|
|
456
458
|
if (fastWidth) return fastWidth.visibleWidth;
|
|
457
459
|
if (text === TRUNCATE_ELLIPSIS) return 1;
|
|
458
|
-
return
|
|
460
|
+
return tuiVisibleWidth2(text);
|
|
459
461
|
}
|
|
460
462
|
function safeTruncateToWidth(text, maxWidth, ellipsis = "...", pad = false) {
|
|
461
463
|
const width = Math.floor(maxWidth);
|
|
@@ -743,12 +745,48 @@ function getTextOutput(result) {
|
|
|
743
745
|
});
|
|
744
746
|
return textBlocks.map((contentBlock) => String(contentBlock.text ?? "")).join("\n").replace(/\r/g, "");
|
|
745
747
|
}
|
|
748
|
+
var WORD_CP_UNKNOWN = 255;
|
|
749
|
+
var WORD_CP_SURROGATE = 254;
|
|
750
|
+
var WORD_CP_CLASS = new Uint8Array(65536).fill(WORD_CP_UNKNOWN);
|
|
751
|
+
for (let code = 48; code <= 57; code++) WORD_CP_CLASS[code] = 1;
|
|
752
|
+
for (let code = 65; code <= 90; code++) WORD_CP_CLASS[code] = 1;
|
|
753
|
+
for (let code = 97; code <= 122; code++) WORD_CP_CLASS[code] = 1;
|
|
754
|
+
WORD_CP_CLASS[39] = 1;
|
|
755
|
+
WORD_CP_CLASS[45] = 1;
|
|
756
|
+
WORD_CP_CLASS[95] = 1;
|
|
757
|
+
WORD_CP_CLASS.fill(WORD_CP_SURROGATE, 55296, 57344);
|
|
758
|
+
var NON_ASCII_WORD_RE = /[\p{L}\p{N}]/u;
|
|
759
|
+
var ASTRAL_WORD_CP = /* @__PURE__ */ new Map();
|
|
760
|
+
function astralWordMembership(codePoint) {
|
|
761
|
+
const cached = ASTRAL_WORD_CP.get(codePoint);
|
|
762
|
+
if (cached !== void 0) return cached;
|
|
763
|
+
const membership = NON_ASCII_WORD_RE.test(String.fromCodePoint(codePoint)) ? 1 : 0;
|
|
764
|
+
ASTRAL_WORD_CP.set(codePoint, membership);
|
|
765
|
+
return membership;
|
|
766
|
+
}
|
|
746
767
|
function countWords(text) {
|
|
768
|
+
const len = text.length;
|
|
747
769
|
let count = 0;
|
|
748
|
-
let inWord =
|
|
749
|
-
for (
|
|
750
|
-
const
|
|
751
|
-
|
|
770
|
+
let inWord = 0;
|
|
771
|
+
for (let i = 0; i < len; i++) {
|
|
772
|
+
const code = text.charCodeAt(i);
|
|
773
|
+
const membership = WORD_CP_CLASS[code] ?? 0;
|
|
774
|
+
let isWord;
|
|
775
|
+
if (membership <= 1) {
|
|
776
|
+
isWord = membership;
|
|
777
|
+
} else if (membership === WORD_CP_SURROGATE) {
|
|
778
|
+
const next = i + 1 < len ? text.charCodeAt(i + 1) : 0;
|
|
779
|
+
if (code <= 56319 && next >= 56320 && next <= 57343) {
|
|
780
|
+
isWord = astralWordMembership(65536 + (code - 55296 << 10) + (next - 56320));
|
|
781
|
+
i++;
|
|
782
|
+
} else {
|
|
783
|
+
isWord = 0;
|
|
784
|
+
}
|
|
785
|
+
} else {
|
|
786
|
+
isWord = NON_ASCII_WORD_RE.test(String.fromCharCode(code)) ? 1 : 0;
|
|
787
|
+
WORD_CP_CLASS[code] = isWord;
|
|
788
|
+
}
|
|
789
|
+
count += isWord & (inWord ^ 1);
|
|
752
790
|
inWord = isWord;
|
|
753
791
|
}
|
|
754
792
|
return count;
|
|
@@ -1615,7 +1653,7 @@ function registerBatchResult(meta, data, context) {
|
|
|
1615
1653
|
if (member) {
|
|
1616
1654
|
const nextStatus = data.isPartial ? "running" : "done";
|
|
1617
1655
|
const nextIsError = !data.isPartial && data.isError;
|
|
1618
|
-
const changed = member.status !== nextStatus || member.isError !== nextIsError || member.errorText !== (nextIsError ? data.errorText : void 0) || member.outputEntries !== data.entries;
|
|
1656
|
+
const changed = member.status !== nextStatus || member.isError !== nextIsError || member.errorText !== (nextIsError ? data.errorText : void 0) || data.entries !== void 0 && member.outputEntries !== data.entries;
|
|
1619
1657
|
member.status = nextStatus;
|
|
1620
1658
|
member.isError = nextIsError;
|
|
1621
1659
|
if (member.isError && data.errorText !== void 0) member.errorText = data.errorText;
|
|
@@ -1629,6 +1667,12 @@ function registerBatchResult(meta, data, context) {
|
|
|
1629
1667
|
}
|
|
1630
1668
|
return { batch, isLeader: batch.leaderId === context.toolCallId };
|
|
1631
1669
|
}
|
|
1670
|
+
function hasFinalBatchOutput(toolCallId) {
|
|
1671
|
+
const batch = batchByCallId.get(toolCallId);
|
|
1672
|
+
if (!batch) return false;
|
|
1673
|
+
const member = batch.members.find((entry) => entry.toolCallId === toolCallId);
|
|
1674
|
+
return member !== void 0 && member.outputEntries !== void 0 && member.status === "done" && !member.isError;
|
|
1675
|
+
}
|
|
1632
1676
|
function batchStatus(batch) {
|
|
1633
1677
|
let done = 0;
|
|
1634
1678
|
let failed = 0;
|
|
@@ -1988,6 +2032,9 @@ function invalidateTurnMembers(turn) {
|
|
|
1988
2032
|
}
|
|
1989
2033
|
}
|
|
1990
2034
|
}
|
|
2035
|
+
function releaseTurnInvalidators(turn) {
|
|
2036
|
+
for (const member of turn.members) invalidateByCallId.delete(member.toolCallId);
|
|
2037
|
+
}
|
|
1991
2038
|
function noteTurnMemberElapsed(toolCallId, elapsedMs) {
|
|
1992
2039
|
if (elapsedMs === void 0) return;
|
|
1993
2040
|
const entry = memberByCallId.get(toolCallId);
|
|
@@ -2879,7 +2926,9 @@ import { getLanguageFromPath } from "@earendil-works/pi-coding-agent";
|
|
|
2879
2926
|
import { highlightCode } from "@earendil-works/pi-coding-agent";
|
|
2880
2927
|
var ESC2 = "\x1B";
|
|
2881
2928
|
var BG_ANSI_PATTERN = new RegExp(`${ESC2}\\[(?:4\\d|10\\d|48;5;\\d{1,3}|48;2;\\d{1,3};\\d{1,3};\\d{1,3}|49)m`, "g");
|
|
2929
|
+
var ANSI_SGR_PATTERN = new RegExp(`${ESC2}\\[([0-9;]*)m`, "g");
|
|
2882
2930
|
var CONTROL_CHARS = "\0-\b\v\f-\x7F";
|
|
2931
|
+
var CONTROL_CHARS_PATTERN = new RegExp(`[${CONTROL_CHARS}]`, "g");
|
|
2883
2932
|
var ADD_ROW_BACKGROUND_MIX_RATIO = 0.24;
|
|
2884
2933
|
var REMOVE_ROW_BACKGROUND_MIX_RATIO = 0.12;
|
|
2885
2934
|
var ADD_INLINE_EMPHASIS_MIX_RATIO = 0.44;
|
|
@@ -2971,7 +3020,7 @@ function resolveDiffPalette(theme) {
|
|
|
2971
3020
|
}
|
|
2972
3021
|
function keepBackgroundAcrossResets(text, rowBgAnsi) {
|
|
2973
3022
|
if (!text) return text;
|
|
2974
|
-
return text.replace(
|
|
3023
|
+
return text.replace(ANSI_SGR_PATTERN, (sequence, rawCodes) => {
|
|
2975
3024
|
const split = String(rawCodes ?? "").split(";").filter(Boolean);
|
|
2976
3025
|
const codes = split.length > 0 ? split : ["0"];
|
|
2977
3026
|
const hasGlobalReset = codes.includes("0");
|
|
@@ -3013,7 +3062,7 @@ function applyBackgroundToVisibleRange(ansiText, start, end, backgroundAnsi, res
|
|
|
3013
3062
|
return output;
|
|
3014
3063
|
}
|
|
3015
3064
|
function sanitizeSingleLineText(value) {
|
|
3016
|
-
return value.replace(/\r/g, "").replace(/\n/g, "").replace(
|
|
3065
|
+
return value.replace(/\r/g, "").replace(/\n/g, "").replace(CONTROL_CHARS_PATTERN, "");
|
|
3017
3066
|
}
|
|
3018
3067
|
function stripInlineBreaksPreserveAnsi(value) {
|
|
3019
3068
|
return value.replace(/\r/g, "").replace(/\n/g, "");
|
|
@@ -3610,6 +3659,101 @@ var AdaptiveDiffComponent = class {
|
|
|
3610
3659
|
}
|
|
3611
3660
|
};
|
|
3612
3661
|
|
|
3662
|
+
// extension-src/pi-style/features/tools/boxed/shared.ts
|
|
3663
|
+
function pendingFlag(context) {
|
|
3664
|
+
return Boolean(context.isPartial);
|
|
3665
|
+
}
|
|
3666
|
+
function displayPath(rawPath, context) {
|
|
3667
|
+
const path = String(rawPath ?? "");
|
|
3668
|
+
if (!path) return "(unknown)";
|
|
3669
|
+
return shortenPath(resolveRelativePath(path, context.cwd));
|
|
3670
|
+
}
|
|
3671
|
+
function pathRangeDetail(rawPath, offset, limit, context) {
|
|
3672
|
+
const path = displayPath(rawPath, context);
|
|
3673
|
+
let range = "";
|
|
3674
|
+
if (offset !== void 0 || limit !== void 0) {
|
|
3675
|
+
const start = offset ?? 1;
|
|
3676
|
+
const end = limit !== void 0 ? Number(start) + Number(limit) - 1 : "";
|
|
3677
|
+
range = `:${start}${end ? `-${end}` : ""}`;
|
|
3678
|
+
}
|
|
3679
|
+
return path ? `${path}${range}` : "(unknown)";
|
|
3680
|
+
}
|
|
3681
|
+
function compactCall(theme, toolName, detailLine, options) {
|
|
3682
|
+
return renderCompactBoxedToolCall(theme, toolName, detailLine, {
|
|
3683
|
+
widthKey: boxedToolWidthKey(toolName, options.detailKey),
|
|
3684
|
+
state: options.context.state,
|
|
3685
|
+
isError: Boolean(options.context.isError),
|
|
3686
|
+
isPartial: Boolean(options.context.isPartial),
|
|
3687
|
+
isPending: pendingFlag(options.context),
|
|
3688
|
+
running: Boolean(options.context.executionStarted)
|
|
3689
|
+
});
|
|
3690
|
+
}
|
|
3691
|
+
function noteExecutionStart(context) {
|
|
3692
|
+
recordExecutionStarted(context.state, context.executionStarted);
|
|
3693
|
+
}
|
|
3694
|
+
function noteBoxedCallState(context) {
|
|
3695
|
+
if (!context.executionStarted) return;
|
|
3696
|
+
if (context.isPartial) startElapsedTicker(context.state, context.invalidate);
|
|
3697
|
+
else {
|
|
3698
|
+
recordExecutionEnded(context.state);
|
|
3699
|
+
stopElapsedTicker(context.state);
|
|
3700
|
+
}
|
|
3701
|
+
}
|
|
3702
|
+
function noteBoxedResultPhase(context, isPartial) {
|
|
3703
|
+
const firstResultPass = !isResultSeen(context.state);
|
|
3704
|
+
markResultSeen(context.state);
|
|
3705
|
+
if (isPartial) startElapsedTicker(context.state, context.invalidate);
|
|
3706
|
+
else {
|
|
3707
|
+
recordExecutionEnded(context.state);
|
|
3708
|
+
stopElapsedTicker(context.state);
|
|
3709
|
+
}
|
|
3710
|
+
return firstResultPass;
|
|
3711
|
+
}
|
|
3712
|
+
function stateElapsedMs(context) {
|
|
3713
|
+
return getStateElapsedMs(context.state);
|
|
3714
|
+
}
|
|
3715
|
+
function compactFooterWithState(theme, result, context, options = {}) {
|
|
3716
|
+
const elapsedMs = stateElapsedMs(context);
|
|
3717
|
+
return renderCompactBoxedFooter(theme, result, {
|
|
3718
|
+
state: context.state,
|
|
3719
|
+
isError: Boolean(options.isError ?? context.isError),
|
|
3720
|
+
isPartial: Boolean(options.isPartial ?? context.isPartial),
|
|
3721
|
+
...elapsedMs === void 0 ? {} : { elapsedMs }
|
|
3722
|
+
});
|
|
3723
|
+
}
|
|
3724
|
+
function resultFooterLines(theme, result, context, extraParts = []) {
|
|
3725
|
+
return [formatBoxedFooter(theme, result, extraParts, stateElapsedMs(context))];
|
|
3726
|
+
}
|
|
3727
|
+
var CACHE_KEY_LONG_PART_THRESHOLD = 64;
|
|
3728
|
+
function fnv1aHex(text) {
|
|
3729
|
+
let hash = 2166136261;
|
|
3730
|
+
for (let i = 0; i < text.length; i++) {
|
|
3731
|
+
hash ^= text.charCodeAt(i);
|
|
3732
|
+
hash = Math.imul(hash, 16777619) >>> 0;
|
|
3733
|
+
}
|
|
3734
|
+
return hash.toString(16).padStart(8, "0");
|
|
3735
|
+
}
|
|
3736
|
+
function boundedCacheKeyPart(part) {
|
|
3737
|
+
if (typeof part !== "string" || part.length <= CACHE_KEY_LONG_PART_THRESHOLD) return part;
|
|
3738
|
+
return `${part.length}:${fnv1aHex(part)}`;
|
|
3739
|
+
}
|
|
3740
|
+
function getRenderCacheKey(prefix, theme, ...parts) {
|
|
3741
|
+
const pieces = [prefix, themeCacheKey(theme), getToolsRenderCacheSignature()];
|
|
3742
|
+
for (const part of parts) pieces.push(boundedCacheKeyPart(part));
|
|
3743
|
+
return pieces.join("|");
|
|
3744
|
+
}
|
|
3745
|
+
function memoizedStateComponent(state, slot, key, build) {
|
|
3746
|
+
if (!state || typeof state !== "object") return build();
|
|
3747
|
+
const cached = state[slot];
|
|
3748
|
+
if (cached && cached.key === key) return cached.component;
|
|
3749
|
+
const component = build();
|
|
3750
|
+
state[slot] = { key, component };
|
|
3751
|
+
return component;
|
|
3752
|
+
}
|
|
3753
|
+
function clearFooterState(context) {
|
|
3754
|
+
clearCompactBoxedFooter(context.state);
|
|
3755
|
+
}
|
|
3756
|
+
|
|
3613
3757
|
// extension-src/pi-style/features/tools/boxed/git.ts
|
|
3614
3758
|
var GIT_SHORT_STATUS_FLAGS = /* @__PURE__ */ new Set(["-s", "--short", "--porcelain"]);
|
|
3615
3759
|
var GIT_DIFF_FORMAT_REJECT = /* @__PURE__ */ new Set([
|
|
@@ -4916,6 +5060,34 @@ function binaryBodyLine(theme, status) {
|
|
|
4916
5060
|
}
|
|
4917
5061
|
function renderGitDiffResult(theme, parsed, options, context) {
|
|
4918
5062
|
const expanded = Boolean(options.expanded);
|
|
5063
|
+
let totalAdditions = 0;
|
|
5064
|
+
let totalRemovals = 0;
|
|
5065
|
+
const sigParts = [];
|
|
5066
|
+
for (const file of parsed.files) {
|
|
5067
|
+
totalAdditions += file.additions;
|
|
5068
|
+
totalRemovals += file.removals;
|
|
5069
|
+
sigParts.push(
|
|
5070
|
+
`${file.path}:${file.body.length}:${file.additions}:${file.removals}:${file.binary ? 1 : 0}:${file.status ?? ""}`
|
|
5071
|
+
);
|
|
5072
|
+
}
|
|
5073
|
+
const sig = sigParts.join(";").slice(0, 2048);
|
|
5074
|
+
return memoizedStateComponent(
|
|
5075
|
+
context.state,
|
|
5076
|
+
"__piStyleGitDiffResult",
|
|
5077
|
+
getRenderCacheKey(
|
|
5078
|
+
"git-diff-result",
|
|
5079
|
+
theme,
|
|
5080
|
+
String(parsed.show),
|
|
5081
|
+
String(expanded),
|
|
5082
|
+
parsed.files.length,
|
|
5083
|
+
totalAdditions,
|
|
5084
|
+
totalRemovals,
|
|
5085
|
+
sig
|
|
5086
|
+
),
|
|
5087
|
+
() => buildGitDiffResultComponent(theme, parsed, expanded, context)
|
|
5088
|
+
);
|
|
5089
|
+
}
|
|
5090
|
+
function buildGitDiffResultComponent(theme, parsed, expanded, context) {
|
|
4919
5091
|
const elapsedMs = getStateElapsedMs(context.state);
|
|
4920
5092
|
const fileCount = parsed.files.length;
|
|
4921
5093
|
const footerParts = [];
|
|
@@ -4987,86 +5159,6 @@ function renderGitDiffResult(theme, parsed, options, context) {
|
|
|
4987
5159
|
};
|
|
4988
5160
|
}
|
|
4989
5161
|
|
|
4990
|
-
// extension-src/pi-style/features/tools/boxed/shared.ts
|
|
4991
|
-
function pendingFlag(context) {
|
|
4992
|
-
return Boolean(context.isPartial);
|
|
4993
|
-
}
|
|
4994
|
-
function displayPath(rawPath, context) {
|
|
4995
|
-
const path = String(rawPath ?? "");
|
|
4996
|
-
if (!path) return "(unknown)";
|
|
4997
|
-
return shortenPath(resolveRelativePath(path, context.cwd));
|
|
4998
|
-
}
|
|
4999
|
-
function pathRangeDetail(rawPath, offset, limit, context) {
|
|
5000
|
-
const path = displayPath(rawPath, context);
|
|
5001
|
-
let range = "";
|
|
5002
|
-
if (offset !== void 0 || limit !== void 0) {
|
|
5003
|
-
const start = offset ?? 1;
|
|
5004
|
-
const end = limit !== void 0 ? Number(start) + Number(limit) - 1 : "";
|
|
5005
|
-
range = `:${start}${end ? `-${end}` : ""}`;
|
|
5006
|
-
}
|
|
5007
|
-
return path ? `${path}${range}` : "(unknown)";
|
|
5008
|
-
}
|
|
5009
|
-
function compactCall(theme, toolName, detailLine, options) {
|
|
5010
|
-
return renderCompactBoxedToolCall(theme, toolName, detailLine, {
|
|
5011
|
-
widthKey: boxedToolWidthKey(toolName, options.detailKey),
|
|
5012
|
-
state: options.context.state,
|
|
5013
|
-
isError: Boolean(options.context.isError),
|
|
5014
|
-
isPartial: Boolean(options.context.isPartial),
|
|
5015
|
-
isPending: pendingFlag(options.context),
|
|
5016
|
-
running: Boolean(options.context.executionStarted)
|
|
5017
|
-
});
|
|
5018
|
-
}
|
|
5019
|
-
function noteExecutionStart(context) {
|
|
5020
|
-
recordExecutionStarted(context.state, context.executionStarted);
|
|
5021
|
-
}
|
|
5022
|
-
function noteBoxedCallState(context) {
|
|
5023
|
-
if (!context.executionStarted) return;
|
|
5024
|
-
if (context.isPartial) startElapsedTicker(context.state, context.invalidate);
|
|
5025
|
-
else {
|
|
5026
|
-
recordExecutionEnded(context.state);
|
|
5027
|
-
stopElapsedTicker(context.state);
|
|
5028
|
-
}
|
|
5029
|
-
}
|
|
5030
|
-
function noteBoxedResultPhase(context, isPartial) {
|
|
5031
|
-
const firstResultPass = !isResultSeen(context.state);
|
|
5032
|
-
markResultSeen(context.state);
|
|
5033
|
-
if (isPartial) startElapsedTicker(context.state, context.invalidate);
|
|
5034
|
-
else {
|
|
5035
|
-
recordExecutionEnded(context.state);
|
|
5036
|
-
stopElapsedTicker(context.state);
|
|
5037
|
-
}
|
|
5038
|
-
return firstResultPass;
|
|
5039
|
-
}
|
|
5040
|
-
function stateElapsedMs(context) {
|
|
5041
|
-
return getStateElapsedMs(context.state);
|
|
5042
|
-
}
|
|
5043
|
-
function compactFooterWithState(theme, result, context, options = {}) {
|
|
5044
|
-
const elapsedMs = stateElapsedMs(context);
|
|
5045
|
-
return renderCompactBoxedFooter(theme, result, {
|
|
5046
|
-
state: context.state,
|
|
5047
|
-
isError: Boolean(options.isError ?? context.isError),
|
|
5048
|
-
isPartial: Boolean(options.isPartial ?? context.isPartial),
|
|
5049
|
-
...elapsedMs === void 0 ? {} : { elapsedMs }
|
|
5050
|
-
});
|
|
5051
|
-
}
|
|
5052
|
-
function resultFooterLines(theme, result, context, extraParts = []) {
|
|
5053
|
-
return [formatBoxedFooter(theme, result, extraParts, stateElapsedMs(context))];
|
|
5054
|
-
}
|
|
5055
|
-
function getRenderCacheKey(prefix, theme, ...parts) {
|
|
5056
|
-
return [prefix, themeCacheKey(theme), getToolsRenderCacheSignature(), ...parts].join("|");
|
|
5057
|
-
}
|
|
5058
|
-
function memoizedStateComponent(state, slot, key, build) {
|
|
5059
|
-
if (!state || typeof state !== "object") return build();
|
|
5060
|
-
const cached = state[slot];
|
|
5061
|
-
if (cached && cached.key === key) return cached.component;
|
|
5062
|
-
const component = build();
|
|
5063
|
-
state[slot] = { key, component };
|
|
5064
|
-
return component;
|
|
5065
|
-
}
|
|
5066
|
-
function clearFooterState(context) {
|
|
5067
|
-
clearCompactBoxedFooter(context.state);
|
|
5068
|
-
}
|
|
5069
|
-
|
|
5070
5162
|
// extension-src/pi-style/features/tools/boxed/bash.ts
|
|
5071
5163
|
var MAX_LINE_CHARS = 2e3;
|
|
5072
5164
|
var ESC3 = "\x1B";
|
|
@@ -5167,6 +5259,25 @@ function countNewlines(text, from, to) {
|
|
|
5167
5259
|
}
|
|
5168
5260
|
return count;
|
|
5169
5261
|
}
|
|
5262
|
+
function findBackwardLineStart(text, need, end = text.length) {
|
|
5263
|
+
let found = 0;
|
|
5264
|
+
for (let i = end - 1; i >= 0; i--) {
|
|
5265
|
+
if (text.charCodeAt(i) === 10 && ++found >= need) return i + 1;
|
|
5266
|
+
}
|
|
5267
|
+
return 0;
|
|
5268
|
+
}
|
|
5269
|
+
function isOutputWhitespaceCode(code) {
|
|
5270
|
+
if (code === 32 || code >= 9 && code <= 13) return true;
|
|
5271
|
+
if (code === 133 || code === 160 || code === 5760) return true;
|
|
5272
|
+
if (code >= 8192 && code <= 8202) return true;
|
|
5273
|
+
return code === 8232 || code === 8233 || code === 8239 || code === 8287 || code === 12288 || code === 65279;
|
|
5274
|
+
}
|
|
5275
|
+
function lastVisibleEnd(text) {
|
|
5276
|
+
for (let i = text.length - 1; i >= 0; i--) {
|
|
5277
|
+
if (!isOutputWhitespaceCode(text.charCodeAt(i))) return i + 1;
|
|
5278
|
+
}
|
|
5279
|
+
return 0;
|
|
5280
|
+
}
|
|
5170
5281
|
function stripBashToolNoticeLines(text) {
|
|
5171
5282
|
const filteredLines = text.replace(/\r/g, "").split("\n").filter((line) => !BASH_TOOL_NOTICE_PATTERN.test(line.trim()));
|
|
5172
5283
|
return filteredLines.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd();
|
|
@@ -5297,8 +5408,10 @@ function bashBodyComponent(preview, emptyLines) {
|
|
|
5297
5408
|
};
|
|
5298
5409
|
}
|
|
5299
5410
|
function renderBashStreamingResult(theme, raw, options, context) {
|
|
5300
|
-
const
|
|
5301
|
-
const hasOutput =
|
|
5411
|
+
const contentEnd = lastVisibleEnd(raw);
|
|
5412
|
+
const hasOutput = contentEnd > 0;
|
|
5413
|
+
const tailStart = hasOutput ? findBackwardLineStart(raw, getToolsRenderConfig().maxCollapsedLines + 10, contentEnd) : 0;
|
|
5414
|
+
const body = stripBashToolNoticeLines(stripAnsi(raw.slice(tailStart, contentEnd)));
|
|
5302
5415
|
const elapsed = getStateElapsedMs(context.state);
|
|
5303
5416
|
const emptyLines = [theme.fg("dim", "No output received yet")];
|
|
5304
5417
|
if (!hasOutput && isInteractiveCommand(context?.args?.command) && (elapsed ?? 0) >= 1e3) {
|
|
@@ -5329,17 +5442,7 @@ function renderBashFinalResult(theme, raw, options, context) {
|
|
|
5329
5442
|
const referenceLines = rawCommand.split("\n").map((line, index) => `${index === 0 ? "$ " : "> "}${line}`);
|
|
5330
5443
|
if (!options.expanded) {
|
|
5331
5444
|
const scanLines = getToolsRenderConfig().maxCollapsedLines + 10;
|
|
5332
|
-
|
|
5333
|
-
let tailStart = 0;
|
|
5334
|
-
for (let i = statusStripped.length - 1; i >= 0; i--) {
|
|
5335
|
-
if (statusStripped.charCodeAt(i) === 10) {
|
|
5336
|
-
nlCount++;
|
|
5337
|
-
if (nlCount >= scanLines) {
|
|
5338
|
-
tailStart = i + 1;
|
|
5339
|
-
break;
|
|
5340
|
-
}
|
|
5341
|
-
}
|
|
5342
|
-
}
|
|
5445
|
+
const tailStart = findBackwardLineStart(statusStripped, scanLines);
|
|
5343
5446
|
const tail = stripBashToolNoticeLines(stripAnsi(statusStripped.slice(tailStart)));
|
|
5344
5447
|
const totalLinesBefore = tailStart > 0 ? countNewlines(statusStripped, 0, tailStart) : 0;
|
|
5345
5448
|
const preview2 = createBashResultPreview(theme, tail, options, outputColor);
|
|
@@ -5397,17 +5500,7 @@ function createBashResultPreview(theme, text, options, color) {
|
|
|
5397
5500
|
if (cacheLines && cacheKey2 === cacheId) return cacheLines;
|
|
5398
5501
|
if (!expanded) {
|
|
5399
5502
|
const needed = cfg.maxCollapsedLines;
|
|
5400
|
-
|
|
5401
|
-
let scanFrom = 0;
|
|
5402
|
-
for (let i = text.length - 1; i >= 0; i--) {
|
|
5403
|
-
if (text.charCodeAt(i) === 10) {
|
|
5404
|
-
totalNewlines++;
|
|
5405
|
-
if (totalNewlines === needed) {
|
|
5406
|
-
scanFrom = i + 1;
|
|
5407
|
-
break;
|
|
5408
|
-
}
|
|
5409
|
-
}
|
|
5410
|
-
}
|
|
5503
|
+
const scanFrom = findBackwardLineStart(text, needed);
|
|
5411
5504
|
if (text.length === 0) {
|
|
5412
5505
|
cacheKey2 = cacheId;
|
|
5413
5506
|
cacheLines = [];
|
|
@@ -5430,26 +5523,26 @@ function createBashResultPreview(theme, text, options, color) {
|
|
|
5430
5523
|
return cacheLines;
|
|
5431
5524
|
}
|
|
5432
5525
|
const normalized = replaceTabs(text);
|
|
5433
|
-
const
|
|
5434
|
-
const
|
|
5526
|
+
const rawLines = normalized.split("\n");
|
|
5527
|
+
const totalLines = rawLines.length;
|
|
5528
|
+
const hasOutput = !(totalLines === 1 && rawLines[0] === "");
|
|
5435
5529
|
if (!hasOutput) {
|
|
5436
5530
|
cacheKey2 = cacheId;
|
|
5437
5531
|
cacheLines = [];
|
|
5438
5532
|
return cacheLines;
|
|
5439
5533
|
}
|
|
5440
|
-
const truncatedLines = logicalLines.map((line) => safeTruncateToWidth(line, bodyWidth, "\u2026"));
|
|
5441
|
-
const expandedLines = truncatedLines.length === 1 && truncatedLines[0] === "" ? [] : truncatedLines;
|
|
5442
5534
|
const applyColor = (l) => color === "error" ? formatToolOutputLine(theme, l, "error") : cfg.dimOutput ? formatToolOutputLine(theme, l) : formatToolOutputLine(theme, l, "text");
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
const
|
|
5535
|
+
const renderRawLine = (line) => safeTruncateToWidth(clampLineLength(line), bodyWidth, "\u2026");
|
|
5536
|
+
if (cfg.maxExpandedLines > 0 && totalLines > cfg.maxExpandedLines) {
|
|
5537
|
+
const truncated = rawLines.slice(-cfg.maxExpandedLines).map((line) => applyColor(renderRawLine(line)));
|
|
5538
|
+
const remaining = totalLines - cfg.maxExpandedLines;
|
|
5446
5539
|
truncated.unshift(theme.fg("dim", `\u2026 ${remaining} earlier lines`));
|
|
5447
5540
|
cacheKey2 = cacheId;
|
|
5448
5541
|
cacheLines = truncated;
|
|
5449
5542
|
return cacheLines;
|
|
5450
5543
|
}
|
|
5451
5544
|
cacheKey2 = cacheId;
|
|
5452
|
-
cacheLines =
|
|
5545
|
+
cacheLines = rawLines.map((line) => applyColor(renderRawLine(line)));
|
|
5453
5546
|
return cacheLines;
|
|
5454
5547
|
}
|
|
5455
5548
|
};
|
|
@@ -5616,6 +5709,7 @@ function isGitDiffClass(cls) {
|
|
|
5616
5709
|
function isGitActionClass(cls) {
|
|
5617
5710
|
return !isBashTreeClass(cls) && cls.kind === "action";
|
|
5618
5711
|
}
|
|
5712
|
+
var PARTIAL_REPARSE_THRESHOLD = 4096;
|
|
5619
5713
|
function parseSemanticOutput(cls, output) {
|
|
5620
5714
|
if (isBashTreeClass(cls)) return parseBashTreeOutput(cls, output);
|
|
5621
5715
|
if (isGhClass(cls)) return parseGhOutput(cls, output);
|
|
@@ -5708,6 +5802,7 @@ var bashTool = {
|
|
|
5708
5802
|
existing.finished = false;
|
|
5709
5803
|
existing.revision++;
|
|
5710
5804
|
delete existing.renderCache;
|
|
5805
|
+
delete existing.lastParsedLength;
|
|
5711
5806
|
}
|
|
5712
5807
|
existing.command = command;
|
|
5713
5808
|
existing.cls = cls;
|
|
@@ -5736,21 +5831,24 @@ var bashTool = {
|
|
|
5736
5831
|
}
|
|
5737
5832
|
if (!options.isPartial || isBashTreeClass(cls)) {
|
|
5738
5833
|
const output = stripBashToolNoticeLines(stripAnsi(getTextOutput(result)));
|
|
5739
|
-
const parsed = parseSemanticOutput(cls, output);
|
|
5740
5834
|
const state = semanticStates.get(context.toolCallId);
|
|
5835
|
+
const shouldParse = !options.isPartial || state === void 0 || state.lastParsedLength === void 0 || output.length - state.lastParsedLength >= PARTIAL_REPARSE_THRESHOLD;
|
|
5836
|
+
const parsed = shouldParse ? parseSemanticOutput(cls, output) : void 0;
|
|
5741
5837
|
if (parsed) {
|
|
5742
5838
|
if (state) {
|
|
5743
5839
|
state.parsed = parsed;
|
|
5744
5840
|
state.finished = !options.isPartial;
|
|
5745
5841
|
state.revision++;
|
|
5746
5842
|
delete state.renderCache;
|
|
5843
|
+
if (options.isPartial) state.lastParsedLength = output.length;
|
|
5747
5844
|
} else
|
|
5748
5845
|
semanticStates.set(context.toolCallId, {
|
|
5749
5846
|
cls,
|
|
5750
5847
|
command: String(context?.args?.command ?? ""),
|
|
5751
5848
|
parsed,
|
|
5752
5849
|
finished: !options.isPartial,
|
|
5753
|
-
revision: 0
|
|
5850
|
+
revision: 0,
|
|
5851
|
+
...options.isPartial ? { lastParsedLength: output.length } : {}
|
|
5754
5852
|
});
|
|
5755
5853
|
if (isGitDiffClass(cls)) {
|
|
5756
5854
|
return renderGitDiffResult(theme, parsed, options, context);
|
|
@@ -5760,11 +5858,17 @@ var bashTool = {
|
|
|
5760
5858
|
}
|
|
5761
5859
|
return EMPTY_BASH_TREE_RESULT;
|
|
5762
5860
|
}
|
|
5763
|
-
if (
|
|
5764
|
-
state
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5861
|
+
if (!shouldParse) {
|
|
5862
|
+
if (state?.parsed !== void 0) return EMPTY_BASH_TREE_RESULT;
|
|
5863
|
+
}
|
|
5864
|
+
if (shouldParse) {
|
|
5865
|
+
if (state) {
|
|
5866
|
+
state.fallback = true;
|
|
5867
|
+
state.finished = !options.isPartial;
|
|
5868
|
+
state.revision++;
|
|
5869
|
+
delete state.renderCache;
|
|
5870
|
+
if (options.isPartial) state.lastParsedLength = output.length;
|
|
5871
|
+
}
|
|
5768
5872
|
}
|
|
5769
5873
|
}
|
|
5770
5874
|
} else if (options.isPartial) {
|
|
@@ -5863,14 +5967,8 @@ var editTool = {
|
|
|
5863
5967
|
const message = firstText(result.content);
|
|
5864
5968
|
const argPath = String(context?.args?.path ?? context?.args?.file_path ?? "");
|
|
5865
5969
|
const sourcePath = details?.path ?? (argPath || extractEditedPath(message));
|
|
5866
|
-
const language = sourcePath ? getLanguageFromPath2(sourcePath) : void 0;
|
|
5867
|
-
const rows = buildSplitRows(diff);
|
|
5868
5970
|
const expanded = options.expanded;
|
|
5869
|
-
const shouldHighlight = Boolean(language) && diff.length <= MAX_HIGHLIGHT_DIFF_CHARS && rows.length <= MAX_HIGHLIGHT_DIFF_ROWS;
|
|
5870
5971
|
const stats = countDiffStats(diff);
|
|
5871
|
-
const maxRows = expanded ? 160 : 36;
|
|
5872
|
-
const diffView = new AdaptiveDiffComponent(theme, rows, maxRows, shouldHighlight ? language : void 0);
|
|
5873
|
-
const expandHint2 = !expanded && diffView.hasCollapsed() ? "Ctrl+O more" : void 0;
|
|
5874
5972
|
return memoizedStateComponent(
|
|
5875
5973
|
context.state,
|
|
5876
5974
|
"__piStyleEditDiffResult",
|
|
@@ -5882,22 +5980,30 @@ var editTool = {
|
|
|
5882
5980
|
sourcePath ?? "",
|
|
5883
5981
|
editDiffFooter(theme, result, context, stats)
|
|
5884
5982
|
),
|
|
5885
|
-
() =>
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5983
|
+
() => {
|
|
5984
|
+
const language = sourcePath ? getLanguageFromPath2(sourcePath) : void 0;
|
|
5985
|
+
const rows = buildSplitRows(diff);
|
|
5986
|
+
const shouldHighlight = Boolean(language) && diff.length <= MAX_HIGHLIGHT_DIFF_CHARS && rows.length <= MAX_HIGHLIGHT_DIFF_ROWS;
|
|
5987
|
+
const maxRows = expanded ? 160 : 36;
|
|
5988
|
+
const diffView = new AdaptiveDiffComponent(theme, rows, maxRows, shouldHighlight ? language : void 0);
|
|
5989
|
+
const expandHint2 = !expanded && diffView.hasCollapsed() ? "Ctrl+O more" : void 0;
|
|
5990
|
+
return renderBoxedToolResult(
|
|
5991
|
+
theme,
|
|
5992
|
+
{
|
|
5993
|
+
render(width) {
|
|
5994
|
+
return diffView.render(width);
|
|
5995
|
+
},
|
|
5996
|
+
invalidate() {
|
|
5997
|
+
diffView.invalidate();
|
|
5998
|
+
}
|
|
5890
5999
|
},
|
|
5891
|
-
|
|
5892
|
-
|
|
6000
|
+
{
|
|
6001
|
+
dividerLabel: diffDividerLabel2(theme, stats),
|
|
6002
|
+
...expandHint2 ? { dividerRightLabel: expandHint2 } : {},
|
|
6003
|
+
footerLines: [editDiffFooter(theme, result, context, stats)]
|
|
5893
6004
|
}
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
dividerLabel: diffDividerLabel2(theme, stats),
|
|
5897
|
-
...expandHint2 ? { dividerRightLabel: expandHint2 } : {},
|
|
5898
|
-
footerLines: [editDiffFooter(theme, result, context, stats)]
|
|
5899
|
-
}
|
|
5900
|
-
)
|
|
6005
|
+
);
|
|
6006
|
+
}
|
|
5901
6007
|
);
|
|
5902
6008
|
}
|
|
5903
6009
|
};
|
|
@@ -6002,14 +6108,16 @@ var findTool = {
|
|
|
6002
6108
|
return renderBatchAwareCall(theme, batch);
|
|
6003
6109
|
},
|
|
6004
6110
|
result(result, options, _theme, context) {
|
|
6005
|
-
const
|
|
6006
|
-
const
|
|
6111
|
+
const isError = Boolean(context.isError);
|
|
6112
|
+
const settled = !options.isPartial && !isError && hasFinalBatchOutput(context.toolCallId);
|
|
6113
|
+
const output = settled ? "" : stripAnsi(getTextOutput(result)).trimEnd();
|
|
6114
|
+
const entries = settled || isError ? void 0 : parseFindOutput(output);
|
|
6007
6115
|
registerBatchResult(
|
|
6008
6116
|
FIND_META,
|
|
6009
6117
|
{
|
|
6010
6118
|
isPartial: Boolean(options.isPartial),
|
|
6011
|
-
isError
|
|
6012
|
-
errorText:
|
|
6119
|
+
isError,
|
|
6120
|
+
errorText: isError ? output || void 0 : void 0,
|
|
6013
6121
|
...entries !== void 0 ? { entries } : {}
|
|
6014
6122
|
},
|
|
6015
6123
|
context
|
|
@@ -6120,14 +6228,19 @@ var grepTool = {
|
|
|
6120
6228
|
return renderGrepPanel(theme, context.toolCallId);
|
|
6121
6229
|
},
|
|
6122
6230
|
result(result, options, _theme, context) {
|
|
6123
|
-
const output = stripAnsi(getTextOutput(result)).trimEnd();
|
|
6124
6231
|
const isError = Boolean(context.isError);
|
|
6232
|
+
const isPartial = Boolean(options.isPartial);
|
|
6233
|
+
const state = grepPanels.get(context.toolCallId);
|
|
6234
|
+
if (!isPartial && !isError && state !== void 0 && state.matches !== void 0 && !state.isPartial) {
|
|
6235
|
+
return EMPTY_GREP_RESULT;
|
|
6236
|
+
}
|
|
6237
|
+
const output = stripAnsi(getTextOutput(result)).trimEnd();
|
|
6125
6238
|
const matches = isError ? [] : parseGrepOutput(output);
|
|
6126
6239
|
registerGrepResult(context.toolCallId, {
|
|
6127
6240
|
matches,
|
|
6128
6241
|
isError,
|
|
6129
6242
|
errorText: isError ? output || void 0 : void 0,
|
|
6130
|
-
isPartial
|
|
6243
|
+
isPartial
|
|
6131
6244
|
});
|
|
6132
6245
|
return EMPTY_GREP_RESULT;
|
|
6133
6246
|
}
|
|
@@ -6154,14 +6267,16 @@ var lsTool = {
|
|
|
6154
6267
|
return renderBatchAwareCall(theme, batch);
|
|
6155
6268
|
},
|
|
6156
6269
|
result(result, options, _theme, context) {
|
|
6157
|
-
const
|
|
6158
|
-
const
|
|
6270
|
+
const isError = Boolean(context.isError);
|
|
6271
|
+
const settled = !options.isPartial && !isError && hasFinalBatchOutput(context.toolCallId);
|
|
6272
|
+
const output = settled ? "" : stripAnsi(getTextOutput(result)).trimEnd();
|
|
6273
|
+
const entries = settled || isError ? void 0 : parseLsOutput(output);
|
|
6159
6274
|
registerBatchResult(
|
|
6160
6275
|
LIST_META,
|
|
6161
6276
|
{
|
|
6162
6277
|
isPartial: Boolean(options.isPartial),
|
|
6163
|
-
isError
|
|
6164
|
-
errorText:
|
|
6278
|
+
isError,
|
|
6279
|
+
errorText: isError ? output || void 0 : void 0,
|
|
6165
6280
|
...entries !== void 0 ? { entries } : {}
|
|
6166
6281
|
},
|
|
6167
6282
|
context
|
|
@@ -6285,15 +6400,9 @@ function renderQuickEditResult(_toolName, result, options, theme, context, confi
|
|
|
6285
6400
|
footerLines: [quickEditFooter(theme, context)]
|
|
6286
6401
|
});
|
|
6287
6402
|
}
|
|
6288
|
-
const rows = buildSplitRows(diff);
|
|
6289
6403
|
const expanded = options.expanded;
|
|
6290
6404
|
const argPath = String(context?.args?.path ?? "");
|
|
6291
|
-
const language = argPath ? getLanguageFromPath3(argPath) : void 0;
|
|
6292
|
-
const shouldHighlight = Boolean(language) && diff.length <= MAX_HIGHLIGHT_DIFF_CHARS2 && rows.length <= MAX_HIGHLIGHT_DIFF_ROWS2;
|
|
6293
6405
|
const stats = countDiffStats(diff);
|
|
6294
|
-
const maxRows = expanded ? 160 : 36;
|
|
6295
|
-
const diffView = new AdaptiveDiffComponent(theme, rows, maxRows, shouldHighlight ? language : void 0);
|
|
6296
|
-
const expandHint2 = !expanded && diffView.hasCollapsed() ? "Ctrl+O more" : void 0;
|
|
6297
6406
|
return memoizedStateComponent(
|
|
6298
6407
|
context.state,
|
|
6299
6408
|
"__piStyleQuickEditDiffResult",
|
|
@@ -6306,22 +6415,30 @@ function renderQuickEditResult(_toolName, result, options, theme, context, confi
|
|
|
6306
6415
|
argPath,
|
|
6307
6416
|
quickEditDiffFooter(theme, result, context, stats)
|
|
6308
6417
|
),
|
|
6309
|
-
() =>
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6418
|
+
() => {
|
|
6419
|
+
const rows = buildSplitRows(diff);
|
|
6420
|
+
const language = argPath ? getLanguageFromPath3(argPath) : void 0;
|
|
6421
|
+
const shouldHighlight = Boolean(language) && diff.length <= MAX_HIGHLIGHT_DIFF_CHARS2 && rows.length <= MAX_HIGHLIGHT_DIFF_ROWS2;
|
|
6422
|
+
const maxRows = expanded ? 160 : 36;
|
|
6423
|
+
const diffView = new AdaptiveDiffComponent(theme, rows, maxRows, shouldHighlight ? language : void 0);
|
|
6424
|
+
const expandHint2 = !expanded && diffView.hasCollapsed() ? "Ctrl+O more" : void 0;
|
|
6425
|
+
return renderBoxedToolResult(
|
|
6426
|
+
theme,
|
|
6427
|
+
{
|
|
6428
|
+
render(width) {
|
|
6429
|
+
return diffView.render(width);
|
|
6430
|
+
},
|
|
6431
|
+
invalidate() {
|
|
6432
|
+
diffView.invalidate();
|
|
6433
|
+
}
|
|
6314
6434
|
},
|
|
6315
|
-
|
|
6316
|
-
|
|
6435
|
+
{
|
|
6436
|
+
dividerLabel: quickEditDividerLabel(theme, stats),
|
|
6437
|
+
...expandHint2 ? { dividerRightLabel: expandHint2 } : {},
|
|
6438
|
+
footerLines: [quickEditDiffFooter(theme, result, context, stats)]
|
|
6317
6439
|
}
|
|
6318
|
-
|
|
6319
|
-
|
|
6320
|
-
dividerLabel: quickEditDividerLabel(theme, stats),
|
|
6321
|
-
...expandHint2 ? { dividerRightLabel: expandHint2 } : {},
|
|
6322
|
-
footerLines: [quickEditDiffFooter(theme, result, context, stats)]
|
|
6323
|
-
}
|
|
6324
|
-
)
|
|
6440
|
+
);
|
|
6441
|
+
}
|
|
6325
6442
|
);
|
|
6326
6443
|
}
|
|
6327
6444
|
function quickEditFooter(theme, context) {
|
|
@@ -6367,13 +6484,13 @@ var readTool = {
|
|
|
6367
6484
|
return renderBatchAwareCall(theme, batch);
|
|
6368
6485
|
},
|
|
6369
6486
|
result(result, options, _theme, context) {
|
|
6370
|
-
const
|
|
6487
|
+
const errorText = context.isError ? stripAnsi(getTextOutput(result)).trimEnd() || void 0 : void 0;
|
|
6371
6488
|
registerBatchResult(
|
|
6372
6489
|
READ_META,
|
|
6373
6490
|
{
|
|
6374
6491
|
isPartial: Boolean(options.isPartial),
|
|
6375
6492
|
isError: Boolean(context.isError),
|
|
6376
|
-
errorText
|
|
6493
|
+
errorText
|
|
6377
6494
|
},
|
|
6378
6495
|
context
|
|
6379
6496
|
);
|
|
@@ -8077,11 +8194,10 @@ function createBuiltinSegments() {
|
|
|
8077
8194
|
content: snapshot.sessionStartedAt === void 0 ? "" : theme.apply("time", formatElapsed2(Date.now() - snapshot.sessionStartedAt)),
|
|
8078
8195
|
compactContent: snapshot.sessionStartedAt === void 0 ? "" : theme.apply("time", formatElapsed2(Date.now() - snapshot.sessionStartedAt))
|
|
8079
8196
|
})),
|
|
8080
|
-
segment("time", 20, ({ theme }) =>
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
})),
|
|
8197
|
+
segment("time", 20, ({ theme }) => {
|
|
8198
|
+
const text = theme.apply("time", clockTime());
|
|
8199
|
+
return { visible: true, content: text, compactContent: text };
|
|
8200
|
+
}),
|
|
8085
8201
|
segment("hostname", 20, ({ snapshot, theme }) => ({
|
|
8086
8202
|
visible: Boolean(snapshot.hostname),
|
|
8087
8203
|
content: theme.apply("muted", snapshot.hostname ?? "")
|
|
@@ -8099,6 +8215,15 @@ function createBuiltinSegments() {
|
|
|
8099
8215
|
];
|
|
8100
8216
|
return new Map(segments.map((item) => [item.id, item]));
|
|
8101
8217
|
}
|
|
8218
|
+
var clockCache;
|
|
8219
|
+
function clockTime() {
|
|
8220
|
+
const now = /* @__PURE__ */ new Date();
|
|
8221
|
+
const minuteKey = now.getHours() * 60 + now.getMinutes();
|
|
8222
|
+
if (clockCache?.minuteKey !== minuteKey) {
|
|
8223
|
+
clockCache = { minuteKey, value: now.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) };
|
|
8224
|
+
}
|
|
8225
|
+
return clockCache.value;
|
|
8226
|
+
}
|
|
8102
8227
|
var CONTEXT_BAR_WIDTH = 10;
|
|
8103
8228
|
function contextBar(percent, width = CONTEXT_BAR_WIDTH) {
|
|
8104
8229
|
const filled = Math.max(0, Math.min(width, Math.round(percent / 100 * width)));
|
|
@@ -8284,7 +8409,24 @@ function colorPrefixFor(active, config, noColor, token) {
|
|
|
8284
8409
|
}
|
|
8285
8410
|
return "";
|
|
8286
8411
|
}
|
|
8412
|
+
function envKeyFor(env) {
|
|
8413
|
+
return `${env.PI_STYLE_NERD_FONTS ?? ""}\0${env.GHOSTTY_RESOURCES_DIR ? "1" : "0"}\0${env.TERM_PROGRAM ?? ""}`;
|
|
8414
|
+
}
|
|
8415
|
+
var glyphModeCache = /* @__PURE__ */ new WeakMap();
|
|
8287
8416
|
function detectGlyphMode(config, env = {}) {
|
|
8417
|
+
let byEnv = glyphModeCache.get(config);
|
|
8418
|
+
if (!byEnv) {
|
|
8419
|
+
byEnv = /* @__PURE__ */ new Map();
|
|
8420
|
+
glyphModeCache.set(config, byEnv);
|
|
8421
|
+
}
|
|
8422
|
+
const envKey = envKeyFor(env);
|
|
8423
|
+
const cached = byEnv.get(envKey);
|
|
8424
|
+
if (cached !== void 0) return cached;
|
|
8425
|
+
const mode = computeGlyphMode(config, env);
|
|
8426
|
+
byEnv.set(envKey, mode);
|
|
8427
|
+
return mode;
|
|
8428
|
+
}
|
|
8429
|
+
function computeGlyphMode(config, env) {
|
|
8288
8430
|
if (env.PI_STYLE_NERD_FONTS === "1") return "nerd";
|
|
8289
8431
|
if (env.PI_STYLE_NERD_FONTS === "0") return "unicode";
|
|
8290
8432
|
if (config.theme.nerdFonts === "on") return "nerd";
|
|
@@ -8299,7 +8441,14 @@ function detectGlyphMode(config, env = {}) {
|
|
|
8299
8441
|
function resolveTheme(active, config, env = {}) {
|
|
8300
8442
|
const noColor = Object.hasOwn(env, "NO_COLOR") && env.NO_COLOR !== "" && config.theme.colors.colorOverride !== "on";
|
|
8301
8443
|
const mode = config.preset === "ascii" ? "ascii" : detectGlyphMode(config, env);
|
|
8302
|
-
const
|
|
8444
|
+
const prefixes = /* @__PURE__ */ new Map();
|
|
8445
|
+
const color = (token) => {
|
|
8446
|
+
const cached = prefixes.get(token);
|
|
8447
|
+
if (cached !== void 0) return cached;
|
|
8448
|
+
const prefix = colorPrefixFor(active, config, noColor, token);
|
|
8449
|
+
prefixes.set(token, prefix);
|
|
8450
|
+
return prefix;
|
|
8451
|
+
};
|
|
8303
8452
|
return {
|
|
8304
8453
|
mode,
|
|
8305
8454
|
noColor,
|
|
@@ -8317,9 +8466,13 @@ function resolveTheme(active, config, env = {}) {
|
|
|
8317
8466
|
var widthOf = visibleWidth3;
|
|
8318
8467
|
function widthSafe(value, width) {
|
|
8319
8468
|
if (width <= 0) return "";
|
|
8320
|
-
const
|
|
8321
|
-
|
|
8322
|
-
|
|
8469
|
+
const measured = widthOf(value);
|
|
8470
|
+
if (measured > width) {
|
|
8471
|
+
const fitted = truncateAnsi(value, width, "");
|
|
8472
|
+
const current = widthOf(fitted);
|
|
8473
|
+
return current < width ? fitted + " ".repeat(width - current) : fitted;
|
|
8474
|
+
}
|
|
8475
|
+
return measured < width ? value + " ".repeat(width - measured) : value;
|
|
8323
8476
|
}
|
|
8324
8477
|
function isNativeBorderLine(line) {
|
|
8325
8478
|
const stripped = stripAnsi(line);
|
|
@@ -8389,6 +8542,8 @@ var StyledEditor = class extends CustomEditor {
|
|
|
8389
8542
|
fullTheme;
|
|
8390
8543
|
onSnapshot;
|
|
8391
8544
|
semantic;
|
|
8545
|
+
/** Set when config changes; invalidate() then rebuilds the (otherwise stable) semantic theme. */
|
|
8546
|
+
semanticDirty = false;
|
|
8392
8547
|
disposed = false;
|
|
8393
8548
|
renderPlanCache;
|
|
8394
8549
|
constructor(tui, theme, keybindings, options) {
|
|
@@ -8409,7 +8564,7 @@ var StyledEditor = class extends CustomEditor {
|
|
|
8409
8564
|
configure(config) {
|
|
8410
8565
|
if (this.disposed) return;
|
|
8411
8566
|
this.config = config;
|
|
8412
|
-
this.
|
|
8567
|
+
this.semanticDirty = true;
|
|
8413
8568
|
this.invalidate();
|
|
8414
8569
|
}
|
|
8415
8570
|
handleInput(data) {
|
|
@@ -8419,7 +8574,10 @@ var StyledEditor = class extends CustomEditor {
|
|
|
8419
8574
|
}
|
|
8420
8575
|
invalidate() {
|
|
8421
8576
|
super.invalidate();
|
|
8422
|
-
|
|
8577
|
+
if (this.semanticDirty) {
|
|
8578
|
+
this.semantic = semanticTheme(this.piTheme, this.config);
|
|
8579
|
+
this.semanticDirty = false;
|
|
8580
|
+
}
|
|
8423
8581
|
this.renderPlanCache = void 0;
|
|
8424
8582
|
this.tui.requestRender();
|
|
8425
8583
|
}
|
|
@@ -9203,9 +9361,6 @@ function uniqueLayout(layout) {
|
|
|
9203
9361
|
function renderGroup(items, separator, padding) {
|
|
9204
9362
|
return items.map((item) => item.content).filter(Boolean).join(`${padding}${separator}${padding}`);
|
|
9205
9363
|
}
|
|
9206
|
-
function widthOf2(items, separator, padding) {
|
|
9207
|
-
return visibleWidth(renderGroup(items, separator, padding));
|
|
9208
|
-
}
|
|
9209
9364
|
function renderStatus(layout, snapshot, width, options) {
|
|
9210
9365
|
if (width <= 0) return { primary: "", lines: [], visibleSegments: [] };
|
|
9211
9366
|
const separator = options.separator ?? "\u2502";
|
|
@@ -9220,7 +9375,15 @@ function renderStatus(layout, snapshot, width, options) {
|
|
|
9220
9375
|
try {
|
|
9221
9376
|
const result = segment2.render(context);
|
|
9222
9377
|
if (!result.visible || !result.content) continue;
|
|
9223
|
-
candidates.set(id, {
|
|
9378
|
+
candidates.set(id, {
|
|
9379
|
+
id,
|
|
9380
|
+
segment: segment2,
|
|
9381
|
+
result,
|
|
9382
|
+
content: result.content,
|
|
9383
|
+
contentWidth: visibleWidth(result.content),
|
|
9384
|
+
compact: false,
|
|
9385
|
+
moved: false
|
|
9386
|
+
});
|
|
9224
9387
|
} catch {
|
|
9225
9388
|
}
|
|
9226
9389
|
}
|
|
@@ -9230,13 +9393,28 @@ function renderStatus(layout, snapshot, width, options) {
|
|
|
9230
9393
|
const secondary = normalized.secondary.map((id) => candidates.get(id)).filter((candidate) => candidate !== void 0);
|
|
9231
9394
|
const visible = [];
|
|
9232
9395
|
const overflow = [];
|
|
9396
|
+
const gapWidth = visibleWidth(`${padding}${separator}${padding}`);
|
|
9397
|
+
let groupWidth = 0;
|
|
9398
|
+
let groupCount = 0;
|
|
9399
|
+
const widthAfter = (baseWidth, count, candidate) => count === 0 ? candidate.contentWidth : baseWidth + gapWidth + candidate.contentWidth;
|
|
9233
9400
|
for (const candidate of primary) {
|
|
9234
9401
|
visible.push(candidate);
|
|
9235
|
-
|
|
9402
|
+
const pushedWidth = widthAfter(groupWidth, groupCount, candidate);
|
|
9403
|
+
if (pushedWidth <= width) {
|
|
9404
|
+
groupWidth = pushedWidth;
|
|
9405
|
+
groupCount++;
|
|
9406
|
+
continue;
|
|
9407
|
+
}
|
|
9236
9408
|
if (candidate.result.compactContent && !candidate.compact) {
|
|
9237
9409
|
candidate.content = candidate.result.compactContent;
|
|
9238
9410
|
candidate.compact = true;
|
|
9239
|
-
|
|
9411
|
+
candidate.contentWidth = visibleWidth(candidate.content);
|
|
9412
|
+
const compactedWidth = widthAfter(groupWidth, groupCount, candidate);
|
|
9413
|
+
if (compactedWidth <= width) {
|
|
9414
|
+
groupWidth = compactedWidth;
|
|
9415
|
+
groupCount++;
|
|
9416
|
+
continue;
|
|
9417
|
+
}
|
|
9240
9418
|
}
|
|
9241
9419
|
visible.pop();
|
|
9242
9420
|
if (candidate.segment.overflow !== "drop" && candidate.segment.overflow !== "primary") {
|
|
@@ -9262,9 +9440,14 @@ function renderStatus(layout, snapshot, width, options) {
|
|
|
9262
9440
|
}
|
|
9263
9441
|
if (visibleWidth(primaryText) > width) primaryText = truncateAnsi(primaryText, width);
|
|
9264
9442
|
const secondaryVisible = [];
|
|
9443
|
+
let secondaryWidth = 0;
|
|
9444
|
+
let secondaryCount = 0;
|
|
9265
9445
|
for (const candidate of [...secondary].sort((a, b) => b.segment.defaultPriority - a.segment.defaultPriority)) {
|
|
9446
|
+
const pushedWidth = widthAfter(secondaryWidth, secondaryCount, candidate);
|
|
9447
|
+
if (pushedWidth > width) continue;
|
|
9266
9448
|
secondaryVisible.push(candidate);
|
|
9267
|
-
|
|
9449
|
+
secondaryWidth = pushedWidth;
|
|
9450
|
+
secondaryCount++;
|
|
9268
9451
|
}
|
|
9269
9452
|
const secondaryText = renderGroup(secondaryVisible, separator, padding);
|
|
9270
9453
|
const lines = secondaryText ? [primaryText, secondaryText] : primaryText ? [primaryText] : [];
|
|
@@ -9317,6 +9500,28 @@ function separatorsFor(config, theme) {
|
|
|
9317
9500
|
if (style === "none") return " ";
|
|
9318
9501
|
return theme.apply("separator", style);
|
|
9319
9502
|
}
|
|
9503
|
+
var themeAssetsCache = /* @__PURE__ */ new WeakMap();
|
|
9504
|
+
function themeAssetsFor(activeTheme, config) {
|
|
9505
|
+
let byConfig = themeAssetsCache.get(activeTheme);
|
|
9506
|
+
if (!byConfig) {
|
|
9507
|
+
byConfig = /* @__PURE__ */ new WeakMap();
|
|
9508
|
+
themeAssetsCache.set(activeTheme, byConfig);
|
|
9509
|
+
}
|
|
9510
|
+
let assets = byConfig.get(config);
|
|
9511
|
+
if (!assets) {
|
|
9512
|
+
const resolved = resolveTheme(
|
|
9513
|
+
activeTheme.colors || activeTheme.fg ? {
|
|
9514
|
+
...activeTheme.colors ? { colors: activeTheme.colors } : {},
|
|
9515
|
+
// Call through the theme instance so `this` binds correctly inside Pi's fg().
|
|
9516
|
+
...activeTheme.fg ? { fg: (color, text) => activeTheme.fg?.(color, text) ?? text } : {}
|
|
9517
|
+
} : void 0,
|
|
9518
|
+
config
|
|
9519
|
+
);
|
|
9520
|
+
assets = { resolved, separator: separatorsFor(config, resolved) };
|
|
9521
|
+
byConfig.set(config, assets);
|
|
9522
|
+
}
|
|
9523
|
+
return assets;
|
|
9524
|
+
}
|
|
9320
9525
|
function installStatusLine(options) {
|
|
9321
9526
|
const existing = installationMap(options.host).get(options.generation);
|
|
9322
9527
|
if (existing) return existing;
|
|
@@ -9349,16 +9554,9 @@ function installStatusLine(options) {
|
|
|
9349
9554
|
}
|
|
9350
9555
|
const render = (activeTheme, width, secondary) => {
|
|
9351
9556
|
if (width <= 0 || !config.enabled || !config.statusLine.enabled) return [];
|
|
9352
|
-
const resolved =
|
|
9353
|
-
activeTheme.colors || activeTheme.fg ? {
|
|
9354
|
-
...activeTheme.colors ? { colors: activeTheme.colors } : {},
|
|
9355
|
-
// Call through the theme instance so `this` binds correctly inside Pi's fg().
|
|
9356
|
-
...activeTheme.fg ? { fg: (color, text) => activeTheme.fg?.(color, text) ?? text } : {}
|
|
9357
|
-
} : void 0,
|
|
9358
|
-
config
|
|
9359
|
-
);
|
|
9557
|
+
const { resolved, separator } = themeAssetsFor(activeTheme, config);
|
|
9360
9558
|
const result = renderStatus(config.statusLine.layout, effectiveSnapshot(snapshot), width, {
|
|
9361
|
-
separator
|
|
9559
|
+
separator,
|
|
9362
9560
|
segments,
|
|
9363
9561
|
theme: resolved,
|
|
9364
9562
|
options: {
|
|
@@ -9439,12 +9637,16 @@ function installStatusLine(options) {
|
|
|
9439
9637
|
};
|
|
9440
9638
|
const factory = (secondary) => (tui, theme) => {
|
|
9441
9639
|
const currentTheme = theme;
|
|
9640
|
+
let renderCache;
|
|
9442
9641
|
const component = {
|
|
9443
9642
|
render(width) {
|
|
9643
|
+
if (renderCache?.width === width) return renderCache.lines;
|
|
9444
9644
|
const lines = render(currentTheme, width, secondary);
|
|
9645
|
+
renderCache = { width, lines };
|
|
9445
9646
|
return lines;
|
|
9446
9647
|
},
|
|
9447
9648
|
invalidate() {
|
|
9649
|
+
renderCache = void 0;
|
|
9448
9650
|
primaryComponent = secondary ? primaryComponent : component;
|
|
9449
9651
|
secondaryComponent = secondary ? component : secondaryComponent;
|
|
9450
9652
|
if (tui.requestRender) tui.requestRender();
|
|
@@ -9862,6 +10064,7 @@ function isPlainRecord(value) {
|
|
|
9862
10064
|
}
|
|
9863
10065
|
|
|
9864
10066
|
// extension-src/pi-style/app/runtime.ts
|
|
10067
|
+
var GIT_INVALIDATE_DEBOUNCE_MS = 250;
|
|
9865
10068
|
function createPiStyleRuntime(host, generation2, requestRender = host.requestRender ?? (() => {
|
|
9866
10069
|
})) {
|
|
9867
10070
|
let disposed = false;
|
|
@@ -9887,6 +10090,7 @@ function createPiStyleRuntime(host, generation2, requestRender = host.requestRen
|
|
|
9887
10090
|
const disposables = new DisposableStore();
|
|
9888
10091
|
const scheduler = new RenderScheduler({ requestRender }, generation2, () => !disposed);
|
|
9889
10092
|
const git = new CachedGitProvider(host.gitRunner);
|
|
10093
|
+
let pendingGitRefresh;
|
|
9890
10094
|
const contextProvider = new InMemoryContextProvider();
|
|
9891
10095
|
const usageProvider = new InMemoryUsageProvider();
|
|
9892
10096
|
const initialContext = contextSnapshot();
|
|
@@ -10119,11 +10323,18 @@ function createPiStyleRuntime(host, generation2, requestRender = host.requestRen
|
|
|
10119
10323
|
},
|
|
10120
10324
|
invalidateGit() {
|
|
10121
10325
|
if (disposed || !host.cwd || !currentConfig.enabled || !currentConfig.statusLine.enabled) return;
|
|
10122
|
-
|
|
10123
|
-
|
|
10326
|
+
const cwd = host.cwd;
|
|
10327
|
+
git.invalidate(cwd);
|
|
10328
|
+
if (pendingGitRefresh !== void 0) return;
|
|
10329
|
+
pendingGitRefresh = setTimeout(() => {
|
|
10330
|
+
pendingGitRefresh = void 0;
|
|
10124
10331
|
if (disposed) return;
|
|
10125
|
-
|
|
10126
|
-
|
|
10332
|
+
void git.get(cwd).then((value) => {
|
|
10333
|
+
if (disposed) return;
|
|
10334
|
+
if (updateSnapshot(withSnapshotPatch({ git: value }))) requestRender();
|
|
10335
|
+
});
|
|
10336
|
+
}, GIT_INVALIDATE_DEBOUNCE_MS);
|
|
10337
|
+
pendingGitRefresh.unref?.();
|
|
10127
10338
|
},
|
|
10128
10339
|
get disposed() {
|
|
10129
10340
|
return disposed;
|
|
@@ -10131,6 +10342,10 @@ function createPiStyleRuntime(host, generation2, requestRender = host.requestRen
|
|
|
10131
10342
|
dispose() {
|
|
10132
10343
|
if (disposed) return;
|
|
10133
10344
|
disposed = true;
|
|
10345
|
+
if (pendingGitRefresh !== void 0) {
|
|
10346
|
+
clearTimeout(pendingGitRefresh);
|
|
10347
|
+
pendingGitRefresh = void 0;
|
|
10348
|
+
}
|
|
10134
10349
|
scheduler.cancel();
|
|
10135
10350
|
disposeStatus();
|
|
10136
10351
|
disposeEditor();
|
|
@@ -10684,6 +10899,8 @@ var MAX_RENDER_CACHE_KEYS_PER_INSTANCE = 8;
|
|
|
10684
10899
|
var MAX_LINE_ANALYSIS_ENTRIES = 4096;
|
|
10685
10900
|
var renderCacheByInstance = /* @__PURE__ */ new WeakMap();
|
|
10686
10901
|
var lineAnalysisCache = /* @__PURE__ */ new Map();
|
|
10902
|
+
var lineCacheEvictionCursor;
|
|
10903
|
+
var childrenScanByInstance = /* @__PURE__ */ new WeakMap();
|
|
10687
10904
|
var messageDecorationTestState = {
|
|
10688
10905
|
decoratePasses: 0,
|
|
10689
10906
|
cacheHits: 0,
|
|
@@ -10706,7 +10923,7 @@ function splitLeadingMarkers(line) {
|
|
|
10706
10923
|
if (end === -1) break;
|
|
10707
10924
|
index = end + 1;
|
|
10708
10925
|
}
|
|
10709
|
-
return { head: line.slice(0, index), rest: line.slice(index) };
|
|
10926
|
+
return index === 0 ? { head: "", rest: line } : { head: line.slice(0, index), rest: line.slice(index) };
|
|
10710
10927
|
}
|
|
10711
10928
|
function leadingSgr(line) {
|
|
10712
10929
|
if (!line.startsWith("\x1B[")) return "";
|
|
@@ -10720,41 +10937,153 @@ function leadingSgr(line) {
|
|
|
10720
10937
|
}
|
|
10721
10938
|
function isBackgroundSgr(sequence) {
|
|
10722
10939
|
if (!sequence.startsWith("\x1B[") || !sequence.endsWith("m")) return false;
|
|
10723
|
-
|
|
10724
|
-
|
|
10725
|
-
|
|
10726
|
-
|
|
10727
|
-
|
|
10940
|
+
let value = 0;
|
|
10941
|
+
let empty = true;
|
|
10942
|
+
let valid = true;
|
|
10943
|
+
for (let index = 2; index < sequence.length - 1; index++) {
|
|
10944
|
+
const code = sequence.charCodeAt(index);
|
|
10945
|
+
if (code === 59) {
|
|
10946
|
+
if (valid && matchesBackgroundCode(empty ? 0 : value)) return true;
|
|
10947
|
+
value = 0;
|
|
10948
|
+
empty = true;
|
|
10949
|
+
valid = true;
|
|
10950
|
+
continue;
|
|
10951
|
+
}
|
|
10952
|
+
if (code < 48 || code > 57) {
|
|
10953
|
+
valid = false;
|
|
10954
|
+
continue;
|
|
10955
|
+
}
|
|
10956
|
+
value = value * 10 + (code - 48);
|
|
10957
|
+
empty = false;
|
|
10728
10958
|
}
|
|
10729
|
-
return
|
|
10959
|
+
return valid && matchesBackgroundCode(empty ? 0 : value);
|
|
10960
|
+
}
|
|
10961
|
+
function matchesBackgroundCode(value) {
|
|
10962
|
+
return value === 48 || value === 49 || value >= 40 && value <= 47 || value >= 100 && value <= 107;
|
|
10963
|
+
}
|
|
10964
|
+
function certifiedAsciiWidth(value) {
|
|
10965
|
+
let width = 0;
|
|
10966
|
+
let index = 0;
|
|
10967
|
+
const length = value.length;
|
|
10968
|
+
while (index < length) {
|
|
10969
|
+
const code = value.charCodeAt(index);
|
|
10970
|
+
if (code === 27) {
|
|
10971
|
+
const next = index + 1 < length ? value.charCodeAt(index + 1) : -1;
|
|
10972
|
+
if (next === 91) {
|
|
10973
|
+
let scan = index + 2;
|
|
10974
|
+
while (scan < length) {
|
|
10975
|
+
const terminator = value.charCodeAt(scan);
|
|
10976
|
+
if (terminator === 109 || // m
|
|
10977
|
+
terminator === 71 || // G
|
|
10978
|
+
terminator === 75 || // K
|
|
10979
|
+
terminator === 72 || // H
|
|
10980
|
+
terminator === 74) {
|
|
10981
|
+
index = scan + 1;
|
|
10982
|
+
break;
|
|
10983
|
+
}
|
|
10984
|
+
scan++;
|
|
10985
|
+
}
|
|
10986
|
+
if (scan >= length) return void 0;
|
|
10987
|
+
continue;
|
|
10988
|
+
}
|
|
10989
|
+
if (next === 93 || next === 95) {
|
|
10990
|
+
let scan = index + 2;
|
|
10991
|
+
let end = -1;
|
|
10992
|
+
while (scan < length) {
|
|
10993
|
+
const terminator = value.charCodeAt(scan);
|
|
10994
|
+
if (terminator === 7) {
|
|
10995
|
+
end = scan + 1;
|
|
10996
|
+
break;
|
|
10997
|
+
}
|
|
10998
|
+
if (terminator === 27 && scan + 1 < length && value.charCodeAt(scan + 1) === 92) {
|
|
10999
|
+
end = scan + 2;
|
|
11000
|
+
break;
|
|
11001
|
+
}
|
|
11002
|
+
scan++;
|
|
11003
|
+
}
|
|
11004
|
+
if (end < 0) return void 0;
|
|
11005
|
+
index = end;
|
|
11006
|
+
continue;
|
|
11007
|
+
}
|
|
11008
|
+
return void 0;
|
|
11009
|
+
}
|
|
11010
|
+
if (code < 32 || code > 126) return void 0;
|
|
11011
|
+
width++;
|
|
11012
|
+
index++;
|
|
11013
|
+
}
|
|
11014
|
+
return width;
|
|
11015
|
+
}
|
|
11016
|
+
function certifiedVisibleWidth(value) {
|
|
11017
|
+
return certifiedAsciiWidth(value) ?? visibleWidth(value);
|
|
11018
|
+
}
|
|
11019
|
+
var prefixWidthMemo;
|
|
11020
|
+
function prefixWidthOf(prefix) {
|
|
11021
|
+
if (prefixWidthMemo?.prefix === prefix) return prefixWidthMemo.width;
|
|
11022
|
+
const width = certifiedVisibleWidth(prefix);
|
|
11023
|
+
prefixWidthMemo = { prefix, width };
|
|
11024
|
+
return width;
|
|
10730
11025
|
}
|
|
10731
11026
|
function contentText(line) {
|
|
11027
|
+
if (!line.includes("\x1B")) return line;
|
|
10732
11028
|
let output = "";
|
|
11029
|
+
let sliceStart = 0;
|
|
10733
11030
|
for (let index = 0; index < line.length; index++) {
|
|
10734
|
-
if (line.charCodeAt(index) !== 27)
|
|
10735
|
-
|
|
10736
|
-
continue;
|
|
10737
|
-
}
|
|
11031
|
+
if (line.charCodeAt(index) !== 27) continue;
|
|
11032
|
+
output += line.slice(sliceStart, index);
|
|
10738
11033
|
const next = line[index + 1];
|
|
10739
11034
|
if (next === "]") {
|
|
10740
11035
|
index += 2;
|
|
10741
11036
|
while (index < line.length && line.charCodeAt(index) !== 7) index++;
|
|
10742
|
-
|
|
10743
|
-
}
|
|
10744
|
-
if (next === "[") {
|
|
11037
|
+
} else if (next === "[") {
|
|
10745
11038
|
index += 2;
|
|
10746
11039
|
while (index < line.length && (line.charCodeAt(index) < 64 || line.charCodeAt(index) > 126)) index++;
|
|
10747
11040
|
}
|
|
11041
|
+
sliceStart = index + 1;
|
|
10748
11042
|
}
|
|
10749
|
-
|
|
11043
|
+
output += line.slice(sliceStart);
|
|
11044
|
+
if (output.includes("\x1B]133;")) {
|
|
11045
|
+
return output.replaceAll(OSC133_ZONE_START, "").replaceAll(OSC133_ZONE_END, "").replaceAll(OSC133_ZONE_FINAL, "");
|
|
11046
|
+
}
|
|
11047
|
+
return output;
|
|
11048
|
+
}
|
|
11049
|
+
function isWhitespaceCode(code) {
|
|
11050
|
+
if (code === 32 || code >= 9 && code <= 13) return true;
|
|
11051
|
+
if (code < 128) return false;
|
|
11052
|
+
return code === 160 || code === 5760 || code >= 8192 && code <= 8202 || code === 8232 || code === 8233 || code === 8239 || code === 8287 || code === 12288 || code === 65279;
|
|
10750
11053
|
}
|
|
10751
11054
|
function hasContent(line) {
|
|
10752
|
-
|
|
11055
|
+
const length = line.length;
|
|
11056
|
+
let index = 0;
|
|
11057
|
+
while (index < length) {
|
|
11058
|
+
const code = line.charCodeAt(index);
|
|
11059
|
+
if (code === 27) {
|
|
11060
|
+
const next = index + 1 < length ? line.charCodeAt(index + 1) : -1;
|
|
11061
|
+
if (next === 93) {
|
|
11062
|
+
index += 2;
|
|
11063
|
+
while (index < length && line.charCodeAt(index) !== 7) index++;
|
|
11064
|
+
} else if (next === 91) {
|
|
11065
|
+
index += 2;
|
|
11066
|
+
while (index < length) {
|
|
11067
|
+
const inner = line.charCodeAt(index);
|
|
11068
|
+
if (inner >= 64 && inner <= 126) break;
|
|
11069
|
+
index++;
|
|
11070
|
+
}
|
|
11071
|
+
}
|
|
11072
|
+
index++;
|
|
11073
|
+
continue;
|
|
11074
|
+
}
|
|
11075
|
+
if (code >= 55296 && code <= 57343) return true;
|
|
11076
|
+
if (!isWhitespaceCode(code)) return true;
|
|
11077
|
+
index++;
|
|
11078
|
+
}
|
|
11079
|
+
return false;
|
|
10753
11080
|
}
|
|
10754
11081
|
function getLineAnalysis(line) {
|
|
10755
11082
|
const cached = lineAnalysisCache.get(line);
|
|
10756
11083
|
if (cached) {
|
|
10757
11084
|
messageDecorationTestState.lineCacheHits++;
|
|
11085
|
+
lineAnalysisCache.delete(line);
|
|
11086
|
+
lineAnalysisCache.set(line, cached);
|
|
10758
11087
|
return cached;
|
|
10759
11088
|
}
|
|
10760
11089
|
messageDecorationTestState.lineCacheMisses++;
|
|
@@ -10762,21 +11091,29 @@ function getLineAnalysis(line) {
|
|
|
10762
11091
|
const backgroundAnsi = leadingSgr(leadingMarkers.rest);
|
|
10763
11092
|
const isBackgroundWrapped = backgroundAnsi !== "" && isBackgroundSgr(backgroundAnsi) && leadingMarkers.rest.endsWith(BG_RESET);
|
|
10764
11093
|
const backgroundBody = isBackgroundWrapped ? leadingMarkers.rest.slice(backgroundAnsi.length, leadingMarkers.rest.length - BG_RESET.length) : void 0;
|
|
11094
|
+
const hasOscStart = line.startsWith(OSC133_ZONE_START);
|
|
10765
11095
|
const analysis = {
|
|
10766
|
-
visibleWidth:
|
|
11096
|
+
visibleWidth: certifiedVisibleWidth(line),
|
|
10767
11097
|
hasContent: hasContent(line),
|
|
10768
|
-
oscEnvelope: extractOscEnvelope(line),
|
|
10769
|
-
hasOscStart
|
|
11098
|
+
oscEnvelope: hasOscStart ? extractOscEnvelope(line) : void 0,
|
|
11099
|
+
hasOscStart,
|
|
10770
11100
|
leadingMarkers,
|
|
10771
11101
|
isBackgroundWrapped,
|
|
10772
11102
|
backgroundAnsi,
|
|
10773
11103
|
backgroundBody,
|
|
10774
|
-
backgroundBodyWidth: backgroundBody === void 0 ? void 0 :
|
|
11104
|
+
backgroundBodyWidth: backgroundBody === void 0 ? void 0 : certifiedVisibleWidth(backgroundBody)
|
|
10775
11105
|
};
|
|
10776
11106
|
lineAnalysisCache.set(line, analysis);
|
|
10777
11107
|
if (lineAnalysisCache.size > MAX_LINE_ANALYSIS_ENTRIES) {
|
|
10778
|
-
|
|
10779
|
-
if (
|
|
11108
|
+
let cursor = lineCacheEvictionCursor;
|
|
11109
|
+
if (cursor === void 0) cursor = lineAnalysisCache.keys();
|
|
11110
|
+
let oldest = cursor.next();
|
|
11111
|
+
if (oldest.done) {
|
|
11112
|
+
cursor = lineAnalysisCache.keys();
|
|
11113
|
+
oldest = cursor.next();
|
|
11114
|
+
}
|
|
11115
|
+
lineCacheEvictionCursor = cursor;
|
|
11116
|
+
if (!oldest.done && oldest.value !== void 0) lineAnalysisCache.delete(oldest.value);
|
|
10780
11117
|
}
|
|
10781
11118
|
return analysis;
|
|
10782
11119
|
}
|
|
@@ -10789,8 +11126,8 @@ function rebuildAtWidth(line, width, lead, leadWidth, analysis = getLineAnalysis
|
|
|
10789
11126
|
return `${lead}${line}${pad}`;
|
|
10790
11127
|
}
|
|
10791
11128
|
function decorateMessageLine(line, index, lastIndex, contentIndex, width, options, analysis = getLineAnalysis(line)) {
|
|
10792
|
-
const { firstEnvelope, firstHasStart, multilineEnvelope, prefix, prefixWidth } = options;
|
|
10793
|
-
const lead = index === contentIndex ? prefix : index > contentIndex ?
|
|
11129
|
+
const { firstEnvelope, firstHasStart, multilineEnvelope, prefix, prefixWidth, continuationLead } = options;
|
|
11130
|
+
const lead = index === contentIndex ? prefix : index > contentIndex ? continuationLead : "";
|
|
10794
11131
|
const leadWidth = index < contentIndex ? 0 : prefixWidth;
|
|
10795
11132
|
if (index === contentIndex && firstEnvelope)
|
|
10796
11133
|
return `${firstEnvelope.start}${rebuildAtWidth(firstEnvelope.body, width, prefix, prefixWidth)}${firstEnvelope.end}`;
|
|
@@ -10846,32 +11183,58 @@ function prefixNative(lines, width, prefix) {
|
|
|
10846
11183
|
if (!Array.isArray(lines) || lines.length === 0 || !lines.every((line) => typeof line === "string")) return void 0;
|
|
10847
11184
|
messageDecorationTestState.decoratePasses++;
|
|
10848
11185
|
const nativeLines = lines;
|
|
10849
|
-
const prefixWidth =
|
|
11186
|
+
const prefixWidth = prefixWidthOf(prefix);
|
|
10850
11187
|
if (width <= prefixWidth) return void 0;
|
|
10851
11188
|
const bodyWidth = width - prefixWidth;
|
|
10852
|
-
const
|
|
11189
|
+
const analyses = nativeLines.map((line) => getLineAnalysis(line));
|
|
10853
11190
|
const last = nativeLines.at(-1) ?? "";
|
|
10854
|
-
const lastAnalysis = getLineAnalysis(last);
|
|
11191
|
+
const lastAnalysis = analyses[analyses.length - 1] ?? getLineAnalysis(last);
|
|
10855
11192
|
const multilineEnvelope = nativeLines.length > 1 && last.startsWith(OSC133_ZONE_END + OSC133_ZONE_FINAL);
|
|
10856
|
-
|
|
10857
|
-
|
|
10858
|
-
|
|
10859
|
-
|
|
11193
|
+
let firstContentIndex = -1;
|
|
11194
|
+
for (let index = 0; index < nativeLines.length; index++) {
|
|
11195
|
+
const analysis = analyses[index] ?? getLineAnalysis(nativeLines[index] ?? "");
|
|
11196
|
+
if (index !== nativeLines.length - 1 || !multilineEnvelope) {
|
|
11197
|
+
if (analysis.hasContent) {
|
|
11198
|
+
firstContentIndex = index;
|
|
11199
|
+
break;
|
|
11200
|
+
}
|
|
11201
|
+
continue;
|
|
11202
|
+
}
|
|
11203
|
+
let earlierHasContent = false;
|
|
11204
|
+
for (let earlier = 0; earlier < index; earlier++) {
|
|
11205
|
+
if ((analyses[earlier] ?? getLineAnalysis(nativeLines[earlier] ?? "")).hasContent) {
|
|
11206
|
+
earlierHasContent = true;
|
|
11207
|
+
break;
|
|
11208
|
+
}
|
|
11209
|
+
}
|
|
11210
|
+
if (!earlierHasContent && lastAnalysis.hasContent) firstContentIndex = index;
|
|
11211
|
+
break;
|
|
11212
|
+
}
|
|
10860
11213
|
if (firstContentIndex < 0) return nativeLines;
|
|
10861
|
-
const firstAnalysis = getLineAnalysis(
|
|
11214
|
+
const firstAnalysis = analyses[0] ?? getLineAnalysis(nativeLines[0] ?? "");
|
|
10862
11215
|
const firstEnvelope = firstContentIndex === 0 ? firstAnalysis.oscEnvelope : void 0;
|
|
10863
11216
|
const firstHasStart = firstContentIndex === 0 && firstAnalysis.hasOscStart;
|
|
11217
|
+
const continuationLead = " ".repeat(prefixWidth);
|
|
10864
11218
|
const decorated = nativeLines.map(
|
|
10865
|
-
(line, index) => decorateMessageLine(
|
|
10866
|
-
|
|
10867
|
-
|
|
10868
|
-
|
|
10869
|
-
|
|
10870
|
-
|
|
10871
|
-
|
|
11219
|
+
(line, index) => decorateMessageLine(
|
|
11220
|
+
line,
|
|
11221
|
+
index,
|
|
11222
|
+
nativeLines.length - 1,
|
|
11223
|
+
firstContentIndex,
|
|
11224
|
+
width,
|
|
11225
|
+
{
|
|
11226
|
+
firstEnvelope,
|
|
11227
|
+
firstHasStart,
|
|
11228
|
+
multilineEnvelope,
|
|
11229
|
+
prefix,
|
|
11230
|
+
prefixWidth,
|
|
11231
|
+
continuationLead
|
|
11232
|
+
},
|
|
11233
|
+
analyses[index]
|
|
11234
|
+
)
|
|
10872
11235
|
);
|
|
10873
|
-
if (!decorated.every((line) =>
|
|
10874
|
-
if (!
|
|
11236
|
+
if (!decorated.every((line) => certifiedVisibleWidth(line) <= width)) return void 0;
|
|
11237
|
+
if (!analyses.every((analysis) => analysis.visibleWidth <= bodyWidth)) return void 0;
|
|
10875
11238
|
return decorated;
|
|
10876
11239
|
}
|
|
10877
11240
|
function decorateMessageRender(original, instance, args, snapshot = {
|
|
@@ -10884,7 +11247,7 @@ function decorateMessageRender(original, instance, args, snapshot = {
|
|
|
10884
11247
|
const width = typeof args[0] === "number" ? args[0] : 0;
|
|
10885
11248
|
const prefix = snapshot.assistantPrefix;
|
|
10886
11249
|
if (!snapshot.assistantEnabled) return Reflect.apply(original, instance, args);
|
|
10887
|
-
const prefixWidth =
|
|
11250
|
+
const prefixWidth = prefixWidthOf(prefix);
|
|
10888
11251
|
if (width <= prefixWidth) return Reflect.apply(original, instance, args);
|
|
10889
11252
|
const reducedWidth = width - prefixWidth;
|
|
10890
11253
|
const native = Reflect.apply(original, instance, [reducedWidth, ...args.slice(1)]);
|
|
@@ -10916,8 +11279,16 @@ function hasToolCallItems(message) {
|
|
|
10916
11279
|
function isBlankTextChild(child) {
|
|
10917
11280
|
const candidate = child;
|
|
10918
11281
|
if (typeof candidate?.setCustomBgFn !== "function" || typeof candidate.render !== "function") return false;
|
|
11282
|
+
if (typeof candidate.text === "string") return contentText(candidate.text).trim() === "";
|
|
10919
11283
|
return contentText(candidate.render(0).join("\n")).trim() === "";
|
|
10920
11284
|
}
|
|
11285
|
+
function childrenUnchangedSinceScan(instance, children) {
|
|
11286
|
+
const state = childrenScanByInstance.get(instance);
|
|
11287
|
+
return state !== void 0 && state.childrenRef === children && state.length === children.length;
|
|
11288
|
+
}
|
|
11289
|
+
function markChildrenScanned(instance, children) {
|
|
11290
|
+
childrenScanByInstance.set(instance, { childrenRef: children, length: children.length });
|
|
11291
|
+
}
|
|
10921
11292
|
function decorateMessageUpdate(original, instance, args, snapshot = {
|
|
10922
11293
|
assistantPrefix: "\u2502 ",
|
|
10923
11294
|
assistantEnabled: true,
|
|
@@ -10927,24 +11298,22 @@ function decorateMessageUpdate(original, instance, args, snapshot = {
|
|
|
10927
11298
|
if (typeof original !== "function") return void 0;
|
|
10928
11299
|
const result = Reflect.apply(original, instance, args);
|
|
10929
11300
|
const target = instance;
|
|
10930
|
-
|
|
10931
|
-
|
|
10932
|
-
if (
|
|
11301
|
+
const children = target.contentContainer?.children;
|
|
11302
|
+
if (children && !childrenUnchangedSinceScan(instance, children)) {
|
|
11303
|
+
if (snapshot.collapseHiddenThinking && target.hideThinkingBlock === true && target.hiddenThinkingLabel === "") {
|
|
10933
11304
|
for (let index = children.length - 1; index >= 0; index--) {
|
|
10934
11305
|
if (!isBlankTextChild(children[index])) continue;
|
|
10935
11306
|
children.splice(index, 1);
|
|
10936
11307
|
if (isSpacerChild(children[index])) children.splice(index, 1);
|
|
10937
11308
|
}
|
|
10938
11309
|
}
|
|
10939
|
-
|
|
10940
|
-
if (snapshot.hideInterimText && hasToolCallItems(args[0])) {
|
|
10941
|
-
const children = target.contentContainer?.children;
|
|
10942
|
-
if (children) {
|
|
11310
|
+
if (snapshot.hideInterimText && hasToolCallItems(args[0])) {
|
|
10943
11311
|
for (let index = children.length - 1; index >= 0; index--) {
|
|
10944
11312
|
if (isInterimTextChild(children[index])) children.splice(index, 1);
|
|
10945
11313
|
}
|
|
10946
11314
|
if (children.every((child) => isSpacerChild(child))) children.length = 0;
|
|
10947
11315
|
}
|
|
11316
|
+
markChildrenScanned(instance, children);
|
|
10948
11317
|
}
|
|
10949
11318
|
return result;
|
|
10950
11319
|
}
|
|
@@ -12363,6 +12732,7 @@ function piStyleExtension(pi) {
|
|
|
12363
12732
|
const run = finishAgentRun();
|
|
12364
12733
|
if (run) {
|
|
12365
12734
|
invalidateTurnMembers(run);
|
|
12735
|
+
releaseTurnInvalidators(run);
|
|
12366
12736
|
requestToolPresentationRender();
|
|
12367
12737
|
}
|
|
12368
12738
|
});
|