@adtl/gateway 0.3.0 → 0.3.2

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/README.md +59 -1
  2. package/dist/audit.d.ts +4 -2
  3. package/dist/audit.d.ts.map +1 -1
  4. package/dist/audit.js.map +1 -1
  5. package/dist/cli.js +80 -15
  6. package/dist/cli.js.map +1 -1
  7. package/dist/config.d.ts +49 -44
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/config.js +10 -3
  10. package/dist/config.js.map +1 -1
  11. package/dist/gateway.d.ts +1 -1
  12. package/dist/gateway.js +1 -1
  13. package/dist/hooks/claudeCode.d.ts +43 -0
  14. package/dist/hooks/claudeCode.d.ts.map +1 -0
  15. package/dist/hooks/claudeCode.js +148 -0
  16. package/dist/hooks/claudeCode.js.map +1 -0
  17. package/dist/hooks/index.d.ts +4 -0
  18. package/dist/hooks/index.d.ts.map +1 -0
  19. package/dist/hooks/index.js +4 -0
  20. package/dist/hooks/index.js.map +1 -0
  21. package/dist/hooks/preset.d.ts +16 -0
  22. package/dist/hooks/preset.d.ts.map +1 -0
  23. package/dist/hooks/preset.js +32 -0
  24. package/dist/hooks/preset.js.map +1 -0
  25. package/dist/hooks/run.d.ts +9 -0
  26. package/dist/hooks/run.d.ts.map +1 -0
  27. package/dist/hooks/run.js +44 -0
  28. package/dist/hooks/run.js.map +1 -0
  29. package/dist/index.d.ts +1 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +1 -0
  32. package/dist/index.js.map +1 -1
  33. package/dist/init/fromMcpJson.d.ts +41 -0
  34. package/dist/init/fromMcpJson.d.ts.map +1 -0
  35. package/dist/init/fromMcpJson.js +141 -0
  36. package/dist/init/fromMcpJson.js.map +1 -0
  37. package/dist/init/index.d.ts +2 -0
  38. package/dist/init/index.d.ts.map +1 -1
  39. package/dist/init/index.js +2 -0
  40. package/dist/init/index.js.map +1 -1
  41. package/dist/init/run.d.ts +13 -0
  42. package/dist/init/run.d.ts.map +1 -1
  43. package/dist/init/run.js +83 -11
  44. package/dist/init/run.js.map +1 -1
  45. package/dist/startup.d.ts +12 -1
  46. package/dist/startup.d.ts.map +1 -1
  47. package/dist/startup.js +27 -3
  48. package/dist/startup.js.map +1 -1
  49. package/package.json +4 -4
  50. package/src/audit.ts +4 -2
  51. package/src/cli.ts +70 -15
  52. package/src/config.ts +9 -3
  53. package/src/gateway.ts +1 -1
  54. package/src/hooks/claudeCode.ts +194 -0
  55. package/src/hooks/index.ts +3 -0
  56. package/src/hooks/preset.ts +47 -0
  57. package/src/hooks/run.ts +49 -0
  58. package/src/index.ts +1 -0
  59. package/src/init/fromMcpJson.ts +165 -0
  60. package/src/init/index.ts +2 -0
  61. package/src/init/run.ts +91 -12
  62. package/src/startup.ts +28 -4
package/README.md CHANGED
@@ -78,6 +78,23 @@ adtl-gateway init -c adtl.yaml --write # update the file (original kept as adt
78
78
 
79
79
  Always review the result: a preset is a starting point, not a judgment about your data.
80
80
 
81
+ #### Starting from Claude Code's `.mcp.json`
82
+
83
+ If your servers are already set up in Claude Code, import them:
84
+
85
+ ```sh
86
+ adtl-gateway init -c adtl.yaml --from .mcp.json # print both files, change nothing
87
+ adtl-gateway init -c adtl.yaml --from .mcp.json --write # write them (originals kept as .bak)
88
+ ```
89
+
90
+ - Every stdio and HTTP server in `.mcp.json` becomes an upstream, with its command, args, env, url and headers. `${VAR}` and `${VAR:-default}` keep working, because the gateway expands them the same way. Names that aren't valid upstream ids are adjusted (`docs.api` becomes `docs-api`).
91
+ - `adtl.yaml` is created if it doesn't exist, with restrictive defaults and the two example policy rules; then rules are drafted for every tool as above.
92
+ - With `--write`, the imported servers in `.mcp.json` are replaced by one `adtl` entry that runs `npx -y @adtl/gateway@<version> --config adtl.yaml`. Everything else in the file is kept. Restart Claude Code afterwards.
93
+ - SSE servers stay in `.mcp.json`, because the gateway only speaks Streamable HTTP. So do entries that already run the gateway, and upstreams already in `adtl.yaml` are never changed. Re-running is safe.
94
+ - Any file with `mcpServers` works, such as Claude Desktop's `claude_desktop_config.json`. Servers added with `claude mcp add` live in `~/.claude.json` instead; list them with `claude mcp list`.
95
+
96
+ The gateway starts upstream servers with a minimal environment plus their `env:` entries, not your whole shell environment. If a server relied on a variable from your shell, add it under its `env:`, e.g. `GITHUB_TOKEN: "${GITHUB_TOKEN}"`.
97
+
81
98
  Labels only get stricter as a session goes on. A session that has read anything untrusted stays untrusted until the session ends.
82
99
 
83
100
  ### Policy
@@ -138,6 +155,46 @@ adtl-gateway --config adtl.yaml --audit
138
155
 
