run402 1.0.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.
package/cli.mjs ADDED
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * run402 — CLI for Run402
4
+ * https://run402.com
5
+ */
6
+
7
+ const [,, cmd, sub, ...rest] = process.argv;
8
+
9
+ const HELP = `run402 v1.0.0 — Full-stack backend infra for AI agents
10
+ https://run402.com
11
+
12
+ Usage:
13
+ run402 <command> [subcommand] [options]
14
+
15
+ Commands:
16
+ wallet Manage your x402 wallet (create, fund, check status)
17
+ projects Manage deployed projects (list, query, inspect, renew, delete)
18
+ deploy Deploy a full-stack app or static site (Postgres + hosting)
19
+ image Generate AI images via x402 micropayments
20
+
21
+ Run 'run402 <command> --help' for detailed usage of each command.
22
+
23
+ Examples:
24
+ run402 wallet create
25
+ run402 wallet fund
26
+ run402 deploy --tier prototype --manifest app.json
27
+ run402 projects list
28
+ run402 projects sql <project_id> "SELECT * FROM users LIMIT 5"
29
+ run402 image generate "a startup mascot, pixel art" --output logo.png
30
+
31
+ Getting started:
32
+ 1. run402 wallet create Create a local wallet
33
+ 2. run402 wallet fund Fund it with test USDC (Base Sepolia faucet)
34
+ 3. run402 deploy ... Deploy your app — payments handled automatically
35
+ `;
36
+
37
+ if (!cmd || cmd === '--help' || cmd === '-h') {
38
+ console.log(HELP);
39
+ process.exit(cmd ? 0 : 0);
40
+ }
41
+
42
+ switch (cmd) {
43
+ case "wallet": {
44
+ const { run } = await import("./lib/wallet.mjs");
45
+ await run(sub, rest);
46
+ break;
47
+ }
48
+ case "projects": {
49
+ const { run } = await import("./lib/projects.mjs");
50
+ await run(sub, rest);
51
+ break;
52
+ }
53
+ case "deploy": {
54
+ const { run } = await import("./lib/deploy.mjs");
55
+ await run([sub, ...rest].filter(Boolean));
56
+ break;
57
+ }
58
+ case "image": {
59
+ const { run } = await import("./lib/image.mjs");
60
+ await run(sub, rest);
61
+ break;
62
+ }
63
+ default:
64
+ console.error(`Unknown command: ${cmd}\n`);
65
+ console.log(HELP);
66
+ process.exit(1);
67
+ }
package/lib/config.mjs ADDED
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Run402 config loader — reads local project and wallet state.
3
+ * Kept in a separate module so credential reads stay isolated.
4
+ */
5
+
6
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, chmodSync } from "fs";
7
+ import { join } from "path";
8
+ import { homedir } from "os";
9
+
10
+ export const CONFIG_DIR = join(homedir(), ".config", "run402");
11
+ export const WALLET_FILE = join(CONFIG_DIR, "wallet.json");
12
+ export const PROJECTS_FILE = join(CONFIG_DIR, "projects.json");
13
+ export const API = "https://api.run402.com";
14
+
15
+ export function readWallet() {
16
+ if (!existsSync(WALLET_FILE)) return null;
17
+ return JSON.parse(readFileSync(WALLET_FILE, "utf-8"));
18
+ }
19
+
20
+ export function saveWallet(data) {
21
+ mkdirSync(CONFIG_DIR, { recursive: true });
22
+ writeFileSync(WALLET_FILE, JSON.stringify(data, null, 2), { mode: 0o600 });
23
+ try { chmodSync(WALLET_FILE, 0o600); } catch {}
24
+ }
25
+
26
+ export function loadProjects() {
27
+ if (!existsSync(PROJECTS_FILE)) return [];
28
+ return JSON.parse(readFileSync(PROJECTS_FILE, "utf-8"));
29
+ }
30
+
31
+ export function saveProjects(projects) {
32
+ mkdirSync(CONFIG_DIR, { recursive: true });
33
+ writeFileSync(PROJECTS_FILE, JSON.stringify(projects, null, 2), { mode: 0o600 });
34
+ }
35
+
36
+ export function findProject(id) {
37
+ const p = loadProjects().find(p => p.project_id === id);
38
+ if (!p) { console.error(`Project ${id} not found in local registry.`); process.exit(1); }
39
+ return p;
40
+ }
package/lib/deploy.mjs ADDED
@@ -0,0 +1,92 @@
1
+ import { readFileSync, existsSync, mkdirSync, writeFileSync } from "fs";
2
+ import { readWallet, loadProjects, API, WALLET_FILE, PROJECTS_FILE } from "./config.mjs";
3
+
4
+ const HELP = `run402 deploy — Deploy a full-stack app or static site on Run402
5
+
6
+ Usage:
7
+ run402 deploy [options]
8
+ cat manifest.json | run402 deploy [options]
9
+
10
+ Options:
11
+ --tier <tier> Deployment tier: prototype | hobby | team (default: prototype)
12
+ --manifest <file> Path to manifest JSON file (default: read from stdin)
13
+ --help, -h Show this help message
14
+
15
+ Tiers:
16
+ prototype Smallest, cheapest — great for demos and experiments
17
+ hobby Mid-tier — personal projects and side hustles
18
+ team Full power — production-ready, shared team access
19
+
20
+ Manifest format (JSON):
21
+ {
22
+ "name": "my-app",
23
+ "files": {
24
+ "index.html": "<html>...</html>",
25
+ "style.css": "body { margin: 0; }"
26
+ },
27
+ "env": {
28
+ "MY_VAR": "value"
29
+ }
30
+ }
31
+
32
+ Examples:
33
+ run402 deploy --tier prototype --manifest app.json
34
+ run402 deploy --tier hobby --manifest app.json
35
+ cat app.json | run402 deploy --tier team
36
+
37
+ Notes:
38
+ - Requires a funded wallet (run402 wallet create && run402 wallet fund)
39
+ - Payments are processed automatically via x402 micropayments (Base Sepolia USDC)
40
+ - Project credentials (project_id, keys, URL) are saved locally after deploy
41
+ - Use 'run402 projects list' to see all deployed projects
42
+ `;
43
+
44
+ async function readStdin() {
45
+ const chunks = [];
46
+ for await (const chunk of process.stdin) chunks.push(chunk);
47
+ return Buffer.concat(chunks).toString("utf-8");
48
+ }
49
+
50
+ function saveProject(project) {
51
+ const projects = loadProjects();
52
+ projects.push({ project_id: project.project_id, anon_key: project.anon_key, service_key: project.service_key, tier: project.tier, lease_expires_at: project.lease_expires_at, site_url: project.site_url || project.subdomain_url, deployed_at: new Date().toISOString() });
53
+ const dir = PROJECTS_FILE.replace(/\/[^/]+$/, "");
54
+ mkdirSync(dir, { recursive: true });
55
+ writeFileSync(PROJECTS_FILE, JSON.stringify(projects, null, 2), { mode: 0o600 });
56
+ }
57
+
58
+ export async function run(args) {
59
+ const opts = { tier: "prototype", manifest: null };
60
+ for (let i = 0; i < args.length; i++) {
61
+ if (args[i] === "--help" || args[i] === "-h") { console.log(HELP); process.exit(0); }
62
+ if (args[i] === "--tier" && args[i + 1]) opts.tier = args[++i];
63
+ if (args[i] === "--manifest" && args[i + 1]) opts.manifest = args[++i];
64
+ }
65
+
66
+ if (!existsSync(WALLET_FILE)) {
67
+ console.error(JSON.stringify({ status: "error", message: "No wallet found. Run: run402 wallet create && run402 wallet fund" }));
68
+ process.exit(1);
69
+ }
70
+ const wallet = readWallet();
71
+ const manifest = opts.manifest ? JSON.parse(readFileSync(opts.manifest, "utf-8")) : JSON.parse(await readStdin());
72
+
73
+ const { privateKeyToAccount } = await import("viem/accounts");
74
+ const { createPublicClient, http } = await import("viem");
75
+ const { baseSepolia } = await import("viem/chains");
76
+ const { x402Client, wrapFetchWithPayment } = await import("@x402/fetch");
77
+ const { ExactEvmScheme } = await import("@x402/evm/exact/client");
78
+ const { toClientEvmSigner } = await import("@x402/evm");
79
+
80
+ const account = privateKeyToAccount(wallet.privateKey);
81
+ const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });
82
+ const signer = toClientEvmSigner(account, publicClient);
83
+ const client = new x402Client();
84
+ client.register("eip155:84532", new ExactEvmScheme(signer));
85
+ const fetchPaid = wrapFetchWithPayment(fetch, client);
86
+
87
+ const res = await fetchPaid(`${API}/v1/deploy/${opts.tier}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(manifest) });
88
+ const result = await res.json();
89
+ if (!res.ok) { console.error(JSON.stringify({ status: "error", http: res.status, ...result })); process.exit(1); }
90
+ saveProject(result);
91
+ console.log(JSON.stringify(result, null, 2));
92
+ }
package/lib/image.mjs ADDED
@@ -0,0 +1,80 @@
1
+ import { writeFileSync, existsSync } from "fs";
2
+ import { readWallet, API, WALLET_FILE } from "./config.mjs";
3
+
4
+ const HELP = `run402 image — Generate AI images via x402 micropayments
5
+
6
+ Usage:
7
+ run402 image generate "<prompt>" [options]
8
+
9
+ Options:
10
+ --aspect <ratio> Image aspect ratio: square | landscape | portrait (default: square)
11
+ --output <file> Save image to file (e.g. output.png)
12
+ If omitted, returns base64 JSON to stdout
13
+ --help, -h Show this help message
14
+
15
+ Examples:
16
+ run402 image generate "a startup mascot, pixel art"
17
+ run402 image generate "futuristic city at night" --aspect landscape
18
+ run402 image generate "portrait of a cat CEO" --aspect portrait --output cat.png
19
+
20
+ Output (without --output):
21
+ { "status": "ok", "aspect": "square", "content_type": "image/png", "image": "<base64>" }
22
+
23
+ Notes:
24
+ - Requires a funded wallet (run402 wallet create && run402 wallet fund)
25
+ - Payments are processed automatically via x402 micropayments (Base Sepolia USDC)
26
+ - Use --output to save directly to a file instead of printing base64
27
+ `;
28
+
29
+ export async function run(sub, args) {
30
+ if (!sub || sub === '--help' || sub === '-h') {
31
+ console.log(HELP);
32
+ process.exit(0);
33
+ }
34
+
35
+ if (sub !== "generate") {
36
+ console.error(`Unknown subcommand: ${sub}\n`);
37
+ console.log(HELP);
38
+ process.exit(1);
39
+ }
40
+
41
+ const opts = { prompt: null, aspect: "square", output: null };
42
+ let i = 0;
43
+ if (i < args.length && !args[i].startsWith("--")) opts.prompt = args[i++];
44
+ while (i < args.length) {
45
+ if (args[i] === "--help" || args[i] === "-h") { console.log(HELP); process.exit(0); }
46
+ else if (args[i] === "--aspect" && args[i + 1]) { opts.aspect = args[++i]; }
47
+ else if (args[i] === "--output" && args[i + 1]) { opts.output = args[++i]; }
48
+ i++;
49
+ }
50
+
51
+ if (!opts.prompt) { console.error(JSON.stringify({ status: "error", message: "Prompt required. Usage: run402 image generate \"your prompt\"" })); process.exit(1); }
52
+ if (!existsSync(WALLET_FILE)) { console.error(JSON.stringify({ status: "error", message: "No wallet found. Run: run402 wallet create && run402 wallet fund" })); process.exit(1); }
53
+
54
+ const wallet = readWallet();
55
+ const { privateKeyToAccount } = await import("viem/accounts");
56
+ const { createPublicClient, http } = await import("viem");
57
+ const { baseSepolia } = await import("viem/chains");
58
+ const { x402Client, wrapFetchWithPayment } = await import("@x402/fetch");
59
+ const { ExactEvmScheme } = await import("@x402/evm/exact/client");
60
+ const { toClientEvmSigner } = await import("@x402/evm");
61
+
62
+ const account = privateKeyToAccount(wallet.privateKey);
63
+ const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });
64
+ const signer = toClientEvmSigner(account, publicClient);
65
+ const client = new x402Client();
66
+ client.register("eip155:84532", new ExactEvmScheme(signer));
67
+ const fetchPaid = wrapFetchWithPayment(fetch, client);
68
+
69
+ const res = await fetchPaid(`${API}/v1/generate-image`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ prompt: opts.prompt, aspect: opts.aspect }) });
70
+ const data = await res.json();
71
+ if (!res.ok) { console.error(JSON.stringify({ status: "error", http: res.status, ...data })); process.exit(1); }
72
+
73
+ if (opts.output) {
74
+ const buf = Buffer.from(data.image, "base64");
75
+ writeFileSync(opts.output, buf);
76
+ console.log(JSON.stringify({ status: "ok", file: opts.output, size: buf.length, aspect: data.aspect }));
77
+ } else {
78
+ console.log(JSON.stringify({ status: "ok", aspect: data.aspect, content_type: data.content_type, image: data.image }));
79
+ }
80
+ }
@@ -0,0 +1,128 @@
1
+ import { findProject, loadProjects, saveProjects, readWallet, API, WALLET_FILE } from "./config.mjs";
2
+ import { existsSync } from "fs";
3
+
4
+ const HELP = `run402 projects — Manage your deployed Run402 projects
5
+
6
+ Usage:
7
+ run402 projects <subcommand> [args...]
8
+
9
+ Subcommands:
10
+ list List all your projects (IDs, tiers, URLs, expiry)
11
+ sql <id> "<query>" Run a SQL query against a project's Postgres DB
12
+ rest <id> <table> [params] Query a table via the REST API (PostgREST)
13
+ usage <id> Show compute/storage usage for a project
14
+ schema <id> Inspect the database schema
15
+ renew <id> Extend the project lease (pays via x402)
16
+ delete <id> Delete a project and remove it from local state
17
+
18
+ Examples:
19
+ run402 projects list
20
+ run402 projects sql abc123 "SELECT * FROM users LIMIT 5"
21
+ run402 projects rest abc123 users "limit=10&select=id,name"
22
+ run402 projects usage abc123
23
+ run402 projects schema abc123
24
+ run402 projects renew abc123
25
+ run402 projects delete abc123
26
+
27
+ Notes:
28
+ - <id> is the project_id shown in 'run402 projects list'
29
+ - 'rest' uses PostgREST query syntax (table name + optional query string)
30
+ - 'renew' requires a funded wallet — payment is automatic via x402
31
+ `;
32
+
33
+ async function setupPaidFetch() {
34
+ if (!existsSync(WALLET_FILE)) {
35
+ console.error(JSON.stringify({ status: "error", message: "No wallet found. Run: run402 wallet create && run402 wallet fund" }));
36
+ process.exit(1);
37
+ }
38
+ const wallet = readWallet();
39
+ const { privateKeyToAccount } = await import("viem/accounts");
40
+ const { createPublicClient, http } = await import("viem");
41
+ const { baseSepolia } = await import("viem/chains");
42
+ const { x402Client, wrapFetchWithPayment } = await import("@x402/fetch");
43
+ const { ExactEvmScheme } = await import("@x402/evm/exact/client");
44
+ const { toClientEvmSigner } = await import("@x402/evm");
45
+ const account = privateKeyToAccount(wallet.privateKey);
46
+ const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });
47
+ const signer = toClientEvmSigner(account, publicClient);
48
+ const client = new x402Client();
49
+ client.register("eip155:84532", new ExactEvmScheme(signer));
50
+ return wrapFetchWithPayment(fetch, client);
51
+ }
52
+
53
+ async function list() {
54
+ const projects = loadProjects();
55
+ if (projects.length === 0) { console.log(JSON.stringify({ status: "ok", projects: [], message: "No projects yet." })); return; }
56
+ console.log(JSON.stringify(projects.map(p => ({ project_id: p.project_id, tier: p.tier, site_url: p.site_url, lease_expires_at: p.lease_expires_at, deployed_at: p.deployed_at })), null, 2));
57
+ }
58
+
59
+ async function sqlCmd(projectId, query) {
60
+ const p = findProject(projectId);
61
+ const res = await fetch(`${API}/admin/v1/projects/${projectId}/sql`, { method: "POST", headers: { "Authorization": `Bearer ${p.service_key}`, "Content-Type": "text/plain" }, body: query });
62
+ console.log(JSON.stringify(await res.json(), null, 2));
63
+ }
64
+
65
+ async function rest(projectId, table, queryParams) {
66
+ const p = findProject(projectId);
67
+ const res = await fetch(`${API}/rest/v1/${table}${queryParams ? '?' + queryParams : ''}`, { headers: { "apikey": p.anon_key } });
68
+ console.log(JSON.stringify(await res.json(), null, 2));
69
+ }
70
+
71
+ async function usage(projectId) {
72
+ const p = findProject(projectId);
73
+ const res = await fetch(`${API}/admin/v1/projects/${projectId}/usage`, { headers: { "Authorization": `Bearer ${p.service_key}` } });
74
+ const data = await res.json();
75
+ if (!res.ok) { console.error(JSON.stringify({ status: "error", http: res.status, ...data })); process.exit(1); }
76
+ console.log(JSON.stringify(data, null, 2));
77
+ }
78
+
79
+ async function schema(projectId) {
80
+ const p = findProject(projectId);
81
+ const res = await fetch(`${API}/admin/v1/projects/${projectId}/schema`, { headers: { "Authorization": `Bearer ${p.service_key}` } });
82
+ const data = await res.json();
83
+ if (!res.ok) { console.error(JSON.stringify({ status: "error", http: res.status, ...data })); process.exit(1); }
84
+ console.log(JSON.stringify(data, null, 2));
85
+ }
86
+
87
+ async function renew(projectId) {
88
+ const fetchPaid = await setupPaidFetch();
89
+ const res = await fetchPaid(`${API}/v1/projects/${projectId}/renew`, { method: "POST", headers: { "Content-Type": "application/json" } });
90
+ const data = await res.json();
91
+ if (!res.ok) { console.error(JSON.stringify({ status: "error", http: res.status, ...data })); process.exit(1); }
92
+ const projects = loadProjects();
93
+ const idx = projects.findIndex(pr => pr.project_id === projectId);
94
+ if (idx >= 0 && data.lease_expires_at) { projects[idx].lease_expires_at = data.lease_expires_at; saveProjects(projects); }
95
+ console.log(JSON.stringify(data, null, 2));
96
+ }
97
+
98
+ async function deleteProject(projectId) {
99
+ const p = findProject(projectId);
100
+ const res = await fetch(`${API}/v1/projects/${projectId}`, { method: "DELETE", headers: { "Authorization": `Bearer ${p.service_key}` } });
101
+ if (res.status === 204 || res.ok) {
102
+ saveProjects(loadProjects().filter(pr => pr.project_id !== projectId));
103
+ console.log(JSON.stringify({ status: "ok", message: `Project ${projectId} deleted.` }));
104
+ } else {
105
+ const data = await res.json().catch(() => ({}));
106
+ console.error(JSON.stringify({ status: "error", http: res.status, ...data })); process.exit(1);
107
+ }
108
+ }
109
+
110
+ export async function run(sub, args) {
111
+ if (!sub || sub === '--help' || sub === '-h') {
112
+ console.log(HELP);
113
+ process.exit(0);
114
+ }
115
+ switch (sub) {
116
+ case "list": await list(); break;
117
+ case "sql": await sqlCmd(args[0], args[1]); break;
118
+ case "rest": await rest(args[0], args[1], args[2]); break;
119
+ case "usage": await usage(args[0]); break;
120
+ case "schema": await schema(args[0]); break;
121
+ case "renew": await renew(args[0]); break;
122
+ case "delete": await deleteProject(args[0]); break;
123
+ default:
124
+ console.error(`Unknown subcommand: ${sub}\n`);
125
+ console.log(HELP);
126
+ process.exit(1);
127
+ }
128
+ }
package/lib/wallet.mjs ADDED
@@ -0,0 +1,89 @@
1
+ import { readWallet, saveWallet, API } from "./config.mjs";
2
+
3
+ const HELP = `run402 wallet — Manage your x402 wallet
4
+
5
+ Usage:
6
+ run402 wallet <subcommand>
7
+
8
+ Subcommands:
9
+ status Show wallet address, network, and funding status
10
+ create Generate a new wallet and save it locally
11
+ fund Request test USDC from the Run402 faucet (Base Sepolia)
12
+ export Print the wallet address (useful for scripting)
13
+
14
+ Notes:
15
+ - Wallet is stored locally at ~/.run402/wallet.json
16
+ - Network: Base Sepolia (testnet) — uses USDC for x402 payments
17
+ - You need to create and fund a wallet before deploying or generating images
18
+
19
+ Examples:
20
+ run402 wallet create
21
+ run402 wallet status
22
+ run402 wallet fund
23
+ run402 wallet export
24
+ `;
25
+
26
+ async function loadDeps() {
27
+ const { generatePrivateKey, privateKeyToAccount } = await import("viem/accounts");
28
+ const { createPublicClient, http } = await import("viem");
29
+ const { baseSepolia } = await import("viem/chains");
30
+ return { generatePrivateKey, privateKeyToAccount, createPublicClient, http, baseSepolia };
31
+ }
32
+
33
+ async function status() {
34
+ const w = readWallet();
35
+ if (!w) {
36
+ console.log(JSON.stringify({ status: "no_wallet", message: "No wallet found. Run: run402 wallet create" }));
37
+ return;
38
+ }
39
+ console.log(JSON.stringify({ status: "ok", address: w.address, network: w.network || "base-sepolia", created: w.created, funded: w.funded || false }));
40
+ }
41
+
42
+ async function create() {
43
+ if (readWallet()) {
44
+ console.log(JSON.stringify({ status: "error", message: "Wallet already exists. Use 'status' to check it." }));
45
+ process.exit(1);
46
+ }
47
+ const { generatePrivateKey, privateKeyToAccount } = await loadDeps();
48
+ const privateKey = generatePrivateKey();
49
+ const account = privateKeyToAccount(privateKey);
50
+ saveWallet({ address: account.address, privateKey, network: "base-sepolia", created: new Date().toISOString(), funded: false });
51
+ console.log(JSON.stringify({ status: "ok", address: account.address, message: "Wallet created and saved." }));
52
+ }
53
+
54
+ async function fund() {
55
+ const w = readWallet();
56
+ if (!w) { console.log(JSON.stringify({ status: "error", message: "No wallet. Run: run402 wallet create" })); process.exit(1); }
57
+ const res = await fetch(`${API}/v1/faucet`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ address: w.address }) });
58
+ const data = await res.json();
59
+ if (res.ok) {
60
+ saveWallet({ ...w, funded: true, lastFaucet: new Date().toISOString() });
61
+ console.log(JSON.stringify({ status: "ok", ...data }));
62
+ } else {
63
+ console.log(JSON.stringify({ status: "error", ...data }));
64
+ process.exit(1);
65
+ }
66
+ }
67
+
68
+ async function exportAddr() {
69
+ const w = readWallet();
70
+ if (!w) { console.log(JSON.stringify({ status: "error", message: "No wallet." })); process.exit(1); }
71
+ console.log(w.address);
72
+ }
73
+
74
+ export async function run(sub, args) {
75
+ if (!sub || sub === '--help' || sub === '-h') {
76
+ console.log(HELP);
77
+ process.exit(0);
78
+ }
79
+ switch (sub) {
80
+ case "status": await status(); break;
81
+ case "create": await create(); break;
82
+ case "fund": await fund(); break;
83
+ case "export": await exportAddr(); break;
84
+ default:
85
+ console.error(`Unknown subcommand: ${sub}\n`);
86
+ console.log(HELP);
87
+ process.exit(1);
88
+ }
89
+ }
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "run402",
3
+ "version": "1.0.0",
4
+ "description": "CLI for Run402 — provision Postgres databases, deploy static sites, generate images, and manage wallets via x402 micropayments.",
5
+ "type": "module",
6
+ "bin": {
7
+ "run402": "cli.mjs"
8
+ },
9
+ "files": [
10
+ "cli.mjs",
11
+ "lib/"
12
+ ],
13
+ "dependencies": {
14
+ "@x402/evm": "^2.6.0",
15
+ "@x402/fetch": "^2.6.0",
16
+ "viem": "^2.47.1"
17
+ },
18
+ "engines": {
19
+ "node": ">=20"
20
+ },
21
+ "license": "MIT",
22
+ "homepage": "https://run402.com",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/kychee-com/run402-mcp.git",
26
+ "directory": "cli"
27
+ },
28
+ "keywords": [
29
+ "run402",
30
+ "x402",
31
+ "postgres",
32
+ "ai-agent",
33
+ "openclaw"
34
+ ]
35
+ }