dexe-mcp 0.7.2 → 0.8.1

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 (91) hide show
  1. package/CHANGELOG.md +129 -0
  2. package/README.md +19 -1
  3. package/dist/cli/doctor.d.ts +11 -0
  4. package/dist/cli/doctor.d.ts.map +1 -0
  5. package/dist/cli/doctor.js +44 -0
  6. package/dist/cli/doctor.js.map +1 -0
  7. package/dist/cli/init.d.ts +2 -0
  8. package/dist/cli/init.d.ts.map +1 -0
  9. package/dist/cli/init.js +306 -0
  10. package/dist/cli/init.js.map +1 -0
  11. package/dist/diag/checks.d.ts +25 -0
  12. package/dist/diag/checks.d.ts.map +1 -0
  13. package/dist/diag/checks.js +387 -0
  14. package/dist/diag/checks.js.map +1 -0
  15. package/dist/env/loader.d.ts +43 -0
  16. package/dist/env/loader.d.ts.map +1 -0
  17. package/dist/env/loader.js +121 -0
  18. package/dist/env/loader.js.map +1 -0
  19. package/dist/env/parse.d.ts +23 -0
  20. package/dist/env/parse.d.ts.map +1 -0
  21. package/dist/env/parse.js +41 -0
  22. package/dist/env/parse.js.map +1 -0
  23. package/dist/env/schema.d.ts +257 -0
  24. package/dist/env/schema.d.ts.map +1 -0
  25. package/dist/env/schema.js +240 -0
  26. package/dist/env/schema.js.map +1 -0
  27. package/dist/governor/tools/extras.js +12 -3
  28. package/dist/governor/tools/extras.js.map +1 -1
  29. package/dist/governor/tools/read.js +16 -4
  30. package/dist/governor/tools/read.js.map +1 -1
  31. package/dist/governor/tools/simulate.d.ts.map +1 -1
  32. package/dist/governor/tools/simulate.js +8 -2
  33. package/dist/governor/tools/simulate.js.map +1 -1
  34. package/dist/index.js +31 -11
  35. package/dist/index.js.map +1 -1
  36. package/dist/lib/requireEnv.d.ts +30 -0
  37. package/dist/lib/requireEnv.d.ts.map +1 -0
  38. package/dist/lib/requireEnv.js +48 -0
  39. package/dist/lib/requireEnv.js.map +1 -0
  40. package/dist/lib/signer.d.ts +8 -0
  41. package/dist/lib/signer.d.ts.map +1 -1
  42. package/dist/lib/signer.js +18 -0
  43. package/dist/lib/signer.js.map +1 -1
  44. package/dist/rpc.d.ts +8 -0
  45. package/dist/rpc.d.ts.map +1 -1
  46. package/dist/rpc.js +18 -0
  47. package/dist/rpc.js.map +1 -1
  48. package/dist/tools/dao.d.ts.map +1 -1
  49. package/dist/tools/dao.js +25 -10
  50. package/dist/tools/dao.js.map +1 -1
  51. package/dist/tools/daoDeploy.js +8 -2
  52. package/dist/tools/daoDeploy.js.map +1 -1
  53. package/dist/tools/doctor.d.ts +11 -0
  54. package/dist/tools/doctor.d.ts.map +1 -0
  55. package/dist/tools/doctor.js +75 -0
  56. package/dist/tools/doctor.js.map +1 -0
  57. package/dist/tools/flow.d.ts.map +1 -1
  58. package/dist/tools/flow.js +16 -4
  59. package/dist/tools/flow.js.map +1 -1
  60. package/dist/tools/gov.js +8 -14
  61. package/dist/tools/gov.js.map +1 -1
  62. package/dist/tools/inbox.d.ts.map +1 -1
  63. package/dist/tools/inbox.js +7 -1
  64. package/dist/tools/inbox.js.map +1 -1
  65. package/dist/tools/index.d.ts.map +1 -1
  66. package/dist/tools/index.js +3 -0
  67. package/dist/tools/index.js.map +1 -1
  68. package/dist/tools/otc.d.ts.map +1 -1
  69. package/dist/tools/otc.js +15 -3
  70. package/dist/tools/otc.js.map +1 -1
  71. package/dist/tools/predict.d.ts.map +1 -1
  72. package/dist/tools/predict.js +7 -1
  73. package/dist/tools/predict.js.map +1 -1
  74. package/dist/tools/proposal.js +8 -2
  75. package/dist/tools/proposal.js.map +1 -1
  76. package/dist/tools/read.js +40 -10
  77. package/dist/tools/read.js.map +1 -1
  78. package/dist/tools/safe.d.ts.map +1 -1
  79. package/dist/tools/safe.js +12 -3
  80. package/dist/tools/safe.js.map +1 -1
  81. package/dist/tools/simulate.d.ts.map +1 -1
  82. package/dist/tools/simulate.js +16 -3
  83. package/dist/tools/simulate.js.map +1 -1
  84. package/dist/tools/subgraph.js +4 -1
  85. package/dist/tools/subgraph.js.map +1 -1
  86. package/dist/tools/txSend.d.ts.map +1 -1
  87. package/dist/tools/txSend.js +18 -1
  88. package/dist/tools/txSend.js.map +1 -1
  89. package/dist/tools/vote.js +8 -2
  90. package/dist/tools/vote.js.map +1 -1
  91. package/package.json +5 -2
