run402 4.8.0 → 4.9.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/lib/org.mjs CHANGED
@@ -16,17 +16,20 @@ Usage:
16
16
  run402 org create [--name <label>]
17
17
  run402 org list
18
18
  run402 org get <org_id>
19
- run402 org rename <org_id> <display_name> (or: --clear to remove the label)
20
- run402 org payout-wallet <org_id> <wallet_address> (or: --clear to remove the explicit default)
19
+ run402 org rename <org_id> --name <display_name> (or: --clear to remove the label)
20
+ run402 org payout-wallet <org_id> --wallet <wallet_address> (or: --clear to remove the explicit default)
21
21
  run402 org whoami
22
22
  run402 org audit <org_id> [--limit N] [--after <cursor>] [--before <cursor>]
23
23
  run402 org member list <org_id>
24
- run402 org member add <org_id> <wallet_address> [--role <role>]
25
- run402 org member role <org_id> <principal_id> <role>
26
- run402 org member rm <org_id> <principal_id>
24
+ run402 org member add <org_id> --wallet <wallet_address> [--role <role>]
25
+ run402 org member role <org_id> --principal <principal_id> --role <role>
26
+ run402 org member rm <org_id> --principal <principal_id>
27
27
  run402 org invite list <org_id>
28
- run402 org invite create <org_id> <email> [--role <role>] [--ttl-hours N]
29
- run402 org invite rm <org_id> <principal_id>
28
+ run402 org invite create <org_id> --email <email> [--role <role>] [--ttl-hours N]
29
+ run402 org invite rm <org_id> --principal <principal_id>
30
+
31
+ Legacy (still supported): the second attribute may also be passed positionally,
32
+ e.g. run402 org member add <org_id> <wallet_address>.
30
33
 
31
34
  Subcommands:
32
35
  create Create an empty org on the prototype tier (you become owner)
@@ -87,18 +90,24 @@ non-revealing 403.
87
90
  rename: `run402 org rename — set or clear an org's display label (owner-only)
88
91
 
89
92
  Usage:
90
- run402 org rename <org_id> <display_name>
93
+ run402 org rename <org_id> --name <display_name>
91
94
  run402 org rename <org_id> --clear
92
95
 
96
+ Legacy (still supported):
97
+ run402 org rename <org_id> <display_name>
98
+
93
99
  Owner-only + step-up gated. Pass --clear (or an empty display_name) to remove
94
100
  the label. Output includes the updated tier and lease timestamps.
95
101
  `,
