pi-cc-extensions 0.8.9 → 0.8.11
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 +3 -2
- package/extensions/agent-autocomplete.ts +11 -16
- package/extensions/ask-user-question/ask-user-question.ts +29 -7
- package/extensions/ask-user-question/config.ts +6 -2
- package/extensions/ask-user-question/index.ts +8 -8
- package/extensions/ask-user-question/rpc-fallback.ts +16 -4
- package/extensions/ask-user-question/state/build-questionnaire.ts +16 -5
- package/extensions/ask-user-question/state/key-router.ts +29 -7
- package/extensions/ask-user-question/state/questionnaire-session.ts +1 -4
- package/extensions/ask-user-question/state/selectors/projections.ts +4 -1
- package/extensions/ask-user-question/state/state-reducer.ts +24 -7
- package/extensions/ask-user-question/tool/response-envelope.ts +4 -1
- package/extensions/ask-user-question/tool/types.ts +5 -1
- package/extensions/ask-user-question/tool/validate-questionnaire.ts +10 -2
- package/extensions/ask-user-question/view/components/inline-input.ts +15 -2
- package/extensions/ask-user-question/view/components/multi-select-view.ts +11 -4
- package/extensions/ask-user-question/view/components/option-list-view.ts +14 -5
- package/extensions/ask-user-question/view/components/preview/preview-block-renderer.ts +13 -7
- package/extensions/ask-user-question/view/components/preview/preview-layout-decider.ts +16 -4
- package/extensions/ask-user-question/view/components/preview/preview-pane.ts +5 -1
- package/extensions/ask-user-question/view/components/submit-picker.ts +3 -1
- package/extensions/ask-user-question/view/components/wrapping-select.ts +20 -4
- package/extensions/ask-user-question/view/dialog-builder.ts +27 -7
- package/extensions/ask-user-question/view/tab-content-strategy.ts +23 -8
- package/extensions/claude-code-style.ts +1722 -1485
- package/extensions/compact-style.ts +120 -43
- package/extensions/context.ts +502 -394
- package/extensions/session-reference-core.ts +8 -3
- package/extensions/session-reference.ts +475 -448
- package/extensions/tool-diff/ATTRIBUTION.md +28 -0
- package/extensions/tool-diff/ansi-utils.ts +113 -0
- package/extensions/tool-diff/diff-presentation.ts +70 -0
- package/extensions/tool-diff/diff-renderer.ts +2827 -0
- package/extensions/tool-diff/index.ts +106 -0
- package/extensions/tool-diff/line-width-safety.ts +91 -0
- package/extensions/tool-diff/render-utils.ts +5 -0
- package/extensions/tool-diff/types.ts +20 -0
- package/extensions/tool-diff/write-display-utils.ts +29 -0
- package/extensions/tool-diff/write-execution.ts +113 -0
- package/extensions/tool-result-sanitize.ts +4 -4
- package/package.json +64 -61
- package/themes/github-dark-default.json +91 -91
|
@@ -298,7 +298,10 @@ export function resultPreview(result: any, isPartial = false): string {
|
|
|
298
298
|
? result.content.find((c: any) => c?.type === "text" && typeof c.text === "string")?.text
|
|
299
299
|
: undefined;
|
|
300
300
|
if (!text) return isPartial ? "running" : "";
|
|
301
|
-
const lines = sanitizeToolResultText(text)
|
|
301
|
+
const lines = sanitizeToolResultText(text)
|
|
302
|
+
.trim()
|
|
303
|
+
.split("\n")
|
|
304
|
+
.filter((line) => line.trim().length > 0);
|
|
302
305
|
if (lines.length === 0) return isPartial ? "running" : "";
|
|
303
306
|
if (lines.length === 1) return lines[0];
|
|
304
307
|
return `${lines.length} lines`;
|
|
@@ -399,7 +402,10 @@ function statusMarker(
|
|
|
399
402
|
if (opts.isError) return theme.fg("error", "✗ ");
|
|
400
403
|
if (opts.running) {
|
|
401
404
|
if (!CLAUDE_LOADING_TOOLS.has(name)) return theme.fg("accent", "● ");
|
|
402
|
-
const frame =
|
|
405
|
+
const frame =
|
|
406
|
+
CLAUDE_LOADING_FRAMES[
|
|
407
|
+
Math.floor(Date.now() / BLINK_INTERVAL_MS) % CLAUDE_LOADING_FRAMES.length
|
|
408
|
+
] ?? "⠋";
|
|
403
409
|
return theme.fg("accent", `${frame} `);
|
|
404
410
|
}
|
|
405
411
|
if (opts.hasResult) return theme.fg("success", "✓ ");
|
|
@@ -409,10 +415,16 @@ function statusMarker(
|
|
|
409
415
|
function textSignalHasVisibleContent(assistantMessageEvent: any): boolean {
|
|
410
416
|
const type = assistantMessageEvent?.type;
|
|
411
417
|
if (type === "text_delta") {
|
|
412
|
-
return
|
|
418
|
+
return (
|
|
419
|
+
typeof assistantMessageEvent.delta === "string" &&
|
|
420
|
+
assistantMessageEvent.delta.trim().length > 0
|
|
421
|
+
);
|
|
413
422
|
}
|
|
414
423
|
if (type === "text_end") {
|
|
415
|
-
return
|
|
424
|
+
return (
|
|
425
|
+
typeof assistantMessageEvent.content === "string" &&
|
|
426
|
+
assistantMessageEvent.content.trim().length > 0
|
|
427
|
+
);
|
|
416
428
|
}
|
|
417
429
|
return false;
|
|
418
430
|
}
|
|
@@ -492,7 +504,8 @@ function updateCurrentThoughtFromMessage(message: any) {
|
|
|
492
504
|
}
|
|
493
505
|
|
|
494
506
|
function anchorCurrentThoughtTo(info: ToolInfo) {
|
|
495
|
-
if (!thoughtTickerEnabled() || !state.currentThoughtHeading || state.thoughtAnchorId === info.id)
|
|
507
|
+
if (!thoughtTickerEnabled() || !state.currentThoughtHeading || state.thoughtAnchorId === info.id)
|
|
508
|
+
return;
|
|
496
509
|
const previousAnchorId = state.thoughtAnchorId;
|
|
497
510
|
state.thoughtAnchorId = info.id;
|
|
498
511
|
invalidateToolById(previousAnchorId);
|
|
@@ -500,10 +513,18 @@ function anchorCurrentThoughtTo(info: ToolInfo) {
|
|
|
500
513
|
}
|
|
501
514
|
|
|
502
515
|
function currentThoughtLine(toolCallId: string, theme: Theme): string {
|
|
503
|
-
if (
|
|
516
|
+
if (
|
|
517
|
+
!thoughtTickerEnabled() ||
|
|
518
|
+
state.thoughtAnchorId !== toolCallId ||
|
|
519
|
+
!state.currentThoughtHeading
|
|
520
|
+
)
|
|
521
|
+
return "";
|
|
504
522
|
const prefix = " ↳ ";
|
|
505
523
|
const budget = previewWidth((process.stdout.columns || 100) - prefix.length);
|
|
506
|
-
return
|
|
524
|
+
return (
|
|
525
|
+
theme.fg("dim", prefix) +
|
|
526
|
+
theme.fg("thinkingText", limitPlain(state.currentThoughtHeading, budget))
|
|
527
|
+
);
|
|
507
528
|
}
|
|
508
529
|
|
|
509
530
|
function upsertToolInfo(id: string, name: string, args: any, invalidate?: () => void): ToolInfo {
|
|
@@ -542,7 +563,10 @@ function joinBurst(info: ToolInfo) {
|
|
|
542
563
|
}
|
|
543
564
|
|
|
544
565
|
// Only consecutive uses of the same tool are grouped.
|
|
545
|
-
if (
|
|
566
|
+
if (
|
|
567
|
+
state.currentBurst.length &&
|
|
568
|
+
state.currentBurst[state.currentBurst.length - 1].name !== info.name
|
|
569
|
+
) {
|
|
546
570
|
state.currentBurst = [];
|
|
547
571
|
}
|
|
548
572
|
|
|
@@ -592,7 +616,10 @@ function updateToolResult(toolCallId: string, result: any, isError = false, isPa
|
|
|
592
616
|
info.running = false;
|
|
593
617
|
if (info.startedAt) info.durationMs = Date.now() - info.startedAt;
|
|
594
618
|
if (state.currentBurst.includes(info) && state.currentBurst.length > 1) {
|
|
595
|
-
info.burstDurationMs = state.currentBurst.reduce(
|
|
619
|
+
info.burstDurationMs = state.currentBurst.reduce(
|
|
620
|
+
(total, tool) => total + (tool.durationMs ?? 0),
|
|
621
|
+
0,
|
|
622
|
+
);
|
|
596
623
|
}
|
|
597
624
|
if (isError) state.runStats.failedCount++;
|
|
598
625
|
}
|
|
@@ -616,7 +643,9 @@ function compactToolLine(
|
|
|
616
643
|
if (info.hidden) return "";
|
|
617
644
|
|
|
618
645
|
const isBurst = (info.burstCount ?? 1) > 1;
|
|
619
|
-
const durationText = formatDuration(
|
|
646
|
+
const durationText = formatDuration(
|
|
647
|
+
(isBurst ? (info.burstDurationMs ?? info.durationMs) : info.durationMs) ?? 0,
|
|
648
|
+
);
|
|
620
649
|
const inner = [info.result ? oneLine(info.result) : "", durationText].filter(Boolean).join(" · ");
|
|
621
650
|
const status = inner ? ` {${inner}}` : info.running ? " {running}" : "";
|
|
622
651
|
const details = `${info.preview}${status}`;
|
|
@@ -629,7 +658,9 @@ function compactToolLine(
|
|
|
629
658
|
if (!isBurst) return indent + marker + theme.fg("muted", limitPlain(details));
|
|
630
659
|
|
|
631
660
|
const prefix = `${info.burstCount}× `;
|
|
632
|
-
const budget = previewWidth(
|
|
661
|
+
const budget = previewWidth(
|
|
662
|
+
(process.stdout.columns || 100) - indent.length - prefix.length - MARKER_WIDTH,
|
|
663
|
+
);
|
|
633
664
|
return indent + marker + theme.fg("muted", prefix + limitPlain(details, budget));
|
|
634
665
|
}
|
|
635
666
|
|
|
@@ -662,20 +693,27 @@ function nativeToolShellChild(component: any): any {
|
|
|
662
693
|
}
|
|
663
694
|
|
|
664
695
|
function toolShellChildren(component: any): any[] {
|
|
665
|
-
return [component.contentText, component.contentBox, component.selfRenderContainer].filter(
|
|
696
|
+
return [component.contentText, component.contentBox, component.selfRenderContainer].filter(
|
|
697
|
+
Boolean,
|
|
698
|
+
);
|
|
666
699
|
}
|
|
667
700
|
|
|
668
701
|
function syncToolShellChild(component: any, target: any, preferredIndex?: number): void {
|
|
669
702
|
if (!target || !Array.isArray(component.children)) return;
|
|
670
703
|
const candidates = new Set(toolShellChildren(component));
|
|
671
704
|
const shellIndexes = component.children
|
|
672
|
-
.map((child: any, index: number) => candidates.has(child) ? index : -1)
|
|
705
|
+
.map((child: any, index: number) => (candidates.has(child) ? index : -1))
|
|
673
706
|
.filter((index: number) => index >= 0);
|
|
674
|
-
const targetIndex =
|
|
675
|
-
|
|
676
|
-
|
|
707
|
+
const targetIndex =
|
|
708
|
+
preferredIndex !== undefined && shellIndexes.includes(preferredIndex)
|
|
709
|
+
? preferredIndex
|
|
710
|
+
: shellIndexes[0];
|
|
677
711
|
if (targetIndex === undefined) {
|
|
678
|
-
if (
|
|
712
|
+
if (
|
|
713
|
+
preferredIndex !== undefined &&
|
|
714
|
+
preferredIndex >= 0 &&
|
|
715
|
+
preferredIndex <= component.children.length
|
|
716
|
+
) {
|
|
679
717
|
component.children.splice(preferredIndex, 0, target);
|
|
680
718
|
} else if (typeof component.addChild === "function") {
|
|
681
719
|
component.addChild(target);
|
|
@@ -706,9 +744,12 @@ function restoreNativeToolShell(component: any): void {
|
|
|
706
744
|
delete component[TOOL_NATIVE_CHILD_KEY];
|
|
707
745
|
}
|
|
708
746
|
|
|
709
|
-
function patchToolExecutionComponent(
|
|
747
|
+
function patchToolExecutionComponent(
|
|
748
|
+
installation: CompactInstallation,
|
|
749
|
+
): ToolPrototypePatch | undefined {
|
|
710
750
|
const prototype = ToolExecutionComponent.prototype as any;
|
|
711
|
-
if (typeof prototype.updateDisplay !== "function" || typeof prototype.render !== "function")
|
|
751
|
+
if (typeof prototype.updateDisplay !== "function" || typeof prototype.render !== "function")
|
|
752
|
+
return undefined;
|
|
712
753
|
|
|
713
754
|
const patch: ToolPrototypePatch = {
|
|
714
755
|
prototype,
|
|
@@ -739,7 +780,12 @@ function patchToolExecutionComponent(installation: CompactInstallation): ToolPro
|
|
|
739
780
|
}
|
|
740
781
|
return patch.originalUpdateDisplay.call(this);
|
|
741
782
|
}
|
|
742
|
-
if (
|
|
783
|
+
if (
|
|
784
|
+
!this.toolCallId ||
|
|
785
|
+
!this.toolName ||
|
|
786
|
+
!this.selfRenderContainer ||
|
|
787
|
+
typeof this.selfRenderContainer.clear !== "function"
|
|
788
|
+
) {
|
|
743
789
|
this.__compactStyleForceSelf = false;
|
|
744
790
|
this.__compactStyleHidden = false;
|
|
745
791
|
restoreNativeToolShell(this);
|
|
@@ -817,27 +863,39 @@ function appendNativeStopReason(component: any, message: any, theme: Theme): voi
|
|
|
817
863
|
component.hasToolCalls = hasToolCalls;
|
|
818
864
|
if (message.stopReason === "length") {
|
|
819
865
|
component.contentContainer.addChild(new Spacer(1));
|
|
820
|
-
component.contentContainer.addChild(
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
866
|
+
component.contentContainer.addChild(
|
|
867
|
+
new Text(
|
|
868
|
+
theme.fg(
|
|
869
|
+
"error",
|
|
870
|
+
"Error: Model stopped because it reached the maximum output token limit. The response may be incomplete.",
|
|
871
|
+
),
|
|
872
|
+
component.outputPad,
|
|
873
|
+
0,
|
|
874
|
+
),
|
|
875
|
+
);
|
|
825
876
|
} else if (!hasToolCalls) {
|
|
826
877
|
if (message.stopReason === "aborted") {
|
|
827
|
-
const abortMessage =
|
|
828
|
-
|
|
829
|
-
|
|
878
|
+
const abortMessage =
|
|
879
|
+
message.errorMessage && message.errorMessage !== "Request was aborted"
|
|
880
|
+
? message.errorMessage
|
|
881
|
+
: "Operation aborted";
|
|
830
882
|
component.contentContainer.addChild(new Spacer(1));
|
|
831
|
-
component.contentContainer.addChild(
|
|
883
|
+
component.contentContainer.addChild(
|
|
884
|
+
new Text(theme.fg("error", abortMessage), component.outputPad, 0),
|
|
885
|
+
);
|
|
832
886
|
} else if (message.stopReason === "error") {
|
|
833
887
|
const errorMessage = message.errorMessage || "Unknown error";
|
|
834
888
|
component.contentContainer.addChild(new Spacer(1));
|
|
835
|
-
component.contentContainer.addChild(
|
|
889
|
+
component.contentContainer.addChild(
|
|
890
|
+
new Text(theme.fg("error", `Error: ${errorMessage}`), component.outputPad, 0),
|
|
891
|
+
);
|
|
836
892
|
}
|
|
837
893
|
}
|
|
838
894
|
}
|
|
839
895
|
|
|
840
|
-
function patchAssistantMessageComponent(
|
|
896
|
+
function patchAssistantMessageComponent(
|
|
897
|
+
installation: CompactInstallation,
|
|
898
|
+
): AssistantPrototypePatch | undefined {
|
|
841
899
|
const prototype = AssistantMessageComponent.prototype as any;
|
|
842
900
|
if (typeof prototype.updateContent !== "function") return undefined;
|
|
843
901
|
|
|
@@ -884,14 +942,19 @@ function patchAssistantMessageComponent(installation: CompactInstallation): Assi
|
|
|
884
942
|
// text and stop-reason paths exactly, while intentionally omitting thinking.
|
|
885
943
|
this.lastMessage = message;
|
|
886
944
|
this.contentContainer.clear();
|
|
887
|
-
const texts = message.content.filter(
|
|
945
|
+
const texts = message.content.filter(
|
|
946
|
+
(content: any) => content.type === "text" && content.text?.trim(),
|
|
947
|
+
);
|
|
888
948
|
const hasToolCalls = message.content.some((content: any) => content.type === "toolCall");
|
|
889
|
-
const hasTerminalNotice =
|
|
890
|
-
|
|
949
|
+
const hasTerminalNotice =
|
|
950
|
+
message.stopReason === "length" ||
|
|
951
|
+
(!hasToolCalls && (message.stopReason === "aborted" || message.stopReason === "error"));
|
|
891
952
|
if (texts.length > 0) {
|
|
892
953
|
this.contentContainer.addChild(new Spacer(1));
|
|
893
954
|
for (const content of texts) {
|
|
894
|
-
this.contentContainer.addChild(
|
|
955
|
+
this.contentContainer.addChild(
|
|
956
|
+
new Markdown(content.text.trim(), this.outputPad, 0, this.markdownTheme),
|
|
957
|
+
);
|
|
895
958
|
}
|
|
896
959
|
}
|
|
897
960
|
if (texts.length > 0 || hasTerminalNotice) {
|
|
@@ -932,7 +995,8 @@ function restorePrototypePatches(installation: CompactInstallation): void {
|
|
|
932
995
|
if (toolPatch.prototype.render === toolPatch.patchedRender) {
|
|
933
996
|
toolPatch.prototype.render = toolPatch.originalRender;
|
|
934
997
|
}
|
|
935
|
-
if (toolPatch.prototype[TOOL_PATCH_KEY] === toolPatch)
|
|
998
|
+
if (toolPatch.prototype[TOOL_PATCH_KEY] === toolPatch)
|
|
999
|
+
delete toolPatch.prototype[TOOL_PATCH_KEY];
|
|
936
1000
|
}
|
|
937
1001
|
|
|
938
1002
|
const assistantPatch = installation.assistantPatch;
|
|
@@ -973,7 +1037,8 @@ export function refreshCompactTranscript(): void {
|
|
|
973
1037
|
|
|
974
1038
|
export function normalizeSummary(input: unknown): CompactSummaryData {
|
|
975
1039
|
const source = (input && typeof input === "object" ? input : {}) as Record<string, unknown>;
|
|
976
|
-
const num = (value: unknown) =>
|
|
1040
|
+
const num = (value: unknown) =>
|
|
1041
|
+
typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
|
|
977
1042
|
return {
|
|
978
1043
|
reads: num(source.reads),
|
|
979
1044
|
edits: num(source.edits),
|
|
@@ -1020,9 +1085,10 @@ export class DynamicSummaryComponent {
|
|
|
1020
1085
|
render(width: number): string[] {
|
|
1021
1086
|
const line = currentMode() !== "off" ? summaryLine(this.data) : "";
|
|
1022
1087
|
if (!line) return [];
|
|
1023
|
-
const italic =
|
|
1024
|
-
|
|
1025
|
-
|
|
1088
|
+
const italic =
|
|
1089
|
+
typeof (this.theme as any).italic === "function"
|
|
1090
|
+
? (this.theme as any).italic(this.theme.fg("muted", line))
|
|
1091
|
+
: this.theme.fg("muted", line);
|
|
1026
1092
|
const prefix = this.theme.fg("borderMuted", "│ ");
|
|
1027
1093
|
return new Text(prefix + italic, 0, 0).render(width);
|
|
1028
1094
|
}
|
|
@@ -1045,6 +1111,7 @@ function appendRunSummary() {
|
|
|
1045
1111
|
|
|
1046
1112
|
export type CompactStyleHooks = {
|
|
1047
1113
|
onSessionStart(event: unknown, ctx: ExtensionContext): void;
|
|
1114
|
+
onSessionCompact(event: unknown, ctx: ExtensionContext): void;
|
|
1048
1115
|
onSessionShutdown(event: unknown, ctx: ExtensionContext): void;
|
|
1049
1116
|
onAgentStart(event: unknown, ctx: ExtensionContext): void;
|
|
1050
1117
|
onAgentEnd(event: unknown, ctx: ExtensionContext): void;
|
|
@@ -1099,8 +1166,9 @@ export function installCompactStyle(pi: ExtensionAPI, host: CompactStyleHost): C
|
|
|
1099
1166
|
try {
|
|
1100
1167
|
patchRenderers(installation);
|
|
1101
1168
|
if (typeof (pi as any).registerEntryRenderer === "function") {
|
|
1102
|
-
pi.registerEntryRenderer(
|
|
1103
|
-
|
|
1169
|
+
pi.registerEntryRenderer(
|
|
1170
|
+
SUMMARY_ENTRY_TYPE,
|
|
1171
|
+
(entry: any, _options: any, theme: Theme) => new DynamicSummaryComponent(entry.data, theme),
|
|
1104
1172
|
);
|
|
1105
1173
|
}
|
|
1106
1174
|
} catch (error) {
|
|
@@ -1121,6 +1189,14 @@ export function installCompactStyle(pi: ExtensionAPI, host: CompactStyleHost): C
|
|
|
1121
1189
|
refreshCompactTranscript();
|
|
1122
1190
|
ctx.ui.setStatus(STATUS_KEY, undefined);
|
|
1123
1191
|
},
|
|
1192
|
+
onSessionCompact: (_event, ctx) => {
|
|
1193
|
+
if (!isOwner()) return;
|
|
1194
|
+
// Pi rebuilds transcript components after compaction without emitting
|
|
1195
|
+
// session_start. Reclaim renderer ownership and repaint retained rows.
|
|
1196
|
+
ensureAssistantPatchOwnership(installation);
|
|
1197
|
+
captureTheme(ctx);
|
|
1198
|
+
refreshCompactTranscript();
|
|
1199
|
+
},
|
|
1124
1200
|
onSessionShutdown: (_event, ctx) => {
|
|
1125
1201
|
if (isOwner()) teardownCompactInstallation(installation);
|
|
1126
1202
|
ctx.ui.setStatus(STATUS_KEY, undefined);
|
|
@@ -1150,7 +1226,8 @@ export function installCompactStyle(pi: ExtensionAPI, host: CompactStyleHost): C
|
|
|
1150
1226
|
ensureAssistantPatchOwnership(installation);
|
|
1151
1227
|
captureTheme(ctx);
|
|
1152
1228
|
const type = event?.assistantMessageEvent?.type;
|
|
1153
|
-
if (typeof type === "string" && type.startsWith("thinking_"))
|
|
1229
|
+
if (typeof type === "string" && type.startsWith("thinking_"))
|
|
1230
|
+
updateCurrentThoughtFromMessage(event.message);
|
|
1154
1231
|
if (textSignalHasVisibleContent(event?.assistantMessageEvent)) {
|
|
1155
1232
|
clearCurrentThought();
|
|
1156
1233
|
state.currentBurst = [];
|