run402 2.42.0 → 2.44.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 (45) hide show
  1. package/cli.mjs +1 -1
  2. package/lib/admin.mjs +22 -22
  3. package/lib/allowance.mjs +1 -1
  4. package/lib/billing.mjs +48 -48
  5. package/lib/operator.mjs +3 -3
  6. package/lib/projects.mjs +137 -9
  7. package/lib/sdk-errors.mjs +1 -1
  8. package/lib/service.mjs +1 -1
  9. package/lib/status.mjs +10 -7
  10. package/lib/tier.mjs +4 -4
  11. package/lib/transfer.mjs +5 -5
  12. package/package.json +1 -1
  13. package/sdk/dist/errors.d.ts +8 -8
  14. package/sdk/dist/errors.d.ts.map +1 -1
  15. package/sdk/dist/errors.js +6 -6
  16. package/sdk/dist/errors.js.map +1 -1
  17. package/sdk/dist/namespaces/admin.d.ts +15 -16
  18. package/sdk/dist/namespaces/admin.d.ts.map +1 -1
  19. package/sdk/dist/namespaces/admin.js +14 -15
  20. package/sdk/dist/namespaces/admin.js.map +1 -1
  21. package/sdk/dist/namespaces/billing.d.ts +47 -53
  22. package/sdk/dist/namespaces/billing.d.ts.map +1 -1
  23. package/sdk/dist/namespaces/billing.js +59 -59
  24. package/sdk/dist/namespaces/billing.js.map +1 -1
  25. package/sdk/dist/namespaces/operator.d.ts +3 -3
  26. package/sdk/dist/namespaces/operator.d.ts.map +1 -1
  27. package/sdk/dist/namespaces/operator.js +1 -1
  28. package/sdk/dist/namespaces/org.types.d.ts +2 -2
  29. package/sdk/dist/namespaces/org.types.js +1 -1
  30. package/sdk/dist/namespaces/projects.d.ts +45 -17
  31. package/sdk/dist/namespaces/projects.d.ts.map +1 -1
  32. package/sdk/dist/namespaces/projects.js +71 -29
  33. package/sdk/dist/namespaces/projects.js.map +1 -1
  34. package/sdk/dist/namespaces/projects.types.d.ts +100 -20
  35. package/sdk/dist/namespaces/projects.types.d.ts.map +1 -1
  36. package/sdk/dist/namespaces/tier.d.ts +11 -11
  37. package/sdk/dist/namespaces/tier.d.ts.map +1 -1
  38. package/sdk/dist/namespaces/transfers.d.ts +8 -8
  39. package/sdk/dist/namespaces/transfers.d.ts.map +1 -1
  40. package/sdk/dist/namespaces/transfers.js +3 -3
  41. package/sdk/dist/namespaces/transfers.js.map +1 -1
  42. package/sdk/dist/scoped.d.ts +3 -2
  43. package/sdk/dist/scoped.d.ts.map +1 -1
  44. package/sdk/dist/scoped.js +5 -2
  45. package/sdk/dist/scoped.js.map +1 -1
package/cli.mjs CHANGED
@@ -47,7 +47,7 @@ Commands:
47
47
  message Send messages to Run402 developers
48
48
  auth Manage project user authentication (magic link, passwords, settings)
49
49
  sender-domain Manage custom email sender domain (register, status, remove)
50
- billing Email billing accounts, Stripe tier checkout, email packs
50
+ billing Email organizations, Stripe tier checkout, email packs
51
51
  contracts KMS contract wallets ($0.04/day rental + $0.000005/sign)
52
52
  agent Manage agent identity (contact info)
53
53
  operator Operator (human/email) session — login, then overview across your wallets
package/lib/admin.mjs CHANGED
@@ -8,9 +8,9 @@ Usage:
8
8
  run402 admin <subcommand> [args...]
9
9
 
10
10
  Subcommands:
11
- lease-perpetual <billing_account_id> (--enable | --disable)
12
- Toggle the account-level escape hatch.
13
- When enabled, the account never advances
11
+ lease-perpetual <organization_id> (--enable | --disable)
12
+ Toggle the organization-level escape hatch.
13
+ When enabled, the organization never advances
14
14
  past 'active' regardless of lease expiry.
15
15
  If the account is currently in a grace
16
16
  state, enabling reactivates it inline
@@ -19,12 +19,12 @@ Subcommands:
19
19
 
20
20
  archive <project_id> [--reason "..."] Moderate-archive a single project. Sets
21
21
  projects.archived_at = NOW(). Independent
22
- of account lifecycle; the rest of the
23
- account's projects keep serving.
22
+ of organization lifecycle; the rest of the
23
+ organization's projects keep serving.
24
24
 
