@quandev104/pi-style 0.2.0 → 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 +16 -0
- package/README.md +1 -1
- package/dist/extensions/pi-style.js +1256 -491
- package/dist/extensions/pi-style.js.map +1 -1
- package/extension-src/pi-style/app/index.ts +3 -2
- package/extension-src/pi-style/app/runtime.ts +99 -86
- package/extension-src/pi-style/app/snapshot.ts +41 -2
- 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 +97 -66
- package/extension-src/pi-style/features/messages/index.ts +469 -90
- package/extension-src/pi-style/features/status-line/index.ts +41 -11
- package/extension-src/pi-style/features/tools/bash-execution.ts +12 -1
- package/extension-src/pi-style/features/tools/boxed/bash.ts +195 -66
- package/extension-src/pi-style/features/tools/boxed/batch.ts +60 -10
- package/extension-src/pi-style/features/tools/boxed/edit.ts +45 -25
- 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 +45 -22
- package/extension-src/pi-style/features/tools/boxed/read.ts +4 -2
- package/extension-src/pi-style/features/tools/boxed/session-config.ts +45 -14
- package/extension-src/pi-style/features/tools/boxed/shared.ts +51 -0
- package/extension-src/pi-style/features/tools/boxed/turn-summary.ts +12 -0
- package/extension-src/pi-style/pi/compatibility-probe.ts +1 -1
- package/extension-src/pi-style/pi/index.ts +28 -13
- package/extension-src/pi-style/pi/session-usage.ts +204 -21
- package/extension-src/pi-style/shared/ansi.ts +17 -5
- package/extension-src/pi-style/shared/box.ts +83 -6
- 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++;
|
|
@@ -183,9 +185,9 @@ function rgbTo256(r, g, b) {
|
|
|
183
185
|
function colorEscapes(mode, hex, kind) {
|
|
184
186
|
if (!isHexColor(hex)) return void 0;
|
|
185
187
|
const { r, g, b } = hexToRgb(hex);
|
|
186
|
-
const
|
|
188
|
+
const cacheKey2 = `${mode}:${kind}:${hex}`;
|
|
187
189
|
const cache = kind === "fg" ? fgEscapeCache : bgEscapeCache;
|
|
188
|
-
let cached = cache.get(
|
|
190
|
+
let cached = cache.get(cacheKey2);
|
|
189
191
|
if (!cached) {
|
|
190
192
|
if (mode === "256color") {
|
|
191
193
|
const idx = rgbTo256(r, g, b);
|
|
@@ -199,7 +201,7 @@ function colorEscapes(mode, hex, kind) {
|
|
|
199
201
|
suffix: kind === "fg" ? "\x1B[39m" : RESET_BACKGROUND
|
|
200
202
|
};
|
|
201
203
|
}
|
|
202
|
-
cache.set(
|
|
204
|
+
cache.set(cacheKey2, cached);
|
|
203
205
|
}
|
|
204
206
|
return cached;
|
|
205
207
|
}
|
|
@@ -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;
|
|
@@ -411,8 +413,8 @@ function truncatePrintableAscii(text, width, ellipsis = TRUNCATE_ELLIPSIS) {
|
|
|
411
413
|
const targetWidth = Math.max(0, width - ellipsisWidth);
|
|
412
414
|
return { text: `${text.slice(0, targetWidth)}${ellipsis}`, visibleWidth: targetWidth + ellipsisWidth };
|
|
413
415
|
}
|
|
414
|
-
function truncateSgrAscii(text, width, ellipsis,
|
|
415
|
-
if (
|
|
416
|
+
function truncateSgrAscii(text, width, ellipsis, visibleWidth4) {
|
|
417
|
+
if (visibleWidth4 <= width) return { text, visibleWidth: visibleWidth4 };
|
|
416
418
|
const ellipsisWidth = knownEllipsisWidth(ellipsis);
|
|
417
419
|
if (ellipsisWidth === null) return null;
|
|
418
420
|
if (ellipsisWidth >= width) return truncatePrintableAscii(ellipsis, width, "");
|
|
@@ -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);
|
|
@@ -684,10 +686,10 @@ function setFullTheme(theme, force = false) {
|
|
|
684
686
|
const themeName = resolveThemeName(theme);
|
|
685
687
|
const sourcePath = resolveThemeSourcePath(theme);
|
|
686
688
|
if (!themeName && !sourcePath) return;
|
|
687
|
-
const
|
|
688
|
-
if (!force &&
|
|
689
|
+
const cacheKey2 = sourcePath || themeName;
|
|
690
|
+
if (!force && cacheKey2 === cachedThemeName && (cachedExtras !== null || cachedVars !== null || cachedColors !== null || cachedThemeExport !== null))
|
|
689
691
|
return;
|
|
690
|
-
cachedThemeName =
|
|
692
|
+
cachedThemeName = cacheKey2;
|
|
691
693
|
const result = readThemeDiscoveryFromPath(sourcePath) ?? (themeName ? discoverThemeExtras(themeName) : null);
|
|
692
694
|
cachedExtras = result?.extras ?? null;
|
|
693
695
|
cachedVars = result?.vars ?? null;
|
|
@@ -703,6 +705,15 @@ function getThemeExtra(_theme, key) {
|
|
|
703
705
|
}
|
|
704
706
|
|
|
705
707
|
// extension-src/pi-style/shared/box.ts
|
|
708
|
+
var THEME_CACHE_KEYS = /* @__PURE__ */ new WeakMap();
|
|
709
|
+
var nextThemeCacheKey = 1;
|
|
710
|
+
function themeCacheKey(theme) {
|
|
711
|
+
const cached = THEME_CACHE_KEYS.get(theme);
|
|
712
|
+
if (cached !== void 0) return cached;
|
|
713
|
+
const created = nextThemeCacheKey++;
|
|
714
|
+
THEME_CACHE_KEYS.set(theme, created);
|
|
715
|
+
return created;
|
|
716
|
+
}
|
|
706
717
|
function shortenPath(path) {
|
|
707
718
|
const home = homedir2();
|
|
708
719
|
if (path.startsWith(home)) return `~${path.slice(home.length)}`;
|
|
@@ -734,12 +745,48 @@ function getTextOutput(result) {
|
|
|
734
745
|
});
|
|
735
746
|
return textBlocks.map((contentBlock) => String(contentBlock.text ?? "")).join("\n").replace(/\r/g, "");
|
|
736
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
|
+
}
|
|
737
767
|
function countWords(text) {
|
|
768
|
+
const len = text.length;
|
|
738
769
|
let count = 0;
|
|
739
|
-
let inWord =
|
|
740
|
-
for (
|
|
741
|
-
const
|
|
742
|
-
|
|
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);
|
|
743
790
|
inWord = isWord;
|
|
744
791
|
}
|
|
745
792
|
return count;
|
|
@@ -868,7 +915,7 @@ function formatBoxedRunningStatus(theme, elapsedMs) {
|
|
|
868
915
|
function dimLine(text) {
|
|
869
916
|
return `\x1B[2m${text}\x1B[22m`;
|
|
870
917
|
}
|
|
871
|
-
function boxFrameText(
|
|
918
|
+
function boxFrameText(_theme, text) {
|
|
872
919
|
return dimLine(text);
|
|
873
920
|
}
|
|
874
921
|
function boxBorder(theme, left, right, width) {
|
|
@@ -1445,6 +1492,18 @@ function setToolsRenderConfig(config) {
|
|
|
1445
1492
|
function getToolsRenderConfig() {
|
|
1446
1493
|
return sessionToolsConfig;
|
|
1447
1494
|
}
|
|
1495
|
+
function getToolsRenderCacheSignature() {
|
|
1496
|
+
return [
|
|
1497
|
+
sessionToolsConfig.maxCollapsedLines,
|
|
1498
|
+
sessionToolsConfig.maxExpandedLines,
|
|
1499
|
+
sessionToolsConfig.dimOutput ? 1 : 0,
|
|
1500
|
+
sessionToolsConfig.showElapsed ? 1 : 0,
|
|
1501
|
+
sessionToolsConfig.batchOpenGlyph,
|
|
1502
|
+
sessionToolsConfig.nerdFonts ? 1 : 0,
|
|
1503
|
+
sessionToolsConfig.collapseAfterTurn ? 1 : 0,
|
|
1504
|
+
sessionToolsConfig.collapseMutatingTools ? 1 : 0
|
|
1505
|
+
].join("|");
|
|
1506
|
+
}
|
|
1448
1507
|
var STARTED_AT_KEY = "__piStyleStartedAt";
|
|
1449
1508
|
var ENDED_AT_KEY = "__piStyleEndedAt";
|
|
1450
1509
|
var RESULT_SEEN_KEY = "__piStyleResultSeen";
|
|
@@ -1472,27 +1531,35 @@ function markResultSeen(state) {
|
|
|
1472
1531
|
if (!state || typeof state !== "object") return;
|
|
1473
1532
|
state[RESULT_SEEN_KEY] = true;
|
|
1474
1533
|
}
|
|
1475
|
-
var
|
|
1534
|
+
var tickerEntries = /* @__PURE__ */ new Map();
|
|
1535
|
+
var sharedTickerHandle;
|
|
1536
|
+
function ensureSharedTicker() {
|
|
1537
|
+
if (sharedTickerHandle !== void 0 || tickerEntries.size === 0) return;
|
|
1538
|
+
sharedTickerHandle = setInterval(() => {
|
|
1539
|
+
for (const { invalidate } of tickerEntries.values()) invalidate();
|
|
1540
|
+
}, 1e3);
|
|
1541
|
+
}
|
|
1542
|
+
function stopSharedTickerIfIdle() {
|
|
1543
|
+
if (sharedTickerHandle === void 0 || tickerEntries.size > 0) return;
|
|
1544
|
+
clearInterval(sharedTickerHandle);
|
|
1545
|
+
sharedTickerHandle = void 0;
|
|
1546
|
+
}
|
|
1476
1547
|
function startElapsedTicker(state, invalidate) {
|
|
1477
1548
|
if (!state || typeof state !== "object") return;
|
|
1478
|
-
|
|
1479
|
-
state
|
|
1480
|
-
|
|
1549
|
+
state[TICKER_KEY] = true;
|
|
1550
|
+
tickerEntries.set(state, { invalidate });
|
|
1551
|
+
ensureSharedTicker();
|
|
1481
1552
|
}
|
|
1482
1553
|
function stopElapsedTicker(state) {
|
|
1483
1554
|
if (!state || typeof state !== "object") return;
|
|
1484
|
-
const handle = state[TICKER_KEY];
|
|
1485
|
-
if (handle !== void 0) clearInterval(handle);
|
|
1486
1555
|
delete state[TICKER_KEY];
|
|
1487
|
-
|
|
1556
|
+
tickerEntries.delete(state);
|
|
1557
|
+
stopSharedTickerIfIdle();
|
|
1488
1558
|
}
|
|
1489
1559
|
function stopAllElapsedTickers() {
|
|
1490
|
-
for (const state of
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
delete state[TICKER_KEY];
|
|
1494
|
-
}
|
|
1495
|
-
tickerStates.clear();
|
|
1560
|
+
for (const state of tickerEntries.keys()) delete state[TICKER_KEY];
|
|
1561
|
+
tickerEntries.clear();
|
|
1562
|
+
stopSharedTickerIfIdle();
|
|
1496
1563
|
}
|
|
1497
1564
|
|
|
1498
1565
|
// extension-src/pi-style/features/tools/boxed/batch.ts
|
|
@@ -1528,6 +1595,7 @@ function createBatch(meta, leaderId, detail, opts = {}) {
|
|
|
1528
1595
|
leaderId,
|
|
1529
1596
|
startedAt: performance.now(),
|
|
1530
1597
|
closed: false,
|
|
1598
|
+
revision: 0,
|
|
1531
1599
|
members: [
|
|
1532
1600
|
{
|
|
1533
1601
|
toolCallId: leaderId,
|
|
@@ -1543,14 +1611,20 @@ function createBatch(meta, leaderId, detail, opts = {}) {
|
|
|
1543
1611
|
batchByCallId.set(leaderId, batch);
|
|
1544
1612
|
return batch;
|
|
1545
1613
|
}
|
|
1614
|
+
function bumpBatchRevision(batch) {
|
|
1615
|
+
batch.revision++;
|
|
1616
|
+
delete batch.renderCache;
|
|
1617
|
+
}
|
|
1546
1618
|
function registerBatchCall(meta, detail, context, opts = {}) {
|
|
1547
1619
|
const existing = batchByCallId.get(context.toolCallId);
|
|
1548
1620
|
if (existing) {
|
|
1549
1621
|
const member2 = existing.members.find((entry) => entry.toolCallId === context.toolCallId);
|
|
1550
1622
|
if (member2) {
|
|
1623
|
+
const changed = member2.detail !== detail || member2.pattern !== opts.pattern || member2.pathLabel !== opts.pathLabel;
|
|
1551
1624
|
member2.detail = detail;
|
|
1552
1625
|
if (opts.pattern !== void 0) member2.pattern = opts.pattern;
|
|
1553
1626
|
if (opts.pathLabel !== void 0) member2.pathLabel = opts.pathLabel;
|
|
1627
|
+
if (changed) bumpBatchRevision(existing);
|
|
1554
1628
|
}
|
|
1555
1629
|
return { batch: existing, isLeader: existing.leaderId === context.toolCallId };
|
|
1556
1630
|
}
|
|
@@ -1569,6 +1643,7 @@ function registerBatchCall(meta, detail, context, opts = {}) {
|
|
|
1569
1643
|
};
|
|
1570
1644
|
current.members.push(member);
|
|
1571
1645
|
batchByCallId.set(context.toolCallId, current);
|
|
1646
|
+
bumpBatchRevision(current);
|
|
1572
1647
|
return { batch: current, isLeader: false };
|
|
1573
1648
|
}
|
|
1574
1649
|
function registerBatchResult(meta, data, context) {
|
|
@@ -1576,17 +1651,28 @@ function registerBatchResult(meta, data, context) {
|
|
|
1576
1651
|
if (!batch || batch.meta.toolName !== meta.toolName) return { batch: void 0, isLeader: false };
|
|
1577
1652
|
const member = batch.members.find((entry) => entry.toolCallId === context.toolCallId);
|
|
1578
1653
|
if (member) {
|
|
1579
|
-
|
|
1580
|
-
|
|
1654
|
+
const nextStatus = data.isPartial ? "running" : "done";
|
|
1655
|
+
const nextIsError = !data.isPartial && data.isError;
|
|
1656
|
+
const changed = member.status !== nextStatus || member.isError !== nextIsError || member.errorText !== (nextIsError ? data.errorText : void 0) || data.entries !== void 0 && member.outputEntries !== data.entries;
|
|
1657
|
+
member.status = nextStatus;
|
|
1658
|
+
member.isError = nextIsError;
|
|
1581
1659
|
if (member.isError && data.errorText !== void 0) member.errorText = data.errorText;
|
|
1582
1660
|
else delete member.errorText;
|
|
1583
1661
|
if (data.entries !== void 0) member.outputEntries = data.entries;
|
|
1662
|
+
if (changed) bumpBatchRevision(batch);
|
|
1584
1663
|
}
|
|
1585
1664
|
if (batch.completedAt === void 0 && batch.members.every((entry) => entry.status === "done")) {
|
|
1586
1665
|
batch.completedAt = performance.now();
|
|
1666
|
+
bumpBatchRevision(batch);
|
|
1587
1667
|
}
|
|
1588
1668
|
return { batch, isLeader: batch.leaderId === context.toolCallId };
|
|
1589
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
|
+
}
|
|
1590
1676
|
function batchStatus(batch) {
|
|
1591
1677
|
let done = 0;
|
|
1592
1678
|
let failed = 0;
|
|
@@ -1776,9 +1862,16 @@ function renderBatchPanelLines(theme, batch, status, width) {
|
|
|
1776
1862
|
function renderBatchAwareCall(theme, batch) {
|
|
1777
1863
|
return {
|
|
1778
1864
|
invalidate() {
|
|
1865
|
+
delete batch.renderCache;
|
|
1779
1866
|
},
|
|
1780
1867
|
render(width) {
|
|
1781
|
-
|
|
1868
|
+
const status = batchStatus(batch);
|
|
1869
|
+
if (!status.allDone) return renderBatchPanelLines(theme, batch, status, width);
|
|
1870
|
+
const cacheKey2 = [themeCacheKey(theme), getToolsRenderCacheSignature(), width, batch.revision].join("|");
|
|
1871
|
+
if (batch.renderCache?.key === cacheKey2) return batch.renderCache.lines;
|
|
1872
|
+
const lines = renderBatchPanelLines(theme, batch, status, width);
|
|
1873
|
+
batch.renderCache = { key: cacheKey2, lines };
|
|
1874
|
+
return lines;
|
|
1782
1875
|
}
|
|
1783
1876
|
};
|
|
1784
1877
|
}
|
|
@@ -1939,6 +2032,9 @@ function invalidateTurnMembers(turn) {
|
|
|
1939
2032
|
}
|
|
1940
2033
|
}
|
|
1941
2034
|
}
|
|
2035
|
+
function releaseTurnInvalidators(turn) {
|
|
2036
|
+
for (const member of turn.members) invalidateByCallId.delete(member.toolCallId);
|
|
2037
|
+
}
|
|
1942
2038
|
function noteTurnMemberElapsed(toolCallId, elapsedMs) {
|
|
1943
2039
|
if (elapsedMs === void 0) return;
|
|
1944
2040
|
const entry = memberByCallId.get(toolCallId);
|
|
@@ -2830,7 +2926,9 @@ import { getLanguageFromPath } from "@earendil-works/pi-coding-agent";
|
|
|
2830
2926
|
import { highlightCode } from "@earendil-works/pi-coding-agent";
|
|
2831
2927
|
var ESC2 = "\x1B";
|
|
2832
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");
|
|
2833
2930
|
var CONTROL_CHARS = "\0-\b\v\f-\x7F";
|
|
2931
|
+
var CONTROL_CHARS_PATTERN = new RegExp(`[${CONTROL_CHARS}]`, "g");
|
|
2834
2932
|
var ADD_ROW_BACKGROUND_MIX_RATIO = 0.24;
|
|
2835
2933
|
var REMOVE_ROW_BACKGROUND_MIX_RATIO = 0.12;
|
|
2836
2934
|
var ADD_INLINE_EMPHASIS_MIX_RATIO = 0.44;
|
|
@@ -2922,7 +3020,7 @@ function resolveDiffPalette(theme) {
|
|
|
2922
3020
|
}
|
|
2923
3021
|
function keepBackgroundAcrossResets(text, rowBgAnsi) {
|
|
2924
3022
|
if (!text) return text;
|
|
2925
|
-
return text.replace(
|
|
3023
|
+
return text.replace(ANSI_SGR_PATTERN, (sequence, rawCodes) => {
|
|
2926
3024
|
const split = String(rawCodes ?? "").split(";").filter(Boolean);
|
|
2927
3025
|
const codes = split.length > 0 ? split : ["0"];
|
|
2928
3026
|
const hasGlobalReset = codes.includes("0");
|
|
@@ -2964,7 +3062,7 @@ function applyBackgroundToVisibleRange(ansiText, start, end, backgroundAnsi, res
|
|
|
2964
3062
|
return output;
|
|
2965
3063
|
}
|
|
2966
3064
|
function sanitizeSingleLineText(value) {
|
|
2967
|
-
return value.replace(/\r/g, "").replace(/\n/g, "").replace(
|
|
3065
|
+
return value.replace(/\r/g, "").replace(/\n/g, "").replace(CONTROL_CHARS_PATTERN, "");
|
|
2968
3066
|
}
|
|
2969
3067
|
function stripInlineBreaksPreserveAnsi(value) {
|
|
2970
3068
|
return value.replace(/\r/g, "").replace(/\n/g, "");
|
|
@@ -3561,6 +3659,101 @@ var AdaptiveDiffComponent = class {
|
|
|
3561
3659
|
}
|
|
3562
3660
|
};
|
|
3563
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
|
+
|
|
3564
3757
|
// extension-src/pi-style/features/tools/boxed/git.ts
|
|
3565
3758
|
var GIT_SHORT_STATUS_FLAGS = /* @__PURE__ */ new Set(["-s", "--short", "--porcelain"]);
|
|
3566
3759
|
var GIT_DIFF_FORMAT_REJECT = /* @__PURE__ */ new Set([
|
|
@@ -4867,6 +5060,34 @@ function binaryBodyLine(theme, status) {
|
|
|
4867
5060
|
}
|
|
4868
5061
|
function renderGitDiffResult(theme, parsed, options, context) {
|
|
4869
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) {
|
|
4870
5091
|
const elapsedMs = getStateElapsedMs(context.state);
|
|
4871
5092
|
const fileCount = parsed.files.length;
|
|
4872
5093
|
const footerParts = [];
|
|
@@ -4938,75 +5159,6 @@ function renderGitDiffResult(theme, parsed, options, context) {
|
|
|
4938
5159
|
};
|
|
4939
5160
|
}
|
|
4940
5161
|
|
|
4941
|
-
// extension-src/pi-style/features/tools/boxed/shared.ts
|
|
4942
|
-
function pendingFlag(context) {
|
|
4943
|
-
return Boolean(context.isPartial);
|
|
4944
|
-
}
|
|
4945
|
-
function displayPath(rawPath, context) {
|
|
4946
|
-
const path = String(rawPath ?? "");
|
|
4947
|
-
if (!path) return "(unknown)";
|
|
4948
|
-
return shortenPath(resolveRelativePath(path, context.cwd));
|
|
4949
|
-
}
|
|
4950
|
-
function pathRangeDetail(rawPath, offset, limit, context) {
|
|
4951
|
-
const path = displayPath(rawPath, context);
|
|
4952
|
-
let range = "";
|
|
4953
|
-
if (offset !== void 0 || limit !== void 0) {
|
|
4954
|
-
const start = offset ?? 1;
|
|
4955
|
-
const end = limit !== void 0 ? Number(start) + Number(limit) - 1 : "";
|
|
4956
|
-
range = `:${start}${end ? `-${end}` : ""}`;
|
|
4957
|
-
}
|
|
4958
|
-
return path ? `${path}${range}` : "(unknown)";
|
|
4959
|
-
}
|
|
4960
|
-
function compactCall(theme, toolName, detailLine, options) {
|
|
4961
|
-
return renderCompactBoxedToolCall(theme, toolName, detailLine, {
|
|
4962
|
-
widthKey: boxedToolWidthKey(toolName, options.detailKey),
|
|
4963
|
-
state: options.context.state,
|
|
4964
|
-
isError: Boolean(options.context.isError),
|
|
4965
|
-
isPartial: Boolean(options.context.isPartial),
|
|
4966
|
-
isPending: pendingFlag(options.context),
|
|
4967
|
-
running: Boolean(options.context.executionStarted)
|
|
4968
|
-
});
|
|
4969
|
-
}
|
|
4970
|
-
function noteExecutionStart(context) {
|
|
4971
|
-
recordExecutionStarted(context.state, context.executionStarted);
|
|
4972
|
-
}
|
|
4973
|
-
function noteBoxedCallState(context) {
|
|
4974
|
-
if (!context.executionStarted) return;
|
|
4975
|
-
if (context.isPartial) startElapsedTicker(context.state, context.invalidate);
|
|
4976
|
-
else {
|
|
4977
|
-
recordExecutionEnded(context.state);
|
|
4978
|
-
stopElapsedTicker(context.state);
|
|
4979
|
-
}
|
|
4980
|
-
}
|
|
4981
|
-
function noteBoxedResultPhase(context, isPartial) {
|
|
4982
|
-
const firstResultPass = !isResultSeen(context.state);
|
|
4983
|
-
markResultSeen(context.state);
|
|
4984
|
-
if (isPartial) startElapsedTicker(context.state, context.invalidate);
|
|
4985
|
-
else {
|
|
4986
|
-
recordExecutionEnded(context.state);
|
|
4987
|
-
stopElapsedTicker(context.state);
|
|
4988
|
-
}
|
|
4989
|
-
return firstResultPass;
|
|
4990
|
-
}
|
|
4991
|
-
function stateElapsedMs(context) {
|
|
4992
|
-
return getStateElapsedMs(context.state);
|
|
4993
|
-
}
|
|
4994
|
-
function compactFooterWithState(theme, result, context, options = {}) {
|
|
4995
|
-
const elapsedMs = stateElapsedMs(context);
|
|
4996
|
-
return renderCompactBoxedFooter(theme, result, {
|
|
4997
|
-
state: context.state,
|
|
4998
|
-
isError: Boolean(options.isError ?? context.isError),
|
|
4999
|
-
isPartial: Boolean(options.isPartial ?? context.isPartial),
|
|
5000
|
-
...elapsedMs === void 0 ? {} : { elapsedMs }
|
|
5001
|
-
});
|
|
5002
|
-
}
|
|
5003
|
-
function resultFooterLines(theme, result, context, extraParts = []) {
|
|
5004
|
-
return [formatBoxedFooter(theme, result, extraParts, stateElapsedMs(context))];
|
|
5005
|
-
}
|
|
5006
|
-
function clearFooterState(context) {
|
|
5007
|
-
clearCompactBoxedFooter(context.state);
|
|
5008
|
-
}
|
|
5009
|
-
|
|
5010
5162
|
// extension-src/pi-style/features/tools/boxed/bash.ts
|
|
5011
5163
|
var MAX_LINE_CHARS = 2e3;
|
|
5012
5164
|
var ESC3 = "\x1B";
|
|
@@ -5107,6 +5259,25 @@ function countNewlines(text, from, to) {
|
|
|
5107
5259
|
}
|
|
5108
5260
|
return count;
|
|
5109
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
|
+
}
|
|
5110
5281
|
function stripBashToolNoticeLines(text) {
|
|
5111
5282
|
const filteredLines = text.replace(/\r/g, "").split("\n").filter((line) => !BASH_TOOL_NOTICE_PATTERN.test(line.trim()));
|
|
5112
5283
|
return filteredLines.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd();
|
|
@@ -5237,8 +5408,10 @@ function bashBodyComponent(preview, emptyLines) {
|
|
|
5237
5408
|
};
|
|
5238
5409
|
}
|
|
5239
5410
|
function renderBashStreamingResult(theme, raw, options, context) {
|
|
5240
|
-
const
|
|
5241
|
-
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)));
|
|
5242
5415
|
const elapsed = getStateElapsedMs(context.state);
|
|
5243
5416
|
const emptyLines = [theme.fg("dim", "No output received yet")];
|
|
5244
5417
|
if (!hasOutput && isInteractiveCommand(context?.args?.command) && (elapsed ?? 0) >= 1e3) {
|
|
@@ -5269,17 +5442,7 @@ function renderBashFinalResult(theme, raw, options, context) {
|
|
|
5269
5442
|
const referenceLines = rawCommand.split("\n").map((line, index) => `${index === 0 ? "$ " : "> "}${line}`);
|
|
5270
5443
|
if (!options.expanded) {
|
|
5271
5444
|
const scanLines = getToolsRenderConfig().maxCollapsedLines + 10;
|
|
5272
|
-
|
|
5273
|
-
let tailStart = 0;
|
|
5274
|
-
for (let i = statusStripped.length - 1; i >= 0; i--) {
|
|
5275
|
-
if (statusStripped.charCodeAt(i) === 10) {
|
|
5276
|
-
nlCount++;
|
|
5277
|
-
if (nlCount >= scanLines) {
|
|
5278
|
-
tailStart = i + 1;
|
|
5279
|
-
break;
|
|
5280
|
-
}
|
|
5281
|
-
}
|
|
5282
|
-
}
|
|
5445
|
+
const tailStart = findBackwardLineStart(statusStripped, scanLines);
|
|
5283
5446
|
const tail = stripBashToolNoticeLines(stripAnsi(statusStripped.slice(tailStart)));
|
|
5284
5447
|
const totalLinesBefore = tailStart > 0 ? countNewlines(statusStripped, 0, tailStart) : 0;
|
|
5285
5448
|
const preview2 = createBashResultPreview(theme, tail, options, outputColor);
|
|
@@ -5322,11 +5485,11 @@ var EMPTY_BASH_RESULT = Object.freeze({
|
|
|
5322
5485
|
}
|
|
5323
5486
|
});
|
|
5324
5487
|
function createBashResultPreview(theme, text, options, color) {
|
|
5325
|
-
let
|
|
5488
|
+
let cacheKey2 = "";
|
|
5326
5489
|
let cacheLines = null;
|
|
5327
5490
|
return {
|
|
5328
5491
|
invalidate() {
|
|
5329
|
-
|
|
5492
|
+
cacheKey2 = "";
|
|
5330
5493
|
cacheLines = null;
|
|
5331
5494
|
},
|
|
5332
5495
|
render(width) {
|
|
@@ -5334,29 +5497,19 @@ function createBashResultPreview(theme, text, options, color) {
|
|
|
5334
5497
|
const cfg = getToolsRenderConfig();
|
|
5335
5498
|
const expanded = Boolean(options.expanded);
|
|
5336
5499
|
const cacheId = `${bodyWidth}|${expanded ? 1 : 0}|${cfg.maxExpandedLines}|${cfg.dimOutput ? 1 : 0}`;
|
|
5337
|
-
if (cacheLines &&
|
|
5500
|
+
if (cacheLines && cacheKey2 === cacheId) return cacheLines;
|
|
5338
5501
|
if (!expanded) {
|
|
5339
5502
|
const needed = cfg.maxCollapsedLines;
|
|
5340
|
-
|
|
5341
|
-
let scanFrom = 0;
|
|
5342
|
-
for (let i = text.length - 1; i >= 0; i--) {
|
|
5343
|
-
if (text.charCodeAt(i) === 10) {
|
|
5344
|
-
totalNewlines++;
|
|
5345
|
-
if (totalNewlines === needed) {
|
|
5346
|
-
scanFrom = i + 1;
|
|
5347
|
-
break;
|
|
5348
|
-
}
|
|
5349
|
-
}
|
|
5350
|
-
}
|
|
5503
|
+
const scanFrom = findBackwardLineStart(text, needed);
|
|
5351
5504
|
if (text.length === 0) {
|
|
5352
|
-
|
|
5505
|
+
cacheKey2 = cacheId;
|
|
5353
5506
|
cacheLines = [];
|
|
5354
5507
|
return cacheLines;
|
|
5355
5508
|
}
|
|
5356
5509
|
const tail = replaceTabs(text.slice(scanFrom)).replace(/\r/g, "");
|
|
5357
5510
|
const shownLines = tail ? tail.split("\n").map((l) => clampLineLength(l)) : [];
|
|
5358
5511
|
if (shownLines.length === 0) {
|
|
5359
|
-
|
|
5512
|
+
cacheKey2 = cacheId;
|
|
5360
5513
|
cacheLines = [];
|
|
5361
5514
|
return cacheLines;
|
|
5362
5515
|
}
|
|
@@ -5365,31 +5518,31 @@ function createBashResultPreview(theme, text, options, color) {
|
|
|
5365
5518
|
if (color === "error") return formatToolOutputLine(theme, truncated, "error");
|
|
5366
5519
|
return cfg.dimOutput ? formatToolOutputLine(theme, truncated) : formatToolOutputLine(theme, truncated, "text");
|
|
5367
5520
|
});
|
|
5368
|
-
|
|
5521
|
+
cacheKey2 = cacheId;
|
|
5369
5522
|
cacheLines = truncatedShown;
|
|
5370
5523
|
return cacheLines;
|
|
5371
5524
|
}
|
|
5372
5525
|
const normalized = replaceTabs(text);
|
|
5373
|
-
const
|
|
5374
|
-
const
|
|
5526
|
+
const rawLines = normalized.split("\n");
|
|
5527
|
+
const totalLines = rawLines.length;
|
|
5528
|
+
const hasOutput = !(totalLines === 1 && rawLines[0] === "");
|
|
5375
5529
|
if (!hasOutput) {
|
|
5376
|
-
|
|
5530
|
+
cacheKey2 = cacheId;
|
|
5377
5531
|
cacheLines = [];
|
|
5378
5532
|
return cacheLines;
|
|
5379
5533
|
}
|
|
5380
|
-
const truncatedLines = logicalLines.map((line) => safeTruncateToWidth(line, bodyWidth, "\u2026"));
|
|
5381
|
-
const expandedLines = truncatedLines.length === 1 && truncatedLines[0] === "" ? [] : truncatedLines;
|
|
5382
5534
|
const applyColor = (l) => color === "error" ? formatToolOutputLine(theme, l, "error") : cfg.dimOutput ? formatToolOutputLine(theme, l) : formatToolOutputLine(theme, l, "text");
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
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;
|
|
5386
5539
|
truncated.unshift(theme.fg("dim", `\u2026 ${remaining} earlier lines`));
|
|
5387
|
-
|
|
5540
|
+
cacheKey2 = cacheId;
|
|
5388
5541
|
cacheLines = truncated;
|
|
5389
5542
|
return cacheLines;
|
|
5390
5543
|
}
|
|
5391
|
-
|
|
5392
|
-
cacheLines =
|
|
5544
|
+
cacheKey2 = cacheId;
|
|
5545
|
+
cacheLines = rawLines.map((line) => applyColor(renderRawLine(line)));
|
|
5393
5546
|
return cacheLines;
|
|
5394
5547
|
}
|
|
5395
5548
|
};
|
|
@@ -5556,6 +5709,7 @@ function isGitDiffClass(cls) {
|
|
|
5556
5709
|
function isGitActionClass(cls) {
|
|
5557
5710
|
return !isBashTreeClass(cls) && cls.kind === "action";
|
|
5558
5711
|
}
|
|
5712
|
+
var PARTIAL_REPARSE_THRESHOLD = 4096;
|
|
5559
5713
|
function parseSemanticOutput(cls, output) {
|
|
5560
5714
|
if (isBashTreeClass(cls)) return parseBashTreeOutput(cls, output);
|
|
5561
5715
|
if (isGhClass(cls)) return parseGhOutput(cls, output);
|
|
@@ -5602,27 +5756,35 @@ function renderSemanticPanel(theme, toolCallId, context) {
|
|
|
5602
5756
|
},
|
|
5603
5757
|
render(width) {
|
|
5604
5758
|
if (!state) return [];
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5759
|
+
const renderFresh = () => {
|
|
5760
|
+
if (state.fallback) {
|
|
5761
|
+
return renderBoxedBashCall(
|
|
5762
|
+
theme,
|
|
5763
|
+
state.command.split("\n"),
|
|
5764
|
+
context,
|
|
5765
|
+
bashWidthKey(state.command, context?.args?.timeout)
|
|
5766
|
+
).render(width);
|
|
5767
|
+
}
|
|
5768
|
+
if (isBashTreeClass(state.cls)) {
|
|
5769
|
+
const treeState = { cls: state.cls };
|
|
5770
|
+
if (state.parsed !== void 0) treeState.parsed = state.parsed;
|
|
5771
|
+
return renderBashTreeLines(theme, treeState, width);
|
|
5772
|
+
}
|
|
5773
|
+
if (isGhClass(state.cls)) {
|
|
5774
|
+
const ghState = { cls: state.cls };
|
|
5775
|
+
if (state.parsed !== void 0) ghState.parsed = state.parsed;
|
|
5776
|
+
return renderGhCardLines(theme, ghState, width);
|
|
5777
|
+
}
|
|
5778
|
+
const gitState = { cls: state.cls };
|
|
5779
|
+
if (state.parsed !== void 0) gitState.parsed = state.parsed;
|
|
5780
|
+
return renderGitCardLines(theme, gitState, width);
|
|
5781
|
+
};
|
|
5782
|
+
if (!state.finished) return renderFresh();
|
|
5783
|
+
const cacheKey2 = [themeCacheKey(theme), getToolsRenderCacheSignature(), width, state.revision].join("|");
|
|
5784
|
+
if (state.renderCache?.key === cacheKey2) return state.renderCache.lines;
|
|
5785
|
+
const lines = renderFresh();
|
|
5786
|
+
state.renderCache = { key: cacheKey2, lines };
|
|
5787
|
+
return lines;
|
|
5626
5788
|
}
|
|
5627
5789
|
};
|
|
5628
5790
|
}
|
|
@@ -5631,7 +5793,27 @@ var bashTool = {
|
|
|
5631
5793
|
noteExecutionStart(context);
|
|
5632
5794
|
const cls = classifyBashSemantic(String(args?.command ?? ""));
|
|
5633
5795
|
if (cls) {
|
|
5634
|
-
|
|
5796
|
+
const command = String(args?.command ?? "");
|
|
5797
|
+
const existing = semanticStates.get(context.toolCallId);
|
|
5798
|
+
if (existing) {
|
|
5799
|
+
if (existing.command !== command || existing.cls.kind !== cls.kind) {
|
|
5800
|
+
delete existing.parsed;
|
|
5801
|
+
delete existing.fallback;
|
|
5802
|
+
existing.finished = false;
|
|
5803
|
+
existing.revision++;
|
|
5804
|
+
delete existing.renderCache;
|
|
5805
|
+
delete existing.lastParsedLength;
|
|
5806
|
+
}
|
|
5807
|
+
existing.command = command;
|
|
5808
|
+
existing.cls = cls;
|
|
5809
|
+
} else {
|
|
5810
|
+
semanticStates.set(context.toolCallId, {
|
|
5811
|
+
cls,
|
|
5812
|
+
command,
|
|
5813
|
+
finished: false,
|
|
5814
|
+
revision: 0
|
|
5815
|
+
});
|
|
5816
|
+
}
|
|
5635
5817
|
return renderSemanticPanel(theme, context.toolCallId, context);
|
|
5636
5818
|
}
|
|
5637
5819
|
noteBoxedCallState(context);
|
|
@@ -5649,15 +5831,24 @@ var bashTool = {
|
|
|
5649
5831
|
}
|
|
5650
5832
|
if (!options.isPartial || isBashTreeClass(cls)) {
|
|
5651
5833
|
const output = stripBashToolNoticeLines(stripAnsi(getTextOutput(result)));
|
|
5652
|
-
const parsed = parseSemanticOutput(cls, output);
|
|
5653
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;
|
|
5654
5837
|
if (parsed) {
|
|
5655
|
-
if (state)
|
|
5656
|
-
|
|
5838
|
+
if (state) {
|
|
5839
|
+
state.parsed = parsed;
|
|
5840
|
+
state.finished = !options.isPartial;
|
|
5841
|
+
state.revision++;
|
|
5842
|
+
delete state.renderCache;
|
|
5843
|
+
if (options.isPartial) state.lastParsedLength = output.length;
|
|
5844
|
+
} else
|
|
5657
5845
|
semanticStates.set(context.toolCallId, {
|
|
5658
5846
|
cls,
|
|
5659
5847
|
command: String(context?.args?.command ?? ""),
|
|
5660
|
-
parsed
|
|
5848
|
+
parsed,
|
|
5849
|
+
finished: !options.isPartial,
|
|
5850
|
+
revision: 0,
|
|
5851
|
+
...options.isPartial ? { lastParsedLength: output.length } : {}
|
|
5661
5852
|
});
|
|
5662
5853
|
if (isGitDiffClass(cls)) {
|
|
5663
5854
|
return renderGitDiffResult(theme, parsed, options, context);
|
|
@@ -5667,7 +5858,18 @@ var bashTool = {
|
|
|
5667
5858
|
}
|
|
5668
5859
|
return EMPTY_BASH_TREE_RESULT;
|
|
5669
5860
|
}
|
|
5670
|
-
if (
|
|
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
|
+
}
|
|
5872
|
+
}
|
|
5671
5873
|
}
|
|
5672
5874
|
} else if (options.isPartial) {
|
|
5673
5875
|
startElapsedTicker(context.state, context.invalidate);
|
|
@@ -5680,7 +5882,20 @@ var bashTool = {
|
|
|
5680
5882
|
if (firstResultPass) return EMPTY_BASH_RESULT;
|
|
5681
5883
|
return renderBashStreamingResult(theme, raw, options, context);
|
|
5682
5884
|
}
|
|
5683
|
-
return
|
|
5885
|
+
return memoizedStateComponent(
|
|
5886
|
+
context.state,
|
|
5887
|
+
"__piStyleBashFinalResult",
|
|
5888
|
+
getRenderCacheKey(
|
|
5889
|
+
"bash-final-result",
|
|
5890
|
+
theme,
|
|
5891
|
+
Boolean(options.expanded),
|
|
5892
|
+
Boolean(context.isError),
|
|
5893
|
+
String(context?.args?.command ?? ""),
|
|
5894
|
+
raw,
|
|
5895
|
+
getStateElapsedMs(context.state) ?? ""
|
|
5896
|
+
),
|
|
5897
|
+
() => renderBashFinalResult(theme, raw, options, context)
|
|
5898
|
+
);
|
|
5684
5899
|
}
|
|
5685
5900
|
};
|
|
5686
5901
|
|
|
@@ -5752,28 +5967,42 @@ var editTool = {
|
|
|
5752
5967
|
const message = firstText(result.content);
|
|
5753
5968
|
const argPath = String(context?.args?.path ?? context?.args?.file_path ?? "");
|
|
5754
5969
|
const sourcePath = details?.path ?? (argPath || extractEditedPath(message));
|
|
5755
|
-
const language = sourcePath ? getLanguageFromPath2(sourcePath) : void 0;
|
|
5756
|
-
const rows = buildSplitRows(diff);
|
|
5757
5970
|
const expanded = options.expanded;
|
|
5758
|
-
const shouldHighlight = Boolean(language) && diff.length <= MAX_HIGHLIGHT_DIFF_CHARS && rows.length <= MAX_HIGHLIGHT_DIFF_ROWS;
|
|
5759
5971
|
const stats = countDiffStats(diff);
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5972
|
+
return memoizedStateComponent(
|
|
5973
|
+
context.state,
|
|
5974
|
+
"__piStyleEditDiffResult",
|
|
5975
|
+
getRenderCacheKey(
|
|
5976
|
+
"edit-diff-result",
|
|
5977
|
+
theme,
|
|
5978
|
+
Boolean(expanded),
|
|
5979
|
+
diff,
|
|
5980
|
+
sourcePath ?? "",
|
|
5981
|
+
editDiffFooter(theme, result, context, stats)
|
|
5982
|
+
),
|
|
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
|
+
}
|
|
5999
|
+
},
|
|
6000
|
+
{
|
|
6001
|
+
dividerLabel: diffDividerLabel2(theme, stats),
|
|
6002
|
+
...expandHint2 ? { dividerRightLabel: expandHint2 } : {},
|
|
6003
|
+
footerLines: [editDiffFooter(theme, result, context, stats)]
|
|
6004
|
+
}
|
|
6005
|
+
);
|
|
5777
6006
|
}
|
|
5778
6007
|
);
|
|
5779
6008
|
}
|
|
@@ -5879,14 +6108,16 @@ var findTool = {
|
|
|
5879
6108
|
return renderBatchAwareCall(theme, batch);
|
|
5880
6109
|
},
|
|
5881
6110
|
result(result, options, _theme, context) {
|
|
5882
|
-
const
|
|
5883
|
-
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);
|
|
5884
6115
|
registerBatchResult(
|
|
5885
6116
|
FIND_META,
|
|
5886
6117
|
{
|
|
5887
6118
|
isPartial: Boolean(options.isPartial),
|
|
5888
|
-
isError
|
|
5889
|
-
errorText:
|
|
6119
|
+
isError,
|
|
6120
|
+
errorText: isError ? output || void 0 : void 0,
|
|
5890
6121
|
...entries !== void 0 ? { entries } : {}
|
|
5891
6122
|
},
|
|
5892
6123
|
context
|
|
@@ -5997,14 +6228,19 @@ var grepTool = {
|
|
|
5997
6228
|
return renderGrepPanel(theme, context.toolCallId);
|
|
5998
6229
|
},
|
|
5999
6230
|
result(result, options, _theme, context) {
|
|
6000
|
-
const output = stripAnsi(getTextOutput(result)).trimEnd();
|
|
6001
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();
|
|
6002
6238
|
const matches = isError ? [] : parseGrepOutput(output);
|
|
6003
6239
|
registerGrepResult(context.toolCallId, {
|
|
6004
6240
|
matches,
|
|
6005
6241
|
isError,
|
|
6006
6242
|
errorText: isError ? output || void 0 : void 0,
|
|
6007
|
-
isPartial
|
|
6243
|
+
isPartial
|
|
6008
6244
|
});
|
|
6009
6245
|
return EMPTY_GREP_RESULT;
|
|
6010
6246
|
}
|
|
@@ -6031,14 +6267,16 @@ var lsTool = {
|
|
|
6031
6267
|
return renderBatchAwareCall(theme, batch);
|
|
6032
6268
|
},
|
|
6033
6269
|
result(result, options, _theme, context) {
|
|
6034
|
-
const
|
|
6035
|
-
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);
|
|
6036
6274
|
registerBatchResult(
|
|
6037
6275
|
LIST_META,
|
|
6038
6276
|
{
|
|
6039
6277
|
isPartial: Boolean(options.isPartial),
|
|
6040
|
-
isError
|
|
6041
|
-
errorText:
|
|
6278
|
+
isError,
|
|
6279
|
+
errorText: isError ? output || void 0 : void 0,
|
|
6042
6280
|
...entries !== void 0 ? { entries } : {}
|
|
6043
6281
|
},
|
|
6044
6282
|
context
|
|
@@ -6162,29 +6400,44 @@ function renderQuickEditResult(_toolName, result, options, theme, context, confi
|
|
|
6162
6400
|
footerLines: [quickEditFooter(theme, context)]
|
|
6163
6401
|
});
|
|
6164
6402
|
}
|
|
6165
|
-
const rows = buildSplitRows(diff);
|
|
6166
6403
|
const expanded = options.expanded;
|
|
6167
6404
|
const argPath = String(context?.args?.path ?? "");
|
|
6168
|
-
const language = argPath ? getLanguageFromPath3(argPath) : void 0;
|
|
6169
|
-
const shouldHighlight = Boolean(language) && diff.length <= MAX_HIGHLIGHT_DIFF_CHARS2 && rows.length <= MAX_HIGHLIGHT_DIFF_ROWS2;
|
|
6170
6405
|
const stats = countDiffStats(diff);
|
|
6171
|
-
|
|
6172
|
-
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6406
|
+
return memoizedStateComponent(
|
|
6407
|
+
context.state,
|
|
6408
|
+
"__piStyleQuickEditDiffResult",
|
|
6409
|
+
getRenderCacheKey(
|
|
6410
|
+
"quick-edit-diff-result",
|
|
6411
|
+
theme,
|
|
6412
|
+
config.toolLabel,
|
|
6413
|
+
Boolean(expanded),
|
|
6414
|
+
diff,
|
|
6415
|
+
argPath,
|
|
6416
|
+
quickEditDiffFooter(theme, result, context, stats)
|
|
6417
|
+
),
|
|
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
|
+
}
|
|
6434
|
+
},
|
|
6435
|
+
{
|
|
6436
|
+
dividerLabel: quickEditDividerLabel(theme, stats),
|
|
6437
|
+
...expandHint2 ? { dividerRightLabel: expandHint2 } : {},
|
|
6438
|
+
footerLines: [quickEditDiffFooter(theme, result, context, stats)]
|
|
6439
|
+
}
|
|
6440
|
+
);
|
|
6188
6441
|
}
|
|
6189
6442
|
);
|
|
6190
6443
|
}
|
|
@@ -6231,13 +6484,13 @@ var readTool = {
|
|
|
6231
6484
|
return renderBatchAwareCall(theme, batch);
|
|
6232
6485
|
},
|
|
6233
6486
|
result(result, options, _theme, context) {
|
|
6234
|
-
const
|
|
6487
|
+
const errorText = context.isError ? stripAnsi(getTextOutput(result)).trimEnd() || void 0 : void 0;
|
|
6235
6488
|
registerBatchResult(
|
|
6236
6489
|
READ_META,
|
|
6237
6490
|
{
|
|
6238
6491
|
isPartial: Boolean(options.isPartial),
|
|
6239
6492
|
isError: Boolean(context.isError),
|
|
6240
|
-
errorText
|
|
6493
|
+
errorText
|
|
6241
6494
|
},
|
|
6242
6495
|
context
|
|
6243
6496
|
);
|
|
@@ -7941,11 +8194,10 @@ function createBuiltinSegments() {
|
|
|
7941
8194
|
content: snapshot.sessionStartedAt === void 0 ? "" : theme.apply("time", formatElapsed2(Date.now() - snapshot.sessionStartedAt)),
|
|
7942
8195
|
compactContent: snapshot.sessionStartedAt === void 0 ? "" : theme.apply("time", formatElapsed2(Date.now() - snapshot.sessionStartedAt))
|
|
7943
8196
|
})),
|
|
7944
|
-
segment("time", 20, ({ theme }) =>
|
|
7945
|
-
|
|
7946
|
-
|
|
7947
|
-
|
|
7948
|
-
})),
|
|
8197
|
+
segment("time", 20, ({ theme }) => {
|
|
8198
|
+
const text = theme.apply("time", clockTime());
|
|
8199
|
+
return { visible: true, content: text, compactContent: text };
|
|
8200
|
+
}),
|
|
7949
8201
|
segment("hostname", 20, ({ snapshot, theme }) => ({
|
|
7950
8202
|
visible: Boolean(snapshot.hostname),
|
|
7951
8203
|
content: theme.apply("muted", snapshot.hostname ?? "")
|
|
@@ -7963,6 +8215,15 @@ function createBuiltinSegments() {
|
|
|
7963
8215
|
];
|
|
7964
8216
|
return new Map(segments.map((item) => [item.id, item]));
|
|
7965
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
|
+
}
|
|
7966
8227
|
var CONTEXT_BAR_WIDTH = 10;
|
|
7967
8228
|
function contextBar(percent, width = CONTEXT_BAR_WIDTH) {
|
|
7968
8229
|
const filled = Math.max(0, Math.min(width, Math.round(percent / 100 * width)));
|
|
@@ -8148,7 +8409,24 @@ function colorPrefixFor(active, config, noColor, token) {
|
|
|
8148
8409
|
}
|
|
8149
8410
|
return "";
|
|
8150
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();
|
|
8151
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) {
|
|
8152
8430
|
if (env.PI_STYLE_NERD_FONTS === "1") return "nerd";
|
|
8153
8431
|
if (env.PI_STYLE_NERD_FONTS === "0") return "unicode";
|
|
8154
8432
|
if (config.theme.nerdFonts === "on") return "nerd";
|
|
@@ -8163,7 +8441,14 @@ function detectGlyphMode(config, env = {}) {
|
|
|
8163
8441
|
function resolveTheme(active, config, env = {}) {
|
|
8164
8442
|
const noColor = Object.hasOwn(env, "NO_COLOR") && env.NO_COLOR !== "" && config.theme.colors.colorOverride !== "on";
|
|
8165
8443
|
const mode = config.preset === "ascii" ? "ascii" : detectGlyphMode(config, env);
|
|
8166
|
-
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
|
+
};
|
|
8167
8452
|
return {
|
|
8168
8453
|
mode,
|
|
8169
8454
|
noColor,
|
|
@@ -8181,9 +8466,13 @@ function resolveTheme(active, config, env = {}) {
|
|
|
8181
8466
|
var widthOf = visibleWidth3;
|
|
8182
8467
|
function widthSafe(value, width) {
|
|
8183
8468
|
if (width <= 0) return "";
|
|
8184
|
-
const
|
|
8185
|
-
|
|
8186
|
-
|
|
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;
|
|
8187
8476
|
}
|
|
8188
8477
|
function isNativeBorderLine(line) {
|
|
8189
8478
|
const stripped = stripAnsi(line);
|
|
@@ -8253,7 +8542,10 @@ var StyledEditor = class extends CustomEditor {
|
|
|
8253
8542
|
fullTheme;
|
|
8254
8543
|
onSnapshot;
|
|
8255
8544
|
semantic;
|
|
8545
|
+
/** Set when config changes; invalidate() then rebuilds the (otherwise stable) semantic theme. */
|
|
8546
|
+
semanticDirty = false;
|
|
8256
8547
|
disposed = false;
|
|
8548
|
+
renderPlanCache;
|
|
8257
8549
|
constructor(tui, theme, keybindings, options) {
|
|
8258
8550
|
super(tui, theme, keybindings);
|
|
8259
8551
|
this.config = options.config;
|
|
@@ -8272,7 +8564,7 @@ var StyledEditor = class extends CustomEditor {
|
|
|
8272
8564
|
configure(config) {
|
|
8273
8565
|
if (this.disposed) return;
|
|
8274
8566
|
this.config = config;
|
|
8275
|
-
this.
|
|
8567
|
+
this.semanticDirty = true;
|
|
8276
8568
|
this.invalidate();
|
|
8277
8569
|
}
|
|
8278
8570
|
handleInput(data) {
|
|
@@ -8282,62 +8574,27 @@ var StyledEditor = class extends CustomEditor {
|
|
|
8282
8574
|
}
|
|
8283
8575
|
invalidate() {
|
|
8284
8576
|
super.invalidate();
|
|
8285
|
-
|
|
8577
|
+
if (this.semanticDirty) {
|
|
8578
|
+
this.semantic = semanticTheme(this.piTheme, this.config);
|
|
8579
|
+
this.semanticDirty = false;
|
|
8580
|
+
}
|
|
8581
|
+
this.renderPlanCache = void 0;
|
|
8286
8582
|
this.tui.requestRender();
|
|
8287
8583
|
}
|
|
8288
8584
|
render(width) {
|
|
8289
8585
|
if (width <= 0) return [];
|
|
8290
|
-
const
|
|
8291
|
-
const
|
|
8292
|
-
if (
|
|
8293
|
-
|
|
8294
|
-
|
|
8295
|
-
const promptWidth2 = widthOf(prompt2) + 1;
|
|
8296
|
-
const prefix2 = `${" ".repeat(padding2)}${prompt2} `;
|
|
8297
|
-
const continuation2 = " ".repeat(padding2 + promptWidth2);
|
|
8298
|
-
const borderIndex = nativeLines.slice(1).findIndex((line) => isNativeBorderLine(line));
|
|
8299
|
-
const split = borderIndex >= 0 ? borderIndex + 1 : nativeLines.length;
|
|
8300
|
-
const body2 = nativeLines.slice(1, split);
|
|
8301
|
-
const dropdown = nativeLines.slice(split);
|
|
8302
|
-
const border = this.borderFor();
|
|
8303
|
-
const kind2 = this.frameKind(style);
|
|
8304
|
-
const renderWidth2 = width - (kind2 === "rounded" ? 2 : 0);
|
|
8305
|
-
const sideColor = kind2 === "rounded" ? this.borderColorFor() : void 0;
|
|
8306
|
-
const wrap = (line) => kind2 === "rounded" && sideColor ? `${sideColor("\u2502")}${line}${sideColor("\u2502")}` : line;
|
|
8307
|
-
const bashHidden2 = this.bashHiddenCount();
|
|
8308
|
-
const renderedBody2 = body2.map((line, index) => {
|
|
8309
|
-
const source = index === 0 && bashHidden2 > 0 ? stripLeadingVisibleChars(line, bashHidden2) : line;
|
|
8310
|
-
return wrap(widthSafe(`${index === 0 ? prefix2 : continuation2}${source}`, renderWidth2));
|
|
8311
|
-
});
|
|
8312
|
-
const dropdownLines = dropdown.map((line) => wrap(widthSafe(line, renderWidth2)));
|
|
8313
|
-
if (kind2 === "rounded") {
|
|
8314
|
-
return [
|
|
8315
|
-
border(`\u256D${"\u2500".repeat(Math.max(0, width - 2))}\u256E`),
|
|
8316
|
-
...renderedBody2,
|
|
8317
|
-
...dropdownLines,
|
|
8318
|
-
border(`\u2570${"\u2500".repeat(Math.max(0, width - 2))}\u256F`)
|
|
8319
|
-
];
|
|
8320
|
-
}
|
|
8321
|
-
return [border("\u2500".repeat(width)), ...renderedBody2, ...dropdownLines, border("\u2500".repeat(width))];
|
|
8322
|
-
}
|
|
8323
|
-
if (style === "native") return nativeLines.map((line) => widthSafe(line, width));
|
|
8324
|
-
const prompt = this.prompt();
|
|
8325
|
-
const promptWidth = widthOf(prompt) + 1;
|
|
8326
|
-
const padding = this.paddingFor(width, style);
|
|
8327
|
-
const kind = this.frameKind(style);
|
|
8328
|
-
const sideReserve = kind === "rounded" ? 2 : 0;
|
|
8329
|
-
const renderWidth = Math.max(1, width - sideReserve);
|
|
8330
|
-
const innerWidth = Math.max(1, renderWidth - promptWidth - padding * 2);
|
|
8331
|
-
const innerLines = super.render(innerWidth);
|
|
8586
|
+
const plan = this.renderPlan(width);
|
|
8587
|
+
const autocompleteState = this.autocompleteState;
|
|
8588
|
+
if (plan.style === "native") return super.render(width).map((line) => widthSafe(line, width));
|
|
8589
|
+
if (autocompleteState) return this.renderAutocompleteFrame(width, plan);
|
|
8590
|
+
const innerLines = super.render(plan.innerWidth);
|
|
8332
8591
|
if (innerLines.length === 0) return [];
|
|
8333
8592
|
const body = innerLines.slice(1, -1);
|
|
8334
|
-
const prefix = `${" ".repeat(padding)}${prompt} `;
|
|
8335
|
-
const continuation = " ".repeat(padding + promptWidth);
|
|
8336
8593
|
const hint = this.config.editor.hint;
|
|
8337
8594
|
const showHint = hint !== "" && this.getText() === "";
|
|
8338
8595
|
const bashHidden = this.bashHiddenCount();
|
|
8339
8596
|
const renderedBody = body.map((line, index) => {
|
|
8340
|
-
const lead = index === 0 ? prefix : continuation;
|
|
8597
|
+
const lead = index === 0 ? plan.prefix : plan.continuation;
|
|
8341
8598
|
const source = index === 0 && bashHidden > 0 ? stripLeadingVisibleChars(line, bashHidden) : line;
|
|
8342
8599
|
let content = `${lead}${source}`;
|
|
8343
8600
|
if (showHint && index === 0 && line) {
|
|
@@ -8346,10 +8603,10 @@ var StyledEditor = class extends CustomEditor {
|
|
|
8346
8603
|
if (end < content.length) content = content.slice(0, end);
|
|
8347
8604
|
content += this.semantic.apply("hint", hint);
|
|
8348
8605
|
}
|
|
8349
|
-
return widthSafe(content, renderWidth);
|
|
8606
|
+
return widthSafe(content, plan.renderWidth);
|
|
8350
8607
|
});
|
|
8351
|
-
const metadata = this.metadata(width, style);
|
|
8352
|
-
const framed = this.frame(width, style, renderedBody, metadata);
|
|
8608
|
+
const metadata = this.metadata(width, plan.style);
|
|
8609
|
+
const framed = this.frame(width, plan.style, renderedBody, metadata);
|
|
8353
8610
|
return framed.map((line) => widthSafe(line, width));
|
|
8354
8611
|
}
|
|
8355
8612
|
dispose() {
|
|
@@ -8357,6 +8614,59 @@ var StyledEditor = class extends CustomEditor {
|
|
|
8357
8614
|
this.disposed = true;
|
|
8358
8615
|
this.invalidate();
|
|
8359
8616
|
}
|
|
8617
|
+
renderPlan(width) {
|
|
8618
|
+
const style = this.styleFor(width);
|
|
8619
|
+
const prompt = this.prompt();
|
|
8620
|
+
const kind = this.frameKind(style);
|
|
8621
|
+
const key = `${width}:${style}:${kind}:${prompt}`;
|
|
8622
|
+
if (this.renderPlanCache?.key === key) return this.renderPlanCache.plan;
|
|
8623
|
+
const promptWidth = widthOf(prompt) + 1;
|
|
8624
|
+
const padding = this.paddingFor(width, style);
|
|
8625
|
+
const sideReserve = kind === "rounded" ? 2 : 0;
|
|
8626
|
+
const renderWidth = Math.max(1, width - sideReserve);
|
|
8627
|
+
const innerWidth = Math.max(1, renderWidth - promptWidth - padding * 2);
|
|
8628
|
+
const prefix = `${" ".repeat(padding)}${prompt} `;
|
|
8629
|
+
const continuation = " ".repeat(padding + promptWidth);
|
|
8630
|
+
const plan = {
|
|
8631
|
+
style,
|
|
8632
|
+
kind,
|
|
8633
|
+
prompt,
|
|
8634
|
+
promptWidth,
|
|
8635
|
+
padding,
|
|
8636
|
+
sideReserve,
|
|
8637
|
+
renderWidth,
|
|
8638
|
+
innerWidth,
|
|
8639
|
+
prefix,
|
|
8640
|
+
continuation
|
|
8641
|
+
};
|
|
8642
|
+
this.renderPlanCache = { key, plan };
|
|
8643
|
+
return plan;
|
|
8644
|
+
}
|
|
8645
|
+
renderAutocompleteFrame(width, plan) {
|
|
8646
|
+
const nativeLines = super.render(width);
|
|
8647
|
+
const borderIndex = nativeLines.slice(1).findIndex((line) => isNativeBorderLine(line));
|
|
8648
|
+
const split = borderIndex >= 0 ? borderIndex + 1 : nativeLines.length;
|
|
8649
|
+
const body = nativeLines.slice(1, split);
|
|
8650
|
+
const dropdown = nativeLines.slice(split);
|
|
8651
|
+
const border = this.borderFor();
|
|
8652
|
+
const sideColor = plan.kind === "rounded" ? this.borderColorFor() : void 0;
|
|
8653
|
+
const wrap = (line) => plan.kind === "rounded" && sideColor ? `${sideColor("\u2502")}${line}${sideColor("\u2502")}` : line;
|
|
8654
|
+
const bashHidden = this.bashHiddenCount();
|
|
8655
|
+
const renderedBody = body.map((line, index) => {
|
|
8656
|
+
const source = index === 0 && bashHidden > 0 ? stripLeadingVisibleChars(line, bashHidden) : line;
|
|
8657
|
+
return wrap(widthSafe(`${index === 0 ? plan.prefix : plan.continuation}${source}`, plan.renderWidth));
|
|
8658
|
+
});
|
|
8659
|
+
const dropdownLines = dropdown.map((line) => wrap(widthSafe(line, plan.renderWidth)));
|
|
8660
|
+
if (plan.kind === "rounded") {
|
|
8661
|
+
return [
|
|
8662
|
+
border(`\u256D${"\u2500".repeat(Math.max(0, width - 2))}\u256E`),
|
|
8663
|
+
...renderedBody,
|
|
8664
|
+
...dropdownLines,
|
|
8665
|
+
border(`\u2570${"\u2500".repeat(Math.max(0, width - 2))}\u256F`)
|
|
8666
|
+
];
|
|
8667
|
+
}
|
|
8668
|
+
return [border("\u2500".repeat(width)), ...renderedBody, ...dropdownLines, border("\u2500".repeat(width))];
|
|
8669
|
+
}
|
|
8360
8670
|
prompt() {
|
|
8361
8671
|
if (this.isBashMode()) {
|
|
8362
8672
|
const glyph = this.semantic.glyph("bashPrompt");
|
|
@@ -8598,13 +8908,13 @@ function resolveAccentRgb(resolved) {
|
|
|
8598
8908
|
function styledLogoLines(resolved) {
|
|
8599
8909
|
const accent = resolveAccentRgb(resolved);
|
|
8600
8910
|
if (!accent) return [...PI_LOGO_LINES];
|
|
8601
|
-
const
|
|
8602
|
-
if (
|
|
8911
|
+
const cacheKey2 = `${resolved.color("accent")}|${resolved.mode}`;
|
|
8912
|
+
if (cacheKey2 === logoGradientCacheKey && logoGradientCacheLines) return logoGradientCacheLines;
|
|
8603
8913
|
const palette = buildLogoPalette(accent);
|
|
8604
8914
|
logoGradientCacheLines = PI_LOGO_LINES.map(
|
|
8605
8915
|
(line, rowIndex) => renderLogoGradientLine(line, palette, rowIndex * LOGO_ROW_PHASE_STEP)
|
|
8606
8916
|
);
|
|
8607
|
-
logoGradientCacheKey =
|
|
8917
|
+
logoGradientCacheKey = cacheKey2;
|
|
8608
8918
|
return logoGradientCacheLines;
|
|
8609
8919
|
}
|
|
8610
8920
|
function compactLogoHeader(resolved, details, width) {
|
|
@@ -9051,9 +9361,6 @@ function uniqueLayout(layout) {
|
|
|
9051
9361
|
function renderGroup(items, separator, padding) {
|
|
9052
9362
|
return items.map((item) => item.content).filter(Boolean).join(`${padding}${separator}${padding}`);
|
|
9053
9363
|
}
|
|
9054
|
-
function widthOf2(items, separator, padding) {
|
|
9055
|
-
return visibleWidth(renderGroup(items, separator, padding));
|
|
9056
|
-
}
|
|
9057
9364
|
function renderStatus(layout, snapshot, width, options) {
|
|
9058
9365
|
if (width <= 0) return { primary: "", lines: [], visibleSegments: [] };
|
|
9059
9366
|
const separator = options.separator ?? "\u2502";
|
|
@@ -9068,7 +9375,15 @@ function renderStatus(layout, snapshot, width, options) {
|
|
|
9068
9375
|
try {
|
|
9069
9376
|
const result = segment2.render(context);
|
|
9070
9377
|
if (!result.visible || !result.content) continue;
|
|
9071
|
-
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
|
+
});
|
|
9072
9387
|
} catch {
|
|
9073
9388
|
}
|
|
9074
9389
|
}
|
|
@@ -9078,13 +9393,28 @@ function renderStatus(layout, snapshot, width, options) {
|
|
|
9078
9393
|
const secondary = normalized.secondary.map((id) => candidates.get(id)).filter((candidate) => candidate !== void 0);
|
|
9079
9394
|
const visible = [];
|
|
9080
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;
|
|
9081
9400
|
for (const candidate of primary) {
|
|
9082
9401
|
visible.push(candidate);
|
|
9083
|
-
|
|
9402
|
+
const pushedWidth = widthAfter(groupWidth, groupCount, candidate);
|
|
9403
|
+
if (pushedWidth <= width) {
|
|
9404
|
+
groupWidth = pushedWidth;
|
|
9405
|
+
groupCount++;
|
|
9406
|
+
continue;
|
|
9407
|
+
}
|
|
9084
9408
|
if (candidate.result.compactContent && !candidate.compact) {
|
|
9085
9409
|
candidate.content = candidate.result.compactContent;
|
|
9086
9410
|
candidate.compact = true;
|
|
9087
|
-
|
|
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
|
+
}
|
|
9088
9418
|
}
|
|
9089
9419
|
visible.pop();
|
|
9090
9420
|
if (candidate.segment.overflow !== "drop" && candidate.segment.overflow !== "primary") {
|
|
@@ -9110,9 +9440,14 @@ function renderStatus(layout, snapshot, width, options) {
|
|
|
9110
9440
|
}
|
|
9111
9441
|
if (visibleWidth(primaryText) > width) primaryText = truncateAnsi(primaryText, width);
|
|
9112
9442
|
const secondaryVisible = [];
|
|
9443
|
+
let secondaryWidth = 0;
|
|
9444
|
+
let secondaryCount = 0;
|
|
9113
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;
|
|
9114
9448
|
secondaryVisible.push(candidate);
|
|
9115
|
-
|
|
9449
|
+
secondaryWidth = pushedWidth;
|
|
9450
|
+
secondaryCount++;
|
|
9116
9451
|
}
|
|
9117
9452
|
const secondaryText = renderGroup(secondaryVisible, separator, padding);
|
|
9118
9453
|
const lines = secondaryText ? [primaryText, secondaryText] : primaryText ? [primaryText] : [];
|
|
@@ -9165,6 +9500,28 @@ function separatorsFor(config, theme) {
|
|
|
9165
9500
|
if (style === "none") return " ";
|
|
9166
9501
|
return theme.apply("separator", style);
|
|
9167
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
|
+
}
|
|
9168
9525
|
function installStatusLine(options) {
|
|
9169
9526
|
const existing = installationMap(options.host).get(options.generation);
|
|
9170
9527
|
if (existing) return existing;
|
|
@@ -9197,16 +9554,9 @@ function installStatusLine(options) {
|
|
|
9197
9554
|
}
|
|
9198
9555
|
const render = (activeTheme, width, secondary) => {
|
|
9199
9556
|
if (width <= 0 || !config.enabled || !config.statusLine.enabled) return [];
|
|
9200
|
-
const resolved =
|
|
9201
|
-
activeTheme.colors || activeTheme.fg ? {
|
|
9202
|
-
...activeTheme.colors ? { colors: activeTheme.colors } : {},
|
|
9203
|
-
// Call through the theme instance so `this` binds correctly inside Pi's fg().
|
|
9204
|
-
...activeTheme.fg ? { fg: (color, text) => activeTheme.fg?.(color, text) ?? text } : {}
|
|
9205
|
-
} : void 0,
|
|
9206
|
-
config
|
|
9207
|
-
);
|
|
9557
|
+
const { resolved, separator } = themeAssetsFor(activeTheme, config);
|
|
9208
9558
|
const result = renderStatus(config.statusLine.layout, effectiveSnapshot(snapshot), width, {
|
|
9209
|
-
separator
|
|
9559
|
+
separator,
|
|
9210
9560
|
segments,
|
|
9211
9561
|
theme: resolved,
|
|
9212
9562
|
options: {
|
|
@@ -9287,12 +9637,16 @@ function installStatusLine(options) {
|
|
|
9287
9637
|
};
|
|
9288
9638
|
const factory = (secondary) => (tui, theme) => {
|
|
9289
9639
|
const currentTheme = theme;
|
|
9640
|
+
let renderCache;
|
|
9290
9641
|
const component = {
|
|
9291
9642
|
render(width) {
|
|
9643
|
+
if (renderCache?.width === width) return renderCache.lines;
|
|
9292
9644
|
const lines = render(currentTheme, width, secondary);
|
|
9645
|
+
renderCache = { width, lines };
|
|
9293
9646
|
return lines;
|
|
9294
9647
|
},
|
|
9295
9648
|
invalidate() {
|
|
9649
|
+
renderCache = void 0;
|
|
9296
9650
|
primaryComponent = secondary ? primaryComponent : component;
|
|
9297
9651
|
secondaryComponent = secondary ? component : secondaryComponent;
|
|
9298
9652
|
if (tui.requestRender) tui.requestRender();
|
|
@@ -9667,16 +10021,52 @@ var RenderScheduler = class {
|
|
|
9667
10021
|
|
|
9668
10022
|
// extension-src/pi-style/app/snapshot.ts
|
|
9669
10023
|
function createSnapshot(generation2, revision = 0, values = {}) {
|
|
9670
|
-
return Object.freeze({ generation: generation2, revision
|
|
10024
|
+
return Object.freeze({ ...values, generation: generation2, revision });
|
|
9671
10025
|
}
|
|
9672
10026
|
function replaceSnapshot(current, generation2, values) {
|
|
9673
10027
|
if (current.generation !== generation2) return current;
|
|
9674
|
-
return createSnapshot(generation2, current.revision + 1, values);
|
|
10028
|
+
return equalStatusSnapshot(current, values) ? current : createSnapshot(generation2, current.revision + 1, values);
|
|
10029
|
+
}
|
|
10030
|
+
function equalStatusSnapshot(current, next) {
|
|
10031
|
+
const currentEntries = Object.entries(current).filter(([key]) => key !== "generation" && key !== "revision");
|
|
10032
|
+
const nextEntries = Object.entries(next).filter(([key]) => key !== "generation" && key !== "revision");
|
|
10033
|
+
if (currentEntries.length !== nextEntries.length) return false;
|
|
10034
|
+
for (const [key, value] of nextEntries) {
|
|
10035
|
+
if (!hasOwn(current, key)) return false;
|
|
10036
|
+
if (!equalValue(current[key], value)) return false;
|
|
10037
|
+
}
|
|
10038
|
+
return true;
|
|
10039
|
+
}
|
|
10040
|
+
function equalValue(left, right) {
|
|
10041
|
+
if (Object.is(left, right)) return true;
|
|
10042
|
+
if (Array.isArray(left) && Array.isArray(right)) {
|
|
10043
|
+
if (left.length !== right.length) return false;
|
|
10044
|
+
for (let index = 0; index < left.length; index++) {
|
|
10045
|
+
if (!equalValue(left[index], right[index])) return false;
|
|
10046
|
+
}
|
|
10047
|
+
return true;
|
|
10048
|
+
}
|
|
10049
|
+
if (!isPlainRecord(left) || !isPlainRecord(right)) return false;
|
|
10050
|
+
const leftKeys = Object.keys(left);
|
|
10051
|
+
const rightKeys = Object.keys(right);
|
|
10052
|
+
if (leftKeys.length !== rightKeys.length) return false;
|
|
10053
|
+
for (const key of rightKeys) {
|
|
10054
|
+
if (!hasOwn(left, key)) return false;
|
|
10055
|
+
if (!equalValue(left[key], right[key])) return false;
|
|
10056
|
+
}
|
|
10057
|
+
return true;
|
|
10058
|
+
}
|
|
10059
|
+
function hasOwn(value, key) {
|
|
10060
|
+
return Object.hasOwn(value, key);
|
|
10061
|
+
}
|
|
10062
|
+
function isPlainRecord(value) {
|
|
10063
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9675
10064
|
}
|
|
9676
10065
|
|
|
9677
10066
|
// extension-src/pi-style/app/runtime.ts
|
|
9678
|
-
|
|
9679
|
-
|
|
10067
|
+
var GIT_INVALIDATE_DEBOUNCE_MS = 250;
|
|
10068
|
+
function createPiStyleRuntime(host, generation2, requestRender = host.requestRender ?? (() => {
|
|
10069
|
+
})) {
|
|
9680
10070
|
let disposed = false;
|
|
9681
10071
|
const extensionStatuses = () => {
|
|
9682
10072
|
if (!host.extensionStatusProvider) return void 0;
|
|
@@ -9687,13 +10077,23 @@ function createPiStyleRuntime(host, generation2, requestRender = () => {
|
|
|
9687
10077
|
return [];
|
|
9688
10078
|
}
|
|
9689
10079
|
};
|
|
10080
|
+
const contextSnapshot = () => {
|
|
10081
|
+
const usage = host.getContextUsage?.();
|
|
10082
|
+
if (!usage) return void 0;
|
|
10083
|
+
return {
|
|
10084
|
+
...usage.tokens !== null ? { currentTokens: usage.tokens } : {},
|
|
10085
|
+
windowTokens: usage.contextWindow,
|
|
10086
|
+
...usage.percent !== null ? { percent: usage.percent } : {}
|
|
10087
|
+
};
|
|
10088
|
+
};
|
|
9690
10089
|
let currentConfig = host.config;
|
|
9691
10090
|
const disposables = new DisposableStore();
|
|
9692
10091
|
const scheduler = new RenderScheduler({ requestRender }, generation2, () => !disposed);
|
|
9693
10092
|
const git = new CachedGitProvider(host.gitRunner);
|
|
10093
|
+
let pendingGitRefresh;
|
|
9694
10094
|
const contextProvider = new InMemoryContextProvider();
|
|
9695
10095
|
const usageProvider = new InMemoryUsageProvider();
|
|
9696
|
-
const
|
|
10096
|
+
const initialContext = contextSnapshot();
|
|
9697
10097
|
const initialStatuses = extensionStatuses();
|
|
9698
10098
|
const initialValues = {
|
|
9699
10099
|
...initialStatuses ? { extensionStatuses: initialStatuses } : {},
|
|
@@ -9702,13 +10102,7 @@ function createPiStyleRuntime(host, generation2, requestRender = () => {
|
|
|
9702
10102
|
...host.model?.reasoning !== void 0 ? { reasoning: host.model.reasoning } : {},
|
|
9703
10103
|
...host.thinkingLevel ? { thinkingLevel: normalizeThinkingLevel(host.thinkingLevel) } : {},
|
|
9704
10104
|
...host.cwd ? { cwd: host.cwd } : {},
|
|
9705
|
-
...
|
|
9706
|
-
context: {
|
|
9707
|
-
...usage.tokens !== null ? { currentTokens: usage.tokens } : {},
|
|
9708
|
-
windowTokens: usage.contextWindow,
|
|
9709
|
-
...usage.percent !== null ? { percent: usage.percent } : {}
|
|
9710
|
-
}
|
|
9711
|
-
} : {}
|
|
10105
|
+
...initialContext ? { context: initialContext } : {}
|
|
9712
10106
|
};
|
|
9713
10107
|
let currentSnapshot = createSnapshot(generation2, 0, initialValues);
|
|
9714
10108
|
let statusLine;
|
|
@@ -9719,14 +10113,35 @@ function createPiStyleRuntime(host, generation2, requestRender = () => {
|
|
|
9719
10113
|
editor: "disabled",
|
|
9720
10114
|
startup: "disabled"
|
|
9721
10115
|
};
|
|
9722
|
-
const
|
|
10116
|
+
const snapshotValues = (snapshot) => {
|
|
10117
|
+
const { generation: _generation, revision: _revision, ...values } = snapshot;
|
|
10118
|
+
return values;
|
|
10119
|
+
};
|
|
10120
|
+
const withSnapshotPatch = (patch) => {
|
|
10121
|
+
const next = { ...snapshotValues(currentSnapshot) };
|
|
10122
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
10123
|
+
if (value === void 0) delete next[key];
|
|
10124
|
+
else next[key] = value;
|
|
10125
|
+
}
|
|
10126
|
+
return next;
|
|
10127
|
+
};
|
|
10128
|
+
const createStartupSnapshot = (config, resources = host.resources) => ({
|
|
9723
10129
|
...currentSnapshot,
|
|
9724
10130
|
reason: host.startupReason ?? "startup",
|
|
9725
10131
|
...host.provider ? { startupProvider: host.provider } : {},
|
|
9726
10132
|
...host.cwd ? { project: host.cwd.split(/[\\/]/).filter(Boolean).at(-1) } : {},
|
|
9727
10133
|
preset: config.preset,
|
|
9728
|
-
...
|
|
10134
|
+
...resources ? { resources } : {}
|
|
9729
10135
|
});
|
|
10136
|
+
const applySnapshot = (nextSnapshot) => {
|
|
10137
|
+
if (nextSnapshot === currentSnapshot) return false;
|
|
10138
|
+
currentSnapshot = nextSnapshot;
|
|
10139
|
+
statusLine?.update(currentSnapshot);
|
|
10140
|
+
editor?.update(currentSnapshot);
|
|
10141
|
+
startup?.update(createStartupSnapshot(currentConfig));
|
|
10142
|
+
return true;
|
|
10143
|
+
};
|
|
10144
|
+
const updateSnapshot = (values) => applySnapshot(replaceSnapshot(currentSnapshot, generation2, values));
|
|
9730
10145
|
const installStatus = () => {
|
|
9731
10146
|
if (!host.hasUI || host.mode !== "tui" || !host.ui || !currentConfig.enabled || !currentConfig.statusLine.enabled) {
|
|
9732
10147
|
installationState = { ...installationState, status: "disabled" };
|
|
@@ -9789,7 +10204,7 @@ function createPiStyleRuntime(host, generation2, requestRender = () => {
|
|
|
9789
10204
|
startup = installStartup({
|
|
9790
10205
|
host: { ...host.ui, mode: host.mode, hasUI: host.hasUI },
|
|
9791
10206
|
config: currentConfig,
|
|
9792
|
-
snapshot:
|
|
10207
|
+
snapshot: createStartupSnapshot(currentConfig),
|
|
9793
10208
|
generation: generation2,
|
|
9794
10209
|
requestRender,
|
|
9795
10210
|
timeoutMs: 3e3,
|
|
@@ -9838,27 +10253,10 @@ function createPiStyleRuntime(host, generation2, requestRender = () => {
|
|
|
9838
10253
|
if (host.cwd && currentConfig.enabled && currentConfig.statusLine.enabled) {
|
|
9839
10254
|
void git.get(host.cwd).then((value) => {
|
|
9840
10255
|
if (disposed) return;
|
|
9841
|
-
|
|
9842
|
-
statusLine?.update(currentSnapshot);
|
|
9843
|
-
editor?.update(currentSnapshot);
|
|
9844
|
-
startup?.update({
|
|
9845
|
-
...currentSnapshot,
|
|
9846
|
-
reason: host.startupReason ?? "startup",
|
|
9847
|
-
...host.provider ? { startupProvider: host.provider } : {},
|
|
9848
|
-
...host.cwd ? { project: host.cwd.split(/[\\/]/).filter(Boolean).at(-1) } : {},
|
|
9849
|
-
preset: currentConfig.preset,
|
|
9850
|
-
...host.resources ? { resources: host.resources } : {}
|
|
9851
|
-
});
|
|
9852
|
-
requestRender();
|
|
9853
|
-
});
|
|
9854
|
-
}
|
|
9855
|
-
if (usage) {
|
|
9856
|
-
contextProvider.set("active", {
|
|
9857
|
-
...usage.tokens !== null ? { currentTokens: usage.tokens } : {},
|
|
9858
|
-
windowTokens: usage.contextWindow,
|
|
9859
|
-
...usage.percent !== null ? { percent: usage.percent } : {}
|
|
10256
|
+
if (updateSnapshot(withSnapshotPatch({ git: value }))) requestRender();
|
|
9860
10257
|
});
|
|
9861
10258
|
}
|
|
10259
|
+
if (initialContext) contextProvider.set("active", initialContext);
|
|
9862
10260
|
return {
|
|
9863
10261
|
generation: generation2,
|
|
9864
10262
|
providerIdentity: { git, context: contextProvider, usage: usageProvider },
|
|
@@ -9867,49 +10265,33 @@ function createPiStyleRuntime(host, generation2, requestRender = () => {
|
|
|
9867
10265
|
},
|
|
9868
10266
|
mode: host.mode,
|
|
9869
10267
|
hasUI: host.hasUI,
|
|
9870
|
-
snapshot
|
|
10268
|
+
get snapshot() {
|
|
10269
|
+
return currentSnapshot;
|
|
10270
|
+
},
|
|
9871
10271
|
disposables,
|
|
9872
10272
|
scheduler,
|
|
9873
10273
|
updateStartupResources(resources) {
|
|
9874
|
-
if (disposed) return;
|
|
9875
|
-
startup
|
|
9876
|
-
...currentSnapshot,
|
|
9877
|
-
reason: host.startupReason ?? "startup",
|
|
9878
|
-
...host.provider ? { startupProvider: host.provider } : {},
|
|
9879
|
-
...host.cwd ? { project: host.cwd.split(/[\\/]/).filter(Boolean).at(-1) } : {},
|
|
9880
|
-
preset: currentConfig.preset,
|
|
9881
|
-
resources
|
|
9882
|
-
});
|
|
10274
|
+
if (disposed || !startup) return false;
|
|
10275
|
+
startup.update(createStartupSnapshot(currentConfig, resources));
|
|
9883
10276
|
requestRender();
|
|
10277
|
+
return true;
|
|
9884
10278
|
},
|
|
9885
10279
|
dismissStartup() {
|
|
9886
10280
|
startup?.dismiss();
|
|
9887
10281
|
},
|
|
9888
|
-
update(values) {
|
|
9889
|
-
if (disposed) return;
|
|
9890
|
-
const
|
|
9891
|
-
|
|
9892
|
-
|
|
9893
|
-
|
|
9894
|
-
|
|
9895
|
-
|
|
9896
|
-
|
|
9897
|
-
|
|
9898
|
-
|
|
9899
|
-
|
|
9900
|
-
|
|
9901
|
-
...statuses ? { extensionStatuses: statuses } : {}
|
|
9902
|
-
});
|
|
9903
|
-
statusLine?.update(currentSnapshot);
|
|
9904
|
-
editor?.update(currentSnapshot);
|
|
9905
|
-
startup?.update({
|
|
9906
|
-
...currentSnapshot,
|
|
9907
|
-
reason: host.startupReason ?? "startup",
|
|
9908
|
-
...host.provider ? { startupProvider: host.provider } : {},
|
|
9909
|
-
...host.cwd ? { project: host.cwd.split(/[\\/]/).filter(Boolean).at(-1) } : {},
|
|
9910
|
-
preset: currentConfig.preset,
|
|
9911
|
-
...host.resources ? { resources: host.resources } : {}
|
|
9912
|
-
});
|
|
10282
|
+
update(values, options = {}) {
|
|
10283
|
+
if (disposed) return false;
|
|
10284
|
+
const patch = {
|
|
10285
|
+
...values
|
|
10286
|
+
};
|
|
10287
|
+
if (options.refreshContextUsage) {
|
|
10288
|
+
const context = contextSnapshot();
|
|
10289
|
+
patch.context = context;
|
|
10290
|
+
if (context) contextProvider.set("active", context);
|
|
10291
|
+
else contextProvider.clear();
|
|
10292
|
+
}
|
|
10293
|
+
if (options.refreshExtensionStatuses) patch.extensionStatuses = extensionStatuses();
|
|
10294
|
+
return updateSnapshot(withSnapshotPatch(patch));
|
|
9913
10295
|
},
|
|
9914
10296
|
configure(nextConfig) {
|
|
9915
10297
|
if (disposed) return;
|
|
@@ -9941,21 +10323,18 @@ function createPiStyleRuntime(host, generation2, requestRender = () => {
|
|
|
9941
10323
|
},
|
|
9942
10324
|
invalidateGit() {
|
|
9943
10325
|
if (disposed || !host.cwd || !currentConfig.enabled || !currentConfig.statusLine.enabled) return;
|
|
9944
|
-
|
|
9945
|
-
|
|
10326
|
+
const cwd = host.cwd;
|
|
10327
|
+
git.invalidate(cwd);
|
|
10328
|
+
if (pendingGitRefresh !== void 0) return;
|
|
10329
|
+
pendingGitRefresh = setTimeout(() => {
|
|
10330
|
+
pendingGitRefresh = void 0;
|
|
9946
10331
|
if (disposed) return;
|
|
9947
|
-
|
|
9948
|
-
|
|
9949
|
-
|
|
9950
|
-
startup?.update({
|
|
9951
|
-
...currentSnapshot,
|
|
9952
|
-
reason: host.startupReason ?? "startup",
|
|
9953
|
-
...host.provider ? { startupProvider: host.provider } : {},
|
|
9954
|
-
...host.cwd ? { project: host.cwd.split(/[\\/]/).filter(Boolean).at(-1) } : {},
|
|
9955
|
-
preset: currentConfig.preset
|
|
10332
|
+
void git.get(cwd).then((value) => {
|
|
10333
|
+
if (disposed) return;
|
|
10334
|
+
if (updateSnapshot(withSnapshotPatch({ git: value }))) requestRender();
|
|
9956
10335
|
});
|
|
9957
|
-
|
|
9958
|
-
|
|
10336
|
+
}, GIT_INVALIDATE_DEBOUNCE_MS);
|
|
10337
|
+
pendingGitRefresh.unref?.();
|
|
9959
10338
|
},
|
|
9960
10339
|
get disposed() {
|
|
9961
10340
|
return disposed;
|
|
@@ -9963,6 +10342,10 @@ function createPiStyleRuntime(host, generation2, requestRender = () => {
|
|
|
9963
10342
|
dispose() {
|
|
9964
10343
|
if (disposed) return;
|
|
9965
10344
|
disposed = true;
|
|
10345
|
+
if (pendingGitRefresh !== void 0) {
|
|
10346
|
+
clearTimeout(pendingGitRefresh);
|
|
10347
|
+
pendingGitRefresh = void 0;
|
|
10348
|
+
}
|
|
9966
10349
|
scheduler.cancel();
|
|
9967
10350
|
disposeStatus();
|
|
9968
10351
|
disposeEditor();
|
|
@@ -10158,10 +10541,10 @@ function createPiStyleApp(initialConfig, reloadPort, onConfigChange) {
|
|
|
10158
10541
|
sessionShutdown() {
|
|
10159
10542
|
runtime.stop();
|
|
10160
10543
|
},
|
|
10161
|
-
update(values, kind = "coalesced") {
|
|
10544
|
+
update(values, kind = "coalesced", options) {
|
|
10162
10545
|
const active = runtime.current;
|
|
10163
10546
|
if (!active) return;
|
|
10164
|
-
active.update(values);
|
|
10547
|
+
if (!active.update(values, options)) return;
|
|
10165
10548
|
active.scheduler.schedule(kind);
|
|
10166
10549
|
},
|
|
10167
10550
|
reload() {
|
|
@@ -10464,9 +10847,11 @@ function renderBashExecutionBox(instance, args) {
|
|
|
10464
10847
|
try {
|
|
10465
10848
|
if (host.piStyleStart === void 0) host.piStyleStart = Date.now();
|
|
10466
10849
|
const renderedWidth = boxWidth(width);
|
|
10850
|
+
const cacheKey2 = `${themeCacheKey(theme)}|${width}|${host.status}|${host.exitCode ?? ""}|${host.command}`;
|
|
10851
|
+
if (host.status !== "running" && host.piStyleRenderCache?.key === cacheKey2) return host.piStyleRenderCache.lines;
|
|
10467
10852
|
const inner = boxInnerWidth(renderedWidth);
|
|
10468
10853
|
const wrapped = content.render(inner).map((line) => boxLine(theme, line.startsWith(" ") ? line.slice(1) : line, renderedWidth));
|
|
10469
|
-
|
|
10854
|
+
const lines = [
|
|
10470
10855
|
"",
|
|
10471
10856
|
boxLabeledBorder(theme, TOP_LEFT, TOP_RIGHT, bashBoxTitle(theme, host), void 0, renderedWidth),
|
|
10472
10857
|
boxBlankLine(theme, renderedWidth),
|
|
@@ -10474,6 +10859,8 @@ function renderBashExecutionBox(instance, args) {
|
|
|
10474
10859
|
boxBlankLine(theme, renderedWidth),
|
|
10475
10860
|
boxLabeledBorder(theme, BOTTOM_LEFT, BOTTOM_RIGHT, bashBoxFooter(theme, host), void 0, renderedWidth)
|
|
10476
10861
|
];
|
|
10862
|
+
if (host.status !== "running") host.piStyleRenderCache = { key: cacheKey2, lines };
|
|
10863
|
+
return lines;
|
|
10477
10864
|
} catch {
|
|
10478
10865
|
return void 0;
|
|
10479
10866
|
}
|
|
@@ -10504,17 +10891,29 @@ import {
|
|
|
10504
10891
|
} from "@earendil-works/pi-coding-agent";
|
|
10505
10892
|
|
|
10506
10893
|
// extension-src/pi-style/features/messages/index.ts
|
|
10507
|
-
import { visibleWidth as visibleWidth4 } from "@earendil-works/pi-tui";
|
|
10508
10894
|
var OSC133_ZONE_START = "\x1B]133;A\x07";
|
|
10509
10895
|
var OSC133_ZONE_END = "\x1B]133;B\x07";
|
|
10510
10896
|
var OSC133_ZONE_FINAL = "\x1B]133;C\x07";
|
|
10897
|
+
var BG_RESET = "\x1B[49m";
|
|
10898
|
+
var MAX_RENDER_CACHE_KEYS_PER_INSTANCE = 8;
|
|
10899
|
+
var MAX_LINE_ANALYSIS_ENTRIES = 4096;
|
|
10900
|
+
var renderCacheByInstance = /* @__PURE__ */ new WeakMap();
|
|
10901
|
+
var lineAnalysisCache = /* @__PURE__ */ new Map();
|
|
10902
|
+
var lineCacheEvictionCursor;
|
|
10903
|
+
var childrenScanByInstance = /* @__PURE__ */ new WeakMap();
|
|
10904
|
+
var messageDecorationTestState = {
|
|
10905
|
+
decoratePasses: 0,
|
|
10906
|
+
cacheHits: 0,
|
|
10907
|
+
cacheMisses: 0,
|
|
10908
|
+
lineCacheHits: 0,
|
|
10909
|
+
lineCacheMisses: 0
|
|
10910
|
+
};
|
|
10511
10911
|
function extractOscEnvelope(line) {
|
|
10512
10912
|
if (!line.startsWith(OSC133_ZONE_START)) return void 0;
|
|
10513
10913
|
const bodyEnd = line.indexOf(OSC133_ZONE_END, OSC133_ZONE_START.length);
|
|
10514
10914
|
if (bodyEnd < 0 || !line.endsWith(OSC133_ZONE_FINAL)) return void 0;
|
|
10515
10915
|
return { start: OSC133_ZONE_START, body: line.slice(OSC133_ZONE_START.length, bodyEnd), end: line.slice(bodyEnd) };
|
|
10516
10916
|
}
|
|
10517
|
-
var BG_RESET = "\x1B[49m";
|
|
10518
10917
|
function splitLeadingMarkers(line) {
|
|
10519
10918
|
let index = 0;
|
|
10520
10919
|
while (line.startsWith("\x1B]", index)) {
|
|
@@ -10524,7 +10923,7 @@ function splitLeadingMarkers(line) {
|
|
|
10524
10923
|
if (end === -1) break;
|
|
10525
10924
|
index = end + 1;
|
|
10526
10925
|
}
|
|
10527
|
-
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) };
|
|
10528
10927
|
}
|
|
10529
10928
|
function leadingSgr(line) {
|
|
10530
10929
|
if (!line.startsWith("\x1B[")) return "";
|
|
@@ -10538,96 +10937,304 @@ function leadingSgr(line) {
|
|
|
10538
10937
|
}
|
|
10539
10938
|
function isBackgroundSgr(sequence) {
|
|
10540
10939
|
if (!sequence.startsWith("\x1B[") || !sequence.endsWith("m")) return false;
|
|
10541
|
-
|
|
10542
|
-
|
|
10543
|
-
|
|
10544
|
-
|
|
10545
|
-
|
|
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;
|
|
10958
|
+
}
|
|
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;
|
|
11025
|
+
}
|
|
11026
|
+
function contentText(line) {
|
|
11027
|
+
if (!line.includes("\x1B")) return line;
|
|
11028
|
+
let output = "";
|
|
11029
|
+
let sliceStart = 0;
|
|
11030
|
+
for (let index = 0; index < line.length; index++) {
|
|
11031
|
+
if (line.charCodeAt(index) !== 27) continue;
|
|
11032
|
+
output += line.slice(sliceStart, index);
|
|
11033
|
+
const next = line[index + 1];
|
|
11034
|
+
if (next === "]") {
|
|
11035
|
+
index += 2;
|
|
11036
|
+
while (index < line.length && line.charCodeAt(index) !== 7) index++;
|
|
11037
|
+
} else if (next === "[") {
|
|
11038
|
+
index += 2;
|
|
11039
|
+
while (index < line.length && (line.charCodeAt(index) < 64 || line.charCodeAt(index) > 126)) index++;
|
|
11040
|
+
}
|
|
11041
|
+
sliceStart = index + 1;
|
|
11042
|
+
}
|
|
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;
|
|
11053
|
+
}
|
|
11054
|
+
function hasContent(line) {
|
|
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++;
|
|
10546
11078
|
}
|
|
10547
11079
|
return false;
|
|
10548
11080
|
}
|
|
10549
|
-
function
|
|
10550
|
-
const
|
|
10551
|
-
|
|
10552
|
-
|
|
10553
|
-
|
|
10554
|
-
|
|
10555
|
-
return
|
|
10556
|
-
}
|
|
10557
|
-
|
|
10558
|
-
|
|
10559
|
-
|
|
10560
|
-
|
|
10561
|
-
const
|
|
10562
|
-
const
|
|
10563
|
-
const
|
|
11081
|
+
function getLineAnalysis(line) {
|
|
11082
|
+
const cached = lineAnalysisCache.get(line);
|
|
11083
|
+
if (cached) {
|
|
11084
|
+
messageDecorationTestState.lineCacheHits++;
|
|
11085
|
+
lineAnalysisCache.delete(line);
|
|
11086
|
+
lineAnalysisCache.set(line, cached);
|
|
11087
|
+
return cached;
|
|
11088
|
+
}
|
|
11089
|
+
messageDecorationTestState.lineCacheMisses++;
|
|
11090
|
+
const leadingMarkers = splitLeadingMarkers(line);
|
|
11091
|
+
const backgroundAnsi = leadingSgr(leadingMarkers.rest);
|
|
11092
|
+
const isBackgroundWrapped = backgroundAnsi !== "" && isBackgroundSgr(backgroundAnsi) && leadingMarkers.rest.endsWith(BG_RESET);
|
|
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);
|
|
11095
|
+
const analysis = {
|
|
11096
|
+
visibleWidth: certifiedVisibleWidth(line),
|
|
11097
|
+
hasContent: hasContent(line),
|
|
11098
|
+
oscEnvelope: hasOscStart ? extractOscEnvelope(line) : void 0,
|
|
11099
|
+
hasOscStart,
|
|
11100
|
+
leadingMarkers,
|
|
11101
|
+
isBackgroundWrapped,
|
|
11102
|
+
backgroundAnsi,
|
|
11103
|
+
backgroundBody,
|
|
11104
|
+
backgroundBodyWidth: backgroundBody === void 0 ? void 0 : certifiedVisibleWidth(backgroundBody)
|
|
11105
|
+
};
|
|
11106
|
+
lineAnalysisCache.set(line, analysis);
|
|
11107
|
+
if (lineAnalysisCache.size > MAX_LINE_ANALYSIS_ENTRIES) {
|
|
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);
|
|
11117
|
+
}
|
|
11118
|
+
return analysis;
|
|
11119
|
+
}
|
|
11120
|
+
function rebuildAtWidth(line, width, lead, leadWidth, analysis = getLineAnalysis(line)) {
|
|
11121
|
+
if (analysis.isBackgroundWrapped && analysis.backgroundBody !== void 0 && analysis.backgroundBodyWidth !== void 0) {
|
|
11122
|
+
const pad2 = " ".repeat(Math.max(0, width - leadWidth - analysis.backgroundBodyWidth));
|
|
11123
|
+
return `${analysis.leadingMarkers.head}${analysis.backgroundAnsi}${lead}${analysis.backgroundBody}${pad2}${BG_RESET}`;
|
|
11124
|
+
}
|
|
11125
|
+
const pad = " ".repeat(Math.max(0, width - leadWidth - analysis.visibleWidth));
|
|
11126
|
+
return `${lead}${line}${pad}`;
|
|
11127
|
+
}
|
|
11128
|
+
function decorateMessageLine(line, index, lastIndex, contentIndex, width, options, analysis = getLineAnalysis(line)) {
|
|
11129
|
+
const { firstEnvelope, firstHasStart, multilineEnvelope, prefix, prefixWidth, continuationLead } = options;
|
|
11130
|
+
const lead = index === contentIndex ? prefix : index > contentIndex ? continuationLead : "";
|
|
11131
|
+
const leadWidth = index < contentIndex ? 0 : prefixWidth;
|
|
10564
11132
|
if (index === contentIndex && firstEnvelope)
|
|
10565
|
-
return `${firstEnvelope.start}${rebuildAtWidth(firstEnvelope.body, width, prefix)}${firstEnvelope.end}`;
|
|
11133
|
+
return `${firstEnvelope.start}${rebuildAtWidth(firstEnvelope.body, width, prefix, prefixWidth)}${firstEnvelope.end}`;
|
|
10566
11134
|
if (index === contentIndex && firstHasStart)
|
|
10567
|
-
return `${OSC133_ZONE_START}${rebuildAtWidth(line.slice(OSC133_ZONE_START.length), width, prefix)}`;
|
|
11135
|
+
return `${OSC133_ZONE_START}${rebuildAtWidth(line.slice(OSC133_ZONE_START.length), width, prefix, prefixWidth)}`;
|
|
10568
11136
|
if (index === lastIndex && multilineEnvelope && index !== contentIndex)
|
|
10569
11137
|
return `${OSC133_ZONE_END}${OSC133_ZONE_FINAL}${rebuildAtWidth(
|
|
10570
11138
|
line.slice((OSC133_ZONE_END + OSC133_ZONE_FINAL).length),
|
|
10571
11139
|
width,
|
|
10572
|
-
lead
|
|
11140
|
+
lead,
|
|
11141
|
+
leadWidth
|
|
10573
11142
|
)}`;
|
|
10574
11143
|
if (index === contentIndex && index === lastIndex && multilineEnvelope && line.startsWith(OSC133_ZONE_END + OSC133_ZONE_FINAL))
|
|
10575
11144
|
return `${OSC133_ZONE_END}${OSC133_ZONE_FINAL}${rebuildAtWidth(
|
|
10576
11145
|
line.slice((OSC133_ZONE_END + OSC133_ZONE_FINAL).length),
|
|
10577
11146
|
width,
|
|
10578
|
-
prefix
|
|
11147
|
+
prefix,
|
|
11148
|
+
prefixWidth
|
|
10579
11149
|
)}`;
|
|
10580
|
-
return rebuildAtWidth(line, width, lead);
|
|
11150
|
+
return rebuildAtWidth(line, width, lead, leadWidth, analysis);
|
|
10581
11151
|
}
|
|
10582
|
-
function
|
|
10583
|
-
|
|
10584
|
-
|
|
10585
|
-
|
|
10586
|
-
|
|
10587
|
-
continue;
|
|
10588
|
-
}
|
|
10589
|
-
const next = line[index + 1];
|
|
10590
|
-
if (next === "]") {
|
|
10591
|
-
index += 2;
|
|
10592
|
-
while (index < line.length && line.charCodeAt(index) !== 7) index++;
|
|
10593
|
-
continue;
|
|
10594
|
-
}
|
|
10595
|
-
if (next === "[") {
|
|
10596
|
-
index += 2;
|
|
10597
|
-
while (index < line.length && (line.charCodeAt(index) < 64 || line.charCodeAt(index) > 126)) index++;
|
|
10598
|
-
}
|
|
11152
|
+
function sameLines(left, right) {
|
|
11153
|
+
if (left === right) return true;
|
|
11154
|
+
if (left.length !== right.length) return false;
|
|
11155
|
+
for (let index = 0; index < left.length; index++) {
|
|
11156
|
+
if (left[index] !== right[index]) return false;
|
|
10599
11157
|
}
|
|
10600
|
-
return
|
|
11158
|
+
return true;
|
|
10601
11159
|
}
|
|
10602
|
-
function
|
|
10603
|
-
return
|
|
11160
|
+
function cacheKey(width, prefix) {
|
|
11161
|
+
return `${width}\0${prefix}`;
|
|
11162
|
+
}
|
|
11163
|
+
function getRenderCache(instance) {
|
|
11164
|
+
let cache = renderCacheByInstance.get(instance);
|
|
11165
|
+
if (!cache) {
|
|
11166
|
+
cache = /* @__PURE__ */ new Map();
|
|
11167
|
+
renderCacheByInstance.set(instance, cache);
|
|
11168
|
+
}
|
|
11169
|
+
return cache;
|
|
11170
|
+
}
|
|
11171
|
+
function storeRenderCache(instance, width, prefix, native, result) {
|
|
11172
|
+
const cache = getRenderCache(instance);
|
|
11173
|
+
const key = cacheKey(width, prefix);
|
|
11174
|
+
if (cache.has(key)) cache.delete(key);
|
|
11175
|
+
cache.set(key, { nativeRef: native, nativeLines: [...native], result: [...result] });
|
|
11176
|
+
while (cache.size > MAX_RENDER_CACHE_KEYS_PER_INSTANCE) {
|
|
11177
|
+
const oldestKey = cache.keys().next().value;
|
|
11178
|
+
if (oldestKey === void 0) break;
|
|
11179
|
+
cache.delete(oldestKey);
|
|
11180
|
+
}
|
|
10604
11181
|
}
|
|
10605
11182
|
function prefixNative(lines, width, prefix) {
|
|
10606
11183
|
if (!Array.isArray(lines) || lines.length === 0 || !lines.every((line) => typeof line === "string")) return void 0;
|
|
11184
|
+
messageDecorationTestState.decoratePasses++;
|
|
10607
11185
|
const nativeLines = lines;
|
|
10608
|
-
const prefixWidth =
|
|
11186
|
+
const prefixWidth = prefixWidthOf(prefix);
|
|
10609
11187
|
if (width <= prefixWidth) return void 0;
|
|
10610
11188
|
const bodyWidth = width - prefixWidth;
|
|
10611
|
-
const
|
|
11189
|
+
const analyses = nativeLines.map((line) => getLineAnalysis(line));
|
|
10612
11190
|
const last = nativeLines.at(-1) ?? "";
|
|
11191
|
+
const lastAnalysis = analyses[analyses.length - 1] ?? getLineAnalysis(last);
|
|
10613
11192
|
const multilineEnvelope = nativeLines.length > 1 && last.startsWith(OSC133_ZONE_END + OSC133_ZONE_FINAL);
|
|
10614
|
-
|
|
10615
|
-
|
|
10616
|
-
|
|
10617
|
-
|
|
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
|
+
}
|
|
10618
11213
|
if (firstContentIndex < 0) return nativeLines;
|
|
10619
|
-
const
|
|
10620
|
-
const
|
|
11214
|
+
const firstAnalysis = analyses[0] ?? getLineAnalysis(nativeLines[0] ?? "");
|
|
11215
|
+
const firstEnvelope = firstContentIndex === 0 ? firstAnalysis.oscEnvelope : void 0;
|
|
11216
|
+
const firstHasStart = firstContentIndex === 0 && firstAnalysis.hasOscStart;
|
|
11217
|
+
const continuationLead = " ".repeat(prefixWidth);
|
|
10621
11218
|
const decorated = nativeLines.map(
|
|
10622
|
-
(line, index) => decorateMessageLine(
|
|
10623
|
-
|
|
10624
|
-
|
|
10625
|
-
|
|
10626
|
-
|
|
10627
|
-
|
|
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
|
+
)
|
|
10628
11235
|
);
|
|
10629
|
-
if (!decorated.every((line) =>
|
|
10630
|
-
if (!
|
|
11236
|
+
if (!decorated.every((line) => certifiedVisibleWidth(line) <= width)) return void 0;
|
|
11237
|
+
if (!analyses.every((analysis) => analysis.visibleWidth <= bodyWidth)) return void 0;
|
|
10631
11238
|
return decorated;
|
|
10632
11239
|
}
|
|
10633
11240
|
function decorateMessageRender(original, instance, args, snapshot = {
|
|
@@ -10640,10 +11247,20 @@ function decorateMessageRender(original, instance, args, snapshot = {
|
|
|
10640
11247
|
const width = typeof args[0] === "number" ? args[0] : 0;
|
|
10641
11248
|
const prefix = snapshot.assistantPrefix;
|
|
10642
11249
|
if (!snapshot.assistantEnabled) return Reflect.apply(original, instance, args);
|
|
10643
|
-
|
|
10644
|
-
|
|
11250
|
+
const prefixWidth = prefixWidthOf(prefix);
|
|
11251
|
+
if (width <= prefixWidth) return Reflect.apply(original, instance, args);
|
|
11252
|
+
const reducedWidth = width - prefixWidth;
|
|
10645
11253
|
const native = Reflect.apply(original, instance, [reducedWidth, ...args.slice(1)]);
|
|
10646
|
-
|
|
11254
|
+
if (!Array.isArray(native) || !native.every((line) => typeof line === "string")) return native;
|
|
11255
|
+
const cached = getRenderCache(instance).get(cacheKey(width, prefix));
|
|
11256
|
+
if (cached && (cached.nativeRef === native || sameLines(cached.nativeLines, native))) {
|
|
11257
|
+
messageDecorationTestState.cacheHits++;
|
|
11258
|
+
return [...cached.result];
|
|
11259
|
+
}
|
|
11260
|
+
messageDecorationTestState.cacheMisses++;
|
|
11261
|
+
const decorated = prefixNative(native, width, prefix) ?? native;
|
|
11262
|
+
storeRenderCache(instance, width, prefix, native, decorated);
|
|
11263
|
+
return decorated;
|
|
10647
11264
|
}
|
|
10648
11265
|
function isSpacerChild(child) {
|
|
10649
11266
|
return typeof child?.setLines === "function";
|
|
@@ -10662,8 +11279,16 @@ function hasToolCallItems(message) {
|
|
|
10662
11279
|
function isBlankTextChild(child) {
|
|
10663
11280
|
const candidate = child;
|
|
10664
11281
|
if (typeof candidate?.setCustomBgFn !== "function" || typeof candidate.render !== "function") return false;
|
|
11282
|
+
if (typeof candidate.text === "string") return contentText(candidate.text).trim() === "";
|
|
10665
11283
|
return contentText(candidate.render(0).join("\n")).trim() === "";
|
|
10666
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
|
+
}
|
|
10667
11292
|
function decorateMessageUpdate(original, instance, args, snapshot = {
|
|
10668
11293
|
assistantPrefix: "\u2502 ",
|
|
10669
11294
|
assistantEnabled: true,
|
|
@@ -10673,24 +11298,22 @@ function decorateMessageUpdate(original, instance, args, snapshot = {
|
|
|
10673
11298
|
if (typeof original !== "function") return void 0;
|
|
10674
11299
|
const result = Reflect.apply(original, instance, args);
|
|
10675
11300
|
const target = instance;
|
|
10676
|
-
|
|
10677
|
-
|
|
10678
|
-
if (
|
|
11301
|
+
const children = target.contentContainer?.children;
|
|
11302
|
+
if (children && !childrenUnchangedSinceScan(instance, children)) {
|
|
11303
|
+
if (snapshot.collapseHiddenThinking && target.hideThinkingBlock === true && target.hiddenThinkingLabel === "") {
|
|
10679
11304
|
for (let index = children.length - 1; index >= 0; index--) {
|
|
10680
11305
|
if (!isBlankTextChild(children[index])) continue;
|
|
10681
11306
|
children.splice(index, 1);
|
|
10682
11307
|
if (isSpacerChild(children[index])) children.splice(index, 1);
|
|
10683
11308
|
}
|
|
10684
11309
|
}
|
|
10685
|
-
|
|
10686
|
-
if (snapshot.hideInterimText && hasToolCallItems(args[0])) {
|
|
10687
|
-
const children = target.contentContainer?.children;
|
|
10688
|
-
if (children) {
|
|
11310
|
+
if (snapshot.hideInterimText && hasToolCallItems(args[0])) {
|
|
10689
11311
|
for (let index = children.length - 1; index >= 0; index--) {
|
|
10690
11312
|
if (isInterimTextChild(children[index])) children.splice(index, 1);
|
|
10691
11313
|
}
|
|
10692
11314
|
if (children.every((child) => isSpacerChild(child))) children.length = 0;
|
|
10693
11315
|
}
|
|
11316
|
+
markChildrenScanned(instance, children);
|
|
10694
11317
|
}
|
|
10695
11318
|
return result;
|
|
10696
11319
|
}
|
|
@@ -11003,7 +11626,7 @@ var KNOWN_NATIVE_IDENTITIES = Object.freeze({
|
|
|
11003
11626
|
});
|
|
11004
11627
|
var TRUSTED_NATIVE_FINGERPRINTS = Object.freeze(
|
|
11005
11628
|
Object.fromEntries(
|
|
11006
|
-
Object.entries(KNOWN_NATIVE_IDENTITIES).map(([key, identities]) => [key, identities[0]
|
|
11629
|
+
Object.entries(KNOWN_NATIVE_IDENTITIES).map(([key, identities]) => [key, identities[0]?.fingerprint ?? ""])
|
|
11007
11630
|
)
|
|
11008
11631
|
);
|
|
11009
11632
|
function fingerprint(value) {
|
|
@@ -11859,22 +12482,134 @@ function createPiStyleSessionCoordinator(pi, hooks = {}) {
|
|
|
11859
12482
|
}
|
|
11860
12483
|
|
|
11861
12484
|
// extension-src/pi-style/pi/session-usage.ts
|
|
12485
|
+
var usageCache = /* @__PURE__ */ new WeakMap();
|
|
11862
12486
|
function usageFromSession(session) {
|
|
11863
|
-
const
|
|
11864
|
-
|
|
11865
|
-
|
|
11866
|
-
|
|
11867
|
-
|
|
11868
|
-
|
|
11869
|
-
|
|
11870
|
-
|
|
11871
|
-
|
|
11872
|
-
|
|
11873
|
-
|
|
11874
|
-
|
|
11875
|
-
|
|
11876
|
-
|
|
11877
|
-
|
|
12487
|
+
const entries = session.getEntries();
|
|
12488
|
+
const state = usageCache.get(session) ?? createState();
|
|
12489
|
+
usageCache.set(session, state);
|
|
12490
|
+
if (entries.length === 0) {
|
|
12491
|
+
state.cacheHits++;
|
|
12492
|
+
state.processedLength = 0;
|
|
12493
|
+
state.lastEntryId = void 0;
|
|
12494
|
+
state.lastEntryRef = void 0;
|
|
12495
|
+
state.lastContribution = emptyContribution();
|
|
12496
|
+
state.totals = emptyTotals();
|
|
12497
|
+
state.cached = void 0;
|
|
12498
|
+
return void 0;
|
|
12499
|
+
}
|
|
12500
|
+
if (state.processedLength === 0) {
|
|
12501
|
+
rebuildFrom(entries, state);
|
|
12502
|
+
return state.cached;
|
|
12503
|
+
}
|
|
12504
|
+
if (entries.length < state.processedLength) {
|
|
12505
|
+
rebuildFrom(entries, state);
|
|
12506
|
+
return state.cached;
|
|
12507
|
+
}
|
|
12508
|
+
const currentLast = entries.at(-1);
|
|
12509
|
+
if (!currentLast) {
|
|
12510
|
+
state.cacheHits++;
|
|
12511
|
+
state.cached = void 0;
|
|
12512
|
+
return void 0;
|
|
12513
|
+
}
|
|
12514
|
+
if (entries.length === state.processedLength) {
|
|
12515
|
+
if (currentLast.id !== state.lastEntryId) {
|
|
12516
|
+
rebuildFrom(entries, state);
|
|
12517
|
+
return state.cached;
|
|
12518
|
+
}
|
|
12519
|
+
if (currentLast !== state.lastEntryRef) refreshTailEntry(currentLast, state);
|
|
12520
|
+
else state.cacheHits++;
|
|
12521
|
+
return state.cached;
|
|
12522
|
+
}
|
|
12523
|
+
const previousLast = entries[state.processedLength - 1];
|
|
12524
|
+
if (!previousLast || previousLast.id !== state.lastEntryId) {
|
|
12525
|
+
rebuildFrom(entries, state);
|
|
12526
|
+
return state.cached;
|
|
12527
|
+
}
|
|
12528
|
+
if (previousLast !== state.lastEntryRef) refreshTailEntry(previousLast, state);
|
|
12529
|
+
for (const entry of entries.slice(state.processedLength)) appendEntry(entry, state);
|
|
12530
|
+
return state.cached;
|
|
12531
|
+
}
|
|
12532
|
+
function resetUsageFromSessionCache(session) {
|
|
12533
|
+
if (session) {
|
|
12534
|
+
usageCache.delete(session);
|
|
12535
|
+
return;
|
|
12536
|
+
}
|
|
12537
|
+
usageCache = /* @__PURE__ */ new WeakMap();
|
|
12538
|
+
}
|
|
12539
|
+
function createState() {
|
|
12540
|
+
return {
|
|
12541
|
+
processedLength: 0,
|
|
12542
|
+
lastEntryId: void 0,
|
|
12543
|
+
lastEntryRef: void 0,
|
|
12544
|
+
lastContribution: emptyContribution(),
|
|
12545
|
+
totals: emptyTotals(),
|
|
12546
|
+
cached: void 0,
|
|
12547
|
+
scannedEntries: 0,
|
|
12548
|
+
cacheHits: 0,
|
|
12549
|
+
rebuilds: 0,
|
|
12550
|
+
tailRefreshes: 0
|
|
12551
|
+
};
|
|
12552
|
+
}
|
|
12553
|
+
function rebuildFrom(entries, state) {
|
|
12554
|
+
state.rebuilds++;
|
|
12555
|
+
state.processedLength = 0;
|
|
12556
|
+
state.lastEntryId = void 0;
|
|
12557
|
+
state.lastEntryRef = void 0;
|
|
12558
|
+
state.lastContribution = emptyContribution();
|
|
12559
|
+
state.totals = emptyTotals();
|
|
12560
|
+
state.cached = void 0;
|
|
12561
|
+
for (const entry of entries) appendEntry(entry, state);
|
|
12562
|
+
}
|
|
12563
|
+
function refreshTailEntry(entry, state) {
|
|
12564
|
+
state.tailRefreshes++;
|
|
12565
|
+
subtractContribution(state.totals, state.lastContribution);
|
|
12566
|
+
const contribution = usageContribution(entry);
|
|
12567
|
+
addContribution(state.totals, contribution);
|
|
12568
|
+
state.lastEntryId = entry.id;
|
|
12569
|
+
state.lastEntryRef = entry;
|
|
12570
|
+
state.lastContribution = contribution;
|
|
12571
|
+
state.cached = snapshotFromTotals(state.totals);
|
|
12572
|
+
state.scannedEntries++;
|
|
12573
|
+
}
|
|
12574
|
+
function appendEntry(entry, state) {
|
|
12575
|
+
const contribution = usageContribution(entry);
|
|
12576
|
+
addContribution(state.totals, contribution);
|
|
12577
|
+
state.processedLength++;
|
|
12578
|
+
state.lastEntryId = entry.id;
|
|
12579
|
+
state.lastEntryRef = entry;
|
|
12580
|
+
state.lastContribution = contribution;
|
|
12581
|
+
state.cached = snapshotFromTotals(state.totals);
|
|
12582
|
+
state.scannedEntries++;
|
|
12583
|
+
}
|
|
12584
|
+
function usageContribution(entry) {
|
|
12585
|
+
if (entry.type === "message") {
|
|
12586
|
+
if (entry.message.role !== "assistant" && entry.message.role !== "toolResult") return emptyContribution();
|
|
12587
|
+
const usage = "usage" in entry.message ? entry.message.usage : void 0;
|
|
12588
|
+
if (!usage) return emptyContribution();
|
|
12589
|
+
return {
|
|
12590
|
+
input: usage.input,
|
|
12591
|
+
output: usage.output,
|
|
12592
|
+
cacheRead: usage.cacheRead,
|
|
12593
|
+
cacheWrite: usage.cacheWrite,
|
|
12594
|
+
cost: usage.cost.total,
|
|
12595
|
+
sawUsage: true
|
|
12596
|
+
};
|
|
12597
|
+
}
|
|
12598
|
+
if ((entry.type === "branch_summary" || entry.type === "compaction") && entry.usage) {
|
|
12599
|
+
return {
|
|
12600
|
+
input: entry.usage.input,
|
|
12601
|
+
output: entry.usage.output,
|
|
12602
|
+
cacheRead: entry.usage.cacheRead,
|
|
12603
|
+
cacheWrite: entry.usage.cacheWrite,
|
|
12604
|
+
cost: entry.usage.cost.total,
|
|
12605
|
+
sawUsage: true
|
|
12606
|
+
};
|
|
12607
|
+
}
|
|
12608
|
+
return emptyContribution();
|
|
12609
|
+
}
|
|
12610
|
+
function snapshotFromTotals(totals) {
|
|
12611
|
+
if (totals.input === 0 && totals.output === 0 && totals.cacheRead === 0 && totals.cacheWrite === 0 && totals.cost === 0)
|
|
12612
|
+
return void 0;
|
|
11878
12613
|
return {
|
|
11879
12614
|
inputTokens: totals.input,
|
|
11880
12615
|
outputTokens: totals.output,
|
|
@@ -11885,18 +12620,30 @@ function usageFromSession(session) {
|
|
|
11885
12620
|
streaming: false
|
|
11886
12621
|
};
|
|
11887
12622
|
}
|
|
11888
|
-
function
|
|
12623
|
+
function addContribution(totals, usage) {
|
|
11889
12624
|
totals.input += usage.input;
|
|
11890
12625
|
totals.output += usage.output;
|
|
11891
12626
|
totals.cacheRead += usage.cacheRead;
|
|
11892
12627
|
totals.cacheWrite += usage.cacheWrite;
|
|
11893
|
-
totals.cost += usage.cost
|
|
12628
|
+
totals.cost += usage.cost;
|
|
12629
|
+
}
|
|
12630
|
+
function subtractContribution(totals, usage) {
|
|
12631
|
+
totals.input -= usage.input;
|
|
12632
|
+
totals.output -= usage.output;
|
|
12633
|
+
totals.cacheRead -= usage.cacheRead;
|
|
12634
|
+
totals.cacheWrite -= usage.cacheWrite;
|
|
12635
|
+
totals.cost -= usage.cost;
|
|
12636
|
+
}
|
|
12637
|
+
function emptyTotals() {
|
|
12638
|
+
return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 };
|
|
12639
|
+
}
|
|
12640
|
+
function emptyContribution() {
|
|
12641
|
+
return { ...emptyTotals(), sawUsage: false };
|
|
11894
12642
|
}
|
|
11895
12643
|
|
|
11896
12644
|
// extension-src/pi-style/pi/index.ts
|
|
11897
12645
|
function usagePatch(ctx) {
|
|
11898
|
-
|
|
11899
|
-
return usage ? { usage } : {};
|
|
12646
|
+
return { usage: usageFromSession(ctx.sessionManager) };
|
|
11900
12647
|
}
|
|
11901
12648
|
function activateReadOnlyTools(pi) {
|
|
11902
12649
|
const available = new Set(pi.getAllTools().map((tool) => tool.name));
|
|
@@ -11931,6 +12678,7 @@ function piStyleExtension(pi) {
|
|
|
11931
12678
|
const coordinator = createPiStyleSessionCoordinator(pi, compatibilityTestHooks);
|
|
11932
12679
|
registerPiStyleCommand(pi, coordinator.app);
|
|
11933
12680
|
pi.on("session_start", async (event, ctx) => {
|
|
12681
|
+
resetUsageFromSessionCache(ctx.sessionManager);
|
|
11934
12682
|
if (pi.getFlag("pi-style-readonly-tools") === true) {
|
|
11935
12683
|
activateReadOnlyTools(pi);
|
|
11936
12684
|
}
|
|
@@ -11964,40 +12712,57 @@ function piStyleExtension(pi) {
|
|
|
11964
12712
|
)
|
|
11965
12713
|
);
|
|
11966
12714
|
pi.on("thinking_level_select", (event) => coordinator.app.update({ thinkingLevel: event.level }, "immediate"));
|
|
11967
|
-
pi.on(
|
|
12715
|
+
pi.on(
|
|
12716
|
+
"session_info_changed",
|
|
12717
|
+
(event) => coordinator.app.update({ sessionName: event.name }, "coalesced", { refreshExtensionStatuses: true })
|
|
12718
|
+
);
|
|
11968
12719
|
pi.on("message_start", () => {
|
|
11969
12720
|
closeActiveBatch();
|
|
11970
12721
|
});
|
|
11971
12722
|
pi.on("message_update", () => coordinator.app.update({}, "coalesced"));
|
|
11972
|
-
pi.on(
|
|
12723
|
+
pi.on(
|
|
12724
|
+
"message_end",
|
|
12725
|
+
(_event, ctx) => coordinator.app.update({ ...usagePatch(ctx) }, "coalesced", { refreshContextUsage: true })
|
|
12726
|
+
);
|
|
11973
12727
|
pi.on("turn_end", (event, ctx) => {
|
|
11974
12728
|
registerTurnFromMessage(event.message, event.toolResults);
|
|
11975
|
-
coordinator.app.update({ ...usagePatch(ctx) }, "deferred");
|
|
12729
|
+
coordinator.app.update({ ...usagePatch(ctx) }, "deferred", { refreshContextUsage: true });
|
|
11976
12730
|
});
|
|
11977
12731
|
pi.on("agent_end", () => {
|
|
11978
12732
|
const run = finishAgentRun();
|
|
11979
12733
|
if (run) {
|
|
11980
12734
|
invalidateTurnMembers(run);
|
|
12735
|
+
releaseTurnInvalidators(run);
|
|
11981
12736
|
requestToolPresentationRender();
|
|
11982
12737
|
}
|
|
11983
12738
|
});
|
|
11984
|
-
pi.on(
|
|
12739
|
+
pi.on(
|
|
12740
|
+
"agent_settled",
|
|
12741
|
+
(_event, ctx) => coordinator.app.update({ ...usagePatch(ctx) }, "coalesced", { refreshContextUsage: true })
|
|
12742
|
+
);
|
|
11985
12743
|
pi.on("session_tree", (_event, ctx) => {
|
|
12744
|
+
resetUsageFromSessionCache(ctx.sessionManager);
|
|
11986
12745
|
rebuildTurnRegistryFromEntries(ctx.sessionManager.getEntries());
|
|
11987
|
-
coordinator.app.update({ ...usagePatch(ctx) }, "deferred");
|
|
12746
|
+
coordinator.app.update({ ...usagePatch(ctx) }, "deferred", { refreshContextUsage: true });
|
|
12747
|
+
});
|
|
12748
|
+
pi.on("session_compact", (_event, ctx) => {
|
|
12749
|
+
resetUsageFromSessionCache(ctx.sessionManager);
|
|
12750
|
+
coordinator.app.update({ ...usagePatch(ctx) }, "deferred", { refreshContextUsage: true });
|
|
11988
12751
|
});
|
|
11989
|
-
pi.on("session_compact", (_event, ctx) => coordinator.app.update({ ...usagePatch(ctx) }, "deferred"));
|
|
11990
12752
|
pi.on("tool_result", (event, ctx) => {
|
|
11991
12753
|
if (["write", "edit", "bash"].includes(event.toolName)) {
|
|
11992
12754
|
coordinator.app.runtime.current?.invalidateGit();
|
|
11993
|
-
coordinator.app.update({ ...usagePatch(ctx) }, "delayed-retry");
|
|
12755
|
+
coordinator.app.update({ ...usagePatch(ctx) }, "delayed-retry", { refreshContextUsage: true });
|
|
11994
12756
|
}
|
|
11995
12757
|
});
|
|
11996
12758
|
pi.on("user_bash", (_event, ctx) => {
|
|
11997
12759
|
coordinator.app.runtime.current?.invalidateGit();
|
|
11998
|
-
coordinator.app.update({ ...usagePatch(ctx) }, "delayed-retry");
|
|
12760
|
+
coordinator.app.update({ ...usagePatch(ctx) }, "delayed-retry", { refreshContextUsage: true });
|
|
12761
|
+
});
|
|
12762
|
+
pi.on("session_shutdown", (_event, ctx) => {
|
|
12763
|
+
resetUsageFromSessionCache(ctx.sessionManager);
|
|
12764
|
+
coordinator.shutdown();
|
|
11999
12765
|
});
|
|
12000
|
-
pi.on("session_shutdown", () => coordinator.shutdown());
|
|
12001
12766
|
}
|
|
12002
12767
|
export {
|
|
12003
12768
|
__setCompatibilityTestHooks,
|