139
156
  or set `gateway.mode: audit` in the file. In audit mode every call goes through and results are not changed. Labels are still tracked, so the decisions are the same as in active mode. Each line in the audit log gets `"mode": "audit"`, and a call the policy would have stopped is logged as `"outcome": "forwarded"` with `"decision": "ask"` or `"block"`, the reason and the matching rules. Once the log looks right, remove the flag.
140
157
 
158
+ ## Claude Code: cover the built-in tools too
159
+
160
+ The gateway only sees MCP calls. Claude Code's own tools (`WebFetch`, `WebSearch`, `Bash`, `Read`, ...) don't go through it, so a page fetched with `WebFetch` would not taint the session, and `Bash` could send data anywhere. `adtl-gateway hook` closes that gap. Add it to `.claude/settings.json` (or `~/.claude/settings.json` for every project):
161
+
162
+ ```json
163
+ {
164
+ "hooks": {
165
+ "PreToolUse": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "npx -y @adtl/gateway hook --config /absolute/path/to/adtl.yaml", "timeout": 10, "onFailure": "block" }] }],
166
+ "PostToolUse": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "npx -y @adtl/gateway hook --config /absolute/path/to/adtl.yaml", "timeout": 10 }] }],
167
+ "PostToolUseFailure": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "npx -y @adtl/gateway hook --config /absolute/path/to/adtl.yaml", "timeout": 10 }] }]
168
+ }
169
+ }
170
+ ```
171
+
172
+ (A global install, `npm i -g @adtl/gateway` and then `adtl-gateway hook ...`, starts faster than `npx`.)
173
+
174
+ What it does:
175
+
176
+ - **After each tool runs**, it labels the output and adds it to the session label. Built-in tools are labeled as the server `claude-code`.
177
+ - **Before each tool runs**, it checks the call against the same policy as the gateway. `block` denies the call. `ask` shows Claude Code's own permission prompt, so you approve in the terminal. `allow` gives no answer, so your normal Claude Code permissions still apply. ADTL never approves a call on its own.
178
+ - **It shares one session label with the gateway.** Claude Code gives the gateway its session id (`CLAUDE_CODE_SESSION_ID`), and both keep the label in `~/.adtl/sessions/<id>.jsonl` (set `ADTL_SESSIONS_DIR` to change the directory). A `WebFetch` taints the session for `github__add_comment`, and a private file read through the gateway counts against a later `Bash` call. Labels last for the whole Claude Code session, including `--resume`.
179
+ - **It covers MCP servers that skip the gateway**, such as connectors added in claude.ai. Their tools are labeled as their server name (`mcp__<server>__<tool>` → server `<server>`), so you can describe them under `servers:` like any upstream. The gateway's own tools (`mcp__adtl__*`) are skipped; pass `--gateway-server <name>` if you registered the gateway under another name.
180
+ - **It fails closed.** If the hook can't decide, it exits with code 2, which stops the call.
181
+ - **It writes to the same audit log** (`gateway.audit`) with `"via": "claude-code-hook"`, and follows `gateway.mode: audit`. The config needs no `gateway:` section if you only use the hooks.
182
+
183
+ Built-in labels, which you can override under `servers.claude-code.tools`:
184
+
185
+ | Tools | Result | Egress |
186
+ |---|---|---|
187
+ | `Read`, `Grep`, `Glob` | trusted, private | none |
188
+ | `WebFetch`, `WebSearch` | untrusted, public | external (a URL or query can carry data out) |
189
+ | `Bash`, `Monitor` | unknown, private | unknown |
190
+ | `Agent` / `Task` | unknown, private | none (the sub-agent's own calls are checked too) |
191
+ | `Write`, `Edit`, `TodoWrite`, other bookkeeping tools | trusted, public | none |
192
+ | anything else | your `defaults` | unknown |
193
+
194
+ With the [example policy](../../examples/adtl.yaml), `Bash` and `WebFetch` run freely in a fresh session, but ask first once the session has read untrusted content, because `no-public-write-after-untrusted` matches `tool.egress: [public, external, unknown]`.
195
+
196
+ The hook also refuses `Write` and `Edit` on your ADTL config and session files, and asks before shell commands that mention the session directory, so the agent can't simply clear its own taint. This is a speed bump, not a sandbox.
197
+
141
198
  ## How it works
142
199
 
143
200
  ```
@@ -155,7 +212,8 @@ The gateway fails closed. If an interceptor errors or times out, the call is sto
155
212
  - Tools, resources and prompts are proxied. Resource subscriptions, `list_changed` notifications and completions are not passed through yet.
156
213
  - Resources and prompts are labeled by server defaults (`servers.<id>.defaults`) or the global defaults; there are no per-resource or per-prompt rules yet. A resource URI that two upstreams could serve is refused rather than guessed.
157
214
  - Approvals come from one push channel (ntfy). Other channels, approvals inside the MCP client, and approver roles are planned.
158
- - Labels last for one gateway process, which is one agent session. They are not carried into files, memory or other agents yet; that's planned for v0.4.
215
+ - Labels last for one agent session: one gateway process, or under Claude Code one Claude Code session (shared with the hooks). They are not carried into files, memory or other agents yet; that's planned for v0.4. A file written after reading untrusted content reads back as trusted.
216
+ - The Claude Code hooks label tools by name, not by what they touched: a `Read` of a downloaded file is as trusted as a `Read` of your own code.
159
217
  - Labels are set by your config. Servers' own trust claims can only make labels stricter, unless you set `acceptServerClaims: true`.
160
218
 
161
219
  ## Links
package/dist/audit.d.ts CHANGED
@@ -7,8 +7,10 @@ export interface AuditEntry {
7
7
  tool?: string;
8
8
  resource?: string;
9
9
  prompt?: string;
10
- /** Final outcome of the call. */
11
- outcome: "forwarded" | "blocked" | "upstream_error";
10
+ /** Final outcome of the call. "asked": handed to Claude Code's permission prompt by the hook. */
11
+ outcome: "forwarded" | "blocked" | "asked" | "upstream_error";
12
+ /** Present when the entry was written by the Claude Code hook rather than the gateway. */
13
+ via?: "claude-code-hook";
12
14
  /** The policy's decision. In audit mode a call can be forwarded with decision "ask" or "block". */
13
15
  decision?: string;
14
16
  /** Present when the gateway ran in audit mode: nothing was stopped or changed. */
@@ -1 +1 @@
1
- {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,YAAY,GAAG,gBAAgB,GAAG,aAAa,CAAC;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,OAAO,EAAE,WAAW,GAAG,SAAS,GAAG,gBAAgB,CAAC;IACpD,mGAAmG;IACnG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kFAAkF;IAClF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,2FAA2F;IAC3F,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACtF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;CAChC;AAED,qBAAa,aAAc,YAAW,SAAS;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM;IAIjC,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;CAG/B;AAED,qBAAa,cAAe,YAAW,SAAS;IAC9C,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,CAAM;IACpC,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;CAG/B"}
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,YAAY,GAAG,gBAAgB,GAAG,aAAa,CAAC;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iGAAiG;IACjG,OAAO,EAAE,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,gBAAgB,CAAC;IAC9D,0FAA0F;IAC1F,GAAG,CAAC,EAAE,kBAAkB,CAAC;IACzB,mGAAmG;IACnG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kFAAkF;IAClF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,2FAA2F;IAC3F,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACtF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;CAChC;AAED,qBAAa,aAAc,YAAW,SAAS;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM;IAIjC,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;CAG/B;AAED,qBAAa,cAAe,YAAW,SAAS;IAC9C,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,CAAM;IACpC,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;CAG/B"}
package/dist/audit.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgCpC,MAAM,OAAO,aAAa;IACH;IAArB,YAAqB,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;QAC/B,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,KAAiB;QACrB,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAClE,CAAC;CACF;AAED,MAAM,OAAO,cAAc;IAChB,OAAO,GAAiB,EAAE,CAAC;IACpC,KAAK,CAAC,KAAiB;QACrB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;CACF"}
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkCpC,MAAM,OAAO,aAAa;IACH;IAArB,YAAqB,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;QAC/B,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,KAAiB;QACrB,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAClE,CAAC;CACF;AAED,MAAM,OAAO,cAAc;IAChB,OAAO,GAAiB,EAAE,CAAC;IACpC,KAAK,CAAC,KAAiB;QACrB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;CACF"}
package/dist/cli.js CHANGED
@@ -4,7 +4,8 @@
4
4
  * servers through ADTL's interceptors.
5
5
  *
6
6
  * adtl-gateway --config adtl.yaml [--audit]
7
- * adtl-gateway init --config adtl.yaml [--write]
7
+ * adtl-gateway init --config adtl.yaml [--from .mcp.json] [--write]
8
+ * adtl-gateway hook --config adtl.yaml [--gateway-server adtl]
8
9
  *
9
10
  * Point your MCP client (e.g. Claude Code's .mcp.json) at this command.
10
11
  * Logs go to stderr; stdout carries MCP JSON-RPC only.
@@ -12,10 +13,12 @@
12
13
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
13
14
  import { EnvExpansionError } from "./config.js";
14
15
  import { GATEWAY_VERSION } from "./gateway.js";
16
+ import { runHook } from "./hooks/run.js";
15
17
  import { runInit } from "./init/run.js";
16
18
  import { GatewayConfigError, loadGatewayConfig, startGateway } from "./startup.js";
17
19
  const USAGE = `Usage: adtl-gateway --config <adtl.yaml> [--audit]
18
- adtl-gateway init --config <adtl.yaml> [--write]
20
+ adtl-gateway init --config <adtl.yaml> [--from <.mcp.json>] [--write]
21
+ adtl-gateway hook --config <adtl.yaml> [--gateway-server <name>]
19
22
 
20
23
  Runs an MCP server over stdio that forwards tool calls to the upstream
21
24
  servers in the config, checking and labeling each call with ADTL.
@@ -31,7 +34,23 @@ init:
31
34
  for each tool the config doesn't cover yet (presets for GitHub,
32
35
  filesystem and fetch; MCP tool hints otherwise). Existing entries are
