import { type ExecFileException } from "node:child_process"; import { type ExtractionHarness } from "./harness.js"; /** * Last-resort extraction harness: nothing Claude-shaped is installed on the * dev's machine (no Agent SDK, no `claude` binary, no `codex` binary), but * they do have a usable credential — so init fetches Claude Code itself via * `npm exec` rather than degrading straight to the honest skip. This is the * fourth and final rung of the ladder in extraction.ts. * * Child contract: `npm exec --yes @anthropic-ai/claude-code@` * runs Anthropic's published `claude` binary in the same headless, read-only * shape as the PATH rung (claude-cli-harness.ts) — prompt on argv via `-p`, * Read/Glob/Grep only and each one scoped to the host root by a permission * rule (confine-to-root.ts), `--setting-sources ""`, credentials on the * child's process env, stdout is the agent's final text, exit 0 = success. The * version is pinned exact (never a range) so this rung's behavior can't * drift out from under init on a machine with no local install to pin * instead. * * Availability deliberately never touches npm or the network — it is called * eagerly for every rung on every `vendo init`, and a probe here would mean * every init pays an npm-registry round trip just to build the "AI polish?" * prompt. The ~250MB download surprise is disclosed instead via the * run-time notice below, right before the first real network access. * * Gateway fuel: mirrors claude-cli-harness.ts — when the dev has none of * ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, CLAUDE_CODE_OAUTH_TOKEN, or * ANTHROPIC_BASE_URL (the corporate-gateway/custom-endpoint path) but * VENDO_API_KEY is set, the child runs against Vendo Cloud's model gateway * instead of degrading to unavailable (see gateway-fuel.ts). Own credential * always wins — availability() must label these honestly (not as "Vendo * Cloud key") since composeGatewayFuel itself refuses to overlay onto any of * them; a wrong label here would make the consent prompt lie about what * run() actually does. As on the PATH rung, the base URL that counts is the * developer's own (shell or an explicit programmatic env) — a project's * `.env` cannot supply one, because sync-flow.ts's readEnvFiles drops it * before any env reaches this rung. */ export declare const ENGINE_PACKAGE_NAME = "@anthropic-ai/claude-code"; export declare const ENGINE_PACKAGE_VERSION = "2.1.224"; interface ExecResult { stdout: string; stderr: string; code: number; } type Exec = (args: string[], options: { cwd: string; env: NodeJS.ProcessEnv; onStderrLine?: (line: string) => void; }) => Promise; /** Pure mapping from a completed `execFile` callback into an ExecResult — * pulled out of the real spawn so the four ways `error` shows up (a normal * nonzero exit, a real spawn-layer failure, the RUN_TIMEOUT_MS kill, or the * MAX_BUFFER_BYTES kill) each get direct unit coverage without actually * spawning anything (mirrors resolveCodexExecResult in * codex-cli-harness.ts). The four are easy to conflate — all leave * `error.code` non-numeric — but they need different messages: a killed * 15-minute extraction run is not npm being uninstalled, and a >10MB * narration stream is not a timeout. */ export declare function resolveNpmExecResult(error: ExecFileException | null, stdout: string, stderr: string): ExecResult; /** Line-buffered splitter for a live-streaming descriptor, extracted out of * execNpmEngine so it's directly unit-testable without a real child * process: a line split across two `data` chunks, and — the bug this * fixes — a trailing line with no final newline, which `flush()` still * delivers instead of silently dropping the child's last progress line * when the stream ends without one. */ export declare function createLineSplitter(onLine: (line: string) => void): { push(chunk: string): void; flush(): void; }; export interface NpxEngineHarnessOptions { /** Test seam. */ exec?: Exec; } export declare function npxEngineHarness(options?: NpxEngineHarnessOptions): ExtractionHarness; export {};