@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
package/CHANGELOG.md CHANGED
@@ -3,6 +3,39 @@
3
3
  `@agentwares/agentguard`, the CLI and MCP proxy. A tag `agentguard-v<version>` publishes the
4
4
  GitHub Release for a version with its section below as the notes.
5
5
 
6
+ ## 0.1.10 — 2026-10-08
7
+
8
+ ### Changed
9
+
10
+ - **agentguard is now okgate.** "Nothing irreversible without an OK." The CLI calls itself
11
+ `okgate`, and npm serves it as a second bin of this package until `@agentwares/okgate` is
12
+ published: `npx -p @agentwares/agentguard okgate init`. Everything it writes from now on uses
13
+ the new names: `okgate.yaml`, `.okgate/`, `OKGATE_*`, the `okgate` MCP server entry, the
14
+ `okgate_get_status` / `okgate_get_report` / `okgate_verify_audit_log` tools, `X-Okgate-Key`,
15
+ and hook commands that run `npx -y -p @agentwares/agentguard@<version> okgate hook pre-tool-use`.
16
+ - The server registers in the MCP Registry as `io.github.agentwares/okgate` (`mcpName`).
17
+
18
+ ### Kept working (until at least 2027-01-15)
19
+
20
+ - The `agentguard` bin, and `npx @agentwares/agentguard`, which runs it.
21
+ - `agentguard.yaml` is read when there is no `okgate.yaml`, including walking up from a coding
22
+ agent's working directory; creating an `okgate.yaml` beside it counts as editing the guard.
23
+ - An existing `.agentguard/` stays the state directory when there is no `.okgate/`, so counters,
24
+ pending approvals and the audit log's hash chain carry on: `okgate verify` passes across the
25
+ rename. Both directories are the guard's own and refused to a coding agent.
26
+ - Each `AGENTGUARD_*` variable applies when its `OKGATE_*` twin is unset. **`AGENTGUARD_KILL=1`
27
+ and `OKGATE_KILL=1` both halt everything, whatever `kill.env` the policy names**, and a KILL
28
+ file under either directory halts; `okgate kill` writes both that exist and `resume` clears both.
29
+ - `hooks status`, `hooks uninstall` and `hooks install` recognise agentguard-era hook entries
30
+ (install replaces one, it never adds a second); `init` recognises the old `agentguard` MCP entry
31
+ and `init --undo` restores a `*.agentguard-backup`; `connect` replaces an `agentguard` entry.
32
+ - `tools/list` shows only `okgate_*`; a `tools/call` for an `agentguard_*` name runs its twin with
33
+ a deprecation note in `_meta["okgate/deprecation"]` until 2027-01-15, then answers
34
+ `TOOL_RENAMED` (`retryable: false`, with the new name in `fix`). Tool results carry the verdict
35
+ under `_meta.okgate` and, for the window, `_meta.agentguard`.
36
+ - `<!-- agentguard: … -->` inline checks, `X-Agentguard-Key`, and `_meta["agentguard/runId"]`.
37
+ - `permission-diff` (and the GitHub Action) diffs `okgate.yaml` and `agentguard.yaml` alike.
38
+
6
39
  ## 0.1.9 — 2026-10-07
7
40
 
8
41
  ### Added