33
36
  never changed. Prints the updated config; review it before using it.
37
+ --from <file> First import the MCP servers of a client config (Claude
38
+ Code's .mcp.json, or any file with "mcpServers") into
39
+ gateway.upstreams, creating the config file if needed.
40
+ With --write, that file is changed to run the gateway
41
+ in place of the imported servers (original kept as .bak).
34
42
  --write Update the config file in place (original kept as .bak).
43
+
44
+ hook:
45
+ The Claude Code hook for PreToolUse, PostToolUse and PostToolUseFailure.
46
+ Labels built-in tools (WebFetch, Read, Bash, ...) and MCP servers outside
47
+ the gateway, and runs the same policy on them, sharing the session label
48
+ with the gateway. Reads the hook event from stdin.
49
+ --gateway-server <name>
50
+ The gateway's name in Claude Code's MCP config; its
51
+ tools are checked by the gateway and skipped here.
52
+ Default: adtl.
53
+
35
54
  -h, --help Show this help.`;
36
55
  function parseArgs(argv) {
37
56
  const out = {};
@@ -39,6 +58,10 @@ function parseArgs(argv) {
39
58
  const a = argv[i];
40
59
  if (i === 0 && a === "init")
41
60
  out.init = true;
61
+ else if (i === 0 && a === "hook")
62
+ out.hook = true;
63
+ else if (a === "--gateway-server" && out.hook)
64
+ out.gatewayServer = argv[++i];
42
65
  else if (a === "-h" || a === "--help")
43
66
  out.help = true;
44
67
  else if (a === "-v" || a === "--version")
@@ -51,6 +74,8 @@ function parseArgs(argv) {
51
74
  out.audit = true;
52
75
  else if (a === "--write" && out.init)
53
76
  out.write = true;
77
+ else if (a === "--from" && out.init)
78
+ out.from = argv[++i];
54
79
  else
55
80
  throw new GatewayConfigError(`Unknown argument: ${a}\n\n${USAGE}`);
56
81
  }
@@ -66,7 +91,9 @@ async function main() {
66
91
  if (!args.config)
67
92
  throw new GatewayConfigError(`Missing --config\n\n${USAGE}`);
68
93
  if (args.init)
69
- return init(args.config, args.write === true);
94
+ return init(args.config, args.write === true, args.from);
95
+ if (args.hook)
96
+ return hook(args.config, args.gatewayServer);
70
97
  const loaded = await loadGatewayConfig(args.config);
71
98
  if (args.audit)
72
99
  loaded.gateway.mode = "audit";
@@ -91,7 +118,21 @@ async function main() {
91
118
  console.error(`[adtl-gateway] ${GATEWAY_VERSION} ready (session ${started.gateway.sessionId})`);
92
119
  }
93
120
  function summarize(r, path, write) {
94
- const lines = r.reports.map((s) => {
121
+ const lines = [];
122
+ if (r.mcp) {
123
+ const m = r.mcp;
124
+ for (const i of m.imported)
125
+ lines.push(` imported ${i.name}${i.id !== i.name ? ` as ${i.id}` : ""} from ${m.path}`);
126
+ for (const k of m.kept)
127
+ lines.push(` ${k.name}: already in the config as ${k.id}, kept as it is`);
128
+ for (const s of m.skipped)
129
+ lines.push(` ${s.name}: left in ${m.path} (${s.reason})`);
130
+ if (!m.imported.length && !m.kept.length)
131
+ lines.push(` nothing to import from ${m.path}`);
132
+ }
133
+ if (r.created)
134
+ lines.push(` ${write ? "created" : "would create"} ${path}`);
135
+ lines.push(...r.reports.map((s) => {
95
136
  const parts = [`${s.added.length} tools added`];
96
137
  if (s.kept.length)
97
138
  parts.push(`${s.kept.length} kept`);
@@ -100,21 +141,44 @@ function summarize(r, path, write) {
100
141
  if (s.stale.length)
101
142
  parts.push(`no longer offered: ${s.stale.join(", ")}`);
102
143
  return ` ${s.id} (${s.preset ? `preset ${s.preset}` : "from tool hints, review"}): ${parts.join("; ")}`;
103
- });
144
+ }));
104
145
  for (const f of r.failed)
105
146
  lines.push(` ${f.id}: could not connect, skipped (${f.error})`);
106
- const changed = r.reports.some((s) => s.added.length || s.addedDefaults);
107
- const tail = !changed
108
- ? "Nothing to add."
109
- : write
110
- ? `Updated ${path} (original saved as ${path}.bak). Review every line marked "review".`
111
- : "Nothing written. Review the config above, then re-run with --write.";
147
+ const changed = r.created || r.mcp?.changed || r.reports.some((s) => s.added.length || s.addedDefaults);
148
+ let tail;
149
+ if (!changed)
150
+ tail = "Nothing to add.";
151
+ else if (!write)
152
+ tail = "Nothing written. Review the config above, then re-run with --write.";
153
+ else {
154
+ tail = r.created ? `Wrote ${path}.` : `Updated ${path} (original saved as ${path}.bak).`;
155
+ if (r.mcp?.changed)
156
+ tail += ` ${r.mcp.path} now runs the gateway (original saved as ${r.mcp.path}.bak); restart your MCP client.`;
157
+ tail += ' Review every line marked "review".';
158
+ }
112
159
  return `${lines.join("\n")}\n${tail}`;
113
160
  }
114
- async function init(path, write) {
115
- const result = await runInit({ path, write });
116
- if (!write)
161
+ async function readStdin() {
162
+ const chunks = [];
163
+ for await (const c of process.stdin)
164
+ chunks.push(c);
165
+ return Buffer.concat(chunks).toString("utf8");
166
+ }
167
+ async function hook(config, gatewayServer) {
168
+ const out = await runHook({ configPath: config, stdin: await readStdin(), ...(gatewayServer ? { gatewayServer } : {}) });
169
+ if (out.stdout)
170
+ process.stdout.write(`${JSON.stringify(out.stdout)}\n`);
171
+ if (out.stderr)
172
+ process.stderr.write(`${out.stderr}\n`);
173
+ process.exitCode = out.exitCode;
174
+ }
175
+ async function init(path, write, from) {
176
+ const result = await runInit({ path, write, ...(from ? { from } : {}) });
177
+ if (!write) {
117
178
  process.stdout.write(result.text);
179
+ if (result.mcp?.changed)
180
+ process.stdout.write(`\n# ${result.mcp.path} with --write:\n${result.mcp.text.replace(/^/gm, "# ")}\n`);
181
+ }
118
182
  console.error(`[adtl-gateway] init\n${summarize(result, path, write)}`);
