@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.
- package/README.md +59 -1
- package/dist/audit.d.ts +4 -2
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js.map +1 -1
- package/dist/cli.js +80 -15
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +49 -44
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +10 -3
- package/dist/config.js.map +1 -1
- package/dist/gateway.d.ts +1 -1
- package/dist/gateway.js +1 -1
- package/dist/hooks/claudeCode.d.ts +43 -0
- package/dist/hooks/claudeCode.d.ts.map +1 -0
- package/dist/hooks/claudeCode.js +148 -0
- package/dist/hooks/claudeCode.js.map +1 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +4 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/preset.d.ts +16 -0
- package/dist/hooks/preset.d.ts.map +1 -0
- package/dist/hooks/preset.js +32 -0
- package/dist/hooks/preset.js.map +1 -0
- package/dist/hooks/run.d.ts +9 -0
- package/dist/hooks/run.d.ts.map +1 -0
- package/dist/hooks/run.js +44 -0
- package/dist/hooks/run.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/init/fromMcpJson.d.ts +41 -0
- package/dist/init/fromMcpJson.d.ts.map +1 -0
- package/dist/init/fromMcpJson.js +141 -0
- package/dist/init/fromMcpJson.js.map +1 -0
- package/dist/init/index.d.ts +2 -0
- package/dist/init/index.d.ts.map +1 -1
- package/dist/init/index.js +2 -0
- package/dist/init/index.js.map +1 -1
- package/dist/init/run.d.ts +13 -0
- package/dist/init/run.d.ts.map +1 -1
- package/dist/init/run.js +83 -11
- package/dist/init/run.js.map +1 -1
- package/dist/startup.d.ts +12 -1
- package/dist/startup.d.ts.map +1 -1
- package/dist/startup.js +27 -3
- package/dist/startup.js.map +1 -1
- package/package.json +4 -4
- package/src/audit.ts +4 -2
- package/src/cli.ts +70 -15
- package/src/config.ts +9 -3
- package/src/gateway.ts +1 -1
- package/src/hooks/claudeCode.ts +194 -0
- package/src/hooks/index.ts +3 -0
- package/src/hooks/preset.ts +47 -0
- package/src/hooks/run.ts +49 -0
- package/src/index.ts +1 -0
- package/src/init/fromMcpJson.ts +165 -0
- package/src/init/index.ts +2 -0
- package/src/init/run.ts +91 -12
- 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,
|
|
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. */
|
package/dist/audit.d.ts.map
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,
|
|
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;
|
|
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 =
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
|
115
|
-
const
|
|
116
|
-
|
|
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
|
-
|
|
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":";AACA
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
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?: ["
|
|
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?: ["
|
|
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?: ["
|
|
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?: ["
|
|
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?: ["
|
|
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
|
-
|
|
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?: ["
|
|
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
|
-
/**
|
|
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. */
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA
|
|
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
|
-
/**
|
|
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_]*)
|
|
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;
|