@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.
Files changed (62) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/audit-5LUDXZLG.js +18 -0
  3. package/dist/chunk-2QDPPTPY.js +179 -0
  4. package/dist/chunk-2QDPPTPY.js.map +1 -0
  5. package/dist/{chunk-SUXQTT3X.js → chunk-4WTFMFRY.js} +18 -16
  6. package/dist/chunk-4WTFMFRY.js.map +1 -0
  7. package/dist/{chunk-VQWQ5TOM.js → chunk-DEVXG3IB.js} +4 -4
  8. package/dist/chunk-DEVXG3IB.js.map +1 -0
  9. package/dist/chunk-F73VDY3W.js +202 -0
  10. package/dist/chunk-F73VDY3W.js.map +1 -0
  11. package/dist/{chunk-X4M7YWQA.js → chunk-IEJK7N3B.js} +32 -27
  12. package/dist/chunk-IEJK7N3B.js.map +1 -0
  13. package/dist/{chunk-ZSLWPKXI.js → chunk-IS3DAHZI.js} +562 -8
  14. package/dist/chunk-IS3DAHZI.js.map +1 -0
  15. package/dist/{chunk-KRKZGAJ3.js → chunk-JSELR4SG.js} +66 -55
  16. package/dist/chunk-JSELR4SG.js.map +1 -0
  17. package/dist/{chunk-TW5KJREH.js → chunk-OM5L7A32.js} +20 -11
  18. package/dist/chunk-OM5L7A32.js.map +1 -0
  19. package/dist/{chunk-HPYZ3JDX.js → chunk-SWZQMPDG.js} +3 -3
  20. package/dist/{chunk-HPYZ3JDX.js.map → chunk-SWZQMPDG.js.map} +1 -1
  21. package/dist/{chunk-D66U3PVB.js → chunk-TJXZBOHL.js} +6 -6
  22. package/dist/chunk-TJXZBOHL.js.map +1 -0
  23. package/dist/{chunk-BKXXTWIS.js → chunk-XOBFANL4.js} +5 -5
  24. package/dist/chunk-XOBFANL4.js.map +1 -0
  25. package/dist/chunk-XPNBYSIN.js +23 -0
  26. package/dist/chunk-XPNBYSIN.js.map +1 -0
  27. package/dist/{chunk-6S7LYVOC.js → chunk-YBVD6HTT.js} +27 -24
  28. package/dist/chunk-YBVD6HTT.js.map +1 -0
  29. package/dist/{chunk-6TUQD666.js → chunk-ZG4LGUJE.js} +100 -81
  30. package/dist/chunk-ZG4LGUJE.js.map +1 -0
  31. package/dist/cli.js +6 -4
  32. package/dist/fixtures/crm-server.js +2 -2
  33. package/dist/fixtures/demo-agent.js +1 -1
  34. package/dist/index.d.ts +5 -5
  35. package/dist/index.js +23 -21
  36. package/dist/index.js.map +1 -1
  37. package/dist/init-MKPQU2JG.js +17 -0
  38. package/dist/{proxy-3Z5YEZ4R.js → proxy-6GP63TLD.js} +21 -29
  39. package/dist/proxy-6GP63TLD.js.map +1 -0
  40. package/dist/tools-XS7PMTLT.js +15 -0
  41. package/llms.txt +8 -6
  42. package/package.json +10 -4
  43. package/server.json +9 -9
  44. package/dist/audit-2YCMHMCP.js +0 -17
  45. package/dist/chunk-3O6KWT3E.js +0 -345
  46. package/dist/chunk-3O6KWT3E.js.map +0 -1
  47. package/dist/chunk-6S7LYVOC.js.map +0 -1
  48. package/dist/chunk-6TUQD666.js.map +0 -1
  49. package/dist/chunk-BKXXTWIS.js.map +0 -1
  50. package/dist/chunk-D66U3PVB.js.map +0 -1
  51. package/dist/chunk-KRKZGAJ3.js.map +0 -1
  52. package/dist/chunk-SUXQTT3X.js.map +0 -1
  53. package/dist/chunk-TW5KJREH.js.map +0 -1
  54. package/dist/chunk-VQWQ5TOM.js.map +0 -1
  55. package/dist/chunk-X4M7YWQA.js.map +0 -1
  56. package/dist/chunk-ZSLWPKXI.js.map +0 -1
  57. package/dist/init-CWROGV5I.js +0 -15
  58. package/dist/proxy-3Z5YEZ4R.js.map +0 -1
  59. package/dist/tools-3LLDG3XQ.js +0 -15
  60. /package/dist/{audit-2YCMHMCP.js.map → audit-5LUDXZLG.js.map} +0 -0
  61. /package/dist/{init-CWROGV5I.js.map → init-MKPQU2JG.js.map} +0 -0
  62. /package/dist/{tools-3LLDG3XQ.js.map → tools-XS7PMTLT.js.map} +0 -0
