/** * adapters/iterm/core.ts — Low-level iTerm2 AppleScript primitives. * * Foundation of all iTerm2 communication. Wraps `osascript` and `spawnSync` * with zero transport-specific imports. */ /** * Environment for any child that can touch AppKit. iTerm exports * __CFBundleIdentifier into its shells; a child that inherits it registers with * LaunchServices AS iTerm2 (an "impostor") for as long as it runs. */ export declare function cleanChildEnv(env?: NodeJS.ProcessEnv): NodeJS.ProcessEnv; export declare function runAppleScript(script: string, timeoutMs?: number): string | null; export declare const REAL_ITERM_SUFFIX = "/iTerm.app/Contents/MacOS/iTerm2"; /** * Parser half of itermPid(), split out for testing. Input is `ps -Ao pid=,comm=`; * only a process whose executable is iTerm's own is accepted, so a bundle-id * impostor (osascript/helper that inherited __CFBundleIdentifier) is never picked. */ export declare function parseItermPid(psOutput: string): number | null; /** Pid of the real iTerm (cached, re-resolved once that pid is gone); null when it is not running. */ export declare function itermPid(): number | null; /** The JXA program run for a body: `app` is bound to the real iTerm process, the body returns a string. */ export declare function buildItermJxa(pid: number, body: string): string; /** * Run JXA against iTerm, addressed by PROCESS ID — never by name, bundle id or * path, all of which LaunchServices resolves through the bundle-id registry * that an impostor process poisons (-600 / -1708). The body sees `app` and * must `return` a string. Same failure value as runAppleScript: null. */ export declare function runItermJxa(body: string, timeoutMs?: number): string | null; /** * Plain-object indirection so tests can replace the osascript call without * mocking node:child_process — a builtin's named export is a fixed snapshot * taken once at module load, so reassigning it post-load (the usual mock * technique) silently does nothing. */ export declare const _internal: { runAppleScript: typeof runAppleScript; runItermJxa: typeof runItermJxa; }; export declare function stripItermPrefix(id: string | undefined): string | undefined; /** * JXA body that finds the session with this id and runs `body` on it. * `body` sees `app`, `aWindow`, `aTab`, `aSession` and must `return` a string; * `fallback` is a JS expression returned when no session matches. */ export declare function withSessionJxa(sessionId: string, body: string, fallback?: string): string; export declare function sendKeystrokeToSession(sessionId: string, asciiCode: number): boolean; export declare function sendEscapeSequenceToSession(sessionId: string, dirChar: string): boolean; export declare function typeIntoSession(sessionId: string, text: string): boolean; export declare function pasteTextIntoSession(sessionId: string, text: string): boolean; export declare function findClaudeSession(): string | null; export declare function isClaudeRunningInSession(sessionId: string): boolean; export declare function isItermRunning(): boolean; export declare function isItermSessionAlive(sessionId: string): boolean; export declare function isScreenLocked(): boolean; /** * Write a line to a tty device. * * This used to build `sh -c "printf '%s\n' '' > "`. Two things * were wrong with that. The path was interpolated unquoted, so everything after * the `/dev/ttys` prefix the check required was shell syntax rather than a * filename. And the text — arbitrary inbound WhatsApp/Telegram/Todoist content — * was held inside single quotes by one hand-rolled escape that had to stay * exactly right forever. Neither risk is worth running a shell to copy bytes * into a file descriptor, so it no longer runs one. */ export declare function writeToTty(ttyPath: string, text: string): boolean; export interface SessionSnapshot { id: string; name: string; profileName: string; tabTitle: string | null; tty: string; atPrompt: boolean; paiName: string | null; /** * Durable, transport-stable id. For tmux this is the pane's @aibroker_id * (survives server restarts, unlike the volatile %N pane id). For iTerm it is * undefined — the GUID in `id` is already stable. Persistent-name lookups key * on this when present so a tmux session keeps its name across %N churn. */ aibrokerId?: string | null; /** Working directory, when the host reports it (tmux). Absent on iTerm. */ cwd?: string | null; /** Host this row came from; absent means iTerm. */ transport?: "iterm" | "tmux"; /** * Whether a Claude is actually running on this terminal, read from the * process table. Undefined when that could not be read — a caller must then * fall back to guessing from the title rather than treat "unknown" as "no". */ isClaude?: boolean; /** * True for a `pai worker follow` pane (iTerm variable `user.paiWorkerPane` * set). Kept in the snapshot for internal lookups; list surfaces drop it. */ workerPane?: boolean; } export declare function wasLastSnapshotReliable(): boolean; export interface ItermBundleIdImpostor { pid: number; executablePath: string; } /** * Parser half of findItermBundleIdImpostors(), split out for testing without * a subprocess. `lsappinfo list` entries look like: * 125) "iTerm2" ASN:0x0-0x412ec2ab: (in front) * bundleID="com.googlecode.iterm2" * executable path="/Applications/iTerm.app/Contents/MacOS/iTerm2" * pid = 66665 ... * A child launched with iTerm's exported __CFBundleIdentifier registers under * the same bundle id from a different executable — that mismatch is the tell. */ export declare function parseLsappinfoImpostors(text: string): ItermBundleIdImpostor[]; /** * Processes registered with LaunchServices under iTerm2's bundle id but NOT * running iTerm's own executable — e.g. an osascript/helper child that * inherited iTerm's __CFBundleIdentifier env var. While registered, anything * addressing iTerm by name or bundle id is routed to the impostor, which answers * with -600/-1708 (iTerm itself is addressed by pid, so it is immune). Diagnostic only: never kills * anything, never throws — on any error this is "found nothing" to a caller * that already treats [] as the safe default. */ export declare function findItermBundleIdImpostors(): ItermBundleIdImpostor[]; /** * Enumerate all iTerm2 sessions, reusing an answer up to SNAPSHOT_TTL_MS old. * * A failed enumeration (osascript error/timeout) is NEVER memoized: it used to * be cached the same as a real `[]`, so one bad poll made every session * "not found" for the full TTL window — observed live, `send_to_session` * reported an empty session list for a target that a listing seconds later * (past the TTL) showed as one of 14 live sessions. A failure now leaves the * previous good snapshot in place (or null, if there was none), so the next * call retries iTerm instead of replaying the failure. */ export declare function snapshotAllSessions(opts?: { fresh?: boolean; }): SessionSnapshot[]; /** Force the next snapshotAllSessions() to re-enumerate rather than reuse. */ export declare function invalidateSnapshotCache(): void; /** * Clear the user.paiName variable from all live iTerm2 sessions. * Used for recovery when session names are corrupt. * Does a single AppleScript pass over all sessions. */ export declare function clearAllPaiNames(): number; //# sourceMappingURL=core.d.ts.map