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.
- package/CHANGELOG.md +129 -0
- package/README.md +19 -1
- package/dist/cli/doctor.d.ts +11 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +44 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/init.d.ts +2 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +306 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/diag/checks.d.ts +25 -0
- package/dist/diag/checks.d.ts.map +1 -0
- package/dist/diag/checks.js +387 -0
- package/dist/diag/checks.js.map +1 -0
- package/dist/env/loader.d.ts +43 -0
- package/dist/env/loader.d.ts.map +1 -0
- package/dist/env/loader.js +121 -0
- package/dist/env/loader.js.map +1 -0
- package/dist/env/parse.d.ts +23 -0
- package/dist/env/parse.d.ts.map +1 -0
- package/dist/env/parse.js +41 -0
- package/dist/env/parse.js.map +1 -0
- package/dist/env/schema.d.ts +257 -0
- package/dist/env/schema.d.ts.map +1 -0
- package/dist/env/schema.js +240 -0
- package/dist/env/schema.js.map +1 -0
- package/dist/governor/tools/extras.js +12 -3
- package/dist/governor/tools/extras.js.map +1 -1
- package/dist/governor/tools/read.js +16 -4
- package/dist/governor/tools/read.js.map +1 -1
- package/dist/governor/tools/simulate.d.ts.map +1 -1
- package/dist/governor/tools/simulate.js +8 -2
- package/dist/governor/tools/simulate.js.map +1 -1
- package/dist/index.js +31 -11
- package/dist/index.js.map +1 -1
- package/dist/lib/requireEnv.d.ts +30 -0
- package/dist/lib/requireEnv.d.ts.map +1 -0
- package/dist/lib/requireEnv.js +48 -0
- package/dist/lib/requireEnv.js.map +1 -0
- package/dist/lib/signer.d.ts +8 -0
- package/dist/lib/signer.d.ts.map +1 -1
- package/dist/lib/signer.js +18 -0
- package/dist/lib/signer.js.map +1 -1
- package/dist/rpc.d.ts +8 -0
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js +18 -0
- package/dist/rpc.js.map +1 -1
- package/dist/tools/dao.d.ts.map +1 -1
- package/dist/tools/dao.js +25 -10
- package/dist/tools/dao.js.map +1 -1
- package/dist/tools/daoDeploy.js +8 -2
- package/dist/tools/daoDeploy.js.map +1 -1
- package/dist/tools/doctor.d.ts +11 -0
- package/dist/tools/doctor.d.ts.map +1 -0
- package/dist/tools/doctor.js +75 -0
- package/dist/tools/doctor.js.map +1 -0
- package/dist/tools/flow.d.ts.map +1 -1
- package/dist/tools/flow.js +16 -4
- package/dist/tools/flow.js.map +1 -1
- package/dist/tools/gov.js +8 -14
- package/dist/tools/gov.js.map +1 -1
- package/dist/tools/inbox.d.ts.map +1 -1
- package/dist/tools/inbox.js +7 -1
- package/dist/tools/inbox.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +3 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/otc.d.ts.map +1 -1
- package/dist/tools/otc.js +15 -3
- package/dist/tools/otc.js.map +1 -1
- package/dist/tools/predict.d.ts.map +1 -1
- package/dist/tools/predict.js +7 -1
- package/dist/tools/predict.js.map +1 -1
- package/dist/tools/proposal.js +8 -2
- package/dist/tools/proposal.js.map +1 -1
- package/dist/tools/read.js +40 -10
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/safe.d.ts.map +1 -1
- package/dist/tools/safe.js +12 -3
- package/dist/tools/safe.js.map +1 -1
- package/dist/tools/simulate.d.ts.map +1 -1
- package/dist/tools/simulate.js +16 -3
- package/dist/tools/simulate.js.map +1 -1
- package/dist/tools/subgraph.js +4 -1
- package/dist/tools/subgraph.js.map +1 -1
- package/dist/tools/txSend.d.ts.map +1 -1
- package/dist/tools/txSend.js +18 -1
- package/dist/tools/txSend.js.map +1 -1
- package/dist/tools/vote.js +8 -2
- package/dist/tools/vote.js.map +1 -1
- package/package.json +5 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,134 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.1 — 2026-05-30
|
|
4
|
+
|
|
5
|
+
### Full soft-fail migration
|
|
6
|
+
|
|
7
|
+
Extends the soft-fail behavior shipped in 0.8.0 (`dexe_read_*` and
|
|
8
|
+
`dexe_tx_send`) to **every** remaining tool that touched the throwing
|
|
9
|
+
`RpcProvider.requireProvider()` / `SignerManager.requireSigner()`
|
|
10
|
+
variants. Missing env now surfaces uniformly across the entire MCP tool
|
|
11
|
+
catalog as a structured error with paste-ready remediation hints —
|
|
12
|
+
never a thrown stack reaching the MCP transport.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- 18 tool files migrated from the throwing variants to the soft
|
|
17
|
+
`tryProvider` / `trySigner` siblings:
|
|
18
|
+
- `src/tools/`: `dao.ts` (incl. the shared `requireBook` helper, now
|
|
19
|
+
returning `EnvGuardResult<AddressBook>`), `daoDeploy.ts`, `flow.ts`,
|
|
20
|
+
`gov.ts`, `inbox.ts`, `otc.ts`, `predict.ts`, `proposal.ts`,
|
|
21
|
+
`safe.ts`, `simulate.ts`, `subgraph.ts`, `vote.ts`
|
|
22
|
+
- `src/governor/tools/`: `extras.ts`, `read.ts`, `simulate.ts`
|
|
23
|
+
- The throwing `requireSigner` / `requireProvider` definitions stay in
|
|
24
|
+
`src/lib/signer.ts` and `src/rpc.ts` for backward compatibility — no
|
|
25
|
+
removed public API. Only the in-tree call sites moved.
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- `tests/lib/soft-fail-migration.test.ts` — regression guard that
|
|
30
|
+
asserts no direct `.requireProvider(` / `.requireSigner(` call exists
|
|
31
|
+
in `src/tools/**` or `src/governor/**`. Catches the regression at
|
|
32
|
+
test-run time if a future tool forgets the soft-fail pattern.
|
|
33
|
+
|
|
34
|
+
### Notes
|
|
35
|
+
|
|
36
|
+
- No env contract change. No new vars. No caller-side change required.
|
|
37
|
+
- Patch-level release because the failure-mode contract is identical to
|
|
38
|
+
0.8.0's; just applied uniformly across the catalog.
|
|
39
|
+
|
|
40
|
+
## 0.8.0 — 2026-05-30
|
|
41
|
+
|
|
42
|
+
### Env onboarding overhaul
|
|
43
|
+
|
|
44
|
+
This release exists to make first-run setup fail-safe for new users
|
|
45
|
+
(human or AI assistant). Previously, when an env var was missing or
|
|
46
|
+
typoed, tools threw raw stacks and the assistant had no way to discover
|
|
47
|
+
which file to edit, which key was missing, or whether `.claude.json` was
|
|
48
|
+
shadowing `.env`. Now there is one diagnostic, one wizard, one skill,
|
|
49
|
+
and one schema that drives every check.
|
|
50
|
+
|
|
51
|
+
**Upgrade:** zero env changes required, no breaking renames or removals.
|
|
52
|
+
See [`docs/MIGRATION.md`](docs/MIGRATION.md) for the 0.7.x → 0.8.0
|
|
53
|
+
guide and the documented behavior change in `dexe_read_*` /
|
|
54
|
+
`dexe_tx_send` error responses.
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
- **`dexe_doctor` tool + CLI.** New diagnostic that walks every
|
|
59
|
+
recognized `DEXE_*` env var, runs reachability checks (RPC
|
|
60
|
+
`eth_chainId` per chain, Pinata `testAuthentication`, IPFS gateway DNS
|
|
61
|
+
lookup, subgraph `{__typename}` introspection, backend HEAD), and
|
|
62
|
+
reports pass/warn/fail per check with paste-ready remediation hints.
|
|
63
|
+
Network checks have a 3s hard timeout that downgrades to `warn` so
|
|
64
|
+
offline laptops don't see all-red. Also runnable as
|
|
65
|
+
`npx dexe-mcp doctor` (exit 0/1/2). See [`docs/DOCTOR.md`](docs/DOCTOR.md).
|
|
66
|
+
- **`npx dexe-mcp init` wizard.** Interactive onboarding via native
|
|
67
|
+
`node:readline/promises`. Asks four questions (network, Pinata JWT,
|
|
68
|
+
Graph API key, signer mode), writes `.env` at the repo root (merge or
|
|
69
|
+
overwrite), and prints a `~/.claude.json` snippet for copy-paste.
|
|
70
|
+
Validates the Pinata JWT against the live endpoint before writing.
|
|
71
|
+
Defaults the signer mode to readonly; warns explicitly and double-confirms
|
|
72
|
+
before storing a private key in plaintext. Never auto-edits
|
|
73
|
+
`.claude.json`. No new dependencies.
|
|
74
|
+
- **Schema-driven env handling.** `src/env/schema.ts` (`ENV_SPEC`,
|
|
75
|
+
`ENV_REGISTRY`) is now the canonical registry for every recognized
|
|
76
|
+
`DEXE_*` var (category, doc, zod schema, enabled flows, secret flag).
|
|
77
|
+
Consumed by the new parser, doctor, fail-soft guards, and the
|
|
78
|
+
`/dexe-setup` skill. Drift guarded by `tests/env/schema.test.ts`
|
|
79
|
+
against `.env.example`.
|
|
80
|
+
- **Startup self-diagnostic banner.** `src/env/loader.ts` reads `.env`
|
|
81
|
+
raw bytes before `process.loadEnvFile()` and emits stderr warnings
|
|
82
|
+
for: UTF-8 BOM, missing trailing newline, spaces around `=`, unknown
|
|
83
|
+
`DEXE_*` keys, and host-env shadowing of `.env` values. Surfaces
|
|
84
|
+
silent parse traps that previously made "I edited .env and nothing
|
|
85
|
+
changed" hard to diagnose.
|
|
86
|
+
- **Fail-soft guard helpers.** New `src/lib/requireEnv.ts` (`requireEnv`,
|
|
87
|
+
`hintFor`) generalizes the existing `requirePinata` pattern from
|
|
88
|
+
`src/tools/ipfs.ts`. Added `SignerManager.trySigner` and
|
|
89
|
+
`RpcProvider.tryProvider` siblings that return `{error, remediation}`
|
|
90
|
+
instead of throwing — keeps the throwing variants for backward
|
|
91
|
+
compatibility.
|
|
92
|
+
- **`/dexe-setup` skill** at `.claude/skills/dexe-setup/SKILL.md`. Calls
|
|
93
|
+
`dexe_doctor`, parses the report, asks the user only for missing
|
|
94
|
+
values, edits `.env` (never `.claude.json`), and tells the user to
|
|
95
|
+
restart Claude Code. Caps at 3 doctor → fix → restart iterations.
|
|
96
|
+
Hard rule: refuse to write `DEXE_PRIVATE_KEY` without explicit user
|
|
97
|
+
opt-in; suggest WalletConnect first.
|
|
98
|
+
- **`docs/SETUP.md` + `docs/DOCTOR.md` + `docs/MIGRATION.md`.**
|
|
99
|
+
Consolidated quickstart with three setup paths, the full check
|
|
100
|
+
reference, and the per-version migration notes.
|
|
101
|
+
- **"For AI assistants" block in `CLAUDE.md`.** Tells future Claude:
|
|
102
|
+
call `dexe_doctor` first; edit `.env` not `.claude.json`; restart is
|
|
103
|
+
required after env changes; the `/dexe-setup` skill exists; point
|
|
104
|
+
upgrading users at `docs/MIGRATION.md`.
|
|
105
|
+
|
|
106
|
+
### Changed
|
|
107
|
+
|
|
108
|
+
- **`src/tools/read.ts` and `src/tools/txSend.ts` hot handlers** migrated
|
|
109
|
+
to the soft `tryProvider`/`trySigner` variants. Missing RPC or
|
|
110
|
+
`DEXE_PRIVATE_KEY` now surfaces as a structured MCP error with fix
|
|
111
|
+
instructions instead of a thrown stack. Other call sites of
|
|
112
|
+
`requireProvider`/`requireSigner` keep their throwing behavior — they
|
|
113
|
+
are migrated incrementally in 0.8.1.
|
|
114
|
+
- **`src/index.ts`** now dispatches `dexe-mcp doctor` and `dexe-mcp init`
|
|
115
|
+
to their respective CLI entry points before opening the MCP stdio
|
|
116
|
+
transport. No-arg invocation still starts the server as before. The
|
|
117
|
+
env loader runs BEFORE the subcommand dispatch so the CLI sees the
|
|
118
|
+
same env as the MCP server.
|
|
119
|
+
- **`docs/TOOLS.md`** bumped to 153 tools / 19 groups (added the
|
|
120
|
+
Diagnostics group containing `dexe_doctor`).
|
|
121
|
+
- **`README.md` Quickstart** now leads with the wizard path
|
|
122
|
+
(`init` + `doctor`) above the manual install instructions.
|
|
123
|
+
|
|
124
|
+
### Notes
|
|
125
|
+
|
|
126
|
+
- No removed APIs. `requireSigner`/`requireProvider` keep throwing so
|
|
127
|
+
every existing call site (~17 outside read.ts and txSend.ts)
|
|
128
|
+
continues to work; the migration is incremental.
|
|
129
|
+
- No new runtime dependencies. The wizard and doctor use only
|
|
130
|
+
`node:readline/promises`, `node:dns/promises`, and native `fetch`.
|
|
131
|
+
|
|
3
132
|
## 0.7.2 — 2026-05-27
|
|
4
133
|
|
|
5
134
|
### Fixed
|
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ That era is ending.
|
|
|
40
40
|
|
|
41
41
|
LLMs can now reason about voting power, weigh proposals against a mandate, draft calldata, simulate execution, and ask your wallet to sign — **continuously, across every DAO you care about, all at once.** What was a UI is becoming a conversation. What was a treasurer's spreadsheet is becoming an always-on agent.
|
|
42
42
|
|
|
43
|
-
**`dexe-mcp` is the substrate that makes it real for the DeXe stack — and now for external OpenZeppelin Governor DAOs as well.** One MCP server.
|
|
43
|
+
**`dexe-mcp` is the substrate that makes it real for the DeXe stack — and now for external OpenZeppelin Governor DAOs as well.** One MCP server. 153 typed tools across 19 groups. Every flow the DeXe frontend exposes — plus a generic `dexe_gov_*` surface targeting Uniswap, Compound, and Optimism.
|
|
44
44
|
|
|
45
45
|
| | What you get |
|
|
46
46
|
|-----|------|
|
|
@@ -87,6 +87,24 @@ The next generation of DAOs will be **operated by language, not by clicks.**
|
|
|
87
87
|
|
|
88
88
|
## Quickstart
|
|
89
89
|
|
|
90
|
+
**Fastest path — wizard + diagnostic:**
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npm install -g dexe-mcp
|
|
94
|
+
npx dexe-mcp init # interactive setup (network, Pinata, signer mode)
|
|
95
|
+
npx dexe-mcp doctor # verify (RPC + Pinata + IPFS gateway + subgraph)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The wizard writes `.env` at the repo root and prints a `~/.claude.json`
|
|
99
|
+
snippet to paste. Then `doctor` walks every recognized `DEXE_*` var and
|
|
100
|
+
returns a pass/warn/fail report with paste-ready remediation hints. See
|
|
101
|
+
[`docs/SETUP.md`](./docs/SETUP.md) for the full runbook,
|
|
102
|
+
[`docs/DOCTOR.md`](./docs/DOCTOR.md) for the check reference, and
|
|
103
|
+
[`docs/MIGRATION.md`](./docs/MIGRATION.md) if you are upgrading from
|
|
104
|
+
0.7.x.
|
|
105
|
+
|
|
106
|
+
**Manual path:**
|
|
107
|
+
|
|
90
108
|
**1.** Install:
|
|
91
109
|
|
|
92
110
|
```bash
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI entrypoint: `npx dexe-mcp doctor`. Runs the same check suite as the
|
|
3
|
+
* MCP tool, prints a flat colorless table to stdout, exits with:
|
|
4
|
+
* - 0 when every check passes
|
|
5
|
+
* - 1 when there are warnings but no failures
|
|
6
|
+
* - 2 when at least one check fails
|
|
7
|
+
*
|
|
8
|
+
* Designed for both human terminal use and CI pipelines.
|
|
9
|
+
*/
|
|
10
|
+
export declare function run(): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=doctor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,wBAAsB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAiCzC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { loadConfig } from "../config.js";
|
|
2
|
+
import { runAllChecks } from "../diag/checks.js";
|
|
3
|
+
/**
|
|
4
|
+
* CLI entrypoint: `npx dexe-mcp doctor`. Runs the same check suite as the
|
|
5
|
+
* MCP tool, prints a flat colorless table to stdout, exits with:
|
|
6
|
+
* - 0 when every check passes
|
|
7
|
+
* - 1 when there are warnings but no failures
|
|
8
|
+
* - 2 when at least one check fails
|
|
9
|
+
*
|
|
10
|
+
* Designed for both human terminal use and CI pipelines.
|
|
11
|
+
*/
|
|
12
|
+
export async function run() {
|
|
13
|
+
const config = await loadConfig().catch(err => {
|
|
14
|
+
process.stderr.write(`[dexe-mcp doctor] config load failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
15
|
+
process.exit(2);
|
|
16
|
+
});
|
|
17
|
+
if (!config) {
|
|
18
|
+
process.exit(2);
|
|
19
|
+
}
|
|
20
|
+
const checks = await runAllChecks({ config });
|
|
21
|
+
let pass = 0;
|
|
22
|
+
let warn = 0;
|
|
23
|
+
let fail = 0;
|
|
24
|
+
for (const c of checks) {
|
|
25
|
+
if (c.status === "pass")
|
|
26
|
+
pass++;
|
|
27
|
+
else if (c.status === "warn")
|
|
28
|
+
warn++;
|
|
29
|
+
else
|
|
30
|
+
fail++;
|
|
31
|
+
}
|
|
32
|
+
for (const c of checks) {
|
|
33
|
+
const tag = c.status === "pass" ? " OK " : c.status === "warn" ? "WARN" : "FAIL";
|
|
34
|
+
process.stdout.write(`[${tag}] ${c.id.padEnd(36)} ${c.message}\n`);
|
|
35
|
+
if (c.remediation) {
|
|
36
|
+
for (const line of c.remediation.split("\n")) {
|
|
37
|
+
process.stdout.write(` -> ${line}\n`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
process.stdout.write(`\nsummary: ${pass} pass / ${warn} warn / ${fail} fail\n`);
|
|
42
|
+
process.exit(fail > 0 ? 2 : warn > 0 ? 1 : 0);
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG;IACvB,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;QAC5C,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,yCAAyC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAC9F,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9C,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;YAAE,IAAI,EAAE,CAAC;aAC3B,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;YAAE,IAAI,EAAE,CAAC;;YAChC,IAAI,EAAE,CAAC;IACd,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;QACjF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC;QACnE,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;YAClB,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC7C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,IAAI,IAAI,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,IAAI,WAAW,IAAI,WAAW,IAAI,SAAS,CAAC,CAAC;IAChF,OAAO,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAsBA,wBAAsB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CA8KzC"}
|
package/dist/cli/init.js
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises";
|
|
2
|
+
import { stdin as input, stdout as output } from "node:process";
|
|
3
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { resolve, dirname } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
/**
|
|
7
|
+
* `npx dexe-mcp init` — zero-config onboarding wizard.
|
|
8
|
+
*
|
|
9
|
+
* Walks the user through a minimal `.env` (network, RPCs, Pinata, subgraph
|
|
10
|
+
* key, signer mode), validates the Pinata JWT against the live endpoint
|
|
11
|
+
* before writing, and prints a paste-ready `.claude.json` snippet. Never
|
|
12
|
+
* auto-edits the user's MCP host config — that is too risky to do
|
|
13
|
+
* automatically (other servers, other env keys, comments to preserve).
|
|
14
|
+
*
|
|
15
|
+
* Uses only the Node 20 standard library (`node:readline/promises`,
|
|
16
|
+
* `node:fs`, native `fetch`) — no new dependency.
|
|
17
|
+
*/
|
|
18
|
+
const TESTNET_DEFAULT_RPC = "https://data-seed-prebsc-1-s1.bnbchain.org:8545";
|
|
19
|
+
const MAINNET_DEFAULT_RPC = "https://bsc-dataseed.bnbchain.org";
|
|
20
|
+
export async function run() {
|
|
21
|
+
if (!input.isTTY) {
|
|
22
|
+
process.stderr.write("[dexe-mcp init] stdin is not a TTY. Pipe-driven init is not supported (too risky for secrets). " +
|
|
23
|
+
"Fill in .env manually instead — see .env.example.\n");
|
|
24
|
+
process.exit(2);
|
|
25
|
+
}
|
|
26
|
+
const rl = createInterface({ input, output });
|
|
27
|
+
try {
|
|
28
|
+
output.write(line("dexe-mcp init — onboarding wizard"));
|
|
29
|
+
output.write(line("─".repeat(64)));
|
|
30
|
+
output.write(line("Builds a minimal .env. Answers are stored in plaintext;"));
|
|
31
|
+
output.write(line("use WalletConnect or readonly mode if that worries you."));
|
|
32
|
+
output.write("\n");
|
|
33
|
+
// ---- Network selection ----------------------------------------------
|
|
34
|
+
const network = await pickOne(rl, "Which network(s)?", [
|
|
35
|
+
["t", "testnet — BSC chain 97 (free faucet BNB, recommended for first run)"],
|
|
36
|
+
["m", "mainnet — BSC chain 56 (real funds)"],
|
|
37
|
+
["b", "both"],
|
|
38
|
+
], "t");
|
|
39
|
+
let rpcTestnet;
|
|
40
|
+
let rpcMainnet;
|
|
41
|
+
if (network === "t" || network === "b") {
|
|
42
|
+
rpcTestnet = (await ask(rl, "Testnet RPC URL", TESTNET_DEFAULT_RPC)).trim();
|
|
43
|
+
}
|
|
44
|
+
if (network === "m" || network === "b") {
|
|
45
|
+
rpcMainnet = (await ask(rl, "Mainnet RPC URL", MAINNET_DEFAULT_RPC)).trim();
|
|
46
|
+
}
|
|
47
|
+
const defaultChainId = network === "m" ? "56" : "97";
|
|
48
|
+
// ---- Pinata JWT (optional) -----------------------------------------
|
|
49
|
+
output.write(line("Pinata JWT enables IPFS uploads (proposal metadata, DAO avatars)."));
|
|
50
|
+
output.write(line("Reads work without it via a public gateway. Press Enter to skip."));
|
|
51
|
+
const pinataJwt = (await ask(rl, "Pinata JWT", "")).trim();
|
|
52
|
+
if (pinataJwt) {
|
|
53
|
+
const ok = await validatePinataJwt(pinataJwt);
|
|
54
|
+
if (!ok) {
|
|
55
|
+
const proceed = await yn(rl, "Pinata says that JWT is invalid (or the network is unreachable). Save anyway?", false);
|
|
56
|
+
if (!proceed) {
|
|
57
|
+
output.write(line("Aborted — re-run init when you have a valid JWT."));
|
|
58
|
+
process.exit(2);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
output.write(line(" → Pinata JWT validated."));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const ipfsGateway = pinataJwt
|
|
66
|
+
? (await ask(rl, "IPFS gateway URL", "https://gateway.pinata.cloud")).trim()
|
|
67
|
+
: "";
|
|
68
|
+
// ---- Subgraph (optional) -------------------------------------------
|
|
69
|
+
output.write(line("Subgraph reads need a Graph API key (free at thegraph.com)."));
|
|
70
|
+
const graphKey = (await ask(rl, "Graph API key (blank to skip subgraph reads)", "")).trim();
|
|
71
|
+
// ---- Signer mode ---------------------------------------------------
|
|
72
|
+
output.write(line(""));
|
|
73
|
+
output.write(line("Signer mode:"));
|
|
74
|
+
output.write(line(" readonly — no broadcast; tools return unsigned calldata (safest)"));
|
|
75
|
+
output.write(line(" walletconnect — broadcast via phone wallet; key never enters this process"));
|
|
76
|
+
output.write(line(" privkey — hot key in .env; convenient for CI and bots, NOT recommended"));
|
|
77
|
+
const signerMode = await pickOne(rl, "Pick a signer mode", [
|
|
78
|
+
["r", "readonly (recommended)"],
|
|
79
|
+
["w", "walletconnect"],
|
|
80
|
+
["p", "privkey (warning: plaintext in .env)"],
|
|
81
|
+
], "r");
|
|
82
|
+
let privateKey;
|
|
83
|
+
let wcProjectId;
|
|
84
|
+
if (signerMode === "p") {
|
|
85
|
+
output.write(line(""));
|
|
86
|
+
output.write(line("⚠ Plaintext private keys in .env are a security risk."));
|
|
87
|
+
output.write(line(" Anyone who reads the file can drain that wallet."));
|
|
88
|
+
output.write(line(" Prefer WalletConnect (re-run init and pick `w`) when possible."));
|
|
89
|
+
const confirm = await yn(rl, "Continue with privkey mode?", false);
|
|
90
|
+
if (!confirm) {
|
|
91
|
+
output.write(line("Aborted — re-run init and pick readonly or walletconnect."));
|
|
92
|
+
process.exit(2);
|
|
93
|
+
}
|
|
94
|
+
const pk = (await ask(rl, "Private key (0x… 64 hex)", "")).trim();
|
|
95
|
+
if (!/^0x[0-9a-fA-F]{64}$/.test(pk)) {
|
|
96
|
+
output.write(line("That does not look like a 64-hex key — aborting."));
|
|
97
|
+
process.exit(2);
|
|
98
|
+
}
|
|
99
|
+
const addr = await deriveAddress(pk);
|
|
100
|
+
output.write(line(` → Derived address: ${addr}`));
|
|
101
|
+
const ok = await yn(rl, "Is that the wallet you intended?", true);
|
|
102
|
+
if (!ok) {
|
|
103
|
+
output.write(line("Aborted — re-run init."));
|
|
104
|
+
process.exit(2);
|
|
105
|
+
}
|
|
106
|
+
privateKey = pk;
|
|
107
|
+
}
|
|
108
|
+
else if (signerMode === "w") {
|
|
109
|
+
wcProjectId = (await ask(rl, "WalletConnect project id (cloud.reown.com)", "")).trim();
|
|
110
|
+
}
|
|
111
|
+
// ---- Build the env block + write .env ------------------------------
|
|
112
|
+
const updates = {};
|
|
113
|
+
if (rpcTestnet)
|
|
114
|
+
updates.DEXE_RPC_URL_TESTNET = rpcTestnet;
|
|
115
|
+
if (rpcMainnet)
|
|
116
|
+
updates.DEXE_RPC_URL_MAINNET = rpcMainnet;
|
|
117
|
+
updates.DEXE_DEFAULT_CHAIN_ID = defaultChainId;
|
|
118
|
+
if (pinataJwt)
|
|
119
|
+
updates.DEXE_PINATA_JWT = pinataJwt;
|
|
120
|
+
if (ipfsGateway)
|
|
121
|
+
updates.DEXE_IPFS_GATEWAY = ipfsGateway;
|
|
122
|
+
if (graphKey)
|
|
123
|
+
updates.DEXE_GRAPH_API_KEY = graphKey;
|
|
124
|
+
if (privateKey)
|
|
125
|
+
updates.DEXE_PRIVATE_KEY = privateKey;
|
|
126
|
+
if (wcProjectId)
|
|
127
|
+
updates.DEXE_WALLETCONNECT_PROJECT_ID = wcProjectId;
|
|
128
|
+
const repoRoot = findRepoRoot();
|
|
129
|
+
const envPath = resolve(repoRoot, ".env");
|
|
130
|
+
// Read the file once up-front (or treat ENOENT as "no existing .env") so
|
|
131
|
+
// the later write isn't a check-then-act TOCTOU: every decision below
|
|
132
|
+
// operates on this captured snapshot, not on a re-stat of the path.
|
|
133
|
+
let existingEnv = null;
|
|
134
|
+
try {
|
|
135
|
+
existingEnv = readFileSync(envPath, "utf8");
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
if (err.code !== "ENOENT")
|
|
139
|
+
throw err;
|
|
140
|
+
}
|
|
141
|
+
let action = "write";
|
|
142
|
+
if (existingEnv !== null) {
|
|
143
|
+
const choice = await pickOne(rl, `Existing .env at ${envPath}. Overwrite or merge?`, [
|
|
144
|
+
["m", "merge — replace known keys, keep everything else (recommended)"],
|
|
145
|
+
["o", "overwrite — wipe and start fresh"],
|
|
146
|
+
["a", "abort — keep .env unchanged, exit"],
|
|
147
|
+
], "m");
|
|
148
|
+
if (choice === "a") {
|
|
149
|
+
output.write(line("Aborted — .env unchanged."));
|
|
150
|
+
process.exit(0);
|
|
151
|
+
}
|
|
152
|
+
action = choice === "o" ? "write" : "merge";
|
|
153
|
+
}
|
|
154
|
+
const content = action === "write" || existingEnv === null
|
|
155
|
+
? renderFreshEnv(updates)
|
|
156
|
+
: mergeEnv(existingEnv, updates);
|
|
157
|
+
writeFileSync(envPath, content, "utf8");
|
|
158
|
+
output.write(line(`✔ Wrote ${envPath} (${Object.keys(updates).length} key${Object.keys(updates).length === 1 ? "" : "s"} set).`));
|
|
159
|
+
output.write(line(""));
|
|
160
|
+
// ---- Print .claude.json snippet ------------------------------------
|
|
161
|
+
output.write(line("Paste this into your ~/.claude.json under `mcpServers`:"));
|
|
162
|
+
output.write(line(""));
|
|
163
|
+
output.write(jsonSnippet(repoRoot));
|
|
164
|
+
output.write(line(""));
|
|
165
|
+
output.write(line(`Next: run \`npx dexe-mcp doctor\` to verify, then restart Claude Code.`));
|
|
166
|
+
}
|
|
167
|
+
finally {
|
|
168
|
+
rl.close();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// ─── prompt helpers ──────────────────────────────────────────────────────
|
|
172
|
+
async function ask(rl, prompt, fallback) {
|
|
173
|
+
const suffix = fallback ? ` [${fallback}]` : "";
|
|
174
|
+
const a = await rl.question(`${prompt}${suffix}: `);
|
|
175
|
+
return a.length === 0 ? fallback : a;
|
|
176
|
+
}
|
|
177
|
+
async function yn(rl, prompt, defaultYes) {
|
|
178
|
+
const suffix = defaultYes ? "[Y/n]" : "[y/N]";
|
|
179
|
+
const a = (await rl.question(`${prompt} ${suffix}: `)).trim().toLowerCase();
|
|
180
|
+
if (!a)
|
|
181
|
+
return defaultYes;
|
|
182
|
+
return a === "y" || a === "yes";
|
|
183
|
+
}
|
|
184
|
+
async function pickOne(rl, prompt, options, defaultKey) {
|
|
185
|
+
output.write(line(prompt));
|
|
186
|
+
for (const [key, label] of options) {
|
|
187
|
+
const tag = key === defaultKey ? `[${key}*]` : `[${key} ]`;
|
|
188
|
+
output.write(line(` ${tag} ${label}`));
|
|
189
|
+
}
|
|
190
|
+
const valid = new Set(options.map(o => o[0]));
|
|
191
|
+
// eslint-disable-next-line no-constant-condition
|
|
192
|
+
while (true) {
|
|
193
|
+
const a = (await rl.question(`Choice (default ${defaultKey}): `)).trim().toLowerCase();
|
|
194
|
+
if (!a)
|
|
195
|
+
return defaultKey;
|
|
196
|
+
if (valid.has(a))
|
|
197
|
+
return a;
|
|
198
|
+
output.write(line(` → please answer one of ${[...valid].join(" / ")}`));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// ─── env file rendering ──────────────────────────────────────────────────
|
|
202
|
+
function renderFreshEnv(updates) {
|
|
203
|
+
const lines = [
|
|
204
|
+
"# dexe-mcp — generated by `npx dexe-mcp init`",
|
|
205
|
+
"# Loaded via process.loadEnvFile() at MCP startup.",
|
|
206
|
+
"# Run `npx dexe-mcp doctor` after any edit to verify.",
|
|
207
|
+
"",
|
|
208
|
+
];
|
|
209
|
+
for (const [k, v] of Object.entries(updates)) {
|
|
210
|
+
lines.push(`${k}=${v}`);
|
|
211
|
+
}
|
|
212
|
+
return lines.join("\n") + "\n";
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Merge new values into an existing .env in place: known keys are replaced,
|
|
216
|
+
* unknown keys + comments + blank lines preserved verbatim. Detects CRLF vs
|
|
217
|
+
* LF and matches the file's existing line endings.
|
|
218
|
+
*/
|
|
219
|
+
function mergeEnv(existing, updates) {
|
|
220
|
+
const eol = /\r\n/.test(existing) ? "\r\n" : "\n";
|
|
221
|
+
const lines = existing.split(/\r?\n/);
|
|
222
|
+
const seen = new Set();
|
|
223
|
+
const out = [];
|
|
224
|
+
for (const line_ of lines) {
|
|
225
|
+
const m = /^(\s*)([A-Za-z_][A-Za-z0-9_]*)\s*=/.exec(line_);
|
|
226
|
+
if (m && Object.prototype.hasOwnProperty.call(updates, m[2])) {
|
|
227
|
+
const key = m[2];
|
|
228
|
+
out.push(`${m[1] ?? ""}${key}=${updates[key]}`);
|
|
229
|
+
seen.add(key);
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
out.push(line_);
|
|
233
|
+
}
|
|
234
|
+
// Append any keys that did not already exist.
|
|
235
|
+
const appended = [];
|
|
236
|
+
for (const [k, v] of Object.entries(updates)) {
|
|
237
|
+
if (seen.has(k))
|
|
238
|
+
continue;
|
|
239
|
+
appended.push(`${k}=${v}`);
|
|
240
|
+
}
|
|
241
|
+
if (appended.length > 0) {
|
|
242
|
+
if (out.length > 0 && out[out.length - 1] !== "")
|
|
243
|
+
out.push("");
|
|
244
|
+
out.push("# added by `npx dexe-mcp init`");
|
|
245
|
+
out.push(...appended);
|
|
246
|
+
}
|
|
247
|
+
// Ensure trailing newline (Node's loadEnvFile drops the last line otherwise).
|
|
248
|
+
if (out.length > 0 && out[out.length - 1] !== "")
|
|
249
|
+
out.push("");
|
|
250
|
+
return out.join(eol);
|
|
251
|
+
}
|
|
252
|
+
// ─── Pinata + ethers helpers ─────────────────────────────────────────────
|
|
253
|
+
async function validatePinataJwt(jwt) {
|
|
254
|
+
try {
|
|
255
|
+
const ctrl = new AbortController();
|
|
256
|
+
const timer = setTimeout(() => ctrl.abort(), 5000);
|
|
257
|
+
const r = await fetch("https://api.pinata.cloud/data/testAuthentication", {
|
|
258
|
+
method: "GET",
|
|
259
|
+
headers: { Authorization: `Bearer ${jwt}` },
|
|
260
|
+
signal: ctrl.signal,
|
|
261
|
+
});
|
|
262
|
+
clearTimeout(timer);
|
|
263
|
+
return r.status >= 200 && r.status < 300;
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
async function deriveAddress(pk) {
|
|
270
|
+
const { Wallet } = await import("ethers");
|
|
271
|
+
return new Wallet(pk).address;
|
|
272
|
+
}
|
|
273
|
+
// ─── path + snippet helpers ──────────────────────────────────────────────
|
|
274
|
+
function findRepoRoot() {
|
|
275
|
+
// `dist/index.js` → `..` is repo root. Walk up if running from src/cli/.
|
|
276
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
277
|
+
// Two known layouts: dist/cli/init.js → up 2; dist/index.js's import → up 1 from dist.
|
|
278
|
+
// Easiest: walk up until we find package.json.
|
|
279
|
+
let cur = here;
|
|
280
|
+
for (let i = 0; i < 6; i++) {
|
|
281
|
+
if (existsSync(resolve(cur, "package.json")))
|
|
282
|
+
return cur;
|
|
283
|
+
cur = resolve(cur, "..");
|
|
284
|
+
}
|
|
285
|
+
return process.cwd();
|
|
286
|
+
}
|
|
287
|
+
function jsonSnippet(repoRoot) {
|
|
288
|
+
const distPath = resolve(repoRoot, "dist", "index.js");
|
|
289
|
+
// Use JSON.stringify to handle Windows backslashes cleanly.
|
|
290
|
+
const safe = JSON.stringify(distPath);
|
|
291
|
+
return [
|
|
292
|
+
"{",
|
|
293
|
+
` "mcpServers": {`,
|
|
294
|
+
` "dexe": {`,
|
|
295
|
+
` "command": "node",`,
|
|
296
|
+
` "args": [${safe}]`,
|
|
297
|
+
` }`,
|
|
298
|
+
` }`,
|
|
299
|
+
`}`,
|
|
300
|
+
"",
|
|
301
|
+
].join("\n");
|
|
302
|
+
}
|
|
303
|
+
function line(s) {
|
|
304
|
+
return s + "\n";
|
|
305
|
+
}
|
|
306
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type EnvCategory } from "../env/schema.js";
|
|
2
|
+
import type { DexeConfig } from "../config.js";
|
|
3
|
+
export type CheckStatus = "pass" | "warn" | "fail";
|
|
4
|
+
export type CheckCategory = EnvCategory | "network" | "process";
|
|
5
|
+
export interface CheckResult {
|
|
6
|
+
id: string;
|
|
7
|
+
category: CheckCategory;
|
|
8
|
+
status: CheckStatus;
|
|
9
|
+
message: string;
|
|
10
|
+
remediation?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface RunCheckOpts {
|
|
13
|
+
/** When omitted, checks that depend on resolved config are skipped. */
|
|
14
|
+
config?: DexeConfig;
|
|
15
|
+
/** Per-network-check timeout. Defaults to 3000ms. */
|
|
16
|
+
timeoutMs?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Run every diagnostic check in parallel, gather results.
|
|
20
|
+
*
|
|
21
|
+
* Network checks have a hard timeout that downgrades to `warn`, never `fail` —
|
|
22
|
+
* an offline laptop or VPN flake should not make the doctor scream red.
|
|
23
|
+
*/
|
|
24
|
+
export declare function runAllChecks(opts?: RunCheckOpts): Promise<CheckResult[]>;
|
|
25
|
+
//# sourceMappingURL=checks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../../src/diag/checks.ts"],"names":[],"mappings":"AACA,OAAO,EAA4C,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE9F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AACnD,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,CAAC;AAEhE,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,uEAAuE;IACvE,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAqBlF"}
|