@herbertgao/pi-extensions 2026.8.8 → 2026.8.9
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 -3
- package/node_modules/@czottmann/pi-automode/CHANGELOG.md +24 -0
- package/node_modules/@czottmann/pi-automode/README.md +78 -112
- package/node_modules/@czottmann/pi-automode/docs/GLOSSARY.md +18 -14
- package/node_modules/@czottmann/pi-automode/docs/adr/ADR-001-permission-precedence-and-trust-boundaries.md +44 -0
- package/node_modules/@czottmann/pi-automode/docs/adr/INDEX.md +5 -0
- package/node_modules/@czottmann/pi-automode/docs/automode-classifier-flow.md +198 -104
- package/node_modules/@czottmann/pi-automode/docs/configuration.md +155 -0
- package/node_modules/@czottmann/pi-automode/docs/defaults.md +55 -14
- package/node_modules/@czottmann/pi-automode/docs/diagnostics.md +90 -0
- package/node_modules/@czottmann/pi-automode/docs/observability-logging.md +61 -26
- package/node_modules/@czottmann/pi-automode/examples/automode.local.json +5 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +172 -18
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/config.ts +127 -30
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +3 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/extension.ts +273 -31
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/log.ts +60 -5
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/paths.ts +92 -8
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/permissions.ts +203 -13
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/state.ts +1 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/types.ts +11 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/utils.ts +9 -1
- package/node_modules/@czottmann/pi-automode/package.json +9 -2
- package/node_modules/@czottmann/pi-automode/skills/automode-diagnostics/SKILL.md +63 -0
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +3 -3
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +3 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +8 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +56 -29
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +15 -13
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-handoff/CHANGELOG.md +29 -0
- package/node_modules/@herbertgao/pi-handoff/README.md +15 -18
- package/node_modules/@herbertgao/pi-handoff/package.json +11 -4
- package/node_modules/@herbertgao/pi-handoff/src/complete-text.ts +33 -0
- package/node_modules/@herbertgao/pi-handoff/src/index.ts +127 -232
- package/node_modules/@herbertgao/pi-handoff/src/session-query.ts +15 -30
- package/node_modules/@herbertgao/pi-mermaid-open/CHANGELOG.md +14 -0
- package/node_modules/@herbertgao/pi-mermaid-open/README.md +21 -4
- package/node_modules/@herbertgao/pi-mermaid-open/herdr-plugin/herdr-plugin.toml +11 -0
- package/node_modules/@herbertgao/pi-mermaid-open/herdr-plugin/viewer.mjs +305 -0
- package/node_modules/@herbertgao/pi-mermaid-open/package.json +15 -4
- package/node_modules/@herbertgao/pi-mermaid-open/src/index.ts +351 -101
- package/node_modules/@herbertgao/pi-preferred-thinking/CHANGELOG.md +12 -0
- package/node_modules/@herbertgao/pi-preferred-thinking/README.md +30 -14
- package/node_modules/@herbertgao/pi-preferred-thinking/package.json +7 -4
- package/node_modules/@herbertgao/pi-preferred-thinking/src/index.ts +140 -85
- package/node_modules/@herbertgao/pi-recap/CHANGELOG.md +12 -0
- package/node_modules/@herbertgao/pi-recap/README.md +5 -3
- package/node_modules/@herbertgao/pi-recap/package.json +9 -3
- package/node_modules/@herbertgao/pi-recap/src/index.ts +3 -7
- package/node_modules/@herbertgao/pi-recap/src/model-picker.ts +6 -19
- package/node_modules/@herbertgao/pi-recap/src/models.ts +9 -21
- package/node_modules/@herbertgao/pi-recap/src/tui.ts +1 -1
- package/node_modules/@herbertgao/pi-rename/CHANGELOG.md +49 -0
- package/node_modules/@herbertgao/pi-rename/README.md +13 -11
- package/node_modules/@herbertgao/pi-rename/package.json +13 -3
- package/node_modules/@herbertgao/pi-rename/src/index.ts +135 -59
- package/node_modules/@herbertgao/pi-rename/src/models.ts +5 -13
- package/node_modules/@herbertgao/pi-rename/src/naming.ts +2 -6
- package/node_modules/@herbertgao/pi-stash/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +8 -0
- package/node_modules/@herbertgao/pi-subagents/README.md +16 -3
- package/node_modules/@herbertgao/pi-subagents/package.json +1 -1
- package/node_modules/@herbertgao/pi-subagents/src/cross-extension-rpc.ts +15 -4
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +16 -0
- package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +5 -1
- package/node_modules/pi-web-access/CHANGELOG.md +13 -0
- package/node_modules/pi-web-access/README.md +2 -2
- package/node_modules/pi-web-access/chrome-cookies.ts +12 -7
- package/node_modules/pi-web-access/gemini-search.ts +28 -10
- package/node_modules/pi-web-access/index.ts +24 -10
- package/node_modules/pi-web-access/package.json +1 -1
- package/package.json +13 -12
|
@@ -9,7 +9,7 @@ import { Key, Markdown, matchesKey, truncateToWidth, visibleWidth } from "@earen
|
|
|
9
9
|
export type ContextPart = {
|
|
10
10
|
label: string;
|
|
11
11
|
tokens: number;
|
|
12
|
-
color: "accent" | "success" | "warning" | "muted" | "dim";
|
|
12
|
+
color: "accent" | "success" | "warning" | "muted" | "dim" | "error";
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
type PreviewKey = "systemPrompt" | "tools" | "toolResults" | "contextFiles" | "skills";
|
|
@@ -43,11 +43,16 @@ export function escCloseHitbox(bounds: DialogBounds): {
|
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
let
|
|
46
|
+
let activeContextOverlays = 0;
|
|
47
47
|
|
|
48
|
-
/** fullscreen
|
|
48
|
+
/** fullscreen 输入包装用于把鼠标事件继续传给当前 context overlay。 */
|
|
49
49
|
export function hasActiveTextPreview(): boolean {
|
|
50
|
-
return
|
|
50
|
+
return activeContextOverlays > 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** fullscreen overlays fall back to 1002; restore motion events for hover states. */
|
|
54
|
+
function ensureFullscreenMouseMotion(tui: any): void {
|
|
55
|
+
if (tui.mode === "fullscreen") tui.terminal?.write?.("\x1b[?1003h\x1b[?1006h");
|
|
51
56
|
}
|
|
52
57
|
|
|
53
58
|
export async function showTextPreview(
|
|
@@ -56,10 +61,11 @@ export async function showTextPreview(
|
|
|
56
61
|
rawContent: string,
|
|
57
62
|
): Promise<void> {
|
|
58
63
|
const content = normalizePreviewText(rawContent);
|
|
59
|
-
|
|
64
|
+
activeContextOverlays++;
|
|
60
65
|
try {
|
|
61
66
|
await ctx.ui.custom(
|
|
62
67
|
(tui, theme, _keybindings, done) => {
|
|
68
|
+
ensureFullscreenMouseMotion(tui);
|
|
63
69
|
let scrollOffset = 0;
|
|
64
70
|
let pageSize = 1;
|
|
65
71
|
let totalLines = 1;
|
|
@@ -249,7 +255,7 @@ export async function showTextPreview(
|
|
|
249
255
|
},
|
|
250
256
|
);
|
|
251
257
|
} finally {
|
|
252
|
-
|
|
258
|
+
activeContextOverlays--;
|
|
253
259
|
}
|
|
254
260
|
}
|
|
255
261
|
|
|
@@ -424,7 +430,7 @@ export function collectContextBreakdown(ctx: ExtensionCommandContext): ContextBr
|
|
|
424
430
|
const parts: ContextPart[] = [
|
|
425
431
|
{ label: "System prompt", tokens: baseSystem, color: "accent" },
|
|
426
432
|
{ label: "Tools", tokens: toolTokens, color: "success" },
|
|
427
|
-
{ label: "
|
|
433
|
+
{ label: "Memory", tokens: contextFileTokens, color: "error" },
|
|
428
434
|
{ label: "Skills", tokens: skillTokens, color: "warning" },
|
|
429
435
|
{ label: "User messages", tokens: user, color: "muted" },
|
|
430
436
|
{ label: "Assistant messages", tokens: assistant, color: "accent" },
|
|
@@ -448,10 +454,12 @@ export default function contextUsageExtension(pi: ExtensionAPI) {
|
|
|
448
454
|
const breakdown = collectContextBreakdown(ctx);
|
|
449
455
|
const estimated = breakdown.parts.reduce((sum, part) => sum + part.tokens, 0);
|
|
450
456
|
const fixedParts = breakdown.parts.filter(
|
|
451
|
-
(part) =>
|
|
457
|
+
(part) =>
|
|
458
|
+
part.label === "System prompt" || part.label === "Memory" || part.label === "Tools",
|
|
452
459
|
);
|
|
453
460
|
const variableParts = breakdown.parts.filter(
|
|
454
|
-
(part) =>
|
|
461
|
+
(part) =>
|
|
462
|
+
part.label !== "System prompt" && part.label !== "Memory" && part.label !== "Tools",
|
|
455
463
|
);
|
|
456
464
|
const orderedParts = [...fixedParts, ...variableParts];
|
|
457
465
|
const fixedTokens = fixedParts.reduce((sum, part) => sum + part.tokens, 0);
|
|
@@ -527,9 +535,9 @@ export default function contextUsageExtension(pi: ExtensionAPI) {
|
|
|
527
535
|
},
|
|
528
536
|
{
|
|
529
537
|
key: "contextFiles",
|
|
530
|
-
label: "
|
|
531
|
-
title: "
|
|
532
|
-
content: contextFilesContent || "No
|
|
538
|
+
label: "Memory",
|
|
539
|
+
title: "Memory Files",
|
|
540
|
+
content: contextFilesContent || "No memory files loaded.",
|
|
533
541
|
},
|
|
534
542
|
{
|
|
535
543
|
key: "skills",
|
|
@@ -549,8 +557,10 @@ export default function contextUsageExtension(pi: ExtensionAPI) {
|
|
|
549
557
|
let selectedPreviewIndex = 0;
|
|
550
558
|
|
|
551
559
|
while (true) {
|
|
552
|
-
|
|
560
|
+
activeContextOverlays++;
|
|
561
|
+
const actionPromise = ctx.ui.custom(
|
|
553
562
|
(tui, theme, _keybindings, done) => {
|
|
563
|
+
ensureFullscreenMouseMotion(tui);
|
|
554
564
|
let previewHitboxes: Array<{
|
|
555
565
|
key: PreviewKey;
|
|
556
566
|
row: number;
|
|
@@ -558,6 +568,8 @@ export default function contextUsageExtension(pi: ExtensionAPI) {
|
|
|
558
568
|
endCol: number;
|
|
559
569
|
}> = [];
|
|
560
570
|
let escHitbox: { row: number; startCol: number; endCol: number } | undefined;
|
|
571
|
+
let escHovered = false;
|
|
572
|
+
let hoveredKey: PreviewKey | undefined;
|
|
561
573
|
|
|
562
574
|
const padLine = (text: string, width: number): string => {
|
|
563
575
|
const truncated = truncateToWidth(text, width, "…");
|
|
@@ -588,27 +600,32 @@ export default function contextUsageExtension(pi: ExtensionAPI) {
|
|
|
588
600
|
}
|
|
589
601
|
|
|
590
602
|
const mouse = parseSgrMousePacket(data);
|
|
591
|
-
if (
|
|
592
|
-
|
|
593
|
-
mouseBaseButton(mouse.code) !== 0 ||
|
|
594
|
-
(mouse.code & 32) !== 0
|
|
595
|
-
)
|
|
596
|
-
return;
|
|
597
|
-
if (
|
|
603
|
+
if (!mouse || mouse.final !== "M") return;
|
|
604
|
+
const overEsc = Boolean(
|
|
598
605
|
escHitbox &&
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
)
|
|
603
|
-
done(undefined);
|
|
604
|
-
return;
|
|
605
|
-
}
|
|
606
|
+
mouse.row === escHitbox.row &&
|
|
607
|
+
mouse.col >= escHitbox.startCol &&
|
|
608
|
+
mouse.col <= escHitbox.endCol,
|
|
609
|
+
);
|
|
606
610
|
const hitbox = previewHitboxes.find(
|
|
607
611
|
(candidate) =>
|
|
608
612
|
mouse.row === candidate.row &&
|
|
609
613
|
mouse.col >= candidate.startCol &&
|
|
610
614
|
mouse.col <= candidate.endCol,
|
|
611
615
|
);
|
|
616
|
+
if ((mouse.code & 32) !== 0) {
|
|
617
|
+
if (overEsc !== escHovered || hitbox?.key !== hoveredKey) {
|
|
618
|
+
escHovered = overEsc;
|
|
619
|
+
hoveredKey = hitbox?.key;
|
|
620
|
+
tui.requestRender();
|
|
621
|
+
}
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
if (mouseBaseButton(mouse.code) !== 0) return;
|
|
625
|
+
if (overEsc) {
|
|
626
|
+
done(undefined);
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
612
629
|
if (hitbox) {
|
|
613
630
|
selectedPreviewIndex = Math.max(
|
|
614
631
|
0,
|
|
@@ -643,6 +660,9 @@ export default function contextUsageExtension(pi: ExtensionAPI) {
|
|
|
643
660
|
Math.max(...allParts.map((part) => part.label.length)),
|
|
644
661
|
);
|
|
645
662
|
const selectedLabel = visiblePreviews[selectedPreviewIndex]?.label;
|
|
663
|
+
const hoverLabel = visiblePreviews.find(
|
|
664
|
+
(preview) => preview.key === hoveredKey,
|
|
665
|
+
)?.label;
|
|
646
666
|
const partRows = allParts.map((part) => {
|
|
647
667
|
const pct = contextWindow > 0 ? (part.tokens / contextWindow) * 100 : 0;
|
|
648
668
|
const swatch = theme.fg(part.color, "■");
|
|
@@ -651,12 +671,13 @@ export default function contextUsageExtension(pi: ExtensionAPI) {
|
|
|
651
671
|
const selected = part.label === selectedLabel;
|
|
652
672
|
const prefix = selected ? "› " : " ";
|
|
653
673
|
const row = padLine(`${prefix}${swatch} ${label} ${amount}`, inner);
|
|
654
|
-
|
|
674
|
+
if (selected) return theme.bg("selectedBg", row);
|
|
675
|
+
return part.label === hoverLabel ? theme.bg("customMessageBg", row) : row;
|
|
655
676
|
});
|
|
656
677
|
const border = (text: string) => theme.fg("border", text);
|
|
657
678
|
const lines = [
|
|
658
679
|
border(`╭${"─".repeat(inner)}╮`),
|
|
659
|
-
`${border("│")}${padLine(` ${title} ${theme.fg("muted", subtitle)}`, inner - escWidth)}${theme.fg("muted", "[esc]")}${border("│")}`,
|
|
680
|
+
`${border("│")}${padLine(` ${title} ${theme.fg("muted", subtitle)}`, inner - escWidth)}${theme.fg(escHovered ? "text" : "muted", "[esc]")}${border("│")}`,
|
|
660
681
|
`${border("├")}${border("─".repeat(inner))}${border("┤")}`,
|
|
661
682
|
`${border("│")}${padLine(` ${segments}`, inner)}${border("│")}`,
|
|
662
683
|
`${border("│")}${" ".repeat(inner)}${border("│")}`,
|
|
@@ -706,6 +727,12 @@ export default function contextUsageExtension(pi: ExtensionAPI) {
|
|
|
706
727
|
},
|
|
707
728
|
},
|
|
708
729
|
);
|
|
730
|
+
let action;
|
|
731
|
+
try {
|
|
732
|
+
action = await actionPromise;
|
|
733
|
+
} finally {
|
|
734
|
+
activeContextOverlays--;
|
|
735
|
+
}
|
|
709
736
|
|
|
710
737
|
if (!action) break;
|
|
711
738
|
const preview = previewByKey.get(action as PreviewKey);
|
|
@@ -141,7 +141,7 @@ export function installMessageDisplayRendering(): () => void {
|
|
|
141
141
|
tracked: new WeakSet(),
|
|
142
142
|
dispose: () => {},
|
|
143
143
|
};
|
|
144
|
-
const track = (component:
|
|
144
|
+
const track = (component: Record<PropertyKey, unknown>): void => {
|
|
145
145
|
for (const ref of patch.components) {
|
|
146
146
|
if (!ref.deref()) patch.components.delete(ref);
|
|
147
147
|
}
|
|
@@ -86,7 +86,8 @@ const TOOL_MOUSE_MOTION_ENABLE = "\x1b[?1003h\x1b[?1006h";
|
|
|
86
86
|
const TOOL_MOUSE_MOTION_DISABLE = "\x1b[?1003l";
|
|
87
87
|
const FULLSCREEN_MOTION_ENABLED = Symbol("ccstyle.fullscreen-motion-enabled");
|
|
88
88
|
const TOOL_MOUSE_OWNER_KEY = Symbol.for("pi.ccstyle.tool-mouse-owner");
|
|
89
|
-
|
|
89
|
+
type ToolMouseOwner = object;
|
|
90
|
+
const DEFAULT_TOOL_MOUSE_OWNER: ToolMouseOwner = {};
|
|
90
91
|
export const TOOL_MOUSE_DISABLE = "\x1b[?1006l\x1b[?1003l\x1b[?1000l";
|
|
91
92
|
|
|
92
93
|
let toolMouseUi: any = null;
|
|
@@ -96,7 +97,7 @@ let toolMouseRenderPatchOriginal: ((...args: any[]) => any) | null = null;
|
|
|
96
97
|
let toolMouseRenderPatchWrapper: ((...args: any[]) => any) | null = null;
|
|
97
98
|
let toolMouseRenderPatchState: { active: boolean } | null = null;
|
|
98
99
|
let toolMouseRawWrite: ((data: string) => unknown) | null = null;
|
|
99
|
-
let toolMouseInstallationOwner:
|
|
100
|
+
let toolMouseInstallationOwner: ToolMouseOwner | null = null;
|
|
100
101
|
let fullscreenMotionTerminal: any = null;
|
|
101
102
|
let ownsFullscreenMotion = false;
|
|
102
103
|
let sessionRenderTimer: ReturnType<typeof setTimeout> | null = null;
|
|
@@ -156,9 +157,10 @@ function updateToolSummaryHover(tui: any, packet: SgrMousePacket): void {
|
|
|
156
157
|
}
|
|
157
158
|
|
|
158
159
|
const EXPAND_PANEL_DOUBLE_CLICK_MS = 400;
|
|
159
|
-
|
|
160
|
+
type ExpandPanelIdentity = string | object;
|
|
161
|
+
let lastExpandPanelClick: { id: ExpandPanelIdentity; at: number } | null = null;
|
|
160
162
|
|
|
161
|
-
function expandPanelIdentity(card: any):
|
|
163
|
+
function expandPanelIdentity(card: any): ExpandPanelIdentity {
|
|
162
164
|
return card instanceof ThinkingPreviewBlock
|
|
163
165
|
? thinkingRunKey(card.messageTimestamp, card.runStartIndex)
|
|
164
166
|
: card;
|
|
@@ -471,7 +473,7 @@ function patchFullscreenViewportInput(tui: any): void {
|
|
|
471
473
|
}
|
|
472
474
|
}
|
|
473
475
|
}
|
|
474
|
-
return
|
|
476
|
+
return original.apply(this, [data]);
|
|
475
477
|
};
|
|
476
478
|
}
|
|
477
479
|
|
|
@@ -611,7 +613,7 @@ function wrapToolRendersForFrame(
|
|
|
611
613
|
) {
|
|
612
614
|
const boxOriginal = box.render;
|
|
613
615
|
const boxWrapped = function (this: any, ...boxArgs: any[]) {
|
|
614
|
-
const boxLines =
|
|
616
|
+
const boxLines = boxOriginal.apply(this, boxArgs);
|
|
615
617
|
if (Array.isArray(boxLines)) contentBoxLines = boxLines.length;
|
|
616
618
|
return boxLines;
|
|
617
619
|
};
|
|
@@ -621,7 +623,7 @@ function wrapToolRendersForFrame(
|
|
|
621
623
|
}
|
|
622
624
|
}
|
|
623
625
|
try {
|
|
624
|
-
const lines =
|
|
626
|
+
const lines = originalRender.apply(this, renderArgs);
|
|
625
627
|
if (!Array.isArray(lines)) return lines;
|
|
626
628
|
renderedTools.push({
|
|
627
629
|
component,
|
|
@@ -697,10 +699,10 @@ function patchToolMouseMotionAfterRender(tui: any): void {
|
|
|
697
699
|
const rawWrite = typeof terminal?.write === "function" ? terminal.write : undefined;
|
|
698
700
|
if (typeof original !== "function") return;
|
|
699
701
|
|
|
700
|
-
toolMouseRawWrite = rawWrite ? (data) =>
|
|
702
|
+
toolMouseRawWrite = rawWrite ? (data) => rawWrite.apply(terminal, [data]) : null;
|
|
701
703
|
const patchState = { active: true };
|
|
702
704
|
const wrapper = function (this: any, ...args: any[]) {
|
|
703
|
-
if (!patchState.active) return
|
|
705
|
+
if (!patchState.active) return original.apply(this, args);
|
|
704
706
|
const renderedTools: FrameToolRender[] = [];
|
|
705
707
|
const idToComponent = new Map<number, any>();
|
|
706
708
|
const frame: IoViewFrameState = {
|
|
@@ -717,7 +719,7 @@ function patchToolMouseMotionAfterRender(tui: any): void {
|
|
|
717
719
|
let sawTuiRender = false;
|
|
718
720
|
if (originalTuiRender) {
|
|
719
721
|
const wrappedTuiRender = function (this: any, ...renderArgs: any[]) {
|
|
720
|
-
const lines =
|
|
722
|
+
const lines = originalTuiRender.apply(this, renderArgs);
|
|
721
723
|
if (!Array.isArray(lines)) return lines;
|
|
722
724
|
sawTuiRender = true;
|
|
723
725
|
const extracted = extractToolFramePlacements(
|
|
@@ -734,7 +736,7 @@ function patchToolMouseMotionAfterRender(tui: any): void {
|
|
|
734
736
|
const previousFrame = getActiveIoViewFrame();
|
|
735
737
|
setActiveIoViewFrame(frame);
|
|
736
738
|
try {
|
|
737
|
-
const result =
|
|
739
|
+
const result = original.apply(this, args);
|
|
738
740
|
succeeded = true;
|
|
739
741
|
// Test harnesses may paint via doRender without tui.render; recover markers there.
|
|
740
742
|
if (!sawTuiRender && Array.isArray(this.previousLines)) {
|
|
@@ -811,7 +813,7 @@ function handleToolMouseInput(data: string): { consume: true } | undefined {
|
|
|
811
813
|
}
|
|
812
814
|
|
|
813
815
|
export function teardownToolMouseInteraction(
|
|
814
|
-
owner:
|
|
816
|
+
owner: ToolMouseOwner = toolMouseInstallationOwner ?? DEFAULT_TOOL_MOUSE_OWNER,
|
|
815
817
|
): void {
|
|
816
818
|
const host = globalThis as any;
|
|
817
819
|
if (host[TOOL_MOUSE_OWNER_KEY] && host[TOOL_MOUSE_OWNER_KEY] !== owner) return;
|
|
@@ -861,7 +863,7 @@ export function resetToolHoverState(): void {
|
|
|
861
863
|
|
|
862
864
|
export function installToolMouseInteraction(
|
|
863
865
|
ctx: any,
|
|
864
|
-
owner:
|
|
866
|
+
owner: ToolMouseOwner = DEFAULT_TOOL_MOUSE_OWNER,
|
|
865
867
|
): void {
|
|
866
868
|
teardownToolMouseInteraction(toolMouseInstallationOwner ?? owner);
|
|
867
869
|
if (ctx?.mode !== "tui" || !ctx?.hasUI) return;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herbertgao/pi-cc-extensions",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.58",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "A Pi productivity suite with Claude Code-style UI, context inspection, and agent/session references",
|
|
6
6
|
"type": "module",
|
|
@@ -69,8 +69,8 @@
|
|
|
69
69
|
},
|
|
70
70
|
"x-upstream": {
|
|
71
71
|
"package": "pi-cc-extensions",
|
|
72
|
-
"version": "0.8.
|
|
72
|
+
"version": "0.8.66",
|
|
73
73
|
"repository": "https://github.com/minuque/pi-cc-extensions",
|
|
74
|
-
"commit": "
|
|
74
|
+
"commit": "e971a39d1685590de81bd445e3a829279d216039"
|
|
75
75
|
}
|
|
76
76
|
}
|
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# @tifan/pi-handoff
|
|
2
2
|
|
|
3
|
+
## 2.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- [#116](https://github.com/HerbertGao/pi-extensions/pull/116) [`ecda398`](https://github.com/HerbertGao/pi-extensions/commit/ecda398b9a95212c512d53325c617e485e6ded8d) Thanks [@HerbertGao](https://github.com/HerbertGao)! - Adopt prompt-marker handoffs that generate a handoff artifact and start a clean session, while retaining the session query tool and local rename package integration.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [[`ecda398`](https://github.com/HerbertGao/pi-extensions/commit/ecda398b9a95212c512d53325c617e485e6ded8d)]:
|
|
12
|
+
- @herbertgao/pi-rename@0.5.0
|
|
13
|
+
|
|
14
|
+
## 2.0.1
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Updated dependencies [[`b2ea184`](https://github.com/tifandotme/pi-extensions/commit/b2ea1841e99243aa4773bd5c33f43c40248859db)]:
|
|
19
|
+
- @tifan/pi-rename@0.5.0
|
|
20
|
+
|
|
21
|
+
## 2.0.0
|
|
22
|
+
|
|
23
|
+
### Major Changes
|
|
24
|
+
|
|
25
|
+
- [`297e825`](https://github.com/tifandotme/pi-extensions/commit/297e825ba42eeed32814a34cd4fe5bdbe935b11c) Thanks [@tifandotme](https://github.com/tifandotme)! - Replace `/handoff-session` with the `-handoff` prompt marker and automatically start the new session from the generated handoff.
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- Updated dependencies [[`e8709bc`](https://github.com/tifandotme/pi-extensions/commit/e8709bc388aa8e094918ec465cfab511358f18ff)]:
|
|
30
|
+
- @tifan/pi-rename@0.4.3
|
|
31
|
+
|
|
3
32
|
## 1.1.2
|
|
4
33
|
|
|
5
34
|
### Patch Changes
|
|
@@ -10,42 +10,39 @@ Start a fresh pi session from a handoff document, and query past sessions for co
|
|
|
10
10
|
pi install npm:@herbertgao/pi-handoff
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
Matt Pocock's [`handoff` skill](https://github.com/mattpocock/skills/blob/main/skills/productivity/handoff/SKILL.md) is required:
|
|
14
16
|
|
|
15
17
|
```bash
|
|
16
|
-
|
|
18
|
+
npx skills add https://github.com/mattpocock/skills --global --skill handoff
|
|
17
19
|
```
|
|
18
20
|
|
|
19
|
-
You also need a `handoff` skill installed and discoverable by pi. For example, install or expose Matt Pocock's `handoff` skill, then run `/reload`.
|
|
20
|
-
|
|
21
21
|
## How it works
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Submit a prompt containing a standalone `-handoff` marker to generate a handoff document from the current session and automatically start a clean session from it. The marker can appear anywhere in the prompt. The handoff is written under the OS temp directory.
|
|
24
24
|
|
|
25
|
-
The new session name
|
|
25
|
+
The new session name uses the current session name when available. Otherwise, it uses the next-session focus, sanitized to lowercase, hyphen-separated text under 60 characters.
|
|
26
26
|
|
|
27
27
|
The handoff includes the previous session path when available, so the next agent can use `session_query` if the handoff omits a detail.
|
|
28
28
|
|
|
29
|
-
##
|
|
29
|
+
## Usage
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
```text
|
|
32
|
+
fix the auth flow -handoff
|
|
33
|
+
```
|
|
32
34
|
|
|
33
|
-
|
|
35
|
+
The standalone `-handoff` marker is consumed before the prompt reaches the agent. The text before and after it becomes the next-session focus. A prompt containing only `-handoff` continues the current work.
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
## `session_query`
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
`session_query`: Answer a question about a previous pi session, given the full path to its `.jsonl` file and the question to ask. It uses the configured `openai-codex/gpt-5.6-luna` model, which must be available and authenticated.
|
|
38
40
|
|
|
39
|
-
-
|
|
40
|
-
- Uses `openai-codex/gpt-5.6-luna` to name the new pi session when available.
|
|
41
|
-
- Requires a discoverable skill named exactly `handoff`.
|
|
42
|
-
- Writes stable, readable files under the OS temp directory, such as `/tmp/pi-handoffs/pi-handoff-2026-06-01-inline-skills.md`.
|
|
43
|
-
- Starts a clean session with native parent-session linking.
|
|
44
|
-
- Does not autosend.
|
|
41
|
+
Pi provides session loading and compaction-aware context reconstruction, but not semantic questions about an arbitrary previous session. `session_query` supplies that model-powered query layer.
|
|
45
42
|
|
|
46
43
|
## Release notes
|
|
47
44
|
|
|
48
|
-
See [CHANGELOG.md](CHANGELOG.md)
|
|
45
|
+
See [CHANGELOG.md](CHANGELOG.md).
|
|
49
46
|
|
|
50
47
|
## License
|
|
51
48
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herbertgao/pi-handoff",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Transfer pi session context to a new session and query past sessions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"handoff",
|
|
@@ -33,7 +33,14 @@
|
|
|
33
33
|
"provenance": true
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@herbertgao/pi-rename": "^0.
|
|
36
|
+
"@herbertgao/pi-rename": "^0.5.0",
|
|
37
|
+
"typebox": "^1.1.38"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"@earendil-works/pi-agent-core": ">=0.84.2",
|
|
41
|
+
"@earendil-works/pi-ai": ">=0.84.2",
|
|
42
|
+
"@earendil-works/pi-coding-agent": ">=0.84.2",
|
|
43
|
+
"@earendil-works/pi-tui": ">=0.84.2"
|
|
37
44
|
},
|
|
38
45
|
"engines": {
|
|
39
46
|
"node": ">=20"
|
|
@@ -46,8 +53,8 @@
|
|
|
46
53
|
},
|
|
47
54
|
"x-upstream": {
|
|
48
55
|
"package": "@tifan/pi-handoff",
|
|
49
|
-
"version": "
|
|
56
|
+
"version": "2.0.1",
|
|
50
57
|
"repository": "https://github.com/tifandotme/pi-extensions",
|
|
51
|
-
"commit": "
|
|
58
|
+
"commit": "3f6b5e628e31817960a02cfae9bcb4a3f4bcd79b"
|
|
52
59
|
}
|
|
53
60
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { complete, type Message } from "@earendil-works/pi-ai/compat"
|
|
2
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent"
|
|
3
|
+
|
|
4
|
+
export async function completeText(
|
|
5
|
+
ctx: Pick<ExtensionContext, "modelRegistry">,
|
|
6
|
+
model: NonNullable<ExtensionContext["model"]>,
|
|
7
|
+
systemPrompt: string,
|
|
8
|
+
message: Message,
|
|
9
|
+
signal?: AbortSignal,
|
|
10
|
+
): Promise<string | null> {
|
|
11
|
+
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model)
|
|
12
|
+
if (!auth.ok) throw new Error(auth.error)
|
|
13
|
+
|
|
14
|
+
const response = await complete(
|
|
15
|
+
model,
|
|
16
|
+
{ systemPrompt, messages: [message] },
|
|
17
|
+
{
|
|
18
|
+
...(auth.apiKey ? { apiKey: auth.apiKey } : {}),
|
|
19
|
+
...(auth.headers ? { headers: auth.headers } : {}),
|
|
20
|
+
...(signal ? { signal } : {}),
|
|
21
|
+
},
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
if (response.stopReason === "aborted") return null
|
|
25
|
+
|
|
26
|
+
return response.content
|
|
27
|
+
.filter((content): content is { type: "text"; text: string } => {
|
|
28
|
+
return content.type === "text"
|
|
29
|
+
})
|
|
30
|
+
.map((content) => content.text)
|
|
31
|
+
.join("\n")
|
|
32
|
+
.trim()
|
|
33
|
+
}
|