// forgen-managed — do not edit; regenerated by `forgen install opencode` /** * forgen — OpenCode plugin (W3-3 P1). forgen 결정적 가드 + 개인화 브릿지: * - tool.execute.before → forgen opencode-guard → block 이면 throw(도구 차단). * - experimental.session.compacting → forgen opencode-context → forge-loop 상태 유지. * 얇은 shim — 로직은 forgen 소유(drift-free). async execFile(이벤트루프 비차단). * GUARD_CMD/CONTEXT_CMD 는 install-opencode 가 절대경로로 치환(런타임 PATH 비의존). */ import { execFile } from "node:child_process" // forgen:guard-cmd — install-opencode 가 [node, <절대 cli 경로>, opencode-guard] 로 치환 const GUARD_CMD: string[] = ["forgen", "opencode-guard"] // forgen:context-cmd — install-opencode 가 [node, <절대 cli 경로>, opencode-context] 로 치환 const CONTEXT_CMD: string[] = ["forgen", "opencode-context"] function runForgen(cmd: string[], stdin: string, timeout: number): Promise { return new Promise((resolve) => { const [bin, ...rest] = cmd const child = execFile(bin, rest, { timeout, encoding: "utf-8" }, (err, stdout) => { if (err) console.error("[forgen] 호출 실패(fail-open):", err.message) resolve(stdout || "") }) child.stdin?.end(stdin) }) } export const forgen = async () => ({ "tool.execute.before": async ( input: { tool?: string }, output: { args?: Record }, ) => { const out = await runForgen(GUARD_CMD, JSON.stringify({ tool: input?.tool, args: output?.args }), 8000) let decision: { block?: boolean; reason?: string } = { block: false } try { if (out) decision = JSON.parse(out) } catch { /* fail-open */ } if (decision.block) throw new Error(decision.reason || "[forgen] blocked by guard") }, "experimental.session.compacting": async ( _input: unknown, output: { context?: string[] }, ) => { const ctx = await runForgen(CONTEXT_CMD, "", 5000) if (ctx.trim() && Array.isArray(output?.context)) { output.context.push(ctx.trim()) } }, }) export default forgen