Add plannotator extension v0.19.10

This commit is contained in:
2026-05-07 11:38:14 +10:00
parent e914bc59c9
commit f37e4565ff
91 changed files with 35103 additions and 0 deletions

View File

@@ -0,0 +1,147 @@
import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
type SendUserMessageContent = Parameters<ExtensionAPI["sendUserMessage"]>[0];
type SendUserMessageOptions = Parameters<ExtensionAPI["sendUserMessage"]>[1];
type NotificationType = "info" | "warning" | "error";
type CurrentPiSession = {
token: symbol;
sendUserMessage: (content: SendUserMessageContent, options?: SendUserMessageOptions) => void;
notify?: (message: string, type?: NotificationType) => void;
identity?: PiSessionIdentity;
};
type CurrentPiSessionStore = {
current?: CurrentPiSession;
};
type PlannotatorGlobal = typeof globalThis & {
__plannotatorCurrentPiSession?: CurrentPiSessionStore;
};
export type CurrentPiSessionRegistration = {
token: symbol;
update: (ctx: ExtensionContext) => void;
clear: () => void;
};
export type PiSessionIdentity = {
sessionId?: string;
sessionFile?: string;
sessionName?: string;
cwd?: string;
};
const globalStore = globalThis as PlannotatorGlobal;
function getStore(): CurrentPiSessionStore {
globalStore.__plannotatorCurrentPiSession ??= {};
return globalStore.__plannotatorCurrentPiSession;
}
function getErrorMessage(err: unknown): string {
return err instanceof Error ? err.message : String(err);
}
export function getPiSessionIdentity(ctx: ExtensionContext): PiSessionIdentity {
return {
sessionId: ctx.sessionManager.getSessionId(),
sessionFile: ctx.sessionManager.getSessionFile(),
sessionName: ctx.sessionManager.getSessionName(),
cwd: ctx.cwd,
};
}
function isDifferentSession(origin: PiSessionIdentity, current: PiSessionIdentity | undefined): boolean {
if (!current) return false;
if (origin.sessionId && current.sessionId) return origin.sessionId !== current.sessionId;
if (origin.sessionFile && current.sessionFile) return origin.sessionFile !== current.sessionFile;
return false;
}
function setCurrentPiSession(token: symbol, pi: ExtensionAPI, ctx?: ExtensionContext): void {
const current: CurrentPiSession = {
token,
sendUserMessage: (content, options) => {
pi.sendUserMessage(content, options);
},
};
if (ctx) {
current.notify = (message, type = "info") => {
ctx.ui.notify(message, type);
};
current.identity = getPiSessionIdentity(ctx);
}
getStore().current = current;
}
export function registerCurrentPiSession(pi: ExtensionAPI): CurrentPiSessionRegistration {
const token = Symbol("plannotator-current-pi-session");
setCurrentPiSession(token, pi);
return {
token,
update: (ctx) => {
setCurrentPiSession(token, pi, ctx);
},
clear: () => {
const store = getStore();
if (store.current?.token === token) {
store.current = undefined;
}
},
};
}
export function notifyCurrentPiSession(
message: string,
type: NotificationType = "info",
origin?: PiSessionIdentity,
): boolean {
const current = getStore().current;
if (!current?.notify) return false;
if (origin && !isDifferentSession(origin, current.identity)) return false;
try {
current.notify(message, type);
return true;
} catch (err) {
console.error(`Plannotator current-session notification failed: ${getErrorMessage(err)}`);
return false;
}
}
export function isCurrentPiSessionDifferentFrom(origin: PiSessionIdentity): boolean {
return isDifferentSession(origin, getStore().current?.identity);
}
function getCurrentPiSessionLabel(): string {
const identity = getStore().current?.identity;
if (!identity) return "unknown";
return identity.sessionName || identity.sessionFile || identity.sessionId || "current active Pi session";
}
export function withCurrentPiSessionFallbackHeader(content: SendUserMessageContent): SendUserMessageContent {
if (typeof content !== "string") return content;
return `This Plannotator feedback was submitted from a browser tab opened before Pi switched sessions. It is being delivered to ${getCurrentPiSessionLabel()} because the original Pi session is no longer active.
${content}`;
}
export function sendUserMessageToCurrentPiSession(
content: SendUserMessageContent,
options?: SendUserMessageOptions,
origin?: PiSessionIdentity,
): { ok: true } | { ok: false; reason: "no-current" | "same-session" | "send-failed"; error: unknown } {
const current = getStore().current;
if (!current) {
return { ok: false, reason: "no-current", error: new Error("No active Pi session is available.") };
}
if (origin && !isDifferentSession(origin, current.identity)) {
return { ok: false, reason: "same-session", error: new Error("No different active Pi session is available.") };
}
try {
current.sendUserMessage(content, options);
return { ok: true };
} catch (err) {
return { ok: false, reason: "send-failed", error: err };
}
}