pi-cc-extensions 0.8.4 → 0.8.6

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/README.md CHANGED
@@ -86,7 +86,6 @@
86
86
 
87
87
  `mode` 可取 `on`、`off` 或 `compact`。旧版 `enabled: true/false` 会自动迁移为 `on/off`。排除名单使用精确工具名;手动修改配置后执行 `/reload`。`Agent` 的专用 renderer 始终保留。
88
88
 
89
- `compact` 不会自动修改 Pi 的 `hideThinkingBlock` 或 `outputPad` 设置。运行总结会持久化到 Session,但只在 `compact` 模式显示。
90
89
 
91
90
  Compact transcript 行为改编自 [avhagedorn/pi-compact-transcript](https://github.com/avhagedorn/pi-compact-transcript) v0.6.2(MIT,Alan Hagedorn)。
92
91
 
@@ -253,8 +253,8 @@ export class ExpandedToolResultText {
253
253
  }
254
254
  }
255
255
 
256
- function renderCollapsedToolResult(body: string, collapsedHint = ""): string {
257
- return `\n ⎿ ${body}${collapsedHint}`;
256
+ export function renderCollapsedToolResult(body: string, collapsedHint = ""): string {
257
+ return ` ↳ ${body}${collapsedHint}`;
258
258
  }
259
259
 
260
260
  function renderExpandedToolResult(
@@ -1172,7 +1172,7 @@ function shouldUseSelfShell(component: any, patch: GlobalToolRenderPatch): boole
1172
1172
  const definition = component.toolDefinition ?? component.builtInToolDefinition;
1173
1173
  const toolName = String(component.toolName || definition?.name || "");
1174
1174
  const useSelfShell =
1175
- patch.mode() !== "off" &&
1175
+ patch.enabled() &&
1176
1176
  SUBAGENT_TOOL_NAMES.has(toolName) &&
1177
1177
  definition != null &&
1178
1178
  definition.renderShell === undefined;
@@ -32,6 +32,7 @@ type AssistantPrototypePatch = {
32
32
  prototype: any;
33
33
  active: boolean;
34
34
  originalUpdateContent: (...args: any[]) => any;
35
+ nativeUpdateContent: (...args: any[]) => any;
35
36
  patchedUpdateContent: (...args: any[]) => any;
36
37
  };
37
38
 
@@ -131,6 +132,7 @@ const MARKER_WIDTH = 2;
131
132
  const STATE_KEY = Symbol.for("pi.ccstyle.compact-style.state");
132
133
  const TOOL_PATCH_KEY = Symbol.for("pi.ccstyle.compact-style.tool-patch");
133
134
  const ASSISTANT_PATCH_KEY = Symbol.for("pi.ccstyle.compact-style.assistant-patch");
135
+ const ASSISTANT_REENTRY_KEY = Symbol.for("pi.ccstyle.compact-style.assistant-reentry");
134
136
  const TOOL_NATIVE_CHILD_KEY = Symbol.for("pi.ccstyle.compact-style.native-tool-child");
135
137
 
136
138
  function newRunStats(): RunStats {
@@ -499,7 +501,7 @@ function anchorCurrentThoughtTo(info: ToolInfo) {
499
501
 
500
502
  function currentThoughtLine(toolCallId: string, theme: Theme): string {
501
503
  if (!thoughtTickerEnabled() || state.thoughtAnchorId !== toolCallId || !state.currentThoughtHeading) return "";
502
- const prefix = " ↳ ";
504
+ const prefix = " ↳ ";
503
505
  const budget = previewWidth((process.stdout.columns || 100) - prefix.length);
504
506
  return theme.fg("dim", prefix) + theme.fg("thinkingText", limitPlain(state.currentThoughtHeading, budget));
505
507
  }
@@ -623,11 +625,12 @@ function compactToolLine(
623
625
  isError: info.isError,
624
626
  hasResult: result != null || !!info.result,
625
627
  });
626
- if (!isBurst) return marker + theme.fg("muted", limitPlain(details));
628
+ const indent = " ";
629
+ if (!isBurst) return indent + marker + theme.fg("muted", limitPlain(details));
627
630
 
628
631
  const prefix = `${info.burstCount}× `;
629
- const budget = previewWidth((process.stdout.columns || 100) - prefix.length - MARKER_WIDTH);
630
- return marker + theme.fg("muted", prefix + limitPlain(details, budget));
632
+ const budget = previewWidth((process.stdout.columns || 100) - indent.length - prefix.length - MARKER_WIDTH);
633
+ return indent + marker + theme.fg("muted", prefix + limitPlain(details, budget));
631
634
  }
632
635
 
633
636
  function shouldCompactComponent(component: any, mode: CompactStyleMode): boolean {
@@ -786,8 +789,11 @@ function patchToolExecutionComponent(installation: CompactInstallation): ToolPro
786
789
  return;
787
790
  }
788
791
 
789
- this.selfRenderContainer.addChild(new Text(line, 0, 0));
790
792
  const thoughtLine = currentThoughtLine(this.toolCallId, theme);
793
+ // Keep a compact tool group visually separate from its thinking ticker,
794
+ // without adding vertical space to ordinary compact tool rows.
795
+ if (thoughtLine) this.selfRenderContainer.addChild(new Spacer(1));
796
+ this.selfRenderContainer.addChild(new Text(line, 0, 0));
791
797
  if (thoughtLine) this.selfRenderContainer.addChild(new Text(thoughtLine, 0, 0));
792
798
  };
793
799
 
@@ -839,20 +845,34 @@ function patchAssistantMessageComponent(installation: CompactInstallation): Assi
839
845
  prototype,
840
846
  active: true,
841
847
  originalUpdateContent: prototype.updateContent,
848
+ nativeUpdateContent: prototype.updateContent,
842
849
  patchedUpdateContent: undefined as any,
843
850
  };