@@ -0,0 +1,202 @@
1
+ import {
2
+ CLIENT_ALIASES,
3
+ hookTarget,
4
+ installHook,
5
+ installedHandlers,
6
+ uninstallHook
7
+ } from "./chunk-2QDPPTPY.js";
8
+ import {
9
+ npxCommand
10
+ } from "./chunk-XPNBYSIN.js";
11
+ import {
12
+ flagBool,
13
+ flagList,
14
+ flagNumber,
15
+ flagString,
16
+ homeFrom,
17
+ version
18
+ } from "./chunk-4WTFMFRY.js";
19
+
20
+ // src/commands/hooks.ts
21
+ import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
22
+ import { dirname, join, relative, resolve } from "path";
23
+ import {
24
+ LEGACY_POLICY_FILE,
25
+ LEGACY_STATE_DIR,
26
+ POLICY_FILE,
27
+ STATE_DIR
28
+ } from "@agentwares/agentguard-core";
29
+ import { findPolicyFile } from "@agentwares/agentguard-core/node";
30
+ function userPolicyPath(home) {
31
+ const next = join(home, STATE_DIR, POLICY_FILE);
32
+ const legacy = join(home, LEGACY_STATE_DIR, LEGACY_POLICY_FILE);
33
+ return !existsSync(next) && existsSync(legacy) ? legacy : next;
34
+ }
35
+ var HOOKS_POLICY_BLOCK = `
36
+ # Hook mode: your coding agent's own shell commands and file edits (Claude Code, Codex, Gemini CLI),
37
+ # checked before they run. \`okgate hooks install\` wired it; \`okgate report\` shows the decisions.
38
+ hooks:
39
+ # dry-run: every decision is logged and nothing is blocked. Read \`okgate report\`, then set
40
+ # enforce. The kill switch (\`okgate kill\`) stops guarded calls in both modes.
41
+ mode: dry-run
42
+ # Irreversible commands run only on a turn a person typed: after the session's previous
43
+ # irreversible command, recent, and naming the action ("push it", or "yes" to "shall I push?").
44
+ # Text the model writes, tool output and injected messages never count. Otherwise the agent
45
+ # gets APPROVAL_REQUIRED and an id; \`okgate approve <id>\` lets that exact command run once.
46
+ # Built in: git-push, merge, tag-delete, rm-outside-workspace, publish, send, guard-config.
47
+ irreversible:
48
+ builtins: true
49
+ window_s: 1800 # the authorizing turn is at most 30 minutes old
50
+ require_mention: true # ...and names the action
51
+ require_origin: false # true: only entries Claude Code labels as typed by a person
52
+ mentions: {} # extra words per class, e.g. { git-push: [deploy] }
53
+ rules: []
54
+ # - name: deploy
55
+ # shell: ["vercel --prod*", "fly deploy*"]
56
+ # mentions: [deploy]
57
+ shell:
58
+ deny: [] # e.g. ["terraform destroy*", "curl * | sh"]
59
+ approval: [] # e.g. ["kubectl delete *"]
60
+ paths:
61
+ deny: [] # e.g. [".env", "*.pem"]
62
+ approval: [] # e.g. ["**/migrations/**"]
63
+ `;
64
+ function renderHooksStarterPolicy(generatedAt = /* @__PURE__ */ new Date()) {
65
+ return `# okgate.yaml \u2014 generated by \`okgate hooks install\` on ${generatedAt.toISOString().slice(0, 10)}
66
+ # Docs: https://github.com/agentwares/agentguard/tree/main/apps/agentguard-cli#hook-mode-a-coding-agents-own-commands
67
+ version: 1
68
+
69
+ # MCP proxy mode (okgate init) reads upstreams; hook mode needs none.
70
+ mode: dry-run
71
+ upstreams: []
72
+ ${HOOKS_POLICY_BLOCK}
73
+ # Kill switch: \`okgate kill\` creates this file; every guarded call is refused until
74
+ # \`okgate resume\`. OKGATE_KILL=1 (or AGENTGUARD_KILL=1) in the environment does the same.
75
+ kill:
76
+ file: .okgate/KILL
77
+
78
+ # Hash-chained JSONL of every decision; \`okgate verify\` proves it was not edited.
79
+ audit:
80
+ path: .okgate/audit.jsonl
81
+ redact: true
82
+ `;
83
+ }
84
+ function quoteArg(arg) {
85
+ return /^[A-Za-z0-9_@%+=:,./-]+$/.test(arg) ? arg : JSON.stringify(arg);
86
+ }
87
+ function clientsFrom(args) {
88
+ const names = flagList(args, "client");
89
+ if (names.length === 0) return ["claude-code"];
90
+ if (names.includes("all")) return ["claude-code", "codex", "gemini-cli"];
91
+ return names.map((n) => {
92
+ const c = CLIENT_ALIASES[n.trim()];
93
+ if (!c) throw new Error(`unknown --client "${n}" (claude, codex, gemini or all)`);
94
+ return c;
95
+ });
96
+ }
97
+ function hasTopLevelHooks(yamlText) {
98
+ return /^hooks\s*:/m.test(yamlText);
99
+ }
100
+ async function hooksCommand(args, io) {
101
+ const sub = args.positionals[0] ?? "status";
102
+ const scope = flagBool(args, "user") ? "user" : "project";
103
+ const home = homeFrom(io);
104
+ const where = { cwd: io.cwd, home };
105
+ const rel = (p) => {
106
+ const r = relative(io.cwd, p);
107
+ return r.startsWith("..") ? p : r || ".";
108
+ };
109
+ const clients = clientsFrom(args);
110
+ const named = flagString(args, "config");
111
+ const policyPath = named !== void 0 ? resolve(io.cwd, named) : scope === "user" ? userPolicyPath(home) : findPolicyFile(io.cwd);
112
+ const base = flagString(args, "command") ?? npxCommand(version());
113
+ const commandFor = (client) => {
114
+ let cmd = `${base} hook pre-tool-use --client ${client === "claude-code" ? "claude" : client === "gemini-cli" ? "gemini" : "codex"}`;
115
+ if (flagString(args, "config")) cmd += ` --config ${quoteArg(policyPath)}`;
116
+ else if (scope === "user") cmd += ` --fallback-config ${quoteArg(policyPath)}`;
117
+ return cmd;
118
+ };
119
+ const timeoutS = Math.max(30, flagNumber(args, "timeout") ?? 30);
120
+ if (sub === "install") {
121
+ if (!existsSync(policyPath)) {
122
+ mkdirSync(dirname(policyPath), { recursive: true });
123
+ writeFileSync(policyPath, renderHooksStarterPolicy());
124
+ io.out(`wrote ${rel(policyPath)} (hooks.mode: dry-run)`);
125
+ } else if (!hasTopLevelHooks(readFileSync(policyPath, "utf8"))) {
126
+ appendFileSync(policyPath, HOOKS_POLICY_BLOCK);
127
+ io.out(`added a hooks: block to ${rel(policyPath)} (hooks.mode: dry-run)`);
128
+ } else io.out(`kept ${rel(policyPath)} (it already has a hooks: block)`);
129
+ for (const client of clients) {
130
+ const target = hookTarget(client, scope, where, commandFor(client), timeoutS);
131
+ const { status, backup } = installHook(target);
132
+ const verb = status === "unchanged" ? "kept " : status === "updated" ? "updated" : "added ";
133
+ io.out(
134
+ `${verb} ${target.label} ${target.event} hook in ${rel(target.settingsPath)}${backup ? ` (backup: ${rel(backup)})` : ""}`
135
+ );
136
+ if (target.note) io.out(` ${target.note}`);
137
+ }
138
+ if (scope === "project" && existsSync(join(io.cwd, ".git"))) {
139
+ const gitignore = join(io.cwd, ".gitignore");
140
+ const text = existsSync(gitignore) ? readFileSync(gitignore, "utf8") : "";
141
+ if (!/^\/?\.okgate\/?$/m.test(text)) {
142
+ appendFileSync(gitignore, `${text && !text.endsWith("\n") ? "\n" : ""}.okgate/
143
+ `);
144
+ io.out(`added .okgate/ to .gitignore (approvals, counters and the audit log stay local)`);
145
+ }
146
+ }
147
+ io.out("");
148
+ io.out("Next:");
149
+ io.out(" 1. start a new session of your coding agent (hooks are read at start)");
150
+ io.out(" 2. work as usual \u2014 hooks.mode is dry-run: decisions are logged, nothing is blocked");
151
+ io.out(" 3. okgate report # what enforce mode would have stopped, and why");
152
+ io.out(` 4. set \`hooks.mode: enforce\` in ${rel(policyPath)} when it looks right`);
153
+ io.out(" undo: okgate hooks uninstall" + (scope === "user" ? " --user" : ""));
154
+ return 0;
155
+ }
156
+ if (sub === "uninstall") {
157
+ let total = 0;
158
+ for (const client of flagString(args, "client") ? clients : ["claude-code", "codex", "gemini-cli"]) {
159
+ const target = hookTarget(client, scope, where, commandFor(client), timeoutS);
160
+ const removed = uninstallHook(target);
161
+ total += removed;
162
+ if (removed) io.out(`removed ${target.label} hook from ${rel(target.settingsPath)}`);
163
+ }
164
+ if (total === 0) io.out(`no okgate hooks in ${scope}-level settings`);
165
+ else
166
+ io.out(
167
+ `kept ${rel(policyPath)} and its state directory (${STATE_DIR}/ or ${LEGACY_STATE_DIR}/); delete them yourself if you want them gone`
168
+ );
169
+ return 0;
170
+ }
171
+ if (sub === "status") {
172
+ for (const s of ["project", "user"]) {
173
+ for (const client of ["claude-code", "codex", "gemini-cli"]) {
174
+ const target = hookTarget(client, s, where, "", timeoutS);
175
+ let handlers;
176
+ try {
177
+ handlers = installedHandlers(target);
178
+ } catch (err) {
179
+ io.out(
180
+ `${s.padEnd(7)} ${target.label.padEnd(11)} unreadable: ${err instanceof Error ? err.message : String(err)}`
181
+ );
182
+ continue;
183
+ }
184
+ io.out(
185
+ `${s.padEnd(7)} ${target.label.padEnd(11)} ${handlers.length ? `installed: ${String(handlers[0].command)}` : "\u2014"} (${rel(target.settingsPath)})`
186
+ );
187
+ }
188
+ }
189
+ return 0;
190
+ }
191
+ io.err(
192
+ "usage: okgate hooks install|uninstall|status [--project|--user] [--client claude|codex|gemini|all] [--command cmd] [--config path]"
193
+ );
194
+ return 1;
195
+ }
196
+
197
+ export {
198
+ HOOKS_POLICY_BLOCK,
199
+ renderHooksStarterPolicy,
200
+ hooksCommand
201
+ };
202
+ //# sourceMappingURL=chunk-F73VDY3W.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/hooks.ts"],"sourcesContent":["/**\n * `okgate hooks install|uninstall|status [--project|--user] [--client claude|codex|gemini]`\n *\n * Install writes the coding agent's pre-execution hook entry (Claude Code `PreToolUse`, Codex\n * `PreToolUse`, Gemini CLI `BeforeTool`) pointing at `okgate hook pre-tool-use`, and makes\n * sure the policy has a `hooks:` block in dry-run. Uninstall removes only okgate's entries.\n */\nimport { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, relative, resolve } from \"node:path\";\nimport {\n LEGACY_POLICY_FILE,\n LEGACY_STATE_DIR,\n POLICY_FILE,\n STATE_DIR,\n type HookClient,\n} from \"@agentwares/agentguard-core\";\nimport { findPolicyFile } from \"@agentwares/agentguard-core/node\";\nimport { flagBool, flagList, flagNumber, flagString, type ParsedArgs } from \"../args.js\";\nimport { homeFrom, type Io } from \"../context.js\";\nimport {\n CLIENT_ALIASES,\n hookTarget,\n installHook,\n installedHandlers,\n uninstallHook,\n type InstallScope,\n} from \"../hooks/clients.js\";\nimport { npxCommand } from \"../install.js\";\nimport { version } from \"../version.js\";\n\n/** `~/.okgate/okgate.yaml`, or the `~/.agentguard/agentguard.yaml` an earlier install wrote. */\nexport function userPolicyPath(home: string): string {\n const next = join(home, STATE_DIR, POLICY_FILE);\n const legacy = join(home, LEGACY_STATE_DIR, LEGACY_POLICY_FILE);\n return !existsSync(next) && existsSync(legacy) ? legacy : next;\n}\n\n/** The commented `hooks:` block: the file people read, so every knob explains itself. */\nexport const HOOKS_POLICY_BLOCK = `\n# Hook mode: your coding agent's own shell commands and file edits (Claude Code, Codex, Gemini CLI),\n# checked before they run. \\`okgate hooks install\\` wired it; \\`okgate report\\` shows the decisions.\nhooks:\n # dry-run: every decision is logged and nothing is blocked. Read \\`okgate report\\`, then set\n # enforce. The kill switch (\\`okgate kill\\`) stops guarded calls in both modes.\n mode: dry-run\n # Irreversible commands run only on a turn a person typed: after the session's previous\n # irreversible command, recent, and naming the action (\"push it\", or \"yes\" to \"shall I push?\").\n # Text the model writes, tool output and injected messages never count. Otherwise the agent\n # gets APPROVAL_REQUIRED and an id; \\`okgate approve <id>\\` lets that exact command run once.\n # Built in: git-push, merge, tag-delete, rm-outside-workspace, publish, send, guard-config.\n irreversible:\n builtins: true\n window_s: 1800 # the authorizing turn is at most 30 minutes old\n require_mention: true # ...and names the action\n require_origin: false # true: only entries Claude Code labels as typed by a person\n mentions: {} # extra words per class, e.g. { git-push: [deploy] }\n rules: []\n # - name: deploy\n # shell: [\"vercel --prod*\", \"fly deploy*\"]\n # mentions: [deploy]\n shell:\n deny: [] # e.g. [\"terraform destroy*\", \"curl * | sh\"]\n approval: [] # e.g. [\"kubectl delete *\"]\n paths:\n deny: [] # e.g. [\".env\", \"*.pem\"]\n approval: [] # e.g. [\"**/migrations/**\"]\n`;\n\n/** A policy for a project that has no okgate.yaml yet: hooks only, no MCP upstreams. */\nexport function renderHooksStarterPolicy(generatedAt = new Date()): string {\n return `# okgate.yaml — generated by \\`okgate hooks install\\` on ${generatedAt.toISOString().slice(0, 10)}\n# Docs: https://github.com/agentwares/agentguard/tree/main/apps/agentguard-cli#hook-mode-a-coding-agents-own-commands\nversion: 1\n\n# MCP proxy mode (okgate init) reads upstreams; hook mode needs none.\nmode: dry-run\nupstreams: []\n${HOOKS_POLICY_BLOCK}\n# Kill switch: \\`okgate kill\\` creates this file; every guarded call is refused until\n# \\`okgate resume\\`. OKGATE_KILL=1 (or AGENTGUARD_KILL=1) in the environment does the same.\nkill:\n file: .okgate/KILL\n\n# Hash-chained JSONL of every decision; \\`okgate verify\\` proves it was not edited.\naudit:\n path: .okgate/audit.jsonl\n redact: true\n`;\n}\n\nfunction quoteArg(arg: string): string {\n return /^[A-Za-z0-9_@%+=:,./-]+$/.test(arg) ? arg : JSON.stringify(arg);\n}\n\nfunction clientsFrom(args: ParsedArgs): HookClient[] {\n const names = flagList(args, \"client\");\n if (names.length === 0) return [\"claude-code\"];\n if (names.includes(\"all\")) return [\"claude-code\", \"codex\", \"gemini-cli\"];\n return names.map((n) => {\n const c = CLIENT_ALIASES[n.trim()];\n if (!c) throw new Error(`unknown --client \"${n}\" (claude, codex, gemini or all)`);\n return c;\n });\n}\n\nfunction hasTopLevelHooks(yamlText: string): boolean {\n return /^hooks\\s*:/m.test(yamlText);\n}\n\nexport async function hooksCommand(args: ParsedArgs, io: Io): Promise<number> {\n const sub = args.positionals[0] ?? \"status\";\n const scope: InstallScope = flagBool(args, \"user\") ? \"user\" : \"project\";\n const home = homeFrom(io);\n const where = { cwd: io.cwd, home };\n const rel = (p: string): string => {\n const r = relative(io.cwd, p);\n return r.startsWith(\"..\") ? p : r || \".\";\n };\n const clients = clientsFrom(args);\n const named = flagString(args, \"config\");\n const policyPath =\n named !== undefined\n ? resolve(io.cwd, named)\n : scope === \"user\"\n ? userPolicyPath(home)\n : findPolicyFile(io.cwd);\n const base = flagString(args, \"command\") ?? npxCommand(version());\n const commandFor = (client: HookClient): string => {\n let cmd = `${base} hook pre-tool-use --client ${client === \"claude-code\" ? \"claude\" : client === \"gemini-cli\" ? \"gemini\" : \"codex\"}`;\n if (flagString(args, \"config\")) cmd += ` --config ${quoteArg(policyPath)}`;\n else if (scope === \"user\") cmd += ` --fallback-config ${quoteArg(policyPath)}`;\n return cmd;\n };\n const timeoutS = Math.max(30, flagNumber(args, \"timeout\") ?? 30);\n\n if (sub === \"install\") {\n // the policy first: a hook with no policy to read guards nothing\n if (!existsSync(policyPath)) {\n mkdirSync(dirname(policyPath), { recursive: true });\n writeFileSync(policyPath, renderHooksStarterPolicy());\n io.out(`wrote ${rel(policyPath)} (hooks.mode: dry-run)`);\n } else if (!hasTopLevelHooks(readFileSync(policyPath, \"utf8\"))) {\n appendFileSync(policyPath, HOOKS_POLICY_BLOCK);\n io.out(`added a hooks: block to ${rel(policyPath)} (hooks.mode: dry-run)`);\n } else io.out(`kept ${rel(policyPath)} (it already has a hooks: block)`);\n\n for (const client of clients) {\n const target = hookTarget(client, scope, where, commandFor(client), timeoutS);\n const { status, backup } = installHook(target);\n const verb =\n status === \"unchanged\" ? \"kept \" : status === \"updated\" ? \"updated\" : \"added \";\n io.out(\n `${verb} ${target.label} ${target.event} hook in ${rel(target.settingsPath)}${backup ? ` (backup: ${rel(backup)})` : \"\"}`,\n );\n if (target.note) io.out(` ${target.note}`);\n }\n\n if (scope === \"project\" && existsSync(join(io.cwd, \".git\"))) {\n const gitignore = join(io.cwd, \".gitignore\");\n const text = existsSync(gitignore) ? readFileSync(gitignore, \"utf8\") : \"\";\n if (!/^\\/?\\.okgate\\/?$/m.test(text)) {\n appendFileSync(gitignore, `${text && !text.endsWith(\"\\n\") ? \"\\n\" : \"\"}.okgate/\\n`);\n io.out(`added .okgate/ to .gitignore (approvals, counters and the audit log stay local)`);\n }\n }\n\n io.out(\"\");\n io.out(\"Next:\");\n io.out(\" 1. start a new session of your coding agent (hooks are read at start)\");\n io.out(\" 2. work as usual — hooks.mode is dry-run: decisions are logged, nothing is blocked\");\n io.out(\" 3. okgate report # what enforce mode would have stopped, and why\");\n io.out(` 4. set \\`hooks.mode: enforce\\` in ${rel(policyPath)} when it looks right`);\n io.out(\" undo: okgate hooks uninstall\" + (scope === \"user\" ? \" --user\" : \"\"));\n return 0;\n }\n\n if (sub === \"uninstall\") {\n let total = 0;\n for (const client of flagString(args, \"client\")\n ? clients\n : ([\"claude-code\", \"codex\", \"gemini-cli\"] as HookClient[])) {\n const target = hookTarget(client, scope, where, commandFor(client), timeoutS);\n const removed = uninstallHook(target);\n total += removed;\n if (removed) io.out(`removed ${target.label} hook from ${rel(target.settingsPath)}`);\n }\n if (total === 0) io.out(`no okgate hooks in ${scope}-level settings`);\n else\n io.out(\n `kept ${rel(policyPath)} and its state directory (${STATE_DIR}/ or ${LEGACY_STATE_DIR}/); delete them yourself if you want them gone`,\n );\n return 0;\n }\n\n if (sub === \"status\") {\n for (const s of [\"project\", \"user\"] as InstallScope[]) {\n for (const client of [\"claude-code\", \"codex\", \"gemini-cli\"] as HookClient[]) {\n const target = hookTarget(client, s, where, \"\", timeoutS);\n let handlers: Record<string, unknown>[];\n try {\n handlers = installedHandlers(target);\n } catch (err) {\n io.out(\n `${s.padEnd(7)} ${target.label.padEnd(11)} unreadable: ${err instanceof Error ? err.message : String(err)}`,\n );\n continue;\n }\n io.out(\n `${s.padEnd(7)} ${target.label.padEnd(11)} ${handlers.length ? `installed: ${String(handlers[0]!.command)}` : \"—\"} (${rel(target.settingsPath)})`,\n );\n }\n }\n return 0;\n }\n\n io.err(\n \"usage: okgate hooks install|uninstall|status [--project|--user] [--client claude|codex|gemini|all] [--command cmd] [--config path]\",\n );\n return 1;\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,3 @@
1
- import {
2
- probeUpstreams
3
- } from "./chunk-VQWQ5TOM.js";
4
1
  import {
5
2
  describeConfigPath,
6
3
  detectClientConfigs,
@@ -8,13 +5,19 @@ import {
8
5
  restoreClientConfig,
9
6
  rewriteClientConfig,
10
7
  serversToUpstreams
11
- } from "./chunk-TW5KJREH.js";
8
+ } from "./chunk-OM5L7A32.js";
9
+ import {
10
+ probeUpstreams
11
+ } from "./chunk-DEVXG3IB.js";
12
+ import {
13
+ RUN
14
+ } from "./chunk-XPNBYSIN.js";
12
15
  import {
13
16
  flagBool,
14
17
  flagString,
15
18
  homeFrom,
16
19
  policyPathFrom
17
- } from "./chunk-SUXQTT3X.js";
20
+ } from "./chunk-4WTFMFRY.js";
18
21
 