96
102
  "payout-wallet": `run402 org payout-wallet — set or clear the tenant route payout wallet
97
103
 
98
104
  Usage:
99
- run402 org payout-wallet <org_id> <wallet_address>
105
+ run402 org payout-wallet <org_id> --wallet <wallet_address>
100
106
  run402 org payout-wallet <org_id> --clear
101
107
 
108
+ Legacy (still supported):
109
+ run402 org payout-wallet <org_id> <wallet_address>
110
+
102
111
  Admin/owner-only + step-up gated. The wallet must already be active and linked
103
112
  to the same org. This wallet receives x402 settlement for function web routes
104
113
  that declare pricing.pay_to = "org_default_payout". Pass --clear to remove the
@@ -120,9 +129,9 @@ for local wallet/profile state use 'run402 status'.
120
129
 
121
130
  Usage:
122
131
  run402 org member list <org_id>
123
- run402 org member add <org_id> <wallet_address> [--role <role>]
124
- run402 org member role <org_id> <principal_id> <role>
125
- run402 org member rm <org_id> <principal_id>
132
+ run402 org member add <org_id> --wallet <wallet_address> [--role <role>]
133
+ run402 org member role <org_id> --principal <principal_id> --role <role>
134
+ run402 org member rm <org_id> --principal <principal_id>
126
135
 
127
136
  Roles: ${ROLE_LIST} (add defaults to developer). Mutations require an active owner.
128
137
  Demoting/removing the org's only active owner fails with 409 LAST_OWNER.
@@ -131,8 +140,11 @@ Demoting/removing the org's only active owner fails with 409 LAST_OWNER.
131
140
 
132
141
  Usage:
133
142
  run402 org invite list <org_id>
134
- run402 org invite create <org_id> <email> [--role <role>] [--ttl-hours N]
135
- run402 org invite rm <org_id> <principal_id>
143
+ run402 org invite create <org_id> --email <email> [--role <role>] [--ttl-hours N]
144
+ run402 org invite rm <org_id> --principal <principal_id>
145
+
146
+ Legacy (still supported): the second attribute may also be passed positionally,
147
+ e.g. run402 org member add <org_id> <wallet_address>.
136
148
 
137
149
  An invite is claimed at the recipient's first login. Mutations require an active owner
138
150
  (plus step-up when driven by a control-plane session).
@@ -200,16 +212,18 @@ async function get(args) {
200
212
 
201
213
  async function rename(args) {
202
214
  const a = normalizeArgv(args);
203
- assertKnownFlags(a, ["--clear", "--help", "-h"]);
215
+ assertKnownFlags(a, ["--name", "--clear", "--help", "-h"], ["--name"]);
204
216
  const clear = a.includes("--clear");
205
- const positionals = requirePositionalCount(a, [], {
206
- min: clear ? 1 : 2,
207
- max: clear ? 1 : 2,
208
- command: "run402 org rename <org_id> <display_name>",
209
- missing: clear ? "Missing <org_id>." : "Missing <org_id> and/or <display_name> (or pass --clear).",
217
+ const nameFlag = flagValue(a, "--name");
218
+ const single = clear || nameFlag !== null;
219
+ const positionals = requirePositionalCount(a, ["--name"], {
220
+ min: single ? 1 : 2,
221
+ max: single ? 1 : 2,
222
+ command: "run402 org rename <org_id> --name <display_name>",
223
+ missing: single ? "Missing <org_id>." : "Missing <org_id> and/or <display_name> (use --name, or pass --clear).",
210
224
  });
211
225
  const org = positionals[0];
212
- const displayName = clear ? null : positionals[1];
226
+ const displayName = clear ? null : (nameFlag ?? positionals[1]);
213
227
  try {
214
228
  console.log(JSON.stringify(await getSdk().org(org).rename(displayName), null, 2));
215
229
  } catch (err) {
@@ -219,16 +233,18 @@ async function rename(args) {
219
233
 
220
234
  async function payoutWallet(args) {
221
235
  const a = normalizeArgv(args);
222
- assertKnownFlags(a, ["--clear", "--help", "-h"]);
236
+ assertKnownFlags(a, ["--wallet", "--clear", "--help", "-h"], ["--wallet"]);
223
237
  const clear = a.includes("--clear");
224
- const positionals = requirePositionalCount(a, [], {
225
- min: clear ? 1 : 2,
226
- max: clear ? 1 : 2,
227
- command: "run402 org payout-wallet <org_id> <wallet_address>",
228
- missing: clear ? "Missing <org_id>." : "Missing <org_id> and/or <wallet_address> (or pass --clear).",
238
+ const walletFlag = flagValue(a, "--wallet");
239
+ const single = clear || walletFlag !== null;
240
+ const positionals = requirePositionalCount(a, ["--wallet"], {
241
+ min: single ? 1 : 2,
242
+ max: single ? 1 : 2,
243
+ command: "run402 org payout-wallet <org_id> --wallet <wallet_address>",
244
+ missing: single ? "Missing <org_id>." : "Missing <org_id> and/or <wallet_address> (use --wallet, or pass --clear).",
229
245
  });
230
246
  const org = positionals[0];
231
- const walletAddress = clear ? null : positionals[1];
247
+ const walletAddress = clear ? null : (walletFlag ?? positionals[1]);
232
248
  try {
233
249
  console.log(JSON.stringify(await getSdk().org(org).setPayoutWallet({ walletAddress }), null, 2));
234
250
  } catch (err) {
@@ -292,12 +308,16 @@ async function runMember(args) {
292
308
 
293
309
  if (memberAction === "add") {
294
310
  const a = normalizeArgv(rest);
295
- assertKnownFlags(a, ["--role", "--help", "-h"], ["--role"]);
311
+ assertKnownFlags(a, ["--role", "--wallet", "--help", "-h"], ["--role", "--wallet"]);
296
312
  const role = flagValue(a, "--role");
297
- const [org, wallet] = requirePositionalCount(a, ["--role"], {
298
- min: 2, max: 2, command: "run402 org member add <org_id> <wallet_address> [--role <role>]",
299
- missing: "Missing <org_id> and/or <wallet_address>.",
313
+ const walletFlag = flagValue(a, "--wallet");
314
+ const count = walletFlag ? 1 : 2;
315
+ const pos = requirePositionalCount(a, ["--role", "--wallet"], {
316
+ min: count, max: count, command: "run402 org member add <org_id> --wallet <wallet_address> [--role <role>]",
317
+ missing: walletFlag ? "Missing <org_id>." : "Missing <org_id> and/or <wallet_address> (use --wallet).",
300
318
  });
319
+ const org = pos[0];
320
+ const wallet = walletFlag ?? pos[1];
301
321
  try {
302
322
  const res = await getSdk().org(org).members.add({ wallet, role: role || undefined });
303
323
  console.log(JSON.stringify(res, null, 2));
@@ -309,11 +329,17 @@ async function runMember(args) {
309
329
 
310
330
  if (memberAction === "role") {
311
331
  const a = normalizeArgv(rest);
312
- assertKnownFlags(a, ["--help", "-h"]);
313
- const [org, principalId, role] = requirePositionalCount(a, [], {
314
- min: 3, max: 3, command: "run402 org member role <org_id> <principal_id> <role>",
315
- missing: "Missing <org_id>, <principal_id>, and/or <role>.",
332
+ assertKnownFlags(a, ["--principal", "--role", "--help", "-h"], ["--principal", "--role"]);
333
+ const principalFlag = flagValue(a, "--principal");
334
+ const roleFlag = flagValue(a, "--role");
335
+ const count = 3 - (principalFlag ? 1 : 0) - (roleFlag ? 1 : 0);
336
+ const pos = requirePositionalCount(a, ["--principal", "--role"], {
337
+ min: count, max: count, command: "run402 org member role <org_id> --principal <principal_id> --role <role>",
338
+ missing: "Missing <org_id>, <principal_id> (--principal), and/or <role> (--role).",
316
339
  });
340
+ const org = pos[0];
341
+ const principalId = principalFlag ?? pos[1];
342
+ const role = roleFlag ?? (principalFlag ? pos[1] : pos[2]);
317
343
  try {
318
344
  console.log(JSON.stringify(await getSdk().org(org).members.setRole(principalId, { role }), null, 2));
319
345
  } catch (err) {
@@ -324,11 +350,15 @@ async function runMember(args) {
324
350
 
325
351
  if (memberAction === "rm") {
326
352
  const a = normalizeArgv(rest);
327
- assertKnownFlags(a, ["--help", "-h"]);
328
- const [org, principalId] = requirePositionalCount(a, [], {
329
- min: 2, max: 2, command: "run402 org member rm <org_id> <principal_id>",
330
- missing: "Missing <org_id> and/or <principal_id>.",
353
+ assertKnownFlags(a, ["--principal", "--help", "-h"], ["--principal"]);
354
+ const principalFlag = flagValue(a, "--principal");
355
+ const count = principalFlag ? 1 : 2;
356
+ const pos = requirePositionalCount(a, ["--principal"], {
357
+ min: count, max: count, command: "run402 org member rm <org_id> --principal <principal_id>",
358
+ missing: principalFlag ? "Missing <org_id>." : "Missing <org_id> and/or <principal_id> (use --principal).",
331
359
  });
360
+ const org = pos[0];
361
+ const principalId = principalFlag ?? pos[1];
332
362
  try {
333
363
  console.log(JSON.stringify(await getSdk().org(org).members.revoke(principalId), null, 2));
334
364
  } catch (err) {
@@ -370,14 +400,18 @@ async function runInvite(args) {
370
400
 
371
401
  if (inviteAction === "create") {
372
402
  const a = normalizeArgv(rest);
373
- const valueFlags = ["--role", "--ttl-hours"];
403
+ const valueFlags = ["--role", "--ttl-hours", "--email"];
374
404
  assertKnownFlags(a, [...valueFlags, "--help", "-h"], valueFlags);
375
405
  const role = flagValue(a, "--role");
376
406
  const ttlFlag = flagValue(a, "--ttl-hours");
377
- const [org, email] = requirePositionalCount(a, valueFlags, {
378
- min: 2, max: 2, command: "run402 org invite create <org_id> <email> [--role <role>]",
379
- missing: "Missing <org_id> and/or <email>.",
407
+ const emailFlag = flagValue(a, "--email");
408
+ const count = emailFlag ? 1 : 2;
409
+ const pos = requirePositionalCount(a, valueFlags, {
410
+ min: count, max: count, command: "run402 org invite create <org_id> --email <email> [--role <role>]",
411
+ missing: emailFlag ? "Missing <org_id>." : "Missing <org_id> and/or <email> (use --email).",
380
412
  });
413
+ const org = pos[0];
414
+ const email = emailFlag ?? pos[1];
381
415
  const inviteTtlHours = ttlFlag === null ? undefined : parseIntegerFlag("--ttl-hours", ttlFlag, { min: 1, max: 8760 });
382
416
  try {
383
417
  const res = await getSdk().org(org).invites.create({ email, role: role || "developer", inviteTtlHours });
@@ -390,11 +424,15 @@ async function runInvite(args) {
390
424
 
391
425
  if (inviteAction === "rm") {
392
426
  const a = normalizeArgv(rest);
393
- assertKnownFlags(a, ["--help", "-h"]);
394
- const [org, principalId] = requirePositionalCount(a, [], {
395
- min: 2, max: 2, command: "run402 org invite rm <org_id> <principal_id>",
396
- missing: "Missing <org_id> and/or <principal_id>.",
427
+ assertKnownFlags(a, ["--principal", "--help", "-h"], ["--principal"]);
428
+ const principalFlag = flagValue(a, "--principal");
429
+ const count = principalFlag ? 1 : 2;
430
+ const pos = requirePositionalCount(a, ["--principal"], {
431
+ min: count, max: count, command: "run402 org invite rm <org_id> --principal <principal_id>",
432
+ missing: principalFlag ? "Missing <org_id>." : "Missing <org_id> and/or <principal_id> (use --principal).",
397
433
  });
434
+ const org = pos[0];
435
+ const principalId = principalFlag ?? pos[1];
398
436
  try {
399
437
  console.log(JSON.stringify(await getSdk().org(org).invites.revoke(principalId), null, 2));
400
438
  } catch (err) {
package/lib/projects.mjs CHANGED
@@ -5,7 +5,7 @@ import { loadLiveControlPlaneSession } from "../core-dist/control-plane-session.
5
5
  import { withAutoApprove } from "./operator.mjs";
6
6
  import { getSdk } from "./sdk.mjs";
7
7
  import { reportSdkError, fail, parseFlagJson } from "./sdk-errors.mjs";
8
- import { assertKnownFlags, failBadProjectId, flagValue, hasHelp, normalizeArgv, positionalArgs, resolvePositionalProject, validateRegularFile } from "./argparse.mjs";
8
+ import { assertKnownFlags, failBadProjectId, flagValue, hasHelp, normalizeArgv, positionalArgs, resolveProjectSelector, validateRegularFile } from "./argparse.mjs";
9
9
 
10
10
  const HELP = `run402 projects — Manage your deployed Run402 projects