844
851
 
845
852
  patch.patchedUpdateContent = function patchedUpdateContent(this: any, message: any) {
853
+ // A renderer loaded after ccstyle may call the previous ccstyle wrapper.
854
+ // Bypass the newly linked downstream wrapper on that re-entry to avoid a
855
+ // recursion loop while preserving the original native renderer.
856
+ if (this[ASSISTANT_REENTRY_KEY] === patch) {
857
+ return patch.nativeUpdateContent.call(this, message);
858
+ }
846
859
  if (!patch.active || !installation.active || state.activeInstallation !== installation) {
847
860
  return patch.originalUpdateContent.call(this, message);
848
861
  }
849
862
 
850
863
  state.assistantComponents.add(this);
851
- state.thinkingHidden = !!this.hideThinkingBlock;
852
864
  const mode = currentMode();
853
- if (mode !== "compact" || !this.hideThinkingBlock || !Array.isArray(message?.content)) {
865
+ // Compact owns thinking presentation: always suppress the full native block
866
+ // and surface only the short ticker, without changing Pi's persisted setting.
867
+ state.thinkingHidden = mode === "compact" || !!this.hideThinkingBlock;
868
+ if (mode !== "compact" || !Array.isArray(message?.content)) {
854
869
  if (mode !== "compact") clearCurrentThought();
855
- return patch.originalUpdateContent.call(this, message);
870
+ this[ASSISTANT_REENTRY_KEY] = patch;
871
+ try {
872
+ return patch.originalUpdateContent.call(this, message);
873
+ } finally {
874
+ delete this[ASSISTANT_REENTRY_KEY];
875
+ }
856
876
  }
857
877
  const theme = state.currentTheme;
858
878
  if (!theme || !this.contentContainer || typeof this.contentContainer.clear !== "function") {
@@ -886,6 +906,17 @@ function patchAssistantMessageComponent(installation: CompactInstallation): Assi
886
906
  return patch;
887
907
  }
888
908
 
909
+ /** Reclaim the outermost assistant renderer after another extension patches it. */
910
+ function ensureAssistantPatchOwnership(installation: CompactInstallation): void {
911
+ const patch = installation.assistantPatch;
912
+ if (!installation.active || !patch) return;
913
+ const prototype = patch.prototype;
914
+ if (prototype.updateContent === patch.patchedUpdateContent) return;
915
+ patch.originalUpdateContent = prototype.updateContent;
916
+ prototype.updateContent = patch.patchedUpdateContent;
917
+ prototype[ASSISTANT_PATCH_KEY] = patch;
918
+ }
919
+
889
920
  function patchRenderers(installation: CompactInstallation): void {
890
921
  installation.toolPatch = patchToolExecutionComponent(installation);
891
922
  installation.assistantPatch = patchAssistantMessageComponent(installation);
@@ -987,16 +1018,20 @@ export class DynamicSummaryComponent {
987
1018
  invalidate(): void {}
988
1019
 
989
1020
  render(width: number): string[] {
990
- const line = isCompact() ? summaryLine(this.data) : "";
1021
+ const line = currentMode() !== "off" ? summaryLine(this.data) : "";
991
1022
  if (!line) return [];
992
- return new Text(this.theme.fg("muted", line), 0, 0).render(width);
1023
+ const italic = typeof (this.theme as any).italic === "function"
1024
+ ? (this.theme as any).italic(this.theme.fg("muted", line))
1025
+ : this.theme.fg("muted", line);
1026
+ const prefix = this.theme.fg("borderMuted", "│ ");
1027
+ return new Text(prefix + italic, 0, 0).render(width);
993
1028
  }
994
1029
  }
995
1030
 
996
1031
  function appendRunSummary() {
997
1032
  const stats = state.runStats;
998
1033
  // A single tool row is already the summary.
999
- if (!isCompact() || stats.toolCount < 2 || !state.pi?.appendEntry) return;
1034
+ if (currentMode() === "off" || stats.toolCount < 2 || !state.pi?.appendEntry) return;
1000
1035
  const data: CompactSummaryData = {
1001
1036
  reads: stats.readFiles.size,
1002
1037
  edits: stats.editFiles.size,
@@ -1077,6 +1112,7 @@ export function installCompactStyle(pi: ExtensionAPI, host: CompactStyleHost): C
1077
1112
  return {
1078
1113
  onSessionStart: (_event, ctx) => {
1079
1114
  if (!isOwner()) return;
1115
+ ensureAssistantPatchOwnership(installation);
1080
1116
  captureTheme(ctx);
1081
1117
  state.agentActive = false;
1082
1118
  state.runStats = newRunStats();
@@ -1111,6 +1147,7 @@ export function installCompactStyle(pi: ExtensionAPI, host: CompactStyleHost): C
1111
1147
  },
1112
1148
  onMessageUpdate: (event, ctx) => {
1113
1149
  if (!isOwner()) return;
1150
+ ensureAssistantPatchOwnership(installation);
1114
1151
  captureTheme(ctx);
1115
1152
  const type = event?.assistantMessageEvent?.type;
1116
1153
  if (typeof type === "string" && type.startsWith("thinking_")) updateCurrentThoughtFromMessage(event.message);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-cc-extensions",
3
- "version": "0.8.4",
3
+ "version": "0.8.6",
4
4
  "description": "A Pi productivity suite with Claude Code-style UI, context inspection, and agent/session references",
5
5
  "type": "module",
6
6
  "keywords": [