19
22
  // src/commands/init.ts
20
23
  import { existsSync, writeFileSync } from "fs";
@@ -38,22 +41,22 @@ function renderStarterPolicy(opts) {
38
41
  (acc, t) => ({ ...acc, [t.classification.class]: (acc[t.classification.class] ?? 0) + 1 }),
39
42
  {}
40
43
  );
41
- const detected = tools.length === 0 ? ["# (no upstreams probed \u2014 run `agentguard tools` after fixing the upstreams above)"] : tools.map(
44
+ const detected = tools.length === 0 ? ["# (no upstreams probed \u2014 run `okgate tools` after fixing the upstreams above)"] : tools.map(
42
45
  (t) => `# ${t.name.padEnd(36)} ${t.classification.class.padEnd(8)} ${t.classification.verb.padEnd(8)} ${t.classification.source}: ${t.classification.reason}`
43
46
  );
44
47
  const probeNotes = (opts.probeErrors ?? []).map((e) => `# ! ${e}`);
45
48
  const upstreamsYaml = opts.upstreams.length ? dump({ upstreams: opts.upstreams.map(cleanUpstream) }) : 'upstreams: []\n # - name: crm\n # url: https://mcp.example.com/mcp\n # auth: ${CRM_TOKEN}\n # - name: files\n # command: npx\n # args: [-y, "@modelcontextprotocol/server-filesystem", "."]';
46
- return `# agentguard.yaml \u2014 generated by \`agentguard init\` on ${date}
49
+ return `# okgate.yaml \u2014 generated by \`okgate init\` on ${date}
47
50
  # Every knob is explained inline. Docs: https://github.com/agentwares/agentguard/tree/main/apps/agentguard-cli#policy
48
51
  version: 1
49
52
 
50
53
  # dry-run: reads pass through; writes and spends are FAKED (plausible success, nothing executes)
51
- # and recorded. Run your agent once, then \`agentguard report\` and \`agentguard diff\`.
54
+ # and recorded. Run your agent once, then \`okgate report\` and \`okgate diff\`.
52
55
  # Flip to \`enforce\` when the diff looks right. Caps and the loop breaker apply in both modes.
53
56
  mode: ${opts.mode ?? "dry-run"}
54
57
 
55
- # The servers your agent used to talk to directly. agentguard connects to them and holds their
56
- # credentials; your agent only talks to agentguard. Use \${ENV_VAR} for secrets.
58
+ # The servers your agent used to talk to directly. okgate connects to them and holds their
59
+ # credentials; your agent only talks to okgate. Use \${ENV_VAR} for secrets.
57
60
  ${upstreamsYaml}
58
61
 
59
62
  # Detected tools (${tools.length}${tools.length ? `: ${Object.entries(counts).map(([k, v]) => `${v} ${k}`).join(", ")}` : ""}):
@@ -100,7 +103,7 @@ dry_run:
100
103
  synthesize: true
101
104
 
102
105
  # Destructive actions that need a human. The agent gets APPROVAL_REQUIRED with an id; you run
103
- # \`agentguard approve <id>\` (or click the link in Slack); the agent retries the identical call once.
106
+ # \`okgate approve <id>\` (or click the link in Slack); the agent retries the identical call once.
104
107
  approval:
105
108
  tools: ${flow(destructive)}
106
109
  wait_s: 0 # > 0 holds the call open this long waiting for the decision
@@ -108,12 +111,12 @@ approval:
108
111
  # notify:
109
112
  # slack: \${SLACK_WEBHOOK_URL}
110
113
 
111
- # Kill switch: \`agentguard kill\` creates this file (or POST /kill on the HTTP proxy); every call
112
- # returns KILLED until \`agentguard resume\`. AGENTGUARD_KILL=1 in the environment does the same.
114
+ # Kill switch: \`okgate kill\` creates this file (or POST /kill on the HTTP proxy); every call
115
+ # returns KILLED until \`okgate resume\`. OKGATE_KILL=1 (or AGENTGUARD_KILL=1) in the environment does the same.
113
116
  kill:
114
- file: .agentguard/KILL
117
+ file: .okgate/KILL
115
118
 
116
- # Scoped agent keys for the HTTP proxy: \`agentguard key create deployer --allow 'crm_get_*'\`.
119
+ # Scoped agent keys for the HTTP proxy: \`okgate key create deployer --allow 'crm_get_*'\`.
117
120
  # Only the key's hash is stored here; the agent sends the key as a Bearer token.
118
121
  agents: []
119
122
 
@@ -122,9 +125,9 @@ agents: []
122
125
  # slack: \${SLACK_WEBHOOK_URL}
123
126
  # on: [LOOP_DETECTED, CAP_EXCEEDED, KILLED, APPROVAL_REQUIRED]
124
127
 
125
- # Hash-chained JSONL of every call; \`agentguard verify\` proves it was not edited.
128
+ # Hash-chained JSONL of every call; \`okgate verify\` proves it was not edited.
126
129
  audit:
127
- path: .agentguard/audit.jsonl
130
+ path: .okgate/audit.jsonl
128
131
  redact: true
129
132
  include_results: false
130
133
  `;
@@ -159,7 +162,9 @@ async function initCommand(args, io) {
159
162
  }
160
163
  }
161
164
  if (restored === 0)
162
- io.err("nothing to undo (no *.agentguard-backup files next to your MCP configs)");
165
+ io.err(
166
+ "nothing to undo (no *.okgate-backup or *.agentguard-backup files next to your MCP configs)"
167
+ );
163
168
  return 0;
164
169
  }
165
170
  const projectLevel = configs.filter((c) => c.path.startsWith(io.cwd + "/"));
@@ -171,7 +176,7 @@ async function initCommand(args, io) {
171
176
  if (!explicit && !flagBool(args, "all")) {
172
177
  for (const c of userLevel)
173
178
  io.out(
174
- `found ${c.path} (${c.label}, user-level) \u2014 not touched; pass --client ${JSON.stringify(c.path)} to route it through agentguard`
179
+ `found ${c.path} (${c.label}, user-level) \u2014 not touched; pass --client ${JSON.stringify(c.path)} to route it through okgate`
175
180
  );
176
181
  }
177
182
  if (!chosen.every((c) => existsSync(c.path))) {
@@ -195,7 +200,7 @@ async function initCommand(args, io) {
195
200
  for (const s of skipped) io.err(`skipped ${s.name}: ${s.reason}`);
196
201
  if (skipped.some((s) => s.reason.includes("already")) && upstreams.length === 0 && existsSync(policyPath)) {
197
202
  io.out(
198
- `already initialized: ${rel(policyPath)} exists and ${chosen.map((c) => rel(c.path)).join(", ")} already points at agentguard`
203
+ `already initialized: ${rel(policyPath)} exists and ${chosen.map((c) => rel(c.path)).join(", ")} already points at okgate`
199
204
  );
200
205
  return 0;
201
206
  }
@@ -213,7 +218,7 @@ async function initCommand(args, io) {
213
218
  if (u.connected) io.out(` ${u.name}: ${u.tools} tools`);
214
219
  else {
215
220
  io.err(
216
- ` ${u.name}: could not connect (${u.error}) \u2014 the proxy will keep retrying at start; fix the entry in agentguard.yaml`
221
+ ` ${u.name}: could not connect (${u.error}) \u2014 the proxy will keep retrying at start; fix the entry in okgate.yaml`
217
222
  );
218
223
  probeErrors.push(`${u.name}: ${u.error}`);
219
224
  }
@@ -236,14 +241,14 @@ async function initCommand(args, io) {
236
241
  for (const c of chosen) {
237
242
  if (resolve(c.path) === resolve(policyPath)) {
238
243
  throw new Error(
239
- `refusing: ${rel(c.path)} is both the policy file (--config) and a client config. Rewriting it would replace the policy with the proxy entry and leave the proxy pointing at itself. Use --config for the policy path and --client for the client's config, or let --config default to agentguard.yaml.`
244
+ `refusing: ${rel(c.path)} is both the policy file (--config) and a client config. Rewriting it would replace the policy with the proxy entry and leave the proxy pointing at itself. Use --config for the policy path and --client for the client's config, or let --config default to okgate.yaml.`
240
245
  );