11
11
 
@@ -21,8 +21,8 @@ Subcommands:
21
21
  tenant-payments [project_id] [--status <s>] List redacted tenant x402 payments for priced routes
22
22
  get [id] Authoritative server read: status, org, tier, active deploy, mailbox, usage vs limits (live; no keys)
23
23
  current Show the active project pointer and validation status
24
- sql [id] "<query>" [--file <path>] [--params '<json>'] Run a SQL query (supports parameterized queries)
25
- rest [id] <table> [params] Query a table via the REST API (PostgREST)
24
+ sql "<query>" [--project <id>] [--file <path>] [--params '<json>'] Run a SQL query (supports parameterized queries)
25
+ rest <table> [--query "<params>"] [--project <id>] Query a table via the REST API (PostgREST)
26
26
  usage [id] Show compute/storage usage for a project
27
27
  costs [id] [--window <w>] Show admin-only per-project revenue/cost/margin
28
28
  schema [id] Inspect the database schema
@@ -210,23 +210,25 @@ Examples:
210
210
  sql: `run402 projects sql — Run a SQL query against a project's database
211
211
 
212
212
  Usage:
213
- run402 projects sql [id] "<query>" [options]
214
- run402 projects sql [id] --file <path> [options]
213
+ run402 projects sql "<query>" [--project <id>] [options]
214
+ run402 projects sql --file <path> [--project <id>] [options]
215
+
216
+ Legacy (still supported):
217
+ run402 projects sql <prj_id> "<query>" [options]
215
218
 
216
219
  Arguments:
217
- [id] Project ID (defaults to the active project if omitted;
218
- must start with 'prj_' — any other first arg is treated
219
- as the query instead)
220
220
  <query> Inline SQL query (quote it to preserve spaces)
221
221
 
222
222
  Options:
223
+ --project <id> Project ID (defaults to the active project; a leading
224
+ prj_... positional is also still accepted)
223
225
  --file <path> Read SQL from a file instead of an inline query
224
226
  --params '<json>' JSON array of parameters for a parameterized query
225
227
 
226
228
  Examples:
227
- run402 projects sql prj_abc123 "SELECT * FROM users LIMIT 5"
228
- run402 projects sql prj_abc123 "SELECT * FROM users WHERE id = $1" --params '[42]'
229
- run402 projects sql prj_abc123 --file setup.sql
229
+ run402 projects sql "SELECT * FROM users LIMIT 5" --project prj_abc123
230
+ run402 projects sql "SELECT * FROM users WHERE id = $1" --params '[42]'
231
+ run402 projects sql --file setup.sql --project prj_abc123
230
232
  `,
