hololake-system-architecture/product-source/hololake-native-desktop/system-integrations/codex-host-bridge/runtime/write-lease.mjs

108 lines
3.7 KiB
JavaScript

#!/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`);