const OL_DIR = __OPENLATCH_DIR__;
const BUDGET_MS = 1500;
const TOAST_MS = 300;
const CAP_BYTES = __CAP_BYTES__;
const WIN = process.platform === "win32";
const HOOK = OL_DIR + (WIN ? "\\bin\\openlatch-hook.exe" : "/bin/openlatch-hook");
const TRUNCATE_ORDER = ["output", "args", "prompt"];
const SEEN = Symbol.for("openlatch.opencode.load-report");
const enc = new TextEncoder();
const size = (value) => enc.encode(JSON.stringify(value)).length;
function longest(holder, key, best) {
const v = holder[key];
if (typeof v === "string") {
if (!best || v.length > best[0][best[1]].length) return [holder, key];
return best;
}
if (v && typeof v === "object") {
for (const k of Object.keys(v)) best = longest(v, k, best);
}
return best;
}
function fit(payload) {
if (size(payload) <= CAP_BYTES) return payload;
const copy = JSON.parse(JSON.stringify(payload));
const cut = [];
for (const field of TRUNCATE_ORDER) {
while (size(copy) > CAP_BYTES) {
const target = longest(copy, field, null);
if (!target || target[0][target[1]].length === 0) break;
const s = target[0][target[1]];
target[0][target[1]] = s.slice(0, Math.floor(s.length / 2));
if (!cut.includes(field)) cut.push(field);
copy.truncated = cut;
}
if (size(copy) <= CAP_BYTES) break;
}
return copy;
}
async function firstLine(stream) {
const reader = stream.getReader();
const dec = new TextDecoder();
let text = "";
try {
for (;;) {
const { value, done } = await reader.read();
if (done) break;
text += dec.decode(value, { stream: true });
const nl = text.indexOf("\n");
if (nl >= 0) {
text = text.slice(0, nl);
break;
}
}
} finally {
try { Promise.resolve(reader.cancel()).catch(() => {}); } catch {}
}
return text.trim();
}
async function call(event, payload, captureOnly) {
let proc = null;
let timer = null;
try {
const argv = [HOOK, "--agent", "opencode", "--event", event, "--openlatch-dir", OL_DIR,
"--plugin-host-pid", String(process.pid)];
if (captureOnly) argv.push("--capture-only");
const body = JSON.stringify(fit(payload));
proc = Bun.spawn(argv, {
stdin: captureOnly ? "pipe" : new Blob([body]),
stdout: captureOnly ? "ignore" : "pipe",
stderr: "ignore",
windowsHide: true,
});
if (captureOnly) {
proc.stdin.write(body);
proc.stdin.end();
return null;
}
const answer = Promise.all([firstLine(proc.stdout), proc.exited]);
const budget = new Promise((resolve) => { timer = setTimeout(() => resolve(null), BUDGET_MS); });
const done = await Promise.race([answer, budget]);
if (!done) {
try { proc.kill("SIGKILL"); } catch {}
return null;
}
const [line, code] = done;
if (code !== 0 || !line) return null;
const verdict = JSON.parse(line);
return verdict && typeof verdict === "object" ? verdict : null;
} catch {
try { if (proc) proc.kill("SIGKILL"); } catch {}
return null;
} finally {
if (timer) clearTimeout(timer);
}
}
const isBlock = (v) => !!v && v.decision === "block" && typeof v.reason === "string" && v.reason.length > 0;
const LIFECYCLE = { "session.created": "session_start", "session.idle": "stop", "session.deleted": "session_end" };
const CHILDREN = new Map();
const CHILDREN_MAX = 1024;
const LOOKUP_MS = 1000;
function remember(id, parent) {
CHILDREN.delete(id);
if (CHILDREN.size >= CHILDREN_MAX) CHILDREN.delete(CHILDREN.keys().next().value);
CHILDREN.set(id, parent);
}
const DELETIONS = new Map();
function deleted(id) {
const count = (DELETIONS.get(id) || 0) + 1;
DELETIONS.delete(id);
if (DELETIONS.size >= CHILDREN_MAX) DELETIONS.delete(DELETIONS.keys().next().value);
DELETIONS.set(id, count);
}
async function lookup(client, id) {
let timer = null;
try {
const asked = Promise.resolve(client.session.get({ path: { id } })).then(
(res) => {
const info = res && res.data;
if (!info || typeof info !== "object") return undefined;
return typeof info.parentID === "string" ? info.parentID : info.parentID === undefined ? null : undefined;
},
() => undefined,
);
const late = new Promise((resolve) => { timer = setTimeout(() => resolve(undefined), LOOKUP_MS); });
return await Promise.race([asked, late]);
} catch {
return undefined;
} finally {
if (timer) clearTimeout(timer);
}
}
const allSynthetic = (parts) => {
const text = parts.filter((p) => p && p.type === "text");
return text.length > 0 && text.every((p) => p.synthetic === true);
};
function loaderEnv() {
const env = process.env;
const set = (name) => (typeof env[name] === "string" && env[name] !== "" ? env[name] : undefined);
const flag = (name) => ["true", "1", "yes", "on", "y"].includes(String(set(name) || "").toLowerCase());
return {
config_dir: set("OPENCODE_CONFIG_DIR"),
config_file: set("OPENCODE_CONFIG"),
config_content_set: set("OPENCODE_CONFIG_CONTENT") !== undefined,
disable_claude_code: flag("OPENCODE_DISABLE_CLAUDE_CODE"),
disable_claude_code_prompt: flag("OPENCODE_DISABLE_CLAUDE_CODE_PROMPT"),
disable_claude_code_skills: flag("OPENCODE_DISABLE_CLAUDE_CODE_SKILLS"),
disable_external_skills: flag("OPENCODE_DISABLE_EXTERNAL_SKILLS"),
};
}
const ARM = Symbol.for("openlatch.relay.arming");
const ARM_CA = Symbol.for("openlatch.relay.arming.ca");
const ENV_JSON_MAX = 16 * 1024;
const PROBE_MS = 500;
const ENV_JSON_KEYS = "HTTPS_PROXY,HTTP_PROXY,NODE_EXTRA_CA_CERTS,NO_PROXY,instance_id";
const INSTANCE_ID = /^[0-9a-f]{32}$/;
const LOOPBACK_NO_PROXY = ["localhost", "127.0.0.1", "::1", "[::1]"];
function builtin(name) {
try {
return typeof process.getBuiltinModule === "function" ? process.getBuiltinModule(name) : undefined;
} catch {
return undefined;
}
}
function loopbackProxy(url) {
const m = typeof url === "string" ? /^http:\/\/(127\.0\.0\.1|\[::1\]):(\d{1,5})\/?$/.exec(url) : null;
if (!m) return null;
const port = Number(m[2]);
return port > 0 && port < 65536 ? { host: m[1] === "[::1]" ? "::1" : m[1], port } : null;
}
function insideOlDir(p) {
const path = builtin("node:path");
if (!path || typeof p !== "string" || !path.isAbsolute(p) || p.split(/[\\/]/).includes("..")) return false;
const rel = path.relative(OL_DIR, p);
return rel !== "" && !rel.startsWith("..") && !path.isAbsolute(rel);
}
function readEnvJson() {
try {
const fs = builtin("node:fs");
const path = builtin("node:path");
if (!fs || !path) return null;
const file = path.join(OL_DIR, "model-relay", "env.json");
let raw;
try {
if (fs.statSync(file).size > ENV_JSON_MAX) return null;
raw = fs.readFileSync(file, "utf8");
} catch (e) {
return e && e.code === "ENOENT" ? undefined : null;
}
if (raw.length > ENV_JSON_MAX) return null;
const env = JSON.parse(raw);
if (!env || typeof env !== "object" || Array.isArray(env)) return null;
if (Object.keys(env).sort().join(",") !== ENV_JSON_KEYS) return null;
if (!loopbackProxy(env.HTTPS_PROXY) || !loopbackProxy(env.HTTP_PROXY)) return null;
if (typeof env.NO_PROXY !== "string" || !insideOlDir(env.NODE_EXTRA_CA_CERTS)) return null;
if (typeof env.instance_id !== "string" || !INSTANCE_ID.test(env.instance_id)) return null;
return env;
} catch {
return null;
}
}
function instanceMatches(env, ms) {
return new Promise((resolve) => {
let req = null;
let settled = false;
let timer = null;
const finish = (ok) => {
if (settled) return;
settled = true;
if (timer) clearTimeout(timer);
try { if (req) req.destroy(); } catch {}
resolve(ok);
};
timer = setTimeout(() => finish(false), ms);
try {
const http = builtin("node:http");
const target = loopbackProxy(env.HTTPS_PROXY);
req = http.request(
{ host: target.host, port: target.port, path: "/admin/model-relay/instance", method: "GET", agent: false },
(res) => {
if (res.statusCode !== 200) return finish(false);
let body = "";
res.setEncoding("utf8");
res.on("data", (chunk) => {
body += chunk;
if (body.length > 1024) finish(false);
});
res.on("end", () => {
try {
finish(JSON.parse(body).instance_id === env.instance_id);
} catch {
finish(false);
}
});
res.on("error", () => finish(false));
},
);
req.on("error", () => finish(false));
req.end();
} catch {
finish(false);
}
});
}
function disarm() {
const armed = globalThis[ARM];
if (!armed) return;
try { if (typeof armed.restore === "function") armed.restore(); } catch {}
for (const [key, value] of armed.saved) {
if (value === undefined) delete process.env[key];
else process.env[key] = value;
}
delete globalThis[ARM];
}
const norm = (pem) => String(pem).replace(/\r\n/g, "\n").trim();
function appendCa(tls, fs, caPath) {
const pem = norm(fs.readFileSync(caPath, "utf8"));
if (!pem.startsWith("-----BEGIN CERTIFICATE-----")) throw new Error("not a certificate");
const ours = globalThis[ARM_CA] || [];
const wanted = ours.includes(pem) ? ours : [...ours, pem];
const current = tls.getCACertificates("default").map(norm);
const missing = wanted.filter((c) => !current.includes(c));
if (missing.length > 0) tls.setDefaultCACertificates([...current, ...missing]);
globalThis[ARM_CA] = wanted;
}
function mergeNoProxy(...values) {
const out = [];
for (const value of values) {
for (const entry of String(value || "").split(",")) {
const e = entry.trim();
if (e && !out.includes(e)) out.push(e);
}
}
return out.join(",");
}
function namesRelay(env) {
const e = process.env;
const proxies = [e.HTTPS_PROXY, e.https_proxy].filter((v) => typeof v === "string" && v !== "");
const ca = e.NODE_EXTRA_CA_CERTS;
if (proxies.length === 0 || typeof ca !== "string" || ca === "") return false;
if (env) return proxies.every((v) => v === env.HTTPS_PROXY) && ca === env.NODE_EXTRA_CA_CERTS;
return proxies.every((v) => loopbackProxy(v) !== null) && insideOlDir(ca);
}
async function armRelay() {
const isBun = typeof process.versions.bun === "string";
const runtime = isBun ? "bun" : "node";
try {
const env = readEnvJson();
if (isBun) {
return { runtime, arming: env !== null && namesRelay(env) ? "armed_by_environment" : "not_armed" };
}
const http = builtin("node:http");
const tls = builtin("node:tls");
const fs = builtin("node:fs");
const apis =
!!http && !!tls && !!fs &&
typeof http.setGlobalProxyFromEnv === "function" &&
typeof tls.setDefaultCACertificates === "function" &&
typeof tls.getCACertificates === "function";
if (!env || !apis || !(await instanceMatches(env, PROBE_MS))) {
disarm();
return { runtime, arming: "not_armed" };
}
disarm();
appendCa(tls, fs, env.NODE_EXTRA_CA_CERTS);
const e = process.env;
const noProxy = mergeNoProxy(e.NO_PROXY, e.no_proxy, LOOPBACK_NO_PROXY.join(","));
const proxy = {
HTTPS_PROXY: env.HTTPS_PROXY,
HTTP_PROXY: env.HTTP_PROXY,
NO_PROXY: noProxy,
https_proxy: env.HTTPS_PROXY,
http_proxy: env.HTTP_PROXY,
no_proxy: noProxy,
};
const values = e.NODE_EXTRA_CA_CERTS ? proxy : { ...proxy, NODE_EXTRA_CA_CERTS: env.NODE_EXTRA_CA_CERTS };
const saved = Object.keys(values).map((key) => [key, e[key]]);
globalThis[ARM] = { restore: undefined, saved };
for (const [key, value] of Object.entries(values)) e[key] = value;
globalThis[ARM].restore = http.setGlobalProxyFromEnv(proxy);
return { runtime, arming: "armed_in_process" };
} catch {
try { if (!isBun) disarm(); } catch {}
return { runtime, arming: "not_armed" };
}
}
const ARMING = await armRelay();
globalThis[SEEN] = {};
export default async function openlatch(ctx) {
let mcpServers = [];
const common = (hook, sessionId) => ({
opencode_hook: hook,
session_id: sessionId,
directory: ctx.directory,
worktree: ctx.worktree,
project_id: ctx.project ? ctx.project.id : undefined,
opencode_client: process.env.OPENCODE_CLIENT || "cli",
mcp_servers: mcpServers,
});
const loadReport = (stage, cfg) => {
try {
const seen = (globalThis[SEEN] = globalThis[SEEN] || {});
if (seen[stage]) return;
seen[stage] = true;
call("plugin_loaded", {
opencode_hook: "plugin_loaded",
opencode_client: process.env.OPENCODE_CLIENT || "cli",
directory: ctx.directory,
worktree: ctx.worktree,
project_id: ctx.project ? ctx.project.id : undefined,
mcp_servers: mcpServers,
plugins: cfg ? (Array.isArray(cfg.plugin) ? cfg.plugin.map(String) : []) : undefined,
loader_env: loaderEnv(),
relay_arming: ARMING.arming,
runtime: ARMING.runtime,
}, true);
} catch {}
};
loadReport("module", undefined);
return {
config: async (cfg) => {
try {
if (cfg && cfg.mcp && typeof cfg.mcp === "object") mcpServers = Object.keys(cfg.mcp);
loadReport("config", cfg);
} catch {}
},
"tool.execute.before": async (input, output) => {
const verdict = await call("pre_tool_use", {
...common("tool.execute.before", input && input.sessionID),
call_id: input && input.callID,
tool: input && input.tool,
args: output && output.args,
}, false);
if (isBlock(verdict)) throw new Error(verdict.reason);
},
"chat.message": async (input, output) => {
let verdict = null;
try {
const message = (output && output.message) || {};
const model = (input && input.model) || message.model;
const parts = (output && Array.isArray(output.parts)) ? output.parts : [];
if (allSynthetic(parts)) return;
verdict = await call("user_prompt_submit", {
...common("chat.message", input && input.sessionID),
message_id: message.id || (input && input.messageID),
agent: message.agent || (input && input.agent),
model: model && model.providerID ? `${model.providerID}/${model.modelID}` : undefined,
prompt: parts.filter((p) => p && p.type === "text").map((p) => p.text).join("\n"),
}, false);
} catch {
verdict = null;
}
if (isBlock(verdict)) {
try {
await Promise.race([
ctx.client.tui.showToast({ body: { variant: "error", message: verdict.reason } }),
new Promise((resolve) => setTimeout(resolve, TOAST_MS)),
]);
} catch {}
throw new Error(verdict.reason);
}
},
"tool.execute.after": async (input, output) => {
try {
const payload = {
...common("tool.execute.after", input && input.sessionID),
call_id: input && input.callID,
tool: input && input.tool,
args: input && input.args,
output: output && output.output,
title: output && output.title,
};
const meta = output && output.metadata;
if (payload.tool === "task" && meta && typeof meta.sessionId === "string") {
payload.child_session_id = meta.sessionId;
}
call("post_tool_use", payload, true);
} catch {}
},
"experimental.session.compacting": async (input) => {
try {
const sessionId = input && input.sessionID;
if (typeof sessionId === "string" && sessionId) {
call("pre_compact", common("experimental.session.compacting", sessionId), true);
}
} catch {}
},
event: async ({ event }) => {
try {
const wire = event && LIFECYCLE[event.type];
if (!wire) return;
const props = event.properties || {};
const sessionId = props.sessionID || (props.info && props.info.id);
if (!sessionId) return;
const payload = common(event.type, sessionId);
if (wire === "session_start") {
const parent = props.info && typeof props.info.parentID === "string" ? props.info.parentID : null;
if (parent) payload.parent_session_id = parent;
remember(sessionId, parent);
}
if (wire === "session_end") {
CHILDREN.delete(sessionId);
deleted(sessionId);
}
call(wire, payload, true);
if (wire !== "stop") return;
let parent = CHILDREN.get(sessionId);
if (parent === undefined) {
const generation = DELETIONS.get(sessionId);
parent = await lookup(ctx.client, sessionId);
if (DELETIONS.get(sessionId) !== generation) return;
if (parent !== undefined) remember(sessionId, parent);
}
if (parent) call("subagent_stop", { ...common(event.type, sessionId), parent_session_id: parent }, true);
} catch {}
},
};
}