@quandev104/pi-style 0.1.7 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.0] - 2026-08-08
4
+
5
+ ### Bug Fixes
6
+
7
+ - *(turn-summary,box)* Broken frames on collapse/expand, faileds plural, stray placeholder rows
8
+
9
+ ### Features
10
+
11
+ - *(turn-summary)* Keep mutating tool blocks visible after the turn
12
+
3
13
  ## [0.1.7] - 2026-08-07
4
14
 
5
15
  ### Features
@@ -949,8 +949,16 @@ function renderBoxedOutputLines(theme, outputLines, width, rawLineBudget = DEFAU
949
949
  let nextInputIndex = 0;
950
950
  let truncated = false;
951
951
  for (; nextInputIndex < outputLines.length; nextInputIndex++) {
952
- const line = boxedTruncatedLine(theme, outputLines[nextInputIndex] ?? "", width);
953
- if (!pushBoundedLines(head, [line], headLimit)) {
952
+ const fragments = (outputLines[nextInputIndex] ?? "").split("\n");
953
+ let headExceeded = false;
954
+ for (const fragment of fragments) {
955
+ const line = boxedTruncatedLine(theme, fragment, width);
956
+ if (!pushBoundedLines(head, [line], headLimit)) {
957
+ headExceeded = true;
958
+ break;
959
+ }
960
+ }
961
+ if (headExceeded) {
954
962
  truncated = true;
955
963
  nextInputIndex++;
956
964
  break;
@@ -960,9 +968,12 @@ function renderBoxedOutputLines(theme, outputLines, width, rawLineBudget = DEFAU
960
968
  const tail = [];
961
969
  const tailStart = Math.max(nextInputIndex, outputLines.length - tailLimit);
962
970
  for (let i = tailStart; i < outputLines.length; i++) {
963
- const line = boxedTruncatedLine(theme, outputLines[i] ?? "", width);
964
- tail.push(line);
965
- if (tail.length > tailLimit) tail.splice(0, tail.length - tailLimit);
971
+ const fragments = (outputLines[i] ?? "").split("\n");
972
+ for (const fragment of fragments) {
973
+ const line = boxedTruncatedLine(theme, fragment, width);
974
+ tail.push(line);
975
+ if (tail.length > tailLimit) tail.splice(0, tail.length - tailLimit);
976
+ }
966
977
  }
967
978
  const skippedInputLines = Math.max(0, tailStart - nextInputIndex);
968
979
  const skippedText = skippedInputLines > 0 ? `\u2026 rendered output truncated; ${skippedInputLines} input lines skipped before tail` : "\u2026 rendered output truncated";
@@ -1083,6 +1094,7 @@ function renderBoxedToolResult(theme, body, options = {}) {
1083
1094
  const bodyLines = typeof body === "function" ? body(maxContentWidth) : body.render(maxContentWidth);
1084
1095
  const errorPrefix = options.isError ? [theme.fg("error", options.errorLabel ?? "\u2717 Error")] : [];
1085
1096
  const outputLines = bodyLines.length > 0 ? [...errorPrefix, ...bodyLines] : [theme.fg("muted", `\u2205 ${options.emptyText ?? "(no output)"}`)];
1097
+ const outputFragments = outputLines.flatMap((line) => line.split("\n"));
1086
1098
  const footerText = (options.footerLines ?? []).join(" \xB7 ");
1087
1099
  const dividerText = typeof options.dividerLabel === "function" ? options.dividerLabel(renderedWidth) : options.dividerLabel ?? "Response";
1088
1100
  const rendered = [
@@ -1097,7 +1109,12 @@ function renderBoxedToolResult(theme, body, options = {}) {
1097
1109
  )
1098
1110
  ],
1099
1111
  boxBlankLine(theme, renderedWidth),
1100
- ...renderBoxedOutputLines(theme, outputLines, renderedWidth, options.renderLineBudget ?? outputLines.length),
1112
+ ...renderBoxedOutputLines(
1113
+ theme,
1114
+ outputFragments,
1115
+ renderedWidth,
1116
+ options.renderLineBudget ?? outputFragments.length
1117
+ ),
1101
1118
  boxBlankLine(theme, renderedWidth),
1102
1119
  boxLabeledBorder(
1103
1120
  theme,
@@ -1419,7 +1436,8 @@ var sessionToolsConfig = {
1419
1436
  showElapsed: true,
1420
1437
  batchOpenGlyph: "\u25CF",
1421
1438
  nerdFonts: false,
1422
- collapseAfterTurn: true
1439
+ collapseAfterTurn: true,
1440
+ collapseMutatingTools: false
1423
1441
  };
1424
1442
  function setToolsRenderConfig(config) {
1425
1443
  sessionToolsConfig = { ...sessionToolsConfig, ...config };
@@ -1775,6 +1793,13 @@ function emptyBatchResult() {
1775
1793
  }
1776
1794
 
1777
1795
  // extension-src/pi-style/features/tools/boxed/turn-summary.ts
1796
+ var MUTATING_TOOLS = /* @__PURE__ */ new Set(["edit", "write", "quick_edit", "substitute_edit", "target_edit"]);
1797
+ function isMutatingTool(toolName) {
1798
+ return MUTATING_TOOLS.has(toolName);
1799
+ }
1800
+ function mutatingCollapses() {
1801
+ return getToolsRenderConfig().collapseMutatingTools;
1802
+ }
1778
1803
  var memberByCallId = /* @__PURE__ */ new Map();
1779
1804
  var invalidateByCallId = /* @__PURE__ */ new Map();
1780
1805
  function resetTurnRegistry() {
@@ -1805,7 +1830,7 @@ function registerTurn(calls, isErrorById, ended) {
1805
1830
  isError: isErrorById.get(toolCallId) === true
1806
1831
  };
1807
1832
  });
1808
- const leader = members.find((member) => !member.isError);
1833
+ const leader = members.find((member) => !member.isError && (!isMutatingTool(member.toolName) || mutatingCollapses()));
1809
1834
  const turn = {
1810
1835
  leaderId: leader?.toolCallId ?? "",
1811
1836
  ended: ended && complete,
@@ -1835,7 +1860,9 @@ function registerTurnFromMessage(message, toolResults) {
1835
1860
  isError: isErrorById.get(toolCallId) === true
1836
1861
  };
1837
1862
  });
1838
- const leader = newMembers.find((member) => !member.isError);
1863
+ const leader = newMembers.find(
1864
+ (member) => !member.isError && (!isMutatingTool(member.toolName) || mutatingCollapses())
1865
+ );
1839
1866
  if (!currentRun) {
1840
1867
  currentRun = {
1841
1868
  leaderId: leader?.toolCallId ?? "",
@@ -1935,11 +1962,13 @@ function turnSummaryParts(turn) {
1935
1962
  const order = [];
1936
1963
  let failedCount = 0;
1937
1964
  let elapsedMs;
1965
+ const collapseMutating = mutatingCollapses();
1938
1966
  for (const member of turn.members) {
1939
1967
  if (member.isError) {
1940
1968
  failedCount++;
1941
1969
  continue;
1942
1970
  }
1971
+ if (!collapseMutating && isMutatingTool(member.toolName)) continue;
1943
1972
  if (member.elapsedMs !== void 0) elapsedMs = (elapsedMs ?? 0) + member.elapsedMs;
1944
1973
  const existing = counts.get(member.toolName);
1945
1974
  if (existing === void 0) {
@@ -1949,8 +1978,8 @@ function turnSummaryParts(turn) {
1949
1978
  }
1950
1979
  const parts = order.map((toolName) => {
1951
1980
  const count = counts.get(toolName) ?? 0;
1952
- const style = TURN_SUMMARY_STYLE[toolName] ?? { verb: "ran", unit: `${toolName} call` };
1953
- return `${style.verb} ${count} ${pluralForm(style.unit, count)}`;
1981
+ const style = TURN_SUMMARY_STYLE[toolName];
1982
+ return style ? `${style.verb} ${count} ${pluralForm(style.unit, count)}` : `used ${count} ${toolName}`;
1954
1983
  });
1955
1984
  return { parts, failedCount, elapsedMs };
1956
1985
  }
@@ -1959,7 +1988,7 @@ function formatTurnSummaryLine(theme, turn) {
1959
1988
  const parts = summary.parts.join(", ");
1960
1989
  let line = `${theme.fg("dim", `\u2794 ${parts}`)}`;
1961
1990
  if (summary.failedCount > 0)
1962
- line += theme.fg("error", ` \xB7 ${summary.failedCount} ${pluralForm("failed", summary.failedCount)}`);
1991
+ line += theme.fg("error", ` \xB7 ${summary.failedCount} ${pluralForm("failure", summary.failedCount)}`);
1963
1992
  if (summary.elapsedMs !== void 0) line += theme.fg("dim", ` \xB7 ${(summary.elapsedMs / 1e3).toFixed(2)}s`);
1964
1993
  return line;
1965
1994
  }
@@ -6314,9 +6343,11 @@ var REGISTRY = {
6314
6343
  target_edit: quickEditToolFor("target_edit")
6315
6344
  };
6316
6345
  function collapsedTurnFor(toolCallId, expanded) {
6317
- if (expanded || !getToolsRenderConfig().collapseAfterTurn) return void 0;
6346
+ const config = getToolsRenderConfig();
6347
+ if (expanded || !config.collapseAfterTurn) return void 0;
6318
6348
  const entry = getTurnEntry(toolCallId);
6319
6349
  if (!entry?.turn.ended || entry.member.isError) return void 0;
6350
+ if (isMutatingTool(entry.member.toolName) && !config.collapseMutatingTools) return void 0;
6320
6351
  return entry.turn;
6321
6352
  }
6322
6353
  function renderBoxedToolCall2(toolName, args, theme, context) {
@@ -6596,14 +6627,27 @@ function createToolDecorationOwner(snapshot = {}) {
6596
6627
  if (typeof renderer !== "function") {
6597
6628
  neutralizeToolContainerBackground(instance);
6598
6629
  if (subtype === "tool-call-renderer")
6599
- return (callArgs, theme, context) => renderBoxedToolCall2(toolName, callArgs, theme, context);
6600
- return (result, options, theme, context) => renderBoxedToolResult2(
6601
- toolName,
6602
- result,
6603
- options,
6604
- theme,
6605
- context
6606
- );
6630
+ return (callArgs, theme, context) => {
6631
+ const component = renderBoxedToolCall2(
6632
+ toolName,
6633
+ callArgs,
6634
+ theme,
6635
+ context
6636
+ );
6637
+ if (component === EMPTY_BATCH_COMPONENT) hideBatchMember(instance);
6638
+ return component;
6639
+ };
6640
+ return (result, options, theme, context) => {
6641
+ const component = renderBoxedToolResult2(
6642
+ toolName,
6643
+ result,
6644
+ options,
6645
+ theme,
6646
+ context
6647
+ );
6648
+ if (component === EMPTY_BATCH_COMPONENT) hideBatchMember(instance);
6649
+ return component;
6650
+ };
6607
6651
  }
6608
6652
  return function(...rendererArgs) {
6609
6653
  const valid = subtype === "tool-call-renderer" ? validCallArgs(rendererArgs) : validResultArgs(rendererArgs);
@@ -6824,7 +6868,8 @@ var DEFAULT_CONFIG = Object.freeze({
6824
6868
  maxExpandedLines: 50,
6825
6869
  dimOutput: false,
6826
6870
  showElapsed: true,
6827
- collapseAfterTurn: true
6871
+ collapseAfterTurn: true,
6872
+ collapseMutatingTools: false
6828
6873
  }),
6829
6874
  theme: Object.freeze({
6830
6875
  nerdFonts: "auto",
@@ -6940,7 +6985,8 @@ function normalizeConfig(input, defaults = DEFAULT_CONFIG) {
6940
6985
  maxExpandedLines: maxExpanded,
6941
6986
  dimOutput: bool(tools.dimOutput, defaults.tools.dimOutput),
6942
6987
  showElapsed: bool(tools.showElapsed, defaults.tools.showElapsed),
6943
- collapseAfterTurn: bool(tools.collapseAfterTurn, defaults.tools.collapseAfterTurn)
6988
+ collapseAfterTurn: bool(tools.collapseAfterTurn, defaults.tools.collapseAfterTurn),
6989
+ collapseMutatingTools: bool(tools.collapseMutatingTools, defaults.tools.collapseMutatingTools)
6944
6990
  }),
6945
6991
  theme: Object.freeze({
6946
6992
  nerdFonts: stringEnum(theme.nerdFonts, ["auto", "on", "off"], defaults.theme.nerdFonts),
@@ -6988,6 +7034,7 @@ var BOOL_PATHS = /* @__PURE__ */ new Set([
6988
7034
  "tools.showElapsed",
6989
7035
  "tools.dimOutput",
6990
7036
  "tools.collapseAfterTurn",
7037
+ "tools.collapseMutatingTools",
6991
7038
  "compatibility.allowSafePatches",
6992
7039
  "compatibility.allowCorePatches",
6993
7040
  "compatibility.preferExistingEditor",
@@ -7458,6 +7505,7 @@ var allowedPaths = /* @__PURE__ */ new Set([
7458
7505
  "tools.dimOutput",
7459
7506
  "tools.showElapsed",
7460
7507
  "tools.collapseAfterTurn",
7508
+ "tools.collapseMutatingTools",
7461
7509
  "theme.nerdFonts",
7462
7510
  "theme.terminalBackgroundSync",
7463
7511
  "theme.autoApply",
@@ -7486,6 +7534,7 @@ function validatePathValue(path, value) {
7486
7534
  "tools.showElapsed",
7487
7535
  "tools.dimOutput",
7488
7536
  "tools.collapseAfterTurn",
7537
+ "tools.collapseMutatingTools",
7489
7538
  "compatibility.allowSafePatches",
7490
7539
  "compatibility.allowCorePatches",
7491
7540
  "compatibility.preferExistingEditor",