25
25
  reactivate <project_id> Un-archive a project (flips archived_at
26
26
  back to NULL). In v1.57 this no longer
27
- touches account-level lifecycle — to
27
+ touches organization-level lifecycle — to
28
28
  reactivate a grace-state account, use
29
29
  \`tier set <tier>\` or enable
30
30
  lease-perpetual above.
@@ -36,17 +36,17 @@ Notes:
36
36
  - Output is JSON.
37
37
 
38
38
  Examples:
39
- run402 admin lease-perpetual ba_abc123 --enable
40
- run402 admin lease-perpetual ba_abc123 --disable
39
+ run402 admin lease-perpetual org_abc123 --enable
40
+ run402 admin lease-perpetual org_abc123 --disable
41
41
  run402 admin archive prj_abuse --reason "ToS violation"
42
42
  run402 admin reactivate prj_abuse
43
43
  `;
44
44
 
45
45
  const SUB_HELP = {
46
- "lease-perpetual": `run402 admin lease-perpetual — Toggle the account-level escape hatch
46
+ "lease-perpetual": `run402 admin lease-perpetual — Toggle the organization-level escape hatch
47
47
 
48
48
  Usage:
49
- run402 admin lease-perpetual <billing_account_id> (--enable | --disable)
49
+ run402 admin lease-perpetual <organization_id> (--enable | --disable)
50
50
 
51
51
  Options:
52
52
  --enable Set lease_perpetual = true (pins every project on the account)
@@ -59,8 +59,8 @@ Notes:
59
59
  the gateway reactivates inline and reports \`reactivated: true\`.
60
60
 
61
61
  Examples:
62
- run402 admin lease-perpetual ba_abc123 --enable
63
- run402 admin lease-perpetual ba_abc123 --disable
62
+ run402 admin lease-perpetual org_abc123 --enable
63
+ run402 admin lease-perpetual org_abc123 --disable
64
64
  `,
65
65
  archive: `run402 admin archive — Moderate-archive a single project
66
66
 
@@ -71,8 +71,8 @@ Options:
71
71
  --reason <text> Free-text moderation reason recorded in the audit log.
72
72
 
73
73
  Notes:
74
- - Sets projects.archived_at = NOW(). Independent of account-level lifecycle —
75
- only this project goes dark; siblings on the same billing account keep
74
+ - Sets projects.archived_at = NOW(). Independent of organization-level lifecycle —
75
+ only this project goes dark; siblings on the same organization keep
76
76
  serving.
77
77
  - No-op when the project is already archived (returns \`note: "already
78
78
  archived"\` without changing archived_at).
@@ -88,9 +88,9 @@ Usage:
88
88
 
89
89
  Notes:
90
90
  - Flips projects.archived_at back to NULL. In v1.57 this was narrowed:
91
- account-level lifecycle reactivation is NOT triggered. Use
91
+ organization-level lifecycle reactivation is NOT triggered. Use
92
92
  \`run402 tier set <tier>\` (the tier flow runs the lifecycle advance) or
93
- \`run402 admin lease-perpetual <ba_id> --enable\` for that.
93
+ \`run402 admin lease-perpetual <org_id> --enable\` for that.
94
94
  - No-op when the project is not archived (returns \`note: "not archived"\`).
95
95
 
96
96
  Examples:
@@ -110,25 +110,25 @@ function validateFlags(sub, args) {
110
110
  }
111
111
 
112
112
  async function leasePerpetual(args) {
113
- const accountId = args.find((a) => typeof a === "string" && !a.startsWith("--"));
113
+ const organizationId = args.find((a) => typeof a === "string" && !a.startsWith("--"));
114
114
  const enable = args.includes("--enable");
115
115
  const disable = args.includes("--disable");
116
- if (!accountId) {
116
+ if (!organizationId) {
117
117
  fail({
118
118
  code: "BAD_USAGE",
119
- message: "Missing <billing_account_id>.",
120
- hint: "run402 admin lease-perpetual <billing_account_id> --enable | --disable",
119
+ message: "Missing <organization_id>.",
120
+ hint: "run402 admin lease-perpetual <organization_id> --enable | --disable",
121
121
  });
122
122
  }
123
123
  if (enable === disable) {
124
124
  fail({
125
125
  code: "BAD_USAGE",
126
126
  message: "Pass exactly one of --enable / --disable.",
127
- hint: "run402 admin lease-perpetual <billing_account_id> --enable | --disable",
127
+ hint: "run402 admin lease-perpetual <organization_id> --enable | --disable",
128
128
  });
129
129
  }
130
130
  try {
131
- const data = await getSdk().admin.setLeasePerpetual(accountId, enable);
131
+ const data = await getSdk().admin.setLeasePerpetual(organizationId, enable);
132
132
  console.log(JSON.stringify(data, null, 2));
133
133
  } catch (err) {
134
134
  reportSdkError(err);
package/lib/allowance.mjs CHANGED
@@ -238,7 +238,7 @@ async function balance() {
238
238
  "base-sepolia_usd_micros": sepoliaUsdc,
239
239
  "tempo-moderato_pathusd_micros": tempoPathUsd,
240
240
  },
241
- run402: billingRes ? { balance_usd_micros: billingRes.available_usd_micros } : "no billing account",
241
+ run402: billingRes ? { balance_usd_micros: billingRes.available_usd_micros } : "no organization",
242
242
  }, null, 2));
243
243
  }
244
244
 
package/lib/billing.mjs CHANGED
@@ -2,25 +2,25 @@ import { getSdk } from "./sdk.mjs";
2
2
  import { reportSdkError, fail } from "./sdk-errors.mjs";
3
3
  import { assertKnownFlags, flagValue, normalizeArgv, parseIntegerFlag, positionalArgs } from "./argparse.mjs";
4
4
 
5
- const HELP = `run402 billing — Email billing accounts, Stripe tier checkout, email packs
5
+ const HELP = `run402 billing — Email organizations, Stripe tier checkout, email packs
6
6
 
7
7
  Usage:
8
8
  run402 billing <subcommand> [args...]
9
9
 
10
10
  Subcommands:
11
- create-email <email> Create an email billing account
12
- link-wallet <account_id> <wallet> Link a wallet to an email account
11
+ create-email <email> Create an email organization
12
+ link-wallet <org_id> <wallet> Link a wallet to an email organization
13
13
  tier-checkout <tier> [--email <e> | --wallet <w>] Stripe tier checkout
14
14
  buy-email-pack [--email <e> | --wallet <w>] Buy \$5 email pack (10,000 emails)
15
- auto-recharge <account_id> <on|off> [--threshold <n>]
16
- balance <identifier> Balance by account id (UUID), wallet (0x...), or email
17
- history <identifier> [--limit <n>] Ledger history by account id (UUID), wallet, or email
15
+ auto-recharge <org_id> <on|off> [--threshold <n>]
16
+ balance <identifier> Balance by organization id (UUID), wallet (0x...), or email
17
+ history <identifier> [--limit <n>] Ledger history by organization id (UUID), wallet, or email
18
18
 
19
19
  Examples:
20
20
  run402 billing create-email user@example.com
21
21
  run402 billing tier-checkout hobby --email user@example.com
22
22
  run402 billing buy-email-pack --wallet 0x1234...
23
- run402 billing auto-recharge acct_abc on --threshold 2000
23
+ run402 billing auto-recharge org_abc on --threshold 2000
24
24
  run402 billing balance user@example.com
25
25
  `;
26
26
 
@@ -34,7 +34,7 @@ Arguments:
34
34
  <tier> Tier name (e.g. hobby, pro)
35
35
 
36
36
  Options:
37
- --email <e> Email billing account to charge
37
+ --email <e> Email organization to charge
38
38
  --wallet <w> Wallet address (0x...) to associate with the checkout
39
39
 
40
40
  Examples:
@@ -47,7 +47,7 @@ Usage:
47
47
  run402 billing buy-email-pack [--email <e> | --wallet <w>]
48
48
 
49
49
  Options:
50
- --email <e> Email billing account to charge
50
+ --email <e> Email organization to charge
51
51
  --wallet <w> Wallet address (0x...) to associate with the purchase
52
52
 
53
53
  Examples:
@@ -57,33 +57,33 @@ Examples:
57
57
  "auto-recharge": `run402 billing auto-recharge — Toggle email-pack auto-recharge
58
58
 
59
59
  Usage:
60
- run402 billing auto-recharge <account_id> <on|off> [--threshold <n>]
60
+ run402 billing auto-recharge <org_id> <on|off> [--threshold <n>]
61
61
 
62
62
  Arguments:
63
- <account_id> Billing account ID
63
+ <org_id> Organization ID
64
64
  <on|off> Enable or disable auto-recharge
65
65
 
66
66
  Options:
67
67
  --threshold <n> Remaining-email threshold that triggers auto-recharge
68
68
 
69
69
  Examples:
70
- run402 billing auto-recharge acct_abc on --threshold 2000
71
- run402 billing auto-recharge acct_abc off
70
+ run402 billing auto-recharge org_abc on --threshold 2000
71
+ run402 billing auto-recharge org_abc off
72
72
  `,
73
- history: `run402 billing history — Show ledger history for a billing account
73
+ history: `run402 billing history — Show ledger history for a organization
74
74
 
75
75
  Usage:
76
76
  run402 billing history <identifier> [--limit <n>]
77
77
 
78
78
  Arguments:
79
- <identifier> Billing account id (UUID), wallet (0x...), or email.
80
- Wallet/email are resolved to the account id first.
79
+ <identifier> Organization id (UUID), wallet (0x...), or email.
80
+ Wallet/email are resolved to the organization id first.
81
81
 
82
82
  Options:
83
83
  --limit <n> Max entries to return (default: 50)
84
84
 
85
85
  Auth:
86
- Requires SIWX from a wallet linked to the account (signed automatically from
86
+ Requires SIWX from a wallet linked to the organization (signed automatically from
87
87
  the local allowance), or an admin key. Email lookups require an admin key.
88
88
 
89
89
  Examples:
@@ -91,17 +91,17 @@ Examples:
91
91
  run402 billing history 0x1234... --limit 100
92
92
  run402 billing history 00000000-0000-4000-8000-000000000001
93
93
  `,
94
- balance: `run402 billing balance — Show balance for a billing account
94
+ balance: `run402 billing balance — Show balance for a organization
95
95
 
96
96
  Usage:
97
97
  run402 billing balance <identifier>
98
98
 
99
99
  Arguments:
100
- <identifier> Billing account id (UUID), wallet (0x...), or email.
101
- Wallet/email are resolved via the accounts lookup.
100
+ <identifier> Organization id (UUID), wallet (0x...), or email.
101
+ Wallet/email are resolved via the organization lookup.
102
102
 
103
103
  Auth:
104
- Requires SIWX from a wallet linked to the account (signed automatically from
104
+ Requires SIWX from a wallet linked to the organization (signed automatically from
105
105
  the local allowance), or an admin key. Email lookups require an admin key.
106
106
 
107
107
  Examples:
@@ -109,38 +109,38 @@ Examples:
109
109
  run402 billing balance 0x1234abcd...
110
110
  run402 billing balance 00000000-0000-4000-8000-000000000001
111
111
  `,
112
- "create-email": `run402 billing create-email — Create an email billing account
112
+ "create-email": `run402 billing create-email — Create an email organization
113
113
 
114
114
  Usage:
115
115
  run402 billing create-email <email>
116
116
 
117
117
  Arguments:
118
- <email> Email address to register as a billing account
118
+ <email> Email address to register as a organization
119
119
 
120
120
  Examples:
121
121
  run402 billing create-email user@example.com
122
122
  `,
123
- "link-wallet": `run402 billing link-wallet — Link a wallet to an email billing account
123
+ "link-wallet": `run402 billing link-wallet — Link a wallet to an email organization
124
124
 
125
125
  Usage:
126
- run402 billing link-wallet <account_id> <wallet>
126
+ run402 billing link-wallet <org_id> <wallet>
127
127
 
128
128
  Arguments:
129
- <account_id> Billing account ID (e.g. acct_abc123)
129
+ <org_id> Organization ID (e.g. org_abc123)
130
130
  <wallet> Wallet address (0x...) to link
131
131
 
132
132
  Notes:
133
- - Tier and quotas are per-billing-account. Linking a wallet merges its
134
- spend into the account-wide pool that already includes every project
135
- on this billing account.
133
+ - Tier and quotas are per-organization. Linking a wallet merges its
134
+ spend into the organization-wide pool that already includes every project
135
+ on this organization.
136
136
  - The response includes a 'pool_implications' block on v1.46+ gateways:
137
- tier, projects_in_pool_count, account_api_calls_current,
138
- account_storage_bytes_current, tier_limits, over_limit. Inspect
137
+ tier, projects_in_pool_count, organization_api_calls_current,
138
+ organization_storage_bytes_current, tier_limits, over_limit. Inspect
139
139
  'over_limit' before linking a wallet whose existing usage might push
140
140
  the merged pool past the tier cap.
141
141
 
142
142
  Examples:
143
- run402 billing link-wallet acct_abc123 0x1234abcd...
143
+ run402 billing link-wallet org_abc123 0x1234abcd...
144
144
  `,
145
145
  };
146
146
 
@@ -177,7 +177,7 @@ async function createEmail(args) {
177
177
  });
