@quandev104/pi-style 0.1.3 → 0.1.4
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 +379 -71
- package/dist/extensions/pi-style.js.map +1 -1
- package/extension-src/pi-style/domain/status.ts +1 -1
- package/extension-src/pi-style/features/tools/boxed/bash.ts +279 -45
- package/extension-src/pi-style/features/tools/boxed/edit.ts +28 -2
- package/extension-src/pi-style/features/tools/boxed/fallback.ts +47 -4
- package/extension-src/pi-style/features/tools/boxed/quick-edit.ts +25 -4
- package/extension-src/pi-style/features/tools/boxed/session-config.ts +64 -4
- package/extension-src/pi-style/features/tools/boxed/shared.ts +41 -1
- package/extension-src/pi-style/features/tools/boxed/write.ts +17 -1
- package/extension-src/pi-style/pi/session-coordinator.ts +9 -1
- package/extension-src/pi-style/shared/box.ts +78 -21
- package/package.json +1 -1
|
@@ -858,10 +858,14 @@ function formatBoxedStatusIcon(theme, isError) {
|
|
|
858
858
|
function formatToolTitlePrefix(theme, name) {
|
|
859
859
|
return colorFromExtra(theme, "bashPromptColor", "bashMode", `\u2794 ${name}`);
|
|
860
860
|
}
|
|
861
|
-
function formatBoxedToolTitle(theme, name, isError) {
|
|
862
|
-
const coloredTitle = isError ? theme.fg("error", `\u2794 ${name} \u2717`) : `${formatToolTitlePrefix(theme, name)} ${formatBoxedStatusIcon(theme, false)}`;
|
|
861
|
+
function formatBoxedToolTitle(theme, name, isError, status) {
|
|
862
|
+
const coloredTitle = isError ? theme.fg("error", `\u2794 ${name} \u2717`) : status === "running" ? `${formatToolTitlePrefix(theme, name)} ${theme.fg("text", "\u25CC")}` : status === "pending" ? formatToolTitlePrefix(theme, name) : `${formatToolTitlePrefix(theme, name)} ${formatBoxedStatusIcon(theme, false)}`;
|
|
863
863
|
return typeof theme?.bold === "function" ? theme.bold(coloredTitle) : coloredTitle;
|
|
864
864
|
}
|
|
865
|
+
function formatBoxedRunningStatus(theme, elapsedMs) {
|
|
866
|
+
const elapsed = elapsedMs === void 0 ? "" : `${theme.fg("text", ` \xB7 ${(elapsedMs / 1e3).toFixed(1)}s`)}`;
|
|
867
|
+
return `${theme.fg("dim", "\u25CC Running")}${elapsed}`;
|
|
868
|
+
}
|
|
865
869
|
function boxFrameText(theme, text) {
|
|
866
870
|
return `${RESET_INTENSITY}${theme.fg("border", text)}`;
|
|
867
871
|
}
|
|
@@ -970,7 +974,12 @@ function renderBoxedToolCall(theme, toolName, detailLines, options = {}) {
|
|
|
970
974
|
},
|
|
971
975
|
render(width) {
|
|
972
976
|
if (cache?.width === width) return cache.lines;
|
|
973
|
-
const title = formatBoxedToolTitle(
|
|
977
|
+
const title = formatBoxedToolTitle(
|
|
978
|
+
theme,
|
|
979
|
+
toolName,
|
|
980
|
+
options.isError,
|
|
981
|
+
options.isPending ? options.running ? "running" : "pending" : void 0
|
|
982
|
+
);
|
|
974
983
|
const headerLabel = options.headerDetail ? `${title} \xB7 ${options.headerDetail}` : title;
|
|
975
984
|
const renderedWidth = boxWidth(width);
|
|
976
985
|
const lines = [
|
|
@@ -978,15 +987,15 @@ function renderBoxedToolCall(theme, toolName, detailLines, options = {}) {
|
|
|
978
987
|
boxBlankLine(theme, renderedWidth),
|
|
979
988
|
...detailLines.flatMap((line) => boxedWrappedLines(theme, line, renderedWidth))
|
|
980
989
|
];
|
|
981
|
-
if (options.isPending) {
|
|
982
|
-
const
|
|
990
|
+
if (options.isPending && !options.resultSeen) {
|
|
991
|
+
const pendingLabel = options.pendingLabel ?? theme.fg("dim", `\u2026 ${options.pendingText ?? "Waiting for output\u2026"}`);
|
|
983
992
|
lines.push(
|
|
984
993
|
boxBlankLine(theme, renderedWidth),
|
|
985
994
|
boxLabeledBorder(
|
|
986
995
|
theme,
|
|
987
996
|
BOX_ROUND_BOTTOM_LEFT,
|
|
988
997
|
BOX_ROUND_BOTTOM_RIGHT,
|
|
989
|
-
|
|
998
|
+
pendingLabel,
|
|
990
999
|
void 0,
|
|
991
1000
|
renderedWidth
|
|
992
1001
|
)
|
|
@@ -1014,7 +1023,12 @@ function renderCompactBoxedToolCall(theme, toolName, detailLine, options = {}) {
|
|
|
1014
1023
|
},
|
|
1015
1024
|
render(width) {
|
|
1016
1025
|
const renderedWidth = boxWidth(width);
|
|
1017
|
-
const title = formatBoxedToolTitle(
|
|
1026
|
+
const title = formatBoxedToolTitle(
|
|
1027
|
+
theme,
|
|
1028
|
+
toolName,
|
|
1029
|
+
options.isError,
|
|
1030
|
+
options.isPending ? options.running ? "running" : "pending" : void 0
|
|
1031
|
+
);
|
|
1018
1032
|
const headerLabel = detailLine ? `${title} \xB7 ${detailLine}` : title;
|
|
1019
1033
|
const compactFooter = typeof options.state?.[COMPACT_FOOTER_KEY] === "string" ? options.state[COMPACT_FOOTER_KEY] : "";
|
|
1020
1034
|
const _footerIsError = Boolean(options.state?.[COMPACT_FOOTER_ERROR_KEY]);
|
|
@@ -1036,13 +1050,13 @@ function renderCompactBoxedToolCall(theme, toolName, detailLine, options = {}) {
|
|
|
1036
1050
|
)
|
|
1037
1051
|
);
|
|
1038
1052
|
} else if (options.isPending) {
|
|
1039
|
-
const
|
|
1053
|
+
const pendingLabel = options.pendingLabel ?? (options.running ? formatBoxedRunningStatus(theme, void 0) : theme.fg("dim", `\u2026 ${options.pendingText ?? "Waiting for output\u2026"}`));
|
|
1040
1054
|
lines.push(
|
|
1041
1055
|
boxLabeledBorder(
|
|
1042
1056
|
theme,
|
|
1043
1057
|
BOX_ROUND_BOTTOM_LEFT,
|
|
1044
1058
|
BOX_ROUND_BOTTOM_RIGHT,
|
|
1045
|
-
|
|
1059
|
+
pendingLabel,
|
|
1046
1060
|
options.bottomRightLabel,
|
|
1047
1061
|
renderedWidth
|
|
1048
1062
|
)
|
|
@@ -1065,19 +1079,21 @@ function renderBoxedToolResult(theme, body, options = {}) {
|
|
|
1065
1079
|
const renderedWidth = boxWidth(width);
|
|
1066
1080
|
const maxContentWidth = boxInnerWidth(renderedWidth);
|
|
1067
1081
|
const bodyLines = typeof body === "function" ? body(maxContentWidth) : body.render(maxContentWidth);
|
|
1068
|
-
const errorPrefix = options.isError ? [theme.fg("error", "\u2717 Error")] : [];
|
|
1082
|
+
const errorPrefix = options.isError ? [theme.fg("error", options.errorLabel ?? "\u2717 Error")] : [];
|
|
1069
1083
|
const outputLines = bodyLines.length > 0 ? [...errorPrefix, ...bodyLines] : [theme.fg("muted", `\u2205 ${options.emptyText ?? "(no output)"}`)];
|
|
1070
1084
|
const footerText = (options.footerLines ?? []).join(" \xB7 ");
|
|
1071
1085
|
const dividerText = typeof options.dividerLabel === "function" ? options.dividerLabel(renderedWidth) : options.dividerLabel ?? "Response";
|
|
1072
1086
|
const rendered = [
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1087
|
+
...options.showDivider === false ? [] : [
|
|
1088
|
+
boxLabeledBorder(
|
|
1089
|
+
theme,
|
|
1090
|
+
BOX_DIVIDER_LEFT,
|
|
1091
|
+
BOX_DIVIDER_RIGHT,
|
|
1092
|
+
theme.fg("dim", dividerText),
|
|
1093
|
+
options.dividerRightLabel ? theme.fg("dim", options.dividerRightLabel) : void 0,
|
|
1094
|
+
renderedWidth
|
|
1095
|
+
)
|
|
1096
|
+
],
|
|
1081
1097
|
boxBlankLine(theme, renderedWidth),
|
|
1082
1098
|
...renderBoxedOutputLines(theme, outputLines, renderedWidth, options.renderLineBudget ?? outputLines.length),
|
|
1083
1099
|
boxBlankLine(theme, renderedWidth),
|
|
@@ -1411,17 +1427,53 @@ function getToolsRenderConfig() {
|
|
|
1411
1427
|
return sessionToolsConfig;
|
|
1412
1428
|
}
|
|
1413
1429
|
var STARTED_AT_KEY = "__piStyleStartedAt";
|
|
1414
|
-
var
|
|
1430
|
+
var ENDED_AT_KEY = "__piStyleEndedAt";
|
|
1431
|
+
var RESULT_SEEN_KEY = "__piStyleResultSeen";
|
|
1432
|
+
var TICKER_KEY = "__piStyleElapsedTicker";
|
|
1415
1433
|
function recordExecutionStarted(state, executionStarted) {
|
|
1416
1434
|
if (!executionStarted || !state || typeof state !== "object") return;
|
|
1417
1435
|
if (typeof state[STARTED_AT_KEY] !== "number") state[STARTED_AT_KEY] = performance.now();
|
|
1418
1436
|
}
|
|
1437
|
+
function recordExecutionEnded(state) {
|
|
1438
|
+
if (!state || typeof state !== "object") return;
|
|
1439
|
+
if (typeof state[ENDED_AT_KEY] !== "number") state[ENDED_AT_KEY] = performance.now();
|
|
1440
|
+
}
|
|
1419
1441
|
function getStateElapsedMs(state) {
|
|
1420
1442
|
if (!state || typeof state !== "object") return void 0;
|
|
1421
|
-
|
|
1422
|
-
|
|
1443
|
+
const started = state[STARTED_AT_KEY];
|
|
1444
|
+
if (typeof started !== "number") return void 0;
|
|
1445
|
+
const ended = state[ENDED_AT_KEY];
|
|
1446
|
+
if (typeof ended === "number") return Math.max(0, ended - started);
|
|
1447
|
+
return Math.max(0, performance.now() - started);
|
|
1448
|
+
}
|
|
1449
|
+
function isResultSeen(state) {
|
|
1450
|
+
return Boolean(state && typeof state === "object" && state[RESULT_SEEN_KEY] === true);
|
|
1451
|
+
}
|
|
1452
|
+
function markResultSeen(state) {
|
|
1453
|
+
if (!state || typeof state !== "object") return;
|
|
1454
|
+
state[RESULT_SEEN_KEY] = true;
|
|
1455
|
+
}
|
|
1456
|
+
var tickerStates = /* @__PURE__ */ new Set();
|
|
1457
|
+
function startElapsedTicker(state, invalidate) {
|
|
1458
|
+
if (!state || typeof state !== "object") return;
|
|
1459
|
+
if (state[TICKER_KEY] !== void 0) return;
|
|
1460
|
+
state[TICKER_KEY] = setInterval(() => invalidate(), 1e3);
|
|
1461
|
+
tickerStates.add(state);
|
|
1462
|
+
}
|
|
1463
|
+
function stopElapsedTicker(state) {
|
|
1464
|
+
if (!state || typeof state !== "object") return;
|
|
1465
|
+
const handle = state[TICKER_KEY];
|
|
1466
|
+
if (handle !== void 0) clearInterval(handle);
|
|
1467
|
+
delete state[TICKER_KEY];
|
|
1468
|
+
tickerStates.delete(state);
|
|
1469
|
+
}
|
|
1470
|
+
function stopAllElapsedTickers() {
|
|
1471
|
+
for (const state of tickerStates) {
|
|
1472
|
+
const handle = state[TICKER_KEY];
|
|
1473
|
+
if (handle !== void 0) clearInterval(handle);
|
|
1474
|
+
delete state[TICKER_KEY];
|
|
1423
1475
|
}
|
|
1424
|
-
|
|
1476
|
+
tickerStates.clear();
|
|
1425
1477
|
}
|
|
1426
1478
|
|
|
1427
1479
|
// extension-src/pi-style/features/tools/boxed/batch.ts
|
|
@@ -2846,7 +2898,7 @@ function createBuiltinSegments() {
|
|
|
2846
2898
|
const token = contextBarToken(percent);
|
|
2847
2899
|
const window = snapshot.context?.windowTokens;
|
|
2848
2900
|
const label = `ctx${window !== void 0 ? ` (${formatTokens(window)})` : ""}:`;
|
|
2849
|
-
const width = options
|
|
2901
|
+
const width = options.context_bar?.width ?? CONTEXT_BAR_WIDTH;
|
|
2850
2902
|
return {
|
|
2851
2903
|
visible: true,
|
|
2852
2904
|
content: `${theme.apply("muted", label)} ${theme.apply(token, contextBar(percent, width))} ${theme.apply(token, `${Math.round(percent)}%`)}`,
|
|
@@ -5280,12 +5332,31 @@ function compactCall(theme, toolName, detailLine, options) {
|
|
|
5280
5332
|
state: options.context.state,
|
|
5281
5333
|
isError: Boolean(options.context.isError),
|
|
5282
5334
|
isPartial: Boolean(options.context.isPartial),
|
|
5283
|
-
isPending: pendingFlag(options.context)
|
|
5335
|
+
isPending: pendingFlag(options.context),
|
|
5336
|
+
running: Boolean(options.context.executionStarted)
|
|
5284
5337
|
});
|
|
5285
5338
|
}
|
|
5286
5339
|
function noteExecutionStart(context) {
|
|
5287
5340
|
recordExecutionStarted(context.state, context.executionStarted);
|
|
5288
5341
|
}
|
|
5342
|
+
function noteBoxedCallState(context) {
|
|
5343
|
+
if (!context.executionStarted) return;
|
|
5344
|
+
if (context.isPartial) startElapsedTicker(context.state, context.invalidate);
|
|
5345
|
+
else {
|
|
5346
|
+
recordExecutionEnded(context.state);
|
|
5347
|
+
stopElapsedTicker(context.state);
|
|
5348
|
+
}
|
|
5349
|
+
}
|
|
5350
|
+
function noteBoxedResultPhase(context, isPartial) {
|
|
5351
|
+
const firstResultPass = !isResultSeen(context.state);
|
|
5352
|
+
markResultSeen(context.state);
|
|
5353
|
+
if (isPartial) startElapsedTicker(context.state, context.invalidate);
|
|
5354
|
+
else {
|
|
5355
|
+
recordExecutionEnded(context.state);
|
|
5356
|
+
stopElapsedTicker(context.state);
|
|
5357
|
+
}
|
|
5358
|
+
return firstResultPass;
|
|
5359
|
+
}
|
|
5289
5360
|
function stateElapsedMs(context) {
|
|
5290
5361
|
return getStateElapsedMs(context.state);
|
|
5291
5362
|
}
|
|
@@ -5423,34 +5494,202 @@ function renderBoxedBashCall(theme, commandLines, context, widthKey) {
|
|
|
5423
5494
|
if (commandLines.length > maxCommandLines + 1) {
|
|
5424
5495
|
detailLines.push(theme.fg("muted", `... ${commandLines.length - maxCommandLines - 1} more lines`));
|
|
5425
5496
|
}
|
|
5426
|
-
|
|
5497
|
+
const running = Boolean(context.executionStarted);
|
|
5498
|
+
const resultSeen = isResultSeen(context.state);
|
|
5499
|
+
const base = {
|
|
5427
5500
|
widthKey,
|
|
5428
5501
|
isError: Boolean(context.isError),
|
|
5429
5502
|
isPartial: Boolean(context.isPartial),
|
|
5430
|
-
isPending: Boolean(context.isPartial)
|
|
5431
|
-
|
|
5503
|
+
isPending: Boolean(context.isPartial),
|
|
5504
|
+
running
|
|
5505
|
+
};
|
|
5506
|
+
if (running && context.isPartial && !resultSeen) {
|
|
5507
|
+
detailLines.push(theme.fg("dim", "No output received yet"));
|
|
5508
|
+
return renderBoxedToolCall(theme, "Bash", detailLines, {
|
|
5509
|
+
...base,
|
|
5510
|
+
pendingLabel: formatBoxedRunningStatus(theme, getStateElapsedMs(context.state))
|
|
5511
|
+
});
|
|
5512
|
+
}
|
|
5513
|
+
return renderBoxedToolCall(theme, "Bash", detailLines, { ...base, resultSeen });
|
|
5432
5514
|
}
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5515
|
+
var BASH_STATUS_PATTERNS = [
|
|
5516
|
+
{
|
|
5517
|
+
re: /(?:^|\n\n)Command timed out after ([\d.]+) seconds$/i,
|
|
5518
|
+
build: (match) => ({ kind: "timeout", seconds: Number(match[1]) })
|
|
5519
|
+
},
|
|
5520
|
+
{ re: /(?:^|\n\n)[^\n]*aborted$/i, build: () => ({ kind: "cancelled" }) },
|
|
5521
|
+
{
|
|
5522
|
+
re: /(?:^|\n\n)Command exited with code (\d+)$/i,
|
|
5523
|
+
build: (match) => ({ kind: "exit", exitCode: Number(match[1]) })
|
|
5524
|
+
}
|
|
5525
|
+
];
|
|
5526
|
+
function parseBashTerminalStatus(text) {
|
|
5527
|
+
const clean = String(text ?? "").replace(/\r/g, "");
|
|
5528
|
+
for (const { re, build } of BASH_STATUS_PATTERNS) {
|
|
5529
|
+
const match = clean.match(re);
|
|
5530
|
+
if (match && match.index !== void 0) {
|
|
5531
|
+
return { status: build(match), body: clean.slice(0, match.index).trimEnd() };
|
|
5532
|
+
}
|
|
5533
|
+
}
|
|
5534
|
+
if (/^(?:operation )?aborted(?: after \d+ retry attempts?)?$/i.test(clean.trim())) {
|
|
5535
|
+
return { status: { kind: "cancelled" }, body: "" };
|
|
5536
|
+
}
|
|
5537
|
+
return { status: void 0, body: clean };
|
|
5538
|
+
}
|
|
5539
|
+
function bashErrorLabel(status) {
|
|
5540
|
+
if (status?.kind === "timeout") return "\u2717 Timed out";
|
|
5541
|
+
if (status?.kind === "cancelled") return "\u2717 Cancelled";
|
|
5542
|
+
return void 0;
|
|
5543
|
+
}
|
|
5544
|
+
function bashEmptyBodyText(status, isError) {
|
|
5545
|
+
if (status?.kind === "timeout") return "No output was received before the timeout";
|
|
5546
|
+
if (status?.kind === "cancelled") return "Command was cancelled without producing output";
|
|
5547
|
+
if (isError) return "Command failed without producing output";
|
|
5548
|
+
return "Command completed without producing output";
|
|
5549
|
+
}
|
|
5550
|
+
function bashFooter(theme, status, elapsedMs, bodyText, isError) {
|
|
5551
|
+
const elapsed = elapsedMs === void 0 ? "--" : `${(elapsedMs / 1e3).toFixed(2)}s`;
|
|
5552
|
+
const words = bodyText.trim() ? formatBoxedWords(bodyText) : "";
|
|
5553
|
+
if (status?.kind === "timeout") {
|
|
5554
|
+
const seconds = Number.isFinite(status.seconds) && status.seconds > 0 ? status.seconds : Number.NaN;
|
|
5555
|
+
return theme.fg(
|
|
5556
|
+
"warning",
|
|
5557
|
+
Number.isFinite(seconds) ? `Terminated after ${seconds.toFixed(1)}s` : "Terminated by timeout"
|
|
5558
|
+
);
|
|
5559
|
+
}
|
|
5560
|
+
if (status?.kind === "cancelled") {
|
|
5561
|
+
return [theme.fg("warning", "Cancelled"), theme.fg("text", elapsed)].join(theme.fg("dim", " \xB7 "));
|
|
5562
|
+
}
|
|
5563
|
+
const exitLabel = status?.kind === "exit" ? `Exit ${status.exitCode}` : isError ? "Failed" : "Exit 0";
|
|
5564
|
+
const exitColor = status?.kind === "exit" && status.exitCode !== 0 ? "error" : "text";
|
|
5565
|
+
const parts = [theme.fg(exitColor, exitLabel), theme.fg("text", elapsed)];
|
|
5566
|
+
if (words) parts.push(theme.fg("dim", words));
|
|
5567
|
+
return parts.join(theme.fg("dim", " \xB7 "));
|
|
5436
5568
|
}
|
|
5437
|
-
|
|
5569
|
+
var INTERACTIVE_COMMANDS = /* @__PURE__ */ new Set([
|
|
5570
|
+
"pi",
|
|
5571
|
+
"vim",
|
|
5572
|
+
"vi",
|
|
5573
|
+
"nvim",
|
|
5574
|
+
"nano",
|
|
5575
|
+
"less",
|
|
5576
|
+
"more",
|
|
5577
|
+
"man",
|
|
5578
|
+
"top",
|
|
5579
|
+
"htop",
|
|
5580
|
+
"btop",
|
|
5581
|
+
"ssh",
|
|
5582
|
+
"telnet",
|
|
5583
|
+
"python",
|
|
5584
|
+
"python3",
|
|
5585
|
+
"node",
|
|
5586
|
+
"sqlite3",
|
|
5587
|
+
"mysql",
|
|
5588
|
+
"psql",
|
|
5589
|
+
"redis-cli",
|
|
5590
|
+
"mongosh",
|
|
5591
|
+
"bc",
|
|
5592
|
+
"irssi"
|
|
5593
|
+
]);
|
|
5594
|
+
function isInteractiveCommand(command) {
|
|
5595
|
+
const base = (String(command ?? "").trim().split(/\s+/)[0] ?? "").split("/").pop() ?? "";
|
|
5596
|
+
return INTERACTIVE_COMMANDS.has(base);
|
|
5597
|
+
}
|
|
5598
|
+
function bashBodyComponent(preview, emptyLines) {
|
|
5599
|
+
if (!emptyLines) return preview;
|
|
5600
|
+
return {
|
|
5601
|
+
invalidate: () => preview.invalidate(),
|
|
5602
|
+
render(width) {
|
|
5603
|
+
const lines = preview.render(width);
|
|
5604
|
+
return lines.length > 0 ? lines : emptyLines;
|
|
5605
|
+
}
|
|
5606
|
+
};
|
|
5607
|
+
}
|
|
5608
|
+
function renderBashStreamingResult(theme, raw, options, context) {
|
|
5609
|
+
const body = stripBashToolNoticeLines(stripAnsi(raw));
|
|
5610
|
+
const hasOutput = body.trim().length > 0;
|
|
5611
|
+
const elapsed = getStateElapsedMs(context.state);
|
|
5612
|
+
const emptyLines = [theme.fg("dim", "No output received yet")];
|
|
5613
|
+
if (!hasOutput && isInteractiveCommand(context?.args?.command) && (elapsed ?? 0) >= 1e3) {
|
|
5614
|
+
emptyLines.push(theme.fg("dim", "The process may be waiting for terminal input"));
|
|
5615
|
+
}
|
|
5616
|
+
const preview = createBashResultPreview(theme, body, options, "toolOutput");
|
|
5438
5617
|
const rawCommand = String(context?.args?.command ?? "...");
|
|
5439
|
-
|
|
5440
|
-
return renderBoxedToolResult(theme, inner, {
|
|
5618
|
+
return renderBoxedToolResult(theme, bashBodyComponent(preview, hasOutput ? void 0 : emptyLines), {
|
|
5441
5619
|
widthKey: bashWidthKey(rawCommand, context?.args?.timeout),
|
|
5442
|
-
referenceLines,
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
],
|
|
5446
|
-
|
|
5447
|
-
isError: context.isError,
|
|
5448
|
-
isPartial: Boolean(context.isPartial)
|
|
5620
|
+
referenceLines: rawCommand.split("\n").map((line, index) => `${index === 0 ? "$ " : "> "}${line}`),
|
|
5621
|
+
dividerLabel: "Output",
|
|
5622
|
+
showDivider: hasOutput,
|
|
5623
|
+
footerLines: [formatBoxedRunningStatus(theme, elapsed)],
|
|
5624
|
+
isPartial: true
|
|
5449
5625
|
});
|
|
5450
5626
|
}
|
|
5451
|
-
function
|
|
5452
|
-
|
|
5627
|
+
function renderBashFinalResult(theme, raw, options, context) {
|
|
5628
|
+
const isError = Boolean(context.isError);
|
|
5629
|
+
const clean = stripAnsi(raw);
|
|
5630
|
+
const { status, body: statusStripped } = parseBashTerminalStatus(clean);
|
|
5631
|
+
const output = stripBashToolNoticeLines(statusStripped);
|
|
5632
|
+
const elapsed = getStateElapsedMs(context.state);
|
|
5633
|
+
const outputColor = isError ? "error" : "toolOutput";
|
|
5634
|
+
const footer = bashFooter(theme, status, elapsed, output, isError);
|
|
5635
|
+
const errorLabel = isError ? bashErrorLabel(status) ?? "\u2717 Error" : void 0;
|
|
5636
|
+
const rawCommand = String(context?.args?.command ?? "...");
|
|
5637
|
+
const widthKey = bashWidthKey(rawCommand, context?.args?.timeout);
|
|
5638
|
+
const referenceLines = rawCommand.split("\n").map((line, index) => `${index === 0 ? "$ " : "> "}${line}`);
|
|
5639
|
+
if (!options.expanded) {
|
|
5640
|
+
const scanLines = getToolsRenderConfig().maxCollapsedLines + 10;
|
|
5641
|
+
let nlCount = 0;
|
|
5642
|
+
let tailStart = 0;
|
|
5643
|
+
for (let i = statusStripped.length - 1; i >= 0; i--) {
|
|
5644
|
+
if (statusStripped.charCodeAt(i) === 10) {
|
|
5645
|
+
nlCount++;
|
|
5646
|
+
if (nlCount >= scanLines) {
|
|
5647
|
+
tailStart = i + 1;
|
|
5648
|
+
break;
|
|
5649
|
+
}
|
|
5650
|
+
}
|
|
5651
|
+
}
|
|
5652
|
+
const tail = stripBashToolNoticeLines(stripAnsi(statusStripped.slice(tailStart)));
|
|
5653
|
+
const totalLinesBefore = tailStart > 0 ? countNewlines(statusStripped, 0, tailStart) : 0;
|
|
5654
|
+
const preview2 = createBashResultPreview(theme, tail, options, outputColor);
|
|
5655
|
+
return renderBoxedToolResult(
|
|
5656
|
+
theme,
|
|
5657
|
+
bashBodyComponent(
|
|
5658
|
+
preview2,
|
|
5659
|
+
statusStripped.trim() ? void 0 : [theme.fg("muted", bashEmptyBodyText(status, isError))]
|
|
5660
|
+
),
|
|
5661
|
+
{
|
|
5662
|
+
widthKey,
|
|
5663
|
+
referenceLines,
|
|
5664
|
+
footerLines: [footer],
|
|
5665
|
+
...totalLinesBefore > 0 ? { expandHint: "Ctrl+O for more" } : {},
|
|
5666
|
+
isError,
|
|
5667
|
+
isPartial: false,
|
|
5668
|
+
...errorLabel ? { errorLabel } : {}
|
|
5669
|
+
}
|
|
5670
|
+
);
|
|
5671
|
+
}
|
|
5672
|
+
const preview = createBashResultPreview(theme, output, options, outputColor);
|
|
5673
|
+
return renderBoxedToolResult(
|
|
5674
|
+
theme,
|
|
5675
|
+
bashBodyComponent(preview, output.trim() ? void 0 : [theme.fg("muted", bashEmptyBodyText(status, isError))]),
|
|
5676
|
+
{
|
|
5677
|
+
widthKey,
|
|
5678
|
+
referenceLines,
|
|
5679
|
+
footerLines: [footer],
|
|
5680
|
+
isError,
|
|
5681
|
+
isPartial: false,
|
|
5682
|
+
...errorLabel ? { errorLabel } : {}
|
|
5683
|
+
}
|
|
5684
|
+
);
|
|
5453
5685
|
}
|
|
5686
|
+
var EMPTY_BASH_RESULT = Object.freeze({
|
|
5687
|
+
invalidate() {
|
|
5688
|
+
},
|
|
5689
|
+
render() {
|
|
5690
|
+
return [];
|
|
5691
|
+
}
|
|
5692
|
+
});
|
|
5454
5693
|
function createBashResultPreview(theme, text, options, color) {
|
|
5455
5694
|
let cacheKey = "";
|
|
5456
5695
|
let cacheLines = null;
|
|
@@ -5792,14 +6031,21 @@ var bashTool = {
|
|
|
5792
6031
|
bashTreeStates.set(context.toolCallId, { cls, command: String(args?.command ?? "") });
|
|
5793
6032
|
return renderBashTreePanel(theme, context.toolCallId, context);
|
|
5794
6033
|
}
|
|
6034
|
+
noteBoxedCallState(context);
|
|
5795
6035
|
const rawCommand = String(args?.command ?? "...");
|
|
5796
6036
|
return renderBoxedBashCall(theme, rawCommand.split("\n"), context, bashWidthKey(rawCommand, args?.timeout));
|
|
5797
6037
|
},
|
|
5798
6038
|
result(result, options, theme, context) {
|
|
6039
|
+
const firstResultPass = !isResultSeen(context.state);
|
|
6040
|
+
markResultSeen(context.state);
|
|
5799
6041
|
const cls = classifyBashCommand(String(context?.args?.command ?? ""));
|
|
5800
6042
|
if (cls && !context.isError) {
|
|
5801
|
-
|
|
5802
|
-
|
|
6043
|
+
if (!options.isPartial) {
|
|
6044
|
+
recordExecutionEnded(context.state);
|
|
6045
|
+
stopElapsedTicker(context.state);
|
|
6046
|
+
}
|
|
6047
|
+
const output = stripBashToolNoticeLines(stripAnsi(getTextOutput(result)));
|
|
6048
|
+
const parsed = parseBashTreeOutput(cls, output);
|
|
5803
6049
|
const state = bashTreeStates.get(context.toolCallId);
|
|
5804
6050
|
if (parsed) {
|
|
5805
6051
|
if (state) state.parsed = parsed;
|
|
@@ -5807,30 +6053,18 @@ var bashTool = {
|
|
|
5807
6053
|
return EMPTY_BASH_TREE_RESULT;
|
|
5808
6054
|
}
|
|
5809
6055
|
if (state) state.fallback = true;
|
|
6056
|
+
} else if (options.isPartial) {
|
|
6057
|
+
startElapsedTicker(context.state, context.invalidate);
|
|
6058
|
+
} else {
|
|
6059
|
+
recordExecutionEnded(context.state);
|
|
6060
|
+
stopElapsedTicker(context.state);
|
|
5810
6061
|
}
|
|
5811
6062
|
const raw = getTextOutput(result);
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
let nlCount = 0;
|
|
5816
|
-
let tailStart = 0;
|
|
5817
|
-
for (let i = raw.length - 1; i >= 0; i--) {
|
|
5818
|
-
if (raw.charCodeAt(i) === 10) {
|
|
5819
|
-
nlCount++;
|
|
5820
|
-
if (nlCount >= scanLines) {
|
|
5821
|
-
tailStart = i + 1;
|
|
5822
|
-
break;
|
|
5823
|
-
}
|
|
5824
|
-
}
|
|
5825
|
-
}
|
|
5826
|
-
const tail = stripBashToolNoticeLines(stripAnsi(raw.slice(tailStart)));
|
|
5827
|
-
const totalLinesBefore = tailStart > 0 ? countNewlines(raw, 0, tailStart) : 0;
|
|
5828
|
-
const inner2 = createBashResultPreview(theme, tail, options, outputColor);
|
|
5829
|
-
return renderBoxedBashResult(theme, inner2, result, context, totalLinesBefore > 0 ? "Ctrl+O for more" : void 0);
|
|
6063
|
+
if (options.isPartial) {
|
|
6064
|
+
if (firstResultPass) return EMPTY_BASH_RESULT;
|
|
6065
|
+
return renderBashStreamingResult(theme, raw, options, context);
|
|
5830
6066
|
}
|
|
5831
|
-
|
|
5832
|
-
const inner = createBashResultPreview(theme, output, options, outputColor);
|
|
5833
|
-
return renderBoxedBashResult(theme, inner, result, context);
|
|
6067
|
+
return renderBashFinalResult(theme, raw, options, context);
|
|
5834
6068
|
}
|
|
5835
6069
|
};
|
|
5836
6070
|
|
|
@@ -6857,6 +7091,13 @@ var AdaptiveDiffComponent = class {
|
|
|
6857
7091
|
// extension-src/pi-style/features/tools/boxed/edit.ts
|
|
6858
7092
|
var MAX_HIGHLIGHT_DIFF_CHARS = 12e3;
|
|
6859
7093
|
var MAX_HIGHLIGHT_DIFF_ROWS = 120;
|
|
7094
|
+
var EMPTY_EDIT_RESULT = Object.freeze({
|
|
7095
|
+
invalidate() {
|
|
7096
|
+
},
|
|
7097
|
+
render() {
|
|
7098
|
+
return [];
|
|
7099
|
+
}
|
|
7100
|
+
});
|
|
6860
7101
|
function diffDividerLabel(theme, stats) {
|
|
6861
7102
|
const plus = stats.additions > 0 ? theme.fg("toolDiffAdded", `+${stats.additions}`) : theme.fg("dim", "+0");
|
|
6862
7103
|
const minus = stats.removals > 0 ? theme.fg("toolDiffRemoved", `-${stats.removals}`) : theme.fg("dim", "-0");
|
|
@@ -6874,17 +7115,24 @@ function editDiffFooter(theme, result, context, stats) {
|
|
|
6874
7115
|
var editTool = {
|
|
6875
7116
|
call(args, theme, context) {
|
|
6876
7117
|
noteExecutionStart(context);
|
|
7118
|
+
noteBoxedCallState(context);
|
|
6877
7119
|
const detail = displayPath(String(args?.path ?? args?.file_path ?? ""), context);
|
|
6878
7120
|
return renderBoxedToolCall(theme, "Edit", [], {
|
|
6879
7121
|
headerDetail: detail,
|
|
6880
7122
|
isError: Boolean(context.isError),
|
|
6881
7123
|
isPartial: Boolean(context.isPartial),
|
|
6882
|
-
isPending: Boolean(context.isPartial)
|
|
7124
|
+
isPending: Boolean(context.isPartial),
|
|
7125
|
+
running: Boolean(context.executionStarted),
|
|
7126
|
+
resultSeen: isResultSeen(context.state)
|
|
6883
7127
|
});
|
|
6884
7128
|
},
|
|
6885
7129
|
result(result, options, theme, context) {
|
|
6886
7130
|
if (options.isPartial) {
|
|
7131
|
+
const firstResultPass = noteBoxedResultPhase(context, options.isPartial);
|
|
7132
|
+
if (firstResultPass) return EMPTY_EDIT_RESULT;
|
|
6887
7133
|
return renderBoxedToolResult(theme, () => [`${theme.fg("dim", "\u21B3")} ${theme.fg("muted", "Applying edit...")}`], {
|
|
7134
|
+
showDivider: false,
|
|
7135
|
+
footerLines: [formatBoxedRunningStatus(theme, stateElapsedMs(context))],
|
|
6888
7136
|
isPartial: true
|
|
6889
7137
|
});
|
|
6890
7138
|
}
|
|
@@ -6938,19 +7186,41 @@ var editTool = {
|
|
|
6938
7186
|
var MAX_FALLBACK_PREVIEW_LINES = 10;
|
|
6939
7187
|
function renderFallbackCall(toolName, args, theme, context) {
|
|
6940
7188
|
noteExecutionStart(context);
|
|
7189
|
+
noteBoxedCallState(context);
|
|
6941
7190
|
return renderBoxedToolCall(theme, formatToolName(String(toolName ?? "Tool")), formatToolParamLines(args, theme), {
|
|
6942
7191
|
isError: Boolean(context.isError),
|
|
6943
7192
|
isPartial: Boolean(context.isPartial),
|
|
6944
|
-
isPending: Boolean(context.isPartial)
|
|
7193
|
+
isPending: Boolean(context.isPartial),
|
|
7194
|
+
running: Boolean(context.executionStarted),
|
|
7195
|
+
resultSeen: isResultSeen(context.state)
|
|
6945
7196
|
});
|
|
6946
7197
|
}
|
|
6947
7198
|
function renderFallbackResult(_toolName, result, options, theme, context) {
|
|
7199
|
+
const firstResultPass = noteBoxedResultPhase(context, options.isPartial);
|
|
6948
7200
|
const isError = Boolean(context.isError);
|
|
6949
7201
|
const expanded = Boolean(options.expanded);
|
|
6950
7202
|
const maxLines = expanded ? getToolsRenderConfig().maxExpandedLines : MAX_FALLBACK_PREVIEW_LINES;
|
|
6951
7203
|
const output = getTextOutput(result);
|
|
6952
7204
|
const elapsedMs = getStateElapsedMs(context.state);
|
|
6953
7205
|
const { lines, omitted } = selectRenderLines(output, maxLines);
|
|
7206
|
+
if (options.isPartial) {
|
|
7207
|
+
if (firstResultPass) return EMPTY_FALLBACK_RESULT;
|
|
7208
|
+
const hasOutput = output.trim().length > 0;
|
|
7209
|
+
return renderBoxedToolResult(
|
|
7210
|
+
theme,
|
|
7211
|
+
() => {
|
|
7212
|
+
const body = lines.map((line) => formatToolOutputLine(theme, line, "toolOutput"));
|
|
7213
|
+
if (!hasOutput) body.push(theme.fg("dim", "No output received yet"));
|
|
7214
|
+
return body;
|
|
7215
|
+
},
|
|
7216
|
+
{
|
|
7217
|
+
dividerLabel: "Output",
|
|
7218
|
+
showDivider: hasOutput,
|
|
7219
|
+
footerLines: [formatBoxedRunningStatus(theme, elapsedMs)],
|
|
7220
|
+
isPartial: true
|
|
7221
|
+
}
|
|
7222
|
+
);
|
|
7223
|
+
}
|
|
6954
7224
|
return renderBoxedToolResult(
|
|
6955
7225
|
theme,
|
|
6956
7226
|
() => {
|
|
@@ -6961,7 +7231,7 @@ function renderFallbackResult(_toolName, result, options, theme, context) {
|
|
|
6961
7231
|
return body;
|
|
6962
7232
|
},
|
|
6963
7233
|
{
|
|
6964
|
-
footerLines: [
|
|
7234
|
+
footerLines: [formatBoxedFooterWithElapsed(theme, elapsedMs, output)],
|
|
6965
7235
|
renderLineBudget: maxLines,
|
|
6966
7236
|
...expanded || omitted <= 0 ? {} : { expandHint: "Ctrl+O for more" },
|
|
6967
7237
|
isError,
|
|
@@ -6969,6 +7239,20 @@ function renderFallbackResult(_toolName, result, options, theme, context) {
|
|
|
6969
7239
|
}
|
|
6970
7240
|
);
|
|
6971
7241
|
}
|
|
7242
|
+
var EMPTY_FALLBACK_RESULT = Object.freeze({
|
|
7243
|
+
invalidate() {
|
|
7244
|
+
},
|
|
7245
|
+
render() {
|
|
7246
|
+
return [];
|
|
7247
|
+
}
|
|
7248
|
+
});
|
|
7249
|
+
function formatBoxedFooterWithElapsed(theme, elapsedMs, output) {
|
|
7250
|
+
const elapsed = elapsedMs === void 0 ? "--" : `${(elapsedMs / 1e3).toFixed(2)}s`;
|
|
7251
|
+
const words = output.trim() ? formatBoxedWords(output) : "";
|
|
7252
|
+
const parts = [theme.fg("text", elapsed)];
|
|
7253
|
+
if (words) parts.push(theme.fg("dim", words));
|
|
7254
|
+
return parts.join(theme.fg("dim", " \xB7 "));
|
|
7255
|
+
}
|
|
6972
7256
|
|
|
6973
7257
|
// extension-src/pi-style/features/tools/boxed/find.ts
|
|
6974
7258
|
var FIND_META = Object.freeze({
|
|
@@ -7055,6 +7339,13 @@ var lsTool = {
|
|
|
7055
7339
|
import { getLanguageFromPath as getLanguageFromPath2 } from "@earendil-works/pi-coding-agent";
|
|
7056
7340
|
var MAX_HIGHLIGHT_DIFF_CHARS2 = 12e3;
|
|
7057
7341
|
var MAX_HIGHLIGHT_DIFF_ROWS2 = 120;
|
|
7342
|
+
var EMPTY_QUICK_EDIT_RESULT = Object.freeze({
|
|
7343
|
+
invalidate() {
|
|
7344
|
+
},
|
|
7345
|
+
render() {
|
|
7346
|
+
return [];
|
|
7347
|
+
}
|
|
7348
|
+
});
|
|
7058
7349
|
var QUICK_EDIT_TOOLS = {
|
|
7059
7350
|
quick_edit: {
|
|
7060
7351
|
toolLabel: "Quick Edit",
|
|
@@ -7137,10 +7428,12 @@ function quickEditDiffFooter(theme, result, context, stats) {
|
|
|
7137
7428
|
}
|
|
7138
7429
|
function renderQuickEditResult(_toolName, result, options, theme, context, config) {
|
|
7139
7430
|
if (options.isPartial) {
|
|
7431
|
+
const firstResultPass = noteBoxedResultPhase(context, options.isPartial);
|
|
7432
|
+
if (firstResultPass) return EMPTY_QUICK_EDIT_RESULT;
|
|
7140
7433
|
return renderBoxedToolResult(
|
|
7141
7434
|
theme,
|
|
7142
7435
|
() => [`${theme.fg("dim", "\u21B3")} ${theme.fg("muted", `Applying ${config.applyingLabel}...`)}`],
|
|
7143
|
-
{ isPartial: true }
|
|
7436
|
+
{ showDivider: false, footerLines: [formatBoxedRunningStatus(theme, stateElapsedMs(context))], isPartial: true }
|
|
7144
7437
|
);
|
|
7145
7438
|
}
|
|
7146
7439
|
const output = getTextOutput(result);
|
|
@@ -7194,12 +7487,15 @@ function quickEditTool(config) {
|
|
|
7194
7487
|
return {
|
|
7195
7488
|
call(args, theme, context) {
|
|
7196
7489
|
noteExecutionStart(context);
|
|
7490
|
+
noteBoxedCallState(context);
|
|
7197
7491
|
const detail = displayPath(String(args?.path ?? ""), context);
|
|
7198
7492
|
return renderBoxedToolCall(theme, config.toolLabel, [], {
|
|
7199
7493
|
headerDetail: detail,
|
|
7200
7494
|
isError: Boolean(context.isError),
|
|
7201
7495
|
isPartial: Boolean(context.isPartial),
|
|
7202
|
-
isPending: Boolean(context.isPartial)
|
|
7496
|
+
isPending: Boolean(context.isPartial),
|
|
7497
|
+
running: Boolean(context.executionStarted),
|
|
7498
|
+
resultSeen: isResultSeen(context.state)
|
|
7203
7499
|
});
|
|
7204
7500
|
},
|
|
7205
7501
|
result(result, options, theme, context) {
|
|
@@ -7239,6 +7535,13 @@ var readTool = {
|
|
|
7239
7535
|
|
|
7240
7536
|
// extension-src/pi-style/features/tools/boxed/write.ts
|
|
7241
7537
|
var WRITE_EXPAND_HINT = "Ctrl+O for more";
|
|
7538
|
+
var EMPTY_WRITE_RESULT = Object.freeze({
|
|
7539
|
+
invalidate() {
|
|
7540
|
+
},
|
|
7541
|
+
render() {
|
|
7542
|
+
return [];
|
|
7543
|
+
}
|
|
7544
|
+
});
|
|
7242
7545
|
function numberedPreviewLines(content) {
|
|
7243
7546
|
const normalized = replaceTabs(String(content ?? "")).replace(/\r/g, "");
|
|
7244
7547
|
if (!normalized) return [];
|
|
@@ -7261,6 +7564,7 @@ function renderWritePreviewBox(theme, detailLine, content, options) {
|
|
|
7261
7564
|
...options.state ? { state: options.state } : {},
|
|
7262
7565
|
isError: options.isError,
|
|
7263
7566
|
isPending: options.isPending,
|
|
7567
|
+
running: Boolean(options.running),
|
|
7264
7568
|
bodyLines: () => {
|
|
7265
7569
|
if (preview.length === 0) return [];
|
|
7266
7570
|
const shown = preview.slice(0, budget).map((line) => formatNumberedLine(theme, line));
|
|
@@ -7287,10 +7591,11 @@ var writeTool = {
|
|
|
7287
7591
|
state: context.state,
|
|
7288
7592
|
isError: Boolean(context.isError),
|
|
7289
7593
|
isPending: Boolean(context.isPartial),
|
|
7594
|
+
running: Boolean(context.executionStarted),
|
|
7290
7595
|
expanded: Boolean(context.expanded)
|
|
7291
7596
|
});
|
|
7292
7597
|
},
|
|
7293
|
-
result(result,
|
|
7598
|
+
result(result, options, theme, context) {
|
|
7294
7599
|
clearFooterState(context);
|
|
7295
7600
|
const output = getTextOutput(result);
|
|
7296
7601
|
const detail = displayPath(String(context?.args?.path ?? context?.args?.file_path ?? ""), context);
|
|
@@ -7302,6 +7607,7 @@ var writeTool = {
|
|
|
7302
7607
|
isError: true
|
|
7303
7608
|
});
|
|
7304
7609
|
}
|
|
7610
|
+
if (options.isPartial) return EMPTY_WRITE_RESULT;
|
|
7305
7611
|
return compactFooterWithState(theme, result, context);
|
|
7306
7612
|
}
|
|
7307
7613
|
};
|
|
@@ -8662,6 +8968,7 @@ function createPiStyleSessionCoordinator(pi, hooks = {}) {
|
|
|
8662
8968
|
resetBatchRegistry();
|
|
8663
8969
|
resetGrepRegistry();
|
|
8664
8970
|
resetBashTreeRegistry();
|
|
8971
|
+
stopAllElapsedTickers();
|
|
8665
8972
|
active = false;
|
|
8666
8973
|
await app.reload();
|
|
8667
8974
|
productGate = app.productPolicy.corePatchGate;
|
|
@@ -8722,6 +9029,7 @@ function createPiStyleSessionCoordinator(pi, hooks = {}) {
|
|
|
8722
9029
|
resetBatchRegistry();
|
|
8723
9030
|
resetGrepRegistry();
|
|
8724
9031
|
resetBashTreeRegistry();
|
|
9032
|
+
stopAllElapsedTickers();
|
|
8725
9033
|
app.sessionShutdown();
|
|
8726
9034
|
}
|
|
8727
9035
|
};
|