119
183
  if (result.failed.length && !result.reports.length)
120
184
  process.exitCode = 1;
@@ -122,6 +186,7 @@ async function init(path, write) {
122
186
  main().catch((err) => {
123
187
  const known = err instanceof GatewayConfigError || err instanceof EnvExpansionError;
124
188
  console.error(known ? `[adtl-gateway] ${err.message}` : err);
125
- process.exit(1);
189
+ // For Claude Code hooks only exit code 2 stops the call; any other code lets it run.
190
+ process.exit(process.argv[2] === "hook" ? 2 : 1);
126
191
  });
127
192
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAmB,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEnF,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uCAmCyB,CAAC;AAcxC,SAAS,SAAS,CAAC,IAAc;IAC/B,MAAM,GAAG,GAAS,EAAE,CAAC;IACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,MAAM;YAAE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;aACxC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,MAAM;YAAE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;aAC7C,IAAI,CAAC,KAAK,kBAAkB,IAAI,GAAG,CAAC,IAAI;YAAE,GAAG,CAAC,aAAa,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aACxE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,QAAQ;YAAE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;aAClD,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,WAAW;YAAE,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC;aACxD,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,UAAU;YAAE,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aAC3D,IAAI,CAAC,EAAE,UAAU,CAAC,WAAW,CAAC;YAAE,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;aACzE,IAAI,CAAC,KAAK,SAAS;YAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC;aACtC,IAAI,CAAC,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI;YAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC;aAClD,IAAI,CAAC,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI;YAAE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;;YACrD,MAAM,IAAI,kBAAkB,CAAC,qBAAqB,CAAC,OAAO,KAAK,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,qFAAqF;IACrF,IAAI,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC9C,IAAI,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAC3D,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,kBAAkB,CAAC,uBAAuB,KAAK,EAAE,CAAC,CAAC;IAC/E,IAAI,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACxE,IAAI,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IAE5D,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpD,IAAI,IAAI,CAAC,KAAK;QAAE,MAAM,CAAC,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC;IAC9C,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;IAE9C,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QAC1B,IAAI,OAAO;YAAE,OAAO;QACpB,OAAO,GAAG,IAAI,CAAC;QACf,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC5C,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACtB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,MAAM,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC;IACvC,kFAAkF;IAClF,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;IACjD,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;IAC5C,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;IAE7C,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;IACjD,OAAO,CAAC,KAAK,CAAC,kBAAkB,eAAe,mBAAmB,OAAO,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;AAClG,CAAC;AAED,SAAS,SAAS,CAAC,CAAa,EAAE,IAAY,EAAE,KAAc;IAC5D,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC;QACV,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC;QAChB,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACrH,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,8BAA8B,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC;QACnG,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;QACtF,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7F,CAAC;IACD,IAAI,CAAC,CAAC,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,IAAI,IAAI,EAAE,CAAC,CAAC;IAC7E,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAChC,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,cAAc,CAAC,CAAC;QAChD,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,CAAC;QACvD,IAAI,CAAC,CAAC,aAAa;YAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAClD,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC3E,OAAO,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,yBAAyB,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IAC3G,CAAC,CAAC,CAAC,CAAC;IACJ,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,iCAAiC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;IAC3F,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,EAAE,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,aAAa,CAAC,CAAC;IACxG,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC,OAAO;QAAE,IAAI,GAAG,iBAAiB,CAAC;SAClC,IAAI,CAAC,KAAK;QAAE,IAAI,GAAG,qEAAqE,CAAC;SACzF,CAAC;QACJ,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,CAAC,CAAC,CAAC,WAAW,IAAI,uBAAuB,IAAI,QAAQ,CAAC;QACzF,IAAI,CAAC,CAAC,GAAG,EAAE,OAAO;YAAE,IAAI,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,4CAA4C,CAAC,CAAC,GAAG,CAAC,IAAI,iCAAiC,CAAC;QAClI,IAAI,IAAI,qCAAqC,CAAC;IAChD,CAAC;IACD,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;AACxC,CAAC;AAED,KAAK,UAAU,SAAS;IACtB,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,EAAE,MAAM,CAAC,IAAI,OAAO,CAAC,KAAK;QAAE,MAAM,CAAC,IAAI,CAAC,CAAW,CAAC,CAAC;IAC9D,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAChD,CAAC;AAED,KAAK,UAAU,IAAI,CAAC,MAAc,EAAE,aAAsB;IACxD,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,SAAS,EAAE,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACzH,IAAI,GAAG,CAAC,MAAM;QAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACxE,IAAI,GAAG,CAAC,MAAM;QAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;IACxD,OAAO,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;AAClC,CAAC;AAED,KAAK,UAAU,IAAI,CAAC,IAAY,EAAE,KAAc,EAAE,IAAa;IAC7D,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACzE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,MAAM,CAAC,GAAG,EAAE,OAAO;YAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,GAAG,CAAC,IAAI,mBAAmB,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACnI,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,wBAAwB,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;IACxE,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM;QAAE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AAC3E,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,MAAM,KAAK,GAAG,GAAG,YAAY,kBAAkB,IAAI,GAAG,YAAY,iBAAiB,CAAC;IACpF,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,kBAAmB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACxE,qFAAqF;IACrF,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,CAAC,CAAC,CAAC"}
package/dist/config.d.ts CHANGED
@@ -21,7 +21,8 @@
21
21
  * to: you@example.com
22
22
  *
23
23
  * `${VAR}` in command, args, env, cwd, url, headers and approval settings is
24
- * replaced from the gateway's environment. A missing variable is a config error.
24
+ * replaced from the gateway's environment. A missing variable is a config error,
25
+ * unless a default is given: `${VAR:-default}`.
25
26
  */
26
27
  import { z } from "zod";
27
28
  export declare const StdioUpstreamSchema: z.ZodObject<{
@@ -121,6 +122,7 @@ export declare const EmailConfigSchema: z.ZodObject<{
121
122
  to: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "atleastone">]>;
122
123
  on: z.ZodDefault<z.ZodArray<z.ZodEnum<["pending", "blocked", "approved", "denied", "timeout", "undeliverable"]>, "atleastone">>;
123
124
  }, "strict", z.ZodTypeAny, {
125
+ on: ["approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked", ...("approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked")[]];
124
126
  smtp: {
125
127
  host: string;
126
128
  port: number;
@@ -130,7 +132,6 @@ export declare const EmailConfigSchema: z.ZodObject<{
130
132
  };
131
133
  from: string;
132
134
  to: string | [string, ...string[]];
133
- on: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]];
134
135
  }, {
135
136
  smtp: {
136
137
  host: string;
@@ -141,7 +142,7 @@ export declare const EmailConfigSchema: z.ZodObject<{
141
142
  };
142
143
  from: string;
143
144
  to: string | [string, ...string[]];
144
- on?: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]] | undefined;
145
+ on?: ["approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked", ...("approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked")[]] | undefined;
145
146
  }>;
