/** * RPC Client for programmatic access to the coding agent. * * Spawns the agent in RPC mode and provides a typed API for all operations. */ import type { AgentMessage, ThinkingLevel } from "@earendil-works/pi-agent-core"; import type { ImageContent, Model } from "@earendil-works/pi-ai"; import type { AgentSessionEvent, SessionStats } from "../../core/agent-session.ts"; import type { KeybindingsConfig } from "../../core/keybindings.ts"; import type { Settings } from "../../core/settings-manager.ts"; import type { BashResult } from "../../core/bash-executor.ts"; import type { CompactionResult } from "../../core/compaction/index.ts"; import type { SessionEntry, SessionTreeNode } from "../../core/session-manager.ts"; import type { ChangelogEntry } from "../../utils/changelog.ts"; import type { RpcSessionInfo, RpcSessionState, RpcSkillInfo, RpcSlashCommand } from "./rpc-types.ts"; export interface RpcClientOptions { /** Path to the CLI entry point (default: searches for dist/cli.js) */ cliPath?: string; /** Working directory for the agent */ cwd?: string; /** Environment variables */ env?: Record; /** Provider to use */ provider?: string; /** Model ID to use */ model?: string; /** Additional CLI arguments */ args?: string[]; } export interface ModelInfo { provider: string; id: string; contextWindow: number; reasoning: boolean; } export type RpcEventListener = (event: AgentSessionEvent) => void; export declare class RpcClient { private process; private stopReadingStdout; private eventListeners; private pendingRequests; private requestId; private stderr; private exitError; private options; constructor(options?: RpcClientOptions); /** * Start the RPC agent process. */ start(): Promise; /** * Stop the RPC agent process. */ stop(): Promise; /** * Subscribe to agent events. */ onEvent(listener: RpcEventListener): () => void; /** * Get collected stderr output (useful for debugging). */ getStderr(): string; /** * Send a prompt to the agent. * Returns immediately after sending; use onEvent() to receive streaming events. * Use waitForIdle() to wait for completion. * @param queueWhileCompacting - Buffer the prompt during compaction and send after compaction_end. */ prompt(message: string, images?: ImageContent[], queueWhileCompacting?: boolean): Promise; /** * Queue a steering message to interrupt the agent mid-run. */ steer(message: string, images?: ImageContent[]): Promise; /** * Queue a follow-up message to be processed after the agent finishes. */ followUp(message: string, images?: ImageContent[]): Promise; /** * Abort current operation. */ abort(): Promise; /** * Clear queued steering and follow-up messages, returning their text. */ clearQueue(): Promise<{ steering: string[]; followUp: string[]; }>; /** * Start a new session, optionally with parent tracking. * @param parentSession - Optional parent session path for lineage tracking * @returns Object with `cancelled: true` if an extension cancelled the new session */ newSession(parentSession?: string): Promise<{ cancelled: boolean; }>; /** * Get current session state. */ getState(): Promise; /** * Set model by provider and ID. */ setModel(provider: string, modelId: string): Promise<{ provider: string; id: string; }>; /** * Cycle to next (or previous) model. */ cycleModel(direction?: "forward" | "backward"): Promise<{ model: { provider: string; id: string; }; thinkingLevel: ThinkingLevel; isScoped: boolean; } | null>; /** * Get list of available models. * @param refresh - When true, refresh model catalogs before listing (TUI parity). */ getAvailableModels(refresh?: boolean): Promise; /** * Set thinking level. */ setThinkingLevel(level: ThinkingLevel): Promise; /** * Cycle thinking level. */ cycleThinkingLevel(): Promise<{ level: ThinkingLevel; } | null>; /** * Get list of available thinking levels for the current model. */ getAvailableThinkingLevels(): Promise; /** * Set steering mode. */ setSteeringMode(mode: "all" | "one-at-a-time"): Promise; /** * Set follow-up mode. */ setFollowUpMode(mode: "all" | "one-at-a-time"): Promise; /** * Compact session context. */ compact(customInstructions?: string): Promise; /** * Set auto-compaction enabled/disabled. */ setAutoCompaction(enabled: boolean): Promise; /** * Set auto-handoff enabled/disabled. */ setAutoHandoff(enabled: boolean): Promise; /** * Set auto-handoff threshold in tokens. */ setAutoHandoffThresholdTokens(tokens: number): Promise; /** * Set auto-retry enabled/disabled. */ setAutoRetry(enabled: boolean): Promise; /** * Abort in-progress retry. */ abortRetry(): Promise; /** * Execute a bash command. */ bash(command: string): Promise; /** * Abort running bash command. */ abortBash(): Promise; /** * Get session statistics. */ getSessionStats(): Promise; /** * Export session to HTML. */ exportHtml(outputPath?: string, themeName?: string): Promise<{ path: string; }>; /** * Switch to a different session file. * @returns Object with `cancelled: true` if an extension cancelled the switch */ switchSession(sessionPath: string): Promise<{ cancelled: boolean; }>; /** * Fork from a specific message. * @returns Object with `text` (the message text) and `cancelled` (if extension cancelled) */ fork(entryId: string): Promise<{ text: string; cancelled: boolean; }>; /** * Clone the current active branch into a new session. * @returns Object with `cancelled: true` if an extension cancelled the clone */ clone(): Promise<{ cancelled: boolean; }>; /** * Get messages available for forking. */ getForkMessages(): Promise>; /** * Get session entries in append order, optionally only those after the `since` entry id. */ getEntries(since?: string): Promise<{ entries: SessionEntry[]; leafId: string | null; }>; /** * Get the session entry tree, optionally filtered. */ getTree(filter?: "default" | "no-tools" | "user-only" | "labeled-only" | "all"): Promise<{ tree: SessionTreeNode[]; leafId: string | null; }>; /** * Get text of last assistant message. */ getLastAssistantText(): Promise; /** * Set the session display name. */ setSessionName(name: string): Promise; /** * Navigate the session tree to a target entry, optionally summarizing the * branch being left. Mirrors the TUI tree-selector flow. */ navigateTree(options: { targetId: string; summarize?: boolean; customInstructions?: string; replaceInstructions?: boolean; label?: string; }): Promise<{ editorText?: string; cancelled: boolean; aborted?: boolean; summaryEntry?: unknown | null; }>; /** * List sessions. scope "current" = sessions in the active cwd; "all" = across all projects. */ listSessions(scope?: "current" | "all"): Promise; /** * Rename a session (by path). Does not switch the active runtime. */ renameSession(path: string, name: string): Promise; /** * Delete a session file (trash first, unlink fallback). Active session is rejected. * @returns The method used: "trash" or "unlink". */ deleteSession(path: string): Promise<{ method: "trash" | "unlink"; }>; /** * Set session-only (ephemeral) scoped models — resolved to concrete model ids, * not persisted to settings. Clears scope with an empty array. */ setSessionModels(options: { enabled?: string[]; reorder?: string[]; }): Promise<{ enabled: string[]; models: ModelInfo[]; }>; /** * Get all messages in the session. */ getMessages(): Promise; /** * Get available commands (extension commands, prompt templates, builtins). */ getCommands(): Promise; /** * Get the resolved skill catalog (per-skill enabled state) plus the raw * global+project merged settings.skills patterns for round-trip toggling. */ getSkills(): Promise<{ skills: RpcSkillInfo[]; patterns: string[]; }>; /** * Get settings for a scope ("global" | "project" | "effective", default "effective"). */ getSettings(scope?: "global" | "project" | "effective"): Promise<{ scope: string; settings: Settings; }>; /** * Bulk-update settings and persist. */ setSettings(values: Partial, scope?: "global" | "project"): Promise; /** * Reset settings to bundled factory defaults (backup preserved). */ factoryResetSettings(): Promise; /** * List providers and the login methods they support. */ getAuthProviders(): Promise; }>>; /** * Login to a provider. API-key flows emit `extension_ui_request: input` with * `inputKind: "secret"`; OAuth flows open a browser and emit notify events. */ login(providerId: string, authType: "oauth" | "api_key"): Promise<{ providerId: string; authType: "oauth" | "api_key"; message: string; }>; /** * Log out of a provider, removing stored credentials. */ logout(providerId: string): Promise; /** * Get providers with configured auth (stored credential or environment). */ getAuthState(): Promise>; /** * Get enabled model patterns (Ctrl+P cycling scope) and available models. */ getScopedModels(): Promise<{ enabled: string[]; models: Model[]; }>; /** * Set enabled model patterns and/or reorder them (Ctrl+P cycling order). */ setScopedModels(options?: { enabled?: string[]; reorder?: string[]; }): Promise; /** * Import and resume a session from a JSONL file (replaces current session). */ importJsonl(path: string): Promise; /** * Run the git helper (worktrees/checkpoints/commits/push). Same behavior as * the `prompt` command: success is reported on preflight, then the normal * agent/message event stream follows. */ git(command: string): Promise; /** * Reload keybindings, extensions, skills, prompts, themes, and context files. */ reload(): Promise; /** * Set or clear a label on a session entry (undefined/empty clears). */ setEntryLabel(entryId: string, label?: string): Promise; /** * Get the current project trust decision and status. */ getTrust(): Promise<{ cwd: string; savedDecision: { path: string; decision: boolean; } | null; projectTrusted: boolean; trustRequired: boolean; }>; /** * Save a project trust decision. Decision takes full effect after restart. */ setTrust(decision: boolean | null): Promise<{ decision: boolean | null; restartRequired: boolean; }>; /** * Get the effective keybinding map. */ getHotkeys(): Promise; /** * Get available themes (built-in + custom) and the current theme setting. */ getAvailableThemes(): Promise<{ themes: Array<{ name: string; path?: string; }>; current: string | undefined; }>; /** * Get the current version and parsed changelog entries. */ getVersionInfo(): Promise<{ version: string; changelog: ChangelogEntry[]; }>; /** * Share the current session as a secret GitHub gist (requires `gh` CLI). */ shareGist(themeName?: string): Promise<{ url: string; gistUrl: string; }>; /** * Wait for agent to become idle (no streaming). * Resolves when agent_settled event is received. */ waitForIdle(timeout?: number): Promise; /** * Collect events until agent becomes idle. */ collectEvents(timeout?: number): Promise; /** * Send prompt and wait for completion, returning all events. */ promptAndWait(message: string, images?: ImageContent[], timeout?: number): Promise; private handleLine; private createProcessExitError; private rejectPendingRequests; private send; private getData; }