@@ -0,0 +1,18 @@
1
+ import {
2
+ TEAM_HISTORY_LINE,
3
+ TEAM_HISTORY_URL,
4
+ auditCommand,
5
+ parseSince
6
+ } from "./chunk-YBVD6HTT.js";
7
+ import "./chunk-F73VDY3W.js";
8
+ import "./chunk-2QDPPTPY.js";
9
+ import "./chunk-XPNBYSIN.js";
10
+ import "./chunk-4WTFMFRY.js";
11
+ import "./chunk-5WRI5ZAA.js";
12
+ export {
13
+ TEAM_HISTORY_LINE,
14
+ TEAM_HISTORY_URL,
15
+ auditCommand,
16
+ parseSince
17
+ };
18
+ //# sourceMappingURL=audit-5LUDXZLG.js.map
@@ -0,0 +1,179 @@
1
+ // src/hooks/clients.ts
2
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
3
+ import { dirname, join } from "path";
4
+ import {
5
+ LEGACY_POLICY_FILE,
6
+ LEGACY_STATE_DIR,
7
+ POLICY_FILE,
8
+ STATE_DIR
9
+ } from "@agentwares/agentguard-core";
10
+ var MATCHERS = {
11
+ "claude-code": "^(Bash|PowerShell|Write|Edit|MultiEdit|NotebookEdit)$|^mcp__",
12
+ codex: "^(Bash|apply_patch)$|^mcp__",
13
+ "gemini-cli": "^(run_shell_command|write_file|replace)$|^mcp_"
14
+ };
15
+ var CLIENT_ALIASES = {
16
+ claude: "claude-code",
17
+ "claude-code": "claude-code",
18
+ codex: "codex",
19
+ gemini: "gemini-cli",
20
+ "gemini-cli": "gemini-cli"
21
+ };
22
+ function hookTarget(client, scope, where, command, timeoutS = 30) {
23
+ const root = scope === "project" ? where.cwd : where.home;
24
+ if (client === "claude-code")
25
+ return {
26
+ client,
27
+ label: "Claude Code",
28
+ scope,
29
+ settingsPath: join(root, ".claude", "settings.json"),
30
+ event: "PreToolUse",
31
+ matcher: MATCHERS[client],
32
+ handler: { type: "command", command, timeout: timeoutS, statusMessage: "okgate" }
33
+ };
34
+ if (client === "codex")
35
+ return {
36
+ client,
37
+ label: "Codex CLI",
38
+ scope,
39
+ settingsPath: join(root, ".codex", "hooks.json"),
40
+ event: "PreToolUse",
41
+ matcher: MATCHERS[client],
42
+ handler: { type: "command", command, timeout: timeoutS, statusMessage: "okgate" },
43
+ note: "Codex runs a new hook only after you trust it: open /hooks in Codex and trust the okgate entry."
44
+ };
45
+ return {
46
+ client,
47
+ label: "Gemini CLI",
48
+ scope,
49
+ settingsPath: join(root, ".gemini", "settings.json"),
50
+ event: "BeforeTool",
51
+ matcher: MATCHERS[client],
52
+ handler: {
53
+ name: "okgate",
54
+ type: "command",
55
+ command,
56
+ timeout: timeoutS * 1e3,
57
+ description: "okgate: one rulebook for shell commands and file edits"
58
+ },
59
+ note: scope === "project" ? "Gemini CLI fingerprints project hooks: confirm the okgate hook the first time it asks." : void 0
60
+ };
61
+ }
62
+ function isGuardHookCommand(command) {
63
+ return typeof command === "string" && /okgate|agentguard/.test(command) && /\bhook\s+pre-tool-use\b/.test(command);
64
+ }
65
+ function backupFor(path) {
66
+ const legacy = `${path}.agentguard-backup`;
67
+ const next = `${path}.okgate-backup`;
68
+ return { existing: [legacy, next].find((b) => existsSync(b)), next };
69
+ }
70
+ function readSettings(path) {
71
+ if (!existsSync(path)) return {};
72
+ const text = readFileSync(path, "utf8");
73
+ if (!text.trim()) return {};
74
+ let parsed;
75
+ try {
76
+ parsed = JSON.parse(text);
77
+ } catch (err) {
78
+ throw new Error(
79
+ `${path} is not valid JSON (${err instanceof Error ? err.message : String(err)}); fix it or move it aside \u2014 okgate will not overwrite it`,
80
+ { cause: err }
81
+ );
82
+ }
83
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
84
+ throw new Error(`${path} is not a JSON object; okgate will not overwrite it`);
85
+ return parsed;
86
+ }
87
+ function groupsOf(settings, event) {
88
+ const hooks = settings.hooks;
89
+ if (!hooks || typeof hooks !== "object") return [];
90
+ const groups = hooks[event];
91
+ return Array.isArray(groups) ? groups : [];
92
+ }
93
+ function installedHandlers(target) {
94
+ const settings = readSettings(target.settingsPath);
95
+ return groupsOf(settings, target.event).flatMap(
96
+ (g) => (g.hooks ?? []).filter((h) => isGuardHookCommand(h.command))
97
+ );
98
+ }
99
+ function installHook(target) {
100
+ const existed = existsSync(target.settingsPath);
101
+ const settings = readSettings(target.settingsPath);
102
+ const hooks = settings.hooks && typeof settings.hooks === "object" ? settings.hooks : {};
103
+ const groups = groupsOf(settings, target.event);
104
+ const isOurs = (h) => isGuardHookCommand(h.command);
105
+ const ours = groups.flatMap((g) => (g.hooks ?? []).filter(isOurs));
106
+ const exact = groups.some(
107
+ (g) => g.matcher === target.matcher && g.hooks?.length === 1 && JSON.stringify(g.hooks[0]) === JSON.stringify(target.handler)
108
+ );
109
+ if (exact && ours.length === 1) return { status: "unchanged" };
110
+ const kept = [];
111
+ for (const group of groups) {
112
+ if (!(group.hooks ?? []).some(isOurs)) {
113
+ kept.push(group);
114
+ continue;
115
+ }
116
+ const others = (group.hooks ?? []).filter((h) => !isOurs(h));
117
+ if (others.length > 0) kept.push({ ...group, hooks: others });
118
+ }
119
+ kept.push({ matcher: target.matcher, hooks: [target.handler] });
120
+ const status = ours.length > 0 ? "updated" : "added";
121
+ hooks[target.event] = kept;
122
+ settings.hooks = hooks;
123
+ let backup;
124
+ if (existed) {
125
+ const { existing, next } = backupFor(target.settingsPath);
126
+ backup = existing ?? next;
127
+ if (!existing) copyFileSync(target.settingsPath, backup);
128
+ }
129
+ mkdirSync(dirname(target.settingsPath), { recursive: true });
130
+ writeFileSync(target.settingsPath, JSON.stringify(settings, null, 2) + "\n");
131
+ return { status, backup };
132
+ }
133
+ function uninstallHook(target) {
134
+ if (!existsSync(target.settingsPath)) return 0;
135
+ const settings = readSettings(target.settingsPath);
136
+ const groups = groupsOf(settings, target.event);
137
+ let removed = 0;
138
+ const kept = [];
139
+ for (const group of groups) {
140
+ const others = (group.hooks ?? []).filter((h) => !isGuardHookCommand(h.command));
141
+ removed += (group.hooks ?? []).length - others.length;
142
+ if (others.length > 0) kept.push({ ...group, hooks: others });
143
+ }
144
+ if (removed === 0) return 0;
145
+ const hooks = settings.hooks;
146
+ if (kept.length > 0) hooks[target.event] = kept;
147
+ else delete hooks[target.event];
148
+ if (Object.keys(hooks).length === 0) delete settings.hooks;
149
+ writeFileSync(target.settingsPath, JSON.stringify(settings, null, 2) + "\n");
150
+ return removed;
151
+ }
152
+ function hookSettingsFiles(where) {
153
+ const out = [];
154
+ for (const root of [where.cwd, where.home]) {
155
+ out.push(
156
+ join(root, ".claude", "settings.json"),
157
+ join(root, ".claude", "settings.local.json"),
158
+ join(root, ".codex", "hooks.json"),
159
+ join(root, ".codex", "config.toml"),
160
+ join(root, ".gemini", "settings.json")
161
+ );
162
+ }
163
+ out.push(
164
+ join(where.home, STATE_DIR, POLICY_FILE),
165
+ join(where.home, LEGACY_STATE_DIR, LEGACY_POLICY_FILE)
166
+ );
167
+ return out;
168
+ }
169
+
170
+ export {
171
+ CLIENT_ALIASES,
172
+ hookTarget,
173
+ backupFor,
174
+ installedHandlers,
175
+ installHook,
176
+ uninstallHook,
177
+ hookSettingsFiles
178
+ };
179
+ //# sourceMappingURL=chunk-2QDPPTPY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/clients.ts"],"sourcesContent":["/**\n * Where each coding agent reads its pre-execution hooks, and the entry okgate writes there.\n * Verified 7 October 2026 against:\n *\n * - Claude Code: https://code.claude.com/docs/en/hooks — `hooks.PreToolUse[]` in\n * `.claude/settings.json` (project) or `~/.claude/settings.json` (user); a matcher with\n * characters beyond letters, digits, `_`, `-`, `,` and `|` is an unanchored regex; `timeout`\n * in seconds.\n * - Codex CLI: https://developers.openai.com/codex/hooks — `hooks.PreToolUse[]` in\n * `.codex/hooks.json` or `~/.codex/hooks.json`; the matcher is a regex over the tool name\n * (`Bash`, `apply_patch`, `mcp__…`); `timeout` in seconds; a new hook runs only after the user\n * trusts it in `/hooks`.\n * - Gemini CLI: https://github.com/google-gemini/gemini-cli/blob/main/docs/hooks/reference.md —\n * `hooks.BeforeTool[]` in `.gemini/settings.json` or `~/.gemini/settings.json`; regex matcher\n * over `run_shell_command`, `write_file`, `replace`, `mcp_…`; `timeout` in milliseconds.\n */\nimport { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } 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\";\n\nexport type InstallScope = \"project\" | \"user\";\n\nexport interface HookTarget {\n client: HookClient;\n label: string;\n scope: InstallScope;\n settingsPath: string;\n event: \"PreToolUse\" | \"BeforeTool\";\n matcher: string;\n handler: Record<string, unknown>;\n /** what the user has to do in the client before the hook runs */\n note?: string;\n}\n\n/** Tools worth a check: the shell, file writes and MCP tools. Reads are left alone. */\nexport const MATCHERS: Record<HookClient, string> = {\n \"claude-code\": \"^(Bash|PowerShell|Write|Edit|MultiEdit|NotebookEdit)$|^mcp__\",\n codex: \"^(Bash|apply_patch)$|^mcp__\",\n \"gemini-cli\": \"^(run_shell_command|write_file|replace)$|^mcp_\",\n};\n\nexport const CLIENT_ALIASES: Record<string, HookClient> = {\n claude: \"claude-code\",\n \"claude-code\": \"claude-code\",\n codex: \"codex\",\n gemini: \"gemini-cli\",\n \"gemini-cli\": \"gemini-cli\",\n};\n\nexport function hookTarget(\n client: HookClient,\n scope: InstallScope,\n where: { cwd: string; home: string },\n command: string,\n timeoutS = 30,\n): HookTarget {\n const root = scope === \"project\" ? where.cwd : where.home;\n if (client === \"claude-code\")\n return {\n client,\n label: \"Claude Code\",\n scope,\n settingsPath: join(root, \".claude\", \"settings.json\"),\n event: \"PreToolUse\",\n matcher: MATCHERS[client],\n handler: { type: \"command\", command, timeout: timeoutS, statusMessage: \"okgate\" },\n };\n if (client === \"codex\")\n return {\n client,\n label: \"Codex CLI\",\n scope,\n settingsPath: join(root, \".codex\", \"hooks.json\"),\n event: \"PreToolUse\",\n matcher: MATCHERS[client],\n handler: { type: \"command\", command, timeout: timeoutS, statusMessage: \"okgate\" },\n note: \"Codex runs a new hook only after you trust it: open /hooks in Codex and trust the okgate entry.\",\n };\n return {\n client,\n label: \"Gemini CLI\",\n scope,\n settingsPath: join(root, \".gemini\", \"settings.json\"),\n event: \"BeforeTool\",\n matcher: MATCHERS[client],\n handler: {\n name: \"okgate\",\n type: \"command\",\n command,\n timeout: timeoutS * 1000,\n description: \"okgate: one rulebook for shell commands and file edits\",\n },\n note:\n scope === \"project\"\n ? \"Gemini CLI fingerprints project hooks: confirm the okgate hook the first time it asks.\"\n : undefined,\n };\n}\n\n/** Is this hook command one okgate wrote, under either name (agentguard before the rename)? */\nexport function isGuardHookCommand(command: unknown): boolean {\n return (\n typeof command === \"string\" &&\n /okgate|agentguard/.test(command) &&\n /\\bhook\\s+pre-tool-use\\b/.test(command)\n );\n}\n\n/**\n * The backup of a file okgate rewrites: `<file>.okgate-backup`, or the `<file>.agentguard-backup`\n * an okgate-era install left, which holds the older original and so wins.\n */\nexport function backupFor(path: string): { existing?: string; next: string } {\n const legacy = `${path}.agentguard-backup`;\n const next = `${path}.okgate-backup`;\n return { existing: [legacy, next].find((b) => existsSync(b)), next };\n}\n\ntype Json = Record<string, unknown>;\ninterface MatcherGroup {\n matcher?: string;\n hooks?: Json[];\n [k: string]: unknown;\n}\n\nfunction readSettings(path: string): Json {\n if (!existsSync(path)) return {};\n const text = readFileSync(path, \"utf8\");\n if (!text.trim()) return {};\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (err) {\n throw new Error(\n `${path} is not valid JSON (${err instanceof Error ? err.message : String(err)}); fix it or move it aside — okgate will not overwrite it`,\n { cause: err },\n );\n }\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed))\n throw new Error(`${path} is not a JSON object; okgate will not overwrite it`);\n return parsed as Json;\n}\n\nfunction groupsOf(settings: Json, event: string): MatcherGroup[] {\n const hooks = settings.hooks;\n if (!hooks || typeof hooks !== \"object\") return [];\n const groups = (hooks as Json)[event];\n return Array.isArray(groups) ? (groups as MatcherGroup[]) : [];\n}\n\n/** The okgate handlers currently in a settings file. */\nexport function installedHandlers(target: HookTarget): Json[] {\n const settings = readSettings(target.settingsPath);\n return groupsOf(settings, target.event).flatMap((g) =>\n (g.hooks ?? []).filter((h) => isGuardHookCommand(h.command)),\n );\n}\n\n/**\n * Write (or update in place) the okgate entry, keeping every other setting and hook. The\n * first change to an existing file leaves a `*.okgate-backup` next to it (or keeps an agentguard-era `*.agentguard-backup`).\n */\nexport function installHook(target: HookTarget): {\n status: \"added\" | \"updated\" | \"unchanged\";\n backup?: string;\n} {\n const existed = existsSync(target.settingsPath);\n const settings = readSettings(target.settingsPath);\n const hooks = (\n settings.hooks && typeof settings.hooks === \"object\" ? settings.hooks : {}\n ) as Json;\n const groups = groupsOf(settings, target.event);\n const isOurs = (h: Json): boolean => isGuardHookCommand(h.command);\n const ours = groups.flatMap((g) => (g.hooks ?? []).filter(isOurs));\n const exact = groups.some(\n (g) =>\n g.matcher === target.matcher &&\n g.hooks?.length === 1 &&\n JSON.stringify(g.hooks[0]) === JSON.stringify(target.handler),\n );\n if (exact && ours.length === 1) return { status: \"unchanged\" };\n const kept: MatcherGroup[] = [];\n for (const group of groups) {\n if (!(group.hooks ?? []).some(isOurs)) {\n kept.push(group);\n continue;\n }\n const others = (group.hooks ?? []).filter((h) => !isOurs(h));\n if (others.length > 0) kept.push({ ...group, hooks: others });\n }\n kept.push({ matcher: target.matcher, hooks: [target.handler] });\n const status = ours.length > 0 ? \"updated\" : \"added\";\n hooks[target.event] = kept;\n settings.hooks = hooks;\n let backup: string | undefined;\n if (existed) {\n const { existing, next } = backupFor(target.settingsPath);\n backup = existing ?? next;\n if (!existing) copyFileSync(target.settingsPath, backup);\n }\n mkdirSync(dirname(target.settingsPath), { recursive: true });\n writeFileSync(target.settingsPath, JSON.stringify(settings, null, 2) + \"\\n\");\n return { status, backup };\n}\n\n/** Remove okgate's entries; other hooks and settings stay. Returns how many were removed. */\nexport function uninstallHook(target: HookTarget): number {\n if (!existsSync(target.settingsPath)) return 0;\n const settings = readSettings(target.settingsPath);\n const groups = groupsOf(settings, target.event);\n let removed = 0;\n const kept: MatcherGroup[] = [];\n for (const group of groups) {\n const others = (group.hooks ?? []).filter((h) => !isGuardHookCommand(h.command));\n removed += (group.hooks ?? []).length - others.length;\n if (others.length > 0) kept.push({ ...group, hooks: others });\n }\n if (removed === 0) return 0;\n const hooks = settings.hooks as Json;\n if (kept.length > 0) hooks[target.event] = kept;\n else delete hooks[target.event];\n if (Object.keys(hooks).length === 0) delete settings.hooks;\n writeFileSync(target.settingsPath, JSON.stringify(settings, null, 2) + \"\\n\");\n return removed;\n}\n\n/** Every settings file that can hold a hook, project and user level: edits to them are guard-config. */\nexport function hookSettingsFiles(where: { cwd: string; home: string }): string[] {\n const out: string[] = [];\n for (const root of [where.cwd, where.home]) {\n out.push(\n join(root, \".claude\", \"settings.json\"),\n join(root, \".claude\", \"settings.local.json\"),\n join(root, \".codex\", \"hooks.json\"),\n join(root, \".codex\", \"config.toml\"),\n join(root, \".gemini\", \"settings.json\"),\n );\n }\n out.push(\n join(where.home, STATE_DIR, POLICY_FILE),\n join(where.home, LEGACY_STATE_DIR, LEGACY_POLICY_FILE),\n );\n return out;\n}\n"],"mappings":"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","names":[]}
@@ -1031,7 +1031,7 @@ async function sendWebhook(url, payload, opts = {}) {
1031
1031
  function approvalSlackMessage(event, url) {
1032
1032
  const a = event.approval;
1033
1033
  const argsText = JSON.stringify(a.args ?? {}, null, 2).slice(0, 1500);
1034
- const text = `[agentguard] approval needed: ${a.tool} (run ${a.run_id}) \u2014 run \`agentguard approve ${a.id}\`${url ? ` or open ${url}` : ""}`;
1034
+ const text = `[okgate] approval needed: ${a.tool} (run ${a.run_id}) \u2014 run \`okgate approve ${a.id}\`${url ? ` or open ${url}` : ""}`;
1035
1035
  const blocks = [
1036
1036
  { type: "header", text: { type: "plain_text", text: `Approval needed: ${a.tool}` } },
1037
1037
  {
@@ -1047,7 +1047,7 @@ function approvalSlackMessage(event, url) {
1047
1047
  elements: [
1048
1048
  {
1049
1049
  type: "mrkdwn",
1050
- text: `Approve: \`agentguard approve ${a.id}\` \xB7 Deny: \`agentguard deny ${a.id}\` \xB7 expires ${a.expires_at}`
1050
+ text: `Approve: \`okgate approve ${a.id}\` \xB7 Deny: \`okgate deny ${a.id}\` \xB7 expires ${a.expires_at}`
1051
1051
  }
1052
1052
  ]
1053
1053
  }
@@ -1070,7 +1070,7 @@ function approvalSlackMessage(event, url) {
1070
1070
  }
1071
1071
  function haltSlackMessage(event) {
1072
1072
  const cause = event.error?.cause ?? "";
1073
- const text = `[agentguard] ${event.type}: ${event.tool} (run ${event.runId}) \u2014 ${cause}`;
1073
+ const text = `[okgate] ${event.type}: ${event.tool} (run ${event.runId}) \u2014 ${cause}`;
1074
1074
  return {
1075
1075
  text,
1076
1076
  blocks: [
@@ -1087,7 +1087,7 @@ ${cause}`
1087
1087
  elements: [
1088
1088
  {
1089
1089
  type: "mrkdwn",
1090
- text: `\`agentguard report --run ${event.runId}\` for the full picture${event.type === "KILLED" ? "" : " \xB7 `agentguard kill` to stop everything"}`
1090
+ text: `\`okgate report --run ${event.runId}\` for the full picture${event.type === "KILLED" ? "" : " \xB7 `okgate kill` to stop everything"}`
1091
1091
  }
1092
1092
  ]
1093
1093
  }
@@ -1119,7 +1119,7 @@ function createAlerter(opts) {
1119
1119
  webhook,
1120
1120
  {
1121
1121
  event: event.type,
1122
- product: "agentguard",
1122
+ product: "okgate",
1123
1123
  subject: message.text,
1124
1124
  summary: event.error?.cause ?? "",
1125
1125
  occurredAt: event.at,
@@ -1143,18 +1143,22 @@ function createAlerter(opts) {
1143
1143
 
1144
1144
  // src/context.ts
1145
1145
  import { existsSync } from "fs";
1146
- import { resolve } from "path";
1147
- import { Guard } from "@agentwares/agentguard-core";
1146
+ import { basename, resolve } from "path";
1147
+ import {
1148
+ Guard,
1149
+ POLICY_FILE,
1150
+ envTwin
1151
+ } from "@agentwares/agentguard-core";
1148
1152
  import {
1149
1153
  FileApprovalStore,
1150
1154
  FileAuditSink,
1151
- FileKillSwitch,
1152
1155
  FileStateStore,
1156
+ findPolicyFile,
1157
+ killSwitchFor,
1153
1158
  loadPolicyFile
1154
1159
  } from "@agentwares/agentguard-core/node";
1155
1160
  import { existsSync as exists, readFileSync as readFileSync2 } from "fs";
1156
1161
  import { homedir } from "os";
1157
- var DEFAULT_POLICY_FILE = "agentguard.yaml";
1158
1162
  function readStdin(maxBytes = 16 * 1024 * 1024, timeoutMs = 1e4) {
1159
1163
  if (process.stdin.isTTY) return Promise.resolve("");
1160
1164
  return new Promise((resolveText) => {
@@ -1190,10 +1194,8 @@ function defaultIo() {
1190
1194
  };
1191
1195
  }
1192
1196
  function policyPathFrom(args, io) {
1193
- return resolve(
1194
- io.cwd,
1195
- flagString(args, "config") ?? io.env.AGENTGUARD_CONFIG ?? DEFAULT_POLICY_FILE
1196
- );
1197
+ const named = flagString(args, "config") ?? envTwin(io.env, "CONFIG");
1198
+ return named !== void 0 ? resolve(io.cwd, named) : findPolicyFile(io.cwd);
1197
1199
  }
1198
1200
  function loadPolicyFor(args, io, opts = {}) {
1199
1201
  return loadPolicyFile(policyPathFrom(args, io), {
@@ -1202,7 +1204,7 @@ function loadPolicyFor(args, io, opts = {}) {
1202
1204
  });
1203
1205
  }
1204
1206
  function createFileGuard(loaded, opts = {}) {
1205
- const kill = new FileKillSwitch(loaded.killPath);
1207
+ const kill = killSwitchFor(loaded);
1206
1208
  const audit = new FileAuditSink(loaded.auditPath);
1207
1209
  const approvals = new FileApprovalStore(loaded.stateDir);
1208
1210
  const alerter = opts.alerts === false ? void 0 : createAlerter({ policy: loaded.policy, approvalUrl: opts.approvalUrl, log: opts.log });
@@ -1213,6 +1215,7 @@ function createFileGuard(loaded, opts = {}) {
1213
1215
  kill,
1214
1216
  approvals,
1215
1217
  env: opts.env ?? process.env,
1218
+ policyFile: basename(loaded.path),
1216
1219
  approvalUrl: opts.approvalUrl,
1217
1220
  onEvent: async (event) => {
1218
1221
  await opts.onEvent?.(event);
@@ -1255,7 +1258,6 @@ export {
1255
1258
  approvalSlackMessage,
1256
1259
  haltSlackMessage,
1257
1260
  createAlerter,
1258
- DEFAULT_POLICY_FILE,
1259
1261
  homeFrom,
1260
1262
  defaultIo,
1261
1263
  policyPathFrom,
@@ -1265,4 +1267,4 @@ export {
1265
1267
  approvalUrlFor,
1266
1268
  describeError
1267
1269
  };
1268
- //# sourceMappingURL=chunk-SUXQTT3X.js.map
1270
+ //# sourceMappingURL=chunk-4WTFMFRY.js.map