146
147
  export declare const ApprovalsConfigSchema: z.ZodObject<{
147
148
  /**
@@ -192,6 +193,7 @@ export declare const ApprovalsConfigSchema: z.ZodObject<{
192
193
  to: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "atleastone">]>;
193
194
  on: z.ZodDefault<z.ZodArray<z.ZodEnum<["pending", "blocked", "approved", "denied", "timeout", "undeliverable"]>, "atleastone">>;
194
195
  }, "strict", z.ZodTypeAny, {
196
+ on: ["approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked", ...("approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked")[]];
195
197
  smtp: {
196
198
  host: string;
197
199
  port: number;
@@ -201,7 +203,6 @@ export declare const ApprovalsConfigSchema: z.ZodObject<{
201
203
  };
202
204
  from: string;
203
205
  to: string | [string, ...string[]];
204
- on: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]];
205
206
  }, {
206
207
  smtp: {
207
208
  host: string;
@@ -212,17 +213,12 @@ export declare const ApprovalsConfigSchema: z.ZodObject<{
212
213
  };
213
214
  from: string;
214
215
  to: string | [string, ...string[]];
215
- on?: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]] | undefined;
216
+ on?: ["approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked", ...("approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked")[]] | undefined;
216
217
  }>>;
217
218
  }, "strict", z.ZodTypeAny, {
218
219
  timeoutSeconds: number;
219
- ntfy?: {
220
- server: string;
221
- topic: string;
222
- replyTopic?: string | undefined;
223
- token?: string | undefined;
224
- } | undefined;
225
220
  email?: {
221
+ on: ["approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked", ...("approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked")[]];
226
222
  smtp: {
227
223
  host: string;
228
224
  port: number;
@@ -232,15 +228,14 @@ export declare const ApprovalsConfigSchema: z.ZodObject<{
232
228
  };
233
229
  from: string;
234
230
  to: string | [string, ...string[]];
235
- on: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]];
236
231
  } | undefined;
237
- }, {
238
232
  ntfy?: {
233
+ server: string;
239
234
  topic: string;
240
- server?: string | undefined;
241
235
  replyTopic?: string | undefined;
242
236
  token?: string | undefined;
243
237
  } | undefined;
238
+ }, {
244
239
  email?: {
245
240
  smtp: {
246
241
  host: string;
@@ -251,9 +246,15 @@ export declare const ApprovalsConfigSchema: z.ZodObject<{
251
246
  };
252
247
  from: string;
253
248
  to: string | [string, ...string[]];
254
- on?: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]] | undefined;
249
+ on?: ["approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked", ...("approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked")[]] | undefined;
255
250
  } | undefined;
256
251
  timeoutSeconds?: number | undefined;
252
+ ntfy?: {
253
+ topic: string;
254
+ server?: string | undefined;
255
+ replyTopic?: string | undefined;
256
+ token?: string | undefined;
257
+ } | undefined;
257
258
  }>;
258
259
  export type ApprovalsConfig = z.infer<typeof ApprovalsConfigSchema>;
259
260
  export declare const GatewayConfigSchema: z.ZodObject<{
@@ -388,6 +389,7 @@ export declare const GatewayConfigSchema: z.ZodObject<{
388
389
  to: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "atleastone">]>;
389
390
  on: z.ZodDefault<z.ZodArray<z.ZodEnum<["pending", "blocked", "approved", "denied", "timeout", "undeliverable"]>, "atleastone">>;
390
391
  }, "strict", z.ZodTypeAny, {
392
+ on: ["approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked", ...("approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked")[]];
391
393
  smtp: {
392
394
  host: string;
393
395
  port: number;
@@ -397,7 +399,6 @@ export declare const GatewayConfigSchema: z.ZodObject<{
397
399
  };
398
400
  from: string;
399
401
  to: string | [string, ...string[]];
400
- on: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]];
401
402
  }, {
402
403
  smtp: {
403
404
  host: string;
@@ -408,17 +409,12 @@ export declare const GatewayConfigSchema: z.ZodObject<{
408
409
  };
409
410
  from: string;
410
411
  to: string | [string, ...string[]];
411
- on?: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]] | undefined;
412
+ on?: ["approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked", ...("approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked")[]] | undefined;
412
413
  }>>;
413
414
  }, "strict", z.ZodTypeAny, {
414
415
  timeoutSeconds: number;
415
- ntfy?: {
416
- server: string;
417
- topic: string;
418
- replyTopic?: string | undefined;
419
- token?: string | undefined;
420
- } | undefined;
421
416
  email?: {
417
+ on: ["approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked", ...("approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked")[]];
422
418
  smtp: {
423
419
  host: string;
424
420
  port: number;
@@ -428,15 +424,14 @@ export declare const GatewayConfigSchema: z.ZodObject<{
428
424
  };
429
425
  from: string;
430
426
  to: string | [string, ...string[]];
431
- on: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]];
432
427
  } | undefined;
433
- }, {
434
428
  ntfy?: {
429
+ server: string;
435
430
  topic: string;
436
- server?: string | undefined;
437
431
  replyTopic?: string | undefined;
438
432
  token?: string | undefined;
439
433
  } | undefined;
434
+ }, {
440
435
  email?: {
441
436
  smtp: {
442
437
  host: string;
@@ -447,9 +442,15 @@ export declare const GatewayConfigSchema: z.ZodObject<{
447
442
  };
448
443
  from: string;
449
444
  to: string | [string, ...string[]];
450
- on?: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]] | undefined;
445
+ on?: ["approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked", ...("approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked")[]] | undefined;
451
446
  } | undefined;
452
447
  timeoutSeconds?: number | undefined;
448
+ ntfy?: {
449
+ topic: string;
450
+ server?: string | undefined;
451
+ replyTopic?: string | undefined;
452
+ token?: string | undefined;
453
+ } | undefined;
453
454
  }>>;
454
455
  /** Timeout for each interceptor invocation, in milliseconds. */
455
456
  interceptorTimeoutMs: z.ZodDefault<z.ZodNumber>;
@@ -465,22 +466,17 @@ export declare const GatewayConfigSchema: z.ZodObject<{
465
466
  }>;
466
467
  mode: "audit" | "active";
467
468
  interceptorTimeoutMs: number;
469
+ audit?: string | undefined;
468
470
  interceptors?: {
469
471
  command: string;
470
472
  args: string[];
471
473
  env: Record<string, string>;
472
474
  cwd?: string | undefined;
473
475
  } | undefined;
474
- audit?: string | undefined;
475
476
  approvals?: {
476
477
  timeoutSeconds: number;
477
- ntfy?: {
478
- server: string;
479
- topic: string;
480
- replyTopic?: string | undefined;
481
- token?: string | undefined;
482
- } | undefined;
483
478
  email?: {
479
+ on: ["approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked", ...("approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked")[]];
484
480
  smtp: {
485
481
  host: string;
486
482
  port: number;
@@ -490,7 +486,12 @@ export declare const GatewayConfigSchema: z.ZodObject<{
490
486
  };
491
487
  from: string;
492
488
  to: string | [string, ...string[]];
493
- on: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]];
489
+ } | undefined;
490
+ ntfy?: {
491
+ server: string;
492
+ topic: string;
493
+ replyTopic?: string | undefined;
494
+ token?: string | undefined;
494
495
  } | undefined;
495
496
  } | undefined;