241
246
  }
242
247
  const { backup, replaced } = rewriteClientConfig(c, policyPath, {
243
248
  agent: flagString(args, "agent")
244
249
  });
245
250
  io.out(
246
- `rewrote ${rel(c.path)} \u2192 ${replaced.length ? `${replaced.join(", ")} now go through` : "points at"} \`npx @agentwares/agentguard proxy\` (backup: ${rel(backup)})`
251
+ `rewrote ${rel(c.path)} \u2192 ${replaced.length ? `${replaced.join(", ")} now go through` : "points at"} \`${RUN} proxy\` (backup: ${rel(backup)})`
247
252
  );
248
253
  }
249
254
  }
@@ -255,11 +260,11 @@ async function initCommand(args, io) {
255
260
  io.out(
256
261
  ` 2. run your agent once \u2014 ${mode === "dry-run" ? "writes are faked; nothing executes upstream" : "enforce mode: caps, loop breaker and approvals are live"}`
257
262
  );
258
- io.out(" 3. agentguard report # what this run would have destroyed / spent");
259
- io.out(" agentguard diff # the record-by-record mutation diff");
263
+ io.out(" 3. okgate report # what this run would have destroyed / spent");
264
+ io.out(" okgate diff # the record-by-record mutation diff");
260
265
  if (mode === "dry-run")
261
266
  io.out(` 4. set \`mode: enforce\` in ${rel(policyPath)} when it looks right`);
262
- io.out(" undo any time: agentguard init --undo");
267
+ io.out(" undo any time: okgate init --undo");
263
268
  return 0;
264
269
  }
