@agentwares/agentguard 0.1.9 → 0.1.10
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/CHANGELOG.md +33 -0
- package/dist/audit-5LUDXZLG.js +18 -0
- package/dist/chunk-2QDPPTPY.js +179 -0
- package/dist/chunk-2QDPPTPY.js.map +1 -0
- package/dist/{chunk-SUXQTT3X.js → chunk-4WTFMFRY.js} +18 -16
- package/dist/chunk-4WTFMFRY.js.map +1 -0
- package/dist/{chunk-VQWQ5TOM.js → chunk-DEVXG3IB.js} +4 -4
- package/dist/chunk-DEVXG3IB.js.map +1 -0
- package/dist/chunk-F73VDY3W.js +202 -0
- package/dist/chunk-F73VDY3W.js.map +1 -0
- package/dist/{chunk-X4M7YWQA.js → chunk-IEJK7N3B.js} +32 -27
- package/dist/chunk-IEJK7N3B.js.map +1 -0
- package/dist/{chunk-ZSLWPKXI.js → chunk-IS3DAHZI.js} +562 -8
- package/dist/chunk-IS3DAHZI.js.map +1 -0
- package/dist/{chunk-KRKZGAJ3.js → chunk-JSELR4SG.js} +66 -55
- package/dist/chunk-JSELR4SG.js.map +1 -0
- package/dist/{chunk-TW5KJREH.js → chunk-OM5L7A32.js} +20 -11
- package/dist/chunk-OM5L7A32.js.map +1 -0
- package/dist/{chunk-HPYZ3JDX.js → chunk-SWZQMPDG.js} +3 -3
- package/dist/{chunk-HPYZ3JDX.js.map → chunk-SWZQMPDG.js.map} +1 -1
- package/dist/{chunk-D66U3PVB.js → chunk-TJXZBOHL.js} +6 -6
- package/dist/chunk-TJXZBOHL.js.map +1 -0
- package/dist/{chunk-BKXXTWIS.js → chunk-XOBFANL4.js} +5 -5
- package/dist/chunk-XOBFANL4.js.map +1 -0
- package/dist/chunk-XPNBYSIN.js +23 -0
- package/dist/chunk-XPNBYSIN.js.map +1 -0
- package/dist/{chunk-6S7LYVOC.js → chunk-YBVD6HTT.js} +27 -24
- package/dist/chunk-YBVD6HTT.js.map +1 -0
- package/dist/{chunk-6TUQD666.js → chunk-ZG4LGUJE.js} +100 -81
- package/dist/chunk-ZG4LGUJE.js.map +1 -0
- package/dist/cli.js +6 -4
- package/dist/fixtures/crm-server.js +2 -2
- package/dist/fixtures/demo-agent.js +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +23 -21
- package/dist/index.js.map +1 -1
- package/dist/init-MKPQU2JG.js +17 -0
- package/dist/{proxy-3Z5YEZ4R.js → proxy-6GP63TLD.js} +21 -29
- package/dist/proxy-6GP63TLD.js.map +1 -0
- package/dist/tools-XS7PMTLT.js +15 -0
- package/llms.txt +8 -6
- package/package.json +10 -4
- package/server.json +9 -9
- package/dist/audit-2YCMHMCP.js +0 -17
- package/dist/chunk-3O6KWT3E.js +0 -345
- package/dist/chunk-3O6KWT3E.js.map +0 -1
- package/dist/chunk-6S7LYVOC.js.map +0 -1
- package/dist/chunk-6TUQD666.js.map +0 -1
- package/dist/chunk-BKXXTWIS.js.map +0 -1
- package/dist/chunk-D66U3PVB.js.map +0 -1
- package/dist/chunk-KRKZGAJ3.js.map +0 -1
- package/dist/chunk-SUXQTT3X.js.map +0 -1
- package/dist/chunk-TW5KJREH.js.map +0 -1
- package/dist/chunk-VQWQ5TOM.js.map +0 -1
- package/dist/chunk-X4M7YWQA.js.map +0 -1
- package/dist/chunk-ZSLWPKXI.js.map +0 -1
- package/dist/init-CWROGV5I.js +0 -15
- package/dist/proxy-3Z5YEZ4R.js.map +0 -1
- package/dist/tools-3LLDG3XQ.js +0 -15
- /package/dist/{audit-2YCMHMCP.js.map → audit-5LUDXZLG.js.map} +0 -0
- /package/dist/{init-CWROGV5I.js.map → init-MKPQU2JG.js.map} +0 -0
- /package/dist/{tools-3LLDG3XQ.js.map → tools-XS7PMTLT.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/audit.ts","../src/audit/cache.ts","../src/audit/enforce.ts","../src/audit/read.ts","../src/audit/repo.ts","../src/audit/sources.ts"],"sourcesContent":["/**\n * `okgate audit [--since 7d|30d|all|YYYY-MM-DD] [--client claude|codex|all] [--json]\n * [--enforce [--preview] [--yes]]`\n *\n * Which written rules the coding agents broke in this repository: the rules come from the repo's\n * CLAUDE.md, AGENTS.md, GEMINI.md, .cursor/rules (and okgate.yaml `audit.rules`); the\n * sessions are this machine's Claude Code and Codex transcripts whose working directory is in the\n * repo. Per rule: sessions checked, sessions broken, the last three dates — and on screen only,\n * the command or path that broke it. No network, no telemetry, no LLM: nothing leaves the\n * machine. `--json` (what `/okgate:audit` reads) carries counts, rule ids and dates, never a\n * command, a path or a prompt from a transcript.\n *\n * `--enforce` writes the checkable rules into okgate.yaml as hook-mode rules — in dry-run;\n * it never switches `hooks.mode` to enforce — shows the diff, and installs the hook if it is not.\n */\nimport { writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { basename, join, resolve } from \"node:path\";\nimport { findPolicyFile } from \"@agentwares/agentguard-core/node\";\nimport {\n NOT_CHECKABLE_HINT,\n applicableNoun,\n describeStep,\n evaluateChecks,\n extractRules,\n planEnforcement,\n stableHash,\n summarizeAudit,\n type AuditClient,\n type AuditContext,\n type AuditStep,\n type GroupAudit,\n type LocatedBreak,\n type Rule,\n type RuleCheck,\n type RuleSummary,\n STATE_DIR,\n envTwin,\n} from \"@agentwares/agentguard-core\";\nimport { flagBool, flagList, flagString, parseArgs, type ParsedArgs } from \"../args.js\";\nimport { homeFrom, type Io } from \"../context.js\";\nimport { AuditCache, sha } from \"../audit/cache.js\";\nimport { applyEnforcePlan, lineDiff } from \"../audit/enforce.js\";\nimport { fetchSteps, readGroup } from \"../audit/read.js\";\nimport { findRepo, readConfigRules, readRuleFiles, repoMatcher } from \"../audit/repo.js\";\nimport {\n claudeGroups,\n claudeProjectDirs,\n codexGroups,\n sourceDirs,\n type TranscriptGroup,\n} from \"../audit/sources.js\";\nimport { installedHandlers, hookTarget } from \"../hooks/clients.js\";\nimport { version } from \"../version.js\";\nimport { hooksCommand } from \"./hooks.js\";\n\n/** The willingness-to-pay test: a page that says what the team view would be, and one button. */\nexport const TEAM_HISTORY_URL = \"https://agentwares-agentguard.vercel.app/team-history\";\nexport const TEAM_HISTORY_LINE = `Team adherence history across repos and developers is coming — ${TEAM_HISTORY_URL}`;\n\nconst CLIENT_LABEL: Record<AuditClient, string> = { \"claude-code\": \"Claude Code\", codex: \"Codex\" };\n\n/** `7d`, `30d`, `24h`, `all`, or a date. Undefined: all history. */\nexport function parseSince(value: string | undefined, now: Date): number | undefined {\n const v = (value ?? \"7d\").trim().toLowerCase();\n if (v === \"all\") return undefined;\n const rel = /^(\\d+)\\s*([dhw])$/.exec(v);\n if (rel) {\n const n = Number(rel[1]);\n const unit = rel[2] === \"h\" ? 3_600_000 : rel[2] === \"w\" ? 7 * 86_400_000 : 86_400_000;\n return now.getTime() - n * unit;\n }\n const t = Date.parse(/^\\d{4}-\\d{2}-\\d{2}$/.test(v) ? `${v}T00:00:00` : v);\n if (!Number.isFinite(t))\n throw new Error(`--since \"${value}\": use 7d, 30d, 24h, all or a date (YYYY-MM-DD)`);\n return t;\n}\n\nfunction clientsFrom(args: ParsedArgs): AuditClient[] {\n const names = flagList(args, \"client\").map((n) => n.trim().toLowerCase());\n if (names.length === 0 || names.includes(\"all\")) return [\"claude-code\", \"codex\"];\n return names.map((n) => {\n if (n === \"claude\" || n === \"claude-code\") return \"claude-code\";\n if (n === \"codex\") return \"codex\";\n throw new Error(`unknown --client \"${n}\" (claude, codex or all)`);\n });\n}\n\nconst pad = (n: number): string => String(n).padStart(2, \"0\");\nconst localTime = (ms: number): string => {\n const d = new Date(ms);\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;\n};\nconst localDay = (ms: number): string => localTime(ms).slice(0, 10);\nconst plural = (n: number, one: string, many = `${one}s`): string => `${n} ${n === 1 ? one : many}`;\nconst clip = (s: string, n: number): string => (s.length > n ? `${s.slice(0, n - 1)}…` : s);\n\ninterface Entry {\n group?: TranscriptGroup;\n audit: GroupAudit;\n /** steps kept from a group read this run, for the evidence */\n steps?: Map<string, AuditStep>;\n}\n\ninterface SourceCount {\n transcripts: number;\n read: number;\n cached: number;\n retained: number;\n /** groups last written before the window: not read */\n older: number;\n}\n\nasync function pool<T>(\n items: readonly T[],\n size: number,\n work: (item: T) => Promise<void>,\n): Promise<void> {\n let next = 0;\n const run = async (): Promise<void> => {\n while (next < items.length) await work(items[next++]!);\n };\n await Promise.all(Array.from({ length: Math.min(size, items.length) }, run));\n}\n\n/** The hook-rule list a check would be enforced through, or \"audit-only\". */\nfunction enforceTarget(check: RuleCheck): string {\n switch (check.spec.kind) {\n case \"run-before\":\n case \"no-commit-to\":\n return \"audit-only\";\n case \"no-edit\":\n return \"hooks.paths.deny\";\n case \"no-new-deps\":\n return check.spec.unlessAsked ? \"hooks.shell.approval\" : \"hooks.shell.deny\";\n case \"no-rm-outside\":\n case \"no-publish\":\n return \"hooks.irreversible.builtins\";\n case \"no-deploy\":\n return \"hooks.irreversible.rules\";\n default:\n return \"hooks.shell.deny\";\n }\n}\n\nexport async function auditCommand(args: ParsedArgs, io: Io): Promise<number> {\n const now = new Date();\n const json = flagBool(args, \"json\") === true;\n const since = parseSince(flagString(args, \"since\"), now);\n const clients = clientsFrom(args);\n const home = homeFrom(io);\n const repo = findRepo(resolve(io.cwd, flagString(args, \"repo\") ?? \".\"));\n const named = flagString(args, \"config\") ?? envTwin(io.env, \"CONFIG\");\n const policyPath =\n named !== undefined ? resolve(repo.checkout, named) : findPolicyFile(repo.checkout);\n\n // the rules\n const files = readRuleFiles(repo.checkout, flagList(args, \"rules\"));\n const config = readConfigRules(policyPath);\n const { rules, errors } = extractRules(files, config.rules, basename(policyPath));\n const warnings = [\n ...(config.warning ? [config.warning] : []),\n ...errors.map((e) => `${e.file}:${e.line}: ${e.message}`),\n ];\n const checks = rules.flatMap((r) => r.checks);\n const keys = [...new Set(checks.map((c) => c.key))];\n\n if (flagBool(args, \"enforce\")) return enforce(args, io, rules, policyPath, repo.checkout, json);\n\n // the sessions\n const dirs = sourceDirs(io.env, home, {\n claudeDir: flagString(args, \"claude-dir\"),\n codexDir: flagString(args, \"codex-dir\"),\n });\n const groups: TranscriptGroup[] = [\n ...(clients.includes(\"claude-code\")\n ? claudeGroups(claudeProjectDirs(dirs[\"claude-code\"], repo.root))\n : []),\n ...(clients.includes(\"codex\") ? codexGroups(dirs.codex) : []),\n ];\n const cache = new AuditCache(\n resolve(io.cwd, flagString(args, \"cache-dir\") ?? join(home, STATE_DIR)),\n sha(repo.root),\n flagBool(args, \"cache\") !== false,\n );\n const inRepo = repoMatcher(repo.root);\n const ctx: AuditContext = {\n repoRoot: repo.root,\n home,\n tmpDirs: [\n tmpdir(),\n io.env.TMPDIR ?? \"\",\n \"/tmp\",\n \"/private/tmp\",\n \"/var/folders\",\n \"/private/var/folders\",\n ].filter(Boolean),\n };\n const counts: Record<AuditClient, SourceCount> = {\n \"claude-code\": { transcripts: 0, read: 0, cached: 0, retained: 0, older: 0 },\n codex: { transcripts: 0, read: 0, cached: 0, retained: 0, older: 0 },\n };\n const entries: Entry[] = [];\n const evidence = !json && flagBool(args, \"evidence\") !== false;\n await pool(groups, 6, async (group) => {\n const c = counts[group.client];\n c.transcripts += group.files.length;\n const hit = cache.lookup(group, keys);\n if (hit) {\n c.cached += group.files.length;\n entries.push({ group, audit: hit });\n return;\n }\n if (since !== undefined && group.lastWrite < since) {\n c.older += group.files.length;\n return;\n }\n let read;\n try {\n read = await readGroup(group, { inRepo });\n } catch {\n return; // unreadable (permissions, deleted mid-run): skip, never fail the audit\n }\n c.read += group.files.length;\n const audit = evaluateChecks(checks, read, ctx);\n cache.store(group, audit);\n const hasBreaks = Object.values(audit.checks).some((o) => o.breaks.length > 0);\n entries.push({\n group,\n audit,\n ...(evidence && hasBreaks\n ? { steps: new Map(read.steps.map((s) => [stableHash(s.id), s])) }\n : {}),\n });\n });\n const present = new Set(groups.map((g) => cache.groupKey(g)));\n for (const client of clients)\n for (const audit of cache.retained(present, client)) {\n counts[client].retained += 1;\n entries.push({ audit });\n }\n\n const summary = summarizeAudit(\n rules,\n entries.map((e) => e.audit),\n { since },\n );\n const plan = planEnforcement(rules);\n const enforceable = new Set([\n ...plan.items.map((i) => i.rule.id),\n ...plan.builtins.map((b) => b.rule.id),\n ...plan.irreversible.map((r) => r.rule.id),\n ]);\n\n if (json) {\n io.out(\n JSON.stringify(\n {\n tool: \"okgate audit\",\n version: version(),\n repo: repo.root,\n checkout: repo.checkout,\n since: since === undefined ? null : new Date(since).toISOString(),\n until: now.toISOString(),\n rule_files: files.map((f) => f.path),\n sources: counts,\n sessions: {\n total: summary.sessions,\n \"claude-code\": summary.sessionsByClient[\"claude-code\"],\n codex: summary.sessionsByClient.codex,\n },\n unread_tool_calls: summary.unread,\n rules: summary.rules.map((r) => ({\n id: r.rule.id,\n n: r.rule.n,\n file: r.rule.file,\n line: r.rule.line,\n text: r.rule.text,\n status: r.status,\n checkable: r.rule.checks.length > 0,\n ...(r.rule.silenced ? { marked_not_checkable: true } : {}),\n sessions_broken: r.sessionsBroken,\n last_broken: r.last.map((b) => new Date(b.at).toISOString()),\n checks: r.checks.map((c, k) => ({\n check: c.label,\n kind: c.kind,\n via: c.via,\n enforce: enforceTarget(r.rule.checks[k]!),\n sessions_applicable: c.sessionsApplicable,\n sessions_broken: c.sessionsBroken,\n sessions_on_request: c.sessionsOnRequest,\n sessions_undetermined: c.sessionsUndetermined,\n breaks: c.breaks,\n refused: c.refused,\n })),\n })),\n not_checkable: {\n count: summary.rules.filter((r) => r.status === \"not-checkable\").length,\n hint: NOT_CHECKABLE_HINT,\n },\n warnings,\n enforce: {\n command: \"okgate audit --enforce\",\n rules: enforceable.size,\n note: \"writes hook-mode rules into okgate.yaml in dry-run; nothing is blocked until hooks.mode is enforce\",\n },\n team_history: { available: false, url: TEAM_HISTORY_URL },\n privacy:\n \"counts, rule ids and dates only: no command, path or prompt from a transcript is in this output, and nothing was sent anywhere\",\n },\n null,\n 2,\n ),\n );\n return 0;\n }\n\n // evidence for the latest breaks, on this screen only\n const lines = new Map<string, string>();\n if (evidence) {\n const wanted = new Map<number, LocatedBreak[]>();\n for (const r of summary.rules)\n for (const b of r.last) {\n const list = wanted.get(b.group) ?? [];\n list.push(b);\n wanted.set(b.group, list);\n }\n for (const [gi, breaks] of wanted) {\n const entry = entries[gi];\n if (!entry?.group) continue;\n let steps = entry.steps;\n if (!steps) {\n try {\n steps = await fetchSteps(entry.group, breaks, { inRepo });\n } catch {\n continue;\n }\n }\n for (const b of breaks) {\n const step = steps.get(b.step);\n if (step) lines.set(`${gi}:${b.step}:${b.what}:${b.index}`, describeStep(step, b, ctx));\n }\n }\n }\n\n renderHuman(io, {\n root: repo.root,\n since,\n files: files.map((f) => f.path),\n counts,\n clients,\n summary,\n evidence: evidence\n ? (b) =>\n lines.get(`${b.group}:${b.step}:${b.what}:${b.index}`) ?? \"(transcript no longer on disk)\"\n : () => undefined,\n enforceable: enforceable.size,\n warnings,\n });\n return 0;\n}\n\ninterface View {\n root: string;\n since?: number;\n files: string[];\n counts: Record<AuditClient, SourceCount>;\n clients: AuditClient[];\n summary: ReturnType<typeof summarizeAudit>;\n evidence: (b: LocatedBreak) => string | undefined;\n enforceable: number;\n warnings: string[];\n}\n\nfunction ruleHead(r: RuleSummary): string {\n const id = `R${r.rule.n}`.padEnd(4);\n return ` ${id} ${clip(r.rule.text, 78)} (${r.rule.file}:${r.rule.line})`;\n}\n\nfunction renderHuman(io: Io, v: View): void {\n const s = v.summary;\n const window = v.since === undefined ? \"all history\" : `since ${localDay(v.since)}`;\n io.out(`okgate audit — ${v.root} · ${window}`);\n const read = v.clients.map((c) => {\n const n = v.counts[c];\n const parts = [`${n.read} read`, `${n.cached} from cache`];\n if (n.retained) parts.push(`${n.retained} kept from deleted transcripts`);\n if (n.older) parts.push(`${n.older} older than the window`);\n return `${CLIENT_LABEL[c]}: ${plural(n.transcripts, \"transcript\")} (${parts.join(\", \")})`;\n });\n io.out(read.join(\" · \"));\n const byClient = v.clients\n .filter((c) => s.sessionsByClient[c] > 0)\n .map((c) => `${CLIENT_LABEL[c]} ${s.sessionsByClient[c]}`);\n io.out(\n `${plural(s.sessions, \"session\")} in this repository${byClient.length ? ` (${byClient.join(\", \")})` : \"\"}. Read on this machine; nothing was sent anywhere.`,\n );\n if (s.unread > 0)\n io.out(\n `${plural(s.unread, \"Codex tool call\")} ran JavaScript (\\`exec\\`), not a command line, and ${s.unread === 1 ? \"was\" : \"were\"} not read.`,\n );\n for (const w of v.warnings) io.out(`warning: ${w}`);\n io.out(\"\");\n\n if (v.files.length === 0 && s.rules.length === 0) {\n io.out(\n \"No rule files here (CLAUDE.md, AGENTS.md, GEMINI.md, .cursor/rules, …) and no audit.rules in okgate.yaml: nothing to audit.\",\n );\n io.out(\"\");\n io.out(TEAM_HISTORY_LINE);\n return;\n }\n const checkable = s.rules.filter((r) => r.status !== \"not-checkable\");\n const perFile = new Map<string, number>();\n for (const r of s.rules) perFile.set(r.rule.file, (perFile.get(r.rule.file) ?? 0) + 1);\n io.out(\n `${plural(s.rules.length, \"rule\")} found (${[...perFile].map(([f, n]) => `${n} in ${f}`).join(\", \")}); ${checkable.length} checkable.`,\n );\n if (s.sessions === 0)\n io.out(\n `No Claude Code or Codex sessions in ${v.root} ${window}. Transcripts are read from ~/.claude/projects and ~/.codex/sessions (--claude-dir, --codex-dir); try --since 30d or --since all.`,\n );\n\n const section = (title: string, list: RuleSummary[], body: (r: RuleSummary) => void): void => {\n if (list.length === 0) return;\n io.out(\"\");\n io.out(title);\n for (const r of list) {\n io.out(ruleHead(r));\n body(r);\n }\n };\n const checkLines = (r: RuleSummary): void => {\n r.rule.checks.forEach((check, k) => {\n const c = r.checks[k]!;\n const noun = applicableNoun(c.kind, check.spec);\n const scope = noun ? ` (${c.sessionsApplicable} ${noun})` : \"\";\n let verdict: string;\n if (c.sessionsBroken > 0) {\n verdict = `broken in ${c.sessionsBroken} of ${s.sessions} sessions${scope}`;\n const extra: string[] = [];\n if (c.breaks > c.sessionsBroken) extra.push(`${c.breaks} times`);\n if (c.sessionsOnRequest > 0)\n extra.push(`${c.sessionsOnRequest} on a turn that asked for it`);\n if (c.refused > 0) extra.push(`${c.refused} refused by the harness`);\n if (extra.length) verdict += `; ${extra.join(\", \")}`;\n } else if (c.sessionsApplicable > 0 || !noun) {\n const n = noun ? c.sessionsApplicable : s.sessions;\n verdict =\n n === 1\n ? `kept in the 1 session${noun ? ` that ${noun}` : \"\"}`\n : `kept in all ${n} sessions${noun ? ` that ${noun}` : \"\"}`;\n } else verdict = `nothing in these sessions could break it`;\n if (c.sessionsUndetermined > 0)\n verdict += `; ${c.sessionsUndetermined} more in sessions that do not say who asked (Codex)`;\n io.out(` ${c.label} — ${verdict}`);\n });\n for (const b of r.last) {\n const what = v.evidence(b);\n io.out(\n ` ${localTime(b.at)}${what ? ` ${what}` : \"\"}${b.refused ? \" [refused]\" : \"\"}${b.asked ? \" [asked]\" : \"\"} · session ${b.session.slice(0, 8)}`,\n );\n }\n };\n section(\n \"BROKEN\",\n s.rules\n .filter((r) => r.status === \"broken\")\n .sort((a, b) => b.sessionsBroken - a.sessionsBroken),\n checkLines,\n );\n section(\n \"KEPT\",\n s.rules.filter((r) => r.status === \"kept\"),\n checkLines,\n );\n section(\n \"NOTHING IN THESE SESSIONS COULD BREAK IT\",\n s.rules.filter((r) => r.status === \"not-applicable\"),\n checkLines,\n );\n const notCheckable = s.rules.filter((r) => r.status === \"not-checkable\");\n if (notCheckable.length > 0) {\n io.out(\"\");\n io.out(\n `NOT CHECKABLE MECHANICALLY (${notCheckable.length}) — ${NOT_CHECKABLE_HINT.replace(/^not checkable mechanically — /, \"\")}`,\n );\n for (const r of notCheckable)\n io.out(`${ruleHead(r)}${r.rule.silenced ? \" [marked none]\" : \"\"}`);\n }\n io.out(\"\");\n if (v.enforceable > 0)\n io.out(\n `Enforce: okgate audit --enforce writes ${plural(v.enforceable, \"rule\")} into okgate.yaml as hook rules, in dry-run (nothing is blocked until hooks.mode: enforce)`,\n );\n io.out(TEAM_HISTORY_LINE);\n}\n\nasync function enforce(\n args: ParsedArgs,\n io: Io,\n rules: Rule[],\n policyPath: string,\n checkout: string,\n json: boolean,\n): Promise<number> {\n const plan = planEnforcement(rules);\n const preview = flagBool(args, \"preview\") === true;\n const edit = applyEnforcePlan(policyPath, plan);\n const diff = lineDiff(edit.before, edit.after);\n const changed = edit.before !== edit.after;\n const blocked = edit.mode === \"enforce\" && flagBool(args, \"yes\") !== true;\n const write = changed && !preview && !blocked;\n if (write) writeFileSync(policyPath, edit.after);\n\n // the hook: install it (project level) if no okgate hook is in place for Claude Code\n const home = homeFrom(io);\n const installed = ([\"project\", \"user\"] as const).some((scope) => {\n try {\n return (\n installedHandlers(hookTarget(\"claude-code\", scope, { cwd: checkout, home }, \"\")).length > 0\n );\n } catch {\n return true; // an unreadable settings file: leave it to `hooks status`\n }\n });\n let hookInstalled = installed;\n const hookOut: string[] = [];\n if (!installed && !preview && !blocked) {\n const sub: Io = { ...io, cwd: checkout, out: (l) => hookOut.push(l) };\n const passthrough = [\"hooks\", \"install\"];\n const config = flagString(args, \"config\");\n if (config) passthrough.push(\"--config\", resolve(io.cwd, config));\n const command = flagString(args, \"command\");\n if (command) passthrough.push(\"--command\", command);\n await hooksCommand(parseArgs(passthrough), sub);\n hookInstalled = true;\n }\n\n if (json) {\n io.out(\n JSON.stringify(\n {\n policy: policyPath,\n written: write,\n preview,\n hooks_mode: edit.mode,\n added: edit.added,\n audit_only: plan.auditOnly.map((a) => ({\n rule: a.rule.id,\n check: a.check.label,\n why: a.why,\n })),\n notes: plan.notes,\n hook_installed: hookInstalled,\n },\n null,\n 2,\n ),\n );\n return blocked && changed ? 1 : 0;\n }\n\n if (!changed)\n io.out(`okgate.yaml already has a hook rule for every enforceable rule (${policyPath}).`);\n else {\n io.out(\n `${write ? (edit.created ? \"wrote\" : \"updated\") : \"would update\"} ${policyPath} — ${plural(edit.added.length, \"hook rule\")}:`,\n );\n for (const line of diff) io.out(` ${line}`);\n }\n if (plan.auditOnly.length > 0) {\n io.out(\"\");\n io.out(\"Audit only (a pre-execution hook cannot check these):\");\n for (const a of plan.auditOnly) io.out(` R${a.rule.n} ${a.check.label} — ${a.why}`);\n }\n if (plan.notes.length > 0) {\n io.out(\"\");\n for (const n of plan.notes) io.out(`note: ${n}`);\n }\n io.out(\"\");\n if (blocked && changed) {\n io.out(\n \"hooks.mode is enforce in this okgate.yaml, so these rules would block at once. Nothing was written. Rerun with --enforce --yes to add them anyway, or set hooks.mode: dry-run first.\",\n );\n return 1;\n }\n if (preview) {\n io.out(\"Preview only: nothing was written. Run okgate audit --enforce to write it.\");\n return 0;\n }\n for (const l of hookOut) io.out(l);\n if (installed) io.out(\"The okgate hook is already installed (okgate hooks status).\");\n io.out(\n `hooks.mode is ${edit.mode}: ${edit.mode === \"dry-run\" ? \"every decision is logged and nothing is blocked. Read okgate report, then set hooks.mode: enforce yourself.\" : \"the rules apply from the next session.\"}`,\n );\n return 0;\n}\n","/**\n * The audit's own copy of the counts, one small file per transcript group under\n * `~/.okgate/audit-cache-v1/`, the way seatledger keeps its own (PROD-1A):\n *\n * 1. Speed: a group whose files are unchanged (same size and mtime) is not read again for checks\n * it already answered.\n * 2. History: Claude Code deletes transcripts older than `cleanupPeriodDays` (30 by default). The\n * counts already taken from a deleted transcript stay here, so a 30- or 90-day audit keeps its\n * history. Delete the directory to forget it.\n *\n * Only what `GroupAudit` holds is written — session ids, times, line numbers, hashed call ids and\n * per-check counts — plus SHA-256 hashes of the repository and transcript paths. Never a command,\n * a path, a prompt or anything else a transcript says.\n */\nimport { createHash } from \"node:crypto\";\nimport { mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type {\n AuditClient,\n CheckBreak,\n CheckOutcome,\n GroupAudit,\n} from \"@agentwares/agentguard-core\";\nimport type { TranscriptGroup } from \"./sources.js\";\n\nexport const CACHE_DIR = \"audit-cache-v1\";\n/** Bump when the readers or the checks change what they count: every entry is then re-read. */\nexport const ENGINE = \"1\";\n\nexport const sha = (text: string): string => createHash(\"sha256\").update(text).digest(\"hex\");\n\ntype WireBreak = [\n at: number,\n session: string,\n step: string,\n file: number,\n line: number,\n what: 0 | 1 | 2,\n index: number,\n asked: 0 | 1 | 2,\n refused: 0 | 1,\n];\n\ninterface Wire {\n v: 1;\n engine: string;\n repo: string;\n group: string;\n client: AuditClient;\n files: [src: string, size: number, mtimeMs: number][];\n sessions: [id: string, client: AuditClient, start: number, end: number, turnsKnown: 0 | 1][];\n unread: number;\n checks: Record<string, { a: string[]; b: WireBreak[] }>;\n}\n\nexport interface CacheEntry {\n repo: string;\n group: string;\n client: AuditClient;\n files: [string, number, number][];\n audit: GroupAudit;\n}\n\nconst WHAT = [\"command\", \"path\", \"call\"] as const;\n\nfunction encodeBreak(b: CheckBreak): WireBreak {\n return [\n b.at,\n b.session,\n b.step,\n b.file,\n b.line,\n WHAT.indexOf(b.what) as 0 | 1 | 2,\n b.index,\n b.asked === null ? 2 : b.asked ? 1 : 0,\n b.refused ? 1 : 0,\n ];\n}\n\nfunction decodeBreak(w: WireBreak): CheckBreak {\n return {\n at: w[0],\n session: w[1],\n step: w[2],\n file: w[3],\n line: w[4],\n what: WHAT[w[5]] ?? \"call\",\n index: w[6],\n asked: w[7] === 2 ? null : w[7] === 1,\n refused: w[8] === 1,\n };\n}\n\nexport function fileSignature(group: TranscriptGroup): [string, number, number][] {\n return group.files.map((f) => [sha(f.path), f.size, Math.round(f.mtimeMs)]);\n}\n\nexport class AuditCache {\n private readonly dir: string;\n private readonly entries = new Map<string, CacheEntry>();\n\n constructor(\n home: string,\n private readonly repo: string,\n private readonly enabled = true,\n ) {\n this.dir = join(home, CACHE_DIR);\n if (!enabled) return;\n let names: string[];\n try {\n names = readdirSync(this.dir);\n } catch {\n return;\n }\n for (const name of names) {\n if (!name.endsWith(\".json\")) continue;\n try {\n const w = JSON.parse(readFileSync(join(this.dir, name), \"utf8\")) as Wire;\n if (w.v !== 1 || w.engine !== ENGINE || w.repo !== repo) continue;\n this.entries.set(w.group, {\n repo: w.repo,\n group: w.group,\n client: w.client,\n files: w.files,\n audit: {\n sessions: w.sessions.map(([id, client, start, end, known]) => ({\n id,\n client,\n start,\n end,\n turnsKnown: known === 1,\n })),\n unread: w.unread,\n checks: Object.fromEntries(\n Object.entries(w.checks).map(([k, c]): [string, CheckOutcome] => [\n k,\n { applicable: c.a, breaks: c.b.map(decodeBreak) },\n ]),\n ),\n },\n });\n } catch {\n // a partial write from an interrupted run: re-read from the transcript\n }\n }\n }\n\n groupKey(group: TranscriptGroup): string {\n return sha(`${this.repo}\\u0000${group.key}`);\n }\n\n /** The cached counts for a group, if its files are unchanged and every check is answered. */\n lookup(group: TranscriptGroup, keys: readonly string[]): GroupAudit | undefined {\n const hit = this.entries.get(this.groupKey(group));\n if (!hit) return undefined;\n if (JSON.stringify(hit.files) !== JSON.stringify(fileSignature(group))) return undefined;\n if (!keys.every((k) => hit.audit.checks[k])) return undefined;\n return hit.audit;\n }\n\n /** Counts kept from groups whose transcripts are gone (deleted by the client's cleanup). */\n retained(present: ReadonlySet<string>, client: AuditClient): GroupAudit[] {\n const out: GroupAudit[] = [];\n for (const e of this.entries.values())\n if (e.client === client && !present.has(e.group)) out.push(e.audit);\n return out;\n }\n\n /** Best effort: a cache that cannot be written only costs speed and history. */\n store(group: TranscriptGroup, audit: GroupAudit): void {\n const key = this.groupKey(group);\n const files = fileSignature(group);\n const prev = this.entries.get(key);\n // checks this run did not ask for stay valid while the files are unchanged\n const checks =\n prev && JSON.stringify(prev.files) === JSON.stringify(files)\n ? { ...prev.audit.checks, ...audit.checks }\n : audit.checks;\n const merged: GroupAudit = { ...audit, checks };\n this.entries.set(key, {\n repo: this.repo,\n group: key,\n client: group.client,\n files,\n audit: merged,\n });\n if (!this.enabled) return;\n const wire: Wire = {\n v: 1,\n engine: ENGINE,\n repo: this.repo,\n group: key,\n client: group.client,\n files,\n sessions: merged.sessions.map((s) => [s.id, s.client, s.start, s.end, s.turnsKnown ? 1 : 0]),\n unread: merged.unread,\n checks: Object.fromEntries(\n Object.entries(merged.checks).map(([k, c]) => [\n k,\n { a: c.applicable, b: c.breaks.map(encodeBreak) },\n ]),\n ),\n };\n try {\n mkdirSync(this.dir, { recursive: true, mode: 0o700 });\n const file = join(this.dir, `${key.slice(0, 32)}.json`);\n const tmp = `${file}.${process.pid}.tmp`;\n writeFileSync(tmp, JSON.stringify(wire), { mode: 0o600 });\n renameSync(tmp, file);\n } catch {\n // read-only home, full disk: the next run reads the transcripts again\n }\n }\n}\n","/**\n * `okgate audit --enforce`: write the plan `planEnforcement` made into okgate.yaml with\n * the `yaml` document API, so every comment and setting already there stays. Each added rule\n * carries a comment naming the rule it came from. `hooks.mode` is never touched: a new policy, or\n * a new hooks block, starts in dry-run.\n */\nimport { existsSync, readFileSync } from \"node:fs\";\nimport YAML, { isMap, isScalar, isSeq, type Document, type Scalar, type YAMLSeq } from \"yaml\";\nimport type { EnforcePlan, Rule } from \"@agentwares/agentguard-core\";\nimport { HOOKS_POLICY_BLOCK, renderHooksStarterPolicy } from \"../commands/hooks.js\";\n\nexport interface EnforceEdit {\n /** the policy before (empty when there was none) and after */\n before: string;\n after: string;\n created: boolean;\n /** one line per hook rule added */\n added: string[];\n mode: \"dry-run\" | \"enforce\";\n}\n\nconst origin = (rule: Rule): string => ` R${rule.n} ${rule.file}:${rule.line}`;\n\nfunction seqAt(doc: Document, path: string[]): YAMLSeq {\n let node = doc.getIn(path, true);\n if (!isSeq(node)) {\n doc.setIn(path, doc.createNode([]));\n node = doc.getIn(path, true);\n }\n const seq = node as YAMLSeq;\n seq.flow = false;\n return seq;\n}\n\nconst values = (seq: YAMLSeq): string[] =>\n seq.items.map((n) => (isScalar(n) ? String(n.value) : \"\")).map((v) => v.toLowerCase());\n\n/** The policy text with the plan applied. Throws on a policy that is not valid YAML. */\nexport function applyEnforcePlan(\n policyPath: string,\n plan: EnforcePlan,\n now = new Date(),\n): EnforceEdit {\n const created = !existsSync(policyPath);\n const before = created ? \"\" : readFileSync(policyPath, \"utf8\");\n let text = created ? renderHooksStarterPolicy(now) : before;\n if (!/^hooks\\s*:/m.test(text)) text = `${text.replace(/\\n*$/, \"\\n\")}${HOOKS_POLICY_BLOCK}`;\n const doc = YAML.parseDocument(text);\n if (doc.errors.length > 0)\n throw new Error(`${policyPath} is not valid YAML: ${doc.errors[0]!.message}`);\n const added: string[] = [];\n\n for (const item of plan.items) {\n const seq = seqAt(doc, item.list.split(\".\"));\n if (values(seq).includes(item.pattern.toLowerCase())) continue;\n const node = doc.createNode(item.pattern) as Scalar;\n node.comment = origin(item.rule);\n seq.items.push(node);\n added.push(`${item.list}: ${item.pattern} (R${item.rule.n}, ${item.check.label})`);\n }\n\n if (plan.builtins.length > 0) {\n const path = [\"hooks\", \"irreversible\", \"builtins\"];\n const node = doc.getIn(path, true);\n const enabled = isScalar(node) ? node.value : undefined;\n if (enabled === false || isSeq(node)) {\n const seq = seqAt(doc, path);\n for (const b of plan.builtins) {\n if (values(seq).includes(b.name)) continue;\n const scalar = doc.createNode(b.name) as Scalar;\n scalar.comment = origin(b.rule);\n seq.items.push(scalar);\n added.push(`hooks.irreversible.builtins: ${b.name} (R${b.rule.n}, ${b.check.label})`);\n }\n }\n // `true` or absent: every built-in class is already on\n }\n\n if (plan.irreversible.length > 0) {\n const seq = seqAt(doc, [\"hooks\", \"irreversible\", \"rules\"]);\n const names = new Set(\n seq.items.map((n) => (isMap(n) ? String(n.get(\"name\") ?? \"\") : \"\")).filter(Boolean),\n );\n for (const r of plan.irreversible) {\n if (names.has(r.name)) continue;\n const node = doc.createNode({ name: r.name, shell: r.shell, mentions: r.mentions });\n if (isMap(node)) node.commentBefore = origin(r.rule);\n seq.items.push(node);\n added.push(\n `hooks.irreversible.rules: ${r.name} (${r.shell.length} commands) (R${r.rule.n}, ${r.check.label})`,\n );\n }\n }\n\n const mode = doc.getIn([\"hooks\", \"mode\"]) === \"enforce\" ? \"enforce\" : \"dry-run\";\n return { before, after: doc.toString({ lineWidth: 0 }), created, added, mode };\n}\n\n/** A unified-style line diff, with `context` unchanged lines around each change. */\nexport function lineDiff(a: string, b: string, context = 2): string[] {\n const x = a === \"\" ? [] : a.replace(/\\n$/, \"\").split(\"\\n\");\n const y = b.replace(/\\n$/, \"\").split(\"\\n\");\n const n = x.length;\n const m = y.length;\n // longest common subsequence, small files only\n const lcs: number[][] = Array.from({ length: n + 1 }, () => new Array<number>(m + 1).fill(0));\n for (let i = n - 1; i >= 0; i -= 1)\n for (let j = m - 1; j >= 0; j -= 1)\n lcs[i]![j] =\n x[i] === y[j] ? lcs[i + 1]![j + 1]! + 1 : Math.max(lcs[i + 1]![j]!, lcs[i]![j + 1]!);\n const ops: { op: \" \" | \"+\" | \"-\"; line: string }[] = [];\n let i = 0;\n let j = 0;\n while (i < n || j < m) {\n if (i < n && j < m && x[i] === y[j]) {\n ops.push({ op: \" \", line: x[i]! });\n i += 1;\n j += 1;\n } else if (j < m && (i >= n || lcs[i]![j + 1]! >= lcs[i + 1]![j]!)) {\n ops.push({ op: \"+\", line: y[j]! });\n j += 1;\n } else {\n ops.push({ op: \"-\", line: x[i]! });\n i += 1;\n }\n }\n const keep = new Set<number>();\n ops.forEach((o, k) => {\n if (o.op === \" \") return;\n for (let d = -context; d <= context; d += 1) keep.add(k + d);\n });\n const out: string[] = [];\n let last = -2;\n ops.forEach((o, k) => {\n if (!keep.has(k)) return;\n if (k !== last + 1 && out.length > 0) out.push(\" …\");\n out.push(`${o.op} ${o.line}`);\n last = k;\n });\n return out;\n}\n","/**\n * Stream a transcript group through agentguard-core's readers. Transcripts run to hundreds of\n * megabytes and most of every line is text the audit never needs, so a substring test decides\n * which lines are parsed at all. Nothing read here is written anywhere: the readers' steps and\n * turns stay in memory, and only `evaluateChecks`' counts reach the cache.\n */\nimport { createReadStream } from \"node:fs\";\nimport { createInterface } from \"node:readline\";\nimport {\n ClaudeCodeAuditReader,\n CodexAuditReader,\n stableHash,\n type AuditReaderOptions,\n type AuditStep,\n type TranscriptAudit,\n} from \"@agentwares/agentguard-core\";\nimport type { TranscriptGroup } from \"./sources.js\";\n\nconst CLAUDE_WANTED = (raw: string): boolean =>\n raw.includes('\"type\":\"assistant\"') || raw.includes('\"type\":\"user\"');\nconst CODEX_WANTED = (raw: string): boolean =>\n raw.includes('\"session_meta\"') ||\n raw.includes('\"turn_context\"') ||\n raw.includes('\"function_call\"') ||\n raw.includes('\"local_shell_call\"') ||\n raw.includes('\"custom_tool_call\"');\n\n/**\n * Each line of a file, 1-based. `onLine` returns false to stop early. Lines that are not JSON\n * (a transcript being written ends mid-line) are skipped.\n */\nasync function eachLine(\n path: string,\n wanted: (raw: string, line: number) => boolean,\n onLine: (value: unknown, line: number) => boolean | void,\n): Promise<void> {\n const stream = createReadStream(path, { encoding: \"utf8\", highWaterMark: 1 << 20 });\n const lines = createInterface({ input: stream, crlfDelay: Infinity });\n let n = 0;\n try {\n for await (const raw of lines) {\n n += 1;\n if (raw.length === 0 || !wanted(raw, n)) continue;\n let value: unknown;\n try {\n value = JSON.parse(raw);\n } catch {\n continue;\n }\n if (onLine(value, n) === false) break;\n }\n } finally {\n lines.close();\n stream.destroy();\n }\n}\n\n/** Every step and turn in a group that happened in the repository. */\nexport async function readGroup(\n group: TranscriptGroup,\n opts: AuditReaderOptions,\n): Promise<TranscriptAudit> {\n if (group.client === \"codex\") {\n const reader = new CodexAuditReader(opts);\n await eachLine(group.files[0]!.path, CODEX_WANTED, (value, line) => {\n reader.add(value, line, 0);\n return reader.relevant;\n });\n return reader.result();\n }\n const reader = new ClaudeCodeAuditReader(opts);\n for (const [i, file] of group.files.entries())\n await eachLine(file.path, CLAUDE_WANTED, (value, line) => reader.add(value, line, i));\n return reader.result();\n}\n\n/**\n * The steps behind a few breaks, for the evidence on screen: only the lines that hold them are\n * parsed (and, for Codex, the lines that say where the rollout ran).\n */\nexport async function fetchSteps(\n group: TranscriptGroup,\n wanted: readonly { file: number; line: number; step: string }[],\n opts: AuditReaderOptions,\n): Promise<Map<string, AuditStep>> {\n const out = new Map<string, AuditStep>();\n const byFile = new Map<number, Set<number>>();\n for (const w of wanted) {\n const set = byFile.get(w.file) ?? new Set<number>();\n set.add(w.line);\n byFile.set(w.file, set);\n }\n for (const [fileIndex, lines] of byFile) {\n const file = group.files[fileIndex];\n if (!file) continue;\n const last = Math.max(...lines);\n const reader =\n group.client === \"codex\" ? new CodexAuditReader(opts) : new ClaudeCodeAuditReader(opts);\n await eachLine(\n file.path,\n (raw, n) =>\n lines.has(n) ||\n (group.client === \"codex\" &&\n (raw.includes('\"session_meta\"') || raw.includes('\"turn_context\"'))),\n (value, n) => {\n reader.add(value, n, fileIndex);\n return n < last;\n },\n );\n for (const step of reader.result().steps) out.set(stableHash(step.id), step);\n }\n return out;\n}\n","/**\n * The repository being audited: where its rule files are, and which working directories count\n * as \"in it\" when matching sessions.\n */\nimport { existsSync, readFileSync, readdirSync, statSync } from \"node:fs\";\nimport { dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport YAML from \"yaml\";\nimport {\n AuditRulesSchema,\n isWithin,\n normalizePath,\n type ConfigRule,\n type RuleFileInput,\n} from \"@agentwares/agentguard-core\";\nimport { pathForms } from \"./sources.js\";\n\nexport interface AuditRepo {\n /** where the rule files are read from: the checkout the command ran in */\n checkout: string;\n /**\n * the repository sessions are matched against: the main checkout when `checkout` is a git\n * worktree, so sessions in its other worktrees (`.claude/worktrees/*`) count too\n */\n root: string;\n}\n\n/** The git checkout holding `cwd` (or `cwd` itself outside git), and its main checkout. */\nexport function findRepo(cwd: string): AuditRepo {\n let dir = resolve(cwd);\n for (let i = 0; i < 64; i += 1) {\n const dotgit = join(dir, \".git\");\n if (existsSync(dotgit)) {\n let root = dir;\n try {\n if (statSync(dotgit).isFile()) {\n // a worktree: `gitdir: <main>/.git/worktrees/<name>`\n const m = /^gitdir:\\s*(.+)$/m.exec(readFileSync(dotgit, \"utf8\"));\n const gitdir = m ? resolve(dir, m[1]!.trim()) : \"\";\n const at = gitdir.lastIndexOf(`${sep}.git${sep}worktrees${sep}`);\n if (at > 0) root = gitdir.slice(0, at);\n }\n } catch {\n // unreadable .git file: audit this checkout alone\n }\n return { checkout: dir, root };\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return { checkout: resolve(cwd), root: resolve(cwd) };\n}\n\n/** Is a session's working directory inside the repository (in any form its path can take)? */\nexport function repoMatcher(root: string): (cwd: string) => boolean {\n const forms = pathForms(root).map(normalizePath);\n return (cwd: string) => forms.some((f) => isWithin(normalizePath(cwd), f));\n}\n\n/** Rule files at the root of a checkout, as agentsmd-lint looks for them, plus Cursor's rules. */\nexport const RULE_FILES = [\n \"CLAUDE.md\",\n \"CLAUDE.local.md\",\n \".claude/CLAUDE.md\",\n \"AGENTS.md\",\n \"GEMINI.md\",\n \".cursorrules\",\n \".github/copilot-instructions.md\",\n \".windsurfrules\",\n \".clinerules\",\n] as const;\n\nconst MAX_CURSOR_RULES = 20;\nconst MAX_BYTES = 512 * 1024;\n\nfunction cursorRules(dir: string, out: string[], depth = 0): void {\n if (depth > 3 || out.length >= MAX_CURSOR_RULES) return;\n let entries;\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n const p = join(dir, e.name);\n if (e.isDirectory()) cursorRules(p, out, depth + 1);\n else if (e.isFile() && /\\.(mdc|md)$/.test(e.name) && out.length < MAX_CURSOR_RULES) out.push(p);\n }\n}\n\n/** The rule files this checkout has, repo-relative, plus any named with `--rules`. */\nexport function readRuleFiles(checkout: string, extra: readonly string[] = []): RuleFileInput[] {\n const paths: string[] = RULE_FILES.map((f) => join(checkout, f));\n cursorRules(join(checkout, \".cursor\", \"rules\"), paths);\n for (const e of extra) paths.push(isAbsolute(e) ? e : resolve(checkout, e));\n const out: RuleFileInput[] = [];\n const seen = new Set<string>();\n for (const p of paths) {\n if (seen.has(p)) continue;\n seen.add(p);\n try {\n if (!statSync(p).isFile()) continue;\n const text = readFileSync(p, \"utf8\").slice(0, MAX_BYTES);\n const rel = relative(checkout, p);\n out.push({ path: rel.startsWith(\"..\") ? p : rel.split(sep).join(\"/\"), text });\n } catch {\n // absent\n }\n }\n return out;\n}\n\n/**\n * `audit.rules` from okgate.yaml, read on its own so a policy that fails for another reason\n * (an unset `${VAR}`, say) does not hide them. Returns a warning instead of throwing.\n */\nexport function readConfigRules(policyPath: string): { rules: ConfigRule[]; warning?: string } {\n if (!existsSync(policyPath)) return { rules: [] };\n let raw: unknown;\n try {\n raw = YAML.parse(readFileSync(policyPath, \"utf8\"));\n } catch (err) {\n return {\n rules: [],\n warning: `${policyPath} is not valid YAML (${err instanceof Error ? err.message : String(err)}); its audit.rules were skipped`,\n };\n }\n const audit = raw && typeof raw === \"object\" ? (raw as Record<string, unknown>).audit : undefined;\n const rules =\n audit && typeof audit === \"object\" ? (audit as Record<string, unknown>).rules : undefined;\n if (rules === undefined) return { rules: [] };\n const parsed = AuditRulesSchema.safeParse(rules);\n if (!parsed.success)\n return {\n rules: [],\n warning: `audit.rules in ${policyPath} is invalid (${parsed.error.issues\n .map((i) => `${i.path.join(\".\")}: ${i.message}`)\n .join(\"; \")}); skipped`,\n };\n return { rules: parsed.data };\n}\n","/**\n * Where coding agents keep their transcripts, and which of them are about one repository.\n *\n * The layout is the one seatledger reads (apps/seatledger-cli/src/paths.ts, PROD-1A), kept in\n * step with it rather than imported: seatledger is not on npm yet, and the public okgate repo\n * is generated without it (see docs/reports/AG-AUDIT.md).\n *\n * - Claude Code: `$CLAUDE_CONFIG_DIR/projects` (comma-separated for several), else\n * `~/.claude/projects` and `~/.config/claude/projects`. One directory per working directory,\n * named after its path with every character that is not a letter or digit turned into `-`;\n * a session is `<session>.jsonl` there, its subagents under `<session>/subagents/`.\n * - Codex: `$CODEX_HOME/sessions` and `$CODEX_HOME/archived_sessions`, `CODEX_HOME` defaulting\n * to `~/.codex`. One rollout per thread, by date; its first line names the working directory.\n */\nimport { existsSync, readdirSync, realpathSync, statSync } from \"node:fs\";\nimport { basename, join, resolve } from \"node:path\";\nimport type { AuditClient } from \"@agentwares/agentguard-core\";\n\nexport interface SourceDirs {\n \"claude-code\": string[];\n codex: string[];\n}\n\nexport function sourceDirs(\n env: NodeJS.ProcessEnv,\n home: string,\n overrides: { claudeDir?: string; codexDir?: string } = {},\n): SourceDirs {\n const claude = overrides.claudeDir\n ? [resolve(overrides.claudeDir)]\n : env.CLAUDE_CONFIG_DIR\n ? env.CLAUDE_CONFIG_DIR.split(\",\")\n .map((d) => d.trim())\n .filter(Boolean)\n .map((d) => join(resolve(d), \"projects\"))\n : [join(home, \".claude\", \"projects\"), join(home, \".config\", \"claude\", \"projects\")];\n const codexHome = env.CODEX_HOME ? resolve(env.CODEX_HOME) : join(home, \".codex\");\n const codex = overrides.codexDir\n ? [resolve(overrides.codexDir)]\n : [join(codexHome, \"sessions\"), join(codexHome, \"archived_sessions\")];\n return { \"claude-code\": claude, codex };\n}\n\nexport interface TranscriptFile {\n path: string;\n size: number;\n mtimeMs: number;\n}\n\n/** What is read, cached and evaluated together: a session and its subagents, or a rollout. */\nexport interface TranscriptGroup {\n client: AuditClient;\n /** the main transcript's path (the session directory for subagents with no main file) */\n key: string;\n files: TranscriptFile[];\n /** the latest write to any of its files */\n lastWrite: number;\n}\n\n/** Spilled tool output and memory notes live beside transcripts; neither is a transcript. */\nconst SKIP_DIRS = new Set([\"tool-results\", \"memory\", \"node_modules\", \".git\"]);\n\nfunction stat(path: string): TranscriptFile | undefined {\n try {\n const s = statSync(path);\n return s.isFile() ? { path, size: s.size, mtimeMs: s.mtimeMs } : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction jsonlUnder(dir: string, out: TranscriptFile[], depth = 0): void {\n if (depth > 6) return;\n let entries;\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n const p = join(dir, e.name);\n if (e.isDirectory()) {\n if (!SKIP_DIRS.has(e.name)) jsonlUnder(p, out, depth + 1);\n } else if (e.isFile() && e.name.endsWith(\".jsonl\")) {\n const f = stat(p);\n if (f) out.push(f);\n }\n }\n}\n\n/** Claude Code's directory name for a working directory. */\nexport function claudeProjectName(dir: string): string {\n return dir.replace(/[^a-zA-Z0-9]/g, \"-\");\n}\n\n/** The forms a path can take in a transcript: as given, and with symlinks resolved (/var → /private/var). */\nexport function pathForms(dir: string): string[] {\n const forms = new Set([resolve(dir)]);\n try {\n forms.add(realpathSync(dir));\n } catch {\n // not on disk (a deleted checkout): the given form only\n }\n return [...forms];\n}\n\n/**\n * Claude Code project directories that can hold sessions for `repoRoot`: its own, and any whose\n * name starts with it (subdirectories, worktrees under it). The name is lossy, so the\n * transcripts' own `cwd` decides in the end.\n */\nexport function claudeProjectDirs(roots: readonly string[], repoRoot: string): string[] {\n const names = pathForms(repoRoot).map(claudeProjectName);\n const out: string[] = [];\n for (const root of roots) {\n let entries;\n try {\n entries = readdirSync(root, { withFileTypes: true });\n } catch {\n continue;\n }\n for (const e of entries) {\n if (!e.isDirectory()) continue;\n if (names.some((n) => e.name === n || e.name.startsWith(`${n}-`)))\n out.push(join(root, e.name));\n }\n }\n return out;\n}\n\n/** Sessions in Claude Code project directories, each with its subagents. */\nexport function claudeGroups(projectDirs: readonly string[]): TranscriptGroup[] {\n const groups: TranscriptGroup[] = [];\n for (const dir of projectDirs) {\n let entries;\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n continue;\n }\n const mains = new Map<string, TranscriptFile>();\n const subdirs: string[] = [];\n for (const e of entries) {\n const p = join(dir, e.name);\n if (e.isFile() && e.name.endsWith(\".jsonl\")) {\n const f = stat(p);\n if (f) mains.set(basename(e.name, \".jsonl\"), f);\n } else if (e.isDirectory() && !SKIP_DIRS.has(e.name)) subdirs.push(e.name);\n }\n for (const [id, main] of mains) {\n const files = [main];\n if (subdirs.includes(id)) jsonlUnder(join(dir, id), files);\n groups.push(group(\"claude-code\", main.path, files));\n }\n for (const id of subdirs) {\n if (mains.has(id)) continue;\n const files: TranscriptFile[] = [];\n jsonlUnder(join(dir, id), files);\n if (files.length > 0) groups.push(group(\"claude-code\", join(dir, id), files));\n }\n }\n return groups;\n}\n\n/** Codex rollouts, one group each. */\nexport function codexGroups(roots: readonly string[]): TranscriptGroup[] {\n const files: TranscriptFile[] = [];\n for (const root of roots) if (existsSync(root)) jsonlUnder(root, files);\n return files.map((f) => group(\"codex\", f.path, [f]));\n}\n\nfunction group(client: AuditClient, key: string, files: TranscriptFile[]): TranscriptGroup {\n files.sort((a, b) => (a.path === key ? -1 : b.path === key ? 1 : a.path.localeCompare(b.path)));\n return { client, key, files, lastWrite: Math.max(...files.map((f) => f.mtimeMs)) };\n}\n"],"mappings":"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","names":["writeFileSync","basename","join","resolve","stableHash","group","readFileSync","readFileSync","i","j","group","reader","existsSync","readFileSync","readdirSync","statSync","join","resolve","YAML","existsSync","readdirSync","join","resolve","join","existsSync","statSync","readFileSync","readdirSync","YAML","resolve","basename","join","group","stableHash","writeFileSync"]}
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
hookSettingsFiles,
|
|
4
|
-
hooksCommand
|
|
5
|
-
} from "./chunk-3O6KWT3E.js";
|
|
6
|
-
import {
|
|
2
|
+
LEGACY_PROXY_SERVER_NAME,
|
|
7
3
|
PROXY_SERVER_NAME,
|
|
8
4
|
describeConfigPath,
|
|
9
5
|
detectClientConfigs,
|
|
10
6
|
isGeminiConfig,
|
|
11
7
|
mergeServerIntoConfig
|
|
12
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-OM5L7A32.js";
|
|
9
|
+
import {
|
|
10
|
+
hooksCommand
|
|
11
|
+
} from "./chunk-F73VDY3W.js";
|
|
12
|
+
import {
|
|
13
|
+
CLIENT_ALIASES,
|
|
14
|
+
hookSettingsFiles
|
|
15
|
+
} from "./chunk-2QDPPTPY.js";
|
|
16
|
+
import {
|
|
17
|
+
INSTALL
|
|
18
|
+
} from "./chunk-XPNBYSIN.js";
|
|
13
19
|
import {
|
|
14
|
-
DEFAULT_POLICY_FILE,
|
|
15
20
|
approvalUrlFor,
|
|
16
21
|
createFileGuard,
|
|
17
22
|
defaultIo,
|
|
@@ -26,23 +31,24 @@ import {
|
|
|
26
31
|
policyPathFrom,
|
|
27
32
|
readRegistration,
|
|
28
33
|
version
|
|
29
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-4WTFMFRY.js";
|
|
30
35
|
|
|
31
36
|
// src/commands/connect.ts
|
|
32
37
|
import { existsSync } from "fs";
|
|
33
38
|
import { relative } from "path";
|
|
39
|
+
import { envTwin } from "@agentwares/agentguard-core";
|
|
34
40
|
var DEFAULT_PROXY_URL = "https://agentwares-agentguard-proxy.vercel.app";
|
|
35
41
|
function fail(e) {
|
|
36
42
|
throw e;
|
|
37
43
|
}
|
|
38
44
|
async function connectCommand(args, io, fetchImpl = fetch) {
|
|
39
|
-
const key = args.positionals[0] ?? io.env
|
|
45
|
+
const key = args.positionals[0] ?? envTwin(io.env, "KEY");
|
|
40
46
|
if (!key) {
|
|
41
|
-
io.err("usage:
|
|
47
|
+
io.err("usage: okgate connect <key> [--write] [--client <path>] [--url <proxy-url>]");
|
|
42
48
|
io.err(" the key is on your dashboard; it starts with agk_");
|
|
43
49
|
return 2;
|
|
44
50
|
}
|
|
45
|
-
const base = (flagString(args, "url") ?? io.env
|
|
51
|
+
const base = (flagString(args, "url") ?? envTwin(io.env, "PROXY_URL") ?? DEFAULT_PROXY_URL).replace(/\/+$/, "");
|
|
46
52
|
let res;
|
|
47
53
|
try {
|
|
48
54
|
res = await fetchImpl(`${base}/connect`, {
|
|
@@ -66,7 +72,7 @@ async function connectCommand(args, io, fetchImpl = fetch) {
|
|
|
66
72
|
fail({
|
|
67
73
|
code: "PROXY_BAD_RESPONSE",
|
|
68
74
|
cause: `${base}/connect returned ${res.status} that was not JSON: ${text.slice(0, 200)}`,
|
|
69
|
-
fix: "check --url points at an
|
|
75
|
+
fix: "check --url points at an okgate proxy, not at the dashboard",
|
|
70
76
|
retryable: false
|
|
71
77
|
});
|
|
72
78
|
}
|
|
@@ -85,7 +91,7 @@ async function connectCommand(args, io, fetchImpl = fetch) {
|
|
|
85
91
|
return 0;
|
|
86
92
|
}
|
|
87
93
|
const rel = (p) => p.startsWith(io.cwd + "/") ? relative(io.cwd, p) : p;
|
|
88
|
-
const entry = conn.mcpServers[PROXY_SERVER_NAME] ?? {
|
|
94
|
+
const entry = conn.mcpServers[PROXY_SERVER_NAME] ?? conn.mcpServers[LEGACY_PROXY_SERVER_NAME] ?? {
|
|
89
95
|
type: "http",
|
|
90
96
|
url: conn.mcpUrl,
|
|
91
97
|
headers: conn.headers
|
|
@@ -112,7 +118,9 @@ async function connectCommand(args, io, fetchImpl = fetch) {
|
|
|
112
118
|
return 1;
|
|
113
119
|
}
|
|
114
120
|
const forClient = isGeminiConfig(c) ? { httpUrl: entry.url, ...entry.headers ? { headers: entry.headers } : {} } : entry;
|
|
115
|
-
const { backup, replaced } = mergeServerIntoConfig(c, PROXY_SERVER_NAME, forClient
|
|
121
|
+
const { backup, replaced } = mergeServerIntoConfig(c, PROXY_SERVER_NAME, forClient, [
|
|
122
|
+
LEGACY_PROXY_SERVER_NAME
|
|
123
|
+
]);
|
|
116
124
|
io.out(
|
|
117
125
|
`${replaced ? "updated" : "wrote "} ${rel(c.path)} (${c.label}) \u2192 ${PROXY_SERVER_NAME} = ${conn.mcpUrl}`
|
|
118
126
|
);
|
|
@@ -136,6 +144,7 @@ run again with --write to add this to your MCP client config`);
|
|
|
136
144
|
}
|
|
137
145
|
|
|
138
146
|
// src/commands/control.ts
|
|
147
|
+
import { KILL_ENV, LEGACY_KILL_ENV } from "@agentwares/agentguard-core";
|
|
139
148
|
async function pokeHttp(io, reg, path, body) {
|
|
140
149
|
if (!reg) return;
|
|
141
150
|
try {
|
|
@@ -158,11 +167,11 @@ async function pokeHttp(io, reg, path, body) {
|
|
|
158
167
|
async function killCommand(args, io) {
|
|
159
168
|
const loaded = loadPolicyFor(args, io, { allowMissingEnv: true });
|
|
160
169
|
const { kill } = createFileGuard(loaded, { alerts: false, env: io.env });
|
|
161
|
-
const reason = args.positionals.join(" ") || flagString(args, "reason") || `
|
|
170
|
+
const reason = args.positionals.join(" ") || flagString(args, "reason") || `okgate kill by ${io.env.USER ?? "operator"}`;
|
|
162
171
|
kill.kill(reason);
|
|
163
172
|
await pokeHttp(io, readRegistration(loaded), "/kill", { reason });
|
|
164
173
|
io.out(
|
|
165
|
-
`KILLED: ${kill.path} written \u2014 every tool call through this policy now returns KILLED. Clear with:
|
|
174
|
+
`KILLED: ${kill.path} written \u2014 every tool call through this policy now returns KILLED. Clear with: okgate resume`
|
|
166
175
|
);
|
|
167
176
|
return 0;
|
|
168
177
|
}
|
|
@@ -172,17 +181,18 @@ async function resumeCommand(args, io) {
|
|
|
172
181
|
kill.resume();
|
|
173
182
|
await pokeHttp(io, readRegistration(loaded), "/resume");
|
|
174
183
|
io.out(`resumed: ${kill.path} removed`);
|
|
175
|
-
|
|
176
|
-
io.
|
|
177
|
-
|
|
178
|
-
|
|
184
|
+
for (const name of /* @__PURE__ */ new Set([loaded.policy.kill.env, KILL_ENV, LEGACY_KILL_ENV]))
|
|
185
|
+
if (io.env[name] && io.env[name] !== "0" && io.env[name].toLowerCase() !== "false")
|
|
186
|
+
io.err(
|
|
187
|
+
`note: ${name} is set in this shell's environment; proxies started from it stay killed`
|
|
188
|
+
);
|
|
179
189
|
return 0;
|
|
180
190
|
}
|
|
181
191
|
async function decideCommand(decision, args, io) {
|
|
182
192
|
const id = args.positionals[0];
|
|
183
193
|
if (!id) {
|
|
184
194
|
io.err(
|
|
185
|
-
`usage:
|
|
195
|
+
`usage: okgate ${decision === "approved" ? "approve" : "deny"} <approval-id> [--by name] [--note text]`
|
|
186
196
|
);
|
|
187
197
|
return 1;
|
|
188
198
|
}
|
|
@@ -195,7 +205,7 @@ async function decideCommand(decision, args, io) {
|
|
|
195
205
|
flagString(args, "note")
|
|
196
206
|
);
|
|
197
207
|
if (!record) {
|
|
198
|
-
io.err(`no approval ${id} \u2014 pending ones:
|
|
208
|
+
io.err(`no approval ${id} \u2014 pending ones: okgate approvals`);
|
|
199
209
|
return 1;
|
|
200
210
|
}
|
|
201
211
|
io.out(
|
|
@@ -220,8 +230,7 @@ async function approvalsCommand(args, io) {
|
|
|
220
230
|
`${r.id} ${r.status.padEnd(9)} ${r.tool} run ${r.run_id}${r.agent ? ` agent ${r.agent}` : ""} expires ${r.expires_at}`
|
|
221
231
|
);
|
|
222
232
|
io.out(` args: ${JSON.stringify(r.args).slice(0, 300)}`);
|
|
223
|
-
if (r.status === "pending")
|
|
224
|
-
io.out(` \u2192 agentguard approve ${r.id} | agentguard deny ${r.id}`);
|
|
233
|
+
if (r.status === "pending") io.out(` \u2192 okgate approve ${r.id} | okgate deny ${r.id}`);
|
|
225
234
|
}
|
|
226
235
|
return 0;
|
|
227
236
|
}
|
|
@@ -229,10 +238,12 @@ async function approvalsCommand(args, io) {
|
|
|
229
238
|
// src/commands/hook.ts
|
|
230
239
|
import { existsSync as existsSync3 } from "fs";
|
|
231
240
|
import { tmpdir } from "os";
|
|
232
|
-
import { dirname, join, resolve } from "path";
|
|
241
|
+
import { basename, dirname, join, resolve } from "path";
|
|
233
242
|
import {
|
|
243
|
+
POLICY_FILES,
|
|
234
244
|
assessHookAction,
|
|
235
245
|
detectHookClient,
|
|
246
|
+
envTwin as envTwin2,
|
|
236
247
|
hookActionFromInput
|
|
237
248
|
} from "@agentwares/agentguard-core";
|
|
238
249
|
|
|
@@ -290,8 +301,10 @@ var RUN_PREFIX = {
|
|
|
290
301
|
function findPolicyUpwards(start) {
|
|
291
302
|
let dir = resolve(start);
|
|
292
303
|
for (let i = 0; i < 64; i += 1) {
|
|
293
|
-
const
|
|
294
|
-
|
|
304
|
+
for (const name of POLICY_FILES) {
|
|
305
|
+
const candidate = join(dir, name);
|
|
306
|
+
if (existsSync3(candidate)) return candidate;
|
|
307
|
+
}
|
|
295
308
|
const parent = dirname(dir);
|
|
296
309
|
if (parent === dir) return void 0;
|
|
297
310
|
dir = parent;
|
|
@@ -304,8 +317,8 @@ function projectDir(io, inputCwd) {
|
|
|
304
317
|
function resolveHookPolicy(args, io, inputCwd) {
|
|
305
318
|
const flag = flagString(args, "config");
|
|
306
319
|
if (flag) return { path: resolve(io.cwd, flag), found: "flag" };
|
|
307
|
-
|
|
308
|
-
|
|
320
|
+
const fromEnv = envTwin2(io.env, "CONFIG");
|
|
321
|
+
if (fromEnv) return { path: resolve(io.cwd, fromEnv), found: "env" };
|
|
309
322
|
const start = projectDir(io, inputCwd) ?? io.cwd;
|
|
310
323
|
const near = findPolicyUpwards(start);
|
|
311
324
|
if (near) return { path: near, found: "project" };
|
|
@@ -326,7 +339,7 @@ function respond(io, client, result, summary, approveCommand) {
|
|
|
326
339
|
const reason = JSON.stringify(e);
|
|
327
340
|
const id = result.approvalId ? `, approval ${result.approvalId}` : "";
|
|
328
341
|
const approve = e.code === "APPROVAL_REQUIRED" && result.approvalId ? ` To let this exact command run once: ${approveCommand(result.approvalId)}` : "";
|
|
329
|
-
const systemMessage = `
|
|
342
|
+
const systemMessage = `okgate refused "${summary.slice(0, 120)}" (${e.code}${id}): ${e.cause}${approve}`;
|
|
330
343
|
if (client === "gemini-cli") out(io, { decision: "deny", reason, systemMessage });
|
|
331
344
|
else
|
|
332
345
|
out(io, {
|
|
@@ -341,7 +354,7 @@ function respond(io, client, result, summary, approveCommand) {
|
|
|
341
354
|
}
|
|
342
355
|
if (result.would) {
|
|
343
356
|
out(io, {
|
|
344
|
-
systemMessage: `
|
|
357
|
+
systemMessage: `okgate (hooks.mode: dry-run) would have stopped "${summary.slice(0, 120)}" with ${result.would.code}: ${result.would.cause} \u2014 it ran; nothing is blocked until hooks.mode is enforce`
|
|
345
358
|
});
|
|
346
359
|
}
|
|
347
360
|
}
|
|
@@ -349,7 +362,7 @@ async function hookCommand(args, io) {
|
|
|
349
362
|
const event = args.positionals[0];
|
|
350
363
|
if (event !== "pre-tool-use") {
|
|
351
364
|
io.err(
|
|
352
|
-
"usage:
|
|
365
|
+
"usage: okgate hook pre-tool-use [--client claude|codex|gemini] [--config okgate.yaml] [--fallback-config path]\n run by a coding agent's pre-execution hook, with the hook's JSON on stdin; `okgate hooks install` sets it up"
|
|
353
366
|
);
|
|
354
367
|
return 1;
|
|
355
368
|
}
|
|
@@ -381,7 +394,13 @@ async function hookCommand(args, io) {
|
|
|
381
394
|
home,
|
|
382
395
|
tmpDirs,
|
|
383
396
|
stateDir: loaded.stateDir,
|
|
384
|
-
|
|
397
|
+
// both names: creating okgate.yaml beside agentguard.yaml would replace the policy read
|
|
398
|
+
guardFiles: [
|
|
399
|
+
loaded.path,
|
|
400
|
+
...POLICY_FILES.map((name) => join(dirname(loaded.path), name)),
|
|
401
|
+
...hookSettingsFiles({ cwd: resolve(workspace), home })
|
|
402
|
+
],
|
|
403
|
+
policyFile: basename(loaded.path)
|
|
385
404
|
};
|
|
386
405
|
const assessment = assessHookAction(loaded.policy, action, ctx);
|
|
387
406
|
const reg = readRegistration(loaded);
|
|
@@ -391,7 +410,7 @@ async function hookCommand(args, io) {
|
|
|
391
410
|
log: (line) => io.err(line)
|
|
392
411
|
});
|
|
393
412
|
const configHint = policyRef.found === "project" && dirname(policyRef.path) === resolve(workspace) ? "" : ` --config ${JSON.stringify(policyRef.path)}`;
|
|
394
|
-
const approveCommand = (id) =>
|
|
413
|
+
const approveCommand = (id) => `${INSTALL} approve ${id}${configHint}`;
|
|
395
414
|
const result = await guard.preflight({
|
|
396
415
|
action,
|
|
397
416
|
assessment,
|
|
@@ -399,7 +418,7 @@ async function hookCommand(args, io) {
|
|
|
399
418
|
humanTurn: () => client === "claude-code" ? humanTurnFromTranscript(action.transcriptPath, {
|
|
400
419
|
requireOrigin: loaded.policy.hooks.irreversible.require_origin
|
|
401
420
|
}) : {
|
|
402
|
-
missing: `${client} transcripts are not a verified format for this check, so an irreversible command needs \`
|
|
421
|
+
missing: `${client} transcripts are not a verified format for this check, so an irreversible command needs \`okgate approve\``
|
|
403
422
|
},
|
|
404
423
|
approveCommand
|
|
405
424
|
});
|
|
@@ -408,7 +427,7 @@ async function hookCommand(args, io) {
|
|
|
408
427
|
} catch (err) {
|
|
409
428
|
warn(
|
|
410
429
|
io,
|
|
411
|
-
`
|
|
430
|
+
`okgate hook error \u2014 this call was NOT checked: ${describeError(err).replace(/\s+/g, " ").slice(0, 400)}`
|
|
412
431
|
);
|
|
413
432
|
return 0;
|
|
414
433
|
}
|
|
@@ -431,9 +450,7 @@ async function keyCommand(args, io) {
|
|
|
431
450
|
const items = seq.items.filter(isMap);
|
|
432
451
|
if (sub === "list" || sub === void 0) {
|
|
433
452
|
if (items.length === 0)
|
|
434
|
-
io.out(
|
|
435
|
-
"no agents in agentguard.yaml \u2014 create one: agentguard key create <name> --allow 'crm_get_*'"
|
|
436
|
-
);
|
|
453
|
+
io.out("no agents in okgate.yaml \u2014 create one: okgate key create <name> --allow 'crm_get_*'");
|
|
437
454
|
for (const a of items) {
|
|
438
455
|
const allow2 = a.get("allow");
|
|
439
456
|
io.out(
|
|
@@ -444,7 +461,7 @@ async function keyCommand(args, io) {
|
|
|
444
461
|
}
|
|
445
462
|
if (!name) {
|
|
446
463
|
io.err(
|
|
447
|
-
"usage:
|
|
464
|
+
"usage: okgate key create <agent> [--allow pattern]... [--deny pattern]... [--writes n] [--spend n] [--deletes n] [--emails n] [--tool-calls n] [--mode dry-run|enforce] [--upstream name]..."
|
|
448
465
|
);
|
|
449
466
|
return 1;
|
|
450
467
|
}
|
|
@@ -456,7 +473,7 @@ async function keyCommand(args, io) {
|
|
|
456
473
|
}
|
|
457
474
|
seq.items.splice(seq.items.indexOf(items[idx]), 1);
|
|
458
475
|
writeFileSync(path, doc.toString());
|
|
459
|
-
io.out(`revoked ${name}: removed from
|
|
476
|
+
io.out(`revoked ${name}: removed from okgate.yaml (running proxies pick it up on restart)`);
|
|
460
477
|
return 0;
|
|
461
478
|
}
|
|
462
479
|
if (sub !== "create") {
|
|
@@ -497,7 +514,7 @@ async function keyCommand(args, io) {
|
|
|
497
514
|
`${existing ? "rotated" : "created"} agent "${name}" in ${path}${allow.length ? ` (allow: ${allow.join(", ")})` : " (allow: all tools)"}`
|
|
498
515
|
);
|
|
499
516
|
io.err(
|
|
500
|
-
"the key is shown once; give it to the agent as `Authorization: Bearer <key>` (HTTP) \u2014 over stdio use `
|
|
517
|
+
"the key is shown once; give it to the agent as `Authorization: Bearer <key>` (HTTP) \u2014 over stdio use `okgate proxy --agent " + name + "`"
|
|
501
518
|
);
|
|
502
519
|
io.out(key);
|
|
503
520
|
return 0;
|
|
@@ -510,6 +527,9 @@ import {
|
|
|
510
527
|
renderPermissionDiffMarkdown
|
|
511
528
|
} from "@agentwares/agentguard-core";
|
|
512
529
|
var DEFAULT_PERMISSION_PATHS = [
|
|
530
|
+
"okgate.yaml",
|
|
531
|
+
"okgate.yml",
|
|
532
|
+
// the policy's name before the rename, still read when there is no okgate.yaml
|
|
513
533
|
"agentguard.yaml",
|
|
514
534
|
"agentguard.yml",
|
|
515
535
|
".claude/settings.json",
|
|
@@ -519,7 +539,7 @@ var DEFAULT_PERMISSION_PATHS = [
|
|
|
519
539
|
".cursor/mcp.json",
|
|
520
540
|
".vscode/mcp.json"
|
|
521
541
|
];
|
|
522
|
-
var PERMISSION_FILE = /(^|\/)(agentguard[^/]*\.ya?ml|\.claude\/settings(\.local)?\.json|[^/]*mcp[^/]*\.json|claude_desktop_config\.json)$/;
|
|
542
|
+
var PERMISSION_FILE = /(^|\/)((okgate|agentguard)[^/]*\.ya?ml|\.claude\/settings(\.local)?\.json|[^/]*mcp[^/]*\.json|claude_desktop_config\.json)$/;
|
|
523
543
|
function git(cwd, argv) {
|
|
524
544
|
try {
|
|
525
545
|
return execFileSync("git", argv, {
|
|
@@ -629,7 +649,7 @@ async function reportCommand(args, io) {
|
|
|
629
649
|
io.out(
|
|
630
650
|
chain.ok ? `Audit chain: ${chain.entries} entries, verified (${loaded.auditPath}).` : `Audit chain BROKEN at entry ${chain.brokenAt}: ${chain.reason}`
|
|
631
651
|
);
|
|
632
|
-
if (runId && listRuns(entries).length > 1) io.out(`Other runs:
|
|
652
|
+
if (runId && listRuns(entries).length > 1) io.out(`Other runs: okgate report --all`);
|
|
633
653
|
return 0;
|
|
634
654
|
}
|
|
635
655
|
async function diffCommand(args, io) {
|
|
@@ -654,11 +674,11 @@ async function verifyCommand(args, io) {
|
|
|
654
674
|
}
|
|
655
675
|
async function statusCommand(args, io) {
|
|
656
676
|
const loaded = loadPolicyFor(args, io, { allowMissingEnv: true });
|
|
657
|
-
const { guard
|
|
677
|
+
const { guard } = createFileGuard(loaded, { alerts: false, env: io.env });
|
|
658
678
|
const entries = readAuditFile(loaded.auditPath);
|
|
659
679
|
const runId = flagString(args, "run") ?? latestRunId(entries) ?? "(none yet)";
|
|
660
680
|
const status = await guard.status(runId);
|
|
661
|
-
const killed =
|
|
681
|
+
const killed = status.killed;
|
|
662
682
|
const reg = readRegistration(loaded);
|
|
663
683
|
const pending = await guard.approvals.list("pending");
|
|
664
684
|
if (flagBool(args, "json")) {
|
|
@@ -682,15 +702,11 @@ async function statusCommand(args, io) {
|
|
|
682
702
|
io.out(
|
|
683
703
|
`policy ${loaded.path} (mode: ${loaded.policy.mode}, ${loaded.policy.upstreams.length} upstreams)`
|
|
684
704
|
);
|
|
685
|
-
io.out(
|
|
686
|
-
|
|
687
|
-
);
|
|
688
|
-
io.out(
|
|
689
|
-
`http ${reg ? `${reg.url} (pid ${reg.pid})` : "not running (agentguard proxy --http)"}`
|
|
690
|
-
);
|
|
705
|
+
io.out(`kill ${killed.killed ? `ON \u2014 ${killed.reason} (okgate resume to clear)` : "off"}`);
|
|
706
|
+
io.out(`http ${reg ? `${reg.url} (pid ${reg.pid})` : "not running (okgate proxy --http)"}`);
|
|
691
707
|
io.out(`audit ${entries.length} entries in ${loaded.auditPath}`);
|
|
692
708
|
io.out(
|
|
693
|
-
`pending ${pending.length} approval${pending.length === 1 ? "" : "s"}${pending.length ? ` \u2014
|
|
709
|
+
`pending ${pending.length} approval${pending.length === 1 ? "" : "s"}${pending.length ? ` \u2014 okgate approvals` : ""}`
|
|
694
710
|
);
|
|
695
711
|
io.out(`run ${runId}`);
|
|
696
712
|
const fmt = (scope) => Object.entries(status.caps[scope]).map(([k, limit]) => `${k} ${status.usage[scope][k] ?? 0}/${limit}`).join(" ") || "no caps";
|
|
@@ -700,41 +716,43 @@ async function statusCommand(args, io) {
|
|
|
700
716
|
}
|
|
701
717
|
|
|
702
718
|
// src/cli.ts
|
|
703
|
-
var proxyCommand = async (args, io) => (await import("./proxy-
|
|
704
|
-
var initCommand = async (args, io) => (await import("./init-
|
|
705
|
-
var toolsCommand = async (args, io) => (await import("./tools-
|
|
706
|
-
var auditCommand = async (args, io) => (await import("./audit-
|
|
707
|
-
var HELP = `
|
|
719
|
+
var proxyCommand = async (args, io) => (await import("./proxy-6GP63TLD.js")).proxyCommand(args, io);
|
|
720
|
+
var initCommand = async (args, io) => (await import("./init-MKPQU2JG.js")).initCommand(args, io);
|
|
721
|
+
var toolsCommand = async (args, io) => (await import("./tools-XS7PMTLT.js")).toolsCommand(args, io);
|
|
722
|
+
var auditCommand = async (args, io) => (await import("./audit-5LUDXZLG.js")).auditCommand(args, io);
|
|
723
|
+
var HELP = `okgate \u2014 MCP policy proxy for agents that touch production
|
|
708
724
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
725
|
+
${INSTALL} init
|
|
726
|
+
read your MCP config, write okgate.yaml (dry-run), route every server through the proxy
|
|
727
|
+
okgate report [--run id|--all] what this run did / would have destroyed / spent, where it was halted
|
|
728
|
+
okgate diff [--run id] record-by-record mutation diff from a dry run
|
|
729
|
+
okgate verify [audit.jsonl] prove the hash-chained audit log was not edited
|
|
730
|
+
okgate connect <key> [--write] point this machine at your hosted proxy (paid tiers)
|
|
714
731
|
|
|
715
|
-
|
|
716
|
-
check a coding agent's own shell commands and file edits against
|
|
732
|
+
okgate hooks install [--project|--user] [--client claude|codex|gemini|all]
|
|
733
|
+
check a coding agent's own shell commands and file edits against okgate.yaml (dry-run first);
|
|
717
734
|
irreversible commands (push, merge, publish, send, rm outside the repo) only on a turn a person typed
|
|
718
|
-
|
|
719
|
-
|
|
735
|
+
okgate hooks uninstall | status
|
|
736
|
+
okgate hook pre-tool-use what the installed hook runs (reads the harness's JSON on stdin)
|
|
720
737
|
|
|
721
|
-
|
|
738
|
+
okgate audit [--since 7d|30d|all] [--client claude|codex|all] [--json]
|
|
722
739
|
which rules in CLAUDE.md / AGENTS.md / GEMINI.md / .cursor/rules your coding agents broke,
|
|
723
740
|
from this machine's Claude Code and Codex sessions in this repo (nothing is sent anywhere)
|
|
724
|
-
|
|
725
|
-
write the checkable rules into
|
|
741
|
+
okgate audit --enforce [--preview]
|
|
742
|
+
write the checkable rules into okgate.yaml as hook rules, in dry-run, and install the hook
|
|
726
743
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
744
|
+
okgate proxy [--http --port 8788] [--agent name] [--run-id id] [--mode dry-run|enforce]
|
|
745
|
+
okgate tools [--json] the tools your agent will see, with class and why
|
|
746
|
+
okgate status [--run id] counters vs caps, kill state, pending approvals
|
|
730
747
|
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
748
|
+
okgate kill [reason] halt every run now (file + running HTTP proxy); okgate resume
|
|
749
|
+
okgate approvals [--all] pending approvals; okgate approve <id> | deny <id> [--note text]
|
|
750
|
+
okgate key create <agent> [--allow 'crm_get_*']... [--deny p] [--writes n] [--spend n] [--mode m]
|
|
751
|
+
okgate key list | revoke <agent>
|
|
752
|
+
okgate permission-diff [--base ref] [--head ref] [--paths a,b] [--format markdown|json] [--fail-on-widen]
|
|
736
753
|
|
|
737
|
-
Options: --config <
|
|
754
|
+
Options: --config <okgate.yaml> (or OKGATE_CONFIG), --json, --help, --version
|
|
755
|
+
Renamed from agentguard: agentguard.yaml, .agentguard/, AGENTGUARD_* and the agentguard bin keep working.
|
|
738
756
|
Docs: https://github.com/agentwares/agentguard/tree/main/apps/agentguard-cli`;
|
|
739
757
|
async function main(argv, io = defaultIo()) {
|
|
740
758
|
const args = parseArgs(argv);
|
|
@@ -805,7 +823,8 @@ async function main(argv, io = defaultIo()) {
|
|
|
805
823
|
return 1;
|
|
806
824
|
}
|
|
807
825
|
}
|
|
808
|
-
var
|
|
826
|
+
var embedded = globalThis[/* @__PURE__ */ Symbol.for("okgate.cli.embedded")] === true;
|
|
827
|
+
var isMain = !embedded && process.argv[1] !== void 0 && /(^|[\\/])(cli\.[cm]?[jt]s|okgate|agentguard)$/.test(process.argv[1]);
|
|
809
828
|
if (isMain) {
|
|
810
829
|
main(process.argv.slice(2)).then(
|
|
811
830
|
(code) => {
|
|
@@ -825,4 +844,4 @@ export {
|
|
|
825
844
|
HELP,
|
|
826
845
|
main
|
|
827
846
|
};
|
|
828
|
-
//# sourceMappingURL=chunk-
|
|
847
|
+
//# sourceMappingURL=chunk-ZG4LGUJE.js.map
|