496
497
  }, {
@@ -503,21 +504,15 @@ export declare const GatewayConfigSchema: z.ZodObject<{
503
504
  url: string;
504
505
  headers?: Record<string, string> | undefined;
505
506
  }>;
507
+ audit?: string | undefined;
506
508
  interceptors?: {
507
509
  command: string;
508
510
  args?: string[] | undefined;
509
511
  env?: Record<string, string> | undefined;
510
512
  cwd?: string | undefined;
511
513
  } | undefined;
512
- audit?: string | undefined;
513
514
  mode?: "audit" | "active" | undefined;
514
515
  approvals?: {
515
- ntfy?: {
516
- topic: string;
517
- server?: string | undefined;
518
- replyTopic?: string | undefined;
519
- token?: string | undefined;
520
- } | undefined;
521
516
  email?: {
522
517
  smtp: {
523
518
  host: string;
@@ -528,9 +523,15 @@ export declare const GatewayConfigSchema: z.ZodObject<{
528
523
  };
529
524
  from: string;
530
525
  to: string | [string, ...string[]];
531
- on?: ["pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable", ...("pending" | "blocked" | "approved" | "denied" | "timeout" | "undeliverable")[]] | undefined;
526
+ on?: ["approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked", ...("approved" | "denied" | "timeout" | "undeliverable" | "pending" | "blocked")[]] | undefined;
532
527
  } | undefined;
533
528
  timeoutSeconds?: number | undefined;
529
+ ntfy?: {
530
+ topic: string;
531
+ server?: string | undefined;
532
+ replyTopic?: string | undefined;
533
+ token?: string | undefined;
534
+ } | undefined;
534
535
  } | undefined;
535
536
  interceptorTimeoutMs?: number | undefined;
536
537
  }>;
@@ -540,7 +541,11 @@ export declare class EnvExpansionError extends Error {
540
541
  readonly variable: string;
541
542
  constructor(variable: string, where: string);
542
543
  }
543
- /** Replace `${VAR}` with values from `env`. `$${VAR}` keeps a literal `${VAR}`. */
544
+ /**
545
+ * Replace `${VAR}` with values from `env`, and `${VAR:-default}` with `default`
546
+ * when VAR is unset or empty (as Claude Code's .mcp.json does). `$${VAR}` keeps
547
+ * a literal `${VAR}`.
548
+ */
544
549
  export declare function expandEnv(value: string, env: NodeJS.ProcessEnv, where: string): string;
545
550
  export declare function expandUpstream<T extends Upstream>(id: string, u: T, env: NodeJS.ProcessEnv): T;
546
551
  /** Expand `${VAR}` in every string of the approvals section. */
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;EAOrB,CAAC;AAEZ,eAAO,MAAM,kBAAkB;;;;;;;;;EAKpB,CAAC;AAEZ,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;IAAqD,CAAC;AACjF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAChE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,eAAO,MAAM,gBAAgB;;IAGzB,+FAA+F;;IAE/F,6DAA6D;;;;;;;;;;;;;EAItD,CAAC;AAEZ,eAAO,MAAM,iBAAiB;;;;QAMtB,yEAAyE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUtE,CAAC;AAEZ,eAAO,MAAM,qBAAqB;IAE9B;;;OAGG;;;;QA/BH,+FAA+F;;QAE/F,6DAA6D;;;;;;;;;;;;;;;;;;YAYzD,yEAAyE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsBtE,CAAC;AACZ,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAQ5B,8GAA8G;;;;;;;;;;;;;;;;;IAE9G,kGAAkG;;IAElG;;;OAGG;;IAEH,uFAAuF;;QA5BvF;;;WAGG;;;;YA/BH,+FAA+F;;YAE/F,6DAA6D;;;;;;;;;;;;;;;;;;gBAYzD,yEAAyE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA4C7E,gEAAgE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGzD,CAAC;AACZ,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,cAAc,OAAO,CAAC;AAEnC,qBAAa,iBAAkB,SAAQ,KAAK;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM;gBAAhB,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAIrD;AAED,mFAAmF;AACnF,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAOtF;AAMD,wBAAgB,cAAc,CAAC,CAAC,SAAS,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,CAAC,CAY9F;AAED,gEAAgE;AAChE,wBAAgB,eAAe,CAAC,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,eAAe,CAQ3F;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,IAAI,YAAY,CAE7D"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;EAOrB,CAAC;AAEZ,eAAO,MAAM,kBAAkB;;;;;;;;;EAKpB,CAAC;AAEZ,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;IAAqD,CAAC;AACjF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAChE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,eAAO,MAAM,gBAAgB;;IAGzB,+FAA+F;;IAE/F,6DAA6D;;;;;;;;;;;;;EAItD,CAAC;AAEZ,eAAO,MAAM,iBAAiB;;;;QAMtB,yEAAyE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUtE,CAAC;AAEZ,eAAO,MAAM,qBAAqB;IAE9B;;;OAGG;;;;QA/BH,+FAA+F;;QAE/F,6DAA6D;;;;;;;;;;;;;;;;;;YAYzD,yEAAyE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsBtE,CAAC;AACZ,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAQ5B,8GAA8G;;;;;;;;;;;;;;;;;IAE9G,kGAAkG;;IAElG;;;OAGG;;IAEH,uFAAuF;;QA5BvF;;;WAGG;;;;YA/BH,+FAA+F;;YAE/F,6DAA6D;;;;;;;;;;;;;;;;;;gBAYzD,yEAAyE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA4C7E,gEAAgE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGzD,CAAC;AACZ,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,cAAc,OAAO,CAAC;AAEnC,qBAAa,iBAAkB,SAAQ,KAAK;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM;gBAAhB,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAIrD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAQtF;AAMD,wBAAgB,cAAc,CAAC,CAAC,SAAS,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,CAAC,CAY9F;AAED,gEAAgE;AAChE,wBAAgB,eAAe,CAAC,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,eAAe,CAQ3F;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,IAAI,YAAY,CAE7D"}
package/dist/config.js CHANGED
@@ -21,7 +21,8 @@
21
21
  * to: you@example.com
