/** * BaseAgentAdapter — abstract base class for agent adapters. * * Provides shared utilities and hook points with sensible defaults. * All built-in adapters extend this class. * * @see 05-adapter-system.md §4 */ import type { AgentName, CostRecord, RetryPolicy, AgentCapabilities, ModelCapabilities, AgentConfig, AgentConfigSchema, AuthState, AuthSetupGuidance, Session, InstalledPlugin, PluginInstallOptions, PluginSearchOptions, PluginListing, SpawnArgs, ParseContext, SubprocessAdapter, RunOptions, AgentEvent, DetectInstallationResult, InstallResult, AdapterInstallOptions, AdapterUpdateOptions, Spawner, InstallMethod } from '@a5c-ai/comm-adapter'; import { StreamAssembler } from '@a5c-ai/comm-adapter'; export { defaultSpawner } from './base-adapter-helpers.js'; export declare function registerAdapterFactory(name: string, factory: () => SubprocessAdapter): void; export declare function getAdapterFactory(name: string): (() => SubprocessAdapter) | undefined; export declare function listRegisteredAdapters(): string[]; export declare abstract class BaseAgentAdapter implements SubprocessAdapter { readonly adapterType: "subprocess"; abstract readonly agent: AgentName; abstract readonly displayName: string; abstract readonly cliCommand: string; abstract readonly minVersion?: string; abstract readonly capabilities: AgentCapabilities; abstract readonly models: ModelCapabilities[]; abstract readonly defaultModelId?: string; abstract readonly configSchema: AgentConfigSchema; abstract buildSpawnArgs(options: RunOptions): SpawnArgs; abstract parseEvent(line: string, context: ParseContext): AgentEvent | AgentEvent[] | null; abstract detectAuth(): Promise; abstract getAuthGuidance(): AuthSetupGuidance; abstract sessionDir(cwd?: string): string; abstract parseSessionFile(filePath: string): Promise; abstract listSessionFiles(cwd?: string): Promise; abstract readConfig(cwd?: string): Promise; abstract writeConfig(config: Partial, cwd?: string): Promise; listPlugins?(): Promise; installPlugin?(pluginId: string, options?: PluginInstallOptions): Promise; uninstallPlugin?(pluginId: string): Promise; searchPlugins?(query: string, options?: PluginSearchOptions): Promise; protected readonly streamAssembler: StreamAssembler; /** Subprocess runner used by install/update/detect. Swap for tests. */ protected _spawner: Spawner; /** Replaces the internal Spawner (used by tests and CLI DI). */ setSpawner(spawner: Spawner): void; protected normalizePrompt(prompt: string | string[]): string; protected stripAnsi(text: string): string; protected parsePlaintextEvent(line: string, context: ParseContext): AgentEvent | null; protected buildPromptTransport(options: RunOptions): { prompt: string; stdin?: string; }; /** * Locates the harness binary and queries its `--version`. Default * implementation uses `which`/`where` + ` --version`. */ detectInstallation(): Promise; /** * Parses a `--version` output line. Default: first semver-like token. * Override to accommodate bespoke version formats. */ protected parseVersionOutput(raw: string): string | undefined; protected resolveWindowsBinaryPath(binPath: string): string; protected resolveVersionProbeCommand(binPath: string): { command: string; args: string[]; }; /** * Picks an install method compatible with the current platform, runs it, * then re-detects. Honors `force` and `dryRun`. */ private _installContext; install(opts?: AdapterInstallOptions): Promise; /** Runs the update/upgrade variant of the install command. */ update(opts?: AdapterUpdateOptions): Promise; /** * Picks the first InstallMethod compatible with the current platform, * preferring non-manual methods. */ protected pickInstallMethod(): InstallMethod | undefined; /** * Replace `` tail with `@` for npm-typed methods. */ protected applyVersionToCommand(method: InstallMethod, version?: string): string; /** * Derives an update command from an install method. */ protected deriveUpdateCommand(method: InstallMethod): string | null; /** * Attempts to parse a line as JSON. Returns the parsed value on success, * or null if the line is not valid JSON. Does not throw. */ protected parseJsonLine(line: string): unknown | null; /** * Normalizes a raw cost/usage object from agent output into the * standard CostRecord type. */ protected assembleCostRecord(raw: unknown): CostRecord | null; /** * Detects the installed CLI version. Returns null in the base implementation. * Subclasses should override to run the agent's CLI with a version flag. */ protected detectVersionFromCli(): Promise; /** * Builds the environment variable record for the subprocess from RunOptions. */ protected buildEnvFromOptions(options: RunOptions): Record; /** * Resolves the session ID to use for this run. */ protected resolveSessionId(options: RunOptions): string | undefined; /** * Called when the agent subprocess fails to spawn. */ onSpawnError(error: Error): AgentEvent; /** * Called when the inactivity timeout fires. */ onTimeout(): AgentEvent; /** * Called when the agent subprocess exits. */ onProcessExit(exitCode: number, signal: string | null): AgentEvent[]; /** * Determines whether a failed run should be retried. */ shouldRetry(event: AgentEvent, attempt: number, policy: RetryPolicy): boolean; /** * Default hook installation: registers in .adapters/hooks.json only. * Override in subclasses to also write native harness config (e.g. * ~/.claude/settings.json) so the hook fires without adapters present. */ installHook(hookType: string, command: string, opts?: { scope?: 'global' | 'project'; id?: string; }): Promise; /** Register a hook in the unified .adapters/hooks.json store. */ protected registerHookInConfig(hookType: string, command: string, opts?: { scope?: 'global' | 'project'; id?: string; }): Promise; /** * Write the hook into the harness's native config. Default: append * `{ command }` to `hooks[hookType]` in configFilePaths[0] if it is * a .json file. Subclasses override to use harness-specific schema. * Best-effort: failures are swallowed so SDK registration still succeeds. */ protected writeNativeHook(hookType: string, command: string): Promise; uninstallHook(id: string, opts?: { scope?: 'global' | 'project'; }): Promise; /** * Append `{ command }` to `hooks[hookType]` in the given JSON file, * preserving any existing hooks and creating the parent directory if * needed. Used by adapters that expose a simple JSON-based native * hook config (codex, gemini, copilot, cursor, opencode, pi, omp, * openclaw, hermes). */ protected appendJsonHook(settingsPath: string, hookType: string, entry: Record): Promise; }