#!/usr/bin/env node import crypto from "node:crypto"; import fs from "node:fs"; import os from "node:os"; import path from "node:path"; const codexHome = process.env.CODEX_HOME ?? path.join(os.homedir(), ".codex"); const controlRoot = process.env.GH_CODEX_CONTROL_ROOT ?? path.join( codexHome, "runtime", "guanghu-codex-host-bridge", "state", "control", ); const controllerPath = path.join(controlRoot, "current-controller.json"); const leasePath = path.join(controlRoot, "write-lease.json"); const categories = new Set(["remote_git", "external_publish", "destructive_cleanup"]); function atomicWrite(file, value) { fs.mkdirSync(path.dirname(file), { recursive: true }); const temporary = `${file}.${process.pid}.tmp`; fs.writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\n`, { encoding: "utf8", mode: 0o600, }); fs.renameSync(temporary, file); } function readJson(file) { return JSON.parse(fs.readFileSync(file, "utf8")); } function parseArgs(argv) { const [action = "status", ...rest] = argv; const values = {}; for (let index = 0; index < rest.length; index += 2) { if (!rest[index]?.startsWith("--") || rest[index + 1] === undefined) { throw new Error("INVALID_ARGUMENTS"); } values[rest[index].slice(2)] = rest[index + 1]; } return { action, values }; } function assertEvidence(controller) { if ( controller?.schema !== "guanghu.codex-current-controller/v1" || controller.direct_human_natural_language !== true || !controller.numbered_event_path || !fs.existsSync(controller.numbered_event_path) ) throw new Error("CURRENT_CONTROLLER_EVIDENCE_INVALID"); const event = readJson(controller.numbered_event_path); if ( event.raw_text_sha256 !== controller.raw_text_sha256 || event.source_kind !== "DIRECT_HUMAN_NATURAL_LANGUAGE" ) throw new Error("CURRENT_CONTROLLER_SOURCE_MISMATCH"); } const { action, values } = parseArgs(process.argv.slice(2)); if (action === "status") { process.stdout.write(`${JSON.stringify({ controller: fs.existsSync(controllerPath) ? readJson(controllerPath) : null, lease: fs.existsSync(leasePath) ? readJson(leasePath) : null, }, null, 2)}\n`); process.exit(0); } if (action === "revoke") { try { fs.unlinkSync(leasePath); } catch (error) { if (error?.code !== "ENOENT") throw error; } process.stdout.write(`${JSON.stringify({ decision: "REVOKED" })}\n`); process.exit(0); } if (action !== "issue") throw new Error("UNKNOWN_ACTION"); const controller = readJson(controllerPath); assertEvidence(controller); if ( values["session-id"] !== controller.session_id || values["turn-id"] !== controller.turn_id ) throw new Error("LEASE_REQUEST_IS_NOT_CURRENT_CONTROLLER_TURN"); if (!categories.has(values.category)) throw new Error("LEASE_CATEGORY_INVALID"); if (!values.reason || !values.target) throw new Error("LEASE_REASON_OR_TARGET_MISSING"); const ttlSeconds = Number(values["ttl-seconds"] ?? 600); if (!Number.isInteger(ttlSeconds) || ttlSeconds < 30 || ttlSeconds > 900) { throw new Error("LEASE_TTL_INVALID"); } const issuedAt = Date.now(); const lease = { schema: "guanghu.codex-one-shot-write-lease/v1", lease_id: crypto.randomUUID(), control_epoch: controller.control_epoch, session_id: controller.session_id, turn_id: controller.turn_id, category: values.category, cwd: path.resolve(values.cwd ?? process.cwd()), target: values.target, reason: values.reason, evidence_event_number: controller.numbered_event_number, evidence_raw_text_sha256: controller.raw_text_sha256, issued_at: new Date(issuedAt).toISOString(), expires_at_unix_ms: issuedAt + ttlSeconds * 1000, one_shot: true, }; atomicWrite(leasePath, lease); process.stdout.write(`${JSON.stringify({ decision: "ISSUED", lease }, null, 2)}\n`);