22
22
  *
23
23
  * `${VAR}` in command, args, env, cwd, url, headers and approval settings is
24
- * replaced from the gateway's environment. A missing variable is a config error.
24
+ * replaced from the gateway's environment. A missing variable is a config error,
25
+ * unless a default is given: `${VAR:-default}`.
25
26
  */
26
27
  import { z } from "zod";
27
28
  import { EMAIL_EVENTS } from "./email.js";
@@ -111,12 +112,18 @@ export class EnvExpansionError extends Error {
111
112
  this.name = "EnvExpansionError";
112
113
  }
113
114
  }
114
- /** Replace `${VAR}` with values from `env`. `$${VAR}` keeps a literal `${VAR}`. */
115
+ /**
116
+ * Replace `${VAR}` with values from `env`, and `${VAR:-default}` with `default`
117
+ * when VAR is unset or empty (as Claude Code's .mcp.json does). `$${VAR}` keeps
118
+ * a literal `${VAR}`.
119
+ */
115
120
  export function expandEnv(value, env, where) {
116
- return value.replace(/(\$?)\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (match, escape, name) => {
121
+ return value.replace(/(\$?)\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}/g, (match, escape, name, fallback) => {
117
122
  if (escape)
118
123
  return match.slice(1);
119
124
  const v = env[name];
125
+ if (fallback !== undefined)
126
+ return v === undefined || v === "" ? fallback : v;
120
127
  if (v === undefined)
121
128
  throw new EnvExpansionError(name, where);
122
129
  return v;