178
178
  }
179
179
  try {
180
- const data = await getSdk().billing.createEmailAccount(email);
180
+ const data = await getSdk().billing.createEmailOrganization(email);
181
181
  console.log(JSON.stringify(data, null, 2));
182
182
  } catch (err) {
183
183
  reportSdkError(err);
@@ -188,23 +188,23 @@ async function linkWallet(args) {
188
188
  const parsedArgs = normalizeArgv(args);
189
189
  assertKnownFlags(parsedArgs, ["--help", "-h"]);
190
190
  const positionals = positionalArgs(parsedArgs);
191
- const accountId = positionals[0];
191
+ const organizationId = positionals[0];
192
192
  const wallet = positionals[1];
193
193
  if (positionals.length > 2) {
194
194
  fail({ code: "BAD_USAGE", message: `Unexpected argument for billing link-wallet: ${positionals[2]}` });
195
195
  }
196
- if (!accountId || !wallet) {
196
+ if (!organizationId || !wallet) {
197
197
  fail({
198
198
  code: "BAD_USAGE",
199
- message: "Missing <account_id> and/or <wallet>.",
200
- hint: "run402 billing link-wallet <account_id> <wallet>",
199
+ message: "Missing <org_id> and/or <wallet>.",
200
+ hint: "run402 billing link-wallet <org_id> <wallet>",
201
201
  });
202
202
  }
203
203
  try {
204
- const data = await getSdk().billing.linkWallet(accountId, wallet);
204
+ const data = await getSdk().billing.linkWallet(organizationId, wallet);
205
205
  const output = {
206
206
  status: data?.status ?? "ok",
207
- billing_account_id: data?.billing_account_id ?? accountId,
207
+ organization_id: data?.organization_id ?? organizationId,
208
208
  wallet: data?.wallet ?? wallet.toLowerCase(),
209
209
  ...(data?.pool_implications ? { pool_implications: data.pool_implications } : {}),
210
210
  };
@@ -265,16 +265,16 @@ async function autoRecharge(args) {
265
265
  const valueFlags = ["--threshold"];
266
266
  assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
267
267
  const positionals = positionalArgs(parsedArgs, valueFlags);
268
- const accountId = positionals[0];
268
+ const organizationId = positionals[0];
269
269
  const state = positionals[1];
270
270
  if (positionals.length > 2) {
271
271
  fail({ code: "BAD_USAGE", message: `Unexpected argument for billing auto-recharge: ${positionals[2]}` });
272
272
  }
273
- if (!accountId || !state || !["on", "off"].includes(state)) {
273
+ if (!organizationId || !state || !["on", "off"].includes(state)) {
274
274
  fail({
275
275
  code: "BAD_USAGE",
276
- message: "Missing <account_id> and/or <on|off>.",
277
- hint: "run402 billing auto-recharge <account_id> <on|off> [--threshold <n>]",
276
+ message: "Missing <org_id> and/or <on|off>.",
277
+ hint: "run402 billing auto-recharge <org_id> <on|off> [--threshold <n>]",
278
278
  });
279
279
  }
280
280
  const thresholdStr = flagValue(parsedArgs, "--threshold");
@@ -283,11 +283,11 @@ async function autoRecharge(args) {
283
283
  : undefined;
284
284
  try {
285
285
  await getSdk().billing.setAutoRecharge({
286
- billingAccountId: accountId,
286
+ organizationId: organizationId,
287
287
  enabled: state === "on",
288
288
  threshold,
289
289
  });
290
- console.log(JSON.stringify({ billing_account_id: accountId, enabled: state === "on", updated: true }));
290
+ console.log(JSON.stringify({ organization_id: organizationId, enabled: state === "on", updated: true }));
291
291
  } catch (err) {
292
292
  reportSdkError(err);
293
293
  }
@@ -305,11 +305,11 @@ async function balance(args) {
305
305
  fail({
306
306
  code: "BAD_USAGE",
307
307
  message: "Missing <identifier>.",
308
- hint: "run402 billing balance <account-id | wallet | email>",
308
+ hint: "run402 billing balance <org-id | wallet | email>",
309
309
  });
310
310
  }
311
311
  try {
312
- const data = await getSdk().billing.getAccount(id);
312
+ const data = await getSdk().billing.getOrganization(id);
313
313
  console.log(JSON.stringify(data, null, 2));
314
314
  } catch (err) {
315
315
  reportSdkError(err);
@@ -329,7 +329,7 @@ async function history(args) {
329
329
  fail({
330
330
  code: "BAD_USAGE",
331
331
  message: "Missing <identifier>.",
332
- hint: "run402 billing history <account-id | wallet | email> [--limit <n>]",
332
+ hint: "run402 billing history <org-id | wallet | email> [--limit <n>]",
333
333
  });
334
334
  }
335
335
  const limit = parsedArgs.includes("--limit")
package/lib/operator.mjs CHANGED
@@ -4,7 +4,7 @@
4
4
  * The operator is YOU, the human, identified by email — distinct from the
5
5
  * AGENT (your wallet / SIWX identity). One browser login spans every wallet
6
6
  * that verified your email, so `operator overview` returns the cross-wallet
7
- * union. For a single wallet's account state, use `run402 status`.
7
+ * union. For a single wallet's organization state, use `run402 status`.
8
8
  *
9
9
  * Auth: browser-delegated device-authorization grant (RFC 8628, the
10
10
  * `aws sso login` model). The CLI never performs WebAuthn — the browser does,
@@ -47,7 +47,7 @@ const HELP = `run402 operator — operator (human / email) session
47
47
 
48
48
  The operator is YOU, the human, identified by email — distinct from the agent
49
49
  (your wallet). One browser login spans every wallet that verified your email.
50
- For a single wallet's account state, use 'run402 status'.
50
+ For a single wallet's organization state, use 'run402 status'.
51
51
 
52
52
  Usage:
53
53
  run402 operator login [--no-open] (read session, device-flow)
@@ -289,7 +289,7 @@ async function loopbackLogin(args, { stepUp }) {
289
289
  if (memberships.length) {
290
290
  process.stderr.write(
291
291
  `Member of ${memberships.length} org(s):\n` +
292
- memberships.map((m) => ` - ${m.billing_account_id} (${m.role}, ${m.status})`).join("\n") +
292
+ memberships.map((m) => ` - ${m.display_name || m.org_id || m.organization_id || "unknown"} (${m.role}, ${m.status})`).join("\n") +
293
293
  "\n",
294
294
  );
295
295
  }
package/lib/projects.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  import { readFileSync } from "fs";
2
2
  import { loadKeyStore, API, allowanceAuthHeaders, resolveProjectId, getActiveProjectId } from "./config.mjs";
3
+ import { loadLiveOperatorSession } from "../core-dist/operator-session.js";
3
4
  import { getSdk } from "./sdk.mjs";
4
5
  import { reportSdkError, fail, parseFlagJson } from "./sdk-errors.mjs";
5
6
  import { assertKnownFlags, failBadProjectId, flagValue, hasHelp, normalizeArgv, positionalArgs, resolvePositionalProject, validateRegularFile } from "./argparse.mjs";
@@ -13,7 +14,8 @@ Subcommands:
13
14
  quote Show pricing tiers
14
15
  provision [--tier <tier>] [--name <n>] [--org <id>] Provision a new Postgres project (pays via x402)
15
16
  use <id> Set the active project (used as default for other commands)
16
- list List all your projects (IDs, URLs, active marker)
17
+ list [--org <id>] [--all] List your projects from the server (name, site_url, custom domains, org_id, active marker)
18
+ rename <id> --name <label> Rename a project (fix an auto-generated name)
17
19
  info [id] Show project details: REST URL, keys
18
20
  keys [id] Print anon_key and service_key as JSON
19
21
  sql [id] "<query>" [--file <path>] [--params '<json>'] Run a SQL query (supports parameterized queries)
@@ -36,6 +38,9 @@ Examples:
36
38
  run402 projects provision --tier hobby --name my-app
37
39
  run402 projects use prj_abc123
38
40
  run402 projects list
41
+ run402 projects list --org 11111111-2222-3333-4444-555555555555
42
+ run402 projects list --all
43
+ run402 projects rename prj_abc123 --name "My Site"
39
44
  run402 projects info prj_abc123
40
45
  run402 projects sql prj_abc123 "SELECT * FROM users LIMIT 5"
41
46
  run402 projects sql prj_abc123 "SELECT * FROM users WHERE id = $1" --params '[42]'
@@ -50,11 +55,25 @@ Examples:
50
55
  run402 projects keys prj_abc123
51
56
  run402 projects delete prj_abc123 --confirm
52
57
 
58
+ Global options (any command):
59
+ --wallet <name> Use a named wallet (profile) for this command. Precedence:
60
+ --wallet > RUN402_WALLET env > nearest .run402.json binding >
61
+ 'run402 wallets use' default > 'default'. See 'run402 wallets'.
62
+
53
63
  Notes:
54
64
  - <id> is the project_id shown in 'run402 projects list' (prefix: 'prj_')
55
65
  - Most commands that take <id> default to the active project when omitted
56
66
  (set it with 'run402 projects use <id>'). Project IDs start with 'prj_';
57
67
  any first positional that doesn't is treated as the next argument instead.
68
+ - 'list' is a SERVER read, not the local keystore: it shows every project the
69
+ active wallet can reach (membership-scoped), with name, site_url, custom
70
+ domains, and org_id. '--org <id>' filters to one org; '--all' reads the
71
+ cross-wallet inventory for every wallet controlling your operator email
72
+ (run 'run402 operator login' first for the union, else it falls back to the
73
+ current wallet's slice). The 'active' marker still comes from local state.
74
+ - 'rename' fixes a project's display name. You must be an org admin (or hold a
75
+ project:write grant) on the owning org; it works even if the project was
76
+ never provisioned from this machine.
58
77
  - 'rest' uses PostgREST query syntax (table name + optional query string)
59
78
  - 'provision' requires a funded allowance — payment is automatic via x402
60
79
  - 'apply-expose' declares the full authorization surface (tables, views, RPCs)
@@ -76,6 +95,53 @@ Notes:
76
95
  `;
77
96
 
78
97
  const SUB_HELP = {
98
+ list: `run402 projects list — List your projects from the server
99
+
100
+ Usage:
101
+ run402 projects list [--org <id>] [--all]
102
+
103
+ Options:
104
+ --org <id> Filter to projects owned by one org (organization).
105
+ Authorize-before-reveal: a non-member or guessed id is a
106
+ 403; a non-UUID id is a 400.
107
+ --all Read the cross-wallet inventory across every wallet
108
+ controlling your operator email. Run 'run402 operator
109
+ login' first for the union; without a session it falls
110
+ back to the current wallet's slice. Mutually exclusive
111
+ with --org.
112
+
113
+ Notes:
114
+ - This is a SERVER read (membership-scoped), not the local keystore. Each row
115
+ has project_id, name, site_url, custom_domains, org_id, status, and an
116
+ 'active' marker derived from local state.
117
+ - Tier and lifecycle live on the organization, not each project — use
118
+ 'run402 status' or 'run402 tier status' for the account view.
119
+
120
+ Examples:
121
+ run402 projects list
122
+ run402 projects list --org 11111111-2222-3333-4444-555555555555
123
+ run402 projects list --all
124
+ run402 projects list --wallet work
125
+ `,
126
+ rename: `run402 projects rename — Rename a project
127
+
128
+ Usage:
129
+ run402 projects rename <id> --name <label>
130
+
131
+ Arguments:
132
+ <id> Project ID (prefix: 'prj_'). Required.
133
+
134
+ Options:
135
+ --name <label> New display name (1-200 chars, no control characters).
136
+
137
+ Notes:
138
+ - You must be an org admin (or hold a project:write grant) on the owning org.
139
+ Authorize-before-reveal: an unauthorized or guessed id returns 403, never a
140
+ not-found oracle. Works even if the project isn't in the local keystore.
141
+
142
+ Examples:
143
+ run402 projects rename prj_abc123 --name "My Site"
144
+ `,
79
145
  provision: `run402 projects provision — Provision a new Postgres project
80
146
 
81
147
  Usage:
@@ -375,12 +441,71 @@ async function getExpose(projectId) {
375
441
  }
376
442
  }
377
443
 
378
- async function list() {
379
- const store = loadKeyStore();
380
- const entries = Object.entries(store.projects);
381
- if (entries.length === 0) { console.log(JSON.stringify([])); return; }
382
- const activeId = store.active_project_id;
383
- console.log(JSON.stringify(entries.map(([id, p]) => ({ project_id: id, active: id === activeId, site_url: p.site_url })), null, 2));
444
+ async function list(args = []) {
445
+ const org = flagValue(args, "--org");
446
+ const all = Array.isArray(args) && args.includes("--all");
447
+ if (all && org) {
448
+ fail({
449
+ code: "BAD_USAGE",
450
+ message: "--all and --org are mutually exclusive.",
451
+ hint: "--all reads the cross-wallet operator inventory; --org filters the membership-scoped list to one org.",
452
+ });
453
+ }
454
+
455
+ // `--all` reads the operator email-union inventory across every wallet
456
+ // controlling your verified email. Pass the cached operator-session token
457
+ // when present (cross-wallet union); otherwise the SDK falls back to SIWX
458
+ // wallet auth and the gateway returns just this wallet's slice.
459
+ const opts = {};
460
+ if (all) {
461
+ opts.all = true;
462
+ const session = loadLiveOperatorSession();
463
+ if (session) opts.token = session.operator_session_token;
464
+ } else if (org) {
465
+ opts.org = org;
466
+ }
467
+
468
+ // Active marker comes from local state; the inventory itself is the server
469
+ // read (NOT the keystore), so it surfaces every project the wallet/email can
470
+ // reach — including ones never provisioned from this machine.
471
+ const activeId = getActiveProjectId();
472
+
473
+ try {
474
+ const data = await getSdk().projects.list(opts);
475
+ const rows = (data.projects || []).map((p) => ({
476
+ project_id: p.id,
477
+ name: p.name ?? null,
478
+ active: p.id === activeId,
479
+ site_url: p.site_url ?? null,
480
+ custom_domains: p.custom_domains ?? [],
481
+ org_id: p.organization_id ?? null,
482
+ status: p.status ?? p.effective_status ?? null,
483
+ }));
484
+ const out = { projects: rows };
485
+ if (data.scope !== undefined) out.scope = data.scope;
486
+ if (data.has_more !== undefined) out.has_more = data.has_more;
487
+ if (data.next_cursor !== undefined && data.next_cursor !== null) out.next_cursor = data.next_cursor;
488
+ console.log(JSON.stringify(out, null, 2));
489
+ } catch (err) {
490
+ reportSdkError(err);
491
+ }
492
+ }
493
+
494
+ async function rename(projectId, args = []) {
495
+ const name = flagValue(args, "--name");
496
+ if (!name) {
497
+ fail({
498
+ code: "BAD_USAGE",
499
+ message: "Missing --name.",
500
+ hint: "run402 projects rename <id> --name \"My Site\"",
501
+ });
502
+ }
503
+ try {
504
+ const data = await getSdk().projects.rename(projectId, name);
505
+ console.log(JSON.stringify({ project_id: data.project_id, name: data.name, renamed: true }, null, 2));
506
+ } catch (err) {
507
+ reportSdkError(err);
508
+ }
384
509
  }
385
510
 
386
511
  async function info(projectId) {
@@ -571,6 +696,8 @@ async function deleteProject(projectId, args = []) {
571
696
 
572
697
  const FLAGS_BY_SUB = {
573
698
  provision: { known: ["--tier", "--name", "--org"], values: ["--tier", "--name", "--org"] },
699
+ list: { known: ["--org", "--all"], values: ["--org"] },
700
+ rename: { known: ["--name"], values: ["--name"] },
574
701
  sql: { known: ["--file", "--params"], values: ["--file", "--params"] },
575
702
  costs: { known: ["--window"], values: ["--window"] },
576
703
  "apply-expose": { known: ["--file"], values: ["--file"] },
@@ -597,7 +724,7 @@ export async function run(sub, args) {
597
724
  fail({
598
725
  code: "REMOVED_COMMAND",
599
726
  message: "`run402 projects pin` was removed in v1.57.",
600
- hint: "Per-project pin is superseded by the account-level escape hatch. Use `run402 admin lease-perpetual <billing_account_id> --enable` (platform-admin only).",
727
+ hint: "Per-project pin is superseded by the organization-level escape hatch. Use `run402 admin lease-perpetual <organization_id> --enable` (platform-admin only).",
601
728
  });
602
729
  }
603
730
  args = normalizeArgv(args);
@@ -610,7 +737,8 @@ export async function run(sub, args) {
610
737
  case "quote": await quote(); break;
611
738
  case "provision": await provision(args); break;
612
739
  case "use": await use(args[0]); break;
613
- case "list": await list(); break;
740
+ case "list": await list(args); break;
741
+ case "rename": { const { projectId, rest } = resolvePositionalProject(args, { rejectBareFirst: true, valueFlags: FLAGS_BY_SUB.rename.values }); await rename(projectId, rest); break; }
614
742
  case "info": { const { projectId } = resolvePositionalProject(args, { rejectBareFirst: true }); await info(projectId); break; }
615
743
  case "keys": { const { projectId } = resolvePositionalProject(args, { rejectBareFirst: true }); await keys(projectId); break; }
616
744
  case "sql": { const { projectId, rest } = resolvePositionalProject(args, { maxBarePositionals: 1, valueFlags: FLAGS_BY_SUB.sql.values, rejectBareFirstWhenFlagPresent: ["--file"] }); await sqlCmd(projectId, rest); break; }
@@ -111,7 +111,7 @@ export function reportSdkError(err) {
111
111
  if (d?.required_capability) need.push(`capability \`${d.required_capability}\``);
112
112
  const needStr = need.length > 0 ? ` (needs ${need.join(" or ")})` : "";
113
113
  payload.hint =
114
- `Authorization denied${needStr}: a wallet authenticates, but the owning org (billing account) ` +
114
+ `Authorization denied${needStr}: a wallet authenticates, but the owning org (organization) ` +
115
115
  "decides access via membership role (owner > admin > developer > billing > viewer) or a per-project grant. " +
116
116
  "High-stakes actions (delete, transfer, membership change) require an active `owner` membership. " +
117
117
  "Returned as 403 even when the project does not exist, so verify the project id too.";
package/lib/service.mjs CHANGED
@@ -22,7 +22,7 @@ Usage:
22
22
  Notes:
23
23
  - Unauthenticated and free; no allowance required
24
24
  - Returns uptime, supported capabilities, operator, and deployment info
25
- - For account state (allowance, balance, tier, projects), use
25
+ - For organization state (allowance, balance, tier, projects), use
26
26
  'run402 status' instead
27
27
 
28
28
  Examples: