run402-mcp 1.50.1 → 1.51.0

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 (43) hide show
  1. package/README.md +345 -153
  2. package/dist/errors.d.ts +3 -0
  3. package/dist/errors.d.ts.map +1 -1
  4. package/dist/errors.js +156 -31
  5. package/dist/errors.js.map +1 -1
  6. package/dist/index.js +5 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/tools/bundle-deploy.d.ts +2 -2
  9. package/dist/tools/bundle-deploy.d.ts.map +1 -1
  10. package/dist/tools/bundle-deploy.js +8 -4
  11. package/dist/tools/bundle-deploy.js.map +1 -1
  12. package/dist/tools/deploy-events.d.ts +25 -0
  13. package/dist/tools/deploy-events.d.ts.map +1 -0
  14. package/dist/tools/deploy-events.js +70 -0
  15. package/dist/tools/deploy-events.js.map +1 -0
  16. package/dist/tools/deploy-list.d.ts +23 -0
  17. package/dist/tools/deploy-list.d.ts.map +1 -0
  18. package/dist/tools/deploy-list.js +65 -0
  19. package/dist/tools/deploy-list.js.map +1 -0
  20. package/dist/tools/deploy-resume.d.ts.map +1 -1
  21. package/dist/tools/deploy-resume.js +2 -3
  22. package/dist/tools/deploy-resume.js.map +1 -1
  23. package/dist/tools/deploy.d.ts.map +1 -1
  24. package/dist/tools/deploy.js +2 -3
  25. package/dist/tools/deploy.js.map +1 -1
  26. package/package.json +6 -1
  27. package/sdk/dist/errors.d.ts +17 -1
  28. package/sdk/dist/errors.d.ts.map +1 -1
  29. package/sdk/dist/errors.js +39 -0
  30. package/sdk/dist/errors.js.map +1 -1
  31. package/sdk/dist/kernel.d.ts.map +1 -1
  32. package/sdk/dist/kernel.js +13 -3
  33. package/sdk/dist/kernel.js.map +1 -1
  34. package/sdk/dist/namespaces/apps.d.ts +1 -1
  35. package/sdk/dist/namespaces/apps.d.ts.map +1 -1
  36. package/sdk/dist/namespaces/apps.js +1 -11
  37. package/sdk/dist/namespaces/apps.js.map +1 -1
  38. package/sdk/dist/namespaces/deploy.d.ts +23 -1
  39. package/sdk/dist/namespaces/deploy.d.ts.map +1 -1
  40. package/sdk/dist/namespaces/deploy.js +132 -25
  41. package/sdk/dist/namespaces/deploy.js.map +1 -1
  42. package/sdk/dist/namespaces/deploy.types.d.ts +20 -0
  43. package/sdk/dist/namespaces/deploy.types.d.ts.map +1 -1
package/README.md CHANGED
@@ -2,247 +2,439 @@
2
2
  <img src=".github/logo.svg" width="120" alt="run402 logo">
3
3
  </p>
4
4
 
5
- <h1 align="center">run402 — SDK, MCP Server, CLI & OpenClaw Skill</h1>
5
+ <h1 align="center">run402 — Postgres, storage & deploys for AI agents</h1>
6
6
 
7
7
  [![Tests](https://github.com/kychee-com/run402/actions/workflows/test.yml/badge.svg)](https://github.com/kychee-com/run402/actions/workflows/test.yml)
8
8
  [![CodeQL](https://github.com/kychee-com/run402/actions/workflows/codeql.yml/badge.svg)](https://github.com/kychee-com/run402/actions/workflows/codeql.yml)
9
- [![npm: run402-mcp](https://img.shields.io/npm/v/run402-mcp?label=run402-mcp)](https://www.npmjs.com/package/run402-mcp)
9
+ [![npm: @run402/sdk](https://img.shields.io/npm/v/@run402/sdk?label=%40run402%2Fsdk)](https://www.npmjs.com/package/@run402/sdk)
10
10
  [![npm: run402](https://img.shields.io/npm/v/run402?label=run402)](https://www.npmjs.com/package/run402)
11
+ [![npm: run402-mcp](https://img.shields.io/npm/v/run402-mcp?label=run402-mcp)](https://www.npmjs.com/package/run402-mcp)
12
+ [![npm: @run402/functions](https://img.shields.io/npm/v/@run402/functions?label=%40run402%2Ffunctions)](https://www.npmjs.com/package/@run402/functions)
11
13
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
12
14
 
13
- Developer tools for [Run402](https://run402.com) provision Postgres databases, deploy static sites, serverless functions, generate images, and manage agent allowances. Available as a typed TypeScript SDK, an MCP server, an OpenClaw skill, and a CLI.
15
+ [Run402](https://run402.com) gives an agent a full Postgres database, REST API, user auth, content-addressed file storage, static site hosting, serverless functions, and image generation provisioned with one call, paid with x402 USDC on Base (or Stripe credits). The prototype tier is free on testnet.
14
16
 
15
- English | [简体中文](./README.zh-CN.md)
17
+ This monorepo ships every surface an agent can pick up:
16
18
 
17
- ## Integrations
19
+ | Package | Use when… |
20
+ |---------|-----------|
21
+ | [`@run402/sdk`](./sdk/) | Calling Run402 from TypeScript — typed kernel, isomorphic (Node 22 / Deno / Bun / V8 isolates) with a Node entry that auto-loads the local keystore + allowance + x402 fetch |
22
+ | [`run402` CLI](./cli/) | Terminal, scripts, CI, agent-controlled shells — JSON in, JSON out, exit code on failure |
23
+ | [`run402-mcp`](./src/) | Claude Desktop, Cursor, Cline, Claude Code — every CLI capability as an MCP tool |
24
+ | [OpenClaw skill](./openclaw/) | OpenClaw agents (no MCP server required) |
25
+ | [`@run402/functions`](./functions/) | Imported _inside_ deployed functions (`db(req)`, `adminDb()`, `getUser()`, `email`, `ai`) and for TypeScript autocomplete in your editor |
18
26
 
19
- | Interface | Use when... |
20
- |-----------|-------------|
21
- | [`sdk/`](./sdk/) (`@run402/sdk`) | Calling run402 from code — inside user-deployed functions, custom agents, or future code-mode sandboxes |
22
- | [`cli/`](./cli/) | Terminal, scripts, CI/CD |
23
- | [`openclaw/`](./openclaw/) | OpenClaw agent (no MCP required) |
24
- | MCP server (this package) | Claude Desktop, Cursor, Cline, Claude Code |
27
+ All four shipped surfaces release in lockstep at the same version and share a single typed kernel: `@run402/sdk`. MCP tools, CLI subcommands, and OpenClaw scripts are thin shims over SDK calls. Pick whichever interface fits your runtime.
25
28
 
26
- ## SDK
29
+ ## 30-second start
27
30
 
28
31
  ```bash
29
- npm install @run402/sdk
32
+ npm install -g run402
33
+ run402 init # creates allowance, requests testnet faucet
34
+ run402 tier set prototype # free on testnet (verifies x402 setup)
35
+ run402 projects provision --name my-app # → anon_key, service_key, project_id
36
+ run402 sites deploy-dir ./dist # incremental deploy of a directory → live URL
37
+ run402 subdomains claim my-app # → https://my-app.run402.com
30
38
  ```
31
39
 
32
- Two entry points: `@run402/sdk` (isomorphic works in Node 22, Deno, Bun, V8 isolates) and `@run402/sdk/node` (zero-config Node defaults: keystore + allowance + x402):
40
+ That's a real Postgres database + a deployed static site, paid for autonomously with testnet USDC.
41
+
42
+ ## The patterns
43
+
44
+ ### Paste-and-go assets — content-addressed URLs with SRI
45
+
46
+ `blobs.put()` returns an `AssetRef` whose `scriptTag()` / `linkTag()` / `imgTag()` emitters produce HTML with the URL, the SRI integrity hash, and modern best-practice attributes (`defer`, `loading="lazy"`, `decoding="async"`, `crossorigin`) already wired. The URL is content-addressed (`pr-<public_id>.run402.com/_blob/<key>-<8hex>.<ext>`), served through the v1.33 CDN, and never needs invalidation:
47
+
48
+ ```ts
49
+ import { run402 } from "@run402/sdk/node";
50
+ const r = run402();
51
+
52
+ const logo = await r.blobs.put(projectId, "logo.png", { bytes: pngBytes });
53
+ const app = await r.blobs.put(projectId, "app.js", { content: jsSource });
54
+ const style = await r.blobs.put(projectId, "app.css", { content: css });
55
+
56
+ const html = `
57
+ <!doctype html>
58
+ <html>
59
+ <head>${style.linkTag()}${app.scriptTag({ type: "module" })}</head>
60
+ <body>${logo.imgTag("Company logo")}</body>
61
+ </html>
62
+ `;
63
+ ```
64
+
65
+ `immutable: true` is the default — the SDK computes the SHA-256 client-side, the gateway returns a content-hashed URL, and the browser refuses execution on byte mismatch. No cache-invalidation choreography, no waiting, no integrity-attribute construction.
66
+
67
+ ### Dark-by-default tables + the expose manifest
68
+
69
+ Tables you create are unreachable via `/rest/v1/*` until you declare them in a manifest. That closes the "agent created a table, forgot to set RLS, data leaked" footgun. The manifest is convergent — applying it twice is a no-op; items removed between applies have their policies, grants, triggers, and views dropped.
70
+
71
+ ```bash
72
+ cat > manifest.json <<'EOF'
73
+ {
74
+ "$schema": "https://run402.com/schemas/manifest.v1.json",
75
+ "version": "1",
76
+ "tables": [
77
+ { "name": "items", "expose": true, "policy": "user_owns_rows",
78
+ "owner_column": "user_id", "force_owner_on_insert": true },
79
+ { "name": "audit", "expose": false }
80
+ ],
81
+ "views": [
82
+ { "name": "leaderboard", "base": "items", "select": ["user_id", "score"], "expose": true }
83
+ ],
84
+ "rpcs": [
85
+ { "name": "compute_streak", "signature": "(user_id uuid)", "grant_to": ["authenticated"] }
86
+ ]
87
+ }
88
+ EOF
89
+
90
+ run402 projects apply-expose <project_id> --file manifest.json
91
+ run402 projects get-expose <project_id>
92
+ ```
93
+
94
+ Built-in policies: `user_owns_rows` (rows where `owner_column = auth.uid()`; with `force_owner_on_insert: true` a BEFORE INSERT trigger sets it), `public_read_authenticated_write` (anyone reads, any authenticated user writes), `public_read_write_UNRESTRICTED` (fully open; requires `i_understand_this_is_unrestricted: true`), and `custom` (escape hatch — your own `CREATE POLICY` SQL).
95
+
96
+ **Auth-as-SDLC alternative:** drop the same JSON as `manifest.json` into your bundle's `files[]` and the gateway reads it, validates it against your migration SQL, applies it, and strips it before serving the site — so authorization travels with your code and never gets publicly served. The deploy returns `manifest_applied: true`; if a table referenced by the manifest isn't in the migration, the deploy is rejected with a structured `errors` array listing every violation.
97
+
98
+ ### Slick deploys — `deployDir` + plan/commit + progress
99
+
100
+ `deployDir` walks a local directory, hashes every file client-side, asks the gateway _which_ bytes it doesn't already have, and PUTs only those. Re-deploying an unchanged tree returns immediately with `bytes_uploaded: 0`.
33
101
 
34
102
  ```ts
35
103
  import { run402 } from "@run402/sdk/node";
36
104
 
37
105
  const r = run402();
38
- const project = await r.projects.provision({ tier: "prototype" });
39
- await r.blobs.put(project.project_id, "hello.txt", { content: "hi" });
40
- await r.sites.deploy(project.project_id, {
41
- files: [{ file: "index.html", data: "<h1>hello</h1>" }],
106
+ const { url, bytes_uploaded, bytes_total } = await r.sites.deployDir({
107
+ project: projectId,
108
+ dir: "./dist",
109
+ onEvent: (e) => process.stderr.write(JSON.stringify(e) + "\n"),
42
110
  });
43
111
  ```
44
112
 
45
- 17 namespaces: `projects`, `blobs`, `functions`, `secrets`, `subdomains`, `domains`, `sites`, `service`, `tier`, `allowance`, `ai`, `auth`, `senderDomain`, `billing`, `apps`, `email` (+ `webhooks`), `contracts`, `admin`.
113
+ Progress events stream over `onEvent` (or stderr from the CLI):
46
114
 
47
- All failures throw typed errors (`PaymentRequired`, `ProjectNotFound`, `Unauthorized`, `ApiError`, `NetworkError`). See [`sdk/README.md`](./sdk/README.md) for details.
115
+ | phase | Fires | Extra |
116
+ |-------|-------|-------|
117
+ | `plan` | After `POST /deploy/v1/plan` | `manifest_size` (file count) |
118
+ | `upload` | After each missing file's bytes finish PUTing | `file`, `sha256`, `done`, `total` |
119
+ | `commit` | Just before `POST /deploy/v1/commit` | — |
120
+ | `poll` | Per server-side copy poll tick | `status`, `elapsed_ms` |
48
121
 
49
- ## Quick Start
122
+ CLI:
50
123
 
51
124
  ```bash
52
- npx run402-mcp
125
+ run402 sites deploy-dir ./dist --project prj_… > result.json 2> events.log
53
126
  ```
54
127
 
55
- ## MCP Tools
128
+ ### In-function helpers — caller-context vs BYPASSRLS
56
129
 
57
- | Tool | Description |
58
- |------|-------------|
59
- | `provision_postgres_project` | Provision a Postgres database. Handles x402 payment. Saves credentials locally. |
60
- | `run_sql` | Execute SQL (DDL or queries). Returns markdown table. |
61
- | `rest_query` | Query/mutate via PostgREST. GET/POST/PATCH/DELETE with query params. |
62
- | `setup_rls` | Apply row-level security templates to tables. |
63
- | `get_schema` | Introspect database schema — tables, columns, types, constraints, RLS policies. |
64
- | `get_usage` | Get project usage report — API calls, storage, limits, lease expiry. |
65
- | `deploy_function` | Deploy a serverless function (Node 22) to a project. |
66
- | `invoke_function` | Invoke a deployed function via HTTP. |
67
- | `get_function_logs` | Get recent logs from a deployed function. |
68
- | `list_functions` | List all deployed functions for a project. |
69
- | `delete_function` | Delete a deployed function. |
70
- | `set_secret` | Set a project secret. Injected as process.env in functions. |
71
- | `list_secrets` | List secret keys for a project (values not shown). |
72
- | `delete_secret` | Delete a secret from a project. |
73
- | `deploy_site` | Deploy static site. Free with active tier. Returns live URL. |
74
- | `claim_subdomain` | Claim custom subdomain (e.g. myapp.run402.com). Free. |
75
- | `delete_subdomain` | Release a subdomain. |
76
- | `list_subdomains` | List all subdomains claimed by a project. |
77
- | `bundle_deploy` | One-call full-stack deploy: database + migrations + RLS + secrets + functions + site + subdomain. |
78
- | `browse_apps` | Browse public apps available for forking. |
79
- | `fork_app` | Fork a published app into a new project. |
80
- | `publish_app` | Publish a project as a forkable app. |
81
- | `list_versions` | List published versions of a project. |
82
- | `get_quote` | Get tier pricing. Free, no auth required. |
83
- | `set_tier` | Subscribe, renew, or upgrade tier. Auto-detects action. Handles x402 payment. |
84
- | `delete_project` | Immediately and irreversibly delete a project (cascade purge) and remove from local key store. |
85
- | `check_balance` | Check billing account balance for an agent allowance address. |
86
- | `list_projects` | List all active projects for an agent allowance address. |
87
- | `allowance_status` | Check local agent allowance status — address, network, funding. |
88
- | `allowance_create` | Create a new local agent allowance (Base Sepolia testnet). |
89
- | `allowance_export` | Export the local agent allowance address. |
90
- | `request_faucet` | Request free testnet USDC from the Run402 faucet. |
91
- | `generate_image` | Generate a PNG image from a text prompt. $0.03 via x402. |
92
- | `create_mailbox` | Create an email mailbox for a project (`slug@mail.run402.com`). |
93
- | `send_email` | Send email — template or raw HTML mode. Single recipient. |
94
- | `list_emails` | List sent emails from the project's mailbox. |
95
- | `get_email` | Get a specific email message with replies. |
96
- | `get_email_raw` | Get raw RFC-822 bytes of an inbound message (base64). For DKIM/zk-email verification. |
97
- | `get_mailbox` | Get the project's mailbox info. |
98
- | `promote_user` | Promote a project user to admin role. |
99
- | `demote_user` | Demote a project user from admin role. |
100
- | `ai_translate` | Translate text via AI (OpenRouter). Metered per project. |
101
- | `ai_moderate` | Moderate text via AI (OpenAI). Free. |
102
- | `ai_usage` | Check AI translation usage and quota. |
103
- | `add_custom_domain` | Add a custom domain to a subdomain (Cloudflare SSL). |
104
- | `list_custom_domains` | List custom domains for a project. |
105
- | `check_domain_status` | Check custom domain verification status. |
106
- | `remove_custom_domain` | Remove a custom domain. |
107
- | `request_magic_link` | Send a passwordless login email (magic link). |
108
- | `verify_magic_link` | Exchange a magic link token for access + refresh tokens. |
109
- | `set_user_password` | Change, reset, or set a user's password. |
110
- | `auth_settings` | Update project auth settings (e.g., allow_password_set). |
111
- | `register_sender_domain` | Register a custom email sending domain (DKIM verification). |
112
- | `sender_domain_status` | Check sender domain verification status. |
113
- | `remove_sender_domain` | Remove a custom sender domain. |
114
- | `create_email_billing_account` | Create a Stripe-only billing account by email (no wallet required). |
115
- | `link_wallet_to_account` | Link a wallet to an email account for hybrid Stripe + x402 access. |
116
- | `tier_checkout` | Subscribe/renew/upgrade to a tier via Stripe (alternative to x402). |
117
- | `buy_email_pack` | Buy a $5 email pack (10,000 emails, never expire). |
118
- | `set_auto_recharge` | Enable/disable auto-recharge for email packs when credits run low. |
119
- | `provision_contract_wallet` | Provision an AWS KMS-backed Ethereum wallet ($0.04/day rental, $1.20 prepay required). |
120
- | `get_contract_wallet` | Get a KMS contract wallet's metadata + live native balance. |
121
- | `list_contract_wallets` | List KMS contract wallets owned by the project. |
122
- | `set_recovery_address` | Set/clear the optional recovery address for auto-drain on day-90 deletion. |
123
- | `set_low_balance_alert` | Set the low-balance alert threshold (in wei). |
124
- | `contract_call` | Submit a smart-contract write call (chain gas + $0.000005 KMS sign fee). |
125
- | `contract_read` | Read-only smart-contract call (free, no signing). |
126
- | `get_contract_call_status` | Look up a contract call by ID — status, gas, receipt. |
127
- | `drain_contract_wallet` | Drain native balance to a destination address (works on suspended wallets). |
128
- | `delete_contract_wallet` | Schedule the KMS key for deletion (refused if balance ≥ dust). |
129
-
130
- ## Client Configuration
131
-
132
- ### CLI
133
-
134
- A standalone CLI is available in the [`cli/`](./cli/) directory.
130
+ Inside a deployed function, import from `@run402/functions`. Two distinct DB clients keep RLS clean:
131
+
132
+ ```ts
133
+ import { db, adminDb, getUser, email, ai } from "@run402/functions";
134
+
135
+ export default async (req: Request) => {
136
+ const user = await getUser(req);
137
+ if (!user) return new Response("unauthorized", { status: 401 });
138
+
139
+ // Caller-context Authorization header is forwarded; RLS evaluates against the caller's role.
140
+ const mine = await db(req).from("items").select("*").eq("user_id", user.id);
141
+
142
+ // BYPASSRLS for platform-authored writes (audit logs, cron cleanup, webhook handlers).
143
+ await adminDb().from("audit").insert({ event: "items_read", user_id: user.id });
144
+
145
+ // Send mail from the project's mailbox discovers it automatically.
146
+ if (mine.length === 0) {
147
+ await email.send({ to: user.email, subject: "Welcome", html: "<h1>hi</h1>" });
148
+ }
149
+
150
+ return Response.json(mine);
151
+ };
152
+ ```
153
+
154
+ `adminDb().sql(query, params?)` runs raw parameterized SQL and always bypasses RLS:
155
+
156
+ ```ts
157
+ const { rows, rowCount } = await adminDb().sql(
158
+ "SELECT count(*)::int AS n FROM items WHERE user_id = $1",
159
+ [user.id],
160
+ );
161
+ ```
162
+
163
+ `@run402/functions` is auto-bundled into deployed code; install it in your editor for full TypeScript autocomplete (also works at build time for static-site generation with `RUN402_SERVICE_KEY` + `RUN402_PROJECT_ID` set).
164
+
165
+ ## SDK `@run402/sdk`
135
166
 
136
167
  ```bash
137
- npm install -g run402
168
+ npm install @run402/sdk
169
+ ```
138
170
 
139
- run402 allowance create
140
- run402 allowance fund
141
- run402 deploy --tier prototype --manifest app.json
171
+ Two entry points:
172
+
173
+ - **`@run402/sdk`** isomorphic. Bring your own `CredentialsProvider` (a session-token shim, a remote vault, anything that resolves project keys + auth headers). Works in Node 22, Deno, Bun, V8 isolates.
174
+ - **`@run402/sdk/node`** — Node-only convenience. Reads `~/.config/run402/projects.json`, signs x402 payments from the local allowance, exposes `sites.deployDir(...)`.
175
+
176
+ ```ts
177
+ import { run402 } from "@run402/sdk/node";
178
+
179
+ const r = run402();
180
+ const project = await r.projects.provision({ tier: "prototype" });
181
+ await r.blobs.put(project.project_id, "hello.txt", { content: "hi" });
142
182
  ```
143
183
 
144
- See [`cli/README.md`](./cli/README.md) for full usage.
184
+ 18 namespaces: `projects`, `blobs`, `functions`, `secrets`, `subdomains`, `domains`, `sites`, `service`, `tier`, `allowance`, `ai`, `auth`, `senderDomain`, `billing`, `apps`, `email` (+ `webhooks`), `contracts`, `admin`. Every operation throws a typed `Run402Error` subclass on failure: `PaymentRequired`, `ProjectNotFound`, `Unauthorized`, `ApiError`, `NetworkError`. See [`sdk/README.md`](./sdk/README.md).
145
185
 
146
- ### OpenClaw
186
+ ## CLI — `run402`
147
187
 
148
- A standalone skill is available in the [`openclaw/`](./openclaw/) directory — no MCP server required. It calls the Run402 API directly via Node.js scripts.
188
+ ```bash
189
+ npm install -g run402
190
+ ```
191
+
192
+ Every subcommand prints JSON to stdout, JSON errors to stderr, exits 0 on success and 1 on failure — designed for an agent shell, not a human. Full reference: [`cli/llms-cli.txt`](./cli/llms-cli.txt) (also at <https://run402.com/llms-cli.txt>).
149
193
 
150
194
  ```bash
151
- cp -r openclaw ~/.openclaw/skills/run402
152
- cd ~/.openclaw/skills/run402/scripts && npm install
195
+ run402 init # one-shot allowance + faucet + tier check
196
+ run402 status # account snapshot (allowance, balance, tier, projects)
197
+ run402 projects provision --name my-app
198
+ run402 projects sql <id> "CREATE TABLE …"
199
+ run402 projects apply-expose <id> --file manifest.json
200
+ run402 sites deploy-dir ./dist
201
+ run402 functions deploy <id> <name> --file fn.ts
202
+ run402 blob put ./asset.png --immutable
203
+ run402 blob diagnose <url> # inspect live CDN state for a public URL
204
+ run402 cdn wait-fresh <url> --sha <hex> # poll until a mutable URL serves the new SHA
153
205
  ```
154
206
 
155
- See [`openclaw/README.md`](./openclaw/README.md) for details.
207
+ The active project is sticky: `run402 projects use <id>` makes `<id>` the default for every subsequent `<id>`-taking subcommand, so most commands work without it.
208
+
209
+ ## MCP server — `run402-mcp`
156
210
 
157
- ### MCP Clients
211
+ ```bash
212
+ npx -y run402-mcp # standalone test
213
+ ```
158
214
 
159
- #### Claude Desktop
215
+ ### Claude Desktop
160
216
 
161
217
  Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
162
218
 
163
219
  ```json
164
220
  {
165
221
  "mcpServers": {
166
- "run402": {
167
- "command": "npx",
168
- "args": ["-y", "run402-mcp"]
169
- }
222
+ "run402": { "command": "npx", "args": ["-y", "run402-mcp"] }
170
223
  }
171
224
  }
172
225
  ```
173
226
 
174
- #### Cursor
227
+ ### Cursor
175
228
 
176
- Add to `.cursor/mcp.json` in your project:
229
+ Add to `.cursor/mcp.json`:
177
230
 
178
231
  ```json
179
232
  {
180
233
  "mcpServers": {
181
- "run402": {
182
- "command": "npx",
183
- "args": ["-y", "run402-mcp"]
184
- }
234
+ "run402": { "command": "npx", "args": ["-y", "run402-mcp"] }
185
235
  }
186
236
  }
187
237
  ```
188
238
 
189
- #### Cline
239
+ ### Cline
190
240
 
191
- Add to Cline MCP settings:
241
+ Add to your Cline MCP settings:
192
242
 
193
243
  ```json
194
244
  {
195
245
  "mcpServers": {
196
- "run402": {
197
- "command": "npx",
198
- "args": ["-y", "run402-mcp"]
199
- }
246
+ "run402": { "command": "npx", "args": ["-y", "run402-mcp"] }
200
247
  }
201
248
  }
202
249
  ```
203
250
 
204
- #### Claude Code
251
+ ### Claude Code
205
252
 
206
253
  ```bash
207
254
  claude mcp add run402 -- npx -y run402-mcp
208
255
  ```
209
256
 
210
- ## How It Works
257
+ ## OpenClaw skill
258
+
259
+ ```bash
260
+ cp -r openclaw ~/.openclaw/skills/run402
261
+ cd ~/.openclaw/skills/run402/scripts && npm install
262
+ ```
263
+
264
+ Each script re-exports from `cli/lib/*.mjs` — the OpenClaw command surface is identical to the CLI command surface by construction. See [`openclaw/README.md`](./openclaw/README.md).
265
+
266
+ ## MCP tools
267
+
268
+ The full MCP surface — every tool is a thin shim over an SDK call.
269
+
270
+ ### Database
271
+
272
+ | Tool | Description |
273
+ |------|-------------|
274
+ | `provision_postgres_project` | Provision a new database. Auto-handles x402 payment. |
275
+ | `run_sql` | Execute SQL (DDL or queries). Returns a markdown table. |
276
+ | `rest_query` | Query/mutate via PostgREST. |
277
+ | `apply_expose` | Apply the declarative authorization manifest (tables, views, RPCs). Convergent — drops items removed between applies. |
278
+ | `get_expose` | Return the current manifest. `source` is either `applied` (from the tracking table) or `introspected` (regenerated from live DB state). |
279
+ | `get_schema` | Introspect tables, columns, types, constraints, RLS policies. |
280
+ | `get_usage` | Per-project usage report (API calls, storage, lease expiry). |
281
+ | `promote_user` / `demote_user` | Manage `project_admin` role on a project user. |
282
+ | `delete_project` | Cascade purge — schema, Lambdas, S3 site files, deployments, secrets, published versions. Irreversible. |
283
+
284
+ ### Blob storage (content-addressed CDN)
285
+
286
+ | Tool | Description |
287
+ |------|-------------|
288
+ | `blob_put` | Upload a blob (any size, up to 5 TiB) via direct-to-S3 presigned URLs. Returns an `AssetRef` with `scriptTag()` / `linkTag()` / `imgTag()` emitters. |
289
+ | `blob_get` | Download a blob to a local file. |
290
+ | `blob_ls` | Keyset-paginated list with prefix filter. |
291
+ | `blob_rm` | Delete a blob. |
292
+ | `blob_sign` | Time-boxed presigned GET URL for a private blob. |
293
+ | `diagnose_public_url` | Live CDN state for a public URL — expected vs observed SHA, cache headers, invalidation status. |
294
+ | `wait_for_cdn_freshness` | Poll a mutable URL until it serves the expected SHA-256. |
295
+
296
+ ### Sites & subdomains
297
+
298
+ | Tool | Description |
299
+ |------|-------------|
300
+ | `deploy_site` | Deploy a static site from inline file bytes. |
301
+ | `deploy_site_dir` | Deploy a static site from a local directory. v1.32 plan/commit transport — only uploads bytes the gateway doesn't have. |
302
+ | `get_deployment` | Fetch deployment status and URL. |
303
+ | `claim_subdomain` | Claim `<name>.run402.com` (idempotent; reassigns to latest deployment on subsequent deploys). |
304
+ | `list_subdomains` / `delete_subdomain` | Manage subdomains. |
305
+ | `add_custom_domain` / `list_custom_domains` / `check_domain_status` / `remove_custom_domain` | Point your own domain at a Run402 subdomain. |
306
+ | `bundle_deploy` | One-call full-stack deploy: database + migrations + authorization manifest (`manifest.json` in `files[]` — gateway validates it, applies it, then strips it before serving the site) + secrets + functions + site + subdomain. |
307
+
308
+ ### Functions & secrets
309
+
310
+ | Tool | Description |
311
+ |------|-------------|
312
+ | `deploy_function` | Deploy a Node 22 serverless function. Cron-schedulable. |
313
+ | `invoke_function` | Invoke a deployed function (test path). |
314
+ | `get_function_logs` | Recent logs (CloudWatch). |
315
+ | `update_function` | Update schedule / timeout / memory without redeploying code. |
316
+ | `list_functions` / `delete_function` | List / remove functions. |
317
+ | `set_secret` / `list_secrets` / `delete_secret` | Manage `process.env` secrets injected into all functions. |
318
+
319
+ ### Auth & email
211
320
 
212
- 1. **Provision** Call `provision_postgres_project` to create a database. The server handles x402 payment negotiation and stores credentials locally.
213
- 2. **Build** — Use `run_sql` to create tables, `rest_query` to insert/query data, and `blob_put` for storage.
214
- 3. **Deploy** — Use `deploy_site` for static sites, `deploy_function` for serverless functions, or `bundle_deploy` for a full-stack app in one call.
215
- 4. **Renew** Call `set_tier` before your lease expires.
321
+ | Tool | Description |
322
+ |------|-------------|
323
+ | `request_magic_link` | Send a passwordless login email. |
324
+ | `verify_magic_link` | Exchange the magic link token for `access_token` + `refresh_token`. |
325
+ | `set_user_password` | Change, reset, or set a user's password. |
326
+ | `auth_settings` | Toggle `allow_password_set` for passwordless users. |
327
+ | `create_mailbox` / `get_mailbox` / `delete_mailbox` | Per-project mailbox at `<slug>@mail.run402.com`. |
328
+ | `send_email` | Template (`project_invite`, `magic_link`, `notification`) or raw HTML. Single recipient. |
329
+ | `list_emails` / `get_email` / `get_email_raw` | Read messages. `get_email_raw` returns RFC-822 bytes for DKIM / zk-email verification. |
330
+ | `register_mailbox_webhook` / `list_mailbox_webhooks` / `get_mailbox_webhook` / `update_mailbox_webhook` / `delete_mailbox_webhook` | Email-event webhooks (delivery, bounced, complained, reply_received). |
331
+ | `register_sender_domain` / `sender_domain_status` / `remove_sender_domain` | Send from your own domain (DKIM verified). |
332
+ | `enable_sender_domain_inbound` / `disable_sender_domain_inbound` | Receive replies on your custom sender domain. |
333
+
334
+ ### AI helpers
335
+
336
+ | Tool | Description |
337
+ |------|-------------|
338
+ | `generate_image` | Text-to-PNG via x402 ($0.03 / image). |
339
+ | `ai_translate` | Translate text. Metered per project. |
340
+ | `ai_moderate` | Moderate text (free). |
341
+ | `ai_usage` | Translation quota (used / included / remaining). |
342
+
343
+ ### Apps marketplace
344
+
345
+ | Tool | Description |
346
+ |------|-------------|
347
+ | `browse_apps` | Browse public forkable apps. |
348
+ | `get_app` | Inspect an app, including expected `bootstrap_variables`. |
349
+ | `fork_app` | Clone schema + site + functions into a new project. Runs the app's `bootstrap` function with provided variables. |
350
+ | `publish_app` | Publish a project as a forkable app. |
351
+ | `list_versions` / `update_version` / `delete_version` | Manage published versions. |
352
+
353
+ ### Tier & billing
354
+
355
+ | Tool | Description |
356
+ |------|-------------|
357
+ | `set_tier` | Subscribe / renew / upgrade a tier (auto-detects action). x402 payment. |
358
+ | `tier_status` | Current tier and lease expiry. |
359
+ | `get_quote` | Tier pricing (free, no auth). |
360
+ | `tier_checkout` | Stripe checkout for a tier (alternative to x402). |
361
+ | `create_email_billing_account` / `link_wallet_to_account` | Email-based billing accounts; hybrid Stripe + x402. |
362
+ | `billing_history` | Ledger history. |
363
+ | `buy_email_pack` | $5 for 10,000 emails (never expire). |
364
+ | `set_auto_recharge` | Auto-buy email packs when credits run low. |
365
+
366
+ ### KMS contract wallets (on-chain signing)
216
367
 
217
- ### Payment Flow
368
+ | Tool | Description |
369
+ |------|-------------|
370
+ | `provision_contract_wallet` | AWS KMS-backed Ethereum wallet. $0.04/day rental + $0.000005 per call. Private keys never leave KMS. |
371
+ | `get_contract_wallet` / `list_contract_wallets` | Metadata + live native balance. |
372
+ | `set_recovery_address` / `set_low_balance_alert` | Optional safety nets. |
373
+ | `contract_call` | Submit a write call (chain gas at-cost + KMS sign fee). |
374
+ | `contract_read` | Read-only call (free). |
375
+ | `get_contract_call_status` | Lifecycle, gas, receipt. |
376
+ | `drain_contract_wallet` | Drain native balance (works on suspended wallets — the safety valve). |
377
+ | `delete_contract_wallet` | Schedule KMS key deletion (refused if balance ≥ dust). |
218
378
 
219
- The prototype tier is free — it uses testnet USDC to test the x402 payment flow end-to-end (no real money). Hobby and team tiers, renewals, and image generation require real x402 micropayments (USDC on Base or Stripe credits). When payment is needed, tools return payment details (not errors) so the LLM can reason about them and guide the user through payment.
379
+ ### Allowance & account
220
380
 
221
- ### Key Storage
381
+ | Tool | Description |
382
+ |------|-------------|
383
+ | `init` | One-shot setup: allowance + faucet + tier check + project list. |
384
+ | `status` | Full account snapshot (allowance, balance, tier, projects). |
385
+ | `allowance_status` / `allowance_create` / `allowance_export` | Local allowance management. |
386
+ | `request_faucet` | Request testnet USDC. |
387
+ | `check_balance` | USDC balance for an allowance address. |
388
+ | `list_projects` | Active projects for a wallet. |
389
+ | `pin_project` | Pin a project (admin only — bypasses lifecycle state machine). |
390
+ | `project_info` / `project_keys` / `project_use` | Inspect / set the active project. |
391
+ | `create_checkout` | Stripe checkout to add cash credit. |
392
+ | `send_message` / `set_agent_contact` | Send feedback to the Run402 team; register agent contact info. |
393
+
394
+ ### Service status (no auth)
222
395
 
223
- Project credentials are saved to `~/.config/run402/projects.json` with `0600` permissions. Each project stores:
224
- - `anon_key` — for public-facing queries (respects RLS)
225
- - `service_key` — for admin operations (bypasses RLS)
226
- - `tier` prototype, hobby, or team
227
- - `expires_at` — lease expiration timestamp
396
+ | Tool | Description |
397
+ |------|-------------|
398
+ | `service_status` | Public availability report 24h/7d/30d uptime per capability, operator, deployment topology. |
399
+ | `service_health` | Liveness probe with per-dependency results. |
228
400
 
229
- ## Environment Variables
401
+ ## Configuration
230
402
 
231
- | Variable | Default | Description |
232
- |----------|---------|-------------|
233
- | `RUN402_API_BASE` | `https://api.run402.com` | API base URL |
234
- | `RUN402_CONFIG_DIR` | `~/.config/run402` | Config directory for key storage |
235
- | `RUN402_ALLOWANCE_PATH` | `{config_dir}/allowance.json` | Custom allowance (wallet) file path |
403
+ | Variable | Default | Purpose |
404
+ |----------|---------|---------|
405
+ | `RUN402_API_BASE` | `https://api.run402.com` | API base URL (override for staging) |
406
+ | `RUN402_CONFIG_DIR` | `~/.config/run402` | Local credential storage directory |
407
+ | `RUN402_ALLOWANCE_PATH` | `{config_dir}/allowance.json` | Custom allowance file path |
408
+
409
+ Local state lives at:
410
+
411
+ - `~/.config/run402/projects.json` (`0600`) — `{ projects: { <id>: { anon_key, service_key, tier, lease_expires_at } } }`
412
+ - `~/.config/run402/allowance.json` (`0600`) — wallet for x402 signing
413
+
414
+ `anon_key` and `service_key` have no expiry — lease enforcement happens server-side. Rotate them by deleting the project and re-provisioning.
236
415
 
237
416
  ## Development
238
417
 
239
418
  ```bash
240
- npm run build # tsc dist/
241
- npm test # all tests (SKILL + sync + unit)
242
- npm run test:sync # check MCP/CLI/OpenClaw stay in sync
243
- npm run test:skill # validate SKILL.md structure
419
+ npm run build # builds core/, sdk/, functions/, then the MCP server
420
+ npm test # SKILL + sync + unit tests
421
+ npm run test:e2e # 47 CLI end-to-end tests
422
+ npm run test:sync # checks MCP/CLI/OpenClaw/SDK stay in sync
423
+ npm run test:skill # validates SKILL.md frontmatter + body
244
424
  ```
245
425
 
426
+ Architecture: every tool / subcommand / skill script is a thin shim over an `@run402/sdk` call. `core/` holds Node-only filesystem primitives (keystore, allowance, SIWE signing) wrapped by the SDK's Node provider. See [`CLAUDE.md`](./CLAUDE.md) for the full layout.
427
+
428
+ ## Links
429
+
430
+ - Web: <https://run402.com>
431
+ - API docs (HTTP): <https://run402.com/llms.txt> · <https://run402.com/openapi.json>
432
+ - CLI docs: <https://run402.com/llms-cli.txt>
433
+ - Status: <https://api.run402.com/status>
434
+ - Health: <https://api.run402.com/health>
435
+
436
+ [简体中文](./README.zh-CN.md)
437
+
246
438
  ## License
247
439
 
248
440
  MIT
package/dist/errors.d.ts CHANGED
@@ -22,6 +22,9 @@ export declare function formatApiError(res: {
22
22
  status: number;
23
23
  body: unknown;
24
24
  }, context: string): ToolResult;
25
+ export declare function formatCanonicalErrorContext(source: unknown, opts?: {
26
+ includeDetails?: boolean;
27
+ }): string[];
25
28
  /**
26
29
  * Consistent "project not found in key store" error.
27
30
  */
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qDAAqD;AAQrD,uDAAuD;AACvD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,EACtC,OAAO,EAAE,MAAM,GACd,UAAU,CA2FZ;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,CAY7D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,CA4BrE"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qDAAqD;AAQrD,uDAAuD;AACvD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,EACtC,OAAO,EAAE,MAAM,GACd,UAAU,CAsGZ;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,OAAO,EACf,IAAI,GAAE;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,GACtC,MAAM,EAAE,CAyBV;AAgGD;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,CAY7D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,CA4BrE"}