// caveman:native-pi — GENERATED by `caveman enable pi`. process.env.CAVEMAN_PI_HOOK_CMD ??= "[\"{{ .chezmoi.homeDir }}/.npm-global/bin/caveman\"]"; // ../pi-extension/src/index.ts import { readFileSync as readFileSync2 } from "node:fs"; import { homedir as homedir3 } from "node:os"; import { join as join4 } from "node:path"; import { Type } from "typebox"; // ../pi-extension/src/lifecycle.ts import { execFile } from "node:child_process"; import { createHash } from "node:crypto"; import { homedir } from "node:os"; import { join as join2 } from "node:path"; // ../pi-extension/src/portable-command.ts import { existsSync, readFileSync, statSync } from "node:fs"; import { dirname, extname, isAbsolute, join, resolve } from "node:path"; function parseWindowsNodeShim(source) { for (const line of source.split(/\r?\n/)) { if (!/(?:\bnode(?:\.exe)?\b|_prog)/i.test(line) || !/%\*/.test(line)) continue; const match = line.match(/"%(?:dp0%|~dp0)\\([^"\r\n]+\.(?:cjs|mjs|js))"\s+%\*/i) ?? line.match(/"([A-Za-z]:[\\/][^"\r\n]+\.(?:cjs|mjs|js))"\s+%\*/i); if (match) return match[1]; } return null; } function envValue(env, name) { const key = Object.keys(env).find((candidate) => candidate.toLowerCase() === name.toLowerCase()); return key === void 0 ? void 0 : env[key]; } function resolveWindowsCommand(command, env) { const pathExt = envValue(env, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD"; const names = extname(command) ? [command] : pathExt.split(";").map((extension) => `${command}${extension.startsWith(".") ? extension : `.${extension}`}`); if (isAbsolute(command) || /[\\/]/.test(command)) { for (const name of names) if (existsSync(name)) return name; return existsSync(command) ? command : void 0; } for (const directory of (envValue(env, "PATH") ?? "").split(";")) { if (!directory) continue; for (const name of names) { const candidate = join(directory, name); if (existsSync(candidate)) return candidate; } } return void 0; } function portableInvocation(command, args, platform = process.platform, env = process.env) { if (platform !== "win32") return { command, args: [...args] }; const executable = resolveWindowsCommand(command, env) ?? command; if (!/\.(?:cmd|bat)$/i.test(executable)) return { command: executable, args: [...args] }; const stat = statSync(executable); if (!stat.isFile() || stat.size > 256 * 1024) { throw new Error(`cannot safely launch Windows command shim: ${executable}`); } const shimScript = parseWindowsNodeShim(readFileSync(executable, "utf8")); if (!shimScript) { throw new Error(`cannot safely launch non-Node Windows command shim: ${executable}; install a native .exe`); } const script = /^[A-Za-z]:[\\/]/.test(shimScript) ? shimScript : resolve(dirname(executable), ...shimScript.split(/[\\/]+/)); if (!statSync(script).isFile()) { throw new Error(`Windows command shim target is missing: ${script}`); } return { command: process.execPath, args: [script, ...args] }; } // ../pi-extension/src/protocol.ts var MAX_CONTEXT_BYTES = 64 * 1024; var MAX_MESSAGE_BYTES = 4 * 1024; var MAX_OUTPUT_REPLACEMENT_BYTES = 2 * 1024 * 1024; var MAX_RECOVERY_REF_BYTES = 1024; var MAX_DECISION_ID_BYTES = 256; var MAX_TOOL_OUTPUT_BYTES = 2 * 1024 * 1024; function fits(value, max) { return typeof value === "string" && Buffer.byteLength(value, "utf8") <= max; } function sanitizeHookResponse(raw) { if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {}; const value = raw; const out = {}; if (fits(value.context, MAX_CONTEXT_BYTES)) out.context = value.context; if (fits(value.message, MAX_MESSAGE_BYTES)) out.message = value.message; if (fits(value.output_replacement, MAX_OUTPUT_REPLACEMENT_BYTES)) out.output_replacement = value.output_replacement; if (fits(value.recovery_ref, MAX_RECOVERY_REF_BYTES)) out.recovery_ref = value.recovery_ref; if (fits(value.decision_id, MAX_DECISION_ID_BYTES)) out.decision_id = value.decision_id; if (typeof value.action === "string") out.action = value.action; const hso = value.hookSpecificOutput; if (hso && typeof hso === "object" && !Array.isArray(hso)) { const nested = hso; const cleaned = {}; if (typeof nested.hookEventName === "string") cleaned.hookEventName = nested.hookEventName; if (fits(nested.additionalContext, MAX_CONTEXT_BYTES)) cleaned.additionalContext = nested.additionalContext; if (fits(nested.updatedToolOutput, MAX_OUTPUT_REPLACEMENT_BYTES)) cleaned.updatedToolOutput = nested.updatedToolOutput; out.hookSpecificOutput = cleaned; } return out; } function additionalContextOf(response) { const context = response?.hookSpecificOutput?.additionalContext ?? response?.context; return context ? context : void 0; } function outputReplacementOf(response) { const replacement = response?.hookSpecificOutput?.updatedToolOutput ?? response?.output_replacement; return replacement ? replacement : void 0; } var ROUTES_BY_API = { "anthropic-messages": "/w/pi", "openai-completions": "/w/pi/openai/v1", "openai-responses": "/w/pi/openai/v1", "google-generative-ai": "/w/pi/v1beta" }; function routeForApi(gateway, api) { const path = api ? ROUTES_BY_API[api] : void 0; return path ? joinUrl(gateway, path) : void 0; } function joinUrl(base, path) { return `${base.replace(/\/+$/, "")}${path}`; } function isLoopbackUrl(url) { try { const host = new URL(url).hostname; return host === "127.0.0.1" || host === "::1" || host === "[::1]" || host === "localhost"; } catch { return false; } } // ../pi-extension/src/lifecycle.ts var HOOK_TIMEOUT_MS = 2e3; var SESSION_START_TIMEOUT_MS = 6e3; var HOOK_MAX_BUFFER = 2 * 1024 * 1024; function resolveHookInvocations(env = process.env) { const localBin = join2(env.CAVEMAN_HOME || join2(homedir(), ".caveman"), "bin", "caveman"); const candidates = [ { command: "caveman", args: [] }, { command: "cave", args: [] }, { command: localBin, args: [] } ]; const stamped = env.CAVEMAN_PI_HOOK_CMD; if (stamped) { try { const parsed = JSON.parse(stamped); if (Array.isArray(parsed) && parsed.length > 0 && parsed.every((part) => typeof part === "string" && part.length > 0)) { candidates.unshift({ command: parsed[0], args: parsed.slice(1) }); } } catch { } } return candidates; } var TRY_NEXT = "__caveman_try_next__"; var HookBridge = class { invocations; constructor(invocations = resolveHookInvocations()) { this.invocations = invocations; } // call runs one native-hook event. Fail-open by contract: any spawn error, // timeout, or unparseable output resolves to undefined. async call(event, payload) { const input = JSON.stringify({ event_name: event, surface: "cli", ...payload }); for (const invocation of this.invocations) { const raw = await this.invoke(invocation, event, input); if (raw === TRY_NEXT) continue; if (raw === void 0 || !raw.trim()) return void 0; try { return sanitizeHookResponse(JSON.parse(raw)); } catch { return void 0; } } return void 0; } invoke(invocation, event, input) { return new Promise((resolve2) => { let portable; try { portable = portableInvocation(invocation.command, [...invocation.args, "native-hook", "pi", event]); } catch { resolve2(TRY_NEXT); return; } const child = execFile( portable.command, portable.args, { timeout: event === "SessionStart" ? SESSION_START_TIMEOUT_MS : HOOK_TIMEOUT_MS, maxBuffer: HOOK_MAX_BUFFER, encoding: "utf8" }, (error, stdout) => { const timedOut = !!error && error.killed === true; if (error && stdout === "") return resolve2(timedOut ? void 0 : TRY_NEXT); resolve2(stdout); } ); child.stdin?.on("error", () => { }); child.stdin?.end(input); }); } }; function promptDigest(prompt) { return { bytes: Buffer.byteLength(prompt, "utf8"), sha256: `sha256:${createHash("sha256").update(prompt, "utf8").digest("hex")}` }; } function taskType(text) { const lower = text.toLowerCase(); const has = (...terms) => terms.some((term) => lower.includes(term)); if (has("migration", "migrate", "schema change", "backfill", "rollback")) return "migration"; if (has("bug", "fix", "broken", "regression", "crash", "error", "incorrect")) return "bugfix"; if (has("investigate", "diagnose", "root cause", "why does", "trace")) return "investigation"; if (has("refactor", "restructure", "reorganize", "cleanup")) return "refactor"; if (has("review", "audit", "critique", "assess")) return "review"; if (has("verify", "verification", "prove", "validate", "check that")) return "verification"; if (has("build", "implement", "add", "create", "ship", "feature")) return "feature"; return "general"; } var TASK_STOPWORDS = /* @__PURE__ */ new Set(["about", "after", "agent", "before", "build", "change", "code", "create", "from", "have", "help", "implement", "into", "make", "please", "project", "repository", "should", "spec", "task", "that", "then", "there", "these", "they", "this", "through", "user", "want", "what", "when", "where", "which", "with", "would", "your"]); function taskTerms(text) { const out = []; const seen = /* @__PURE__ */ new Set(); for (const raw of text.match(/[A-Za-z][A-Za-z0-9_./-]{2,63}/g) ?? []) { const term = raw.toLowerCase().replace(/^[-./]+|[-./]+$/g, ""); if (!term || term.includes("..") || TASK_STOPWORDS.has(term) || seen.has(term)) continue; if (/^(?:sk|pk|rk|ghp|github_pat|xox[baprs]|akia)[-_]/i.test(term) || /^[a-z0-9_-]{40,}$/i.test(term)) continue; seen.add(term); out.push(term); if (out.length === 12) break; } return out; } function taskContinuation(text) { const prompt = text.trim().toLowerCase(); if (!prompt || prompt.length > 160 || prompt.split(/\s+/).length > 14) return false; return /^(?:please\s+)?(?:continue|go ahead|keep going|proceed|do (?:it|that)|fix (?:it|that)|retry|try again|explain (?:it|that)|what do you mean|yes|yep|yeah|why\??|how\??)[.!?\s]*$/.test(prompt); } // ../pi-extension/src/provider.ts var ProviderRouter = class { pi; notify; gateway; gateOpen = false; overridden = /* @__PURE__ */ new Set(); applying = false; warnedModels = /* @__PURE__ */ new Set(); constructor(pi, notify) { this.pi = pi; this.notify = notify; } // openGate is called once per session after the recovery gate held. Refuses // non-loopback gateways: managed routing needs auth proof v1 does not carry. async openGate(gateway, ctx) { if (!isLoopbackUrl(gateway)) { this.notify("Caveman: direct mode, no compression this session (gateway is not loopback)", "warning"); return; } this.gateway = gateway; this.gateOpen = true; await this.apply(ctx.model, ctx); } closeGate() { this.gateOpen = false; this.clearOverrides(); } routing() { return this.gateOpen && this.overridden.size > 0; } // apply routes one model's provider, or restores direct mode when the model // has no verified route. Called from the gate and from model_select; the // applying flag swallows the model_select echo of our own setModel call. async apply(model, ctx) { if (!this.gateOpen || this.applying || !this.gateway) return; if (!model) return; const route = routeForApi(this.gateway, model.api); let oauth = true; try { oauth = ctx.modelRegistry.isUsingOAuth(model); } catch { } if (!route || oauth) { this.clearOverrides(); const key = `${model.provider}/${model.id}`; if (!this.warnedModels.has(key)) { this.warnedModels.add(key); const reason = oauth ? "OAuth/subscription credentials are not routed" : `unsupported API "${model.api}"`; this.notify(`Caveman: pass-through for ${key} (${reason}); no compression`, "warning"); } return; } this.applying = true; try { for (const provider of this.overridden) { if (provider !== model.provider) { this.pi.unregisterProvider(provider); this.overridden.delete(provider); } } this.pi.registerProvider(model.provider, { baseUrl: route }); this.overridden.add(model.provider); const refreshed = ctx.modelRegistry.find(model.provider, model.id); if (!refreshed || !await this.pi.setModel(refreshed)) { this.clearOverrides(); this.notify("Caveman: direct mode, no compression this session (model re-resolution failed)", "warning"); return; } } catch { this.clearOverrides(); this.notify("Caveman: direct mode, no compression this session (provider override failed)", "warning"); } finally { this.applying = false; } } clearOverrides() { for (const provider of this.overridden) { try { this.pi.unregisterProvider(provider); } catch { } } this.overridden.clear(); } }; // ../pi-extension/src/recovery.ts import { execFile as execFile2, spawn } from "node:child_process"; import { existsSync as existsSync2 } from "node:fs"; import { homedir as homedir2 } from "node:os"; import { delimiter, join as join3 } from "node:path"; var PROBE_TIMEOUT_MS = 2e3; var CALL_TIMEOUT_MS = 3e4; var INIT_TIMEOUT_MS = 2e3; function resolveMcpBinary(env = process.env) { const explicit = env.CAVEMAN_MCP_BIN?.trim(); if (explicit) return explicit; const name = process.platform === "win32" ? "caveman-mcp.exe" : "caveman-mcp"; for (const dir of (env.PATH ?? "").split(delimiter)) { if (dir && existsSync2(join3(dir, name))) return join3(dir, name); } const local = join3(env.CAVEMAN_HOME || join3(homedir2(), ".caveman"), "bin", name); return existsSync2(local) ? local : void 0; } var RecoveryClient = class { binary; child; initialized = false; probed; ensuring; nextId = 1; pending = /* @__PURE__ */ new Map(); buffer = ""; disposed = false; constructor(binary = resolveMcpBinary()) { this.binary = binary; } // ensure probes the binary once and brings up an initialized child. Returns // false (never throws) when recovery cannot hold — the caller passes through. async ensure() { if (this.disposed || !this.binary) return false; if (this.child && this.initialized) return true; this.ensuring ??= this.bringUp().finally(() => { this.ensuring = void 0; }); return this.ensuring; } async bringUp() { if (this.probed === void 0) this.probed = await this.probe(); if (!this.probed || this.disposed) return false; if (this.child && this.initialized) return true; return this.start(); } ready() { return Boolean(this.child && this.initialized && !this.disposed); } async retrieve(handle, query, signal) { if (!await this.ensure()) { return { text: JSON.stringify({ error: "cave_recovery_unavailable", message: "caveman-mcp is not available this session" }), isError: true }; } try { const result = await this.call("tools/call", { name: "caveman_retrieve", arguments: { recovery_handle: handle, ...query ? { query } : {} } }, signal); const value = result; const text = (value.content ?? []).map((block) => block.type === "text" && typeof block.text === "string" ? block.text : "").join(""); return { text, isError: Boolean(value.isError) }; } catch (error) { return { text: JSON.stringify({ error: "cave_recovery_transport", message: error.message }), isError: true }; } } dispose() { this.disposed = true; const child = this.child; this.child = void 0; this.initialized = false; for (const [, entry] of this.pending) { clearTimeout(entry.timer); entry.reject(new Error("recovery client disposed")); } this.pending.clear(); this.stop(child); void this.ensuring?.then(() => { const late = this.child; this.child = void 0; this.stop(late); }); } // resolveMcpBinary appends .exe on win32, but CAVEMAN_MCP_BIN is an operator // override that can name anything — including a .cmd shim, which execFile // and spawn both refuse with EFTYPE. Route through the same resolver the hook // bridge uses so the override is as spawnable as the default. Fail-closed: // callers treat a throw as "recovery cannot hold" and pass through. invocation(args) { try { return portableInvocation(this.binary, args); } catch { return void 0; } } probe() { return new Promise((resolve2) => { const portable = this.invocation(["version", "--json"]); if (!portable) return resolve2(false); execFile2(portable.command, portable.args, { timeout: PROBE_TIMEOUT_MS, encoding: "utf8" }, (error, stdout) => { if (error) return resolve2(false); try { const parsed = JSON.parse(stdout); resolve2(Array.isArray(parsed?.capabilities) && parsed.capabilities.includes("mcp_recovery")); } catch { resolve2(false); } }); }); } async start() { let child; try { const portable = this.invocation([]); if (!portable) return false; child = spawn(portable.command, portable.args, { stdio: ["pipe", "pipe", "ignore"] }); } catch { return false; } this.child = child; this.initialized = false; this.buffer = ""; child.on("error", () => this.onChildGone(child)); child.on("exit", () => this.onChildGone(child)); child.stdin?.on("error", () => this.onChildGone(child)); child.stdout?.setEncoding("utf8"); child.stdout?.on("data", (chunk) => this.onData(chunk)); try { await this.call("initialize", { protocolVersion: "2024-11-05", capabilities: {}, clientInfo: { name: "caveman-pi-extension", version: "0.1.0" } }, void 0, INIT_TIMEOUT_MS); this.notify("notifications/initialized"); if (this.disposed) { this.onChildGone(child); this.stop(child); return false; } this.initialized = true; return true; } catch { this.onChildGone(child); this.stop(child); return false; } } stop(child) { if (!child) return; try { child.stdin?.end(); } catch { } const term = setTimeout(() => { try { child.kill("SIGTERM"); } catch { } }, 500); const kill = setTimeout(() => { try { child.kill("SIGKILL"); } catch { } }, 2e3); child.once("exit", () => { clearTimeout(term); clearTimeout(kill); }); } onChildGone(child) { if (this.child !== child) return; this.child = void 0; this.initialized = false; for (const [, entry] of this.pending) { clearTimeout(entry.timer); entry.reject(new Error("caveman-mcp exited")); } this.pending.clear(); } onData(chunk) { this.buffer += chunk; let newline; while ((newline = this.buffer.indexOf("\n")) !== -1) { const line = this.buffer.slice(0, newline).trim(); this.buffer = this.buffer.slice(newline + 1); if (!line) continue; let message; try { message = JSON.parse(line); } catch { continue; } if (typeof message.id !== "number") continue; const entry = this.pending.get(message.id); if (!entry) continue; this.pending.delete(message.id); clearTimeout(entry.timer); if (message.error) entry.reject(new Error(message.error.message || "caveman-mcp error")); else entry.resolve(message.result); } } call(method, params, signal, timeoutMs = CALL_TIMEOUT_MS) { const child = this.child; if (!child?.stdin?.writable) return Promise.reject(new Error("caveman-mcp not running")); if (signal?.aborted) return Promise.reject(new Error("retrieve cancelled")); const id = this.nextId++; return new Promise((resolve2, reject) => { const timer = setTimeout(() => { this.pending.delete(id); reject(new Error(`caveman-mcp ${method} timed out`)); }, timeoutMs); timer.unref?.(); const onAbort = () => { this.pending.delete(id); clearTimeout(timer); reject(new Error("retrieve cancelled")); }; signal?.addEventListener("abort", onAbort, { once: true }); this.pending.set(id, { resolve: (value) => { signal?.removeEventListener("abort", onAbort); resolve2(value); }, reject: (error) => { signal?.removeEventListener("abort", onAbort); reject(error); }, timer }); child.stdin.write(JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n", (error) => { if (error) { this.pending.delete(id); clearTimeout(timer); signal?.removeEventListener("abort", onAbort); reject(error); } }); }); } notify(method) { try { this.child?.stdin?.write(JSON.stringify({ jsonrpc: "2.0", method }) + "\n"); } catch { } } }; // ../pi-extension/src/tool-output.ts async function shrinkToolResult(bridge, sessionId, event) { const text = event.content.map((block) => block.type === "text" && typeof block.text === "string" ? block.text : "").join(""); if (!text) return void 0; if (Buffer.byteLength(text, "utf8") > MAX_TOOL_OUTPUT_BYTES) return void 0; const response = await bridge.call(event.isError ? "PostToolUseFailure" : "PostToolUse", { session_id: sessionId, tool_name: event.toolName, tool_input: event.input, tool_output: text }); const replacement = outputReplacementOf(response); if (!replacement) return void 0; return { content: [{ type: "text", text: replacement }, ...event.content.filter((block) => block.type !== "text")] }; } // ../pi-extension/src/index.ts var HEALTH_TIMEOUT_MS = 750; var RECOVERY_TOOL = "caveman_retrieve"; function cavemanHome() { return process.env.CAVEMAN_HOME || join4(homedir3(), ".caveman"); } function gatewayUrl() { const env = process.env.CAVE_GATEWAY_URL?.trim(); if (env) return env; try { const config = JSON.parse(readFileSync2(join4(homedir3(), ".caveman-cloud", "config.json"), "utf8")); if (typeof config.gatewayUrl === "string" && config.gatewayUrl) return config.gatewayUrl; } catch { } return "http://127.0.0.1:8787"; } function runStateRecoveryViaMcp(gateway) { let port; try { const url = new URL(gateway); port = url.port || (url.protocol === "https:" ? "443" : "80"); } catch { return void 0; } try { const state = JSON.parse(readFileSync2(join4(cavemanHome(), "run", `${port}.json`), "utf8")); if (state?.schema !== "caveman.proxy.run.v1") return void 0; if (typeof state.pid !== "number" || typeof state.instance_token !== "string") return void 0; if (state.owner !== "wrap" && state.owner !== "start") return void 0; try { process.kill(state.pid, 0); } catch { return void 0; } return Boolean(state.recovery_via_mcp); } catch { return void 0; } } async function proxyAliveOnce(gateway) { const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), HEALTH_TIMEOUT_MS); try { const response = await fetch(`${gateway.replace(/\/+$/, "")}/health/live`, { signal: controller.signal }); await response.body?.cancel(); return response.ok; } catch { return false; } finally { clearTimeout(timer); } } async function proxyAlive(gateway) { for (let attempt = 0; attempt < 3; attempt++) { if (await proxyAliveOnce(gateway)) return true; await new Promise((resolve2) => setTimeout(resolve2, 300)); } return false; } function index_default(pi) { const bridge = new HookBridge(); const recovery = new RecoveryClient(); let router; let sessionId = "default"; let coreContext; let pendingContext = []; let pendingBytes = 0; let gateDone = false; const notify = (ctx, message, kind) => { if (ctx?.hasUI) ctx.ui.notify(message, kind); else process.stderr.write(`${message} `); }; const debug = (message) => { if (process.env.CAVEMAN_PI_DEBUG === "1") process.stderr.write(`[caveman-pi] ${message} `); }; const guardedBase = (fn, label = fn.name || "handler") => (async (...args) => { try { debug(`enter ${label}`); const result = await fn(...args); debug(`exit ${label}`); return result; } catch (error) { process.stderr.write(`caveman pi extension: ${error.message} `); return void 0; } }); const GUARD = (label) => (fn) => guardedBase(fn, label); const GUARD_session_start = GUARD("session_start"); const GUARD_model_select = GUARD("model_select"); const GUARD_before_agent_start = GUARD("before_agent_start"); const GUARD_turn_start = GUARD("turn_start"); const GUARD_turn_end = GUARD("turn_end"); const GUARD_tool_call = GUARD("tool_call"); const GUARD_tool_result = GUARD("tool_result"); const GUARD_session_before_compact = GUARD("session_before_compact"); const GUARD_session_compact = GUARD("session_compact"); const GUARD_session_shutdown = GUARD("session_shutdown"); pi.registerTool({ name: RECOVERY_TOOL, label: "Retrieve compressed context", description: "Recover exact original content from a Caveman recovery handle.", parameters: Type.Object({ recovery_handle: Type.String({ description: "Exact ccr_ handle returned by Caveman or copied from a <> marker." }), query: Type.Optional(Type.String({ description: "One broad description covering every detail needed from this handle." })) }), async execute(_toolCallId, params, signal) { const result = await recovery.retrieve(params.recovery_handle, params.query, signal); if (result.isError) throw new Error(result.text || "caveman_retrieve failed"); return { content: [{ type: "text", text: result.text }], details: { recovery_handle: params.recovery_handle } }; } }); pi.on("session_start", GUARD_session_start(async (_event, ctx) => { router ??= new ProviderRouter(pi, (message, kind) => notify(ctx, message, kind)); gateDone = false; coreContext = void 0; pendingContext = []; pendingBytes = 0; try { sessionId = ctx.sessionManager.getSessionId() || "default"; } catch { sessionId = "default"; } const start = await bridge.call("SessionStart", { session_id: sessionId }); coreContext = additionalContextOf(start); if (!start) { gateDone = true; notify(ctx, "Caveman: direct mode, no compression this session (caveman native runtime unreachable)", "warning"); return; } const gateway = gatewayUrl(); const alive = await proxyAlive(gateway); const published = runStateRecoveryViaMcp(gateway); const recoveryReady = alive ? await recovery.ensure() : false; gateDone = true; if (!alive || published === void 0) { notify(ctx, "Caveman: direct mode, no compression this session (local proxy not running)", "warning"); return; } if (!published || !recoveryReady) { notify(ctx, "Caveman: direct mode, no compression this session (recovery not available \u2014 run `caveman doctor pi`)", "warning"); return; } await router.openGate(gateway, ctx); })); pi.on("model_select", GUARD_model_select(async (event, ctx) => { if (gateDone) await router?.apply(event.model, ctx); })); pi.on("before_agent_start", GUARD_before_agent_start(async (event, ctx) => { const response = await bridge.call("UserPromptSubmit", { session_id: sessionId, model: ctx.model?.id, provider: ctx.model?.provider, prompt: promptDigest(event.prompt), task_type: taskType(event.prompt), task_terms: taskTerms(event.prompt), task_continuation: taskContinuation(event.prompt) }); const dynamic = [additionalContextOf(response), ...pendingContext].filter(Boolean); pendingContext = []; pendingBytes = 0; if (!coreContext && dynamic.length === 0) return void 0; const parts = [event.systemPrompt, coreContext, ...dynamic].filter(Boolean); return { systemPrompt: parts.join("\n\n") }; })); pi.on("turn_start", GUARD_turn_start(() => { void bridge.call("ModelBefore", { session_id: sessionId }); })); pi.on("turn_end", GUARD_turn_end(async () => { await bridge.call("ModelAfter", { session_id: sessionId }); void bridge.call("Stop", { session_id: sessionId }); })); pi.on("tool_call", GUARD_tool_call(async (event) => { const response = await bridge.call("PreToolUse", { session_id: sessionId, tool_name: event.toolName, tool_input: event.input }); const context = additionalContextOf(response); const bytes = context ? Buffer.byteLength(context, "utf8") : 0; if (context && pendingBytes + bytes <= MAX_CONTEXT_BYTES) { pendingContext.push(context); pendingBytes += bytes; } })); pi.on("tool_result", GUARD_tool_result((event) => event.toolName === RECOVERY_TOOL ? void 0 : shrinkToolResult(bridge, sessionId, event))); pi.on("session_before_compact", GUARD_session_before_compact(() => { void bridge.call("PreCompact", { session_id: sessionId }); })); pi.on("session_compact", GUARD_session_compact(async () => { const response = await bridge.call("PostCompact", { session_id: sessionId }); const context = additionalContextOf(response); if (context) coreContext = context; })); pi.on("session_shutdown", GUARD_session_shutdown(async () => { await bridge.call("SessionEnd", { session_id: sessionId }); router?.closeGate(); recovery.dispose(); })); } export { index_default as default };