@0xmaxma/claude-gateway 1.8.1 → 1.8.3
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 +7 -2
- package/config.template.json +4 -0
- package/dist/agent/dreaming/config.d.ts +6 -0
- package/dist/agent/dreaming/config.d.ts.map +1 -1
- package/dist/agent/dreaming/config.js +17 -24
- package/dist/agent/dreaming/config.js.map +1 -1
- package/dist/agent/knowledge/config.d.ts.map +1 -1
- package/dist/agent/knowledge/config.js +7 -13
- package/dist/agent/knowledge/config.js.map +1 -1
- package/dist/agent/runner.d.ts +87 -13
- package/dist/agent/runner.d.ts.map +1 -1
- package/dist/agent/runner.js +342 -117
- package/dist/agent/runner.js.map +1 -1
- package/dist/agent/turn-stream.d.ts +202 -0
- package/dist/agent/turn-stream.d.ts.map +1 -0
- package/dist/agent/turn-stream.js +322 -0
- package/dist/agent/turn-stream.js.map +1 -0
- package/dist/api/apps-router.d.ts.map +1 -1
- package/dist/api/apps-router.js +14 -2
- package/dist/api/apps-router.js.map +1 -1
- package/dist/api/gateway-router.d.ts.map +1 -1
- package/dist/api/gateway-router.js +2 -3
- package/dist/api/gateway-router.js.map +1 -1
- package/dist/api/line-webhook-router.d.ts +43 -1
- package/dist/api/line-webhook-router.d.ts.map +1 -1
- package/dist/api/line-webhook-router.js +286 -38
- package/dist/api/line-webhook-router.js.map +1 -1
- package/dist/api/router.d.ts +7 -1
- package/dist/api/router.d.ts.map +1 -1
- package/dist/api/router.js +328 -114
- package/dist/api/router.js.map +1 -1
- package/dist/apps/agent-manager.d.ts.map +1 -1
- package/dist/apps/agent-manager.js +4 -1
- package/dist/apps/agent-manager.js.map +1 -1
- package/dist/apps/installer.d.ts +75 -2
- package/dist/apps/installer.d.ts.map +1 -1
- package/dist/apps/installer.js +198 -13
- package/dist/apps/installer.js.map +1 -1
- package/dist/cli/command-names.d.ts +69 -12
- package/dist/cli/command-names.d.ts.map +1 -1
- package/dist/cli/command-names.js +125 -4
- package/dist/cli/command-names.js.map +1 -1
- package/dist/config/agent-env.d.ts +41 -0
- package/dist/config/agent-env.d.ts.map +1 -0
- package/dist/config/agent-env.js +154 -0
- package/dist/config/agent-env.js.map +1 -0
- package/dist/config/loader.d.ts +33 -2
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +33 -9
- package/dist/config/loader.js.map +1 -1
- package/dist/config/watcher.d.ts +1 -0
- package/dist/config/watcher.d.ts.map +1 -1
- package/dist/config/watcher.js +17 -1
- package/dist/config/watcher.js.map +1 -1
- package/dist/cron/manager.d.ts +2 -0
- package/dist/cron/manager.d.ts.map +1 -1
- package/dist/cron/manager.js +63 -28
- package/dist/cron/manager.js.map +1 -1
- package/dist/entry.js +1 -3
- package/dist/entry.js.map +1 -1
- package/dist/index.js +25 -54
- package/dist/index.js.map +1 -1
- package/dist/load-dotenv.d.ts +17 -0
- package/dist/load-dotenv.d.ts.map +1 -1
- package/dist/load-dotenv.js +32 -9
- package/dist/load-dotenv.js.map +1 -1
- package/dist/session/store.d.ts +9 -0
- package/dist/session/store.d.ts.map +1 -1
- package/dist/session/store.js +12 -0
- package/dist/session/store.js.map +1 -1
- package/dist/shell/bypass-dialog.d.ts +142 -0
- package/dist/shell/bypass-dialog.d.ts.map +1 -0
- package/dist/shell/bypass-dialog.js +207 -0
- package/dist/shell/bypass-dialog.js.map +1 -0
- package/dist/shell/claude-pty-shell.js +42 -3
- package/dist/shell/claude-pty-shell.js.map +1 -1
- package/dist/shell/screen.d.ts +7 -0
- package/dist/shell/screen.d.ts.map +1 -1
- package/dist/shell/screen.js +10 -1
- package/dist/shell/screen.js.map +1 -1
- package/dist/types.d.ts +20 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/config-num.d.ts +22 -0
- package/dist/utils/config-num.d.ts.map +1 -0
- package/dist/utils/config-num.js +34 -0
- package/dist/utils/config-num.js.map +1 -0
- package/mcp/tools/cron/module.ts +4 -4
- package/mcp/tools/telegram/module.ts +29 -6
- package/mcp/tools/telegram/typing.ts +1 -1
- package/package.json +1 -1
|
@@ -1,10 +1,55 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.SUPERVISOR_MARKER = exports.CHILD_MARKER = void 0;
|
|
37
|
+
exports.isDirectSystemdChild = isDirectSystemdChild;
|
|
4
38
|
exports.isGatewayStartInvocation = isGatewayStartInvocation;
|
|
5
39
|
exports.isSupervised = isSupervised;
|
|
6
40
|
exports.claimSupervisorEnv = claimSupervisorEnv;
|
|
7
41
|
exports.classifyInvocation = classifyInvocation;
|
|
42
|
+
exports.resolveInvocationSignals = resolveInvocationSignals;
|
|
43
|
+
/**
|
|
44
|
+
* CLI invocation classification, deliberately cheap (no heavy imports) so the
|
|
45
|
+
* boot entry point can decide what an invocation means without loading either
|
|
46
|
+
* the CLI runner or the server.
|
|
47
|
+
*
|
|
48
|
+
* Starting the gateway is explicit: only `gateway start` boots. Everything else
|
|
49
|
+
* — a bare `claude-gateway`, `--help`, a typo — goes to the CLI, so discovery
|
|
50
|
+
* can never leave a stray server listening on the port.
|
|
51
|
+
*/
|
|
52
|
+
const fs = __importStar(require("fs"));
|
|
8
53
|
/**
|
|
9
54
|
* Set on the gateway's own environment once it has decided to boot, so every
|
|
10
55
|
* process it spawns — agents, and any shell they open — is identifiable as a
|
|
@@ -14,6 +59,48 @@ exports.CHILD_MARKER = 'CLAUDE_GATEWAY_CHILD';
|
|
|
14
59
|
/** Records which supervisor started the gateway, after the inherited markers
|
|
15
60
|
* are scrubbed. Only the boot process sets it; children inherit it unused. */
|
|
16
61
|
exports.SUPERVISOR_MARKER = 'CLAUDE_GATEWAY_SUPERVISOR';
|
|
62
|
+
/**
|
|
63
|
+
* True when this process's immediate parent is systemd itself — not merely a
|
|
64
|
+
* descendant of some process that systemd happens to manage.
|
|
65
|
+
*
|
|
66
|
+
* `INVOCATION_ID` is inherited by every descendant of a systemd unit's main
|
|
67
|
+
* process, including a shell that unit opens. A unit whose only job is to host
|
|
68
|
+
* a terminal (a web-terminal service, say) taints every command a human types
|
|
69
|
+
* into it with an `INVOCATION_ID` that was never meant to identify *that*
|
|
70
|
+
* command. This check is what lets `isSupervised()` tell "systemd forked me
|
|
71
|
+
* directly" from "I'm several processes deep inside something systemd manages".
|
|
72
|
+
*
|
|
73
|
+
* Identified by `comm` name rather than pid, deliberately including `ppid === 1`:
|
|
74
|
+
* on a systemd-based Linux host pid 1 *is* systemd, so its `comm` reads
|
|
75
|
+
* "systemd" like any other systemd process — but pid 1 is not always systemd.
|
|
76
|
+
* A container run with `--init` (tini, dumb-init, s6) or a non-systemd host
|
|
77
|
+
* makes pid 1 something else entirely, and `orphan-receivers.ts` documents the
|
|
78
|
+
* identical ambiguity for its own ppid-based check without resolving it (that
|
|
79
|
+
* function only proves "the parent is gone", so an unverified pid 1 costs it
|
|
80
|
+
* nothing; this one hands out `legacy-boot`, so it can't afford to guess).
|
|
81
|
+
* `systemd --user`'s per-user manager is a different, unpredictable pid, but
|
|
82
|
+
* its `comm` is "systemd" too — the same read covers both without a special
|
|
83
|
+
* case for either.
|
|
84
|
+
*
|
|
85
|
+
* Linux-only (systemd itself is Linux-only) and fails closed: any error, or
|
|
86
|
+
* any other platform, returns `false`. A false negative costs a legacy unit a
|
|
87
|
+
* help screen instead of booting; a false positive risks a second server on
|
|
88
|
+
* the gateway's port, which is the worse failure.
|
|
89
|
+
*
|
|
90
|
+
* `readComm` is injectable for tests — real pid 1 is only genuinely systemd on
|
|
91
|
+
* a systemd-based host, so a test asserting against the live `/proc/1/comm`
|
|
92
|
+
* would pass or fail depending on where it happened to run (a Docker
|
|
93
|
+
* devcontainer's pid 1 is commonly tini or dumb-init). Injecting a fake reader
|
|
94
|
+
* proves the no-special-case behavior deterministically instead.
|
|
95
|
+
*/
|
|
96
|
+
function isDirectSystemdChild(ppid = process.ppid, readComm = (pid) => fs.readFileSync(`/proc/${pid}/comm`, 'utf8')) {
|
|
97
|
+
try {
|
|
98
|
+
return readComm(ppid).trim() === 'systemd';
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
17
104
|
/** True only for the explicit foreground-server invocation. */
|
|
18
105
|
function isGatewayStartInvocation(argv) {
|
|
19
106
|
return argv[0] === 'gateway' && argv[1] === 'start';
|
|
@@ -35,9 +122,25 @@ function isGatewayStartInvocation(argv) {
|
|
|
35
122
|
* The remaining variables are not equal evidence, so they are not weighed
|
|
36
123
|
* equally:
|
|
37
124
|
*
|
|
38
|
-
* - `
|
|
39
|
-
*
|
|
40
|
-
*
|
|
125
|
+
* - `pm_id` is trusted unconditionally — checked *before* `INVOCATION_ID`, not
|
|
126
|
+
* just alongside it, because `pm2 startup systemd` runs the PM2 daemon
|
|
127
|
+
* itself under systemd: a PM2-managed gateway then genuinely has both
|
|
128
|
+
* markers, `INVOCATION_ID` inherited from that systemd-started daemon and
|
|
129
|
+
* `pm_id` set directly by PM2. Its immediate parent is PM2, not systemd, so
|
|
130
|
+
* `parentIsSystemd` is correctly `false` — checking `INVOCATION_ID` first
|
|
131
|
+
* would reject a real pre-1.8 PM2 unit on that basis alone, never reaching
|
|
132
|
+
* the `pm_id` evidence that should have settled it. PM2-managed processes
|
|
133
|
+
* aren't generally used to host an interactive terminal the way a systemd
|
|
134
|
+
* unit can (see `isDirectSystemdChild`), so the same inheritance-based
|
|
135
|
+
* spoofing risk fixed for `INVOCATION_ID` hasn't been observed for `pm_id`
|
|
136
|
+
* itself — an asymmetry, not a proof it can't happen.
|
|
137
|
+
* - `INVOCATION_ID` is *identity minted by systemd*, but only for the exact
|
|
138
|
+
* process it forked — every descendant of that process inherits the same
|
|
139
|
+
* value, including a shell some *other*, unrelated unit opens (a
|
|
140
|
+
* web-terminal service, say). So it is trusted only alongside
|
|
141
|
+
* `signals.parentIsSystemd`, which proves this process — not some ancestor
|
|
142
|
+
* several levels up — is the one systemd actually launched. Once proven, a
|
|
143
|
+
* terminal being attached doesn't overrule it, so a legacy unit with
|
|
41
144
|
* `StandardInput=tty` still boots rather than printing help at its service
|
|
42
145
|
* manager.
|
|
43
146
|
* - `PM2_HOME` is *configuration* — where PM2 keeps its data. An operator can
|
|
@@ -47,8 +150,10 @@ function isGatewayStartInvocation(argv) {
|
|
|
47
150
|
function isSupervised(env, signals = {}) {
|
|
48
151
|
if (env[exports.CHILD_MARKER])
|
|
49
152
|
return false;
|
|
50
|
-
if (env.
|
|
153
|
+
if (env.pm_id !== undefined)
|
|
51
154
|
return true;
|
|
155
|
+
if (env.INVOCATION_ID)
|
|
156
|
+
return signals.parentIsSystemd === true;
|
|
52
157
|
return !!env.PM2_HOME && !signals.hasTty;
|
|
53
158
|
}
|
|
54
159
|
/**
|
|
@@ -106,4 +211,20 @@ function classifyInvocation(argv, env, signals = {}) {
|
|
|
106
211
|
return 'legacy-boot';
|
|
107
212
|
return 'cli';
|
|
108
213
|
}
|
|
214
|
+
/**
|
|
215
|
+
* Builds the `InvocationSignals` for the current process from real OS/env
|
|
216
|
+
* state. Shared by src/entry.ts and src/index.ts — both call
|
|
217
|
+
* `classifyInvocation()` independently (src/index.ts must keep dispatching on
|
|
218
|
+
* its own for service units written before the entry-point split), so without
|
|
219
|
+
* this the same `hasTty`/`parentIsSystemd` construction would live twice and
|
|
220
|
+
* could drift out of sync between the two call sites.
|
|
221
|
+
*/
|
|
222
|
+
function resolveInvocationSignals(env = process.env) {
|
|
223
|
+
return {
|
|
224
|
+
hasTty: process.stdin.isTTY === true,
|
|
225
|
+
// Only isSupervised()'s INVOCATION_ID branch reads this; skip the /proc
|
|
226
|
+
// read entirely otherwise (the common bare-terminal and boot cases).
|
|
227
|
+
parentIsSystemd: env.INVOCATION_ID ? isDirectSystemdChild() : undefined,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
109
230
|
//# sourceMappingURL=command-names.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-names.js","sourceRoot":"","sources":["../../src/cli/command-names.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"command-names.js","sourceRoot":"","sources":["../../src/cli/command-names.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-agent `.env` loading.
|
|
3
|
+
*
|
|
4
|
+
* Agent secrets (bot tokens above all) live in
|
|
5
|
+
* `~/.claude-gateway/agents/<id>/.env` and are referenced from `config.json`
|
|
6
|
+
* as `${VAR}` placeholders. `loadConfig()` resolves those placeholders from
|
|
7
|
+
* `process.env` alone, so the `.env` files must be folded into `process.env`
|
|
8
|
+
* *before* every config load — not just the one at startup.
|
|
9
|
+
*
|
|
10
|
+
* Issue #427: `agent_create` writes a new `agents/<id>/.env` and a `${VAR}`
|
|
11
|
+
* placeholder into `config.json` while the gateway is already running. Without
|
|
12
|
+
* a refresh on reload, that variable is never in `process.env`, the agent is
|
|
13
|
+
* silently dropped from the reloaded snapshot, and `agent.added` never fires —
|
|
14
|
+
* so the handler that *would* have loaded the `.env` is itself unreachable.
|
|
15
|
+
*
|
|
16
|
+
* The same one-way copy makes `process.env` a cache that outlives the file it
|
|
17
|
+
* came from: once a token is in there, a rotated value on disk cannot displace
|
|
18
|
+
* it. That is why this module tracks which variables it injected — see
|
|
19
|
+
* `injected` below.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* The gateway's agents directory — the sibling `agents/` of `config.json`,
|
|
23
|
+
* which is where per-agent workspaces and their `.env` files live.
|
|
24
|
+
*
|
|
25
|
+
* Falls back to `~/.claude-gateway/agents` when there is no config path: the
|
|
26
|
+
* API routers serve requests whose `configPath` may be unset, and the apps
|
|
27
|
+
* agent manager has no config path at all.
|
|
28
|
+
*/
|
|
29
|
+
export declare function agentsDirForConfig(configPath?: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Fold every `agents/<id>/.env` under `gatewayAgentsDir` into `process.env`.
|
|
32
|
+
*
|
|
33
|
+
* Safe to run before each config load: it picks up agents that appeared since
|
|
34
|
+
* the last one, and re-reading an unchanged file changes nothing.
|
|
35
|
+
* A missing directory, an unreadable file, or a `.env` belonging to an agent
|
|
36
|
+
* that is not in the config are all non-fatal: config loading has its own
|
|
37
|
+
* per-agent error handling, and failing here would take the whole gateway down
|
|
38
|
+
* over one bad file.
|
|
39
|
+
*/
|
|
40
|
+
export declare function loadAgentEnvFiles(gatewayAgentsDir: string): void;
|
|
41
|
+
//# sourceMappingURL=agent-env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-env.d.ts","sourceRoot":"","sources":["../../src/config/agent-env.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAI9D;AAkDD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAmBhE"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.agentsDirForConfig = agentsDirForConfig;
|
|
37
|
+
exports.loadAgentEnvFiles = loadAgentEnvFiles;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const os = __importStar(require("os"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const load_dotenv_1 = require("../load-dotenv");
|
|
42
|
+
/**
|
|
43
|
+
* Per-agent `.env` loading.
|
|
44
|
+
*
|
|
45
|
+
* Agent secrets (bot tokens above all) live in
|
|
46
|
+
* `~/.claude-gateway/agents/<id>/.env` and are referenced from `config.json`
|
|
47
|
+
* as `${VAR}` placeholders. `loadConfig()` resolves those placeholders from
|
|
48
|
+
* `process.env` alone, so the `.env` files must be folded into `process.env`
|
|
49
|
+
* *before* every config load — not just the one at startup.
|
|
50
|
+
*
|
|
51
|
+
* Issue #427: `agent_create` writes a new `agents/<id>/.env` and a `${VAR}`
|
|
52
|
+
* placeholder into `config.json` while the gateway is already running. Without
|
|
53
|
+
* a refresh on reload, that variable is never in `process.env`, the agent is
|
|
54
|
+
* silently dropped from the reloaded snapshot, and `agent.added` never fires —
|
|
55
|
+
* so the handler that *would* have loaded the `.env` is itself unreachable.
|
|
56
|
+
*
|
|
57
|
+
* The same one-way copy makes `process.env` a cache that outlives the file it
|
|
58
|
+
* came from: once a token is in there, a rotated value on disk cannot displace
|
|
59
|
+
* it. That is why this module tracks which variables it injected — see
|
|
60
|
+
* `injected` below.
|
|
61
|
+
*/
|
|
62
|
+
/**
|
|
63
|
+
* The gateway's agents directory — the sibling `agents/` of `config.json`,
|
|
64
|
+
* which is where per-agent workspaces and their `.env` files live.
|
|
65
|
+
*
|
|
66
|
+
* Falls back to `~/.claude-gateway/agents` when there is no config path: the
|
|
67
|
+
* API routers serve requests whose `configPath` may be unset, and the apps
|
|
68
|
+
* agent manager has no config path at all.
|
|
69
|
+
*/
|
|
70
|
+
function agentsDirForConfig(configPath) {
|
|
71
|
+
return configPath
|
|
72
|
+
? path.join(path.dirname(configPath), 'agents')
|
|
73
|
+
: path.join(os.homedir(), '.claude-gateway', 'agents');
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Variables this module injected, and the file each one came from.
|
|
77
|
+
*
|
|
78
|
+
* `process.env` is the only thing `loadConfig()` interpolates from, and it is
|
|
79
|
+
* process-lifetime state — so without this ledger there is no way to tell a
|
|
80
|
+
* value the *operator* exported (which must never be clobbered) from one we
|
|
81
|
+
* ourselves copied out of a `.env` on an earlier reload (which is just a stale
|
|
82
|
+
* cache of a file that may since have changed). Both look identical in
|
|
83
|
+
* `process.env`.
|
|
84
|
+
*/
|
|
85
|
+
const injected = new Map();
|
|
86
|
+
/**
|
|
87
|
+
* Fold a single agent's `.env` file into `process.env`.
|
|
88
|
+
*
|
|
89
|
+
* A variable the process already had — exported by the operator, or provided
|
|
90
|
+
* by a *different* agent's `.env` — always wins; the file never clobbers it.
|
|
91
|
+
* A variable this module injected from *this* file is refreshed when the file
|
|
92
|
+
* changes, so a rotated token takes effect on reload instead of the process
|
|
93
|
+
* serving the revoked one until it is restarted.
|
|
94
|
+
*
|
|
95
|
+
* The `value === current` check is what keeps those two cases apart after the
|
|
96
|
+
* first load: if anything else has since assigned to the variable, the ledger
|
|
97
|
+
* no longer matches, ownership is dropped, and the file goes back to losing.
|
|
98
|
+
* Re-loading an unchanged file remains a no-op.
|
|
99
|
+
*
|
|
100
|
+
* Line syntax is `parseDotenv`'s, shared with `~/.claude-gateway/.env`, so a
|
|
101
|
+
* quoted token means the same thing in both places.
|
|
102
|
+
*/
|
|
103
|
+
function loadAgentEnvFile(envFile) {
|
|
104
|
+
for (const { key, value } of (0, load_dotenv_1.parseDotenv)(fs.readFileSync(envFile, 'utf8'))) {
|
|
105
|
+
const current = process.env[key];
|
|
106
|
+
if (current === undefined) {
|
|
107
|
+
process.env[key] = value;
|
|
108
|
+
injected.set(key, { file: envFile, value });
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const owned = injected.get(key);
|
|
112
|
+
if (owned && owned.file === envFile && owned.value === current) {
|
|
113
|
+
if (value !== current) {
|
|
114
|
+
process.env[key] = value;
|
|
115
|
+
injected.set(key, { file: envFile, value });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Fold every `agents/<id>/.env` under `gatewayAgentsDir` into `process.env`.
|
|
122
|
+
*
|
|
123
|
+
* Safe to run before each config load: it picks up agents that appeared since
|
|
124
|
+
* the last one, and re-reading an unchanged file changes nothing.
|
|
125
|
+
* A missing directory, an unreadable file, or a `.env` belonging to an agent
|
|
126
|
+
* that is not in the config are all non-fatal: config loading has its own
|
|
127
|
+
* per-agent error handling, and failing here would take the whole gateway down
|
|
128
|
+
* over one bad file.
|
|
129
|
+
*/
|
|
130
|
+
function loadAgentEnvFiles(gatewayAgentsDir) {
|
|
131
|
+
let entries;
|
|
132
|
+
try {
|
|
133
|
+
if (!fs.existsSync(gatewayAgentsDir))
|
|
134
|
+
return;
|
|
135
|
+
entries = fs.readdirSync(gatewayAgentsDir);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
for (const agentId of entries) {
|
|
141
|
+
const envFile = path.join(gatewayAgentsDir, agentId, '.env');
|
|
142
|
+
try {
|
|
143
|
+
if (!fs.existsSync(envFile))
|
|
144
|
+
continue;
|
|
145
|
+
loadAgentEnvFile(envFile);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
// Unreadable .env (permissions, race with a concurrent write): skip it
|
|
149
|
+
// and let loadConfig() report the resulting unresolvable ${VAR}.
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=agent-env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-env.js","sourceRoot":"","sources":["../../src/config/agent-env.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,gDAIC;AA4DD,8CAmBC;AArHD,uCAAyB;AACzB,uCAAyB;AACzB,2CAA6B;AAC7B,gDAA6C;AAE7C;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;;;;GAOG;AACH,SAAgB,kBAAkB,CAAC,UAAmB;IACpD,OAAO,UAAU;QACf,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC;QAC/C,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,iBAAiB,EAAE,QAAQ,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA2C,CAAC;AAEpE;;;;;;;;;;;;;;;;GAgBG;AACH,SAAS,gBAAgB,CAAC,OAAe;IACvC,KAAK,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,IAAA,yBAAW,EAAC,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;QAC3E,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YACzB,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YAC5C,SAAS;QACX,CAAC;QAED,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;YAC/D,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;gBACtB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;gBACzB,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,iBAAiB,CAAC,gBAAwB;IACxD,IAAI,OAAiB,CAAC;IACtB,IAAI,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC;YAAE,OAAO;QAC7C,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;IACT,CAAC;IACD,KAAK,MAAM,OAAO,IAAI,OAAO,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7D,IAAI,CAAC;YACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;gBAAE,SAAS;YACtC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,uEAAuE;YACvE,iEAAiE;YACjE,SAAS;QACX,CAAC;IACH,CAAC;AACH,CAAC"}
|
package/dist/config/loader.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GatewayConfig } from '../types';
|
|
1
|
+
import { GatewayConfig, Logger } from '../types';
|
|
2
2
|
export declare class ConfigValidationError extends Error {
|
|
3
3
|
constructor(message: string);
|
|
4
4
|
}
|
|
@@ -6,11 +6,42 @@ export declare class DuplicateAgentIdError extends Error {
|
|
|
6
6
|
constructor(id: string);
|
|
7
7
|
}
|
|
8
8
|
export declare class MissingEnvVarError extends Error {
|
|
9
|
+
/**
|
|
10
|
+
* The unresolved variable, exposed separately so callers can log it as a
|
|
11
|
+
* field instead of scraping it back out of `message`.
|
|
12
|
+
*/
|
|
13
|
+
readonly varName: string;
|
|
9
14
|
constructor(varName: string);
|
|
10
15
|
}
|
|
16
|
+
/** An agent that was dropped from the loaded config rather than started. */
|
|
17
|
+
export interface SkippedAgent {
|
|
18
|
+
/** The agent's id, or `index N` when the entry was too malformed to have one. */
|
|
19
|
+
id: string;
|
|
20
|
+
/** Human-readable cause, e.g. `Missing environment variable: ACME_BOT_TOKEN`. */
|
|
21
|
+
reason: string;
|
|
22
|
+
/** Set only when the agent was dropped because a `${VAR}` did not resolve. */
|
|
23
|
+
missingVar?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface LoadConfigOptions {
|
|
26
|
+
/**
|
|
27
|
+
* Called once per dropped agent. Skipping is deliberately non-fatal (one bad
|
|
28
|
+
* agent must not take the gateway down), which historically made it invisible:
|
|
29
|
+
* the only signal was a `console.warn` that never reaches `logs/gateway.log`.
|
|
30
|
+
* Callers that have a structured logger should pass this so a dropped agent
|
|
31
|
+
* is diagnosable — see issue #427.
|
|
32
|
+
*/
|
|
33
|
+
onSkippedAgent?: (skipped: SkippedAgent) => void;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Emit one `SkippedAgent` through a caller's structured logger.
|
|
37
|
+
*
|
|
38
|
+
* Shared by the startup load and every reload so both write the same fields
|
|
39
|
+
* under the same key — `grep "Agent skipped" logs/gateway.log` finds either.
|
|
40
|
+
*/
|
|
41
|
+
export declare function logSkippedAgents(logger: Logger, skipped: readonly SkippedAgent[], message: string): void;
|
|
11
42
|
/**
|
|
12
43
|
* Load and validate config.json from the given path.
|
|
13
44
|
* Interpolates ${VAR} env vars throughout the config.
|
|
14
45
|
*/
|
|
15
|
-
export declare function loadConfig(configPath: string): GatewayConfig;
|
|
46
|
+
export declare function loadConfig(configPath: string, options?: LoadConfigOptions): GatewayConfig;
|
|
16
47
|
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGjD,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,EAAE,EAAE,MAAM;CAIvB;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAEb,OAAO,EAAE,MAAM;CAK5B;AAuED,4EAA4E;AAC5E,MAAM,WAAW,YAAY;IAC3B,iFAAiF;IACjF,EAAE,EAAE,MAAM,CAAC;IACX,iFAAiF;IACjF,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;CAClD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,OAAO,EAAE,MAAM,GACd,IAAI,CAQN;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,aAAa,CAwJzF"}
|
package/dist/config/loader.js
CHANGED
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.MissingEnvVarError = exports.DuplicateAgentIdError = exports.ConfigValidationError = void 0;
|
|
37
|
+
exports.logSkippedAgents = logSkippedAgents;
|
|
37
38
|
exports.loadConfig = loadConfig;
|
|
38
39
|
const fs = __importStar(require("fs"));
|
|
39
40
|
const public_url_1 = require("./public-url");
|
|
@@ -55,6 +56,7 @@ class MissingEnvVarError extends Error {
|
|
|
55
56
|
constructor(varName) {
|
|
56
57
|
super(`Missing environment variable: ${varName}`);
|
|
57
58
|
this.name = 'MissingEnvVarError';
|
|
59
|
+
this.varName = varName;
|
|
58
60
|
}
|
|
59
61
|
}
|
|
60
62
|
exports.MissingEnvVarError = MissingEnvVarError;
|
|
@@ -123,11 +125,38 @@ function validateAgent(agent, index) {
|
|
|
123
125
|
}
|
|
124
126
|
return null;
|
|
125
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Emit one `SkippedAgent` through a caller's structured logger.
|
|
130
|
+
*
|
|
131
|
+
* Shared by the startup load and every reload so both write the same fields
|
|
132
|
+
* under the same key — `grep "Agent skipped" logs/gateway.log` finds either.
|
|
133
|
+
*/
|
|
134
|
+
function logSkippedAgents(logger, skipped, message) {
|
|
135
|
+
for (const s of skipped) {
|
|
136
|
+
logger.warn(message, {
|
|
137
|
+
id: s.id,
|
|
138
|
+
reason: s.reason,
|
|
139
|
+
...(s.missingVar ? { missingVar: s.missingVar } : {}),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
126
143
|
/**
|
|
127
144
|
* Load and validate config.json from the given path.
|
|
128
145
|
* Interpolates ${VAR} env vars throughout the config.
|
|
129
146
|
*/
|
|
130
|
-
function loadConfig(configPath) {
|
|
147
|
+
function loadConfig(configPath, options) {
|
|
148
|
+
const skippedAgents = [];
|
|
149
|
+
/**
|
|
150
|
+
* The single place an agent is dropped. Both the console warning and the
|
|
151
|
+
* structured-logger callback go through here on purpose: when they were two
|
|
152
|
+
* parallel statements per call site, a new skip site could easily carry one
|
|
153
|
+
* and not the other — reintroducing exactly the invisible drop of #427.
|
|
154
|
+
*/
|
|
155
|
+
const skipAgent = (id, reason, missingVar) => {
|
|
156
|
+
console.warn(`[gateway] Skipping agent "${id}": ${reason}`);
|
|
157
|
+
skippedAgents.push(id);
|
|
158
|
+
options?.onSkippedAgent?.({ id, reason, ...(missingVar ? { missingVar } : {}) });
|
|
159
|
+
};
|
|
131
160
|
let raw;
|
|
132
161
|
try {
|
|
133
162
|
raw = fs.readFileSync(configPath, 'utf-8');
|
|
@@ -154,19 +183,15 @@ function loadConfig(configPath) {
|
|
|
154
183
|
}
|
|
155
184
|
// Validate each agent before interpolation — skip invalid agents with a warning
|
|
156
185
|
const validAgents = [];
|
|
157
|
-
const skippedAgents = [];
|
|
158
186
|
for (let i = 0; i < config.agents.length; i++) {
|
|
159
187
|
const agent = config.agents[i];
|
|
160
188
|
if (typeof agent !== 'object' || agent === null) {
|
|
161
|
-
|
|
162
|
-
skippedAgents.push(`index ${i}`);
|
|
189
|
+
skipAgent(`index ${i}`, 'Config entry must be an object');
|
|
163
190
|
continue;
|
|
164
191
|
}
|
|
165
192
|
const error = validateAgent(agent, i);
|
|
166
193
|
if (error) {
|
|
167
|
-
|
|
168
|
-
console.warn(`[gateway] Skipping agent "${agentId}": ${error}`);
|
|
169
|
-
skippedAgents.push(String(agentId));
|
|
194
|
+
skipAgent(String(agent.id || `index ${i}`), error);
|
|
170
195
|
continue;
|
|
171
196
|
}
|
|
172
197
|
validAgents.push(agent);
|
|
@@ -230,8 +255,7 @@ function loadConfig(configPath) {
|
|
|
230
255
|
}
|
|
231
256
|
catch (err) {
|
|
232
257
|
if (err instanceof MissingEnvVarError) {
|
|
233
|
-
|
|
234
|
-
skippedAgents.push(String(agent.id));
|
|
258
|
+
skipAgent(String(agent.id), err.message, err.varName);
|
|
235
259
|
continue;
|
|
236
260
|
}
|
|
237
261
|
throw err;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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"}
|
package/dist/config/watcher.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export declare class ConfigWatcher extends EventEmitter {
|
|
|
17
17
|
on(event: 'channel.removed', listener: (agentId: string, channel: string) => void): this;
|
|
18
18
|
private watchHandle;
|
|
19
19
|
private currentConfig;
|
|
20
|
+
private readonly agentsDir;
|
|
20
21
|
constructor(configPath: string, initialConfig: GatewayConfig, logger: Logger);
|
|
21
22
|
start(): void;
|
|
22
23
|
stop(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../../src/config/watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../../src/config/watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAGtC,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAK9D,QAAA,MAAM,2BAA2B,EAAE,MAAM,EAMxC,CAAC;AAOF,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;CACxB;AAOD,qBAAa,aAAc,SAAQ,YAAY;IAe3C,OAAO,CAAC,QAAQ,CAAC,UAAU;IAE3B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAhBzB,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,KAAK,IAAI,GAAG,IAAI;IACrH,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,IAAI;IACtE,EAAE,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IACtF,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAMxF,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAGhB,UAAU,EAAE,MAAM,EACnC,aAAa,EAAE,aAAa,EACX,MAAM,EAAE,MAAM;IAOjC,KAAK,IAAI,IAAI;IASb,IAAI,IAAI,IAAI;IAKZ,kCAAkC;IAClC,SAAS,IAAI,aAAa;IAI1B,MAAM,IAAI,IAAI;IAgGd,OAAO,CAAC,UAAU;CAoEnB;AAED,2EAA2E;AAC3E,iBAAS,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAoBlD;AAGD,OAAO,EAAE,SAAS,IAAI,UAAU,EAAE,2BAA2B,EAAE,CAAC"}
|
package/dist/config/watcher.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.HOT_RELOADABLE_AGENT_FIELDS = exports.ConfigWatcher = void 0;
|
|
|
4
4
|
exports._deepEqual = deepEqual;
|
|
5
5
|
const events_1 = require("events");
|
|
6
6
|
const loader_1 = require("./loader");
|
|
7
|
+
const agent_env_1 = require("./agent-env");
|
|
7
8
|
const factory_1 = require("../watch/factory");
|
|
8
9
|
const paths_1 = require("../utils/paths");
|
|
9
10
|
// Fields that can be hot-reloaded without restarting the gateway
|
|
@@ -30,6 +31,7 @@ class ConfigWatcher extends events_1.EventEmitter {
|
|
|
30
31
|
this.logger = logger;
|
|
31
32
|
this.watchHandle = null;
|
|
32
33
|
this.currentConfig = structuredClone(initialConfig);
|
|
34
|
+
this.agentsDir = (0, agent_env_1.agentsDirForConfig)(configPath);
|
|
33
35
|
}
|
|
34
36
|
start() {
|
|
35
37
|
this.watchHandle = (0, factory_1.createWatcher)({
|
|
@@ -48,9 +50,20 @@ class ConfigWatcher extends events_1.EventEmitter {
|
|
|
48
50
|
return this.currentConfig;
|
|
49
51
|
}
|
|
50
52
|
reload() {
|
|
53
|
+
// Fold any per-agent .env files into process.env BEFORE interpolation.
|
|
54
|
+
// An agent added while the gateway is running (MCP `agent_create`) writes
|
|
55
|
+
// its token to a brand-new agents/<id>/.env and only a ${VAR} placeholder
|
|
56
|
+
// into config.json. Without this refresh that variable is absent from
|
|
57
|
+
// process.env, loadConfig() drops the agent, the diff below sees nothing,
|
|
58
|
+
// and `agent.added` — whose handler is what used to load the .env — never
|
|
59
|
+
// fires. Issue #427.
|
|
60
|
+
(0, agent_env_1.loadAgentEnvFiles)(this.agentsDir);
|
|
51
61
|
let newConfig;
|
|
62
|
+
const skipped = [];
|
|
52
63
|
try {
|
|
53
|
-
newConfig = (0, loader_1.loadConfig)(this.configPath
|
|
64
|
+
newConfig = (0, loader_1.loadConfig)(this.configPath, {
|
|
65
|
+
onSkippedAgent: (s) => skipped.push(s),
|
|
66
|
+
});
|
|
54
67
|
newConfig.gateway.logDir = (0, paths_1.expandHome)(newConfig.gateway.logDir);
|
|
55
68
|
}
|
|
56
69
|
catch (err) {
|
|
@@ -59,6 +72,9 @@ class ConfigWatcher extends events_1.EventEmitter {
|
|
|
59
72
|
});
|
|
60
73
|
return;
|
|
61
74
|
}
|
|
75
|
+
// Report drops before the no-change bail-out below: a silently dropped
|
|
76
|
+
// agent produces exactly zero diff, so this is the only trace it leaves.
|
|
77
|
+
(0, loader_1.logSkippedAgents)(this.logger, skipped, 'Agent skipped during config reload');
|
|
62
78
|
const { fieldChanges, addedAgents } = this.diffConfig(this.currentConfig, newConfig);
|
|
63
79
|
if (fieldChanges.length === 0 && addedAgents.length === 0) {
|
|
64
80
|
this.logger.info('Config file changed but no effective differences detected');
|