265
270
 
@@ -267,4 +272,4 @@ export {
267
272
  renderStarterPolicy,
268
273
  initCommand
269
274
  };
270
- //# sourceMappingURL=chunk-X4M7YWQA.js.map
275
+ //# sourceMappingURL=chunk-IEJK7N3B.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/init.ts"],"sourcesContent":["/**\n * `okgate init` — the 60-second install. Reads the agent's existing MCP config, probes the\n * servers, writes `okgate.yaml` (dry-run by default) and rewrites the config so everything\n * goes through the proxy. `--undo` restores the backup.\n */\nimport { existsSync, writeFileSync } from \"node:fs\";\nimport { relative, resolve } from \"node:path\";\nimport YAML from \"yaml\";\nimport { type Upstream } from \"@agentwares/agentguard-core\";\nimport { flagBool, flagString, type ParsedArgs } from \"../args.js\";\nimport {\n describeConfigPath,\n detectClientConfigs,\n readServers,\n restoreClientConfig,\n rewriteClientConfig,\n serversToUpstreams,\n type ClientConfigFile,\n} from \"../configs.js\";\nimport { homeFrom, policyPathFrom, type Io } from \"../context.js\";\nimport { RUN } from \"../install.js\";\nimport { probeUpstreams, type ProbedTool } from \"./tools.js\";\n\nexport interface StarterPolicyOptions {\n upstreams: Upstream[];\n tools?: ProbedTool[];\n mode?: \"dry-run\" | \"enforce\";\n generatedAt?: Date;\n probeErrors?: string[];\n}\n\nfunction dump(value: unknown, indent = 0): string {\n const text = YAML.stringify(value, { indent: 2, lineWidth: 100 }).trimEnd();\n const pad = \" \".repeat(indent);\n return text\n .split(\"\\n\")\n .map((l) => pad + l)\n .join(\"\\n\");\n}\n\nfunction flow(list: string[]): string {\n return list.length === 0 ? \"[]\" : `[${list.map((s) => JSON.stringify(s)).join(\", \")}]`;\n}\n\n/** The commented starter policy — the file people read, so every knob explains itself. */\nexport function renderStarterPolicy(opts: StarterPolicyOptions): string {\n const tools = opts.tools ?? [];\n const unknown = tools.filter((t) => t.classification.class === \"unknown\").map((t) => t.name);\n const destructive = tools\n .filter((t) => t.classification.destructive || t.classification.verb === \"delete\")\n .map((t) => t.name);\n const spend = tools.filter((t) => t.classification.class === \"spend\").map((t) => t.name);\n const date = (opts.generatedAt ?? new Date()).toISOString().slice(0, 10);\n const counts = tools.reduce<Record<string, number>>(\n (acc, t) => ({ ...acc, [t.classification.class]: (acc[t.classification.class] ?? 0) + 1 }),\n {},\n );\n const detected =\n tools.length === 0\n ? [\"# (no upstreams probed — run `okgate tools` after fixing the upstreams above)\"]\n : tools.map(\n (t) =>\n `# ${t.name.padEnd(36)} ${t.classification.class.padEnd(8)} ${t.classification.verb.padEnd(8)} ${t.classification.source}: ${t.classification.reason}`,\n );\n const probeNotes = (opts.probeErrors ?? []).map((e) => `# ! ${e}`);\n const upstreamsYaml = opts.upstreams.length\n ? dump({ upstreams: opts.upstreams.map(cleanUpstream) })\n : 'upstreams: []\\n # - name: crm\\n # url: https://mcp.example.com/mcp\\n # auth: ${CRM_TOKEN}\\n # - name: files\\n # command: npx\\n # args: [-y, \"@modelcontextprotocol/server-filesystem\", \".\"]';\n\n return `# okgate.yaml — generated by \\`okgate init\\` on ${date}\n# Every knob is explained inline. Docs: https://github.com/agentwares/agentguard/tree/main/apps/agentguard-cli#policy\nversion: 1\n\n# dry-run: reads pass through; writes and spends are FAKED (plausible success, nothing executes)\n# and recorded. Run your agent once, then \\`okgate report\\` and \\`okgate diff\\`.\n# Flip to \\`enforce\\` when the diff looks right. Caps and the loop breaker apply in both modes.\nmode: ${opts.mode ?? \"dry-run\"}\n\n# The servers your agent used to talk to directly. okgate connects to them and holds their\n# credentials; your agent only talks to okgate. Use \\${ENV_VAR} for secrets.\n${upstreamsYaml}\n\n# Detected tools (${tools.length}${\n tools.length\n ? `: ${Object.entries(counts)\n .map(([k, v]) => `${v} ${k}`)\n .join(\", \")}`\n : \"\"\n }):\n${[...detected, ...probeNotes].join(\"\\n\")}\n# readOnlyHint annotations and verb heuristics classify most tools. List anything that is wrong here;\n# these patterns win over annotations. \\`*\\` matches anything.\nclassify:\n read: []\n write: ${flow(unknown)}${unknown.length ? \" # could not be classified — treated as writes; move to read: if they only read\" : \"\"}\n spend: ${flow(spend)}\n unknown: write # a tool nobody can classify counts as a write (alternatives: read | block)\n\n# Blast-radius caps. The call that would exceed a cap gets CAP_EXCEEDED with the remaining budget.\n# \\`writes\\` counts every write or spend; \\`deletes\\`/\\`emails\\` count the subsets matched by \\`counters\\`.\ncaps:\n per_run:\n tool_calls: 400\n writes: 50\n deletes: 10\n emails: 5\n spend_usd: 25\n per_day:\n spend_usd: 200\n\n# Dollar amounts. Declare how to read the amount from a spend tool's arguments; results reporting\n# cost_usd / amount_usd are picked up automatically. Unknown spend tools cost \\`default_usd\\`.\nspend:\n tools: {}\n # stripe_create_charge: { amount_arg: amount, divisor: 100, currency_arg: currency }\n # openai_*: { fixed_usd: 0.01 }\n default_usd: 0\n\n# Semantic loop breaker: the same (tool, normalized arguments) ${3} times in the last 30 calls, or a\n# repeating A→B→A→B cycle, returns LOOP_DETECTED. Timestamps, ids and whitespace are ignored.\nloop:\n window: 30\n max_repeats: 3\n max_cycle_len: 4\n max_read_repeats: 10\n\n# Always fake these, even in enforce mode. Remove entries as you gain trust.\ndry_run:\n tools: []\n synthesize: true\n\n# Destructive actions that need a human. The agent gets APPROVAL_REQUIRED with an id; you run\n# \\`okgate approve <id>\\` (or click the link in Slack); the agent retries the identical call once.\napproval:\n tools: ${flow(destructive)}\n wait_s: 0 # > 0 holds the call open this long waiting for the decision\n ttl_s: 3600\n # notify:\n # slack: \\${SLACK_WEBHOOK_URL}\n\n# Kill switch: \\`okgate kill\\` creates this file (or POST /kill on the HTTP proxy); every call\n# returns KILLED until \\`okgate resume\\`. OKGATE_KILL=1 (or AGENTGUARD_KILL=1) in the environment does the same.\nkill:\n file: .okgate/KILL\n\n# Scoped agent keys for the HTTP proxy: \\`okgate key create deployer --allow 'crm_get_*'\\`.\n# Only the key's hash is stored here; the agent sends the key as a Bearer token.\nagents: []\n\n# Alerts on halts (Slack incoming webhook or any HTTPS endpoint; signed with X-Agentwares-Signature).\n# alerts:\n# slack: \\${SLACK_WEBHOOK_URL}\n# on: [LOOP_DETECTED, CAP_EXCEEDED, KILLED, APPROVAL_REQUIRED]\n\n# Hash-chained JSONL of every call; \\`okgate verify\\` proves it was not edited.\naudit:\n path: .okgate/audit.jsonl\n redact: true\n include_results: false\n`;\n}\n\nfunction cleanUpstream(u: Upstream): Record<string, unknown> {\n const out: Record<string, unknown> = { name: u.name };\n if (u.url) {\n out.url = u.url;\n if (Object.keys(u.headers).length) out.headers = u.headers;\n } else {\n out.command = u.command;\n if (u.args.length) out.args = u.args;\n if (Object.keys(u.env).length) out.env = u.env;\n if (u.cwd) out.cwd = u.cwd;\n }\n return out;\n}\n\nexport async function initCommand(args: ParsedArgs, io: Io): Promise<number> {\n const policyPath = policyPathFrom(args, io);\n const explicit = flagString(args, \"client\");\n const configs: ClientConfigFile[] = explicit\n ? [describeConfigPath(resolve(io.cwd, explicit))]\n : detectClientConfigs(io.cwd, homeFrom(io), io.env);\n const rel = (p: string): string => {\n const r = relative(io.cwd, p);\n return r.startsWith(\"..\") ? p : r || \".\";\n };\n\n if (flagBool(args, \"undo\")) {\n let restored = 0;\n for (const c of configs) {\n if (restoreClientConfig(c)) {\n io.out(`restored ${rel(c.path)} from backup`);\n restored += 1;\n }\n }\n if (restored === 0)\n io.err(\n \"nothing to undo (no *.okgate-backup or *.agentguard-backup files next to your MCP configs)\",\n );\n return 0;\n }\n\n // Only project-level configs are rewritten by default. User-level files (Claude Desktop,\n // ~/.cursor, Windsurf, ~/.claude.json) affect every project, so they need an explicit --client.\n const projectLevel = configs.filter((c) => c.path.startsWith(io.cwd + \"/\"));\n const userLevel = configs.filter((c) => !projectLevel.includes(c));\n let chosen: ClientConfigFile[];\n if (explicit) chosen = configs;\n else if (flagBool(args, \"all\")) chosen = configs;\n else chosen = projectLevel.slice(0, 1);\n if (!explicit && !flagBool(args, \"all\")) {\n for (const c of userLevel)\n io.out(\n `found ${c.path} (${c.label}, user-level) — not touched; pass --client ${JSON.stringify(c.path)} to route it through okgate`,\n );\n }\n if (!chosen.every((c) => existsSync(c.path))) {\n io.err(`no MCP config at ${chosen.map((c) => c.path).join(\", \")}`);\n return 1;\n }\n\n const servers: Record<string, ReturnType<typeof readServers>[string]> = {};\n for (const c of chosen) {\n const found = readServers(c);\n io.out(\n `found ${rel(c.path)} (${c.label}) → ${Object.keys(found).length} server${Object.keys(found).length === 1 ? \"\" : \"s\"}: ${Object.keys(found).join(\", \") || \"none\"}`,\n );\n for (const [name, entry] of Object.entries(found))\n if (!(name in servers)) servers[name] = entry;\n }\n if (chosen.length === 0)\n io.out(\n \"found no MCP config (Claude Code .mcp.json, Cursor, VS Code, Claude Desktop, Windsurf, Gemini CLI) — writing a policy with no upstreams\",\n );\n const { upstreams, skipped } = serversToUpstreams(servers);\n for (const s of skipped) io.err(`skipped ${s.name}: ${s.reason}`);\n if (\n skipped.some((s) => s.reason.includes(\"already\")) &&\n upstreams.length === 0 &&\n existsSync(policyPath)\n ) {\n io.out(\n `already initialized: ${rel(policyPath)} exists and ${chosen.map((c) => rel(c.path)).join(\", \")} already points at okgate`,\n );\n return 0;\n }\n\n let probed: ProbedTool[] = [];\n const probeErrors: string[] = [];\n if (flagBool(args, \"probe\") !== false && upstreams.length > 0) {\n io.out(`probing ${upstreams.length} upstream${upstreams.length === 1 ? \"\" : \"s\"}…`);\n const result = await probeUpstreams(upstreams, {\n log: () => undefined,\n env: io.env,\n timeoutMs: 20_000,\n });\n probed = result.tools;\n for (const u of result.upstreams) {\n if (u.connected) io.out(` ${u.name}: ${u.tools} tools`);\n else {\n io.err(\n ` ${u.name}: could not connect (${u.error}) — the proxy will keep retrying at start; fix the entry in okgate.yaml`,\n );\n probeErrors.push(`${u.name}: ${u.error}`);\n }\n }\n }\n\n const mode = (flagString(args, \"mode\") as \"dry-run\" | \"enforce\" | undefined) ?? \"dry-run\";\n if (existsSync(policyPath) && !flagBool(args, \"force\")) {\n io.out(`kept ${rel(policyPath)} (exists; pass --force to regenerate)`);\n } else {\n writeFileSync(policyPath, renderStarterPolicy({ upstreams, tools: probed, mode, probeErrors }));\n const counts = probed.reduce<Record<string, number>>(\n (acc, t) => ({ ...acc, [t.classification.class]: (acc[t.classification.class] ?? 0) + 1 }),\n {},\n );\n io.out(\n `wrote ${rel(policyPath)} (mode: ${mode}, ${upstreams.length} upstream${upstreams.length === 1 ? \"\" : \"s\"}${\n probed.length\n ? `, ${probed.length} tools: ${Object.entries(counts)\n .map(([k, v]) => `${v} ${k}`)\n .join(\", \")}`\n : \"\"\n })`,\n );\n }\n\n if (flagBool(args, \"rewrite\") !== false) {\n for (const c of chosen) {\n // `--config` names the policy file, and `--client` names the client's. Point both at the\n // same file — easy, because an MCP client's file is also called a config — and the\n // rewrite replaces the policy with the proxy entry and then points the proxy at that.\n // The upstreams survive only in the backup, and the proxy starts with nothing to guard.\n if (resolve(c.path) === resolve(policyPath)) {\n throw new Error(\n `refusing: ${rel(c.path)} is both the policy file (--config) and a client config. ` +\n `Rewriting it would replace the policy with the proxy entry and leave the proxy ` +\n `pointing at itself. Use --config for the policy path and --client for the ` +\n `client's config, or let --config default to okgate.yaml.`,\n );\n }\n const { backup, replaced } = rewriteClientConfig(c, policyPath, {\n agent: flagString(args, \"agent\"),\n });\n io.out(\n `rewrote ${rel(c.path)} → ${replaced.length ? `${replaced.join(\", \")} now go through` : \"points at\"} \\`${RUN} proxy\\` (backup: ${rel(backup)})`,\n );\n }\n }\n\n io.out(\"\");\n io.out(\"Next:\");\n io.out(\n ` 1. restart your MCP client so it re-reads ${chosen.map((c) => rel(c.path)).join(\", \") || \"its config\"}`,\n );\n io.out(\n ` 2. run your agent once — ${mode === \"dry-run\" ? \"writes are faked; nothing executes upstream\" : \"enforce mode: caps, loop breaker and approvals are live\"}`,\n );\n io.out(\" 3. okgate report # what this run would have destroyed / spent\");\n io.out(\" okgate diff # the record-by-record mutation diff\");\n if (mode === \"dry-run\")\n io.out(` 4. set \\`mode: enforce\\` in ${rel(policyPath)} when it looks right`);\n io.out(\" undo any time: okgate init --undo\");\n return 0;\n}\n"],"mappings":"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","names":[]}