@quandev104/pi-style 0.2.0 → 0.2.1
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 +6 -0
- package/dist/extensions/pi-style.js +691 -296
- 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 +72 -84
- package/extension-src/pi-style/app/snapshot.ts +41 -2
- package/extension-src/pi-style/features/editor/index.ts +80 -61
- package/extension-src/pi-style/features/messages/index.ts +194 -56
- package/extension-src/pi-style/features/tools/bash-execution.ts +12 -1
- package/extension-src/pi-style/features/tools/boxed/bash.ts +99 -31
- package/extension-src/pi-style/features/tools/boxed/batch.ts +44 -10
- package/extension-src/pi-style/features/tools/boxed/edit.ts +30 -15
- package/extension-src/pi-style/features/tools/boxed/quick-edit.ts +31 -15
- package/extension-src/pi-style/features/tools/boxed/session-config.ts +45 -14
- package/extension-src/pi-style/features/tools/boxed/shared.ts +25 -0
- package/extension-src/pi-style/pi/compatibility-probe.ts +1 -1
- package/extension-src/pi-style/pi/index.ts +26 -13
- package/extension-src/pi-style/pi/session-usage.ts +204 -21
- package/extension-src/pi-style/shared/box.ts +13 -2
- package/package.json +1 -1
|
@@ -183,9 +183,9 @@ function rgbTo256(r, g, b) {
|
|
|
183
183
|
function colorEscapes(mode, hex, kind) {
|
|
184
184
|
if (!isHexColor(hex)) return void 0;
|
|
185
185
|
const { r, g, b } = hexToRgb(hex);
|
|
186
|
-
const
|
|
186
|
+
const cacheKey2 = `${mode}:${kind}:${hex}`;
|
|
187
187
|
const cache = kind === "fg" ? fgEscapeCache : bgEscapeCache;
|
|
188
|
-
let cached = cache.get(
|
|
188
|
+
let cached = cache.get(cacheKey2);
|
|
189
189
|
if (!cached) {
|
|
190
190
|
if (mode === "256color") {
|
|
191
191
|
const idx = rgbTo256(r, g, b);
|
|
@@ -199,7 +199,7 @@ function colorEscapes(mode, hex, kind) {
|
|
|
199
199
|
suffix: kind === "fg" ? "\x1B[39m" : RESET_BACKGROUND
|
|
200
200
|
};
|
|
201
201
|
}
|
|
202
|
-
cache.set(
|
|
202
|
+
cache.set(cacheKey2, cached);
|
|
203
203
|
}
|
|
204
204
|
return cached;
|
|
205
205
|
}
|
|
@@ -411,8 +411,8 @@ function truncatePrintableAscii(text, width, ellipsis = TRUNCATE_ELLIPSIS) {
|
|
|
411
411
|
const targetWidth = Math.max(0, width - ellipsisWidth);
|
|
412
412
|
return { text: `${text.slice(0, targetWidth)}${ellipsis}`, visibleWidth: targetWidth + ellipsisWidth };
|
|
413
413
|
}
|
|
414
|
-
function truncateSgrAscii(text, width, ellipsis,
|
|
415
|
-
if (
|
|
414
|
+
function truncateSgrAscii(text, width, ellipsis, visibleWidth4) {
|
|
415
|
+
if (visibleWidth4 <= width) return { text, visibleWidth: visibleWidth4 };
|
|
416
416
|
const ellipsisWidth = knownEllipsisWidth(ellipsis);
|
|
417
417
|
if (ellipsisWidth === null) return null;
|
|
418
418
|
if (ellipsisWidth >= width) return truncatePrintableAscii(ellipsis, width, "");
|
|
@@ -684,10 +684,10 @@ function setFullTheme(theme, force = false) {
|
|
|
684
684
|
const themeName = resolveThemeName(theme);
|
|
685
685
|
const sourcePath = resolveThemeSourcePath(theme);
|
|
686
686
|
if (!themeName && !sourcePath) return;
|
|
687
|
-
const
|
|
688
|
-
if (!force &&
|
|
687
|
+
const cacheKey2 = sourcePath || themeName;
|
|
688
|
+
if (!force && cacheKey2 === cachedThemeName && (cachedExtras !== null || cachedVars !== null || cachedColors !== null || cachedThemeExport !== null))
|
|
689
689
|
return;
|
|
690
|
-
cachedThemeName =
|
|
690
|
+
cachedThemeName = cacheKey2;
|
|
691
691
|
const result = readThemeDiscoveryFromPath(sourcePath) ?? (themeName ? discoverThemeExtras(themeName) : null);
|
|
692
692
|
cachedExtras = result?.extras ?? null;
|
|
693
693
|
cachedVars = result?.vars ?? null;
|
|
@@ -703,6 +703,15 @@ function getThemeExtra(_theme, key) {
|
|
|
703
703
|
}
|
|
704
704
|
|
|
705
705
|
// extension-src/pi-style/shared/box.ts
|
|
706
|
+
var THEME_CACHE_KEYS = /* @__PURE__ */ new WeakMap();
|
|
707
|
+
var nextThemeCacheKey = 1;
|
|
708
|
+
function themeCacheKey(theme) {
|
|
709
|
+
const cached = THEME_CACHE_KEYS.get(theme);
|
|
710
|
+
if (cached !== void 0) return cached;
|
|
711
|
+
const created = nextThemeCacheKey++;
|
|
712
|
+
THEME_CACHE_KEYS.set(theme, created);
|
|
713
|
+
return created;
|
|
714
|
+
}
|
|
706
715
|
function shortenPath(path) {
|
|
707
716
|
const home = homedir2();
|
|
708
717
|
if (path.startsWith(home)) return `~${path.slice(home.length)}`;
|
|
@@ -868,7 +877,7 @@ function formatBoxedRunningStatus(theme, elapsedMs) {
|
|
|
868
877
|
function dimLine(text) {
|
|
869
878
|
return `\x1B[2m${text}\x1B[22m`;
|
|
870
879
|
}
|
|
871
|
-
function boxFrameText(
|
|
880
|
+
function boxFrameText(_theme, text) {
|
|
872
881
|
return dimLine(text);
|
|
873
882
|
}
|
|
874
883
|
function boxBorder(theme, left, right, width) {
|
|
@@ -1445,6 +1454,18 @@ function setToolsRenderConfig(config) {
|
|
|
1445
1454
|
function getToolsRenderConfig() {
|
|
1446
1455
|
return sessionToolsConfig;
|
|
1447
1456
|
}
|
|
1457
|
+
function getToolsRenderCacheSignature() {
|
|
1458
|
+
return [
|
|
1459
|
+
sessionToolsConfig.maxCollapsedLines,
|
|
1460
|
+
sessionToolsConfig.maxExpandedLines,
|
|
1461
|
+
sessionToolsConfig.dimOutput ? 1 : 0,
|
|
1462
|
+
sessionToolsConfig.showElapsed ? 1 : 0,
|
|
1463
|
+
sessionToolsConfig.batchOpenGlyph,
|
|
1464
|
+
sessionToolsConfig.nerdFonts ? 1 : 0,
|
|
1465
|
+
sessionToolsConfig.collapseAfterTurn ? 1 : 0,
|
|
1466
|
+
sessionToolsConfig.collapseMutatingTools ? 1 : 0
|
|
1467
|
+
].join("|");
|
|
1468
|
+
}
|
|
1448
1469
|
var STARTED_AT_KEY = "__piStyleStartedAt";
|
|
1449
1470
|
var ENDED_AT_KEY = "__piStyleEndedAt";
|
|
1450
1471
|
var RESULT_SEEN_KEY = "__piStyleResultSeen";
|
|
@@ -1472,27 +1493,35 @@ function markResultSeen(state) {
|
|
|
1472
1493
|
if (!state || typeof state !== "object") return;
|
|
1473
1494
|
state[RESULT_SEEN_KEY] = true;
|
|
1474
1495
|
}
|
|
1475
|
-
var
|
|
1496
|
+
var tickerEntries = /* @__PURE__ */ new Map();
|
|
1497
|
+
var sharedTickerHandle;
|
|
1498
|
+
function ensureSharedTicker() {
|
|
1499
|
+
if (sharedTickerHandle !== void 0 || tickerEntries.size === 0) return;
|
|
1500
|
+
sharedTickerHandle = setInterval(() => {
|
|
1501
|
+
for (const { invalidate } of tickerEntries.values()) invalidate();
|
|
1502
|
+
}, 1e3);
|
|
1503
|
+
}
|
|
1504
|
+
function stopSharedTickerIfIdle() {
|
|
1505
|
+
if (sharedTickerHandle === void 0 || tickerEntries.size > 0) return;
|
|
1506
|
+
clearInterval(sharedTickerHandle);
|
|
1507
|
+
sharedTickerHandle = void 0;
|
|
1508
|
+
}
|
|
1476
1509
|
function startElapsedTicker(state, invalidate) {
|
|
1477
1510
|
if (!state || typeof state !== "object") return;
|
|
1478
|
-
|
|
1479
|
-
state
|
|
1480
|
-
|
|
1511
|
+
state[TICKER_KEY] = true;
|
|
1512
|
+
tickerEntries.set(state, { invalidate });
|
|
1513
|
+
ensureSharedTicker();
|
|
1481
1514
|
}
|
|
1482
1515
|
function stopElapsedTicker(state) {
|
|
1483
1516
|
if (!state || typeof state !== "object") return;
|
|
1484
|
-
const handle = state[TICKER_KEY];
|
|
1485
|
-
if (handle !== void 0) clearInterval(handle);
|
|
1486
1517
|
delete state[TICKER_KEY];
|
|
1487
|
-
|
|
1518
|
+
tickerEntries.delete(state);
|
|
1519
|
+
stopSharedTickerIfIdle();
|
|
1488
1520
|
}
|
|
1489
1521
|
function stopAllElapsedTickers() {
|
|
1490
|
-
for (const state of
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
delete state[TICKER_KEY];
|
|
1494
|
-
}
|
|
1495
|
-
tickerStates.clear();
|
|
1522
|
+
for (const state of tickerEntries.keys()) delete state[TICKER_KEY];
|
|
1523
|
+
tickerEntries.clear();
|
|
1524
|
+
stopSharedTickerIfIdle();
|
|
1496
1525
|
}
|
|
1497
1526
|
|
|
1498
1527
|
// extension-src/pi-style/features/tools/boxed/batch.ts
|
|
@@ -1528,6 +1557,7 @@ function createBatch(meta, leaderId, detail, opts = {}) {
|
|
|
1528
1557
|
leaderId,
|
|
1529
1558
|
startedAt: performance.now(),
|
|
1530
1559
|
closed: false,
|
|
1560
|
+
revision: 0,
|
|
1531
1561
|
members: [
|
|
1532
1562
|
{
|
|
1533
1563
|
toolCallId: leaderId,
|
|
@@ -1543,14 +1573,20 @@ function createBatch(meta, leaderId, detail, opts = {}) {
|
|
|
1543
1573
|
batchByCallId.set(leaderId, batch);
|
|
1544
1574
|
return batch;
|
|
1545
1575
|
}
|
|
1576
|
+
function bumpBatchRevision(batch) {
|
|
1577
|
+
batch.revision++;
|
|
1578
|
+
delete batch.renderCache;
|
|
1579
|
+
}
|
|
1546
1580
|
function registerBatchCall(meta, detail, context, opts = {}) {
|
|
1547
1581
|
const existing = batchByCallId.get(context.toolCallId);
|
|
1548
1582
|
if (existing) {
|
|
1549
1583
|
const member2 = existing.members.find((entry) => entry.toolCallId === context.toolCallId);
|
|
1550
1584
|
if (member2) {
|
|
1585
|
+
const changed = member2.detail !== detail || member2.pattern !== opts.pattern || member2.pathLabel !== opts.pathLabel;
|
|
1551
1586
|
member2.detail = detail;
|
|
1552
1587
|
if (opts.pattern !== void 0) member2.pattern = opts.pattern;
|
|
1553
1588
|
if (opts.pathLabel !== void 0) member2.pathLabel = opts.pathLabel;
|
|
1589
|
+
if (changed) bumpBatchRevision(existing);
|
|
1554
1590
|
}
|
|
1555
1591
|
return { batch: existing, isLeader: existing.leaderId === context.toolCallId };
|
|
1556
1592
|
}
|
|
@@ -1569,6 +1605,7 @@ function registerBatchCall(meta, detail, context, opts = {}) {
|
|
|
1569
1605
|
};
|
|
1570
1606
|
current.members.push(member);
|
|
1571
1607
|
batchByCallId.set(context.toolCallId, current);
|
|
1608
|
+
bumpBatchRevision(current);
|
|
1572
1609
|
return { batch: current, isLeader: false };
|
|
1573
1610
|
}
|
|
1574
1611
|
function registerBatchResult(meta, data, context) {
|
|
@@ -1576,14 +1613,19 @@ function registerBatchResult(meta, data, context) {
|
|
|
1576
1613
|
if (!batch || batch.meta.toolName !== meta.toolName) return { batch: void 0, isLeader: false };
|
|
1577
1614
|
const member = batch.members.find((entry) => entry.toolCallId === context.toolCallId);
|
|
1578
1615
|
if (member) {
|
|
1579
|
-
|
|
1580
|
-
|
|
1616
|
+
const nextStatus = data.isPartial ? "running" : "done";
|
|
1617
|
+
const nextIsError = !data.isPartial && data.isError;
|
|
1618
|
+
const changed = member.status !== nextStatus || member.isError !== nextIsError || member.errorText !== (nextIsError ? data.errorText : void 0) || member.outputEntries !== data.entries;
|
|
1619
|
+
member.status = nextStatus;
|
|
1620
|
+
member.isError = nextIsError;
|
|
1581
1621
|
if (member.isError && data.errorText !== void 0) member.errorText = data.errorText;
|
|
1582
1622
|
else delete member.errorText;
|
|
1583
1623
|
if (data.entries !== void 0) member.outputEntries = data.entries;
|
|
1624
|
+
if (changed) bumpBatchRevision(batch);
|
|
1584
1625
|
}
|
|
1585
1626
|
if (batch.completedAt === void 0 && batch.members.every((entry) => entry.status === "done")) {
|
|
1586
1627
|
batch.completedAt = performance.now();
|
|
1628
|
+
bumpBatchRevision(batch);
|
|
1587
1629
|
}
|
|
1588
1630
|
return { batch, isLeader: batch.leaderId === context.toolCallId };
|
|
1589
1631
|
}
|
|
@@ -1776,9 +1818,16 @@ function renderBatchPanelLines(theme, batch, status, width) {
|
|
|
1776
1818
|
function renderBatchAwareCall(theme, batch) {
|
|
1777
1819
|
return {
|
|
1778
1820
|
invalidate() {
|
|
1821
|
+
delete batch.renderCache;
|
|
1779
1822
|
},
|
|
1780
1823
|
render(width) {
|
|
1781
|
-
|
|
1824
|
+
const status = batchStatus(batch);
|
|
1825
|
+
if (!status.allDone) return renderBatchPanelLines(theme, batch, status, width);
|
|
1826
|
+
const cacheKey2 = [themeCacheKey(theme), getToolsRenderCacheSignature(), width, batch.revision].join("|");
|
|
1827
|
+
if (batch.renderCache?.key === cacheKey2) return batch.renderCache.lines;
|
|
1828
|
+
const lines = renderBatchPanelLines(theme, batch, status, width);
|
|
1829
|
+
batch.renderCache = { key: cacheKey2, lines };
|
|
1830
|
+
return lines;
|
|
1782
1831
|
}
|
|
1783
1832
|
};
|
|
1784
1833
|
}
|
|
@@ -5003,6 +5052,17 @@ function compactFooterWithState(theme, result, context, options = {}) {
|
|
|
5003
5052
|
function resultFooterLines(theme, result, context, extraParts = []) {
|
|
5004
5053
|
return [formatBoxedFooter(theme, result, extraParts, stateElapsedMs(context))];
|
|
5005
5054
|
}
|
|
5055
|
+
function getRenderCacheKey(prefix, theme, ...parts) {
|
|
5056
|
+
return [prefix, themeCacheKey(theme), getToolsRenderCacheSignature(), ...parts].join("|");
|
|
5057
|
+
}
|
|
5058
|
+
function memoizedStateComponent(state, slot, key, build) {
|
|
5059
|
+
if (!state || typeof state !== "object") return build();
|
|
5060
|
+
const cached = state[slot];
|
|
5061
|
+
if (cached && cached.key === key) return cached.component;
|
|
5062
|
+
const component = build();
|
|
5063
|
+
state[slot] = { key, component };
|
|
5064
|
+
return component;
|
|
5065
|
+
}
|
|
5006
5066
|
function clearFooterState(context) {
|
|
5007
5067
|
clearCompactBoxedFooter(context.state);
|
|
5008
5068
|
}
|
|
@@ -5322,11 +5382,11 @@ var EMPTY_BASH_RESULT = Object.freeze({
|
|
|
5322
5382
|
}
|
|
5323
5383
|
});
|
|
5324
5384
|
function createBashResultPreview(theme, text, options, color) {
|
|
5325
|
-
let
|
|
5385
|
+
let cacheKey2 = "";
|
|
5326
5386
|
let cacheLines = null;
|
|
5327
5387
|
return {
|
|
5328
5388
|
invalidate() {
|
|
5329
|
-
|
|
5389
|
+
cacheKey2 = "";
|
|
5330
5390
|
cacheLines = null;
|
|
5331
5391
|
},
|
|
5332
5392
|
render(width) {
|
|
@@ -5334,7 +5394,7 @@ function createBashResultPreview(theme, text, options, color) {
|
|
|
5334
5394
|
const cfg = getToolsRenderConfig();
|
|
5335
5395
|
const expanded = Boolean(options.expanded);
|
|
5336
5396
|
const cacheId = `${bodyWidth}|${expanded ? 1 : 0}|${cfg.maxExpandedLines}|${cfg.dimOutput ? 1 : 0}`;
|
|
5337
|
-
if (cacheLines &&
|
|
5397
|
+
if (cacheLines && cacheKey2 === cacheId) return cacheLines;
|
|
5338
5398
|
if (!expanded) {
|
|
5339
5399
|
const needed = cfg.maxCollapsedLines;
|
|
5340
5400
|
let totalNewlines = 0;
|
|
@@ -5349,14 +5409,14 @@ function createBashResultPreview(theme, text, options, color) {
|
|
|
5349
5409
|
}
|
|
5350
5410
|
}
|
|
5351
5411
|
if (text.length === 0) {
|
|
5352
|
-
|
|
5412
|
+
cacheKey2 = cacheId;
|
|
5353
5413
|
cacheLines = [];
|
|
5354
5414
|
return cacheLines;
|
|
5355
5415
|
}
|
|
5356
5416
|
const tail = replaceTabs(text.slice(scanFrom)).replace(/\r/g, "");
|
|
5357
5417
|
const shownLines = tail ? tail.split("\n").map((l) => clampLineLength(l)) : [];
|
|
5358
5418
|
if (shownLines.length === 0) {
|
|
5359
|
-
|
|
5419
|
+
cacheKey2 = cacheId;
|
|
5360
5420
|
cacheLines = [];
|
|
5361
5421
|
return cacheLines;
|
|
5362
5422
|
}
|
|
@@ -5365,7 +5425,7 @@ function createBashResultPreview(theme, text, options, color) {
|
|
|
5365
5425
|
if (color === "error") return formatToolOutputLine(theme, truncated, "error");
|
|
5366
5426
|
return cfg.dimOutput ? formatToolOutputLine(theme, truncated) : formatToolOutputLine(theme, truncated, "text");
|
|
5367
5427
|
});
|
|
5368
|
-
|
|
5428
|
+
cacheKey2 = cacheId;
|
|
5369
5429
|
cacheLines = truncatedShown;
|
|
5370
5430
|
return cacheLines;
|
|
5371
5431
|
}
|
|
@@ -5373,7 +5433,7 @@ function createBashResultPreview(theme, text, options, color) {
|
|
|
5373
5433
|
const logicalLines = normalized.split("\n").map((l) => clampLineLength(l));
|
|
5374
5434
|
const hasOutput = !(logicalLines.length === 1 && logicalLines[0] === "");
|
|
5375
5435
|
if (!hasOutput) {
|
|
5376
|
-
|
|
5436
|
+
cacheKey2 = cacheId;
|
|
5377
5437
|
cacheLines = [];
|
|
5378
5438
|
return cacheLines;
|
|
5379
5439
|
}
|
|
@@ -5384,11 +5444,11 @@ function createBashResultPreview(theme, text, options, color) {
|
|
|
5384
5444
|
const truncated = expandedLines.slice(-cfg.maxExpandedLines).map(applyColor);
|
|
5385
5445
|
const remaining = expandedLines.length - cfg.maxExpandedLines;
|
|
5386
5446
|
truncated.unshift(theme.fg("dim", `\u2026 ${remaining} earlier lines`));
|
|
5387
|
-
|
|
5447
|
+
cacheKey2 = cacheId;
|
|
5388
5448
|
cacheLines = truncated;
|
|
5389
5449
|
return cacheLines;
|
|
5390
5450
|
}
|
|
5391
|
-
|
|
5451
|
+
cacheKey2 = cacheId;
|
|
5392
5452
|
cacheLines = expandedLines.map(applyColor);
|
|
5393
5453
|
return cacheLines;
|
|
5394
5454
|
}
|
|
@@ -5602,27 +5662,35 @@ function renderSemanticPanel(theme, toolCallId, context) {
|
|
|
5602
5662
|
},
|
|
5603
5663
|
render(width) {
|
|
5604
5664
|
if (!state) return [];
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5665
|
+
const renderFresh = () => {
|
|
5666
|
+
if (state.fallback) {
|
|
5667
|
+
return renderBoxedBashCall(
|
|
5668
|
+
theme,
|
|
5669
|
+
state.command.split("\n"),
|
|
5670
|
+
context,
|
|
5671
|
+
bashWidthKey(state.command, context?.args?.timeout)
|
|
5672
|
+
).render(width);
|
|
5673
|
+
}
|
|
5674
|
+
if (isBashTreeClass(state.cls)) {
|
|
5675
|
+
const treeState = { cls: state.cls };
|
|
5676
|
+
if (state.parsed !== void 0) treeState.parsed = state.parsed;
|
|
5677
|
+
return renderBashTreeLines(theme, treeState, width);
|
|
5678
|
+
}
|
|
5679
|
+
if (isGhClass(state.cls)) {
|
|
5680
|
+
const ghState = { cls: state.cls };
|
|
5681
|
+
if (state.parsed !== void 0) ghState.parsed = state.parsed;
|
|
5682
|
+
return renderGhCardLines(theme, ghState, width);
|
|
5683
|
+
}
|
|
5684
|
+
const gitState = { cls: state.cls };
|
|
5685
|
+
if (state.parsed !== void 0) gitState.parsed = state.parsed;
|
|
5686
|
+
return renderGitCardLines(theme, gitState, width);
|
|
5687
|
+
};
|
|
5688
|
+
if (!state.finished) return renderFresh();
|
|
5689
|
+
const cacheKey2 = [themeCacheKey(theme), getToolsRenderCacheSignature(), width, state.revision].join("|");
|
|
5690
|
+
if (state.renderCache?.key === cacheKey2) return state.renderCache.lines;
|
|
5691
|
+
const lines = renderFresh();
|
|
5692
|
+
state.renderCache = { key: cacheKey2, lines };
|
|
5693
|
+
return lines;
|
|
5626
5694
|
}
|
|
5627
5695
|
};
|
|
5628
5696
|
}
|
|
@@ -5631,7 +5699,26 @@ var bashTool = {
|
|
|
5631
5699
|
noteExecutionStart(context);
|
|
5632
5700
|
const cls = classifyBashSemantic(String(args?.command ?? ""));
|
|
5633
5701
|
if (cls) {
|
|
5634
|
-
|
|
5702
|
+
const command = String(args?.command ?? "");
|
|
5703
|
+
const existing = semanticStates.get(context.toolCallId);
|
|
5704
|
+
if (existing) {
|
|
5705
|
+
if (existing.command !== command || existing.cls.kind !== cls.kind) {
|
|
5706
|
+
delete existing.parsed;
|
|
5707
|
+
delete existing.fallback;
|
|
5708
|
+
existing.finished = false;
|
|
5709
|
+
existing.revision++;
|
|
5710
|
+
delete existing.renderCache;
|
|
5711
|
+
}
|
|
5712
|
+
existing.command = command;
|
|
5713
|
+
existing.cls = cls;
|
|
5714
|
+
} else {
|
|
5715
|
+
semanticStates.set(context.toolCallId, {
|
|
5716
|
+
cls,
|
|
5717
|
+
command,
|
|
5718
|
+
finished: false,
|
|
5719
|
+
revision: 0
|
|
5720
|
+
});
|
|
5721
|
+
}
|
|
5635
5722
|
return renderSemanticPanel(theme, context.toolCallId, context);
|
|
5636
5723
|
}
|
|
5637
5724
|
noteBoxedCallState(context);
|
|
@@ -5652,12 +5739,18 @@ var bashTool = {
|
|
|
5652
5739
|
const parsed = parseSemanticOutput(cls, output);
|
|
5653
5740
|
const state = semanticStates.get(context.toolCallId);
|
|
5654
5741
|
if (parsed) {
|
|
5655
|
-
if (state)
|
|
5656
|
-
|
|
5742
|
+
if (state) {
|
|
5743
|
+
state.parsed = parsed;
|
|
5744
|
+
state.finished = !options.isPartial;
|
|
5745
|
+
state.revision++;
|
|
5746
|
+
delete state.renderCache;
|
|
5747
|
+
} else
|
|
5657
5748
|
semanticStates.set(context.toolCallId, {
|
|
5658
5749
|
cls,
|
|
5659
5750
|
command: String(context?.args?.command ?? ""),
|
|
5660
|
-
parsed
|
|
5751
|
+
parsed,
|
|
5752
|
+
finished: !options.isPartial,
|
|
5753
|
+
revision: 0
|
|
5661
5754
|
});
|
|
5662
5755
|
if (isGitDiffClass(cls)) {
|
|
5663
5756
|
return renderGitDiffResult(theme, parsed, options, context);
|
|
@@ -5667,7 +5760,12 @@ var bashTool = {
|
|
|
5667
5760
|
}
|
|
5668
5761
|
return EMPTY_BASH_TREE_RESULT;
|
|
5669
5762
|
}
|
|
5670
|
-
if (state)
|
|
5763
|
+
if (state) {
|
|
5764
|
+
state.fallback = true;
|
|
5765
|
+
state.finished = !options.isPartial;
|
|
5766
|
+
state.revision++;
|
|
5767
|
+
delete state.renderCache;
|
|
5768
|
+
}
|
|
5671
5769
|
}
|
|
5672
5770
|
} else if (options.isPartial) {
|
|
5673
5771
|
startElapsedTicker(context.state, context.invalidate);
|
|
@@ -5680,7 +5778,20 @@ var bashTool = {
|
|
|
5680
5778
|
if (firstResultPass) return EMPTY_BASH_RESULT;
|
|
5681
5779
|
return renderBashStreamingResult(theme, raw, options, context);
|
|
5682
5780
|
}
|
|
5683
|
-
return
|
|
5781
|
+
return memoizedStateComponent(
|
|
5782
|
+
context.state,
|
|
5783
|
+
"__piStyleBashFinalResult",
|
|
5784
|
+
getRenderCacheKey(
|
|
5785
|
+
"bash-final-result",
|
|
5786
|
+
theme,
|
|
5787
|
+
Boolean(options.expanded),
|
|
5788
|
+
Boolean(context.isError),
|
|
5789
|
+
String(context?.args?.command ?? ""),
|
|
5790
|
+
raw,
|
|
5791
|
+
getStateElapsedMs(context.state) ?? ""
|
|
5792
|
+
),
|
|
5793
|
+
() => renderBashFinalResult(theme, raw, options, context)
|
|
5794
|
+
);
|
|
5684
5795
|
}
|
|
5685
5796
|
};
|
|
5686
5797
|
|
|
@@ -5760,21 +5871,33 @@ var editTool = {
|
|
|
5760
5871
|
const maxRows = expanded ? 160 : 36;
|
|
5761
5872
|
const diffView = new AdaptiveDiffComponent(theme, rows, maxRows, shouldHighlight ? language : void 0);
|
|
5762
5873
|
const expandHint2 = !expanded && diffView.hasCollapsed() ? "Ctrl+O more" : void 0;
|
|
5763
|
-
return
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5874
|
+
return memoizedStateComponent(
|
|
5875
|
+
context.state,
|
|
5876
|
+
"__piStyleEditDiffResult",
|
|
5877
|
+
getRenderCacheKey(
|
|
5878
|
+
"edit-diff-result",
|
|
5879
|
+
theme,
|
|
5880
|
+
Boolean(expanded),
|
|
5881
|
+
diff,
|
|
5882
|
+
sourcePath ?? "",
|
|
5883
|
+
editDiffFooter(theme, result, context, stats)
|
|
5884
|
+
),
|
|
5885
|
+
() => renderBoxedToolResult(
|
|
5886
|
+
theme,
|
|
5887
|
+
{
|
|
5888
|
+
render(width) {
|
|
5889
|
+
return diffView.render(width);
|
|
5890
|
+
},
|
|
5891
|
+
invalidate() {
|
|
5892
|
+
diffView.invalidate();
|
|
5893
|
+
}
|
|
5768
5894
|
},
|
|
5769
|
-
|
|
5770
|
-
|
|
5895
|
+
{
|
|
5896
|
+
dividerLabel: diffDividerLabel2(theme, stats),
|
|
5897
|
+
...expandHint2 ? { dividerRightLabel: expandHint2 } : {},
|
|
5898
|
+
footerLines: [editDiffFooter(theme, result, context, stats)]
|
|
5771
5899
|
}
|
|
5772
|
-
|
|
5773
|
-
{
|
|
5774
|
-
dividerLabel: diffDividerLabel2(theme, stats),
|
|
5775
|
-
...expandHint2 ? { dividerRightLabel: expandHint2 } : {},
|
|
5776
|
-
footerLines: [editDiffFooter(theme, result, context, stats)]
|
|
5777
|
-
}
|
|
5900
|
+
)
|
|
5778
5901
|
);
|
|
5779
5902
|
}
|
|
5780
5903
|
};
|
|
@@ -6171,21 +6294,34 @@ function renderQuickEditResult(_toolName, result, options, theme, context, confi
|
|
|
6171
6294
|
const maxRows = expanded ? 160 : 36;
|
|
6172
6295
|
const diffView = new AdaptiveDiffComponent(theme, rows, maxRows, shouldHighlight ? language : void 0);
|
|
6173
6296
|
const expandHint2 = !expanded && diffView.hasCollapsed() ? "Ctrl+O more" : void 0;
|
|
6174
|
-
return
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6297
|
+
return memoizedStateComponent(
|
|
6298
|
+
context.state,
|
|
6299
|
+
"__piStyleQuickEditDiffResult",
|
|
6300
|
+
getRenderCacheKey(
|
|
6301
|
+
"quick-edit-diff-result",
|
|
6302
|
+
theme,
|
|
6303
|
+
config.toolLabel,
|
|
6304
|
+
Boolean(expanded),
|
|
6305
|
+
diff,
|
|
6306
|
+
argPath,
|
|
6307
|
+
quickEditDiffFooter(theme, result, context, stats)
|
|
6308
|
+
),
|
|
6309
|
+
() => renderBoxedToolResult(
|
|
6310
|
+
theme,
|
|
6311
|
+
{
|
|
6312
|
+
render(width) {
|
|
6313
|
+
return diffView.render(width);
|
|
6314
|
+
},
|
|
6315
|
+
invalidate() {
|
|
6316
|
+
diffView.invalidate();
|
|
6317
|
+
}
|
|
6179
6318
|
},
|
|
6180
|
-
|
|
6181
|
-
|
|
6319
|
+
{
|
|
6320
|
+
dividerLabel: quickEditDividerLabel(theme, stats),
|
|
6321
|
+
...expandHint2 ? { dividerRightLabel: expandHint2 } : {},
|
|
6322
|
+
footerLines: [quickEditDiffFooter(theme, result, context, stats)]
|
|
6182
6323
|
}
|
|
6183
|
-
|
|
6184
|
-
{
|
|
6185
|
-
dividerLabel: quickEditDividerLabel(theme, stats),
|
|
6186
|
-
...expandHint2 ? { dividerRightLabel: expandHint2 } : {},
|
|
6187
|
-
footerLines: [quickEditDiffFooter(theme, result, context, stats)]
|
|
6188
|
-
}
|
|
6324
|
+
)
|
|
6189
6325
|
);
|
|
6190
6326
|
}
|
|
6191
6327
|
function quickEditFooter(theme, context) {
|
|
@@ -8254,6 +8390,7 @@ var StyledEditor = class extends CustomEditor {
|
|
|
8254
8390
|
onSnapshot;
|
|
8255
8391
|
semantic;
|
|
8256
8392
|
disposed = false;
|
|
8393
|
+
renderPlanCache;
|
|
8257
8394
|
constructor(tui, theme, keybindings, options) {
|
|
8258
8395
|
super(tui, theme, keybindings);
|
|
8259
8396
|
this.config = options.config;
|
|
@@ -8283,61 +8420,23 @@ var StyledEditor = class extends CustomEditor {
|
|
|
8283
8420
|
invalidate() {
|
|
8284
8421
|
super.invalidate();
|
|
8285
8422
|
this.semantic = semanticTheme(this.piTheme, this.config);
|
|
8423
|
+
this.renderPlanCache = void 0;
|
|
8286
8424
|
this.tui.requestRender();
|
|
8287
8425
|
}
|
|
8288
8426
|
render(width) {
|
|
8289
8427
|
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);
|
|
8428
|
+
const plan = this.renderPlan(width);
|
|
8429
|
+
const autocompleteState = this.autocompleteState;
|
|
8430
|
+
if (plan.style === "native") return super.render(width).map((line) => widthSafe(line, width));
|
|
8431
|
+
if (autocompleteState) return this.renderAutocompleteFrame(width, plan);
|
|
8432
|
+
const innerLines = super.render(plan.innerWidth);
|
|
8332
8433
|
if (innerLines.length === 0) return [];
|
|
8333
8434
|
const body = innerLines.slice(1, -1);
|
|
8334
|
-
const prefix = `${" ".repeat(padding)}${prompt} `;
|
|
8335
|
-
const continuation = " ".repeat(padding + promptWidth);
|
|
8336
8435
|
const hint = this.config.editor.hint;
|
|
8337
8436
|
const showHint = hint !== "" && this.getText() === "";
|
|
8338
8437
|
const bashHidden = this.bashHiddenCount();
|
|
8339
8438
|
const renderedBody = body.map((line, index) => {
|
|
8340
|
-
const lead = index === 0 ? prefix : continuation;
|
|
8439
|
+
const lead = index === 0 ? plan.prefix : plan.continuation;
|
|
8341
8440
|
const source = index === 0 && bashHidden > 0 ? stripLeadingVisibleChars(line, bashHidden) : line;
|
|
8342
8441
|
let content = `${lead}${source}`;
|
|
8343
8442
|
if (showHint && index === 0 && line) {
|
|
@@ -8346,10 +8445,10 @@ var StyledEditor = class extends CustomEditor {
|
|
|
8346
8445
|
if (end < content.length) content = content.slice(0, end);
|
|
8347
8446
|
content += this.semantic.apply("hint", hint);
|
|
8348
8447
|
}
|
|
8349
|
-
return widthSafe(content, renderWidth);
|
|
8448
|
+
return widthSafe(content, plan.renderWidth);
|
|
8350
8449
|
});
|
|
8351
|
-
const metadata = this.metadata(width, style);
|
|
8352
|
-
const framed = this.frame(width, style, renderedBody, metadata);
|
|
8450
|
+
const metadata = this.metadata(width, plan.style);
|
|
8451
|
+
const framed = this.frame(width, plan.style, renderedBody, metadata);
|
|
8353
8452
|
return framed.map((line) => widthSafe(line, width));
|
|
8354
8453
|
}
|
|
8355
8454
|
dispose() {
|
|
@@ -8357,6 +8456,59 @@ var StyledEditor = class extends CustomEditor {
|
|
|
8357
8456
|
this.disposed = true;
|
|
8358
8457
|
this.invalidate();
|
|
8359
8458
|
}
|
|
8459
|
+
renderPlan(width) {
|
|
8460
|
+
const style = this.styleFor(width);
|
|
8461
|
+
const prompt = this.prompt();
|
|
8462
|
+
const kind = this.frameKind(style);
|
|
8463
|
+
const key = `${width}:${style}:${kind}:${prompt}`;
|
|
8464
|
+
if (this.renderPlanCache?.key === key) return this.renderPlanCache.plan;
|
|
8465
|
+
const promptWidth = widthOf(prompt) + 1;
|
|
8466
|
+
const padding = this.paddingFor(width, style);
|
|
8467
|
+
const sideReserve = kind === "rounded" ? 2 : 0;
|
|
8468
|
+
const renderWidth = Math.max(1, width - sideReserve);
|
|
8469
|
+
const innerWidth = Math.max(1, renderWidth - promptWidth - padding * 2);
|
|
8470
|
+
const prefix = `${" ".repeat(padding)}${prompt} `;
|
|
8471
|
+
const continuation = " ".repeat(padding + promptWidth);
|
|
8472
|
+
const plan = {
|
|
8473
|
+
style,
|
|
8474
|
+
kind,
|
|
8475
|
+
prompt,
|
|
8476
|
+
promptWidth,
|
|
8477
|
+
padding,
|
|
8478
|
+
sideReserve,
|
|
8479
|
+
renderWidth,
|
|
8480
|
+
innerWidth,
|
|
8481
|
+
prefix,
|
|
8482
|
+
continuation
|
|
8483
|
+
};
|
|
8484
|
+
this.renderPlanCache = { key, plan };
|
|
8485
|
+
return plan;
|
|
8486
|
+
}
|
|
8487
|
+
renderAutocompleteFrame(width, plan) {
|
|
8488
|
+
const nativeLines = super.render(width);
|
|
8489
|
+
const borderIndex = nativeLines.slice(1).findIndex((line) => isNativeBorderLine(line));
|
|
8490
|
+
const split = borderIndex >= 0 ? borderIndex + 1 : nativeLines.length;
|
|
8491
|
+
const body = nativeLines.slice(1, split);
|
|
8492
|
+
const dropdown = nativeLines.slice(split);
|
|
8493
|
+
const border = this.borderFor();
|
|
8494
|
+
const sideColor = plan.kind === "rounded" ? this.borderColorFor() : void 0;
|
|
8495
|
+
const wrap = (line) => plan.kind === "rounded" && sideColor ? `${sideColor("\u2502")}${line}${sideColor("\u2502")}` : line;
|
|
8496
|
+
const bashHidden = this.bashHiddenCount();
|
|
8497
|
+
const renderedBody = body.map((line, index) => {
|
|
8498
|
+
const source = index === 0 && bashHidden > 0 ? stripLeadingVisibleChars(line, bashHidden) : line;
|
|
8499
|
+
return wrap(widthSafe(`${index === 0 ? plan.prefix : plan.continuation}${source}`, plan.renderWidth));
|
|
8500
|
+
});
|
|
8501
|
+
const dropdownLines = dropdown.map((line) => wrap(widthSafe(line, plan.renderWidth)));
|
|
8502
|
+
if (plan.kind === "rounded") {
|
|
8503
|
+
return [
|
|
8504
|
+
border(`\u256D${"\u2500".repeat(Math.max(0, width - 2))}\u256E`),
|
|
8505
|
+
...renderedBody,
|
|
8506
|
+
...dropdownLines,
|
|
8507
|
+
border(`\u2570${"\u2500".repeat(Math.max(0, width - 2))}\u256F`)
|
|
8508
|
+
];
|
|
8509
|
+
}
|
|
8510
|
+
return [border("\u2500".repeat(width)), ...renderedBody, ...dropdownLines, border("\u2500".repeat(width))];
|
|
8511
|
+
}
|
|
8360
8512
|
prompt() {
|
|
8361
8513
|
if (this.isBashMode()) {
|
|
8362
8514
|
const glyph = this.semantic.glyph("bashPrompt");
|
|
@@ -8598,13 +8750,13 @@ function resolveAccentRgb(resolved) {
|
|
|
8598
8750
|
function styledLogoLines(resolved) {
|
|
8599
8751
|
const accent = resolveAccentRgb(resolved);
|
|
8600
8752
|
if (!accent) return [...PI_LOGO_LINES];
|
|
8601
|
-
const
|
|
8602
|
-
if (
|
|
8753
|
+
const cacheKey2 = `${resolved.color("accent")}|${resolved.mode}`;
|
|
8754
|
+
if (cacheKey2 === logoGradientCacheKey && logoGradientCacheLines) return logoGradientCacheLines;
|
|
8603
8755
|
const palette = buildLogoPalette(accent);
|
|
8604
8756
|
logoGradientCacheLines = PI_LOGO_LINES.map(
|
|
8605
8757
|
(line, rowIndex) => renderLogoGradientLine(line, palette, rowIndex * LOGO_ROW_PHASE_STEP)
|
|
8606
8758
|
);
|
|
8607
|
-
logoGradientCacheKey =
|
|
8759
|
+
logoGradientCacheKey = cacheKey2;
|
|
8608
8760
|
return logoGradientCacheLines;
|
|
8609
8761
|
}
|
|
8610
8762
|
function compactLogoHeader(resolved, details, width) {
|
|
@@ -9667,16 +9819,51 @@ var RenderScheduler = class {
|
|
|
9667
9819
|
|
|
9668
9820
|
// extension-src/pi-style/app/snapshot.ts
|
|
9669
9821
|
function createSnapshot(generation2, revision = 0, values = {}) {
|
|
9670
|
-
return Object.freeze({ generation: generation2, revision
|
|
9822
|
+
return Object.freeze({ ...values, generation: generation2, revision });
|
|
9671
9823
|
}
|
|
9672
9824
|
function replaceSnapshot(current, generation2, values) {
|
|
9673
9825
|
if (current.generation !== generation2) return current;
|
|
9674
|
-
return createSnapshot(generation2, current.revision + 1, values);
|
|
9826
|
+
return equalStatusSnapshot(current, values) ? current : createSnapshot(generation2, current.revision + 1, values);
|
|
9827
|
+
}
|
|
9828
|
+
function equalStatusSnapshot(current, next) {
|
|
9829
|
+
const currentEntries = Object.entries(current).filter(([key]) => key !== "generation" && key !== "revision");
|
|
9830
|
+
const nextEntries = Object.entries(next).filter(([key]) => key !== "generation" && key !== "revision");
|
|
9831
|
+
if (currentEntries.length !== nextEntries.length) return false;
|
|
9832
|
+
for (const [key, value] of nextEntries) {
|
|
9833
|
+
if (!hasOwn(current, key)) return false;
|
|
9834
|
+
if (!equalValue(current[key], value)) return false;
|
|
9835
|
+
}
|
|
9836
|
+
return true;
|
|
9837
|
+
}
|
|
9838
|
+
function equalValue(left, right) {
|
|
9839
|
+
if (Object.is(left, right)) return true;
|
|
9840
|
+
if (Array.isArray(left) && Array.isArray(right)) {
|
|
9841
|
+
if (left.length !== right.length) return false;
|
|
9842
|
+
for (let index = 0; index < left.length; index++) {
|
|
9843
|
+
if (!equalValue(left[index], right[index])) return false;
|
|
9844
|
+
}
|
|
9845
|
+
return true;
|
|
9846
|
+
}
|
|
9847
|
+
if (!isPlainRecord(left) || !isPlainRecord(right)) return false;
|
|
9848
|
+
const leftKeys = Object.keys(left);
|
|
9849
|
+
const rightKeys = Object.keys(right);
|
|
9850
|
+
if (leftKeys.length !== rightKeys.length) return false;
|
|
9851
|
+
for (const key of rightKeys) {
|
|
9852
|
+
if (!hasOwn(left, key)) return false;
|
|
9853
|
+
if (!equalValue(left[key], right[key])) return false;
|
|
9854
|
+
}
|
|
9855
|
+
return true;
|
|
9856
|
+
}
|
|
9857
|
+
function hasOwn(value, key) {
|
|
9858
|
+
return Object.hasOwn(value, key);
|
|
9859
|
+
}
|
|
9860
|
+
function isPlainRecord(value) {
|
|
9861
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9675
9862
|
}
|
|
9676
9863
|
|
|
9677
9864
|
// extension-src/pi-style/app/runtime.ts
|
|
9678
|
-
function createPiStyleRuntime(host, generation2, requestRender = () => {
|
|
9679
|
-
}) {
|
|
9865
|
+
function createPiStyleRuntime(host, generation2, requestRender = host.requestRender ?? (() => {
|
|
9866
|
+
})) {
|
|
9680
9867
|
let disposed = false;
|
|
9681
9868
|
const extensionStatuses = () => {
|
|
9682
9869
|
if (!host.extensionStatusProvider) return void 0;
|
|
@@ -9687,13 +9874,22 @@ function createPiStyleRuntime(host, generation2, requestRender = () => {
|
|
|
9687
9874
|
return [];
|
|
9688
9875
|
}
|
|
9689
9876
|
};
|
|
9877
|
+
const contextSnapshot = () => {
|
|
9878
|
+
const usage = host.getContextUsage?.();
|
|
9879
|
+
if (!usage) return void 0;
|
|
9880
|
+
return {
|
|
9881
|
+
...usage.tokens !== null ? { currentTokens: usage.tokens } : {},
|
|
9882
|
+
windowTokens: usage.contextWindow,
|
|
9883
|
+
...usage.percent !== null ? { percent: usage.percent } : {}
|
|
9884
|
+
};
|
|
9885
|
+
};
|
|
9690
9886
|
let currentConfig = host.config;
|
|
9691
9887
|
const disposables = new DisposableStore();
|
|
9692
9888
|
const scheduler = new RenderScheduler({ requestRender }, generation2, () => !disposed);
|
|
9693
9889
|
const git = new CachedGitProvider(host.gitRunner);
|
|
9694
9890
|
const contextProvider = new InMemoryContextProvider();
|
|
9695
9891
|
const usageProvider = new InMemoryUsageProvider();
|
|
9696
|
-
const
|
|
9892
|
+
const initialContext = contextSnapshot();
|
|
9697
9893
|
const initialStatuses = extensionStatuses();
|
|
9698
9894
|
const initialValues = {
|
|
9699
9895
|
...initialStatuses ? { extensionStatuses: initialStatuses } : {},
|
|
@@ -9702,13 +9898,7 @@ function createPiStyleRuntime(host, generation2, requestRender = () => {
|
|
|
9702
9898
|
...host.model?.reasoning !== void 0 ? { reasoning: host.model.reasoning } : {},
|
|
9703
9899
|
...host.thinkingLevel ? { thinkingLevel: normalizeThinkingLevel(host.thinkingLevel) } : {},
|
|
9704
9900
|
...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
|
-
} : {}
|
|
9901
|
+
...initialContext ? { context: initialContext } : {}
|
|
9712
9902
|
};
|
|
9713
9903
|
let currentSnapshot = createSnapshot(generation2, 0, initialValues);
|
|
9714
9904
|
let statusLine;
|
|
@@ -9719,14 +9909,35 @@ function createPiStyleRuntime(host, generation2, requestRender = () => {
|
|
|
9719
9909
|
editor: "disabled",
|
|
9720
9910
|
startup: "disabled"
|
|
9721
9911
|
};
|
|
9722
|
-
const
|
|
9912
|
+
const snapshotValues = (snapshot) => {
|
|
9913
|
+
const { generation: _generation, revision: _revision, ...values } = snapshot;
|
|
9914
|
+
return values;
|
|
9915
|
+
};
|
|
9916
|
+
const withSnapshotPatch = (patch) => {
|
|
9917
|
+
const next = { ...snapshotValues(currentSnapshot) };
|
|
9918
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
9919
|
+
if (value === void 0) delete next[key];
|
|
9920
|
+
else next[key] = value;
|
|
9921
|
+
}
|
|
9922
|
+
return next;
|
|
9923
|
+
};
|
|
9924
|
+
const createStartupSnapshot = (config, resources = host.resources) => ({
|
|
9723
9925
|
...currentSnapshot,
|
|
9724
9926
|
reason: host.startupReason ?? "startup",
|
|
9725
9927
|
...host.provider ? { startupProvider: host.provider } : {},
|
|
9726
9928
|
...host.cwd ? { project: host.cwd.split(/[\\/]/).filter(Boolean).at(-1) } : {},
|
|
9727
9929
|
preset: config.preset,
|
|
9728
|
-
...
|
|
9930
|
+
...resources ? { resources } : {}
|
|
9729
9931
|
});
|
|
9932
|
+
const applySnapshot = (nextSnapshot) => {
|
|
9933
|
+
if (nextSnapshot === currentSnapshot) return false;
|
|
9934
|
+
currentSnapshot = nextSnapshot;
|
|
9935
|
+
statusLine?.update(currentSnapshot);
|
|
9936
|
+
editor?.update(currentSnapshot);
|
|
9937
|
+
startup?.update(createStartupSnapshot(currentConfig));
|
|
9938
|
+
return true;
|
|
9939
|
+
};
|
|
9940
|
+
const updateSnapshot = (values) => applySnapshot(replaceSnapshot(currentSnapshot, generation2, values));
|
|
9730
9941
|
const installStatus = () => {
|
|
9731
9942
|
if (!host.hasUI || host.mode !== "tui" || !host.ui || !currentConfig.enabled || !currentConfig.statusLine.enabled) {
|
|
9732
9943
|
installationState = { ...installationState, status: "disabled" };
|
|
@@ -9789,7 +10000,7 @@ function createPiStyleRuntime(host, generation2, requestRender = () => {
|
|
|
9789
10000
|
startup = installStartup({
|
|
9790
10001
|
host: { ...host.ui, mode: host.mode, hasUI: host.hasUI },
|
|
9791
10002
|
config: currentConfig,
|
|
9792
|
-
snapshot:
|
|
10003
|
+
snapshot: createStartupSnapshot(currentConfig),
|
|
9793
10004
|
generation: generation2,
|
|
9794
10005
|
requestRender,
|
|
9795
10006
|
timeoutMs: 3e3,
|
|
@@ -9838,27 +10049,10 @@ function createPiStyleRuntime(host, generation2, requestRender = () => {
|
|
|
9838
10049
|
if (host.cwd && currentConfig.enabled && currentConfig.statusLine.enabled) {
|
|
9839
10050
|
void git.get(host.cwd).then((value) => {
|
|
9840
10051
|
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 } : {}
|
|
10052
|
+
if (updateSnapshot(withSnapshotPatch({ git: value }))) requestRender();
|
|
9860
10053
|
});
|
|
9861
10054
|
}
|
|
10055
|
+
if (initialContext) contextProvider.set("active", initialContext);
|
|
9862
10056
|
return {
|
|
9863
10057
|
generation: generation2,
|
|
9864
10058
|
providerIdentity: { git, context: contextProvider, usage: usageProvider },
|
|
@@ -9867,49 +10061,33 @@ function createPiStyleRuntime(host, generation2, requestRender = () => {
|
|
|
9867
10061
|
},
|
|
9868
10062
|
mode: host.mode,
|
|
9869
10063
|
hasUI: host.hasUI,
|
|
9870
|
-
snapshot
|
|
10064
|
+
get snapshot() {
|
|
10065
|
+
return currentSnapshot;
|
|
10066
|
+
},
|
|
9871
10067
|
disposables,
|
|
9872
10068
|
scheduler,
|
|
9873
10069
|
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
|
-
});
|
|
10070
|
+
if (disposed || !startup) return false;
|
|
10071
|
+
startup.update(createStartupSnapshot(currentConfig, resources));
|
|
9883
10072
|
requestRender();
|
|
10073
|
+
return true;
|
|
9884
10074
|
},
|
|
9885
10075
|
dismissStartup() {
|
|
9886
10076
|
startup?.dismiss();
|
|
9887
10077
|
},
|
|
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
|
-
});
|
|
10078
|
+
update(values, options = {}) {
|
|
10079
|
+
if (disposed) return false;
|
|
10080
|
+
const patch = {
|
|
10081
|
+
...values
|
|
10082
|
+
};
|
|
10083
|
+
if (options.refreshContextUsage) {
|
|
10084
|
+
const context = contextSnapshot();
|
|
10085
|
+
patch.context = context;
|
|
10086
|
+
if (context) contextProvider.set("active", context);
|
|
10087
|
+
else contextProvider.clear();
|
|
10088
|
+
}
|
|
10089
|
+
if (options.refreshExtensionStatuses) patch.extensionStatuses = extensionStatuses();
|
|
10090
|
+
return updateSnapshot(withSnapshotPatch(patch));
|
|
9913
10091
|
},
|
|
9914
10092
|
configure(nextConfig) {
|
|
9915
10093
|
if (disposed) return;
|
|
@@ -9944,17 +10122,7 @@ function createPiStyleRuntime(host, generation2, requestRender = () => {
|
|
|
9944
10122
|
git.invalidate(host.cwd);
|
|
9945
10123
|
void git.get(host.cwd).then((value) => {
|
|
9946
10124
|
if (disposed) return;
|
|
9947
|
-
|
|
9948
|
-
statusLine?.update(currentSnapshot);
|
|
9949
|
-
editor?.update(currentSnapshot);
|
|
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
|
|
9956
|
-
});
|
|
9957
|
-
requestRender();
|
|
10125
|
+
if (updateSnapshot(withSnapshotPatch({ git: value }))) requestRender();
|
|
9958
10126
|
});
|
|
9959
10127
|
},
|
|
9960
10128
|
get disposed() {
|
|
@@ -10158,10 +10326,10 @@ function createPiStyleApp(initialConfig, reloadPort, onConfigChange) {
|
|
|
10158
10326
|
sessionShutdown() {
|
|
10159
10327
|
runtime.stop();
|
|
10160
10328
|
},
|
|
10161
|
-
update(values, kind = "coalesced") {
|
|
10329
|
+
update(values, kind = "coalesced", options) {
|
|
10162
10330
|
const active = runtime.current;
|
|
10163
10331
|
if (!active) return;
|
|
10164
|
-
active.update(values);
|
|
10332
|
+
if (!active.update(values, options)) return;
|
|
10165
10333
|
active.scheduler.schedule(kind);
|
|
10166
10334
|
},
|
|
10167
10335
|
reload() {
|
|
@@ -10464,9 +10632,11 @@ function renderBashExecutionBox(instance, args) {
|
|
|
10464
10632
|
try {
|
|
10465
10633
|
if (host.piStyleStart === void 0) host.piStyleStart = Date.now();
|
|
10466
10634
|
const renderedWidth = boxWidth(width);
|
|
10635
|
+
const cacheKey2 = `${themeCacheKey(theme)}|${width}|${host.status}|${host.exitCode ?? ""}|${host.command}`;
|
|
10636
|
+
if (host.status !== "running" && host.piStyleRenderCache?.key === cacheKey2) return host.piStyleRenderCache.lines;
|
|
10467
10637
|
const inner = boxInnerWidth(renderedWidth);
|
|
10468
10638
|
const wrapped = content.render(inner).map((line) => boxLine(theme, line.startsWith(" ") ? line.slice(1) : line, renderedWidth));
|
|
10469
|
-
|
|
10639
|
+
const lines = [
|
|
10470
10640
|
"",
|
|
10471
10641
|
boxLabeledBorder(theme, TOP_LEFT, TOP_RIGHT, bashBoxTitle(theme, host), void 0, renderedWidth),
|
|
10472
10642
|
boxBlankLine(theme, renderedWidth),
|
|
@@ -10474,6 +10644,8 @@ function renderBashExecutionBox(instance, args) {
|
|
|
10474
10644
|
boxBlankLine(theme, renderedWidth),
|
|
10475
10645
|
boxLabeledBorder(theme, BOTTOM_LEFT, BOTTOM_RIGHT, bashBoxFooter(theme, host), void 0, renderedWidth)
|
|
10476
10646
|
];
|
|
10647
|
+
if (host.status !== "running") host.piStyleRenderCache = { key: cacheKey2, lines };
|
|
10648
|
+
return lines;
|
|
10477
10649
|
} catch {
|
|
10478
10650
|
return void 0;
|
|
10479
10651
|
}
|
|
@@ -10504,17 +10676,27 @@ import {
|
|
|
10504
10676
|
} from "@earendil-works/pi-coding-agent";
|
|
10505
10677
|
|
|
10506
10678
|
// extension-src/pi-style/features/messages/index.ts
|
|
10507
|
-
import { visibleWidth as visibleWidth4 } from "@earendil-works/pi-tui";
|
|
10508
10679
|
var OSC133_ZONE_START = "\x1B]133;A\x07";
|
|
10509
10680
|
var OSC133_ZONE_END = "\x1B]133;B\x07";
|
|
10510
10681
|
var OSC133_ZONE_FINAL = "\x1B]133;C\x07";
|
|
10682
|
+
var BG_RESET = "\x1B[49m";
|
|
10683
|
+
var MAX_RENDER_CACHE_KEYS_PER_INSTANCE = 8;
|
|
10684
|
+
var MAX_LINE_ANALYSIS_ENTRIES = 4096;
|
|
10685
|
+
var renderCacheByInstance = /* @__PURE__ */ new WeakMap();
|
|
10686
|
+
var lineAnalysisCache = /* @__PURE__ */ new Map();
|
|
10687
|
+
var messageDecorationTestState = {
|
|
10688
|
+
decoratePasses: 0,
|
|
10689
|
+
cacheHits: 0,
|
|
10690
|
+
cacheMisses: 0,
|
|
10691
|
+
lineCacheHits: 0,
|
|
10692
|
+
lineCacheMisses: 0
|
|
10693
|
+
};
|
|
10511
10694
|
function extractOscEnvelope(line) {
|
|
10512
10695
|
if (!line.startsWith(OSC133_ZONE_START)) return void 0;
|
|
10513
10696
|
const bodyEnd = line.indexOf(OSC133_ZONE_END, OSC133_ZONE_START.length);
|
|
10514
10697
|
if (bodyEnd < 0 || !line.endsWith(OSC133_ZONE_FINAL)) return void 0;
|
|
10515
10698
|
return { start: OSC133_ZONE_START, body: line.slice(OSC133_ZONE_START.length, bodyEnd), end: line.slice(bodyEnd) };
|
|
10516
10699
|
}
|
|
10517
|
-
var BG_RESET = "\x1B[49m";
|
|
10518
10700
|
function splitLeadingMarkers(line) {
|
|
10519
10701
|
let index = 0;
|
|
10520
10702
|
while (line.startsWith("\x1B]", index)) {
|
|
@@ -10546,39 +10728,6 @@ function isBackgroundSgr(sequence) {
|
|
|
10546
10728
|
}
|
|
10547
10729
|
return false;
|
|
10548
10730
|
}
|
|
10549
|
-
function rebuildAtWidth(line, width, lead) {
|
|
10550
|
-
const { head, rest } = splitLeadingMarkers(line);
|
|
10551
|
-
const bgAnsi = leadingSgr(rest);
|
|
10552
|
-
if (bgAnsi && isBackgroundSgr(bgAnsi) && rest.endsWith(BG_RESET)) {
|
|
10553
|
-
const body = rest.slice(bgAnsi.length, rest.length - BG_RESET.length);
|
|
10554
|
-
const pad = " ".repeat(Math.max(0, width - visibleWidth4(lead) - visibleWidth4(body)));
|
|
10555
|
-
return `${head}${bgAnsi}${lead}${body}${pad}${BG_RESET}`;
|
|
10556
|
-
}
|
|
10557
|
-
const padded = `${lead}${line}`;
|
|
10558
|
-
return `${padded}${" ".repeat(Math.max(0, width - visibleWidth4(padded)))}`;
|
|
10559
|
-
}
|
|
10560
|
-
function decorateMessageLine(line, index, lastIndex, contentIndex, width, options) {
|
|
10561
|
-
const { firstEnvelope, firstHasStart, multilineEnvelope, prefix } = options;
|
|
10562
|
-
const prefixWidth = visibleWidth4(prefix);
|
|
10563
|
-
const lead = index === contentIndex ? prefix : index > contentIndex ? " ".repeat(prefixWidth) : "";
|
|
10564
|
-
if (index === contentIndex && firstEnvelope)
|
|
10565
|
-
return `${firstEnvelope.start}${rebuildAtWidth(firstEnvelope.body, width, prefix)}${firstEnvelope.end}`;
|
|
10566
|
-
if (index === contentIndex && firstHasStart)
|
|
10567
|
-
return `${OSC133_ZONE_START}${rebuildAtWidth(line.slice(OSC133_ZONE_START.length), width, prefix)}`;
|
|
10568
|
-
if (index === lastIndex && multilineEnvelope && index !== contentIndex)
|
|
10569
|
-
return `${OSC133_ZONE_END}${OSC133_ZONE_FINAL}${rebuildAtWidth(
|
|
10570
|
-
line.slice((OSC133_ZONE_END + OSC133_ZONE_FINAL).length),
|
|
10571
|
-
width,
|
|
10572
|
-
lead
|
|
10573
|
-
)}`;
|
|
10574
|
-
if (index === contentIndex && index === lastIndex && multilineEnvelope && line.startsWith(OSC133_ZONE_END + OSC133_ZONE_FINAL))
|
|
10575
|
-
return `${OSC133_ZONE_END}${OSC133_ZONE_FINAL}${rebuildAtWidth(
|
|
10576
|
-
line.slice((OSC133_ZONE_END + OSC133_ZONE_FINAL).length),
|
|
10577
|
-
width,
|
|
10578
|
-
prefix
|
|
10579
|
-
)}`;
|
|
10580
|
-
return rebuildAtWidth(line, width, lead);
|
|
10581
|
-
}
|
|
10582
10731
|
function contentText(line) {
|
|
10583
10732
|
let output = "";
|
|
10584
10733
|
for (let index = 0; index < line.length; index++) {
|
|
@@ -10602,32 +10751,127 @@ function contentText(line) {
|
|
|
10602
10751
|
function hasContent(line) {
|
|
10603
10752
|
return [...contentText(line)].some((character) => !/\s/u.test(character));
|
|
10604
10753
|
}
|
|
10754
|
+
function getLineAnalysis(line) {
|
|
10755
|
+
const cached = lineAnalysisCache.get(line);
|
|
10756
|
+
if (cached) {
|
|
10757
|
+
messageDecorationTestState.lineCacheHits++;
|
|
10758
|
+
return cached;
|
|
10759
|
+
}
|
|
10760
|
+
messageDecorationTestState.lineCacheMisses++;
|
|
10761
|
+
const leadingMarkers = splitLeadingMarkers(line);
|
|
10762
|
+
const backgroundAnsi = leadingSgr(leadingMarkers.rest);
|
|
10763
|
+
const isBackgroundWrapped = backgroundAnsi !== "" && isBackgroundSgr(backgroundAnsi) && leadingMarkers.rest.endsWith(BG_RESET);
|
|
10764
|
+
const backgroundBody = isBackgroundWrapped ? leadingMarkers.rest.slice(backgroundAnsi.length, leadingMarkers.rest.length - BG_RESET.length) : void 0;
|
|
10765
|
+
const analysis = {
|
|
10766
|
+
visibleWidth: visibleWidth(line),
|
|
10767
|
+
hasContent: hasContent(line),
|
|
10768
|
+
oscEnvelope: extractOscEnvelope(line),
|
|
10769
|
+
hasOscStart: line.startsWith(OSC133_ZONE_START),
|
|
10770
|
+
leadingMarkers,
|
|
10771
|
+
isBackgroundWrapped,
|
|
10772
|
+
backgroundAnsi,
|
|
10773
|
+
backgroundBody,
|
|
10774
|
+
backgroundBodyWidth: backgroundBody === void 0 ? void 0 : visibleWidth(backgroundBody)
|
|
10775
|
+
};
|
|
10776
|
+
lineAnalysisCache.set(line, analysis);
|
|
10777
|
+
if (lineAnalysisCache.size > MAX_LINE_ANALYSIS_ENTRIES) {
|
|
10778
|
+
const oldestKey = lineAnalysisCache.keys().next().value;
|
|
10779
|
+
if (oldestKey !== void 0) lineAnalysisCache.delete(oldestKey);
|
|
10780
|
+
}
|
|
10781
|
+
return analysis;
|
|
10782
|
+
}
|
|
10783
|
+
function rebuildAtWidth(line, width, lead, leadWidth, analysis = getLineAnalysis(line)) {
|
|
10784
|
+
if (analysis.isBackgroundWrapped && analysis.backgroundBody !== void 0 && analysis.backgroundBodyWidth !== void 0) {
|
|
10785
|
+
const pad2 = " ".repeat(Math.max(0, width - leadWidth - analysis.backgroundBodyWidth));
|
|
10786
|
+
return `${analysis.leadingMarkers.head}${analysis.backgroundAnsi}${lead}${analysis.backgroundBody}${pad2}${BG_RESET}`;
|
|
10787
|
+
}
|
|
10788
|
+
const pad = " ".repeat(Math.max(0, width - leadWidth - analysis.visibleWidth));
|
|
10789
|
+
return `${lead}${line}${pad}`;
|
|
10790
|
+
}
|
|
10791
|
+
function decorateMessageLine(line, index, lastIndex, contentIndex, width, options, analysis = getLineAnalysis(line)) {
|
|
10792
|
+
const { firstEnvelope, firstHasStart, multilineEnvelope, prefix, prefixWidth } = options;
|
|
10793
|
+
const lead = index === contentIndex ? prefix : index > contentIndex ? " ".repeat(prefixWidth) : "";
|
|
10794
|
+
const leadWidth = index < contentIndex ? 0 : prefixWidth;
|
|
10795
|
+
if (index === contentIndex && firstEnvelope)
|
|
10796
|
+
return `${firstEnvelope.start}${rebuildAtWidth(firstEnvelope.body, width, prefix, prefixWidth)}${firstEnvelope.end}`;
|
|
10797
|
+
if (index === contentIndex && firstHasStart)
|
|
10798
|
+
return `${OSC133_ZONE_START}${rebuildAtWidth(line.slice(OSC133_ZONE_START.length), width, prefix, prefixWidth)}`;
|
|
10799
|
+
if (index === lastIndex && multilineEnvelope && index !== contentIndex)
|
|
10800
|
+
return `${OSC133_ZONE_END}${OSC133_ZONE_FINAL}${rebuildAtWidth(
|
|
10801
|
+
line.slice((OSC133_ZONE_END + OSC133_ZONE_FINAL).length),
|
|
10802
|
+
width,
|
|
10803
|
+
lead,
|
|
10804
|
+
leadWidth
|
|
10805
|
+
)}`;
|
|
10806
|
+
if (index === contentIndex && index === lastIndex && multilineEnvelope && line.startsWith(OSC133_ZONE_END + OSC133_ZONE_FINAL))
|
|
10807
|
+
return `${OSC133_ZONE_END}${OSC133_ZONE_FINAL}${rebuildAtWidth(
|
|
10808
|
+
line.slice((OSC133_ZONE_END + OSC133_ZONE_FINAL).length),
|
|
10809
|
+
width,
|
|
10810
|
+
prefix,
|
|
10811
|
+
prefixWidth
|
|
10812
|
+
)}`;
|
|
10813
|
+
return rebuildAtWidth(line, width, lead, leadWidth, analysis);
|
|
10814
|
+
}
|
|
10815
|
+
function sameLines(left, right) {
|
|
10816
|
+
if (left === right) return true;
|
|
10817
|
+
if (left.length !== right.length) return false;
|
|
10818
|
+
for (let index = 0; index < left.length; index++) {
|
|
10819
|
+
if (left[index] !== right[index]) return false;
|
|
10820
|
+
}
|
|
10821
|
+
return true;
|
|
10822
|
+
}
|
|
10823
|
+
function cacheKey(width, prefix) {
|
|
10824
|
+
return `${width}\0${prefix}`;
|
|
10825
|
+
}
|
|
10826
|
+
function getRenderCache(instance) {
|
|
10827
|
+
let cache = renderCacheByInstance.get(instance);
|
|
10828
|
+
if (!cache) {
|
|
10829
|
+
cache = /* @__PURE__ */ new Map();
|
|
10830
|
+
renderCacheByInstance.set(instance, cache);
|
|
10831
|
+
}
|
|
10832
|
+
return cache;
|
|
10833
|
+
}
|
|
10834
|
+
function storeRenderCache(instance, width, prefix, native, result) {
|
|
10835
|
+
const cache = getRenderCache(instance);
|
|
10836
|
+
const key = cacheKey(width, prefix);
|
|
10837
|
+
if (cache.has(key)) cache.delete(key);
|
|
10838
|
+
cache.set(key, { nativeRef: native, nativeLines: [...native], result: [...result] });
|
|
10839
|
+
while (cache.size > MAX_RENDER_CACHE_KEYS_PER_INSTANCE) {
|
|
10840
|
+
const oldestKey = cache.keys().next().value;
|
|
10841
|
+
if (oldestKey === void 0) break;
|
|
10842
|
+
cache.delete(oldestKey);
|
|
10843
|
+
}
|
|
10844
|
+
}
|
|
10605
10845
|
function prefixNative(lines, width, prefix) {
|
|
10606
10846
|
if (!Array.isArray(lines) || lines.length === 0 || !lines.every((line) => typeof line === "string")) return void 0;
|
|
10847
|
+
messageDecorationTestState.decoratePasses++;
|
|
10607
10848
|
const nativeLines = lines;
|
|
10608
|
-
const prefixWidth =
|
|
10849
|
+
const prefixWidth = visibleWidth(prefix);
|
|
10609
10850
|
if (width <= prefixWidth) return void 0;
|
|
10610
10851
|
const bodyWidth = width - prefixWidth;
|
|
10611
10852
|
const first = nativeLines[0] ?? "";
|
|
10612
10853
|
const last = nativeLines.at(-1) ?? "";
|
|
10854
|
+
const lastAnalysis = getLineAnalysis(last);
|
|
10613
10855
|
const multilineEnvelope = nativeLines.length > 1 && last.startsWith(OSC133_ZONE_END + OSC133_ZONE_FINAL);
|
|
10614
10856
|
const firstContentIndex = nativeLines.findIndex((line, index) => {
|
|
10615
|
-
if (index !== nativeLines.length - 1 || !multilineEnvelope) return
|
|
10616
|
-
return !nativeLines.slice(0, index).some((earlier) =>
|
|
10857
|
+
if (index !== nativeLines.length - 1 || !multilineEnvelope) return getLineAnalysis(line).hasContent;
|
|
10858
|
+
return !nativeLines.slice(0, index).some((earlier) => getLineAnalysis(earlier).hasContent) && lastAnalysis.hasContent;
|
|
10617
10859
|
});
|
|
10618
10860
|
if (firstContentIndex < 0) return nativeLines;
|
|
10619
|
-
const
|
|
10620
|
-
const
|
|
10861
|
+
const firstAnalysis = getLineAnalysis(first);
|
|
10862
|
+
const firstEnvelope = firstContentIndex === 0 ? firstAnalysis.oscEnvelope : void 0;
|
|
10863
|
+
const firstHasStart = firstContentIndex === 0 && firstAnalysis.hasOscStart;
|
|
10621
10864
|
const decorated = nativeLines.map(
|
|
10622
10865
|
(line, index) => decorateMessageLine(line, index, nativeLines.length - 1, firstContentIndex, width, {
|
|
10623
10866
|
firstEnvelope,
|
|
10624
10867
|
firstHasStart,
|
|
10625
10868
|
multilineEnvelope,
|
|
10626
|
-
prefix
|
|
10869
|
+
prefix,
|
|
10870
|
+
prefixWidth
|
|
10627
10871
|
})
|
|
10628
10872
|
);
|
|
10629
|
-
if (!decorated.every((line) =>
|
|
10630
|
-
if (!nativeLines.every((line) =>
|
|
10873
|
+
if (!decorated.every((line) => visibleWidth(line) <= width)) return void 0;
|
|
10874
|
+
if (!nativeLines.every((line) => getLineAnalysis(line).visibleWidth <= bodyWidth)) return void 0;
|
|
10631
10875
|
return decorated;
|
|
10632
10876
|
}
|
|
10633
10877
|
function decorateMessageRender(original, instance, args, snapshot = {
|
|
@@ -10640,10 +10884,20 @@ function decorateMessageRender(original, instance, args, snapshot = {
|
|
|
10640
10884
|
const width = typeof args[0] === "number" ? args[0] : 0;
|
|
10641
10885
|
const prefix = snapshot.assistantPrefix;
|
|
10642
10886
|
if (!snapshot.assistantEnabled) return Reflect.apply(original, instance, args);
|
|
10643
|
-
|
|
10644
|
-
|
|
10887
|
+
const prefixWidth = visibleWidth(prefix);
|
|
10888
|
+
if (width <= prefixWidth) return Reflect.apply(original, instance, args);
|
|
10889
|
+
const reducedWidth = width - prefixWidth;
|
|
10645
10890
|
const native = Reflect.apply(original, instance, [reducedWidth, ...args.slice(1)]);
|
|
10646
|
-
|
|
10891
|
+
if (!Array.isArray(native) || !native.every((line) => typeof line === "string")) return native;
|
|
10892
|
+
const cached = getRenderCache(instance).get(cacheKey(width, prefix));
|
|
10893
|
+
if (cached && (cached.nativeRef === native || sameLines(cached.nativeLines, native))) {
|
|
10894
|
+
messageDecorationTestState.cacheHits++;
|
|
10895
|
+
return [...cached.result];
|
|
10896
|
+
}
|
|
10897
|
+
messageDecorationTestState.cacheMisses++;
|
|
10898
|
+
const decorated = prefixNative(native, width, prefix) ?? native;
|
|
10899
|
+
storeRenderCache(instance, width, prefix, native, decorated);
|
|
10900
|
+
return decorated;
|
|
10647
10901
|
}
|
|
10648
10902
|
function isSpacerChild(child) {
|
|
10649
10903
|
return typeof child?.setLines === "function";
|
|
@@ -11003,7 +11257,7 @@ var KNOWN_NATIVE_IDENTITIES = Object.freeze({
|
|
|
11003
11257
|
});
|
|
11004
11258
|
var TRUSTED_NATIVE_FINGERPRINTS = Object.freeze(
|
|
11005
11259
|
Object.fromEntries(
|
|
11006
|
-
Object.entries(KNOWN_NATIVE_IDENTITIES).map(([key, identities]) => [key, identities[0]
|
|
11260
|
+
Object.entries(KNOWN_NATIVE_IDENTITIES).map(([key, identities]) => [key, identities[0]?.fingerprint ?? ""])
|
|
11007
11261
|
)
|
|
11008
11262
|
);
|
|
11009
11263
|
function fingerprint(value) {
|
|
@@ -11859,22 +12113,134 @@ function createPiStyleSessionCoordinator(pi, hooks = {}) {
|
|
|
11859
12113
|
}
|
|
11860
12114
|
|
|
11861
12115
|
// extension-src/pi-style/pi/session-usage.ts
|
|
12116
|
+
var usageCache = /* @__PURE__ */ new WeakMap();
|
|
11862
12117
|
function usageFromSession(session) {
|
|
11863
|
-
const
|
|
11864
|
-
|
|
11865
|
-
|
|
11866
|
-
|
|
11867
|
-
|
|
11868
|
-
|
|
11869
|
-
|
|
11870
|
-
|
|
11871
|
-
|
|
11872
|
-
|
|
11873
|
-
|
|
11874
|
-
|
|
11875
|
-
|
|
11876
|
-
|
|
11877
|
-
|
|
12118
|
+
const entries = session.getEntries();
|
|
12119
|
+
const state = usageCache.get(session) ?? createState();
|
|
12120
|
+
usageCache.set(session, state);
|
|
12121
|
+
if (entries.length === 0) {
|
|
12122
|
+
state.cacheHits++;
|
|
12123
|
+
state.processedLength = 0;
|
|
12124
|
+
state.lastEntryId = void 0;
|
|
12125
|
+
state.lastEntryRef = void 0;
|
|
12126
|
+
state.lastContribution = emptyContribution();
|
|
12127
|
+
state.totals = emptyTotals();
|
|
12128
|
+
state.cached = void 0;
|
|
12129
|
+
return void 0;
|
|
12130
|
+
}
|
|
12131
|
+
if (state.processedLength === 0) {
|
|
12132
|
+
rebuildFrom(entries, state);
|
|
12133
|
+
return state.cached;
|
|
12134
|
+
}
|
|
12135
|
+
if (entries.length < state.processedLength) {
|
|
12136
|
+
rebuildFrom(entries, state);
|
|
12137
|
+
return state.cached;
|
|
12138
|
+
}
|
|
12139
|
+
const currentLast = entries.at(-1);
|
|
12140
|
+
if (!currentLast) {
|
|
12141
|
+
state.cacheHits++;
|
|
12142
|
+
state.cached = void 0;
|
|
12143
|
+
return void 0;
|
|
12144
|
+
}
|
|
12145
|
+
if (entries.length === state.processedLength) {
|
|
12146
|
+
if (currentLast.id !== state.lastEntryId) {
|
|
12147
|
+
rebuildFrom(entries, state);
|
|
12148
|
+
return state.cached;
|
|
12149
|
+
}
|
|
12150
|
+
if (currentLast !== state.lastEntryRef) refreshTailEntry(currentLast, state);
|
|
12151
|
+
else state.cacheHits++;
|
|
12152
|
+
return state.cached;
|
|
12153
|
+
}
|
|
12154
|
+
const previousLast = entries[state.processedLength - 1];
|
|
12155
|
+
if (!previousLast || previousLast.id !== state.lastEntryId) {
|
|
12156
|
+
rebuildFrom(entries, state);
|
|
12157
|
+
return state.cached;
|
|
12158
|
+
}
|
|
12159
|
+
if (previousLast !== state.lastEntryRef) refreshTailEntry(previousLast, state);
|
|
12160
|
+
for (const entry of entries.slice(state.processedLength)) appendEntry(entry, state);
|
|
12161
|
+
return state.cached;
|
|
12162
|
+
}
|
|
12163
|
+
function resetUsageFromSessionCache(session) {
|
|
12164
|
+
if (session) {
|
|
12165
|
+
usageCache.delete(session);
|
|
12166
|
+
return;
|
|
12167
|
+
}
|
|
12168
|
+
usageCache = /* @__PURE__ */ new WeakMap();
|
|
12169
|
+
}
|
|
12170
|
+
function createState() {
|
|
12171
|
+
return {
|
|
12172
|
+
processedLength: 0,
|
|
12173
|
+
lastEntryId: void 0,
|
|
12174
|
+
lastEntryRef: void 0,
|
|
12175
|
+
lastContribution: emptyContribution(),
|
|
12176
|
+
totals: emptyTotals(),
|
|
12177
|
+
cached: void 0,
|
|
12178
|
+
scannedEntries: 0,
|
|
12179
|
+
cacheHits: 0,
|
|
12180
|
+
rebuilds: 0,
|
|
12181
|
+
tailRefreshes: 0
|
|
12182
|
+
};
|
|
12183
|
+
}
|
|
12184
|
+
function rebuildFrom(entries, state) {
|
|
12185
|
+
state.rebuilds++;
|
|
12186
|
+
state.processedLength = 0;
|
|
12187
|
+
state.lastEntryId = void 0;
|
|
12188
|
+
state.lastEntryRef = void 0;
|
|
12189
|
+
state.lastContribution = emptyContribution();
|
|
12190
|
+
state.totals = emptyTotals();
|
|
12191
|
+
state.cached = void 0;
|
|
12192
|
+
for (const entry of entries) appendEntry(entry, state);
|
|
12193
|
+
}
|
|
12194
|
+
function refreshTailEntry(entry, state) {
|
|
12195
|
+
state.tailRefreshes++;
|
|
12196
|
+
subtractContribution(state.totals, state.lastContribution);
|
|
12197
|
+
const contribution = usageContribution(entry);
|
|
12198
|
+
addContribution(state.totals, contribution);
|
|
12199
|
+
state.lastEntryId = entry.id;
|
|
12200
|
+
state.lastEntryRef = entry;
|
|
12201
|
+
state.lastContribution = contribution;
|
|
12202
|
+
state.cached = snapshotFromTotals(state.totals);
|
|
12203
|
+
state.scannedEntries++;
|
|
12204
|
+
}
|
|
12205
|
+
function appendEntry(entry, state) {
|
|
12206
|
+
const contribution = usageContribution(entry);
|
|
12207
|
+
addContribution(state.totals, contribution);
|
|
12208
|
+
state.processedLength++;
|
|
12209
|
+
state.lastEntryId = entry.id;
|
|
12210
|
+
state.lastEntryRef = entry;
|
|
12211
|
+
state.lastContribution = contribution;
|
|
12212
|
+
state.cached = snapshotFromTotals(state.totals);
|
|
12213
|
+
state.scannedEntries++;
|
|
12214
|
+
}
|
|
12215
|
+
function usageContribution(entry) {
|
|
12216
|
+
if (entry.type === "message") {
|
|
12217
|
+
if (entry.message.role !== "assistant" && entry.message.role !== "toolResult") return emptyContribution();
|
|
12218
|
+
const usage = "usage" in entry.message ? entry.message.usage : void 0;
|
|
12219
|
+
if (!usage) return emptyContribution();
|
|
12220
|
+
return {
|
|
12221
|
+
input: usage.input,
|
|
12222
|
+
output: usage.output,
|
|
12223
|
+
cacheRead: usage.cacheRead,
|
|
12224
|
+
cacheWrite: usage.cacheWrite,
|
|
12225
|
+
cost: usage.cost.total,
|
|
12226
|
+
sawUsage: true
|
|
12227
|
+
};
|
|
12228
|
+
}
|
|
12229
|
+
if ((entry.type === "branch_summary" || entry.type === "compaction") && entry.usage) {
|
|
12230
|
+
return {
|
|
12231
|
+
input: entry.usage.input,
|
|
12232
|
+
output: entry.usage.output,
|
|
12233
|
+
cacheRead: entry.usage.cacheRead,
|
|
12234
|
+
cacheWrite: entry.usage.cacheWrite,
|
|
12235
|
+
cost: entry.usage.cost.total,
|
|
12236
|
+
sawUsage: true
|
|
12237
|
+
};
|
|
12238
|
+
}
|
|
12239
|
+
return emptyContribution();
|
|
12240
|
+
}
|
|
12241
|
+
function snapshotFromTotals(totals) {
|
|
12242
|
+
if (totals.input === 0 && totals.output === 0 && totals.cacheRead === 0 && totals.cacheWrite === 0 && totals.cost === 0)
|
|
12243
|
+
return void 0;
|
|
11878
12244
|
return {
|
|
11879
12245
|
inputTokens: totals.input,
|
|
11880
12246
|
outputTokens: totals.output,
|
|
@@ -11885,18 +12251,30 @@ function usageFromSession(session) {
|
|
|
11885
12251
|
streaming: false
|
|
11886
12252
|
};
|
|
11887
12253
|
}
|
|
11888
|
-
function
|
|
12254
|
+
function addContribution(totals, usage) {
|
|
11889
12255
|
totals.input += usage.input;
|
|
11890
12256
|
totals.output += usage.output;
|
|
11891
12257
|
totals.cacheRead += usage.cacheRead;
|
|
11892
12258
|
totals.cacheWrite += usage.cacheWrite;
|
|
11893
|
-
totals.cost += usage.cost
|
|
12259
|
+
totals.cost += usage.cost;
|
|
12260
|
+
}
|
|
12261
|
+
function subtractContribution(totals, usage) {
|
|
12262
|
+
totals.input -= usage.input;
|
|
12263
|
+
totals.output -= usage.output;
|
|
12264
|
+
totals.cacheRead -= usage.cacheRead;
|
|
12265
|
+
totals.cacheWrite -= usage.cacheWrite;
|
|
12266
|
+
totals.cost -= usage.cost;
|
|
12267
|
+
}
|
|
12268
|
+
function emptyTotals() {
|
|
12269
|
+
return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 };
|
|
12270
|
+
}
|
|
12271
|
+
function emptyContribution() {
|
|
12272
|
+
return { ...emptyTotals(), sawUsage: false };
|
|
11894
12273
|
}
|
|
11895
12274
|
|
|
11896
12275
|
// extension-src/pi-style/pi/index.ts
|
|
11897
12276
|
function usagePatch(ctx) {
|
|
11898
|
-
|
|
11899
|
-
return usage ? { usage } : {};
|
|
12277
|
+
return { usage: usageFromSession(ctx.sessionManager) };
|
|
11900
12278
|
}
|
|
11901
12279
|
function activateReadOnlyTools(pi) {
|
|
11902
12280
|
const available = new Set(pi.getAllTools().map((tool) => tool.name));
|
|
@@ -11931,6 +12309,7 @@ function piStyleExtension(pi) {
|
|
|
11931
12309
|
const coordinator = createPiStyleSessionCoordinator(pi, compatibilityTestHooks);
|
|
11932
12310
|
registerPiStyleCommand(pi, coordinator.app);
|
|
11933
12311
|
pi.on("session_start", async (event, ctx) => {
|
|
12312
|
+
resetUsageFromSessionCache(ctx.sessionManager);
|
|
11934
12313
|
if (pi.getFlag("pi-style-readonly-tools") === true) {
|
|
11935
12314
|
activateReadOnlyTools(pi);
|
|
11936
12315
|
}
|
|
@@ -11964,15 +12343,21 @@ function piStyleExtension(pi) {
|
|
|
11964
12343
|
)
|
|
11965
12344
|
);
|
|
11966
12345
|
pi.on("thinking_level_select", (event) => coordinator.app.update({ thinkingLevel: event.level }, "immediate"));
|
|
11967
|
-
pi.on(
|
|
12346
|
+
pi.on(
|
|
12347
|
+
"session_info_changed",
|
|
12348
|
+
(event) => coordinator.app.update({ sessionName: event.name }, "coalesced", { refreshExtensionStatuses: true })
|
|
12349
|
+
);
|
|
11968
12350
|
pi.on("message_start", () => {
|
|
11969
12351
|
closeActiveBatch();
|
|
11970
12352
|
});
|
|
11971
12353
|
pi.on("message_update", () => coordinator.app.update({}, "coalesced"));
|
|
11972
|
-
pi.on(
|
|
12354
|
+
pi.on(
|
|
12355
|
+
"message_end",
|
|
12356
|
+
(_event, ctx) => coordinator.app.update({ ...usagePatch(ctx) }, "coalesced", { refreshContextUsage: true })
|
|
12357
|
+
);
|
|
11973
12358
|
pi.on("turn_end", (event, ctx) => {
|
|
11974
12359
|
registerTurnFromMessage(event.message, event.toolResults);
|
|
11975
|
-
coordinator.app.update({ ...usagePatch(ctx) }, "deferred");
|
|
12360
|
+
coordinator.app.update({ ...usagePatch(ctx) }, "deferred", { refreshContextUsage: true });
|
|
11976
12361
|
});
|
|
11977
12362
|
pi.on("agent_end", () => {
|
|
11978
12363
|
const run = finishAgentRun();
|
|
@@ -11981,23 +12366,33 @@ function piStyleExtension(pi) {
|
|
|
11981
12366
|
requestToolPresentationRender();
|
|
11982
12367
|
}
|
|
11983
12368
|
});
|
|
11984
|
-
pi.on(
|
|
12369
|
+
pi.on(
|
|
12370
|
+
"agent_settled",
|
|
12371
|
+
(_event, ctx) => coordinator.app.update({ ...usagePatch(ctx) }, "coalesced", { refreshContextUsage: true })
|
|
12372
|
+
);
|
|
11985
12373
|
pi.on("session_tree", (_event, ctx) => {
|
|
12374
|
+
resetUsageFromSessionCache(ctx.sessionManager);
|
|
11986
12375
|
rebuildTurnRegistryFromEntries(ctx.sessionManager.getEntries());
|
|
11987
|
-
coordinator.app.update({ ...usagePatch(ctx) }, "deferred");
|
|
12376
|
+
coordinator.app.update({ ...usagePatch(ctx) }, "deferred", { refreshContextUsage: true });
|
|
12377
|
+
});
|
|
12378
|
+
pi.on("session_compact", (_event, ctx) => {
|
|
12379
|
+
resetUsageFromSessionCache(ctx.sessionManager);
|
|
12380
|
+
coordinator.app.update({ ...usagePatch(ctx) }, "deferred", { refreshContextUsage: true });
|
|
11988
12381
|
});
|
|
11989
|
-
pi.on("session_compact", (_event, ctx) => coordinator.app.update({ ...usagePatch(ctx) }, "deferred"));
|
|
11990
12382
|
pi.on("tool_result", (event, ctx) => {
|
|
11991
12383
|
if (["write", "edit", "bash"].includes(event.toolName)) {
|
|
11992
12384
|
coordinator.app.runtime.current?.invalidateGit();
|
|
11993
|
-
coordinator.app.update({ ...usagePatch(ctx) }, "delayed-retry");
|
|
12385
|
+
coordinator.app.update({ ...usagePatch(ctx) }, "delayed-retry", { refreshContextUsage: true });
|
|
11994
12386
|
}
|
|
11995
12387
|
});
|
|
11996
12388
|
pi.on("user_bash", (_event, ctx) => {
|
|
11997
12389
|
coordinator.app.runtime.current?.invalidateGit();
|
|
11998
|
-
coordinator.app.update({ ...usagePatch(ctx) }, "delayed-retry");
|
|
12390
|
+
coordinator.app.update({ ...usagePatch(ctx) }, "delayed-retry", { refreshContextUsage: true });
|
|
12391
|
+
});
|
|
12392
|
+
pi.on("session_shutdown", (_event, ctx) => {
|
|
12393
|
+
resetUsageFromSessionCache(ctx.sessionManager);
|
|
12394
|
+
coordinator.shutdown();
|
|
11999
12395
|
});
|
|
12000
|
-
pi.on("session_shutdown", () => coordinator.shutdown());
|
|
12001
12396
|
}
|
|
12002
12397
|
export {
|
|
12003
12398
|
__setCompatibilityTestHooks,
|