231
233
  costs: `run402 projects costs — Show admin-only per-project finance
232
234
 
@@ -411,6 +413,12 @@ async function applyExpose(projectId, args = []) {
411
413
 
412
414
  async function validateExpose(args = []) {
413
415
  let projectId = null;
416
+ let projectFlag = null;
417
+ if (args.includes("--project")) {
418
+ projectFlag = flagValue(args, "--project");
419
+ const idx = args.indexOf("--project");
420
+ args = [...args.slice(0, idx), ...args.slice(idx + 2)];
421
+ }
414
422
  let file = null;
415
423
  let inline = null;
416
424
  let migrationFile = null;
@@ -473,8 +481,15 @@ async function validateExpose(args = []) {
473
481
  });
474
482
  }
475
483
 
484
+ if (projectFlag !== null && projectId !== null && projectFlag !== projectId) {
485
+ fail({
486
+ code: "BAD_USAGE",
487
+ message: `Conflicting project ids: --project ${projectFlag} vs positional ${projectId}`,
488
+ details: { project_flag: projectFlag, positional: projectId },
489
+ });
490
+ }
476
491
  const activeProjectId = getActiveProjectId();
477
- const project = projectId || activeProjectId || undefined;
492
+ const project = projectFlag || projectId || activeProjectId || undefined;
478
493
  if (!project) allowanceAuthHeaders("/projects/v1/expose/validate");
479
494
  const migration = migrationFile ? readFileSync(migrationFile, "utf-8") : migrationSql;
480
495
 
@@ -697,6 +712,10 @@ function toCliExposeValidationResult(data) {
697
712
  return { has_errors: hasErrors, ...rest };
698
713
  }
699
714
 
715
+ // The SDK now returns the gateway SQL envelope verbatim (snake_case
716
+ // row_count) — the wire shape is uniform end-to-end. This shim survives one
717
+ // release as belt-and-braces against a stale local SDK build that still
718
+ // camelCases, then can be deleted.
700
719
  function toCliSqlResult(data) {
701
720
  if (!data || typeof data !== "object" || Array.isArray(data)) return data;
702
721
  if ("row_count" in data) return data;
@@ -705,12 +724,15 @@ function toCliSqlResult(data) {
705
724
  return { ...rest, row_count: rowCount };
706
725
  }
707
726
 
708
- async function rest(projectId, table, queryParams) {
727
+ async function rest(projectId, restArgs = []) {
728
+ const positionals = positionalArgs(restArgs, FLAGS_BY_SUB.rest.values);
729
+ const table = positionals[0];
730
+ const queryParams = flagValue(restArgs, "--query") ?? positionals[1];
709
731
  if (!table) {
710
732
  fail({
711
733
  code: "BAD_USAGE",
712
- message: "Missing <table> argument. Usage: run402 projects rest [id] <table> [\"<query>\"]",
713
- hint: "Run 'run402 projects schema <id>' to list tables.",
734
+ message: "Missing <table> argument. Usage: run402 projects rest <table> [--query \"<query>\"] [--project <id>]",
735
+ hint: "Run 'run402 projects schema' to list tables.",
714
736
  });
715
737
  }
716
738
  try {
@@ -841,19 +863,26 @@ const FLAGS_BY_SUB = {
841
863
  values: ["--tier", "--name", "--org", "--idempotency-key"],
842
864
  },
843
865
  list: { known: ["--org", "--all"], values: ["--org"] },
844
- rename: { known: ["--name"], values: ["--name"] },
845
- "tenant-payments": { known: ["--status", "--limit", "--after"], values: ["--status", "--limit", "--after"] },
846
- sql: { known: ["--file", "--params"], values: ["--file", "--params"] },
847
- costs: { known: ["--window"], values: ["--window"] },
848
- "apply-expose": { known: ["--file"], values: ["--file"] },
866
+ rename: { known: ["--project", "--name"], values: ["--project", "--name"] },
867
+ "tenant-payments": { known: ["--project", "--status", "--limit", "--after"], values: ["--project", "--status", "--limit", "--after"] },
868
+ get: { known: ["--project"], values: ["--project"] },
869
+ rest: { known: ["--project", "--query"], values: ["--project", "--query"] },
870
+ usage: { known: ["--project"], values: ["--project"] },
871
+ schema: { known: ["--project"], values: ["--project"] },
872
+ "get-expose": { known: ["--project"], values: ["--project"] },
873
+ "promote-user": { known: ["--project"], values: ["--project"] },
874
+ "demote-user": { known: ["--project"], values: ["--project"] },
875
+ sql: { known: ["--project", "--file", "--params"], values: ["--project", "--file", "--params"] },
876
+ costs: { known: ["--project", "--window"], values: ["--project", "--window"] },
877
+ "apply-expose": { known: ["--project", "--file"], values: ["--project", "--file"] },
849
878
  "validate-expose": {
850
- known: ["--file", "--migration-file", "--migration-sql"],
851
- values: ["--file", "--migration-file", "--migration-sql"],
879
+ known: ["--project", "--file", "--migration-file", "--migration-sql"],
880
+ values: ["--project", "--file", "--migration-file", "--migration-sql"],
852
881
  },
853
- delete: { known: ["--confirm"], values: [] },
882
+ delete: { known: ["--project", "--confirm"], values: ["--project"] },
854
883
  export: {
855
- known: ["--scope", "--auth", "--consistency", "--idempotency-key", "--output", "--poll-interval", "--timeout", "--wait", "--json", "--json-stream"],
856
- values: ["--scope", "--auth", "--consistency", "--idempotency-key", "--output", "--poll-interval", "--timeout"],
884
+ known: ["--project", "--scope", "--auth", "--consistency", "--idempotency-key", "--output", "--poll-interval", "--timeout", "--wait", "--json", "--json-stream"],
885
+ values: ["--project", "--scope", "--auth", "--consistency", "--idempotency-key", "--output", "--poll-interval", "--timeout"],
857
886
  },
858
887
  };
859
888
 
@@ -888,27 +917,27 @@ export async function run(sub, args) {
888
917
  case "use": await use(args[0]); break;
889
918
  case "list": await list(args); break;
890
919
  case "current": await current(); break;
891
- case "rename": { const { projectId, rest } = resolvePositionalProject(args, { rejectBareFirst: true, valueFlags: FLAGS_BY_SUB.rename.values }); await rename(projectId, rest); break; }
892
- case "tenant-payments": { const { projectId, rest } = resolvePositionalProject(args, { rejectBareFirst: true, valueFlags: FLAGS_BY_SUB["tenant-payments"].values }); await tenantPayments(projectId, rest); break; }
893
- case "get": { const { projectId } = resolvePositionalProject(args, { rejectBareFirst: true }); await get(projectId); break; }
920
+ case "rename": { const { projectId, rest } = resolveProjectSelector(args, { rejectBareFirst: true, valueFlags: FLAGS_BY_SUB.rename.values }); await rename(projectId, rest); break; }
921
+ case "tenant-payments": { const { projectId, rest } = resolveProjectSelector(args, { rejectBareFirst: true, valueFlags: FLAGS_BY_SUB["tenant-payments"].values }); await tenantPayments(projectId, rest); break; }
922
+ case "get": { const { projectId } = resolveProjectSelector(args, { rejectBareFirst: true }); await get(projectId); break; }
894
923
  case "info": commandMoved("info"); break;
895
924
  case "keys": commandMoved("keys"); break;
896
- case "sql": { const { projectId, rest } = resolvePositionalProject(args, { maxBarePositionals: 1, valueFlags: FLAGS_BY_SUB.sql.values, rejectBareFirstWhenFlagPresent: ["--file"] }); await sqlCmd(projectId, rest); break; }
897
- case "rest": { const { projectId, rest: restArgs } = resolvePositionalProject(args); await rest(projectId, restArgs[0], restArgs[1]); break; }
898
- case "usage": { const { projectId } = resolvePositionalProject(args, { rejectBareFirst: true }); await usage(projectId); break; }
899
- case "costs": { const { projectId, rest } = resolvePositionalProject(args, { rejectBareFirst: true, valueFlags: FLAGS_BY_SUB.costs.values }); await costs(projectId, rest); break; }
900
- case "schema": { const { projectId } = resolvePositionalProject(args, { rejectBareFirst: true }); await schema(projectId); break; }
901
- case "apply-expose": { const { projectId, rest } = resolvePositionalProject(args, { maxBarePositionals: 1, valueFlags: FLAGS_BY_SUB["apply-expose"].values, rejectBareFirstWhenFlagPresent: ["--file"] }); await applyExpose(projectId, rest); break; }
925
+ case "sql": { const { projectId, rest } = resolveProjectSelector(args, { maxBarePositionals: 1, valueFlags: FLAGS_BY_SUB.sql.values, rejectBareFirstWhenFlagPresent: ["--file"] }); await sqlCmd(projectId, rest); break; }
926
+ case "rest": { const { projectId, rest: restArgs } = resolveProjectSelector(args, { valueFlags: FLAGS_BY_SUB.rest.values }); await rest(projectId, restArgs); break; }
927
+ case "usage": { const { projectId } = resolveProjectSelector(args, { rejectBareFirst: true }); await usage(projectId); break; }
928
+ case "costs": { const { projectId, rest } = resolveProjectSelector(args, { rejectBareFirst: true, valueFlags: FLAGS_BY_SUB.costs.values }); await costs(projectId, rest); break; }
929
+ case "schema": { const { projectId } = resolveProjectSelector(args, { rejectBareFirst: true }); await schema(projectId); break; }
930
+ case "apply-expose": { const { projectId, rest } = resolveProjectSelector(args, { maxBarePositionals: 1, valueFlags: FLAGS_BY_SUB["apply-expose"].values, rejectBareFirstWhenFlagPresent: ["--file"] }); await applyExpose(projectId, rest); break; }
902
931
  case "validate-expose": await validateExpose(args); break;
903
- case "get-expose": { const { projectId } = resolvePositionalProject(args, { rejectBareFirst: true }); await getExpose(projectId); break; }
904
- case "delete": { const { projectId, rest } = resolvePositionalProject(args, { rejectBareFirst: true }); await deleteProject(projectId, rest); break; }
932
+ case "get-expose": { const { projectId } = resolveProjectSelector(args, { rejectBareFirst: true }); await getExpose(projectId); break; }
933
+ case "delete": { const { projectId, rest } = resolveProjectSelector(args, { rejectBareFirst: true }); await deleteProject(projectId, rest); break; }
905
934
  case "export": {
906
935
  const { run } = await import("./cloud.mjs");
907
936
  await run("archives", ["create", ...args]);
908
937
  break;
909
938
  }
910
- case "promote-user": { const { projectId, rest } = resolvePositionalProject(args); await promoteUser(projectId, rest[0]); break; }
911
- case "demote-user": { const { projectId, rest } = resolvePositionalProject(args); await demoteUser(projectId, rest[0]); break; }
939
+ case "promote-user": { const { projectId, rest } = resolveProjectSelector(args); await promoteUser(projectId, rest[0]); break; }
940
+ case "demote-user": { const { projectId, rest } = resolveProjectSelector(args); await demoteUser(projectId, rest[0]); break; }
912
941
  default:
913
942
  fail({ code: "UNKNOWN_SUBCOMMAND", message: `Unknown projects subcommand: ${sub}`, hint: "Run `run402 projects --help` for usage.", details: { command: "projects", subcommand: sub } });
914
943
  }