@@ -0,0 +1,387 @@
1
+ import { resolve as dnsResolve } from "node:dns/promises";
2
+ import { ENV_REGISTRY } from "../env/schema.js";
3
+ import { parseEnv } from "../env/parse.js";
4
+ /**
5
+ * Run every diagnostic check in parallel, gather results.
6
+ *
7
+ * Network checks have a hard timeout that downgrades to `warn`, never `fail` —
8
+ * an offline laptop or VPN flake should not make the doctor scream red.
9
+ */
10
+ export async function runAllChecks(opts = {}) {
11
+ const timeoutMs = opts.timeoutMs ?? 3000;
12
+ const results = [];
13
+ results.push(...envPresenceChecks());
14
+ const network = await Promise.all([
15
+ ...rpcReachabilityChecks(opts.config, timeoutMs),
16
+ pinataJwtCheck(timeoutMs),
17
+ ipfsGatewayDnsCheck(timeoutMs),
18
+ ...subgraphChecks(timeoutMs),
19
+ backendCheck(timeoutMs),
20
+ ]);
21
+ for (const r of network) {
22
+ if (r)
23
+ results.push(r);
24
+ }
25
+ results.push(...signerGuardConfigCheck());
26
+ results.push(...chainConsistencyCheck(opts.config));
27
+ return results;
28
+ }
29
+ // ─── presence ───────────────────────────────────────────────────────────────
30
+ function envPresenceChecks() {
31
+ const out = [];
32
+ const parsed = parseEnv();
33
+ for (const [k, v] of Object.entries(ENV_REGISTRY)) {
34
+ const set = !!process.env[k]?.trim();
35
+ const issue = parsed.issues.find(i => i.key === k);
36
+ if (issue) {
37
+ out.push({
38
+ id: `env.${k}`,
39
+ category: v.category,
40
+ status: "fail",
41
+ message: issue.message,
42
+ remediation: `Fix ${k} in .env. ${v.doc}`,
43
+ });
44
+ }
45
+ else if (set) {
46
+ out.push({
47
+ id: `env.${k}`,
48
+ category: v.category,
49
+ status: "pass",
50
+ message: v.secret ? "set (redacted)" : "set",
51
+ });
52
+ }
53
+ else if (v.required) {
54
+ out.push({
55
+ id: `env.${k}`,
56
+ category: v.category,
57
+ status: "fail",
58
+ message: "not set (required)",
59
+ remediation: `Add ${k}=${v.example} to .env. ${v.doc}`,
60
+ });
61
+ }
62
+ // optional + unset: emit nothing (avoid noise)
63
+ }
64
+ return out;
65
+ }
66
+ // ─── rpc reachability ──────────────────────────────────────────────────────
67
+ function rpcReachabilityChecks(config, timeoutMs) {
68
+ if (!config || config.chains.size === 0)
69
+ return [];
70
+ const out = [];
71
+ for (const chain of config.chains.values()) {
72
+ out.push((async () => {
73
+ const res = await fetchJsonWithTimeout(chain.rpcUrl, {
74
+ method: "POST",
75
+ headers: { "content-type": "application/json" },
76
+ body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_chainId", params: [] }),
77
+ }, timeoutMs);
78
+ if (res.kind === "timeout") {
79
+ return {
80
+ id: `rpc.reachable.${chain.chainId}`,
81
+ category: "network",
82
+ status: "warn",
83
+ message: `RPC ${chain.rpcUrl} timed out after ${timeoutMs}ms`,
84
+ remediation: "Check connectivity. If intermittent, ignore. Otherwise pick a different RPC at https://chainlist.org.",
85
+ };
86
+ }
87
+ if (res.kind === "error") {
88
+ return {
89
+ id: `rpc.reachable.${chain.chainId}`,
90
+ category: "network",
91
+ status: "fail",
92
+ message: `RPC ${chain.rpcUrl} unreachable: ${res.error}`,
93
+ remediation: "Replace the RPC URL. Browse alternatives at https://chainlist.org and restart the MCP.",
94
+ };
95
+ }
96
+ const expected = `0x${chain.chainId.toString(16)}`;
97
+ const got = res.body?.result;
98
+ if (got !== expected) {
99
+ return {
100
+ id: `rpc.reachable.${chain.chainId}`,
101
+ category: "network",
102
+ status: "fail",
103
+ message: `RPC returned chainId=${got ?? "?"} but configured chainId=${chain.chainId}`,
104
+ remediation: `RPC at ${chain.rpcUrl} is for the wrong chain. Replace it.`,
105
+ };
106
+ }
107
+ return {
108
+ id: `rpc.reachable.${chain.chainId}`,
109
+ category: "network",
110
+ status: "pass",
111
+ message: `eth_chainId=${chain.chainId} (${chain.rpcUrl})`,
112
+ };
113
+ })());
114
+ }
115
+ return out;
116
+ }
117
+ // ─── pinata jwt ──────────────────────────────────────────────────────────
118
+ async function pinataJwtCheck(timeoutMs) {
119
+ const jwt = process.env.DEXE_PINATA_JWT?.trim();
120
+ if (!jwt)
121
+ return null;
122
+ const res = await fetchJsonWithTimeout("https://api.pinata.cloud/data/testAuthentication", { method: "GET", headers: { Authorization: `Bearer ${jwt}` } }, timeoutMs);
123
+ if (res.kind === "timeout") {
124
+ return {
125
+ id: "pinata.jwt",
126
+ category: "ipfs",
127
+ status: "warn",
128
+ message: `Pinata auth check timed out (${timeoutMs}ms)`,
129
+ };
130
+ }
131
+ if (res.kind === "error") {
132
+ return {
133
+ id: "pinata.jwt",
134
+ category: "ipfs",
135
+ status: "fail",
136
+ message: `Pinata reachability: ${res.error}`,
137
+ };
138
+ }
139
+ if (res.status >= 400) {
140
+ return {
141
+ id: "pinata.jwt",
142
+ category: "ipfs",
143
+ status: "fail",
144
+ message: `Pinata testAuthentication returned HTTP ${res.status}`,
145
+ remediation: "Regenerate the JWT at https://app.pinata.cloud/developers/api-keys with `pinning` scope and update DEXE_PINATA_JWT.",
146
+ };
147
+ }
148
+ return { id: "pinata.jwt", category: "ipfs", status: "pass", message: "authenticated" };
149
+ }
150
+ // ─── ipfs gateway dns ──────────────────────────────────────────────────────
151
+ async function ipfsGatewayDnsCheck(timeoutMs) {
152
+ const gw = process.env.DEXE_IPFS_GATEWAY?.trim();
153
+ if (!gw)
154
+ return null;
155
+ let host;
156
+ try {
157
+ host = new URL(gw).hostname;
158
+ }
159
+ catch {
160
+ return {
161
+ id: "ipfs.gateway.dns",
162
+ category: "ipfs",
163
+ status: "fail",
164
+ message: "DEXE_IPFS_GATEWAY is not a valid URL",
165
+ remediation: "Use the form https://<subdomain>.mypinata.cloud",
166
+ };
167
+ }
168
+ try {
169
+ await Promise.race([
170
+ dnsResolve(host),
171
+ new Promise((_, rej) => setTimeout(() => rej(new Error("timeout")), timeoutMs)),
172
+ ]);
173
+ return {
174
+ id: "ipfs.gateway.dns",
175
+ category: "ipfs",
176
+ status: "pass",
177
+ message: `resolved ${host}`,
178
+ };
179
+ }
180
+ catch (err) {
181
+ return {
182
+ id: "ipfs.gateway.dns",
183
+ category: "ipfs",
184
+ status: "fail",
185
+ message: `DNS lookup for ${host} failed: ${err instanceof Error ? err.message : String(err)}`,
186
+ remediation: "Check the hostname in DEXE_IPFS_GATEWAY. Pinata dedicated gateways follow https://<subdomain>.mypinata.cloud.",
187
+ };
188
+ }
189
+ }
190
+ // ─── subgraph reachability ─────────────────────────────────────────────────
191
+ function subgraphChecks(timeoutMs) {
192
+ const out = [];
193
+ const targets = [
194
+ { key: "DEXE_SUBGRAPH_POOLS_URL", id: "subgraph.pools" },
195
+ { key: "DEXE_SUBGRAPH_VALIDATORS_URL", id: "subgraph.validators" },
196
+ { key: "DEXE_SUBGRAPH_INTERACTIONS_URL", id: "subgraph.interactions" },
197
+ ];
198
+ const apiKey = process.env.DEXE_GRAPH_API_KEY?.trim();
199
+ for (const t of targets) {
200
+ const url = process.env[t.key]?.trim();
201
+ if (!url)
202
+ continue;
203
+ out.push((async () => {
204
+ const headers = { "content-type": "application/json" };
205
+ if (apiKey)
206
+ headers.Authorization = `Bearer ${apiKey}`;
207
+ const res = await fetchJsonWithTimeout(url, { method: "POST", headers, body: JSON.stringify({ query: "{ __typename }" }) }, timeoutMs);
208
+ if (res.kind === "timeout") {
209
+ return {
210
+ id: `${t.id}.reachable`,
211
+ category: "network",
212
+ status: "warn",
213
+ message: `${t.key} timed out`,
214
+ };
215
+ }
216
+ if (res.kind === "error") {
217
+ return {
218
+ id: `${t.id}.reachable`,
219
+ category: "network",
220
+ status: "fail",
221
+ message: `${t.key}: ${res.error}`,
222
+ };
223
+ }
224
+ if (res.status >= 400) {
225
+ return {
226
+ id: `${t.id}.reachable`,
227
+ category: "network",
228
+ status: "fail",
229
+ message: `${t.key} returned HTTP ${res.status}`,
230
+ remediation: "Check the URL and DEXE_GRAPH_API_KEY (decentralized gateway requires Bearer auth).",
231
+ };
232
+ }
233
+ return {
234
+ id: `${t.id}.reachable`,
235
+ category: "network",
236
+ status: "pass",
237
+ message: "ok",
238
+ };
239
+ })());
240
+ }
241
+ return out;
242
+ }
243
+ // ─── backend ─────────────────────────────────────────────────────────────
244
+ async function backendCheck(timeoutMs) {
245
+ const url = process.env.DEXE_BACKEND_API_URL?.trim();
246
+ if (!url)
247
+ return null;
248
+ const target = url.replace(/\/+$/, "") + "/";
249
+ const res = await fetchJsonWithTimeout(target, { method: "GET" }, timeoutMs);
250
+ if (res.kind === "timeout") {
251
+ return {
252
+ id: "backend.reachable",
253
+ category: "network",
254
+ status: "warn",
255
+ message: `${url} timed out`,
256
+ };
257
+ }
258
+ if (res.kind === "error") {
259
+ return {
260
+ id: "backend.reachable",
261
+ category: "network",
262
+ status: "fail",
263
+ message: `${url}: ${res.error}`,
264
+ };
265
+ }
266
+ return {
267
+ id: "backend.reachable",
268
+ category: "network",
269
+ status: "pass",
270
+ message: `HTTP ${res.status}`,
271
+ };
272
+ }
273
+ // ─── signer broadcast guards ─────────────────────────────────────────────
274
+ function signerGuardConfigCheck() {
275
+ const out = [];
276
+ const allow = process.env.DEXE_SIGNER_ALLOWLIST?.trim();
277
+ if (allow) {
278
+ const entries = allow.split(",").map(s => s.trim()).filter(Boolean);
279
+ const bad = entries.filter(e => !/^0x[0-9a-fA-F]{40}$/.test(e));
280
+ if (bad.length) {
281
+ out.push({
282
+ id: "signer.allowlist",
283
+ category: "signer",
284
+ status: "fail",
285
+ message: `invalid address(es): ${bad.join(", ")}`,
286
+ });
287
+ }
288
+ else {
289
+ out.push({
290
+ id: "signer.allowlist",
291
+ category: "signer",
292
+ status: "pass",
293
+ message: `${entries.length} addr(s) allowed`,
294
+ });
295
+ }
296
+ }
297
+ const maxV = process.env.DEXE_SIGNER_MAX_VALUE_WEI?.trim();
298
+ if (maxV) {
299
+ try {
300
+ BigInt(maxV);
301
+ out.push({
302
+ id: "signer.maxValue",
303
+ category: "signer",
304
+ status: "pass",
305
+ message: `cap=${maxV} wei`,
306
+ });
307
+ }
308
+ catch {
309
+ out.push({
310
+ id: "signer.maxValue",
311
+ category: "signer",
312
+ status: "fail",
313
+ message: `not a wei integer: ${maxV}`,
314
+ });
315
+ }
316
+ }
317
+ const rate = process.env.DEXE_SIGNER_MAX_BROADCASTS_PER_MIN?.trim();
318
+ if (rate) {
319
+ const n = Number(rate);
320
+ if (Number.isInteger(n) && n > 0) {
321
+ out.push({
322
+ id: "signer.rate",
323
+ category: "signer",
324
+ status: "pass",
325
+ message: `${n}/min`,
326
+ });
327
+ }
328
+ else {
329
+ out.push({
330
+ id: "signer.rate",
331
+ category: "signer",
332
+ status: "fail",
333
+ message: `not a positive int: ${rate}`,
334
+ });
335
+ }
336
+ }
337
+ return out;
338
+ }
339
+ // ─── chain consistency ───────────────────────────────────────────────────
340
+ function chainConsistencyCheck(config) {
341
+ if (!config)
342
+ return [];
343
+ const out = [];
344
+ if (process.env.DEXE_PRIVATE_KEY?.trim() && config.chains.size === 0) {
345
+ out.push({
346
+ id: "chain.signerNeedsRpc",
347
+ category: "signer",
348
+ status: "fail",
349
+ message: "DEXE_PRIVATE_KEY is set but no RPC is configured — broadcasts will fail.",
350
+ remediation: "Set DEXE_RPC_URL_TESTNET or DEXE_RPC_URL_MAINNET in .env.",
351
+ });
352
+ }
353
+ if (config.chains.size > 0) {
354
+ const ids = [...config.chains.keys()].sort((a, b) => a - b);
355
+ out.push({
356
+ id: "chain.consistency",
357
+ category: "rpc",
358
+ status: "pass",
359
+ message: `defaultChainId=${config.defaultChainId} in configured=[${ids.join(", ")}]`,
360
+ });
361
+ }
362
+ return out;
363
+ }
364
+ async function fetchJsonWithTimeout(url, init, timeoutMs) {
365
+ const ctrl = new AbortController();
366
+ const timer = setTimeout(() => ctrl.abort(), timeoutMs);
367
+ try {
368
+ const r = await fetch(url, { ...init, signal: ctrl.signal });
369
+ let body = undefined;
370
+ try {
371
+ body = await r.json();
372
+ }
373
+ catch {
374
+ // not json — ignore
375
+ }
376
+ return { kind: "ok", status: r.status, body };
377
+ }
378
+ catch (err) {
379
+ if (err.name === "AbortError")
380
+ return { kind: "timeout" };
381
+ return { kind: "error", error: err instanceof Error ? err.message : String(err) };
382
+ }
383
+ finally {
384
+ clearTimeout(timer);
385
+ }
386
+ }
387
+ //# sourceMappingURL=checks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checks.js","sourceRoot":"","sources":["../../src/diag/checks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { type EnvKey } from "./schema.js";
2
+ /**
3
+ * Diagnostic report produced by `loadEnvFile`. Written to stderr by
4
+ * `writeStartupBanner` and surfaced via `dexe_doctor`.
5
+ */
6
+ export interface EnvLoadReport {
7
+ envFilePath: string;
8
+ envFileExists: boolean;
9
+ envFileLoaded: boolean;
10
+ loadedNodeVersion: string;
11
+ /** Raw-byte parse warnings (BOM, missing trailing newline, spaces around =). */
12
+ parseWarnings: string[];
13
+ /** DEXE_* vars in process.env that ENV_SPEC does not know about. */
14
+ unknownDexeVars: string[];
15
+ /** Vars that are NOT set but would unlock a common flow if they were. */
16
+ missingButEnablesFlows: Array<{
17
+ key: EnvKey;
18
+ flows: readonly string[];
19
+ }>;
20
+ /**
21
+ * Schema keys that were already in process.env BEFORE .env was loaded —
22
+ * meaning they were injected by the MCP host (.claude.json env block) and
23
+ * SHADOW the .env file. Subtle precedence trap.
24
+ */
25
+ preExistingVars: EnvKey[];
26
+ }
27
+ /**
28
+ * Read .env from disk, scan its raw bytes for common parse-traps, then call
29
+ * `process.loadEnvFile()`. Never throws; surfaces problems via the returned
30
+ * report so the startup banner and doctor can show them.
31
+ *
32
+ * @param envFilePath absolute path to the .env file
33
+ * @param prevEnvSnapshot set of DEXE_* keys that were already in
34
+ * `process.env` before this function runs. Pass an empty set to skip the
35
+ * precedence-collision check.
36
+ */
37
+ export declare function loadEnvFile(envFilePath: string, prevEnvSnapshot: ReadonlySet<string>): EnvLoadReport;
38
+ /**
39
+ * Print a one-banner summary of `loadEnvFile`'s findings to stderr. stdout
40
+ * is the MCP protocol channel — never write to it.
41
+ */
42
+ export declare function writeStartupBanner(report: EnvLoadReport): void;
43
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/env/loader.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,MAAM,EAEZ,MAAM,aAAa,CAAC;AAErB;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gFAAgF;IAChF,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,oEAAoE;IACpE,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,yEAAyE;IACzE,sBAAsB,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IACzE;;;;OAIG;IACH,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CACzB,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,GACnC,aAAa,CA2Ff;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CA6B9D"}
@@ -0,0 +1,121 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { ENV_REGISTRY, DYNAMIC_PER_CHAIN_RPC_RE, envKeys, isKnownEnvKey, } from "./schema.js";
3
+ /**
4
+ * Read .env from disk, scan its raw bytes for common parse-traps, then call
5
+ * `process.loadEnvFile()`. Never throws; surfaces problems via the returned
6
+ * report so the startup banner and doctor can show them.
7
+ *
8
+ * @param envFilePath absolute path to the .env file
9
+ * @param prevEnvSnapshot set of DEXE_* keys that were already in
10
+ * `process.env` before this function runs. Pass an empty set to skip the
11
+ * precedence-collision check.
12
+ */
13
+ export function loadEnvFile(envFilePath, prevEnvSnapshot) {
14
+ const parseWarnings = [];
15
+ const envFileExists = existsSync(envFilePath);
16
+ let envFileLoaded = false;
17
+ if (envFileExists) {
18
+ try {
19
+ const raw = readFileSync(envFilePath);
20
+ // UTF-8 BOM — process.loadEnvFile may misparse the first key.
21
+ if (raw.length >= 3 && raw[0] === 0xef && raw[1] === 0xbb && raw[2] === 0xbf) {
22
+ parseWarnings.push(".env begins with a UTF-8 BOM — process.loadEnvFile may misparse the first line. " +
23
+ "Re-save the file without BOM.");
24
+ }
25
+ // Missing trailing newline — Node silently drops the last line.
26
+ if (raw.length > 0 && raw[raw.length - 1] !== 0x0a /* \n */) {
27
+ parseWarnings.push(".env does not end with a newline — process.loadEnvFile silently drops the last line. " +
28
+ "Add a trailing newline to fix.");
29
+ }
30
+ // Spaces around `=` produce surprising values.
31
+ const spaceLines = [];
32
+ raw
33
+ .toString("utf8")
34
+ .split(/\r?\n/)
35
+ .forEach((line, i) => {
36
+ if (!line || line.trimStart().startsWith("#"))
37
+ return;
38
+ if (/^\s*[A-Za-z_][A-Za-z0-9_]*\s+=/.test(line) ||
39
+ /^\s*[A-Za-z_][A-Za-z0-9_]*=\s/.test(line)) {
40
+ spaceLines.push(i + 1);
41
+ }
42
+ });
43
+ if (spaceLines.length) {
44
+ parseWarnings.push(`.env has spaces around \`=\` on line(s) ${spaceLines.join(", ")} — values may include leading/trailing whitespace. Remove the spaces.`);
45
+ }
46
+ }
47
+ catch (err) {
48
+ parseWarnings.push(`.env is unreadable: ${err instanceof Error ? err.message : String(err)}`);
49
+ }
50
+ try {
51
+ process.loadEnvFile(envFilePath);
52
+ envFileLoaded = true;
53
+ }
54
+ catch (err) {
55
+ parseWarnings.push(`process.loadEnvFile failed (Node < 21.7 or syntax error): ${err instanceof Error ? err.message : String(err)}`);
56
+ }
57
+ }
58
+ // DEXE_* vars present that we don't recognize (typos, deprecated keys).
59
+ const unknownDexeVars = [];
60
+ for (const key of Object.keys(process.env)) {
61
+ if (!key.startsWith("DEXE_"))
62
+ continue;
63
+ if (DYNAMIC_PER_CHAIN_RPC_RE.test(key))
64
+ continue;
65
+ if (!isKnownEnvKey(key))
66
+ unknownDexeVars.push(key);
67
+ }
68
+ // Vars NOT set but which would enable a common flow.
69
+ const missingButEnablesFlows = [];
70
+ for (const [k, v] of Object.entries(ENV_REGISTRY)) {
71
+ if (!v.enablesFlows?.length)
72
+ continue;
73
+ if (process.env[k]?.trim())
74
+ continue;
75
+ missingButEnablesFlows.push({ key: k, flows: v.enablesFlows });
76
+ }
77
+ // Schema keys present in process.env BEFORE we loaded .env — they came
78
+ // from the MCP host (.claude.json env block) and will shadow .env.
79
+ const preExistingVars = envKeys().filter(k => prevEnvSnapshot.has(k));
80
+ return {
81
+ envFilePath,
82
+ envFileExists,
83
+ envFileLoaded,
84
+ loadedNodeVersion: process.version,
85
+ parseWarnings,
86
+ unknownDexeVars,
87
+ missingButEnablesFlows,
88
+ preExistingVars,
89
+ };
90
+ }
91
+ /**
92
+ * Print a one-banner summary of `loadEnvFile`'s findings to stderr. stdout
93
+ * is the MCP protocol channel — never write to it.
94
+ */
95
+ export function writeStartupBanner(report) {
96
+ const w = (s) => {
97
+ process.stderr.write(`[dexe-mcp] ${s}\n`);
98
+ };
99
+ if (!report.envFileExists) {
100
+ w(`no .env at ${report.envFilePath} — using process env only`);
101
+ }
102
+ else if (report.envFileLoaded) {
103
+ w(`loaded .env from ${report.envFilePath} (Node ${report.loadedNodeVersion})`);
104
+ }
105
+ else {
106
+ w(`.env present but not loaded — see warnings below`);
107
+ }
108
+ for (const wmsg of report.parseWarnings) {
109
+ w(`warn: ${wmsg}`);
110
+ }
111
+ if (report.unknownDexeVars.length) {
112
+ w(`warn: unrecognized DEXE_* vars (typo or deprecated): ${report.unknownDexeVars.join(", ")}. Run dexe_doctor for details.`);
113
+ }
114
+ if (report.preExistingVars.length) {
115
+ w(`warn: [${report.preExistingVars.join(", ")}] were set by the MCP host env block ` +
116
+ `and will SHADOW .env. process.loadEnvFile does not override pre-set values. ` +
117
+ `Remove them from .claude.json to use .env values, or update them there. ` +
118
+ `Run dexe_doctor for details.`);
119
+ }
120
+ }
121
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/env/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EACL,YAAY,EACZ,wBAAwB,EACxB,OAAO,EACP,aAAa,GAGd,MAAM,aAAa,CAAC;AAyBrB;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CACzB,WAAmB,EACnB,eAAoC;IAEpC,MAAM,aAAa,GAAa,EAAE,CAAC;IACnC,MAAM,aAAa,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IAC9C,IAAI,aAAa,GAAG,KAAK,CAAC;IAE1B,IAAI,aAAa,EAAE,CAAC;QAClB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;YACtC,8DAA8D;YAC9D,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC7E,aAAa,CAAC,IAAI,CAChB,kFAAkF;oBAChF,+BAA+B,CAClC,CAAC;YACJ,CAAC;YACD,gEAAgE;YAChE,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAC5D,aAAa,CAAC,IAAI,CAChB,uFAAuF;oBACrF,gCAAgC,CACnC,CAAC;YACJ,CAAC;YACD,+CAA+C;YAC/C,MAAM,UAAU,GAAa,EAAE,CAAC;YAChC,GAAG;iBACA,QAAQ,CAAC,MAAM,CAAC;iBAChB,KAAK,CAAC,OAAO,CAAC;iBACd,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;gBACnB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;oBAAE,OAAO;gBACtD,IACE,gCAAgC,CAAC,IAAI,CAAC,IAAI,CAAC;oBAC3C,+BAA+B,CAAC,IAAI,CAAC,IAAI,CAAC,EAC1C,CAAC;oBACD,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBACzB,CAAC;YACH,CAAC,CAAC,CAAC;YACL,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;gBACtB,aAAa,CAAC,IAAI,CAChB,2CAA2C,UAAU,CAAC,IAAI,CACxD,IAAI,CACL,uEAAuE,CACzE,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,aAAa,CAAC,IAAI,CAChB,uBAAuB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC1E,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;YACjC,aAAa,GAAG,IAAI,CAAC;QACvB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,aAAa,CAAC,IAAI,CAChB,6DACE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CACjD,EAAE,CACH,CAAC;QACJ,CAAC;IACH,CAAC;IAED,wEAAwE;IACxE,MAAM,eAAe,GAAa,EAAE,CAAC;IACrC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3C,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC;YAAE,SAAS;QACvC,IAAI,wBAAwB,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,SAAS;QACjD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC;YAAE,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrD,CAAC;IAED,qDAAqD;IACrD,MAAM,sBAAsB,GAAqD,EAAE,CAAC;IACpF,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAyB,EAAE,CAAC;QAC1E,IAAI,CAAC,CAAC,CAAC,YAAY,EAAE,MAAM;YAAE,SAAS;QACtC,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE;YAAE,SAAS;QACrC,sBAAsB,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,uEAAuE;IACvE,mEAAmE;IACnE,MAAM,eAAe,GAAa,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAEhF,OAAO;QACL,WAAW;QACX,aAAa;QACb,aAAa;QACb,iBAAiB,EAAE,OAAO,CAAC,OAAO;QAClC,aAAa;QACb,eAAe;QACf,sBAAsB;QACtB,eAAe;KAChB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAqB;IACtD,MAAM,CAAC,GAAG,CAAC,CAAS,EAAQ,EAAE;QAC5B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC,CAAC;IACF,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC;QAC1B,CAAC,CAAC,cAAc,MAAM,CAAC,WAAW,2BAA2B,CAAC,CAAC;IACjE,CAAC;SAAM,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;QAChC,CAAC,CAAC,oBAAoB,MAAM,CAAC,WAAW,UAAU,MAAM,CAAC,iBAAiB,GAAG,CAAC,CAAC;IACjF,CAAC;SAAM,CAAC;QACN,CAAC,CAAC,kDAAkD,CAAC,CAAC;IACxD,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;QACxC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IACrB,CAAC;IACD,IAAI,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC;QAClC,CAAC,CACC,wDAAwD,MAAM,CAAC,eAAe,CAAC,IAAI,CACjF,IAAI,CACL,gCAAgC,CAClC,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC;QAClC,CAAC,CACC,UAAU,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,uCAAuC;YAChF,8EAA8E;YAC9E,0EAA0E;YAC1E,8BAA8B,CACjC,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { type EnvKey } from "./schema.js";
2
+ export interface EnvIssue {
3
+ key: EnvKey;
4
+ severity: "error" | "warn";
5
+ message: string;
6
+ }
7
+ export interface EnvParseResult {
8
+ /** Trimmed raw values for every key that passed validation. */
9
+ values: Partial<Record<EnvKey, string>>;
10
+ /** All validation failures + missing-required warnings. */
11
+ issues: EnvIssue[];
12
+ }
13
+ /**
14
+ * Walk ENV_SPEC, run each entry's zod schema against the provided env table,
15
+ * and collect categorized issues. Pure — no I/O, no logging, no side effects.
16
+ *
17
+ * Callers:
18
+ * - src/config.ts (startup)
19
+ * - src/diag/checks.ts (doctor)
20
+ * - tests (parity / regression)
21
+ */
22
+ export declare function parseEnv(env?: NodeJS.ProcessEnv): EnvParseResult;
23
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/env/parse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAiB,MAAM,aAAa,CAAC;AAEvE,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,+DAA+D;IAC/D,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACxC,2DAA2D;IAC3D,MAAM,EAAE,QAAQ,EAAE,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,cAAc,CA+B7E"}
@@ -0,0 +1,41 @@
1
+ import { ENV_REGISTRY } from "./schema.js";
2
+ /**
3
+ * Walk ENV_SPEC, run each entry's zod schema against the provided env table,
4
+ * and collect categorized issues. Pure — no I/O, no logging, no side effects.
5
+ *
6
+ * Callers:
7
+ * - src/config.ts (startup)
8
+ * - src/diag/checks.ts (doctor)
9
+ * - tests (parity / regression)
10
+ */
11
+ export function parseEnv(env = process.env) {
12
+ const values = {};
13
+ const issues = [];
14
+ for (const [key, entry] of Object.entries(ENV_REGISTRY)) {
15
+ const raw = env[key]?.trim();
16
+ if (!raw) {
17
+ if (entry.required) {
18
+ issues.push({
19
+ key,
20
+ severity: "error",
21
+ message: `Required env var ${key} is not set. ${entry.doc}`,
22
+ });
23
+ }
24
+ continue;
25
+ }
26
+ const r = entry.schema.safeParse(raw);
27
+ if (!r.success) {
28
+ issues.push({
29
+ key,
30
+ severity: "error",
31
+ message: `Invalid ${key}=${entry.secret ? "<redacted>" : raw}: ${r.error.issues
32
+ .map(i => i.message)
33
+ .join("; ")}`,
34
+ });
35
+ continue;
36
+ }
37
+ values[key] = raw;
38
+ }
39
+ return { values, issues };
40
+ }
41
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/env/parse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA8B,MAAM,aAAa,CAAC;AAevE;;;;;;;;GAQG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC3D,MAAM,MAAM,GAAoC,EAAE,CAAC;IACnD,MAAM,MAAM,GAAe,EAAE,CAAC;IAE9B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAyB,EAAE,CAAC;QAChF,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACnB,MAAM,CAAC,IAAI,CAAC;oBACV,GAAG;oBACH,QAAQ,EAAE,OAAO;oBACjB,OAAO,EAAE,oBAAoB,GAAG,gBAAgB,KAAK,CAAC,GAAG,EAAE;iBAC5D,CAAC,CAAC;YACL,CAAC;YACD,SAAS;QACX,CAAC;QACD,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,CAAC;gBACV,GAAG;gBACH,QAAQ,EAAE,OAAO;gBACjB,OAAO,EAAE,WAAW,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM;qBAC5E,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;qBACnB,IAAI,CAAC,IAAI,CAAC,EAAE;aAChB,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IACpB,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC5B,CAAC"}