sessionpipe-core 0.13.3 → 0.13.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/control.js +101 -1
- package/dist/control.js.map +4 -4
- package/dist/index.js +445 -235
- package/dist/index.js.map +4 -4
- package/dist/schema/v1.d.ts.map +1 -1
- package/dist/schema.js +1 -1
- package/dist/schema.js.map +2 -2
- package/dist/service.js +1 -1
- package/dist/src/adapters/acp-control.d.ts +2 -2
- package/dist/src/adapters/acp-control.d.ts.map +1 -1
- package/dist/src/adapters/claude-code-control.d.ts +46 -5
- package/dist/src/adapters/claude-code-control.d.ts.map +1 -1
- package/dist/src/adapters/claude-code.d.ts.map +1 -1
- package/dist/src/adapters/headless.d.ts +29 -1
- package/dist/src/adapters/headless.d.ts.map +1 -1
- package/dist/src/adapters/types.d.ts +20 -1
- package/dist/src/adapters/types.d.ts.map +1 -1
- package/dist/src/control/frames.d.ts +87 -0
- package/dist/src/control/frames.d.ts.map +1 -0
- package/dist/src/control/index.d.ts +3 -2
- package/dist/src/control/index.d.ts.map +1 -1
- package/dist/src/readers/transcripts.d.ts +7 -2
- package/dist/src/readers/transcripts.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/adapters/claude-code-pool.ts", "../src/paths.ts", "../src/adapters/claude-code.ts", "../src/readers/files.ts", "../src/readers/git.ts", "../src/adapters/codex-rollout.ts", "../src/readers/transcripts.ts", "../src/adapters/claude-shaped.ts", "../src/adapters/acp-control.ts", "../src/adapters/headless.ts", "../src/launched-by.ts", "../src/adapters/antigravity.ts", "../src/adapters/antigravity-control.ts", "../src/adapters/claude-code-control.ts", "../src/control/verify.ts", "../src/adapters/codex.ts", "../src/adapters/codex-config.ts", "../src/adapters/codex-control.ts", "../src/adapters/devin.ts", "../src/readers/sqlite.ts", "../src/adapters/gemini-cli.ts", "../src/adapters/index.ts", "../src/config.ts", "../src/ulid.ts", "../src/events.ts", "../src/outbox.ts", "../src/privacy/
|
|
4
|
-
"sourcesContent": ["// SPDX-License-Identifier: Apache-2.0\n// The Claude Code pool: everything the daemon's loopback proxy has to know about\n// Anthropic, in one file, so nothing else in core names an endpoint, a header or a\n// credential file. Pure functions over bytes, headers and JSON, plus four `fetch`\n// wrappers whose `fetch` is injected: the tests never reach the network or the keychain.\n//\n// Facts were read from the installed Claude Code (2.1.312) with `strings`, and checked\n// against bb's Account Pooler for the request shapes; none of its code is copied.\n// - OAuth: PKCE S256 against `authorize`, the code pasted back as `code#state` (the\n// manual redirect, `callback`), exchanged at `token` as JSON\n// `{grant_type, code, state, client_id, redirect_uri, code_verifier}`; refreshed with\n// `{grant_type: \"refresh_token\", refresh_token, client_id}`. Every OAuth call carries\n// `anthropic-beta: oauth-2025-04-20`. Claude Code 2.1.312 signs in at\n// platform.claude.com (the token URL and the manual callback); the older\n// console.anthropic.com names bb still uses are the same service.\n// - Limits come back on every response as `anthropic-ratelimit-unified-*` headers:\n// `5h`/`7d` (and `7d_<model>`) \u00D7 `utilization` (a fraction 0\u20131), `reset` (epoch\n// seconds), `status`; a whole-account `status` (allowed \u00B7 allowed_warning \u00B7 rejected);\n// on a refusal `representative-claim` names the window and `reset` says when. The\n// usage endpoint says the same per window as `{utilization (a percent), resets_at}`.\n// - Claude Code's own login is a generic password in the macOS keychain, service\n// `Claude Code-credentials` (plus `-<8 hex of sha256(config dir)>` when\n// CLAUDE_CONFIG_DIR is set), account = the login user; elsewhere\n// `<config dir>/.credentials.json`. Either holds\n// `{claudeAiOauth: {accessToken, refreshToken, expiresAt (epoch ms), \u2026}}`.\n// - `metadata.user_id` in a request body is, since 2.1.x, a JSON string\n// `{\"device_id\",\"account_uuid\",\"session_id\"[,\"parent_session_id\"]}`; older builds sent\n// `user_<hash>_account_<uuid>_session_<uuid>`. Both are read; the account part is\n// rewritten in place so the serving account sees its own id and nothing else moves.\n\nimport { createHash, randomBytes } from \"node:crypto\";\nimport { readFileSync } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { homeDir } from \"../paths.js\";\nimport type { DataOf } from \"../types.js\";\nimport { claudeDirs } from \"./claude-code.js\";\n\nexport type LimitWindow = DataOf<\"limits.observed\">[\"windows\"][number];\n\n/** Claude Code 2.1.312's own prod endpoints. bb signs in at claude.ai/oauth/authorize with\n * console.anthropic.com's callback and token URL, which still answer; the paste-back code\n * works the same at either. */\nexport const POOL_ENDPOINTS = {\n authorize: \"https://claude.com/cai/oauth/authorize\",\n token: \"https://platform.claude.com/v1/oauth/token\",\n callback: \"https://platform.claude.com/oauth/code/callback\",\n profile: \"https://api.anthropic.com/api/oauth/profile\",\n usage: \"https://api.anthropic.com/api/oauth/usage\",\n api: \"https://api.anthropic.com\",\n clientId: \"9d1c250a-e61b-44d9-88ed-5944d1962f5e\",\n // The six Claude Code itself asks for with this client id: a token minted with fewer\n // than the client's usual set is the kind of thing that fails only live.\n scopes: [\n \"user:inference\",\n \"user:profile\",\n \"org:create_api_key\",\n \"user:sessions:claude_code\",\n \"user:mcp_servers\",\n \"user:file_upload\",\n ],\n beta: \"oauth-2025-04-20\",\n} as const;\n\nexport interface PoolCredential {\n access: string;\n refresh: string;\n /** Epoch milliseconds. */\n expires_at: number;\n}\nexport type PoolStatus = \"allowed\" | \"allowed_warning\" | \"rejected\";\nexport interface PoolLimits {\n windows: LimitWindow[];\n /** The account as a whole. */\n status?: PoolStatus;\n /** On a refusal: the window that refused (`five_hour`, `seven_day`, \u2026) and when it resets. */\n claim?: string;\n resets_at?: string;\n observed_at: number;\n}\nexport interface PoolProfile {\n account_uuid: string;\n email: string;\n org?: string;\n plan?: string;\n}\nexport interface ImportableLogin {\n /** The Claude Code config dir the login belongs to. */\n dir: string;\n credential: PoolCredential;\n /** From the dir's .claude.json; absent when that file has no login (fetchProfile fills it). */\n account_uuid?: string;\n email?: string;\n source: \"keychain\" | \"file\";\n}\n\n/** The person has to sign in (again): a refused code, a dead refresh token, a 401. */\nexport class PoolAuthError extends Error {}\n/** Anthropic did not answer properly right now; the same call may work in a minute. */\nexport class PoolUpstreamError extends Error {}\n\n// --- limits ---------------------------------------------------------------------------\n\nconst PREFIX = \"anthropic-ratelimit-unified-\";\nconst WINDOW_IDS: Record<string, string> = { \"5h\": \"five_hour\", \"7d\": \"seven_day\" };\nconst WINDOW_MINUTES: Record<string, number> = { five_hour: 300, seven_day: 10_080 };\nconst STATUSES = new Set<string>([\"allowed\", \"allowed_warning\", \"rejected\"]);\nconst ID_RE = /^[a-z0-9_]{1,64}$/;\n\ntype HeaderBag = Headers | Record<string, string | string[] | undefined>;\n/** Every header as (lowercase name, first value). */\nfunction entries(h: HeaderBag): [string, string][] {\n const out: [string, string][] = [];\n if (h instanceof Headers) {\n h.forEach((v, k) => {\n out.push([k.toLowerCase(), v]);\n });\n return out;\n }\n for (const [k, v] of Object.entries(h)) {\n const s = Array.isArray(v) ? v[0] : v;\n if (typeof s === \"string\") out.push([k.toLowerCase(), s]);\n }\n return out;\n}\n/** Epoch seconds (a header's `reset`, usage's numeric `resets_at`) or an RFC 3339 string\n * as RFC 3339; anything that is not a plausible time is no time. */\nfunction isoTime(v: unknown): string | undefined {\n if (typeof v === \"number\") return v > 0 && v < 1e11 ? new Date(v * 1000).toISOString() : undefined;\n if (typeof v !== \"string\") return undefined;\n const s = v.trim();\n if (/^\\d+(\\.\\d+)?$/.test(s)) return isoTime(Number(s));\n if (!/^\\d{4}-\\d{2}-\\d{2}T/.test(s)) return undefined;\n const t = Date.parse(s);\n return Number.isFinite(t) ? new Date(t).toISOString() : undefined;\n}\nconst percentOf = (n: number) => Math.round(Math.max(0, n) * 10) / 10;\n/** The window id a `5h`/`7d`/`7d_opus` header part names; the same ids Claude Code's status line uses. */\nconst windowId = (part: string): string => WINDOW_IDS[part] ?? `seven_day_${part.slice(3)}`;\n\n/** The account's limits from a response's headers; null when the limiter did not run\n * (no `anthropic-ratelimit-unified-*` header at all). A window needs a readable\n * utilization; a status or a reset alone is kept on the account. */\nexport function readLimits(headers: HeaderBag, now: number): PoolLimits | null {\n const seen = new Map<string, { used?: number; resets_at?: string }>();\n const out: PoolLimits = { windows: [], observed_at: now };\n let any = false;\n for (const [name, value] of entries(headers)) {\n if (!name.startsWith(PREFIX)) continue;\n any = true;\n const rest = name.slice(PREFIX.length);\n if (rest === \"status\") {\n if (STATUSES.has(value)) out.status = value as PoolStatus;\n continue;\n }\n if (rest === \"representative-claim\") {\n if (ID_RE.test(value)) out.claim = value;\n continue;\n }\n if (rest === \"reset\") {\n const t = isoTime(value);\n if (t) out.resets_at = t;\n continue;\n }\n const m = /^(5h|7d|7d_[a-z0-9_]+)-(utilization|reset)$/.exec(rest);\n if (!m) continue;\n const id = windowId(m[1] as string);\n if (!ID_RE.test(id)) continue;\n const w = seen.get(id) ?? {};\n seen.set(id, w);\n if (m[2] === \"utilization\") {\n const n = Number(value);\n if (value.trim() && Number.isFinite(n)) w.used = percentOf(n * 100);\n } else {\n const t = isoTime(value);\n if (t) w.resets_at = t;\n }\n }\n if (!any) return null;\n for (const [id, w] of seen) {\n if (w.used === undefined) continue;\n const minutes = WINDOW_MINUTES[id];\n out.windows.push({\n id,\n used_percent: w.used,\n ...(w.resets_at ? { resets_at: w.resets_at } : {}),\n ...(minutes ? { window_minutes: minutes } : {}),\n });\n }\n return out;\n}\n\n/** The usage endpoint's JSON: `{five_hour: {utilization, resets_at}, seven_day: {\u2026},\n * seven_day_<model>: {\u2026}, \u2026}`, utilization a percent already. Any other key shaped\n * like a window passes through under its own id; null when none is. */\nexport function usageLimits(json: unknown, now: number): PoolLimits | null {\n if (!json || typeof json !== \"object\" || Array.isArray(json)) return null;\n const windows: LimitWindow[] = [];\n for (const [id, v] of Object.entries(json as Record<string, unknown>)) {\n if (!ID_RE.test(id) || !v || typeof v !== \"object\" || Array.isArray(v)) continue;\n const w = v as { utilization?: unknown; resets_at?: unknown };\n if (typeof w.utilization !== \"number\" || !Number.isFinite(w.utilization)) continue;\n const resets_at = isoTime(w.resets_at);\n const minutes = WINDOW_MINUTES[id];\n windows.push({\n id,\n used_percent: percentOf(w.utilization),\n ...(resets_at ? { resets_at } : {}),\n ...(minutes ? { window_minutes: minutes } : {}),\n });\n }\n return windows.length ? { windows: windows.slice(0, 8), observed_at: now } : null;\n}\n\n// --- metadata.user_id -----------------------------------------------------------------\n\nconst UUID = \"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\";\nconst UUID_RE = new RegExp(`^${UUID}$`, \"i\");\nconst LEGACY_ACCOUNT = new RegExp(`(?:^|_)account_(${UUID})(?=_|$)`, \"i\");\nconst LEGACY_SESSION = new RegExp(`(?:^|_)session_(${UUID})$`, \"i\");\n\nfunction userIdOf(body: unknown): string | null {\n let v = body;\n if (Buffer.isBuffer(v) || typeof v === \"string\") {\n try {\n v = JSON.parse(v.toString());\n } catch {\n return null;\n }\n }\n const id = (v as { metadata?: { user_id?: unknown } } | null)?.metadata?.user_id;\n return typeof id === \"string\" && id.length <= 4096 ? id : null;\n}\n/** The session and account a `metadata.user_id` names, in either of its two forms. */\nfunction partsOf(id: string): { session?: string; account?: string } {\n if (id.startsWith(\"{\")) {\n try {\n const j = JSON.parse(id) as { account_uuid?: unknown; session_id?: unknown };\n return {\n ...(typeof j.session_id === \"string\" && j.session_id ? { session: j.session_id } : {}),\n ...(typeof j.account_uuid === \"string\" && UUID_RE.test(j.account_uuid) ? { account: j.account_uuid } : {}),\n };\n } catch {\n return {};\n }\n }\n const s = LEGACY_SESSION.exec(id)?.[1];\n const a = LEGACY_ACCOUNT.exec(id)?.[1];\n return { ...(s ? { session: s } : {}), ...(a ? { account: a } : {}) };\n}\n\n/** `metadata.user_id` of a request body (parsed, or the raw bytes): the session to pin\n * on and the account the body claims. null when the body carries none. */\nexport function parseUserId(body: unknown): { session?: string; account?: string } | null {\n const id = userIdOf(body);\n return id === null ? null : partsOf(id);\n}\n\n/** The body with the account part of `metadata.user_id` set to `accountUuid`, the same\n * bytes when there is nothing to rewrite. Done on the string, not a parse/stringify\n * round trip: Claude Code's bodies are JSON.stringify output and would survive one, but\n * a body a person built by hand (an SDK, a `CLAUDE_CODE_EXTRA_BODY`) can carry number\n * forms and escapes a round trip rewrites, and a prompt cache is keyed on bytes. The\n * only change is the UUID inside that one string literal. */\nexport function withAccount(body: Buffer, accountUuid: string): Buffer {\n if (!UUID_RE.test(accountUuid)) return body;\n const id = userIdOf(body);\n if (id === null) return body;\n const current = partsOf(id).account;\n if (current && current.toLowerCase() === accountUuid.toLowerCase()) return body;\n // Claude Code 2.1.312 under ANTHROPIC_AUTH_TOKEN sends the JSON form with\n // `\"account_uuid\":\"\"`: the slot is there, empty, and is filled the same way.\n const empty = !current && id.startsWith(\"{\") && emptyAccountSlot(id);\n if (!current && !empty) return body;\n const text = body.toString(\"utf8\");\n // The literal as JSON.stringify writes it; a body that escaped it another way\n // (`\\u005f` for an underscore) is left alone rather than guessed at.\n const literal = JSON.stringify(id).slice(1, -1);\n const was = current ?? \"\";\n const at = current ? literal.indexOf(current) : literal.indexOf(EMPTY_SLOT) + EMPTY_SLOT.length;\n const ms = [...text.matchAll(/\"user_id\"\\s*:\\s*\"((?:[^\"\\\\]|\\\\.)*)\"/g)].filter((x) => x[1] === literal);\n if (!ms.length) return body;\n if (ms.length === 1) {\n const m = ms[0] as RegExpExecArray;\n const start = m.index + m[0].length - 1 - literal.length + at;\n return Buffer.from(text.slice(0, start) + accountUuid + text.slice(start + was.length), \"utf8\");\n }\n // The same literal under another `user_id` key too (a tool's input schema): rewrite\n // the one in `metadata` structurally rather than guess which literal is it. A round\n // trip costs the byte-stable cache key, not correctness.\n const j = JSON.parse(text) as { metadata: { user_id: string } };\n if (current) j.metadata.user_id = id.replace(current, accountUuid);\n else\n j.metadata.user_id = JSON.stringify({ ...(JSON.parse(id) as Record<string, unknown>), account_uuid: accountUuid });\n return Buffer.from(JSON.stringify(j), \"utf8\");\n}\n\n/** `\"account_uuid\":\"\"` as JSON.stringify writes it inside the escaped user_id literal. */\nconst EMPTY_SLOT = '\\\\\"account_uuid\\\\\":\\\\\"';\n/** The JSON form with an empty account: a slot to fill, not an account to replace. */\nfunction emptyAccountSlot(id: string): boolean {\n try {\n return (JSON.parse(id) as { account_uuid?: unknown }).account_uuid === \"\";\n } catch {\n return false;\n }\n}\n\n// --- headers upstream -----------------------------------------------------------------\n\n/** Headers that describe this hop, not the request; and the ones the proxy owns. */\nconst DROP = new Set([\n \"connection\",\n \"keep-alive\",\n \"transfer-encoding\",\n \"te\",\n \"trailer\",\n \"upgrade\",\n \"host\",\n \"content-length\",\n \"authorization\",\n \"x-api-key\",\n]);\n\n/** The request's headers as they go to Anthropic: the serving account's bearer in place\n * of the pool's own token, the OAuth beta present, hop-by-hop and the ones the sender\n * sets (host, content-length) gone. Our token and any x-api-key never go through. */\nexport function upstreamHeaders(\n req: Record<string, string | string[] | undefined>,\n access: string,\n): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(req)) {\n const name = k.toLowerCase();\n if (v === undefined || DROP.has(name) || name.startsWith(\"proxy-\")) continue;\n out[name] = Array.isArray(v) ? v.join(\", \") : v;\n }\n out.authorization = `Bearer ${access}`;\n const betas = (out[\"anthropic-beta\"] ?? \"\")\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n if (!betas.includes(POOL_ENDPOINTS.beta)) betas.push(POOL_ENDPOINTS.beta);\n out[\"anthropic-beta\"] = betas.join(\",\");\n return out;\n}\n\n// --- OAuth ----------------------------------------------------------------------------\n\n/** PKCE, as Claude Code builds its own sign-in URL (the same parameters in the same\n * order; `code=true` asks for the paste-back page). 32 random bytes base64url is a\n * 43-character verifier, inside RFC 7636's 43\u2013128. */\nexport function beginLogin(random: (n: number) => Buffer = randomBytes): {\n url: string;\n verifier: string;\n state: string;\n} {\n const verifier = random(32).toString(\"base64url\");\n const state = random(32).toString(\"base64url\");\n const challenge = createHash(\"sha256\").update(verifier).digest(\"base64url\");\n const u = new URL(POOL_ENDPOINTS.authorize);\n u.searchParams.append(\"code\", \"true\");\n u.searchParams.append(\"client_id\", POOL_ENDPOINTS.clientId);\n u.searchParams.append(\"response_type\", \"code\");\n u.searchParams.append(\"redirect_uri\", POOL_ENDPOINTS.callback);\n u.searchParams.append(\"scope\", POOL_ENDPOINTS.scopes.join(\" \"));\n u.searchParams.append(\"code_challenge\", challenge);\n u.searchParams.append(\"code_challenge_method\", \"S256\");\n u.searchParams.append(\"state\", state);\n return { url: u.toString(), verifier, state };\n}\n\n/** What the person pasted: `code#state` from the callback page, the callback URL\n * itself, or a bare code. A state that is there and differs is somebody else's login. */\nfunction pastedCode(pasted: string, state: string): string {\n const s = pasted.trim();\n if (!s) throw new PoolAuthError(\"Paste the code the sign-in page shows.\");\n if (/^https?:\\/\\//i.test(s)) {\n let u: URL;\n try {\n u = new URL(s);\n } catch {\n throw new PoolAuthError(\"That is not the sign-in page's code.\");\n }\n const code = u.searchParams.get(\"code\");\n const st = u.searchParams.get(\"state\");\n if (!code) throw new PoolAuthError(\"That URL carries no code.\");\n if (st !== null && st !== state) throw new PoolAuthError(\"That code belongs to another sign-in; start again.\");\n return code;\n }\n const hash = s.indexOf(\"#\");\n if (hash < 0) return s;\n const code = s.slice(0, hash).trim();\n const st = s.slice(hash + 1).trim();\n if (!code) throw new PoolAuthError(\"Paste the code the sign-in page shows.\");\n if (st && st !== state) throw new PoolAuthError(\"That code belongs to another sign-in; start again.\");\n return code;\n}\n\ntype Fetch = typeof globalThis.fetch;\nconst JSON_HEADERS = { \"content-type\": \"application/json\", \"anthropic-beta\": POOL_ENDPOINTS.beta };\n\nasync function post(fetch: Fetch, url: string, body: unknown, what: string): Promise<Response> {\n try {\n return await fetch(url, { method: \"POST\", headers: JSON_HEADERS, body: JSON.stringify(body) });\n } catch (e) {\n throw new PoolUpstreamError(`${what}: ${(e as Error).message || \"no answer from Anthropic\"}`);\n }\n}\nasync function get(fetch: Fetch, url: string, access: string, what: string): Promise<Response> {\n try {\n return await fetch(url, { headers: { authorization: `Bearer ${access}`, \"anthropic-beta\": POOL_ENDPOINTS.beta } });\n } catch (e) {\n throw new PoolUpstreamError(`${what}: ${(e as Error).message || \"no answer from Anthropic\"}`);\n }\n}\nasync function jsonOf(r: Response): Promise<unknown> {\n try {\n return await r.json();\n } catch {\n return null;\n }\n}\n/** A token response into a credential; the refresh token stays when the answer omits it. */\nfunction credentialOf(j: unknown, now: number, keepRefresh: string | undefined, what: string): PoolCredential {\n const t = j as { access_token?: unknown; refresh_token?: unknown; expires_in?: unknown } | null;\n const refresh = typeof t?.refresh_token === \"string\" && t.refresh_token ? t.refresh_token : keepRefresh;\n if (!t || typeof t.access_token !== \"string\" || !t.access_token || !refresh || typeof t.expires_in !== \"number\")\n throw new PoolUpstreamError(`${what}: Anthropic's answer had no token in it`);\n return { access: t.access_token, refresh, expires_at: now + t.expires_in * 1000 };\n}\n\n/** Exchange the pasted code for a credential and read whose it is. */\nexport async function completeLogin(\n code: string,\n pending: { verifier: string; state: string },\n fetch: Fetch,\n now: () => number,\n): Promise<{ credential: PoolCredential; profile: PoolProfile }> {\n const c = pastedCode(code, pending.state);\n const r = await post(\n fetch,\n POOL_ENDPOINTS.token,\n {\n grant_type: \"authorization_code\",\n code: c,\n state: pending.state,\n client_id: POOL_ENDPOINTS.clientId,\n redirect_uri: POOL_ENDPOINTS.callback,\n code_verifier: pending.verifier,\n },\n \"sign-in\",\n );\n if (r.status >= 400 && r.status < 500)\n throw new PoolAuthError(`Anthropic did not accept the code (HTTP ${r.status}); start the sign-in again.`);\n if (!r.ok) throw new PoolUpstreamError(`sign-in: Anthropic answered HTTP ${r.status}; try again in a minute`);\n const credential = credentialOf(await jsonOf(r), now(), undefined, \"sign-in\");\n const profile = await fetchProfile(credential.access, fetch);\n return { credential, profile };\n}\n\n/** A fresh access token. 400/401 means the refresh token is dead (revoked, expired,\n * used elsewhere): the person signs in again. Anything else is Anthropic's moment. */\nexport async function refreshCredential(\n cred: PoolCredential,\n fetch: Fetch,\n now: () => number,\n): Promise<PoolCredential> {\n const r = await post(\n fetch,\n POOL_ENDPOINTS.token,\n { grant_type: \"refresh_token\", refresh_token: cred.refresh, client_id: POOL_ENDPOINTS.clientId },\n \"refresh\",\n );\n if (r.status === 400 || r.status === 401)\n throw new PoolAuthError(\"This account's sign-in has expired; sign in again.\");\n if (!r.ok) throw new PoolUpstreamError(`refresh: Anthropic answered HTTP ${r.status}; try again in a minute`);\n return credentialOf(await jsonOf(r), now(), cred.refresh, \"refresh\");\n}\n\n/** Whose token this is: `{account: {uuid, email, \u2026}, organization: {name, \u2026}}`. */\nexport async function fetchProfile(access: string, fetch: Fetch): Promise<PoolProfile> {\n const r = await get(fetch, POOL_ENDPOINTS.profile, access, \"profile\");\n if (r.status === 401 || r.status === 403)\n throw new PoolAuthError(\"Anthropic does not know this token; sign in again.\");\n if (!r.ok) throw new PoolUpstreamError(`profile: Anthropic answered HTTP ${r.status}; try again in a minute`);\n const j = (await jsonOf(r)) as {\n account?: { uuid?: unknown; email?: unknown; subscription_type?: unknown };\n organization?: { name?: unknown };\n } | null;\n const a = j?.account;\n if (typeof a?.uuid !== \"string\" || !UUID_RE.test(a.uuid) || typeof a.email !== \"string\" || !a.email)\n throw new PoolUpstreamError(\"profile: Anthropic's answer did not say whose token this is\");\n const org = j?.organization?.name;\n const plan = a.subscription_type;\n return {\n account_uuid: a.uuid.toLowerCase(),\n email: a.email,\n ...(typeof org === \"string\" && org ? { org } : {}),\n ...(typeof plan === \"string\" && plan ? { plan } : {}),\n };\n}\n\n/** The account's windows from the usage endpoint; null when it reports none. */\nexport async function fetchUsage(access: string, fetch: Fetch, now: () => number): Promise<PoolLimits | null> {\n const r = await get(fetch, POOL_ENDPOINTS.usage, access, \"usage\");\n if (r.status === 401 || r.status === 403)\n throw new PoolAuthError(\"Anthropic does not know this token; sign in again.\");\n if (!r.ok) throw new PoolUpstreamError(`usage: Anthropic answered HTTP ${r.status}; try again in a minute`);\n return usageLimits(await jsonOf(r), now());\n}\n\n// --- Claude Code's own logins ---------------------------------------------------------\n\nconst SERVICE = \"Claude Code-credentials\";\n/** The keychain service Claude Code keeps a config dir's login under: bare for the\n * default dir, suffixed with 8 hex of sha256(dir) when CLAUDE_CONFIG_DIR names one. */\nexport function keychainService(dir: string, home: string, platform: NodeJS.Platform = process.platform): string {\n // \"The default dir\" is a comparison of resolved paths (this process's own path\n // module: what the file system here uses), case-blind on Windows, where the same\n // folder arrives as `C:\\Users\\\u2026` from one place and `c:\\users\\\u2026` from another.\n // The suffix stays a hash of the dir as given: it names an item Claude Code wrote.\n const norm = (x: string) => (platform === \"win32\" ? path.resolve(x).toLowerCase() : path.resolve(x));\n if (norm(dir) === norm(path.join(home, \".claude\"))) return SERVICE;\n return `${SERVICE}-${createHash(\"sha256\").update(dir).digest(\"hex\").slice(0, 8)}`;\n}\n/** The keychain item's account: the login user, as Claude Code names it. */\nfunction keychainUser(env: NodeJS.ProcessEnv): string {\n let u = env.USER;\n if (!u) {\n try {\n u = os.userInfo().username;\n } catch {\n u = \"\";\n }\n }\n return /^[a-zA-Z0-9._-]+$/.test(u) ? u : \"claude-code-user\";\n}\nfunction credentialIn(text: string): PoolCredential | null {\n try {\n const o = (\n JSON.parse(text) as { claudeAiOauth?: { accessToken?: unknown; refreshToken?: unknown; expiresAt?: unknown } }\n ).claudeAiOauth;\n if (typeof o?.accessToken !== \"string\" || !o.accessToken || typeof o.refreshToken !== \"string\" || !o.refreshToken)\n return null;\n // No expiry on record means refresh before the first use.\n return {\n access: o.accessToken,\n refresh: o.refreshToken,\n expires_at: typeof o.expiresAt === \"number\" ? o.expiresAt : 0,\n };\n } catch {\n return null;\n }\n}\nconst EMAIL_RE = /^[^@\\s]{1,64}@[^@\\s]{1,189}$/;\ntype ReadFile = (file: string) => string;\nconst readText: ReadFile = (f) => readFileSync(f, \"utf8\");\n\n/** Every Claude Code login on this machine the pool could copy, one per config dir\n * (claudeDirs): the credential from the keychain (macOS) or `.credentials.json`, and\n * who it is from the dir's .claude.json. `exec` runs `security` and returns stdout; it\n * is the only thing that touches the keychain, so a test hands in a fake. Returns []\n * on any failure and never throws: an import that finds nothing is a message, not a\n * crash, and a token never reaches a log through here. */\nexport function importableLogins(\n env: NodeJS.ProcessEnv,\n exec: (cmd: string, args: string[]) => string,\n readFile: ReadFile = readText,\n platform: NodeJS.Platform = process.platform,\n): ImportableLogin[] {\n const out: ImportableLogin[] = [];\n const home = env.HOME || homeDir();\n const user = keychainUser(env);\n for (const dir of claudeDirs(env, home)) {\n let credential: PoolCredential | null = null;\n let source: ImportableLogin[\"source\"] = \"file\";\n if (platform === \"darwin\") {\n const service = keychainService(dir, home, platform);\n // Claude Code writes the item under the login user; an item saved another way\n // (an older build, a renamed user) is still found by service alone.\n for (const args of [\n [\"find-generic-password\", \"-s\", service, \"-a\", user, \"-w\"],\n [\"find-generic-password\", \"-s\", service, \"-w\"],\n ]) {\n try {\n credential = credentialIn(exec(\"security\", args).trim());\n } catch {}\n if (credential) break;\n }\n if (credential) source = \"keychain\";\n }\n if (!credential) {\n try {\n credential = credentialIn(readFile(path.join(dir, \".credentials.json\")));\n } catch {}\n }\n if (!credential) continue;\n out.push({ dir, credential, ...whoIs(dir, home, readFile), source });\n }\n return out;\n}\n/** The dir's login, as claude-code.ts reads it: the default dir keeps its .claude.json at ~/.claude.json. */\nfunction whoIs(dir: string, home: string, readFile: ReadFile): { account_uuid?: string; email?: string } {\n const files = [path.join(dir, \".claude.json\")];\n if (path.resolve(dir) === path.join(home, \".claude\")) files.unshift(path.join(home, \".claude.json\"));\n for (const f of files) {\n try {\n const a = (JSON.parse(readFile(f)) as { oauthAccount?: { accountUuid?: unknown; emailAddress?: unknown } })\n .oauthAccount;\n if (typeof a?.accountUuid === \"string\" && UUID_RE.test(a.accountUuid)) {\n const email = typeof a.emailAddress === \"string\" && EMAIL_RE.test(a.emailAddress) ? a.emailAddress : undefined;\n return { account_uuid: a.accountUuid.toLowerCase(), ...(email ? { email } : {}) };\n }\n } catch {}\n }\n return {};\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// Where sessionpipe keeps its files (spec: the client's Files section).\n// config ~/.config/sessionpipe/config.json SESSIONPIPE_CONFIG\n// state ~/.local/state/sessionpipe/ SESSIONPIPE_STATE\n// Windows %APPDATA%\\sessionpipe\\ and %LOCALAPPDATA%\\sessionpipe\\\nimport os from \"node:os\";\nimport path from \"node:path\";\n\n/** The home directory, read when asked: a test that sets HOME after importing core\n * (or a process whose HOME changes) gets the new one, never one cached at load. */\nexport const homeDir = (): string => os.homedir();\n\nexport function configFile(env: NodeJS.ProcessEnv = process.env): string {\n if (env.SESSIONPIPE_CONFIG) return path.resolve(env.SESSIONPIPE_CONFIG);\n if (process.platform === \"win32\")\n return path.join(env.APPDATA || path.join(homeDir(), \"AppData\", \"Roaming\"), \"sessionpipe\", \"config.json\");\n return path.join(env.XDG_CONFIG_HOME || path.join(homeDir(), \".config\"), \"sessionpipe\", \"config.json\");\n}\n\nexport function stateDir(env: NodeJS.ProcessEnv = process.env): string {\n if (env.SESSIONPIPE_STATE) return path.resolve(env.SESSIONPIPE_STATE);\n if (process.platform === \"win32\")\n return path.join(env.LOCALAPPDATA || path.join(homeDir(), \"AppData\", \"Local\"), \"sessionpipe\");\n return path.join(env.XDG_STATE_HOME || path.join(homeDir(), \".local\", \"state\"), \"sessionpipe\");\n}\n\n/** `~` for the home directory, as the session block writes paths. */\nexport function tilde(p: string, home: string = homeDir()): string {\n if (!p) return p;\n if (p === home) return \"~\";\n return p.startsWith(home + path.sep) || p.startsWith(`${home}/`) ? `~${p.slice(home.length)}` : p;\n}\n\n/** The other way: `~`, `~/\u2026` (or `~\\\u2026`) under the home directory, as a control `start`'s\n * `cwd` may name a folder an event reported (CONTROL.md \u00A73.1). Anything else, `~user`\n * included, is returned as it is. */\nexport function untilde(p: string, home: string = homeDir()): string {\n if (p === \"~\") return home;\n return /^~[\\\\/]/.test(p) ? path.join(home, p.slice(2)) : p;\n}\n\n/** A file-name-safe id. */\nexport const safeId = (s: string): string =>\n String(s)\n .replace(/[^A-Za-z0-9_.-]/g, \"_\")\n .slice(0, 160);\n", "// SPDX-License-Identifier: Apache-2.0\n// Claude Code (Anthropic) \u2014 docs: https://code.claude.com/docs/en/hooks\n// Config: settings.json in EVERY config dir (~/.claude, $CLAUDE_CONFIG_DIR, ~/.claude-*):\n// one per account; hooks written to one never fire for the others. Reads only the\n// hook's stdin, the transcript it names, the per-pid session registry and the config\n// dir's .claude.json account (its id; its email only for control's pair and hello) \u2014\n// or, with no login there, the API its settings.json names (that one key, no token).\n// The one exception is the person's to make: with `remote_titles` on, the sign-in\n// token is read to ask claude.ai for a session's name, and sent nowhere else.\n// Ported from spacesheep-cli lib/sessions.js.\n\nimport { execFileSync } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { userInfo } from \"node:os\";\nimport path from \"node:path\";\nimport { homeDir } from \"../paths.js\";\nimport { ends, parseLines, recentFiles, scanLines } from \"../readers/files.js\";\nimport { gitFacts } from \"../readers/git.js\";\nimport { isInjected, readClaude } from \"../readers/transcripts.js\";\nimport type { DataOf, HarnessAccount } from \"../types.js\";\nimport {\n formatJson,\n installClaudeShaped,\n installedClaudeShaped,\n OURS,\n readJson,\n readJsonFile,\n uninstallClaudeShaped,\n writeBack,\n} from \"./claude-shaped.js\";\nimport type {\n Adapter,\n BackfillRow,\n FactsState,\n HookCommand,\n HookInput,\n HookResult,\n InstallOptions,\n InstallReport,\n SessionFacts,\n} from \"./types.js\";\n\nconst NAME = \"claude-code\";\nexport const CLAUDE_EVENTS = [\n \"SessionStart\",\n \"UserPromptSubmit\",\n \"PreToolUse\",\n \"PostToolUse\",\n \"PostToolUseFailure\",\n \"PermissionRequest\",\n \"Notification\",\n \"Stop\",\n \"SubagentStart\",\n \"SubagentStop\",\n \"PreCompact\",\n \"PostCompact\",\n \"SessionEnd\",\n \"StopFailure\",\n] as const;\n/** With no sink above tier 0 only the heartbeat needs a tool event: one, not three (issue #12). */\nconst LEAN_SKIP = new Set([\"PreToolUse\", \"PostToolUseFailure\"]);\nconst eventsFor = (lean?: boolean) => (lean ? CLAUDE_EVENTS.filter((e) => !LEAN_SKIP.has(e)) : [...CLAUDE_EVENTS]);\nconst OPTS = {\n matcherFor: (e: string) => (/Tool|Permission/.test(e) ? \"\" : undefined),\n timeout: 5,\n // The hook waits up to 125 s for a verified control answer, and only when control\n // is paired on this machine; everywhere else it exits in milliseconds as before.\n timeoutFor: (e: string) => (e === \"PermissionRequest\" ? 130 : undefined),\n};\nconst DESKTOP_ID = /^local_[A-Za-z0-9-]{1,64}$/;\n\n/** Every Claude Code config dir on this machine. `home` follows the env's HOME, so a\n * caller with its own env (a test) never reaches the real ~/.claude: the install test\n * once rewrote a real settings.json with its fake hook paths on every run. */\nexport function claudeDirs(env: NodeJS.ProcessEnv = process.env, home = env.HOME || homeDir()): string[] {\n const out: string[] = [];\n const add = (d?: string) => {\n if (!d) return;\n const r = path.resolve(d);\n if (!out.includes(r)) out.push(r);\n };\n add(path.join(home, \".claude\"));\n add(env.CLAUDE_CONFIG_DIR);\n try {\n for (const e of readdirSync(home, { withFileTypes: true })) {\n if (!e.isDirectory() || !/^\\.claude[-_.]/.test(e.name)) continue;\n const d = path.join(home, e.name);\n if (existsSync(path.join(d, \"projects\")) || existsSync(path.join(d, \"settings.json\"))) add(d);\n }\n } catch {}\n return out.filter((d, i) => i === 0 || existsSync(d));\n}\nconst settingsIn = (dir: string) => path.join(dir, \"settings.json\");\nconst configDirOf = (transcript: string) => path.dirname(path.dirname(path.dirname(transcript)));\n\nconst validTool = (n: unknown): n is string => typeof n === \"string\" && /^[A-Za-z0-9_.:-]{1,120}$/.test(n);\nconst endReason = (r: unknown): \"clear\" | \"logout\" | \"exit\" | \"other\" =>\n r === \"clear\" || r === \"logout\" || r === \"exit\" ? r : r === \"prompt_input_exit\" ? \"exit\" : \"other\";\nconst notifKind = (t: unknown): \"permission\" | \"question\" | \"elicitation\" | \"idle\" | \"error\" =>\n t === \"permission_prompt\"\n ? \"permission\"\n : t === \"idle_prompt\"\n ? \"idle\"\n : t === \"elicitation_dialog\"\n ? \"elicitation\"\n : \"question\";\n\nexport const claudeCode: Adapter = {\n name: NAME,\n events: CLAUDE_EVENTS,\n detect: (env = process.env) => claudeDirs(env).some((d) => existsSync(d)),\n configFiles: (env = process.env) => claudeDirs(env).map(settingsIn),\n install: (cmd, env = process.env, opts: InstallOptions = {}) =>\n claudeDirs(env).flatMap((d) => {\n const hooks = installClaudeShaped(settingsIn(d), NAME, eventsFor(opts.lean), cmd, OPTS);\n // A file the hooks could not go into (not JSON, or refused) gets the one report, theirs.\n const line =\n opts.statusLine === undefined || hooks.skipped ? null : statusLine(settingsIn(d), opts.statusLine, cmd);\n return line ? [hooks, line] : [hooks];\n }),\n uninstall: (env = process.env, opts: InstallOptions = {}) =>\n claudeDirs(env).map((d) => {\n const line = statusLine(settingsIn(d), false);\n const hooks = uninstallClaudeShaped(settingsIn(d), CLAUDE_EVENTS, {\n created: opts.created?.includes(settingsIn(d)),\n });\n // A status line taken out, then the hooks' write refused: \"not touched\" would be\n // false of the file, so the one report says both.\n if (line?.changed && !line.skipped && hooks.skipped)\n return { ...hooks, note: `status line removed, hooks not: ${hooks.note?.replace(/; not touched$/, \"\")}` };\n return line && !hooks.changed && !hooks.skipped ? line : hooks;\n }),\n installed: (cmd, env = process.env, opts: InstallOptions = {}) =>\n claudeDirs(env).map((d) => ({\n file: settingsIn(d),\n state: installedClaudeShaped(settingsIn(d), NAME, eventsFor(opts.lean), cmd, OPTS),\n })),\n\n fromHook(input: HookInput): HookResult | null {\n const event = input.argv[1] ?? \"\";\n let s: Record<string, unknown> = {};\n try {\n // A stdin that is JSON but not an object (`null`, a number) is no payload.\n const j: unknown = input.stdin ? JSON.parse(input.stdin) : {};\n if (j && typeof j === \"object\" && !Array.isArray(j)) s = j as Record<string, unknown>;\n } catch {}\n const id = (s.session_id ?? s.sessionId) as string | undefined;\n if (!id) return null;\n if (notClaudeCode(String(id), s)) return null;\n const session: HookResult[\"session\"] = { id: String(id), cwd: typeof s.cwd === \"string\" ? s.cwd : input.cwd };\n if (typeof s.model === \"string\") session.model = s.model;\n if (typeof s.agent_id === \"string\" && event.startsWith(\"Subagent\") === false && s.agent_id)\n session.parent_id = null;\n const turn_id = typeof s.prompt_id === \"string\" ? s.prompt_id : undefined;\n const tool = validTool(s.tool_name) ? s.tool_name : undefined;\n const call_id = typeof s.tool_use_id === \"string\" ? s.tool_use_id : undefined;\n const ms = typeof s.duration_ms === \"number\" ? Math.round(s.duration_ms) : undefined;\n const agent_id = typeof s.agent_id === \"string\" ? s.agent_id : undefined;\n // PermissionRequest carries no tool_use_id (recorded 2026-09-28): the id is a hash\n // of the prompt, the tool and its input, so the same prompt yields the same id and\n // a later control answer can name it.\n const permissionId = () =>\n `perm-${createHash(\"sha256\")\n .update(`${turn_id ?? \"\"}|${tool ?? \"\"}|${JSON.stringify(s.tool_input ?? null)}`)\n .digest(\"hex\")\n .slice(0, 16)}`;\n const ev = (type: string, data: Record<string, unknown>) => ({ type, data: prune(data), harnessEvent: event });\n const events: HookResult[\"events\"] = [];\n switch (event) {\n case \"SessionStart\":\n events.push(ev(\"session.started\", { source: pickSource(s.source ?? s.trigger) }));\n break;\n case \"UserPromptSubmit\": {\n // Only a string prompt is read; anything else is left unread rather than guessed at.\n const prompt = typeof s.prompt === \"string\" ? s.prompt : undefined;\n events.push(\n ev(\"turn.started\", {\n turn_id,\n prompt_chars: prompt === undefined ? undefined : [...prompt].length,\n // Claude Code's hook schema documents `source`\n // (user | sdk | system | loop_wakeup | schedule_wakeup | poll_event) and says a\n // payload may omit it while the field rolls out; 2.1.304's payload has no such\n // key at all. Forwarded verbatim, shape-guarded only: the list is the harness's\n // to extend.\n submitted_by: harnessWord(s.source),\n // One of Claude Code's own prompt wrappers: the prompt is a block the harness\n // wrote, so it is not the person's words. Absent is unknown, never \"the person\" \u2014\n // and `true` is never \"no person caused this turn\", because a Talk or\n // `sessionpipe wait` delivery hands the person's own message over inside a\n // <task-notification> (PROTOCOL.md \u00A74).\n injected: prompt !== undefined && injectedBlock(prompt) ? true : undefined,\n }),\n );\n break;\n }\n case \"PreToolUse\":\n if (tool) events.push(ev(\"tool.started\", { tool, call_id, turn_id, agent_id, input: s.tool_input }));\n break;\n case \"PostToolUse\":\n if (tool)\n events.push(\n ev(\"tool.ended\", {\n tool,\n call_id,\n turn_id,\n agent_id,\n ms,\n ok: true,\n input: s.tool_input,\n output: s.tool_response,\n }),\n );\n break;\n case \"PostToolUseFailure\":\n if (tool)\n events.push(\n ev(\"tool.ended\", {\n tool,\n call_id,\n turn_id,\n agent_id,\n ms,\n ok: false,\n error: errText(s.error ?? s.tool_response),\n input: s.tool_input,\n output: s.tool_response,\n }),\n );\n break;\n case \"PermissionRequest\":\n events.push(\n ev(\"attention.needed\", {\n attention_id: call_id ?? permissionId(),\n kind: \"permission\",\n tool,\n message: tool ? `${tool}${describe(s.tool_input)}` : undefined,\n agent_id,\n }),\n );\n break;\n case \"Notification\":\n events.push(\n ev(\"attention.needed\", {\n attention_id: `notif-${Date.now()}`,\n kind: notifKind(s.notification_type),\n message: typeof s.message === \"string\" ? s.message.slice(0, 200) : undefined,\n agent_id,\n }),\n );\n break;\n case \"Stop\":\n // In-flight background work (shell commands, monitors, subagents, workflows)\n // that will wake the session when it finishes: a paused session, not a done one\n // (Claude Code's `background_tasks`, in every Stop recorded since 2.1.258). A count, never what they run.\n events.push(ev(\"turn.ended\", { turn_id, reason: \"stop\", background: backgroundCount(s.background_tasks) }));\n break;\n case \"StopFailure\":\n // The turn ended on an API error (rate_limit, overloaded, authentication_failed,\n // server_error \u2026); the payload key is `error` (issue #10, recorded 2026-09-28).\n events.push(\n ev(\"turn.ended\", {\n turn_id,\n reason: \"error\",\n error: typeof s.error === \"string\" ? s.error.slice(0, 200) : undefined,\n }),\n );\n break;\n case \"SubagentStart\":\n events.push(\n ev(\"subagent.started\", {\n agent_id: String(s.agent_id ?? \"\"),\n agent_type: typeof s.agent_type === \"string\" ? s.agent_type : undefined,\n }),\n );\n break;\n case \"SubagentStop\":\n // The same list, with this subagent still in it: the count once it is out, so a\n // receiver holding the session as waiting on its work sees the count fall (#153).\n events.push(\n ev(\"subagent.ended\", {\n agent_id: String(s.agent_id ?? \"\"),\n agent_type: typeof s.agent_type === \"string\" ? s.agent_type : undefined,\n background: backgroundCount(s.background_tasks, String(s.agent_id ?? \"\")),\n }),\n );\n break;\n case \"PreCompact\":\n events.push(ev(\"context.compacted\", { trigger: s.trigger === \"manual\" ? \"manual\" : \"auto\" }));\n break;\n case \"PostCompact\":\n break; // PreCompact already said it; a second event would double-count\n case \"SessionEnd\":\n events.push(ev(\"session.ended\", { reason: endReason(s.reason) }));\n break;\n case \"StatusLine\": {\n // Not a hook: our status line command (install --status-line), which hook.ts\n // hands on only when the limits changed.\n const limits = claudeLimits(s.rate_limits);\n if (!limits) return null;\n events.push(ev(\"limits.observed\", limits));\n break;\n }\n default:\n return null;\n }\n const hints: Record<string, unknown> = {};\n // The prompt, for the turn's first turn.progress: the transcript may not hold it\n // yet when the worker runs. Never an event field of its own (tier 2 carries it).\n if (event === \"UserPromptSubmit\" && typeof s.prompt === \"string\") hints.prompt = s.prompt;\n const host = input.env.CLAUDE_CODE_HOST_SESSION_ID;\n if (host && DESKTOP_ID.test(host)) hints.desktop_id = host;\n // Whether a person attends the session, in Claude Code's own word (\"1\" or \"0\" in a hook's\n // environment); a turn the control daemon runs on the person's signed message is theirs.\n // facts() turns it into session.attended once it knows whether the session has a link.\n const attended = input.env.CLAUDE_CODE_SESSION_ATTENDED;\n if (attended === \"1\" || attended === \"0\") hints.attended = attended === \"1\" || !!input.env.SESSIONPIPE_CONTROL_JOB;\n // The registry file is found while the process tree stands (the detached\n // worker's parent is gone by the time it runs). Heartbeat-class events skip it.\n if (event !== \"PreToolUse\" && event !== \"PostToolUse\") hints.claude_pid = claudePid(input.env);\n const r: HookResult = { session, events, hints };\n if (typeof s.transcript_path === \"string\") r.transcript = s.transcript_path;\n return r;\n },\n\n readTranscript(file, fromLine) {\n let text = \"\";\n try {\n text = readFileSync(file, \"utf8\");\n } catch {\n return { turns: [], line: fromLine };\n }\n return readClaude(text.split(\"\\n\"), fromLine);\n },\n\n facts(session, transcript, hints, state): SessionFacts {\n const out: SessionFacts = {};\n if (transcript) Object.assign(out, claudeFacts(transcript, session.id, hints, state));\n const cwd = out.cwd ?? session.cwd;\n Object.assign(out, gitFacts(cwd), out.branch ? { branch: out.branch } : {});\n if (!out.url && typeof hints.desktop_id === \"string\") out.url = `claude://code/continue/${hints.desktop_id}`;\n // A Remote Control session says \"0\" though a person drives it from claude.ai: it runs as a\n // headless child of `claude remote-control`. Its link is what tells it from a `claude -p`;\n // CLAUDE_CODE_ENVIRONMENT_KIND cannot, since a `claude -p` started inside a Remote Control\n // session inherits \"bridge\", while the registry entry it writes has no bridge id of its own.\n if (typeof hints.attended === \"boolean\") out.attended = hints.attended || !!out.url;\n return out;\n },\n\n remoteFacts: (session, local, transcript, state, env = process.env) =>\n claudeRemoteFacts(session.id, local, transcript, state, env),\n\n backfill(sinceMs, env = process.env): BackfillRow[] {\n const rows: BackfillRow[] = [];\n const files: string[] = [];\n for (const d of claudeDirs(env))\n files.push(...recentFiles(path.join(d, \"projects\"), 1, sinceMs, (n) => /^[0-9a-f-]{36}\\.jsonl$/.test(n)));\n const noState: FactsState = { get: () => ({}), save: () => {} };\n for (const f of files) {\n const id = path.basename(f, \".jsonl\");\n const facts = claudeFacts(f, id, {}, noState);\n if (!facts.started_at || !facts.last_at) continue;\n const { started_at, last_at, first_ask: _fa, harness_version: _hv, ...rest } = facts;\n const cwd = rest.cwd;\n rows.push({\n session: { id, ...rest, ...gitFacts(cwd), ...(rest.branch ? { branch: rest.branch } : {}) },\n started_at,\n last_at,\n transcript: f,\n });\n }\n return rows;\n },\n};\n\n/** sessionpipe's own waiter (CONTROL.md \u00A78), which a session runs as a background command\n * to stay reachable: it ends only when a message arrives, so it is not work the session\n * waits on. Matched by its command, whatever path or shim runs it. */\nconst WAITER_RE = /(?:^|[\\s\"'`/\\\\])sessionpipe(?:\\.\\w+)?[\"']?\\s+wait(?:\\s|$)/;\n\n/** How much background work Claude Code lists that will wake the session when it ends\n * (`background_tasks`, in every Stop and SubagentStop since 2.1.258): a count, never what\n * it runs. Not counted: sessionpipe's own waiter, and the subagent whose own stop this is,\n * which Claude Code still lists as running (issue #153). Undefined when the harness\n * doesn't say. */\nexport function backgroundCount(tasks: unknown, ending?: string): number | undefined {\n if (!Array.isArray(tasks)) return undefined;\n return tasks.filter((t) => {\n const task = t as { id?: unknown; command?: unknown } | null;\n if (ending !== undefined && task?.id === ending) return false;\n return !(typeof task?.command === \"string\" && WAITER_RE.test(task.command));\n }).length;\n}\n\n/** Claude Code runs a status line only on events (a new assistant message, a window's\n * reset), and the hook sends at most one change a minute, so a turn's last numbers\n * would wait for the next prompt. The timer runs it again while the session is idle. */\nconst LINE_REFRESH_S = 60;\n\n/** Claude Code hands an account's limits only to its status line command\n * (https://code.claude.com/docs/en/statusline), so with `--status-line` ours is that\n * command. Someone else's status line is never replaced. Null: nothing to report. */\nfunction statusLine(file: string, want: boolean, cmd?: HookCommand): InstallReport | null {\n const f = readJsonFile(file);\n if (!f.ok) return null; // the hooks' report already says why\n const cur = f.value.statusLine as { command?: unknown; refreshInterval?: unknown } | undefined;\n const ours = typeof cur?.command === \"string\" && OURS.test(cur.command);\n const command = cmd?.([NAME, \"StatusLine\"]).command;\n if (want && cur && !ours)\n return { file, changed: false, skipped: true, note: \"a status line of your own is set; limits are not read\" };\n if (want ? ours && cur?.command === command && cur?.refreshInterval === LINE_REFRESH_S : !ours) return null;\n if (want) f.value.statusLine = { type: \"command\", command, refreshInterval: LINE_REFRESH_S };\n else delete f.value.statusLine;\n return (\n writeBack(file, formatJson(f.value, f), f.existed) ?? {\n file,\n changed: true,\n note: want ? \"status line written (account limits)\" : \"status line removed\",\n }\n );\n}\n\n/** Epoch seconds as RFC 3339; anything that is not a plausible time is no time. */\nconst epochIso = (t: unknown): string | undefined =>\n typeof t === \"number\" && t > 0 && t < 1e11 ? new Date(t * 1000).toISOString() : undefined;\n\nconst WINDOW_MINUTES: Record<string, number> = { five_hour: 300, seven_day: 10_080 };\n\n/** The status line's `rate_limits`: `five_hour`, `seven_day` and, behind a gateway,\n * `spend_limit`, each with `used_percentage` and `resets_at` in epoch seconds. Only\n * Pro and Max accounts (or a gateway) have them, and only after a session's first\n * response; a window drops out once it resets. */\nexport function claudeLimits(rl: unknown): DataOf<\"limits.observed\"> | null {\n if (!rl || typeof rl !== \"object\" || Array.isArray(rl)) return null;\n const windows: DataOf<\"limits.observed\">[\"windows\"] = [];\n for (const [id, w] of Object.entries(rl as Record<string, { used_percentage?: unknown; resets_at?: unknown }>)) {\n if (!/^[a-z0-9_]{1,64}$/.test(id) || typeof w?.used_percentage !== \"number\" || w.used_percentage < 0) continue;\n windows.push(\n prune({\n id,\n used_percent: w.used_percentage,\n window_minutes: WINDOW_MINUTES[id],\n resets_at: epochIso(w.resets_at),\n }),\n );\n }\n return windows.length ? { windows: windows.slice(0, 8) } : null;\n}\n\nfunction prune<T extends Record<string, unknown>>(o: T): T {\n for (const k of Object.keys(o)) if (o[k] === undefined) delete o[k];\n return o;\n}\nconst UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n/** Another harness reading this settings file, not Claude Code. Several harnesses\n * import `~/.claude/settings.json` hooks, so our entries there can be run by a tool\n * that has its own adapter: it would arrive under the wrong name, with ids that mean\n * nothing to a Claude Code reader. Every Claude Code payload names a transcript and a\n * UUID session (all 21 recorded fixtures do); a payload with neither is somebody else's. */\nexport function notClaudeCode(id: string, s: Record<string, unknown>): boolean {\n return typeof s.transcript_path !== \"string\" && !UUID.test(id);\n}\nfunction pickSource(v: unknown): string {\n return typeof v === \"string\" && [\"startup\", \"resume\", \"clear\", \"compact\", \"fork\"].includes(v) ? v : \"unknown\";\n}\n/** One of the harness's own words for who submitted a prompt, forwarded as is (PROTOCOL.md\n * \u00A74, `turn.started.submitted_by`). Not an enum of ours: a value we have never seen is\n * still carried, so the guard is the shape the spec allows \u2014 a bare word of at most 40\n * characters, which is all a receiver may show or group by. Tier 0 is not redacted\n * (PRIVACY.md \u00A72), so that shape is the only guard there is. */\nconst harnessWord = (v: unknown): string | undefined =>\n typeof v === \"string\" && /^[A-Za-z0-9][A-Za-z0-9_.-]{0,39}$/.test(v) ? v : undefined;\n/** Claude Code's own prompt wrappers, as a CLOSED list: a task notification, a peer message,\n * a system reminder, a local command's output, a slash command's expansion \u2014 with or\n * without a closing tag, after trimming. Narrower than the reader's `isInjected` on\n * purpose, because the two directions do not cost the same. A wrapper we have not recorded\n * yet reads as unknown and a receiver keeps the turn, which is what it does today; a shape\n * test wide enough to catch every wrapper also fires on a person who pasted nothing but an\n * SVG, an HTML page or a JSX element, and a recency board acting on that would drop one of\n * the person's own turns. Dropping one record from a transcript costs little, which is why\n * the reader's test stays wide; ADAPTERS.md (Claude Code \u00B7 Quirks) says why they differ. */\nconst WRAPPER =\n /^<(?:task-notification|cross-session-message|system-reminder|local-command-stdout|command-[a-z-]+)[\\s/>]/i;\nconst injectedBlock = (prompt: string): boolean => WRAPPER.test(prompt.trim());\nfunction errText(v: unknown): string | undefined {\n if (typeof v === \"string\") return v.slice(0, 2000);\n if (v && typeof v === \"object\") {\n const e = v as { error?: unknown; message?: unknown };\n if (typeof e.error === \"string\") return e.error.slice(0, 2000);\n if (typeof e.message === \"string\") return e.message.slice(0, 2000);\n }\n return undefined;\n}\nfunction describe(input: unknown): string {\n if (!input || typeof input !== \"object\") return \"\";\n const i = input as Record<string, unknown>;\n const v = i.command ?? i.file_path ?? i.path ?? i.url ?? i.pattern;\n return typeof v === \"string\" ? ` ${v.slice(0, 120)}` : \"\";\n}\n\n// --- facts: title, url, model, account, from Claude Code's own files ------------------\n\nconst NAME_RANK: Record<string, \"custom\" | \"harness\"> = {\n user: \"custom\",\n auto: \"harness\",\n hook: \"harness\",\n peer: \"harness\",\n};\ninterface Registry {\n sessionId: string | null;\n name: string | null;\n name_source: \"custom\" | \"harness\" | null;\n bridge: string | null;\n}\nfunction registryEntry(j: unknown): Registry | null {\n if (!j || typeof j !== \"object\") return null;\n const r = j as { sessionId?: unknown; name?: unknown; nameSource?: string; bridgeSessionId?: unknown };\n const source = r.nameSource ? NAME_RANK[r.nameSource] : undefined;\n return {\n sessionId: r.sessionId ? String(r.sessionId) : null,\n name: source && typeof r.name === \"string\" && r.name.trim() ? r.name.trim() : null,\n name_source: source ?? null,\n bridge: typeof r.bridgeSessionId === \"string\" ? r.bridgeSessionId : null,\n };\n}\nconst liveCache = new Map<string, Map<string, Registry>>();\nfunction claudeLive(dir: string): Map<string, Registry> {\n const hit = liveCache.get(dir);\n if (hit) return hit;\n const map = new Map<string, Registry>();\n let names: string[] = [];\n try {\n names = readdirSync(path.join(dir, \"sessions\")).filter((n) => n.endsWith(\".json\"));\n } catch {}\n for (const n of names) {\n try {\n const e = registryEntry(JSON.parse(readFileSync(path.join(dir, \"sessions\", n), \"utf8\")));\n if (e?.sessionId) map.set(e.sessionId, e);\n } catch {}\n }\n liveCache.set(dir, map);\n return map;\n}\nfunction claudeLiveByPid(dir: string, pid: unknown): Registry | null {\n if (!pid) return null;\n try {\n return registryEntry(JSON.parse(readFileSync(path.join(dir, \"sessions\", `${pid}.json`), \"utf8\")));\n } catch {\n return null;\n }\n}\n/** The Claude Code process that ran this hook: the nearest ancestor with a registry\n * file (hooks run under a shell, so usually the parent's parent). */\nexport function claudePid(env: NodeJS.ProcessEnv = process.env): number | null {\n try {\n const dirs = claudeDirs(env);\n const has = (pid: number) => dirs.some((d) => existsSync(path.join(d, \"sessions\", `${pid}.json`)));\n let pid = process.ppid;\n if (has(pid)) return pid;\n const parent = parentOf();\n for (let hop = 0; hop < 6 && pid > 1; hop++) {\n pid = parent(pid);\n if (pid > 1 && has(pid)) return pid;\n }\n } catch {}\n return null;\n}\nfunction parentOf(): (pid: number) => number {\n if (process.platform === \"linux\") {\n return (pid) => {\n try {\n const st = readFileSync(`/proc/${pid}/stat`, \"utf8\");\n return Number(st.slice(st.lastIndexOf(\")\") + 2).split(\" \")[1]) || 0;\n } catch {\n return 0;\n }\n };\n }\n const table = new Map<number, number>();\n try {\n const out = execFileSync(\"ps\", [\"-axo\", \"pid=,ppid=\"], {\n encoding: \"utf8\",\n timeout: 2000,\n maxBuffer: 8 * 1024 * 1024,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n });\n for (const l of out.split(\"\\n\")) {\n const m = /^\\s*(\\d+)\\s+(\\d+)/.exec(l);\n if (m) table.set(Number(m[1]), Number(m[2]));\n }\n } catch {}\n return (pid) => table.get(pid) || 0;\n}\nconst EMAIL_RE = /^[^@\\s]{1,64}@[^@\\s]{1,189}$/;\n/** Who a config dir is signed in as, from its .claude.json (the default dir keeps it\n * at ~/.claude.json): the account id, and the email it signs in with. A dir with no\n * claude.ai login that runs on another API is that API's account (apiAccount). */\nfunction claudeLogin(dir: string, home = homeDir()): { id: string; email?: string; name?: string } | null {\n const files = [path.join(dir, \".claude.json\")];\n if (path.resolve(dir) === path.join(home, \".claude\")) files.unshift(path.join(home, \".claude.json\"));\n for (const f of files) {\n try {\n const a = (\n JSON.parse(readFileSync(f, \"utf8\")) as { oauthAccount?: { accountUuid?: unknown; emailAddress?: unknown } }\n ).oauthAccount;\n if (typeof a?.accountUuid === \"string\" && a.accountUuid) {\n const email = typeof a.emailAddress === \"string\" && EMAIL_RE.test(a.emailAddress) ? a.emailAddress : undefined;\n return { id: a.accountUuid.slice(0, 128), ...(email ? { email } : {}) };\n }\n } catch {}\n }\n return apiAccount(dir);\n}\n/** Anthropic's own API: a key for it is an Anthropic account no local file names. */\nconst ANTHROPIC_HOST = /(^|\\.)anthropic\\.com$/i;\n/** A config dir whose settings send Claude Code to another API (`env.ANTHROPIC_BASE_URL`:\n * Kimi on a Modal endpoint, GLM on Z.ai) has no claude.ai login, so its account is the\n * endpoint: `api-` and 16 hex of the SHA-256 of its origin for events (the same on every\n * machine that uses it), and its host as the name control's pair and hello give it.\n * Only that one key is read; the tokens and headers beside it never are. */\nfunction apiAccount(dir: string): { id: string; name: string } | null {\n const base = (readJson(settingsIn(dir)) as { env?: { ANTHROPIC_BASE_URL?: unknown } }).env?.ANTHROPIC_BASE_URL;\n if (typeof base !== \"string\") return null;\n let u: URL;\n try {\n u = new URL(base.trim());\n } catch {\n return null;\n }\n if ((u.protocol !== \"https:\" && u.protocol !== \"http:\") || !u.hostname || ANTHROPIC_HOST.test(u.hostname))\n return null;\n // The origin alone: a path or a user:password@ can carry a key.\n const origin = `${u.protocol}//${u.host}`;\n return { id: `api-${createHash(\"sha256\").update(origin).digest(\"hex\").slice(0, 16)}`, name: u.host };\n}\nconst accountCache = new Map<string, string | null>();\n/** The account id for `session.account_id`: never the email. Events go to every sink,\n * a team board included; the email (or an API's host) reaches only a receiver the\n * person paired with, in control's pair and hello (claudeAccounts). */\nfunction claudeAccount(dir: string): string | null {\n const hit = accountCache.get(dir);\n if (hit !== undefined) return hit;\n const acct = claudeLogin(dir)?.id ?? null;\n accountCache.set(dir, acct);\n return acct;\n}\n/** Every account signed in across these config dirs, read fresh (a person signs in to\n * another account without restarting anything), for control's pair and hello. */\nexport function claudeAccounts(dirs: string[], home = homeDir()): HarnessAccount[] {\n const out: HarnessAccount[] = [];\n for (const d of dirs) {\n const l = claudeLogin(d, home);\n if (!l) continue;\n const seen = out.find((a) => a.id === l.id);\n if (!seen) out.push({ harness: NAME, ...l });\n else if (!seen.email && l.email) seen.email = l.email;\n }\n return out;\n}\n/** Each config dir with the account it is signed in as, for whoever asks the harness a\n * question per dir (control's hello asks `claude auth status` for each). Dirs naming\n * nobody are left out. */\nexport function claudeAccountDirs(dirs: string[], home = homeDir()): { id: string; dir: string }[] {\n const out: { id: string; dir: string }[] = [];\n for (const d of dirs) {\n const l = claudeLogin(d, home);\n if (l) out.push({ id: l.id, dir: d });\n }\n return out;\n}\nconst LINK_RE = /^https:\\/\\/claude\\.ai\\/code\\/session_[A-Za-z0-9]+$/;\nfunction transcriptLink(records: Record<string, unknown>[]): string | null {\n for (let i = records.length - 1; i >= 0; i--) {\n const j = records[i] as { type?: string; subtype?: string; url?: unknown; bridgeSessionId?: unknown };\n if (j.type === \"system\" && j.subtype === \"bridge_status\" && typeof j.url === \"string\" && LINK_RE.test(j.url))\n return j.url;\n if (j.type === \"bridge-session\" && typeof j.bridgeSessionId === \"string\") {\n const m = /^(?:cse|session)_([A-Za-z0-9]+)$/.exec(j.bridgeSessionId);\n if (m) return `https://claude.ai/code/session_${m[1]}`;\n }\n }\n return null;\n}\n/** A first ask as the Claude Code app titles an untitled session: whitespace\n * collapsed, whole up to 50 characters, else its first 50 and \"...\". */\nexport function appTitle(text: string): string {\n const t = String(text).replace(/\\s+/g, \" \").trim();\n return t.length > 50 ? `${t.slice(0, 50)}...` : t;\n}\nfunction askText(j: Record<string, unknown> | null): string | null {\n if (!j || j.type !== \"user\" || j.isMeta || j.isSidechain) return null;\n const origin = j.origin as { kind?: string } | undefined;\n if (origin?.kind && origin.kind !== \"human\") return null;\n const c = (j.message as { content?: unknown } | undefined)?.content;\n const text = (\n typeof c === \"string\"\n ? c\n : Array.isArray(c)\n ? c\n .filter((b) => b && b.type === \"text\" && typeof b.text === \"string\")\n .map((b) => b.text as string)\n .join(\"\\n\")\n : \"\"\n ).trim();\n if (!text || isInjected(text)) return null;\n return text;\n}\nfunction firstAsk(records: Record<string, unknown>[]): string | null {\n for (const j of records) {\n const t = askText(j);\n if (t) return appTitle(t);\n }\n return null;\n}\nfunction scanTitles(file: string, from: number, found: { custom?: string | null; ai?: string | null }) {\n const out = { custom: found.custom ?? null, ai: found.ai ?? null, upto: from };\n let size = 0;\n try {\n size = statSync(file).size;\n } catch {\n return out;\n }\n if (size < from) {\n out.upto = 0;\n out.custom = out.ai = null;\n from = 0;\n }\n // Only lines carrying a title record are parsed; the rest of the new bytes are skipped.\n let pos = 0;\n scanLines<null>(\n file,\n (l) => {\n pos += Buffer.byteLength(l, \"utf8\") + 1;\n if (pos <= from || l.indexOf('-title\"') < 0) return null;\n try {\n const j = JSON.parse(l) as { type?: string; customTitle?: string; aiTitle?: string };\n if (j.type === \"custom-title\" && j.customTitle) out.custom = j.customTitle;\n if (j.type === \"ai-title\" && j.aiTitle) out.ai = j.aiTitle;\n } catch {}\n return null;\n },\n 512 * 1024 * 1024,\n );\n out.upto = size;\n return out;\n}\n\n/** A session's title and where it came from, best first: /rename (registry \"user\"\n * name or custom-title) \u2192 Claude Code's own title (registry \"auto\" name or\n * ai-title) \u2192 the first ask, marked first-ask so a real title later replaces it. */\nexport function claudeFacts(\n file: string,\n sessionId: string,\n hints: Record<string, unknown>,\n state: FactsState,\n): SessionFacts {\n const { head, tail } = ends(file, 64 * 1024, 256 * 1024);\n const H = parseLines(head);\n const T = parseLines(tail);\n const out: SessionFacts = {};\n const id = sessionId || path.basename(file, \".jsonl\");\n const mem = state.get(NAME, id);\n let custom: string | null = null;\n let ai: string | null = null;\n for (const j of H.concat(T)) {\n if (j.type === \"custom-title\" && typeof j.customTitle === \"string\") custom = j.customTitle;\n if (j.type === \"ai-title\" && typeof j.aiTitle === \"string\") ai = j.aiTitle;\n }\n let size = 0;\n try {\n size = statSync(file).size;\n } catch {}\n if (!custom && !ai && size > 64 * 1024 + 256 * 1024) {\n const s = scanTitles(file, Number(mem.scan_upto) || 0, {\n custom: mem.scan_custom as string | null,\n ai: mem.scan_ai as string | null,\n });\n custom = s.custom;\n ai = s.ai;\n state.save(NAME, id, { scan_upto: s.upto, scan_custom: s.custom, scan_ai: s.ai });\n }\n const dir = configDirOf(file);\n const live = claudeLive(dir).get(id) ?? claudeLiveByPid(dir, hints.claude_pid);\n if (live?.name) state.save(NAME, id, { name: live.name, name_source: live.name_source });\n const bridge =\n live?.bridge && /^session_[A-Za-z0-9]+$/.test(live.bridge) ? `https://claude.ai/code/${live.bridge}` : null;\n const url = bridge ?? transcriptLink(T) ?? transcriptLink(H) ?? (typeof mem.url === \"string\" ? mem.url : null);\n if (url) {\n out.url = url;\n state.save(NAME, id, { url });\n }\n const name = live?.name\n ? { title: live.name, source: live.name_source as \"custom\" | \"harness\" }\n : typeof mem.name === \"string\"\n ? { title: mem.name, source: mem.name_source as \"custom\" | \"harness\" }\n : null;\n const pick =\n (name && name.source === \"custom\" && name) ||\n (custom && { title: custom, source: \"custom\" as const }) ||\n name ||\n (ai && { title: ai, source: \"harness\" as const });\n let ask = typeof mem.first_ask === \"string\" ? mem.first_ask : firstAsk(H);\n if (!ask && size > 64 * 1024 && !mem.first_ask_none) {\n ask = scanLines<string>(file, (l) => {\n try {\n const t = askText(JSON.parse(l) as Record<string, unknown>);\n return t ? appTitle(t) : null;\n } catch {\n return null;\n }\n });\n if (!ask && size > 16 * 1024 * 1024) state.save(NAME, id, { first_ask_none: true });\n }\n if (ask) {\n out.first_ask = ask;\n if (!mem.first_ask) state.save(NAME, id, { first_ask: ask });\n }\n if (pick) {\n out.title = String(pick.title).slice(0, 120);\n out.title_source = pick.source;\n } else if (ask) {\n out.title = ask;\n out.title_source = \"first-ask\";\n }\n const acct = claudeAccount(dir);\n if (acct) out.account_id = acct;\n for (let i = T.length - 1; i >= 0; i--) {\n const m = (T[i] as { message?: { model?: string } }).message?.model;\n if (T[i]?.type === \"assistant\" && m && m !== \"<synthetic>\") {\n out.model = m;\n break;\n }\n }\n const meta = [...T].reverse().find((j) => j.version) ?? H.find((j) => j.version);\n if (meta?.version) out.harness_version = String(meta.version);\n const times = H.concat(T)\n .map((j) => Date.parse(String(j.timestamp ?? \"\")))\n .filter((n) => n > 0);\n if (times.length) {\n out.started_at = Math.min(...times);\n out.last_at = Math.max(...times);\n }\n const withCwd = H.find((j) => typeof j.cwd === \"string\");\n if (withCwd) {\n out.cwd = withCwd.cwd as string;\n if (typeof withCwd.gitBranch === \"string\" && withCwd.gitBranch !== \"HEAD\") out.branch = withCwd.gitBranch;\n }\n return out;\n}\n\n// --- claude.ai's name for a session, only when the person turned it on ------------------\n\n/** claude.ai names a Remote Control session itself, seconds after its first message, and\n * never tells the machine: no file here holds that name, so the Claude app shows one\n * and every local reader another. With `remote_titles` on, the worker asks claude.ai the\n * way Claude Code reads a session. Again after a minute while it has no name yet, then\n * every half hour: a rename in the Claude app reaches the transcript as a custom-title,\n * which outranks this anyway. */\nconst REMOTE_RETRY_MS = 60_000;\nconst REMOTE_REFRESH_MS = 30 * 60_000;\nconst CLAUDE_API = \"https://api.anthropic.com\";\nconst KEYCHAIN = \"Claude Code-credentials\";\n/** The worker holds the session's lock while it asks, and a sibling hook waits 6 s for it. */\nconst REMOTE_TIMEOUT_MS = 3000;\nconst KEYCHAIN_TIMEOUT_MS = 2000;\n/** A session is a few kB; anything past this is not one. */\nconst REMOTE_MAX_BYTES = 1 << 20;\n/** A name as Claude Code itself cleans one: control and bidirectional characters become\n * spaces, runs of space one, the ends trimmed. */\nconst cleanName = (s: string) =>\n s\n .replace(/[\\p{Cc}\\u061C\\u200E\\u200F\\u202A-\\u202E\\u2066-\\u2069]/gu, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n\n/** claude.ai's name for a session with a claude.ai link, unless the person named it\n * here: `{title, title_source: \"harness\"}`, or nothing. */\nexport async function claudeRemoteFacts(\n id: string,\n local: SessionFacts,\n transcript: string | undefined,\n state: FactsState,\n env: NodeJS.ProcessEnv,\n now = Date.now(),\n): Promise<Partial<SessionFacts>> {\n if (!transcript || !local.url || !LINK_RE.test(local.url) || local.title_source === \"custom\") return {};\n const mem = state.get(NAME, id);\n let title = typeof mem.remote_title === \"string\" ? mem.remote_title : null;\n if (now - (Number(mem.remote_at) || 0) >= (title ? REMOTE_REFRESH_MS : REMOTE_RETRY_MS)) {\n // Marked before the call: a claude.ai that doesn't answer isn't asked on every hook.\n state.save(NAME, id, { remote_at: now });\n const token = claudeAiToken(configDirOf(transcript), env, now);\n const got = token ? await claudeAiTitle(local.url.slice(local.url.lastIndexOf(\"/\") + 1), token) : undefined;\n if (got !== undefined) {\n title = got?.slice(0, 200) ?? null;\n state.save(NAME, id, { remote_title: title });\n }\n }\n return title ? { title: title.slice(0, 120), title_source: \"harness\" } : {};\n}\n\n/** The keychain items Claude Code keeps a config dir's sign-in under: `Claude\n * Code-credentials`, and for a CLAUDE_CONFIG_DIR, `-` and 8 hex of the SHA-256 of that\n * path as it was set (tried as the hook's env names it, then as the dir itself). */\nfunction keychainServices(dir: string, env: NodeJS.ProcessEnv): string[] {\n const named = (p: string) =>\n `${KEYCHAIN}-${createHash(\"sha256\").update(p.normalize(\"NFC\")).digest(\"hex\").slice(0, 8)}`;\n const out = new Set<string>();\n if (env.CLAUDE_CONFIG_DIR && path.resolve(env.CLAUDE_CONFIG_DIR) === dir) out.add(named(env.CLAUDE_CONFIG_DIR));\n if (dir === path.join(env.HOME || homeDir(), \".claude\")) out.add(KEYCHAIN);\n out.add(named(dir));\n return [...out];\n}\n\n/** A token this process already read, by config dir, until a minute before it expires:\n * `sessionpipe titles on` asks about every recent session, one `security` each would be\n * slow. In memory only, for the life of the process. */\nconst tokenCache = new Map<string, { token: string; expires: number }>();\n/** The access token Claude Code signed in to `dir` with: from the macOS keychain, else\n * from `<dir>/.credentials.json`. Never written anywhere, never logged. One that has\n * expired is not refreshed, since that would rotate Claude Code's own login: the lookup\n * waits for Claude Code to refresh it. */\nexport function claudeAiToken(dir: string, env: NodeJS.ProcessEnv, now: number): string | null {\n const hit = tokenCache.get(dir);\n if (hit && hit.expires > now + 60_000) return hit.token;\n const raw: string[] = [];\n if (process.platform === \"darwin\")\n for (const service of keychainServices(dir, env)) {\n try {\n const user = env.USER || userInfo().username;\n const account = /^[\\w.-]+$/.test(user) ? user : \"claude-code-user\";\n raw.push(\n execFileSync(\"security\", [\"find-generic-password\", \"-a\", account, \"-w\", \"-s\", service], {\n encoding: \"utf8\",\n timeout: KEYCHAIN_TIMEOUT_MS,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }),\n );\n break;\n } catch {}\n }\n try {\n raw.push(readFileSync(path.join(dir, \".credentials.json\"), \"utf8\"));\n } catch {}\n for (const r of raw) {\n try {\n // Claude Code writes the item as hex (`-X`); `security -w` prints it back as text,\n // or as that hex where it isn't printable.\n const t = r.trim();\n const o = (\n JSON.parse(/^(?:[0-9a-f]{2})+$/i.test(t) ? Buffer.from(t, \"hex\").toString(\"utf8\") : t) as {\n claudeAiOauth?: { accessToken?: unknown; expiresAt?: unknown };\n }\n ).claudeAiOauth;\n if (typeof o?.accessToken !== \"string\" || !o.accessToken) continue;\n const expires = typeof o.expiresAt === \"number\" ? o.expiresAt : Number.POSITIVE_INFINITY;\n if (expires <= now + 60_000) continue;\n tokenCache.set(dir, { token: o.accessToken, expires });\n return o.accessToken;\n } catch {}\n }\n return null;\n}\n\ninterface RemoteSession {\n id?: unknown;\n title?: unknown;\n}\n/** claude.ai's name for the session `bridge` (`session_\u2026`), from the endpoint Claude Code\n * reads a session from: a string, null when it has none yet, undefined when it couldn't\n * be asked or wouldn't say (offline, a 401 or 404, an answer about another session), so\n * the last answer stands. The token goes to api.anthropic.com alone: a redirect is\n * refused, never followed. */\nexport async function claudeAiTitle(bridge: string, token: string): Promise<string | null | undefined> {\n try {\n const r = await fetch(`${CLAUDE_API}/v1/code/sessions/${bridge}`, {\n headers: { Authorization: `Bearer ${token}`, \"anthropic-version\": \"2023-06-01\", \"User-Agent\": \"sessionpipe\" },\n redirect: \"error\",\n signal: AbortSignal.timeout(REMOTE_TIMEOUT_MS),\n });\n if (r.status !== 200 || Number(r.headers.get(\"content-length\")) > REMOTE_MAX_BYTES) return undefined;\n const text = await r.text();\n if (text.length > REMOTE_MAX_BYTES) return undefined;\n // claude.ai answers `{response_shape: {\u2026}}` (conformance/remote/claude-code); Claude Code\n // also reads `session`, and a bare session is taken too. Asked as `session_\u2026`, it names\n // the session `cse_\u2026`: the same one.\n const j = JSON.parse(text) as (RemoteSession & { response_shape?: RemoteSession; session?: RemoteSession }) | null;\n const s = j?.response_shape ?? j?.session ?? j;\n const bare = (x: string) => x.replace(/^(?:session|cse)_/, \"\");\n if (typeof s?.id !== \"string\" || bare(s.id) !== bare(bridge)) return undefined;\n return (typeof s.title === \"string\" && cleanName(s.title)) || null;\n } catch {\n return undefined;\n }\n}\n\n/** For tests: each hook runs in a fresh process; a test that edits the registry mid-run clears the cache. */\nexport const _resetClaudeCaches = (): void => {\n liveCache.clear();\n accountCache.clear();\n tokenCache.clear();\n};\n", "// SPDX-License-Identifier: Apache-2.0\n// Reading the ends of large files, JSON lines, and recent files under a root.\nimport { closeSync, fstatSync, openSync, readdirSync, readSync, statSync } from \"node:fs\";\nimport path from \"node:path\";\n\n/** The first and last bytes of a file, as lines \u2014 a transcript can be tens of MB. */\nexport function ends(file: string, headBytes: number, tailBytes: number): { head: string[]; tail: string[] } {\n let fd: number | undefined;\n try {\n fd = openSync(file, \"r\");\n const size = fstatSync(fd).size;\n const read = (pos: number, len: number) => {\n const b = Buffer.alloc(len);\n const n = readSync(fd as number, b, 0, len, pos);\n return b.subarray(0, n).toString(\"utf8\");\n };\n const head = read(0, Math.min(size, headBytes));\n const tail = size > headBytes ? read(Math.max(0, size - tailBytes), Math.min(size, tailBytes)) : head;\n return { head: head.split(\"\\n\").slice(0, -1), tail: tail.split(\"\\n\").slice(size > headBytes ? 1 : 0) };\n } catch {\n return { head: [], tail: [] };\n } finally {\n if (fd !== undefined)\n try {\n closeSync(fd);\n } catch {}\n }\n}\n\nexport const parseLines = (lines: string[]): Record<string, unknown>[] =>\n lines\n .map((l) => {\n try {\n return JSON.parse(l) as Record<string, unknown>;\n } catch {\n return null;\n }\n })\n .filter((x): x is Record<string, unknown> => !!x);\n\n/** Read line by line up to `cap` bytes, stopping when `visit` returns a value. */\nexport function scanLines<T>(file: string, visit: (line: string) => T | null, cap = 16 * 1024 * 1024): T | null {\n let fd: number | undefined;\n try {\n fd = openSync(file, \"r\");\n const buf = Buffer.alloc(1024 * 1024);\n let pos = 0;\n let rest: Buffer = Buffer.alloc(0);\n while (pos < cap) {\n const n = readSync(fd, buf, 0, buf.length, pos);\n if (!n) break;\n pos += n;\n let chunk = Buffer.concat([rest, buf.subarray(0, n)]);\n let nl = chunk.indexOf(10);\n while (nl >= 0) {\n const r = visit(chunk.subarray(0, nl).toString(\"utf8\"));\n if (r !== null) return r;\n chunk = chunk.subarray(nl + 1);\n nl = chunk.indexOf(10);\n }\n rest = chunk;\n }\n } catch {\n } finally {\n if (fd !== undefined)\n try {\n closeSync(fd);\n } catch {}\n }\n return null;\n}\n\nexport function recentFiles(root: string, depth: number, sinceMs: number, match: (name: string) => boolean): string[] {\n const out: string[] = [];\n const walk = (dir: string, d: number) => {\n let names: import(\"node:fs\").Dirent[] = [];\n try {\n names = readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of names) {\n const p = path.join(dir, e.name);\n if (e.isDirectory()) {\n if (d < depth) walk(p, d + 1);\n continue;\n }\n if (!match(e.name)) continue;\n try {\n if (statSync(p).mtimeMs >= sinceMs) out.push(p);\n } catch {}\n }\n };\n walk(root, 0);\n return out;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// The repo and branch of a folder, from git itself; credentials stripped from the\n// remote. Cached per folder for the life of the process (a worker run).\nimport { execFileSync } from \"node:child_process\";\n\nconst cache = new Map<string, { repo?: string; branch?: string }>();\n\nexport function gitFacts(cwd: string | undefined): { repo?: string; branch?: string } {\n if (!cwd) return {};\n const hit = cache.get(cwd);\n if (hit) return hit;\n const run = (args: string[]) => {\n try {\n return execFileSync(\"git\", [\"-C\", cwd, ...args], {\n encoding: \"utf8\",\n timeout: 1500,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim();\n } catch {\n return \"\";\n }\n };\n const out: { repo?: string; branch?: string } = {};\n const repo = run([\"remote\", \"get-url\", \"origin\"]);\n if (repo) out.repo = stripCredentials(repo);\n const branch = run([\"rev-parse\", \"--abbrev-ref\", \"HEAD\"]);\n if (branch && branch !== \"HEAD\") out.branch = branch;\n cache.set(cwd, out);\n return out;\n}\n\n/** `https://user:token@host/x` \u2192 `https://host/x`; `git@github.com:a/b.git` \u2192 `github.com/a/b`. */\nexport function stripCredentials(url: string): string {\n // The ssh forms first: the `git@` they are known by is what the credential strip removes.\n const ssh = /^(?:ssh:\\/\\/)?git@([^:/]+)[:/](.+?)(?:\\.git)?$/.exec(url);\n if (ssh) return `${ssh[1]}/${ssh[2]}`;\n return url\n .replace(/\\/\\/[^/@]*@/, \"//\")\n .replace(/^https?:\\/\\//, \"\")\n .replace(/\\.git$/, \"\");\n}\n", "// SPDX-License-Identifier: Apache-2.0\n\n/** A thread another thread started \u2014 a subagent, a review \u2014 names a `source.subagent`\n * in its own metadata (the rollout's first record). A fork the person made carries\n * only `forked_from_id`, and is a session of its own. */\nexport function codexSubagent(meta: Record<string, unknown> | null | undefined): boolean {\n if (meta?.type !== \"session_meta\") return false;\n const p = meta.payload as { source?: { subagent?: unknown } } | undefined;\n return !!p?.source?.subagent;\n}\n\n/** A fork starts with its own metadata, then replays the parent's history. Only\n * an event naming the new thread establishes where its own records begin. */\nexport function codexReplayBoundary(meta: Record<string, unknown> | null | undefined) {\n if (meta?.type !== \"session_meta\") return undefined;\n const p = meta.payload as { id?: unknown; forked_from_id?: unknown; source?: { subagent?: unknown } } | undefined;\n if (!p || (!p.forked_from_id && !p.source?.subagent)) return undefined;\n return (record: Record<string, unknown> | null) =>\n typeof p.id === \"string\" &&\n !!p.id &&\n record?.type === \"event_msg\" &&\n (record.payload as { thread_id?: unknown } | undefined)?.thread_id === p.id;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// Transcript readers: complete turns (a person's message + everything the assistant\n// said before the next one), each with the line it ends on, and the line the\n// cursor may advance to once every turn is delivered. Ported from spacesheep-cli\n// lib/memory.js. One reader per harness file format; nothing else is vendor code.\nimport { codexReplayBoundary } from \"../adapters/codex-rollout.js\";\nimport type { TranscriptRead } from \"../adapters/types.js\";\n\ninterface Msg {\n role: \"user\" | \"assistant\";\n text: string;\n at: number;\n line: number;\n /** This ask reached the session from somewhere other than its own keyboard: another\n * local session handed it over, or a channel pushed it, which are the two ways a\n * control daemon reaches a session in place (spec/CONTROL.md \u00A76.3, \u00A78). The words are\n * the person's; the arrival was not. */\n injected?: true;\n}\n\nexport function pairTurns(msgs: Msg[], endLine: number): TranscriptRead {\n const turns: {\n user: string;\n assistant: string;\n at: number;\n startLine: number;\n endLine: number;\n injected?: true;\n }[] = [];\n let cur: (typeof turns)[number] | null = null;\n for (const m of msgs) {\n if (m.role === \"user\") {\n // Never overwrite a prompt that has no reply yet: in an agentic turn the reply\n // comes after tool calls, and a second user record is not a new question.\n if (cur && !cur.assistant) {\n cur.user += `\\n\\n${m.text}`;\n continue;\n }\n if (cur) turns.push(cur);\n cur = {\n user: m.text,\n assistant: \"\",\n at: m.at,\n startLine: m.line,\n endLine: m.line,\n ...(m.injected ? { injected: true as const } : {}),\n };\n } else {\n if (!cur) cur = { user: \"\", assistant: \"\", at: m.at, startLine: m.line, endLine: m.line };\n cur.assistant += (cur.assistant ? \"\\n\\n\" : \"\") + m.text;\n cur.endLine = m.line;\n }\n }\n if (cur?.assistant) turns.push(cur);\n // A user message with no reply yet stays unsent: the cursor stops before it.\n const line = cur && !cur.assistant ? cur.startLine : endLine;\n const out: TranscriptRead = {\n turns: turns.map((t) => ({\n user: t.user,\n assistant: t.assistant,\n at: t.at,\n endLine: t.endLine,\n ...(t.injected ? { injected: true as const } : {}),\n })),\n line,\n };\n if (cur && !cur.assistant && cur.user)\n out.open = { user: cur.user, at: cur.at, ...(cur.injected ? { injected: true as const } : {}) };\n return out;\n}\n\n/** Injected context the person never typed: <tag>\u2026</tag> wrappers (the tag may carry\n * attributes, as Claude Code's `<cross-session-message from=\"\u2026\">` does), HTML comments,\n * slash-command expansions. */\nexport const isInjected = (text: string): boolean =>\n (/^<[a-z_-]+(?:\\s[^>]*)?>/i.test(text) && /<\\/[a-z_-]+>\\s*$/i.test(text)) ||\n /^<!--\\s/.test(text) ||\n /^<command-/.test(text);\n\nconst parse = (raw: string): Record<string, unknown> | null => {\n try {\n return JSON.parse(raw) as Record<string, unknown>;\n } catch {\n return null;\n }\n};\n/** The line after the last whole one. A trailing line that does not parse has no\n * newline yet (a write in progress): the cursor stops before it, or the prompt in\n * it would never be read. */\nconst endOf = (lines: string[]) => {\n const last = lines[lines.length - 1];\n if (last === undefined) return 0;\n return last === \"\" || parse(last) === null ? lines.length - 1 : lines.length;\n};\nconst textParts = (c: unknown, kinds: string[]): string => {\n if (typeof c === \"string\") return c;\n if (!Array.isArray(c)) return \"\";\n return c\n .filter(\n (b) =>\n b &&\n typeof b === \"object\" &&\n kinds.includes((b as { type?: string }).type ?? \"\") &&\n typeof (b as { text?: unknown }).text === \"string\",\n )\n .map((b) => (b as { text: string }).text)\n .join(\"\\n\");\n};\n\n/** An origin whose message is somebody's words rather than the harness talking to\n * itself: `human` is the person at the keyboard, `peer` is a message another local\n * session handed this one \u2014 which is how a control daemon reaches a session in place,\n * so the words in it are the person's too (spec/CONTROL.md \u00A76.3). Older versions wrote\n * no origin at all, which also means the person. */\nconst SPOKEN = new Set([\"human\", \"peer\"]);\n\n/** Claude Code's own preamble around a message from another session: a first line\n * introducing it, and a closing paragraph telling the model what a peer message is and\n * isn't. Neither is anything the person typed. */\nconst PEER_INTRO = /sent a message[^\\n]*:$/;\nconst PEER_OUTRO = \"\\n\\nThis came from another \";\n/** The envelope the sender wraps its text in (cli control/inbox.ts). */\nconst ENVELOPE = /^<cross-session-message\\b[^>]*>\\n([\\s\\S]*)\\n<\\/cross-session-message>$/;\n\n/** What the person actually typed, out of a peer row. Claude Code records the parsed\n * body on the origin when the sender declared its permission class; otherwise the row\n * holds the preamble and the message together, and the preamble is cut off here. A row\n * read without this is a turn whose ask is the harness's own words. */\nexport function peerAsk(origin: unknown, text: string): string {\n const body = (origin as { body?: unknown } | undefined)?.body;\n let t = typeof body === \"string\" && body.trim() ? body : text;\n if (t !== body) {\n const nl = t.indexOf(\"\\n\");\n if (nl > 0 && PEER_INTRO.test(t.slice(0, nl))) t = t.slice(nl + 1);\n const outro = t.indexOf(PEER_OUTRO);\n if (outro > 0) t = t.slice(0, outro);\n }\n return (ENVELOPE.exec(t.trim())?.[1] ?? t).trim();\n}\n\n/** A message sent while a turn was running, absorbed by that turn. Claude Code writes it\n * as an attachment, never as a `user` record: {type:\"attachment\",\n * attachment:{type:\"queued_command\", prompt, commandMode:\"prompt\", origin:{kind:\"human\"}}}.\n * A message from another session is the same record with `origin.kind: \"peer\"` and the\n * text already on its own; a task notification shares it with another `commandMode`.\n * Older versions wrote no origin. */\nconst queuedPrompt = (a: unknown): string => {\n if (!a || typeof a !== \"object\") return \"\";\n const q = a as { type?: unknown; commandMode?: unknown; origin?: { kind?: string }; prompt?: unknown };\n if (q.type !== \"queued_command\" || (q.commandMode ?? \"prompt\") !== \"prompt\") return \"\";\n // Older versions wrote no origin at all, which means the person at the keyboard.\n const kind = q.origin?.kind ?? \"human\";\n if (!SPOKEN.has(kind)) return \"\";\n const text = textParts(q.prompt, [\"text\"]).trim();\n return kind === \"peer\" ? peerAsk(q.origin, text) : text;\n};\n\n/** A channel's message (Claude Code `--channels`: Telegram, sessionpipe's own) as Claude\n * Code records it: {type:\"user\", isMeta:true, origin:{kind:\"channel\", server}, content:\n * `<channel source=\"\u2026\" \u2026>\\n\u2026\\n</channel>`}. The words inside are the person's, sent from\n * elsewhere: the turn's ask. Anything else in that record is nobody's words. */\nconst channelText = (text: string): string => /^<channel\\b[^>]*>([\\s\\S]*)<\\/channel>$/.exec(text)?.[1]?.trim() ?? \"\";\n\n/** Claude Code / Droid: {type:\"user\"|\"assistant\", message:{content}, timestamp, isMeta, isSidechain, origin},\n * plus the person's mid-turn messages (queuedPrompt) and messages from a channel (channelText). */\nexport function readClaude(lines: string[], from: number): TranscriptRead {\n const msgs: Msg[] = [];\n for (let i = from; i < lines.length; i++) {\n const j = lines[i] ? parse(lines[i] as string) : null;\n if (!j || j.isSidechain) continue;\n const origin = j.origin as { kind?: string } | undefined;\n // A message another session handed this one in place is the person's words reaching\n // the session: a turn's ask. Claude Code marks the row `isMeta` because the preamble\n // is the harness's; the ask is not. Two mechanisms deliver one: a channel (#161,\n // `origin.kind === \"channel\"`, the words wrapped in `<channel>`) and the inbox (#150,\n // `origin.kind === \"peer\"`, a framed message `peerAsk` unwraps).\n const channel = j.type === \"user\" && origin?.kind === \"channel\";\n const peer = origin?.kind === \"peer\";\n if (j.type === \"user\" && (j.isCompactSummary || j.repeatsCompactSummary)) continue;\n if (j.type === \"user\" && !channel && !peer && (j.isMeta || (origin?.kind && origin.kind !== \"human\"))) continue;\n const at = Date.parse(String(j.timestamp ?? \"\")) || Date.now();\n const c = (j.message as { content?: unknown } | undefined)?.content;\n if (channel) {\n // Like a peer's: the words are the person's, the arrival was not the keyboard's.\n const text = channelText(textParts(c, [\"text\"]).trim());\n if (text) msgs.push({ role: \"user\", text, at, line: i, injected: true });\n } else if (j.type === \"user\") {\n const raw = textParts(c, [\"text\"]).trim();\n const text = peer ? peerAsk(origin, raw) : raw;\n // The tag test applies to a peer row like any other. `peerAsk` has taken the\n // envelope off already, so what is left is the message itself \u2014 and any local\n // program of this uid can write one, so a body shaped like harness markup must not\n // become a turn whose ask is that markup, published as something the person typed.\n if (!text || isInjected(text)) continue;\n msgs.push({ role: \"user\", text, at, line: i, ...(peer ? { injected: true as const } : {}) });\n } else if (j.type === \"assistant\" && Array.isArray(c)) {\n const text = textParts(c, [\"text\"]).trim();\n if (text) msgs.push({ role: \"assistant\", text, at, line: i });\n } else if (j.type === \"attachment\") {\n const text = queuedPrompt(j.attachment);\n if (text && !isInjected(text)) msgs.push({ role: \"user\", text, at, line: i });\n }\n }\n return pairTurns(msgs, endOf(lines));\n}\n\n/** What Codex writes into a session as a \"user\" message that the person never typed:\n * `<environment_context>` and the like, and the AGENTS.md it read (`# AGENTS.md\n * instructions for <folder>` followed by `<INSTRUCTIONS>`). */\nexport function codexInjected(text: string): boolean {\n return /^<[a-z_-]+>/i.test(text) || /^# AGENTS\\.md instructions\\b/i.test(text);\n}\n\n/** Codex rollout: {type:\"response_item\", payload:{type:\"message\", role, content:[{type:\"input_text\"|\"output_text\", text}]}}. */\nexport function readCodex(lines: string[], from: number): TranscriptRead {\n const msgs: Msg[] = [];\n const boundary = codexReplayBoundary(parse(lines.find((line) => line.trim()) ?? \"\"));\n // Find the boundary from the header even when resuming inside the replay.\n // Keep absolute line numbers: the delivery cursor refers to the original file.\n const start = boundary ? lines.findIndex((line) => boundary(parse(line))) : 0;\n if (start < 0) return pairTurns(msgs, endOf(lines));\n for (let i = Math.max(from, start); i < lines.length; i++) {\n const j = lines[i] ? parse(lines[i] as string) : null;\n if (!j || j.type !== \"response_item\") continue;\n const p = j.payload as { type?: string; role?: string; content?: unknown } | undefined;\n if (!p || p.type !== \"message\") continue;\n const at = Date.parse(String(j.timestamp ?? \"\")) || Date.now();\n const text = textParts(p.content, [\"input_text\", \"output_text\"]).trim();\n if (!text) continue;\n if (p.role === \"user\") {\n if (codexInjected(text)) continue; // Codex's own injections, not the person's words\n msgs.push({ role: \"user\", text, at, line: i });\n } else if (p.role === \"assistant\") msgs.push({ role: \"assistant\", text, at, line: i });\n }\n return pairTurns(msgs, endOf(lines));\n}\n\n/** Gemini CLI chat log: {type:\"user\"|\"gemini\", content|message|text, timestamp}. */\nexport function readGemini(lines: string[], from: number): TranscriptRead {\n const msgs: Msg[] = [];\n for (let i = from; i < lines.length; i++) {\n const j = lines[i] ? parse(lines[i] as string) : null;\n if (!j) continue;\n const role = j.type === \"user\" ? \"user\" : j.type === \"gemini\" || j.type === \"model\" ? \"assistant\" : null;\n if (!role) continue;\n const raw = j.content ?? j.message ?? j.text;\n const text = (typeof raw === \"string\" ? raw : textParts(raw, [\"text\"])).trim();\n if (!text) continue;\n const at = Date.parse(String(j.timestamp ?? \"\")) || Date.now();\n msgs.push({ role, text, at, line: i });\n }\n return pairTurns(msgs, endOf(lines));\n}\n\n/** Antigravity: one step per line, type USER_INPUT | PLANNER_RESPONSE, content with <USER_REQUEST> wrapping. */\nexport function readAntigravity(lines: string[], from: number): TranscriptRead {\n const msgs: Msg[] = [];\n for (let i = from; i < lines.length; i++) {\n const j = lines[i] ? parse(lines[i] as string) : null;\n if (!j || typeof j.content !== \"string\") continue;\n const at = Date.parse(String(j.created_at ?? j.timestamp ?? \"\")) || Date.now();\n if (j.type === \"USER_INPUT\") {\n const m = /<USER_REQUEST>([\\s\\S]*?)(?:<\\/USER_REQUEST>|$)/.exec(j.content);\n const text = (m ? (m[1] as string) : j.content).trim();\n if (text) msgs.push({ role: \"user\", text, at, line: i });\n } else if (j.type === \"PLANNER_RESPONSE\") {\n const text = j.content.trim();\n if (text) msgs.push({ role: \"assistant\", text, at, line: i });\n }\n }\n return pairTurns(msgs, endOf(lines));\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// The hooks file shape Claude Code introduced and Codex, Droid and (with\n// `version: 1`) Cursor and Copilot reuse: {\"hooks\":{\"<Event>\":[{\"matcher\"?,\n// \"hooks\":[{\"type\":\"command\",\"command\",\"timeout\"}]}]}}. Ours is one entry per\n// event; a re-install replaces a stale entry of ours (an old node path) and never\n// touches anyone else's.\n//\n// Two rules from issue #8: a file that is not plain JSON (a comment, a trailing\n// comma, a write in progress) is never written back \u2014 the harness is skipped and\n// the report says why; and a file is written back in its own shape (indent, final\n// newline, a byte-order mark) so uninstall leaves it byte-identical. A file that did not exist before\n// install is reported `created`, and uninstall deletes it once it is empty again.\nimport { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { HookCommand, InstallReport } from \"./types.js\";\n\nexport interface ClaudeShapedOptions {\n /** Which events take a `matcher` (tool and permission events). */\n matcherFor: (event: string) => string | undefined;\n /** Seconds (milliseconds for Gemini CLI). */\n timeout: number;\n /** A longer timeout for one event (Claude Code's PermissionRequest, which may wait\n * for a verified control answer: spec/CONTROL.md \u00A76). */\n timeoutFor?: (event: string) => number | undefined;\n /** Extra top-level keys the file must carry (Cursor/Copilot: version: 1). */\n top?: Record<string, unknown>;\n}\n\n/** A command of ours: a path that contains \"sessionpipe\" and ends in hook.js (or in\n * sessionpipe-hook, the launcher that outlives a node upgrade), then a harness and an event. */\nexport const OURS = /(?:sessionpipe[^\"\\n]*[\\\\/]hook\\.js|[\\\\/]sessionpipe-hook)\"?\\s+[a-z][a-z-]*\\s+[A-Za-z]+\\s*$/;\nexport const isOurs = (h: { hooks?: { command?: string }[] }): boolean =>\n Array.isArray(h?.hooks) && h.hooks.some((x) => typeof x.command === \"string\" && OURS.test(x.command));\n\nexport type JsonFile =\n | {\n ok: true;\n existed: true;\n value: Record<string, unknown>;\n raw: string;\n indent: string;\n eol: string;\n finalNewline: boolean;\n bom: boolean;\n }\n | {\n ok: true;\n existed: false;\n value: Record<string, unknown>;\n raw: \"\";\n indent: \" \";\n eol: \"\\n\";\n finalNewline: true;\n bom: false;\n }\n | { ok: false; existed: true; reason: string };\n\n/** Read a JSON config file with its shape. Never guesses: a parse failure is a\n * refusal to touch the file, not an empty object. */\nexport function readJsonFile(file: string): JsonFile {\n let raw: string;\n try {\n raw = readFileSync(file, \"utf8\");\n } catch {\n return { ok: true, existed: false, value: {}, raw: \"\", indent: \" \", eol: \"\\n\", finalNewline: true, bom: false };\n }\n // A UTF-8 byte-order mark (PowerShell 5's UTF8 encoding, older Windows editors): JSON.parse\n // refuses it, the harnesses read past it. Kept, and written back, like the line ends.\n const bom = raw.charCodeAt(0) === 0xfeff;\n if (bom) raw = raw.slice(1);\n let value: unknown;\n try {\n value = JSON.parse(raw);\n } catch {\n const hint = /^\\s*\\/\\/|\\/\\*/m.test(raw) ? \"not plain JSON (it has comments)\" : \"not plain JSON\";\n return { ok: false, existed: true, reason: hint };\n }\n if (!value || typeof value !== \"object\" || Array.isArray(value))\n return { ok: false, existed: true, reason: \"not a JSON object\" };\n const eol = raw.includes(\"\\r\\n\") ? \"\\r\\n\" : \"\\n\";\n const m = /^( +|\\t+)\\S/m.exec(raw);\n const indent = m?.[1] ?? \" \";\n return {\n ok: true,\n existed: true,\n value: value as Record<string, unknown>,\n raw,\n indent,\n eol,\n finalNewline: /\\r?\\n$/.test(raw),\n bom,\n };\n}\n\n/** Serialise in the file's own shape. */\nexport function formatJson(\n value: unknown,\n f: { indent: string; eol: string; finalNewline: boolean; bom?: boolean },\n): string {\n const text = JSON.stringify(value, null, f.indent).replace(/\\n/g, f.eol);\n return (f.bom ? \"\\uFEFF\" : \"\") + (f.finalNewline ? text + f.eol : text);\n}\n\n/** Back-compat helper for callers that only read. */\nexport function readJson(file: string): Record<string, unknown> {\n const f = readJsonFile(file);\n return f.ok ? f.value : {};\n}\n\n/** The report for a config file the system would not let us change, with the error's\n * code, so `install` and `uninstall` go on to the next file instead of ending on this\n * one. Node opens a file for truncation before it writes, so an error from the open\n * (EACCES; EPERM, which Windows gives a read-only file; EROFS) or from making its\n * folder left the file as it was, and so does a delete refused; the note says so. Only\n * an error from the write itself (ENOSPC, EIO) can have left the file cut short, and\n * that note says to check it instead. */\nfunction refused(\n file: string,\n e: unknown,\n what: \"write\" | \"remove\",\n existed: boolean,\n): InstallReport & { note: string } {\n const { code, syscall } = e as NodeJS.ErrnoException;\n const why = `can't ${what} it (${code ?? String(e)})`;\n if (what === \"remove\" || syscall === \"open\" || syscall === \"mkdir\")\n return { file, changed: false, skipped: true, note: `${why}; not touched` };\n return {\n file,\n changed: true,\n skipped: true,\n ...(existed ? {} : { created: true }),\n note: `${why} part way; check the file before the harness reads it`,\n };\n}\n\n/** Write a config file back, its folder made first. Null once written; otherwise the\n * report for the refusal (see `refused`), which the caller returns in place of its own.\n * `existed` is whether the file was there before: a file cut short is still one\n * sessionpipe made, and the config remembers it as `created`. */\nexport function writeBack(file: string, text: string, existed = true): InstallReport | null {\n try {\n mkdirSync(path.dirname(file), { recursive: true });\n writeFileSync(file, text);\n return null;\n } catch (e) {\n return refused(file, e, \"write\", existed);\n }\n}\n\n/** Remove a config file sessionpipe created and uninstall has emptied. A delete needs\n * the folder's leave where a write needs only the file's, so a delete refused (a\n * ~/.claude owned by root, a folder ACL on Windows) writes the file back empty instead:\n * our hooks come out either way, and the note says what stayed. */\nexport function removeEmptied(file: string, empty: string): InstallReport {\n try {\n unlinkSync(file);\n return { file, changed: true, note: \"removed (sessionpipe created it)\" };\n } catch (e) {\n const bad = refused(file, e, \"remove\", true);\n return (\n writeBack(file, empty) ?? {\n file,\n changed: true,\n note: `emptied; ${bad.note.replace(/; not touched$/, \"\")}, so the empty file stays`,\n }\n );\n }\n}\n\nfunction entryFor(event: string, harness: string, cmd: HookCommand, o: ClaudeShapedOptions) {\n const matcher = o.matcherFor(event);\n return {\n ...(matcher !== undefined ? { matcher } : {}),\n hooks: [{ type: \"command\", command: cmd([harness, event]).command, timeout: o.timeoutFor?.(event) ?? o.timeout }],\n };\n}\n\nexport function installClaudeShaped(\n file: string,\n harness: string,\n events: readonly string[],\n cmd: HookCommand,\n o: ClaudeShapedOptions,\n): InstallReport {\n const f = readJsonFile(file);\n if (!f.ok) return { file, changed: false, skipped: true, note: `${f.reason}; not touched` };\n const settings = f.value;\n const hooks = (settings.hooks && typeof settings.hooks === \"object\" ? settings.hooks : {}) as Record<\n string,\n unknown[]\n >;\n let changed = false;\n const want = new Set(events);\n // Events we no longer hook (a lean install) lose their entry of ours.\n for (const ev of Object.keys(hooks)) {\n if (want.has(ev)) continue;\n const list = Array.isArray(hooks[ev]) ? hooks[ev] : [];\n const kept = list.filter((h) => !isOurs(h as never));\n if (kept.length !== list.length) {\n changed = true;\n if (kept.length) hooks[ev] = kept;\n else delete hooks[ev];\n }\n }\n for (const ev of events) {\n const list = Array.isArray(hooks[ev]) ? hooks[ev] : [];\n const entry = entryFor(ev, harness, cmd, o);\n const mine = list.filter((h) => isOurs(h as never));\n if (mine.length === 1 && JSON.stringify(mine[0]) === JSON.stringify(entry)) continue;\n hooks[ev] = list.filter((h) => !isOurs(h as never)).concat([entry]);\n changed = true;\n }\n if (o.top)\n for (const [k, v] of Object.entries(o.top))\n if (settings[k] !== v) {\n settings[k] = v;\n changed = true;\n }\n if (changed) {\n settings.hooks = hooks;\n const bad = writeBack(file, formatJson(settings, f), f.existed);\n if (bad) return bad;\n }\n return { file, changed, created: !f.existed && changed };\n}\n\nexport function uninstallClaudeShaped(\n file: string,\n events: readonly string[],\n opts: { created?: boolean | undefined } = {},\n): InstallReport {\n if (!existsSync(file)) return { file, changed: false };\n const f = readJsonFile(file);\n if (!f.ok) return { file, changed: false, skipped: true, note: `${f.reason}; not touched` };\n const settings = f.value;\n const hooks = settings.hooks as Record<string, unknown[]> | undefined;\n if (!hooks || typeof hooks !== \"object\") return { file, changed: false };\n let changed = false;\n for (const ev of [...events, ...Object.keys(hooks)]) {\n const list = Array.isArray(hooks[ev]) ? hooks[ev] : [];\n const kept = list.filter((h) => !isOurs(h as never));\n if (kept.length !== list.length) {\n changed = true;\n if (kept.length) hooks[ev] = kept;\n else delete hooks[ev];\n }\n }\n if (!changed) return { file, changed: false };\n if (!Object.keys(hooks).length) delete settings.hooks;\n if (opts.created && !Object.keys(settings).length) return removeEmptied(file, formatJson(settings, f));\n return writeBack(file, formatJson(settings, f)) ?? { file, changed: true };\n}\n\nexport function installedClaudeShaped(\n file: string,\n harness: string,\n events: readonly string[],\n cmd: HookCommand,\n o: ClaudeShapedOptions,\n): \"current\" | \"stale\" | \"missing\" {\n const f = readJsonFile(file);\n const hooks = (f.ok ? (f.value.hooks ?? {}) : {}) as Record<string, unknown[]>;\n let present = 0;\n let current = 0;\n for (const ev of events) {\n const list = Array.isArray(hooks[ev]) ? hooks[ev] : [];\n const mine = list.filter((h) => isOurs(h as never));\n if (mine.length) present++;\n if (mine.length === 1 && JSON.stringify(mine[0]) === JSON.stringify(entryFor(ev, harness, cmd, o))) current++;\n }\n // An entry of ours on an event outside the wanted set (a lean install after a full one) is stale.\n for (const ev of Object.keys(hooks))\n if (!events.includes(ev) && (Array.isArray(hooks[ev]) ? hooks[ev] : []).some((h) => isOurs(h as never)))\n return \"stale\";\n if (!present) return \"missing\";\n return current === events.length ? \"current\" : \"stale\";\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// Any agent that speaks the Agent Client Protocol (agentclientprotocol.com) \u2014 control\n// delivery (spec/CONTROL.md \u00A76, ADAPTERS.md \"Agents driven through ACP\"). One client\n// for all of them: the daemon runs the agent's own CLI as a child, speaks JSON-RPC 2.0\n// over its stdin and stdout (`initialize`, `session/new` or `session/load`,\n// `session/prompt`, `session/cancel`), reads the reply from its `agent_message_chunk`\n// updates, and answers its `session/request_permission` from the machine's mode. The\n// agent names its own session, so the daemon keeps the start's id as its name\n// (CONTROL.md \u00A76 `start`), and keeps the process for the next message (`api` mode).\n// Which agents, and how each is launched, is the ACP registry's word\n// (github.com/agentclientprotocol/registry, 2026-10-22); only one already installed\n// here is ever run. Shapes measured against codex-acp 2.2.2 on 2026-10-22.\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { deniedNote, findBinary, JOB_TIMEOUT_MS, type Mode, shimNote, spawnable } from \"./headless.js\";\n\nexport interface AcpAgent {\n /** sessionpipe's harness name (ADAPTERS.md): the registry's id unless a hook adapter already named it. */\n harness: string;\n /** The registry's id. */\n registry: string;\n label: string;\n /** The CLI's name on PATH. */\n bin: string;\n args: string[];\n}\n\n/** The agents the daemon can drive, with the launch line the registry publishes. */\nexport const ACP_AGENTS: readonly AcpAgent[] = [\n { harness: \"gemini-cli\", registry: \"gemini\", label: \"Gemini CLI\", bin: \"gemini\", args: [\"--acp\"] },\n { harness: \"devin\", registry: \"devin\", label: \"Devin\", bin: \"devin\", args: [\"acp\"] },\n { harness: \"opencode\", registry: \"opencode\", label: \"OpenCode\", bin: \"opencode\", args: [\"acp\"] },\n { harness: \"cursor\", registry: \"cursor\", label: \"Cursor\", bin: \"cursor-agent\", args: [\"acp\"] },\n { harness: \"copilot-cli\", registry: \"github-copilot-cli\", label: \"Copilot CLI\", bin: \"copilot\", args: [\"--acp\"] },\n {\n harness: \"droid\",\n registry: \"factory-droid\",\n label: \"Droid\",\n bin: \"droid\",\n args: [\"exec\", \"--output-format\", \"acp-daemon\"],\n },\n { harness: \"goose\", registry: \"goose\", label: \"goose\", bin: \"goose\", args: [\"acp\"] },\n { harness: \"kilo\", registry: \"kilo\", label: \"Kilo\", bin: \"kilo\", args: [\"acp\"] },\n {\n harness: \"qwen-code\",\n registry: \"qwen-code\",\n label: \"Qwen Code\",\n bin: \"qwen\",\n args: [\"--acp\", \"--experimental-skills\"],\n },\n { harness: \"cline\", registry: \"cline\", label: \"Cline\", bin: \"cline\", args: [\"--acp\"] },\n { harness: \"auggie\", registry: \"auggie\", label: \"Auggie\", bin: \"auggie\", args: [\"--acp\"] },\n { harness: \"kimi\", registry: \"kimi\", label: \"Kimi CLI\", bin: \"kimi\", args: [\"acp\"] },\n { harness: \"amp\", registry: \"amp-acp\", label: \"Amp\", bin: \"amp-acp\", args: [] },\n { harness: \"mistral-vibe\", registry: \"mistral-vibe\", label: \"Mistral Vibe\", bin: \"vibe-acp\", args: [] },\n { harness: \"bob\", registry: \"bob\", label: \"Bob\", bin: \"bob\", args: [\"acp\"] },\n { harness: \"grok-build\", registry: \"grok-build\", label: \"Grok Build\", bin: \"grok\", args: [\"agent\", \"stdio\"] },\n { harness: \"qoder\", registry: \"qoder\", label: \"Qoder CLI\", bin: \"qodercli\", args: [\"--acp\"] },\n { harness: \"minimax-code\", registry: \"minimax-code\", label: \"MiniMax Code\", bin: \"mcode\", args: [\"acp\"] },\n { harness: \"codebuddy-code\", registry: \"codebuddy-code\", label: \"Codebuddy Code\", bin: \"codebuddy\", args: [\"--acp\"] },\n { harness: \"nova\", registry: \"nova\", label: \"Nova\", bin: \"nova\", args: [\"acp\"] },\n { harness: \"dimcode\", registry: \"dimcode\", label: \"DimCode\", bin: \"dim\", args: [\"acp\"] },\n { harness: \"dirac\", registry: \"dirac\", label: \"Dirac\", bin: \"dirac\", args: [\"--acp\"] },\n { harness: \"harn\", registry: \"harn\", label: \"Harn\", bin: \"harn\", args: [\"serve\", \"acp\"] },\n { harness: \"vtcode\", registry: \"vtcode\", label: \"VT Code\", bin: \"vtcode\", args: [\"acp\"] },\n { harness: \"stakpak\", registry: \"stakpak\", label: \"Stakpak\", bin: \"stakpak\", args: [\"acp\"] },\n { harness: \"crow-cli\", registry: \"crow-cli\", label: \"crow-cli\", bin: \"crow-cli\", args: [\"acp\"] },\n { harness: \"corust-agent\", registry: \"corust-agent\", label: \"Corust Agent\", bin: \"corust-agent-acp\", args: [] },\n { harness: \"cortex-code\", registry: \"cortex-code\", label: \"Cortex Code\", bin: \"cortex\", args: [\"acp\", \"serve\"] },\n { harness: \"kimchi\", registry: \"kimchi\", label: \"Kimchi\", bin: \"kimchi\", args: [\"--mode\", \"acp\"] },\n];\n\nexport const ACP_HARNESSES: readonly string[] = ACP_AGENTS.map((a) => a.harness);\n\nexport const acpAgent = (harness: string): AcpAgent | undefined => ACP_AGENTS.find((a) => a.harness === harness);\n\n/** The env var that names an agent's CLI by hand: `SESSIONPIPE_ACP_GEMINI_CLI`. */\nexport const acpOverride = (harness: string): string => `SESSIONPIPE_ACP_${harness.toUpperCase().replace(/-/g, \"_\")}`;\n\n/** An agent's CLI on this machine: the override, else on PATH, else beside the node\n * running this (an `npm install -g` there) or where the installers put it. */\nexport function findAcpAgent(\n harness: string,\n env: NodeJS.ProcessEnv = process.env,\n home = os.homedir(),\n nodeDir = path.dirname(process.execPath),\n): { bin: string; args: string[] } | null {\n const a = acpAgent(harness);\n if (!a) return null;\n const bin = findBinary({\n override: env[acpOverride(harness)],\n names: process.platform === \"win32\" ? [`${a.bin}.exe`, `${a.bin}.cmd`] : [a.bin],\n env,\n dirs: [\n nodeDir,\n path.join(home, \".local\", \"bin\"),\n path.join(home, \".cargo\", \"bin\"),\n \"/opt/homebrew/bin\",\n \"/usr/local/bin\",\n ],\n });\n return bin ? { bin, args: a.args } : null;\n}\n\n/** The ACP agents installed here, by harness name, for the daemon's hello. */\nexport function acpHarnesses(env: NodeJS.ProcessEnv = process.env): string[] {\n return ACP_HARNESSES.filter((h) => findAcpAgent(h, env));\n}\n\ntype Json = Record<string, unknown>;\nconst obj = (v: unknown): Json | null => (v && typeof v === \"object\" && !Array.isArray(v) ? (v as Json) : null);\nconst str = (v: unknown): string => (typeof v === \"string\" ? v : \"\");\n\ninterface Option {\n optionId: string;\n kind: string;\n}\n\n/** Which permission option the machine's mode picks, or null for `cancelled`: safe\n * refuses (once, else always), auto allows (once, else always). Inherit refuses as safe\n * does: the agent asked because its own settings want a person, and none is there.\n * Never the other way. */\nexport function permissionChoice(options: unknown, mode: Mode): Option | null {\n const list = (Array.isArray(options) ? options : [])\n .map(obj)\n .filter((o): o is Json => !!o && !!str(o.optionId))\n .map((o) => ({ optionId: str(o.optionId), kind: str(o.kind) }));\n const want = mode === \"auto\" ? [\"allow_once\", \"allow_always\"] : [\"reject_once\", \"reject_always\"];\n for (const k of want) {\n const hit = list.find((o) => o.kind === k);\n if (hit) return hit;\n }\n return null;\n}\n\n/** A JSON-RPC error in words: its message, and its `data` where that says more (goose\n * 1.55 answers session/new with \"Internal error\" and the reason in `data`). */\nexport function errorWords(err: Json): string {\n const message = str(err.message);\n const data = str(err.data) || str(obj(err.data)?.message);\n return data && data !== message ? (message ? `${message}: ${data}` : data) : message;\n}\n\n/** What a request to run something was called, for the reply's list of refusals. */\nfunction toolName(call: Json | null, titles: Map<string, string>): string | null {\n if (!call) return null;\n const t = str(call.title) || titles.get(str(call.toolCallId)) || str(call.name) || str(call.toolCallId);\n return t ? t.slice(0, 80) : null;\n}\n\n/** A session the daemon holds (the shape of daemon.ts's SdkSession, plus the agent's own id). */\nexport interface AcpHeld {\n /** Deliver one message; resolves with the agent's reply when the turn ends. */\n send(text: string): Promise<{ reply: string; error?: string }>;\n interrupt(): Promise<void>;\n close(): void;\n readonly busy: boolean;\n readonly lastUsed: number;\n readonly mode: \"api\";\n /** The id the agent gave the session. */\n readonly session: string;\n /** The process is gone or was closed: nothing more can be sent. */\n readonly closed: boolean;\n}\n\nexport interface AcpOptions {\n bin: string;\n args: string[];\n cwd: string;\n mode: Mode;\n label: string;\n env?: NodeJS.ProcessEnv;\n /** Reopen this session of the agent's (`session/load`) instead of starting a new one. */\n load?: string;\n /** The reply so far, each time it grows. */\n onText?: (text: string) => void;\n log?: (line: string) => void;\n now?: () => number;\n /** A turn still running after this is cancelled, then stopped. */\n timeoutMs?: number;\n /** How long the agent may take to answer `initialize` and open the session. */\n openTimeoutMs?: number;\n /** On close, how long the agent gets to leave by itself before SIGTERM (then SIGKILL). */\n closeGraceMs?: number;\n}\n\nexport type AcpStart = { held: AcpHeld } | { failed: string } | { unsupported: string };\n\nconst CLIENT_INFO = { name: \"sessionpipe\", title: \"sessionpipe control\", version: \"1\" };\n\n/** Run an ACP agent and open a session in it. Resolves once the agent has answered\n * `session/new` (or `session/load`); every later turn goes through `held.send`. */\nexport function startAcp(o: AcpOptions): Promise<AcpStart> {\n const now = o.now ?? Date.now;\n const log = o.log ?? (() => {});\n const label = o.label;\n let child: ChildProcess;\n const c = spawnable(o.bin, o.args);\n if (!c) return Promise.resolve({ failed: `couldn't start ${label}: ${shimNote(o.bin)}` });\n try {\n child = spawn(c.file, c.args, {\n cwd: o.cwd,\n // The caller's env as given (the daemon's is jobEnv's already, with the ask's\n // lineage on top), marked as a control job.\n env: { ...o.env, SESSIONPIPE_CONTROL_JOB: \"1\" },\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n detached: process.platform !== \"win32\",\n windowsHide: true,\n });\n } catch (e) {\n return Promise.resolve({ failed: `couldn't start ${label}: ${(e as Error).message}` });\n }\n const kill = (sig: NodeJS.Signals) => {\n try {\n if (process.platform !== \"win32\" && child.pid) process.kill(-child.pid, sig);\n else child.kill(sig);\n } catch {}\n };\n\n let gone: string | null = null; // why the process is no longer there\n let errTail = \"\";\n let nextId = 1;\n const pending = new Map<number, { resolve: (r: unknown) => void; reject: (e: Error) => void }>();\n const write = (m: Json) => {\n if (gone) return;\n try {\n child.stdin?.write(`${JSON.stringify(m)}\\n`);\n } catch {}\n };\n const request = (method: string, params: Json, timeoutMs: number): Promise<unknown> =>\n new Promise((resolve, reject) => {\n if (gone) return reject(new Error(gone));\n const id = nextId++;\n const t = setTimeout(() => {\n pending.delete(id);\n reject(new Error(`${label} didn't answer ${method} in ${Math.round(timeoutMs / 1000)} s`));\n }, timeoutMs);\n t.unref();\n pending.set(id, {\n resolve: (r) => {\n clearTimeout(t);\n resolve(r);\n },\n reject: (e) => {\n clearTimeout(t);\n reject(e);\n },\n });\n write({ jsonrpc: \"2.0\", id, method, params });\n });\n const notify = (method: string, params: Json) => write({ jsonrpc: \"2.0\", method, params });\n\n // The turn in flight: its reply as it grows, and what it was refused.\n // `message`: the id of the chunk before, null for one that had none, undefined before any.\n let turn: { text: string; message?: string | null; denied: string[]; count: number } | null = null;\n const titles = new Map<string, string>();\n const onUpdate = (u: Json | null) => {\n if (!u) return;\n const kind = str(u.sessionUpdate);\n if (kind === \"tool_call\" && str(u.toolCallId) && str(u.title)) {\n if (titles.size >= 200) titles.clear();\n titles.set(str(u.toolCallId), str(u.title));\n return;\n }\n if (kind !== \"agent_message_chunk\" || !turn) return;\n const c = obj(u.content);\n if (c?.type !== \"text\" || !str(c.text)) return;\n // A new message after a tool step starts a new paragraph.\n const mid = str(u.messageId) || null;\n if (turn.message !== undefined && mid !== turn.message && turn.text.trim())\n turn.text = `${turn.text.trimEnd()}\\n\\n`;\n turn.message = mid;\n turn.text += str(c.text);\n o.onText?.(turn.text);\n };\n const onRequest = (id: unknown, method: string, params: Json | null) => {\n if (method !== \"session/request_permission\") {\n write({ jsonrpc: \"2.0\", id: id as string, error: { code: -32601, message: `Method not found: ${method}` } });\n return;\n }\n const pick = permissionChoice(params?.options, o.mode);\n if (!pick?.kind.startsWith(\"allow\")) {\n const name = toolName(obj(params?.toolCall), titles);\n if (turn) {\n turn.count++;\n if (name && !turn.denied.includes(name) && turn.denied.length < 20) turn.denied.push(name);\n }\n }\n write({\n jsonrpc: \"2.0\",\n id: id as string,\n result: { outcome: pick ? { outcome: \"selected\", optionId: pick.optionId } : { outcome: \"cancelled\" } },\n });\n };\n const onLine = (line: string) => {\n let m: Json | null;\n try {\n m = obj(JSON.parse(line));\n } catch {\n return;\n }\n if (!m) return;\n const method = str(m.method);\n if (method) {\n if (m.id !== undefined) onRequest(m.id, method, obj(m.params));\n else if (method === \"session/update\") onUpdate(obj(obj(m.params)?.update));\n return;\n }\n const p = typeof m.id === \"number\" ? pending.get(m.id) : undefined;\n if (!p) return;\n pending.delete(m.id as number);\n const err = obj(m.error);\n if (err) p.reject(new Error(errorWords(err) || `${label} returned error ${String(err.code ?? \"?\")}`));\n else p.resolve(m.result);\n };\n let partial = \"\";\n child.stdout?.on(\"data\", (b: Buffer) => {\n const lines = (partial + b.toString(\"utf8\")).split(\"\\n\");\n partial = lines.pop() as string;\n for (const l of lines) if (l.trim()) onLine(l);\n if (partial.length > 4 * 1024 * 1024) partial = \"\";\n });\n child.stderr?.on(\"data\", (b: Buffer) => {\n errTail = (errTail + b.toString(\"utf8\")).slice(-4000);\n });\n const left = (why: string) => {\n if (gone) return;\n gone = why;\n for (const p of pending.values()) p.reject(new Error(why));\n pending.clear();\n };\n child.on(\"error\", (e) => left(`couldn't start ${label}: ${e.message}`));\n const exited = (code: number | null, signal: NodeJS.Signals | null) => {\n const tail = errTail.trim().split(\"\\n\").slice(-3).join(\" \").trim();\n left(`${label} exited (${signal || `code ${code}`})${tail ? `: ${tail}` : \"\"}`);\n };\n child.on(\"exit\", exited);\n // A tool the agent left running can hold its stdout open after it exited; `close`\n // is also the end for a process that never started.\n child.on(\"close\", exited);\n\n let closed = false;\n const close = () => {\n if (closed) return;\n closed = true;\n try {\n child.stdin?.end();\n } catch {}\n const grace = o.closeGraceMs ?? 2000;\n const t = setTimeout(() => kill(\"SIGTERM\"), grace);\n t.unref();\n const k = setTimeout(() => kill(\"SIGKILL\"), grace * 6);\n k.unref();\n child.once(\"exit\", () => {\n clearTimeout(t);\n clearTimeout(k);\n });\n };\n\n const open = o.openTimeoutMs ?? 60_000;\n\n function held(session: string): AcpHeld {\n let busy = false;\n let lastUsed = now();\n return {\n session,\n mode: \"api\",\n get busy() {\n return busy;\n },\n get lastUsed() {\n return lastUsed;\n },\n get closed() {\n return closed || !!gone;\n },\n async send(text) {\n if (closed) return { reply: \"\", error: `${label} was closed` };\n busy = true;\n lastUsed = now();\n const t = { text: \"\", denied: [], count: 0 };\n turn = t;\n const limit = o.timeoutMs ?? JOB_TIMEOUT_MS;\n let timedOut = false;\n const timer = setTimeout(() => {\n timedOut = true;\n notify(\"session/cancel\", { sessionId: session });\n setTimeout(close, 5000).unref();\n }, limit);\n timer.unref();\n try {\n const res = obj(\n await request(\"session/prompt\", { sessionId: session, prompt: [{ type: \"text\", text }] }, limit + 10_000),\n );\n const stop = str(res?.stopReason);\n const words = t.text.trim() || `(${label} finished without a written reply.)`;\n const refused = deniedNote(t.denied, t.count);\n if (stop === \"end_turn\" || stop === \"max_tokens\") return { reply: words + refused };\n if (stop === \"refusal\") return { reply: `${words}\\n\\n(${label} refused the request.)${refused}` };\n if (stop === \"cancelled\")\n return timedOut\n ? {\n reply: \"\",\n error: `${label} was still working after ${Math.round(limit / 60_000)} minutes, so it was stopped`,\n }\n : { reply: `${words}\\n\\n(The turn was cancelled.)${refused}` };\n return { reply: \"\", error: `${label} ended the turn with ${stop || \"no stop reason\"}` };\n } catch (e) {\n return { reply: \"\", error: (e as Error).message };\n } finally {\n clearTimeout(timer);\n turn = null;\n busy = false;\n lastUsed = now();\n }\n },\n async interrupt() {\n notify(\"session/cancel\", { sessionId: session });\n },\n close,\n };\n }\n\n return (async (): Promise<AcpStart> => {\n let signIn = \"\";\n try {\n const init = obj(\n await request(\n \"initialize\",\n {\n protocolVersion: 1,\n clientCapabilities: { fs: { readTextFile: false, writeTextFile: false }, terminal: false },\n clientInfo: CLIENT_INFO,\n },\n open,\n ),\n );\n const caps = obj(init?.agentCapabilities);\n const info = obj(init?.agentInfo);\n log(\n `${label}: ${str(info?.name) || \"agent\"} ${str(info?.version)} (ACP ${String(init?.protocolVersion ?? \"?\")})`,\n );\n // An agent that lists ways to sign in may refuse a session until someone did, at\n // the machine's terminal: the daemon never signs in for anyone. The agent's own\n // words for the first way, when it gives any (goose: \"Run `goose configure` \u2026\").\n const methods = Array.isArray(init?.authMethods) ? init.authMethods.map(obj) : [];\n if (methods.length) {\n const how = str(methods[0]?.description) || str(methods[0]?.name);\n signIn = ` (if ${label} wants a sign-in, do it at the machine's terminal${how ? `: ${how}` : \"\"})`;\n }\n if (o.load) {\n if (!caps?.loadSession) {\n close();\n return { unsupported: `${label} can't reopen a session once it has been closed (no session/load)` };\n }\n await request(\"session/load\", { sessionId: o.load, cwd: o.cwd, mcpServers: [] }, open);\n return { held: held(o.load) };\n }\n const res = obj(await request(\"session/new\", { cwd: o.cwd, mcpServers: [] }, open));\n const session = str(res?.sessionId);\n if (!session) throw new Error(`${label} opened a session without naming it`);\n return { held: held(session) };\n } catch (e) {\n close();\n return { failed: `${(e as Error).message}${signIn}` };\n }\n })();\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// One headless agent turn as a child process (spec/CONTROL.md \u00A76): the spawner the\n// control daemon runs every harness through, and the shape each harness's reading of\n// its own output takes. Which binary, which flags and how the answer is read are the\n// harness's own (`<harness>-control.ts`); what is the same for all of them is here.\nimport { spawn } from \"node:child_process\";\nimport { accessSync, constants, readFileSync, statSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { withoutLineage } from \"../launched-by.js\";\n\n/** A headless turn still running after this is stopped. */\nexport const JOB_TIMEOUT_MS = 30 * 60_000;\nconst OUT_CAP = 1024 * 1024;\n\n/** How a turn the daemon runs may act (spec/CONTROL.md \u00A72), chosen at the machine's own\n * terminal: safe, the harness's auto mode, or inherit (no permission flag, so the\n * harness starts in its own default on this machine). */\nexport type Mode = \"safe\" | \"auto\" | \"inherit\";\n\nexport function isExe(p: string): boolean {\n try {\n if (!statSync(p).isFile()) return false;\n accessSync(p, constants.X_OK);\n return true;\n } catch {\n return false;\n }\n}\n\n/** A harness's CLI: the override the person set (`SESSIONPIPE_<NAME>`), else the first\n * of `names` on PATH, else the first of `dirs` that holds one. A launchd or systemd\n * service starts with a short PATH, so the installers' own folders are looked in too. */\nexport function findBinary(o: {\n override?: string | undefined;\n names: string[];\n dirs: string[];\n env?: NodeJS.ProcessEnv;\n}): string | null {\n if (o.override && isExe(o.override)) return o.override;\n for (const d of String(o.env?.PATH || \"\").split(path.delimiter)) {\n if (!d || !path.isAbsolute(d)) continue;\n for (const n of o.names) if (isExe(path.join(d, n))) return path.join(d, n);\n }\n for (const d of o.dirs) for (const n of o.names) if (isExe(path.join(d, n))) return path.join(d, n);\n return null;\n}\n\n/** The script an npm-style `.cmd` shim runs: the one `\"%dp0%\\\\\u2026\"` or `\"%~dp0\\\\\u2026\"` word\n * before `%*` (npm's cmd-shim, old and new; pnpm's is the same shape), beside the shim.\n * Null when the file is no such shim, or names nothing that is there. */\nexport function shimTarget(shim: string): string | null {\n let text = \"\";\n try {\n text = readFileSync(shim, \"utf8\");\n } catch {\n return null;\n }\n const m = /\"%(?:~dp0|dp0%)\\\\([^\"]+)\"\\s+%\\*/.exec(text);\n if (!m) return null;\n const target = path.resolve(path.dirname(shim), (m[1] as string).split(\"\\\\\").join(path.sep));\n try {\n return statSync(target).isFile() ? target : null;\n } catch {\n return null;\n }\n}\n\n/** `bin` and `args` as spawn takes them with no shell. Node refuses to spawn a `.cmd` or\n * `.bat` without one (CVE-2024-27980, since 20.12), and on Windows an `npm install -g`\n * leaves exactly such a shim (`claude.cmd`, `codex.cmd`); a shell would hand a prompt's\n * every character to cmd.exe, so the shim's own script runs under this node instead.\n * Null for a launcher script that names no script to run (issue #165). */\nexport function spawnable(bin: string, args: string[]): { file: string; args: string[] } | null {\n if (!/\\.(cmd|bat)$/i.test(bin)) return { file: bin, args };\n const target = shimTarget(bin);\n return target ? { file: process.execPath, args: [target, ...args] } : null;\n}\n\n/** Why a launcher script can't be run, for the person. */\nexport const shimNote = (bin: string) =>\n `${path.basename(bin)} is a launcher script that names no program to run; point the harness's override (SESSIONPIPE_CLAUDE, SESSIONPIPE_CODEX, \u2026) at the program itself`;\n\n/** As `spawnable`, for a probe whose arguments are fixed words (`--help`, `auth status`):\n * a launcher script that can't be read runs through a shell, as one quoted command\n * (arguments beside `shell: true` are deprecated from node 24, DEP0190). */\nexport function probe(bin: string, args: string[]): { file: string; args: string[]; shell: boolean } {\n const s = spawnable(bin, args);\n return s ? { ...s, shell: false } : { file: [`\"${bin}\"`, ...args].join(\" \"), args: [], shell: true };\n}\n\n/** The env every headless turn runs with: SESSIONPIPE_CONTROL_JOB tells the turn's own\n * hooks that the daemon runs it, so its Stop hook never takes a message meant for a\n * person's session (cli/src/hook.ts); and none of the lineage this process inherited\n * (a daemon started from inside an asked session), so a child carries only what its\n * caller adds after this (CONTROL.md \u00A713). */\nexport function jobEnv(env: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv {\n return { ...withoutLineage(env), SESSIONPIPE_CONTROL_JOB: \"1\" };\n}\n\n/** Whether a harness is signed in, in its own words. `loggedIn: null` means it can't\n * say (too old, or it didn't answer): never a reason to refuse. */\nexport interface Login {\n loggedIn: boolean | null;\n /** claude.ai, an API key, a long-lived token\u2026 as the harness names it. */\n method?: string;\n subscription?: string;\n}\n\nexport interface RunResult {\n error?: string;\n code?: number | null;\n signal?: NodeJS.Signals | null;\n stdout?: string | null;\n tooBig?: boolean;\n stderr?: string;\n timedOut?: boolean;\n}\n\nexport interface RunOptions {\n cwd: string;\n env: NodeJS.ProcessEnv;\n timeoutMs?: number;\n /** Streaming: each stdout line as it arrives. Only the lines `keep` names are kept\n * for the RunResult (none by default), so a long stream never hits the cap. */\n onLine?: (line: string) => void;\n keep?: (line: string) => boolean;\n}\n\n/** Run one headless turn in its own process group, stdin closed (Codex waits on an open\n * one), holding at most 1 MB of stdout. */\nexport function runHeadless(bin: string, args: string[], o: RunOptions): Promise<RunResult> {\n return new Promise((resolve) => {\n let out: Buffer[] = [];\n let outLen = 0;\n let tooBig = false;\n let errTail = \"\";\n let timedOut = false;\n let settled = false;\n let child: import(\"node:child_process\").ChildProcess;\n const c = spawnable(bin, args);\n if (!c) {\n resolve({ error: shimNote(bin) });\n return;\n }\n try {\n child = spawn(c.file, c.args, {\n cwd: o.cwd,\n env: o.env,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n detached: process.platform !== \"win32\",\n windowsHide: true,\n });\n } catch (e) {\n resolve({ error: (e as Error).message });\n return;\n }\n const kill = (sig: NodeJS.Signals) => {\n try {\n if (process.platform !== \"win32\" && child.pid) process.kill(-child.pid, sig);\n else child.kill(sig);\n } catch {\n try {\n child.kill(sig);\n } catch {}\n }\n };\n const keep = (line: string) => {\n if (!o.keep?.(line)) return;\n out = [Buffer.from(line)];\n outLen = line.length;\n };\n let partial = \"\";\n child.stdout?.on(\"data\", (b: Buffer) => {\n if (o.onLine) {\n const chunk = partial + b.toString(\"utf8\");\n const lines = chunk.split(\"\\n\");\n partial = lines.pop() as string;\n for (const line of lines) {\n if (!line.trim()) continue;\n try {\n o.onLine(line);\n } catch {}\n keep(line);\n }\n if (partial.length > OUT_CAP) partial = \"\";\n return;\n }\n if (tooBig) return;\n if (outLen + b.length > OUT_CAP) {\n tooBig = true;\n out = [];\n return;\n }\n out.push(b);\n outLen += b.length;\n });\n child.stderr?.on(\"data\", (b: Buffer) => {\n errTail = (errTail + b.toString(\"utf8\")).slice(-4000);\n });\n const timer = setTimeout(() => {\n timedOut = true;\n kill(\"SIGTERM\");\n setTimeout(() => kill(\"SIGKILL\"), 10_000).unref();\n }, o.timeoutMs ?? JOB_TIMEOUT_MS);\n const result = (code: number | null, signal: NodeJS.Signals | null): RunResult => ({\n code,\n signal,\n stdout: tooBig ? null : Buffer.concat(out).toString(\"utf8\"),\n tooBig,\n stderr: errTail,\n timedOut,\n });\n const finish = (r: RunResult) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(r);\n };\n child.on(\"error\", (e) => finish({ error: e.message }));\n // A tool the agent left running can hold stdout open after the harness exits.\n child.on(\"exit\", (code, signal) => setTimeout(() => finish(result(code, signal)), 2000).unref());\n child.on(\"close\", (code, signal) => {\n // The last line may end without a newline: it is often the result itself.\n if (o.onLine && partial.trim()) {\n try {\n o.onLine(partial);\n } catch {}\n keep(partial);\n partial = \"\";\n }\n finish(result(code, signal));\n });\n });\n}\n\n/** A harness's output read as it streams: the session it names, the answer so far, and\n * the outcome once the process is gone. One per run. */\nexport interface Reading {\n /** One stdout line. True when the answer so far changed. */\n feed(line: string): boolean;\n /** The session id the harness revealed (it picks its own), or null so far. */\n readonly session: string | null;\n /** The answer so far, whole. */\n readonly text: string;\n /** How many lines were fed. */\n readonly lines: number;\n outcome(res: RunResult): { failed: string } | { reply: string };\n}\n\n/** The last few lines a harness wrote to stderr, on one line. */\nexport function stderrTail(stderr: string | undefined, n = 3): string {\n return String(stderr || \"\")\n .trim()\n .split(\"\\n\")\n .slice(-n)\n .join(\" \")\n .trim();\n}\n\n/** What a run that wasn't there to ask says about the actions it was refused. */\nexport function deniedNote(names: string[], count: number): string {\n if (!count) return \"\";\n return `\\n\\n(Not allowed on this machine, since nobody was there to approve: ${names.join(\", \") || `${count} action(s)`}.)`;\n}\n\n/** A process that failed before or without its answer, in words. */\nexport function runFailure(label: string, res: RunResult): string | null {\n if (res.error) return `couldn't start ${label}: ${res.error}`;\n if (res.timedOut) return `${label} was still working after 30 minutes, so it was stopped`;\n return null;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// The two session fields every harness shares and no hook payload carries: who started\n// this session on purpose, and which session it answers. Both come from the environment\n// the session was started in, and the hook carries them along (PROTOCOL.md \u00A73).\nimport type { Adapter, HookInput, HookResult } from \"./adapters/types.js\";\n\n/** PROTOCOL.md \u00A73 `launched_by`: a launcher that starts a session for another one (a\n * script running `claude -p`) names itself here as `<harness>:<id>`, and the hook\n * carries it along. */\nexport const LAUNCHED_BY_ENV = \"SESSIONPIPE_LAUNCHED_BY\";\n/** PROTOCOL.md \u00A73 `delegated_by`: the control daemon that starts or resumes a session\n * for another session's ask (CONTROL.md \u00A713) or a handoff (\u00A76) names that session\n * here, and the child's hooks stamp it on every event. */\nexport const DELEGATED_BY_ENV = \"SESSIONPIPE_ASKED_BY\";\n/** CONTROL.md \u00A713: the asks a session is nested in, comma-joined, read by the next ask. */\nexport const ASK_CHAIN_ENV = \"SESSIONPIPE_ASK_CHAIN\";\n/** The three lineage variables. They are inherited like any environment, so anything\n * that starts a further session resets them (PROTOCOL.md \u00A73, CONTROL.md \u00A713); the\n * daemon most of all, which starts sessions for receivers and askers alike and must\n * not stamp its own shell's lineage on them. */\nexport const LINEAGE_ENV = [LAUNCHED_BY_ENV, DELEGATED_BY_ENV, ASK_CHAIN_ENV] as const;\nconst SESSION_REF = /^[a-z][a-z0-9-]{0,39}:[A-Za-z0-9._:-]{1,128}$/;\n\n/** `env` without the lineage variables: what a child that is nobody's gets. */\nexport function withoutLineage(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n const e = { ...env };\n for (const k of LINEAGE_ENV) delete e[k];\n return e;\n}\n\n/** The `<harness>:<id>` a variable names, or nothing when it is absent or malformed. */\nfunction refIn(env: Record<string, string | undefined>, name: string): string | undefined {\n const v = env[name]?.trim();\n return v && SESSION_REF.test(v) ? v : undefined;\n}\n\n/** The launcher the environment names, or nothing when it is absent or malformed. */\nexport function launchedBy(env: Record<string, string | undefined>): string | undefined {\n return refIn(env, LAUNCHED_BY_ENV);\n}\n\n/** The session this one was started or resumed for, or nothing when the environment\n * doesn't say or says it badly. */\nexport function delegatedBy(env: Record<string, string | undefined>): string | undefined {\n return refIn(env, DELEGATED_BY_ENV);\n}\n\n/** An adapter's reading of a hook, plus what every harness shares: the launcher and the\n * asker, unless the harness gave the session a parent of its own (a subagent's lineage\n * is its parent, which carries both) or the value names the session itself (a\n * launcher that forgot to reset it). */\nexport function readHook(adapter: Adapter, input: HookInput): HookResult | null {\n const r = adapter.fromHook(input);\n if (r && !r.session.parent_id) {\n const self = `${adapter.name}:${r.session.id}`;\n const launcher = launchedBy(input.env);\n if (launcher && launcher !== self) r.session.launched_by = launcher;\n const asker = delegatedBy(input.env);\n if (asker && asker !== self) r.session.delegated_by = asker;\n }\n return r;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// Antigravity (Google) \u2014 docs: https://antigravity.google/docs/hooks\n// Config: ~/.gemini/config/hooks.json \u2014 top-level keys are hook NAMES, ours is\n// \"sessionpipe\". stdin is camelCase with NO event name (it rides in argv). A hook's\n// stdout is its answer; non-JSON is a deny. Timeouts in seconds. No session end\n// exists. Ported from spacesheep-cli lib/sessions.js (facts, remote url, projects).\n//\n// No PreToolUse. Its answer must carry a `decision` (allow / deny / ask / force_ask),\n// none of which means \"carry on\": `{}` is read as a deny with no reason, which blocked\n// every tool call on every machine 0.1\u20130.6.0 was installed on (2026-10-04, Antigravity\n// 2.19.1), and `allow` would wave calls past the person's own review settings. So the\n// tool events come from PostToolUse alone, which carries no tool name (only `stepIdx`\n// and `error`): it is a \"still working\" beat.\nimport { existsSync, readdirSync, readFileSync, realpathSync, statSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { homeDir } from \"../paths.js\";\nimport { ends, parseLines } from \"../readers/files.js\";\nimport { readAntigravity } from \"../readers/transcripts.js\";\nimport { formatJson, readJsonFile, removeEmptied, writeBack } from \"./claude-shaped.js\";\nimport type {\n Adapter,\n BackfillRow,\n HookCommand,\n HookInput,\n HookResult,\n InstallOptions,\n InstallReport,\n SessionFacts,\n} from \"./types.js\";\n\nconst NAME = \"antigravity\";\nconst HOOK_NAME = \"sessionpipe\";\nexport const AG_EVENTS = [\"PreInvocation\", \"PostInvocation\", \"PostToolUse\", \"Stop\"] as const;\n/** What a PreToolUse entry an older install left behind gets, until a restarted\n * conversation reads the rewritten hooks.json: the person's own prompt, with why. The\n * hook (cli/src/hook.ts) and the launcher (cli/src/launcher.ts) print the same line. */\nexport const AG_STALE_PRETOOL =\n '{\"decision\":\"ask\",\"reason\":\"sessionpipe: an outdated PreToolUse hook is still loaded. Restart this conversation (or run sessionpipe install) to drop it.\"}\\n';\n/** Antigravity's answer for one event: `{}` is \"carry on\" for every event we register. */\nexport const antigravityAnswer = (event: string): string => (event === \"PreToolUse\" ? AG_STALE_PRETOOL : \"{}\\n\");\nconst gemini = (env: NodeJS.ProcessEnv) => env.GEMINI_CLI_HOME || path.join(homeDir(), \".gemini\");\nconst hooksFile = (env: NodeJS.ProcessEnv) => path.join(gemini(env), \"config\", \"hooks.json\");\nconst projectsDir = (env: NodeJS.ProcessEnv) => path.join(gemini(env), \"config\", \"projects\");\nconst dataDirs = (env: NodeJS.ProcessEnv) =>\n [\"antigravity\", \"antigravity-cli\", \"antigravity-ide\"].map((d) => path.join(gemini(env), d));\nconst ID_RE = /^[A-Za-z0-9_-]{1,128}$/;\nconst validTool = (n: unknown): n is string => typeof n === \"string\" && /^[A-Za-z0-9_.:-]{1,120}$/.test(n);\n\n// One tool event already, so a lean install is the same entry.\nfunction entry(cmd: HookCommand) {\n const handler = (e: string) => ({ type: \"command\", command: cmd([NAME, e]).command, timeout: 5 });\n const out: Record<string, unknown> = { enabled: true };\n for (const e of AG_EVENTS) out[e] = /Tool/.test(e) ? [{ matcher: \"*\", hooks: [handler(e)] }] : [handler(e)];\n return out;\n}\n\nexport const antigravity: Adapter = {\n name: NAME,\n events: AG_EVENTS,\n detect: (env = process.env) =>\n existsSync(path.join(gemini(env), \"config\")) || dataDirs(env).some((d) => existsSync(d)),\n configFiles: (env = process.env) => [hooksFile(env)],\n install(cmd, env = process.env): InstallReport[] {\n const file = hooksFile(env);\n const f = readJsonFile(file);\n if (!f.ok) return [{ file, changed: false, skipped: true, note: `${f.reason}; not touched` }];\n const hooks = f.value;\n const e = entry(cmd);\n if (JSON.stringify(hooks[HOOK_NAME]) === JSON.stringify(e)) return [{ file, changed: false }];\n hooks[HOOK_NAME] = e;\n return [\n writeBack(file, formatJson(hooks, f), f.existed) ?? {\n file,\n changed: true,\n created: !f.existed,\n note: \"hooks.json is read when a conversation starts; open ones report after a restart\",\n },\n ];\n },\n uninstall(env = process.env, opts: InstallOptions = {}): InstallReport[] {\n const file = hooksFile(env);\n if (!existsSync(file)) return [{ file, changed: false }];\n const f = readJsonFile(file);\n if (!f.ok) return [{ file, changed: false, skipped: true, note: `${f.reason}; not touched` }];\n const hooks = f.value;\n if (!(HOOK_NAME in hooks)) return [{ file, changed: false }];\n delete hooks[HOOK_NAME];\n if (opts.created?.includes(file) && !Object.keys(hooks).length) return [removeEmptied(file, formatJson(hooks, f))];\n return [writeBack(file, formatJson(hooks, f)) ?? { file, changed: true }];\n },\n installed(cmd, env = process.env) {\n const file = hooksFile(env);\n const f = readJsonFile(file);\n const have = f.ok ? f.value[HOOK_NAME] : undefined;\n return [\n {\n file,\n state: !have ? \"missing\" : JSON.stringify(have) === JSON.stringify(entry(cmd)) ? \"current\" : \"stale\",\n },\n ];\n },\n\n fromHook(input: HookInput): HookResult | null {\n const event = input.argv[1] ?? \"\";\n let s: Record<string, unknown> = {};\n try {\n // A stdin that is JSON but not an object (`null`, a number) is no payload.\n const j: unknown = input.stdin ? JSON.parse(input.stdin) : {};\n if (j && typeof j === \"object\" && !Array.isArray(j)) s = j as Record<string, unknown>;\n } catch {}\n const id = (s.conversationId ?? s.session_id ?? s.sessionId) as string | undefined;\n const stdout = antigravityAnswer(event);\n if (!id) return { session: { id: \"\" }, events: [], stdout };\n const workspaces = agWorkspaces(s.workspacePaths);\n const session: HookResult[\"session\"] = { id: String(id), cwd: workspaces[0] ?? input.cwd };\n if (typeof s.modelName === \"string\" && s.modelName !== \"auto\") session.model = s.modelName;\n const toolCall = s.toolCall as { name?: unknown; args?: unknown } | undefined;\n const tool = validTool(toolCall?.name) ? toolCall?.name : validTool(s.toolName) ? s.toolName : undefined;\n const ev = (type: string, data: Record<string, unknown>) => ({ type, data: prune(data), harnessEvent: event });\n const events: HookResult[\"events\"] = [];\n switch (event) {\n case \"PreInvocation\":\n // Fires before every model call of an execution; only the first is the person's ask.\n if (Number(s.invocationNum) === 0 || s.invocationNum === undefined) {\n events.push(ev(\"session.started\", { source: \"unknown\" }));\n events.push(ev(\"turn.started\", {}));\n } else events.push(ev(\"session.heartbeat\", {}));\n break;\n case \"PostInvocation\":\n break;\n case \"PreToolUse\":\n if (tool) events.push(ev(\"tool.started\", { tool, input: toolCall?.args }));\n break;\n case \"PostToolUse\":\n // Antigravity names no tool here; a beat keeps a long run of tools \"working\".\n if (!tool) events.push(ev(\"session.heartbeat\", {}));\n else\n events.push(\n ev(\"tool.ended\", {\n tool,\n ok: !s.error,\n error: typeof s.error === \"string\" ? s.error.slice(0, 2000) : undefined,\n input: toolCall?.args,\n }),\n );\n break;\n case \"Stop\":\n events.push(ev(\"turn.ended\", { reason: s.error ? \"error\" : \"stop\" }));\n break;\n default:\n return { session, events: [], stdout };\n }\n const r: HookResult = { session, events, stdout, hints: { workspaces } };\n if (typeof s.transcriptPath === \"string\") r.transcript = s.transcriptPath;\n return r;\n },\n\n readTranscript(file, fromLine) {\n let text = \"\";\n try {\n text = readFileSync(file, \"utf8\");\n } catch {\n return { turns: [], line: fromLine };\n }\n return readAntigravity(text.split(\"\\n\"), fromLine);\n },\n\n facts(session, transcript, hints): SessionFacts {\n if (!transcript) return {};\n return antigravityFacts(transcript, {\n conversation: session.id,\n workspaces: (hints.workspaces as string[] | undefined) ?? (session.cwd ? [session.cwd] : []),\n env: process.env,\n });\n },\n\n backfill(sinceMs, env = process.env): BackfillRow[] {\n const rows: BackfillRow[] = [];\n for (const data of dataDirs(env)) {\n let ids: string[] = [];\n try {\n ids = readdirSync(path.join(data, \"brain\")).filter((n) => /^[0-9a-f-]{36}$/i.test(n));\n } catch {}\n for (const id of ids) {\n const f = path.join(data, \"brain\", id, \".system_generated\", \"logs\", \"transcript.jsonl\");\n try {\n if (statSync(f).mtimeMs < sinceMs) continue;\n } catch {\n continue;\n }\n const facts = antigravityFacts(f, { conversation: id, workspaces: [], env });\n if (!facts.started_at || !facts.last_at) continue;\n const { started_at, last_at, first_ask: _fa, harness_version: _hv, ...rest } = facts;\n rows.push({ session: { id, ...rest }, started_at, last_at });\n }\n }\n return rows;\n },\n};\n\nfunction prune<T extends Record<string, unknown>>(o: T): T {\n for (const k of Object.keys(o)) if (o[k] === undefined) delete o[k];\n return o;\n}\n\n/** A folder as Antigravity writes it (a file:// URI or a path) \u2192 an absolute path, or null. */\nexport function agPath(p: unknown): string | null {\n if (typeof p !== \"string\" || !p) return null;\n let s = p;\n if (/^file:/i.test(s)) {\n try {\n s = decodeURIComponent(new URL(s).pathname);\n } catch {\n return null;\n }\n if (process.platform === \"win32\" && /^\\/[A-Za-z]:/.test(s)) s = s.slice(1);\n } else if (/^[a-z][a-z0-9+.-]*:\\/\\//i.test(s)) return null;\n if (!path.isAbsolute(s)) return null;\n return path.resolve(s);\n}\nexport const agWorkspaces = (paths: unknown): string[] =>\n (Array.isArray(paths) ? paths : [])\n .map(agPath)\n .filter((p): p is string => !!p)\n .filter((p, i, a) => a.indexOf(p) === i);\n\nfunction agVariants(p: string): string[] {\n const out = [p];\n try {\n const r = realpathSync.native(p);\n if (r !== p) out.push(r);\n } catch {}\n return out;\n}\nfunction agProjects(dir: string): { id: string; folders: string[] }[] {\n const out: { id: string; folders: string[] }[] = [];\n let names: string[] = [];\n try {\n names = readdirSync(dir).filter((n) => n.endsWith(\".json\"));\n } catch {\n return out;\n }\n for (const n of names) {\n const id = n.slice(0, -5);\n if (!ID_RE.test(id)) continue;\n let j: { projectResources?: { resources?: { folderUri?: unknown; gitFolder?: { folderUri?: unknown } }[] } };\n try {\n j = JSON.parse(readFileSync(path.join(dir, n), \"utf8\"));\n } catch {\n continue;\n }\n const folders: string[] = [];\n // A resource is one of the kinds in Antigravity's project.proto: a plain folder is\n // `{ folderUri }`, a git checkout `{ gitFolder: { folderUri, defaultBranch, allowWrite } }`\n // (what 2.23.1 writes for a folder under git); google3 and remote resources name no folder.\n for (const r of j?.projectResources?.resources ?? []) {\n const f = agPath(r?.folderUri ?? r?.gitFolder?.folderUri);\n if (f) folders.push(...agVariants(f));\n }\n if (folders.length) out.push({ id, folders });\n }\n return out;\n}\n/** The project whose folder is the workspace or contains it; the deepest wins. */\nexport function agMatchProject(projects: { id: string; folders: string[] }[], workspaces: string[]): string | null {\n const ws: string[] = [];\n for (const w of workspaces) {\n const p = agPath(w);\n if (p) ws.push(...agVariants(p));\n }\n let best: string | null = null;\n let bestLen = -1;\n for (const pr of projects)\n for (const f of pr.folders) {\n const within = ws.some((w) => w === f || w.startsWith(f.endsWith(path.sep) ? f : f + path.sep));\n if (within && f.length > bestLen) {\n best = pr.id;\n bestLen = f.length;\n }\n }\n return best;\n}\n\n/** Antigravity's web remote: https://antigravity.google.com/r/<installation uuid>-v2, with\n * ?p=c/<conversation>?section=<project> when the project is known. */\nexport function antigravityRemoteUrl(\n transcript: string,\n opts: { conversation?: string; workspaces?: string[]; env: NodeJS.ProcessEnv; projectsDir?: string },\n): string | null {\n const i = transcript.indexOf(`${path.sep}brain${path.sep}`);\n const dirs = (i > 0 ? [transcript.slice(0, i)] : []).concat(dataDirs(opts.env));\n for (const d of dirs) {\n try {\n const m = /installation_uuid:\\s*\"([0-9a-f-]{36})\"/i.exec(\n readFileSync(path.join(d, \"antigravity_state.pbtxt\"), \"utf8\"),\n );\n if (!m) continue;\n const base = `https://antigravity.google.com/r/${m[1]}-v2`;\n const conv = opts.conversation ?? \"\";\n if (!ID_RE.test(conv) || !opts.workspaces?.length) return base;\n const project = agMatchProject(agProjects(opts.projectsDir ?? projectsDir(opts.env)), opts.workspaces);\n return project ? `${base}?p=${encodeURIComponent(`c/${conv}?section=${project}`)}` : base;\n } catch {}\n }\n return null;\n}\n\nexport function antigravityFacts(\n file: string,\n opts: { conversation: string; workspaces: string[]; env: NodeJS.ProcessEnv },\n): SessionFacts {\n const { head, tail } = ends(file, 128 * 1024, 64 * 1024);\n const H = parseLines(head);\n const T = parseLines(tail);\n const out: SessionFacts = {};\n const url = antigravityRemoteUrl(file, opts);\n if (url) out.url = url;\n for (const j of H) {\n if (j.type !== \"USER_INPUT\" || typeof j.content !== \"string\") continue;\n const m = /<USER_REQUEST>([\\s\\S]*?)(?:<\\/USER_REQUEST>|$)/.exec(j.content);\n const text = (m ? (m[1] as string) : j.content).trim();\n const line = (text.split(\"\\n\").find((l) => l.trim()) ?? \"\").trim();\n if (!line || /^<[a-z_-]+>/i.test(line)) continue;\n out.title = line.length > 80 ? `${line.slice(0, 80).replace(/\\s+\\S*$/, \"\")}\u2026` : line;\n out.title_source = \"first-ask\";\n break;\n }\n const times = H.concat(T)\n .map((j) => Date.parse(String(j.created_at ?? j.timestamp ?? \"\")))\n .filter((n) => n > 0);\n if (times.length) {\n out.started_at = Math.min(...times);\n out.last_at = Math.max(...times);\n }\n return out;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// Antigravity (Google) \u2014 control delivery (spec/CONTROL.md \u00A76). Its CLI, `agy`, as the\n// control daemon needs it: which `agy` to run, one headless turn (`agy -p \u2026 --output-\n// format stream-json`, and `--conversation <id>` for the next message), and its stream\n// read as it arrives. agy picks a new conversation's id itself (the `init` line) and\n// starts a fresh one for an id it doesn't know, so the daemon names it after the\n// command that started it (CONTROL.md \u00A76 `start`). No transcript records the folder, so\n// the daemon keeps that too. Shapes measured on agy 1.2.16, 2026-10-04.\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport type { RunLevel, StartPermission } from \"../control/verify.js\";\nimport { deniedNote, findBinary, jobEnv, type Mode, type Reading, type RunResult, runFailure } from \"./headless.js\";\n\nconst LABEL = \"Antigravity\";\n\n/** The `agy` to run: SESSIONPIPE_AGY, else on PATH, else where its installer puts it. */\nexport function findAgy(env: NodeJS.ProcessEnv = process.env, home = os.homedir()): string | null {\n return findBinary({\n override: env.SESSIONPIPE_AGY,\n names: process.platform === \"win32\" ? [\"agy.exe\", \"agy.cmd\"] : [\"agy\"],\n env,\n dirs: [path.join(home, \".local\", \"bin\"), \"/opt/homebrew/bin\", \"/usr/local/bin\"],\n });\n}\n\n/** Permission flags for a level. Safe: none \u2014 agy denies every tool call nobody is\n * there to approve, and says which. Edits: `--mode accept-edits`, its widest, which is\n * also what an auto machine's mode means for it. Inherit: none either, so agy runs as\n * it would by itself. agy has no read-only mode known, so `read` is never offered and\n * throws rather than run at safe. Never `--dangerously-skip-permissions`: no path here\n * writes it. */\nexport function agyModeFlags(level: RunLevel): string[] {\n if (level === \"read\") throw new Error(\"Antigravity has no read-only mode\");\n return level === \"safe\" || level === \"inherit\" ? [] : [\"--mode\", \"accept-edits\"];\n}\n\n/** The levels a start may ask agy for on a machine in `mode`: safe, and edits on an\n * auto machine. */\nexport const offeredLevels = (mode: Mode): StartPermission[] => (mode === \"auto\" ? [\"safe\", \"edits\"] : [\"safe\"]);\n\n/** What a start that names no level gets, said as what it is: edits on an auto machine,\n * no flag on an inherit one. */\nexport const defaultLevel = (mode: Mode): RunLevel => (mode === \"auto\" ? \"edits\" : mode);\n\n/** One headless turn in the folder it is spawned in. A message that starts with a dash\n * would read as a flag after `-p`; a leading space keeps it the prompt. */\nexport function agyArgs(o: { permission: RunLevel; prompt: string; resume?: string }): string[] {\n const prompt = o.prompt.startsWith(\"-\") ? ` ${o.prompt}` : o.prompt;\n return [\n ...(o.resume ? [\"--conversation\", o.resume] : []),\n \"-p\",\n prompt,\n \"--output-format\",\n \"stream-json\",\n ...agyModeFlags(o.permission),\n ];\n}\n\n/** The env a headless turn runs with. */\nexport const agyEnv = (env: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv => jobEnv(env);\n\nexport interface AgyResult {\n status: string;\n response: string;\n error: string;\n denied: unknown[];\n}\n\n/** One stream-json line, as much of it as the daemon uses. */\nexport interface AgyPiece {\n /** The conversation's id, which agy chose (`init`, then every step and the result). */\n session?: string;\n /** Text an `agent_response` step wrote, and which step it belongs to. */\n delta?: { step: number; text: string };\n /** The final `result`. */\n result?: AgyResult;\n /** An `error_message` step's words: the reason only if the run then fails. */\n note?: string;\n}\n\nexport function agyLine(line: string): AgyPiece | null {\n let j: Record<string, unknown>;\n try {\n j = JSON.parse(line);\n } catch {\n return null;\n }\n if (!j || typeof j !== \"object\") return null;\n const str = (v: unknown) => (typeof v === \"string\" ? v : \"\");\n const out: AgyPiece = {};\n if (j.event === \"init\") {\n if (str(j.conversation_id)) out.session = str(j.conversation_id);\n } else if (j.event === \"step_update\") {\n const s = (j.step_update ?? {}) as Record<string, unknown>;\n if (str(s.conversation_id)) out.session = str(s.conversation_id);\n if (s.step_type === \"agent_response\" && str(s.text_delta))\n out.delta = { step: Number(s.step_index ?? 0), text: str(s.text_delta) };\n if (s.step_type === \"error_message\") {\n const why = str(s.text_delta) || str(s.error) || str(s.message);\n if (why) out.note = why;\n }\n } else if (j.event === \"result\") {\n const r = (j.result ?? {}) as Record<string, unknown>;\n if (str(r.conversation_id)) out.session = str(r.conversation_id);\n out.result = {\n status: str(r.status),\n response: str(r.response),\n error: str(r.error),\n denied: Array.isArray(r.denied_actions) ? r.denied_actions : [],\n };\n } else return null;\n return Object.keys(out).length ? out : null;\n}\n\n/** What agy names a denied action by, whatever shape the entry has. */\nfunction deniedName(d: unknown): string | null {\n if (typeof d === \"string\") return d.slice(0, 80);\n if (!d || typeof d !== \"object\") return null;\n const o = d as Record<string, unknown>;\n for (const k of [\"tool_name\", \"toolName\", \"name\", \"tool\", \"action\", \"type\"])\n if (typeof o[k] === \"string\" && o[k]) return (o[k] as string).slice(0, 80);\n return null;\n}\n\n/** An `AGY_ERROR: {\u2026}` agy may end stderr with, in words. */\nexport function agyError(stderr: string | undefined): string {\n const s = String(stderr || \"\");\n const i = s.lastIndexOf(\"AGY_ERROR:\");\n if (i < 0) return \"\";\n const raw = s.slice(i + \"AGY_ERROR:\".length).trim();\n try {\n const j = JSON.parse(raw) as Record<string, unknown>;\n for (const k of [\"message\", \"error\", \"detail\"]) if (typeof j[k] === \"string\" && j[k]) return j[k] as string;\n } catch {}\n return (raw.split(\"\\n\")[0] as string).slice(0, 300);\n}\n\n/** An agy run read as it streams: the answer is the agent_response steps' text, and the\n * result's `response` once it comes. */\nexport class AgyReading implements Reading {\n session: string | null = null;\n lines = 0;\n private buf = \"\";\n private step: number | null = null;\n private result: AgyResult | null = null;\n private note: string | null = null;\n\n get text(): string {\n return this.buf;\n }\n\n feed(line: string): boolean {\n this.lines++;\n const p = agyLine(line);\n if (!p) return false;\n if (p.session && !this.session) this.session = p.session;\n if (p.note) this.note = p.note;\n if (p.result) this.result = p.result;\n if (!p.delta) return false;\n // A new response step after a tool step starts a new paragraph.\n if (this.step !== null && p.delta.step !== this.step && this.buf && !this.buf.endsWith(\"\\n\\n\")) this.buf += \"\\n\\n\";\n this.step = p.delta.step;\n this.buf += p.delta.text;\n return true;\n }\n\n outcome(res: RunResult): { failed: string } | { reply: string } {\n const broke = runFailure(LABEL, res);\n if (broke) return { failed: broke };\n const r = this.result;\n if (!r) {\n const why = agyError(res.stderr) || this.note || \"\";\n return {\n failed: `Antigravity exited (${res.signal || `code ${res.code}`}) without an answer${why ? `: ${why}` : \"\"}`,\n };\n }\n if (r.status !== \"SUCCESS\")\n return { failed: r.error || agyError(res.stderr) || this.note || \"Antigravity reported an error\" };\n const names = [...new Set(r.denied.map(deniedName).filter((n): n is string => !!n))];\n const text = r.response.trim()\n ? r.response.trim()\n : this.buf.trim() || \"(Antigravity finished without a written reply.)\";\n return { reply: text + deniedNote(names, r.denied.length) };\n }\n}\n\nexport const reading = (): AgyReading => new AgyReading();\n", "// SPDX-License-Identifier: Apache-2.0\n// Claude Code (Anthropic) \u2014 control delivery (spec/CONTROL.md \u00A76). Claude Code on\n// this machine, as the control daemon needs it: which `claude` to\n// run and with which permission flags, where a session's transcript is and which\n// folder it runs in, whether a live process holds it, and running one headless\n// turn (`claude -p --resume`, `--fork-session`, `--session-id`). Ported from the\n// spacesheep CLI's machine listener (lib/machine.js, 1.22), which ran it in\n// production first.\nimport { execFile, execFileSync } from \"node:child_process\";\nimport { closeSync, openSync, readdirSync, readFileSync, readSync, statSync } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { levelRank, type RunLevel, START_PERMISSIONS, type StartPermission } from \"../control/verify.js\";\nimport { withoutLineage } from \"../launched-by.js\";\nimport {\n isExe,\n JOB_TIMEOUT_MS,\n type Login,\n type Mode,\n probe,\n type RunOptions,\n type RunResult,\n runHeadless,\n} from \"./headless.js\";\n\nexport { JOB_TIMEOUT_MS, type Login, type Mode, type RunResult };\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n/** A transcript someone else wrote this recently is in use. */\nconst LIVE_WRITE_MS = 90_000;\n\n/** Dotted versions by number, a missing part as 0: 1.9.0 < 1.10 = 1.10.0. */\nexport const cmpVersion = (a: string, b: string) => {\n const pa = a.split(\".\").map(Number);\n const pb = b.split(\".\").map(Number);\n for (let i = 0; i < Math.max(pa.length, pb.length); i++)\n if ((pa[i] ?? 0) !== (pb[i] ?? 0)) return (pa[i] ?? 0) - (pb[i] ?? 0);\n return 0;\n};\n\n/** The `claude` to run: on PATH, else where the installers put it, else the newest\n * copy the desktop app ships. Null when this machine has none. */\n/** The bin folders of the node version managers (nvm, fnm, volta, asdf), newest node\n * first within each, in the folders they use by default or the ones their variables name. */\nexport function versionManagerBins(env: NodeJS.ProcessEnv = process.env, home = os.homedir()): string[] {\n const out: string[] = [];\n const versions = (dir: string, tail: string[]): void => {\n let names: string[] = [];\n try {\n names = readdirSync(dir).filter((n) => /^v?\\d+(\\.\\d+)*$/.test(n));\n } catch {\n return;\n }\n for (const n of names.sort((a, b) => cmpVersion(a.replace(/^v/, \"\"), b.replace(/^v/, \"\"))).reverse())\n out.push(path.join(dir, n, ...tail));\n };\n versions(path.join(env.NVM_DIR || path.join(home, \".nvm\"), \"versions\", \"node\"), [\"bin\"]);\n const fnmDirs = env.FNM_DIR\n ? [env.FNM_DIR]\n : [\n path.join(home, \"Library\", \"Application Support\", \"fnm\"),\n path.join(home, \".local\", \"share\", \"fnm\"),\n path.join(home, \".fnm\"),\n ];\n for (const d of fnmDirs) versions(path.join(d, \"node-versions\"), [\"installation\", \"bin\"]);\n out.push(path.join(env.VOLTA_HOME || path.join(home, \".volta\"), \"bin\"));\n versions(path.join(env.ASDF_DATA_DIR || path.join(home, \".asdf\"), \"installs\", \"nodejs\"), [\"bin\"]);\n return out;\n}\n\nexport function findClaude(env: NodeJS.ProcessEnv = process.env, home = os.homedir()): string | null {\n if (env.SESSIONPIPE_CLAUDE && isExe(env.SESSIONPIPE_CLAUDE)) return env.SESSIONPIPE_CLAUDE;\n const names = process.platform === \"win32\" ? [\"claude.exe\", \"claude.cmd\"] : [\"claude\"];\n for (const d of String(env.PATH || \"\").split(path.delimiter)) {\n if (!d || !path.isAbsolute(d)) continue;\n for (const n of names) if (isExe(path.join(d, n))) return path.join(d, n);\n }\n for (const p of [\n path.join(home, \".claude\", \"local\", \"claude\"),\n path.join(home, \".local\", \"bin\", \"claude\"),\n \"/opt/homebrew/bin/claude\",\n \"/usr/local/bin/claude\",\n ])\n if (isExe(p)) return p;\n // A node version manager's folders: launchd and systemd start the daemon with a bare\n // PATH, and a `claude` that `npm install -g` put under nvm was never found that way\n // (2026-11-05: \"can't copy it (no --fork-session)\" for a Claude Code that had the flag).\n for (const d of versionManagerBins(env, home)) if (isExe(path.join(d, \"claude\"))) return path.join(d, \"claude\");\n const app = path.join(home, \"Library\", \"Application Support\", \"Claude\", \"claude-code\");\n let versions: string[] = [];\n try {\n versions = readdirSync(app)\n .filter((n) => /^\\d+(\\.\\d+)*$/.test(n))\n .sort(cmpVersion)\n .reverse();\n } catch {}\n for (const v of versions) {\n const p = path.join(app, v, \"claude.app\", \"Contents\", \"MacOS\", \"claude\");\n if (isExe(p)) return p;\n }\n return null;\n}\n\n/** One option's text in `claude --help`: its line and the deeper-indented lines under it. */\nfunction optionBlock(help: string, flag: string): string | null {\n const lines = help.split(\"\\n\");\n const re = new RegExp(`^\\\\s{0,4}(?:-\\\\w, )?${flag.replace(/-/g, \"\\\\-\")}(?![\\\\w-])`);\n const start = lines.findIndex((l) => re.test(l));\n if (start < 0) return null;\n const out = [lines[start] as string];\n for (let i = start + 1; i < lines.length && lines[i]?.trim() && !/^\\s{0,4}-/.test(lines[i] as string); i++)\n out.push(lines[i] as string);\n return out.join(\" \");\n}\n\nexport interface Caps {\n hasMode: boolean;\n modes: string[];\n promptsNone: boolean;\n fork: boolean;\n /** `--output-format stream-json` with `--include-partial-messages`: the answer can be\n * forwarded as it is written. Optional so older callers' literals still type. */\n stream?: boolean;\n /** Why `claude --help` couldn't be read, when it couldn't: it timed out (a machine still\n * starting up), or failed without listing `--permission-mode`. Such caps say nothing\n * about this Claude Code's modes, so they are never read as \"it has none\". */\n unread?: string;\n}\n\nexport function parseCaps(help: string): Caps {\n const pm = optionBlock(help, \"--permission-mode\");\n const pp = optionBlock(help, \"--permission-prompts\");\n return {\n hasMode: !!pm,\n modes: pm ? [...pm.matchAll(/\"([A-Za-z]+)\"/g)].map((m) => m[1] as string) : [],\n promptsNone: !!pp && /\"none\"/.test(pp),\n fork: !!optionBlock(help, \"--fork-session\"),\n stream: !!optionBlock(help, \"--include-partial-messages\"),\n };\n}\n\n/** The `--permission-mode` each level (CONTROL.md \u00A73.1) is, where it is one mode. */\nconst LEVEL_MODE: Record<Exclude<StartPermission, \"safe\">, string> = {\n read: \"plan\",\n edits: \"acceptEdits\",\n auto: \"auto\",\n};\n\n/** Permission flags for a level (a machine's mode is one: safe, auto, inherit). Read:\n * plan mode. Safe: `dontAsk` (nothing that needs approval runs). Edits: acceptEdits.\n * Auto: Claude Code's own auto mode. Inherit: none, so the turn starts in the mode\n * Claude Code picks by itself here, its settings' `permissions.defaultMode` (a resume\n * too: Claude Code never restores a session's earlier mode). A level this Claude Code\n * has no mode for is a refusal, never another level, and so is every level but inherit\n * while its --help can't be read (safe would otherwise run with no flag at all). Never\n * bypassPermissions \u2014 no path here writes it. */\nexport function modeFlags(level: RunLevel, caps: Caps): { args: string[] } | { error: string } {\n if (level === \"inherit\") return { args: [] };\n if (caps.unread)\n return { error: `this machine couldn't read its Claude Code's options (${caps.unread}); try again in a minute` };\n if (level === \"auto\" && !caps.modes.includes(\"auto\"))\n return { error: \"this machine is in auto mode, but its Claude Code has no auto permission mode\" };\n if (level !== \"safe\") {\n const m = LEVEL_MODE[level];\n if (!caps.modes.includes(m)) return { error: `this machine's Claude Code has no ${m} permission mode` };\n return { args: [\"--permission-mode\", m] };\n }\n if (caps.modes.includes(\"dontAsk\")) return { args: [\"--permission-mode\", \"dontAsk\"] };\n const args: string[] = [];\n if (caps.hasMode)\n args.push(\n \"--permission-mode\",\n caps.modes.includes(\"manual\") && !caps.modes.includes(\"default\") ? \"manual\" : \"default\",\n );\n if (caps.promptsNone) args.push(\"--permission-prompts\", \"none\");\n return { args };\n}\n\n/** The widest level a start may name on a machine in `mode`: the mode itself, and safe\n * on an inherit machine, whose own default sessionpipe can't rank, so a message there may\n * only narrow to a level that never runs anything needing approval. */\nexport const ceilingLevel = (mode: Mode): StartPermission => (mode === \"inherit\" ? \"safe\" : mode);\n\n/** The levels a start may ask Claude Code for on a machine in `mode`: never above its\n * ceiling, and each only where `claude --help` lists the mode it maps to (safe always).\n * None while that --help couldn't be read: an offered safe would be taken and then run\n * with no permission flag at all. */\nexport function offeredLevels(mode: Mode, caps: Caps): StartPermission[] {\n if (caps.unread) return [];\n return START_PERMISSIONS.filter(\n (l) => levelRank(l) <= levelRank(ceilingLevel(mode)) && (l === \"safe\" || caps.modes.includes(LEVEL_MODE[l])),\n );\n}\n\n/** What a start that names no level gets: what the machine's mode means for Claude Code. */\nexport const defaultLevel = (mode: Mode): RunLevel => mode;\n\n/** How a headless run prints: streamed where this Claude Code can, else one JSON at the end. */\nexport function outputArgs(caps: { stream?: boolean }): string[] {\n return caps.stream\n ? [\"--output-format\", \"stream-json\", \"--verbose\", \"--include-partial-messages\"]\n : [\"--output-format\", \"json\"];\n}\n\n/** One headless `claude -p` run: a new session (`session`), or the next message of one\n * (`resume`, optionally as a fork). The model is its own argument after `--model`, and\n * a prompt that starts with a dash gets a leading space, so it is never read as a flag. */\nexport function claudeArgs(o: {\n caps: Caps;\n level: RunLevel;\n prompt: string;\n session?: string;\n resume?: string;\n fork?: boolean;\n model?: string;\n allowedTools?: string[];\n}): { args: string[] } | { error: string } {\n const mf = modeFlags(o.level, o.caps);\n if (\"error\" in mf) return mf;\n const where = o.resume\n ? [\"--resume\", o.resume, ...(o.fork ? [\"--fork-session\"] : [])]\n : [\"--session-id\", o.session as string];\n return {\n args: [\n \"-p\",\n ...outputArgs(o.caps),\n ...mf.args,\n ...(o.model ? [\"--model\", o.model] : []),\n ...(o.allowedTools?.length ? [`--allowedTools=${o.allowedTools.join(\",\")}`] : []),\n ...where,\n o.prompt.startsWith(\"-\") ? ` ${o.prompt}` : o.prompt,\n ],\n };\n}\n\n/** The env a headless turn runs with: ours, minus the markers that make Claude Code\n * think it runs inside another session and minus any lineage this process inherited\n * (jobEnv), with CLAUDE_CONFIG_DIR naming the account. */\nexport function claudeEnv(configDir?: string, env: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv {\n const e = withoutLineage(env);\n for (const k of [\n \"CLAUDECODE\",\n \"CLAUDE_CODE_SESSION_ID\",\n \"CLAUDE_CODE_HOST_SESSION_ID\",\n \"CLAUDE_CODE_ENTRYPOINT\",\n \"CLAUDE_CODE_SESSION_ATTENDED\",\n \"CLAUDE_CODE_SSE_PORT\",\n ])\n delete e[k];\n e.SESSIONPIPE_CONTROL_JOB = \"1\";\n if (configDir !== undefined) {\n if (path.resolve(configDir) === path.resolve(os.homedir(), \".claude\")) delete e.CLAUDE_CONFIG_DIR;\n else e.CLAUDE_CONFIG_DIR = configDir;\n }\n return e;\n}\n\n/** Whether Claude Code is signed in for one account, in Claude Code's own words\n * (`claude auth status --json`). `loggedIn: null` means this Claude Code can't say\n * (too old for `auth status`, or it didn't answer): never a reason to refuse. */\nexport function parseAuthStatus(stdout: string | null | undefined): Login {\n const text = String(stdout || \"\").trim();\n const start = text.indexOf(\"{\");\n if (start < 0) return { loggedIn: null };\n try {\n const j = JSON.parse(text.slice(start)) as Record<string, unknown>;\n if (typeof j.loggedIn !== \"boolean\") return { loggedIn: null };\n return {\n loggedIn: j.loggedIn,\n ...(typeof j.authMethod === \"string\" ? { method: j.authMethod } : {}),\n ...(typeof j.subscriptionType === \"string\" ? { subscription: j.subscriptionType } : {}),\n };\n } catch {\n return { loggedIn: null };\n }\n}\n\n/** Ask Claude Code whether the account in `configDir` (the default one when omitted)\n * is signed in, from this process \u2014 which is the point: a login kept in the macOS\n * keychain is readable from the screen's own session and not from a background\n * service on a Mac nobody is logged in to, or from an ssh shell, so a headless turn\n * started there dies with \"please run /login\". */\nexport function claudeLogin(bin: string, configDir?: string, env: NodeJS.ProcessEnv = process.env): Promise<Login> {\n // Through `probe`: a .cmd shim (an npm install on Windows) can't be spawned bare, and\n // execFile's synchronous throw would reject this promise and take doctor down with it.\n const c = probe(bin, [\"auth\", \"status\", \"--json\"]);\n return new Promise((resolve) => {\n execFile(\n c.file,\n c.args,\n { encoding: \"utf8\", timeout: 20_000, env: claudeEnv(configDir, env), maxBuffer: 256 * 1024, shell: c.shell },\n // `auth status` may exit non-zero when signed out; its JSON still says so.\n (_err, stdout) => resolve(parseAuthStatus(stdout)),\n );\n });\n}\n\n/** The command that signs one account in, quoted for a sentence. */\nexport function loginCommand(configDir: string | undefined): string {\n const home = os.homedir();\n const isDefault = !configDir || path.resolve(configDir) === path.resolve(home, \".claude\");\n return isDefault ? \"`claude auth login`\" : `\\`CLAUDE_CONFIG_DIR=${configDir.replace(home, \"~\")} claude auth login\\``;\n}\n\n/** What to tell the person when an account isn't signed in for the daemon. */\nexport function loginHint(configDir: string | undefined, platform: NodeJS.Platform = process.platform): string {\n const shown = configDir ? configDir.replace(os.homedir(), \"~\") : \"~/.claude\";\n const login = loginCommand(configDir);\n if (platform === \"darwin\")\n return `Claude Code (${shown}) isn't signed in as this machine's background service sees it. On a Mac its login lives in the login keychain, which a background service can read only while someone is logged in at the screen: log in at the Mac, or run ${login} there.`;\n return `Claude Code (${shown}) isn't signed in on this machine: run ${login} there.`;\n}\n\n/** What `claude --help` lists. A run that fails still counts when it printed its\n * `--permission-mode` line; one that didn't (a timeout on a machine still starting up,\n * most often) is `unread`, never a Claude Code with no modes. */\nexport function detectCaps(bin: string, timeoutMs = 30_000): Caps {\n const c = probe(bin, [\"--help\"]); // a claude.cmd shim can't be spawned bare (#165)\n try {\n return parseCaps(\n execFileSync(c.file, c.args, {\n encoding: \"utf8\",\n timeout: timeoutMs,\n env: claudeEnv(),\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n maxBuffer: 4 * 1024 * 1024,\n shell: c.shell,\n }),\n );\n } catch (e) {\n const err = e as { stdout?: string; code?: string };\n const caps = parseCaps(String(err?.stdout || \"\"));\n if (caps.hasMode) return caps;\n const why = err?.code === \"ETIMEDOUT\" ? `timed out after ${timeoutMs / 1000} s` : \"failed\";\n return { ...caps, unread: `\\`${path.basename(bin)} --help\\` ${why}` };\n }\n}\n\nexport interface Transcript {\n file: string;\n configDir: string;\n project: string;\n}\n\n/** <config dir>/projects/<folder>/<session>.jsonl in one Claude Code config dir. */\nfunction transcriptIn(session: string, dir: string): Transcript | null {\n let projects: import(\"node:fs\").Dirent[] = [];\n try {\n projects = readdirSync(path.join(dir, \"projects\"), { withFileTypes: true });\n } catch {\n return null;\n }\n for (const p of projects) {\n if (!p.isDirectory()) continue;\n const file = path.join(dir, \"projects\", p.name, `${session}.jsonl`);\n try {\n if (statSync(file).isFile()) return { file, configDir: dir, project: p.name };\n } catch {}\n }\n return null;\n}\n\n/** <config dir>/projects/<folder>/<session>.jsonl in any Claude Code config dir. */\nexport function findTranscript(session: string, dirs: readonly string[]): Transcript | null {\n if (!UUID_RE.test(session)) return null;\n for (const dir of dirs) {\n const t = transcriptIn(session, dir);\n if (t) return t;\n }\n return null;\n}\n\n/** Every config dir that holds this session's transcript, in the order given. One\n * session id can be filed in several accounts: a transcript copied between homes, the\n * same id resumed under another account. There were six such ids on one Mac in\n * October 2026, and picking the first \u2014 which is what reading one home does \u2014 put a\n * message into an account that was signed out. */\nexport function findTranscripts(session: string, dirs: readonly string[]): Transcript[] {\n if (!UUID_RE.test(session)) return [];\n const out: Transcript[] = [];\n for (const dir of dirs) {\n const t = transcriptIn(session, dir);\n if (t) out.push(t);\n }\n return out;\n}\n\n/** Which Claude Code account a session belongs to, when more than one has its\n * transcript: the one whose own `sessions/` says a live process holds it. `ambiguous`\n * is a refusal rather than a guess \u2014 it names every account that has the transcript,\n * and in `live` the ones holding it open, which is none of them or more than one. Both\n * are named by their directory name alone, since an ack travels to the receiver. Null\n * when no account has the session at all. */\nexport type HomeChoice = { transcript: Transcript } | { ambiguous: string[]; live: string[] };\n\nconst homeName = (t: Transcript) => path.basename(t.configDir);\n\nexport function resolveHome(session: string, dirs: readonly string[]): HomeChoice | null {\n const all = findTranscripts(session, dirs);\n if (!all.length) return null;\n if (all.length === 1) return { transcript: all[0] as Transcript };\n const live = all.filter((t) => liveRecords(session, t.configDir).length > 0);\n if (live.length === 1) return { transcript: live[0] as Transcript };\n return {\n ambiguous: [...new Set(all.map(homeName))].sort(),\n live: [...new Set(live.map(homeName))].sort(),\n };\n}\n\nconst projectName = (cwd: string) => cwd.replace(/[^a-zA-Z0-9]/g, \"-\");\n\n/** The folder a session runs in, from its transcript's own records (never from a\n * command): the `cwd` whose project name is the folder the transcript is filed\n * under, else the first `cwd`. Streams; a line over 2 MB is skipped. */\nexport function sessionFolder(t: Transcript, cap = 8 * 1024 * 1024): string | null {\n let first: string | null = null;\n let count = 0;\n let fd: number | undefined;\n const look = (line: Buffer): string | null => {\n if (line.indexOf('\"cwd\"') < 0) return null;\n let j: { cwd?: unknown };\n try {\n j = JSON.parse(line.toString(\"utf8\"));\n } catch {\n return null;\n }\n if (!j || typeof j.cwd !== \"string\" || !path.isAbsolute(j.cwd)) return null;\n if (projectName(j.cwd) === t.project) return j.cwd;\n first ??= j.cwd;\n count++;\n return null;\n };\n try {\n fd = openSync(t.file, \"r\");\n const buf = Buffer.alloc(256 * 1024);\n let pos = 0;\n let rest = Buffer.alloc(0);\n let skipping = false;\n while (pos < cap && count < 50) {\n const n = readSync(fd, buf, 0, buf.length, pos);\n if (!n) {\n if (!skipping && rest.length) {\n const hit = look(rest);\n if (hit) return hit;\n }\n break;\n }\n pos += n;\n let chunk = rest.length ? Buffer.concat([rest, buf.subarray(0, n)]) : buf.subarray(0, n);\n let nl = chunk.indexOf(10);\n while (nl >= 0) {\n const line = chunk.subarray(0, nl);\n chunk = chunk.subarray(nl + 1);\n if (skipping) skipping = false;\n else {\n const hit = look(line);\n if (hit) return hit;\n }\n nl = chunk.indexOf(10);\n }\n if (chunk.length > 2 * 1024 * 1024) {\n skipping = true;\n rest = Buffer.alloc(0);\n } else rest = skipping ? Buffer.alloc(0) : Buffer.from(chunk);\n }\n } catch {\n } finally {\n if (fd !== undefined)\n try {\n closeSync(fd);\n } catch {}\n }\n return first;\n}\n\nfunction pidAlive(pid: number): boolean {\n if (!Number.isSafeInteger(pid) || pid <= 1) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch (e) {\n return (e as { code?: string }).code === \"EPERM\";\n }\n}\n\n/** One live Claude Code process's registry row, `<config>/sessions/<pid>.json`, as the\n * in-place `inbox` lane needs it (spec/CONTROL.md \u00A76.3). Every session that registers\n * files one \u2014 a terminal window, the desktop app and a claude.ai bridge worker alike,\n * all of them `kind: \"interactive\"`; a `-p` one-shot's row is not one of those. */\nexport interface LiveRecord {\n /** The config dir this row was read from: the lane never crosses accounts. */\n configDir: string;\n file: string;\n pid: number;\n /** Claude Code's own local inbox for this process, or null when it published none. */\n socket: string | null;\n /** 1 is the only inbox protocol this code speaks; anything else is refused. */\n peerProtocol: number | null;\n /** The process's start time as the registry spells it (UTC), so a recycled pid can be\n * told from the process that filed the row. */\n procStart: string | null;\n status: string | null;\n /** `interactive` for a session the harness holds open for the person. */\n kind: string | null;\n entrypoint: string | null;\n /** `<pid>.<sha>.key`, 0600: where the inbox's auth token lives (needed off macOS). */\n keyFile: string | null;\n}\n\nconst registryRow = (file: string, configDir: string, j: Record<string, unknown>): LiveRecord => {\n const pid = Number(j.pid ?? path.basename(file).slice(0, -5));\n const str = (v: unknown) => (typeof v === \"string\" && v ? v : null);\n let keyFile: string | null = null;\n try {\n // Claude Code's own spelling: `<pid>.<64 hex>.key`, 0600, beside the registry row.\n const want = new RegExp(`^${pid}\\\\.[0-9a-f]{64}\\\\.key$`);\n const hit = readdirSync(path.dirname(file)).find((n) => want.test(n));\n if (hit) keyFile = path.join(path.dirname(file), hit);\n } catch {}\n return {\n configDir,\n file,\n pid,\n socket: str(j.messagingSocketPath),\n peerProtocol: typeof j.peerProtocol === \"number\" ? j.peerProtocol : null,\n procStart: str(j.procStart),\n status: str(j.status),\n kind: str(j.kind),\n entrypoint: str(j.entrypoint),\n keyFile,\n };\n};\n\n/** Every live registry row for this session, across the config dirs given. A row whose\n * pid is gone is not one: the file outlives the process. */\nexport function liveRecords(session: string, dirs: string | readonly string[]): LiveRecord[] {\n const out: LiveRecord[] = [];\n for (const dir of typeof dirs === \"string\" ? [dirs] : dirs) {\n let names: string[] = [];\n try {\n names = readdirSync(path.join(dir, \"sessions\")).filter((n) => /^\\d+\\.json$/.test(n));\n } catch {\n continue;\n }\n for (const n of names) {\n const file = path.join(dir, \"sessions\", n);\n let j: Record<string, unknown>;\n try {\n j = JSON.parse(readFileSync(file, \"utf8\")) as Record<string, unknown>;\n } catch {\n continue;\n }\n if (String(j.sessionId) !== session) continue;\n const row = registryRow(file, dir, j);\n if (pidAlive(row.pid)) out.push(row);\n }\n }\n return out;\n}\n\n/** The ONE live process that holds this session, or null. Two rows \u2014 two accounts, or\n * two processes in one \u2014 is a refusal rather than a guess: a lane that writes into a\n * live session has to know which process it is writing to (spec/CONTROL.md \u00A76.3). */\nexport function liveRecord(session: string, dirs: string | readonly string[]): LiveRecord | null {\n const all = liveRecords(session, dirs);\n return all.length === 1 ? (all[0] as LiveRecord) : null;\n}\n\n/** A Claude Code process holds this session right now: its registry file,\n * <config>/sessions/<pid>.json, names it and the pid is alive (interactive and\n * Agent SDK sessions both file one). */\nexport function liveProcess(session: string, configDir: string): boolean {\n return liveRecords(session, configDir).length > 0;\n}\n\n/** Claude Code's own permission modes, by how much a turn may do in them without being\n * asked about (its own order, 2.1.310). `plan` writes nothing at all. `default`,\n * `manual` and `dontAsk` share a step: none of them lets anything through that needs\n * approval \u2014 the first two ask the person, `dontAsk` refuses instead. `acceptEdits`\n * writes files; `auto` runs most things; `bypassPermissions` asks about nothing.\n *\n * Used to tell one mode from another and to compare two, never to pick one. -1 is \"not\n * a mode this code knows\", which compares below everything. */\nexport const MODE_RANK: Record<string, number> = {\n plan: 0,\n default: 1,\n manual: 1,\n dontAsk: 1,\n acceptEdits: 2,\n auto: 3,\n bypassPermissions: 4,\n};\nexport const CLAUDE_MODES = Object.keys(MODE_RANK);\nexport const modeRank = (m: string | null | undefined): number => (m && m in MODE_RANK ? (MODE_RANK[m] as number) : -1);\n\n/** The permission mode a hook payload reports for its own session, or null. Claude Code\n * writes `permission_mode` on every hook payload; `permissionMode` is the spelling its\n * transcript records use, and is read too so one reader serves both.\n *\n * This is the only place a mode the person chose at the keyboard can be read from: a\n * session's registry row doesn't carry it, and the transcript names it only on turns\n * that happen to record one. hook.ts repeats the shape test, because it imports nothing\n * but node builtins. */\nexport function hookMode(payload: unknown): string | null {\n if (!payload || typeof payload !== \"object\") return null;\n const p = payload as { permission_mode?: unknown; permissionMode?: unknown };\n const v = typeof p.permission_mode === \"string\" ? p.permission_mode : p.permissionMode;\n return typeof v === \"string\" && CLAUDE_MODES.includes(v) ? v : null;\n}\n\n/** The permission class Claude Code's own inbox checks a sender's declared class\n * against (2.1.310): `bypassPermissions` is `bypass`; a mode that prompts before it\n * acts is `prompting`. `plan` is neither \u2014 its class there depends on a capability and\n * a TTY this code cannot see \u2014 and nor is `auto`, nor a mode nothing has recorded, so\n * those get no in-place lane at all (spec/CONTROL.md \u00A76.3). */\nexport function peerClass(mode: string | null | undefined): \"bypass\" | \"prompting\" | null {\n if (mode === \"bypassPermissions\") return \"bypass\";\n if (mode === \"default\" || mode === \"manual\" || mode === \"dontAsk\" || mode === \"acceptEdits\") return \"prompting\";\n return null;\n}\n\n/** One Claude Code account's permission settings, user scope only\n * (`<config dir>/settings.json`): a folder's own settings may tighten these but never\n * loosen them, and a managed policy may tighten them further. Only the three keys\n * something here acts on.\n *\n * Reading user scope alone can overstate how wide a home is, never understate it, and\n * everything that reads this treats a wider answer as a reason NOT to act (the inbox\n * lane needs the machine's class to equal the session's own; a narrowing is re-asserted\n * only where the home's default is at least as wide). */\nexport interface HomeSettings {\n /** `permissions.defaultMode`: what a session with no flag starts in. Null: not said,\n * or the file could not be read. */\n defaultMode: string | null;\n /** `disableAutoMode: \"disable\"`: asking for auto mode quietly gives Manual instead. */\n disableAutoMode: boolean;\n /** `disableBypassPermissionsMode: \"disable\"`: this home cannot be in bypass at all. */\n disableBypass: boolean;\n}\n\nexport const NO_HOME_SETTINGS: HomeSettings = { defaultMode: null, disableAutoMode: false, disableBypass: false };\n\nexport function homeSettings(configDir: string | undefined, home = os.homedir()): HomeSettings {\n const file = path.join(configDir ?? path.join(home, \".claude\"), \"settings.json\");\n let j: Record<string, unknown>;\n try {\n j = JSON.parse(readFileSync(file, \"utf8\")) as Record<string, unknown>;\n } catch {\n return { ...NO_HOME_SETTINGS };\n }\n if (!j || typeof j !== \"object\" || Array.isArray(j)) return { ...NO_HOME_SETTINGS };\n const p = (j.permissions && typeof j.permissions === \"object\" ? j.permissions : {}) as Record<string, unknown>;\n // Both spellings: Claude Code reads these two under `permissions`, and settings\n // written by hand (and its own older docs) put them at the top level.\n const off = (k: string) => j[k] === \"disable\" || p[k] === \"disable\";\n return {\n defaultMode: typeof p.defaultMode === \"string\" && CLAUDE_MODES.includes(p.defaultMode) ? p.defaultMode : null,\n disableAutoMode: off(\"disableAutoMode\"),\n disableBypass: off(\"disableBypassPermissionsMode\"),\n };\n}\n\n/** The `--permission-mode` a relaunch of ONE session re-asserts, or null for no flag at\n * all (spec/CONTROL.md \u00A76 `prompt`). Only a narrowing the session itself chose, and\n * only where it is one:\n *\n * - `plan` always: nothing this harness has is narrower, so it cannot widen anything;\n * - `dontAsk` and `acceptEdits` where the account's own default is at least as wide\n * (`MODE_RANK`), so a re-assertion is never wider than what the machine itself does\n * with no flag. Settings that can't be read mean it isn't re-asserted;\n * - everything else \u2014 `default`, `manual`, `auto`, `bypassPermissions`, nothing\n * recorded \u2014 is no flag, and the account's own default decides.\n *\n * The default it compares against is the account's own (`permissions.defaultMode`, user\n * scope). A folder's settings or a managed policy may narrow that further, invisibly\n * here; both narrow what the re-asserted mode can actually do too, so the comparison\n * errs on the side of asking.\n *\n * It never returns `auto` or `bypassPermissions`: the two values a setting can quietly\n * turn into something else, and the two this code must never write. `auto` is the\n * incident this came from \u2014 it asks for a mode that `disableAutoMode` turns into Manual,\n * so a session that recorded it gets no flag and the account's default instead.\n *\n * No flag is not neutral. On a fleet whose accounts default to bypass it is the widest\n * outcome there is, which is why a narrowing the person chose has to be said again. */\nexport function relaunchMode(recorded: string | null | undefined, home: HomeSettings): string | null {\n if (recorded === \"plan\") return recorded;\n if ((recorded === \"dontAsk\" || recorded === \"acceptEdits\") && modeRank(home.defaultMode) >= modeRank(recorded))\n return recorded;\n return null;\n}\n\n/** Written in the last 90 s, and not by a job of ours. */\nexport function recentlyWritten(file: string, ourLastEnd?: number, now = Date.now()): boolean {\n let m: number;\n try {\n m = statSync(file).mtimeMs;\n } catch {\n return false;\n }\n if (now - m > LIVE_WRITE_MS) return false;\n return !(ourLastEnd && m <= ourLastEnd + 2000);\n}\n\n/** Run one headless turn (headless.ts). Streaming (`--output-format stream-json`), only\n * the `result` line is kept for the RunResult unless the caller says otherwise. */\nexport function runClaude(bin: string, args: string[], o: RunOptions): Promise<RunResult> {\n return runHeadless(bin, args, { ...o, keep: o.keep ?? ((line) => line.includes('\"type\":\"result\"')) });\n}\n\nexport interface ClaudeResult {\n type?: string;\n result?: unknown;\n is_error?: boolean;\n subtype?: string;\n session_id?: unknown;\n permission_denials?: { tool_name?: unknown }[];\n}\n\n/** `--output-format json`: one result object, or an array whose last `result` entry it is. */\nexport function parseResult(stdout: string | null | undefined): ClaudeResult | null {\n const s = String(stdout || \"\").trim();\n if (!s) return null;\n const pick = (j: unknown): ClaudeResult | null => {\n if (Array.isArray(j)) {\n for (let i = j.length - 1; i >= 0; i--) if (j[i]?.type === \"result\") return j[i];\n return null;\n }\n return j && typeof j === \"object\" ? (j as ClaudeResult) : null;\n };\n try {\n return pick(JSON.parse(s));\n } catch {}\n const lines = s.split(\"\\n\");\n for (let i = lines.length - 1; i >= 0; i--) {\n try {\n const j = pick(JSON.parse(lines[i] as string));\n if (j && (j.type === \"result\" || \"result\" in j)) return j;\n } catch {}\n }\n return null;\n}\n\nexport const isUuid = (s: unknown): s is string => typeof s === \"string\" && UUID_RE.test(s);\n", "// SPDX-License-Identifier: Apache-2.0\n// The one verifier for signed control commands (spec/CONTROL.md \u00A74\u2013\u00A75). A machine\n// runs a command only when this says yes; a receiver MAY run it too, as an early\n// word, so a bad command is refused where the person can see why.\n//\n// WebCrypto only (globalThis.crypto.subtle), no node: imports, no clock of its own\n// (`now` is passed in): the same file runs in a Cloudflare Worker, in a browser and\n// in Node \u2265 20, and conformance/control-vectors/ pins its answers.\n//\n// Every signature covers the EXACT bytes as transmitted (`cmd`, `grant.str`): the\n// strings are parsed to read their fields and never re-serialized to verify.\n\n/** One passkey tap vouches for a day key for at most this long. */\nexport const GRANT_MAX_MS = 24 * 3600_000;\n/** Clock slack between the signing device, the receiver and the machine. */\nexport const SKEW_MS = 5 * 60_000;\n/** The machine judges a command by when it was SIGNED: a message sent while the lid\n * was shut still runs when the machine wakes, up to a day later. */\nexport const MACHINE_MAX_AGE_MS = 24 * 3600_000;\n/** A receiver's early check is stricter: a command is carried within ten minutes of\n * being signed, or not at all. */\nexport const RECEIVER_MAX_AGE_MS = 10 * 60_000;\n/** How long a machine remembers a nonce: longer than MACHINE_MAX_AGE_MS + SKEW_MS. */\nexport const NONCE_TTL_MS = 25 * 3600_000;\n/** The whole command string, in UTF-16 code units (what JSON.parse sees). */\nexport const CMD_MAX = 48_000;\n/** A prompt's text, in characters. */\nexport const TEXT_MAX = 20_000;\n/** A permission answer's note. */\nexport const NOTE_MAX = 2_000;\n/** A grant string. */\nexport const GRANT_STR_MAX = 2_000;\n/** Attachments on a `start` or a `prompt` (CONTROL.md \u00A73.1): at most this many files, */\nexport const FILES_MAX = 10;\n/** each at most this many bytes, */\nexport const FILE_SIZE_MAX = 26_214_400;\n/** together at most this many, */\nexport const FILES_TOTAL_MAX = 52_428_800;\n/** with a name of at most this many characters (after NFC) */\nexport const FILE_NAME_MAX = 200;\n/** and a media type of at most this many. */\nexport const FILE_TYPE_MAX = 100;\n/** A start's `model` (CONTROL.md \u00A73.1): at most this many characters, */\nexport const MODEL_MAX = 100;\n/** in this alphabet, never starting with a dash, so it can never read as a flag. */\nexport const MODEL_RE = /^[A-Za-z0-9][A-Za-z0-9._:/@[\\]-]*$/;\n/** The levels a start may ask for (CONTROL.md \u00A73.1), narrowest first. Closed: no level\n * is wider than `auto`, and none turns a harness's approval off. */\nexport const START_PERMISSIONS = [\"read\", \"safe\", \"edits\", \"auto\"] as const;\nexport type StartPermission = (typeof START_PERMISSIONS)[number];\n/** What a run is started with: a level, or `inherit` (CONTROL.md \u00A72) \u2014 no permission\n * flag at all, so the harness starts in its own default on the machine. Only a machine\n * the person put in inherit mode runs that way; a command never names it. */\nexport type RunLevel = StartPermission | \"inherit\";\n\n/** Where a level sits, narrowest (0) to widest; -1 for anything that isn't one. */\nexport const levelRank = (l: unknown): number => START_PERMISSIONS.indexOf(l as StartPermission);\n/** The narrower of two levels: what a later run of a session gets, its recorded level\n * against what the machine's mode allows now. */\nexport const narrower = (a: StartPermission, b: StartPermission): StartPermission =>\n levelRank(a) <= levelRank(b) ? a : b;\n\nexport const COMMAND_TYPE = \"sessionpipe.control\";\nexport const GRANT_TYPE = \"sessionpipe.grant\";\nexport const CONTROL_KINDS = [\"prompt\", \"permission.answer\", \"cancel\", \"start\", \"key.add\", \"pool\"] as const;\n/** The session a `key.add` names: the machine's own key store, not a coding session. */\nexport const KEY_STORE_SESSION = \"sessionpipe:keys\";\n/** The session a `pool` names: the machine's account pool (CONTROL.md \u00A76 `pool`). */\nexport const POOL_SESSION = \"sessionpipe:pool\";\nexport type ControlKind = (typeof CONTROL_KINDS)[number];\n/** What a `pool` command may ask (CONTROL.md \u00A76 `pool`). Closed: an action added later\n * is refused by every machine that predates it. */\nexport const POOL_ACTIONS = [\n \"on\",\n \"off\",\n \"enable\",\n \"disable\",\n \"remove\",\n \"order\",\n \"refresh\",\n \"login.begin\",\n \"login.complete\",\n] as const;\nexport type PoolAction = (typeof POOL_ACTIONS)[number];\n/** A pooled account's id (or a pending sign-in's): what `session.account_id` carries. */\nexport const POOL_ACCOUNT_RE = /^[A-Za-z0-9._:-]{1,128}$/;\n/** An `order` names at most this many accounts: the pool holds no more. */\nexport const POOL_ORDER_MAX = 20;\n/** The pasted `code#state` of a sign-in, in characters, on one line. */\nexport const POOL_CODE_MAX = 512;\n\n/** COSE algorithm ids a trusted key may use. */\nexport const ES256 = -7;\nexport const RS256 = -257;\n\n/** The kinds of key a machine may trust (CONTROL.md \u00A72): a WebAuthn passkey, or a\n * device key an app holds in hardware where it has no passkey to offer. */\nexport const KEY_TYPES = [\"passkey\", \"device\"] as const;\nexport type KeyType = (typeof KEY_TYPES)[number];\n\n/** A key enrolled on the machine: a passkey's credential id, COSE alg and SPKI\n * (base64url); a device key also says so (`type`), and what its app declared about\n * it (`store`, `uv`). The machine verifies by its own record, never by a message. */\nexport interface TrustedKey {\n id: string;\n alg: number;\n spki: string;\n /** Present only on a device key (CONTROL.md \u00A72 \"Device keys\"). */\n type?: \"device\";\n store?: \"hardware\";\n uv?: \"each-use\";\n}\n/** A WebAuthn assertion: credential id, authenticatorData, clientDataJSON, signature (base64url). */\nexport interface Assertion {\n cred: string;\n ad: string;\n cd: string;\n sig: string;\n}\n/** A device key's signature (CONTROL.md \u00A73.2): its id and 64 bytes r\u2016s over deviceMessage(). */\nexport interface DeviceSignature {\n cred: string;\n sig: string;\n}\n/** The day's grant: a passkey's assertion over sha256(str), where str names the day key. */\nexport interface GrantBundle extends Assertion {\n str: string;\n}\n/** The day's grant from a device key: its signature over deviceMessage(\"grant\", rp, sha256(str)). */\nexport interface DeviceGrant extends DeviceSignature {\n str: string;\n}\n/** What a receiver carries for one command (control.json minus the receiver's envelope). */\nexport interface SignedCommand {\n cmd: string;\n csig?: string | null;\n grant?: GrantBundle | DeviceGrant | null;\n confirm?: Assertion | DeviceSignature | null;\n}\nexport interface Grant {\n v: 1;\n t: typeof GRANT_TYPE;\n pub: string;\n iat: number;\n exp: number;\n rp: string;\n}\n/** One file attached to a `start`: the bytes live on the receiver, named by their hash. */\nexport interface ControlFile {\n /** The file name the machine writes (NFC). */\n name: string;\n /** Media type, `type/subtype`. */\n type: string;\n /** Bytes. */\n size: number;\n /** SHA-256 of the bytes, base64url without padding (43 characters). */\n sha256: string;\n}\nexport interface ControlCommand {\n v: 1;\n t: typeof COMMAND_TYPE;\n machine: string;\n kind: ControlKind;\n /** `<harness>:<id>`, e.g. `claude-code:8c132906-\u2026`. */\n session: string;\n text?: string;\n for?: string;\n decision?: \"allow\" | \"deny\";\n note?: string;\n cwd?: string;\n /** key.add only: the key to trust from now on, as the receiver holds it (a passkey,\n * or a device key with its `type`, `store` and `uv`). */\n key?: TrustedKey;\n /** key.add only: what the person calls the device (\"iPhone\"), for `control keys`. */\n name?: string;\n /** start, prompt: files to download, verify and write into the session's folder. */\n files?: ControlFile[];\n /** start only: the level the new session runs at (never above the machine's mode). */\n permission?: StartPermission;\n /** start only: the model the harness runs, as the harness names it. */\n model?: string;\n /** pool only (session `sessionpipe:pool`): what to do with the account pool. */\n pool_action?: PoolAction;\n /** pool: the account (enable, disable, remove, refresh), or the pending sign-in's id\n * (login.complete). */\n pool_account?: string;\n /** pool, order: every account of the pool once, in the order wanted. */\n pool_order?: string[];\n /** pool, login.complete: the `code#state` the person pasted back. */\n pool_code?: string;\n /** start, prompt: `<harness>:<id>` of a session on the same machine that gets the\n * answer as a message once the turn ends (CONTROL.md \u00A76, a handoff). */\n reply_to?: string;\n nonce: string;\n iat: number;\n}\n\n/** Why a command was refused. Stable: conformance vectors and acks name these. */\nexport type RefusalCode =\n | \"malformed\"\n | \"not_a_command\"\n | \"wrong_machine\"\n | \"unknown_kind\"\n | \"bad_session\"\n | \"bad_fields\"\n | \"bad_nonce\"\n | \"too_old\"\n | \"future\"\n | \"unsigned\"\n | \"untrusted_key\"\n | \"bad_assertion\"\n | \"bad_grant\"\n | \"outside_grant\"\n | \"bad_csig\"\n | \"replay\"\n | \"nonce_store\";\n\nexport type Verdict =\n | { ok: true; cmd: ControlCommand; via: \"grant\" | \"confirm\"; key: string }\n | { ok: false; code: RefusalCode; why: string };\n\nexport interface VerifyOptions {\n /** This machine's id; a command for another machine is refused. */\n machine: string;\n /** The receiver's WebAuthn rp id the keys were enrolled for (well-known control.signing.rp_id). */\n rpId: string;\n /** The keys enrolled on this machine (or, for a receiver's early check, the account's). */\n trusted: TrustedKey[];\n /** Epoch ms. */\n now: number;\n /** MACHINE_MAX_AGE_MS on a machine (default), RECEIVER_MAX_AGE_MS on a receiver. */\n maxAgeMs?: number;\n /** Called once, last, only for a command whose signatures all verified: answer\n * true when the nonce was seen before, otherwise record it (durably) and answer\n * false. A throw refuses the command (`nonce_store`): never run what could not\n * be remembered. Omit it on a receiver's early check. */\n seenNonce?: (nonce: string) => boolean | Promise<boolean>;\n}\n\nconst NONCE_RE = /^[A-Za-z0-9_-]{22,64}$/;\nconst MACHINE_RE = /^m_[A-Za-z0-9_-]{16,40}$/;\nconst HARNESS_RE = /^[a-z][a-z0-9-]{0,39}$/;\nconst SESSION_ID_RE = /^[A-Za-z0-9._:-]{1,128}$/;\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nconst B64URL_RE = /^[A-Za-z0-9_-]*$/;\nconst SHA256_RE = /^[A-Za-z0-9_-]{43}$/;\nconst MEDIA_TYPE_RE = /^[a-z0-9][a-z0-9!#$&^_.+-]*\\/[a-z0-9][a-z0-9!#$&^_.+-]*$/i;\n// biome-ignore lint/suspicious/noControlCharactersInRegex: control characters are exactly what it rejects\nconst BAD_NAME_CHAR_RE = /[/\\\\\\x00-\\x1f\\x7f]/;\nconst UP = 0x01;\nconst UV = 0x04;\n\n/** The fields each kind carries besides the common ones (CONTROL.md \u00A73.1). The set is\n * closed: a field it doesn't list is `bad_fields`, so a field added later fails closed\n * on a machine that predates it instead of being ignored. */\nconst COMMON_FIELDS: readonly string[] = [\"v\", \"t\", \"machine\", \"kind\", \"session\", \"nonce\", \"iat\", \"note\"];\nconst FIELDS: Record<ControlKind, readonly string[]> = {\n prompt: [\"text\", \"files\", \"reply_to\"],\n \"permission.answer\": [\"for\", \"decision\"],\n cancel: [],\n start: [\"text\", \"cwd\", \"files\", \"permission\", \"model\", \"reply_to\"],\n \"key.add\": [\"key\", \"name\"],\n pool: [\"pool_action\", \"pool_account\", \"pool_order\", \"pool_code\"],\n};\n/** The fields only a `pool` carries. */\nconst POOL_FIELDS = FIELDS.pool;\n\n// --- encodings ------------------------------------------------------------------\n\nconst enc = new TextEncoder();\nconst dec = new TextDecoder();\n\nexport function b64url(bytes: Uint8Array | ArrayBuffer): string {\n const u = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);\n let s = \"\";\n for (const b of u) s += String.fromCharCode(b);\n return btoa(s).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\n/** base64url without padding, strictly; null for anything else. */\nexport function fromB64url(s: unknown): Uint8Array | null {\n if (typeof s !== \"string\" || !B64URL_RE.test(s) || s.length % 4 === 1) return null;\n try {\n const bin = atob(s.replace(/-/g, \"+\").replace(/_/g, \"/\") + \"===\".slice((s.length + 3) % 4));\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n } catch {\n return null;\n }\n}\n\nexport async function sha256(data: string | Uint8Array): Promise<Uint8Array> {\n const bytes = typeof data === \"string\" ? enc.encode(data) : data;\n return new Uint8Array(await crypto.subtle.digest(\"SHA-256\", bytes as Uint8Array<ArrayBuffer>));\n}\n\nfunction concat(a: Uint8Array, b: Uint8Array): Uint8Array {\n const out = new Uint8Array(a.length + b.length);\n out.set(a, 0);\n out.set(b, a.length);\n return out;\n}\n\n/** Equal, compared whole: a mismatch costs the same as a match. */\nexport function sameBytes(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false;\n let d = 0;\n for (let i = 0; i < a.length; i++) d |= (a[i] as number) ^ (b[i] as number);\n return d === 0;\n}\n\n/** A DER ECDSA signature (what WebAuthn returns) as the 64-byte r\u2016s WebCrypto verifies.\n * Strict: every length must match the bytes, so one signature has one encoding (a\n * P-256 signature is at most 72 bytes, so the short length form is the only one). */\nexport function derToRaw(der: Uint8Array): Uint8Array | null {\n if (der[0] !== 0x30 || der.length < 8 || der[1] !== der.length - 2) return null;\n let i = 2;\n const part = (): Uint8Array | null => {\n if (der[i] !== 0x02) return null;\n const len = der[i + 1] as number;\n if (len < 1 || len > 33) return null;\n let v = der.slice(i + 2, i + 2 + len);\n if (v.length !== len) return null;\n // Minimal integers only: no needless leading zero, and never negative.\n if ((v[0] as number) & 0x80) return null;\n if (len > 1 && v[0] === 0 && !((v[1] as number) & 0x80)) return null;\n i += 2 + len;\n while (v.length > 32 && v[0] === 0) v = v.slice(1);\n if (v.length > 32) return null;\n const out = new Uint8Array(32);\n out.set(v, 32 - v.length);\n return out;\n };\n const r = part();\n const s = part();\n return r && s && i === der.length ? concat(r, s) : null;\n}\n\nconst u8 = (b: Uint8Array) => b as Uint8Array<ArrayBuffer>;\n/** WebCrypto's key type, named without the DOM lib (Workers, Node and browsers all have it). */\ntype CryptoKey = Awaited<ReturnType<typeof crypto.subtle.importKey>>;\n\nasync function importKey(key: TrustedKey): Promise<CryptoKey | null> {\n const spki = fromB64url(key.spki);\n if (!spki?.length) return null;\n try {\n if (key.alg === ES256)\n return await crypto.subtle.importKey(\"spki\", u8(spki), { name: \"ECDSA\", namedCurve: \"P-256\" }, false, [\"verify\"]);\n if (key.alg === RS256) {\n const k = await crypto.subtle.importKey(\"spki\", u8(spki), { name: \"RSASSA-PKCS1-v1_5\", hash: \"SHA-256\" }, false, [\n \"verify\",\n ]);\n const bits = (k.algorithm as { modulusLength?: number }).modulusLength as number; // every RSA key has one\n return bits >= 2048 ? k : null;\n }\n } catch {}\n return null;\n}\n\nconst PASSKEY_FIELDS = new Set([\"id\", \"alg\", \"spki\"]);\nconst DEVICE_FIELDS = new Set([\"id\", \"alg\", \"spki\", \"type\", \"store\", \"uv\"]);\n/** The only fields a device signature has (`str` only in a grant). */\nexport const DEVICE_SIG_FIELDS = [\"cred\", \"sig\", \"str\"] as const;\n\n/** A device key's id: the SHA-256 of its SPKI bytes, base64url without padding. */\nexport async function deviceKeyId(spki: string): Promise<string> {\n return b64url(await sha256(fromB64url(spki) ?? new Uint8Array()));\n}\n\n/** A device key's declared rules, ignoring any bookkeeping fields a store keeps beside\n * them (a name, when it was added): ES256, hardware, verified each use, named by its\n * SPKI's hash, and a P-256 key WebCrypto can import. */\nasync function deviceRecordValid(key: TrustedKey): Promise<boolean> {\n if (key.type !== \"device\" || key.alg !== ES256 || key.store !== \"hardware\" || key.uv !== \"each-use\") return false;\n if (typeof key.id !== \"string\" || !SHA256_RE.test(key.id) || key.id !== (await deviceKeyId(key.spki))) return false;\n return !!(await importKey(key));\n}\n\n/** Can this key be enrolled at all? A machine refuses to trust a key it could never\n * verify with. The key's fields are closed: a passkey is `id`, `alg`, `spki` and\n * nothing else; a device key adds exactly `type`, `store` and `uv` (CONTROL.md \u00A72),\n * so a kind added later is refused by every machine that predates it. */\nexport async function keyUsable(key: TrustedKey): Promise<boolean> {\n if (!key || typeof key !== \"object\" || Array.isArray(key)) return false;\n const fields = Object.keys(key).filter((k) => (key as unknown as Record<string, unknown>)[k] !== undefined);\n if (\"type\" in key && key.type !== undefined) {\n if (!fields.every((f) => DEVICE_FIELDS.has(f))) return false;\n return deviceRecordValid(key);\n }\n if (!fields.every((f) => PASSKEY_FIELDS.has(f))) return false;\n return (\n typeof key.id === \"string\" &&\n /^[A-Za-z0-9_-]{16,1400}$/.test(key.id) &&\n (key.alg === ES256 || key.alg === RS256) &&\n !!(await importKey(key))\n );\n}\n\n// --- WebAuthn -------------------------------------------------------------------\n\n/** A WebAuthn origin a key may have been used from: https on the rp id or a subdomain;\n * for rp id `localhost`, plain http on any port too. A bare origin, as a browser writes it. */\nexport function originAllowed(origin: unknown, rpId: string): boolean {\n if (typeof origin !== \"string\" || !rpId) return false;\n let u: URL;\n try {\n u = new URL(origin);\n } catch {\n return false;\n }\n if (u.origin !== origin) return false;\n if (u.hostname !== rpId && !u.hostname.endsWith(`.${rpId}`)) return false;\n if (u.protocol === \"https:\") return true;\n return u.protocol === \"http:\" && rpId === \"localhost\";\n}\n\ntype Check = { ok: true } | { ok: false; why: string };\nconst no = (why: string): Check => ({ ok: false, why });\n\n// --- device keys (CONTROL.md \u00A73.2) ------------------------------------------------\n\n/** The first line of every message a device key signs. */\nexport const DEVICE_CONTEXT = \"sessionpipe.device.v1\";\n/** What a device signature is for: one use can never answer for another. */\nexport type DevicePurpose = \"grant\" | \"confirm\" | \"pair\";\n\n/** The exact bytes a device key signs: the context, the purpose, the rp id as the\n * machine recorded it, and the base64url (no padding) of the 32-byte challenge a\n * passkey would sign for that purpose, joined by single line feeds, none at the end. */\nexport function deviceMessage(purpose: DevicePurpose, rpId: string, challenge: Uint8Array): Uint8Array {\n return enc.encode(`${DEVICE_CONTEXT}\\n${purpose}\\n${rpId}\\n${b64url(challenge)}`);\n}\n\n/** One device signature over `challenge` for `purpose`, made with the device key `key`. */\nasync function verifyDeviceSignature(\n challenge: Uint8Array,\n a: object,\n key: TrustedKey,\n rpId: string,\n purpose: DevicePurpose,\n): Promise<Check> {\n const sig = a as Record<string, unknown>;\n for (const f of Object.keys(sig)) {\n if (f === \"str\" && purpose === \"grant\") continue;\n if (f !== \"cred\" && f !== \"sig\") return no(`a device key's signature carries no ${f}`);\n }\n if (sig.cred !== key.id) return no(\"signed with a key this machine doesn't trust\");\n if (!(await deviceRecordValid(key))) return no(\"a trusted key is unusable\");\n const raw = fromB64url(sig.sig);\n if (raw?.length !== 64) return no(\"a device key's signature is 64 bytes, r\u2016s\");\n const pub = await importKey(key);\n /* v8 ignore next -- deviceRecordValid imported it already */\n if (!pub) return no(\"a trusted key is unusable\");\n let good = false;\n try {\n good = await crypto.subtle.verify(\n { name: \"ECDSA\", hash: \"SHA-256\" },\n pub,\n u8(raw),\n u8(deviceMessage(purpose, rpId, challenge)),\n );\n } catch {\n /* v8 ignore next -- WebCrypto answers false for a bad signature; a throw is a broken runtime */\n good = false;\n }\n return good ? { ok: true } : no(\"the device key's signature doesn't verify\");\n}\n\n/** One signature over `challenge` by `key`, chosen from the machine's own record of\n * the key, never from the signature: a device key's signature for `purpose`\n * (CONTROL.md \u00A73.2), or a passkey assertion made by a verified person. */\nexport async function verifyAssertion(\n challenge: Uint8Array,\n a: Assertion | DeviceSignature | null | undefined,\n key: TrustedKey,\n rpId: string,\n purpose: DevicePurpose,\n): Promise<Check> {\n if (!a || typeof a !== \"object\") return no(\"no passkey signature\");\n if (key.type !== undefined) {\n if (key.type !== \"device\") return no(\"a trusted key is unusable\");\n return verifyDeviceSignature(challenge, a, key, rpId, purpose);\n }\n return verifyPasskeyAssertion(challenge, a as Assertion, key, rpId);\n}\n\nasync function verifyPasskeyAssertion(\n challenge: Uint8Array,\n a: Assertion,\n key: TrustedKey,\n rpId: string,\n): Promise<Check> {\n if (a.cred !== key.id) return no(\"signed with a key this machine doesn't trust\");\n const cdBytes = fromB64url(a.cd);\n const ad = fromB64url(a.ad);\n const sig = fromB64url(a.sig);\n if (!cdBytes || !ad || !sig?.length) return no(\"the passkey signature is malformed\");\n let cd: { type?: unknown; challenge?: unknown; origin?: unknown; crossOrigin?: unknown };\n try {\n cd = JSON.parse(dec.decode(cdBytes));\n } catch {\n return no(\"the passkey signature is malformed\");\n }\n if (!cd || typeof cd !== \"object\") return no(\"the passkey signature is malformed\");\n if (cd.type !== \"webauthn.get\") return no(\"the passkey answered a different question\");\n if (cd.challenge !== b64url(challenge)) return no(\"the passkey signed something else\");\n if (!originAllowed(cd.origin, rpId)) return no(`the passkey was used on another site, not ${rpId}`);\n if (cd.crossOrigin === true) return no(\"the passkey was used inside another site's frame\");\n if (ad.length < 37) return no(\"the passkey signature is malformed\");\n if (!sameBytes(ad.slice(0, 32), await sha256(rpId))) return no(`the passkey belongs to another site, not ${rpId}`);\n const flags = ad[32] as number;\n if (!(flags & UP) || !(flags & UV)) return no(\"the passkey signed without verifying the person\");\n const pub = await importKey(key);\n if (!pub) return no(\"a trusted key is unusable\");\n const signed = concat(ad, await sha256(cdBytes));\n let good = false;\n try {\n if (key.alg === ES256) {\n const raw = derToRaw(sig);\n good = !!raw && (await crypto.subtle.verify({ name: \"ECDSA\", hash: \"SHA-256\" }, pub, u8(raw), u8(signed)));\n } else {\n good = await crypto.subtle.verify({ name: \"RSASSA-PKCS1-v1_5\" }, pub, u8(sig), u8(signed));\n }\n } catch {\n good = false;\n }\n return good ? { ok: true } : no(\"the passkey signature doesn't verify\");\n}\n\n/** What a passkey signs to enroll on a machine: bound to that machine and that pairing code. */\nexport function pairChallenge(machine: string, code: string): Promise<Uint8Array> {\n return sha256(`sessionpipe.pair:${machine}:${code}`);\n}\n\n/** The enrollment proof: the new key's assertion over pairChallenge(machine, code).\n * Only after this verifies does the key go into the machine's trust store. */\nexport async function verifyEnrollment(o: {\n machine: string;\n code: string;\n key: TrustedKey;\n proof: Assertion | DeviceSignature;\n rpId: string;\n}): Promise<Check> {\n if (!(await keyUsable(o.key))) return no(\"the key is in a shape this machine can't use\");\n return verifyAssertion(await pairChallenge(o.machine, o.code), o.proof, o.key, o.rpId, \"pair\");\n}\n\n// --- the command ------------------------------------------------------------------\n\ntype Parsed = { ok: true; cmd: ControlCommand } | { ok: false; code: RefusalCode; why: string };\nconst bad = (code: RefusalCode, why: string): { ok: false; code: RefusalCode; why: string } => ({\n ok: false,\n code,\n why,\n});\nconst isNum = (n: unknown): n is number => typeof n === \"number\" && Number.isFinite(n);\n\n/** The session id rule per harness (ADAPTERS.md): Claude Code ids are UUIDs. */\nexport function sessionIdOk(harness: string, id: string): boolean {\n if (!SESSION_ID_RE.test(id)) return false;\n if (harness === \"claude-code\") return UUID_RE.test(id);\n return true;\n}\n\n/** Split `<harness>:<id>`; null when either half breaks its rule. */\nexport function parseSessionRef(ref: unknown): { harness: string; id: string } | null {\n if (typeof ref !== \"string\") return null;\n const i = ref.indexOf(\":\");\n if (i <= 0) return null;\n const harness = ref.slice(0, i);\n const id = ref.slice(i + 1);\n return HARNESS_RE.test(harness) && sessionIdOk(harness, id) ? { harness, id } : null;\n}\n\n/** Read the command's fields from the exact string. Structure only; no clock, no keys. */\nexport function parseCommand(str: unknown): Parsed {\n if (typeof str !== \"string\" || !str || str.length > CMD_MAX)\n return bad(\"malformed\", \"the command is missing or too long\");\n let c: Record<string, unknown>;\n try {\n c = JSON.parse(str);\n } catch {\n return bad(\"malformed\", \"the command is not JSON\");\n }\n if (!c || typeof c !== \"object\" || Array.isArray(c)) return bad(\"malformed\", \"the command is not an object\");\n if (c.v !== 1 || c.t !== COMMAND_TYPE) return bad(\"not_a_command\", \"not a sessionpipe control command\");\n if (typeof c.machine !== \"string\" || !MACHINE_RE.test(c.machine)) return bad(\"malformed\", \"which machine?\");\n if (!CONTROL_KINDS.includes(c.kind as ControlKind))\n return bad(\"unknown_kind\", \"the command asks for something unknown\");\n const ref = parseSessionRef(c.session);\n if (!ref) return bad(\"bad_session\", \"which session?\");\n if (typeof c.nonce !== \"string\" || !NONCE_RE.test(c.nonce))\n return bad(\"bad_nonce\", \"the nonce is missing or malformed\");\n if (!isNum(c.iat) || !Number.isInteger(c.iat) || c.iat <= 0)\n return bad(\"malformed\", \"the command has no signing time\");\n const has = (k: string) => c[k] !== undefined;\n const text = () => typeof c.text === \"string\" && c.text.trim().length > 0 && c.text.length <= TEXT_MAX;\n // A handoff's reply_to (CONTROL.md \u00A76): a session ref by the adapter's rule, never the\n // command's own session. Whether that session is on this machine is the daemon's to say.\n const replyToProblem = (): string | null => {\n if (!has(\"reply_to\")) return null;\n if (!parseSessionRef(c.reply_to)) return \"a reply_to names a session on this machine, <harness>:<id>\";\n if (c.reply_to === c.session) return \"a reply_to can't name the command's own session\";\n return null;\n };\n switch (c.kind as ControlKind) {\n case \"prompt\": {\n if (!text()) return bad(\"bad_fields\", `a prompt needs text, at most ${TEXT_MAX} characters`);\n if (has(\"for\") || has(\"decision\") || has(\"cwd\"))\n return bad(\"bad_fields\", \"a prompt carries text, files and a reply_to\");\n if (has(\"files\")) {\n const why = filesProblem(c.files);\n if (why) return bad(\"bad_fields\", why);\n }\n const why = replyToProblem();\n if (why) return bad(\"bad_fields\", why);\n break;\n }\n case \"start\": {\n if (!text()) return bad(\"bad_fields\", `a new session needs text, at most ${TEXT_MAX} characters`);\n if (typeof c.cwd !== \"string\" || !(isAbsolute(c.cwd) || HOME_RELATIVE_RE.test(c.cwd)) || c.cwd.length > 1024)\n return bad(\"bad_fields\", \"a new session needs an absolute folder, or one under ~\");\n if (has(\"for\") || has(\"decision\"))\n return bad(\"bad_fields\", \"a start carries text, cwd, files, a permission, a model and a reply_to\");\n if (has(\"files\")) {\n const why = filesProblem(c.files);\n if (why) return bad(\"bad_fields\", why);\n }\n const why = replyToProblem();\n if (why) return bad(\"bad_fields\", why);\n if (has(\"permission\") && levelRank(c.permission) < 0)\n return bad(\"bad_fields\", `a permission is one of ${START_PERMISSIONS.join(\", \")}`);\n if (has(\"model\") && (typeof c.model !== \"string\" || c.model.length > MODEL_MAX || !MODEL_RE.test(c.model)))\n return bad(\"bad_fields\", `a model is 1 to ${MODEL_MAX} letters, digits and ._:/@[]-, not starting with a dash`);\n break;\n }\n case \"permission.answer\":\n if (typeof c.for !== \"string\" || !c.for || c.for.length > 128) return bad(\"bad_fields\", \"which attention?\");\n if (c.decision !== \"allow\" && c.decision !== \"deny\") return bad(\"bad_fields\", \"allow or deny?\");\n if (has(\"text\") || has(\"cwd\")) return bad(\"bad_fields\", \"a permission answer carries for, decision and note\");\n break;\n case \"cancel\":\n if (has(\"text\") || has(\"for\") || has(\"decision\") || has(\"cwd\"))\n return bad(\"bad_fields\", \"a cancel carries nothing\");\n break;\n case \"key.add\": {\n // A device the machine already trusts vouches for a new one (CONTROL.md \u00A72): the\n // new key's id, algorithm and public key (and, for a device key, its type, store\n // and uv) are inside the signed bytes.\n if (c.session !== KEY_STORE_SESSION) return bad(\"bad_session\", `a key.add names ${KEY_STORE_SESSION}`);\n const k = c.key as Record<string, unknown> | undefined;\n const b64 = (v: unknown, min: number, max: number) =>\n typeof v === \"string\" && v.length >= min && v.length <= max && /^[A-Za-z0-9_-]+$/.test(v);\n if (\n !k ||\n typeof k !== \"object\" ||\n Array.isArray(k) ||\n !b64(k.id, 16, 1400) ||\n (k.alg !== -7 && k.alg !== -257) ||\n !b64(k.spki, 40, 2000)\n )\n return bad(\"bad_fields\", \"a key.add carries the key: id, alg (-7 or -257) and spki\");\n if (k.type !== undefined) {\n if (k.type !== \"device\") return bad(\"bad_fields\", \"a key's type is device, or absent for a passkey\");\n if (k.alg !== ES256 || k.store !== \"hardware\" || k.uv !== \"each-use\" || !SHA256_RE.test(k.id as string))\n return bad(\"bad_fields\", \"a device key is ES256, store hardware, uv each-use, named by its SPKI's hash\");\n if (Object.keys(k).some((f) => !DEVICE_FIELDS.has(f)))\n return bad(\"bad_fields\", \"a device key carries id, alg, spki, type, store and uv\");\n } else if (Object.keys(k).some((f) => !PASSKEY_FIELDS.has(f)))\n return bad(\"bad_fields\", \"a passkey carries id, alg and spki: store and uv belong to a device key\");\n if (has(\"name\") && (typeof c.name !== \"string\" || !c.name.trim() || c.name.length > 80))\n return bad(\"bad_fields\", \"a device name is text, at most 80 characters\");\n if (has(\"text\") || has(\"for\") || has(\"decision\") || has(\"cwd\"))\n return bad(\"bad_fields\", \"a key.add carries the key and a name\");\n break;\n }\n case \"pool\": {\n if (c.session !== POOL_SESSION) return bad(\"bad_session\", `a pool command names ${POOL_SESSION}`);\n const why = poolProblem(c);\n if (why) return bad(\"bad_fields\", why);\n break;\n }\n }\n if (c.kind !== \"key.add\" && (has(\"key\") || has(\"name\"))) return bad(\"bad_fields\", \"only a key.add carries a key\");\n if (c.kind !== \"pool\" && POOL_FIELDS.some(has)) return bad(\"bad_fields\", \"only a pool command carries pool fields\");\n if (c.kind !== \"start\" && c.kind !== \"prompt\" && has(\"files\"))\n return bad(\"bad_fields\", \"only a start or a prompt carries files\");\n if (c.kind !== \"start\" && c.kind !== \"prompt\" && has(\"reply_to\"))\n return bad(\"bad_fields\", \"only a start or a prompt carries a reply_to\");\n if (c.kind !== \"start\" && (has(\"permission\") || has(\"model\")))\n return bad(\"bad_fields\", \"only a start carries a model or a permission\");\n const allowed = FIELDS[c.kind as ControlKind];\n for (const k of Object.keys(c))\n if (!COMMON_FIELDS.includes(k) && !allowed.includes(k))\n return bad(\"bad_fields\", `the command carries a field its kind doesn't have: ${k.slice(0, 40)}`);\n if (has(\"note\") && (typeof c.note !== \"string\" || c.note.length > NOTE_MAX))\n return bad(\"bad_fields\", `a note is text, at most ${NOTE_MAX} characters`);\n return { ok: true, cmd: c as unknown as ControlCommand };\n}\n\n/** Why a `pool` command's fields break the rules (CONTROL.md \u00A76 `pool`), or null when\n * they don't. Each action takes exactly its own fields: an account where the action\n * names one, the whole order for `order`, the pasted code for `login.complete`. The\n * machine still checks the account exists and the order is complete (`refused`). */\nexport function poolProblem(c: Record<string, unknown>): string | null {\n const action = c.pool_action;\n if (!POOL_ACTIONS.includes(action as PoolAction))\n return `a pool command's action is one of ${POOL_ACTIONS.join(\", \")}`;\n const a = action as PoolAction;\n const account = c.pool_account !== undefined;\n const order = c.pool_order !== undefined;\n const code = c.pool_code !== undefined;\n const needsAccount = a === \"enable\" || a === \"disable\" || a === \"remove\" || a === \"login.complete\";\n if (needsAccount && !account) return `${a} names an account`;\n if (account && !needsAccount && a !== \"refresh\") return `${a} names no account`;\n if (account && (typeof c.pool_account !== \"string\" || !POOL_ACCOUNT_RE.test(c.pool_account)))\n return \"an account id is 1 to 128 letters, digits and ._:-\";\n if (order !== (a === \"order\")) return a === \"order\" ? \"order carries the whole order\" : `${a} carries no order`;\n if (order) {\n const o = c.pool_order;\n if (!Array.isArray(o) || o.length < 1 || o.length > POOL_ORDER_MAX)\n return `an order is a list of 1 to ${POOL_ORDER_MAX} account ids`;\n if (!o.every((id) => typeof id === \"string\" && POOL_ACCOUNT_RE.test(id)))\n return \"an account id is 1 to 128 letters, digits and ._:-\";\n if (new Set(o).size !== o.length) return \"an order names each account once\";\n }\n if (code !== (a === \"login.complete\"))\n return a === \"login.complete\" ? \"login.complete carries the pasted code\" : `${a} carries no code`;\n if (\n code &&\n (typeof c.pool_code !== \"string\" ||\n !c.pool_code ||\n c.pool_code.length > POOL_CODE_MAX ||\n /[\\r\\n]/.test(c.pool_code))\n )\n return `a code is 1 to ${POOL_CODE_MAX} characters on one line`;\n return null;\n}\n\n/** Why a start's or a prompt's `files` breaks the rules (CONTROL.md \u00A73.1), or null when it doesn't. */\nexport function filesProblem(files: unknown): string | null {\n if (!Array.isArray(files) || files.length < 1 || files.length > FILES_MAX)\n return `files is a list of 1 to ${FILES_MAX} files`;\n const seen = new Set<string>();\n let total = 0;\n for (const f of files as unknown[]) {\n if (!f || typeof f !== \"object\" || Array.isArray(f)) return \"each file is an object\";\n const { name, type, size, sha256: hash } = f as Record<string, unknown>;\n const why = fileNameProblem(name);\n if (why) return why;\n const key = (name as string).normalize(\"NFC\").toLowerCase();\n if (seen.has(key)) return \"two files have the same name\";\n seen.add(key);\n if (typeof type !== \"string\" || type.length > FILE_TYPE_MAX || !MEDIA_TYPE_RE.test(type))\n return \"a file's type isn't a media type\";\n if (!isNum(size) || !Number.isInteger(size) || size < 1 || size > FILE_SIZE_MAX)\n return `a file is 1 byte to ${FILE_SIZE_MAX / 1_048_576} MiB`;\n total += size;\n if (typeof hash !== \"string\" || !SHA256_RE.test(hash)) return \"a file's sha256 isn't 43 base64url characters\";\n }\n if (total > FILES_TOTAL_MAX) return `the files add up to more than ${FILES_TOTAL_MAX / 1_048_576} MiB`;\n return null;\n}\n\n/** A file name the machine can write inside the session's folder and nowhere else. */\nfunction fileNameProblem(name: unknown): string | null {\n if (typeof name !== \"string\") return \"a file has no name\";\n const n = name.normalize(\"NFC\");\n if (n.length < 1 || n.length > FILE_NAME_MAX) return `a file name is 1 to ${FILE_NAME_MAX} characters`;\n if (BAD_NAME_CHAR_RE.test(n)) return \"a file name has a slash, a backslash or a control character\";\n if (n.startsWith(\".\")) return \"a file name can't start with a dot\";\n return null;\n}\n\n/** A `start`'s `cwd` under the machine's home: `~` alone, or `~/\u2026` (`~\\\u2026`). Never `~user`. */\nexport const HOME_RELATIVE_RE = /^~(?:[\\\\/]|$)/;\n\nfunction isAbsolute(p: string): boolean {\n return p.startsWith(\"/\") || /^[A-Za-z]:[\\\\/]/.test(p);\n}\n\n/** The grant's fields, read from its exact string. */\nexport function parseGrant(str: unknown, rpId: string): { ok: true; grant: Grant } | { ok: false; why: string } {\n if (typeof str !== \"string\" || !str || str.length > GRANT_STR_MAX)\n return { ok: false, why: \"the grant is missing or too long\" };\n let g: Record<string, unknown>;\n try {\n g = JSON.parse(str);\n } catch {\n return { ok: false, why: \"the grant is not JSON\" };\n }\n if (!g || typeof g !== \"object\" || Array.isArray(g)) return { ok: false, why: \"the grant is not an object\" };\n if (g.v !== 1 || g.t !== GRANT_TYPE) return { ok: false, why: \"not a sessionpipe grant\" };\n if (g.rp !== rpId) return { ok: false, why: `the grant is for another site, not ${rpId}` };\n if (typeof g.pub !== \"string\" || !fromB64url(g.pub)?.length || !isNum(g.iat) || !isNum(g.exp))\n return { ok: false, why: \"the grant is missing parts\" };\n if (g.exp <= g.iat) return { ok: false, why: \"the grant ends before it starts\" };\n if (g.exp - g.iat > GRANT_MAX_MS + SKEW_MS) return { ok: false, why: \"the grant lasts longer than a day\" };\n return { ok: true, grant: g as unknown as Grant };\n}\n\nasync function verifyCsig(cmd: string, csig: unknown, pub: string): Promise<boolean> {\n const sig = fromB64url(csig);\n const spki = fromB64url(pub);\n if (sig?.length !== 64 || !spki) return false;\n try {\n const key = await crypto.subtle.importKey(\"spki\", u8(spki), { name: \"ECDSA\", namedCurve: \"P-256\" }, false, [\n \"verify\",\n ]);\n return await crypto.subtle.verify({ name: \"ECDSA\", hash: \"SHA-256\" }, key, u8(sig), u8(enc.encode(cmd)));\n } catch {\n return false;\n }\n}\n\n/**\n * Is this a command this machine may run? The checks, in the spec's order\n * (CONTROL.md \u00A75): the exact bytes parse; the command is for this machine; it is\n * signed \u2014 a grant from a trusted key plus the day key's signature, or a confirm\n * over sha256(cmd); it was signed within the age window; its nonce is new.\n * The folder and open-attention checks that follow are the daemon's (they read\n * the machine, not the command).\n */\nexport async function verifyCommand(s: SignedCommand | null | undefined, o: VerifyOptions): Promise<Verdict> {\n if (!s || typeof s !== \"object\") return bad(\"malformed\", \"nothing to verify\");\n const p = parseCommand(s.cmd);\n if (!p.ok) return p;\n const c = p.cmd;\n if (c.machine !== o.machine) return bad(\"wrong_machine\", \"the command is for another machine\");\n\n let via: \"grant\" | \"confirm\" | null = null;\n let keyId = \"\";\n let refusal: { code: RefusalCode; why: string } | null = null;\n if (s.grant && s.csig) {\n const r = await checkGrantPath(s, c, o);\n if (r.ok) {\n via = \"grant\";\n keyId = r.key;\n } else refusal = r;\n }\n if (!via && s.confirm) {\n const key = o.trusted.find((k) => k && k.id === s.confirm?.cred);\n if (!key) refusal = { code: \"untrusted_key\", why: \"confirmed with a key this machine doesn't trust\" };\n else {\n const a = await verifyAssertion(await sha256(s.cmd), s.confirm, key, o.rpId, \"confirm\");\n if (a.ok) {\n via = \"confirm\";\n keyId = key.id;\n } else refusal = { code: \"bad_assertion\", why: a.why };\n }\n }\n if (!via) {\n if (refusal) return bad(refusal.code, refusal.why);\n return bad(\"unsigned\", \"the command isn't signed\");\n }\n // The key a key.add brings must be one this machine could ever verify with: an\n // SPKI it can import for that alg, and every rule of a device key (CONTROL.md \u00A72).\n if (c.kind === \"key.add\" && !(await keyUsable(c.key as TrustedKey)))\n return bad(\"bad_fields\", \"the key a key.add brings is in a shape this machine can't use\");\n if (c.iat > o.now + SKEW_MS) return bad(\"future\", \"the command is dated in the future (is this clock right?)\");\n if (o.now - c.iat > (o.maxAgeMs ?? MACHINE_MAX_AGE_MS)) return bad(\"too_old\", \"the command was signed too long ago\");\n if (o.seenNonce) {\n let seen: boolean;\n try {\n seen = await o.seenNonce(c.nonce);\n } catch {\n return bad(\"nonce_store\", \"the nonce couldn't be recorded, so the command didn't run\");\n }\n if (seen) return bad(\"replay\", \"this command was already used once\");\n }\n return { ok: true, cmd: c, via, key: keyId };\n}\n\nasync function checkGrantPath(\n s: SignedCommand,\n c: ControlCommand,\n o: VerifyOptions,\n): Promise<{ ok: true; key: string } | { ok: false; code: RefusalCode; why: string }> {\n const bundle = s.grant as GrantBundle | DeviceGrant;\n const g = parseGrant(bundle.str, o.rpId);\n if (!g.ok) return bad(\"bad_grant\", g.why);\n const key = o.trusted.find((k) => k && k.id === bundle.cred);\n if (!key) return bad(\"untrusted_key\", \"the grant was signed with a key this machine doesn't trust\");\n const a = await verifyAssertion(await sha256(bundle.str), bundle, key, o.rpId, \"grant\");\n if (!a.ok) return bad(\"bad_assertion\", a.why);\n if (!(await verifyCsig(s.cmd, s.csig, g.grant.pub)))\n return bad(\"bad_csig\", \"the command's signature doesn't verify \u2014 it was changed after it was signed\");\n if (c.iat < g.grant.iat - SKEW_MS || c.iat > g.grant.exp)\n return bad(\"outside_grant\", \"the command was signed outside its grant's window\");\n return { ok: true, key: key.id };\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// Codex CLI (OpenAI) \u2014 docs: https://learn.chatgpt.com/docs/hooks\n// Config: ~/.codex/hooks.json (Claude-shaped, 12 events, timeouts in seconds) AND\n// `notify` at the top level of config.toml as the fallback when hooks are off or\n// not yet trusted (non-managed hooks need a /hooks review in the CLI). An existing\n// notify (Codex Computer Use) is chained through --previous-notify, never replaced.\nimport { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { homeDir } from \"../paths.js\";\nimport { ends, parseLines, recentFiles, scanLines } from \"../readers/files.js\";\nimport { codexInjected, readCodex } from \"../readers/transcripts.js\";\nimport type { DataOf } from \"../types.js\";\nimport { installClaudeShaped, installedClaudeShaped, uninstallClaudeShaped, writeBack } from \"./claude-shaped.js\";\nimport * as toml from \"./codex-config.js\";\nimport { codexReplayBoundary, codexSubagent } from \"./codex-rollout.js\";\nimport type {\n Adapter,\n BackfillRow,\n HookCommand,\n HookInput,\n HookResult,\n InstalledReport,\n InstallOptions,\n InstallReport,\n SessionFacts,\n} from \"./types.js\";\n\nconst NAME = \"codex\";\nexport const CODEX_EVENTS = [\n \"SessionStart\",\n \"UserPromptSubmit\",\n \"PreToolUse\",\n \"PostToolUse\",\n \"PermissionRequest\",\n \"Stop\",\n \"Interrupt\",\n \"SubagentStart\",\n \"SubagentStop\",\n \"PreCompact\",\n \"PostCompact\",\n \"SessionEnd\",\n] as const;\nconst OPTS = { matcherFor: (e: string) => (/Tool|Permission/.test(e) ? \"\" : undefined), timeout: 5 };\nconst eventsFor = (lean?: boolean) => (lean ? CODEX_EVENTS.filter((e) => e !== \"PreToolUse\") : [...CODEX_EVENTS]);\n\nconst codexHome = (env: NodeJS.ProcessEnv) => env.CODEX_HOME || path.join(homeDir(), \".codex\");\nconst hooksFile = (env: NodeJS.ProcessEnv) => path.join(codexHome(env), \"hooks.json\");\nconst configFile = (env: NodeJS.ProcessEnv) => path.join(codexHome(env), \"config.toml\");\nconst sessionsDir = (env: NodeJS.ProcessEnv) => path.join(codexHome(env), \"sessions\");\n\nconst validTool = (n: unknown): n is string => typeof n === \"string\" && /^[A-Za-z0-9_.:-]{1,120}$/.test(n);\nconst endReason = (r: unknown): \"clear\" | \"logout\" | \"exit\" | \"other\" =>\n r === \"clear\" || r === \"logout\" || r === \"exit\" ? r : \"other\";\n\n/** What config.toml without our notify line means, said with every refusal of it. */\nconst UNTIL_APPROVED =\n \"Codex will report nothing until you approve the hooks: start `codex` and accept the hook review\";\n\nfunction installNotify(cmd: HookCommand, env: NodeJS.ProcessEnv) {\n const file = configFile(env);\n let text = \"\";\n let existed = true;\n try {\n text = readFileSync(file, \"utf8\");\n } catch (e) {\n // Absent only when the system says so: a file that is there but can't be read (0200,\n // root's) is still the person's, never `created` for uninstall to delete.\n existed = (e as NodeJS.ErrnoException).code !== \"ENOENT\";\n }\n const argv = cmd([NAME, \"notify\"]).argv;\n const line = `notify = ${JSON.stringify(argv)}`;\n const n = toml.readNotify(text);\n /** The file written, with this note; or the refusal's report in its place. */\n const write = (next: string, note: string): InstallReport => {\n const bad = writeBack(file, next, existed);\n return bad ? { ...bad, note: `${bad.note}. ${UNTIL_APPROVED}` } : { file, changed: true, note };\n };\n if (n && !n.other) {\n if (!n.misplaced && JSON.stringify(n.argv) === JSON.stringify(argv))\n return { file, changed: false, note: \"notify current\" };\n return write(\n toml.withNotify(text, line),\n n.misplaced\n ? \"notify moved to the top level (it sat inside a [table], where Codex never reads it)\"\n : \"notify updated\",\n );\n }\n if (n?.other) {\n const prev = toml.previousNotify(n.argv);\n if (toml.isComputerUse(n.argv)) {\n if (prev && toml.OURS.test(JSON.stringify(prev))) {\n if (JSON.stringify(prev) === JSON.stringify(argv))\n return { file, changed: false, note: \"notify current (after Codex Computer Use)\" };\n }\n if (!prev || toml.OURS.test(JSON.stringify(prev)))\n return write(\n toml.replaceNotify(text, n, `notify = ${toml.withPreviousRaw(n.raw, argv)}`),\n \"chained after Codex Computer Use (--previous-notify)\",\n );\n }\n return {\n file,\n changed: false,\n skipped: true,\n note: `notify belongs to ${(n.argv?.[0] ?? n.raw).replace(/^.*\\//, \"\").slice(0, 40)}; left alone. ${UNTIL_APPROVED}`,\n };\n }\n return write(toml.withNotify(text, line), \"notify set at the top level\");\n}\n\nfunction uninstallNotify(env: NodeJS.ProcessEnv): InstallReport {\n const file = configFile(env);\n let text: string;\n try {\n text = readFileSync(file, \"utf8\");\n } catch {\n return { file, changed: false };\n }\n const n = toml.readNotify(text);\n if (!n) return { file, changed: false };\n if (!n.other) return writeBack(file, toml.withoutNotify(text)) ?? { file, changed: true };\n const prev = toml.previousNotify(n.argv);\n if (toml.isComputerUse(n.argv) && prev && toml.OURS.test(JSON.stringify(prev)))\n return (\n writeBack(file, toml.replaceNotify(text, n, `notify = ${toml.stripPreviousRaw(n.raw)}`)) ?? {\n file,\n changed: true,\n }\n );\n return { file, changed: false };\n}\n\n/** The rollout file of one thread: `<CODEX_HOME>/sessions/YYYY/MM/DD/rollout-<time>-<thread\n * id>.jsonl`, newest day first. Null for an id that isn't a thread id's shape, so a\n * short or odd one never matches some other session's file. */\nexport function findRollout(threadId: string, env: NodeJS.ProcessEnv = process.env): string | null {\n if (!/^[A-Za-z0-9-]{8,128}$/.test(threadId)) return null;\n let best: string | null = null;\n const walk = (dir: string, depth: number) => {\n let names: string[] = [];\n try {\n names = readdirSync(dir);\n } catch {\n return;\n }\n for (const n of names.sort().reverse()) {\n const p = path.join(dir, n);\n if (n.endsWith(`-${threadId}.jsonl`)) {\n best = p;\n return;\n }\n if (depth < 3) {\n walk(p, depth + 1);\n if (best) return;\n }\n }\n };\n walk(sessionsDir(env), 0);\n return best;\n}\n\n/** A rollout's first record, its own session_meta. About 50 KB (it carries the base\n * instructions), so it is read on its own rather than from a sampled head. */\nfunction rolloutMeta(file: string): Record<string, unknown> | null {\n return scanLines(file, (line) => parseLines([line])[0] ?? {});\n}\n\n/** A rollout named for a thread other than `id` (`rollout-<time>-<thread id>.jsonl`).\n * A name of any other shape says nothing, so it is not taken for another thread's. */\nfunction ofAnotherThread(file: string, id: string): boolean {\n const other = threadOf(file);\n return !!other && other !== id.toLowerCase();\n}\n/** The thread a rollout is named for, lowercased; null for a name of any other shape. */\nfunction threadOf(file: string): string | null {\n const m = /-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\\.jsonl(?:\\.zst)?$/i.exec(file);\n return m?.[1] ? m[1].toLowerCase() : null;\n}\n\nexport const codex: Adapter = {\n name: NAME,\n events: CODEX_EVENTS,\n detect: (env = process.env) => existsSync(codexHome(env)),\n configFiles: (env = process.env) => [hooksFile(env), configFile(env)],\n install: (cmd, env = process.env, opts: InstallOptions = {}) => [\n installClaudeShaped(hooksFile(env), NAME, eventsFor(opts.lean), cmd, OPTS),\n installNotify(cmd, env),\n ],\n uninstall: (env = process.env, opts: InstallOptions = {}) => [\n uninstallClaudeShaped(hooksFile(env), CODEX_EVENTS, { created: opts.created?.includes(hooksFile(env)) }),\n uninstallNotify(env),\n ],\n installed: (cmd, env = process.env, opts: InstallOptions = {}) => {\n const out: InstalledReport[] = [\n {\n file: hooksFile(env),\n state: installedClaudeShaped(hooksFile(env), NAME, eventsFor(opts.lean), cmd, OPTS),\n note: \"Codex runs non-managed hooks only after the review in `codex` (/hooks); until then nothing is reported unless the notify fallback is ours\",\n },\n ];\n let text = \"\";\n try {\n text = readFileSync(configFile(env), \"utf8\");\n } catch {}\n const n = toml.readNotify(text);\n const argv = cmd([NAME, \"notify\"]).argv;\n const prev = n ? toml.previousNotify(n.argv) : null;\n const ours = n && (!n.other || (prev && JSON.stringify(prev) === JSON.stringify(argv)));\n out.push({\n file: configFile(env),\n state:\n !n || (n.other && !ours)\n ? \"missing\"\n : n.misplaced\n ? \"misplaced\"\n : JSON.stringify(n.argv) === JSON.stringify(argv) || (prev && JSON.stringify(prev) === JSON.stringify(argv))\n ? \"current\"\n : \"stale\",\n });\n return out;\n },\n\n fromHook(input: HookInput): HookResult | null {\n const event = input.argv[1] ?? \"\";\n let s: Record<string, unknown> = {};\n if (event === \"notify\") {\n // Codex's notify passes one JSON argument: {\"type\":\"agent-turn-complete\",\"thread-id\":\u2026,\"turn-id\":\u2026,\"cwd\":\u2026}\n const raw = input.argv.find((a) => a.startsWith(\"{\")) ?? input.stdin;\n try {\n const j: unknown = raw ? JSON.parse(raw) : {};\n if (j && typeof j === \"object\" && !Array.isArray(j)) s = j as Record<string, unknown>;\n } catch {}\n const id = (s[\"thread-id\"] ?? s.thread_id ?? s[\"session-id\"] ?? s.session_id) as string | undefined;\n if (!id) return null;\n // Notify names the thread whose turn ended. Without a rollout it is an ephemeral\n // thread, kept nowhere (the hooks' `transcript_path: null` below). A subagent's\n // thread belongs to its parent, whose hooks already report it: SubagentStart and\n // SubagentStop name it as `agent_id`. Neither is a session of its own.\n const file = findRollout(String(id), input.env as NodeJS.ProcessEnv);\n if (!file || codexSubagent(rolloutMeta(file))) return null;\n const r: HookResult = {\n session: { id: String(id), cwd: typeof s.cwd === \"string\" ? s.cwd : input.cwd },\n events: [\n {\n type: \"turn.ended\",\n data: { reason: \"stop\", ...(typeof s[\"turn-id\"] === \"string\" ? { turn_id: s[\"turn-id\"] } : {}) },\n harnessEvent: \"notify\",\n },\n ],\n hints: {},\n transcript: file,\n };\n return r;\n }\n try {\n // A stdin that is JSON but not an object (`null`, a number) is no payload.\n const j: unknown = input.stdin ? JSON.parse(input.stdin) : {};\n if (j && typeof j === \"object\" && !Array.isArray(j)) s = j as Record<string, unknown>;\n } catch {}\n const id = (s.session_id ?? s.thread_id ?? s.conversation_id ?? s[\"thread-id\"] ?? s[\"session-id\"]) as\n | string\n | undefined;\n if (!id) return null;\n // `transcript_path: null` is an ephemeral thread (recorded on codex-cli 0.160.0):\n // Codex Desktop's own background threads (ambient suggestions and their safety\n // review) and `codex exec --ephemeral`. Codex keeps nothing of one, so there is no\n // session to name, read or resume.\n if (s.transcript_path === null) return null;\n const session: HookResult[\"session\"] = { id: String(id), cwd: typeof s.cwd === \"string\" ? s.cwd : input.cwd };\n if (typeof s.model === \"string\") session.model = s.model;\n const turn_id = typeof s.turn_id === \"string\" ? s.turn_id : undefined;\n const tool = validTool(s.tool_name) ? s.tool_name : undefined;\n const call_id = typeof s.tool_use_id === \"string\" ? s.tool_use_id : undefined;\n // A subagent's hooks carry the parent's session_id (ADAPTERS.md, Threads): its own\n // id where the payload names it, else the thread its rollout is named for. Without\n // it a subagent's tool calls read as the main thread's (issue #208: a sink that\n // thins subagents' tool events would be sent every one).\n const thread = typeof s.transcript_path === \"string\" ? threadOf(s.transcript_path) : null;\n const agent_id =\n typeof s.agent_id === \"string\" && s.agent_id\n ? s.agent_id\n : typeof s.subagent_id === \"string\" && s.subagent_id\n ? s.subagent_id\n : thread && thread !== String(id).toLowerCase()\n ? thread\n : undefined;\n const ev = (type: string, data: Record<string, unknown>) => ({ type, data: prune(data), harnessEvent: event });\n const events: HookResult[\"events\"] = [];\n switch (event) {\n case \"SessionStart\":\n events.push(\n ev(\"session.started\", {\n source:\n typeof s.source === \"string\" && [\"startup\", \"resume\", \"clear\", \"compact\", \"fork\"].includes(s.source)\n ? s.source\n : \"unknown\",\n }),\n );\n break;\n case \"UserPromptSubmit\":\n events.push(\n ev(\"turn.started\", {\n turn_id,\n prompt_chars: typeof s.prompt === \"string\" ? [...s.prompt].length : undefined,\n }),\n );\n break;\n case \"PreToolUse\":\n if (tool) events.push(ev(\"tool.started\", { tool, call_id, turn_id, agent_id, input: s.tool_input }));\n break;\n case \"PostToolUse\":\n if (tool)\n events.push(\n ev(\"tool.ended\", {\n tool,\n call_id,\n turn_id,\n agent_id,\n ok: true,\n input: s.tool_input,\n output: s.tool_response,\n }),\n );\n break;\n case \"PermissionRequest\":\n events.push(\n ev(\"attention.needed\", {\n attention_id: call_id ?? `perm-${Date.now()}`,\n kind: \"permission\",\n tool,\n agent_id,\n }),\n );\n break;\n case \"Stop\":\n events.push(ev(\"turn.ended\", { turn_id, reason: \"stop\" }));\n break;\n case \"Interrupt\":\n events.push(ev(\"turn.ended\", { turn_id, reason: \"interrupt\" }));\n break;\n case \"SubagentStart\":\n events.push(\n ev(\"subagent.started\", {\n agent_id: String(s.agent_id ?? s.subagent_id ?? \"\"),\n agent_type: typeof s.agent_type === \"string\" ? s.agent_type : undefined,\n }),\n );\n break;\n case \"SubagentStop\":\n events.push(\n ev(\"subagent.ended\", {\n agent_id: String(s.agent_id ?? s.subagent_id ?? \"\"),\n agent_type: typeof s.agent_type === \"string\" ? s.agent_type : undefined,\n }),\n );\n break;\n case \"PreCompact\":\n events.push(ev(\"context.compacted\", { trigger: s.trigger === \"manual\" ? \"manual\" : \"auto\" }));\n break;\n case \"PostCompact\":\n break;\n case \"SessionEnd\":\n events.push(ev(\"session.ended\", { reason: endReason(s.reason) }));\n break;\n default:\n return null;\n }\n const r: HookResult = { session, events, hints: {} };\n // Inside a subagent Codex sends the parent's session_id with the subagent's own\n // rollout (its SubagentStart, its tool calls): that file is not this session's.\n if (typeof s.transcript_path === \"string\" && !ofAnotherThread(s.transcript_path, String(id)))\n r.transcript = s.transcript_path;\n return r;\n },\n\n readTranscript(file, fromLine) {\n let text = \"\";\n try {\n text = readFileSync(file, \"utf8\");\n } catch {\n return { turns: [], line: fromLine };\n }\n return readCodex(text.split(\"\\n\"), fromLine);\n },\n\n facts(session, transcript): SessionFacts {\n const out: SessionFacts = {};\n if (transcript) Object.assign(out, codexFacts(transcript));\n return out;\n },\n\n backfill(sinceMs, env = process.env): BackfillRow[] {\n const rows: BackfillRow[] = [];\n for (const f of recentFiles(sessionsDir(env), 3, sinceMs, (n) => /^rollout-.*\\.jsonl$/.test(n))) {\n const m = /([0-9a-f]{8}-[0-9a-f-]{27,})\\.jsonl$/i.exec(path.basename(f));\n if (!m?.[1]) continue;\n // A subagent's rollout is part of its parent's session, as in fromHook's notify.\n if (codexSubagent(rolloutMeta(f))) continue;\n const facts = codexFacts(f);\n if (!facts.started_at || !facts.last_at) continue;\n const { started_at, last_at, first_ask: _fa, harness_version: _hv, ...rest } = facts;\n rows.push({ session: { id: m[1], ...rest }, started_at, last_at });\n }\n return rows;\n },\n\n limits: (transcript) => codexLimits(transcript),\n};\n\n/** Epoch seconds as RFC 3339; anything that is not a plausible time is no time. */\nconst epochIso = (t: unknown): string | undefined =>\n typeof t === \"number\" && t > 0 && t < 1e11 ? new Date(t * 1000).toISOString() : undefined;\n\nfunction prune<T extends Record<string, unknown>>(o: T): T {\n for (const k of Object.keys(o)) if (o[k] === undefined) delete o[k];\n return o;\n}\n\n/** The account's limits from the last `token_count` that carries them (recorded\n * 2026-10-21, codex-cli 0.163): `rate_limits.primary` / `secondary`, each with\n * `used_percent`, `window_minutes` and `resets_at` in epoch seconds, and `plan_type`.\n * Every turn writes one, so the tail is enough. Codex keeps one snapshot and overwrites\n * it with whichever bucket the server named last (`limit_id`: `codex`, or a model's own\n * such as `codex_other`), so only the account's `codex` bucket is read, never another's\n * windows under its names. */\nexport function codexLimits(file: string): DataOf<\"limits.observed\"> | null {\n const { tail } = ends(file, 0, 256 * 1024);\n for (const r of parseLines(tail).reverse()) {\n const p = r.payload as { type?: unknown; rate_limits?: unknown } | undefined;\n if (r.type !== \"event_msg\" || p?.type !== \"token_count\") continue;\n if (!p.rate_limits || typeof p.rate_limits !== \"object\") continue;\n const rl = p.rate_limits as Record<string, unknown>;\n if (rl.limit_id != null && rl.limit_id !== \"codex\") continue;\n const windows: DataOf<\"limits.observed\">[\"windows\"] = [];\n for (const id of [\"primary\", \"secondary\"]) {\n const w = rl[id] as { used_percent?: unknown; window_minutes?: unknown; resets_at?: unknown } | null;\n if (typeof w?.used_percent !== \"number\" || w.used_percent < 0) continue;\n windows.push(\n prune({\n id,\n used_percent: w.used_percent,\n window_minutes:\n Number.isInteger(w.window_minutes) && Number(w.window_minutes) > 0 ? Number(w.window_minutes) : undefined,\n resets_at: epochIso(w.resets_at),\n }),\n );\n }\n if (!windows.length) return null;\n return prune({ windows, plan: typeof rl.plan_type === \"string\" ? rl.plan_type.slice(0, 64) : undefined });\n }\n return null;\n}\n\n/** Codex keeps no title; its first real ask stands in. A fork's replay is not its ask. */\nexport function codexFacts(file: string): SessionFacts {\n const { head, tail } = ends(file, 128 * 1024, 64 * 1024);\n let H = parseLines(head);\n let T = parseLines(tail);\n const out: SessionFacts = {};\n const meta = H.find((j) => j.type === \"session_meta\" && j.payload);\n const boundary = codexReplayBoundary(meta);\n if (meta?.payload) {\n const p = meta.payload as {\n cwd?: string;\n cli_version?: string;\n git?: { branch?: string; repository_url?: string };\n };\n if (p.cwd) out.cwd = p.cwd;\n if (p.cli_version) out.harness_version = String(p.cli_version);\n if (p.git?.branch) out.branch = p.git.branch;\n if (p.git?.repository_url) out.repo = String(p.git.repository_url).replace(/\\/\\/[^/@]*@/, \"//\");\n }\n if (boundary) {\n const h = H.findIndex(boundary);\n const t = T.findIndex(boundary);\n H = h < 0 ? [] : H.slice(h);\n // The samples can overlap, so trim each one at the boundary independently.\n // If both miss it, scan the gap before trusting the tail: it could still be\n // parent replay. Stop as soon as the boundary is found, without loading the file.\n const found =\n h >= 0 ||\n t >= 0 ||\n scanLines(file, (line) => (boundary(parseLines([line])[0] ?? null) ? true : null), Number.POSITIVE_INFINITY);\n T = t >= 0 ? T.slice(t) : found ? T : [];\n }\n const ctx = H.concat(T)\n .reverse()\n .find((j) => j.type === \"turn_context\" && (j.payload as { model?: string } | undefined)?.model) as\n | { payload?: { model?: string } }\n | undefined;\n if (ctx?.payload?.model) out.model = ctx.payload.model;\n for (const j of H) {\n const p = j.payload as { type?: string; role?: string; content?: { type?: string; text?: string }[] } | undefined;\n if (j.type !== \"response_item\" || !p || p.type !== \"message\" || p.role !== \"user\") continue;\n const text = (p.content ?? [])\n .filter((b) => b && b.type === \"input_text\" && typeof b.text === \"string\")\n .map((b) => b.text as string)\n .join(\"\\n\")\n .trim();\n if (!text || codexInjected(text)) continue;\n const line = text.split(\"\\n\")[0] as string; // trimmed, so its first line is its first non-blank one\n out.title = line.length > 80 ? `${line.slice(0, 80).replace(/\\s+\\S*$/, \"\")}\u2026` : line;\n out.title_source = \"first-ask\";\n break;\n }\n const times = (boundary && meta ? [meta, ...H, ...T] : H.concat(T))\n .map((j) => Date.parse(String(j.timestamp ?? \"\")))\n .filter((n) => n > 0);\n if (times.length) {\n out.started_at = Math.min(...times);\n out.last_at = Math.max(...times);\n }\n return out;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// Codex's ~/.codex/config.toml, as far as the notify fallback needs it: its one\n// top-level `notify` command. Codex reads `notify` only at the top level \u2014 before\n// the first [table] \u2014 and Codex itself appends a [projects.\"<path>\"] table for every\n// folder it trusts, so a line appended at the end lands inside one and never runs.\n// Ported from spacesheep-cli lib/codex-config.js. Pure text in, text out.\n\nconst NOTIFY_LINE = /^[ \\t]*notify[ \\t]*=[ \\t]*(\\[.*\\])[ \\t]*(?:#.*)?(?=\\r?$)/m;\nconst NOTIFY_KEY = /^[ \\t]*notify[ \\t]*=/m;\n/** A notify that runs sessionpipe's hook directly (or through its launcher). */\nexport const OURS = /(?:hook\\.js|sessionpipe-hook)\",\\s*\"codex\",\\s*\"notify\"/;\n\nfunction scan(line: string, st: { depth: number; str: string | null }): void {\n let i = 0;\n while (i < line.length) {\n if (st.str) {\n const j = line.indexOf(st.str, i);\n if (j < 0) return;\n i = j + 3;\n st.str = null;\n continue;\n }\n const ch = line[i];\n if (ch === \"#\") return;\n if (line.startsWith('\"\"\"', i) || line.startsWith(\"'''\", i)) {\n st.str = line.slice(i, i + 3);\n i += 3;\n continue;\n }\n if (ch === '\"') {\n i++;\n while (i < line.length && line[i] !== '\"') i += line[i] === \"\\\\\" ? 2 : 1;\n i++;\n continue;\n }\n if (ch === \"'\") {\n const j = line.indexOf(\"'\", i + 1);\n i = j < 0 ? line.length : j + 1;\n continue;\n }\n if (ch === \"[\") st.depth++;\n else if (ch === \"]\") st.depth = Math.max(0, st.depth - 1);\n i++;\n }\n}\n\n/** Offset of the first table header, or -1. */\nexport function firstTableAt(text: string): number {\n const st = { depth: 0, str: null as string | null };\n let pos = 0;\n for (const line of text.split(\"\\n\")) {\n if (!st.str && st.depth === 0 && /^[ \\t]*\\[/.test(line)) return pos;\n scan(line, st);\n pos += line.length + 1;\n }\n return -1;\n}\n\nfunction split(text: string) {\n const at = firstTableAt(text);\n return at < 0 ? { head: text, tail: \"\", at: text.length } : { head: text.slice(0, at), tail: text.slice(at), at };\n}\n\nexport function parseArgv(raw: string): string[] | null {\n try {\n const a = JSON.parse(raw) as unknown;\n return Array.isArray(a) && a.every((x) => typeof x === \"string\") ? (a as string[]) : null;\n } catch {\n return null;\n }\n}\n\nexport interface Notify {\n raw: string;\n argv: string[] | null;\n index: number;\n length: number;\n misplaced: boolean;\n other: boolean;\n}\n\n/** notify as Codex sees it; `misplaced` for a line of ours inside a table. */\nexport function readNotify(text: string): Notify | null {\n const { head, tail, at } = split(text);\n const m = NOTIFY_LINE.exec(head);\n if (m) {\n const raw = m[1] as string;\n return { raw, argv: parseArgv(raw), index: m.index, length: m[0].length, misplaced: false, other: !OURS.test(raw) };\n }\n const k = NOTIFY_KEY.exec(head);\n if (k) {\n const rest = head.slice(k.index).split(\"\\n\")[0] as string;\n return {\n raw: rest.replace(NOTIFY_KEY, \"\").trim(),\n argv: null,\n index: k.index,\n length: 0,\n misplaced: false,\n other: true,\n };\n }\n const t = NOTIFY_LINE.exec(tail);\n if (t) {\n const raw = t[1] as string;\n if (OURS.test(raw))\n return { raw, argv: parseArgv(raw), index: at + t.index, length: t[0].length, misplaced: true, other: false };\n }\n return null;\n}\n\nfunction dropLine(text: string, index: number, length: number): string {\n return text.slice(0, index) + text.slice(index + length).replace(/^\\r?\\n/, \"\");\n}\n\n/** Put `line` at the top level: before the first table, or at the end of a file that has\n * none. The line takes the file's own line end, so a CRLF file stays one. */\nexport function insertTopLevel(text: string, line: string): string {\n const { head, tail } = split(text);\n // The line joins the top-level section, so its line end is that section's own; a head\n // with no line end of its own takes the file's.\n const body = head.replace(/\\s*$/, \"\");\n const eol = (body.includes(\"\\n\") ? body : text).includes(\"\\r\\n\") ? \"\\r\\n\" : \"\\n\";\n const top = head.trim() ? head.replace(/\\s*$/, eol) : \"\";\n if (!tail) return top + line + eol;\n return `${top + line}${eol}${eol}${tail}`;\n}\n\n/** The config with `line` as its notify, for a config whose notify is ours or absent. */\nexport function withNotify(text: string, line: string): string {\n const n = readNotify(text);\n if (n && !n.misplaced && !n.other) return text.slice(0, n.index) + line + text.slice(n.index + n.length);\n if (n?.misplaced) return insertTopLevel(dropLine(text, n.index, n.length), line);\n return insertTopLevel(text, line);\n}\n\n/** The config with its notify line `n` (as readNotify found it in `text`) replaced by `line`. */\nexport function replaceNotify(text: string, n: Notify, line: string): string {\n return text.slice(0, n.index) + line + text.slice(n.index + n.length);\n}\n\n/** The config with our top-level or misplaced notify removed. */\nexport function withoutNotify(text: string): string {\n const n = readNotify(text);\n if (!n || n.other || !n.length) return text;\n return dropLine(text, n.index, n.length);\n}\n\n// Codex Computer Use takes the notify slot itself and keeps the command it found in\n// its own argv: [client, \"turn-ended\", \"--previous-notify\", \"<that command as JSON>\"].\nconst PREVIOUS = \"--previous-notify\";\nexport function previousNotify(argv: string[] | null): string[] | null {\n if (!Array.isArray(argv)) return null;\n const i = argv.indexOf(PREVIOUS);\n return i >= 0 && typeof argv[i + 1] === \"string\" ? parseArgv(argv[i + 1] as string) : null;\n}\nexport function withPrevious(argv: string[], prev: string[] | null): string[] {\n const out = argv.slice();\n const i = out.indexOf(PREVIOUS);\n if (i >= 0) out.splice(i, 2);\n if (prev) out.push(PREVIOUS, JSON.stringify(prev));\n return out;\n}\n/** The raw notify value with its --previous-notify pair removed, formatting kept. */\nexport function stripPreviousRaw(raw: string): string {\n return raw.replace(/,\\s*\"--previous-notify\",\\s*\"(?:[^\"\\\\]|\\\\.)*\"\\s*(?=\\])/, \"\");\n}\n/** The raw notify value with `prev` as its --previous-notify, formatting of the rest kept. */\nexport function withPreviousRaw(raw: string, prev: string[]): string {\n const base = stripPreviousRaw(raw).replace(/\\s*\\]\\s*$/, \"\");\n return `${base}, \"--previous-notify\", ${JSON.stringify(JSON.stringify(prev))}]`;\n}\nexport const isComputerUse = (argv: string[] | null): boolean =>\n Array.isArray(argv) && typeof argv[0] === \"string\" && /(^|\\/)SkyComputerUseClient$/.test(argv[0]);\n", "// SPDX-License-Identifier: Apache-2.0\n// Codex CLI (OpenAI) \u2014 control delivery (spec/CONTROL.md \u00A76). Codex on this machine,\n// as the control daemon needs it: which `codex` to run, with which sandbox flags, one\n// headless turn (`codex exec --json` for a new session, `codex exec resume --json <id>`\n// for the next message), and its JSONL output read as it streams. Codex picks a new\n// session's id itself (the first line, `thread.started`), so the daemon names it after\n// the command that started it (CONTROL.md \u00A76 `start`). Shapes measured on codex-cli\n// 0.160.0, 2026-10-04.\nimport { execFile } from \"node:child_process\";\nimport { readFileSync } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { MODEL_RE, type RunLevel, type StartPermission } from \"../control/verify.js\";\nimport {\n findBinary,\n jobEnv,\n type Login,\n type Mode,\n probe,\n type Reading,\n type RunResult,\n runFailure,\n stderrTail,\n} from \"./headless.js\";\n\nexport { codexFacts, findRollout } from \"./codex.js\";\n\nconst LABEL = \"Codex\";\n\n/** The `codex` to run: SESSIONPIPE_CODEX, else on PATH, else beside the node running\n * this (an `npm install -g` there) or where the installers put it. */\nexport function findCodex(\n env: NodeJS.ProcessEnv = process.env,\n home = os.homedir(),\n nodeDir = path.dirname(process.execPath),\n): string | null {\n return findBinary({\n override: env.SESSIONPIPE_CODEX,\n names: process.platform === \"win32\" ? [\"codex.exe\", \"codex.cmd\"] : [\"codex\"],\n env,\n dirs: [nodeDir, path.join(home, \".local\", \"bin\"), \"/opt/homebrew/bin\", \"/usr/local/bin\"],\n });\n}\n\n/** Sandbox flags for a level (a machine's mode is one: safe, auto, inherit). Read: the\n * read-only sandbox. Safe: workspace-write, and nothing escalates unattended (exec never\n * asks); that sandbox already edits inside the folder, so `edits` is never offered and\n * means the same. Auto: approval requests go through Codex's own automatic review.\n * Inherit: none, so `sandbox_mode` and `approval_policy` come from the person's own\n * config.toml, a new session's and a resume's alike. Never\n * `--dangerously-bypass-approvals-and-sandbox`, `--dangerously-bypass-hook-trust` or\n * `danger-full-access`: no path here writes them. */\nexport function codexModeFlags(level: RunLevel, resume = false): string[] {\n if (level === \"inherit\") return [];\n const sandbox = level === \"read\" ? \"read-only\" : \"workspace-write\";\n // `codex exec resume` takes neither `-s` nor `--approve-for-me` (0.160: \"unexpected\n // argument\"), so a resume says the same thing as config overrides, which it does take.\n if (resume)\n return level === \"auto\"\n ? [\n \"-c\",\n 'sandbox_mode=\"workspace-write\"',\n \"-c\",\n 'approval_policy=\"on-request\"',\n \"-c\",\n 'approvals_reviewer=\"auto_review\"',\n ]\n : [\"-c\", `sandbox_mode=\"${sandbox}\"`];\n return level === \"auto\" ? [\"--approve-for-me\"] : [\"-s\", sandbox];\n}\n\n/** The levels a start may ask Codex for on a machine in `mode`: read and safe, and auto\n * on an auto machine. */\nexport const offeredLevels = (mode: Mode): StartPermission[] =>\n mode === \"auto\" ? [\"read\", \"safe\", \"auto\"] : [\"read\", \"safe\"];\n\n/** What a start that names no level gets: what the machine's mode means for Codex. */\nexport const defaultLevel = (mode: Mode): RunLevel => mode;\n\n/** One headless turn. A new session runs in `cwd` (`-C`); a resume names the thread.\n * The model is its own argument after `-m`. The prompt goes after `--`, so a message\n * that starts with a dash is never a flag. */\nexport function codexArgs(o: {\n permission: RunLevel;\n prompt: string;\n cwd?: string;\n resume?: string;\n model?: string;\n}): string[] {\n const common = [\"--json\", \"--skip-git-repo-check\"];\n const model = o.model ? [\"-m\", o.model] : [];\n if (o.resume)\n return [\"exec\", \"resume\", ...common, ...codexModeFlags(o.permission, true), ...model, \"--\", o.resume, o.prompt];\n return [\n \"exec\",\n ...common,\n ...(o.cwd ? [\"-C\", o.cwd] : []),\n ...codexModeFlags(o.permission),\n ...model,\n \"--\",\n o.prompt,\n ];\n}\n\n/** The models a hello offers for Codex (CONTROL.md \u00A72 `start`): the slugs Codex's own\n * picker lists, from `$CODEX_HOME/models_cache.json` (visibility `list`; hidden ones,\n * such as its review model, left out), at most 50. Empty when there is no cache. */\nexport function codexModels(env: NodeJS.ProcessEnv = process.env, home = os.homedir()): string[] {\n try {\n const file = path.join(env.CODEX_HOME || path.join(home, \".codex\"), \"models_cache.json\");\n const j = JSON.parse(readFileSync(file, \"utf8\")) as { models?: unknown };\n if (!Array.isArray(j.models)) return [];\n const out: string[] = [];\n for (const m of j.models as { slug?: unknown; visibility?: unknown }[])\n if (m && m.visibility === \"list\" && typeof m.slug === \"string\" && MODEL_RE.test(m.slug) && m.slug.length <= 100)\n if (!out.includes(m.slug)) out.push(m.slug);\n return out.slice(0, 50);\n } catch {\n return [];\n }\n}\n\n/** The env a headless turn runs with. */\nexport const codexEnv = (env: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv => jobEnv(env);\n\nexport const LOGIN_HINT = \"Codex isn't signed in on this machine: run `codex login --device-auth` there.\";\n\n/** Whether Codex can run as this process: CODEX_API_KEY in the env is enough; else\n * `codex login status` (exit 0 signed in, exit 1 \"Not logged in\"). Anything else \u2014\n * it didn't run, it timed out \u2014 is null, never a reason to refuse. */\nexport function codexLogin(bin: string, env: NodeJS.ProcessEnv = process.env): Promise<Login> {\n if (env.CODEX_API_KEY) return Promise.resolve({ loggedIn: true, method: \"api key\" });\n const c = probe(bin, [\"login\", \"status\"]); // a codex.cmd shim can't be spawned bare (#165)\n return new Promise((resolve) => {\n execFile(\n c.file,\n c.args,\n { encoding: \"utf8\", timeout: 20_000, env: codexEnv(env), maxBuffer: 256 * 1024, shell: c.shell },\n (err) => {\n if (!err) return resolve({ loggedIn: true });\n const code = (err as { code?: unknown }).code;\n resolve(code === 1 ? { loggedIn: false } : { loggedIn: null });\n },\n );\n });\n}\n\n/** One `--json` line, as much of it as the daemon uses. */\nexport interface CodexPiece {\n /** `thread.started`: the session's id, which Codex chose. */\n session?: string;\n /** A finished `agent_message`: one part of the answer. */\n message?: string;\n /** `turn.completed` (or `turn.failed`). */\n done?: boolean;\n /** `turn.failed`: why. */\n failed?: string;\n /** A top-level `error` (\"Reconnecting... 2/5\"): transient, the reason only if the run then fails. */\n note?: string;\n /** An `error` item: a warning Codex printed and carried on after (hook trust, a clamped timeout). */\n warning?: string;\n}\n\nexport function codexLine(line: string): CodexPiece | null {\n let j: {\n type?: unknown;\n thread_id?: unknown;\n message?: unknown;\n item?: { type?: unknown; text?: unknown; message?: unknown };\n error?: { message?: unknown };\n };\n try {\n j = JSON.parse(line);\n } catch {\n return null;\n }\n if (!j || typeof j !== \"object\") return null;\n const str = (v: unknown) => (typeof v === \"string\" ? v : \"\");\n switch (j.type) {\n case \"thread.started\":\n return str(j.thread_id) ? { session: str(j.thread_id) } : null;\n case \"item.completed\": {\n const it = j.item;\n if (it?.type === \"agent_message\" && str(it.text)) return { message: str(it.text) };\n if (it?.type === \"error\" && str(it.message)) return { warning: str(it.message) };\n return null;\n }\n case \"turn.completed\":\n return { done: true };\n case \"turn.failed\":\n return { done: true, failed: str(j.error?.message) || \"Codex reported an error\" };\n case \"error\":\n return str(j.message) ? { note: str(j.message) } : null;\n default:\n return null;\n }\n}\n\n/** A Codex run read as it streams: the answer is its finished agent messages. */\nexport class CodexReading implements Reading {\n session: string | null = null;\n lines = 0;\n readonly warnings: string[] = [];\n private readonly messages: string[] = [];\n private done = false;\n private failed: string | null = null;\n private note: string | null = null;\n\n get text(): string {\n return this.messages.join(\"\\n\\n\");\n }\n\n feed(line: string): boolean {\n this.lines++;\n const p = codexLine(line);\n if (!p) return false;\n if (p.session && !this.session) this.session = p.session;\n if (p.note) this.note = p.note;\n if (p.warning && this.warnings.length < 20) this.warnings.push(p.warning);\n if (p.failed) this.failed = p.failed;\n if (p.done) this.done = true;\n if (p.message?.trim()) {\n this.messages.push(p.message.trim());\n return true;\n }\n return false;\n }\n\n /** A failure is `turn.failed`, or a run that exits non-zero having said nothing; an\n * `error` item before a turn that then succeeds is only a warning. */\n outcome(res: RunResult): { failed: string } | { reply: string } {\n const broke = runFailure(LABEL, res);\n if (broke) return { failed: broke };\n if (this.failed) return { failed: this.failed };\n if (this.done || res.code === 0 || this.messages.length)\n return { reply: this.text || \"(Codex finished without a written reply.)\" };\n const why = this.note || codexStderr(res.stderr) || this.warnings.at(-1) || \"\";\n return { failed: `Codex exited (${res.signal || `code ${res.code}`}) without an answer${why ? `: ${why}` : \"\"}` };\n }\n}\n\n/** stderr's tail without the line Codex prints even with stdin closed. */\nfunction codexStderr(stderr: string | undefined): string {\n return stderrTail(\n String(stderr || \"\")\n .split(\"\\n\")\n .filter((l) => !/^Reading additional input from stdin/.test(l.trim()))\n .join(\"\\n\"),\n );\n}\n\nexport const reading = (): CodexReading => new CodexReading();\n", "// SPDX-License-Identifier: Apache-2.0\n// Devin CLI (Cognition) \u2014 docs: https://docs.devin.ai/cli/extensibility/hooks/overview\n// Config: the `hooks` key of the user config file \u2014 `~/.config/devin/config.json`\n// (`$XDG_CONFIG_HOME/devin/config.json` when that is set), `%APPDATA%\\devin\\config.json`\n// on Windows. Claude-shaped, matcher a REGEX on the tool name, timeouts in SECONDS.\n// That file is the only user-level location Devin reads hooks from; `hooks.v1.json` is\n// project-level only.\n//\n// Devin accepts exactly eight event names and rejects the WHOLE file on one it does not\n// know (\"unknown variant `Notification`, expected one of \u2026\"), which silently disables\n// every hook in it. DEVIN_EVENTS is that set, and nothing else may be added to it.\n//\n// The payload carries no `cwd`, no `transcript_path` and no `model`: the folder comes\n// from DEVIN_PROJECT_DIR in the hook's environment, and the transcript, the model, the\n// title and the times come from Devin's own session store \u2014 one SQLite file under the\n// data directory, read only, through readers/sqlite.ts. A session's transcript is\n// addressed as \"<database>#<session id>\", because readTranscript is given a file.\n//\n// stdout stays empty for every event: Devin reads a decision from stdout, and silence\n// plus exit 0 is \"carry on\" (printing nothing, printing `{}`, exiting 1 and blowing the\n// timeout were all measured as non-blocking; only exit 2 or an explicit\n// {\"decision\":\"block\"} blocks a tool).\nimport { createHash } from \"node:crypto\";\nimport { existsSync, readlinkSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { homeDir } from \"../paths.js\";\nimport { querySqlite } from \"../readers/sqlite.js\";\nimport { pairTurns } from \"../readers/transcripts.js\";\nimport { installClaudeShaped, installedClaudeShaped, readJson, uninstallClaudeShaped } from \"./claude-shaped.js\";\nimport type {\n Adapter,\n BackfillRow,\n HookInput,\n HookResult,\n InstallOptions,\n SessionFacts,\n TranscriptRead,\n} from \"./types.js\";\n\nconst NAME = \"devin\";\n/** The eight event names Devin accepts. One it does not know makes it drop the whole\n * hooks file, so this list is exact, not a superset \u2014 see devin.test.ts. */\nexport const DEVIN_EVENTS = [\n \"SessionStart\",\n \"UserPromptSubmit\",\n \"PreToolUse\",\n \"PostToolUse\",\n \"PermissionRequest\",\n \"Stop\",\n \"PostCompaction\",\n \"SessionEnd\",\n] as const;\nconst OPTS = { matcherFor: (e: string) => (/Tool|Permission/.test(e) ? \"\" : undefined), timeout: 5 };\nconst eventsFor = (lean?: boolean) => (lean ? DEVIN_EVENTS.filter((e) => e !== \"PreToolUse\") : [...DEVIN_EVENTS]);\nconst INSTALL_NOTE =\n \"Devin drops a whole hooks file on one event name it doesn't know; `/hooks` in `devin` lists what loaded\";\nconst CLAUDE_NOTE =\n \"Devin also reads ~/.claude/settings.json hooks (read_config_from.claude); a Claude-only event name there makes it ignore that file whole\";\n\nconst deadFileNote = (bad: string) =>\n `Devin loads NO hooks from this file: \"${bad}\" is not one of its event names and it rejects the file whole \u2014 remove that key (\\`/hooks\\` in \\`devin\\` lists what loaded)`;\n\n/** The first `hooks` key in the file that Devin does not accept, if there is one.\n * One such key disables every hook in the file, ours and any other tool's. */\nexport function foreignEvent(file: string): string | undefined {\n const hooks = readJson(file).hooks;\n if (!hooks || typeof hooks !== \"object\" || Array.isArray(hooks)) return undefined;\n const ok = DEVIN_EVENTS as readonly string[];\n return Object.keys(hooks).find((k) => !ok.includes(k));\n}\n\nconst homeOf = (env: NodeJS.ProcessEnv) => env.HOME || homeDir();\nconst appData = (env: NodeJS.ProcessEnv) => env.APPDATA || path.join(homeOf(env), \"AppData\", \"Roaming\");\n/** `~/.config/devin`, `$XDG_CONFIG_HOME/devin`, or `%APPDATA%\\devin`. */\nexport const devinConfigDir = (env: NodeJS.ProcessEnv = process.env): string =>\n process.platform === \"win32\"\n ? path.join(appData(env), \"devin\")\n : path.join(env.XDG_CONFIG_HOME || path.join(homeOf(env), \".config\"), \"devin\");\nconst configFile = (env: NodeJS.ProcessEnv) => path.join(devinConfigDir(env), \"config.json\");\n/** `~/.local/share/devin/cli`, `$XDG_DATA_HOME/devin/cli`, or `%APPDATA%\\devin\\cli`. */\nexport const devinDataDir = (env: NodeJS.ProcessEnv = process.env): string =>\n process.platform === \"win32\"\n ? path.join(appData(env), \"devin\", \"cli\")\n : path.join(env.XDG_DATA_HOME || path.join(homeOf(env), \".local\", \"share\"), \"devin\", \"cli\");\nconst sessionsDb = (env: NodeJS.ProcessEnv) => path.join(devinDataDir(env), \"sessions.db\");\n\nconst SESSION_ID = /^[A-Za-z0-9._:-]{1,128}$/;\nconst validTool = (n: unknown): n is string => typeof n === \"string\" && /^[A-Za-z0-9_.:-]{1,120}$/.test(n);\nconst endReason = (r: unknown): \"clear\" | \"logout\" | \"exit\" | \"other\" =>\n r === \"clear\" || r === \"logout\" || r === \"exit\" ? r : \"other\";\nconst pickSource = (v: unknown): string =>\n typeof v === \"string\" && [\"startup\", \"resume\", \"clear\", \"compact\", \"fork\"].includes(v) ? v : \"unknown\";\nfunction errText(v: unknown): string | undefined {\n if (typeof v === \"string\" && v) return v.slice(0, 2000);\n if (v && typeof v === \"object\") {\n const e = v as { message?: unknown; error?: unknown };\n if (typeof e.message === \"string\" && e.message) return e.message.slice(0, 2000);\n if (typeof e.error === \"string\" && e.error) return e.error.slice(0, 2000);\n }\n return undefined;\n}\nconst cut = (s: string, n: number): string => (s.length > n ? `${s.slice(0, n).replace(/\\s+\\S*$/, \"\")}\u2026` : s);\n\nexport const devin: Adapter = {\n name: NAME,\n events: DEVIN_EVENTS,\n detect: (env = process.env) => existsSync(devinConfigDir(env)) || existsSync(devinDataDir(env)),\n configFiles: (env = process.env) => [configFile(env)],\n install: (cmd, env = process.env, opts: InstallOptions = {}) => {\n const file = configFile(env);\n const r = installClaudeShaped(file, NAME, eventsFor(opts.lean), cmd, OPTS);\n if (r.skipped) return [r];\n const bad = foreignEvent(file);\n return [{ ...r, note: bad ? deadFileNote(bad) : INSTALL_NOTE }];\n },\n uninstall: (env = process.env, opts: InstallOptions = {}) => [\n uninstallClaudeShaped(configFile(env), DEVIN_EVENTS, { created: opts.created?.includes(configFile(env)) }),\n ],\n installed: (cmd, env = process.env, opts: InstallOptions = {}) => {\n const file = configFile(env);\n const state = installedClaudeShaped(file, NAME, eventsFor(opts.lean), cmd, OPTS);\n // Our entries can be present and current and still report nothing: one event name\n // Devin does not know makes it drop the whole file, ours with it. `status` has to\n // say so, or it tells the person reporting is on while it is dead.\n const bad = state === \"missing\" ? undefined : foreignEvent(file);\n return [{ file, state: bad ? \"inactive\" : state, note: bad ? deadFileNote(bad) : CLAUDE_NOTE }];\n },\n\n fromHook(input: HookInput): HookResult | null {\n const event = input.argv[1] ?? \"\";\n let s: Record<string, unknown> = {};\n try {\n // A stdin that is JSON but not an object (`null`, a number) is no payload.\n const j: unknown = input.stdin ? JSON.parse(input.stdin) : {};\n if (j && typeof j === \"object\" && !Array.isArray(j)) s = j as Record<string, unknown>;\n } catch {}\n const id = typeof s.session_id === \"string\" ? s.session_id : \"\";\n if (!id) return null;\n // Nothing in the payload names the folder; DEVIN_PROJECT_DIR is the only thing that does.\n const session: HookResult[\"session\"] = { id, cwd: input.env.DEVIN_PROJECT_DIR ?? input.cwd };\n const turn_id = typeof s.prompt_id === \"string\" ? s.prompt_id : undefined;\n const tool = validTool(s.tool_name) ? s.tool_name : undefined;\n const call_id = typeof s.tool_use_id === \"string\" ? s.tool_use_id : undefined;\n // Every recorded payload has an object here, but the field is free-form: a Devin\n // version or an MCP-style tool could send a bare string, and then there is no\n // `success` and no `output` to read \u2014 the whole value IS the output.\n const response =\n s.tool_response && typeof s.tool_response === \"object\" && !Array.isArray(s.tool_response)\n ? (s.tool_response as { success?: unknown; output?: unknown; error?: unknown })\n : undefined;\n // The same prompt must always name the same attention (CONTROL.md \u00A76). Devin's\n // PermissionRequest does carry tool_use_id; the hash is the fallback for one that\n // doesn't, and is the bytes ADAPTERS.md's common conventions prescribe.\n const permissionId = () =>\n `perm-${createHash(\"sha256\")\n .update(`${turn_id ?? \"\"}|${tool ?? \"\"}|${JSON.stringify(s.tool_input ?? null)}`)\n .digest(\"hex\")\n .slice(0, 16)}`;\n const ev = (type: string, data: Record<string, unknown>) => ({ type, data: prune(data), harnessEvent: event });\n const events: HookResult[\"events\"] = [];\n switch (event) {\n case \"SessionStart\":\n events.push(ev(\"session.started\", { source: pickSource(s.source) }));\n break;\n case \"UserPromptSubmit\":\n events.push(\n ev(\"turn.started\", {\n turn_id,\n prompt_chars: typeof s.prompt === \"string\" ? [...s.prompt].length : undefined,\n }),\n );\n break;\n case \"PreToolUse\":\n if (tool) events.push(ev(\"tool.started\", { tool, call_id, turn_id, input: s.tool_input }));\n break;\n case \"PostToolUse\":\n // Devin is the one harness that says so outright: tool_response.success.\n if (tool)\n events.push(\n ev(\"tool.ended\", {\n tool,\n call_id,\n turn_id,\n // `ok` is required on tool.ended (PROTOCOL.md \u00A7events), so a response\n // that carries no success flag at all reads as \"nothing said it failed\".\n ok: response?.success !== false,\n error: errText(response?.error),\n input: s.tool_input,\n output: response ? response.output : s.tool_response,\n }),\n );\n break;\n case \"PermissionRequest\":\n events.push(ev(\"attention.needed\", { attention_id: call_id ?? permissionId(), kind: \"permission\", tool }));\n break;\n case \"Stop\":\n events.push(ev(\"turn.ended\", { turn_id, reason: \"stop\" }));\n break;\n case \"PostCompaction\":\n // Devin has no pre-compaction event; the payload carries only the summary.\n events.push(ev(\"context.compacted\", { trigger: \"auto\" }));\n break;\n case \"SessionEnd\":\n events.push(ev(\"session.ended\", { reason: endReason(s.reason) }));\n break;\n default:\n return null;\n }\n return {\n session,\n events,\n hints: {},\n transcript: transcriptRef(sessionsDb(input.env as NodeJS.ProcessEnv), id),\n };\n },\n\n readTranscript(file, fromLine) {\n const ref = splitRef(file);\n if (!ref) return { turns: [], line: fromLine };\n return readDevinChain(ref.db, ref.session, fromLine);\n },\n\n facts(session, transcript, _hints, _state, env = process.env): SessionFacts {\n const out: SessionFacts = {};\n const version = devinVersion(env);\n if (version) out.harness_version = version;\n const account = devinAccount(env);\n if (account) out.account_id = account;\n const ref = splitRef(transcript) ?? { db: sessionsDb(env), session: session.id };\n if (!SESSION_ID.test(ref.session)) return out;\n const rows = querySqlite(ref.db, SESSION_SQL, [ref.session]);\n const row = rows?.[0];\n if (!row) return out;\n Object.assign(out, sessionFacts(row));\n return out;\n },\n\n backfill(sinceMs, env = process.env): BackfillRow[] {\n const rows = querySqlite(sessionsDb(env), BACKFILL_SQL, [\"text\", Math.floor(sinceMs / 1000)]);\n if (!rows) return [];\n const out: BackfillRow[] = [];\n for (const row of rows) {\n const id = String(row.id); // text, the query says\n if (!SESSION_ID.test(id)) continue;\n const { started_at, last_at, ...rest } = sessionFacts(row);\n if (!started_at || !last_at) continue;\n out.push({ session: { id, ...rest }, started_at, last_at });\n }\n return out;\n },\n};\n\nfunction prune<T extends Record<string, unknown>>(o: T): T {\n for (const k of Object.keys(o)) if (o[k] === undefined) delete o[k];\n return o;\n}\n\n// --- the session store ---------------------------------------------------------------\n\n/** `<database>#<session id>`: readTranscript is given a file, and Devin keeps every\n * session in one database, so the session has to ride in the string. */\nexport const transcriptRef = (db: string, session: string): string => `${db}#${session}`;\nexport function splitRef(ref: string | undefined): { db: string; session: string } | null {\n if (!ref) return null;\n const at = ref.lastIndexOf(\"#\");\n if (at <= 0) return null;\n const db = ref.slice(0, at);\n const session = ref.slice(at + 1);\n return db && SESSION_ID.test(session) ? { db, session } : null;\n}\n\n/** `message_nodes` is a forest: it keeps abandoned branches too (27 nodes for a\n * two-turn session). The transcript is the one chain that ends at\n * `sessions.main_chain_id`, walked up through `parent_node_id` \u2014 never every node. */\n/** The walk stops at the cursor (`m.node_id >= ?`): everything below it has been read\n * already, and without that bound every Stop pulled `chat_message` for every ancestor\n * \u2014 the root of a real chain carries a 17 kB system prompt and four more system\n * blocks, re-read on every event, and past 32 MB the child and CLI engines give up\n * and return nothing. The cap keeps the NEWEST rows (`DESC`), re-sorted below: an\n * ascending cap would have kept the oldest and delivered no new turn ever again.\n * `UNION`, not `UNION ALL`: SQLite queues a row only if it has not queued the same row\n * before, so a chain that loops back on itself (a node its own parent, two that name\n * each other) ends at the first node it reaches twice. Under `UNION ALL` it recursed\n * for ever, and on the in-process engine nothing can interrupt that: the worker spins,\n * holds the session's lock and delivers nothing. */\nconst CHAIN_LIMIT = 4000;\nexport const CHAIN_SQL = `WITH RECURSIVE chain(node_id, parent_node_id, chat_message, created_at) AS (\n SELECT node_id, parent_node_id, chat_message, created_at FROM message_nodes\n WHERE session_id = ? AND node_id = (SELECT main_chain_id FROM sessions WHERE id = ?)\n UNION\n SELECT m.node_id, m.parent_node_id, m.chat_message, m.created_at FROM message_nodes m\n JOIN chain c ON m.node_id = c.parent_node_id AND m.session_id = ? AND m.node_id >= ?\n)\nSELECT node_id, chat_message, created_at FROM chain ORDER BY node_id DESC LIMIT ${CHAIN_LIMIT}`;\n\n/** Times are unix SECONDS in this store. The first ask comes from `prompt_history`,\n * because `sessions.title` holds whatever the titler last produced \u2014 a backticked\n * command, or a raw `functions.Shell:0{\u2026}` mid-turn. */\nconst SESSION_FIELDS = `s.model, s.working_directory, s.created_at, s.last_activity_at,\n (SELECT p.content FROM prompt_history p WHERE p.session_id = s.id AND p.is_shell = 0\n ORDER BY p.timestamp ASC, p.id ASC LIMIT 1) AS first_ask`;\nconst SESSION_SQL = `SELECT ${SESSION_FIELDS} FROM sessions s WHERE s.id = ? LIMIT 1`;\n// typeof(id) = 'text' (the literal rides as a parameter: the CLI engine takes no quote\n// in the SQL): an id a session ref could carry. A blob id comes back from the sqlite3\n// CLI as a string shaped by its version, so the database says what it is.\nconst BACKFILL_SQL = `SELECT s.id, ${SESSION_FIELDS} FROM sessions s\n WHERE s.hidden = 0 AND typeof(s.id) = ? AND s.last_activity_at >= ?\n ORDER BY s.last_activity_at DESC LIMIT 500`;\n\nfunction sessionFacts(row: Record<string, unknown>): SessionFacts {\n const out: SessionFacts = {};\n if (typeof row.model === \"string\" && row.model) out.model = row.model;\n if (typeof row.working_directory === \"string\" && path.isAbsolute(row.working_directory))\n out.cwd = row.working_directory;\n const started = Number(row.created_at);\n const last = Number(row.last_activity_at);\n if (Number.isFinite(started) && started > 0) out.started_at = Math.round(started * 1000);\n if (Number.isFinite(last) && last > 0) out.last_at = Math.round(last * 1000);\n if (typeof row.first_ask === \"string\") {\n const line = row.first_ask.split(\"\\n\").find((l) => l.trim()) ?? \"\";\n if (line.trim()) {\n out.title = cut(line.trim(), 80);\n out.title_source = \"first-ask\";\n }\n }\n return out;\n}\n\ninterface ChatMessage {\n role?: unknown;\n content?: unknown;\n metadata?: { is_user_input?: unknown; created_at?: unknown } | null;\n}\n\n/** The canonical chain as turns. `node_id` is the cursor: it rises along the chain and\n * is stable across a resume, so a later read starts where the last one stopped.\n * `role: \"system\"` is Cognition's own prompt (and the skills manifest, and the\n * generated system_info block), never the person's words \u2014 it is skipped at every\n * tier, as is `role: \"tool\"`. */\nexport function readDevinChain(db: string, session: string, fromLine: number): TranscriptRead {\n if (!SESSION_ID.test(session)) return { turns: [], line: fromLine };\n const floor = Number.isFinite(fromLine) && fromLine > 0 ? Math.floor(fromLine) : 0;\n const rows = querySqlite(db, CHAIN_SQL, [session, session, session, floor]);\n if (!rows?.length) return { turns: [], line: fromLine };\n const msgs: { role: \"user\" | \"assistant\"; text: string; at: number; line: number }[] = [];\n let end = fromLine;\n for (const row of rows) {\n const node = Number(row.node_id);\n if (!Number.isFinite(node)) continue;\n if (node + 1 > end) end = node + 1;\n if (node < fromLine) continue;\n let j: ChatMessage;\n try {\n j = JSON.parse(String(row.chat_message ?? \"\")) as ChatMessage;\n } catch {\n continue;\n }\n const text = typeof j.content === \"string\" ? j.content.trim() : \"\";\n if (!text) continue;\n // The message's own time, not the row's. `message_nodes.created_at` is when the row\n // batch was last WRITTEN: Devin rewrites it on every save of the chain, so every\n // node of a chain usually carries one identical value, and it is not even monotonic\n // along the chain. Measured on a live store 2026-10-08: a two-turn session had all\n // four of its chain nodes at 23:33:10 while their own `metadata.created_at` read\n // 23:32:29, :34, 23:33:08 and :10 (turn 1 reported 41 s late, both turns at the same\n // instant); one node's row time was rewritten 12 s later between two reads; and a\n // descendant's row time was 27 s EARLIER than its ancestor's. The column is only the\n // fallback for a row whose message has no time of its own.\n const secs = Number(row.created_at);\n const at =\n Date.parse(String(j.metadata?.created_at ?? \"\")) ||\n (Number.isFinite(secs) && secs > 0 ? Math.round(secs * 1000) : 0) ||\n Date.now();\n if (j.role === \"user\" && j.metadata?.is_user_input === true) msgs.push({ role: \"user\", text, at, line: node });\n else if (j.role === \"assistant\") msgs.push({ role: \"assistant\", text, at, line: node });\n }\n // The rows come newest first (the cap keeps the newest); a transcript runs the other way.\n msgs.sort((a, b) => a.line - b.line);\n return pairTurns(msgs, end);\n}\n\n/** `<data dir>/_versions/current` is a symlink to the running version's folder. */\nexport function devinVersion(env: NodeJS.ProcessEnv = process.env): string | undefined {\n try {\n const target = readlinkSync(path.join(devinDataDir(env), \"_versions\", \"current\"));\n const name = path.basename(target);\n return /^[0-9][0-9A-Za-z.+-]{0,63}$/.test(name) ? name : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** The organisation the CLI is signed in to, from the user config \u2014 the only account id\n * Devin keeps in a plain local file. Never the email, and never credentials.toml. */\nexport function devinAccount(env: NodeJS.ProcessEnv = process.env): string | undefined {\n const d = readJson(configFile(env)).devin as { org_id?: unknown } | undefined;\n const id = d && typeof d === \"object\" ? d.org_id : undefined;\n return typeof id === \"string\" && /^[A-Za-z0-9_.:-]{1,128}$/.test(id) ? id : undefined;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// Read-only SQLite, for a harness that keeps its sessions in a database instead of a\n// JSONL file. Three ways in, tried in order, because `node:sqlite` does not exist on\n// Node 20 (the floor this package builds for) and is behind --experimental-sqlite on\n// 22.5\u201322.12:\n// \"node\" in this process, through createRequire \u2014 no static import, so the bundle\n// still loads on a Node without the module;\n// \"child\" one `node --experimental-sqlite -e \u2026` run through execFileSync: no shell,\n// arguments passed as argv, a short timeout;\n// \"cli\" the `sqlite3` binary, when it is on PATH and every parameter is a plain\n// scalar that can be written as a literal.\n// Every path opens the file read-only, is bounded in time, and returns null instead of\n// throwing: a database that is busy, missing, locked or unreadable costs the caller\n// nothing but an empty read.\nimport { execFileSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\n\nexport type SqliteParam = string | number;\nexport type SqliteRow = Record<string, unknown>;\nexport type SqliteEngine = \"auto\" | \"node\" | \"child\" | \"cli\";\n\nexport interface SqliteOptions {\n /** Busy timeout and the child's wall clock, in ms (default 2000). */\n timeoutMs?: number;\n /** Force one way in; \"auto\" tries node, then child, then cli (default). */\n engine?: SqliteEngine;\n /** Largest reply a child or the CLI may print (default 32 MB). */\n maxBuffer?: number;\n}\n\ninterface Statement {\n all(...params: SqliteParam[]): unknown[];\n}\ninterface Db {\n prepare(sql: string): Statement;\n exec(sql: string): void;\n close(): void;\n}\ntype DbCtor = new (path: string, options?: Record<string, unknown>) => Db;\n\n/** `node:sqlite` is still experimental, and Node says so on stderr the first time it is\n * used. A reader has no business writing to a harness's terminal, so that one warning\n * is swallowed while the module is loaded and used \u2014 nothing else is, and the original\n * emitter is back before this returns. (The child path passes --no-warnings instead.)\n * Exported for its test: Node emits that warning once per process. */\nexport function quiet<T>(fn: () => T): T {\n const original = process.emitWarning;\n try {\n process.emitWarning = ((warning: unknown, ...rest: unknown[]) => {\n const kind = typeof rest[0] === \"string\" ? rest[0] : (rest[0] as { type?: string } | undefined)?.type;\n if (kind === \"ExperimentalWarning\" && /sqlite/i.test(String(warning))) return;\n (original as (...a: unknown[]) => void).call(process, warning, ...rest);\n }) as typeof process.emitWarning;\n return fn();\n } finally {\n process.emitWarning = original;\n }\n}\n\nlet ctorCache: DbCtor | null | undefined;\n/** `node:sqlite` if this Node has it; null if it does not (Node 20, or 22.x unflagged). */\nfunction dbCtor(): DbCtor | null {\n if (ctorCache !== undefined) return ctorCache;\n ctorCache = null;\n try {\n const req = createRequire(import.meta.url);\n const m = quiet(() => req(\"node:sqlite\")) as { DatabaseSync?: unknown };\n if (typeof m?.DatabaseSync === \"function\") ctorCache = m.DatabaseSync as DbCtor;\n } catch {}\n return ctorCache;\n}\n\n/** SQLite gives back strings, numbers, null, BigInt and Uint8Array; the protocol takes JSON. */\nfunction plain(row: unknown): SqliteRow | null {\n if (!row || typeof row !== \"object\") return null;\n const out: SqliteRow = {};\n for (const [k, v] of Object.entries(row as SqliteRow)) {\n if (typeof v === \"bigint\") out[k] = Number(v);\n else if (v instanceof Uint8Array) out[k] = null;\n else out[k] = v;\n }\n return out;\n}\nconst rows = (v: unknown): SqliteRow[] | null => {\n if (!Array.isArray(v)) return null;\n const out: SqliteRow[] = [];\n for (const r of v) {\n const p = plain(r);\n if (p) out.push(p);\n }\n return out;\n};\n\nfunction viaNode(file: string, sql: string, params: SqliteParam[], o: Required<SqliteOptions>): SqliteRow[] | null {\n const C = dbCtor();\n if (!C) return null;\n let db: Db;\n try {\n db = quiet(() => new C(file, { readOnly: true, timeout: o.timeoutMs }));\n } catch {\n return null;\n }\n try {\n try {\n db.exec(`PRAGMA busy_timeout = ${Math.round(o.timeoutMs)}`);\n } catch {}\n return quiet(() => rows(db.prepare(sql).all(...params)));\n } catch {\n return null;\n } finally {\n try {\n db.close();\n } catch {}\n }\n}\n\n/** Runs in a child Node, with the file, the SQL, the parameters and the timeout as argv. */\nconst CHILD = `const { DatabaseSync } = require(\"node:sqlite\");\nconst [, file, sql, params, ms] = process.argv;\nconst db = new DatabaseSync(file, { readOnly: true, timeout: Number(ms) });\ntry { db.exec(\"PRAGMA busy_timeout = \" + Number(ms)); } catch {}\nconst out = db.prepare(sql).all(...JSON.parse(params));\ndb.close();\nprocess.stdout.write(JSON.stringify(out));`;\n\nfunction viaChild(file: string, sql: string, params: SqliteParam[], o: Required<SqliteOptions>): SqliteRow[] | null {\n try {\n const out = execFileSync(\n process.execPath,\n [\"--experimental-sqlite\", \"--no-warnings\", \"-e\", CHILD, file, sql, JSON.stringify(params), String(o.timeoutMs)],\n {\n encoding: \"utf8\",\n timeout: o.timeoutMs + 3000,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n maxBuffer: o.maxBuffer,\n windowsHide: true,\n },\n );\n return rows(JSON.parse(out || \"null\"));\n } catch {\n return null;\n }\n}\n\n/** A parameter safe to write into SQL as a literal: no quote, no backslash, no newline. */\nconst SAFE = /^[A-Za-z0-9 ._:@/+-]{0,256}$/;\nexport function inlineParams(sql: string, params: SqliteParam[]): string | null {\n if (sql.includes(\"'\")) return null; // a literal in the SQL would make the `?` count a guess\n const holes = sql.split(\"?\").length - 1;\n if (holes !== params.length) return null;\n let i = 0;\n let bad = false;\n const out = sql.replace(/\\?/g, () => {\n const p = params[i++];\n if (typeof p === \"number\") {\n if (!Number.isFinite(p)) {\n bad = true;\n return \"NULL\";\n }\n return String(p);\n }\n if (typeof p !== \"string\" || !SAFE.test(p)) {\n bad = true;\n return \"NULL\";\n }\n return `'${p}'`;\n });\n return bad ? null : out;\n}\n\nfunction viaCli(file: string, sql: string, params: SqliteParam[], o: Required<SqliteOptions>): SqliteRow[] | null {\n const text = inlineParams(sql, params);\n if (!text) return null;\n try {\n const out = execFileSync(\"sqlite3\", [\"-readonly\", \"-json\", file, text], {\n encoding: \"utf8\",\n timeout: o.timeoutMs + 3000,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n maxBuffer: o.maxBuffer,\n windowsHide: true,\n }).trim();\n if (!out) return [];\n return rows(JSON.parse(out));\n } catch {\n return null;\n }\n}\n\n/** One read-only query. Null means \"could not read it\", never an exception. */\nexport function querySqlite(\n file: string,\n sql: string,\n params: SqliteParam[] = [],\n opts: SqliteOptions = {},\n): SqliteRow[] | null {\n const o: Required<SqliteOptions> = {\n timeoutMs: opts.timeoutMs ?? 2000,\n engine: opts.engine ?? \"auto\",\n maxBuffer: opts.maxBuffer ?? 32 * 1024 * 1024,\n };\n if (!file) return null;\n try {\n if (!existsSync(file)) return null;\n } catch {\n return null;\n }\n const ways =\n o.engine === \"auto\"\n ? ([viaNode, viaChild, viaCli] as const)\n : o.engine === \"node\"\n ? ([viaNode] as const)\n : o.engine === \"child\"\n ? ([viaChild] as const)\n : ([viaCli] as const);\n for (const way of ways) {\n const r = way(file, sql, params, o);\n if (r) return r;\n }\n return null;\n}\n\n/** Is `node:sqlite` in this process? (Tests skip what they cannot set up.) */\nexport const sqliteInProcess = (): boolean => dbCtor() !== null;\n", "// SPDX-License-Identifier: Apache-2.0\n// Gemini CLI (Google) \u2014 docs: https://geminicli.com/docs/hooks/reference\n// Config: ~/.gemini/settings.json `hooks` key, same array-of-groups shape as Claude\n// Code but timeouts in MILLISECONDS and a `name` per handler. stdout must be JSON or\n// empty. Its own telemetry defaults logPrompts on; the installer says so once.\nimport { execFileSync } from \"node:child_process\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { homeDir } from \"../paths.js\";\nimport { ends, parseLines } from \"../readers/files.js\";\nimport { readGemini } from \"../readers/transcripts.js\";\nimport { installClaudeShaped, installedClaudeShaped, readJson, uninstallClaudeShaped } from \"./claude-shaped.js\";\nimport { findBinary, probe } from \"./headless.js\";\nimport type { Adapter, HookInput, HookResult, InstallOptions, SessionFacts } from \"./types.js\";\n\nconst NAME = \"gemini-cli\";\nexport const GEMINI_EVENTS = [\n \"SessionStart\",\n \"BeforeAgent\",\n \"BeforeTool\",\n \"AfterTool\",\n \"Notification\",\n \"AfterAgent\",\n \"PreCompress\",\n \"SessionEnd\",\n] as const;\nconst OPTS = { matcherFor: (e: string) => (/Tool/.test(e) ? \".*\" : undefined), timeout: 5000 };\nconst geminiDir = (env: NodeJS.ProcessEnv) => env.GEMINI_CLI_HOME || path.join(homeDir(), \".gemini\");\nconst settings = (env: NodeJS.ProcessEnv) => path.join(geminiDir(env), \"settings.json\");\nconst validTool = (n: unknown): n is string => typeof n === \"string\" && /^[A-Za-z0-9_.:-]{1,120}$/.test(n);\nconst eventsFor = (lean?: boolean) => (lean ? GEMINI_EVENTS.filter((e) => e !== \"BeforeTool\") : [...GEMINI_EVENTS]);\n\n/** `gemini --version`. On Windows the CLI is npm's gemini.cmd shim, which node refuses to\n * spawn bare, so there it is looked up on PATH and run as `probe` says (the shim's own\n * script under this node, else through a shell). */\nexport function geminiVersion(\n platform: NodeJS.Platform = process.platform,\n env: NodeJS.ProcessEnv = process.env,\n): string {\n const win = platform === \"win32\";\n const bin = win\n ? findBinary({ names: [\"gemini.exe\", \"gemini.cmd\"], dirs: [path.dirname(process.execPath)], env })\n : \"gemini\";\n if (!bin) throw new Error(\"no gemini on PATH\");\n const c = probe(bin, [\"--version\"]);\n return execFileSync(c.file, c.args, {\n encoding: \"utf8\",\n timeout: 4000,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n env,\n shell: c.shell,\n }).trim();\n}\n\n/** Before 0.46 the hooks system is off unless tools.enableHooks is true (issue #11). */\nexport function geminiHooksActive(settingsFile: string): { active: boolean; note?: string } {\n const tools = readJson(settingsFile).tools as { enableHooks?: unknown } | undefined;\n if (tools?.enableHooks === true) return { active: true };\n if (tools?.enableHooks === false)\n return { active: false, note: \"inactive: tools.enableHooks is false in settings.json\" };\n let version = \"\";\n try {\n version = geminiVersion();\n } catch {\n return {\n active: true,\n note: \"could not run `gemini --version`; hooks need tools.enableHooks on versions before 0.46\",\n };\n }\n const m = /(\\d+)\\.(\\d+)/.exec(version);\n if (m && (Number(m[1]) > 0 || Number(m[2]) >= 46)) return { active: true };\n return {\n active: false,\n note: `inactive: Gemini CLI ${version || \"?\"} runs hooks only with \"tools\": {\"enableHooks\": true} in settings.json`,\n };\n}\n\nexport const geminiCli: Adapter = {\n name: NAME,\n events: GEMINI_EVENTS,\n // ~/.gemini also belongs to Antigravity; Gemini CLI is here when its settings or its chat logs exist.\n detect: (env = process.env) => existsSync(settings(env)) || existsSync(path.join(geminiDir(env), \"tmp\")),\n configFiles: (env = process.env) => [settings(env)],\n install: (cmd, env = process.env, opts: InstallOptions = {}) => {\n const r = installClaudeShaped(settings(env), NAME, eventsFor(opts.lean), cmd, OPTS);\n const a = geminiHooksActive(settings(env));\n return [a.note && !r.skipped ? { ...r, note: [r.note, a.note].filter(Boolean).join(\"; \") } : r];\n },\n uninstall: (env = process.env, opts: InstallOptions = {}) => [\n uninstallClaudeShaped(settings(env), GEMINI_EVENTS, { created: opts.created?.includes(settings(env)) }),\n ],\n installed: (cmd, env = process.env, opts: InstallOptions = {}) => {\n const state = installedClaudeShaped(settings(env), NAME, eventsFor(opts.lean), cmd, OPTS);\n const a = geminiHooksActive(settings(env));\n return [\n {\n file: settings(env),\n state: state === \"current\" && !a.active ? \"inactive\" : state,\n ...(a.note ? { note: a.note } : {}),\n },\n ];\n },\n\n fromHook(input: HookInput): HookResult | null {\n const event = input.argv[1] ?? \"\";\n let s: Record<string, unknown> = {};\n try {\n // A stdin that is JSON but not an object (`null`, a number) is no payload.\n const j: unknown = input.stdin ? JSON.parse(input.stdin) : {};\n if (j && typeof j === \"object\" && !Array.isArray(j)) s = j as Record<string, unknown>;\n } catch {}\n const id = s.session_id as string | undefined;\n if (!id) return null;\n const session: HookResult[\"session\"] = { id: String(id), cwd: typeof s.cwd === \"string\" ? s.cwd : input.cwd };\n const tool = validTool(s.tool_name) ? s.tool_name : undefined;\n const ev = (type: string, data: Record<string, unknown>) => ({ type, data: prune(data), harnessEvent: event });\n const events: HookResult[\"events\"] = [];\n switch (event) {\n case \"SessionStart\":\n events.push(\n ev(\"session.started\", {\n source:\n typeof s.source === \"string\" && [\"startup\", \"resume\", \"clear\"].includes(s.source) ? s.source : \"unknown\",\n }),\n );\n break;\n case \"BeforeAgent\":\n events.push(\n ev(\"turn.started\", { prompt_chars: typeof s.prompt === \"string\" ? [...s.prompt].length : undefined }),\n );\n break;\n case \"BeforeTool\":\n if (tool) events.push(ev(\"tool.started\", { tool, input: s.tool_input }));\n break;\n case \"AfterTool\": {\n const resp = s.tool_response as { error?: unknown; llmContent?: unknown } | undefined;\n const err =\n resp && typeof resp === \"object\" && resp.error\n ? String(typeof resp.error === \"string\" ? resp.error : JSON.stringify(resp.error)).slice(0, 2000)\n : undefined;\n if (tool)\n events.push(\n ev(\"tool.ended\", {\n tool,\n ok: !err,\n error: err,\n input: s.tool_input,\n output: resp?.llmContent ?? s.tool_response,\n }),\n );\n break;\n }\n case \"Notification\":\n events.push(\n ev(\"attention.needed\", {\n attention_id: `notif-${Date.now()}`,\n kind: s.notification_type === \"ToolPermission\" ? \"permission\" : \"question\",\n message: typeof s.message === \"string\" ? s.message.slice(0, 200) : undefined,\n }),\n );\n break;\n case \"AfterAgent\":\n events.push(ev(\"turn.ended\", { reason: \"stop\" }));\n break;\n case \"PreCompress\":\n events.push(ev(\"context.compacted\", { trigger: s.trigger === \"manual\" ? \"manual\" : \"auto\" }));\n break;\n case \"SessionEnd\":\n events.push(\n ev(\"session.ended\", {\n reason:\n s.reason === \"clear\" || s.reason === \"logout\" || s.reason === \"exit\"\n ? s.reason\n : s.reason === \"prompt_input_exit\"\n ? \"exit\"\n : \"other\",\n }),\n );\n break;\n default:\n return null;\n }\n const r: HookResult = { session, events, hints: {} };\n if (typeof s.transcript_path === \"string\") r.transcript = s.transcript_path;\n return r;\n },\n\n readTranscript(file, fromLine) {\n let text = \"\";\n try {\n text = readFileSync(file, \"utf8\");\n } catch {\n return { turns: [], line: fromLine };\n }\n return readGemini(text.split(\"\\n\"), fromLine);\n },\n\n facts(_session, transcript): SessionFacts {\n const out: SessionFacts = {};\n if (!transcript) return out;\n const { head, tail } = ends(transcript, 64 * 1024, 64 * 1024);\n const H = parseLines(head);\n const T = parseLines(tail);\n const first = H.find((j) => j.type === \"user\");\n const raw = first ? (first.content ?? first.message ?? first.text) : undefined;\n const text = typeof raw === \"string\" ? raw.trim() : \"\";\n if (text) {\n const line = text.split(\"\\n\")[0] as string; // trimmed, so its first line is its first non-blank one\n out.title = line.length > 80 ? `${line.slice(0, 80).replace(/\\s+\\S*$/, \"\")}\u2026` : line;\n out.title_source = \"first-ask\";\n }\n const times = H.concat(T)\n .map((j) => Date.parse(String(j.timestamp ?? \"\")))\n .filter((n) => n > 0);\n if (times.length) {\n out.started_at = Math.min(...times);\n out.last_at = Math.max(...times);\n }\n return out;\n },\n\n backfill: () => [], // chat logs are keyed by a project hash, not a session id we can name; the first hook of a resumed session reports it\n};\n\nfunction prune<T extends Record<string, unknown>>(o: T): T {\n for (const k of Object.keys(o)) if (o[k] === undefined) delete o[k];\n return o;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// The registry: the only place that lists vendors. A new harness is one file here\n// plus its fixtures and its row in spec/ADAPTERS.md.\nimport { acpHarnesses } from \"./acp-control.js\";\nimport { antigravity } from \"./antigravity.js\";\nimport { findAgy } from \"./antigravity-control.js\";\nimport { claudeCode } from \"./claude-code.js\";\nimport { findClaude } from \"./claude-code-control.js\";\nimport { codex } from \"./codex.js\";\nimport { findCodex } from \"./codex-control.js\";\nimport { devin } from \"./devin.js\";\nimport { geminiCli } from \"./gemini-cli.js\";\nimport type { Adapter } from \"./types.js\";\n\nexport const ADAPTERS: readonly Adapter[] = [claudeCode, codex, geminiCli, antigravity, devin];\nexport const adapterByName = (name: string): Adapter | undefined => ADAPTERS.find((a) => a.name === name);\nexport * as acpControl from \"./acp-control.js\";\nexport { AG_STALE_PRETOOL, antigravityAnswer } from \"./antigravity.js\";\nexport * as antigravityControl from \"./antigravity-control.js\";\nexport { claudeAccountDirs, claudeAccounts, claudeDirs, notClaudeCode } from \"./claude-code.js\";\nexport * as claudeControl from \"./claude-code-control.js\";\nexport * as codexControl from \"./codex-control.js\";\nexport { DEVIN_EVENTS, devinConfigDir, devinDataDir, readDevinChain } from \"./devin.js\";\nexport {\n deniedNote,\n JOB_TIMEOUT_MS,\n jobEnv,\n type Login,\n type Reading,\n type RunOptions,\n type RunResult,\n runHeadless,\n} from \"./headless.js\";\n\n/** How many harnesses a pairing request or a hello lists at most (control-pair.json,\n * control-hello.json). */\nexport const HELLO_HARNESSES_MAX = 20;\n\n/** The harnesses a control daemon here can drive headlessly (CONTROL.md \u00A76): each whose\n * CLI is installed on this machine, and every ACP agent that is. What `control pair`\n * and every hello advertise: the three with their own drivers first, then the ACP\n * agents in the registry's order, at most HELLO_HARNESSES_MAX of them. */\nexport function drivableHarnesses(env: NodeJS.ProcessEnv = process.env): string[] {\n return [\n ...(findClaude(env) ? [\"claude-code\"] : []),\n ...(findCodex(env) ? [\"codex\"] : []),\n ...(findAgy(env) ? [\"antigravity\"] : []),\n ...acpHarnesses(env),\n ].slice(0, HELLO_HARNESSES_MAX);\n}\nexport type {\n Adapter,\n AdapterEvent,\n BackfillRow,\n FactsState,\n HookCommand,\n HookInput,\n HookResult,\n InstallReport,\n SessionFacts,\n TranscriptRead,\n Turn,\n} from \"./types.js\";\nexport { antigravity, claudeCode, codex, devin, geminiCli };\n", "// SPDX-License-Identifier: Apache-2.0\n// ~/.config/sessionpipe/config.json, mode 0600: the machine's name, the sinks with\n// their tier and token, per-harness switches, the update check, remote titles.\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { configFile, tilde } from \"./paths.js\";\nimport type { Tier } from \"./types.js\";\n\nexport interface SinkConfig {\n name: string;\n /** https://\u2026, file:PATH, stdout, otlp:URL */\n url: string;\n tier: Tier;\n pii?: boolean;\n /** @deprecated Never set: control is per machine (spec/CONTROL.md \u00A72). Kept so an\n * older config still reads. */\n control?: boolean;\n token?: string;\n /** whsec_\u2026 for Standard Webhooks signatures. */\n secret?: string;\n /** The token (and secret) live in this store instead of in this file; the client\n * reads them from it when it sends. */\n token_in?: \"keychain\" | \"secret-service\";\n /** Learned from the receiver's well-known file (`sink add`, `connect`; read again by a\n * worker once a day): its tier cap, and the tool events it asked for. */\n max_tier?: Tier;\n receiver_tools?: \"all\" | \"main\" | \"beat\";\n well_known_at?: string;\n /** When a worker last tried to read it again, whether or not the read went through. */\n well_known_checked_at?: string;\n paused?: string;\n /** Which tool events this sink is sent (issue #208): `all`; `main`, a subagent's at\n * most one per session per minute; `beat`, every tool event at most one per session\n * per minute. Unset: what the receiver's well-known file asked for (`receiver_tools`),\n * else `all`, so no receiver's view changes unless it asked. The outbox keeps every\n * event either way. */\n tools?: \"all\" | \"main\" | \"beat\";\n}\n\nexport interface Config {\n machine?: string;\n sinks: SinkConfig[];\n /** `status_line`: Claude Code's status line is ours (install --status-line). */\n harnesses: Record<string, { enabled?: boolean; created?: string[]; status_line?: boolean }>;\n update_check?: boolean;\n keep_days?: number;\n /** Ask a harness's own service for a session's name (an adapter's `remoteFacts`):\n * claude.ai's, for Claude Code. Off unless the person turns it on (`sessionpipe\n * titles on`): it means reading the harness's sign-in token on this machine. */\n remote_titles?: boolean;\n}\n\nexport const DEFAULT_CONFIG: Config = { sinks: [], harnesses: {}, update_check: true, keep_days: 30 };\n\nexport function readConfig(file: string = configFile()): Config {\n try {\n const j = JSON.parse(readFileSync(file, \"utf8\")) as Partial<Config>;\n return {\n ...DEFAULT_CONFIG,\n ...j,\n sinks: Array.isArray(j.sinks) ? j.sinks : [],\n harnesses: j.harnesses && typeof j.harnesses === \"object\" ? j.harnesses : {},\n };\n } catch {\n return { ...DEFAULT_CONFIG, sinks: [], harnesses: {} };\n }\n}\n\n/** Why `file` cannot be read as a config, or undefined when it can: missing, blank, or a\n * JSON object. readConfig reads such a file as the defaults, so hooks go on. */\nfunction configProblem(file: string): string | undefined {\n let text: string;\n try {\n text = readFileSync(file, \"utf8\");\n } catch (e) {\n // Every error readFileSync throws carries a Node error code.\n const code = (e as NodeJS.ErrnoException).code;\n return code === \"ENOENT\" ? undefined : `could not be read (${code})`;\n }\n if (!text.trim()) return undefined;\n if (text.charCodeAt(0) === 0xfeff) return \"starts with a byte-order mark (save it as UTF-8 without one)\";\n try {\n const j: unknown = JSON.parse(text);\n return j && typeof j === \"object\" && !Array.isArray(j) ? undefined : \"is not a JSON object\";\n } catch (e) {\n // Where, never V8's excerpt of the text: that can be part of a sink's token.\n const m = (e as Error).message;\n const at = (/line \\d+ column \\d+/.exec(m) ?? /position \\d+/.exec(m))?.[0];\n return `is not valid JSON${at ? ` at ${at}` : \"\"}`;\n }\n}\n\n/** Throw if `file` holds something readConfig could not read: writing the defaults over a\n * hand edit's typo would lose the machine's name and every sink with its token. A\n * command with an effect before its save calls this first, so it stops before any. */\nexport function assertConfigWritable(file: string = configFile()): void {\n const problem = configProblem(file);\n if (problem)\n throw new Error(\n `${tilde(file)} ${problem}, so it was not written over: that would lose its machine name and sinks. Fix it, or move it aside to start again, then run this again.`,\n );\n}\n\nexport function writeConfig(c: Config, file: string = configFile()): void {\n assertConfigWritable(file);\n mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });\n writeFileSync(file, `${JSON.stringify(c, null, 2)}\\n`, { mode: 0o600 });\n if (process.platform !== \"win32\" && existsSync(file)) {\n try {\n chmodSync(file, 0o600);\n } catch {}\n }\n}\n\n/** The machine's name: what the person configured, else the hostname without a\n * local suffix. Never guessed from anything else (a hand-typed name once linked 64\n * versions to nothing). */\nexport function machineName(c: Config, hostname: string): string {\n if (c.machine) return String(c.machine).slice(0, 80);\n return hostname.replace(/\\.(local|lan|home)$/i, \"\");\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// ULID: 48-bit ms timestamp + 80 random bits, Crockford base32. Monotonic within a\n// process so two events in the same millisecond still sort in emit order.\nimport { randomBytes } from \"node:crypto\";\n\nconst ALPHABET = \"0123456789ABCDEFGHJKMNPQRSTVWXYZ\";\nlet lastTime = 0;\nlet lastRand: number[] = [];\n\nfunction encodeTime(t: number): string {\n let out = \"\";\n let n = t;\n for (let i = 0; i < 10; i++) {\n out = ALPHABET[n % 32] + out;\n n = Math.floor(n / 32);\n }\n return out;\n}\n\nexport function ulid(now: number = Date.now()): string {\n if (now === lastTime) {\n // increment the random part\n for (let i = lastRand.length - 1; i >= 0; i--) {\n const v = (lastRand[i] as number) + 1;\n if (v < 32) {\n lastRand[i] = v;\n break;\n }\n lastRand[i] = 0;\n }\n } else {\n lastTime = now;\n lastRand = Array.from(randomBytes(16), (b) => b % 32);\n }\n return encodeTime(now) + lastRand.map((v) => ALPHABET[v]).join(\"\");\n}\n\nexport const isUlid = (s: string): boolean => /^[0-9A-HJKMNP-TV-Z]{26}$/.test(s);\n", "// SPDX-License-Identifier: Apache-2.0\n// From an adapter's output to a protocol event: id, time, the full session block\n// as known now, and the raw (tier 3) data. Filtering per sink happens later.\nimport type { AdapterEvent } from \"./adapters/types.js\";\nimport type { Event, Session } from \"./types.js\";\nimport { ulid } from \"./ulid.js\";\n\nexport interface EventContext {\n harness: { name: string; version?: string };\n session: Session;\n now?: number;\n}\n\nexport function makeEvent(a: AdapterEvent, ctx: EventContext): Event {\n const now = ctx.now ?? Date.now();\n const harness: Event[\"harness\"] = { name: ctx.harness.name, event: a.harnessEvent };\n if (ctx.harness.version) harness.version = ctx.harness.version;\n return {\n protocol: 1,\n id: ulid(now),\n type: a.type,\n time: new Date(now).toISOString(),\n tier: 3,\n harness,\n session: ctx.session,\n privacy: { rulesets: [], pii: false },\n data: a.data,\n };\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// The outbox: append-only JSONL per (harness, session) under\n// <state>/outbox/<harness>/<session>.jsonl, a per-session seq counter, a per-sink\n// cursor that moves only when the sink acknowledged, and a per-session lock so two\n// workers never interleave. Never lose, never duplicate.\n\nimport { randomBytes } from \"node:crypto\";\nimport {\n appendFileSync,\n closeSync,\n existsSync,\n mkdirSync,\n openSync,\n readdirSync,\n readFileSync,\n readSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport path from \"node:path\";\nimport { safeId } from \"./paths.js\";\nimport type { Event } from \"./types.js\";\n\nexport interface OutboxRef {\n harness: string;\n session: string;\n}\n\nconst READ_CHUNK = 1024 * 1024;\nconst READ_MAX = 8 * 1024 * 1024;\n\nexport class Outbox {\n constructor(readonly root: string) {}\n\n dir(harness: string): string {\n return path.join(this.root, \"outbox\", safeId(harness));\n }\n file(ref: OutboxRef): string {\n return path.join(this.dir(ref.harness), `${safeId(ref.session)}.jsonl`);\n }\n private seqFile(ref: OutboxRef): string {\n return path.join(this.dir(ref.harness), `${safeId(ref.session)}.seq`);\n }\n\n /** The next seq for a session, persisted (survives a hibernating machine and a\n * restart; an in-memory counter would restart at 0 and collide). */\n nextSeq(ref: OutboxRef): number {\n const f = this.seqFile(ref);\n let n = -1;\n try {\n const t = readFileSync(f, \"utf8\").trim();\n if (/^\\d+$/.test(t)) n = Number(t);\n } catch {}\n // A missing or unreadable counter (a crash between truncate and write leaves it\n // empty) with an existing outbox: recover from the file's last line.\n if (n < 0) n = this.lastSeqInFile(ref) + 1;\n mkdirSync(path.dirname(f), { recursive: true, mode: 0o700 });\n writeFileSync(f, String(n + 1), { mode: 0o600 });\n return n;\n }\n\n private lastSeqInFile(ref: OutboxRef): number {\n const f = this.file(ref);\n if (!existsSync(f)) return -1;\n const lines = readFileSync(f, \"utf8\").trim().split(\"\\n\");\n for (let i = lines.length - 1; i >= 0; i--) {\n try {\n const j = JSON.parse(lines[i] as string) as Event;\n if (typeof j.session?.seq === \"number\") return j.session.seq;\n } catch {}\n }\n return -1;\n }\n\n append(ref: OutboxRef, events: Event[]): void {\n if (!events.length) return;\n mkdirSync(this.dir(ref.harness), { recursive: true, mode: 0o700 });\n appendFileSync(this.file(ref), `${events.map((e) => JSON.stringify(e)).join(\"\\n\")}\\n`, { mode: 0o600 });\n }\n\n /** Every session file, newest first. */\n sessions(): OutboxRef[] {\n const out: { ref: OutboxRef; mtime: number }[] = [];\n const base = path.join(this.root, \"outbox\");\n if (!existsSync(base)) return [];\n for (const h of readdirSync(base)) {\n const d = path.join(base, h);\n let names: string[] = [];\n try {\n names = readdirSync(d).filter((n) => n.endsWith(\".jsonl\"));\n } catch {\n continue;\n }\n for (const n of names) {\n try {\n out.push({ ref: { harness: h, session: n.slice(0, -6) }, mtime: statSync(path.join(d, n)).mtimeMs });\n } catch {}\n }\n }\n return out.sort((a, b) => b.mtime - a.mtime).map((x) => x.ref);\n }\n\n /** Read events after byte offset `from`; returns them and the new offset. Lines\n * are read whole; a partial trailing line (a write in progress) is left. A read\n * takes READ_CHUNK bytes at a time, not the rest of the file: a session file grows\n * to tens of MB and a drain takes it in batches of 50. It reads on until the batch\n * is full or the file ends, so lines that parse to nothing never stop a drain; one\n * line longer than the chunk gets a larger one, up to READ_MAX. */\n read(ref: OutboxRef, from: number, maxEvents = 500): { events: Event[]; offset: number } {\n const f = this.file(ref);\n if (!existsSync(f)) return { events: [], offset: from };\n const size = statSync(f).size;\n if (from >= size) return { events: [], offset: from };\n const fd = openSync(f, \"r\");\n try {\n const events: Event[] = [];\n let offset = from;\n let chunk = READ_CHUNK;\n while (events.length < maxEvents && offset < size) {\n const buf = Buffer.alloc(Math.min(size - offset, chunk));\n const n = readSync(fd, buf, 0, buf.length, offset);\n const text = buf.subarray(0, n).toString(\"utf8\");\n let pos = 0;\n let used = 0;\n while (events.length < maxEvents) {\n const nl = text.indexOf(\"\\n\", pos);\n if (nl < 0) break;\n const line = text.slice(pos, nl);\n pos = nl + 1;\n used += Buffer.byteLength(line, \"utf8\") + 1;\n if (!line.trim()) continue;\n try {\n events.push(JSON.parse(line) as Event);\n } catch {}\n }\n offset += used;\n if (used) continue;\n // No whole line in this chunk: a line longer than it, or a write in progress.\n if (offset + n >= size || chunk >= READ_MAX) break;\n chunk *= 2;\n }\n return { events, offset };\n } finally {\n closeSync(fd);\n }\n }\n\n /** Files older than `days` are pruned, and each sink's cursor into them. The seq\n * counter stays: a session resumed after the window counts on from where it was,\n * so a receiver's (harness, session, seq) dedup doesn't take its new events for\n * ones it already has, and the sinks read the new file from its start.\n * It all happens under the drain's `flush` lock, since a drain holds the whole\n * cursor map and writes it back: a file and its cursor keys go together, so a\n * session resumed in between can't keep a key past its new file's end. While a\n * drain runs, nothing is pruned (0); the next prune does it. It never throws: it\n * is a cleanup, and a hook's drain comes after it. */\n prune(days: number, now = Date.now()): number {\n let release: (() => void) | null = null;\n try {\n release = takeNamedLock(this.root, \"flush\");\n } catch {}\n if (!release) return 0;\n let n = 0;\n try {\n const cutoff = now - days * 86_400_000;\n const aged = this.sessions().filter((ref) => {\n try {\n return statSync(this.file(ref)).mtimeMs < cutoff;\n } catch {\n return false;\n }\n });\n // The keys go first: a worker that dies or fails to write here leaves a file\n // with no cursor, which a sink sends again (a receiver's dedup takes it), never\n // a cursor past the end of a file a resume starts. Each file is checked again\n // right before it goes: one a hook appended to meanwhile stays.\n this.dropStaleCursors(new Set(aged.map((ref) => `${ref.harness}/${ref.session}`)));\n for (const ref of aged) {\n const f = this.file(ref);\n try {\n if (statSync(f).mtimeMs < cutoff) {\n unlinkSync(f);\n n++;\n }\n } catch {}\n }\n } catch {\n } finally {\n release();\n }\n return n;\n }\n\n /** A sink's cursor into a session file about to be pruned (`gone`), or one already\n * missing (an earlier prune, an older release, by hand) is removed. The caller\n * holds the `flush` lock. */\n private dropStaleCursors(gone: Set<string>): void {\n let names: string[] = [];\n try {\n names = readdirSync(path.join(this.root, \"cursors\")).filter((n) => n.endsWith(\".json\"));\n } catch {}\n const stale = (c: Record<string, number>): string[] =>\n Object.keys(c).filter((k) => {\n if (gone.has(k)) return true;\n const i = k.indexOf(\"/\");\n return !existsSync(this.file({ harness: k.slice(0, i), session: k.slice(i + 1) }));\n });\n for (const n of names) {\n const s = new Cursors(this.root, n.slice(0, -5));\n const c = s.read();\n const keys = stale(c);\n if (!keys.length) continue;\n for (const k of keys) delete c[k];\n s.write(c);\n }\n }\n\n delete(ref: OutboxRef): void {\n // The cursor keys go before the files: a death between leaves the old file with\n // no cursor, so the next drain sends it whole and the person, who sees no \"removed\"\n // line, runs forget again; the other way round leaves a cursor past the end of\n // the file a session that goes on starts, and nothing says so.\n this.dropCursors(ref);\n for (const f of [this.file(ref), this.seqFile(ref)]) {\n try {\n unlinkSync(f);\n } catch {}\n }\n }\n\n /** The key every sink's cursor holds for a session is removed with the session's\n * file: the key alone pointed into the old file, and a session that went on (still\n * running, or resumed later) had its new file's first events unsent until it grew\n * past that offset. Every file under <state>/cursors is taken (a sink since taken\n * out of the config still has one; one that doesn't parse reads as empty and is\n * left), by the key a drain writes (the file's own name, `safeId`) and by the ref\n * as given. The caller holds the drain's `flush` lock: a drain holds the whole\n * cursor map and writes it back, so a key dropped under it would come back. */\n private dropCursors(ref: OutboxRef): void {\n const keys = new Set([`${ref.harness}/${ref.session}`, `${safeId(ref.harness)}/${safeId(ref.session)}`]);\n let names: string[] = [];\n try {\n names = readdirSync(path.join(this.root, \"cursors\")).filter((n) => n.endsWith(\".json\"));\n } catch {\n return;\n }\n for (const n of names) {\n const s = new Cursors(this.root, n.slice(0, -5));\n const c = s.read();\n const had = Object.keys(c).filter((k) => keys.has(k));\n if (!had.length) continue;\n for (const k of had) delete c[k];\n s.write(c);\n }\n }\n}\n\n/** Per-sink cursor: byte offset per session file, moved only on a 2xx. */\nexport class Cursors {\n constructor(\n readonly root: string,\n readonly sink: string,\n ) {}\n private file(): string {\n return path.join(this.root, \"cursors\", `${safeId(this.sink)}.json`);\n }\n /** The map; empty when the file is missing, cut off mid-write, or holds anything\n * but an object (`null`, a list), so a drain never indexes into those. */\n read(): Record<string, number> {\n try {\n const c = JSON.parse(readFileSync(this.file(), \"utf8\")) as unknown;\n return c && typeof c === \"object\" && !Array.isArray(c) ? (c as Record<string, number>) : {};\n } catch {\n return {};\n }\n }\n write(c: Record<string, number>): void {\n const f = this.file();\n mkdirSync(path.dirname(f), { recursive: true, mode: 0o700 });\n const tmp = `${f}.${process.pid}.tmp`;\n writeFileSync(tmp, JSON.stringify(c), { mode: 0o600 });\n renameSync(tmp, f);\n }\n key(ref: OutboxRef): string {\n return `${ref.harness}/${ref.session}`;\n }\n}\n\n/** A lock per session so two workers never interleave. Stale once the worker that\n * took it is gone (its 15 s deadline ends it without a release), or after 5 min. */\nexport function takeLock(root: string, ref: OutboxRef, staleMs = 5 * 60_000): (() => void) | null {\n return takeNamedLock(root, `${safeId(ref.harness)}-${safeId(ref.session)}`, staleMs);\n}\n\n/** A named lock under <root>/locks, held by one process at a time: the file names\n * its pid and a nonce. Stale once that process is gone, or after `staleMs`. A stale\n * lock is taken over by renaming it aside first: of two workers that both judged it\n * stale, one rename wins, and one that moved a fresh lock instead (another worker's,\n * made in between) puts it back and stands down. The release deletes the file only\n * while it is still this taker's, so a lock taken over can't be wiped by its old\n * holder. Two holders at once used to mean two drains reading the same cursors and\n * sending the same batch (issue #208's one-request-a-second pace rests on one). */\nexport function takeNamedLock(root: string, name: string, staleMs = 5 * 60_000): (() => void) | null {\n const dir = path.join(root, \"locks\");\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n const f = path.join(dir, `${name}.lock`);\n const nonce = randomBytes(8).toString(\"hex\");\n const mine = `${process.pid} ${nonce}`;\n let body: string | null = null;\n try {\n body = readFileSync(f, \"utf8\");\n const stale = Date.now() - statSync(f).mtimeMs > staleMs || !processAlive(Number(body.split(\" \")[0]));\n if (!stale) return null;\n } catch {\n body = null;\n }\n if (body !== null) {\n const aside = `${f}.${process.pid}.${nonce}.stale`;\n try {\n renameSync(f, aside);\n } catch {\n return null;\n }\n // The aside name is this call's own: nobody else reads or removes it.\n const moved = readFileSync(aside, \"utf8\");\n unlinkSync(aside);\n if (moved !== body) {\n try {\n writeFileSync(f, moved, { flag: \"wx\" });\n } catch {}\n return null;\n }\n }\n try {\n writeFileSync(f, mine, { flag: \"wx\" });\n } catch {\n return null;\n }\n return () => {\n try {\n if (readFileSync(f, \"utf8\") === mine) unlinkSync(f);\n } catch {}\n };\n}\n\n/** `takeNamedLock`, tried again every `everyMs` until `forMs` have passed: for a\n * command whose work goes under a lock a worker holds for seconds (a drain). null\n * once the time is up. */\nexport async function waitNamedLock(\n root: string,\n name: string,\n forMs: number,\n everyMs = 100,\n): Promise<(() => void) | null> {\n for (let waited = 0; ; waited += everyMs) {\n const release = takeNamedLock(root, name);\n if (release || waited >= forMs) return release;\n await new Promise((r) => setTimeout(r, everyMs));\n }\n}\n\n/** Whether the process a lock or a claimed job names is still running. A pid that\n * can't be read counts as running: the age rule decides then. */\nexport function processAlive(pid: number): boolean {\n if (!Number.isInteger(pid) || pid <= 0) return true;\n try {\n process.kill(pid, 0);\n return true;\n } catch (e) {\n return (e as NodeJS.ErrnoException).code === \"EPERM\";\n }\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// pii@1 \u2014 an opt-in second pass that reduces identifiers (spec/PRIVACY.md \u00A72). It\n// does not promise anonymity; it removes the obvious.\nimport { createHash } from \"node:crypto\";\n\nexport const RULESET_PII = \"pii@1\";\n\nconst EMAIL = /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\\b/g;\n/** E.164 and common national forms: an optional +, 7\u201315 digits with separators,\n * optional area-code parentheses. A version number (22.23.1) or an IP never matches:\n * the run must not sit between dots, and needs \u2265 7 digits. An ISO date (2026-10-31)\n * has a phone's shape, so it is tried first (group 1) and kept, but only when nothing\n * after it could carry the run on: no letter or digit, and no separator then two digits\n * (a phone's group is two to four; one digit, as in \"2026-10-31 5 files\", never is),\n * unless that is a time's hour (\" 12:\", 00\u201323), and not right after a \")\" or a \"+\"\n * with a country code: a phone's prefix this pass could not take (\"x(415) 2026-10-31\",\n * \"[phone]+1 2026-10-31\") would take the date on the next one. Any other date is read\n * as before. The date may follow a `+` (a diff's added line), so a second pass over\n * \"[phone]+2026-10-31\" keeps it too. */\nconst PHONE =\n /(?<![\\w.])(?:(?<!\\)[ .-]?|\\+\\d{1,3}[ .-]?)(\\+?(?:19|20)\\d{2}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\\d|3[01]))(?:(?= (?:[01]?\\d|2[0-3]):)|(?!\\w|[ .-]\\d\\d))|(?:\\+\\d{1,3}[ .-]?)?(?:\\(\\d{2,4}\\)[ .-]?)?\\d{2,4}(?:[ .-]?\\d{2,4}){1,3}(?!\\w))/g;\n\nfunction looksPhone(s: string): boolean {\n const digits = s.replace(/\\D/g, \"\");\n if (digits.length < 7 || digits.length > 15) return false;\n // \"port 8891, pr 12345\": a bare run with no separator or + is a number, not a phone.\n if (!/[+() .-]/.test(s)) return false;\n // \"22.23.1\", \"185.199.108.153\": dots alone are a version or an address.\n if (!/[+() -]/.test(s)) return false;\n return true;\n}\n\n/** Replace emails and phone numbers, and write `home` as `~`. */\nexport function reducePii(text: string, home?: string): string {\n if (!text) return text;\n let out = text.replace(EMAIL, \"[email]\");\n out = out.replace(PHONE, (m, date?: string) => (!date && looksPhone(m) ? \"[phone]\" : m));\n if (home) {\n const h = home.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n out = out.replace(new RegExp(`(?<![A-Za-z0-9_])${h}(?=/|$|\\\\s|[\"'\\`])`, \"g\"), \"~\");\n }\n return out;\n}\n\n/** The machine's name under pii@1: the first 8 hex of its SHA-256. */\nexport function hashMachine(name: string): string {\n return createHash(\"sha256\").update(name).digest(\"hex\").slice(0, 8);\n}\n\n/** Apply pii@1 to every string in a value; `home` becomes `~`. */\nexport function reducePiiDeep<T>(v: T, home?: string): T {\n if (typeof v === \"string\") return reducePii(v, home) as T;\n if (Array.isArray(v)) return v.map((x) => reducePiiDeep(x, home)) as T;\n if (v && typeof v === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [k, x] of Object.entries(v as Record<string, unknown>)) out[k] = reducePiiDeep(x, home);\n return out as T;\n }\n return v;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// secrets@1 \u2014 credentials out of every string, on the person's machine, before an\n// event reaches the outbox. Ported from spacesheep-cli lib/redact.js (Michael\n// Makarov, MIT \u2192 Apache-2.0, see NOTICE). The ruleset is defined in\n// spec/PRIVACY.md \u00A72 and pinned by conformance/redaction/secrets.json.\n//\n// Every pattern is linear: bounded repetition, no nested quantifiers. The\n// adversarial vectors (password_ \u00D7 5000, a 50 000-space run) pin that.\n\nexport const RULESET_SECRETS = \"secrets@1\";\nexport const REDACTED = \"[redacted]\";\n\n/** Token formats that are a credential by their shape alone. Each is anchored on a\n * vendor prefix, so a commit sha or a UUID never matches. */\nconst TOKEN_PATTERNS: RegExp[] = [\n /-----BEGIN [A-Z0-9 ]*PRIVATE KEY(?: BLOCK)?-----[\\s\\S]*?(?:-----END [A-Z0-9 ]*PRIVATE KEY(?: BLOCK)?-----|$)/g,\n /\\b(?:AKIA|ASIA|ABIA|ACCA)[0-9A-Z]{16}\\b/g, // AWS access key id\n /\\bgh[pousr]_[A-Za-z0-9]{30,}\\b/g, // GitHub\n /\\bgithub_pat_[A-Za-z0-9_]{30,}\\b/g,\n /\\bglpat-[A-Za-z0-9_-]{20,}\\b/g, // GitLab\n /\\bxox[abposre]-[A-Za-z0-9-]{10,}\\b/g, // Slack\n /\\bhttps:\\/\\/hooks\\.slack\\.com\\/services\\/[A-Za-z0-9/_-]+/g,\n /\\bhttps:\\/\\/(?:ptb\\.|canary\\.)?discord(?:app)?\\.com\\/api\\/webhooks\\/[0-9]+\\/[A-Za-z0-9_-]+/g,\n /\\bsk-(?:ant-|proj-|svcacct-|admin-|or-v1-)?[A-Za-z0-9_-]{20,}\\b/g, // Anthropic, OpenAI, DeepSeek, OpenRouter\n /\\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\\b/g, // Stripe secret / restricted\n /\\bwhsec_[A-Za-z0-9+/=]{20,}/g, // Stripe / Svix / Standard Webhooks secret\n /\\bAIza[0-9A-Za-z_-]{35}\\b/g, // Google API key\n /\\bya29\\.[0-9A-Za-z_-]{20,}/g, // Google OAuth access token\n /\\b1\\/\\/0[0-9A-Za-z_-]{30,}/g, // Google OAuth refresh token\n /\\bGOCSPX-[0-9A-Za-z_-]{20,}/g, // Google OAuth client secret\n /\\bxai-[A-Za-z0-9]{30,}\\b/g,\n /\\bgsk_[A-Za-z0-9]{30,}\\b/g, // Groq\n /\\bpplx-[A-Za-z0-9]{30,}\\b/g, // Perplexity\n /\\bhf_[A-Za-z0-9]{30,}\\b/g, // Hugging Face\n /\\bpcsk_[A-Za-z0-9_]{30,}\\b/g, // Pinecone\n /\\bnpm_[A-Za-z0-9]{30,}\\b/g,\n /\\bpypi-[A-Za-z0-9_-]{50,}/g,\n /\\bSG\\.[A-Za-z0-9_-]{16,}\\.[A-Za-z0-9_-]{16,}/g, // SendGrid\n /\\bshp(?:at|ss|ca|pa)_[a-fA-F0-9]{32}\\b/g, // Shopify\n /\\bdop_v1_[a-f0-9]{64}\\b/g, // DigitalOcean\n /\\b(?:lin_api|lin_oauth)_[A-Za-z0-9]{30,}\\b/g, // Linear\n /\\b(?:ntn|secret)_[A-Za-z0-9]{40,}\\b/g, // Notion\n /\\bsbp_[a-f0-9]{40}\\b/g, // Supabase\n /\\bfigd_[A-Za-z0-9_-]{30,}/g, // Figma\n /\\bdp\\.(?:pt|st|sa|ct)\\.[A-Za-z0-9]{30,}/g, // Doppler\n /\\bgrn_[A-Za-z0-9_-]{20,}/g, // Granola\n /\\bss_[a-f0-9]{32,}\\b/g, // spacesheep API keys\n /\\b[0-9]{8,10}:AA[A-Za-z0-9_-]{33}\\b/g, // Telegram bot token\n /\\beyJ[A-Za-z0-9_-]{10,}\\.eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}/g, // JWT\n];\n/** `scheme://user:password@host` \u2014 the password goes, the user and host stay. */\nconst URL_CREDENTIALS = /\\b([a-z][a-z0-9+.-]{1,20}:\\/\\/[^\\s:/@'\"`<>]{1,100}:)([^\\s@/'\"`<>]{1,200})(@)/gi;\n/** `Authorization: Bearer \u2026` / `Basic \u2026`, and a bare `Bearer <token>` in a curl line. */\nconst AUTH_HEADER = /\\b((?:Bearer|Basic|Token)\\s+)([A-Za-z0-9._~+/=-]{16,})/g;\n// The words that name a secret, in prose. `key` alone is too common (\"the key\n// point\"), so it only counts with a qualifier.\nconst SECRET_WORD =\n \"(?:pass(?:word|wd|phrase|code)?s?|pwd|secret(?:[ _-]?key)?s?|client[ _-]?secret|api[ _-]?keys?|apikeys?|access[ _-]?keys?|access[ _-]?tokens?|auth[ _-]?tokens?|refresh[ _-]?tokens?|private[ _-]?keys?|tokens?|credentials?|creds)\";\n/** Strict form: a NAME, an explicit separator (`=`, `:`, `=>`), a value. The name is\n * one flat run of identifier characters judged in code (isSecretName), never by a\n * nested pattern. Only a secret name goes on to consume its value \u2014 otherwise\n * `https:` would swallow the `?token=\u2026` behind it. */\nconst NAME_SEP = /(?<![A-Za-z0-9_])([A-Za-z][A-Za-z0-9_-]{1,79})([\"']?\\s{0,3}(?::=|=>|=|:)\\s{0,3})/g;\nconst VALUE = /\"([^\"\\n]{1,300})\"|'([^'\\n]{1,300})'|`([^`\\n]{1,300})`|([^\\s\"'`,;&)}\\]]{1,300})/y;\n\nfunction redactAssignments(text: string): string {\n let out = \"\";\n let last = 0;\n NAME_SEP.lastIndex = 0;\n for (let m = NAME_SEP.exec(text); m; m = NAME_SEP.exec(text)) {\n const name = m[1] as string;\n if (!isSecretName(name)) continue;\n VALUE.lastIndex = NAME_SEP.lastIndex;\n const v = VALUE.exec(text);\n if (!v) continue;\n const value = (v[1] ?? v[2] ?? v[3] ?? v[4]) as string;\n NAME_SEP.lastIndex = VALUE.lastIndex;\n if (isPlaceholder(value) || value.includes(REDACTED)) continue;\n // `max_tokens: 4096`, `input_tokens=12k` \u2014 a token COUNT, not a token.\n if (/tokens?$/i.test(name) && /^\\d+(?:[.,]\\d+)*[km]?$/i.test(value)) continue;\n const q = v[1] != null ? '\"' : v[2] != null ? \"'\" : v[3] != null ? \"`\" : \"\";\n out += text.slice(last, v.index) + q + REDACTED + q;\n last = VALUE.lastIndex;\n }\n return last ? out + text.slice(last) : text;\n}\n\n/** Is this identifier the name of a secret? `DB_PASSWORD`, `apiKey`, `client-secret`,\n * `AWS_SECRET_ACCESS_KEY`, `GITHUB_TOKEN`; an env-style `STRIPE_KEY` too. Not\n * `password_hash`, `tokenizer`, `sort_key`. */\nexport function isSecretName(name: string): boolean {\n if (/^[A-Z0-9_]+_KEY$/.test(name)) return true;\n const flat = name.toLowerCase().replace(/[_-]/g, \"\");\n return /(?:pass(?:word|wd|phrase|code)|pwd|secret|secretkey|secretaccesskey|clientsecret|apikey|accesskey|accesstoken|authtoken|refreshtoken|privatekey|token|credential|creds)s?$/.test(\n flat,\n );\n}\n\n/** Loose form: prose. \"password is Hunter2!\", \"the token was ghx\u2026\". Only a value\n * that looks generated counts, so \"the password is wrong\" passes untouched.\n * Whitespace runs are bounded so a long run can't make the match quadratic. */\nconst PROSE = new RegExp(\n `(\\\\b${SECRET_WORD}(?:[ \\\\t]{1,3}(?:is|was|=|:|to|as|of|for[ \\\\t]{1,3}\\\\S{1,40}[ \\\\t]{1,3}is))?[ \\\\t]{1,3})([\"'\\`]?)([^\\\\s\"'\\`]{6,200})\\\\2`,\n \"gi\",\n);\n\n/** A value that is plainly not the secret itself: a type, a variable, a template, an\n * already-redacted marker, an env lookup. */\nfunction isPlaceholder(v: string): boolean {\n const s = v.replace(/[.,;:!?]+$/, \"\");\n if (!s) return true;\n if (\n /^(?:string|number|boolean|bool|str|int|any|unknown|null|undefined|none|nil|true|false|optional|required|text|varchar|password|secret|token|env|string\\[\\]|object|bytes)$/i.test(\n s,\n )\n )\n return true;\n if (/^\\[?redacted\\]?$/i.test(s) || /^\\*+$/.test(s) || /^x{3,}$/i.test(s) || /^\\.{3}$|^\u2026$/.test(s)) return true;\n if (/^[<{$%]/.test(s)) return true; // <your-key>, ${VAR}, {{var}}, $VAR, %VAR%\n if (\n /^(?:process\\.env|env|os\\.environ|c\\.env|this\\.env|import\\.meta\\.env|getenv|config|settings|secrets|args|opts|options|req|request|body|params|input|data|user|self|this)\\b/i.test(\n s,\n )\n )\n return true;\n if (/^[A-Za-z_$][\\w$]*(?:\\.[A-Za-z_$][\\w$]*)+$/.test(s)) return true; // a member path: form.password\n if (/[(]/.test(s)) return true; // a call: hash(pw), getSecret()\n if (/^(?:your|my|the|a|an|some|new|old)[-_ ]/i.test(s)) return true; // your-api-key\n return false;\n}\n\n/** Does a prose value look like something generated, rather than an English word? */\nfunction looksSecret(v: string): boolean {\n const s = v.replace(/[.,;:!?)]+$/, \"\");\n if (s.length < 6) return false;\n if (isPlaceholder(s)) return false;\n if (/^https?:\\/\\//i.test(s)) return false; // a link, handled by URL_CREDENTIALS if it carries one\n if (/^[a-z]+(?:[-'][a-z]+)*$/.test(s)) return false; // a lowercase word\n if (/^[A-Z][a-z]+$/.test(s)) return false; // a capitalised word\n if (/^\\d+(?:[.,]\\d+)*[a-z%]*$/i.test(s)) return false; // a count: 4096, 128k, 3.5, 50%\n if (/^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+$/.test(s)) return false; // an env var's NAME\n const kinds = [/[a-z]/, /[A-Z]/, /[0-9]/, /[^A-Za-z0-9]/].filter((r) => r.test(s)).length;\n return kinds >= 3 || (/[0-9]/.test(s) && /[A-Za-z]/.test(s));\n}\n\n/** Redact every credential in `text`. Returns the same string when there is none. */\nexport function redactSecrets(text: string): string {\n if (!text) return text;\n let out = text;\n for (const re of TOKEN_PATTERNS) out = out.replace(re, REDACTED);\n out = out.replace(URL_CREDENTIALS, (_m, head: string, _pw: string, at: string) => `${head}${REDACTED}${at}`);\n out = out.replace(AUTH_HEADER, (_m, head: string) => `${head}${REDACTED}`);\n out = redactAssignments(out);\n out = out.replace(PROSE, (m, head: string, q: string, v: string) =>\n !looksSecret(v) || v.includes(REDACTED) ? m : `${head}${q}${REDACTED}${q}`,\n );\n return out;\n}\n\n/** Did redaction change anything? */\nexport function hasSecret(text: string): boolean {\n return !!text && redactSecrets(text) !== text;\n}\n\n/** Redact every string in a JSON-able value (keys are left alone). */\nexport function redactDeep<T>(v: T): T {\n if (typeof v === \"string\") return redactSecrets(v) as T;\n if (Array.isArray(v)) return v.map(redactDeep) as T;\n if (v && typeof v === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [k, x] of Object.entries(v as Record<string, unknown>)) out[k] = redactDeep(x);\n return out as T;\n }\n return v;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// filter(event, tier, pii): the pure function every sink runs an event through.\n// Removes by ALLOWLIST per type and tier (spec/PRIVACY.md \u00A71), redacts every string\n// above tier 0 with secrets@1, and runs pii@1 when asked. Returns null when the\n// type is not carried at the tier. The conformance runner runs the same function.\nimport type { Event, Tier } from \"../types.js\";\nimport { hashMachine, RULESET_PII, reducePiiDeep } from \"./pii.js\";\nimport { RULESET_SECRETS, redactDeep } from \"./secrets.js\";\n\n/** The lowest tier that carries each known type (kept in step with schema/v1.ts). */\nexport const TYPE_TIER: Record<string, Tier> = {\n \"session.started\": 0,\n \"session.heartbeat\": 0,\n \"session.ended\": 0,\n \"session.backfill\": 0,\n \"session.forgotten\": 0,\n \"turn.started\": 0,\n \"turn.ended\": 0,\n \"turn.transcript\": 2,\n \"turn.progress\": 2,\n \"tool.started\": 1,\n \"tool.ended\": 1,\n \"files.changed\": 1,\n \"attention.needed\": 0,\n \"attention.cleared\": 0,\n \"subagent.started\": 1,\n \"subagent.ended\": 1,\n \"context.compacted\": 1,\n \"limits.observed\": 1,\n \"delegation.started\": 0,\n \"delegation.ended\": 0,\n native: 3,\n};\n\n/** data keys allowed per type at tier N (cumulative: tier 1 includes tier 0's). */\nconst DATA_ALLOW: Record<string, Partial<Record<Tier, string[]>>> = {\n \"session.started\": { 0: [\"source\"] },\n \"session.heartbeat\": { 0: [] },\n \"session.ended\": { 0: [\"reason\"] },\n \"session.backfill\": { 0: [\"started_at\", \"last_at\", \"turns\"] },\n \"session.forgotten\": { 0: [] },\n \"turn.started\": { 0: [\"turn_id\", \"submitted_by\", \"injected\"], 1: [\"prompt_chars\"] },\n \"turn.ended\": { 0: [\"turn_id\", \"reason\", \"ms\", \"background\"], 1: [\"error\"] },\n \"turn.transcript\": { 2: [\"turn\", \"user\", \"assistant\", \"at\", \"injected\"] },\n \"turn.progress\": { 2: [\"turn\", \"user\", \"assistant\", \"at\", \"injected\"] },\n \"tool.started\": { 1: [\"tool\", \"call_id\", \"turn_id\", \"agent_id\"], 3: [\"input\"] },\n \"tool.ended\": { 1: [\"tool\", \"call_id\", \"turn_id\", \"agent_id\", \"ms\", \"ok\", \"error\"], 3: [\"input\", \"output\"] },\n \"files.changed\": { 1: [\"paths\"] },\n \"attention.needed\": { 0: [\"attention_id\", \"kind\"], 1: [\"tool\", \"message\", \"agent_id\"] },\n \"attention.cleared\": { 0: [\"attention_id\", \"how\"] },\n \"subagent.started\": { 1: [\"agent_id\", \"agent_type\"] },\n \"subagent.ended\": { 1: [\"agent_id\", \"agent_type\", \"background\"] },\n \"context.compacted\": { 1: [\"trigger\"] },\n \"limits.observed\": { 1: [\"windows\", \"plan\", \"account_id\"] },\n \"delegation.started\": { 0: [\"ask_id\", \"via\", \"harness\", \"to\"], 1: [\"text\"] },\n \"delegation.ended\": { 0: [\"ask_id\", \"to\", \"ok\", \"ms\", \"error\", \"relayed\"], 2: [\"reply\"] },\n};\n\nconst SESSION_ALLOW = [\n \"id\",\n \"seq\",\n \"machine\",\n \"cwd\",\n \"repo\",\n \"branch\",\n \"model\",\n \"title\",\n \"title_source\",\n \"url\",\n \"account_id\",\n \"attended\",\n \"parent_id\",\n \"launched_by\",\n \"delegated_by\",\n];\nconst MAX_SIDE = 20_000;\nconst MAX_IO = 64 * 1024;\n\nfunction allowedKeys(type: string, tier: Tier): string[] | null {\n const table = DATA_ALLOW[type];\n if (!table) return null; // unknown type: kept whole (receivers keep extra keys), redacted\n const out: string[] = [];\n for (let t = 0; t <= tier; t++) for (const k of table[t as Tier] ?? []) out.push(k);\n return out;\n}\n\nfunction cap(v: unknown, max: number): unknown {\n if (typeof v === \"string\") return v.length > max ? `${v.slice(0, max)}\u2026` : v;\n if (v && typeof v === \"object\") {\n const s = JSON.stringify(v);\n return s.length > max ? `${s.slice(0, max)}\u2026` : v;\n }\n return v;\n}\n\n/** At most `max` characters, keeping the end: an ellipsis, then the last max \u2212 1. */\nexport function capTail(v: string, max: number): string {\n return v.length > max ? `\u2026${v.slice(v.length - max + 1)}` : v;\n}\n\nexport interface FilterOptions {\n /** The person's home directory, for pii@1's `~` rewrite. */\n home?: string;\n}\n\n/** The event as a sink at `tier` may see it, or null when the type is above the tier. */\nexport function filterEvent(event: Event, tier: Tier, pii: boolean, opts: FilterOptions = {}): Event | null {\n const minTier = TYPE_TIER[event.type];\n if (minTier !== undefined && minTier > tier) return null;\n\n const session: Record<string, unknown> = {};\n for (const k of SESSION_ALLOW)\n if (event.session[k as keyof typeof event.session] !== undefined)\n session[k] = event.session[k as keyof typeof event.session];\n\n let data: Record<string, unknown> = {};\n const keys = allowedKeys(event.type, tier);\n if (keys === null) data = { ...event.data };\n else for (const k of keys) if (event.data[k] !== undefined) data[k] = event.data[k];\n if (typeof data.user === \"string\") data.user = cap(data.user, MAX_SIDE);\n // A turn still running is read for where it is now: its reply keeps the end.\n if (typeof data.assistant === \"string\")\n data.assistant = event.type === \"turn.progress\" ? capTail(data.assistant, MAX_SIDE) : cap(data.assistant, MAX_SIDE);\n if (data.input !== undefined) data.input = cap(data.input, MAX_IO);\n if (data.output !== undefined) data.output = cap(data.output, MAX_IO);\n if (typeof data.message === \"string\") data.message = cap(data.message, 200);\n // What an ask asked, and what came back (PROTOCOL.md \u00A74 delegation.*): the daemon cuts\n // them too, but the cap is this function's promise.\n if (event.type === \"delegation.started\" && typeof data.text === \"string\") data.text = cap(data.text, 200);\n if (event.type === \"delegation.ended\" && typeof data.reply === \"string\") data.reply = cap(data.reply, MAX_SIDE);\n\n const rulesets: string[] = [];\n let out: Event = { ...event, tier, session: session as Event[\"session\"], data, privacy: { rulesets, pii } };\n if (tier > 0) {\n // Redact, then the caps above already applied: a cut before redaction could leave half a key.\n out = { ...out, session: redactDeep(out.session), data: redactDeep(out.data) };\n rulesets.push(RULESET_SECRETS);\n }\n if (pii) {\n const s = reducePiiDeep(out.session, opts.home) as Record<string, unknown>;\n if (typeof s.machine === \"string\") s.machine = hashMachine(s.machine);\n delete s.account_id;\n const d = reducePiiDeep(out.data, opts.home) as Record<string, unknown>;\n // limits.observed names the account its numbers belong to: the same identifier\n // pii@1 drops from the session block, so it goes the same way.\n delete d.account_id;\n out = { ...out, session: s as Event[\"session\"], data: d };\n rulesets.push(RULESET_PII);\n }\n out.privacy = { rulesets, pii };\n return out;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// A session's short id (spec/PROTOCOL.md \u00A73): the first 8 hex digits of\n// sha256(\"sessionpipe.session:\" + harness + \":\" + id). What a person reads in a log\n// line, a notification, a search box; derived, never sent. Not a prefix of the id\n// itself: Codex ids are time-ordered (UUIDv7), and two sessions started in the same\n// minute share their first eight characters.\nimport { createHash } from \"node:crypto\";\n\nexport function shortId(harness: string, id: string): string {\n return createHash(\"sha256\").update(`sessionpipe.session:${harness}:${id}`).digest(\"hex\").slice(0, 8);\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// file:PATH \u2014 append filtered events as JSONL. The zero-server sink.\nimport { appendFileSync, mkdirSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { Event, Tier } from \"../types.js\";\nimport type { DeliveryResult, Sink } from \"./types.js\";\n\nexport class FileSink implements Sink {\n constructor(\n readonly name: string,\n readonly file: string,\n readonly tier: Tier,\n readonly pii: boolean,\n ) {}\n async send(events: Event[]): Promise<DeliveryResult> {\n try {\n mkdirSync(path.dirname(this.file), { recursive: true });\n appendFileSync(this.file, `${events.map((e) => JSON.stringify(e)).join(\"\\n\")}\\n`);\n return { ok: true, acknowledged: events.length, accepted: events.length, duplicates: 0, rejected: [] };\n } catch (e) {\n return { ok: false, acknowledged: 0, error: String((e as Error).message), action: \"retry\" };\n }\n }\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// stdout \u2014 one JSON line per event to a writable (the worker's stdout is ignored\n// when spawned by a hook, so this sink is for `sessionpipe tail` and tests).\nimport type { Event, Tier } from \"../types.js\";\nimport type { DeliveryResult, Sink } from \"./types.js\";\n\nexport class StdoutSink implements Sink {\n constructor(\n readonly name: string,\n readonly tier: Tier,\n readonly pii: boolean,\n private readonly write: (line: string) => void = (l) => process.stdout.write(`${l}\\n`),\n ) {}\n async send(events: Event[]): Promise<DeliveryResult> {\n try {\n for (const e of events) this.write(JSON.stringify(e));\n return { ok: true, acknowledged: events.length, accepted: events.length, duplicates: 0, rejected: [] };\n } catch (e) {\n // A closed pipe (`sessionpipe tail | head`): a result, like every other sink.\n return { ok: false, acknowledged: 0, error: String((e as Error).message ?? e), action: \"retry\" };\n }\n }\n}\n", "// SPDX-License-Identifier: Apache-2.0\n/** @sessionpipe/core \u2014 protocol types, adapters, privacy, outbox, sinks. Zero runtime dependencies. */\nexport const PROTOCOL_VERSION = 1 as const;\nexport * as claudePool from \"./adapters/claude-code-pool.js\";\nexport * from \"./adapters/index.js\";\nexport {\n assertConfigWritable,\n type Config,\n DEFAULT_CONFIG,\n machineName,\n readConfig,\n type SinkConfig,\n writeConfig,\n} from \"./config.js\";\nexport { type EventContext, makeEvent } from \"./events.js\";\nexport {\n ASK_CHAIN_ENV,\n DELEGATED_BY_ENV,\n delegatedBy,\n LAUNCHED_BY_ENV,\n LINEAGE_ENV,\n launchedBy,\n readHook,\n withoutLineage,\n} from \"./launched-by.js\";\nexport {\n Cursors,\n Outbox,\n type OutboxRef,\n processAlive,\n takeLock,\n takeNamedLock,\n waitNamedLock,\n} from \"./outbox.js\";\nexport { configFile, homeDir, safeId, stateDir, tilde, untilde } from \"./paths.js\";\nexport * from \"./privacy/index.js\";\nexport { gitFacts, stripCredentials } from \"./readers/git.js\";\nexport {\n isInjected,\n pairTurns,\n peerAsk,\n readAntigravity,\n readClaude,\n readCodex,\n readGemini,\n} from \"./readers/transcripts.js\";\nexport { shortId } from \"./short-id.js\";\nexport * from \"./sinks/index.js\";\nexport type * from \"./types.js\";\nexport { isUlid, ulid } from \"./ulid.js\";\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["createHash", "readFileSync", "os", "path", "execFileSync", "existsSync", "readdirSync", "readFileSync", "statSync", "path", "path", "cap", "path", "settings", "entry", "path", "readdirSync", "existsSync", "readFileSync", "rows", "pid", "execFileSync", "statSync", "WINDOW_MINUTES", "UUID", "createHash", "code", "st", "fetch", "path", "os", "EMAIL_RE", "readFileSync", "spawn", "os", "path", "readFileSync", "statSync", "path", "statSync", "path", "readFileSync", "os", "path", "spawn", "c", "refused", "existsSync", "readdirSync", "readFileSync", "statSync", "path", "NAME", "path", "ID_RE", "validTool", "existsSync", "prune", "readFileSync", "rows", "readdirSync", "statSync", "os", "path", "os", "path", "str", "claudeLogin", "defaultLevel", "offeredLevels", "execFileSync", "closeSync", "openSync", "readdirSync", "readFileSync", "readSync", "statSync", "os", "path", "UUID_RE", "os", "readdirSync", "path", "offeredLevels", "defaultLevel", "claudeLogin", "execFileSync", "statSync", "cap", "openSync", "readSync", "closeSync", "str", "readFileSync", "existsSync", "readdirSync", "readFileSync", "path", "OURS", "NAME", "OPTS", "eventsFor", "path", "hooksFile", "configFile", "validTool", "endReason", "readFileSync", "OURS", "readdirSync", "existsSync", "id", "r", "prune", "rows", "epochIso", "defaultLevel", "offeredLevels", "reading", "execFile", "readFileSync", "os", "path", "LABEL", "os", "path", "offeredLevels", "defaultLevel", "readFileSync", "execFile", "str", "reading", "createHash", "existsSync", "path", "execFileSync", "existsSync", "NAME", "OPTS", "eventsFor", "path", "configFile", "validTool", "endReason", "pickSource", "errText", "existsSync", "createHash", "prune", "rows", "execFileSync", "existsSync", "readFileSync", "path", "NAME", "OPTS", "path", "validTool", "eventsFor", "execFileSync", "existsSync", "prune", "readFileSync", "existsSync", "mkdirSync", "readFileSync", "writeFileSync", "path", "readFileSync", "mkdirSync", "path", "writeFileSync", "existsSync", "randomBytes", "randomBytes", "closeSync", "existsSync", "mkdirSync", "openSync", "readdirSync", "readFileSync", "readSync", "statSync", "unlinkSync", "writeFileSync", "path", "path", "readFileSync", "mkdirSync", "writeFileSync", "existsSync", "readdirSync", "statSync", "openSync", "readSync", "closeSync", "unlinkSync", "randomBytes", "createHash", "
|
|
3
|
+
"sources": ["../src/adapters/claude-code-pool.ts", "../src/paths.ts", "../src/adapters/claude-code.ts", "../src/control/frames.ts", "../src/readers/files.ts", "../src/readers/git.ts", "../src/adapters/codex-rollout.ts", "../src/readers/transcripts.ts", "../src/adapters/claude-shaped.ts", "../src/adapters/acp-control.ts", "../src/adapters/headless.ts", "../src/launched-by.ts", "../src/adapters/antigravity.ts", "../src/adapters/antigravity-control.ts", "../src/adapters/claude-code-control.ts", "../src/control/verify.ts", "../src/privacy/pii.ts", "../src/privacy/secrets.ts", "../src/adapters/codex.ts", "../src/adapters/codex-config.ts", "../src/adapters/codex-control.ts", "../src/adapters/devin.ts", "../src/readers/sqlite.ts", "../src/adapters/gemini-cli.ts", "../src/adapters/index.ts", "../src/config.ts", "../src/ulid.ts", "../src/events.ts", "../src/outbox.ts", "../src/privacy/filter.ts", "../src/short-id.ts", "../src/sinks/file.ts", "../src/sinks/stdout.ts", "../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["// SPDX-License-Identifier: Apache-2.0\n// The Claude Code pool: everything the daemon's loopback proxy has to know about\n// Anthropic, in one file, so nothing else in core names an endpoint, a header or a\n// credential file. Pure functions over bytes, headers and JSON, plus four `fetch`\n// wrappers whose `fetch` is injected: the tests never reach the network or the keychain.\n//\n// Facts were read from the installed Claude Code (2.1.312) with `strings`, and checked\n// against bb's Account Pooler for the request shapes; none of its code is copied.\n// - OAuth: PKCE S256 against `authorize`, the code pasted back as `code#state` (the\n// manual redirect, `callback`), exchanged at `token` as JSON\n// `{grant_type, code, state, client_id, redirect_uri, code_verifier}`; refreshed with\n// `{grant_type: \"refresh_token\", refresh_token, client_id}`. Every OAuth call carries\n// `anthropic-beta: oauth-2025-04-20`. Claude Code 2.1.312 signs in at\n// platform.claude.com (the token URL and the manual callback); the older\n// console.anthropic.com names bb still uses are the same service.\n// - Limits come back on every response as `anthropic-ratelimit-unified-*` headers:\n// `5h`/`7d` (and `7d_<model>`) \u00D7 `utilization` (a fraction 0\u20131), `reset` (epoch\n// seconds), `status`; a whole-account `status` (allowed \u00B7 allowed_warning \u00B7 rejected);\n// on a refusal `representative-claim` names the window and `reset` says when. The\n// usage endpoint says the same per window as `{utilization (a percent), resets_at}`.\n// - Claude Code's own login is a generic password in the macOS keychain, service\n// `Claude Code-credentials` (plus `-<8 hex of sha256(config dir)>` when\n// CLAUDE_CONFIG_DIR is set), account = the login user; elsewhere\n// `<config dir>/.credentials.json`. Either holds\n// `{claudeAiOauth: {accessToken, refreshToken, expiresAt (epoch ms), \u2026}}`.\n// - `metadata.user_id` in a request body is, since 2.1.x, a JSON string\n// `{\"device_id\",\"account_uuid\",\"session_id\"[,\"parent_session_id\"]}`; older builds sent\n// `user_<hash>_account_<uuid>_session_<uuid>`. Both are read; the account part is\n// rewritten in place so the serving account sees its own id and nothing else moves.\n\nimport { createHash, randomBytes } from \"node:crypto\";\nimport { readFileSync } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { homeDir } from \"../paths.js\";\nimport type { DataOf } from \"../types.js\";\nimport { claudeDirs } from \"./claude-code.js\";\n\nexport type LimitWindow = DataOf<\"limits.observed\">[\"windows\"][number];\n\n/** Claude Code 2.1.312's own prod endpoints. bb signs in at claude.ai/oauth/authorize with\n * console.anthropic.com's callback and token URL, which still answer; the paste-back code\n * works the same at either. */\nexport const POOL_ENDPOINTS = {\n authorize: \"https://claude.com/cai/oauth/authorize\",\n token: \"https://platform.claude.com/v1/oauth/token\",\n callback: \"https://platform.claude.com/oauth/code/callback\",\n profile: \"https://api.anthropic.com/api/oauth/profile\",\n usage: \"https://api.anthropic.com/api/oauth/usage\",\n api: \"https://api.anthropic.com\",\n clientId: \"9d1c250a-e61b-44d9-88ed-5944d1962f5e\",\n // The six Claude Code itself asks for with this client id: a token minted with fewer\n // than the client's usual set is the kind of thing that fails only live.\n scopes: [\n \"user:inference\",\n \"user:profile\",\n \"org:create_api_key\",\n \"user:sessions:claude_code\",\n \"user:mcp_servers\",\n \"user:file_upload\",\n ],\n beta: \"oauth-2025-04-20\",\n} as const;\n\nexport interface PoolCredential {\n access: string;\n refresh: string;\n /** Epoch milliseconds. */\n expires_at: number;\n}\nexport type PoolStatus = \"allowed\" | \"allowed_warning\" | \"rejected\";\nexport interface PoolLimits {\n windows: LimitWindow[];\n /** The account as a whole. */\n status?: PoolStatus;\n /** On a refusal: the window that refused (`five_hour`, `seven_day`, \u2026) and when it resets. */\n claim?: string;\n resets_at?: string;\n observed_at: number;\n}\nexport interface PoolProfile {\n account_uuid: string;\n email: string;\n org?: string;\n plan?: string;\n}\nexport interface ImportableLogin {\n /** The Claude Code config dir the login belongs to. */\n dir: string;\n credential: PoolCredential;\n /** From the dir's .claude.json; absent when that file has no login (fetchProfile fills it). */\n account_uuid?: string;\n email?: string;\n source: \"keychain\" | \"file\";\n}\n\n/** The person has to sign in (again): a refused code, a dead refresh token, a 401. */\nexport class PoolAuthError extends Error {}\n/** Anthropic did not answer properly right now; the same call may work in a minute. */\nexport class PoolUpstreamError extends Error {}\n\n// --- limits ---------------------------------------------------------------------------\n\nconst PREFIX = \"anthropic-ratelimit-unified-\";\nconst WINDOW_IDS: Record<string, string> = { \"5h\": \"five_hour\", \"7d\": \"seven_day\" };\nconst WINDOW_MINUTES: Record<string, number> = { five_hour: 300, seven_day: 10_080 };\nconst STATUSES = new Set<string>([\"allowed\", \"allowed_warning\", \"rejected\"]);\nconst ID_RE = /^[a-z0-9_]{1,64}$/;\n\ntype HeaderBag = Headers | Record<string, string | string[] | undefined>;\n/** Every header as (lowercase name, first value). */\nfunction entries(h: HeaderBag): [string, string][] {\n const out: [string, string][] = [];\n if (h instanceof Headers) {\n h.forEach((v, k) => {\n out.push([k.toLowerCase(), v]);\n });\n return out;\n }\n for (const [k, v] of Object.entries(h)) {\n const s = Array.isArray(v) ? v[0] : v;\n if (typeof s === \"string\") out.push([k.toLowerCase(), s]);\n }\n return out;\n}\n/** Epoch seconds (a header's `reset`, usage's numeric `resets_at`) or an RFC 3339 string\n * as RFC 3339; anything that is not a plausible time is no time. */\nfunction isoTime(v: unknown): string | undefined {\n if (typeof v === \"number\") return v > 0 && v < 1e11 ? new Date(v * 1000).toISOString() : undefined;\n if (typeof v !== \"string\") return undefined;\n const s = v.trim();\n if (/^\\d+(\\.\\d+)?$/.test(s)) return isoTime(Number(s));\n if (!/^\\d{4}-\\d{2}-\\d{2}T/.test(s)) return undefined;\n const t = Date.parse(s);\n return Number.isFinite(t) ? new Date(t).toISOString() : undefined;\n}\nconst percentOf = (n: number) => Math.round(Math.max(0, n) * 10) / 10;\n/** The window id a `5h`/`7d`/`7d_opus` header part names; the same ids Claude Code's status line uses. */\nconst windowId = (part: string): string => WINDOW_IDS[part] ?? `seven_day_${part.slice(3)}`;\n\n/** The account's limits from a response's headers; null when the limiter did not run\n * (no `anthropic-ratelimit-unified-*` header at all). A window needs a readable\n * utilization; a status or a reset alone is kept on the account. */\nexport function readLimits(headers: HeaderBag, now: number): PoolLimits | null {\n const seen = new Map<string, { used?: number; resets_at?: string }>();\n const out: PoolLimits = { windows: [], observed_at: now };\n let any = false;\n for (const [name, value] of entries(headers)) {\n if (!name.startsWith(PREFIX)) continue;\n any = true;\n const rest = name.slice(PREFIX.length);\n if (rest === \"status\") {\n if (STATUSES.has(value)) out.status = value as PoolStatus;\n continue;\n }\n if (rest === \"representative-claim\") {\n if (ID_RE.test(value)) out.claim = value;\n continue;\n }\n if (rest === \"reset\") {\n const t = isoTime(value);\n if (t) out.resets_at = t;\n continue;\n }\n const m = /^(5h|7d|7d_[a-z0-9_]+)-(utilization|reset)$/.exec(rest);\n if (!m) continue;\n const id = windowId(m[1] as string);\n if (!ID_RE.test(id)) continue;\n const w = seen.get(id) ?? {};\n seen.set(id, w);\n if (m[2] === \"utilization\") {\n const n = Number(value);\n if (value.trim() && Number.isFinite(n)) w.used = percentOf(n * 100);\n } else {\n const t = isoTime(value);\n if (t) w.resets_at = t;\n }\n }\n if (!any) return null;\n for (const [id, w] of seen) {\n if (w.used === undefined) continue;\n const minutes = WINDOW_MINUTES[id];\n out.windows.push({\n id,\n used_percent: w.used,\n ...(w.resets_at ? { resets_at: w.resets_at } : {}),\n ...(minutes ? { window_minutes: minutes } : {}),\n });\n }\n return out;\n}\n\n/** The usage endpoint's JSON: `{five_hour: {utilization, resets_at}, seven_day: {\u2026},\n * seven_day_<model>: {\u2026}, \u2026}`, utilization a percent already. Any other key shaped\n * like a window passes through under its own id; null when none is. */\nexport function usageLimits(json: unknown, now: number): PoolLimits | null {\n if (!json || typeof json !== \"object\" || Array.isArray(json)) return null;\n const windows: LimitWindow[] = [];\n for (const [id, v] of Object.entries(json as Record<string, unknown>)) {\n if (!ID_RE.test(id) || !v || typeof v !== \"object\" || Array.isArray(v)) continue;\n const w = v as { utilization?: unknown; resets_at?: unknown };\n if (typeof w.utilization !== \"number\" || !Number.isFinite(w.utilization)) continue;\n const resets_at = isoTime(w.resets_at);\n const minutes = WINDOW_MINUTES[id];\n windows.push({\n id,\n used_percent: percentOf(w.utilization),\n ...(resets_at ? { resets_at } : {}),\n ...(minutes ? { window_minutes: minutes } : {}),\n });\n }\n return windows.length ? { windows: windows.slice(0, 8), observed_at: now } : null;\n}\n\n// --- metadata.user_id -----------------------------------------------------------------\n\nconst UUID = \"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\";\nconst UUID_RE = new RegExp(`^${UUID}$`, \"i\");\nconst LEGACY_ACCOUNT = new RegExp(`(?:^|_)account_(${UUID})(?=_|$)`, \"i\");\nconst LEGACY_SESSION = new RegExp(`(?:^|_)session_(${UUID})$`, \"i\");\n\nfunction userIdOf(body: unknown): string | null {\n let v = body;\n if (Buffer.isBuffer(v) || typeof v === \"string\") {\n try {\n v = JSON.parse(v.toString());\n } catch {\n return null;\n }\n }\n const id = (v as { metadata?: { user_id?: unknown } } | null)?.metadata?.user_id;\n return typeof id === \"string\" && id.length <= 4096 ? id : null;\n}\n/** The session and account a `metadata.user_id` names, in either of its two forms. */\nfunction partsOf(id: string): { session?: string; account?: string } {\n if (id.startsWith(\"{\")) {\n try {\n const j = JSON.parse(id) as { account_uuid?: unknown; session_id?: unknown };\n return {\n ...(typeof j.session_id === \"string\" && j.session_id ? { session: j.session_id } : {}),\n ...(typeof j.account_uuid === \"string\" && UUID_RE.test(j.account_uuid) ? { account: j.account_uuid } : {}),\n };\n } catch {\n return {};\n }\n }\n const s = LEGACY_SESSION.exec(id)?.[1];\n const a = LEGACY_ACCOUNT.exec(id)?.[1];\n return { ...(s ? { session: s } : {}), ...(a ? { account: a } : {}) };\n}\n\n/** `metadata.user_id` of a request body (parsed, or the raw bytes): the session to pin\n * on and the account the body claims. null when the body carries none. */\nexport function parseUserId(body: unknown): { session?: string; account?: string } | null {\n const id = userIdOf(body);\n return id === null ? null : partsOf(id);\n}\n\n/** The body with the account part of `metadata.user_id` set to `accountUuid`, the same\n * bytes when there is nothing to rewrite. Done on the string, not a parse/stringify\n * round trip: Claude Code's bodies are JSON.stringify output and would survive one, but\n * a body a person built by hand (an SDK, a `CLAUDE_CODE_EXTRA_BODY`) can carry number\n * forms and escapes a round trip rewrites, and a prompt cache is keyed on bytes. The\n * only change is the UUID inside that one string literal. */\nexport function withAccount(body: Buffer, accountUuid: string): Buffer {\n if (!UUID_RE.test(accountUuid)) return body;\n const id = userIdOf(body);\n if (id === null) return body;\n const current = partsOf(id).account;\n if (current && current.toLowerCase() === accountUuid.toLowerCase()) return body;\n // Claude Code 2.1.312 under ANTHROPIC_AUTH_TOKEN sends the JSON form with\n // `\"account_uuid\":\"\"`: the slot is there, empty, and is filled the same way.\n const empty = !current && id.startsWith(\"{\") && emptyAccountSlot(id);\n if (!current && !empty) return body;\n const text = body.toString(\"utf8\");\n // The literal as JSON.stringify writes it; a body that escaped it another way\n // (`\\u005f` for an underscore) is left alone rather than guessed at.\n const literal = JSON.stringify(id).slice(1, -1);\n const was = current ?? \"\";\n const at = current ? literal.indexOf(current) : literal.indexOf(EMPTY_SLOT) + EMPTY_SLOT.length;\n const ms = [...text.matchAll(/\"user_id\"\\s*:\\s*\"((?:[^\"\\\\]|\\\\.)*)\"/g)].filter((x) => x[1] === literal);\n if (!ms.length) return body;\n if (ms.length === 1) {\n const m = ms[0] as RegExpExecArray;\n const start = m.index + m[0].length - 1 - literal.length + at;\n return Buffer.from(text.slice(0, start) + accountUuid + text.slice(start + was.length), \"utf8\");\n }\n // The same literal under another `user_id` key too (a tool's input schema): rewrite\n // the one in `metadata` structurally rather than guess which literal is it. A round\n // trip costs the byte-stable cache key, not correctness.\n const j = JSON.parse(text) as { metadata: { user_id: string } };\n if (current) j.metadata.user_id = id.replace(current, accountUuid);\n else\n j.metadata.user_id = JSON.stringify({ ...(JSON.parse(id) as Record<string, unknown>), account_uuid: accountUuid });\n return Buffer.from(JSON.stringify(j), \"utf8\");\n}\n\n/** `\"account_uuid\":\"\"` as JSON.stringify writes it inside the escaped user_id literal. */\nconst EMPTY_SLOT = '\\\\\"account_uuid\\\\\":\\\\\"';\n/** The JSON form with an empty account: a slot to fill, not an account to replace. */\nfunction emptyAccountSlot(id: string): boolean {\n try {\n return (JSON.parse(id) as { account_uuid?: unknown }).account_uuid === \"\";\n } catch {\n return false;\n }\n}\n\n// --- headers upstream -----------------------------------------------------------------\n\n/** Headers that describe this hop, not the request; and the ones the proxy owns. */\nconst DROP = new Set([\n \"connection\",\n \"keep-alive\",\n \"transfer-encoding\",\n \"te\",\n \"trailer\",\n \"upgrade\",\n \"host\",\n \"content-length\",\n \"authorization\",\n \"x-api-key\",\n]);\n\n/** The request's headers as they go to Anthropic: the serving account's bearer in place\n * of the pool's own token, the OAuth beta present, hop-by-hop and the ones the sender\n * sets (host, content-length) gone. Our token and any x-api-key never go through. */\nexport function upstreamHeaders(\n req: Record<string, string | string[] | undefined>,\n access: string,\n): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(req)) {\n const name = k.toLowerCase();\n if (v === undefined || DROP.has(name) || name.startsWith(\"proxy-\")) continue;\n out[name] = Array.isArray(v) ? v.join(\", \") : v;\n }\n out.authorization = `Bearer ${access}`;\n const betas = (out[\"anthropic-beta\"] ?? \"\")\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n if (!betas.includes(POOL_ENDPOINTS.beta)) betas.push(POOL_ENDPOINTS.beta);\n out[\"anthropic-beta\"] = betas.join(\",\");\n return out;\n}\n\n// --- OAuth ----------------------------------------------------------------------------\n\n/** PKCE, as Claude Code builds its own sign-in URL (the same parameters in the same\n * order; `code=true` asks for the paste-back page). 32 random bytes base64url is a\n * 43-character verifier, inside RFC 7636's 43\u2013128. */\nexport function beginLogin(random: (n: number) => Buffer = randomBytes): {\n url: string;\n verifier: string;\n state: string;\n} {\n const verifier = random(32).toString(\"base64url\");\n const state = random(32).toString(\"base64url\");\n const challenge = createHash(\"sha256\").update(verifier).digest(\"base64url\");\n const u = new URL(POOL_ENDPOINTS.authorize);\n u.searchParams.append(\"code\", \"true\");\n u.searchParams.append(\"client_id\", POOL_ENDPOINTS.clientId);\n u.searchParams.append(\"response_type\", \"code\");\n u.searchParams.append(\"redirect_uri\", POOL_ENDPOINTS.callback);\n u.searchParams.append(\"scope\", POOL_ENDPOINTS.scopes.join(\" \"));\n u.searchParams.append(\"code_challenge\", challenge);\n u.searchParams.append(\"code_challenge_method\", \"S256\");\n u.searchParams.append(\"state\", state);\n return { url: u.toString(), verifier, state };\n}\n\n/** What the person pasted: `code#state` from the callback page, the callback URL\n * itself, or a bare code. A state that is there and differs is somebody else's login. */\nfunction pastedCode(pasted: string, state: string): string {\n const s = pasted.trim();\n if (!s) throw new PoolAuthError(\"Paste the code the sign-in page shows.\");\n if (/^https?:\\/\\//i.test(s)) {\n let u: URL;\n try {\n u = new URL(s);\n } catch {\n throw new PoolAuthError(\"That is not the sign-in page's code.\");\n }\n const code = u.searchParams.get(\"code\");\n const st = u.searchParams.get(\"state\");\n if (!code) throw new PoolAuthError(\"That URL carries no code.\");\n if (st !== null && st !== state) throw new PoolAuthError(\"That code belongs to another sign-in; start again.\");\n return code;\n }\n const hash = s.indexOf(\"#\");\n if (hash < 0) return s;\n const code = s.slice(0, hash).trim();\n const st = s.slice(hash + 1).trim();\n if (!code) throw new PoolAuthError(\"Paste the code the sign-in page shows.\");\n if (st && st !== state) throw new PoolAuthError(\"That code belongs to another sign-in; start again.\");\n return code;\n}\n\ntype Fetch = typeof globalThis.fetch;\nconst JSON_HEADERS = { \"content-type\": \"application/json\", \"anthropic-beta\": POOL_ENDPOINTS.beta };\n\nasync function post(fetch: Fetch, url: string, body: unknown, what: string): Promise<Response> {\n try {\n return await fetch(url, { method: \"POST\", headers: JSON_HEADERS, body: JSON.stringify(body) });\n } catch (e) {\n throw new PoolUpstreamError(`${what}: ${(e as Error).message || \"no answer from Anthropic\"}`);\n }\n}\nasync function get(fetch: Fetch, url: string, access: string, what: string): Promise<Response> {\n try {\n return await fetch(url, { headers: { authorization: `Bearer ${access}`, \"anthropic-beta\": POOL_ENDPOINTS.beta } });\n } catch (e) {\n throw new PoolUpstreamError(`${what}: ${(e as Error).message || \"no answer from Anthropic\"}`);\n }\n}\nasync function jsonOf(r: Response): Promise<unknown> {\n try {\n return await r.json();\n } catch {\n return null;\n }\n}\n/** A token response into a credential; the refresh token stays when the answer omits it. */\nfunction credentialOf(j: unknown, now: number, keepRefresh: string | undefined, what: string): PoolCredential {\n const t = j as { access_token?: unknown; refresh_token?: unknown; expires_in?: unknown } | null;\n const refresh = typeof t?.refresh_token === \"string\" && t.refresh_token ? t.refresh_token : keepRefresh;\n if (!t || typeof t.access_token !== \"string\" || !t.access_token || !refresh || typeof t.expires_in !== \"number\")\n throw new PoolUpstreamError(`${what}: Anthropic's answer had no token in it`);\n return { access: t.access_token, refresh, expires_at: now + t.expires_in * 1000 };\n}\n\n/** Exchange the pasted code for a credential and read whose it is. */\nexport async function completeLogin(\n code: string,\n pending: { verifier: string; state: string },\n fetch: Fetch,\n now: () => number,\n): Promise<{ credential: PoolCredential; profile: PoolProfile }> {\n const c = pastedCode(code, pending.state);\n const r = await post(\n fetch,\n POOL_ENDPOINTS.token,\n {\n grant_type: \"authorization_code\",\n code: c,\n state: pending.state,\n client_id: POOL_ENDPOINTS.clientId,\n redirect_uri: POOL_ENDPOINTS.callback,\n code_verifier: pending.verifier,\n },\n \"sign-in\",\n );\n if (r.status >= 400 && r.status < 500)\n throw new PoolAuthError(`Anthropic did not accept the code (HTTP ${r.status}); start the sign-in again.`);\n if (!r.ok) throw new PoolUpstreamError(`sign-in: Anthropic answered HTTP ${r.status}; try again in a minute`);\n const credential = credentialOf(await jsonOf(r), now(), undefined, \"sign-in\");\n const profile = await fetchProfile(credential.access, fetch);\n return { credential, profile };\n}\n\n/** A fresh access token. 400/401 means the refresh token is dead (revoked, expired,\n * used elsewhere): the person signs in again. Anything else is Anthropic's moment. */\nexport async function refreshCredential(\n cred: PoolCredential,\n fetch: Fetch,\n now: () => number,\n): Promise<PoolCredential> {\n const r = await post(\n fetch,\n POOL_ENDPOINTS.token,\n { grant_type: \"refresh_token\", refresh_token: cred.refresh, client_id: POOL_ENDPOINTS.clientId },\n \"refresh\",\n );\n if (r.status === 400 || r.status === 401)\n throw new PoolAuthError(\"This account's sign-in has expired; sign in again.\");\n if (!r.ok) throw new PoolUpstreamError(`refresh: Anthropic answered HTTP ${r.status}; try again in a minute`);\n return credentialOf(await jsonOf(r), now(), cred.refresh, \"refresh\");\n}\n\n/** Whose token this is: `{account: {uuid, email, \u2026}, organization: {name, \u2026}}`. */\nexport async function fetchProfile(access: string, fetch: Fetch): Promise<PoolProfile> {\n const r = await get(fetch, POOL_ENDPOINTS.profile, access, \"profile\");\n if (r.status === 401 || r.status === 403)\n throw new PoolAuthError(\"Anthropic does not know this token; sign in again.\");\n if (!r.ok) throw new PoolUpstreamError(`profile: Anthropic answered HTTP ${r.status}; try again in a minute`);\n const j = (await jsonOf(r)) as {\n account?: { uuid?: unknown; email?: unknown; subscription_type?: unknown };\n organization?: { name?: unknown };\n } | null;\n const a = j?.account;\n if (typeof a?.uuid !== \"string\" || !UUID_RE.test(a.uuid) || typeof a.email !== \"string\" || !a.email)\n throw new PoolUpstreamError(\"profile: Anthropic's answer did not say whose token this is\");\n const org = j?.organization?.name;\n const plan = a.subscription_type;\n return {\n account_uuid: a.uuid.toLowerCase(),\n email: a.email,\n ...(typeof org === \"string\" && org ? { org } : {}),\n ...(typeof plan === \"string\" && plan ? { plan } : {}),\n };\n}\n\n/** The account's windows from the usage endpoint; null when it reports none. */\nexport async function fetchUsage(access: string, fetch: Fetch, now: () => number): Promise<PoolLimits | null> {\n const r = await get(fetch, POOL_ENDPOINTS.usage, access, \"usage\");\n if (r.status === 401 || r.status === 403)\n throw new PoolAuthError(\"Anthropic does not know this token; sign in again.\");\n if (!r.ok) throw new PoolUpstreamError(`usage: Anthropic answered HTTP ${r.status}; try again in a minute`);\n return usageLimits(await jsonOf(r), now());\n}\n\n// --- Claude Code's own logins ---------------------------------------------------------\n\nconst SERVICE = \"Claude Code-credentials\";\n/** The keychain service Claude Code keeps a config dir's login under: bare for the\n * default dir, suffixed with 8 hex of sha256(dir) when CLAUDE_CONFIG_DIR names one. */\nexport function keychainService(dir: string, home: string, platform: NodeJS.Platform = process.platform): string {\n // \"The default dir\" is a comparison of resolved paths (this process's own path\n // module: what the file system here uses), case-blind on Windows, where the same\n // folder arrives as `C:\\Users\\\u2026` from one place and `c:\\users\\\u2026` from another.\n // The suffix stays a hash of the dir as given: it names an item Claude Code wrote.\n const norm = (x: string) => (platform === \"win32\" ? path.resolve(x).toLowerCase() : path.resolve(x));\n if (norm(dir) === norm(path.join(home, \".claude\"))) return SERVICE;\n return `${SERVICE}-${createHash(\"sha256\").update(dir).digest(\"hex\").slice(0, 8)}`;\n}\n/** The keychain item's account: the login user, as Claude Code names it. */\nfunction keychainUser(env: NodeJS.ProcessEnv): string {\n let u = env.USER;\n if (!u) {\n try {\n u = os.userInfo().username;\n } catch {\n u = \"\";\n }\n }\n return /^[a-zA-Z0-9._-]+$/.test(u) ? u : \"claude-code-user\";\n}\nfunction credentialIn(text: string): PoolCredential | null {\n try {\n const o = (\n JSON.parse(text) as { claudeAiOauth?: { accessToken?: unknown; refreshToken?: unknown; expiresAt?: unknown } }\n ).claudeAiOauth;\n if (typeof o?.accessToken !== \"string\" || !o.accessToken || typeof o.refreshToken !== \"string\" || !o.refreshToken)\n return null;\n // No expiry on record means refresh before the first use.\n return {\n access: o.accessToken,\n refresh: o.refreshToken,\n expires_at: typeof o.expiresAt === \"number\" ? o.expiresAt : 0,\n };\n } catch {\n return null;\n }\n}\nconst EMAIL_RE = /^[^@\\s]{1,64}@[^@\\s]{1,189}$/;\ntype ReadFile = (file: string) => string;\nconst readText: ReadFile = (f) => readFileSync(f, \"utf8\");\n\n/** Every Claude Code login on this machine the pool could copy, one per config dir\n * (claudeDirs): the credential from the keychain (macOS) or `.credentials.json`, and\n * who it is from the dir's .claude.json. `exec` runs `security` and returns stdout; it\n * is the only thing that touches the keychain, so a test hands in a fake. Returns []\n * on any failure and never throws: an import that finds nothing is a message, not a\n * crash, and a token never reaches a log through here. */\nexport function importableLogins(\n env: NodeJS.ProcessEnv,\n exec: (cmd: string, args: string[]) => string,\n readFile: ReadFile = readText,\n platform: NodeJS.Platform = process.platform,\n): ImportableLogin[] {\n const out: ImportableLogin[] = [];\n const home = env.HOME || homeDir();\n const user = keychainUser(env);\n for (const dir of claudeDirs(env, home)) {\n let credential: PoolCredential | null = null;\n let source: ImportableLogin[\"source\"] = \"file\";\n if (platform === \"darwin\") {\n const service = keychainService(dir, home, platform);\n // Claude Code writes the item under the login user; an item saved another way\n // (an older build, a renamed user) is still found by service alone.\n for (const args of [\n [\"find-generic-password\", \"-s\", service, \"-a\", user, \"-w\"],\n [\"find-generic-password\", \"-s\", service, \"-w\"],\n ]) {\n try {\n credential = credentialIn(exec(\"security\", args).trim());\n } catch {}\n if (credential) break;\n }\n if (credential) source = \"keychain\";\n }\n if (!credential) {\n try {\n credential = credentialIn(readFile(path.join(dir, \".credentials.json\")));\n } catch {}\n }\n if (!credential) continue;\n out.push({ dir, credential, ...whoIs(dir, home, readFile), source });\n }\n return out;\n}\n/** The dir's login, as claude-code.ts reads it: the default dir keeps its .claude.json at ~/.claude.json. */\nfunction whoIs(dir: string, home: string, readFile: ReadFile): { account_uuid?: string; email?: string } {\n const files = [path.join(dir, \".claude.json\")];\n if (path.resolve(dir) === path.join(home, \".claude\")) files.unshift(path.join(home, \".claude.json\"));\n for (const f of files) {\n try {\n const a = (JSON.parse(readFile(f)) as { oauthAccount?: { accountUuid?: unknown; emailAddress?: unknown } })\n .oauthAccount;\n if (typeof a?.accountUuid === \"string\" && UUID_RE.test(a.accountUuid)) {\n const email = typeof a.emailAddress === \"string\" && EMAIL_RE.test(a.emailAddress) ? a.emailAddress : undefined;\n return { account_uuid: a.accountUuid.toLowerCase(), ...(email ? { email } : {}) };\n }\n } catch {}\n }\n return {};\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// Where sessionpipe keeps its files (spec: the client's Files section).\n// config ~/.config/sessionpipe/config.json SESSIONPIPE_CONFIG\n// state ~/.local/state/sessionpipe/ SESSIONPIPE_STATE\n// Windows %APPDATA%\\sessionpipe\\ and %LOCALAPPDATA%\\sessionpipe\\\nimport os from \"node:os\";\nimport path from \"node:path\";\n\n/** The home directory, read when asked: a test that sets HOME after importing core\n * (or a process whose HOME changes) gets the new one, never one cached at load. */\nexport const homeDir = (): string => os.homedir();\n\nexport function configFile(env: NodeJS.ProcessEnv = process.env): string {\n if (env.SESSIONPIPE_CONFIG) return path.resolve(env.SESSIONPIPE_CONFIG);\n if (process.platform === \"win32\")\n return path.join(env.APPDATA || path.join(homeDir(), \"AppData\", \"Roaming\"), \"sessionpipe\", \"config.json\");\n return path.join(env.XDG_CONFIG_HOME || path.join(homeDir(), \".config\"), \"sessionpipe\", \"config.json\");\n}\n\nexport function stateDir(env: NodeJS.ProcessEnv = process.env): string {\n if (env.SESSIONPIPE_STATE) return path.resolve(env.SESSIONPIPE_STATE);\n if (process.platform === \"win32\")\n return path.join(env.LOCALAPPDATA || path.join(homeDir(), \"AppData\", \"Local\"), \"sessionpipe\");\n return path.join(env.XDG_STATE_HOME || path.join(homeDir(), \".local\", \"state\"), \"sessionpipe\");\n}\n\n/** `~` for the home directory, as the session block writes paths. */\nexport function tilde(p: string, home: string = homeDir()): string {\n if (!p) return p;\n if (p === home) return \"~\";\n return p.startsWith(home + path.sep) || p.startsWith(`${home}/`) ? `~${p.slice(home.length)}` : p;\n}\n\n/** The other way: `~`, `~/\u2026` (or `~\\\u2026`) under the home directory, as a control `start`'s\n * `cwd` may name a folder an event reported (CONTROL.md \u00A73.1). Anything else, `~user`\n * included, is returned as it is. */\nexport function untilde(p: string, home: string = homeDir()): string {\n if (p === \"~\") return home;\n return /^~[\\\\/]/.test(p) ? path.join(home, p.slice(2)) : p;\n}\n\n/** A file-name-safe id. */\nexport const safeId = (s: string): string =>\n String(s)\n .replace(/[^A-Za-z0-9_.-]/g, \"_\")\n .slice(0, 160);\n", "// SPDX-License-Identifier: Apache-2.0\n// Claude Code (Anthropic) \u2014 docs: https://code.claude.com/docs/en/hooks\n// Config: settings.json in EVERY config dir (~/.claude, $CLAUDE_CONFIG_DIR, ~/.claude-*):\n// one per account; hooks written to one never fire for the others. Reads only the\n// hook's stdin, the transcript it names, the per-pid session registry and the config\n// dir's .claude.json account (its id; its email only for control's pair and hello) \u2014\n// or, with no login there, the API its settings.json names (that one key, no token).\n// The one exception is the person's to make: with `remote_titles` on, the sign-in\n// token is read to ask claude.ai for a session's name, and sent nowhere else.\n// Ported from spacesheep-cli lib/sessions.js.\n\nimport { execFileSync } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { userInfo } from \"node:os\";\nimport path from \"node:path\";\nimport { deliveredWords } from \"../control/frames.js\";\nimport { homeDir } from \"../paths.js\";\nimport { ends, parseLines, recentFiles, scanLines } from \"../readers/files.js\";\nimport { gitFacts } from \"../readers/git.js\";\nimport { isInjected, readClaude } from \"../readers/transcripts.js\";\nimport type { DataOf, HarnessAccount } from \"../types.js\";\nimport {\n formatJson,\n installClaudeShaped,\n installedClaudeShaped,\n OURS,\n readJson,\n readJsonFile,\n uninstallClaudeShaped,\n writeBack,\n} from \"./claude-shaped.js\";\nimport type {\n Adapter,\n BackfillRow,\n FactsState,\n HookCommand,\n HookInput,\n HookResult,\n InstallOptions,\n InstallReport,\n SessionFacts,\n} from \"./types.js\";\n\nconst NAME = \"claude-code\";\nexport const CLAUDE_EVENTS = [\n \"SessionStart\",\n \"UserPromptSubmit\",\n \"PreToolUse\",\n \"PostToolUse\",\n \"PostToolUseFailure\",\n \"PermissionRequest\",\n \"Notification\",\n \"Stop\",\n \"SubagentStart\",\n \"SubagentStop\",\n \"PreCompact\",\n \"PostCompact\",\n \"SessionEnd\",\n \"StopFailure\",\n] as const;\n/** With no sink above tier 0 only the heartbeat needs a tool event: one, not three (issue #12). */\nconst LEAN_SKIP = new Set([\"PreToolUse\", \"PostToolUseFailure\"]);\nconst eventsFor = (lean?: boolean) => (lean ? CLAUDE_EVENTS.filter((e) => !LEAN_SKIP.has(e)) : [...CLAUDE_EVENTS]);\nconst OPTS = {\n matcherFor: (e: string) => (/Tool|Permission/.test(e) ? \"\" : undefined),\n timeout: 5,\n // The hook waits up to 125 s for a verified control answer, and only when control\n // is paired on this machine; everywhere else it exits in milliseconds as before.\n timeoutFor: (e: string) => (e === \"PermissionRequest\" ? 130 : undefined),\n};\nconst DESKTOP_ID = /^local_[A-Za-z0-9-]{1,64}$/;\n\n/** Every Claude Code config dir on this machine. `home` follows the env's HOME, so a\n * caller with its own env (a test) never reaches the real ~/.claude: the install test\n * once rewrote a real settings.json with its fake hook paths on every run. */\nexport function claudeDirs(env: NodeJS.ProcessEnv = process.env, home = env.HOME || homeDir()): string[] {\n const out: string[] = [];\n const add = (d?: string) => {\n if (!d) return;\n const r = path.resolve(d);\n if (!out.includes(r)) out.push(r);\n };\n add(path.join(home, \".claude\"));\n add(env.CLAUDE_CONFIG_DIR);\n try {\n for (const e of readdirSync(home, { withFileTypes: true })) {\n if (!e.isDirectory() || !/^\\.claude[-_.]/.test(e.name)) continue;\n const d = path.join(home, e.name);\n if (existsSync(path.join(d, \"projects\")) || existsSync(path.join(d, \"settings.json\"))) add(d);\n }\n } catch {}\n return out.filter((d, i) => i === 0 || existsSync(d));\n}\nconst settingsIn = (dir: string) => path.join(dir, \"settings.json\");\nconst configDirOf = (transcript: string) => path.dirname(path.dirname(path.dirname(transcript)));\n\nconst validTool = (n: unknown): n is string => typeof n === \"string\" && /^[A-Za-z0-9_.:-]{1,120}$/.test(n);\nconst endReason = (r: unknown): \"clear\" | \"logout\" | \"exit\" | \"other\" =>\n r === \"clear\" || r === \"logout\" || r === \"exit\" ? r : r === \"prompt_input_exit\" ? \"exit\" : \"other\";\nconst notifKind = (t: unknown): \"permission\" | \"question\" | \"elicitation\" | \"idle\" | \"error\" =>\n t === \"permission_prompt\"\n ? \"permission\"\n : t === \"idle_prompt\"\n ? \"idle\"\n : t === \"elicitation_dialog\"\n ? \"elicitation\"\n : \"question\";\n\nexport const claudeCode: Adapter = {\n name: NAME,\n events: CLAUDE_EVENTS,\n detect: (env = process.env) => claudeDirs(env).some((d) => existsSync(d)),\n configFiles: (env = process.env) => claudeDirs(env).map(settingsIn),\n install: (cmd, env = process.env, opts: InstallOptions = {}) =>\n claudeDirs(env).flatMap((d) => {\n const hooks = installClaudeShaped(settingsIn(d), NAME, eventsFor(opts.lean), cmd, OPTS);\n // A file the hooks could not go into (not JSON, or refused) gets the one report, theirs.\n const line =\n opts.statusLine === undefined || hooks.skipped ? null : statusLine(settingsIn(d), opts.statusLine, cmd);\n return line ? [hooks, line] : [hooks];\n }),\n uninstall: (env = process.env, opts: InstallOptions = {}) =>\n claudeDirs(env).map((d) => {\n const line = statusLine(settingsIn(d), false);\n const hooks = uninstallClaudeShaped(settingsIn(d), CLAUDE_EVENTS, {\n created: opts.created?.includes(settingsIn(d)),\n });\n // A status line taken out, then the hooks' write refused: \"not touched\" would be\n // false of the file, so the one report says both.\n if (line?.changed && !line.skipped && hooks.skipped)\n return { ...hooks, note: `status line removed, hooks not: ${hooks.note?.replace(/; not touched$/, \"\")}` };\n return line && !hooks.changed && !hooks.skipped ? line : hooks;\n }),\n installed: (cmd, env = process.env, opts: InstallOptions = {}) =>\n claudeDirs(env).map((d) => ({\n file: settingsIn(d),\n state: installedClaudeShaped(settingsIn(d), NAME, eventsFor(opts.lean), cmd, OPTS),\n })),\n\n fromHook(input: HookInput): HookResult | null {\n const event = input.argv[1] ?? \"\";\n let s: Record<string, unknown> = {};\n try {\n // A stdin that is JSON but not an object (`null`, a number) is no payload.\n const j: unknown = input.stdin ? JSON.parse(input.stdin) : {};\n if (j && typeof j === \"object\" && !Array.isArray(j)) s = j as Record<string, unknown>;\n } catch {}\n const id = (s.session_id ?? s.sessionId) as string | undefined;\n if (!id) return null;\n if (notClaudeCode(String(id), s)) return null;\n const session: HookResult[\"session\"] = { id: String(id), cwd: typeof s.cwd === \"string\" ? s.cwd : input.cwd };\n if (typeof s.model === \"string\") session.model = s.model;\n if (typeof s.agent_id === \"string\" && event.startsWith(\"Subagent\") === false && s.agent_id)\n session.parent_id = null;\n const turn_id = typeof s.prompt_id === \"string\" ? s.prompt_id : undefined;\n const tool = validTool(s.tool_name) ? s.tool_name : undefined;\n const call_id = typeof s.tool_use_id === \"string\" ? s.tool_use_id : undefined;\n const ms = typeof s.duration_ms === \"number\" ? Math.round(s.duration_ms) : undefined;\n const agent_id = typeof s.agent_id === \"string\" ? s.agent_id : undefined;\n // PermissionRequest carries no tool_use_id (recorded 2026-09-28): the id is a hash\n // of the prompt, the tool and its input, so the same prompt yields the same id and\n // a later control answer can name it.\n const permissionId = () =>\n `perm-${createHash(\"sha256\")\n .update(`${turn_id ?? \"\"}|${tool ?? \"\"}|${JSON.stringify(s.tool_input ?? null)}`)\n .digest(\"hex\")\n .slice(0, 16)}`;\n const ev = (type: string, data: Record<string, unknown>) => ({ type, data: prune(data), harnessEvent: event });\n const events: HookResult[\"events\"] = [];\n switch (event) {\n case \"SessionStart\":\n events.push(ev(\"session.started\", { source: pickSource(s.source ?? s.trigger) }));\n break;\n case \"UserPromptSubmit\": {\n // Only a string prompt is read; anything else is left unread rather than guessed at.\n const prompt = typeof s.prompt === \"string\" ? s.prompt : undefined;\n events.push(\n ev(\"turn.started\", {\n turn_id,\n prompt_chars: prompt === undefined ? undefined : [...prompt].length,\n // Claude Code's hook schema documents `source`\n // (user | sdk | system | loop_wakeup | schedule_wakeup | poll_event) and says a\n // payload may omit it while the field rolls out; 2.1.304's payload has no such\n // key at all. Forwarded verbatim, shape-guarded only: the list is the harness's\n // to extend.\n submitted_by: harnessWord(s.source),\n // One of Claude Code's own prompt wrappers: the prompt is a block the harness\n // wrote, so it is not the person's words. Absent is unknown, never \"the person\" \u2014\n // and `true` is never \"no person caused this turn\", because a Talk or\n // `sessionpipe wait` delivery hands the person's own message over inside a\n // <task-notification> (PROTOCOL.md \u00A74).\n injected: prompt !== undefined && injectedBlock(prompt) ? true : undefined,\n }),\n );\n break;\n }\n case \"PreToolUse\":\n if (tool) events.push(ev(\"tool.started\", { tool, call_id, turn_id, agent_id, input: s.tool_input }));\n break;\n case \"PostToolUse\":\n if (tool)\n events.push(\n ev(\"tool.ended\", {\n tool,\n call_id,\n turn_id,\n agent_id,\n ms,\n ok: true,\n input: s.tool_input,\n output: s.tool_response,\n }),\n );\n break;\n case \"PostToolUseFailure\":\n if (tool)\n events.push(\n ev(\"tool.ended\", {\n tool,\n call_id,\n turn_id,\n agent_id,\n ms,\n ok: false,\n error: errText(s.error ?? s.tool_response),\n input: s.tool_input,\n output: s.tool_response,\n }),\n );\n break;\n case \"PermissionRequest\":\n events.push(\n ev(\"attention.needed\", {\n attention_id: call_id ?? permissionId(),\n kind: \"permission\",\n tool,\n message: tool ? `${tool}${describe(s.tool_input)}` : undefined,\n agent_id,\n }),\n );\n break;\n case \"Notification\":\n events.push(\n ev(\"attention.needed\", {\n attention_id: `notif-${Date.now()}`,\n kind: notifKind(s.notification_type),\n message: typeof s.message === \"string\" ? s.message.slice(0, 200) : undefined,\n agent_id,\n }),\n );\n break;\n case \"Stop\":\n // In-flight background work (shell commands, monitors, subagents, workflows)\n // that will wake the session when it finishes: a paused session, not a done one\n // (Claude Code's `background_tasks`, in every Stop recorded since 2.1.258). A count, never what they run.\n events.push(ev(\"turn.ended\", { turn_id, reason: \"stop\", background: backgroundCount(s.background_tasks) }));\n break;\n case \"StopFailure\":\n // The turn ended on an API error (rate_limit, overloaded, authentication_failed,\n // server_error \u2026); the payload key is `error` (issue #10, recorded 2026-09-28).\n events.push(\n ev(\"turn.ended\", {\n turn_id,\n reason: \"error\",\n error: typeof s.error === \"string\" ? s.error.slice(0, 200) : undefined,\n }),\n );\n break;\n case \"SubagentStart\":\n events.push(\n ev(\"subagent.started\", {\n agent_id: String(s.agent_id ?? \"\"),\n agent_type: typeof s.agent_type === \"string\" ? s.agent_type : undefined,\n }),\n );\n break;\n case \"SubagentStop\":\n // The same list, with this subagent still in it: the count once it is out, so a\n // receiver holding the session as waiting on its work sees the count fall (#153).\n events.push(\n ev(\"subagent.ended\", {\n agent_id: String(s.agent_id ?? \"\"),\n agent_type: typeof s.agent_type === \"string\" ? s.agent_type : undefined,\n background: backgroundCount(s.background_tasks, String(s.agent_id ?? \"\")),\n }),\n );\n break;\n case \"PreCompact\":\n events.push(ev(\"context.compacted\", { trigger: s.trigger === \"manual\" ? \"manual\" : \"auto\" }));\n break;\n case \"PostCompact\":\n break; // PreCompact already said it; a second event would double-count\n case \"SessionEnd\":\n events.push(ev(\"session.ended\", { reason: endReason(s.reason) }));\n break;\n case \"StatusLine\": {\n // Not a hook: our status line command (install --status-line), which hook.ts\n // hands on only when the limits changed.\n const limits = claudeLimits(s.rate_limits);\n if (!limits) return null;\n events.push(ev(\"limits.observed\", limits));\n break;\n }\n default:\n return null;\n }\n const hints: Record<string, unknown> = {};\n // The prompt, for the turn's first turn.progress: the transcript may not hold it\n // yet when the worker runs. Never an event field of its own (tier 2 carries it).\n if (event === \"UserPromptSubmit\" && typeof s.prompt === \"string\") hints.prompt = s.prompt;\n // The turn's last words, as its Stop names them (`last_assistant_message`, in every Stop\n // recorded since 2.1.258): how the worker knows the transcript holds the whole turn. A\n // terminal session's Stop fires before its last row reaches the file, because Claude\n // Code queues its transcript writes for 100 ms (measured on 2.1.322: the worker read the\n // file 90 to 135 ms after the row was made and found it in 1 turn of 9). Like the\n // prompt, never an event field of its own.\n if (event === \"Stop\" && typeof s.last_assistant_message === \"string\" && s.last_assistant_message.trim())\n hints.final = s.last_assistant_message;\n const host = input.env.CLAUDE_CODE_HOST_SESSION_ID;\n if (host && DESKTOP_ID.test(host)) hints.desktop_id = host;\n // Whether a person attends the session, in Claude Code's own word (\"1\" or \"0\" in a hook's\n // environment); a turn the control daemon runs on the person's signed message is theirs.\n // facts() turns it into session.attended once it knows whether the session has a link.\n const attended = input.env.CLAUDE_CODE_SESSION_ATTENDED;\n if (attended === \"1\" || attended === \"0\") hints.attended = attended === \"1\" || !!input.env.SESSIONPIPE_CONTROL_JOB;\n // The registry file is found while the process tree stands (the detached\n // worker's parent is gone by the time it runs). Heartbeat-class events skip it.\n if (event !== \"PreToolUse\" && event !== \"PostToolUse\") hints.claude_pid = claudePid(input.env);\n const r: HookResult = { session, events, hints };\n if (typeof s.transcript_path === \"string\") r.transcript = s.transcript_path;\n return r;\n },\n\n readTranscript(file, fromLine) {\n let text = \"\";\n try {\n text = readFileSync(file, \"utf8\");\n } catch {\n return { turns: [], line: fromLine };\n }\n return readClaude(text.split(\"\\n\"), fromLine);\n },\n\n facts(session, transcript, hints, state): SessionFacts {\n const out: SessionFacts = {};\n if (transcript) Object.assign(out, claudeFacts(transcript, session.id, hints, state));\n const cwd = out.cwd ?? session.cwd;\n Object.assign(out, gitFacts(cwd), out.branch ? { branch: out.branch } : {});\n if (!out.url && typeof hints.desktop_id === \"string\") out.url = `claude://code/continue/${hints.desktop_id}`;\n // A Remote Control session says \"0\" though a person drives it from claude.ai: it runs as a\n // headless child of `claude remote-control`. Its link is what tells it from a `claude -p`;\n // CLAUDE_CODE_ENVIRONMENT_KIND cannot, since a `claude -p` started inside a Remote Control\n // session inherits \"bridge\", while the registry entry it writes has no bridge id of its own.\n if (typeof hints.attended === \"boolean\") out.attended = hints.attended || !!out.url;\n return out;\n },\n\n remoteFacts: (session, local, transcript, state, env = process.env) =>\n claudeRemoteFacts(session.id, local, transcript, state, env),\n\n backfill(sinceMs, env = process.env): BackfillRow[] {\n const rows: BackfillRow[] = [];\n const files: string[] = [];\n for (const d of claudeDirs(env))\n files.push(...recentFiles(path.join(d, \"projects\"), 1, sinceMs, (n) => /^[0-9a-f-]{36}\\.jsonl$/.test(n)));\n const noState: FactsState = { get: () => ({}), save: () => {} };\n for (const f of files) {\n const id = path.basename(f, \".jsonl\");\n const facts = claudeFacts(f, id, {}, noState);\n if (!facts.started_at || !facts.last_at) continue;\n const { started_at, last_at, first_ask: _fa, harness_version: _hv, ...rest } = facts;\n const cwd = rest.cwd;\n rows.push({\n session: { id, ...rest, ...gitFacts(cwd), ...(rest.branch ? { branch: rest.branch } : {}) },\n started_at,\n last_at,\n transcript: f,\n });\n }\n return rows;\n },\n};\n\n/** sessionpipe's own waiter (CONTROL.md \u00A78), which a session runs as a background command\n * to stay reachable: it ends only when a message arrives, so it is not work the session\n * waits on. Matched by its command, whatever path or shim runs it. */\nconst WAITER_RE = /(?:^|[\\s\"'`/\\\\])sessionpipe(?:\\.\\w+)?[\"']?\\s+wait(?:\\s|$)/;\n\n/** How much background work Claude Code lists that will wake the session when it ends\n * (`background_tasks`, in every Stop and SubagentStop since 2.1.258): a count, never what\n * it runs. Not counted: sessionpipe's own waiter, and the subagent whose own stop this is,\n * which Claude Code still lists as running (issue #153). Undefined when the harness\n * doesn't say. */\nexport function backgroundCount(tasks: unknown, ending?: string): number | undefined {\n if (!Array.isArray(tasks)) return undefined;\n return tasks.filter((t) => {\n const task = t as { id?: unknown; command?: unknown } | null;\n if (ending !== undefined && task?.id === ending) return false;\n return !(typeof task?.command === \"string\" && WAITER_RE.test(task.command));\n }).length;\n}\n\n/** Claude Code runs a status line only on events (a new assistant message, a window's\n * reset), and the hook sends at most one change a minute, so a turn's last numbers\n * would wait for the next prompt. The timer runs it again while the session is idle. */\nconst LINE_REFRESH_S = 60;\n\n/** Claude Code hands an account's limits only to its status line command\n * (https://code.claude.com/docs/en/statusline), so with `--status-line` ours is that\n * command. Someone else's status line is never replaced. Null: nothing to report. */\nfunction statusLine(file: string, want: boolean, cmd?: HookCommand): InstallReport | null {\n const f = readJsonFile(file);\n if (!f.ok) return null; // the hooks' report already says why\n const cur = f.value.statusLine as { command?: unknown; refreshInterval?: unknown } | undefined;\n const ours = typeof cur?.command === \"string\" && OURS.test(cur.command);\n const command = cmd?.([NAME, \"StatusLine\"]).command;\n if (want && cur && !ours)\n return { file, changed: false, skipped: true, note: \"a status line of your own is set; limits are not read\" };\n if (want ? ours && cur?.command === command && cur?.refreshInterval === LINE_REFRESH_S : !ours) return null;\n if (want) f.value.statusLine = { type: \"command\", command, refreshInterval: LINE_REFRESH_S };\n else delete f.value.statusLine;\n return (\n writeBack(file, formatJson(f.value, f), f.existed) ?? {\n file,\n changed: true,\n note: want ? \"status line written (account limits)\" : \"status line removed\",\n }\n );\n}\n\n/** Epoch seconds as RFC 3339; anything that is not a plausible time is no time. */\nconst epochIso = (t: unknown): string | undefined =>\n typeof t === \"number\" && t > 0 && t < 1e11 ? new Date(t * 1000).toISOString() : undefined;\n\nconst WINDOW_MINUTES: Record<string, number> = { five_hour: 300, seven_day: 10_080 };\n\n/** The status line's `rate_limits`: `five_hour`, `seven_day` and, behind a gateway,\n * `spend_limit`, each with `used_percentage` and `resets_at` in epoch seconds. Only\n * Pro and Max accounts (or a gateway) have them, and only after a session's first\n * response; a window drops out once it resets. */\nexport function claudeLimits(rl: unknown): DataOf<\"limits.observed\"> | null {\n if (!rl || typeof rl !== \"object\" || Array.isArray(rl)) return null;\n const windows: DataOf<\"limits.observed\">[\"windows\"] = [];\n for (const [id, w] of Object.entries(rl as Record<string, { used_percentage?: unknown; resets_at?: unknown }>)) {\n if (!/^[a-z0-9_]{1,64}$/.test(id) || typeof w?.used_percentage !== \"number\" || w.used_percentage < 0) continue;\n windows.push(\n prune({\n id,\n used_percent: w.used_percentage,\n window_minutes: WINDOW_MINUTES[id],\n resets_at: epochIso(w.resets_at),\n }),\n );\n }\n return windows.length ? { windows: windows.slice(0, 8) } : null;\n}\n\nfunction prune<T extends Record<string, unknown>>(o: T): T {\n for (const k of Object.keys(o)) if (o[k] === undefined) delete o[k];\n return o;\n}\nconst UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n/** Another harness reading this settings file, not Claude Code. Several harnesses\n * import `~/.claude/settings.json` hooks, so our entries there can be run by a tool\n * that has its own adapter: it would arrive under the wrong name, with ids that mean\n * nothing to a Claude Code reader. Every Claude Code payload names a transcript and a\n * UUID session (all 21 recorded fixtures do); a payload with neither is somebody else's. */\nexport function notClaudeCode(id: string, s: Record<string, unknown>): boolean {\n return typeof s.transcript_path !== \"string\" && !UUID.test(id);\n}\nfunction pickSource(v: unknown): string {\n return typeof v === \"string\" && [\"startup\", \"resume\", \"clear\", \"compact\", \"fork\"].includes(v) ? v : \"unknown\";\n}\n/** One of the harness's own words for who submitted a prompt, forwarded as is (PROTOCOL.md\n * \u00A74, `turn.started.submitted_by`). Not an enum of ours: a value we have never seen is\n * still carried, so the guard is the shape the spec allows \u2014 a bare word of at most 40\n * characters, which is all a receiver may show or group by. Tier 0 is not redacted\n * (PRIVACY.md \u00A72), so that shape is the only guard there is. */\nconst harnessWord = (v: unknown): string | undefined =>\n typeof v === \"string\" && /^[A-Za-z0-9][A-Za-z0-9_.-]{0,39}$/.test(v) ? v : undefined;\n/** Claude Code's own prompt wrappers, as a CLOSED list: a task notification, a peer message,\n * a system reminder, a local command's output, a slash command's expansion \u2014 with or\n * without a closing tag, after trimming. Narrower than the reader's `isInjected` on\n * purpose, because the two directions do not cost the same. A wrapper we have not recorded\n * yet reads as unknown and a receiver keeps the turn, which is what it does today; a shape\n * test wide enough to catch every wrapper also fires on a person who pasted nothing but an\n * SVG, an HTML page or a JSX element, and a recency board acting on that would drop one of\n * the person's own turns. Dropping one record from a transcript costs little, which is why\n * the reader's test stays wide; ADAPTERS.md (Claude Code \u00B7 Quirks) says why they differ. */\nconst WRAPPER =\n /^<(?:task-notification|cross-session-message|system-reminder|local-command-stdout|command-[a-z-]+)[\\s/>]/i;\nconst injectedBlock = (prompt: string): boolean => WRAPPER.test(prompt.trim());\nfunction errText(v: unknown): string | undefined {\n if (typeof v === \"string\") return v.slice(0, 2000);\n if (v && typeof v === \"object\") {\n const e = v as { error?: unknown; message?: unknown };\n if (typeof e.error === \"string\") return e.error.slice(0, 2000);\n if (typeof e.message === \"string\") return e.message.slice(0, 2000);\n }\n return undefined;\n}\nfunction describe(input: unknown): string {\n if (!input || typeof input !== \"object\") return \"\";\n const i = input as Record<string, unknown>;\n const v = i.command ?? i.file_path ?? i.path ?? i.url ?? i.pattern;\n return typeof v === \"string\" ? ` ${v.slice(0, 120)}` : \"\";\n}\n\n// --- facts: title, url, model, account, from Claude Code's own files ------------------\n\nconst NAME_RANK: Record<string, \"custom\" | \"harness\"> = {\n user: \"custom\",\n auto: \"harness\",\n hook: \"harness\",\n peer: \"harness\",\n};\ninterface Registry {\n sessionId: string | null;\n name: string | null;\n name_source: \"custom\" | \"harness\" | null;\n bridge: string | null;\n}\nfunction registryEntry(j: unknown): Registry | null {\n if (!j || typeof j !== \"object\") return null;\n const r = j as { sessionId?: unknown; name?: unknown; nameSource?: string; bridgeSessionId?: unknown };\n const source = r.nameSource ? NAME_RANK[r.nameSource] : undefined;\n return {\n sessionId: r.sessionId ? String(r.sessionId) : null,\n name: source && typeof r.name === \"string\" && r.name.trim() ? r.name.trim() : null,\n name_source: source ?? null,\n bridge: typeof r.bridgeSessionId === \"string\" ? r.bridgeSessionId : null,\n };\n}\nconst liveCache = new Map<string, Map<string, Registry>>();\nfunction claudeLive(dir: string): Map<string, Registry> {\n const hit = liveCache.get(dir);\n if (hit) return hit;\n const map = new Map<string, Registry>();\n let names: string[] = [];\n try {\n names = readdirSync(path.join(dir, \"sessions\")).filter((n) => n.endsWith(\".json\"));\n } catch {}\n for (const n of names) {\n try {\n const e = registryEntry(JSON.parse(readFileSync(path.join(dir, \"sessions\", n), \"utf8\")));\n if (e?.sessionId) map.set(e.sessionId, e);\n } catch {}\n }\n liveCache.set(dir, map);\n return map;\n}\nfunction claudeLiveByPid(dir: string, pid: unknown): Registry | null {\n if (!pid) return null;\n try {\n return registryEntry(JSON.parse(readFileSync(path.join(dir, \"sessions\", `${pid}.json`), \"utf8\")));\n } catch {\n return null;\n }\n}\n/** The Claude Code process that ran this hook: the nearest ancestor with a registry\n * file (hooks run under a shell, so usually the parent's parent). */\nexport function claudePid(env: NodeJS.ProcessEnv = process.env): number | null {\n try {\n const dirs = claudeDirs(env);\n const has = (pid: number) => dirs.some((d) => existsSync(path.join(d, \"sessions\", `${pid}.json`)));\n let pid = process.ppid;\n if (has(pid)) return pid;\n const parent = parentOf();\n for (let hop = 0; hop < 6 && pid > 1; hop++) {\n pid = parent(pid);\n if (pid > 1 && has(pid)) return pid;\n }\n } catch {}\n return null;\n}\nfunction parentOf(): (pid: number) => number {\n if (process.platform === \"linux\") {\n return (pid) => {\n try {\n const st = readFileSync(`/proc/${pid}/stat`, \"utf8\");\n return Number(st.slice(st.lastIndexOf(\")\") + 2).split(\" \")[1]) || 0;\n } catch {\n return 0;\n }\n };\n }\n const table = new Map<number, number>();\n try {\n const out = execFileSync(\"ps\", [\"-axo\", \"pid=,ppid=\"], {\n encoding: \"utf8\",\n timeout: 2000,\n maxBuffer: 8 * 1024 * 1024,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n });\n for (const l of out.split(\"\\n\")) {\n const m = /^\\s*(\\d+)\\s+(\\d+)/.exec(l);\n if (m) table.set(Number(m[1]), Number(m[2]));\n }\n } catch {}\n return (pid) => table.get(pid) || 0;\n}\nconst EMAIL_RE = /^[^@\\s]{1,64}@[^@\\s]{1,189}$/;\n/** Who a config dir is signed in as, from its .claude.json (the default dir keeps it\n * at ~/.claude.json): the account id, and the email it signs in with. A dir with no\n * claude.ai login that runs on another API is that API's account (apiAccount). */\nfunction claudeLogin(dir: string, home = homeDir()): { id: string; email?: string; name?: string } | null {\n const files = [path.join(dir, \".claude.json\")];\n if (path.resolve(dir) === path.join(home, \".claude\")) files.unshift(path.join(home, \".claude.json\"));\n for (const f of files) {\n try {\n const a = (\n JSON.parse(readFileSync(f, \"utf8\")) as { oauthAccount?: { accountUuid?: unknown; emailAddress?: unknown } }\n ).oauthAccount;\n if (typeof a?.accountUuid === \"string\" && a.accountUuid) {\n const email = typeof a.emailAddress === \"string\" && EMAIL_RE.test(a.emailAddress) ? a.emailAddress : undefined;\n return { id: a.accountUuid.slice(0, 128), ...(email ? { email } : {}) };\n }\n } catch {}\n }\n return apiAccount(dir);\n}\n/** Anthropic's own API: a key for it is an Anthropic account no local file names. */\nconst ANTHROPIC_HOST = /(^|\\.)anthropic\\.com$/i;\n/** A config dir whose settings send Claude Code to another API (`env.ANTHROPIC_BASE_URL`:\n * Kimi on a Modal endpoint, GLM on Z.ai) has no claude.ai login, so its account is the\n * endpoint: `api-` and 16 hex of the SHA-256 of its origin for events (the same on every\n * machine that uses it), and its host as the name control's pair and hello give it.\n * Only that one key is read; the tokens and headers beside it never are. */\nfunction apiAccount(dir: string): { id: string; name: string } | null {\n const base = (readJson(settingsIn(dir)) as { env?: { ANTHROPIC_BASE_URL?: unknown } }).env?.ANTHROPIC_BASE_URL;\n if (typeof base !== \"string\") return null;\n let u: URL;\n try {\n u = new URL(base.trim());\n } catch {\n return null;\n }\n if ((u.protocol !== \"https:\" && u.protocol !== \"http:\") || !u.hostname || ANTHROPIC_HOST.test(u.hostname))\n return null;\n // The origin alone: a path or a user:password@ can carry a key.\n const origin = `${u.protocol}//${u.host}`;\n return { id: `api-${createHash(\"sha256\").update(origin).digest(\"hex\").slice(0, 16)}`, name: u.host };\n}\nconst accountCache = new Map<string, string | null>();\n/** The account id for `session.account_id`: never the email. Events go to every sink,\n * a team board included; the email (or an API's host) reaches only a receiver the\n * person paired with, in control's pair and hello (claudeAccounts). */\nfunction claudeAccount(dir: string): string | null {\n const hit = accountCache.get(dir);\n if (hit !== undefined) return hit;\n const acct = claudeLogin(dir)?.id ?? null;\n accountCache.set(dir, acct);\n return acct;\n}\n/** Every account signed in across these config dirs, read fresh (a person signs in to\n * another account without restarting anything), for control's pair and hello. */\nexport function claudeAccounts(dirs: string[], home = homeDir()): HarnessAccount[] {\n const out: HarnessAccount[] = [];\n for (const d of dirs) {\n const l = claudeLogin(d, home);\n if (!l) continue;\n const seen = out.find((a) => a.id === l.id);\n if (!seen) out.push({ harness: NAME, ...l });\n else if (!seen.email && l.email) seen.email = l.email;\n }\n return out;\n}\n/** Each config dir with the account it is signed in as, for whoever asks the harness a\n * question per dir (control's hello asks `claude auth status` for each). Dirs naming\n * nobody are left out. */\nexport function claudeAccountDirs(dirs: string[], home = homeDir()): { id: string; dir: string }[] {\n const out: { id: string; dir: string }[] = [];\n for (const d of dirs) {\n const l = claudeLogin(d, home);\n if (l) out.push({ id: l.id, dir: d });\n }\n return out;\n}\nconst LINK_RE = /^https:\\/\\/claude\\.ai\\/code\\/session_[A-Za-z0-9]+$/;\nfunction transcriptLink(records: Record<string, unknown>[]): string | null {\n for (let i = records.length - 1; i >= 0; i--) {\n const j = records[i] as { type?: string; subtype?: string; url?: unknown; bridgeSessionId?: unknown };\n if (j.type === \"system\" && j.subtype === \"bridge_status\" && typeof j.url === \"string\" && LINK_RE.test(j.url))\n return j.url;\n if (j.type === \"bridge-session\" && typeof j.bridgeSessionId === \"string\") {\n const m = /^(?:cse|session)_([A-Za-z0-9]+)$/.exec(j.bridgeSessionId);\n if (m) return `https://claude.ai/code/session_${m[1]}`;\n }\n }\n return null;\n}\n/** A first ask as the Claude Code app titles an untitled session: whitespace\n * collapsed, whole up to 50 characters, else its first 50 and \"...\". */\nexport function appTitle(text: string): string {\n const t = String(text).replace(/\\s+/g, \" \").trim();\n return t.length > 50 ? `${t.slice(0, 50)}...` : t;\n}\nfunction askText(j: Record<string, unknown> | null): string | null {\n if (!j || j.type !== \"user\" || j.isMeta || j.isSidechain) return null;\n const origin = j.origin as { kind?: string } | undefined;\n if (origin?.kind && origin.kind !== \"human\") return null;\n const c = (j.message as { content?: unknown } | undefined)?.content;\n // A session the control daemon started is named after what the person asked, not after\n // the line sessionpipe added to say where the ask came from (a short ask left room for\n // it in the 50 characters of a title).\n const text = deliveredWords(\n (typeof c === \"string\"\n ? c\n : Array.isArray(c)\n ? c\n .filter((b) => b && b.type === \"text\" && typeof b.text === \"string\")\n .map((b) => b.text as string)\n .join(\"\\n\")\n : \"\"\n ).trim(),\n ).text;\n if (!text || isInjected(text)) return null;\n return text;\n}\nfunction firstAsk(records: Record<string, unknown>[]): string | null {\n for (const j of records) {\n const t = askText(j);\n if (t) return appTitle(t);\n }\n return null;\n}\nfunction scanTitles(file: string, from: number, found: { custom?: string | null; ai?: string | null }) {\n const out = { custom: found.custom ?? null, ai: found.ai ?? null, upto: from };\n let size = 0;\n try {\n size = statSync(file).size;\n } catch {\n return out;\n }\n if (size < from) {\n out.upto = 0;\n out.custom = out.ai = null;\n from = 0;\n }\n // Only lines carrying a title record are parsed; the rest of the new bytes are skipped.\n let pos = 0;\n scanLines<null>(\n file,\n (l) => {\n pos += Buffer.byteLength(l, \"utf8\") + 1;\n if (pos <= from || l.indexOf('-title\"') < 0) return null;\n try {\n const j = JSON.parse(l) as { type?: string; customTitle?: string; aiTitle?: string };\n if (j.type === \"custom-title\" && j.customTitle) out.custom = j.customTitle;\n if (j.type === \"ai-title\" && j.aiTitle) out.ai = j.aiTitle;\n } catch {}\n return null;\n },\n 512 * 1024 * 1024,\n );\n out.upto = size;\n return out;\n}\n\n/** A session's title and where it came from, best first: /rename (registry \"user\"\n * name or custom-title) \u2192 Claude Code's own title (registry \"auto\" name or\n * ai-title) \u2192 the first ask, marked first-ask so a real title later replaces it. */\nexport function claudeFacts(\n file: string,\n sessionId: string,\n hints: Record<string, unknown>,\n state: FactsState,\n): SessionFacts {\n const { head, tail } = ends(file, 64 * 1024, 256 * 1024);\n const H = parseLines(head);\n const T = parseLines(tail);\n const out: SessionFacts = {};\n const id = sessionId || path.basename(file, \".jsonl\");\n const mem = state.get(NAME, id);\n let custom: string | null = null;\n let ai: string | null = null;\n for (const j of H.concat(T)) {\n if (j.type === \"custom-title\" && typeof j.customTitle === \"string\") custom = j.customTitle;\n if (j.type === \"ai-title\" && typeof j.aiTitle === \"string\") ai = j.aiTitle;\n }\n let size = 0;\n try {\n size = statSync(file).size;\n } catch {}\n if (!custom && !ai && size > 64 * 1024 + 256 * 1024) {\n const s = scanTitles(file, Number(mem.scan_upto) || 0, {\n custom: mem.scan_custom as string | null,\n ai: mem.scan_ai as string | null,\n });\n custom = s.custom;\n ai = s.ai;\n state.save(NAME, id, { scan_upto: s.upto, scan_custom: s.custom, scan_ai: s.ai });\n }\n const dir = configDirOf(file);\n const live = claudeLive(dir).get(id) ?? claudeLiveByPid(dir, hints.claude_pid);\n if (live?.name) state.save(NAME, id, { name: live.name, name_source: live.name_source });\n const bridge =\n live?.bridge && /^session_[A-Za-z0-9]+$/.test(live.bridge) ? `https://claude.ai/code/${live.bridge}` : null;\n const url = bridge ?? transcriptLink(T) ?? transcriptLink(H) ?? (typeof mem.url === \"string\" ? mem.url : null);\n if (url) {\n out.url = url;\n state.save(NAME, id, { url });\n }\n const name = live?.name\n ? { title: live.name, source: live.name_source as \"custom\" | \"harness\" }\n : typeof mem.name === \"string\"\n ? { title: mem.name, source: mem.name_source as \"custom\" | \"harness\" }\n : null;\n const pick =\n (name && name.source === \"custom\" && name) ||\n (custom && { title: custom, source: \"custom\" as const }) ||\n name ||\n (ai && { title: ai, source: \"harness\" as const });\n let ask = typeof mem.first_ask === \"string\" ? mem.first_ask : firstAsk(H);\n if (!ask && size > 64 * 1024 && !mem.first_ask_none) {\n ask = scanLines<string>(file, (l) => {\n try {\n const t = askText(JSON.parse(l) as Record<string, unknown>);\n return t ? appTitle(t) : null;\n } catch {\n return null;\n }\n });\n if (!ask && size > 16 * 1024 * 1024) state.save(NAME, id, { first_ask_none: true });\n }\n if (ask) {\n out.first_ask = ask;\n if (!mem.first_ask) state.save(NAME, id, { first_ask: ask });\n }\n if (pick) {\n out.title = String(pick.title).slice(0, 120);\n out.title_source = pick.source;\n } else if (ask) {\n out.title = ask;\n out.title_source = \"first-ask\";\n }\n const acct = claudeAccount(dir);\n if (acct) out.account_id = acct;\n for (let i = T.length - 1; i >= 0; i--) {\n const m = (T[i] as { message?: { model?: string } }).message?.model;\n if (T[i]?.type === \"assistant\" && m && m !== \"<synthetic>\") {\n out.model = m;\n break;\n }\n }\n const meta = [...T].reverse().find((j) => j.version) ?? H.find((j) => j.version);\n if (meta?.version) out.harness_version = String(meta.version);\n const times = H.concat(T)\n .map((j) => Date.parse(String(j.timestamp ?? \"\")))\n .filter((n) => n > 0);\n if (times.length) {\n out.started_at = Math.min(...times);\n out.last_at = Math.max(...times);\n }\n const withCwd = H.find((j) => typeof j.cwd === \"string\");\n if (withCwd) {\n out.cwd = withCwd.cwd as string;\n if (typeof withCwd.gitBranch === \"string\" && withCwd.gitBranch !== \"HEAD\") out.branch = withCwd.gitBranch;\n }\n return out;\n}\n\n// --- claude.ai's name for a session, only when the person turned it on ------------------\n\n/** claude.ai names a Remote Control session itself, seconds after its first message, and\n * never tells the machine: no file here holds that name, so the Claude app shows one\n * and every local reader another. With `remote_titles` on, the worker asks claude.ai the\n * way Claude Code reads a session. Again after a minute while it has no name yet, then\n * every half hour: a rename in the Claude app reaches the transcript as a custom-title,\n * which outranks this anyway. */\nconst REMOTE_RETRY_MS = 60_000;\nconst REMOTE_REFRESH_MS = 30 * 60_000;\nconst CLAUDE_API = \"https://api.anthropic.com\";\nconst KEYCHAIN = \"Claude Code-credentials\";\n/** The worker holds the session's lock while it asks, and a sibling hook waits 6 s for it. */\nconst REMOTE_TIMEOUT_MS = 3000;\nconst KEYCHAIN_TIMEOUT_MS = 2000;\n/** A session is a few kB; anything past this is not one. */\nconst REMOTE_MAX_BYTES = 1 << 20;\n/** A name as Claude Code itself cleans one: control and bidirectional characters become\n * spaces, runs of space one, the ends trimmed. */\nconst cleanName = (s: string) =>\n s\n .replace(/[\\p{Cc}\\u061C\\u200E\\u200F\\u202A-\\u202E\\u2066-\\u2069]/gu, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n\n/** claude.ai's name for a session with a claude.ai link, unless the person named it\n * here: `{title, title_source: \"harness\"}`, or nothing. */\nexport async function claudeRemoteFacts(\n id: string,\n local: SessionFacts,\n transcript: string | undefined,\n state: FactsState,\n env: NodeJS.ProcessEnv,\n now = Date.now(),\n): Promise<Partial<SessionFacts>> {\n if (!transcript || !local.url || !LINK_RE.test(local.url) || local.title_source === \"custom\") return {};\n const mem = state.get(NAME, id);\n let title = typeof mem.remote_title === \"string\" ? mem.remote_title : null;\n if (now - (Number(mem.remote_at) || 0) >= (title ? REMOTE_REFRESH_MS : REMOTE_RETRY_MS)) {\n // Marked before the call: a claude.ai that doesn't answer isn't asked on every hook.\n state.save(NAME, id, { remote_at: now });\n const token = claudeAiToken(configDirOf(transcript), env, now);\n const got = token ? await claudeAiTitle(local.url.slice(local.url.lastIndexOf(\"/\") + 1), token) : undefined;\n if (got !== undefined) {\n title = got?.slice(0, 200) ?? null;\n state.save(NAME, id, { remote_title: title });\n }\n }\n return title ? { title: title.slice(0, 120), title_source: \"harness\" } : {};\n}\n\n/** The keychain items Claude Code keeps a config dir's sign-in under: `Claude\n * Code-credentials`, and for a CLAUDE_CONFIG_DIR, `-` and 8 hex of the SHA-256 of that\n * path as it was set (tried as the hook's env names it, then as the dir itself). */\nfunction keychainServices(dir: string, env: NodeJS.ProcessEnv): string[] {\n const named = (p: string) =>\n `${KEYCHAIN}-${createHash(\"sha256\").update(p.normalize(\"NFC\")).digest(\"hex\").slice(0, 8)}`;\n const out = new Set<string>();\n if (env.CLAUDE_CONFIG_DIR && path.resolve(env.CLAUDE_CONFIG_DIR) === dir) out.add(named(env.CLAUDE_CONFIG_DIR));\n if (dir === path.join(env.HOME || homeDir(), \".claude\")) out.add(KEYCHAIN);\n out.add(named(dir));\n return [...out];\n}\n\n/** A token this process already read, by config dir, until a minute before it expires:\n * `sessionpipe titles on` asks about every recent session, one `security` each would be\n * slow. In memory only, for the life of the process. */\nconst tokenCache = new Map<string, { token: string; expires: number }>();\n/** The access token Claude Code signed in to `dir` with: from the macOS keychain, else\n * from `<dir>/.credentials.json`. Never written anywhere, never logged. One that has\n * expired is not refreshed, since that would rotate Claude Code's own login: the lookup\n * waits for Claude Code to refresh it. */\nexport function claudeAiToken(dir: string, env: NodeJS.ProcessEnv, now: number): string | null {\n const hit = tokenCache.get(dir);\n if (hit && hit.expires > now + 60_000) return hit.token;\n const raw: string[] = [];\n if (process.platform === \"darwin\")\n for (const service of keychainServices(dir, env)) {\n try {\n const user = env.USER || userInfo().username;\n const account = /^[\\w.-]+$/.test(user) ? user : \"claude-code-user\";\n raw.push(\n execFileSync(\"security\", [\"find-generic-password\", \"-a\", account, \"-w\", \"-s\", service], {\n encoding: \"utf8\",\n timeout: KEYCHAIN_TIMEOUT_MS,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }),\n );\n break;\n } catch {}\n }\n try {\n raw.push(readFileSync(path.join(dir, \".credentials.json\"), \"utf8\"));\n } catch {}\n for (const r of raw) {\n try {\n // Claude Code writes the item as hex (`-X`); `security -w` prints it back as text,\n // or as that hex where it isn't printable.\n const t = r.trim();\n const o = (\n JSON.parse(/^(?:[0-9a-f]{2})+$/i.test(t) ? Buffer.from(t, \"hex\").toString(\"utf8\") : t) as {\n claudeAiOauth?: { accessToken?: unknown; expiresAt?: unknown };\n }\n ).claudeAiOauth;\n if (typeof o?.accessToken !== \"string\" || !o.accessToken) continue;\n const expires = typeof o.expiresAt === \"number\" ? o.expiresAt : Number.POSITIVE_INFINITY;\n if (expires <= now + 60_000) continue;\n tokenCache.set(dir, { token: o.accessToken, expires });\n return o.accessToken;\n } catch {}\n }\n return null;\n}\n\ninterface RemoteSession {\n id?: unknown;\n title?: unknown;\n}\n/** claude.ai's name for the session `bridge` (`session_\u2026`), from the endpoint Claude Code\n * reads a session from: a string, null when it has none yet, undefined when it couldn't\n * be asked or wouldn't say (offline, a 401 or 404, an answer about another session), so\n * the last answer stands. The token goes to api.anthropic.com alone: a redirect is\n * refused, never followed. */\nexport async function claudeAiTitle(bridge: string, token: string): Promise<string | null | undefined> {\n try {\n const r = await fetch(`${CLAUDE_API}/v1/code/sessions/${bridge}`, {\n headers: { Authorization: `Bearer ${token}`, \"anthropic-version\": \"2023-06-01\", \"User-Agent\": \"sessionpipe\" },\n redirect: \"error\",\n signal: AbortSignal.timeout(REMOTE_TIMEOUT_MS),\n });\n if (r.status !== 200 || Number(r.headers.get(\"content-length\")) > REMOTE_MAX_BYTES) return undefined;\n const text = await r.text();\n if (text.length > REMOTE_MAX_BYTES) return undefined;\n // claude.ai answers `{response_shape: {\u2026}}` (conformance/remote/claude-code); Claude Code\n // also reads `session`, and a bare session is taken too. Asked as `session_\u2026`, it names\n // the session `cse_\u2026`: the same one.\n const j = JSON.parse(text) as (RemoteSession & { response_shape?: RemoteSession; session?: RemoteSession }) | null;\n const s = j?.response_shape ?? j?.session ?? j;\n const bare = (x: string) => x.replace(/^(?:session|cse)_/, \"\");\n if (typeof s?.id !== \"string\" || bare(s.id) !== bare(bridge)) return undefined;\n return (typeof s.title === \"string\" && cleanName(s.title)) || null;\n } catch {\n return undefined;\n }\n}\n\n/** For tests: each hook runs in a fresh process; a test that edits the registry mid-run clears the cache. */\nexport const _resetClaudeCaches = (): void => {\n liveCache.clear();\n accountCache.clear();\n tokenCache.clear();\n};\n", "// SPDX-License-Identifier: Apache-2.0\n// The words sessionpipe puts around a message it delivers to a session (spec/CONTROL.md\n// \u00A76, \u00A78, \u00A713), in one place: whoever delivers a message builds them here, and the\n// transcript readers take them off again with `deliveredWords`, so the `user` side of a\n// turn is what the person wrote and never what the machine wrote around it. The shapes\n// `deliveredWords` knows are made from the builders themselves, so a sentence changed\n// here is recognised in the same edit. No `node:` imports: this is part of\n// sessionpipe-core/control, which a Worker or a browser may import.\n\n/** The receiver's own host, for a line a person reads; the whole string when it is not\n * a URL. */\nexport function hostOf(receiver: string): string {\n try {\n return new URL(receiver).host;\n } catch {\n return receiver;\n }\n}\n\n/** Said with every message that reaches a live session: the answer goes back by itself\n * (the daemon reads it from the transcript), so the model never invents a command to\n * reply with (a real session tried `sessionpipe send`, 2026-10-01). */\nexport const IN_PLACE_ANSWER =\n \"Answer it right here, as you would answer the person at the keyboard: your reply is sent back to them automatically. Don't run a command or call a tool just to send it.\";\n\n/** What held a session when a copy of it was made instead (CONTROL.md \u00A76, What counts as\n * held), as the machine found it: a window the person has it open in, another process's\n * run of it, or only a write to its transcript too recent to account for. */\nexport const COPY_WHYS = [\"open\", \"running\", \"recent\"] as const;\nexport type CopyWhy = (typeof COPY_WHYS)[number];\n\n/** Said with a message a copy of a session is answering, so the model knows its reply is\n * the only part the person sees, while its work is as real as the original's. The first\n * note said \"nothing you do here appears in it \u2026 don't carry on the original's work\", and\n * a copy asked to change a page answered that a copy can't publish (2026-11-05). Why\n * there is a copy is said as the machine found it: an original that is open in a\n * window, or one that something else is using. */\nexport const copyNote = (why: CopyWhy): string =>\n `You are a copy of that session, started because the original is ${why === \"open\" ? \"open in a window\" : \"in use by another process\"}, and you have its conversation, folder and tools. Do what the message asks the way the original would: edits, commands and publishing all take effect for real. Only this conversation stays here, so the person reads your reply and not the original's${why === \"open\" ? \" window\" : \"\"}: say what you did, then stop.`;\n\n/** Said after a message `sessionpipe wait` prints (CONTROL.md \u00A78), so the session starts\n * the waiter again. */\nexport const RE_ARM =\n \"(Answer it right here, as you would answer the person at the keyboard: your reply is sent back to them automatically, so don't run a command or call a tool just to send it. Then, without mentioning it, start `sessionpipe wait` again as a background command, with the longest timeout your harness allows, to keep receiving messages.)\";\n\n/** The framed text a session receives (CONTROL.md \u00A76): the model and the person can tell\n * where it came from. */\nexport function frame(text: string, receiver: string): string {\n return `Message via ${hostOf(receiver)} (sessionpipe control, signed on the sender's device):\\n\\n${text}`;\n}\n\n/** A message id a mark is made of: a whole ULID, which is what a receiver gives a\n * message (HTTP.md \u00A73). */\nconst WHOLE_ID = /^[0-9A-HJKMNP-TV-Z]{26}$/;\n\n/** What the daemon looks for in the row the session's transcript records for a message\n * handed to it in place (\u00A76 `prompt`, \u00A76.3): a turn is only proof of delivery when it is\n * THIS message's turn, and only what the session wrote after that row is its answer.\n *\n * Null for an id that is not a whole ULID. The id is the receiver's and nobody signed\n * it: its characters go into a header that says \"signed on the sender's device\" and\n * into the session's context, so nothing but the alphabet of a ULID is ever taken from\n * it (an id of `x\\n\\nrm -rf ~` put those words in the header), and a short one (\"42\")\n * would make a mark anybody's words contain. */\nexport const messageMark = (id: string): string | null => (WHOLE_ID.test(id) ? `message ${id.slice(-12)}` : null);\n\nconst marked = (text: string, host: string, mark: string): string =>\n `Message via ${host} (sessionpipe control, signed on the sender's device; ${mark}):\\n\\n${text}`;\n\n/** The framed text for a message handed to a live session in place \u2014 at its Stop, to\n * its waiter, into its inbox: `frame()` with that mark in it, since the session answers\n * in a turn of its own and the daemon has to recognise the message again in the\n * transcript to know which words are its answer. A message whose id makes no mark gets\n * `frame()` as it is: nothing of the id reaches the session. */\nexport function frameMarked(text: string, receiver: string, id: string): string {\n const mark = messageMark(id);\n return mark ? marked(text, hostOf(receiver), mark) : frame(text, receiver);\n}\n\n/** A new session's first message: the person's words first, where they come from after\n * (Claude Code names a session from the start of its first message). */\nexport function frameStart(text: string, receiver: string): string {\n return `${text}\\n\\n(Sent via ${hostOf(receiver)} with sessionpipe control, signed on the sender's device.)`;\n}\n\n/** What a session another session asked receives (CONTROL.md \u00A713), new or not: the task\n * first, then who asked and that the answer travels by itself. Handed to a live session\n * in place it names the message too (`mark`), which is how the daemon finds the answer\n * in that session's transcript. */\nexport function frameAsk(text: string, from: string | undefined, mark?: string | null): string {\n return `${text}\\n\\n(Asked by ${from ?? \"another session\"} on this machine with sessionpipe ask${mark ? `, ${mark}` : \"\"}. Answer here in full: your reply is returned to that session automatically. Don't run a command or call a tool just to send it.)`;\n}\n\n/** A handoff's answer as it lands in `reply_to` (CONTROL.md \u00A76). `from` is the session\n * that answered, as a person reads it (`<harness>:<short id>`). */\nexport function frameHandoff(from: string, receiver: string, reply: string): string {\n return `Answer from ${from} (sessionpipe handoff, asked via ${hostOf(receiver)}):\\n\\n${reply}`;\n}\n\n/** A line a builder above writes, as a test for it: the builder is run with a mark where\n * the host, the id or the asker goes, and the mark becomes `hole`. */\nconst HOLE = \"\\u0000\";\n/** Where a message's own mark goes (`messageMark`), in a line that has another hole too. */\nconst MARK = \"\\u0001\";\nconst lineOf = (built: string, hole = \"(\\\\S+)\"): RegExp =>\n new RegExp(\n `^${built\n .trim()\n .replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replaceAll(HOLE, hole)\n .replaceAll(MARK, \"message \\\\S+\")}$`,\n );\n\n// Where each builder puts its own line in the text a session gets, which is the only\n// place `deliveredWords` looks for it. A new wording (an ask that names its message,\n// another note to a copy) is one more entry in the list its builder belongs to.\n/** The first paragraph, the words after it: `frame`, `frameMarked`. */\nconst HEAD_LINES = [lineOf(frame(\"\", HOLE)), lineOf(marked(\"\", HOLE, MARK))];\n/** The last paragraph, the words before it: `frameStart`. */\nconst START_LINES = [lineOf(frameStart(\"\", HOLE))];\n/** The last paragraph, the task before it: `frameAsk`. Whoever asked is named as it gave\n * itself, a session reference or \"another session\". */\nconst ASK_LINES = [lineOf(frameAsk(\"\", HOLE), \"[^\\\\n]{1,300}\")];\n/** The same paragraph where the ask was handed to a live session in place and names its\n * message: who asked is captured, so the plain paragraph can be put back. */\nconst MARKED_ASK_LINES = [lineOf(frameAsk(\"\", HOLE, MARK), \"([^\\\\n]{1,300}?)\")];\n/** The first paragraph, the answer after it: `frameHandoff`. */\nconst HANDOFF_LINES = [lineOf(frameHandoff(HOLE, HOLE, \"\"))];\n/** What a copy was told by 0.13.0 to 0.13.2. Nothing says it now (told \"nothing you do\n * here appears in it\", a copy asked to change a page answered that a copy can't publish,\n * 2026-11-05); every copy those versions made has it in its transcript, after the\n * person's words, so a reader still takes it off. Read, never written. */\nconst COPY_NOTE_0_13_0 =\n \"You are a copy of that session, started to answer this message: the conversation above is a replay, the original session is somewhere else, and nothing you do here appears in it. Answer the message and stop; don't carry on the original's work.\";\n/** What a copy is told, in each of its forms (two today: an original open in a window,\n * and one something else is using), and what one was told before. */\nconst COPY_NOTES = [...new Set(COPY_WHYS.map(copyNote)), COPY_NOTE_0_13_0];\n/** What the daemon may add, once, after the words of a message a receiver sent\n * (control/daemon.ts: a Stop hook's block and the inbox, a copy, a waiter). */\nconst NOTES = [IN_PLACE_ANSWER, ...COPY_NOTES, RE_ARM];\n/** And after an ask or a handoff's answer, whose own lines already say how the answer\n * travels: a copy, a waiter. */\nconst ASK_NOTES = [...COPY_NOTES, RE_ARM];\n\nconst lineIn = (lines: RegExp[], line: string): RegExpExecArray | null => {\n for (const l of lines) {\n const m = l.exec(line);\n if (m) return m;\n }\n return null;\n};\n\n/** `frame()` and `frameMarked()` undone, and nothing else: the person's words, and the\n * host they were sent from. A channel shows the words as the message and says where\n * they came from beside it (CONTROL.md \u00A78). Text neither of them made comes back whole,\n * from nowhere. */\nexport function unframe(text: string): { text: string; via: string | null } {\n const cut = text.indexOf(\"\\n\\n\");\n const head = cut < 0 ? null : lineIn(HEAD_LINES, text.slice(0, cut));\n return head ? { text: text.slice(cut + 2), via: head[1] as string } : { text, via: null };\n}\n\n/** A delivered message with sessionpipe's own words taken off: the line that says where\n * it came from (before the words for a message into a session that exists, after them\n * for a new session's first), and the one note to the model that may follow the words\n * (how the answer travels, that the session is a copy, to start the waiter again).\n *\n * Only where sessionpipe puts them. A sentence is taken off in the place and the form\n * the daemon builds it in, never because a paragraph somewhere reads like one: a person\n * can type or paste any of these words, and a prompt that is nothing but one of them is\n * what the person wrote. So a note comes off only after the words of a text that carries\n * a frame, a frame's line only with words beside it, and text in no shape the daemon\n * builds comes back exactly as it was, `delivered: false`. `via` is the receiver's host\n * when the frame names one.\n *\n * Kept, because they say whose words these are and not how they travelled: the\n * paragraph `frameAsk` puts after a task (`(Asked by <session> on this machine with\n * sessionpipe ask. \u2026)`, in that plain form whether or not the ask named its message on\n * the way), and the first line of a handoff's answer. The task is an\n * agent's and the answer is an agent's; a receiver tells them from the person's own\n * words by exactly those lines, so a text without them would be drawn as something the\n * person wrote. Kept too, because it is what the message says: the list of attached\n * files. */\nexport function deliveredWords(text: string): { text: string; via: string | null; delivered: boolean } {\n const paragraphs = text.split(\"\\n\\n\");\n const at = (i: number): string => (paragraphs[i] as string).trim();\n const n = paragraphs.length;\n // The words end before a note, when the text ends with one and is more than the note.\n const note = n > 1 && NOTES.includes(at(n - 1)) ? at(n - 1) : null;\n const end = note === null ? n : n - 1;\n const words = (from: number, to: number) => paragraphs.slice(from, to).join(\"\\n\\n\").trim();\n const head = lineIn(HEAD_LINES, at(0));\n if (head && words(1, end)) return { text: words(1, end), via: head[1] as string, delivered: true };\n const start = note === null ? lineIn(START_LINES, at(n - 1)) : null;\n if (start && words(0, n - 1)) return { text: words(0, n - 1), via: start[1] as string, delivered: true };\n // An agent's task and an agent's answer keep the line that says so; a note after it goes.\n const asks = note === null || ASK_NOTES.includes(note);\n const theirs =\n asks && ((lineIn(ASK_LINES, at(end - 1)) && words(0, end - 1)) || (lineIn(HANDOFF_LINES, at(0)) && words(1, end)));\n if (theirs) return { text: note === null ? text : words(0, end), via: null, delivered: true };\n // An ask handed to a live session in place names its message as well. Who asked is\n // kept, in the paragraph every ask has; the mark said how the task travelled, and goes.\n const marked = asks ? lineIn(MARKED_ASK_LINES, at(end - 1)) : null;\n if (marked && words(0, end - 1))\n return { text: `${words(0, end - 1)}${frameAsk(\"\", marked[1] as string)}`, via: null, delivered: true };\n return { text, via: null, delivered: false };\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// Reading the ends of large files, JSON lines, and recent files under a root.\nimport { closeSync, fstatSync, openSync, readdirSync, readSync, statSync } from \"node:fs\";\nimport path from \"node:path\";\n\n/** The first and last bytes of a file, as lines \u2014 a transcript can be tens of MB. */\nexport function ends(file: string, headBytes: number, tailBytes: number): { head: string[]; tail: string[] } {\n let fd: number | undefined;\n try {\n fd = openSync(file, \"r\");\n const size = fstatSync(fd).size;\n const read = (pos: number, len: number) => {\n const b = Buffer.alloc(len);\n const n = readSync(fd as number, b, 0, len, pos);\n return b.subarray(0, n).toString(\"utf8\");\n };\n const head = read(0, Math.min(size, headBytes));\n const tail = size > headBytes ? read(Math.max(0, size - tailBytes), Math.min(size, tailBytes)) : head;\n return { head: head.split(\"\\n\").slice(0, -1), tail: tail.split(\"\\n\").slice(size > headBytes ? 1 : 0) };\n } catch {\n return { head: [], tail: [] };\n } finally {\n if (fd !== undefined)\n try {\n closeSync(fd);\n } catch {}\n }\n}\n\nexport const parseLines = (lines: string[]): Record<string, unknown>[] =>\n lines\n .map((l) => {\n try {\n return JSON.parse(l) as Record<string, unknown>;\n } catch {\n return null;\n }\n })\n .filter((x): x is Record<string, unknown> => !!x);\n\n/** Read line by line up to `cap` bytes, stopping when `visit` returns a value. */\nexport function scanLines<T>(file: string, visit: (line: string) => T | null, cap = 16 * 1024 * 1024): T | null {\n let fd: number | undefined;\n try {\n fd = openSync(file, \"r\");\n const buf = Buffer.alloc(1024 * 1024);\n let pos = 0;\n let rest: Buffer = Buffer.alloc(0);\n while (pos < cap) {\n const n = readSync(fd, buf, 0, buf.length, pos);\n if (!n) break;\n pos += n;\n let chunk = Buffer.concat([rest, buf.subarray(0, n)]);\n let nl = chunk.indexOf(10);\n while (nl >= 0) {\n const r = visit(chunk.subarray(0, nl).toString(\"utf8\"));\n if (r !== null) return r;\n chunk = chunk.subarray(nl + 1);\n nl = chunk.indexOf(10);\n }\n rest = chunk;\n }\n } catch {\n } finally {\n if (fd !== undefined)\n try {\n closeSync(fd);\n } catch {}\n }\n return null;\n}\n\nexport function recentFiles(root: string, depth: number, sinceMs: number, match: (name: string) => boolean): string[] {\n const out: string[] = [];\n const walk = (dir: string, d: number) => {\n let names: import(\"node:fs\").Dirent[] = [];\n try {\n names = readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of names) {\n const p = path.join(dir, e.name);\n if (e.isDirectory()) {\n if (d < depth) walk(p, d + 1);\n continue;\n }\n if (!match(e.name)) continue;\n try {\n if (statSync(p).mtimeMs >= sinceMs) out.push(p);\n } catch {}\n }\n };\n walk(root, 0);\n return out;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// The repo and branch of a folder, from git itself; credentials stripped from the\n// remote. Cached per folder for the life of the process (a worker run).\nimport { execFileSync } from \"node:child_process\";\n\nconst cache = new Map<string, { repo?: string; branch?: string }>();\n\nexport function gitFacts(cwd: string | undefined): { repo?: string; branch?: string } {\n if (!cwd) return {};\n const hit = cache.get(cwd);\n if (hit) return hit;\n const run = (args: string[]) => {\n try {\n return execFileSync(\"git\", [\"-C\", cwd, ...args], {\n encoding: \"utf8\",\n timeout: 1500,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim();\n } catch {\n return \"\";\n }\n };\n const out: { repo?: string; branch?: string } = {};\n const repo = run([\"remote\", \"get-url\", \"origin\"]);\n if (repo) out.repo = stripCredentials(repo);\n const branch = run([\"rev-parse\", \"--abbrev-ref\", \"HEAD\"]);\n if (branch && branch !== \"HEAD\") out.branch = branch;\n cache.set(cwd, out);\n return out;\n}\n\n/** `https://user:token@host/x` \u2192 `https://host/x`; `git@github.com:a/b.git` \u2192 `github.com/a/b`. */\nexport function stripCredentials(url: string): string {\n // The ssh forms first: the `git@` they are known by is what the credential strip removes.\n const ssh = /^(?:ssh:\\/\\/)?git@([^:/]+)[:/](.+?)(?:\\.git)?$/.exec(url);\n if (ssh) return `${ssh[1]}/${ssh[2]}`;\n return url\n .replace(/\\/\\/[^/@]*@/, \"//\")\n .replace(/^https?:\\/\\//, \"\")\n .replace(/\\.git$/, \"\");\n}\n", "// SPDX-License-Identifier: Apache-2.0\n\n/** A thread another thread started \u2014 a subagent, a review \u2014 names a `source.subagent`\n * in its own metadata (the rollout's first record). A fork the person made carries\n * only `forked_from_id`, and is a session of its own. */\nexport function codexSubagent(meta: Record<string, unknown> | null | undefined): boolean {\n if (meta?.type !== \"session_meta\") return false;\n const p = meta.payload as { source?: { subagent?: unknown } } | undefined;\n return !!p?.source?.subagent;\n}\n\n/** A fork starts with its own metadata, then replays the parent's history. Only\n * an event naming the new thread establishes where its own records begin. */\nexport function codexReplayBoundary(meta: Record<string, unknown> | null | undefined) {\n if (meta?.type !== \"session_meta\") return undefined;\n const p = meta.payload as { id?: unknown; forked_from_id?: unknown; source?: { subagent?: unknown } } | undefined;\n if (!p || (!p.forked_from_id && !p.source?.subagent)) return undefined;\n return (record: Record<string, unknown> | null) =>\n typeof p.id === \"string\" &&\n !!p.id &&\n record?.type === \"event_msg\" &&\n (record.payload as { thread_id?: unknown } | undefined)?.thread_id === p.id;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// Transcript readers: complete turns (a person's message + everything the assistant\n// said before the next one), each with the line it ends on, and the line the\n// cursor may advance to once every turn is delivered. Ported from spacesheep-cli\n// lib/memory.js. One reader per harness file format; nothing else is vendor code.\nimport { codexReplayBoundary } from \"../adapters/codex-rollout.js\";\nimport type { TranscriptRead } from \"../adapters/types.js\";\nimport { deliveredWords } from \"../control/frames.js\";\n\ninterface Msg {\n /** `interrupt` carries no words: the person stopped the running turn at this line. */\n role: \"user\" | \"assistant\" | \"interrupt\";\n text: string;\n at: number;\n line: number;\n /** This ask reached the session from somewhere other than its own keyboard: another\n * local session handed it over, or a channel pushed it, which are the two ways a\n * control daemon reaches a session in place (spec/CONTROL.md \u00A76.3, \u00A78). The words are\n * the person's; the arrival was not. */\n injected?: true;\n /** The harness's own id for the prompt (a `user` message's only). */\n id?: string;\n}\n\n/** `tail`: also say where the last turn starts and what the assistant said last in it\n * (TranscriptRead.tail), for a reader whose harness names a turn's last words. */\nexport function pairTurns(msgs: Msg[], endLine: number, tail = false): TranscriptRead {\n const turns: {\n user: string;\n assistant: string;\n at: number;\n startLine: number;\n endLine: number;\n injected?: true;\n id?: string;\n interrupted?: true;\n /** The assistant's last message in the turn, so far. */\n said?: string;\n }[] = [];\n let cur: (typeof turns)[number] | null = null;\n for (const m of msgs) {\n if (m.role === \"interrupt\") {\n // The person stopped the turn: it is whole as it stands, with whatever it had said,\n // and what follows is another turn. No hook fires for this, so without it the\n // prompt would wait for a reply that is not coming and join the next prompt instead.\n if (cur) {\n cur.interrupted = true;\n cur.endLine = m.line;\n turns.push(cur);\n cur = null;\n }\n } else if (m.role === \"user\") {\n // Never overwrite a prompt that has no reply yet: in an agentic turn the reply\n // comes after tool calls, and a second user record is not a new question.\n if (cur && !cur.assistant) {\n cur.user += `\\n\\n${m.text}`;\n if (m.id) cur.id = m.id;\n continue;\n }\n if (cur) turns.push(cur);\n cur = {\n user: m.text,\n assistant: \"\",\n at: m.at,\n startLine: m.line,\n endLine: m.line,\n ...(m.injected ? { injected: true as const } : {}),\n ...(m.id ? { id: m.id } : {}),\n };\n } else {\n if (!cur) cur = { user: \"\", assistant: \"\", at: m.at, startLine: m.line, endLine: m.line };\n cur.assistant += (cur.assistant ? \"\\n\\n\" : \"\") + m.text;\n cur.endLine = m.line;\n cur.said = m.text;\n }\n }\n if (cur?.assistant) turns.push(cur);\n // A user message with no reply yet stays unsent: the cursor stops before it.\n const line = cur && !cur.assistant ? cur.startLine : endLine;\n const out: TranscriptRead = {\n turns: turns.map((t) => ({\n user: t.user,\n assistant: t.assistant,\n at: t.at,\n endLine: t.endLine,\n ...(t.injected ? { injected: true as const } : {}),\n ...(t.id ? { id: t.id } : {}),\n ...(t.interrupted ? { interrupted: true as const } : {}),\n })),\n line,\n };\n if (cur && !cur.assistant && cur.user)\n out.open = {\n user: cur.user,\n at: cur.at,\n ...(cur.injected ? { injected: true as const } : {}),\n ...(cur.id ? { id: cur.id } : {}),\n };\n const last = turns[turns.length - 1];\n // An interrupted turn says nothing more, so it has no last words to wait for.\n if (tail && last)\n out.tail = { start: last.startLine, ...(last.said !== undefined && !last.interrupted ? { said: last.said } : {}) };\n return out;\n}\n\n/** Injected context the person never typed: <tag>\u2026</tag> wrappers (the tag may carry\n * attributes, as Claude Code's `<cross-session-message from=\"\u2026\">` does), HTML comments,\n * slash-command expansions. */\nexport const isInjected = (text: string): boolean =>\n (/^<[a-z_-]+(?:\\s[^>]*)?>/i.test(text) && /<\\/[a-z_-]+>\\s*$/i.test(text)) ||\n /^<!--\\s/.test(text) ||\n /^<command-/.test(text);\n\nconst parse = (raw: string): Record<string, unknown> | null => {\n try {\n return JSON.parse(raw) as Record<string, unknown>;\n } catch {\n return null;\n }\n};\n/** The line after the last whole one. A trailing line that does not parse has no\n * newline yet (a write in progress): the cursor stops before it, or the prompt in\n * it would never be read. */\nconst endOf = (lines: string[]) => {\n const last = lines[lines.length - 1];\n if (last === undefined) return 0;\n return last === \"\" || parse(last) === null ? lines.length - 1 : lines.length;\n};\nconst textParts = (c: unknown, kinds: string[]): string => {\n if (typeof c === \"string\") return c;\n if (!Array.isArray(c)) return \"\";\n return c\n .filter(\n (b) =>\n b &&\n typeof b === \"object\" &&\n kinds.includes((b as { type?: string }).type ?? \"\") &&\n typeof (b as { text?: unknown }).text === \"string\",\n )\n .map((b) => (b as { text: string }).text)\n .join(\"\\n\");\n};\n\n/** An origin whose message is somebody's words rather than the harness talking to\n * itself: `human` is the person at the keyboard, `peer` is a message another local\n * session handed this one \u2014 which is how a control daemon reaches a session in place,\n * so the words in it are the person's too (spec/CONTROL.md \u00A76.3). Older versions wrote\n * no origin at all, which also means the person. */\nconst SPOKEN = new Set([\"human\", \"peer\"]);\n\n/** A `peer` message that came from one of the session's own agents, not from another\n * session: a subagent handing its report back (`handback: true`, recorded on 2.1.312 and\n * 2.1.322 with the report in `<agent-message from=\"<agent id>\">`), or a task of the\n * session's messaging it (`senderTaskId`). Claude Code files both under the origin it\n * uses for another session's message, and says in the row itself that they are \"model\n * output, NOT a message from the user\". They are nobody's ask. */\nconst fromAgent = (origin: unknown): boolean => {\n const o = origin as { handback?: unknown; senderTaskId?: unknown } | undefined;\n return o?.handback === true || typeof o?.senderTaskId === \"string\";\n};\n\n/** Claude Code's own preamble around a message from another session: a first line\n * introducing it, and a closing paragraph telling the model what a peer message is and\n * isn't. Neither is anything the person typed. */\nconst PEER_INTRO = /sent a message[^\\n]*:$/;\nconst PEER_OUTRO = \"\\n\\nThis came from another \";\n/** The envelope the sender wraps its text in (cli control/inbox.ts). */\nconst ENVELOPE = /^<cross-session-message\\b[^>]*>\\n([\\s\\S]*)\\n<\\/cross-session-message>$/;\n\n/** What the person actually typed, out of a peer row. Claude Code records the parsed\n * body on the origin when the sender declared its permission class; otherwise the row\n * holds the preamble and the message together, and the preamble is cut off here. A row\n * read without this is a turn whose ask is the harness's own words. */\nexport function peerAsk(origin: unknown, text: string): string {\n const body = (origin as { body?: unknown } | undefined)?.body;\n let t = typeof body === \"string\" && body.trim() ? body : text;\n if (t !== body) {\n const nl = t.indexOf(\"\\n\");\n if (nl > 0 && PEER_INTRO.test(t.slice(0, nl))) t = t.slice(nl + 1);\n const outro = t.indexOf(PEER_OUTRO);\n if (outro > 0) t = t.slice(0, outro);\n }\n return (ENVELOPE.exec(t.trim())?.[1] ?? t).trim();\n}\n\n/** A message sent while a turn was running, absorbed by that turn. Claude Code writes it\n * as an attachment, never as a `user` record: {type:\"attachment\",\n * attachment:{type:\"queued_command\", prompt, commandMode:\"prompt\", origin:{kind:\"human\"}}}.\n * A message from another session is the same record with `origin.kind: \"peer\"` and the\n * text already on its own; a task notification shares it with another `commandMode`.\n * Older versions wrote no origin. */\nconst queuedPrompt = (a: unknown): string => {\n if (!a || typeof a !== \"object\") return \"\";\n const q = a as { type?: unknown; commandMode?: unknown; origin?: { kind?: string }; prompt?: unknown };\n if (q.type !== \"queued_command\" || (q.commandMode ?? \"prompt\") !== \"prompt\") return \"\";\n // Older versions wrote no origin at all, which means the person at the keyboard.\n const kind = q.origin?.kind ?? \"human\";\n if (!SPOKEN.has(kind) || fromAgent(q.origin)) return \"\";\n const text = textParts(q.prompt, [\"text\"]).trim();\n return kind === \"peer\" ? peerAsk(q.origin, text) : text;\n};\n\n/** A channel's message (Claude Code `--channels`: Telegram, sessionpipe's own) as Claude\n * Code records it: {type:\"user\", isMeta:true, origin:{kind:\"channel\", server}, content:\n * `<channel source=\"\u2026\" \u2026>\\n\u2026\\n</channel>`}. The words inside are the person's, sent from\n * elsewhere: the turn's ask. Anything else in that record is nobody's words. */\nconst channelText = (text: string): string => /^<channel\\b[^>]*>([\\s\\S]*)<\\/channel>$/.exec(text)?.[1]?.trim() ?? \"\";\n\n/** What Claude Code writes, as a `user` record, where the person stopped a turn (Esc, or\n * the first Ctrl-C): `[Request interrupted by user]`, or `\u2026 for tool use]` when a tool\n * was running. Its own test for the marker has the same shape. Nobody typed it. */\nconst INTERRUPTED = /^\\[Request interrupted by user[^\\]]*\\]$/;\n/** What Claude Code writes as the assistant's, under its own `<synthetic>` model, when it\n * resumes a session whose last prompt never got an answer: the process was ended\n * mid-turn (the daemon's Stop, a kill, a crash). Nobody said it. Recorded on 2.1.322. */\nconst NO_REPLY = \"No response requested.\";\n\n/** How Claude Code hands the model a blocking hook's reason: a meta `user` record,\n * `<Event> hook feedback:\\n<reason>`. sessionpipe's own Stop hook blocks with a message\n * the control daemon queued for the session (CONTROL.md \u00A76: delivered in place, shown in\n * the terminal as a Stop hook's), so that reason is the person's words in sessionpipe's\n * frame, and the turn that answers it is theirs. The words, when the record is one of\n * those; nothing for any other hook's feedback, which is the harness's. */\nconst HOOK_FEEDBACK = /^[A-Za-z]+ hook feedback:\\n/;\nconst hookDelivery = (text: string): string => {\n const head = HOOK_FEEDBACK.exec(text);\n if (!head) return \"\";\n const said = deliveredWords(text.slice(head[0].length));\n return said.delivered ? said.text : \"\";\n};\n\nconst hasBlock = (c: unknown, type: string): boolean =>\n Array.isArray(c) && c.some((b) => b && typeof b === \"object\" && (b as { type?: unknown }).type === type);\n\n/** Claude Code / Droid: {type:\"user\"|\"assistant\", message:{content}, timestamp, isMeta, isSidechain, origin},\n * plus the person's mid-turn messages (queuedPrompt) and messages from a channel (channelText). */\nexport function readClaude(lines: string[], from: number): TranscriptRead {\n const msgs: Msg[] = [];\n // For `tail.said`: the line of the assistant's latest words while nothing of their turn\n // follows them. A tool call or a tool result after them means the turn went on, so they\n // were not its last; once a message has begun another turn, its tools are its own.\n let saidLine = -1;\n let turnOver = false;\n for (let i = from; i < lines.length; i++) {\n const j = lines[i] ? parse(lines[i] as string) : null;\n if (!j || j.isSidechain) continue;\n const origin = j.origin as { kind?: string } | undefined;\n // A message another session handed this one in place is the person's words reaching\n // the session: a turn's ask. Claude Code marks the row `isMeta` because the preamble\n // is the harness's; the ask is not. Two mechanisms deliver one: a channel (#161,\n // `origin.kind === \"channel\"`, the words wrapped in `<channel>`) and the inbox (#150,\n // `origin.kind === \"peer\"`, a framed message `peerAsk` unwraps).\n const channel = j.type === \"user\" && origin?.kind === \"channel\";\n const peer = origin?.kind === \"peer\";\n const c = (j.message as { content?: unknown } | undefined)?.content;\n if (\n !turnOver &&\n ((j.type === \"assistant\" && hasBlock(c, \"tool_use\")) || (j.type === \"user\" && hasBlock(c, \"tool_result\")))\n )\n saidLine = -1;\n if (j.type === \"user\" && (j.isCompactSummary || j.repeatsCompactSummary)) continue;\n const at = Date.parse(String(j.timestamp ?? \"\")) || Date.now();\n const id = typeof j.promptId === \"string\" && j.promptId ? j.promptId : undefined;\n /** A message that is a turn's ask, or joins one: whatever follows is that turn's.\n * sessionpipe's own words around a delivered message are taken off first, wherever\n * the message arrived, and the tag test applies to what is left, whoever sent it:\n * any local program of this uid can write a peer row, so a body shaped like harness\n * markup must not become a turn whose ask is that markup, published as something the\n * person typed. */\n const ask = (said: string, m: { injected?: true; id?: string } = {}) => {\n const text = deliveredWords(said).text;\n if (!text || isInjected(text)) return;\n msgs.push({ role: \"user\", text, at, line: i, ...m });\n turnOver = true;\n };\n if (j.type === \"user\" && !channel && !peer && (j.isMeta || (origin?.kind && origin.kind !== \"human\"))) {\n // Nobody's words, with one exception: a message sessionpipe's Stop hook delivered.\n // It begins a turn of its own, like a peer's or a channel's, and is marked the same.\n if (j.isMeta && !origin?.kind)\n ask(hookDelivery(textParts(c, [\"text\"]).trim()), { injected: true, ...(id ? { id } : {}) });\n continue;\n }\n if (channel) {\n // Like a peer's: the words are the person's, the arrival was not the keyboard's.\n ask(channelText(textParts(c, [\"text\"]).trim()), { injected: true });\n } else if (j.type === \"user\") {\n const raw = textParts(c, [\"text\"]).trim();\n if (!peer && INTERRUPTED.test(raw)) {\n msgs.push({ role: \"interrupt\", text: \"\", at, line: i });\n turnOver = true;\n } else if (!peer) ask(raw, id ? { id } : {});\n // `peerAsk` takes Claude Code's preamble and the envelope off; a subagent's report,\n // which Claude Code files as a peer's message, is not an ask at all.\n else if (!fromAgent(origin)) ask(peerAsk(origin, raw), { injected: true, ...(id ? { id } : {}) });\n } else if (j.type === \"assistant\" && Array.isArray(c)) {\n const text = textParts(c, [\"text\"]).trim();\n if (text === NO_REPLY && (j.message as { model?: unknown }).model === \"<synthetic>\") {\n // The turn before it was ended where it stood, like one the person stopped with\n // Esc: whole as it is, and this row is not what it said. Claude Code's other\n // synthetic rows (an API error, a spent balance) are the turn's real outcome.\n msgs.push({ role: \"interrupt\", text: \"\", at, line: i });\n turnOver = true;\n } else if (text) {\n msgs.push({ role: \"assistant\", text, at, line: i });\n saidLine = i;\n turnOver = false;\n }\n } else if (j.type === \"attachment\") ask(queuedPrompt(j.attachment));\n }\n const out = pairTurns(msgs, endOf(lines), true);\n // pairTurns took the last turn's last message for its last words; here they are that\n // only while no tool call or result of the same turn came after them.\n if (out.tail && saidLine !== (out.turns[out.turns.length - 1] as { endLine: number }).endLine) delete out.tail.said;\n return out;\n}\n\n/** What Codex writes into a session as a \"user\" message that the person never typed:\n * `<environment_context>` and the like, and the AGENTS.md it read (`# AGENTS.md\n * instructions for <folder>` followed by `<INSTRUCTIONS>`). */\nexport function codexInjected(text: string): boolean {\n return /^<[a-z_-]+>/i.test(text) || /^# AGENTS\\.md instructions\\b/i.test(text);\n}\n\n/** Codex rollout: {type:\"response_item\", payload:{type:\"message\", role, content:[{type:\"input_text\"|\"output_text\", text}]}}. */\nexport function readCodex(lines: string[], from: number): TranscriptRead {\n const msgs: Msg[] = [];\n const boundary = codexReplayBoundary(parse(lines.find((line) => line.trim()) ?? \"\"));\n // Find the boundary from the header even when resuming inside the replay.\n // Keep absolute line numbers: the delivery cursor refers to the original file.\n const start = boundary ? lines.findIndex((line) => boundary(parse(line))) : 0;\n if (start < 0) return pairTurns(msgs, endOf(lines));\n for (let i = Math.max(from, start); i < lines.length; i++) {\n const j = lines[i] ? parse(lines[i] as string) : null;\n if (!j || j.type !== \"response_item\") continue;\n const p = j.payload as { type?: string; role?: string; content?: unknown } | undefined;\n if (!p || p.type !== \"message\") continue;\n const at = Date.parse(String(j.timestamp ?? \"\")) || Date.now();\n const text = textParts(p.content, [\"input_text\", \"output_text\"]).trim();\n if (!text) continue;\n if (p.role === \"user\") {\n if (codexInjected(text)) continue; // Codex's own injections, not the person's words\n msgs.push({ role: \"user\", text, at, line: i });\n } else if (p.role === \"assistant\") msgs.push({ role: \"assistant\", text, at, line: i });\n }\n return pairTurns(msgs, endOf(lines));\n}\n\n/** Gemini CLI chat log: {type:\"user\"|\"gemini\", content|message|text, timestamp}. */\nexport function readGemini(lines: string[], from: number): TranscriptRead {\n const msgs: Msg[] = [];\n for (let i = from; i < lines.length; i++) {\n const j = lines[i] ? parse(lines[i] as string) : null;\n if (!j) continue;\n const role = j.type === \"user\" ? \"user\" : j.type === \"gemini\" || j.type === \"model\" ? \"assistant\" : null;\n if (!role) continue;\n const raw = j.content ?? j.message ?? j.text;\n const text = (typeof raw === \"string\" ? raw : textParts(raw, [\"text\"])).trim();\n if (!text) continue;\n const at = Date.parse(String(j.timestamp ?? \"\")) || Date.now();\n msgs.push({ role, text, at, line: i });\n }\n return pairTurns(msgs, endOf(lines));\n}\n\n/** Antigravity: one step per line, type USER_INPUT | PLANNER_RESPONSE, content with <USER_REQUEST> wrapping. */\nexport function readAntigravity(lines: string[], from: number): TranscriptRead {\n const msgs: Msg[] = [];\n for (let i = from; i < lines.length; i++) {\n const j = lines[i] ? parse(lines[i] as string) : null;\n if (!j || typeof j.content !== \"string\") continue;\n const at = Date.parse(String(j.created_at ?? j.timestamp ?? \"\")) || Date.now();\n if (j.type === \"USER_INPUT\") {\n const m = /<USER_REQUEST>([\\s\\S]*?)(?:<\\/USER_REQUEST>|$)/.exec(j.content);\n const text = (m ? (m[1] as string) : j.content).trim();\n if (text) msgs.push({ role: \"user\", text, at, line: i });\n } else if (j.type === \"PLANNER_RESPONSE\") {\n const text = j.content.trim();\n if (text) msgs.push({ role: \"assistant\", text, at, line: i });\n }\n }\n return pairTurns(msgs, endOf(lines));\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// The hooks file shape Claude Code introduced and Codex, Droid and (with\n// `version: 1`) Cursor and Copilot reuse: {\"hooks\":{\"<Event>\":[{\"matcher\"?,\n// \"hooks\":[{\"type\":\"command\",\"command\",\"timeout\"}]}]}}. Ours is one entry per\n// event; a re-install replaces a stale entry of ours (an old node path) and never\n// touches anyone else's.\n//\n// Two rules from issue #8: a file that is not plain JSON (a comment, a trailing\n// comma, a write in progress) is never written back \u2014 the harness is skipped and\n// the report says why; and a file is written back in its own shape (indent, final\n// newline, a byte-order mark) so uninstall leaves it byte-identical. A file that did not exist before\n// install is reported `created`, and uninstall deletes it once it is empty again.\nimport { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { HookCommand, InstallReport } from \"./types.js\";\n\nexport interface ClaudeShapedOptions {\n /** Which events take a `matcher` (tool and permission events). */\n matcherFor: (event: string) => string | undefined;\n /** Seconds (milliseconds for Gemini CLI). */\n timeout: number;\n /** A longer timeout for one event (Claude Code's PermissionRequest, which may wait\n * for a verified control answer: spec/CONTROL.md \u00A76). */\n timeoutFor?: (event: string) => number | undefined;\n /** Extra top-level keys the file must carry (Cursor/Copilot: version: 1). */\n top?: Record<string, unknown>;\n}\n\n/** A command of ours: a path that contains \"sessionpipe\" and ends in hook.js (or in\n * sessionpipe-hook, the launcher that outlives a node upgrade), then a harness and an event. */\nexport const OURS = /(?:sessionpipe[^\"\\n]*[\\\\/]hook\\.js|[\\\\/]sessionpipe-hook)\"?\\s+[a-z][a-z-]*\\s+[A-Za-z]+\\s*$/;\nexport const isOurs = (h: { hooks?: { command?: string }[] }): boolean =>\n Array.isArray(h?.hooks) && h.hooks.some((x) => typeof x.command === \"string\" && OURS.test(x.command));\n\nexport type JsonFile =\n | {\n ok: true;\n existed: true;\n value: Record<string, unknown>;\n raw: string;\n indent: string;\n eol: string;\n finalNewline: boolean;\n bom: boolean;\n }\n | {\n ok: true;\n existed: false;\n value: Record<string, unknown>;\n raw: \"\";\n indent: \" \";\n eol: \"\\n\";\n finalNewline: true;\n bom: false;\n }\n | { ok: false; existed: true; reason: string };\n\n/** Read a JSON config file with its shape. Never guesses: a parse failure is a\n * refusal to touch the file, not an empty object. */\nexport function readJsonFile(file: string): JsonFile {\n let raw: string;\n try {\n raw = readFileSync(file, \"utf8\");\n } catch {\n return { ok: true, existed: false, value: {}, raw: \"\", indent: \" \", eol: \"\\n\", finalNewline: true, bom: false };\n }\n // A UTF-8 byte-order mark (PowerShell 5's UTF8 encoding, older Windows editors): JSON.parse\n // refuses it, the harnesses read past it. Kept, and written back, like the line ends.\n const bom = raw.charCodeAt(0) === 0xfeff;\n if (bom) raw = raw.slice(1);\n let value: unknown;\n try {\n value = JSON.parse(raw);\n } catch {\n const hint = /^\\s*\\/\\/|\\/\\*/m.test(raw) ? \"not plain JSON (it has comments)\" : \"not plain JSON\";\n return { ok: false, existed: true, reason: hint };\n }\n if (!value || typeof value !== \"object\" || Array.isArray(value))\n return { ok: false, existed: true, reason: \"not a JSON object\" };\n const eol = raw.includes(\"\\r\\n\") ? \"\\r\\n\" : \"\\n\";\n const m = /^( +|\\t+)\\S/m.exec(raw);\n const indent = m?.[1] ?? \" \";\n return {\n ok: true,\n existed: true,\n value: value as Record<string, unknown>,\n raw,\n indent,\n eol,\n finalNewline: /\\r?\\n$/.test(raw),\n bom,\n };\n}\n\n/** Serialise in the file's own shape. */\nexport function formatJson(\n value: unknown,\n f: { indent: string; eol: string; finalNewline: boolean; bom?: boolean },\n): string {\n const text = JSON.stringify(value, null, f.indent).replace(/\\n/g, f.eol);\n return (f.bom ? \"\\uFEFF\" : \"\") + (f.finalNewline ? text + f.eol : text);\n}\n\n/** Back-compat helper for callers that only read. */\nexport function readJson(file: string): Record<string, unknown> {\n const f = readJsonFile(file);\n return f.ok ? f.value : {};\n}\n\n/** The report for a config file the system would not let us change, with the error's\n * code, so `install` and `uninstall` go on to the next file instead of ending on this\n * one. Node opens a file for truncation before it writes, so an error from the open\n * (EACCES; EPERM, which Windows gives a read-only file; EROFS) or from making its\n * folder left the file as it was, and so does a delete refused; the note says so. Only\n * an error from the write itself (ENOSPC, EIO) can have left the file cut short, and\n * that note says to check it instead. */\nfunction refused(\n file: string,\n e: unknown,\n what: \"write\" | \"remove\",\n existed: boolean,\n): InstallReport & { note: string } {\n const { code, syscall } = e as NodeJS.ErrnoException;\n const why = `can't ${what} it (${code ?? String(e)})`;\n if (what === \"remove\" || syscall === \"open\" || syscall === \"mkdir\")\n return { file, changed: false, skipped: true, note: `${why}; not touched` };\n return {\n file,\n changed: true,\n skipped: true,\n ...(existed ? {} : { created: true }),\n note: `${why} part way; check the file before the harness reads it`,\n };\n}\n\n/** Write a config file back, its folder made first. Null once written; otherwise the\n * report for the refusal (see `refused`), which the caller returns in place of its own.\n * `existed` is whether the file was there before: a file cut short is still one\n * sessionpipe made, and the config remembers it as `created`. */\nexport function writeBack(file: string, text: string, existed = true): InstallReport | null {\n try {\n mkdirSync(path.dirname(file), { recursive: true });\n writeFileSync(file, text);\n return null;\n } catch (e) {\n return refused(file, e, \"write\", existed);\n }\n}\n\n/** Remove a config file sessionpipe created and uninstall has emptied. A delete needs\n * the folder's leave where a write needs only the file's, so a delete refused (a\n * ~/.claude owned by root, a folder ACL on Windows) writes the file back empty instead:\n * our hooks come out either way, and the note says what stayed. */\nexport function removeEmptied(file: string, empty: string): InstallReport {\n try {\n unlinkSync(file);\n return { file, changed: true, note: \"removed (sessionpipe created it)\" };\n } catch (e) {\n const bad = refused(file, e, \"remove\", true);\n return (\n writeBack(file, empty) ?? {\n file,\n changed: true,\n note: `emptied; ${bad.note.replace(/; not touched$/, \"\")}, so the empty file stays`,\n }\n );\n }\n}\n\nfunction entryFor(event: string, harness: string, cmd: HookCommand, o: ClaudeShapedOptions) {\n const matcher = o.matcherFor(event);\n return {\n ...(matcher !== undefined ? { matcher } : {}),\n hooks: [{ type: \"command\", command: cmd([harness, event]).command, timeout: o.timeoutFor?.(event) ?? o.timeout }],\n };\n}\n\nexport function installClaudeShaped(\n file: string,\n harness: string,\n events: readonly string[],\n cmd: HookCommand,\n o: ClaudeShapedOptions,\n): InstallReport {\n const f = readJsonFile(file);\n if (!f.ok) return { file, changed: false, skipped: true, note: `${f.reason}; not touched` };\n const settings = f.value;\n const hooks = (settings.hooks && typeof settings.hooks === \"object\" ? settings.hooks : {}) as Record<\n string,\n unknown[]\n >;\n let changed = false;\n const want = new Set(events);\n // Events we no longer hook (a lean install) lose their entry of ours.\n for (const ev of Object.keys(hooks)) {\n if (want.has(ev)) continue;\n const list = Array.isArray(hooks[ev]) ? hooks[ev] : [];\n const kept = list.filter((h) => !isOurs(h as never));\n if (kept.length !== list.length) {\n changed = true;\n if (kept.length) hooks[ev] = kept;\n else delete hooks[ev];\n }\n }\n for (const ev of events) {\n const list = Array.isArray(hooks[ev]) ? hooks[ev] : [];\n const entry = entryFor(ev, harness, cmd, o);\n const mine = list.filter((h) => isOurs(h as never));\n if (mine.length === 1 && JSON.stringify(mine[0]) === JSON.stringify(entry)) continue;\n hooks[ev] = list.filter((h) => !isOurs(h as never)).concat([entry]);\n changed = true;\n }\n if (o.top)\n for (const [k, v] of Object.entries(o.top))\n if (settings[k] !== v) {\n settings[k] = v;\n changed = true;\n }\n if (changed) {\n settings.hooks = hooks;\n const bad = writeBack(file, formatJson(settings, f), f.existed);\n if (bad) return bad;\n }\n return { file, changed, created: !f.existed && changed };\n}\n\nexport function uninstallClaudeShaped(\n file: string,\n events: readonly string[],\n opts: { created?: boolean | undefined } = {},\n): InstallReport {\n if (!existsSync(file)) return { file, changed: false };\n const f = readJsonFile(file);\n if (!f.ok) return { file, changed: false, skipped: true, note: `${f.reason}; not touched` };\n const settings = f.value;\n const hooks = settings.hooks as Record<string, unknown[]> | undefined;\n if (!hooks || typeof hooks !== \"object\") return { file, changed: false };\n let changed = false;\n for (const ev of [...events, ...Object.keys(hooks)]) {\n const list = Array.isArray(hooks[ev]) ? hooks[ev] : [];\n const kept = list.filter((h) => !isOurs(h as never));\n if (kept.length !== list.length) {\n changed = true;\n if (kept.length) hooks[ev] = kept;\n else delete hooks[ev];\n }\n }\n if (!changed) return { file, changed: false };\n if (!Object.keys(hooks).length) delete settings.hooks;\n if (opts.created && !Object.keys(settings).length) return removeEmptied(file, formatJson(settings, f));\n return writeBack(file, formatJson(settings, f)) ?? { file, changed: true };\n}\n\nexport function installedClaudeShaped(\n file: string,\n harness: string,\n events: readonly string[],\n cmd: HookCommand,\n o: ClaudeShapedOptions,\n): \"current\" | \"stale\" | \"missing\" {\n const f = readJsonFile(file);\n const hooks = (f.ok ? (f.value.hooks ?? {}) : {}) as Record<string, unknown[]>;\n let present = 0;\n let current = 0;\n for (const ev of events) {\n const list = Array.isArray(hooks[ev]) ? hooks[ev] : [];\n const mine = list.filter((h) => isOurs(h as never));\n if (mine.length) present++;\n if (mine.length === 1 && JSON.stringify(mine[0]) === JSON.stringify(entryFor(ev, harness, cmd, o))) current++;\n }\n // An entry of ours on an event outside the wanted set (a lean install after a full one) is stale.\n for (const ev of Object.keys(hooks))\n if (!events.includes(ev) && (Array.isArray(hooks[ev]) ? hooks[ev] : []).some((h) => isOurs(h as never)))\n return \"stale\";\n if (!present) return \"missing\";\n return current === events.length ? \"current\" : \"stale\";\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// Any agent that speaks the Agent Client Protocol (agentclientprotocol.com) \u2014 control\n// delivery (spec/CONTROL.md \u00A76, ADAPTERS.md \"Agents driven through ACP\"). One client\n// for all of them: the daemon runs the agent's own CLI as a child, speaks JSON-RPC 2.0\n// over its stdin and stdout (`initialize`, `session/new` or `session/load`,\n// `session/prompt`, `session/cancel`), reads the reply from its `agent_message_chunk`\n// updates, and answers its `session/request_permission` from the machine's mode. The\n// agent names its own session, so the daemon keeps the start's id as its name\n// (CONTROL.md \u00A76 `start`), and keeps the process for the next message (`api` mode).\n// Which agents, and how each is launched, is the ACP registry's word\n// (github.com/agentclientprotocol/registry, 2026-10-22); only one already installed\n// here is ever run. Shapes measured against codex-acp 2.2.2 on 2026-10-22.\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { CANCELLED_NOTE, deniedNote, findBinary, JOB_TIMEOUT_MS, type Mode, shimNote, spawnable } from \"./headless.js\";\n\n// What a cancelled turn's reply ends with, for the daemon's other way of stopping one.\nexport { CANCELLED_NOTE };\n\nexport interface AcpAgent {\n /** sessionpipe's harness name (ADAPTERS.md): the registry's id unless a hook adapter already named it. */\n harness: string;\n /** The registry's id. */\n registry: string;\n label: string;\n /** The CLI's name on PATH. */\n bin: string;\n args: string[];\n}\n\n/** The agents the daemon can drive, with the launch line the registry publishes. */\nexport const ACP_AGENTS: readonly AcpAgent[] = [\n { harness: \"gemini-cli\", registry: \"gemini\", label: \"Gemini CLI\", bin: \"gemini\", args: [\"--acp\"] },\n { harness: \"devin\", registry: \"devin\", label: \"Devin\", bin: \"devin\", args: [\"acp\"] },\n { harness: \"opencode\", registry: \"opencode\", label: \"OpenCode\", bin: \"opencode\", args: [\"acp\"] },\n { harness: \"cursor\", registry: \"cursor\", label: \"Cursor\", bin: \"cursor-agent\", args: [\"acp\"] },\n { harness: \"copilot-cli\", registry: \"github-copilot-cli\", label: \"Copilot CLI\", bin: \"copilot\", args: [\"--acp\"] },\n {\n harness: \"droid\",\n registry: \"factory-droid\",\n label: \"Droid\",\n bin: \"droid\",\n args: [\"exec\", \"--output-format\", \"acp-daemon\"],\n },\n { harness: \"goose\", registry: \"goose\", label: \"goose\", bin: \"goose\", args: [\"acp\"] },\n { harness: \"kilo\", registry: \"kilo\", label: \"Kilo\", bin: \"kilo\", args: [\"acp\"] },\n {\n harness: \"qwen-code\",\n registry: \"qwen-code\",\n label: \"Qwen Code\",\n bin: \"qwen\",\n args: [\"--acp\", \"--experimental-skills\"],\n },\n { harness: \"cline\", registry: \"cline\", label: \"Cline\", bin: \"cline\", args: [\"--acp\"] },\n { harness: \"auggie\", registry: \"auggie\", label: \"Auggie\", bin: \"auggie\", args: [\"--acp\"] },\n { harness: \"kimi\", registry: \"kimi\", label: \"Kimi CLI\", bin: \"kimi\", args: [\"acp\"] },\n { harness: \"amp\", registry: \"amp-acp\", label: \"Amp\", bin: \"amp-acp\", args: [] },\n { harness: \"mistral-vibe\", registry: \"mistral-vibe\", label: \"Mistral Vibe\", bin: \"vibe-acp\", args: [] },\n { harness: \"bob\", registry: \"bob\", label: \"Bob\", bin: \"bob\", args: [\"acp\"] },\n { harness: \"grok-build\", registry: \"grok-build\", label: \"Grok Build\", bin: \"grok\", args: [\"agent\", \"stdio\"] },\n { harness: \"qoder\", registry: \"qoder\", label: \"Qoder CLI\", bin: \"qodercli\", args: [\"--acp\"] },\n { harness: \"minimax-code\", registry: \"minimax-code\", label: \"MiniMax Code\", bin: \"mcode\", args: [\"acp\"] },\n { harness: \"codebuddy-code\", registry: \"codebuddy-code\", label: \"Codebuddy Code\", bin: \"codebuddy\", args: [\"--acp\"] },\n { harness: \"nova\", registry: \"nova\", label: \"Nova\", bin: \"nova\", args: [\"acp\"] },\n { harness: \"dimcode\", registry: \"dimcode\", label: \"DimCode\", bin: \"dim\", args: [\"acp\"] },\n { harness: \"dirac\", registry: \"dirac\", label: \"Dirac\", bin: \"dirac\", args: [\"--acp\"] },\n { harness: \"harn\", registry: \"harn\", label: \"Harn\", bin: \"harn\", args: [\"serve\", \"acp\"] },\n { harness: \"vtcode\", registry: \"vtcode\", label: \"VT Code\", bin: \"vtcode\", args: [\"acp\"] },\n { harness: \"stakpak\", registry: \"stakpak\", label: \"Stakpak\", bin: \"stakpak\", args: [\"acp\"] },\n { harness: \"crow-cli\", registry: \"crow-cli\", label: \"crow-cli\", bin: \"crow-cli\", args: [\"acp\"] },\n { harness: \"corust-agent\", registry: \"corust-agent\", label: \"Corust Agent\", bin: \"corust-agent-acp\", args: [] },\n { harness: \"cortex-code\", registry: \"cortex-code\", label: \"Cortex Code\", bin: \"cortex\", args: [\"acp\", \"serve\"] },\n { harness: \"kimchi\", registry: \"kimchi\", label: \"Kimchi\", bin: \"kimchi\", args: [\"--mode\", \"acp\"] },\n];\n\nexport const ACP_HARNESSES: readonly string[] = ACP_AGENTS.map((a) => a.harness);\n\nexport const acpAgent = (harness: string): AcpAgent | undefined => ACP_AGENTS.find((a) => a.harness === harness);\n\n/** The env var that names an agent's CLI by hand: `SESSIONPIPE_ACP_GEMINI_CLI`. */\nexport const acpOverride = (harness: string): string => `SESSIONPIPE_ACP_${harness.toUpperCase().replace(/-/g, \"_\")}`;\n\n/** An agent's CLI on this machine: the override, else on PATH, else beside the node\n * running this (an `npm install -g` there) or where the installers put it. */\nexport function findAcpAgent(\n harness: string,\n env: NodeJS.ProcessEnv = process.env,\n home = os.homedir(),\n nodeDir = path.dirname(process.execPath),\n): { bin: string; args: string[] } | null {\n const a = acpAgent(harness);\n if (!a) return null;\n const bin = findBinary({\n override: env[acpOverride(harness)],\n names: process.platform === \"win32\" ? [`${a.bin}.exe`, `${a.bin}.cmd`] : [a.bin],\n env,\n dirs: [\n nodeDir,\n path.join(home, \".local\", \"bin\"),\n path.join(home, \".cargo\", \"bin\"),\n \"/opt/homebrew/bin\",\n \"/usr/local/bin\",\n ],\n });\n return bin ? { bin, args: a.args } : null;\n}\n\n/** The ACP agents installed here, by harness name, for the daemon's hello. */\nexport function acpHarnesses(env: NodeJS.ProcessEnv = process.env): string[] {\n return ACP_HARNESSES.filter((h) => findAcpAgent(h, env));\n}\n\ntype Json = Record<string, unknown>;\nconst obj = (v: unknown): Json | null => (v && typeof v === \"object\" && !Array.isArray(v) ? (v as Json) : null);\nconst str = (v: unknown): string => (typeof v === \"string\" ? v : \"\");\n\ninterface Option {\n optionId: string;\n kind: string;\n}\n\n/** Which permission option the machine's mode picks, or null for `cancelled`: safe\n * refuses (once, else always), auto allows (once, else always). Inherit refuses as safe\n * does: the agent asked because its own settings want a person, and none is there.\n * Never the other way. */\nexport function permissionChoice(options: unknown, mode: Mode): Option | null {\n const list = (Array.isArray(options) ? options : [])\n .map(obj)\n .filter((o): o is Json => !!o && !!str(o.optionId))\n .map((o) => ({ optionId: str(o.optionId), kind: str(o.kind) }));\n const want = mode === \"auto\" ? [\"allow_once\", \"allow_always\"] : [\"reject_once\", \"reject_always\"];\n for (const k of want) {\n const hit = list.find((o) => o.kind === k);\n if (hit) return hit;\n }\n return null;\n}\n\n/** A JSON-RPC error in words: its message, and its `data` where that says more (goose\n * 1.55 answers session/new with \"Internal error\" and the reason in `data`). */\nexport function errorWords(err: Json): string {\n const message = str(err.message);\n const data = str(err.data) || str(obj(err.data)?.message);\n return data && data !== message ? (message ? `${message}: ${data}` : data) : message;\n}\n\n/** What a request to run something was called, for the reply's list of refusals. */\nfunction toolName(call: Json | null, titles: Map<string, string>): string | null {\n if (!call) return null;\n const t = str(call.title) || titles.get(str(call.toolCallId)) || str(call.name) || str(call.toolCallId);\n return t ? t.slice(0, 80) : null;\n}\n\n/** A session the daemon holds (the shape of daemon.ts's SdkSession, plus the agent's own id). */\nexport interface AcpHeld {\n /** Deliver one message; resolves with the agent's reply when the turn ends. */\n send(text: string): Promise<{ reply: string; error?: string }>;\n interrupt(): Promise<void>;\n close(): void;\n readonly busy: boolean;\n readonly lastUsed: number;\n readonly mode: \"api\";\n /** The id the agent gave the session. */\n readonly session: string;\n /** The process is gone or was closed: nothing more can be sent. */\n readonly closed: boolean;\n}\n\nexport interface AcpOptions {\n bin: string;\n args: string[];\n cwd: string;\n mode: Mode;\n label: string;\n env?: NodeJS.ProcessEnv;\n /** Reopen this session of the agent's (`session/load`) instead of starting a new one. */\n load?: string;\n /** The reply so far, each time it grows. */\n onText?: (text: string) => void;\n log?: (line: string) => void;\n now?: () => number;\n /** A turn still running after this is cancelled, then stopped. */\n timeoutMs?: number;\n /** How long the agent may take to answer `initialize` and open the session. */\n openTimeoutMs?: number;\n /** On close, how long the agent gets to leave by itself before SIGTERM (then SIGKILL). */\n closeGraceMs?: number;\n}\n\nexport type AcpStart = { held: AcpHeld } | { failed: string } | { unsupported: string };\n\nconst CLIENT_INFO = { name: \"sessionpipe\", title: \"sessionpipe control\", version: \"1\" };\n\n/** Run an ACP agent and open a session in it. Resolves once the agent has answered\n * `session/new` (or `session/load`); every later turn goes through `held.send`. */\nexport function startAcp(o: AcpOptions): Promise<AcpStart> {\n const now = o.now ?? Date.now;\n const log = o.log ?? (() => {});\n const label = o.label;\n let child: ChildProcess;\n const c = spawnable(o.bin, o.args);\n if (!c) return Promise.resolve({ failed: `couldn't start ${label}: ${shimNote(o.bin)}` });\n try {\n child = spawn(c.file, c.args, {\n cwd: o.cwd,\n // The caller's env as given (the daemon's is jobEnv's already, with the ask's\n // lineage on top), marked as a control job.\n env: { ...o.env, SESSIONPIPE_CONTROL_JOB: \"1\" },\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n detached: process.platform !== \"win32\",\n windowsHide: true,\n });\n } catch (e) {\n return Promise.resolve({ failed: `couldn't start ${label}: ${(e as Error).message}` });\n }\n const kill = (sig: NodeJS.Signals) => {\n try {\n if (process.platform !== \"win32\" && child.pid) process.kill(-child.pid, sig);\n else child.kill(sig);\n } catch {}\n };\n\n let gone: string | null = null; // why the process is no longer there\n let errTail = \"\";\n let nextId = 1;\n const pending = new Map<number, { resolve: (r: unknown) => void; reject: (e: Error) => void }>();\n const write = (m: Json) => {\n if (gone) return;\n try {\n child.stdin?.write(`${JSON.stringify(m)}\\n`);\n } catch {}\n };\n const request = (method: string, params: Json, timeoutMs: number): Promise<unknown> =>\n new Promise((resolve, reject) => {\n if (gone) return reject(new Error(gone));\n const id = nextId++;\n const t = setTimeout(() => {\n pending.delete(id);\n reject(new Error(`${label} didn't answer ${method} in ${Math.round(timeoutMs / 1000)} s`));\n }, timeoutMs);\n t.unref();\n pending.set(id, {\n resolve: (r) => {\n clearTimeout(t);\n resolve(r);\n },\n reject: (e) => {\n clearTimeout(t);\n reject(e);\n },\n });\n write({ jsonrpc: \"2.0\", id, method, params });\n });\n const notify = (method: string, params: Json) => write({ jsonrpc: \"2.0\", method, params });\n\n // The turn in flight: its reply as it grows, and what it was refused.\n // `message`: the id of the chunk before, null for one that had none, undefined before any.\n let turn: { text: string; message?: string | null; denied: string[]; count: number } | null = null;\n const titles = new Map<string, string>();\n const onUpdate = (u: Json | null) => {\n if (!u) return;\n const kind = str(u.sessionUpdate);\n if (kind === \"tool_call\" && str(u.toolCallId) && str(u.title)) {\n if (titles.size >= 200) titles.clear();\n titles.set(str(u.toolCallId), str(u.title));\n return;\n }\n if (kind !== \"agent_message_chunk\" || !turn) return;\n const c = obj(u.content);\n if (c?.type !== \"text\" || !str(c.text)) return;\n // A new message after a tool step starts a new paragraph.\n const mid = str(u.messageId) || null;\n if (turn.message !== undefined && mid !== turn.message && turn.text.trim())\n turn.text = `${turn.text.trimEnd()}\\n\\n`;\n turn.message = mid;\n turn.text += str(c.text);\n o.onText?.(turn.text);\n };\n const onRequest = (id: unknown, method: string, params: Json | null) => {\n if (method !== \"session/request_permission\") {\n write({ jsonrpc: \"2.0\", id: id as string, error: { code: -32601, message: `Method not found: ${method}` } });\n return;\n }\n const pick = permissionChoice(params?.options, o.mode);\n if (!pick?.kind.startsWith(\"allow\")) {\n const name = toolName(obj(params?.toolCall), titles);\n if (turn) {\n turn.count++;\n if (name && !turn.denied.includes(name) && turn.denied.length < 20) turn.denied.push(name);\n }\n }\n write({\n jsonrpc: \"2.0\",\n id: id as string,\n result: { outcome: pick ? { outcome: \"selected\", optionId: pick.optionId } : { outcome: \"cancelled\" } },\n });\n };\n const onLine = (line: string) => {\n let m: Json | null;\n try {\n m = obj(JSON.parse(line));\n } catch {\n return;\n }\n if (!m) return;\n const method = str(m.method);\n if (method) {\n if (m.id !== undefined) onRequest(m.id, method, obj(m.params));\n else if (method === \"session/update\") onUpdate(obj(obj(m.params)?.update));\n return;\n }\n const p = typeof m.id === \"number\" ? pending.get(m.id) : undefined;\n if (!p) return;\n pending.delete(m.id as number);\n const err = obj(m.error);\n if (err) p.reject(new Error(errorWords(err) || `${label} returned error ${String(err.code ?? \"?\")}`));\n else p.resolve(m.result);\n };\n let partial = \"\";\n child.stdout?.on(\"data\", (b: Buffer) => {\n const lines = (partial + b.toString(\"utf8\")).split(\"\\n\");\n partial = lines.pop() as string;\n for (const l of lines) if (l.trim()) onLine(l);\n if (partial.length > 4 * 1024 * 1024) partial = \"\";\n });\n child.stderr?.on(\"data\", (b: Buffer) => {\n errTail = (errTail + b.toString(\"utf8\")).slice(-4000);\n });\n const left = (why: string) => {\n if (gone) return;\n gone = why;\n for (const p of pending.values()) p.reject(new Error(why));\n pending.clear();\n };\n child.on(\"error\", (e) => left(`couldn't start ${label}: ${e.message}`));\n // An agent that has stopped reading (it closed its input, and may still be running):\n // a write to it fails on the pipe, after write() has returned. With nobody listening\n // that was an error no one caught, in the daemon, and the message waited out its whole\n // limit for an answer. Whoever is waiting hears it now, and the session reads as\n // gone, so its holder closes it and the next message opens another.\n child.stdin?.on(\"error\", (e) => left(`${label} stopped taking input: ${e.message}`));\n // The process has exited (or never was): there is nothing left to end, and the number\n // of its group is no longer certain to be its own.\n let dead = false;\n const exited = (code: number | null, signal: NodeJS.Signals | null) => {\n dead = true;\n const tail = errTail.trim().split(\"\\n\").slice(-3).join(\" \").trim();\n left(`${label} exited (${signal || `code ${code}`})${tail ? `: ${tail}` : \"\"}`);\n };\n child.on(\"exit\", exited);\n // A tool the agent left running can hold its stdout open after it exited; `close`\n // is also the end for a process that never started.\n child.on(\"close\", exited);\n\n let closed = false;\n const close = () => {\n if (closed) return;\n closed = true;\n try {\n child.stdin?.end();\n } catch {}\n // Closed after it left (a held agent that exited is closed by whoever finds it gone):\n // no signal follows it. The two timers below were armed all the same, their only\n // disarming an `exit` that had already happened, and SIGTERM and then SIGKILL went to\n // the group of a process that was gone.\n if (dead) return;\n const grace = o.closeGraceMs ?? 2000;\n const t = setTimeout(() => kill(\"SIGTERM\"), grace);\n t.unref();\n const k = setTimeout(() => kill(\"SIGKILL\"), grace * 6);\n k.unref();\n child.once(\"exit\", () => {\n clearTimeout(t);\n clearTimeout(k);\n });\n };\n\n const open = o.openTimeoutMs ?? 60_000;\n\n function held(session: string): AcpHeld {\n let busy = false;\n let lastUsed = now();\n return {\n session,\n mode: \"api\",\n get busy() {\n return busy;\n },\n get lastUsed() {\n return lastUsed;\n },\n get closed() {\n return closed || !!gone;\n },\n async send(text) {\n if (closed) return { reply: \"\", error: `${label} was closed` };\n busy = true;\n lastUsed = now();\n const t = { text: \"\", denied: [], count: 0 };\n turn = t;\n const limit = o.timeoutMs ?? JOB_TIMEOUT_MS;\n let timedOut = false;\n const timer = setTimeout(() => {\n timedOut = true;\n notify(\"session/cancel\", { sessionId: session });\n setTimeout(close, 5000).unref();\n }, limit);\n timer.unref();\n try {\n const res = obj(\n await request(\"session/prompt\", { sessionId: session, prompt: [{ type: \"text\", text }] }, limit + 10_000),\n );\n const stop = str(res?.stopReason);\n const words = t.text.trim() || `(${label} finished without a written reply.)`;\n const refused = deniedNote(t.denied, t.count);\n if (stop === \"end_turn\" || stop === \"max_tokens\") return { reply: words + refused };\n if (stop === \"refusal\") return { reply: `${words}\\n\\n(${label} refused the request.)${refused}` };\n if (stop === \"cancelled\")\n return timedOut\n ? {\n reply: \"\",\n error: `${label} was still working after ${Math.round(limit / 60_000)} minutes, so it was stopped`,\n }\n : { reply: `${words}\\n\\n${CANCELLED_NOTE}${refused}` };\n return { reply: \"\", error: `${label} ended the turn with ${stop || \"no stop reason\"}` };\n } catch (e) {\n return { reply: \"\", error: (e as Error).message };\n } finally {\n clearTimeout(timer);\n turn = null;\n busy = false;\n lastUsed = now();\n }\n },\n async interrupt() {\n notify(\"session/cancel\", { sessionId: session });\n },\n close,\n };\n }\n\n return (async (): Promise<AcpStart> => {\n let signIn = \"\";\n try {\n const init = obj(\n await request(\n \"initialize\",\n {\n protocolVersion: 1,\n clientCapabilities: { fs: { readTextFile: false, writeTextFile: false }, terminal: false },\n clientInfo: CLIENT_INFO,\n },\n open,\n ),\n );\n const caps = obj(init?.agentCapabilities);\n const info = obj(init?.agentInfo);\n log(\n `${label}: ${str(info?.name) || \"agent\"} ${str(info?.version)} (ACP ${String(init?.protocolVersion ?? \"?\")})`,\n );\n // An agent that lists ways to sign in may refuse a session until someone did, at\n // the machine's terminal: the daemon never signs in for anyone. The agent's own\n // words for the first way, when it gives any (goose: \"Run `goose configure` \u2026\").\n const methods = Array.isArray(init?.authMethods) ? init.authMethods.map(obj) : [];\n if (methods.length) {\n const how = str(methods[0]?.description) || str(methods[0]?.name);\n signIn = ` (if ${label} wants a sign-in, do it at the machine's terminal${how ? `: ${how}` : \"\"})`;\n }\n if (o.load) {\n if (!caps?.loadSession) {\n close();\n return { unsupported: `${label} can't reopen a session once it has been closed (no session/load)` };\n }\n await request(\"session/load\", { sessionId: o.load, cwd: o.cwd, mcpServers: [] }, open);\n return { held: held(o.load) };\n }\n const res = obj(await request(\"session/new\", { cwd: o.cwd, mcpServers: [] }, open));\n const session = str(res?.sessionId);\n if (!session) throw new Error(`${label} opened a session without naming it`);\n return { held: held(session) };\n } catch (e) {\n close();\n return { failed: `${(e as Error).message}${signIn}` };\n }\n })();\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// One headless agent turn as a child process (spec/CONTROL.md \u00A76): the spawner the\n// control daemon runs every harness through, and the shape each harness's reading of\n// its own output takes. Which binary, which flags and how the answer is read are the\n// harness's own (`<harness>-control.ts`); what is the same for all of them is here.\nimport { spawn } from \"node:child_process\";\nimport { accessSync, constants, readFileSync, statSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { withoutLineage } from \"../launched-by.js\";\n\n/** A headless turn still running after this is stopped. */\nexport const JOB_TIMEOUT_MS = 30 * 60_000;\nconst OUT_CAP = 1024 * 1024;\n\n/** How a turn the daemon runs may act (spec/CONTROL.md \u00A72), chosen at the machine's own\n * terminal: safe, the harness's auto mode, or inherit (no permission flag, so the\n * harness starts in its own default on this machine). */\nexport type Mode = \"safe\" | \"auto\" | \"inherit\";\n\nexport function isExe(p: string): boolean {\n try {\n if (!statSync(p).isFile()) return false;\n accessSync(p, constants.X_OK);\n return true;\n } catch {\n return false;\n }\n}\n\n/** A harness's CLI: the override the person set (`SESSIONPIPE_<NAME>`), else the first\n * of `names` on PATH, else the first of `dirs` that holds one. A launchd or systemd\n * service starts with a short PATH, so the installers' own folders are looked in too. */\nexport function findBinary(o: {\n override?: string | undefined;\n names: string[];\n dirs: string[];\n env?: NodeJS.ProcessEnv;\n}): string | null {\n if (o.override && isExe(o.override)) return o.override;\n for (const d of String(o.env?.PATH || \"\").split(path.delimiter)) {\n if (!d || !path.isAbsolute(d)) continue;\n for (const n of o.names) if (isExe(path.join(d, n))) return path.join(d, n);\n }\n for (const d of o.dirs) for (const n of o.names) if (isExe(path.join(d, n))) return path.join(d, n);\n return null;\n}\n\n/** The script an npm-style `.cmd` shim runs: the one `\"%dp0%\\\\\u2026\"` or `\"%~dp0\\\\\u2026\"` word\n * before `%*` (npm's cmd-shim, old and new; pnpm's is the same shape), beside the shim.\n * Null when the file is no such shim, or names nothing that is there. */\nexport function shimTarget(shim: string): string | null {\n let text = \"\";\n try {\n text = readFileSync(shim, \"utf8\");\n } catch {\n return null;\n }\n const m = /\"%(?:~dp0|dp0%)\\\\([^\"]+)\"\\s+%\\*/.exec(text);\n if (!m) return null;\n const target = path.resolve(path.dirname(shim), (m[1] as string).split(\"\\\\\").join(path.sep));\n try {\n return statSync(target).isFile() ? target : null;\n } catch {\n return null;\n }\n}\n\n/** `bin` and `args` as spawn takes them with no shell. Node refuses to spawn a `.cmd` or\n * `.bat` without one (CVE-2024-27980, since 20.12), and on Windows an `npm install -g`\n * leaves exactly such a shim (`claude.cmd`, `codex.cmd`); a shell would hand a prompt's\n * every character to cmd.exe, so the shim's own script runs under this node instead.\n * Null for a launcher script that names no script to run (issue #165). */\nexport function spawnable(bin: string, args: string[]): { file: string; args: string[] } | null {\n if (!/\\.(cmd|bat)$/i.test(bin)) return { file: bin, args };\n const target = shimTarget(bin);\n return target ? { file: process.execPath, args: [target, ...args] } : null;\n}\n\n/** Why a launcher script can't be run, for the person. */\nexport const shimNote = (bin: string) =>\n `${path.basename(bin)} is a launcher script that names no program to run; point the harness's override (SESSIONPIPE_CLAUDE, SESSIONPIPE_CODEX, \u2026) at the program itself`;\n\n/** As `spawnable`, for a probe whose arguments are fixed words (`--help`, `auth status`):\n * a launcher script that can't be read runs through a shell, as one quoted command\n * (arguments beside `shell: true` are deprecated from node 24, DEP0190). */\nexport function probe(bin: string, args: string[]): { file: string; args: string[]; shell: boolean } {\n const s = spawnable(bin, args);\n return s ? { ...s, shell: false } : { file: [`\"${bin}\"`, ...args].join(\" \"), args: [], shell: true };\n}\n\n/** The env every headless turn runs with: SESSIONPIPE_CONTROL_JOB tells the turn's own\n * hooks that the daemon runs it, so its Stop hook never takes a message meant for a\n * person's session (cli/src/hook.ts); and none of the lineage this process inherited\n * (a daemon started from inside an asked session), so a child carries only what its\n * caller adds after this (CONTROL.md \u00A713). */\nexport function jobEnv(env: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv {\n return { ...withoutLineage(env), SESSIONPIPE_CONTROL_JOB: \"1\" };\n}\n\n/** Whether a harness is signed in, in its own words. `loggedIn: null` means it can't\n * say (too old, or it didn't answer): never a reason to refuse. */\nexport interface Login {\n loggedIn: boolean | null;\n /** claude.ai, an API key, a long-lived token\u2026 as the harness names it. */\n method?: string;\n subscription?: string;\n}\n\nexport interface RunResult {\n error?: string;\n code?: number | null;\n signal?: NodeJS.Signals | null;\n stdout?: string | null;\n tooBig?: boolean;\n stderr?: string;\n timedOut?: boolean;\n /** The caller stopped it (`RunOptions.signal`) before it finished. */\n stopped?: boolean;\n}\n\nexport interface RunOptions {\n cwd: string;\n env: NodeJS.ProcessEnv;\n timeoutMs?: number;\n /** The caller's way to stop the run it started (spec/CONTROL.md \u00A76 `cancel`): once\n * aborted, the child is ended the way a run past its cap is. Aborted before the run\n * began, nothing is spawned at all. */\n signal?: AbortSignal;\n /** Streaming: each stdout line as it arrives. Only the lines `keep` names are kept\n * for the RunResult (none by default), so a long stream never hits the cap. */\n onLine?: (line: string) => void;\n keep?: (line: string) => boolean;\n}\n\n/** Run one headless turn in its own process group, stdin closed (Codex waits on an open\n * one), holding at most 1 MB of stdout. The run ends by itself, at its cap, or when the\n * caller stops it: the last two the same way, SIGTERM to the child's own process group\n * (the harness and the tools it started), then SIGKILL to whatever is left \u2014 ten\n * seconds later while the child lives, or the moment the child exits, whichever comes\n * first.\n *\n * Only ever the child this call spawned, and only while that is certain. The group is\n * named by the child's pid, and once the child has exited and its group has emptied\n * the number is the kernel's to hand out again: so the last signal goes out as the\n * child exits, when the group can only be its own, and nothing is sent to that number\n * after \u2014 no timer left running, no Stop and no cap that arrives while the result waits\n * on a tool still holding stdout.\n *\n * That is all a signal to a group can do, and it is not everything: it reaches the\n * processes that are in the group as it is sent. A tool that left the group is not\n * one, and neither, on macOS at least, is one a member is forking at that instant (a\n * shell forking `sleep` as the SIGKILL landed outlived it in 7 runs of 720). Nothing\n * goes after those. The run does not wait for them either: its result is out when the\n * child's stdout closes, and two seconds after the child's exit at the latest. */\nexport function runHeadless(bin: string, args: string[], o: RunOptions): Promise<RunResult> {\n return new Promise((resolve) => {\n let out: Buffer[] = [];\n let outLen = 0;\n let tooBig = false;\n let errTail = \"\";\n let timedOut = false;\n let stopped = false;\n let settled = false;\n let child: import(\"node:child_process\").ChildProcess;\n if (o.signal?.aborted) {\n resolve({ stopped: true });\n return;\n }\n const c = spawnable(bin, args);\n if (!c) {\n resolve({ error: shimNote(bin) });\n return;\n }\n try {\n child = spawn(c.file, c.args, {\n cwd: o.cwd,\n env: o.env,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n detached: process.platform !== \"win32\",\n windowsHide: true,\n });\n } catch (e) {\n resolve({ error: (e as Error).message });\n return;\n }\n const kill = (sig: NodeJS.Signals) => {\n try {\n if (process.platform !== \"win32\" && child.pid) process.kill(-child.pid, sig);\n else child.kill(sig);\n } catch {\n try {\n child.kill(sig);\n } catch {}\n }\n };\n const keep = (line: string) => {\n if (!o.keep?.(line)) return;\n out = [Buffer.from(line)];\n outLen = line.length;\n };\n let partial = \"\";\n child.stdout?.on(\"data\", (b: Buffer) => {\n if (o.onLine) {\n const chunk = partial + b.toString(\"utf8\");\n const lines = chunk.split(\"\\n\");\n partial = lines.pop() as string;\n for (const line of lines) {\n if (!line.trim()) continue;\n try {\n o.onLine(line);\n } catch {}\n keep(line);\n }\n if (partial.length > OUT_CAP) partial = \"\";\n return;\n }\n if (tooBig) return;\n if (outLen + b.length > OUT_CAP) {\n tooBig = true;\n out = [];\n return;\n }\n out.push(b);\n outLen += b.length;\n });\n child.stderr?.on(\"data\", (b: Buffer) => {\n errTail = (errTail + b.toString(\"utf8\")).slice(-4000);\n });\n /** The SIGKILL that follows the SIGTERM, while it is still to come. */\n let ending: NodeJS.Timeout | null = null;\n /** The child has exited: its pid, and the group it named, are no longer this run's. */\n let gone = false;\n const end = () => {\n kill(\"SIGTERM\");\n // Asked to end twice (its cap, then a Stop): still one SIGKILL, ten seconds after the first.\n ending ??= setTimeout(() => {\n ending = null;\n kill(\"SIGKILL\");\n }, 10_000);\n ending.unref();\n };\n const timer = setTimeout(() => {\n if (gone) return;\n timedOut = true;\n end();\n }, o.timeoutMs ?? JOB_TIMEOUT_MS);\n const stop = () => {\n if (gone) return;\n stopped = true;\n end();\n };\n o.signal?.addEventListener(\"abort\", stop, { once: true });\n const result = (code: number | null, signal: NodeJS.Signals | null): RunResult => ({\n code,\n signal,\n stdout: tooBig ? null : Buffer.concat(out).toString(\"utf8\"),\n tooBig,\n stderr: errTail,\n timedOut,\n ...(stopped ? { stopped } : {}),\n });\n const finish = (r: RunResult) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n o.signal?.removeEventListener(\"abort\", stop);\n resolve(r);\n };\n child.on(\"error\", (e) => finish({ error: e.message }));\n child.on(\"exit\", (code, signal) => {\n // It was being ended and has gone: what it left in its group (a tool that ignores\n // SIGTERM) is ended now, once, and the ten-second timer with it.\n if (ending) {\n clearTimeout(ending);\n ending = null;\n kill(\"SIGKILL\");\n }\n gone = true;\n // A tool the agent left running can hold stdout open after the harness exits.\n setTimeout(() => finish(result(code, signal)), 2000).unref();\n });\n child.on(\"close\", (code, signal) => {\n // The last line may end without a newline: it is often the result itself.\n if (o.onLine && partial.trim()) {\n try {\n o.onLine(partial);\n } catch {}\n keep(partial);\n partial = \"\";\n }\n finish(result(code, signal));\n });\n });\n}\n\n/** A harness's output read as it streams: the session it names, the answer so far, and\n * the outcome once the process is gone. One per run. */\nexport interface Reading {\n /** One stdout line. True when the answer so far changed. */\n feed(line: string): boolean;\n /** The session id the harness revealed (it picks its own), or null so far. */\n readonly session: string | null;\n /** The answer so far, whole. */\n readonly text: string;\n /** How many lines were fed. */\n readonly lines: number;\n outcome(res: RunResult): { failed: string } | { reply: string };\n}\n\n/** The last few lines a harness wrote to stderr, on one line. */\nexport function stderrTail(stderr: string | undefined, n = 3): string {\n return String(stderr || \"\")\n .trim()\n .split(\"\\n\")\n .slice(-n)\n .join(\" \")\n .trim();\n}\n\n/** Said at the end of what a turn had written when it was stopped on the person's\n * request (spec/CONTROL.md \u00A76 `cancel`): the same words whichever way it was stopped, an\n * ACP agent's `session/cancel` or the end of a headless run's own process. */\nexport const CANCELLED_NOTE = \"(The turn was cancelled.)\";\n\n/** What a run that wasn't there to ask says about the actions it was refused. */\nexport function deniedNote(names: string[], count: number): string {\n if (!count) return \"\";\n return `\\n\\n(Not allowed on this machine, since nobody was there to approve: ${names.join(\", \") || `${count} action(s)`}.)`;\n}\n\n/** A process that failed before or without its answer, in words. */\nexport function runFailure(label: string, res: RunResult): string | null {\n if (res.error) return `couldn't start ${label}: ${res.error}`;\n if (res.timedOut) return `${label} was still working after 30 minutes, so it was stopped`;\n return null;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// The two session fields every harness shares and no hook payload carries: who started\n// this session on purpose, and which session it answers. Both come from the environment\n// the session was started in, and the hook carries them along (PROTOCOL.md \u00A73).\nimport type { Adapter, HookInput, HookResult } from \"./adapters/types.js\";\n\n/** PROTOCOL.md \u00A73 `launched_by`: a launcher that starts a session for another one (a\n * script running `claude -p`) names itself here as `<harness>:<id>`, and the hook\n * carries it along. */\nexport const LAUNCHED_BY_ENV = \"SESSIONPIPE_LAUNCHED_BY\";\n/** PROTOCOL.md \u00A73 `delegated_by`: the control daemon that starts or resumes a session\n * for another session's ask (CONTROL.md \u00A713) or a handoff (\u00A76) names that session\n * here, and the child's hooks stamp it on every event. */\nexport const DELEGATED_BY_ENV = \"SESSIONPIPE_ASKED_BY\";\n/** CONTROL.md \u00A713: the asks a session is nested in, comma-joined, read by the next ask. */\nexport const ASK_CHAIN_ENV = \"SESSIONPIPE_ASK_CHAIN\";\n/** The three lineage variables. They are inherited like any environment, so anything\n * that starts a further session resets them (PROTOCOL.md \u00A73, CONTROL.md \u00A713); the\n * daemon most of all, which starts sessions for receivers and askers alike and must\n * not stamp its own shell's lineage on them. */\nexport const LINEAGE_ENV = [LAUNCHED_BY_ENV, DELEGATED_BY_ENV, ASK_CHAIN_ENV] as const;\nconst SESSION_REF = /^[a-z][a-z0-9-]{0,39}:[A-Za-z0-9._:-]{1,128}$/;\n\n/** `env` without the lineage variables: what a child that is nobody's gets. */\nexport function withoutLineage(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n const e = { ...env };\n for (const k of LINEAGE_ENV) delete e[k];\n return e;\n}\n\n/** The `<harness>:<id>` a variable names, or nothing when it is absent or malformed. */\nfunction refIn(env: Record<string, string | undefined>, name: string): string | undefined {\n const v = env[name]?.trim();\n return v && SESSION_REF.test(v) ? v : undefined;\n}\n\n/** The launcher the environment names, or nothing when it is absent or malformed. */\nexport function launchedBy(env: Record<string, string | undefined>): string | undefined {\n return refIn(env, LAUNCHED_BY_ENV);\n}\n\n/** The session this one was started or resumed for, or nothing when the environment\n * doesn't say or says it badly. */\nexport function delegatedBy(env: Record<string, string | undefined>): string | undefined {\n return refIn(env, DELEGATED_BY_ENV);\n}\n\n/** An adapter's reading of a hook, plus what every harness shares: the launcher and the\n * asker, unless the harness gave the session a parent of its own (a subagent's lineage\n * is its parent, which carries both) or the value names the session itself (a\n * launcher that forgot to reset it). */\nexport function readHook(adapter: Adapter, input: HookInput): HookResult | null {\n const r = adapter.fromHook(input);\n if (r && !r.session.parent_id) {\n const self = `${adapter.name}:${r.session.id}`;\n const launcher = launchedBy(input.env);\n if (launcher && launcher !== self) r.session.launched_by = launcher;\n const asker = delegatedBy(input.env);\n if (asker && asker !== self) r.session.delegated_by = asker;\n }\n return r;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// Antigravity (Google) \u2014 docs: https://antigravity.google/docs/hooks\n// Config: ~/.gemini/config/hooks.json \u2014 top-level keys are hook NAMES, ours is\n// \"sessionpipe\". stdin is camelCase with NO event name (it rides in argv). A hook's\n// stdout is its answer; non-JSON is a deny. Timeouts in seconds. No session end\n// exists. Ported from spacesheep-cli lib/sessions.js (facts, remote url, projects).\n//\n// No PreToolUse. Its answer must carry a `decision` (allow / deny / ask / force_ask),\n// none of which means \"carry on\": `{}` is read as a deny with no reason, which blocked\n// every tool call on every machine 0.1\u20130.6.0 was installed on (2026-10-04, Antigravity\n// 2.19.1), and `allow` would wave calls past the person's own review settings. So the\n// tool events come from PostToolUse alone, which carries no tool name (only `stepIdx`\n// and `error`): it is a \"still working\" beat.\nimport { existsSync, readdirSync, readFileSync, realpathSync, statSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { homeDir } from \"../paths.js\";\nimport { ends, parseLines } from \"../readers/files.js\";\nimport { readAntigravity } from \"../readers/transcripts.js\";\nimport { formatJson, readJsonFile, removeEmptied, writeBack } from \"./claude-shaped.js\";\nimport type {\n Adapter,\n BackfillRow,\n HookCommand,\n HookInput,\n HookResult,\n InstallOptions,\n InstallReport,\n SessionFacts,\n} from \"./types.js\";\n\nconst NAME = \"antigravity\";\nconst HOOK_NAME = \"sessionpipe\";\nexport const AG_EVENTS = [\"PreInvocation\", \"PostInvocation\", \"PostToolUse\", \"Stop\"] as const;\n/** What a PreToolUse entry an older install left behind gets, until a restarted\n * conversation reads the rewritten hooks.json: the person's own prompt, with why. The\n * hook (cli/src/hook.ts) and the launcher (cli/src/launcher.ts) print the same line. */\nexport const AG_STALE_PRETOOL =\n '{\"decision\":\"ask\",\"reason\":\"sessionpipe: an outdated PreToolUse hook is still loaded. Restart this conversation (or run sessionpipe install) to drop it.\"}\\n';\n/** Antigravity's answer for one event: `{}` is \"carry on\" for every event we register. */\nexport const antigravityAnswer = (event: string): string => (event === \"PreToolUse\" ? AG_STALE_PRETOOL : \"{}\\n\");\nconst gemini = (env: NodeJS.ProcessEnv) => env.GEMINI_CLI_HOME || path.join(homeDir(), \".gemini\");\nconst hooksFile = (env: NodeJS.ProcessEnv) => path.join(gemini(env), \"config\", \"hooks.json\");\nconst projectsDir = (env: NodeJS.ProcessEnv) => path.join(gemini(env), \"config\", \"projects\");\nconst dataDirs = (env: NodeJS.ProcessEnv) =>\n [\"antigravity\", \"antigravity-cli\", \"antigravity-ide\"].map((d) => path.join(gemini(env), d));\nconst ID_RE = /^[A-Za-z0-9_-]{1,128}$/;\nconst validTool = (n: unknown): n is string => typeof n === \"string\" && /^[A-Za-z0-9_.:-]{1,120}$/.test(n);\n\n// One tool event already, so a lean install is the same entry.\nfunction entry(cmd: HookCommand) {\n const handler = (e: string) => ({ type: \"command\", command: cmd([NAME, e]).command, timeout: 5 });\n const out: Record<string, unknown> = { enabled: true };\n for (const e of AG_EVENTS) out[e] = /Tool/.test(e) ? [{ matcher: \"*\", hooks: [handler(e)] }] : [handler(e)];\n return out;\n}\n\nexport const antigravity: Adapter = {\n name: NAME,\n events: AG_EVENTS,\n detect: (env = process.env) =>\n existsSync(path.join(gemini(env), \"config\")) || dataDirs(env).some((d) => existsSync(d)),\n configFiles: (env = process.env) => [hooksFile(env)],\n install(cmd, env = process.env): InstallReport[] {\n const file = hooksFile(env);\n const f = readJsonFile(file);\n if (!f.ok) return [{ file, changed: false, skipped: true, note: `${f.reason}; not touched` }];\n const hooks = f.value;\n const e = entry(cmd);\n if (JSON.stringify(hooks[HOOK_NAME]) === JSON.stringify(e)) return [{ file, changed: false }];\n hooks[HOOK_NAME] = e;\n return [\n writeBack(file, formatJson(hooks, f), f.existed) ?? {\n file,\n changed: true,\n created: !f.existed,\n note: \"hooks.json is read when a conversation starts; open ones report after a restart\",\n },\n ];\n },\n uninstall(env = process.env, opts: InstallOptions = {}): InstallReport[] {\n const file = hooksFile(env);\n if (!existsSync(file)) return [{ file, changed: false }];\n const f = readJsonFile(file);\n if (!f.ok) return [{ file, changed: false, skipped: true, note: `${f.reason}; not touched` }];\n const hooks = f.value;\n if (!(HOOK_NAME in hooks)) return [{ file, changed: false }];\n delete hooks[HOOK_NAME];\n if (opts.created?.includes(file) && !Object.keys(hooks).length) return [removeEmptied(file, formatJson(hooks, f))];\n return [writeBack(file, formatJson(hooks, f)) ?? { file, changed: true }];\n },\n installed(cmd, env = process.env) {\n const file = hooksFile(env);\n const f = readJsonFile(file);\n const have = f.ok ? f.value[HOOK_NAME] : undefined;\n return [\n {\n file,\n state: !have ? \"missing\" : JSON.stringify(have) === JSON.stringify(entry(cmd)) ? \"current\" : \"stale\",\n },\n ];\n },\n\n fromHook(input: HookInput): HookResult | null {\n const event = input.argv[1] ?? \"\";\n let s: Record<string, unknown> = {};\n try {\n // A stdin that is JSON but not an object (`null`, a number) is no payload.\n const j: unknown = input.stdin ? JSON.parse(input.stdin) : {};\n if (j && typeof j === \"object\" && !Array.isArray(j)) s = j as Record<string, unknown>;\n } catch {}\n const id = (s.conversationId ?? s.session_id ?? s.sessionId) as string | undefined;\n const stdout = antigravityAnswer(event);\n if (!id) return { session: { id: \"\" }, events: [], stdout };\n const workspaces = agWorkspaces(s.workspacePaths);\n const session: HookResult[\"session\"] = { id: String(id), cwd: workspaces[0] ?? input.cwd };\n if (typeof s.modelName === \"string\" && s.modelName !== \"auto\") session.model = s.modelName;\n const toolCall = s.toolCall as { name?: unknown; args?: unknown } | undefined;\n const tool = validTool(toolCall?.name) ? toolCall?.name : validTool(s.toolName) ? s.toolName : undefined;\n const ev = (type: string, data: Record<string, unknown>) => ({ type, data: prune(data), harnessEvent: event });\n const events: HookResult[\"events\"] = [];\n switch (event) {\n case \"PreInvocation\":\n // Fires before every model call of an execution; only the first is the person's ask.\n if (Number(s.invocationNum) === 0 || s.invocationNum === undefined) {\n events.push(ev(\"session.started\", { source: \"unknown\" }));\n events.push(ev(\"turn.started\", {}));\n } else events.push(ev(\"session.heartbeat\", {}));\n break;\n case \"PostInvocation\":\n break;\n case \"PreToolUse\":\n if (tool) events.push(ev(\"tool.started\", { tool, input: toolCall?.args }));\n break;\n case \"PostToolUse\":\n // Antigravity names no tool here; a beat keeps a long run of tools \"working\".\n if (!tool) events.push(ev(\"session.heartbeat\", {}));\n else\n events.push(\n ev(\"tool.ended\", {\n tool,\n ok: !s.error,\n error: typeof s.error === \"string\" ? s.error.slice(0, 2000) : undefined,\n input: toolCall?.args,\n }),\n );\n break;\n case \"Stop\":\n events.push(ev(\"turn.ended\", { reason: s.error ? \"error\" : \"stop\" }));\n break;\n default:\n return { session, events: [], stdout };\n }\n const r: HookResult = { session, events, stdout, hints: { workspaces } };\n if (typeof s.transcriptPath === \"string\") r.transcript = s.transcriptPath;\n return r;\n },\n\n readTranscript(file, fromLine) {\n let text = \"\";\n try {\n text = readFileSync(file, \"utf8\");\n } catch {\n return { turns: [], line: fromLine };\n }\n return readAntigravity(text.split(\"\\n\"), fromLine);\n },\n\n facts(session, transcript, hints): SessionFacts {\n if (!transcript) return {};\n return antigravityFacts(transcript, {\n conversation: session.id,\n workspaces: (hints.workspaces as string[] | undefined) ?? (session.cwd ? [session.cwd] : []),\n env: process.env,\n });\n },\n\n backfill(sinceMs, env = process.env): BackfillRow[] {\n const rows: BackfillRow[] = [];\n for (const data of dataDirs(env)) {\n let ids: string[] = [];\n try {\n ids = readdirSync(path.join(data, \"brain\")).filter((n) => /^[0-9a-f-]{36}$/i.test(n));\n } catch {}\n for (const id of ids) {\n const f = path.join(data, \"brain\", id, \".system_generated\", \"logs\", \"transcript.jsonl\");\n try {\n if (statSync(f).mtimeMs < sinceMs) continue;\n } catch {\n continue;\n }\n const facts = antigravityFacts(f, { conversation: id, workspaces: [], env });\n if (!facts.started_at || !facts.last_at) continue;\n const { started_at, last_at, first_ask: _fa, harness_version: _hv, ...rest } = facts;\n rows.push({ session: { id, ...rest }, started_at, last_at });\n }\n }\n return rows;\n },\n};\n\nfunction prune<T extends Record<string, unknown>>(o: T): T {\n for (const k of Object.keys(o)) if (o[k] === undefined) delete o[k];\n return o;\n}\n\n/** A folder as Antigravity writes it (a file:// URI or a path) \u2192 an absolute path, or null. */\nexport function agPath(p: unknown): string | null {\n if (typeof p !== \"string\" || !p) return null;\n let s = p;\n if (/^file:/i.test(s)) {\n try {\n s = decodeURIComponent(new URL(s).pathname);\n } catch {\n return null;\n }\n if (process.platform === \"win32\" && /^\\/[A-Za-z]:/.test(s)) s = s.slice(1);\n } else if (/^[a-z][a-z0-9+.-]*:\\/\\//i.test(s)) return null;\n if (!path.isAbsolute(s)) return null;\n return path.resolve(s);\n}\nexport const agWorkspaces = (paths: unknown): string[] =>\n (Array.isArray(paths) ? paths : [])\n .map(agPath)\n .filter((p): p is string => !!p)\n .filter((p, i, a) => a.indexOf(p) === i);\n\nfunction agVariants(p: string): string[] {\n const out = [p];\n try {\n const r = realpathSync.native(p);\n if (r !== p) out.push(r);\n } catch {}\n return out;\n}\nfunction agProjects(dir: string): { id: string; folders: string[] }[] {\n const out: { id: string; folders: string[] }[] = [];\n let names: string[] = [];\n try {\n names = readdirSync(dir).filter((n) => n.endsWith(\".json\"));\n } catch {\n return out;\n }\n for (const n of names) {\n const id = n.slice(0, -5);\n if (!ID_RE.test(id)) continue;\n let j: { projectResources?: { resources?: { folderUri?: unknown; gitFolder?: { folderUri?: unknown } }[] } };\n try {\n j = JSON.parse(readFileSync(path.join(dir, n), \"utf8\"));\n } catch {\n continue;\n }\n const folders: string[] = [];\n // A resource is one of the kinds in Antigravity's project.proto: a plain folder is\n // `{ folderUri }`, a git checkout `{ gitFolder: { folderUri, defaultBranch, allowWrite } }`\n // (what 2.23.1 writes for a folder under git); google3 and remote resources name no folder.\n for (const r of j?.projectResources?.resources ?? []) {\n const f = agPath(r?.folderUri ?? r?.gitFolder?.folderUri);\n if (f) folders.push(...agVariants(f));\n }\n if (folders.length) out.push({ id, folders });\n }\n return out;\n}\n/** The project whose folder is the workspace or contains it; the deepest wins. */\nexport function agMatchProject(projects: { id: string; folders: string[] }[], workspaces: string[]): string | null {\n const ws: string[] = [];\n for (const w of workspaces) {\n const p = agPath(w);\n if (p) ws.push(...agVariants(p));\n }\n let best: string | null = null;\n let bestLen = -1;\n for (const pr of projects)\n for (const f of pr.folders) {\n const within = ws.some((w) => w === f || w.startsWith(f.endsWith(path.sep) ? f : f + path.sep));\n if (within && f.length > bestLen) {\n best = pr.id;\n bestLen = f.length;\n }\n }\n return best;\n}\n\n/** Antigravity's web remote: https://antigravity.google.com/r/<installation uuid>-v2, with\n * ?p=c/<conversation>?section=<project> when the project is known. */\nexport function antigravityRemoteUrl(\n transcript: string,\n opts: { conversation?: string; workspaces?: string[]; env: NodeJS.ProcessEnv; projectsDir?: string },\n): string | null {\n const i = transcript.indexOf(`${path.sep}brain${path.sep}`);\n const dirs = (i > 0 ? [transcript.slice(0, i)] : []).concat(dataDirs(opts.env));\n for (const d of dirs) {\n try {\n const m = /installation_uuid:\\s*\"([0-9a-f-]{36})\"/i.exec(\n readFileSync(path.join(d, \"antigravity_state.pbtxt\"), \"utf8\"),\n );\n if (!m) continue;\n const base = `https://antigravity.google.com/r/${m[1]}-v2`;\n const conv = opts.conversation ?? \"\";\n if (!ID_RE.test(conv) || !opts.workspaces?.length) return base;\n const project = agMatchProject(agProjects(opts.projectsDir ?? projectsDir(opts.env)), opts.workspaces);\n return project ? `${base}?p=${encodeURIComponent(`c/${conv}?section=${project}`)}` : base;\n } catch {}\n }\n return null;\n}\n\nexport function antigravityFacts(\n file: string,\n opts: { conversation: string; workspaces: string[]; env: NodeJS.ProcessEnv },\n): SessionFacts {\n const { head, tail } = ends(file, 128 * 1024, 64 * 1024);\n const H = parseLines(head);\n const T = parseLines(tail);\n const out: SessionFacts = {};\n const url = antigravityRemoteUrl(file, opts);\n if (url) out.url = url;\n for (const j of H) {\n if (j.type !== \"USER_INPUT\" || typeof j.content !== \"string\") continue;\n const m = /<USER_REQUEST>([\\s\\S]*?)(?:<\\/USER_REQUEST>|$)/.exec(j.content);\n const text = (m ? (m[1] as string) : j.content).trim();\n const line = (text.split(\"\\n\").find((l) => l.trim()) ?? \"\").trim();\n if (!line || /^<[a-z_-]+>/i.test(line)) continue;\n out.title = line.length > 80 ? `${line.slice(0, 80).replace(/\\s+\\S*$/, \"\")}\u2026` : line;\n out.title_source = \"first-ask\";\n break;\n }\n const times = H.concat(T)\n .map((j) => Date.parse(String(j.created_at ?? j.timestamp ?? \"\")))\n .filter((n) => n > 0);\n if (times.length) {\n out.started_at = Math.min(...times);\n out.last_at = Math.max(...times);\n }\n return out;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// Antigravity (Google) \u2014 control delivery (spec/CONTROL.md \u00A76). Its CLI, `agy`, as the\n// control daemon needs it: which `agy` to run, one headless turn (`agy -p \u2026 --output-\n// format stream-json`, and `--conversation <id>` for the next message), and its stream\n// read as it arrives. agy picks a new conversation's id itself (the `init` line) and\n// starts a fresh one for an id it doesn't know, so the daemon names it after the\n// command that started it (CONTROL.md \u00A76 `start`). No transcript records the folder, so\n// the daemon keeps that too. Shapes measured on agy 1.2.16, 2026-10-04.\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport type { RunLevel, StartPermission } from \"../control/verify.js\";\nimport { deniedNote, findBinary, jobEnv, type Mode, type Reading, type RunResult, runFailure } from \"./headless.js\";\n\nconst LABEL = \"Antigravity\";\n\n/** The `agy` to run: SESSIONPIPE_AGY, else on PATH, else where its installer puts it. */\nexport function findAgy(env: NodeJS.ProcessEnv = process.env, home = os.homedir()): string | null {\n return findBinary({\n override: env.SESSIONPIPE_AGY,\n names: process.platform === \"win32\" ? [\"agy.exe\", \"agy.cmd\"] : [\"agy\"],\n env,\n dirs: [path.join(home, \".local\", \"bin\"), \"/opt/homebrew/bin\", \"/usr/local/bin\"],\n });\n}\n\n/** Permission flags for a level. Safe: none \u2014 agy denies every tool call nobody is\n * there to approve, and says which. Edits: `--mode accept-edits`, its widest, which is\n * also what an auto machine's mode means for it. Inherit: none either, so agy runs as\n * it would by itself. agy has no read-only mode known, so `read` is never offered and\n * throws rather than run at safe. Never `--dangerously-skip-permissions`: no path here\n * writes it. */\nexport function agyModeFlags(level: RunLevel): string[] {\n if (level === \"read\") throw new Error(\"Antigravity has no read-only mode\");\n return level === \"safe\" || level === \"inherit\" ? [] : [\"--mode\", \"accept-edits\"];\n}\n\n/** The levels a start may ask agy for on a machine in `mode`: safe, and edits on an\n * auto machine. */\nexport const offeredLevels = (mode: Mode): StartPermission[] => (mode === \"auto\" ? [\"safe\", \"edits\"] : [\"safe\"]);\n\n/** What a start that names no level gets, said as what it is: edits on an auto machine,\n * no flag on an inherit one. */\nexport const defaultLevel = (mode: Mode): RunLevel => (mode === \"auto\" ? \"edits\" : mode);\n\n/** One headless turn in the folder it is spawned in. A message that starts with a dash\n * would read as a flag after `-p`; a leading space keeps it the prompt. */\nexport function agyArgs(o: { permission: RunLevel; prompt: string; resume?: string }): string[] {\n const prompt = o.prompt.startsWith(\"-\") ? ` ${o.prompt}` : o.prompt;\n return [\n ...(o.resume ? [\"--conversation\", o.resume] : []),\n \"-p\",\n prompt,\n \"--output-format\",\n \"stream-json\",\n ...agyModeFlags(o.permission),\n ];\n}\n\n/** The env a headless turn runs with. */\nexport const agyEnv = (env: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv => jobEnv(env);\n\nexport interface AgyResult {\n status: string;\n response: string;\n error: string;\n denied: unknown[];\n}\n\n/** One stream-json line, as much of it as the daemon uses. */\nexport interface AgyPiece {\n /** The conversation's id, which agy chose (`init`, then every step and the result). */\n session?: string;\n /** Text an `agent_response` step wrote, and which step it belongs to. */\n delta?: { step: number; text: string };\n /** The final `result`. */\n result?: AgyResult;\n /** An `error_message` step's words: the reason only if the run then fails. */\n note?: string;\n}\n\nexport function agyLine(line: string): AgyPiece | null {\n let j: Record<string, unknown>;\n try {\n j = JSON.parse(line);\n } catch {\n return null;\n }\n if (!j || typeof j !== \"object\") return null;\n const str = (v: unknown) => (typeof v === \"string\" ? v : \"\");\n const out: AgyPiece = {};\n if (j.event === \"init\") {\n if (str(j.conversation_id)) out.session = str(j.conversation_id);\n } else if (j.event === \"step_update\") {\n const s = (j.step_update ?? {}) as Record<string, unknown>;\n if (str(s.conversation_id)) out.session = str(s.conversation_id);\n if (s.step_type === \"agent_response\" && str(s.text_delta))\n out.delta = { step: Number(s.step_index ?? 0), text: str(s.text_delta) };\n if (s.step_type === \"error_message\") {\n const why = str(s.text_delta) || str(s.error) || str(s.message);\n if (why) out.note = why;\n }\n } else if (j.event === \"result\") {\n const r = (j.result ?? {}) as Record<string, unknown>;\n if (str(r.conversation_id)) out.session = str(r.conversation_id);\n out.result = {\n status: str(r.status),\n response: str(r.response),\n error: str(r.error),\n denied: Array.isArray(r.denied_actions) ? r.denied_actions : [],\n };\n } else return null;\n return Object.keys(out).length ? out : null;\n}\n\n/** What agy names a denied action by, whatever shape the entry has. */\nfunction deniedName(d: unknown): string | null {\n if (typeof d === \"string\") return d.slice(0, 80);\n if (!d || typeof d !== \"object\") return null;\n const o = d as Record<string, unknown>;\n for (const k of [\"tool_name\", \"toolName\", \"name\", \"tool\", \"action\", \"type\"])\n if (typeof o[k] === \"string\" && o[k]) return (o[k] as string).slice(0, 80);\n return null;\n}\n\n/** An `AGY_ERROR: {\u2026}` agy may end stderr with, in words. */\nexport function agyError(stderr: string | undefined): string {\n const s = String(stderr || \"\");\n const i = s.lastIndexOf(\"AGY_ERROR:\");\n if (i < 0) return \"\";\n const raw = s.slice(i + \"AGY_ERROR:\".length).trim();\n try {\n const j = JSON.parse(raw) as Record<string, unknown>;\n for (const k of [\"message\", \"error\", \"detail\"]) if (typeof j[k] === \"string\" && j[k]) return j[k] as string;\n } catch {}\n return (raw.split(\"\\n\")[0] as string).slice(0, 300);\n}\n\n/** An agy run read as it streams: the answer is the agent_response steps' text, and the\n * result's `response` once it comes. */\nexport class AgyReading implements Reading {\n session: string | null = null;\n lines = 0;\n private buf = \"\";\n private step: number | null = null;\n private result: AgyResult | null = null;\n private note: string | null = null;\n\n get text(): string {\n return this.buf;\n }\n\n feed(line: string): boolean {\n this.lines++;\n const p = agyLine(line);\n if (!p) return false;\n if (p.session && !this.session) this.session = p.session;\n if (p.note) this.note = p.note;\n if (p.result) this.result = p.result;\n if (!p.delta) return false;\n // A new response step after a tool step starts a new paragraph.\n if (this.step !== null && p.delta.step !== this.step && this.buf && !this.buf.endsWith(\"\\n\\n\")) this.buf += \"\\n\\n\";\n this.step = p.delta.step;\n this.buf += p.delta.text;\n return true;\n }\n\n outcome(res: RunResult): { failed: string } | { reply: string } {\n const broke = runFailure(LABEL, res);\n if (broke) return { failed: broke };\n const r = this.result;\n if (!r) {\n const why = agyError(res.stderr) || this.note || \"\";\n return {\n failed: `Antigravity exited (${res.signal || `code ${res.code}`}) without an answer${why ? `: ${why}` : \"\"}`,\n };\n }\n if (r.status !== \"SUCCESS\")\n return { failed: r.error || agyError(res.stderr) || this.note || \"Antigravity reported an error\" };\n const names = [...new Set(r.denied.map(deniedName).filter((n): n is string => !!n))];\n const text = r.response.trim()\n ? r.response.trim()\n : this.buf.trim() || \"(Antigravity finished without a written reply.)\";\n return { reply: text + deniedNote(names, r.denied.length) };\n }\n}\n\nexport const reading = (): AgyReading => new AgyReading();\n", "// SPDX-License-Identifier: Apache-2.0\n// Claude Code (Anthropic) \u2014 control delivery (spec/CONTROL.md \u00A76). Claude Code on\n// this machine, as the control daemon needs it: which `claude` to\n// run and with which permission flags, where a session's transcript is and which\n// folder it runs in, whether a live process holds it, and running one headless\n// turn (`claude -p --resume`, `--fork-session`, `--session-id`). Ported from the\n// spacesheep CLI's machine listener (lib/machine.js, 1.22), which ran it in\n// production first.\nimport { execFile, execFileSync } from \"node:child_process\";\nimport { closeSync, openSync, readdirSync, readFileSync, readSync, statSync } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { levelRank, type RunLevel, START_PERMISSIONS, type StartPermission } from \"../control/verify.js\";\nimport { withoutLineage } from \"../launched-by.js\";\nimport { reducePii } from \"../privacy/pii.js\";\nimport { redactSecrets } from \"../privacy/secrets.js\";\nimport {\n isExe,\n JOB_TIMEOUT_MS,\n type Login,\n type Mode,\n probe,\n type RunOptions,\n type RunResult,\n runHeadless,\n} from \"./headless.js\";\n\nexport { JOB_TIMEOUT_MS, type Login, type Mode, type RunResult };\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n/** A transcript someone else wrote this recently is in use. */\nconst LIVE_WRITE_MS = 90_000;\n\n/** Dotted versions by number, a missing part as 0: 1.9.0 < 1.10 = 1.10.0. */\nexport const cmpVersion = (a: string, b: string) => {\n const pa = a.split(\".\").map(Number);\n const pb = b.split(\".\").map(Number);\n for (let i = 0; i < Math.max(pa.length, pb.length); i++)\n if ((pa[i] ?? 0) !== (pb[i] ?? 0)) return (pa[i] ?? 0) - (pb[i] ?? 0);\n return 0;\n};\n\n/** The `claude` to run: on PATH, else where the installers put it, else the newest\n * copy the desktop app ships. Null when this machine has none. */\n/** The bin folders of the node version managers (nvm, fnm, volta, asdf), newest node\n * first within each, in the folders they use by default or the ones their variables name. */\nexport function versionManagerBins(env: NodeJS.ProcessEnv = process.env, home = os.homedir()): string[] {\n const out: string[] = [];\n const versions = (dir: string, tail: string[]): void => {\n let names: string[] = [];\n try {\n names = readdirSync(dir).filter((n) => /^v?\\d+(\\.\\d+)*$/.test(n));\n } catch {\n return;\n }\n for (const n of names.sort((a, b) => cmpVersion(a.replace(/^v/, \"\"), b.replace(/^v/, \"\"))).reverse())\n out.push(path.join(dir, n, ...tail));\n };\n versions(path.join(env.NVM_DIR || path.join(home, \".nvm\"), \"versions\", \"node\"), [\"bin\"]);\n const fnmDirs = env.FNM_DIR\n ? [env.FNM_DIR]\n : [\n path.join(home, \"Library\", \"Application Support\", \"fnm\"),\n path.join(home, \".local\", \"share\", \"fnm\"),\n path.join(home, \".fnm\"),\n ];\n for (const d of fnmDirs) versions(path.join(d, \"node-versions\"), [\"installation\", \"bin\"]);\n out.push(path.join(env.VOLTA_HOME || path.join(home, \".volta\"), \"bin\"));\n versions(path.join(env.ASDF_DATA_DIR || path.join(home, \".asdf\"), \"installs\", \"nodejs\"), [\"bin\"]);\n return out;\n}\n\nexport function findClaude(env: NodeJS.ProcessEnv = process.env, home = os.homedir()): string | null {\n if (env.SESSIONPIPE_CLAUDE && isExe(env.SESSIONPIPE_CLAUDE)) return env.SESSIONPIPE_CLAUDE;\n const names = process.platform === \"win32\" ? [\"claude.exe\", \"claude.cmd\"] : [\"claude\"];\n for (const d of String(env.PATH || \"\").split(path.delimiter)) {\n if (!d || !path.isAbsolute(d)) continue;\n for (const n of names) if (isExe(path.join(d, n))) return path.join(d, n);\n }\n for (const p of [\n path.join(home, \".claude\", \"local\", \"claude\"),\n path.join(home, \".local\", \"bin\", \"claude\"),\n \"/opt/homebrew/bin/claude\",\n \"/usr/local/bin/claude\",\n ])\n if (isExe(p)) return p;\n // A node version manager's folders: launchd and systemd start the daemon with a bare\n // PATH, and a `claude` that `npm install -g` put under nvm was never found that way\n // (2026-11-05: \"can't copy it (no --fork-session)\" for a Claude Code that had the flag).\n for (const d of versionManagerBins(env, home)) if (isExe(path.join(d, \"claude\"))) return path.join(d, \"claude\");\n const app = path.join(home, \"Library\", \"Application Support\", \"Claude\", \"claude-code\");\n let versions: string[] = [];\n try {\n versions = readdirSync(app)\n .filter((n) => /^\\d+(\\.\\d+)*$/.test(n))\n .sort(cmpVersion)\n .reverse();\n } catch {}\n for (const v of versions) {\n const p = path.join(app, v, \"claude.app\", \"Contents\", \"MacOS\", \"claude\");\n if (isExe(p)) return p;\n }\n return null;\n}\n\n/** One option's text in `claude --help`: its line and the deeper-indented lines under it. */\nfunction optionBlock(help: string, flag: string): string | null {\n const lines = help.split(\"\\n\");\n const re = new RegExp(`^\\\\s{0,4}(?:-\\\\w, )?${flag.replace(/-/g, \"\\\\-\")}(?![\\\\w-])`);\n const start = lines.findIndex((l) => re.test(l));\n if (start < 0) return null;\n const out = [lines[start] as string];\n for (let i = start + 1; i < lines.length && lines[i]?.trim() && !/^\\s{0,4}-/.test(lines[i] as string); i++)\n out.push(lines[i] as string);\n return out.join(\" \");\n}\n\nexport interface Caps {\n hasMode: boolean;\n modes: string[];\n promptsNone: boolean;\n fork: boolean;\n /** `--output-format stream-json` with `--include-partial-messages`: the answer can be\n * forwarded as it is written. Optional so older callers' literals still type. */\n stream?: boolean;\n /** Why `claude --help` couldn't be read, when it couldn't: it timed out (a machine still\n * starting up), or failed without listing `--permission-mode`. Such caps say nothing\n * about this Claude Code's modes, so they are never read as \"it has none\". */\n unread?: string;\n}\n\nexport function parseCaps(help: string): Caps {\n const pm = optionBlock(help, \"--permission-mode\");\n const pp = optionBlock(help, \"--permission-prompts\");\n return {\n hasMode: !!pm,\n modes: pm ? [...pm.matchAll(/\"([A-Za-z]+)\"/g)].map((m) => m[1] as string) : [],\n promptsNone: !!pp && /\"none\"/.test(pp),\n fork: !!optionBlock(help, \"--fork-session\"),\n stream: !!optionBlock(help, \"--include-partial-messages\"),\n };\n}\n\n/** The `--permission-mode` each level (CONTROL.md \u00A73.1) is, where it is one mode. */\nconst LEVEL_MODE: Record<Exclude<StartPermission, \"safe\">, string> = {\n read: \"plan\",\n edits: \"acceptEdits\",\n auto: \"auto\",\n};\n\n/** Permission flags for a level (a machine's mode is one: safe, auto, inherit). Read:\n * plan mode. Safe: `dontAsk` (nothing that needs approval runs). Edits: acceptEdits.\n * Auto: Claude Code's own auto mode. Inherit: none, so the turn starts in the mode\n * Claude Code picks by itself here, its settings' `permissions.defaultMode` (a resume\n * too: Claude Code never restores a session's earlier mode). A level this Claude Code\n * has no mode for is a refusal, never another level, and so is every level but inherit\n * while its --help can't be read (safe would otherwise run with no flag at all). Never\n * bypassPermissions \u2014 no path here writes it. */\nexport function modeFlags(level: RunLevel, caps: Caps): { args: string[] } | { error: string } {\n if (level === \"inherit\") return { args: [] };\n if (caps.unread)\n return { error: `this machine couldn't read its Claude Code's options (${caps.unread}); try again in a minute` };\n if (level === \"auto\" && !caps.modes.includes(\"auto\"))\n return { error: \"this machine is in auto mode, but its Claude Code has no auto permission mode\" };\n if (level !== \"safe\") {\n const m = LEVEL_MODE[level];\n if (!caps.modes.includes(m)) return { error: `this machine's Claude Code has no ${m} permission mode` };\n return { args: [\"--permission-mode\", m] };\n }\n if (caps.modes.includes(\"dontAsk\")) return { args: [\"--permission-mode\", \"dontAsk\"] };\n const args: string[] = [];\n if (caps.hasMode)\n args.push(\n \"--permission-mode\",\n caps.modes.includes(\"manual\") && !caps.modes.includes(\"default\") ? \"manual\" : \"default\",\n );\n if (caps.promptsNone) args.push(\"--permission-prompts\", \"none\");\n return { args };\n}\n\n/** The widest level a start may name on a machine in `mode`: the mode itself, and safe\n * on an inherit machine, whose own default sessionpipe can't rank, so a message there may\n * only narrow to a level that never runs anything needing approval. */\nexport const ceilingLevel = (mode: Mode): StartPermission => (mode === \"inherit\" ? \"safe\" : mode);\n\n/** The levels a start may ask Claude Code for on a machine in `mode`: never above its\n * ceiling, and each only where `claude --help` lists the mode it maps to (safe always).\n * None while that --help couldn't be read: an offered safe would be taken and then run\n * with no permission flag at all. */\nexport function offeredLevels(mode: Mode, caps: Caps): StartPermission[] {\n if (caps.unread) return [];\n return START_PERMISSIONS.filter(\n (l) => levelRank(l) <= levelRank(ceilingLevel(mode)) && (l === \"safe\" || caps.modes.includes(LEVEL_MODE[l])),\n );\n}\n\n/** What a start that names no level gets: what the machine's mode means for Claude Code. */\nexport const defaultLevel = (mode: Mode): RunLevel => mode;\n\n/** How a headless run prints: streamed where this Claude Code can, else one JSON at the end. */\nexport function outputArgs(caps: { stream?: boolean }): string[] {\n return caps.stream\n ? [\"--output-format\", \"stream-json\", \"--verbose\", \"--include-partial-messages\"]\n : [\"--output-format\", \"json\"];\n}\n\n/** One headless `claude -p` run: a new session (`session`), or the next message of one\n * (`resume`, optionally as a fork). The model is its own argument after `--model`, and\n * a prompt that starts with a dash gets a leading space, so it is never read as a flag. */\nexport function claudeArgs(o: {\n caps: Caps;\n level: RunLevel;\n prompt: string;\n session?: string;\n resume?: string;\n fork?: boolean;\n model?: string;\n allowedTools?: string[];\n}): { args: string[] } | { error: string } {\n const mf = modeFlags(o.level, o.caps);\n if (\"error\" in mf) return mf;\n const where = o.resume\n ? [\"--resume\", o.resume, ...(o.fork ? [\"--fork-session\"] : [])]\n : [\"--session-id\", o.session as string];\n return {\n args: [\n \"-p\",\n ...outputArgs(o.caps),\n ...mf.args,\n ...(o.model ? [\"--model\", o.model] : []),\n ...(o.allowedTools?.length ? [`--allowedTools=${o.allowedTools.join(\",\")}`] : []),\n ...where,\n o.prompt.startsWith(\"-\") ? ` ${o.prompt}` : o.prompt,\n ],\n };\n}\n\n/** The env a headless turn runs with: ours, minus the markers that make Claude Code\n * think it runs inside another session and minus any lineage this process inherited\n * (jobEnv), with CLAUDE_CONFIG_DIR naming the account. */\nexport function claudeEnv(configDir?: string, env: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv {\n const e = withoutLineage(env);\n for (const k of [\n \"CLAUDECODE\",\n \"CLAUDE_CODE_SESSION_ID\",\n \"CLAUDE_CODE_HOST_SESSION_ID\",\n \"CLAUDE_CODE_ENTRYPOINT\",\n \"CLAUDE_CODE_SESSION_ATTENDED\",\n \"CLAUDE_CODE_SSE_PORT\",\n ])\n delete e[k];\n e.SESSIONPIPE_CONTROL_JOB = \"1\";\n if (configDir !== undefined) {\n if (path.resolve(configDir) === path.resolve(os.homedir(), \".claude\")) delete e.CLAUDE_CONFIG_DIR;\n else e.CLAUDE_CONFIG_DIR = configDir;\n }\n return e;\n}\n\n/** Whether Claude Code is signed in for one account, in Claude Code's own words\n * (`claude auth status --json`). `loggedIn: null` means this Claude Code can't say\n * (too old for `auth status`, or it didn't answer): never a reason to refuse. */\nexport function parseAuthStatus(stdout: string | null | undefined): Login {\n const text = String(stdout || \"\").trim();\n const start = text.indexOf(\"{\");\n if (start < 0) return { loggedIn: null };\n try {\n const j = JSON.parse(text.slice(start)) as Record<string, unknown>;\n if (typeof j.loggedIn !== \"boolean\") return { loggedIn: null };\n return {\n loggedIn: j.loggedIn,\n ...(typeof j.authMethod === \"string\" ? { method: j.authMethod } : {}),\n ...(typeof j.subscriptionType === \"string\" ? { subscription: j.subscriptionType } : {}),\n };\n } catch {\n return { loggedIn: null };\n }\n}\n\n/** Ask Claude Code whether the account in `configDir` (the default one when omitted)\n * is signed in, from this process \u2014 which is the point: a login kept in the macOS\n * keychain is readable from the screen's own session and not from a background\n * service on a Mac nobody is logged in to, or from an ssh shell, so a headless turn\n * started there dies with \"please run /login\". */\nexport function claudeLogin(bin: string, configDir?: string, env: NodeJS.ProcessEnv = process.env): Promise<Login> {\n // Through `probe`: a .cmd shim (an npm install on Windows) can't be spawned bare, and\n // execFile's synchronous throw would reject this promise and take doctor down with it.\n const c = probe(bin, [\"auth\", \"status\", \"--json\"]);\n return new Promise((resolve) => {\n execFile(\n c.file,\n c.args,\n { encoding: \"utf8\", timeout: 20_000, env: claudeEnv(configDir, env), maxBuffer: 256 * 1024, shell: c.shell },\n // `auth status` may exit non-zero when signed out; its JSON still says so.\n (_err, stdout) => resolve(parseAuthStatus(stdout)),\n );\n });\n}\n\n/** The command that signs one account in, quoted for a sentence. */\nexport function loginCommand(configDir: string | undefined): string {\n const home = os.homedir();\n const isDefault = !configDir || path.resolve(configDir) === path.resolve(home, \".claude\");\n return isDefault ? \"`claude auth login`\" : `\\`CLAUDE_CONFIG_DIR=${configDir.replace(home, \"~\")} claude auth login\\``;\n}\n\n/** What to tell the person when an account isn't signed in for the daemon. */\nexport function loginHint(configDir: string | undefined, platform: NodeJS.Platform = process.platform): string {\n const shown = configDir ? configDir.replace(os.homedir(), \"~\") : \"~/.claude\";\n const login = loginCommand(configDir);\n if (platform === \"darwin\")\n return `Claude Code (${shown}) isn't signed in as this machine's background service sees it. On a Mac its login lives in the login keychain, which a background service can read only while someone is logged in at the screen: log in at the Mac, or run ${login} there.`;\n return `Claude Code (${shown}) isn't signed in on this machine: run ${login} there.`;\n}\n\n/** A terminal's escape sequences (colours, cursor moves), which a command's stderr can\n * carry; built from the character's code so the pattern holds no control character. */\nconst ANSI = new RegExp(`${String.fromCharCode(27)}\\\\[[0-9;?]*[ -/]*[@-~]`, \"g\");\n\n/** Why a `--help` run failed, in the run's own words: the first line it wrote to stderr\n * (a `claude` that is a script whose `node` isn't on the service's PATH says \"env: node:\n * No such file or directory\"), else how it ended. One line, at most 200 characters, with\n * the home folder written `~` and anything shaped like a secret removed: the line goes\n * into a refusal, which the receiver shows to the person who sent the message. \"Failed\"\n * alone told them nothing to act on. */\nexport function helpFailure(\n err: { code?: string | number; status?: number | null; signal?: string | null; stderr?: unknown } | null | undefined,\n home: string = os.homedir(),\n): string {\n if (err?.code === \"ENOENT\") return \"failed: no such file\";\n if (err?.code === \"EACCES\") return \"failed: the file can't be run (permission denied)\";\n const plain = Array.from(String(err?.stderr ?? \"\").replace(ANSI, \"\"))\n .filter((ch) => {\n const c = ch.charCodeAt(0);\n return c === 10 || (c >= 32 && c !== 127);\n })\n .join(\"\");\n const line = plain\n .split(\"\\n\")\n .map((l) => l.replace(/\\s+/g, \" \").trim())\n .find((l) => l.length > 0);\n if (line) {\n const said = redactSecrets(reducePii(line, home));\n return `failed: ${said.length > 200 ? `${said.slice(0, 199)}\u2026` : said}`;\n }\n if (err?.signal) return `failed: killed by ${err.signal}`;\n if (typeof err?.status === \"number\") return `failed with exit code ${err.status}`;\n return \"failed\";\n}\n\n/** What `claude --help` lists. A run that fails still counts when it printed its\n * `--permission-mode` line; one that didn't (a timeout on a machine still starting up,\n * most often) is `unread`, never a Claude Code with no modes, and says why (helpFailure). */\nexport function detectCaps(bin: string, timeoutMs = 30_000): Caps {\n const c = probe(bin, [\"--help\"]); // a claude.cmd shim can't be spawned bare (#165)\n try {\n return parseCaps(\n execFileSync(c.file, c.args, {\n encoding: \"utf8\",\n timeout: timeoutMs,\n env: claudeEnv(),\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n maxBuffer: 4 * 1024 * 1024,\n shell: c.shell,\n }),\n );\n } catch (e) {\n const err = e as {\n stdout?: string;\n stderr?: string;\n code?: string;\n status?: number | null;\n signal?: string | null;\n };\n const caps = parseCaps(String(err?.stdout || \"\"));\n if (caps.hasMode) return caps;\n const why = err?.code === \"ETIMEDOUT\" ? `timed out after ${timeoutMs / 1000} s` : helpFailure(err);\n return { ...caps, unread: `\\`${path.basename(bin)} --help\\` ${why}` };\n }\n}\n\nexport interface Transcript {\n file: string;\n configDir: string;\n project: string;\n}\n\n/** What the lookup of a transcript asks of the disk: whether a path is a file, and what a\n * folder holds. The disk's own unless a test hands in one that ignores case, or one\n * that tells it apart, whatever the machine the test runs on does. */\nexport interface Disk {\n statSync(file: string): { isFile(): boolean };\n readdirSync(folder: string): string[];\n}\nconst DISK: Disk = { statSync, readdirSync };\n\n/** <config dir>/projects/<folder>/<session>.jsonl in one Claude Code config dir.\n *\n * Each project folder is asked for the file by its path, and the folder that answers is\n * then listed to see under which name: a disk that ignores case (macOS, Windows) opens\n * `8c13\u2026.jsonl` for `8C13\u2026`, and the session that answers is then one that nothing else\n * on the machine knows by that spelling. Its registry row and its hooks name it as its\n * harness wrote it, so a session found the other way was open in a window, mid-turn,\n * and looked idle (spec/CONTROL.md \u00A76, What counts as held). Only the folder that\n * answered is listed: listing every one is a quarter of a second on a machine with\n * 600,000 transcripts, several times a message, on the daemon's one thread.\n *\n * `anySpelling` asks the other question: is there a file a NEW session of this id would\n * be written into. The disk is asked for the id as given, in lower case and in upper\n * case, so a disk that tells them apart gives the answer one that doesn't would. */\nfunction transcriptIn(session: string, dir: string, anySpelling: boolean, disk: Disk): Transcript | null {\n let projects: import(\"node:fs\").Dirent[] = [];\n try {\n projects = readdirSync(path.join(dir, \"projects\"), { withFileTypes: true });\n } catch {\n return null;\n }\n const spellings = anySpelling ? [...new Set([session, session.toLowerCase(), session.toUpperCase()])] : [session];\n const same = anySpelling ? (n: string, want: string) => n.toLowerCase() === want.toLowerCase() : Object.is;\n for (const p of projects) {\n if (!p.isDirectory()) continue;\n const folder = path.join(dir, \"projects\", p.name);\n for (const spelling of spellings) {\n const want = `${spelling}.jsonl`;\n try {\n if (!disk.statSync(path.join(folder, want)).isFile()) continue;\n const name = disk.readdirSync(folder).find((n) => same(n, want));\n if (name) return { file: path.join(folder, name), configDir: dir, project: p.name };\n } catch {}\n }\n }\n return null;\n}\n\n/** <config dir>/projects/<folder>/<session>.jsonl in any Claude Code config dir: the\n * session of exactly that id, or with `anySpelling` whatever is filed under the id in\n * any case (the test for \"this new session's id is taken\"). */\nexport function findTranscript(\n session: string,\n dirs: readonly string[],\n o: { anySpelling?: boolean; disk?: Disk } = {},\n): Transcript | null {\n if (!UUID_RE.test(session)) return null;\n for (const dir of dirs) {\n const t = transcriptIn(session, dir, !!o.anySpelling, o.disk ?? DISK);\n if (t) return t;\n }\n return null;\n}\n\n/** Every config dir that holds this session's transcript, in the order given. One\n * session id can be filed in several accounts: a transcript copied between homes, the\n * same id resumed under another account. There were six such ids on one Mac in\n * October 2026, and picking the first \u2014 which is what reading one home does \u2014 put a\n * message into an account that was signed out. */\nexport function findTranscripts(session: string, dirs: readonly string[]): Transcript[] {\n if (!UUID_RE.test(session)) return [];\n const out: Transcript[] = [];\n for (const dir of dirs) {\n const t = transcriptIn(session, dir, false, DISK);\n if (t) out.push(t);\n }\n return out;\n}\n\n/** Which Claude Code account a session belongs to, when more than one has its\n * transcript: the one whose own `sessions/` says a live process holds it. `ambiguous`\n * is a refusal rather than a guess \u2014 it names every account that has the transcript,\n * and in `live` the ones holding it open, which is none of them or more than one. Both\n * are named by their directory name alone, since an ack travels to the receiver. Null\n * when no account has the session at all. */\nexport type HomeChoice = { transcript: Transcript } | { ambiguous: string[]; live: string[] };\n\nconst homeName = (t: Transcript) => path.basename(t.configDir);\n\nexport function resolveHome(session: string, dirs: readonly string[]): HomeChoice | null {\n const all = findTranscripts(session, dirs);\n if (!all.length) return null;\n if (all.length === 1) return { transcript: all[0] as Transcript };\n const live = all.filter((t) => liveRecords(session, t.configDir).length > 0);\n if (live.length === 1) return { transcript: live[0] as Transcript };\n return {\n ambiguous: [...new Set(all.map(homeName))].sort(),\n live: [...new Set(live.map(homeName))].sort(),\n };\n}\n\nconst projectName = (cwd: string) => cwd.replace(/[^a-zA-Z0-9]/g, \"-\");\n\n/** The folder a session runs in, from its transcript's own records (never from a\n * command): the `cwd` whose project name is the folder the transcript is filed\n * under, else the first `cwd`. Streams; a line over 2 MB is skipped. */\nexport function sessionFolder(t: Transcript, cap = 8 * 1024 * 1024): string | null {\n let first: string | null = null;\n let count = 0;\n let fd: number | undefined;\n const look = (line: Buffer): string | null => {\n if (line.indexOf('\"cwd\"') < 0) return null;\n let j: { cwd?: unknown };\n try {\n j = JSON.parse(line.toString(\"utf8\"));\n } catch {\n return null;\n }\n if (!j || typeof j.cwd !== \"string\" || !path.isAbsolute(j.cwd)) return null;\n if (projectName(j.cwd) === t.project) return j.cwd;\n first ??= j.cwd;\n count++;\n return null;\n };\n try {\n fd = openSync(t.file, \"r\");\n const buf = Buffer.alloc(256 * 1024);\n let pos = 0;\n let rest = Buffer.alloc(0);\n let skipping = false;\n while (pos < cap && count < 50) {\n const n = readSync(fd, buf, 0, buf.length, pos);\n if (!n) {\n if (!skipping && rest.length) {\n const hit = look(rest);\n if (hit) return hit;\n }\n break;\n }\n pos += n;\n let chunk = rest.length ? Buffer.concat([rest, buf.subarray(0, n)]) : buf.subarray(0, n);\n let nl = chunk.indexOf(10);\n while (nl >= 0) {\n const line = chunk.subarray(0, nl);\n chunk = chunk.subarray(nl + 1);\n if (skipping) skipping = false;\n else {\n const hit = look(line);\n if (hit) return hit;\n }\n nl = chunk.indexOf(10);\n }\n if (chunk.length > 2 * 1024 * 1024) {\n skipping = true;\n rest = Buffer.alloc(0);\n } else rest = skipping ? Buffer.alloc(0) : Buffer.from(chunk);\n }\n } catch {\n } finally {\n if (fd !== undefined)\n try {\n closeSync(fd);\n } catch {}\n }\n return first;\n}\n\nfunction pidAlive(pid: number): boolean {\n if (!Number.isSafeInteger(pid) || pid <= 1) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch (e) {\n return (e as { code?: string }).code === \"EPERM\";\n }\n}\n\n/** One live Claude Code process's registry row, `<config>/sessions/<pid>.json`, as the\n * in-place `inbox` lane needs it (spec/CONTROL.md \u00A76.3). Every session that registers\n * files one \u2014 a terminal window, the desktop app and a claude.ai bridge worker alike,\n * all of them `kind: \"interactive\"`; a `-p` one-shot's row is not one of those. */\nexport interface LiveRecord {\n /** The config dir this row was read from: the lane never crosses accounts. */\n configDir: string;\n file: string;\n pid: number;\n /** Claude Code's own local inbox for this process, or null when it published none. */\n socket: string | null;\n /** 1 is the only inbox protocol this code speaks; anything else is refused. */\n peerProtocol: number | null;\n /** The process's start time as the registry spells it (UTC), so a recycled pid can be\n * told from the process that filed the row. */\n procStart: string | null;\n status: string | null;\n /** `interactive` for a session the harness holds open for the person. */\n kind: string | null;\n entrypoint: string | null;\n /** `<pid>.<sha>.key`, 0600: where the inbox's auth token lives (needed off macOS). */\n keyFile: string | null;\n}\n\nconst registryRow = (file: string, configDir: string, j: Record<string, unknown>): LiveRecord => {\n const pid = Number(j.pid ?? path.basename(file).slice(0, -5));\n const str = (v: unknown) => (typeof v === \"string\" && v ? v : null);\n let keyFile: string | null = null;\n try {\n // Claude Code's own spelling: `<pid>.<64 hex>.key`, 0600, beside the registry row.\n const want = new RegExp(`^${pid}\\\\.[0-9a-f]{64}\\\\.key$`);\n const hit = readdirSync(path.dirname(file)).find((n) => want.test(n));\n if (hit) keyFile = path.join(path.dirname(file), hit);\n } catch {}\n return {\n configDir,\n file,\n pid,\n socket: str(j.messagingSocketPath),\n peerProtocol: typeof j.peerProtocol === \"number\" ? j.peerProtocol : null,\n procStart: str(j.procStart),\n status: str(j.status),\n kind: str(j.kind),\n entrypoint: str(j.entrypoint),\n keyFile,\n };\n};\n\n/** Every live registry row for this session, across the config dirs given. A row whose\n * pid is gone is not one: the file outlives the process. */\nexport function liveRecords(session: string, dirs: string | readonly string[]): LiveRecord[] {\n const out: LiveRecord[] = [];\n for (const dir of typeof dirs === \"string\" ? [dirs] : dirs) {\n let names: string[] = [];\n try {\n names = readdirSync(path.join(dir, \"sessions\")).filter((n) => /^\\d+\\.json$/.test(n));\n } catch {\n continue;\n }\n for (const n of names) {\n const file = path.join(dir, \"sessions\", n);\n let j: Record<string, unknown>;\n try {\n j = JSON.parse(readFileSync(file, \"utf8\")) as Record<string, unknown>;\n } catch {\n continue;\n }\n if (String(j.sessionId) !== session) continue;\n const row = registryRow(file, dir, j);\n if (pidAlive(row.pid)) out.push(row);\n }\n }\n return out;\n}\n\n/** The ONE live process that holds this session, or null. Two rows \u2014 two accounts, or\n * two processes in one \u2014 is a refusal rather than a guess: a lane that writes into a\n * live session has to know which process it is writing to (spec/CONTROL.md \u00A76.3). */\nexport function liveRecord(session: string, dirs: string | readonly string[]): LiveRecord | null {\n const all = liveRecords(session, dirs);\n return all.length === 1 ? (all[0] as LiveRecord) : null;\n}\n\n/** A Claude Code process holds this session right now: its registry file,\n * <config>/sessions/<pid>.json, names it and the pid is alive (interactive and\n * Agent SDK sessions both file one). */\nexport function liveProcess(session: string, configDir: string): boolean {\n return liveRecords(session, configDir).length > 0;\n}\n\n/** Claude Code's own permission modes, by how much a turn may do in them without being\n * asked about (its own order, 2.1.310). `plan` writes nothing at all. `default`,\n * `manual` and `dontAsk` share a step: none of them lets anything through that needs\n * approval \u2014 the first two ask the person, `dontAsk` refuses instead. `acceptEdits`\n * writes files; `auto` runs most things; `bypassPermissions` asks about nothing.\n *\n * Used to tell one mode from another and to compare two, never to pick one. -1 is \"not\n * a mode this code knows\", which compares below everything. */\nexport const MODE_RANK: Record<string, number> = {\n plan: 0,\n default: 1,\n manual: 1,\n dontAsk: 1,\n acceptEdits: 2,\n auto: 3,\n bypassPermissions: 4,\n};\nexport const CLAUDE_MODES = Object.keys(MODE_RANK);\nexport const modeRank = (m: string | null | undefined): number => (m && m in MODE_RANK ? (MODE_RANK[m] as number) : -1);\n\n/** The permission mode a hook payload reports for its own session, or null. Claude Code\n * writes `permission_mode` on every hook payload; `permissionMode` is the spelling its\n * transcript records use, and is read too so one reader serves both.\n *\n * This is the only place a mode the person chose at the keyboard can be read from: a\n * session's registry row doesn't carry it, and the transcript names it only on turns\n * that happen to record one. hook.ts repeats the shape test, because it imports nothing\n * but node builtins. */\nexport function hookMode(payload: unknown): string | null {\n if (!payload || typeof payload !== \"object\") return null;\n const p = payload as { permission_mode?: unknown; permissionMode?: unknown };\n const v = typeof p.permission_mode === \"string\" ? p.permission_mode : p.permissionMode;\n return typeof v === \"string\" && CLAUDE_MODES.includes(v) ? v : null;\n}\n\n/** The permission class Claude Code's own inbox checks a sender's declared class\n * against (2.1.310): `bypassPermissions` is `bypass`; a mode that prompts before it\n * acts is `prompting`. `plan` is neither \u2014 its class there depends on a capability and\n * a TTY this code cannot see \u2014 and nor is `auto`, nor a mode nothing has recorded, so\n * those get no in-place lane at all (spec/CONTROL.md \u00A76.3). */\nexport function peerClass(mode: string | null | undefined): \"bypass\" | \"prompting\" | null {\n if (mode === \"bypassPermissions\") return \"bypass\";\n if (mode === \"default\" || mode === \"manual\" || mode === \"dontAsk\" || mode === \"acceptEdits\") return \"prompting\";\n return null;\n}\n\n/** One Claude Code account's permission settings, user scope only\n * (`<config dir>/settings.json`): a folder's own settings may tighten these but never\n * loosen them, and a managed policy may tighten them further. Only the three keys\n * something here acts on.\n *\n * Reading user scope alone can overstate how wide a home is, never understate it, and\n * everything that reads this treats a wider answer as a reason NOT to act (the inbox\n * lane needs the machine's class to equal the session's own; a narrowing is re-asserted\n * only where the home's default is at least as wide). */\nexport interface HomeSettings {\n /** `permissions.defaultMode`: what a session with no flag starts in. Null: not said,\n * or the file could not be read. */\n defaultMode: string | null;\n /** `disableAutoMode: \"disable\"`: asking for auto mode quietly gives Manual instead. */\n disableAutoMode: boolean;\n /** `disableBypassPermissionsMode: \"disable\"`: this home cannot be in bypass at all. */\n disableBypass: boolean;\n}\n\nexport const NO_HOME_SETTINGS: HomeSettings = { defaultMode: null, disableAutoMode: false, disableBypass: false };\n\nexport function homeSettings(configDir: string | undefined, home = os.homedir()): HomeSettings {\n const file = path.join(configDir ?? path.join(home, \".claude\"), \"settings.json\");\n let j: Record<string, unknown>;\n try {\n j = JSON.parse(readFileSync(file, \"utf8\")) as Record<string, unknown>;\n } catch {\n return { ...NO_HOME_SETTINGS };\n }\n if (!j || typeof j !== \"object\" || Array.isArray(j)) return { ...NO_HOME_SETTINGS };\n const p = (j.permissions && typeof j.permissions === \"object\" ? j.permissions : {}) as Record<string, unknown>;\n // Both spellings: Claude Code reads these two under `permissions`, and settings\n // written by hand (and its own older docs) put them at the top level.\n const off = (k: string) => j[k] === \"disable\" || p[k] === \"disable\";\n return {\n defaultMode: typeof p.defaultMode === \"string\" && CLAUDE_MODES.includes(p.defaultMode) ? p.defaultMode : null,\n disableAutoMode: off(\"disableAutoMode\"),\n disableBypass: off(\"disableBypassPermissionsMode\"),\n };\n}\n\n/** The `--permission-mode` a relaunch of ONE session re-asserts, or null for no flag at\n * all (spec/CONTROL.md \u00A76 `prompt`). Only a narrowing the session itself chose, and\n * only where it is one:\n *\n * - `plan` always: nothing this harness has is narrower, so it cannot widen anything;\n * - `dontAsk` and `acceptEdits` where the account's own default is at least as wide\n * (`MODE_RANK`), so a re-assertion is never wider than what the machine itself does\n * with no flag. Settings that can't be read mean it isn't re-asserted;\n * - everything else \u2014 `default`, `manual`, `auto`, `bypassPermissions`, nothing\n * recorded \u2014 is no flag, and the account's own default decides.\n *\n * The default it compares against is the account's own (`permissions.defaultMode`, user\n * scope). A folder's settings or a managed policy may narrow that further, invisibly\n * here; both narrow what the re-asserted mode can actually do too, so the comparison\n * errs on the side of asking.\n *\n * It never returns `auto` or `bypassPermissions`: the two values a setting can quietly\n * turn into something else, and the two this code must never write. `auto` is the\n * incident this came from \u2014 it asks for a mode that `disableAutoMode` turns into Manual,\n * so a session that recorded it gets no flag and the account's default instead.\n *\n * No flag is not neutral. On a fleet whose accounts default to bypass it is the widest\n * outcome there is, which is why a narrowing the person chose has to be said again. */\nexport function relaunchMode(recorded: string | null | undefined, home: HomeSettings): string | null {\n if (recorded === \"plan\") return recorded;\n if ((recorded === \"dontAsk\" || recorded === \"acceptEdits\") && modeRank(home.defaultMode) >= modeRank(recorded))\n return recorded;\n return null;\n}\n\n/** Written in the last 90 s by something the caller can't account for: a writer that may\n * still be there (spec/CONTROL.md \u00A76, never two writers on one transcript). `knownEnd` is\n * the last time a run of that session is known to have finished \u2014 a job of the caller's\n * own, whose process it saw close, or the session's own end as its hooks reported it \u2014\n * and a write no later than that (two seconds of slack for the last rows) was made by a\n * process that is done with the file, however recent it is. */\nexport function recentlyWritten(file: string, knownEnd?: number, now = Date.now()): boolean {\n let m: number;\n try {\n m = statSync(file).mtimeMs;\n } catch {\n return false;\n }\n return recentWrite(m, knownEnd, now);\n}\n\n/** The rule itself, for a transcript last written at `written` (epoch ms): held by its\n * last 90 seconds, unless a run known to have finished at `knownEnd` accounts for the\n * write (conformance/control-held.json has the cases). */\nexport const recentWrite = (written: number, knownEnd: number | undefined, now: number): boolean =>\n now - written <= LIVE_WRITE_MS && !(knownEnd && written <= knownEnd + 2000);\n\n/** Run one headless turn (headless.ts). Streaming (`--output-format stream-json`), only\n * the `result` line is kept for the RunResult unless the caller says otherwise. */\nexport function runClaude(bin: string, args: string[], o: RunOptions): Promise<RunResult> {\n return runHeadless(bin, args, { ...o, keep: o.keep ?? ((line) => line.includes('\"type\":\"result\"')) });\n}\n\nexport interface ClaudeResult {\n type?: string;\n result?: unknown;\n is_error?: boolean;\n subtype?: string;\n session_id?: unknown;\n permission_denials?: { tool_name?: unknown }[];\n}\n\n/** `--output-format json`: one result object, or an array whose last `result` entry it is. */\nexport function parseResult(stdout: string | null | undefined): ClaudeResult | null {\n const s = String(stdout || \"\").trim();\n if (!s) return null;\n const pick = (j: unknown): ClaudeResult | null => {\n if (Array.isArray(j)) {\n for (let i = j.length - 1; i >= 0; i--) if (j[i]?.type === \"result\") return j[i];\n return null;\n }\n return j && typeof j === \"object\" ? (j as ClaudeResult) : null;\n };\n try {\n return pick(JSON.parse(s));\n } catch {}\n const lines = s.split(\"\\n\");\n for (let i = lines.length - 1; i >= 0; i--) {\n try {\n const j = pick(JSON.parse(lines[i] as string));\n if (j && (j.type === \"result\" || \"result\" in j)) return j;\n } catch {}\n }\n return null;\n}\n\nexport const isUuid = (s: unknown): s is string => typeof s === \"string\" && UUID_RE.test(s);\n\n/** The session a streamed run (`--output-format stream-json`) says it is, from its\n * `system` / `init` line, which comes before any turn: a `--fork-session` run names its\n * copy there. The `result` line says it again, but a run that is stopped before it\n * finishes never prints one, and the copy it made is still on disk. Null for any other\n * line. */\nexport function initSession(line: string): string | null {\n if (!line.includes('\"init\"')) return null;\n try {\n const j = JSON.parse(line) as { type?: unknown; subtype?: unknown; session_id?: unknown };\n // A line that holds the word is an object, an array or a string: never null.\n return j.type === \"system\" && j.subtype === \"init\" && isUuid(j.session_id) ? j.session_id : null;\n } catch {\n return null;\n }\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// The one verifier for signed control commands (spec/CONTROL.md \u00A74\u2013\u00A75). A machine\n// runs a command only when this says yes; a receiver MAY run it too, as an early\n// word, so a bad command is refused where the person can see why.\n//\n// WebCrypto only (globalThis.crypto.subtle), no node: imports, no clock of its own\n// (`now` is passed in): the same file runs in a Cloudflare Worker, in a browser and\n// in Node \u2265 20, and conformance/control-vectors/ pins its answers.\n//\n// Every signature covers the EXACT bytes as transmitted (`cmd`, `grant.str`): the\n// strings are parsed to read their fields and never re-serialized to verify.\n\n/** One passkey tap vouches for a day key for at most this long. */\nexport const GRANT_MAX_MS = 24 * 3600_000;\n/** Clock slack between the signing device, the receiver and the machine. */\nexport const SKEW_MS = 5 * 60_000;\n/** The machine judges a command by when it was SIGNED: a message sent while the lid\n * was shut still runs when the machine wakes, up to a day later. */\nexport const MACHINE_MAX_AGE_MS = 24 * 3600_000;\n/** A receiver's early check is stricter: a command is carried within ten minutes of\n * being signed, or not at all. */\nexport const RECEIVER_MAX_AGE_MS = 10 * 60_000;\n/** How long a machine remembers a nonce: longer than MACHINE_MAX_AGE_MS + SKEW_MS. */\nexport const NONCE_TTL_MS = 25 * 3600_000;\n/** The whole command string, in UTF-16 code units (what JSON.parse sees). */\nexport const CMD_MAX = 48_000;\n/** A prompt's text, in characters. */\nexport const TEXT_MAX = 20_000;\n/** A permission answer's note. */\nexport const NOTE_MAX = 2_000;\n/** A grant string. */\nexport const GRANT_STR_MAX = 2_000;\n/** Attachments on a `start` or a `prompt` (CONTROL.md \u00A73.1): at most this many files, */\nexport const FILES_MAX = 10;\n/** each at most this many bytes, */\nexport const FILE_SIZE_MAX = 26_214_400;\n/** together at most this many, */\nexport const FILES_TOTAL_MAX = 52_428_800;\n/** with a name of at most this many characters (after NFC) */\nexport const FILE_NAME_MAX = 200;\n/** and a media type of at most this many. */\nexport const FILE_TYPE_MAX = 100;\n/** A start's `model` (CONTROL.md \u00A73.1): at most this many characters, */\nexport const MODEL_MAX = 100;\n/** in this alphabet, never starting with a dash, so it can never read as a flag. */\nexport const MODEL_RE = /^[A-Za-z0-9][A-Za-z0-9._:/@[\\]-]*$/;\n/** The levels a start may ask for (CONTROL.md \u00A73.1), narrowest first. Closed: no level\n * is wider than `auto`, and none turns a harness's approval off. */\nexport const START_PERMISSIONS = [\"read\", \"safe\", \"edits\", \"auto\"] as const;\nexport type StartPermission = (typeof START_PERMISSIONS)[number];\n/** What a run is started with: a level, or `inherit` (CONTROL.md \u00A72) \u2014 no permission\n * flag at all, so the harness starts in its own default on the machine. Only a machine\n * the person put in inherit mode runs that way; a command never names it. */\nexport type RunLevel = StartPermission | \"inherit\";\n\n/** Where a level sits, narrowest (0) to widest; -1 for anything that isn't one. */\nexport const levelRank = (l: unknown): number => START_PERMISSIONS.indexOf(l as StartPermission);\n/** The narrower of two levels: what a later run of a session gets, its recorded level\n * against what the machine's mode allows now. */\nexport const narrower = (a: StartPermission, b: StartPermission): StartPermission =>\n levelRank(a) <= levelRank(b) ? a : b;\n\nexport const COMMAND_TYPE = \"sessionpipe.control\";\nexport const GRANT_TYPE = \"sessionpipe.grant\";\nexport const CONTROL_KINDS = [\"prompt\", \"permission.answer\", \"cancel\", \"start\", \"key.add\", \"pool\"] as const;\n/** The session a `key.add` names: the machine's own key store, not a coding session. */\nexport const KEY_STORE_SESSION = \"sessionpipe:keys\";\n/** The session a `pool` names: the machine's account pool (CONTROL.md \u00A76 `pool`). */\nexport const POOL_SESSION = \"sessionpipe:pool\";\nexport type ControlKind = (typeof CONTROL_KINDS)[number];\n/** What a `pool` command may ask (CONTROL.md \u00A76 `pool`). Closed: an action added later\n * is refused by every machine that predates it. */\nexport const POOL_ACTIONS = [\n \"on\",\n \"off\",\n \"enable\",\n \"disable\",\n \"remove\",\n \"order\",\n \"refresh\",\n \"login.begin\",\n \"login.complete\",\n] as const;\nexport type PoolAction = (typeof POOL_ACTIONS)[number];\n/** A pooled account's id (or a pending sign-in's): what `session.account_id` carries. */\nexport const POOL_ACCOUNT_RE = /^[A-Za-z0-9._:-]{1,128}$/;\n/** An `order` names at most this many accounts: the pool holds no more. */\nexport const POOL_ORDER_MAX = 20;\n/** The pasted `code#state` of a sign-in, in characters, on one line. */\nexport const POOL_CODE_MAX = 512;\n\n/** COSE algorithm ids a trusted key may use. */\nexport const ES256 = -7;\nexport const RS256 = -257;\n\n/** The kinds of key a machine may trust (CONTROL.md \u00A72): a WebAuthn passkey, or a\n * device key an app holds in hardware where it has no passkey to offer. */\nexport const KEY_TYPES = [\"passkey\", \"device\"] as const;\nexport type KeyType = (typeof KEY_TYPES)[number];\n\n/** A key enrolled on the machine: a passkey's credential id, COSE alg and SPKI\n * (base64url); a device key also says so (`type`), and what its app declared about\n * it (`store`, `uv`). The machine verifies by its own record, never by a message. */\nexport interface TrustedKey {\n id: string;\n alg: number;\n spki: string;\n /** Present only on a device key (CONTROL.md \u00A72 \"Device keys\"). */\n type?: \"device\";\n store?: \"hardware\";\n uv?: \"each-use\";\n}\n/** A WebAuthn assertion: credential id, authenticatorData, clientDataJSON, signature (base64url). */\nexport interface Assertion {\n cred: string;\n ad: string;\n cd: string;\n sig: string;\n}\n/** A device key's signature (CONTROL.md \u00A73.2): its id and 64 bytes r\u2016s over deviceMessage(). */\nexport interface DeviceSignature {\n cred: string;\n sig: string;\n}\n/** The day's grant: a passkey's assertion over sha256(str), where str names the day key. */\nexport interface GrantBundle extends Assertion {\n str: string;\n}\n/** The day's grant from a device key: its signature over deviceMessage(\"grant\", rp, sha256(str)). */\nexport interface DeviceGrant extends DeviceSignature {\n str: string;\n}\n/** What a receiver carries for one command (control.json minus the receiver's envelope). */\nexport interface SignedCommand {\n cmd: string;\n csig?: string | null;\n grant?: GrantBundle | DeviceGrant | null;\n confirm?: Assertion | DeviceSignature | null;\n}\nexport interface Grant {\n v: 1;\n t: typeof GRANT_TYPE;\n pub: string;\n iat: number;\n exp: number;\n rp: string;\n}\n/** One file attached to a `start`: the bytes live on the receiver, named by their hash. */\nexport interface ControlFile {\n /** The file name the machine writes (NFC). */\n name: string;\n /** Media type, `type/subtype`. */\n type: string;\n /** Bytes. */\n size: number;\n /** SHA-256 of the bytes, base64url without padding (43 characters). */\n sha256: string;\n}\nexport interface ControlCommand {\n v: 1;\n t: typeof COMMAND_TYPE;\n machine: string;\n kind: ControlKind;\n /** `<harness>:<id>`, e.g. `claude-code:8c132906-\u2026`. */\n session: string;\n text?: string;\n for?: string;\n decision?: \"allow\" | \"deny\";\n note?: string;\n cwd?: string;\n /** key.add only: the key to trust from now on, as the receiver holds it (a passkey,\n * or a device key with its `type`, `store` and `uv`). */\n key?: TrustedKey;\n /** key.add only: what the person calls the device (\"iPhone\"), for `control keys`. */\n name?: string;\n /** start, prompt: files to download, verify and write into the session's folder. */\n files?: ControlFile[];\n /** start only: the level the new session runs at (never above the machine's mode). */\n permission?: StartPermission;\n /** start only: the model the harness runs, as the harness names it. */\n model?: string;\n /** pool only (session `sessionpipe:pool`): what to do with the account pool. */\n pool_action?: PoolAction;\n /** pool: the account (enable, disable, remove, refresh), or the pending sign-in's id\n * (login.complete). */\n pool_account?: string;\n /** pool, order: every account of the pool once, in the order wanted. */\n pool_order?: string[];\n /** pool, login.complete: the `code#state` the person pasted back. */\n pool_code?: string;\n /** start, prompt: `<harness>:<id>` of a session on the same machine that gets the\n * answer as a message once the turn ends (CONTROL.md \u00A76, a handoff). */\n reply_to?: string;\n nonce: string;\n iat: number;\n}\n\n/** Why a command was refused. Stable: conformance vectors and acks name these. */\nexport type RefusalCode =\n | \"malformed\"\n | \"not_a_command\"\n | \"wrong_machine\"\n | \"unknown_kind\"\n | \"bad_session\"\n | \"bad_fields\"\n | \"bad_nonce\"\n | \"too_old\"\n | \"future\"\n | \"unsigned\"\n | \"untrusted_key\"\n | \"bad_assertion\"\n | \"bad_grant\"\n | \"outside_grant\"\n | \"bad_csig\"\n | \"replay\"\n | \"nonce_store\";\n\nexport type Verdict =\n | { ok: true; cmd: ControlCommand; via: \"grant\" | \"confirm\"; key: string }\n | { ok: false; code: RefusalCode; why: string };\n\nexport interface VerifyOptions {\n /** This machine's id; a command for another machine is refused. */\n machine: string;\n /** The receiver's WebAuthn rp id the keys were enrolled for (well-known control.signing.rp_id). */\n rpId: string;\n /** The keys enrolled on this machine (or, for a receiver's early check, the account's). */\n trusted: TrustedKey[];\n /** Epoch ms. */\n now: number;\n /** MACHINE_MAX_AGE_MS on a machine (default), RECEIVER_MAX_AGE_MS on a receiver. */\n maxAgeMs?: number;\n /** Called once, last, only for a command whose signatures all verified: answer\n * true when the nonce was seen before, otherwise record it (durably) and answer\n * false. A throw refuses the command (`nonce_store`): never run what could not\n * be remembered. Omit it on a receiver's early check. */\n seenNonce?: (nonce: string) => boolean | Promise<boolean>;\n}\n\nconst NONCE_RE = /^[A-Za-z0-9_-]{22,64}$/;\nconst MACHINE_RE = /^m_[A-Za-z0-9_-]{16,40}$/;\nconst HARNESS_RE = /^[a-z][a-z0-9-]{0,39}$/;\nconst SESSION_ID_RE = /^[A-Za-z0-9._:-]{1,128}$/;\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nconst B64URL_RE = /^[A-Za-z0-9_-]*$/;\nconst SHA256_RE = /^[A-Za-z0-9_-]{43}$/;\nconst MEDIA_TYPE_RE = /^[a-z0-9][a-z0-9!#$&^_.+-]*\\/[a-z0-9][a-z0-9!#$&^_.+-]*$/i;\n// biome-ignore lint/suspicious/noControlCharactersInRegex: control characters are exactly what it rejects\nconst BAD_NAME_CHAR_RE = /[/\\\\\\x00-\\x1f\\x7f]/;\nconst UP = 0x01;\nconst UV = 0x04;\n\n/** The fields each kind carries besides the common ones (CONTROL.md \u00A73.1). The set is\n * closed: a field it doesn't list is `bad_fields`, so a field added later fails closed\n * on a machine that predates it instead of being ignored. */\nconst COMMON_FIELDS: readonly string[] = [\"v\", \"t\", \"machine\", \"kind\", \"session\", \"nonce\", \"iat\", \"note\"];\nconst FIELDS: Record<ControlKind, readonly string[]> = {\n prompt: [\"text\", \"files\", \"reply_to\"],\n \"permission.answer\": [\"for\", \"decision\"],\n cancel: [],\n start: [\"text\", \"cwd\", \"files\", \"permission\", \"model\", \"reply_to\"],\n \"key.add\": [\"key\", \"name\"],\n pool: [\"pool_action\", \"pool_account\", \"pool_order\", \"pool_code\"],\n};\n/** The fields only a `pool` carries. */\nconst POOL_FIELDS = FIELDS.pool;\n\n// --- encodings ------------------------------------------------------------------\n\nconst enc = new TextEncoder();\nconst dec = new TextDecoder();\n\nexport function b64url(bytes: Uint8Array | ArrayBuffer): string {\n const u = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);\n let s = \"\";\n for (const b of u) s += String.fromCharCode(b);\n return btoa(s).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\n/** base64url without padding, strictly; null for anything else. */\nexport function fromB64url(s: unknown): Uint8Array | null {\n if (typeof s !== \"string\" || !B64URL_RE.test(s) || s.length % 4 === 1) return null;\n try {\n const bin = atob(s.replace(/-/g, \"+\").replace(/_/g, \"/\") + \"===\".slice((s.length + 3) % 4));\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n } catch {\n return null;\n }\n}\n\nexport async function sha256(data: string | Uint8Array): Promise<Uint8Array> {\n const bytes = typeof data === \"string\" ? enc.encode(data) : data;\n return new Uint8Array(await crypto.subtle.digest(\"SHA-256\", bytes as Uint8Array<ArrayBuffer>));\n}\n\nfunction concat(a: Uint8Array, b: Uint8Array): Uint8Array {\n const out = new Uint8Array(a.length + b.length);\n out.set(a, 0);\n out.set(b, a.length);\n return out;\n}\n\n/** Equal, compared whole: a mismatch costs the same as a match. */\nexport function sameBytes(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false;\n let d = 0;\n for (let i = 0; i < a.length; i++) d |= (a[i] as number) ^ (b[i] as number);\n return d === 0;\n}\n\n/** A DER ECDSA signature (what WebAuthn returns) as the 64-byte r\u2016s WebCrypto verifies.\n * Strict: every length must match the bytes, so one signature has one encoding (a\n * P-256 signature is at most 72 bytes, so the short length form is the only one). */\nexport function derToRaw(der: Uint8Array): Uint8Array | null {\n if (der[0] !== 0x30 || der.length < 8 || der[1] !== der.length - 2) return null;\n let i = 2;\n const part = (): Uint8Array | null => {\n if (der[i] !== 0x02) return null;\n const len = der[i + 1] as number;\n if (len < 1 || len > 33) return null;\n let v = der.slice(i + 2, i + 2 + len);\n if (v.length !== len) return null;\n // Minimal integers only: no needless leading zero, and never negative.\n if ((v[0] as number) & 0x80) return null;\n if (len > 1 && v[0] === 0 && !((v[1] as number) & 0x80)) return null;\n i += 2 + len;\n while (v.length > 32 && v[0] === 0) v = v.slice(1);\n if (v.length > 32) return null;\n const out = new Uint8Array(32);\n out.set(v, 32 - v.length);\n return out;\n };\n const r = part();\n const s = part();\n return r && s && i === der.length ? concat(r, s) : null;\n}\n\nconst u8 = (b: Uint8Array) => b as Uint8Array<ArrayBuffer>;\n/** WebCrypto's key type, named without the DOM lib (Workers, Node and browsers all have it). */\ntype CryptoKey = Awaited<ReturnType<typeof crypto.subtle.importKey>>;\n\nasync function importKey(key: TrustedKey): Promise<CryptoKey | null> {\n const spki = fromB64url(key.spki);\n if (!spki?.length) return null;\n try {\n if (key.alg === ES256)\n return await crypto.subtle.importKey(\"spki\", u8(spki), { name: \"ECDSA\", namedCurve: \"P-256\" }, false, [\"verify\"]);\n if (key.alg === RS256) {\n const k = await crypto.subtle.importKey(\"spki\", u8(spki), { name: \"RSASSA-PKCS1-v1_5\", hash: \"SHA-256\" }, false, [\n \"verify\",\n ]);\n const bits = (k.algorithm as { modulusLength?: number }).modulusLength as number; // every RSA key has one\n return bits >= 2048 ? k : null;\n }\n } catch {}\n return null;\n}\n\nconst PASSKEY_FIELDS = new Set([\"id\", \"alg\", \"spki\"]);\nconst DEVICE_FIELDS = new Set([\"id\", \"alg\", \"spki\", \"type\", \"store\", \"uv\"]);\n/** The only fields a device signature has (`str` only in a grant). */\nexport const DEVICE_SIG_FIELDS = [\"cred\", \"sig\", \"str\"] as const;\n\n/** A device key's id: the SHA-256 of its SPKI bytes, base64url without padding. */\nexport async function deviceKeyId(spki: string): Promise<string> {\n return b64url(await sha256(fromB64url(spki) ?? new Uint8Array()));\n}\n\n/** A device key's declared rules, ignoring any bookkeeping fields a store keeps beside\n * them (a name, when it was added): ES256, hardware, verified each use, named by its\n * SPKI's hash, and a P-256 key WebCrypto can import. */\nasync function deviceRecordValid(key: TrustedKey): Promise<boolean> {\n if (key.type !== \"device\" || key.alg !== ES256 || key.store !== \"hardware\" || key.uv !== \"each-use\") return false;\n if (typeof key.id !== \"string\" || !SHA256_RE.test(key.id) || key.id !== (await deviceKeyId(key.spki))) return false;\n return !!(await importKey(key));\n}\n\n/** Can this key be enrolled at all? A machine refuses to trust a key it could never\n * verify with. The key's fields are closed: a passkey is `id`, `alg`, `spki` and\n * nothing else; a device key adds exactly `type`, `store` and `uv` (CONTROL.md \u00A72),\n * so a kind added later is refused by every machine that predates it. */\nexport async function keyUsable(key: TrustedKey): Promise<boolean> {\n if (!key || typeof key !== \"object\" || Array.isArray(key)) return false;\n const fields = Object.keys(key).filter((k) => (key as unknown as Record<string, unknown>)[k] !== undefined);\n if (\"type\" in key && key.type !== undefined) {\n if (!fields.every((f) => DEVICE_FIELDS.has(f))) return false;\n return deviceRecordValid(key);\n }\n if (!fields.every((f) => PASSKEY_FIELDS.has(f))) return false;\n return (\n typeof key.id === \"string\" &&\n /^[A-Za-z0-9_-]{16,1400}$/.test(key.id) &&\n (key.alg === ES256 || key.alg === RS256) &&\n !!(await importKey(key))\n );\n}\n\n// --- WebAuthn -------------------------------------------------------------------\n\n/** A WebAuthn origin a key may have been used from: https on the rp id or a subdomain;\n * for rp id `localhost`, plain http on any port too. A bare origin, as a browser writes it. */\nexport function originAllowed(origin: unknown, rpId: string): boolean {\n if (typeof origin !== \"string\" || !rpId) return false;\n let u: URL;\n try {\n u = new URL(origin);\n } catch {\n return false;\n }\n if (u.origin !== origin) return false;\n if (u.hostname !== rpId && !u.hostname.endsWith(`.${rpId}`)) return false;\n if (u.protocol === \"https:\") return true;\n return u.protocol === \"http:\" && rpId === \"localhost\";\n}\n\ntype Check = { ok: true } | { ok: false; why: string };\nconst no = (why: string): Check => ({ ok: false, why });\n\n// --- device keys (CONTROL.md \u00A73.2) ------------------------------------------------\n\n/** The first line of every message a device key signs. */\nexport const DEVICE_CONTEXT = \"sessionpipe.device.v1\";\n/** What a device signature is for: one use can never answer for another. */\nexport type DevicePurpose = \"grant\" | \"confirm\" | \"pair\";\n\n/** The exact bytes a device key signs: the context, the purpose, the rp id as the\n * machine recorded it, and the base64url (no padding) of the 32-byte challenge a\n * passkey would sign for that purpose, joined by single line feeds, none at the end. */\nexport function deviceMessage(purpose: DevicePurpose, rpId: string, challenge: Uint8Array): Uint8Array {\n return enc.encode(`${DEVICE_CONTEXT}\\n${purpose}\\n${rpId}\\n${b64url(challenge)}`);\n}\n\n/** One device signature over `challenge` for `purpose`, made with the device key `key`. */\nasync function verifyDeviceSignature(\n challenge: Uint8Array,\n a: object,\n key: TrustedKey,\n rpId: string,\n purpose: DevicePurpose,\n): Promise<Check> {\n const sig = a as Record<string, unknown>;\n for (const f of Object.keys(sig)) {\n if (f === \"str\" && purpose === \"grant\") continue;\n if (f !== \"cred\" && f !== \"sig\") return no(`a device key's signature carries no ${f}`);\n }\n if (sig.cred !== key.id) return no(\"signed with a key this machine doesn't trust\");\n if (!(await deviceRecordValid(key))) return no(\"a trusted key is unusable\");\n const raw = fromB64url(sig.sig);\n if (raw?.length !== 64) return no(\"a device key's signature is 64 bytes, r\u2016s\");\n const pub = await importKey(key);\n /* v8 ignore next -- deviceRecordValid imported it already */\n if (!pub) return no(\"a trusted key is unusable\");\n let good = false;\n try {\n good = await crypto.subtle.verify(\n { name: \"ECDSA\", hash: \"SHA-256\" },\n pub,\n u8(raw),\n u8(deviceMessage(purpose, rpId, challenge)),\n );\n } catch {\n /* v8 ignore next -- WebCrypto answers false for a bad signature; a throw is a broken runtime */\n good = false;\n }\n return good ? { ok: true } : no(\"the device key's signature doesn't verify\");\n}\n\n/** One signature over `challenge` by `key`, chosen from the machine's own record of\n * the key, never from the signature: a device key's signature for `purpose`\n * (CONTROL.md \u00A73.2), or a passkey assertion made by a verified person. */\nexport async function verifyAssertion(\n challenge: Uint8Array,\n a: Assertion | DeviceSignature | null | undefined,\n key: TrustedKey,\n rpId: string,\n purpose: DevicePurpose,\n): Promise<Check> {\n if (!a || typeof a !== \"object\") return no(\"no passkey signature\");\n if (key.type !== undefined) {\n if (key.type !== \"device\") return no(\"a trusted key is unusable\");\n return verifyDeviceSignature(challenge, a, key, rpId, purpose);\n }\n return verifyPasskeyAssertion(challenge, a as Assertion, key, rpId);\n}\n\nasync function verifyPasskeyAssertion(\n challenge: Uint8Array,\n a: Assertion,\n key: TrustedKey,\n rpId: string,\n): Promise<Check> {\n if (a.cred !== key.id) return no(\"signed with a key this machine doesn't trust\");\n const cdBytes = fromB64url(a.cd);\n const ad = fromB64url(a.ad);\n const sig = fromB64url(a.sig);\n if (!cdBytes || !ad || !sig?.length) return no(\"the passkey signature is malformed\");\n let cd: { type?: unknown; challenge?: unknown; origin?: unknown; crossOrigin?: unknown };\n try {\n cd = JSON.parse(dec.decode(cdBytes));\n } catch {\n return no(\"the passkey signature is malformed\");\n }\n if (!cd || typeof cd !== \"object\") return no(\"the passkey signature is malformed\");\n if (cd.type !== \"webauthn.get\") return no(\"the passkey answered a different question\");\n if (cd.challenge !== b64url(challenge)) return no(\"the passkey signed something else\");\n if (!originAllowed(cd.origin, rpId)) return no(`the passkey was used on another site, not ${rpId}`);\n if (cd.crossOrigin === true) return no(\"the passkey was used inside another site's frame\");\n if (ad.length < 37) return no(\"the passkey signature is malformed\");\n if (!sameBytes(ad.slice(0, 32), await sha256(rpId))) return no(`the passkey belongs to another site, not ${rpId}`);\n const flags = ad[32] as number;\n if (!(flags & UP) || !(flags & UV)) return no(\"the passkey signed without verifying the person\");\n const pub = await importKey(key);\n if (!pub) return no(\"a trusted key is unusable\");\n const signed = concat(ad, await sha256(cdBytes));\n let good = false;\n try {\n if (key.alg === ES256) {\n const raw = derToRaw(sig);\n good = !!raw && (await crypto.subtle.verify({ name: \"ECDSA\", hash: \"SHA-256\" }, pub, u8(raw), u8(signed)));\n } else {\n good = await crypto.subtle.verify({ name: \"RSASSA-PKCS1-v1_5\" }, pub, u8(sig), u8(signed));\n }\n } catch {\n good = false;\n }\n return good ? { ok: true } : no(\"the passkey signature doesn't verify\");\n}\n\n/** What a passkey signs to enroll on a machine: bound to that machine and that pairing code. */\nexport function pairChallenge(machine: string, code: string): Promise<Uint8Array> {\n return sha256(`sessionpipe.pair:${machine}:${code}`);\n}\n\n/** The enrollment proof: the new key's assertion over pairChallenge(machine, code).\n * Only after this verifies does the key go into the machine's trust store. */\nexport async function verifyEnrollment(o: {\n machine: string;\n code: string;\n key: TrustedKey;\n proof: Assertion | DeviceSignature;\n rpId: string;\n}): Promise<Check> {\n if (!(await keyUsable(o.key))) return no(\"the key is in a shape this machine can't use\");\n return verifyAssertion(await pairChallenge(o.machine, o.code), o.proof, o.key, o.rpId, \"pair\");\n}\n\n// --- the command ------------------------------------------------------------------\n\ntype Parsed = { ok: true; cmd: ControlCommand } | { ok: false; code: RefusalCode; why: string };\nconst bad = (code: RefusalCode, why: string): { ok: false; code: RefusalCode; why: string } => ({\n ok: false,\n code,\n why,\n});\nconst isNum = (n: unknown): n is number => typeof n === \"number\" && Number.isFinite(n);\n\n/** The session id rule per harness (ADAPTERS.md): Claude Code ids are UUIDs. */\nexport function sessionIdOk(harness: string, id: string): boolean {\n if (!SESSION_ID_RE.test(id)) return false;\n if (harness === \"claude-code\") return UUID_RE.test(id);\n return true;\n}\n\n/** Split `<harness>:<id>`; null when either half breaks its rule. */\nexport function parseSessionRef(ref: unknown): { harness: string; id: string } | null {\n if (typeof ref !== \"string\") return null;\n const i = ref.indexOf(\":\");\n if (i <= 0) return null;\n const harness = ref.slice(0, i);\n const id = ref.slice(i + 1);\n return HARNESS_RE.test(harness) && sessionIdOk(harness, id) ? { harness, id } : null;\n}\n\n/** Read the command's fields from the exact string. Structure only; no clock, no keys. */\nexport function parseCommand(str: unknown): Parsed {\n if (typeof str !== \"string\" || !str || str.length > CMD_MAX)\n return bad(\"malformed\", \"the command is missing or too long\");\n let c: Record<string, unknown>;\n try {\n c = JSON.parse(str);\n } catch {\n return bad(\"malformed\", \"the command is not JSON\");\n }\n if (!c || typeof c !== \"object\" || Array.isArray(c)) return bad(\"malformed\", \"the command is not an object\");\n if (c.v !== 1 || c.t !== COMMAND_TYPE) return bad(\"not_a_command\", \"not a sessionpipe control command\");\n if (typeof c.machine !== \"string\" || !MACHINE_RE.test(c.machine)) return bad(\"malformed\", \"which machine?\");\n if (!CONTROL_KINDS.includes(c.kind as ControlKind))\n return bad(\"unknown_kind\", \"the command asks for something unknown\");\n const ref = parseSessionRef(c.session);\n if (!ref) return bad(\"bad_session\", \"which session?\");\n if (typeof c.nonce !== \"string\" || !NONCE_RE.test(c.nonce))\n return bad(\"bad_nonce\", \"the nonce is missing or malformed\");\n if (!isNum(c.iat) || !Number.isInteger(c.iat) || c.iat <= 0)\n return bad(\"malformed\", \"the command has no signing time\");\n const has = (k: string) => c[k] !== undefined;\n const text = () => typeof c.text === \"string\" && c.text.trim().length > 0 && c.text.length <= TEXT_MAX;\n // A handoff's reply_to (CONTROL.md \u00A76): a session ref by the adapter's rule, never the\n // command's own session. Whether that session is on this machine is the daemon's to say.\n const replyToProblem = (): string | null => {\n if (!has(\"reply_to\")) return null;\n if (!parseSessionRef(c.reply_to)) return \"a reply_to names a session on this machine, <harness>:<id>\";\n if (c.reply_to === c.session) return \"a reply_to can't name the command's own session\";\n return null;\n };\n switch (c.kind as ControlKind) {\n case \"prompt\": {\n if (!text()) return bad(\"bad_fields\", `a prompt needs text, at most ${TEXT_MAX} characters`);\n if (has(\"for\") || has(\"decision\") || has(\"cwd\"))\n return bad(\"bad_fields\", \"a prompt carries text, files and a reply_to\");\n if (has(\"files\")) {\n const why = filesProblem(c.files);\n if (why) return bad(\"bad_fields\", why);\n }\n const why = replyToProblem();\n if (why) return bad(\"bad_fields\", why);\n break;\n }\n case \"start\": {\n if (!text()) return bad(\"bad_fields\", `a new session needs text, at most ${TEXT_MAX} characters`);\n if (typeof c.cwd !== \"string\" || !(isAbsolute(c.cwd) || HOME_RELATIVE_RE.test(c.cwd)) || c.cwd.length > 1024)\n return bad(\"bad_fields\", \"a new session needs an absolute folder, or one under ~\");\n if (has(\"for\") || has(\"decision\"))\n return bad(\"bad_fields\", \"a start carries text, cwd, files, a permission, a model and a reply_to\");\n if (has(\"files\")) {\n const why = filesProblem(c.files);\n if (why) return bad(\"bad_fields\", why);\n }\n const why = replyToProblem();\n if (why) return bad(\"bad_fields\", why);\n if (has(\"permission\") && levelRank(c.permission) < 0)\n return bad(\"bad_fields\", `a permission is one of ${START_PERMISSIONS.join(\", \")}`);\n if (has(\"model\") && (typeof c.model !== \"string\" || c.model.length > MODEL_MAX || !MODEL_RE.test(c.model)))\n return bad(\"bad_fields\", `a model is 1 to ${MODEL_MAX} letters, digits and ._:/@[]-, not starting with a dash`);\n break;\n }\n case \"permission.answer\":\n if (typeof c.for !== \"string\" || !c.for || c.for.length > 128) return bad(\"bad_fields\", \"which attention?\");\n if (c.decision !== \"allow\" && c.decision !== \"deny\") return bad(\"bad_fields\", \"allow or deny?\");\n if (has(\"text\") || has(\"cwd\")) return bad(\"bad_fields\", \"a permission answer carries for, decision and note\");\n break;\n case \"cancel\":\n if (has(\"text\") || has(\"for\") || has(\"decision\") || has(\"cwd\"))\n return bad(\"bad_fields\", \"a cancel carries nothing\");\n break;\n case \"key.add\": {\n // A device the machine already trusts vouches for a new one (CONTROL.md \u00A72): the\n // new key's id, algorithm and public key (and, for a device key, its type, store\n // and uv) are inside the signed bytes.\n if (c.session !== KEY_STORE_SESSION) return bad(\"bad_session\", `a key.add names ${KEY_STORE_SESSION}`);\n const k = c.key as Record<string, unknown> | undefined;\n const b64 = (v: unknown, min: number, max: number) =>\n typeof v === \"string\" && v.length >= min && v.length <= max && /^[A-Za-z0-9_-]+$/.test(v);\n if (\n !k ||\n typeof k !== \"object\" ||\n Array.isArray(k) ||\n !b64(k.id, 16, 1400) ||\n (k.alg !== -7 && k.alg !== -257) ||\n !b64(k.spki, 40, 2000)\n )\n return bad(\"bad_fields\", \"a key.add carries the key: id, alg (-7 or -257) and spki\");\n if (k.type !== undefined) {\n if (k.type !== \"device\") return bad(\"bad_fields\", \"a key's type is device, or absent for a passkey\");\n if (k.alg !== ES256 || k.store !== \"hardware\" || k.uv !== \"each-use\" || !SHA256_RE.test(k.id as string))\n return bad(\"bad_fields\", \"a device key is ES256, store hardware, uv each-use, named by its SPKI's hash\");\n if (Object.keys(k).some((f) => !DEVICE_FIELDS.has(f)))\n return bad(\"bad_fields\", \"a device key carries id, alg, spki, type, store and uv\");\n } else if (Object.keys(k).some((f) => !PASSKEY_FIELDS.has(f)))\n return bad(\"bad_fields\", \"a passkey carries id, alg and spki: store and uv belong to a device key\");\n if (has(\"name\") && (typeof c.name !== \"string\" || !c.name.trim() || c.name.length > 80))\n return bad(\"bad_fields\", \"a device name is text, at most 80 characters\");\n if (has(\"text\") || has(\"for\") || has(\"decision\") || has(\"cwd\"))\n return bad(\"bad_fields\", \"a key.add carries the key and a name\");\n break;\n }\n case \"pool\": {\n if (c.session !== POOL_SESSION) return bad(\"bad_session\", `a pool command names ${POOL_SESSION}`);\n const why = poolProblem(c);\n if (why) return bad(\"bad_fields\", why);\n break;\n }\n }\n if (c.kind !== \"key.add\" && (has(\"key\") || has(\"name\"))) return bad(\"bad_fields\", \"only a key.add carries a key\");\n if (c.kind !== \"pool\" && POOL_FIELDS.some(has)) return bad(\"bad_fields\", \"only a pool command carries pool fields\");\n if (c.kind !== \"start\" && c.kind !== \"prompt\" && has(\"files\"))\n return bad(\"bad_fields\", \"only a start or a prompt carries files\");\n if (c.kind !== \"start\" && c.kind !== \"prompt\" && has(\"reply_to\"))\n return bad(\"bad_fields\", \"only a start or a prompt carries a reply_to\");\n if (c.kind !== \"start\" && (has(\"permission\") || has(\"model\")))\n return bad(\"bad_fields\", \"only a start carries a model or a permission\");\n const allowed = FIELDS[c.kind as ControlKind];\n for (const k of Object.keys(c))\n if (!COMMON_FIELDS.includes(k) && !allowed.includes(k))\n return bad(\"bad_fields\", `the command carries a field its kind doesn't have: ${k.slice(0, 40)}`);\n if (has(\"note\") && (typeof c.note !== \"string\" || c.note.length > NOTE_MAX))\n return bad(\"bad_fields\", `a note is text, at most ${NOTE_MAX} characters`);\n return { ok: true, cmd: c as unknown as ControlCommand };\n}\n\n/** Why a `pool` command's fields break the rules (CONTROL.md \u00A76 `pool`), or null when\n * they don't. Each action takes exactly its own fields: an account where the action\n * names one, the whole order for `order`, the pasted code for `login.complete`. The\n * machine still checks the account exists and the order is complete (`refused`). */\nexport function poolProblem(c: Record<string, unknown>): string | null {\n const action = c.pool_action;\n if (!POOL_ACTIONS.includes(action as PoolAction))\n return `a pool command's action is one of ${POOL_ACTIONS.join(\", \")}`;\n const a = action as PoolAction;\n const account = c.pool_account !== undefined;\n const order = c.pool_order !== undefined;\n const code = c.pool_code !== undefined;\n const needsAccount = a === \"enable\" || a === \"disable\" || a === \"remove\" || a === \"login.complete\";\n if (needsAccount && !account) return `${a} names an account`;\n if (account && !needsAccount && a !== \"refresh\") return `${a} names no account`;\n if (account && (typeof c.pool_account !== \"string\" || !POOL_ACCOUNT_RE.test(c.pool_account)))\n return \"an account id is 1 to 128 letters, digits and ._:-\";\n if (order !== (a === \"order\")) return a === \"order\" ? \"order carries the whole order\" : `${a} carries no order`;\n if (order) {\n const o = c.pool_order;\n if (!Array.isArray(o) || o.length < 1 || o.length > POOL_ORDER_MAX)\n return `an order is a list of 1 to ${POOL_ORDER_MAX} account ids`;\n if (!o.every((id) => typeof id === \"string\" && POOL_ACCOUNT_RE.test(id)))\n return \"an account id is 1 to 128 letters, digits and ._:-\";\n if (new Set(o).size !== o.length) return \"an order names each account once\";\n }\n if (code !== (a === \"login.complete\"))\n return a === \"login.complete\" ? \"login.complete carries the pasted code\" : `${a} carries no code`;\n if (\n code &&\n (typeof c.pool_code !== \"string\" ||\n !c.pool_code ||\n c.pool_code.length > POOL_CODE_MAX ||\n /[\\r\\n]/.test(c.pool_code))\n )\n return `a code is 1 to ${POOL_CODE_MAX} characters on one line`;\n return null;\n}\n\n/** Why a start's or a prompt's `files` breaks the rules (CONTROL.md \u00A73.1), or null when it doesn't. */\nexport function filesProblem(files: unknown): string | null {\n if (!Array.isArray(files) || files.length < 1 || files.length > FILES_MAX)\n return `files is a list of 1 to ${FILES_MAX} files`;\n const seen = new Set<string>();\n let total = 0;\n for (const f of files as unknown[]) {\n if (!f || typeof f !== \"object\" || Array.isArray(f)) return \"each file is an object\";\n const { name, type, size, sha256: hash } = f as Record<string, unknown>;\n const why = fileNameProblem(name);\n if (why) return why;\n const key = (name as string).normalize(\"NFC\").toLowerCase();\n if (seen.has(key)) return \"two files have the same name\";\n seen.add(key);\n if (typeof type !== \"string\" || type.length > FILE_TYPE_MAX || !MEDIA_TYPE_RE.test(type))\n return \"a file's type isn't a media type\";\n if (!isNum(size) || !Number.isInteger(size) || size < 1 || size > FILE_SIZE_MAX)\n return `a file is 1 byte to ${FILE_SIZE_MAX / 1_048_576} MiB`;\n total += size;\n if (typeof hash !== \"string\" || !SHA256_RE.test(hash)) return \"a file's sha256 isn't 43 base64url characters\";\n }\n if (total > FILES_TOTAL_MAX) return `the files add up to more than ${FILES_TOTAL_MAX / 1_048_576} MiB`;\n return null;\n}\n\n/** A file name the machine can write inside the session's folder and nowhere else. */\nfunction fileNameProblem(name: unknown): string | null {\n if (typeof name !== \"string\") return \"a file has no name\";\n const n = name.normalize(\"NFC\");\n if (n.length < 1 || n.length > FILE_NAME_MAX) return `a file name is 1 to ${FILE_NAME_MAX} characters`;\n if (BAD_NAME_CHAR_RE.test(n)) return \"a file name has a slash, a backslash or a control character\";\n if (n.startsWith(\".\")) return \"a file name can't start with a dot\";\n return null;\n}\n\n/** A `start`'s `cwd` under the machine's home: `~` alone, or `~/\u2026` (`~\\\u2026`). Never `~user`. */\nexport const HOME_RELATIVE_RE = /^~(?:[\\\\/]|$)/;\n\nfunction isAbsolute(p: string): boolean {\n return p.startsWith(\"/\") || /^[A-Za-z]:[\\\\/]/.test(p);\n}\n\n/** The grant's fields, read from its exact string. */\nexport function parseGrant(str: unknown, rpId: string): { ok: true; grant: Grant } | { ok: false; why: string } {\n if (typeof str !== \"string\" || !str || str.length > GRANT_STR_MAX)\n return { ok: false, why: \"the grant is missing or too long\" };\n let g: Record<string, unknown>;\n try {\n g = JSON.parse(str);\n } catch {\n return { ok: false, why: \"the grant is not JSON\" };\n }\n if (!g || typeof g !== \"object\" || Array.isArray(g)) return { ok: false, why: \"the grant is not an object\" };\n if (g.v !== 1 || g.t !== GRANT_TYPE) return { ok: false, why: \"not a sessionpipe grant\" };\n if (g.rp !== rpId) return { ok: false, why: `the grant is for another site, not ${rpId}` };\n if (typeof g.pub !== \"string\" || !fromB64url(g.pub)?.length || !isNum(g.iat) || !isNum(g.exp))\n return { ok: false, why: \"the grant is missing parts\" };\n if (g.exp <= g.iat) return { ok: false, why: \"the grant ends before it starts\" };\n if (g.exp - g.iat > GRANT_MAX_MS + SKEW_MS) return { ok: false, why: \"the grant lasts longer than a day\" };\n return { ok: true, grant: g as unknown as Grant };\n}\n\nasync function verifyCsig(cmd: string, csig: unknown, pub: string): Promise<boolean> {\n const sig = fromB64url(csig);\n const spki = fromB64url(pub);\n if (sig?.length !== 64 || !spki) return false;\n try {\n const key = await crypto.subtle.importKey(\"spki\", u8(spki), { name: \"ECDSA\", namedCurve: \"P-256\" }, false, [\n \"verify\",\n ]);\n return await crypto.subtle.verify({ name: \"ECDSA\", hash: \"SHA-256\" }, key, u8(sig), u8(enc.encode(cmd)));\n } catch {\n return false;\n }\n}\n\n/**\n * Is this a command this machine may run? The checks, in the spec's order\n * (CONTROL.md \u00A75): the exact bytes parse; the command is for this machine; it is\n * signed \u2014 a grant from a trusted key plus the day key's signature, or a confirm\n * over sha256(cmd); it was signed within the age window; its nonce is new.\n * The folder and open-attention checks that follow are the daemon's (they read\n * the machine, not the command).\n */\nexport async function verifyCommand(s: SignedCommand | null | undefined, o: VerifyOptions): Promise<Verdict> {\n if (!s || typeof s !== \"object\") return bad(\"malformed\", \"nothing to verify\");\n const p = parseCommand(s.cmd);\n if (!p.ok) return p;\n const c = p.cmd;\n if (c.machine !== o.machine) return bad(\"wrong_machine\", \"the command is for another machine\");\n\n let via: \"grant\" | \"confirm\" | null = null;\n let keyId = \"\";\n let refusal: { code: RefusalCode; why: string } | null = null;\n if (s.grant && s.csig) {\n const r = await checkGrantPath(s, c, o);\n if (r.ok) {\n via = \"grant\";\n keyId = r.key;\n } else refusal = r;\n }\n if (!via && s.confirm) {\n const key = o.trusted.find((k) => k && k.id === s.confirm?.cred);\n if (!key) refusal = { code: \"untrusted_key\", why: \"confirmed with a key this machine doesn't trust\" };\n else {\n const a = await verifyAssertion(await sha256(s.cmd), s.confirm, key, o.rpId, \"confirm\");\n if (a.ok) {\n via = \"confirm\";\n keyId = key.id;\n } else refusal = { code: \"bad_assertion\", why: a.why };\n }\n }\n if (!via) {\n if (refusal) return bad(refusal.code, refusal.why);\n return bad(\"unsigned\", \"the command isn't signed\");\n }\n // The key a key.add brings must be one this machine could ever verify with: an\n // SPKI it can import for that alg, and every rule of a device key (CONTROL.md \u00A72).\n if (c.kind === \"key.add\" && !(await keyUsable(c.key as TrustedKey)))\n return bad(\"bad_fields\", \"the key a key.add brings is in a shape this machine can't use\");\n if (c.iat > o.now + SKEW_MS) return bad(\"future\", \"the command is dated in the future (is this clock right?)\");\n if (o.now - c.iat > (o.maxAgeMs ?? MACHINE_MAX_AGE_MS)) return bad(\"too_old\", \"the command was signed too long ago\");\n if (o.seenNonce) {\n let seen: boolean;\n try {\n seen = await o.seenNonce(c.nonce);\n } catch {\n return bad(\"nonce_store\", \"the nonce couldn't be recorded, so the command didn't run\");\n }\n if (seen) return bad(\"replay\", \"this command was already used once\");\n }\n return { ok: true, cmd: c, via, key: keyId };\n}\n\nasync function checkGrantPath(\n s: SignedCommand,\n c: ControlCommand,\n o: VerifyOptions,\n): Promise<{ ok: true; key: string } | { ok: false; code: RefusalCode; why: string }> {\n const bundle = s.grant as GrantBundle | DeviceGrant;\n const g = parseGrant(bundle.str, o.rpId);\n if (!g.ok) return bad(\"bad_grant\", g.why);\n const key = o.trusted.find((k) => k && k.id === bundle.cred);\n if (!key) return bad(\"untrusted_key\", \"the grant was signed with a key this machine doesn't trust\");\n const a = await verifyAssertion(await sha256(bundle.str), bundle, key, o.rpId, \"grant\");\n if (!a.ok) return bad(\"bad_assertion\", a.why);\n if (!(await verifyCsig(s.cmd, s.csig, g.grant.pub)))\n return bad(\"bad_csig\", \"the command's signature doesn't verify \u2014 it was changed after it was signed\");\n if (c.iat < g.grant.iat - SKEW_MS || c.iat > g.grant.exp)\n return bad(\"outside_grant\", \"the command was signed outside its grant's window\");\n return { ok: true, key: key.id };\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// pii@1 \u2014 an opt-in second pass that reduces identifiers (spec/PRIVACY.md \u00A72). It\n// does not promise anonymity; it removes the obvious.\nimport { createHash } from \"node:crypto\";\n\nexport const RULESET_PII = \"pii@1\";\n\nconst EMAIL = /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\\b/g;\n/** E.164 and common national forms: an optional +, 7\u201315 digits with separators,\n * optional area-code parentheses. A version number (22.23.1) or an IP never matches:\n * the run must not sit between dots, and needs \u2265 7 digits. An ISO date (2026-10-31)\n * has a phone's shape, so it is tried first (group 1) and kept, but only when nothing\n * after it could carry the run on: no letter or digit, and no separator then two digits\n * (a phone's group is two to four; one digit, as in \"2026-10-31 5 files\", never is),\n * unless that is a time's hour (\" 12:\", 00\u201323), and not right after a \")\" or a \"+\"\n * with a country code: a phone's prefix this pass could not take (\"x(415) 2026-10-31\",\n * \"[phone]+1 2026-10-31\") would take the date on the next one. Any other date is read\n * as before. The date may follow a `+` (a diff's added line), so a second pass over\n * \"[phone]+2026-10-31\" keeps it too. */\nconst PHONE =\n /(?<![\\w.])(?:(?<!\\)[ .-]?|\\+\\d{1,3}[ .-]?)(\\+?(?:19|20)\\d{2}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\\d|3[01]))(?:(?= (?:[01]?\\d|2[0-3]):)|(?!\\w|[ .-]\\d\\d))|(?:\\+\\d{1,3}[ .-]?)?(?:\\(\\d{2,4}\\)[ .-]?)?\\d{2,4}(?:[ .-]?\\d{2,4}){1,3}(?!\\w))/g;\n\nfunction looksPhone(s: string): boolean {\n const digits = s.replace(/\\D/g, \"\");\n if (digits.length < 7 || digits.length > 15) return false;\n // \"port 8891, pr 12345\": a bare run with no separator or + is a number, not a phone.\n if (!/[+() .-]/.test(s)) return false;\n // \"22.23.1\", \"185.199.108.153\": dots alone are a version or an address.\n if (!/[+() -]/.test(s)) return false;\n return true;\n}\n\n/** Replace emails and phone numbers, and write `home` as `~`. */\nexport function reducePii(text: string, home?: string): string {\n if (!text) return text;\n let out = text.replace(EMAIL, \"[email]\");\n out = out.replace(PHONE, (m, date?: string) => (!date && looksPhone(m) ? \"[phone]\" : m));\n if (home) {\n const h = home.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n out = out.replace(new RegExp(`(?<![A-Za-z0-9_])${h}(?=/|$|\\\\s|[\"'\\`])`, \"g\"), \"~\");\n }\n return out;\n}\n\n/** The machine's name under pii@1: the first 8 hex of its SHA-256. */\nexport function hashMachine(name: string): string {\n return createHash(\"sha256\").update(name).digest(\"hex\").slice(0, 8);\n}\n\n/** Apply pii@1 to every string in a value; `home` becomes `~`. */\nexport function reducePiiDeep<T>(v: T, home?: string): T {\n if (typeof v === \"string\") return reducePii(v, home) as T;\n if (Array.isArray(v)) return v.map((x) => reducePiiDeep(x, home)) as T;\n if (v && typeof v === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [k, x] of Object.entries(v as Record<string, unknown>)) out[k] = reducePiiDeep(x, home);\n return out as T;\n }\n return v;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// secrets@1 \u2014 credentials out of every string, on the person's machine, before an\n// event reaches the outbox. Ported from spacesheep-cli lib/redact.js (Michael\n// Makarov, MIT \u2192 Apache-2.0, see NOTICE). The ruleset is defined in\n// spec/PRIVACY.md \u00A72 and pinned by conformance/redaction/secrets.json.\n//\n// Every pattern is linear: bounded repetition, no nested quantifiers. The\n// adversarial vectors (password_ \u00D7 5000, a 50 000-space run) pin that.\n\nexport const RULESET_SECRETS = \"secrets@1\";\nexport const REDACTED = \"[redacted]\";\n\n/** Token formats that are a credential by their shape alone. Each is anchored on a\n * vendor prefix, so a commit sha or a UUID never matches. */\nconst TOKEN_PATTERNS: RegExp[] = [\n /-----BEGIN [A-Z0-9 ]*PRIVATE KEY(?: BLOCK)?-----[\\s\\S]*?(?:-----END [A-Z0-9 ]*PRIVATE KEY(?: BLOCK)?-----|$)/g,\n /\\b(?:AKIA|ASIA|ABIA|ACCA)[0-9A-Z]{16}\\b/g, // AWS access key id\n /\\bgh[pousr]_[A-Za-z0-9]{30,}\\b/g, // GitHub\n /\\bgithub_pat_[A-Za-z0-9_]{30,}\\b/g,\n /\\bglpat-[A-Za-z0-9_-]{20,}\\b/g, // GitLab\n /\\bxox[abposre]-[A-Za-z0-9-]{10,}\\b/g, // Slack\n /\\bhttps:\\/\\/hooks\\.slack\\.com\\/services\\/[A-Za-z0-9/_-]+/g,\n /\\bhttps:\\/\\/(?:ptb\\.|canary\\.)?discord(?:app)?\\.com\\/api\\/webhooks\\/[0-9]+\\/[A-Za-z0-9_-]+/g,\n /\\bsk-(?:ant-|proj-|svcacct-|admin-|or-v1-)?[A-Za-z0-9_-]{20,}\\b/g, // Anthropic, OpenAI, DeepSeek, OpenRouter\n /\\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\\b/g, // Stripe secret / restricted\n /\\bwhsec_[A-Za-z0-9+/=]{20,}/g, // Stripe / Svix / Standard Webhooks secret\n /\\bAIza[0-9A-Za-z_-]{35}\\b/g, // Google API key\n /\\bya29\\.[0-9A-Za-z_-]{20,}/g, // Google OAuth access token\n /\\b1\\/\\/0[0-9A-Za-z_-]{30,}/g, // Google OAuth refresh token\n /\\bGOCSPX-[0-9A-Za-z_-]{20,}/g, // Google OAuth client secret\n /\\bxai-[A-Za-z0-9]{30,}\\b/g,\n /\\bgsk_[A-Za-z0-9]{30,}\\b/g, // Groq\n /\\bpplx-[A-Za-z0-9]{30,}\\b/g, // Perplexity\n /\\bhf_[A-Za-z0-9]{30,}\\b/g, // Hugging Face\n /\\bpcsk_[A-Za-z0-9_]{30,}\\b/g, // Pinecone\n /\\bnpm_[A-Za-z0-9]{30,}\\b/g,\n /\\bpypi-[A-Za-z0-9_-]{50,}/g,\n /\\bSG\\.[A-Za-z0-9_-]{16,}\\.[A-Za-z0-9_-]{16,}/g, // SendGrid\n /\\bshp(?:at|ss|ca|pa)_[a-fA-F0-9]{32}\\b/g, // Shopify\n /\\bdop_v1_[a-f0-9]{64}\\b/g, // DigitalOcean\n /\\b(?:lin_api|lin_oauth)_[A-Za-z0-9]{30,}\\b/g, // Linear\n /\\b(?:ntn|secret)_[A-Za-z0-9]{40,}\\b/g, // Notion\n /\\bsbp_[a-f0-9]{40}\\b/g, // Supabase\n /\\bfigd_[A-Za-z0-9_-]{30,}/g, // Figma\n /\\bdp\\.(?:pt|st|sa|ct)\\.[A-Za-z0-9]{30,}/g, // Doppler\n /\\bgrn_[A-Za-z0-9_-]{20,}/g, // Granola\n /\\bss_[a-f0-9]{32,}\\b/g, // spacesheep API keys\n /\\b[0-9]{8,10}:AA[A-Za-z0-9_-]{33}\\b/g, // Telegram bot token\n /\\beyJ[A-Za-z0-9_-]{10,}\\.eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}/g, // JWT\n];\n/** `scheme://user:password@host` \u2014 the password goes, the user and host stay. */\nconst URL_CREDENTIALS = /\\b([a-z][a-z0-9+.-]{1,20}:\\/\\/[^\\s:/@'\"`<>]{1,100}:)([^\\s@/'\"`<>]{1,200})(@)/gi;\n/** `Authorization: Bearer \u2026` / `Basic \u2026`, and a bare `Bearer <token>` in a curl line. */\nconst AUTH_HEADER = /\\b((?:Bearer|Basic|Token)\\s+)([A-Za-z0-9._~+/=-]{16,})/g;\n// The words that name a secret, in prose. `key` alone is too common (\"the key\n// point\"), so it only counts with a qualifier.\nconst SECRET_WORD =\n \"(?:pass(?:word|wd|phrase|code)?s?|pwd|secret(?:[ _-]?key)?s?|client[ _-]?secret|api[ _-]?keys?|apikeys?|access[ _-]?keys?|access[ _-]?tokens?|auth[ _-]?tokens?|refresh[ _-]?tokens?|private[ _-]?keys?|tokens?|credentials?|creds)\";\n/** Strict form: a NAME, an explicit separator (`=`, `:`, `=>`), a value. The name is\n * one flat run of identifier characters judged in code (isSecretName), never by a\n * nested pattern. Only a secret name goes on to consume its value \u2014 otherwise\n * `https:` would swallow the `?token=\u2026` behind it. */\nconst NAME_SEP = /(?<![A-Za-z0-9_])([A-Za-z][A-Za-z0-9_-]{1,79})([\"']?\\s{0,3}(?::=|=>|=|:)\\s{0,3})/g;\nconst VALUE = /\"([^\"\\n]{1,300})\"|'([^'\\n]{1,300})'|`([^`\\n]{1,300})`|([^\\s\"'`,;&)}\\]]{1,300})/y;\n\nfunction redactAssignments(text: string): string {\n let out = \"\";\n let last = 0;\n NAME_SEP.lastIndex = 0;\n for (let m = NAME_SEP.exec(text); m; m = NAME_SEP.exec(text)) {\n const name = m[1] as string;\n if (!isSecretName(name)) continue;\n VALUE.lastIndex = NAME_SEP.lastIndex;\n const v = VALUE.exec(text);\n if (!v) continue;\n const value = (v[1] ?? v[2] ?? v[3] ?? v[4]) as string;\n NAME_SEP.lastIndex = VALUE.lastIndex;\n if (isPlaceholder(value) || value.includes(REDACTED)) continue;\n // `max_tokens: 4096`, `input_tokens=12k` \u2014 a token COUNT, not a token.\n if (/tokens?$/i.test(name) && /^\\d+(?:[.,]\\d+)*[km]?$/i.test(value)) continue;\n const q = v[1] != null ? '\"' : v[2] != null ? \"'\" : v[3] != null ? \"`\" : \"\";\n out += text.slice(last, v.index) + q + REDACTED + q;\n last = VALUE.lastIndex;\n }\n return last ? out + text.slice(last) : text;\n}\n\n/** Is this identifier the name of a secret? `DB_PASSWORD`, `apiKey`, `client-secret`,\n * `AWS_SECRET_ACCESS_KEY`, `GITHUB_TOKEN`; an env-style `STRIPE_KEY` too. Not\n * `password_hash`, `tokenizer`, `sort_key`. */\nexport function isSecretName(name: string): boolean {\n if (/^[A-Z0-9_]+_KEY$/.test(name)) return true;\n const flat = name.toLowerCase().replace(/[_-]/g, \"\");\n return /(?:pass(?:word|wd|phrase|code)|pwd|secret|secretkey|secretaccesskey|clientsecret|apikey|accesskey|accesstoken|authtoken|refreshtoken|privatekey|token|credential|creds)s?$/.test(\n flat,\n );\n}\n\n/** Loose form: prose. \"password is Hunter2!\", \"the token was ghx\u2026\". Only a value\n * that looks generated counts, so \"the password is wrong\" passes untouched.\n * Whitespace runs are bounded so a long run can't make the match quadratic. */\nconst PROSE = new RegExp(\n `(\\\\b${SECRET_WORD}(?:[ \\\\t]{1,3}(?:is|was|=|:|to|as|of|for[ \\\\t]{1,3}\\\\S{1,40}[ \\\\t]{1,3}is))?[ \\\\t]{1,3})([\"'\\`]?)([^\\\\s\"'\\`]{6,200})\\\\2`,\n \"gi\",\n);\n\n/** A value that is plainly not the secret itself: a type, a variable, a template, an\n * already-redacted marker, an env lookup. */\nfunction isPlaceholder(v: string): boolean {\n const s = v.replace(/[.,;:!?]+$/, \"\");\n if (!s) return true;\n if (\n /^(?:string|number|boolean|bool|str|int|any|unknown|null|undefined|none|nil|true|false|optional|required|text|varchar|password|secret|token|env|string\\[\\]|object|bytes)$/i.test(\n s,\n )\n )\n return true;\n if (/^\\[?redacted\\]?$/i.test(s) || /^\\*+$/.test(s) || /^x{3,}$/i.test(s) || /^\\.{3}$|^\u2026$/.test(s)) return true;\n if (/^[<{$%]/.test(s)) return true; // <your-key>, ${VAR}, {{var}}, $VAR, %VAR%\n if (\n /^(?:process\\.env|env|os\\.environ|c\\.env|this\\.env|import\\.meta\\.env|getenv|config|settings|secrets|args|opts|options|req|request|body|params|input|data|user|self|this)\\b/i.test(\n s,\n )\n )\n return true;\n if (/^[A-Za-z_$][\\w$]*(?:\\.[A-Za-z_$][\\w$]*)+$/.test(s)) return true; // a member path: form.password\n if (/[(]/.test(s)) return true; // a call: hash(pw), getSecret()\n if (/^(?:your|my|the|a|an|some|new|old)[-_ ]/i.test(s)) return true; // your-api-key\n return false;\n}\n\n/** Does a prose value look like something generated, rather than an English word? */\nfunction looksSecret(v: string): boolean {\n const s = v.replace(/[.,;:!?)]+$/, \"\");\n if (s.length < 6) return false;\n if (isPlaceholder(s)) return false;\n if (/^https?:\\/\\//i.test(s)) return false; // a link, handled by URL_CREDENTIALS if it carries one\n if (/^[a-z]+(?:[-'][a-z]+)*$/.test(s)) return false; // a lowercase word\n if (/^[A-Z][a-z]+$/.test(s)) return false; // a capitalised word\n if (/^\\d+(?:[.,]\\d+)*[a-z%]*$/i.test(s)) return false; // a count: 4096, 128k, 3.5, 50%\n if (/^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+$/.test(s)) return false; // an env var's NAME\n const kinds = [/[a-z]/, /[A-Z]/, /[0-9]/, /[^A-Za-z0-9]/].filter((r) => r.test(s)).length;\n return kinds >= 3 || (/[0-9]/.test(s) && /[A-Za-z]/.test(s));\n}\n\n/** Redact every credential in `text`. Returns the same string when there is none. */\nexport function redactSecrets(text: string): string {\n if (!text) return text;\n let out = text;\n for (const re of TOKEN_PATTERNS) out = out.replace(re, REDACTED);\n out = out.replace(URL_CREDENTIALS, (_m, head: string, _pw: string, at: string) => `${head}${REDACTED}${at}`);\n out = out.replace(AUTH_HEADER, (_m, head: string) => `${head}${REDACTED}`);\n out = redactAssignments(out);\n out = out.replace(PROSE, (m, head: string, q: string, v: string) =>\n !looksSecret(v) || v.includes(REDACTED) ? m : `${head}${q}${REDACTED}${q}`,\n );\n return out;\n}\n\n/** Did redaction change anything? */\nexport function hasSecret(text: string): boolean {\n return !!text && redactSecrets(text) !== text;\n}\n\n/** Redact every string in a JSON-able value (keys are left alone). */\nexport function redactDeep<T>(v: T): T {\n if (typeof v === \"string\") return redactSecrets(v) as T;\n if (Array.isArray(v)) return v.map(redactDeep) as T;\n if (v && typeof v === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [k, x] of Object.entries(v as Record<string, unknown>)) out[k] = redactDeep(x);\n return out as T;\n }\n return v;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// Codex CLI (OpenAI) \u2014 docs: https://learn.chatgpt.com/docs/hooks\n// Config: ~/.codex/hooks.json (Claude-shaped, 12 events, timeouts in seconds) AND\n// `notify` at the top level of config.toml as the fallback when hooks are off or\n// not yet trusted (non-managed hooks need a /hooks review in the CLI). An existing\n// notify (Codex Computer Use) is chained through --previous-notify, never replaced.\nimport { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { homeDir } from \"../paths.js\";\nimport { ends, parseLines, recentFiles, scanLines } from \"../readers/files.js\";\nimport { codexInjected, readCodex } from \"../readers/transcripts.js\";\nimport type { DataOf } from \"../types.js\";\nimport { installClaudeShaped, installedClaudeShaped, uninstallClaudeShaped, writeBack } from \"./claude-shaped.js\";\nimport * as toml from \"./codex-config.js\";\nimport { codexReplayBoundary, codexSubagent } from \"./codex-rollout.js\";\nimport type {\n Adapter,\n BackfillRow,\n HookCommand,\n HookInput,\n HookResult,\n InstalledReport,\n InstallOptions,\n InstallReport,\n SessionFacts,\n} from \"./types.js\";\n\nconst NAME = \"codex\";\nexport const CODEX_EVENTS = [\n \"SessionStart\",\n \"UserPromptSubmit\",\n \"PreToolUse\",\n \"PostToolUse\",\n \"PermissionRequest\",\n \"Stop\",\n \"Interrupt\",\n \"SubagentStart\",\n \"SubagentStop\",\n \"PreCompact\",\n \"PostCompact\",\n \"SessionEnd\",\n] as const;\nconst OPTS = { matcherFor: (e: string) => (/Tool|Permission/.test(e) ? \"\" : undefined), timeout: 5 };\nconst eventsFor = (lean?: boolean) => (lean ? CODEX_EVENTS.filter((e) => e !== \"PreToolUse\") : [...CODEX_EVENTS]);\n\nconst codexHome = (env: NodeJS.ProcessEnv) => env.CODEX_HOME || path.join(homeDir(), \".codex\");\nconst hooksFile = (env: NodeJS.ProcessEnv) => path.join(codexHome(env), \"hooks.json\");\nconst configFile = (env: NodeJS.ProcessEnv) => path.join(codexHome(env), \"config.toml\");\nconst sessionsDir = (env: NodeJS.ProcessEnv) => path.join(codexHome(env), \"sessions\");\n\nconst validTool = (n: unknown): n is string => typeof n === \"string\" && /^[A-Za-z0-9_.:-]{1,120}$/.test(n);\nconst endReason = (r: unknown): \"clear\" | \"logout\" | \"exit\" | \"other\" =>\n r === \"clear\" || r === \"logout\" || r === \"exit\" ? r : \"other\";\n\n/** What config.toml without our notify line means, said with every refusal of it. */\nconst UNTIL_APPROVED =\n \"Codex will report nothing until you approve the hooks: start `codex` and accept the hook review\";\n\nfunction installNotify(cmd: HookCommand, env: NodeJS.ProcessEnv) {\n const file = configFile(env);\n let text = \"\";\n let existed = true;\n try {\n text = readFileSync(file, \"utf8\");\n } catch (e) {\n // Absent only when the system says so: a file that is there but can't be read (0200,\n // root's) is still the person's, never `created` for uninstall to delete.\n existed = (e as NodeJS.ErrnoException).code !== \"ENOENT\";\n }\n const argv = cmd([NAME, \"notify\"]).argv;\n const line = `notify = ${JSON.stringify(argv)}`;\n const n = toml.readNotify(text);\n /** The file written, with this note; or the refusal's report in its place. */\n const write = (next: string, note: string): InstallReport => {\n const bad = writeBack(file, next, existed);\n return bad ? { ...bad, note: `${bad.note}. ${UNTIL_APPROVED}` } : { file, changed: true, note };\n };\n if (n && !n.other) {\n if (!n.misplaced && JSON.stringify(n.argv) === JSON.stringify(argv))\n return { file, changed: false, note: \"notify current\" };\n return write(\n toml.withNotify(text, line),\n n.misplaced\n ? \"notify moved to the top level (it sat inside a [table], where Codex never reads it)\"\n : \"notify updated\",\n );\n }\n if (n?.other) {\n const prev = toml.previousNotify(n.argv);\n if (toml.isComputerUse(n.argv)) {\n if (prev && toml.OURS.test(JSON.stringify(prev))) {\n if (JSON.stringify(prev) === JSON.stringify(argv))\n return { file, changed: false, note: \"notify current (after Codex Computer Use)\" };\n }\n if (!prev || toml.OURS.test(JSON.stringify(prev)))\n return write(\n toml.replaceNotify(text, n, `notify = ${toml.withPreviousRaw(n.raw, argv)}`),\n \"chained after Codex Computer Use (--previous-notify)\",\n );\n }\n return {\n file,\n changed: false,\n skipped: true,\n note: `notify belongs to ${(n.argv?.[0] ?? n.raw).replace(/^.*\\//, \"\").slice(0, 40)}; left alone. ${UNTIL_APPROVED}`,\n };\n }\n return write(toml.withNotify(text, line), \"notify set at the top level\");\n}\n\nfunction uninstallNotify(env: NodeJS.ProcessEnv): InstallReport {\n const file = configFile(env);\n let text: string;\n try {\n text = readFileSync(file, \"utf8\");\n } catch {\n return { file, changed: false };\n }\n const n = toml.readNotify(text);\n if (!n) return { file, changed: false };\n if (!n.other) return writeBack(file, toml.withoutNotify(text)) ?? { file, changed: true };\n const prev = toml.previousNotify(n.argv);\n if (toml.isComputerUse(n.argv) && prev && toml.OURS.test(JSON.stringify(prev)))\n return (\n writeBack(file, toml.replaceNotify(text, n, `notify = ${toml.stripPreviousRaw(n.raw)}`)) ?? {\n file,\n changed: true,\n }\n );\n return { file, changed: false };\n}\n\n/** The rollout file of one thread: `<CODEX_HOME>/sessions/YYYY/MM/DD/rollout-<time>-<thread\n * id>.jsonl`, newest day first. Null for an id that isn't a thread id's shape, so a\n * short or odd one never matches some other session's file. */\nexport function findRollout(threadId: string, env: NodeJS.ProcessEnv = process.env): string | null {\n if (!/^[A-Za-z0-9-]{8,128}$/.test(threadId)) return null;\n let best: string | null = null;\n const walk = (dir: string, depth: number) => {\n let names: string[] = [];\n try {\n names = readdirSync(dir);\n } catch {\n return;\n }\n for (const n of names.sort().reverse()) {\n const p = path.join(dir, n);\n if (n.endsWith(`-${threadId}.jsonl`)) {\n best = p;\n return;\n }\n if (depth < 3) {\n walk(p, depth + 1);\n if (best) return;\n }\n }\n };\n walk(sessionsDir(env), 0);\n return best;\n}\n\n/** A rollout's first record, its own session_meta. About 50 KB (it carries the base\n * instructions), so it is read on its own rather than from a sampled head. */\nfunction rolloutMeta(file: string): Record<string, unknown> | null {\n return scanLines(file, (line) => parseLines([line])[0] ?? {});\n}\n\n/** A rollout named for a thread other than `id` (`rollout-<time>-<thread id>.jsonl`).\n * A name of any other shape says nothing, so it is not taken for another thread's. */\nfunction ofAnotherThread(file: string, id: string): boolean {\n const other = threadOf(file);\n return !!other && other !== id.toLowerCase();\n}\n/** The thread a rollout is named for, lowercased; null for a name of any other shape. */\nfunction threadOf(file: string): string | null {\n const m = /-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\\.jsonl(?:\\.zst)?$/i.exec(file);\n return m?.[1] ? m[1].toLowerCase() : null;\n}\n\nexport const codex: Adapter = {\n name: NAME,\n events: CODEX_EVENTS,\n detect: (env = process.env) => existsSync(codexHome(env)),\n configFiles: (env = process.env) => [hooksFile(env), configFile(env)],\n install: (cmd, env = process.env, opts: InstallOptions = {}) => [\n installClaudeShaped(hooksFile(env), NAME, eventsFor(opts.lean), cmd, OPTS),\n installNotify(cmd, env),\n ],\n uninstall: (env = process.env, opts: InstallOptions = {}) => [\n uninstallClaudeShaped(hooksFile(env), CODEX_EVENTS, { created: opts.created?.includes(hooksFile(env)) }),\n uninstallNotify(env),\n ],\n installed: (cmd, env = process.env, opts: InstallOptions = {}) => {\n const out: InstalledReport[] = [\n {\n file: hooksFile(env),\n state: installedClaudeShaped(hooksFile(env), NAME, eventsFor(opts.lean), cmd, OPTS),\n note: \"Codex runs non-managed hooks only after the review in `codex` (/hooks); until then nothing is reported unless the notify fallback is ours\",\n },\n ];\n let text = \"\";\n try {\n text = readFileSync(configFile(env), \"utf8\");\n } catch {}\n const n = toml.readNotify(text);\n const argv = cmd([NAME, \"notify\"]).argv;\n const prev = n ? toml.previousNotify(n.argv) : null;\n const ours = n && (!n.other || (prev && JSON.stringify(prev) === JSON.stringify(argv)));\n out.push({\n file: configFile(env),\n state:\n !n || (n.other && !ours)\n ? \"missing\"\n : n.misplaced\n ? \"misplaced\"\n : JSON.stringify(n.argv) === JSON.stringify(argv) || (prev && JSON.stringify(prev) === JSON.stringify(argv))\n ? \"current\"\n : \"stale\",\n });\n return out;\n },\n\n fromHook(input: HookInput): HookResult | null {\n const event = input.argv[1] ?? \"\";\n let s: Record<string, unknown> = {};\n if (event === \"notify\") {\n // Codex's notify passes one JSON argument: {\"type\":\"agent-turn-complete\",\"thread-id\":\u2026,\"turn-id\":\u2026,\"cwd\":\u2026}\n const raw = input.argv.find((a) => a.startsWith(\"{\")) ?? input.stdin;\n try {\n const j: unknown = raw ? JSON.parse(raw) : {};\n if (j && typeof j === \"object\" && !Array.isArray(j)) s = j as Record<string, unknown>;\n } catch {}\n const id = (s[\"thread-id\"] ?? s.thread_id ?? s[\"session-id\"] ?? s.session_id) as string | undefined;\n if (!id) return null;\n // Notify names the thread whose turn ended. Without a rollout it is an ephemeral\n // thread, kept nowhere (the hooks' `transcript_path: null` below). A subagent's\n // thread belongs to its parent, whose hooks already report it: SubagentStart and\n // SubagentStop name it as `agent_id`. Neither is a session of its own.\n const file = findRollout(String(id), input.env as NodeJS.ProcessEnv);\n if (!file || codexSubagent(rolloutMeta(file))) return null;\n const r: HookResult = {\n session: { id: String(id), cwd: typeof s.cwd === \"string\" ? s.cwd : input.cwd },\n events: [\n {\n type: \"turn.ended\",\n data: { reason: \"stop\", ...(typeof s[\"turn-id\"] === \"string\" ? { turn_id: s[\"turn-id\"] } : {}) },\n harnessEvent: \"notify\",\n },\n ],\n hints: {},\n transcript: file,\n };\n return r;\n }\n try {\n // A stdin that is JSON but not an object (`null`, a number) is no payload.\n const j: unknown = input.stdin ? JSON.parse(input.stdin) : {};\n if (j && typeof j === \"object\" && !Array.isArray(j)) s = j as Record<string, unknown>;\n } catch {}\n const id = (s.session_id ?? s.thread_id ?? s.conversation_id ?? s[\"thread-id\"] ?? s[\"session-id\"]) as\n | string\n | undefined;\n if (!id) return null;\n // `transcript_path: null` is an ephemeral thread (recorded on codex-cli 0.160.0):\n // Codex Desktop's own background threads (ambient suggestions and their safety\n // review) and `codex exec --ephemeral`. Codex keeps nothing of one, so there is no\n // session to name, read or resume.\n if (s.transcript_path === null) return null;\n const session: HookResult[\"session\"] = { id: String(id), cwd: typeof s.cwd === \"string\" ? s.cwd : input.cwd };\n if (typeof s.model === \"string\") session.model = s.model;\n const turn_id = typeof s.turn_id === \"string\" ? s.turn_id : undefined;\n const tool = validTool(s.tool_name) ? s.tool_name : undefined;\n const call_id = typeof s.tool_use_id === \"string\" ? s.tool_use_id : undefined;\n // A subagent's hooks carry the parent's session_id (ADAPTERS.md, Threads): its own\n // id where the payload names it, else the thread its rollout is named for. Without\n // it a subagent's tool calls read as the main thread's (issue #208: a sink that\n // thins subagents' tool events would be sent every one).\n const thread = typeof s.transcript_path === \"string\" ? threadOf(s.transcript_path) : null;\n const agent_id =\n typeof s.agent_id === \"string\" && s.agent_id\n ? s.agent_id\n : typeof s.subagent_id === \"string\" && s.subagent_id\n ? s.subagent_id\n : thread && thread !== String(id).toLowerCase()\n ? thread\n : undefined;\n const ev = (type: string, data: Record<string, unknown>) => ({ type, data: prune(data), harnessEvent: event });\n const events: HookResult[\"events\"] = [];\n switch (event) {\n case \"SessionStart\":\n events.push(\n ev(\"session.started\", {\n source:\n typeof s.source === \"string\" && [\"startup\", \"resume\", \"clear\", \"compact\", \"fork\"].includes(s.source)\n ? s.source\n : \"unknown\",\n }),\n );\n break;\n case \"UserPromptSubmit\":\n events.push(\n ev(\"turn.started\", {\n turn_id,\n prompt_chars: typeof s.prompt === \"string\" ? [...s.prompt].length : undefined,\n }),\n );\n break;\n case \"PreToolUse\":\n if (tool) events.push(ev(\"tool.started\", { tool, call_id, turn_id, agent_id, input: s.tool_input }));\n break;\n case \"PostToolUse\":\n if (tool)\n events.push(\n ev(\"tool.ended\", {\n tool,\n call_id,\n turn_id,\n agent_id,\n ok: true,\n input: s.tool_input,\n output: s.tool_response,\n }),\n );\n break;\n case \"PermissionRequest\":\n events.push(\n ev(\"attention.needed\", {\n attention_id: call_id ?? `perm-${Date.now()}`,\n kind: \"permission\",\n tool,\n agent_id,\n }),\n );\n break;\n case \"Stop\":\n events.push(ev(\"turn.ended\", { turn_id, reason: \"stop\" }));\n break;\n case \"Interrupt\":\n events.push(ev(\"turn.ended\", { turn_id, reason: \"interrupt\" }));\n break;\n case \"SubagentStart\":\n events.push(\n ev(\"subagent.started\", {\n agent_id: String(s.agent_id ?? s.subagent_id ?? \"\"),\n agent_type: typeof s.agent_type === \"string\" ? s.agent_type : undefined,\n }),\n );\n break;\n case \"SubagentStop\":\n events.push(\n ev(\"subagent.ended\", {\n agent_id: String(s.agent_id ?? s.subagent_id ?? \"\"),\n agent_type: typeof s.agent_type === \"string\" ? s.agent_type : undefined,\n }),\n );\n break;\n case \"PreCompact\":\n events.push(ev(\"context.compacted\", { trigger: s.trigger === \"manual\" ? \"manual\" : \"auto\" }));\n break;\n case \"PostCompact\":\n break;\n case \"SessionEnd\":\n events.push(ev(\"session.ended\", { reason: endReason(s.reason) }));\n break;\n default:\n return null;\n }\n const r: HookResult = { session, events, hints: {} };\n // Inside a subagent Codex sends the parent's session_id with the subagent's own\n // rollout (its SubagentStart, its tool calls): that file is not this session's.\n if (typeof s.transcript_path === \"string\" && !ofAnotherThread(s.transcript_path, String(id)))\n r.transcript = s.transcript_path;\n return r;\n },\n\n readTranscript(file, fromLine) {\n let text = \"\";\n try {\n text = readFileSync(file, \"utf8\");\n } catch {\n return { turns: [], line: fromLine };\n }\n return readCodex(text.split(\"\\n\"), fromLine);\n },\n\n facts(session, transcript): SessionFacts {\n const out: SessionFacts = {};\n if (transcript) Object.assign(out, codexFacts(transcript));\n return out;\n },\n\n backfill(sinceMs, env = process.env): BackfillRow[] {\n const rows: BackfillRow[] = [];\n for (const f of recentFiles(sessionsDir(env), 3, sinceMs, (n) => /^rollout-.*\\.jsonl$/.test(n))) {\n const m = /([0-9a-f]{8}-[0-9a-f-]{27,})\\.jsonl$/i.exec(path.basename(f));\n if (!m?.[1]) continue;\n // A subagent's rollout is part of its parent's session, as in fromHook's notify.\n if (codexSubagent(rolloutMeta(f))) continue;\n const facts = codexFacts(f);\n if (!facts.started_at || !facts.last_at) continue;\n const { started_at, last_at, first_ask: _fa, harness_version: _hv, ...rest } = facts;\n rows.push({ session: { id: m[1], ...rest }, started_at, last_at });\n }\n return rows;\n },\n\n limits: (transcript) => codexLimits(transcript),\n};\n\n/** Epoch seconds as RFC 3339; anything that is not a plausible time is no time. */\nconst epochIso = (t: unknown): string | undefined =>\n typeof t === \"number\" && t > 0 && t < 1e11 ? new Date(t * 1000).toISOString() : undefined;\n\nfunction prune<T extends Record<string, unknown>>(o: T): T {\n for (const k of Object.keys(o)) if (o[k] === undefined) delete o[k];\n return o;\n}\n\n/** The account's limits from the last `token_count` that carries them (recorded\n * 2026-10-21, codex-cli 0.163): `rate_limits.primary` / `secondary`, each with\n * `used_percent`, `window_minutes` and `resets_at` in epoch seconds, and `plan_type`.\n * Every turn writes one, so the tail is enough. Codex keeps one snapshot and overwrites\n * it with whichever bucket the server named last (`limit_id`: `codex`, or a model's own\n * such as `codex_other`), so only the account's `codex` bucket is read, never another's\n * windows under its names. */\nexport function codexLimits(file: string): DataOf<\"limits.observed\"> | null {\n const { tail } = ends(file, 0, 256 * 1024);\n for (const r of parseLines(tail).reverse()) {\n const p = r.payload as { type?: unknown; rate_limits?: unknown } | undefined;\n if (r.type !== \"event_msg\" || p?.type !== \"token_count\") continue;\n if (!p.rate_limits || typeof p.rate_limits !== \"object\") continue;\n const rl = p.rate_limits as Record<string, unknown>;\n if (rl.limit_id != null && rl.limit_id !== \"codex\") continue;\n const windows: DataOf<\"limits.observed\">[\"windows\"] = [];\n for (const id of [\"primary\", \"secondary\"]) {\n const w = rl[id] as { used_percent?: unknown; window_minutes?: unknown; resets_at?: unknown } | null;\n if (typeof w?.used_percent !== \"number\" || w.used_percent < 0) continue;\n windows.push(\n prune({\n id,\n used_percent: w.used_percent,\n window_minutes:\n Number.isInteger(w.window_minutes) && Number(w.window_minutes) > 0 ? Number(w.window_minutes) : undefined,\n resets_at: epochIso(w.resets_at),\n }),\n );\n }\n if (!windows.length) return null;\n return prune({ windows, plan: typeof rl.plan_type === \"string\" ? rl.plan_type.slice(0, 64) : undefined });\n }\n return null;\n}\n\n/** Codex keeps no title; its first real ask stands in. A fork's replay is not its ask. */\nexport function codexFacts(file: string): SessionFacts {\n const { head, tail } = ends(file, 128 * 1024, 64 * 1024);\n let H = parseLines(head);\n let T = parseLines(tail);\n const out: SessionFacts = {};\n const meta = H.find((j) => j.type === \"session_meta\" && j.payload);\n const boundary = codexReplayBoundary(meta);\n if (meta?.payload) {\n const p = meta.payload as {\n cwd?: string;\n cli_version?: string;\n git?: { branch?: string; repository_url?: string };\n };\n if (p.cwd) out.cwd = p.cwd;\n if (p.cli_version) out.harness_version = String(p.cli_version);\n if (p.git?.branch) out.branch = p.git.branch;\n if (p.git?.repository_url) out.repo = String(p.git.repository_url).replace(/\\/\\/[^/@]*@/, \"//\");\n }\n if (boundary) {\n const h = H.findIndex(boundary);\n const t = T.findIndex(boundary);\n H = h < 0 ? [] : H.slice(h);\n // The samples can overlap, so trim each one at the boundary independently.\n // If both miss it, scan the gap before trusting the tail: it could still be\n // parent replay. Stop as soon as the boundary is found, without loading the file.\n const found =\n h >= 0 ||\n t >= 0 ||\n scanLines(file, (line) => (boundary(parseLines([line])[0] ?? null) ? true : null), Number.POSITIVE_INFINITY);\n T = t >= 0 ? T.slice(t) : found ? T : [];\n }\n const ctx = H.concat(T)\n .reverse()\n .find((j) => j.type === \"turn_context\" && (j.payload as { model?: string } | undefined)?.model) as\n | { payload?: { model?: string } }\n | undefined;\n if (ctx?.payload?.model) out.model = ctx.payload.model;\n for (const j of H) {\n const p = j.payload as { type?: string; role?: string; content?: { type?: string; text?: string }[] } | undefined;\n if (j.type !== \"response_item\" || !p || p.type !== \"message\" || p.role !== \"user\") continue;\n const text = (p.content ?? [])\n .filter((b) => b && b.type === \"input_text\" && typeof b.text === \"string\")\n .map((b) => b.text as string)\n .join(\"\\n\")\n .trim();\n if (!text || codexInjected(text)) continue;\n const line = text.split(\"\\n\")[0] as string; // trimmed, so its first line is its first non-blank one\n out.title = line.length > 80 ? `${line.slice(0, 80).replace(/\\s+\\S*$/, \"\")}\u2026` : line;\n out.title_source = \"first-ask\";\n break;\n }\n const times = (boundary && meta ? [meta, ...H, ...T] : H.concat(T))\n .map((j) => Date.parse(String(j.timestamp ?? \"\")))\n .filter((n) => n > 0);\n if (times.length) {\n out.started_at = Math.min(...times);\n out.last_at = Math.max(...times);\n }\n return out;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// Codex's ~/.codex/config.toml, as far as the notify fallback needs it: its one\n// top-level `notify` command. Codex reads `notify` only at the top level \u2014 before\n// the first [table] \u2014 and Codex itself appends a [projects.\"<path>\"] table for every\n// folder it trusts, so a line appended at the end lands inside one and never runs.\n// Ported from spacesheep-cli lib/codex-config.js. Pure text in, text out.\n\nconst NOTIFY_LINE = /^[ \\t]*notify[ \\t]*=[ \\t]*(\\[.*\\])[ \\t]*(?:#.*)?(?=\\r?$)/m;\nconst NOTIFY_KEY = /^[ \\t]*notify[ \\t]*=/m;\n/** A notify that runs sessionpipe's hook directly (or through its launcher). */\nexport const OURS = /(?:hook\\.js|sessionpipe-hook)\",\\s*\"codex\",\\s*\"notify\"/;\n\nfunction scan(line: string, st: { depth: number; str: string | null }): void {\n let i = 0;\n while (i < line.length) {\n if (st.str) {\n const j = line.indexOf(st.str, i);\n if (j < 0) return;\n i = j + 3;\n st.str = null;\n continue;\n }\n const ch = line[i];\n if (ch === \"#\") return;\n if (line.startsWith('\"\"\"', i) || line.startsWith(\"'''\", i)) {\n st.str = line.slice(i, i + 3);\n i += 3;\n continue;\n }\n if (ch === '\"') {\n i++;\n while (i < line.length && line[i] !== '\"') i += line[i] === \"\\\\\" ? 2 : 1;\n i++;\n continue;\n }\n if (ch === \"'\") {\n const j = line.indexOf(\"'\", i + 1);\n i = j < 0 ? line.length : j + 1;\n continue;\n }\n if (ch === \"[\") st.depth++;\n else if (ch === \"]\") st.depth = Math.max(0, st.depth - 1);\n i++;\n }\n}\n\n/** Offset of the first table header, or -1. */\nexport function firstTableAt(text: string): number {\n const st = { depth: 0, str: null as string | null };\n let pos = 0;\n for (const line of text.split(\"\\n\")) {\n if (!st.str && st.depth === 0 && /^[ \\t]*\\[/.test(line)) return pos;\n scan(line, st);\n pos += line.length + 1;\n }\n return -1;\n}\n\nfunction split(text: string) {\n const at = firstTableAt(text);\n return at < 0 ? { head: text, tail: \"\", at: text.length } : { head: text.slice(0, at), tail: text.slice(at), at };\n}\n\nexport function parseArgv(raw: string): string[] | null {\n try {\n const a = JSON.parse(raw) as unknown;\n return Array.isArray(a) && a.every((x) => typeof x === \"string\") ? (a as string[]) : null;\n } catch {\n return null;\n }\n}\n\nexport interface Notify {\n raw: string;\n argv: string[] | null;\n index: number;\n length: number;\n misplaced: boolean;\n other: boolean;\n}\n\n/** notify as Codex sees it; `misplaced` for a line of ours inside a table. */\nexport function readNotify(text: string): Notify | null {\n const { head, tail, at } = split(text);\n const m = NOTIFY_LINE.exec(head);\n if (m) {\n const raw = m[1] as string;\n return { raw, argv: parseArgv(raw), index: m.index, length: m[0].length, misplaced: false, other: !OURS.test(raw) };\n }\n const k = NOTIFY_KEY.exec(head);\n if (k) {\n const rest = head.slice(k.index).split(\"\\n\")[0] as string;\n return {\n raw: rest.replace(NOTIFY_KEY, \"\").trim(),\n argv: null,\n index: k.index,\n length: 0,\n misplaced: false,\n other: true,\n };\n }\n const t = NOTIFY_LINE.exec(tail);\n if (t) {\n const raw = t[1] as string;\n if (OURS.test(raw))\n return { raw, argv: parseArgv(raw), index: at + t.index, length: t[0].length, misplaced: true, other: false };\n }\n return null;\n}\n\nfunction dropLine(text: string, index: number, length: number): string {\n return text.slice(0, index) + text.slice(index + length).replace(/^\\r?\\n/, \"\");\n}\n\n/** Put `line` at the top level: before the first table, or at the end of a file that has\n * none. The line takes the file's own line end, so a CRLF file stays one. */\nexport function insertTopLevel(text: string, line: string): string {\n const { head, tail } = split(text);\n // The line joins the top-level section, so its line end is that section's own; a head\n // with no line end of its own takes the file's.\n const body = head.replace(/\\s*$/, \"\");\n const eol = (body.includes(\"\\n\") ? body : text).includes(\"\\r\\n\") ? \"\\r\\n\" : \"\\n\";\n const top = head.trim() ? head.replace(/\\s*$/, eol) : \"\";\n if (!tail) return top + line + eol;\n return `${top + line}${eol}${eol}${tail}`;\n}\n\n/** The config with `line` as its notify, for a config whose notify is ours or absent. */\nexport function withNotify(text: string, line: string): string {\n const n = readNotify(text);\n if (n && !n.misplaced && !n.other) return text.slice(0, n.index) + line + text.slice(n.index + n.length);\n if (n?.misplaced) return insertTopLevel(dropLine(text, n.index, n.length), line);\n return insertTopLevel(text, line);\n}\n\n/** The config with its notify line `n` (as readNotify found it in `text`) replaced by `line`. */\nexport function replaceNotify(text: string, n: Notify, line: string): string {\n return text.slice(0, n.index) + line + text.slice(n.index + n.length);\n}\n\n/** The config with our top-level or misplaced notify removed. */\nexport function withoutNotify(text: string): string {\n const n = readNotify(text);\n if (!n || n.other || !n.length) return text;\n return dropLine(text, n.index, n.length);\n}\n\n// Codex Computer Use takes the notify slot itself and keeps the command it found in\n// its own argv: [client, \"turn-ended\", \"--previous-notify\", \"<that command as JSON>\"].\nconst PREVIOUS = \"--previous-notify\";\nexport function previousNotify(argv: string[] | null): string[] | null {\n if (!Array.isArray(argv)) return null;\n const i = argv.indexOf(PREVIOUS);\n return i >= 0 && typeof argv[i + 1] === \"string\" ? parseArgv(argv[i + 1] as string) : null;\n}\nexport function withPrevious(argv: string[], prev: string[] | null): string[] {\n const out = argv.slice();\n const i = out.indexOf(PREVIOUS);\n if (i >= 0) out.splice(i, 2);\n if (prev) out.push(PREVIOUS, JSON.stringify(prev));\n return out;\n}\n/** The raw notify value with its --previous-notify pair removed, formatting kept. */\nexport function stripPreviousRaw(raw: string): string {\n return raw.replace(/,\\s*\"--previous-notify\",\\s*\"(?:[^\"\\\\]|\\\\.)*\"\\s*(?=\\])/, \"\");\n}\n/** The raw notify value with `prev` as its --previous-notify, formatting of the rest kept. */\nexport function withPreviousRaw(raw: string, prev: string[]): string {\n const base = stripPreviousRaw(raw).replace(/\\s*\\]\\s*$/, \"\");\n return `${base}, \"--previous-notify\", ${JSON.stringify(JSON.stringify(prev))}]`;\n}\nexport const isComputerUse = (argv: string[] | null): boolean =>\n Array.isArray(argv) && typeof argv[0] === \"string\" && /(^|\\/)SkyComputerUseClient$/.test(argv[0]);\n", "// SPDX-License-Identifier: Apache-2.0\n// Codex CLI (OpenAI) \u2014 control delivery (spec/CONTROL.md \u00A76). Codex on this machine,\n// as the control daemon needs it: which `codex` to run, with which sandbox flags, one\n// headless turn (`codex exec --json` for a new session, `codex exec resume --json <id>`\n// for the next message), and its JSONL output read as it streams. Codex picks a new\n// session's id itself (the first line, `thread.started`), so the daemon names it after\n// the command that started it (CONTROL.md \u00A76 `start`). Shapes measured on codex-cli\n// 0.160.0, 2026-10-04.\nimport { execFile } from \"node:child_process\";\nimport { readFileSync } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { MODEL_RE, type RunLevel, type StartPermission } from \"../control/verify.js\";\nimport {\n findBinary,\n jobEnv,\n type Login,\n type Mode,\n probe,\n type Reading,\n type RunResult,\n runFailure,\n stderrTail,\n} from \"./headless.js\";\n\nexport { codexFacts, findRollout } from \"./codex.js\";\n\nconst LABEL = \"Codex\";\n\n/** The `codex` to run: SESSIONPIPE_CODEX, else on PATH, else beside the node running\n * this (an `npm install -g` there) or where the installers put it. */\nexport function findCodex(\n env: NodeJS.ProcessEnv = process.env,\n home = os.homedir(),\n nodeDir = path.dirname(process.execPath),\n): string | null {\n return findBinary({\n override: env.SESSIONPIPE_CODEX,\n names: process.platform === \"win32\" ? [\"codex.exe\", \"codex.cmd\"] : [\"codex\"],\n env,\n dirs: [nodeDir, path.join(home, \".local\", \"bin\"), \"/opt/homebrew/bin\", \"/usr/local/bin\"],\n });\n}\n\n/** Sandbox flags for a level (a machine's mode is one: safe, auto, inherit). Read: the\n * read-only sandbox. Safe: workspace-write, and nothing escalates unattended (exec never\n * asks); that sandbox already edits inside the folder, so `edits` is never offered and\n * means the same. Auto: approval requests go through Codex's own automatic review.\n * Inherit: none, so `sandbox_mode` and `approval_policy` come from the person's own\n * config.toml, a new session's and a resume's alike. Never\n * `--dangerously-bypass-approvals-and-sandbox`, `--dangerously-bypass-hook-trust` or\n * `danger-full-access`: no path here writes them. */\nexport function codexModeFlags(level: RunLevel, resume = false): string[] {\n if (level === \"inherit\") return [];\n const sandbox = level === \"read\" ? \"read-only\" : \"workspace-write\";\n // `codex exec resume` takes neither `-s` nor `--approve-for-me` (0.160: \"unexpected\n // argument\"), so a resume says the same thing as config overrides, which it does take.\n if (resume)\n return level === \"auto\"\n ? [\n \"-c\",\n 'sandbox_mode=\"workspace-write\"',\n \"-c\",\n 'approval_policy=\"on-request\"',\n \"-c\",\n 'approvals_reviewer=\"auto_review\"',\n ]\n : [\"-c\", `sandbox_mode=\"${sandbox}\"`];\n return level === \"auto\" ? [\"--approve-for-me\"] : [\"-s\", sandbox];\n}\n\n/** The levels a start may ask Codex for on a machine in `mode`: read and safe, and auto\n * on an auto machine. */\nexport const offeredLevels = (mode: Mode): StartPermission[] =>\n mode === \"auto\" ? [\"read\", \"safe\", \"auto\"] : [\"read\", \"safe\"];\n\n/** What a start that names no level gets: what the machine's mode means for Codex. */\nexport const defaultLevel = (mode: Mode): RunLevel => mode;\n\n/** One headless turn. A new session runs in `cwd` (`-C`); a resume names the thread.\n * The model is its own argument after `-m`. The prompt goes after `--`, so a message\n * that starts with a dash is never a flag. */\nexport function codexArgs(o: {\n permission: RunLevel;\n prompt: string;\n cwd?: string;\n resume?: string;\n model?: string;\n}): string[] {\n const common = [\"--json\", \"--skip-git-repo-check\"];\n const model = o.model ? [\"-m\", o.model] : [];\n if (o.resume)\n return [\"exec\", \"resume\", ...common, ...codexModeFlags(o.permission, true), ...model, \"--\", o.resume, o.prompt];\n return [\n \"exec\",\n ...common,\n ...(o.cwd ? [\"-C\", o.cwd] : []),\n ...codexModeFlags(o.permission),\n ...model,\n \"--\",\n o.prompt,\n ];\n}\n\n/** The models a hello offers for Codex (CONTROL.md \u00A72 `start`): the slugs Codex's own\n * picker lists, from `$CODEX_HOME/models_cache.json` (visibility `list`; hidden ones,\n * such as its review model, left out), at most 50. Empty when there is no cache. */\nexport function codexModels(env: NodeJS.ProcessEnv = process.env, home = os.homedir()): string[] {\n try {\n const file = path.join(env.CODEX_HOME || path.join(home, \".codex\"), \"models_cache.json\");\n const j = JSON.parse(readFileSync(file, \"utf8\")) as { models?: unknown };\n if (!Array.isArray(j.models)) return [];\n const out: string[] = [];\n for (const m of j.models as { slug?: unknown; visibility?: unknown }[])\n if (m && m.visibility === \"list\" && typeof m.slug === \"string\" && MODEL_RE.test(m.slug) && m.slug.length <= 100)\n if (!out.includes(m.slug)) out.push(m.slug);\n return out.slice(0, 50);\n } catch {\n return [];\n }\n}\n\n/** The env a headless turn runs with. */\nexport const codexEnv = (env: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv => jobEnv(env);\n\nexport const LOGIN_HINT = \"Codex isn't signed in on this machine: run `codex login --device-auth` there.\";\n\n/** Whether Codex can run as this process: CODEX_API_KEY in the env is enough; else\n * `codex login status` (exit 0 signed in, exit 1 \"Not logged in\"). Anything else \u2014\n * it didn't run, it timed out \u2014 is null, never a reason to refuse. */\nexport function codexLogin(bin: string, env: NodeJS.ProcessEnv = process.env): Promise<Login> {\n if (env.CODEX_API_KEY) return Promise.resolve({ loggedIn: true, method: \"api key\" });\n const c = probe(bin, [\"login\", \"status\"]); // a codex.cmd shim can't be spawned bare (#165)\n return new Promise((resolve) => {\n execFile(\n c.file,\n c.args,\n { encoding: \"utf8\", timeout: 20_000, env: codexEnv(env), maxBuffer: 256 * 1024, shell: c.shell },\n (err) => {\n if (!err) return resolve({ loggedIn: true });\n const code = (err as { code?: unknown }).code;\n resolve(code === 1 ? { loggedIn: false } : { loggedIn: null });\n },\n );\n });\n}\n\n/** One `--json` line, as much of it as the daemon uses. */\nexport interface CodexPiece {\n /** `thread.started`: the session's id, which Codex chose. */\n session?: string;\n /** A finished `agent_message`: one part of the answer. */\n message?: string;\n /** `turn.completed` (or `turn.failed`). */\n done?: boolean;\n /** `turn.failed`: why. */\n failed?: string;\n /** A top-level `error` (\"Reconnecting... 2/5\"): transient, the reason only if the run then fails. */\n note?: string;\n /** An `error` item: a warning Codex printed and carried on after (hook trust, a clamped timeout). */\n warning?: string;\n}\n\nexport function codexLine(line: string): CodexPiece | null {\n let j: {\n type?: unknown;\n thread_id?: unknown;\n message?: unknown;\n item?: { type?: unknown; text?: unknown; message?: unknown };\n error?: { message?: unknown };\n };\n try {\n j = JSON.parse(line);\n } catch {\n return null;\n }\n if (!j || typeof j !== \"object\") return null;\n const str = (v: unknown) => (typeof v === \"string\" ? v : \"\");\n switch (j.type) {\n case \"thread.started\":\n return str(j.thread_id) ? { session: str(j.thread_id) } : null;\n case \"item.completed\": {\n const it = j.item;\n if (it?.type === \"agent_message\" && str(it.text)) return { message: str(it.text) };\n if (it?.type === \"error\" && str(it.message)) return { warning: str(it.message) };\n return null;\n }\n case \"turn.completed\":\n return { done: true };\n case \"turn.failed\":\n return { done: true, failed: str(j.error?.message) || \"Codex reported an error\" };\n case \"error\":\n return str(j.message) ? { note: str(j.message) } : null;\n default:\n return null;\n }\n}\n\n/** A Codex run read as it streams: the answer is its finished agent messages. */\nexport class CodexReading implements Reading {\n session: string | null = null;\n lines = 0;\n readonly warnings: string[] = [];\n private readonly messages: string[] = [];\n private done = false;\n private failed: string | null = null;\n private note: string | null = null;\n\n get text(): string {\n return this.messages.join(\"\\n\\n\");\n }\n\n feed(line: string): boolean {\n this.lines++;\n const p = codexLine(line);\n if (!p) return false;\n if (p.session && !this.session) this.session = p.session;\n if (p.note) this.note = p.note;\n if (p.warning && this.warnings.length < 20) this.warnings.push(p.warning);\n if (p.failed) this.failed = p.failed;\n if (p.done) this.done = true;\n if (p.message?.trim()) {\n this.messages.push(p.message.trim());\n return true;\n }\n return false;\n }\n\n /** A failure is `turn.failed`, or a run that exits non-zero having said nothing; an\n * `error` item before a turn that then succeeds is only a warning. */\n outcome(res: RunResult): { failed: string } | { reply: string } {\n const broke = runFailure(LABEL, res);\n if (broke) return { failed: broke };\n if (this.failed) return { failed: this.failed };\n if (this.done || res.code === 0 || this.messages.length)\n return { reply: this.text || \"(Codex finished without a written reply.)\" };\n const why = this.note || codexStderr(res.stderr) || this.warnings.at(-1) || \"\";\n return { failed: `Codex exited (${res.signal || `code ${res.code}`}) without an answer${why ? `: ${why}` : \"\"}` };\n }\n}\n\n/** stderr's tail without the line Codex prints even with stdin closed. */\nfunction codexStderr(stderr: string | undefined): string {\n return stderrTail(\n String(stderr || \"\")\n .split(\"\\n\")\n .filter((l) => !/^Reading additional input from stdin/.test(l.trim()))\n .join(\"\\n\"),\n );\n}\n\nexport const reading = (): CodexReading => new CodexReading();\n", "// SPDX-License-Identifier: Apache-2.0\n// Devin CLI (Cognition) \u2014 docs: https://docs.devin.ai/cli/extensibility/hooks/overview\n// Config: the `hooks` key of the user config file \u2014 `~/.config/devin/config.json`\n// (`$XDG_CONFIG_HOME/devin/config.json` when that is set), `%APPDATA%\\devin\\config.json`\n// on Windows. Claude-shaped, matcher a REGEX on the tool name, timeouts in SECONDS.\n// That file is the only user-level location Devin reads hooks from; `hooks.v1.json` is\n// project-level only.\n//\n// Devin accepts exactly eight event names and rejects the WHOLE file on one it does not\n// know (\"unknown variant `Notification`, expected one of \u2026\"), which silently disables\n// every hook in it. DEVIN_EVENTS is that set, and nothing else may be added to it.\n//\n// The payload carries no `cwd`, no `transcript_path` and no `model`: the folder comes\n// from DEVIN_PROJECT_DIR in the hook's environment, and the transcript, the model, the\n// title and the times come from Devin's own session store \u2014 one SQLite file under the\n// data directory, read only, through readers/sqlite.ts. A session's transcript is\n// addressed as \"<database>#<session id>\", because readTranscript is given a file.\n//\n// stdout stays empty for every event: Devin reads a decision from stdout, and silence\n// plus exit 0 is \"carry on\" (printing nothing, printing `{}`, exiting 1 and blowing the\n// timeout were all measured as non-blocking; only exit 2 or an explicit\n// {\"decision\":\"block\"} blocks a tool).\nimport { createHash } from \"node:crypto\";\nimport { existsSync, readlinkSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { homeDir } from \"../paths.js\";\nimport { querySqlite } from \"../readers/sqlite.js\";\nimport { pairTurns } from \"../readers/transcripts.js\";\nimport { installClaudeShaped, installedClaudeShaped, readJson, uninstallClaudeShaped } from \"./claude-shaped.js\";\nimport type {\n Adapter,\n BackfillRow,\n HookInput,\n HookResult,\n InstallOptions,\n SessionFacts,\n TranscriptRead,\n} from \"./types.js\";\n\nconst NAME = \"devin\";\n/** The eight event names Devin accepts. One it does not know makes it drop the whole\n * hooks file, so this list is exact, not a superset \u2014 see devin.test.ts. */\nexport const DEVIN_EVENTS = [\n \"SessionStart\",\n \"UserPromptSubmit\",\n \"PreToolUse\",\n \"PostToolUse\",\n \"PermissionRequest\",\n \"Stop\",\n \"PostCompaction\",\n \"SessionEnd\",\n] as const;\nconst OPTS = { matcherFor: (e: string) => (/Tool|Permission/.test(e) ? \"\" : undefined), timeout: 5 };\nconst eventsFor = (lean?: boolean) => (lean ? DEVIN_EVENTS.filter((e) => e !== \"PreToolUse\") : [...DEVIN_EVENTS]);\nconst INSTALL_NOTE =\n \"Devin drops a whole hooks file on one event name it doesn't know; `/hooks` in `devin` lists what loaded\";\nconst CLAUDE_NOTE =\n \"Devin also reads ~/.claude/settings.json hooks (read_config_from.claude); a Claude-only event name there makes it ignore that file whole\";\n\nconst deadFileNote = (bad: string) =>\n `Devin loads NO hooks from this file: \"${bad}\" is not one of its event names and it rejects the file whole \u2014 remove that key (\\`/hooks\\` in \\`devin\\` lists what loaded)`;\n\n/** The first `hooks` key in the file that Devin does not accept, if there is one.\n * One such key disables every hook in the file, ours and any other tool's. */\nexport function foreignEvent(file: string): string | undefined {\n const hooks = readJson(file).hooks;\n if (!hooks || typeof hooks !== \"object\" || Array.isArray(hooks)) return undefined;\n const ok = DEVIN_EVENTS as readonly string[];\n return Object.keys(hooks).find((k) => !ok.includes(k));\n}\n\nconst homeOf = (env: NodeJS.ProcessEnv) => env.HOME || homeDir();\nconst appData = (env: NodeJS.ProcessEnv) => env.APPDATA || path.join(homeOf(env), \"AppData\", \"Roaming\");\n/** `~/.config/devin`, `$XDG_CONFIG_HOME/devin`, or `%APPDATA%\\devin`. */\nexport const devinConfigDir = (env: NodeJS.ProcessEnv = process.env): string =>\n process.platform === \"win32\"\n ? path.join(appData(env), \"devin\")\n : path.join(env.XDG_CONFIG_HOME || path.join(homeOf(env), \".config\"), \"devin\");\nconst configFile = (env: NodeJS.ProcessEnv) => path.join(devinConfigDir(env), \"config.json\");\n/** `~/.local/share/devin/cli`, `$XDG_DATA_HOME/devin/cli`, or `%APPDATA%\\devin\\cli`. */\nexport const devinDataDir = (env: NodeJS.ProcessEnv = process.env): string =>\n process.platform === \"win32\"\n ? path.join(appData(env), \"devin\", \"cli\")\n : path.join(env.XDG_DATA_HOME || path.join(homeOf(env), \".local\", \"share\"), \"devin\", \"cli\");\nconst sessionsDb = (env: NodeJS.ProcessEnv) => path.join(devinDataDir(env), \"sessions.db\");\n\nconst SESSION_ID = /^[A-Za-z0-9._:-]{1,128}$/;\nconst validTool = (n: unknown): n is string => typeof n === \"string\" && /^[A-Za-z0-9_.:-]{1,120}$/.test(n);\nconst endReason = (r: unknown): \"clear\" | \"logout\" | \"exit\" | \"other\" =>\n r === \"clear\" || r === \"logout\" || r === \"exit\" ? r : \"other\";\nconst pickSource = (v: unknown): string =>\n typeof v === \"string\" && [\"startup\", \"resume\", \"clear\", \"compact\", \"fork\"].includes(v) ? v : \"unknown\";\nfunction errText(v: unknown): string | undefined {\n if (typeof v === \"string\" && v) return v.slice(0, 2000);\n if (v && typeof v === \"object\") {\n const e = v as { message?: unknown; error?: unknown };\n if (typeof e.message === \"string\" && e.message) return e.message.slice(0, 2000);\n if (typeof e.error === \"string\" && e.error) return e.error.slice(0, 2000);\n }\n return undefined;\n}\nconst cut = (s: string, n: number): string => (s.length > n ? `${s.slice(0, n).replace(/\\s+\\S*$/, \"\")}\u2026` : s);\n\nexport const devin: Adapter = {\n name: NAME,\n events: DEVIN_EVENTS,\n detect: (env = process.env) => existsSync(devinConfigDir(env)) || existsSync(devinDataDir(env)),\n configFiles: (env = process.env) => [configFile(env)],\n install: (cmd, env = process.env, opts: InstallOptions = {}) => {\n const file = configFile(env);\n const r = installClaudeShaped(file, NAME, eventsFor(opts.lean), cmd, OPTS);\n if (r.skipped) return [r];\n const bad = foreignEvent(file);\n return [{ ...r, note: bad ? deadFileNote(bad) : INSTALL_NOTE }];\n },\n uninstall: (env = process.env, opts: InstallOptions = {}) => [\n uninstallClaudeShaped(configFile(env), DEVIN_EVENTS, { created: opts.created?.includes(configFile(env)) }),\n ],\n installed: (cmd, env = process.env, opts: InstallOptions = {}) => {\n const file = configFile(env);\n const state = installedClaudeShaped(file, NAME, eventsFor(opts.lean), cmd, OPTS);\n // Our entries can be present and current and still report nothing: one event name\n // Devin does not know makes it drop the whole file, ours with it. `status` has to\n // say so, or it tells the person reporting is on while it is dead.\n const bad = state === \"missing\" ? undefined : foreignEvent(file);\n return [{ file, state: bad ? \"inactive\" : state, note: bad ? deadFileNote(bad) : CLAUDE_NOTE }];\n },\n\n fromHook(input: HookInput): HookResult | null {\n const event = input.argv[1] ?? \"\";\n let s: Record<string, unknown> = {};\n try {\n // A stdin that is JSON but not an object (`null`, a number) is no payload.\n const j: unknown = input.stdin ? JSON.parse(input.stdin) : {};\n if (j && typeof j === \"object\" && !Array.isArray(j)) s = j as Record<string, unknown>;\n } catch {}\n const id = typeof s.session_id === \"string\" ? s.session_id : \"\";\n if (!id) return null;\n // Nothing in the payload names the folder; DEVIN_PROJECT_DIR is the only thing that does.\n const session: HookResult[\"session\"] = { id, cwd: input.env.DEVIN_PROJECT_DIR ?? input.cwd };\n const turn_id = typeof s.prompt_id === \"string\" ? s.prompt_id : undefined;\n const tool = validTool(s.tool_name) ? s.tool_name : undefined;\n const call_id = typeof s.tool_use_id === \"string\" ? s.tool_use_id : undefined;\n // Every recorded payload has an object here, but the field is free-form: a Devin\n // version or an MCP-style tool could send a bare string, and then there is no\n // `success` and no `output` to read \u2014 the whole value IS the output.\n const response =\n s.tool_response && typeof s.tool_response === \"object\" && !Array.isArray(s.tool_response)\n ? (s.tool_response as { success?: unknown; output?: unknown; error?: unknown })\n : undefined;\n // The same prompt must always name the same attention (CONTROL.md \u00A76). Devin's\n // PermissionRequest does carry tool_use_id; the hash is the fallback for one that\n // doesn't, and is the bytes ADAPTERS.md's common conventions prescribe.\n const permissionId = () =>\n `perm-${createHash(\"sha256\")\n .update(`${turn_id ?? \"\"}|${tool ?? \"\"}|${JSON.stringify(s.tool_input ?? null)}`)\n .digest(\"hex\")\n .slice(0, 16)}`;\n const ev = (type: string, data: Record<string, unknown>) => ({ type, data: prune(data), harnessEvent: event });\n const events: HookResult[\"events\"] = [];\n switch (event) {\n case \"SessionStart\":\n events.push(ev(\"session.started\", { source: pickSource(s.source) }));\n break;\n case \"UserPromptSubmit\":\n events.push(\n ev(\"turn.started\", {\n turn_id,\n prompt_chars: typeof s.prompt === \"string\" ? [...s.prompt].length : undefined,\n }),\n );\n break;\n case \"PreToolUse\":\n if (tool) events.push(ev(\"tool.started\", { tool, call_id, turn_id, input: s.tool_input }));\n break;\n case \"PostToolUse\":\n // Devin is the one harness that says so outright: tool_response.success.\n if (tool)\n events.push(\n ev(\"tool.ended\", {\n tool,\n call_id,\n turn_id,\n // `ok` is required on tool.ended (PROTOCOL.md \u00A7events), so a response\n // that carries no success flag at all reads as \"nothing said it failed\".\n ok: response?.success !== false,\n error: errText(response?.error),\n input: s.tool_input,\n output: response ? response.output : s.tool_response,\n }),\n );\n break;\n case \"PermissionRequest\":\n events.push(ev(\"attention.needed\", { attention_id: call_id ?? permissionId(), kind: \"permission\", tool }));\n break;\n case \"Stop\":\n events.push(ev(\"turn.ended\", { turn_id, reason: \"stop\" }));\n break;\n case \"PostCompaction\":\n // Devin has no pre-compaction event; the payload carries only the summary.\n events.push(ev(\"context.compacted\", { trigger: \"auto\" }));\n break;\n case \"SessionEnd\":\n events.push(ev(\"session.ended\", { reason: endReason(s.reason) }));\n break;\n default:\n return null;\n }\n return {\n session,\n events,\n hints: {},\n transcript: transcriptRef(sessionsDb(input.env as NodeJS.ProcessEnv), id),\n };\n },\n\n readTranscript(file, fromLine) {\n const ref = splitRef(file);\n if (!ref) return { turns: [], line: fromLine };\n return readDevinChain(ref.db, ref.session, fromLine);\n },\n\n facts(session, transcript, _hints, _state, env = process.env): SessionFacts {\n const out: SessionFacts = {};\n const version = devinVersion(env);\n if (version) out.harness_version = version;\n const account = devinAccount(env);\n if (account) out.account_id = account;\n const ref = splitRef(transcript) ?? { db: sessionsDb(env), session: session.id };\n if (!SESSION_ID.test(ref.session)) return out;\n const rows = querySqlite(ref.db, SESSION_SQL, [ref.session]);\n const row = rows?.[0];\n if (!row) return out;\n Object.assign(out, sessionFacts(row));\n return out;\n },\n\n backfill(sinceMs, env = process.env): BackfillRow[] {\n const rows = querySqlite(sessionsDb(env), BACKFILL_SQL, [\"text\", Math.floor(sinceMs / 1000)]);\n if (!rows) return [];\n const out: BackfillRow[] = [];\n for (const row of rows) {\n const id = String(row.id); // text, the query says\n if (!SESSION_ID.test(id)) continue;\n const { started_at, last_at, ...rest } = sessionFacts(row);\n if (!started_at || !last_at) continue;\n out.push({ session: { id, ...rest }, started_at, last_at });\n }\n return out;\n },\n};\n\nfunction prune<T extends Record<string, unknown>>(o: T): T {\n for (const k of Object.keys(o)) if (o[k] === undefined) delete o[k];\n return o;\n}\n\n// --- the session store ---------------------------------------------------------------\n\n/** `<database>#<session id>`: readTranscript is given a file, and Devin keeps every\n * session in one database, so the session has to ride in the string. */\nexport const transcriptRef = (db: string, session: string): string => `${db}#${session}`;\nexport function splitRef(ref: string | undefined): { db: string; session: string } | null {\n if (!ref) return null;\n const at = ref.lastIndexOf(\"#\");\n if (at <= 0) return null;\n const db = ref.slice(0, at);\n const session = ref.slice(at + 1);\n return db && SESSION_ID.test(session) ? { db, session } : null;\n}\n\n/** `message_nodes` is a forest: it keeps abandoned branches too (27 nodes for a\n * two-turn session). The transcript is the one chain that ends at\n * `sessions.main_chain_id`, walked up through `parent_node_id` \u2014 never every node. */\n/** The walk stops at the cursor (`m.node_id >= ?`): everything below it has been read\n * already, and without that bound every Stop pulled `chat_message` for every ancestor\n * \u2014 the root of a real chain carries a 17 kB system prompt and four more system\n * blocks, re-read on every event, and past 32 MB the child and CLI engines give up\n * and return nothing. The cap keeps the NEWEST rows (`DESC`), re-sorted below: an\n * ascending cap would have kept the oldest and delivered no new turn ever again.\n * `UNION`, not `UNION ALL`: SQLite queues a row only if it has not queued the same row\n * before, so a chain that loops back on itself (a node its own parent, two that name\n * each other) ends at the first node it reaches twice. Under `UNION ALL` it recursed\n * for ever, and on the in-process engine nothing can interrupt that: the worker spins,\n * holds the session's lock and delivers nothing. */\nconst CHAIN_LIMIT = 4000;\nexport const CHAIN_SQL = `WITH RECURSIVE chain(node_id, parent_node_id, chat_message, created_at) AS (\n SELECT node_id, parent_node_id, chat_message, created_at FROM message_nodes\n WHERE session_id = ? AND node_id = (SELECT main_chain_id FROM sessions WHERE id = ?)\n UNION\n SELECT m.node_id, m.parent_node_id, m.chat_message, m.created_at FROM message_nodes m\n JOIN chain c ON m.node_id = c.parent_node_id AND m.session_id = ? AND m.node_id >= ?\n)\nSELECT node_id, chat_message, created_at FROM chain ORDER BY node_id DESC LIMIT ${CHAIN_LIMIT}`;\n\n/** Times are unix SECONDS in this store. The first ask comes from `prompt_history`,\n * because `sessions.title` holds whatever the titler last produced \u2014 a backticked\n * command, or a raw `functions.Shell:0{\u2026}` mid-turn. */\nconst SESSION_FIELDS = `s.model, s.working_directory, s.created_at, s.last_activity_at,\n (SELECT p.content FROM prompt_history p WHERE p.session_id = s.id AND p.is_shell = 0\n ORDER BY p.timestamp ASC, p.id ASC LIMIT 1) AS first_ask`;\nconst SESSION_SQL = `SELECT ${SESSION_FIELDS} FROM sessions s WHERE s.id = ? LIMIT 1`;\n// typeof(id) = 'text' (the literal rides as a parameter: the CLI engine takes no quote\n// in the SQL): an id a session ref could carry. A blob id comes back from the sqlite3\n// CLI as a string shaped by its version, so the database says what it is.\nconst BACKFILL_SQL = `SELECT s.id, ${SESSION_FIELDS} FROM sessions s\n WHERE s.hidden = 0 AND typeof(s.id) = ? AND s.last_activity_at >= ?\n ORDER BY s.last_activity_at DESC LIMIT 500`;\n\nfunction sessionFacts(row: Record<string, unknown>): SessionFacts {\n const out: SessionFacts = {};\n if (typeof row.model === \"string\" && row.model) out.model = row.model;\n if (typeof row.working_directory === \"string\" && path.isAbsolute(row.working_directory))\n out.cwd = row.working_directory;\n const started = Number(row.created_at);\n const last = Number(row.last_activity_at);\n if (Number.isFinite(started) && started > 0) out.started_at = Math.round(started * 1000);\n if (Number.isFinite(last) && last > 0) out.last_at = Math.round(last * 1000);\n if (typeof row.first_ask === \"string\") {\n const line = row.first_ask.split(\"\\n\").find((l) => l.trim()) ?? \"\";\n if (line.trim()) {\n out.title = cut(line.trim(), 80);\n out.title_source = \"first-ask\";\n }\n }\n return out;\n}\n\ninterface ChatMessage {\n role?: unknown;\n content?: unknown;\n metadata?: { is_user_input?: unknown; created_at?: unknown } | null;\n}\n\n/** The canonical chain as turns. `node_id` is the cursor: it rises along the chain and\n * is stable across a resume, so a later read starts where the last one stopped.\n * `role: \"system\"` is Cognition's own prompt (and the skills manifest, and the\n * generated system_info block), never the person's words \u2014 it is skipped at every\n * tier, as is `role: \"tool\"`. */\nexport function readDevinChain(db: string, session: string, fromLine: number): TranscriptRead {\n if (!SESSION_ID.test(session)) return { turns: [], line: fromLine };\n const floor = Number.isFinite(fromLine) && fromLine > 0 ? Math.floor(fromLine) : 0;\n const rows = querySqlite(db, CHAIN_SQL, [session, session, session, floor]);\n if (!rows?.length) return { turns: [], line: fromLine };\n const msgs: { role: \"user\" | \"assistant\"; text: string; at: number; line: number }[] = [];\n let end = fromLine;\n for (const row of rows) {\n const node = Number(row.node_id);\n if (!Number.isFinite(node)) continue;\n if (node + 1 > end) end = node + 1;\n if (node < fromLine) continue;\n let j: ChatMessage;\n try {\n j = JSON.parse(String(row.chat_message ?? \"\")) as ChatMessage;\n } catch {\n continue;\n }\n const text = typeof j.content === \"string\" ? j.content.trim() : \"\";\n if (!text) continue;\n // The message's own time, not the row's. `message_nodes.created_at` is when the row\n // batch was last WRITTEN: Devin rewrites it on every save of the chain, so every\n // node of a chain usually carries one identical value, and it is not even monotonic\n // along the chain. Measured on a live store 2026-10-08: a two-turn session had all\n // four of its chain nodes at 23:33:10 while their own `metadata.created_at` read\n // 23:32:29, :34, 23:33:08 and :10 (turn 1 reported 41 s late, both turns at the same\n // instant); one node's row time was rewritten 12 s later between two reads; and a\n // descendant's row time was 27 s EARLIER than its ancestor's. The column is only the\n // fallback for a row whose message has no time of its own.\n const secs = Number(row.created_at);\n const at =\n Date.parse(String(j.metadata?.created_at ?? \"\")) ||\n (Number.isFinite(secs) && secs > 0 ? Math.round(secs * 1000) : 0) ||\n Date.now();\n if (j.role === \"user\" && j.metadata?.is_user_input === true) msgs.push({ role: \"user\", text, at, line: node });\n else if (j.role === \"assistant\") msgs.push({ role: \"assistant\", text, at, line: node });\n }\n // The rows come newest first (the cap keeps the newest); a transcript runs the other way.\n msgs.sort((a, b) => a.line - b.line);\n return pairTurns(msgs, end);\n}\n\n/** `<data dir>/_versions/current` is a symlink to the running version's folder. */\nexport function devinVersion(env: NodeJS.ProcessEnv = process.env): string | undefined {\n try {\n const target = readlinkSync(path.join(devinDataDir(env), \"_versions\", \"current\"));\n const name = path.basename(target);\n return /^[0-9][0-9A-Za-z.+-]{0,63}$/.test(name) ? name : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** The organisation the CLI is signed in to, from the user config \u2014 the only account id\n * Devin keeps in a plain local file. Never the email, and never credentials.toml. */\nexport function devinAccount(env: NodeJS.ProcessEnv = process.env): string | undefined {\n const d = readJson(configFile(env)).devin as { org_id?: unknown } | undefined;\n const id = d && typeof d === \"object\" ? d.org_id : undefined;\n return typeof id === \"string\" && /^[A-Za-z0-9_.:-]{1,128}$/.test(id) ? id : undefined;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// Read-only SQLite, for a harness that keeps its sessions in a database instead of a\n// JSONL file. Three ways in, tried in order, because `node:sqlite` does not exist on\n// Node 20 (the floor this package builds for) and is behind --experimental-sqlite on\n// 22.5\u201322.12:\n// \"node\" in this process, through createRequire \u2014 no static import, so the bundle\n// still loads on a Node without the module;\n// \"child\" one `node --experimental-sqlite -e \u2026` run through execFileSync: no shell,\n// arguments passed as argv, a short timeout;\n// \"cli\" the `sqlite3` binary, when it is on PATH and every parameter is a plain\n// scalar that can be written as a literal.\n// Every path opens the file read-only, is bounded in time, and returns null instead of\n// throwing: a database that is busy, missing, locked or unreadable costs the caller\n// nothing but an empty read.\nimport { execFileSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\n\nexport type SqliteParam = string | number;\nexport type SqliteRow = Record<string, unknown>;\nexport type SqliteEngine = \"auto\" | \"node\" | \"child\" | \"cli\";\n\nexport interface SqliteOptions {\n /** Busy timeout and the child's wall clock, in ms (default 2000). */\n timeoutMs?: number;\n /** Force one way in; \"auto\" tries node, then child, then cli (default). */\n engine?: SqliteEngine;\n /** Largest reply a child or the CLI may print (default 32 MB). */\n maxBuffer?: number;\n}\n\ninterface Statement {\n all(...params: SqliteParam[]): unknown[];\n}\ninterface Db {\n prepare(sql: string): Statement;\n exec(sql: string): void;\n close(): void;\n}\ntype DbCtor = new (path: string, options?: Record<string, unknown>) => Db;\n\n/** `node:sqlite` is still experimental, and Node says so on stderr the first time it is\n * used. A reader has no business writing to a harness's terminal, so that one warning\n * is swallowed while the module is loaded and used \u2014 nothing else is, and the original\n * emitter is back before this returns. (The child path passes --no-warnings instead.)\n * Exported for its test: Node emits that warning once per process. */\nexport function quiet<T>(fn: () => T): T {\n const original = process.emitWarning;\n try {\n process.emitWarning = ((warning: unknown, ...rest: unknown[]) => {\n const kind = typeof rest[0] === \"string\" ? rest[0] : (rest[0] as { type?: string } | undefined)?.type;\n if (kind === \"ExperimentalWarning\" && /sqlite/i.test(String(warning))) return;\n (original as (...a: unknown[]) => void).call(process, warning, ...rest);\n }) as typeof process.emitWarning;\n return fn();\n } finally {\n process.emitWarning = original;\n }\n}\n\nlet ctorCache: DbCtor | null | undefined;\n/** `node:sqlite` if this Node has it; null if it does not (Node 20, or 22.x unflagged). */\nfunction dbCtor(): DbCtor | null {\n if (ctorCache !== undefined) return ctorCache;\n ctorCache = null;\n try {\n const req = createRequire(import.meta.url);\n const m = quiet(() => req(\"node:sqlite\")) as { DatabaseSync?: unknown };\n if (typeof m?.DatabaseSync === \"function\") ctorCache = m.DatabaseSync as DbCtor;\n } catch {}\n return ctorCache;\n}\n\n/** SQLite gives back strings, numbers, null, BigInt and Uint8Array; the protocol takes JSON. */\nfunction plain(row: unknown): SqliteRow | null {\n if (!row || typeof row !== \"object\") return null;\n const out: SqliteRow = {};\n for (const [k, v] of Object.entries(row as SqliteRow)) {\n if (typeof v === \"bigint\") out[k] = Number(v);\n else if (v instanceof Uint8Array) out[k] = null;\n else out[k] = v;\n }\n return out;\n}\nconst rows = (v: unknown): SqliteRow[] | null => {\n if (!Array.isArray(v)) return null;\n const out: SqliteRow[] = [];\n for (const r of v) {\n const p = plain(r);\n if (p) out.push(p);\n }\n return out;\n};\n\nfunction viaNode(file: string, sql: string, params: SqliteParam[], o: Required<SqliteOptions>): SqliteRow[] | null {\n const C = dbCtor();\n if (!C) return null;\n let db: Db;\n try {\n db = quiet(() => new C(file, { readOnly: true, timeout: o.timeoutMs }));\n } catch {\n return null;\n }\n try {\n try {\n db.exec(`PRAGMA busy_timeout = ${Math.round(o.timeoutMs)}`);\n } catch {}\n return quiet(() => rows(db.prepare(sql).all(...params)));\n } catch {\n return null;\n } finally {\n try {\n db.close();\n } catch {}\n }\n}\n\n/** Runs in a child Node, with the file, the SQL, the parameters and the timeout as argv. */\nconst CHILD = `const { DatabaseSync } = require(\"node:sqlite\");\nconst [, file, sql, params, ms] = process.argv;\nconst db = new DatabaseSync(file, { readOnly: true, timeout: Number(ms) });\ntry { db.exec(\"PRAGMA busy_timeout = \" + Number(ms)); } catch {}\nconst out = db.prepare(sql).all(...JSON.parse(params));\ndb.close();\nprocess.stdout.write(JSON.stringify(out));`;\n\nfunction viaChild(file: string, sql: string, params: SqliteParam[], o: Required<SqliteOptions>): SqliteRow[] | null {\n try {\n const out = execFileSync(\n process.execPath,\n [\"--experimental-sqlite\", \"--no-warnings\", \"-e\", CHILD, file, sql, JSON.stringify(params), String(o.timeoutMs)],\n {\n encoding: \"utf8\",\n timeout: o.timeoutMs + 3000,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n maxBuffer: o.maxBuffer,\n windowsHide: true,\n },\n );\n return rows(JSON.parse(out || \"null\"));\n } catch {\n return null;\n }\n}\n\n/** A parameter safe to write into SQL as a literal: no quote, no backslash, no newline. */\nconst SAFE = /^[A-Za-z0-9 ._:@/+-]{0,256}$/;\nexport function inlineParams(sql: string, params: SqliteParam[]): string | null {\n if (sql.includes(\"'\")) return null; // a literal in the SQL would make the `?` count a guess\n const holes = sql.split(\"?\").length - 1;\n if (holes !== params.length) return null;\n let i = 0;\n let bad = false;\n const out = sql.replace(/\\?/g, () => {\n const p = params[i++];\n if (typeof p === \"number\") {\n if (!Number.isFinite(p)) {\n bad = true;\n return \"NULL\";\n }\n return String(p);\n }\n if (typeof p !== \"string\" || !SAFE.test(p)) {\n bad = true;\n return \"NULL\";\n }\n return `'${p}'`;\n });\n return bad ? null : out;\n}\n\nfunction viaCli(file: string, sql: string, params: SqliteParam[], o: Required<SqliteOptions>): SqliteRow[] | null {\n const text = inlineParams(sql, params);\n if (!text) return null;\n try {\n const out = execFileSync(\"sqlite3\", [\"-readonly\", \"-json\", file, text], {\n encoding: \"utf8\",\n timeout: o.timeoutMs + 3000,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n maxBuffer: o.maxBuffer,\n windowsHide: true,\n }).trim();\n if (!out) return [];\n return rows(JSON.parse(out));\n } catch {\n return null;\n }\n}\n\n/** One read-only query. Null means \"could not read it\", never an exception. */\nexport function querySqlite(\n file: string,\n sql: string,\n params: SqliteParam[] = [],\n opts: SqliteOptions = {},\n): SqliteRow[] | null {\n const o: Required<SqliteOptions> = {\n timeoutMs: opts.timeoutMs ?? 2000,\n engine: opts.engine ?? \"auto\",\n maxBuffer: opts.maxBuffer ?? 32 * 1024 * 1024,\n };\n if (!file) return null;\n try {\n if (!existsSync(file)) return null;\n } catch {\n return null;\n }\n const ways =\n o.engine === \"auto\"\n ? ([viaNode, viaChild, viaCli] as const)\n : o.engine === \"node\"\n ? ([viaNode] as const)\n : o.engine === \"child\"\n ? ([viaChild] as const)\n : ([viaCli] as const);\n for (const way of ways) {\n const r = way(file, sql, params, o);\n if (r) return r;\n }\n return null;\n}\n\n/** Is `node:sqlite` in this process? (Tests skip what they cannot set up.) */\nexport const sqliteInProcess = (): boolean => dbCtor() !== null;\n", "// SPDX-License-Identifier: Apache-2.0\n// Gemini CLI (Google) \u2014 docs: https://geminicli.com/docs/hooks/reference\n// Config: ~/.gemini/settings.json `hooks` key, same array-of-groups shape as Claude\n// Code but timeouts in MILLISECONDS and a `name` per handler. stdout must be JSON or\n// empty. Its own telemetry defaults logPrompts on; the installer says so once.\nimport { execFileSync } from \"node:child_process\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { homeDir } from \"../paths.js\";\nimport { ends, parseLines } from \"../readers/files.js\";\nimport { readGemini } from \"../readers/transcripts.js\";\nimport { installClaudeShaped, installedClaudeShaped, readJson, uninstallClaudeShaped } from \"./claude-shaped.js\";\nimport { findBinary, probe } from \"./headless.js\";\nimport type { Adapter, HookInput, HookResult, InstallOptions, SessionFacts } from \"./types.js\";\n\nconst NAME = \"gemini-cli\";\nexport const GEMINI_EVENTS = [\n \"SessionStart\",\n \"BeforeAgent\",\n \"BeforeTool\",\n \"AfterTool\",\n \"Notification\",\n \"AfterAgent\",\n \"PreCompress\",\n \"SessionEnd\",\n] as const;\nconst OPTS = { matcherFor: (e: string) => (/Tool/.test(e) ? \".*\" : undefined), timeout: 5000 };\nconst geminiDir = (env: NodeJS.ProcessEnv) => env.GEMINI_CLI_HOME || path.join(homeDir(), \".gemini\");\nconst settings = (env: NodeJS.ProcessEnv) => path.join(geminiDir(env), \"settings.json\");\nconst validTool = (n: unknown): n is string => typeof n === \"string\" && /^[A-Za-z0-9_.:-]{1,120}$/.test(n);\nconst eventsFor = (lean?: boolean) => (lean ? GEMINI_EVENTS.filter((e) => e !== \"BeforeTool\") : [...GEMINI_EVENTS]);\n\n/** `gemini --version`. On Windows the CLI is npm's gemini.cmd shim, which node refuses to\n * spawn bare, so there it is looked up on PATH and run as `probe` says (the shim's own\n * script under this node, else through a shell). */\nexport function geminiVersion(\n platform: NodeJS.Platform = process.platform,\n env: NodeJS.ProcessEnv = process.env,\n): string {\n const win = platform === \"win32\";\n const bin = win\n ? findBinary({ names: [\"gemini.exe\", \"gemini.cmd\"], dirs: [path.dirname(process.execPath)], env })\n : \"gemini\";\n if (!bin) throw new Error(\"no gemini on PATH\");\n const c = probe(bin, [\"--version\"]);\n return execFileSync(c.file, c.args, {\n encoding: \"utf8\",\n timeout: 4000,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n env,\n shell: c.shell,\n }).trim();\n}\n\n/** Before 0.46 the hooks system is off unless tools.enableHooks is true (issue #11). */\nexport function geminiHooksActive(settingsFile: string): { active: boolean; note?: string } {\n const tools = readJson(settingsFile).tools as { enableHooks?: unknown } | undefined;\n if (tools?.enableHooks === true) return { active: true };\n if (tools?.enableHooks === false)\n return { active: false, note: \"inactive: tools.enableHooks is false in settings.json\" };\n let version = \"\";\n try {\n version = geminiVersion();\n } catch {\n return {\n active: true,\n note: \"could not run `gemini --version`; hooks need tools.enableHooks on versions before 0.46\",\n };\n }\n const m = /(\\d+)\\.(\\d+)/.exec(version);\n if (m && (Number(m[1]) > 0 || Number(m[2]) >= 46)) return { active: true };\n return {\n active: false,\n note: `inactive: Gemini CLI ${version || \"?\"} runs hooks only with \"tools\": {\"enableHooks\": true} in settings.json`,\n };\n}\n\nexport const geminiCli: Adapter = {\n name: NAME,\n events: GEMINI_EVENTS,\n // ~/.gemini also belongs to Antigravity; Gemini CLI is here when its settings or its chat logs exist.\n detect: (env = process.env) => existsSync(settings(env)) || existsSync(path.join(geminiDir(env), \"tmp\")),\n configFiles: (env = process.env) => [settings(env)],\n install: (cmd, env = process.env, opts: InstallOptions = {}) => {\n const r = installClaudeShaped(settings(env), NAME, eventsFor(opts.lean), cmd, OPTS);\n const a = geminiHooksActive(settings(env));\n return [a.note && !r.skipped ? { ...r, note: [r.note, a.note].filter(Boolean).join(\"; \") } : r];\n },\n uninstall: (env = process.env, opts: InstallOptions = {}) => [\n uninstallClaudeShaped(settings(env), GEMINI_EVENTS, { created: opts.created?.includes(settings(env)) }),\n ],\n installed: (cmd, env = process.env, opts: InstallOptions = {}) => {\n const state = installedClaudeShaped(settings(env), NAME, eventsFor(opts.lean), cmd, OPTS);\n const a = geminiHooksActive(settings(env));\n return [\n {\n file: settings(env),\n state: state === \"current\" && !a.active ? \"inactive\" : state,\n ...(a.note ? { note: a.note } : {}),\n },\n ];\n },\n\n fromHook(input: HookInput): HookResult | null {\n const event = input.argv[1] ?? \"\";\n let s: Record<string, unknown> = {};\n try {\n // A stdin that is JSON but not an object (`null`, a number) is no payload.\n const j: unknown = input.stdin ? JSON.parse(input.stdin) : {};\n if (j && typeof j === \"object\" && !Array.isArray(j)) s = j as Record<string, unknown>;\n } catch {}\n const id = s.session_id as string | undefined;\n if (!id) return null;\n const session: HookResult[\"session\"] = { id: String(id), cwd: typeof s.cwd === \"string\" ? s.cwd : input.cwd };\n const tool = validTool(s.tool_name) ? s.tool_name : undefined;\n const ev = (type: string, data: Record<string, unknown>) => ({ type, data: prune(data), harnessEvent: event });\n const events: HookResult[\"events\"] = [];\n switch (event) {\n case \"SessionStart\":\n events.push(\n ev(\"session.started\", {\n source:\n typeof s.source === \"string\" && [\"startup\", \"resume\", \"clear\"].includes(s.source) ? s.source : \"unknown\",\n }),\n );\n break;\n case \"BeforeAgent\":\n events.push(\n ev(\"turn.started\", { prompt_chars: typeof s.prompt === \"string\" ? [...s.prompt].length : undefined }),\n );\n break;\n case \"BeforeTool\":\n if (tool) events.push(ev(\"tool.started\", { tool, input: s.tool_input }));\n break;\n case \"AfterTool\": {\n const resp = s.tool_response as { error?: unknown; llmContent?: unknown } | undefined;\n const err =\n resp && typeof resp === \"object\" && resp.error\n ? String(typeof resp.error === \"string\" ? resp.error : JSON.stringify(resp.error)).slice(0, 2000)\n : undefined;\n if (tool)\n events.push(\n ev(\"tool.ended\", {\n tool,\n ok: !err,\n error: err,\n input: s.tool_input,\n output: resp?.llmContent ?? s.tool_response,\n }),\n );\n break;\n }\n case \"Notification\":\n events.push(\n ev(\"attention.needed\", {\n attention_id: `notif-${Date.now()}`,\n kind: s.notification_type === \"ToolPermission\" ? \"permission\" : \"question\",\n message: typeof s.message === \"string\" ? s.message.slice(0, 200) : undefined,\n }),\n );\n break;\n case \"AfterAgent\":\n events.push(ev(\"turn.ended\", { reason: \"stop\" }));\n break;\n case \"PreCompress\":\n events.push(ev(\"context.compacted\", { trigger: s.trigger === \"manual\" ? \"manual\" : \"auto\" }));\n break;\n case \"SessionEnd\":\n events.push(\n ev(\"session.ended\", {\n reason:\n s.reason === \"clear\" || s.reason === \"logout\" || s.reason === \"exit\"\n ? s.reason\n : s.reason === \"prompt_input_exit\"\n ? \"exit\"\n : \"other\",\n }),\n );\n break;\n default:\n return null;\n }\n const r: HookResult = { session, events, hints: {} };\n if (typeof s.transcript_path === \"string\") r.transcript = s.transcript_path;\n return r;\n },\n\n readTranscript(file, fromLine) {\n let text = \"\";\n try {\n text = readFileSync(file, \"utf8\");\n } catch {\n return { turns: [], line: fromLine };\n }\n return readGemini(text.split(\"\\n\"), fromLine);\n },\n\n facts(_session, transcript): SessionFacts {\n const out: SessionFacts = {};\n if (!transcript) return out;\n const { head, tail } = ends(transcript, 64 * 1024, 64 * 1024);\n const H = parseLines(head);\n const T = parseLines(tail);\n const first = H.find((j) => j.type === \"user\");\n const raw = first ? (first.content ?? first.message ?? first.text) : undefined;\n const text = typeof raw === \"string\" ? raw.trim() : \"\";\n if (text) {\n const line = text.split(\"\\n\")[0] as string; // trimmed, so its first line is its first non-blank one\n out.title = line.length > 80 ? `${line.slice(0, 80).replace(/\\s+\\S*$/, \"\")}\u2026` : line;\n out.title_source = \"first-ask\";\n }\n const times = H.concat(T)\n .map((j) => Date.parse(String(j.timestamp ?? \"\")))\n .filter((n) => n > 0);\n if (times.length) {\n out.started_at = Math.min(...times);\n out.last_at = Math.max(...times);\n }\n return out;\n },\n\n backfill: () => [], // chat logs are keyed by a project hash, not a session id we can name; the first hook of a resumed session reports it\n};\n\nfunction prune<T extends Record<string, unknown>>(o: T): T {\n for (const k of Object.keys(o)) if (o[k] === undefined) delete o[k];\n return o;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// The registry: the only place that lists vendors. A new harness is one file here\n// plus its fixtures and its row in spec/ADAPTERS.md.\nimport { acpHarnesses } from \"./acp-control.js\";\nimport { antigravity } from \"./antigravity.js\";\nimport { findAgy } from \"./antigravity-control.js\";\nimport { claudeCode } from \"./claude-code.js\";\nimport { findClaude } from \"./claude-code-control.js\";\nimport { codex } from \"./codex.js\";\nimport { findCodex } from \"./codex-control.js\";\nimport { devin } from \"./devin.js\";\nimport { geminiCli } from \"./gemini-cli.js\";\nimport type { Adapter } from \"./types.js\";\n\nexport const ADAPTERS: readonly Adapter[] = [claudeCode, codex, geminiCli, antigravity, devin];\nexport const adapterByName = (name: string): Adapter | undefined => ADAPTERS.find((a) => a.name === name);\nexport * as acpControl from \"./acp-control.js\";\nexport { AG_STALE_PRETOOL, antigravityAnswer } from \"./antigravity.js\";\nexport * as antigravityControl from \"./antigravity-control.js\";\nexport { claudeAccountDirs, claudeAccounts, claudeDirs, notClaudeCode } from \"./claude-code.js\";\nexport * as claudeControl from \"./claude-code-control.js\";\nexport * as codexControl from \"./codex-control.js\";\nexport { DEVIN_EVENTS, devinConfigDir, devinDataDir, readDevinChain } from \"./devin.js\";\nexport {\n deniedNote,\n JOB_TIMEOUT_MS,\n jobEnv,\n type Login,\n type Reading,\n type RunOptions,\n type RunResult,\n runHeadless,\n} from \"./headless.js\";\n\n/** How many harnesses a pairing request or a hello lists at most (control-pair.json,\n * control-hello.json). */\nexport const HELLO_HARNESSES_MAX = 20;\n\n/** The harnesses a control daemon here can drive headlessly (CONTROL.md \u00A76): each whose\n * CLI is installed on this machine, and every ACP agent that is. What `control pair`\n * and every hello advertise: the three with their own drivers first, then the ACP\n * agents in the registry's order, at most HELLO_HARNESSES_MAX of them. */\nexport function drivableHarnesses(env: NodeJS.ProcessEnv = process.env): string[] {\n return [\n ...(findClaude(env) ? [\"claude-code\"] : []),\n ...(findCodex(env) ? [\"codex\"] : []),\n ...(findAgy(env) ? [\"antigravity\"] : []),\n ...acpHarnesses(env),\n ].slice(0, HELLO_HARNESSES_MAX);\n}\nexport type {\n Adapter,\n AdapterEvent,\n BackfillRow,\n FactsState,\n HookCommand,\n HookInput,\n HookResult,\n InstallReport,\n SessionFacts,\n TranscriptRead,\n Turn,\n} from \"./types.js\";\nexport { antigravity, claudeCode, codex, devin, geminiCli };\n", "// SPDX-License-Identifier: Apache-2.0\n// ~/.config/sessionpipe/config.json, mode 0600: the machine's name, the sinks with\n// their tier and token, per-harness switches, the update check, remote titles.\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { configFile, tilde } from \"./paths.js\";\nimport type { Tier } from \"./types.js\";\n\nexport interface SinkConfig {\n name: string;\n /** https://\u2026, file:PATH, stdout, otlp:URL */\n url: string;\n tier: Tier;\n pii?: boolean;\n /** @deprecated Never set: control is per machine (spec/CONTROL.md \u00A72). Kept so an\n * older config still reads. */\n control?: boolean;\n token?: string;\n /** whsec_\u2026 for Standard Webhooks signatures. */\n secret?: string;\n /** The token (and secret) live in this store instead of in this file; the client\n * reads them from it when it sends. */\n token_in?: \"keychain\" | \"secret-service\";\n /** Learned from the receiver's well-known file (`sink add`, `connect`; read again by a\n * worker once a day): its tier cap, and the tool events it asked for. */\n max_tier?: Tier;\n receiver_tools?: \"all\" | \"main\" | \"beat\";\n well_known_at?: string;\n /** When a worker last tried to read it again, whether or not the read went through. */\n well_known_checked_at?: string;\n paused?: string;\n /** Which tool events this sink is sent (issue #208): `all`; `main`, a subagent's at\n * most one per session per minute; `beat`, every tool event at most one per session\n * per minute. Unset: what the receiver's well-known file asked for (`receiver_tools`),\n * else `all`, so no receiver's view changes unless it asked. The outbox keeps every\n * event either way. */\n tools?: \"all\" | \"main\" | \"beat\";\n}\n\nexport interface Config {\n machine?: string;\n sinks: SinkConfig[];\n /** `status_line`: Claude Code's status line is ours (install --status-line). */\n harnesses: Record<string, { enabled?: boolean; created?: string[]; status_line?: boolean }>;\n update_check?: boolean;\n keep_days?: number;\n /** Ask a harness's own service for a session's name (an adapter's `remoteFacts`):\n * claude.ai's, for Claude Code. Off unless the person turns it on (`sessionpipe\n * titles on`): it means reading the harness's sign-in token on this machine. */\n remote_titles?: boolean;\n}\n\nexport const DEFAULT_CONFIG: Config = { sinks: [], harnesses: {}, update_check: true, keep_days: 30 };\n\nexport function readConfig(file: string = configFile()): Config {\n try {\n const j = JSON.parse(readFileSync(file, \"utf8\")) as Partial<Config>;\n return {\n ...DEFAULT_CONFIG,\n ...j,\n sinks: Array.isArray(j.sinks) ? j.sinks : [],\n harnesses: j.harnesses && typeof j.harnesses === \"object\" ? j.harnesses : {},\n };\n } catch {\n return { ...DEFAULT_CONFIG, sinks: [], harnesses: {} };\n }\n}\n\n/** Why `file` cannot be read as a config, or undefined when it can: missing, blank, or a\n * JSON object. readConfig reads such a file as the defaults, so hooks go on. */\nfunction configProblem(file: string): string | undefined {\n let text: string;\n try {\n text = readFileSync(file, \"utf8\");\n } catch (e) {\n // Every error readFileSync throws carries a Node error code.\n const code = (e as NodeJS.ErrnoException).code;\n return code === \"ENOENT\" ? undefined : `could not be read (${code})`;\n }\n if (!text.trim()) return undefined;\n if (text.charCodeAt(0) === 0xfeff) return \"starts with a byte-order mark (save it as UTF-8 without one)\";\n try {\n const j: unknown = JSON.parse(text);\n return j && typeof j === \"object\" && !Array.isArray(j) ? undefined : \"is not a JSON object\";\n } catch (e) {\n // Where, never V8's excerpt of the text: that can be part of a sink's token.\n const m = (e as Error).message;\n const at = (/line \\d+ column \\d+/.exec(m) ?? /position \\d+/.exec(m))?.[0];\n return `is not valid JSON${at ? ` at ${at}` : \"\"}`;\n }\n}\n\n/** Throw if `file` holds something readConfig could not read: writing the defaults over a\n * hand edit's typo would lose the machine's name and every sink with its token. A\n * command with an effect before its save calls this first, so it stops before any. */\nexport function assertConfigWritable(file: string = configFile()): void {\n const problem = configProblem(file);\n if (problem)\n throw new Error(\n `${tilde(file)} ${problem}, so it was not written over: that would lose its machine name and sinks. Fix it, or move it aside to start again, then run this again.`,\n );\n}\n\nexport function writeConfig(c: Config, file: string = configFile()): void {\n assertConfigWritable(file);\n mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });\n writeFileSync(file, `${JSON.stringify(c, null, 2)}\\n`, { mode: 0o600 });\n if (process.platform !== \"win32\" && existsSync(file)) {\n try {\n chmodSync(file, 0o600);\n } catch {}\n }\n}\n\n/** The machine's name: what the person configured, else the hostname without a\n * local suffix. Never guessed from anything else (a hand-typed name once linked 64\n * versions to nothing). */\nexport function machineName(c: Config, hostname: string): string {\n if (c.machine) return String(c.machine).slice(0, 80);\n return hostname.replace(/\\.(local|lan|home)$/i, \"\");\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// ULID: 48-bit ms timestamp + 80 random bits, Crockford base32. Monotonic within a\n// process so two events in the same millisecond still sort in emit order.\nimport { randomBytes } from \"node:crypto\";\n\nconst ALPHABET = \"0123456789ABCDEFGHJKMNPQRSTVWXYZ\";\nlet lastTime = 0;\nlet lastRand: number[] = [];\n\nfunction encodeTime(t: number): string {\n let out = \"\";\n let n = t;\n for (let i = 0; i < 10; i++) {\n out = ALPHABET[n % 32] + out;\n n = Math.floor(n / 32);\n }\n return out;\n}\n\nexport function ulid(now: number = Date.now()): string {\n if (now === lastTime) {\n // increment the random part\n for (let i = lastRand.length - 1; i >= 0; i--) {\n const v = (lastRand[i] as number) + 1;\n if (v < 32) {\n lastRand[i] = v;\n break;\n }\n lastRand[i] = 0;\n }\n } else {\n lastTime = now;\n lastRand = Array.from(randomBytes(16), (b) => b % 32);\n }\n return encodeTime(now) + lastRand.map((v) => ALPHABET[v]).join(\"\");\n}\n\nexport const isUlid = (s: string): boolean => /^[0-9A-HJKMNP-TV-Z]{26}$/.test(s);\n", "// SPDX-License-Identifier: Apache-2.0\n// From an adapter's output to a protocol event: id, time, the full session block\n// as known now, and the raw (tier 3) data. Filtering per sink happens later.\nimport type { AdapterEvent } from \"./adapters/types.js\";\nimport type { Event, Session } from \"./types.js\";\nimport { ulid } from \"./ulid.js\";\n\nexport interface EventContext {\n harness: { name: string; version?: string };\n session: Session;\n now?: number;\n}\n\nexport function makeEvent(a: AdapterEvent, ctx: EventContext): Event {\n const now = ctx.now ?? Date.now();\n const harness: Event[\"harness\"] = { name: ctx.harness.name, event: a.harnessEvent };\n if (ctx.harness.version) harness.version = ctx.harness.version;\n return {\n protocol: 1,\n id: ulid(now),\n type: a.type,\n time: new Date(now).toISOString(),\n tier: 3,\n harness,\n session: ctx.session,\n privacy: { rulesets: [], pii: false },\n data: a.data,\n };\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// The outbox: append-only JSONL per (harness, session) under\n// <state>/outbox/<harness>/<session>.jsonl, a per-session seq counter, a per-sink\n// cursor that moves only when the sink acknowledged, and a per-session lock so two\n// workers never interleave. Never lose, never duplicate.\n\nimport { randomBytes } from \"node:crypto\";\nimport {\n appendFileSync,\n closeSync,\n existsSync,\n mkdirSync,\n openSync,\n readdirSync,\n readFileSync,\n readSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport path from \"node:path\";\nimport { safeId } from \"./paths.js\";\nimport type { Event } from \"./types.js\";\n\nexport interface OutboxRef {\n harness: string;\n session: string;\n}\n\nconst READ_CHUNK = 1024 * 1024;\nconst READ_MAX = 8 * 1024 * 1024;\n\nexport class Outbox {\n constructor(readonly root: string) {}\n\n dir(harness: string): string {\n return path.join(this.root, \"outbox\", safeId(harness));\n }\n file(ref: OutboxRef): string {\n return path.join(this.dir(ref.harness), `${safeId(ref.session)}.jsonl`);\n }\n private seqFile(ref: OutboxRef): string {\n return path.join(this.dir(ref.harness), `${safeId(ref.session)}.seq`);\n }\n\n /** The next seq for a session, persisted (survives a hibernating machine and a\n * restart; an in-memory counter would restart at 0 and collide). */\n nextSeq(ref: OutboxRef): number {\n const f = this.seqFile(ref);\n let n = -1;\n try {\n const t = readFileSync(f, \"utf8\").trim();\n if (/^\\d+$/.test(t)) n = Number(t);\n } catch {}\n // A missing or unreadable counter (a crash between truncate and write leaves it\n // empty) with an existing outbox: recover from the file's last line.\n if (n < 0) n = this.lastSeqInFile(ref) + 1;\n mkdirSync(path.dirname(f), { recursive: true, mode: 0o700 });\n writeFileSync(f, String(n + 1), { mode: 0o600 });\n return n;\n }\n\n private lastSeqInFile(ref: OutboxRef): number {\n const f = this.file(ref);\n if (!existsSync(f)) return -1;\n const lines = readFileSync(f, \"utf8\").trim().split(\"\\n\");\n for (let i = lines.length - 1; i >= 0; i--) {\n try {\n const j = JSON.parse(lines[i] as string) as Event;\n if (typeof j.session?.seq === \"number\") return j.session.seq;\n } catch {}\n }\n return -1;\n }\n\n append(ref: OutboxRef, events: Event[]): void {\n if (!events.length) return;\n mkdirSync(this.dir(ref.harness), { recursive: true, mode: 0o700 });\n appendFileSync(this.file(ref), `${events.map((e) => JSON.stringify(e)).join(\"\\n\")}\\n`, { mode: 0o600 });\n }\n\n /** Every session file, newest first. */\n sessions(): OutboxRef[] {\n const out: { ref: OutboxRef; mtime: number }[] = [];\n const base = path.join(this.root, \"outbox\");\n if (!existsSync(base)) return [];\n for (const h of readdirSync(base)) {\n const d = path.join(base, h);\n let names: string[] = [];\n try {\n names = readdirSync(d).filter((n) => n.endsWith(\".jsonl\"));\n } catch {\n continue;\n }\n for (const n of names) {\n try {\n out.push({ ref: { harness: h, session: n.slice(0, -6) }, mtime: statSync(path.join(d, n)).mtimeMs });\n } catch {}\n }\n }\n return out.sort((a, b) => b.mtime - a.mtime).map((x) => x.ref);\n }\n\n /** Read events after byte offset `from`; returns them and the new offset. Lines\n * are read whole; a partial trailing line (a write in progress) is left. A read\n * takes READ_CHUNK bytes at a time, not the rest of the file: a session file grows\n * to tens of MB and a drain takes it in batches of 50. It reads on until the batch\n * is full or the file ends, so lines that parse to nothing never stop a drain; one\n * line longer than the chunk gets a larger one, up to READ_MAX. */\n read(ref: OutboxRef, from: number, maxEvents = 500): { events: Event[]; offset: number } {\n const f = this.file(ref);\n if (!existsSync(f)) return { events: [], offset: from };\n const size = statSync(f).size;\n if (from >= size) return { events: [], offset: from };\n const fd = openSync(f, \"r\");\n try {\n const events: Event[] = [];\n let offset = from;\n let chunk = READ_CHUNK;\n while (events.length < maxEvents && offset < size) {\n const buf = Buffer.alloc(Math.min(size - offset, chunk));\n const n = readSync(fd, buf, 0, buf.length, offset);\n const text = buf.subarray(0, n).toString(\"utf8\");\n let pos = 0;\n let used = 0;\n while (events.length < maxEvents) {\n const nl = text.indexOf(\"\\n\", pos);\n if (nl < 0) break;\n const line = text.slice(pos, nl);\n pos = nl + 1;\n used += Buffer.byteLength(line, \"utf8\") + 1;\n if (!line.trim()) continue;\n try {\n events.push(JSON.parse(line) as Event);\n } catch {}\n }\n offset += used;\n if (used) continue;\n // No whole line in this chunk: a line longer than it, or a write in progress.\n if (offset + n >= size || chunk >= READ_MAX) break;\n chunk *= 2;\n }\n return { events, offset };\n } finally {\n closeSync(fd);\n }\n }\n\n /** Files older than `days` are pruned, and each sink's cursor into them. The seq\n * counter stays: a session resumed after the window counts on from where it was,\n * so a receiver's (harness, session, seq) dedup doesn't take its new events for\n * ones it already has, and the sinks read the new file from its start.\n * It all happens under the drain's `flush` lock, since a drain holds the whole\n * cursor map and writes it back: a file and its cursor keys go together, so a\n * session resumed in between can't keep a key past its new file's end. While a\n * drain runs, nothing is pruned (0); the next prune does it. It never throws: it\n * is a cleanup, and a hook's drain comes after it. */\n prune(days: number, now = Date.now()): number {\n let release: (() => void) | null = null;\n try {\n release = takeNamedLock(this.root, \"flush\");\n } catch {}\n if (!release) return 0;\n let n = 0;\n try {\n const cutoff = now - days * 86_400_000;\n const aged = this.sessions().filter((ref) => {\n try {\n return statSync(this.file(ref)).mtimeMs < cutoff;\n } catch {\n return false;\n }\n });\n // The keys go first: a worker that dies or fails to write here leaves a file\n // with no cursor, which a sink sends again (a receiver's dedup takes it), never\n // a cursor past the end of a file a resume starts. Each file is checked again\n // right before it goes: one a hook appended to meanwhile stays.\n this.dropStaleCursors(new Set(aged.map((ref) => `${ref.harness}/${ref.session}`)));\n for (const ref of aged) {\n const f = this.file(ref);\n try {\n if (statSync(f).mtimeMs < cutoff) {\n unlinkSync(f);\n n++;\n }\n } catch {}\n }\n } catch {\n } finally {\n release();\n }\n return n;\n }\n\n /** A sink's cursor into a session file about to be pruned (`gone`), or one already\n * missing (an earlier prune, an older release, by hand) is removed. The caller\n * holds the `flush` lock. */\n private dropStaleCursors(gone: Set<string>): void {\n let names: string[] = [];\n try {\n names = readdirSync(path.join(this.root, \"cursors\")).filter((n) => n.endsWith(\".json\"));\n } catch {}\n const stale = (c: Record<string, number>): string[] =>\n Object.keys(c).filter((k) => {\n if (gone.has(k)) return true;\n const i = k.indexOf(\"/\");\n return !existsSync(this.file({ harness: k.slice(0, i), session: k.slice(i + 1) }));\n });\n for (const n of names) {\n const s = new Cursors(this.root, n.slice(0, -5));\n const c = s.read();\n const keys = stale(c);\n if (!keys.length) continue;\n for (const k of keys) delete c[k];\n s.write(c);\n }\n }\n\n delete(ref: OutboxRef): void {\n // The cursor keys go before the files: a death between leaves the old file with\n // no cursor, so the next drain sends it whole and the person, who sees no \"removed\"\n // line, runs forget again; the other way round leaves a cursor past the end of\n // the file a session that goes on starts, and nothing says so.\n this.dropCursors(ref);\n for (const f of [this.file(ref), this.seqFile(ref)]) {\n try {\n unlinkSync(f);\n } catch {}\n }\n }\n\n /** The key every sink's cursor holds for a session is removed with the session's\n * file: the key alone pointed into the old file, and a session that went on (still\n * running, or resumed later) had its new file's first events unsent until it grew\n * past that offset. Every file under <state>/cursors is taken (a sink since taken\n * out of the config still has one; one that doesn't parse reads as empty and is\n * left), by the key a drain writes (the file's own name, `safeId`) and by the ref\n * as given. The caller holds the drain's `flush` lock: a drain holds the whole\n * cursor map and writes it back, so a key dropped under it would come back. */\n private dropCursors(ref: OutboxRef): void {\n const keys = new Set([`${ref.harness}/${ref.session}`, `${safeId(ref.harness)}/${safeId(ref.session)}`]);\n let names: string[] = [];\n try {\n names = readdirSync(path.join(this.root, \"cursors\")).filter((n) => n.endsWith(\".json\"));\n } catch {\n return;\n }\n for (const n of names) {\n const s = new Cursors(this.root, n.slice(0, -5));\n const c = s.read();\n const had = Object.keys(c).filter((k) => keys.has(k));\n if (!had.length) continue;\n for (const k of had) delete c[k];\n s.write(c);\n }\n }\n}\n\n/** Per-sink cursor: byte offset per session file, moved only on a 2xx. */\nexport class Cursors {\n constructor(\n readonly root: string,\n readonly sink: string,\n ) {}\n private file(): string {\n return path.join(this.root, \"cursors\", `${safeId(this.sink)}.json`);\n }\n /** The map; empty when the file is missing, cut off mid-write, or holds anything\n * but an object (`null`, a list), so a drain never indexes into those. */\n read(): Record<string, number> {\n try {\n const c = JSON.parse(readFileSync(this.file(), \"utf8\")) as unknown;\n return c && typeof c === \"object\" && !Array.isArray(c) ? (c as Record<string, number>) : {};\n } catch {\n return {};\n }\n }\n write(c: Record<string, number>): void {\n const f = this.file();\n mkdirSync(path.dirname(f), { recursive: true, mode: 0o700 });\n const tmp = `${f}.${process.pid}.tmp`;\n writeFileSync(tmp, JSON.stringify(c), { mode: 0o600 });\n renameSync(tmp, f);\n }\n key(ref: OutboxRef): string {\n return `${ref.harness}/${ref.session}`;\n }\n}\n\n/** A lock per session so two workers never interleave. Stale once the worker that\n * took it is gone (its 15 s deadline ends it without a release), or after 5 min. */\nexport function takeLock(root: string, ref: OutboxRef, staleMs = 5 * 60_000): (() => void) | null {\n return takeNamedLock(root, `${safeId(ref.harness)}-${safeId(ref.session)}`, staleMs);\n}\n\n/** A named lock under <root>/locks, held by one process at a time: the file names\n * its pid and a nonce. Stale once that process is gone, or after `staleMs`. A stale\n * lock is taken over by renaming it aside first: of two workers that both judged it\n * stale, one rename wins, and one that moved a fresh lock instead (another worker's,\n * made in between) puts it back and stands down. The release deletes the file only\n * while it is still this taker's, so a lock taken over can't be wiped by its old\n * holder. Two holders at once used to mean two drains reading the same cursors and\n * sending the same batch (issue #208's one-request-a-second pace rests on one). */\nexport function takeNamedLock(root: string, name: string, staleMs = 5 * 60_000): (() => void) | null {\n const dir = path.join(root, \"locks\");\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n const f = path.join(dir, `${name}.lock`);\n const nonce = randomBytes(8).toString(\"hex\");\n const mine = `${process.pid} ${nonce}`;\n let body: string | null = null;\n try {\n body = readFileSync(f, \"utf8\");\n const stale = Date.now() - statSync(f).mtimeMs > staleMs || !processAlive(Number(body.split(\" \")[0]));\n if (!stale) return null;\n } catch {\n body = null;\n }\n if (body !== null) {\n const aside = `${f}.${process.pid}.${nonce}.stale`;\n try {\n renameSync(f, aside);\n } catch {\n return null;\n }\n // The aside name is this call's own: nobody else reads or removes it.\n const moved = readFileSync(aside, \"utf8\");\n unlinkSync(aside);\n if (moved !== body) {\n try {\n writeFileSync(f, moved, { flag: \"wx\" });\n } catch {}\n return null;\n }\n }\n try {\n writeFileSync(f, mine, { flag: \"wx\" });\n } catch {\n return null;\n }\n return () => {\n try {\n if (readFileSync(f, \"utf8\") === mine) unlinkSync(f);\n } catch {}\n };\n}\n\n/** `takeNamedLock`, tried again every `everyMs` until `forMs` have passed: for a\n * command whose work goes under a lock a worker holds for seconds (a drain). null\n * once the time is up. */\nexport async function waitNamedLock(\n root: string,\n name: string,\n forMs: number,\n everyMs = 100,\n): Promise<(() => void) | null> {\n for (let waited = 0; ; waited += everyMs) {\n const release = takeNamedLock(root, name);\n if (release || waited >= forMs) return release;\n await new Promise((r) => setTimeout(r, everyMs));\n }\n}\n\n/** Whether the process a lock or a claimed job names is still running. A pid that\n * can't be read counts as running: the age rule decides then. */\nexport function processAlive(pid: number): boolean {\n if (!Number.isInteger(pid) || pid <= 0) return true;\n try {\n process.kill(pid, 0);\n return true;\n } catch (e) {\n return (e as NodeJS.ErrnoException).code === \"EPERM\";\n }\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// filter(event, tier, pii): the pure function every sink runs an event through.\n// Removes by ALLOWLIST per type and tier (spec/PRIVACY.md \u00A71), redacts every string\n// above tier 0 with secrets@1, and runs pii@1 when asked. Returns null when the\n// type is not carried at the tier. The conformance runner runs the same function.\nimport type { Event, Tier } from \"../types.js\";\nimport { hashMachine, RULESET_PII, reducePiiDeep } from \"./pii.js\";\nimport { RULESET_SECRETS, redactDeep } from \"./secrets.js\";\n\n/** The lowest tier that carries each known type (kept in step with schema/v1.ts). */\nexport const TYPE_TIER: Record<string, Tier> = {\n \"session.started\": 0,\n \"session.heartbeat\": 0,\n \"session.ended\": 0,\n \"session.backfill\": 0,\n \"session.forgotten\": 0,\n \"turn.started\": 0,\n \"turn.ended\": 0,\n \"turn.transcript\": 2,\n \"turn.progress\": 2,\n \"tool.started\": 1,\n \"tool.ended\": 1,\n \"files.changed\": 1,\n \"attention.needed\": 0,\n \"attention.cleared\": 0,\n \"subagent.started\": 1,\n \"subagent.ended\": 1,\n \"context.compacted\": 1,\n \"limits.observed\": 1,\n \"delegation.started\": 0,\n \"delegation.ended\": 0,\n native: 3,\n};\n\n/** data keys allowed per type at tier N (cumulative: tier 1 includes tier 0's). */\nconst DATA_ALLOW: Record<string, Partial<Record<Tier, string[]>>> = {\n \"session.started\": { 0: [\"source\"] },\n \"session.heartbeat\": { 0: [] },\n \"session.ended\": { 0: [\"reason\"] },\n \"session.backfill\": { 0: [\"started_at\", \"last_at\", \"turns\"] },\n \"session.forgotten\": { 0: [] },\n \"turn.started\": { 0: [\"turn_id\", \"submitted_by\", \"injected\"], 1: [\"prompt_chars\"] },\n \"turn.ended\": { 0: [\"turn_id\", \"reason\", \"ms\", \"background\"], 1: [\"error\"] },\n \"turn.transcript\": { 2: [\"turn\", \"user\", \"assistant\", \"at\", \"injected\"] },\n \"turn.progress\": { 2: [\"turn\", \"user\", \"assistant\", \"at\", \"injected\"] },\n \"tool.started\": { 1: [\"tool\", \"call_id\", \"turn_id\", \"agent_id\"], 3: [\"input\"] },\n \"tool.ended\": { 1: [\"tool\", \"call_id\", \"turn_id\", \"agent_id\", \"ms\", \"ok\", \"error\"], 3: [\"input\", \"output\"] },\n \"files.changed\": { 1: [\"paths\"] },\n \"attention.needed\": { 0: [\"attention_id\", \"kind\"], 1: [\"tool\", \"message\", \"agent_id\"] },\n \"attention.cleared\": { 0: [\"attention_id\", \"how\"] },\n \"subagent.started\": { 1: [\"agent_id\", \"agent_type\"] },\n \"subagent.ended\": { 1: [\"agent_id\", \"agent_type\", \"background\"] },\n \"context.compacted\": { 1: [\"trigger\"] },\n \"limits.observed\": { 1: [\"windows\", \"plan\", \"account_id\"] },\n \"delegation.started\": { 0: [\"ask_id\", \"via\", \"harness\", \"to\"], 1: [\"text\"] },\n \"delegation.ended\": { 0: [\"ask_id\", \"to\", \"ok\", \"ms\", \"error\", \"relayed\"], 2: [\"reply\"] },\n};\n\nconst SESSION_ALLOW = [\n \"id\",\n \"seq\",\n \"machine\",\n \"cwd\",\n \"repo\",\n \"branch\",\n \"model\",\n \"title\",\n \"title_source\",\n \"url\",\n \"account_id\",\n \"attended\",\n \"parent_id\",\n \"launched_by\",\n \"delegated_by\",\n];\nconst MAX_SIDE = 20_000;\nconst MAX_IO = 64 * 1024;\n\nfunction allowedKeys(type: string, tier: Tier): string[] | null {\n const table = DATA_ALLOW[type];\n if (!table) return null; // unknown type: kept whole (receivers keep extra keys), redacted\n const out: string[] = [];\n for (let t = 0; t <= tier; t++) for (const k of table[t as Tier] ?? []) out.push(k);\n return out;\n}\n\nfunction cap(v: unknown, max: number): unknown {\n if (typeof v === \"string\") return v.length > max ? `${v.slice(0, max)}\u2026` : v;\n if (v && typeof v === \"object\") {\n const s = JSON.stringify(v);\n return s.length > max ? `${s.slice(0, max)}\u2026` : v;\n }\n return v;\n}\n\n/** At most `max` characters, keeping the end: an ellipsis, then the last max \u2212 1. */\nexport function capTail(v: string, max: number): string {\n return v.length > max ? `\u2026${v.slice(v.length - max + 1)}` : v;\n}\n\nexport interface FilterOptions {\n /** The person's home directory, for pii@1's `~` rewrite. */\n home?: string;\n}\n\n/** The event as a sink at `tier` may see it, or null when the type is above the tier. */\nexport function filterEvent(event: Event, tier: Tier, pii: boolean, opts: FilterOptions = {}): Event | null {\n const minTier = TYPE_TIER[event.type];\n if (minTier !== undefined && minTier > tier) return null;\n\n const session: Record<string, unknown> = {};\n for (const k of SESSION_ALLOW)\n if (event.session[k as keyof typeof event.session] !== undefined)\n session[k] = event.session[k as keyof typeof event.session];\n\n let data: Record<string, unknown> = {};\n const keys = allowedKeys(event.type, tier);\n if (keys === null) data = { ...event.data };\n else for (const k of keys) if (event.data[k] !== undefined) data[k] = event.data[k];\n if (typeof data.user === \"string\") data.user = cap(data.user, MAX_SIDE);\n // A turn still running is read for where it is now: its reply keeps the end.\n if (typeof data.assistant === \"string\")\n data.assistant = event.type === \"turn.progress\" ? capTail(data.assistant, MAX_SIDE) : cap(data.assistant, MAX_SIDE);\n if (data.input !== undefined) data.input = cap(data.input, MAX_IO);\n if (data.output !== undefined) data.output = cap(data.output, MAX_IO);\n if (typeof data.message === \"string\") data.message = cap(data.message, 200);\n // What an ask asked, and what came back (PROTOCOL.md \u00A74 delegation.*): the daemon cuts\n // them too, but the cap is this function's promise.\n if (event.type === \"delegation.started\" && typeof data.text === \"string\") data.text = cap(data.text, 200);\n if (event.type === \"delegation.ended\" && typeof data.reply === \"string\") data.reply = cap(data.reply, MAX_SIDE);\n\n const rulesets: string[] = [];\n let out: Event = { ...event, tier, session: session as Event[\"session\"], data, privacy: { rulesets, pii } };\n if (tier > 0) {\n // Redact, then the caps above already applied: a cut before redaction could leave half a key.\n out = { ...out, session: redactDeep(out.session), data: redactDeep(out.data) };\n rulesets.push(RULESET_SECRETS);\n }\n if (pii) {\n const s = reducePiiDeep(out.session, opts.home) as Record<string, unknown>;\n if (typeof s.machine === \"string\") s.machine = hashMachine(s.machine);\n delete s.account_id;\n const d = reducePiiDeep(out.data, opts.home) as Record<string, unknown>;\n // limits.observed names the account its numbers belong to: the same identifier\n // pii@1 drops from the session block, so it goes the same way.\n delete d.account_id;\n out = { ...out, session: s as Event[\"session\"], data: d };\n rulesets.push(RULESET_PII);\n }\n out.privacy = { rulesets, pii };\n return out;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// A session's short id (spec/PROTOCOL.md \u00A73): the first 8 hex digits of\n// sha256(\"sessionpipe.session:\" + harness + \":\" + id). What a person reads in a log\n// line, a notification, a search box; derived, never sent. Not a prefix of the id\n// itself: Codex ids are time-ordered (UUIDv7), and two sessions started in the same\n// minute share their first eight characters.\nimport { createHash } from \"node:crypto\";\n\nexport function shortId(harness: string, id: string): string {\n return createHash(\"sha256\").update(`sessionpipe.session:${harness}:${id}`).digest(\"hex\").slice(0, 8);\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// file:PATH \u2014 append filtered events as JSONL. The zero-server sink.\nimport { appendFileSync, mkdirSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { Event, Tier } from \"../types.js\";\nimport type { DeliveryResult, Sink } from \"./types.js\";\n\nexport class FileSink implements Sink {\n constructor(\n readonly name: string,\n readonly file: string,\n readonly tier: Tier,\n readonly pii: boolean,\n ) {}\n async send(events: Event[]): Promise<DeliveryResult> {\n try {\n mkdirSync(path.dirname(this.file), { recursive: true });\n appendFileSync(this.file, `${events.map((e) => JSON.stringify(e)).join(\"\\n\")}\\n`);\n return { ok: true, acknowledged: events.length, accepted: events.length, duplicates: 0, rejected: [] };\n } catch (e) {\n return { ok: false, acknowledged: 0, error: String((e as Error).message), action: \"retry\" };\n }\n }\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// stdout \u2014 one JSON line per event to a writable (the worker's stdout is ignored\n// when spawned by a hook, so this sink is for `sessionpipe tail` and tests).\nimport type { Event, Tier } from \"../types.js\";\nimport type { DeliveryResult, Sink } from \"./types.js\";\n\nexport class StdoutSink implements Sink {\n constructor(\n readonly name: string,\n readonly tier: Tier,\n readonly pii: boolean,\n private readonly write: (line: string) => void = (l) => process.stdout.write(`${l}\\n`),\n ) {}\n async send(events: Event[]): Promise<DeliveryResult> {\n try {\n for (const e of events) this.write(JSON.stringify(e));\n return { ok: true, acknowledged: events.length, accepted: events.length, duplicates: 0, rejected: [] };\n } catch (e) {\n // A closed pipe (`sessionpipe tail | head`): a result, like every other sink.\n return { ok: false, acknowledged: 0, error: String((e as Error).message ?? e), action: \"retry\" };\n }\n }\n}\n", "// SPDX-License-Identifier: Apache-2.0\n/** @sessionpipe/core \u2014 protocol types, adapters, privacy, outbox, sinks. Zero runtime dependencies. */\nexport const PROTOCOL_VERSION = 1 as const;\nexport * as claudePool from \"./adapters/claude-code-pool.js\";\nexport * from \"./adapters/index.js\";\nexport {\n assertConfigWritable,\n type Config,\n DEFAULT_CONFIG,\n machineName,\n readConfig,\n type SinkConfig,\n writeConfig,\n} from \"./config.js\";\nexport { type EventContext, makeEvent } from \"./events.js\";\nexport {\n ASK_CHAIN_ENV,\n DELEGATED_BY_ENV,\n delegatedBy,\n LAUNCHED_BY_ENV,\n LINEAGE_ENV,\n launchedBy,\n readHook,\n withoutLineage,\n} from \"./launched-by.js\";\nexport {\n Cursors,\n Outbox,\n type OutboxRef,\n processAlive,\n takeLock,\n takeNamedLock,\n waitNamedLock,\n} from \"./outbox.js\";\nexport { configFile, homeDir, safeId, stateDir, tilde, untilde } from \"./paths.js\";\nexport * from \"./privacy/index.js\";\nexport { gitFacts, stripCredentials } from \"./readers/git.js\";\nexport {\n isInjected,\n pairTurns,\n peerAsk,\n readAntigravity,\n readClaude,\n readCodex,\n readGemini,\n} from \"./readers/transcripts.js\";\nexport { shortId } from \"./short-id.js\";\nexport * from \"./sinks/index.js\";\nexport type * from \"./types.js\";\nexport { isUlid, ulid } from \"./ulid.js\";\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["createHash", "readFileSync", "os", "path", "execFileSync", "existsSync", "readdirSync", "readFileSync", "statSync", "path", "marked", "path", "cap", "path", "settings", "entry", "path", "readdirSync", "existsSync", "readFileSync", "rows", "pid", "execFileSync", "statSync", "WINDOW_MINUTES", "UUID", "createHash", "code", "st", "fetch", "path", "os", "EMAIL_RE", "readFileSync", "spawn", "os", "path", "readFileSync", "statSync", "path", "statSync", "path", "readFileSync", "os", "path", "spawn", "c", "refused", "existsSync", "readdirSync", "readFileSync", "statSync", "path", "NAME", "path", "ID_RE", "validTool", "existsSync", "prune", "readFileSync", "rows", "readdirSync", "statSync", "os", "path", "os", "path", "str", "claudeLogin", "defaultLevel", "offeredLevels", "execFileSync", "closeSync", "openSync", "readdirSync", "readFileSync", "readSync", "statSync", "os", "path", "createHash", "UUID_RE", "os", "readdirSync", "path", "offeredLevels", "defaultLevel", "claudeLogin", "plain", "execFileSync", "statSync", "cap", "openSync", "readSync", "closeSync", "str", "readFileSync", "existsSync", "readdirSync", "readFileSync", "path", "OURS", "NAME", "OPTS", "eventsFor", "path", "hooksFile", "configFile", "validTool", "endReason", "readFileSync", "OURS", "readdirSync", "existsSync", "id", "r", "prune", "rows", "epochIso", "defaultLevel", "offeredLevels", "reading", "execFile", "readFileSync", "os", "path", "LABEL", "os", "path", "offeredLevels", "defaultLevel", "readFileSync", "execFile", "str", "reading", "createHash", "existsSync", "path", "execFileSync", "existsSync", "NAME", "OPTS", "eventsFor", "path", "configFile", "validTool", "endReason", "pickSource", "errText", "existsSync", "createHash", "prune", "rows", "execFileSync", "existsSync", "readFileSync", "path", "NAME", "OPTS", "path", "validTool", "eventsFor", "execFileSync", "existsSync", "prune", "readFileSync", "existsSync", "mkdirSync", "readFileSync", "writeFileSync", "path", "readFileSync", "mkdirSync", "path", "writeFileSync", "existsSync", "randomBytes", "randomBytes", "closeSync", "existsSync", "mkdirSync", "openSync", "readdirSync", "readFileSync", "readSync", "statSync", "unlinkSync", "writeFileSync", "path", "path", "readFileSync", "mkdirSync", "writeFileSync", "existsSync", "readdirSync", "statSync", "openSync", "readSync", "closeSync", "unlinkSync", "randomBytes", "createHash", "appendFileSync", "mkdirSync", "path"]
|
|
7
7
|
}
|