/** * Pi SDK adapter boundary * Zones: pi agent sdk boundary, shared adapters * Owns direct pi SDK imports and exposes narrow bridge-facing helpers/types for the extension composition layer */ import { type AgentEndEvent, type AgentStartEvent, type BeforeAgentStartEvent, type ExtensionAPI, type ExtensionCommandContext, type ExtensionContext, type SessionBeforeCompactEvent, type SessionCompactEvent, type SessionShutdownEvent, type SessionStartEvent, type SlashCommandInfo, SettingsManager, } from "@earendil-works/pi-coding-agent"; export type { AgentEndEvent, AgentStartEvent, BeforeAgentStartEvent, ExtensionAPI, ExtensionCommandContext, ExtensionContext, SessionBeforeCompactEvent, SessionCompactEvent, SessionShutdownEvent, SessionStartEvent, SlashCommandInfo, }; export interface ToolExecutionStartEvent { type: "tool_execution_start"; toolCallId: string; toolName: string; args: unknown; } export interface ToolExecutionUpdateEvent { type: "tool_execution_update"; toolCallId: string; toolName: string; args: unknown; partialResult: unknown; } export interface ToolExecutionEndEvent { type: "tool_execution_end"; toolCallId: string; toolName: string; result: unknown; isError: boolean; } export interface PiSettingsManager { reload: () => Promise; flush: () => Promise; getEnabledModels: () => string[] | undefined; setEnabledModels: (patterns: string[] | undefined) => void; } export type PiSlashCommandInfo = SlashCommandInfo; export type PiRunMode = "tui" | "rpc" | "json" | "print"; function isPiRunMode(value: unknown): value is PiRunMode { return ( value === "tui" || value === "rpc" || value === "json" || value === "print" ); } export function getExtensionContextMode(ctx: unknown): PiRunMode | undefined { const mode = typeof ctx === "object" && ctx !== null ? (ctx as { mode?: unknown }).mode : undefined; return isPiRunMode(mode) ? mode : undefined; } export function isExtensionContextPassiveRunMode(ctx: unknown): boolean { const mode = getExtensionContextMode(ctx); return mode === "print" || mode === "json"; } export function canStartPollingInExtensionContext(ctx: unknown): boolean { return !isExtensionContextPassiveRunMode(ctx); } export function formatPollingStartBlockedByRunMode(ctx: unknown): string { const mode = getExtensionContextMode(ctx); return mode ? `XMPP connection is unavailable in Pi ${mode} mode. Use /xmpp-connect from a long-lived Pi session.` : "XMPP connection is unavailable in this Pi run mode."; } export type PiSendUserMessageOptions = NonNullable< Parameters[1] >; export interface PiExtensionApiRuntimePorts { sendUserMessage: ExtensionAPI["sendUserMessage"]; exec: ExtensionAPI["exec"]; getCommands: ExtensionAPI["getCommands"]; getThinkingLevel: ExtensionAPI["getThinkingLevel"]; setThinkingLevel: ExtensionAPI["setThinkingLevel"]; setModel: ExtensionAPI["setModel"]; } export function createExtensionApiRuntimePorts( api: Pick< ExtensionAPI, | "sendUserMessage" | "exec" | "getCommands" | "getThinkingLevel" | "setThinkingLevel" | "setModel" >, ): PiExtensionApiRuntimePorts { return { sendUserMessage: (content, options) => api.sendUserMessage(content, options), exec: (command, args, options) => api.exec(command, args, options), getCommands: () => api.getCommands(), getThinkingLevel: () => api.getThinkingLevel(), setThinkingLevel: (level) => api.setThinkingLevel(level), setModel: (model) => api.setModel(model), }; } export function createSettingsManager(cwd: string): PiSettingsManager { return SettingsManager.create(cwd); } export function getExtensionContextModel( ctx: ExtensionContext, ): ExtensionContext["model"] { return ctx.model; } export function getExtensionContextCwd(ctx: ExtensionContext): string { return ctx.cwd; } export function isExtensionContextIdle(ctx: ExtensionContext): boolean { return ctx.isIdle(); } export function hasExtensionContextPendingMessages( ctx: ExtensionContext, ): boolean { return ctx.hasPendingMessages(); } export function compactExtensionContext( ctx: ExtensionContext, callbacks: Parameters[0], ): ReturnType { return ctx.compact(callbacks); }