run402 4.7.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/deploy-v2.mjs CHANGED
@@ -34,7 +34,7 @@ import {
34
34
  import { getSdk } from "./sdk.mjs";
35
35
  import { reportSdkError, fail } from "./sdk-errors.mjs";
36
36
  import { API, allowanceAuthHeaders, getActiveProjectId, resolveProjectId, isCoreApiTarget } from "./config.mjs";
37
- import { normalizeArgv } from "./argparse.mjs";
37
+ import { flagValue, normalizeArgv } from "./argparse.mjs";
38
38
  import { loadLiveControlPlaneSession } from "../core-dist/control-plane-session.js";
39
39
  import { withAutoApprove } from "./operator.mjs";
40
40
  import { editRequestAction, nextAction, retryAction } from "./next-actions.mjs";
@@ -220,7 +220,12 @@ Output:
220
220
  const REHEARSE_HELP = `run402 deploy rehearse — Run a persisted plan on a contained branch
221
221
 
222
222
  Usage:
223
- run402 deploy rehearse <plan_id> [--project <id>] [--teardown keep|on_pass|always] [--json]
223
+ run402 deploy rehearse <plan_id> [--project <id>] [--teardown on_pass|keep|always] [--json]
224
+
225
+ Options:
226
+ --teardown <mode> on_pass (default: passed rehearsals delete their branch;
227
+ failed rehearsals keep it), keep, always. When omitted,
228
+ the gateway default (on_pass) applies.
224
229
 
225
230
  Use \`run402 apply --manifest app.json --rehearse --json\` for the canonical
226
231
  one-shot plan → upload → rehearse report flow.
@@ -367,11 +372,13 @@ async function rehearseCmd(rawArgs) {
367
372
  }
368
373
  const planId = positionals[0];
369
374
  if (!planId || positionals.length > 1) {
370
- fail({ code: "BAD_USAGE", message: "Usage: run402 deploy rehearse <plan_id> [--project <id>] [--teardown keep|on_pass|always] [--json]" });
375
+ fail({ code: "BAD_USAGE", message: "Usage: run402 deploy rehearse <plan_id> [--project <id>] [--teardown on_pass|keep|always] [--json]" });
371
376
  }
372
- const teardown = flagValue(args, "--teardown") ?? "keep";
373
- if (!["keep", "on_pass", "always"].includes(teardown)) {
374
- fail({ code: "BAD_USAGE", message: "--teardown must be one of: keep, on_pass, always", details: { flag: "--teardown", value: teardown } });
377
+ // When --teardown is absent, omit it from the request body entirely — the
378
+ // gateway defaults to on_pass (passed rehearsals delete their branch).
379
+ const teardown = flagValue(args, "--teardown") ?? undefined;
380
+ if (teardown !== undefined && !["keep", "on_pass", "always"].includes(teardown)) {
381
+ fail({ code: "BAD_USAGE", message: "--teardown must be one of: on_pass, keep, always", details: { flag: "--teardown", value: teardown } });
375
382
  }
376
383
  const project = flagValue(args, "--project") ?? undefined;
377
384
  if (!isCoreApiTarget() && !loadLiveControlPlaneSession()) {
@@ -482,6 +489,7 @@ function parsePromoteArgs(args) {
482
489
  "--allow-warnings",
483
490
  "--quiet",
484
491
  "--final-only",
492
+ "--json",
485
493
  "--help",
486
494
  "-h",
487
495
  ];
@@ -513,6 +521,7 @@ function parsePromoteArgs(args) {
513
521
  opts.quiet = true;
514
522
  continue;
515
523
  }
524
+ if (arg === "--json") { continue; }
516
525
  if (arg === "--allow-warnings") {
517
526
  opts.allowWarnings = true;
518
527
  continue;
@@ -1856,6 +1865,7 @@ async function diagnoseCmd(args) {
1856
1865
  for (let i = 0; i < args.length; i++) {
1857
1866
  const arg = args[i];
1858
1867
  if (arg === "--help" || arg === "-h") { console.log(DIAGNOSE_HELP); process.exit(0); }
1868
+ if (arg === "--json") { continue; }
1859
1869
  if (arg === "--project" && args[i + 1]) { opts.project = args[++i]; continue; }
1860
1870
  if (arg === "--method" && args[i + 1]) { opts.method = args[++i]; continue; }
1861
1871
  if (arg?.startsWith("--project=")) { opts.project = arg.slice("--project=".length); continue; }
@@ -1890,6 +1900,7 @@ async function resolveCmd(args) {
1890
1900
  for (let i = 0; i < args.length; i++) {
1891
1901
  const arg = args[i];
1892
1902
  if (arg === "--help" || arg === "-h") { console.log(RESOLVE_HELP); process.exit(0); }
1903
+ if (arg === "--json") { continue; }
1893
1904
  if (arg === "--project" && args[i + 1]) { opts.project = args[++i]; continue; }
1894
1905
  if (arg === "--url" && args[i + 1]) { opts.url = args[++i]; continue; }
1895
1906
  if (arg === "--host" && args[i + 1]) { opts.host = args[++i]; continue; }
@@ -1979,9 +1990,11 @@ function redactResolveInput(input) {
1979
1990
  function parseDeploySubcommandArgs(rawArgs, { command, help, valueFlags = [], booleanFlags = [] }) {
1980
1991
  const args = normalizeArgv(rawArgs);
1981
1992
  const valueFlagSet = new Set(valueFlags);
1982
- const booleanFlagSet = new Set(booleanFlags);
1993
+ // CLI-wide convention: --json is accepted by every deploy subcommand (a
1994
+ // no-op where stdout is already JSON).
1995
+ const booleanFlagSet = new Set([...booleanFlags, "--json"]);
1983
1996
  const numericFlagSet = new Set(["--limit", "--site-limit", "--timeout"]);
1984
- const allowedFlags = new Set([...valueFlags, ...booleanFlags, "--help", "-h"]);
1997
+ const allowedFlags = new Set([...valueFlags, ...booleanFlags, "--json", "--help", "-h"]);
1985
1998
  const flags = {};
1986
1999
  const positionals = [];
1987
2000
 
package/lib/functions.mjs CHANGED
@@ -2,7 +2,7 @@ import { readFileSync } from "fs";
2
2
  import { findProject, API } from "./config.mjs";
3
3
  import { getSdk } from "./sdk.mjs";
4
4
  import { reportSdkError, fail } from "./sdk-errors.mjs";
5
- import { assertKnownFlags, hasHelp, normalizeArgv, parseIntegerFlag, validateRegularFile } from "./argparse.mjs";
5
+ import { assertKnownFlags, hasHelp, normalizeArgv, parseIntegerFlag, resolveProjectSelector, validateRegularFile } from "./argparse.mjs";
6
6
  import { cliCommandAction } from "./next-actions.mjs";
7
7
 
8
8
  const FUNCTION_LOG_REQUEST_ID_RE = /^(?:req|fnrun|fnatt)_[A-Za-z0-9_-]{4,128}$/;
@@ -15,47 +15,52 @@ Usage:
15
15
  run402 functions <subcommand> [args...]
16
16
 
17
17
  Subcommands:
18
- deploy <id> <name> --file <file> [--timeout <s>] [--memory <mb>] [--deps <pkg,...>] [--schedule <cron>]
18
+ deploy <name> --file <file> [--project <id>] [--timeout <s>] [--memory <mb>] [--deps <pkg,...>] [--schedule <cron>]
19
19
  Deploy a function to a project
20
- invoke <id> <name> [--method <M>] [--body <json>] [--idempotency-key <key>] [--wait] [--timeout-ms <ms>] [--poll-interval-ms <ms>] [--raw]
20
+ invoke <name> [--project <id>] [--method <M>] [--body <json>] [--idempotency-key <key>] [--wait] [--timeout-ms <ms>] [--poll-interval-ms <ms>] [--raw]
21
21
  Invoke a deployed function. Default
22
22
  wraps the SDK result as JSON on stdout.
23
23
  --raw prints the response body verbatim
24
24
  (string body → text + newline, JSON
25
25
  body → pretty-printed JSON).
26
- logs <id> <name> [--tail <n>] [--since <ts>] [--request-id <req_...>] [--follow]
26
+ logs <name> [--project <id>] [--tail <n>] [--since <ts>] [--request-id <req_...>] [--follow]
27
27
  Get function logs
28
28
  runs <action> ... Create, inspect, cancel, redrive, and
29
29
  wait for durable function runs
30
- update <id> <name> [--schedule <cron>] [--schedule-remove] [--timeout <s>] [--memory <mb>]
30
+ update <name> [--project <id>] [--schedule <cron>] [--schedule-remove] [--timeout <s>] [--memory <mb>]
31
31
  Update function schedule or config without re-deploying
32
- rebuild <id> [<name>] [--all] Refresh function(s) onto the current platform
32
+ rebuild [<name>] [--all] [--project <id>]
33
+ Refresh function(s) onto the current platform
33
34
  runtime (re-bundles from stored source; no
34
35
  source change). Pass <name> for one function
35
36
  or --all for every function in the project.
36
- list <id> List all functions for a project
37
- delete <id> <name> Delete a function
37
+ list [--project <id>] List all functions for a project
38
+ delete <name> [--project <id>] Delete a function
39
+
40
+ Legacy (still supported): a leading prj_... positional selects the project,
41
+ e.g. run402 functions deploy prj_abc123 stripe-webhook --file handler.ts
38
42
 
39
43
  Examples:
40
- run402 functions deploy prj_abc123 stripe-webhook --file handler.ts
41
- run402 functions deploy prj_abc123 send-reminders --file remind.ts --schedule '*/15 * * * *'
42
- run402 functions deploy prj_abc123 send-reminders --file remind.ts --schedule '' # remove schedule
43
- run402 functions invoke prj_abc123 stripe-webhook --body '{"event":"test"}'
44
- run402 functions logs prj_abc123 stripe-webhook --tail 100
45
- run402 functions logs prj_abc123 stripe-webhook --since 2026-03-29T14:00:00Z
46
- run402 functions logs prj_abc123 stripe-webhook --request-id req_abc123
47
- run402 functions logs prj_abc123 stripe-webhook --follow
48
- run402 functions runs create prj_abc123 worker --event-type reminder.send --idempotency-key reminder:123 --delay 10m
49
- run402 functions runs get prj_abc123 fnrun_abc123
50
- run402 functions update prj_abc123 send-reminders --schedule '0 */4 * * *'
51
- run402 functions update prj_abc123 send-reminders --schedule-remove
52
- run402 functions update prj_abc123 my-func --timeout 15 --memory 256
53
- run402 functions rebuild prj_abc123 stripe-webhook
54
- run402 functions rebuild prj_abc123 --all
55
- run402 functions list prj_abc123
56
- run402 functions delete prj_abc123 stripe-webhook
44
+ run402 functions deploy stripe-webhook --file handler.ts --project prj_abc123
45
+ run402 functions deploy send-reminders --file remind.ts --schedule '*/15 * * * *'
46
+ run402 functions deploy send-reminders --file remind.ts --schedule '' # remove schedule
47
+ run402 functions invoke stripe-webhook --body '{"event":"test"}' --project prj_abc123
48
+ run402 functions logs stripe-webhook --tail 100
49
+ run402 functions logs stripe-webhook --since 2026-03-29T14:00:00Z
50
+ run402 functions logs stripe-webhook --request-id req_abc123
51
+ run402 functions logs stripe-webhook --follow
52
+ run402 functions runs create worker --event-type reminder.send --idempotency-key reminder:123 --delay 10m
53
+ run402 functions runs get fnrun_abc123 --project prj_abc123
54
+ run402 functions update send-reminders --schedule '0 */4 * * *'
55
+ run402 functions update send-reminders --schedule-remove
56
+ run402 functions update my-func --timeout 15 --memory 256
57
+ run402 functions rebuild stripe-webhook --project prj_abc123
58
+ run402 functions rebuild --all
59
+ run402 functions list --project prj_abc123
60
+ run402 functions delete stripe-webhook --project prj_abc123
57
61
 
58
62
  Notes:
63
+ - --project defaults to the active project ('run402 projects use')
59
64
  - Code must export a default async function: export default async (req: Request) => Response
60
65
  - Deploy may require payment if the project lease has expired
61
66
  - 'rebuild' is opt-in and never changes your source: it re-bundles the stored
@@ -67,13 +72,16 @@ const SUB_HELP = {
67
72
  deploy: `run402 functions deploy — Deploy a function to a project
68
73
 
69
74
  Usage:
75
+ run402 functions deploy <name> --file <file> [--project <id>] [options]
76
+
77
+ Legacy (still supported):
70
78
  run402 functions deploy <project_id> <name> --file <file> [options]
71
79
 
72
80
  Arguments:
73
- <project_id> Target project ID
74
81
  <name> Function name (used in the invoke URL path)
75
82
 
76
83
  Options:
84
+ --project <id> Target project ID (defaults to the active project)
77
85
  --file <file> Required: path to the function source file
78
86
  --timeout <s> Runtime timeout in seconds
79
87
  --memory <mb> Memory in MB
@@ -109,13 +117,16 @@ Examples:
109
117
  invoke: `run402 functions invoke — Invoke a deployed function
110
118
 
111
119
  Usage:
120
+ run402 functions invoke <name> [--project <id>] [options]
121
+
122
+ Legacy (still supported):
112
123
  run402 functions invoke <project_id> <name> [options]
113
124
 
114
125
  Arguments:
115
- <project_id> Target project ID
116
126
  <name> Function name
117
127
 
118
128
  Options:
129
+ --project <id> Target project ID (defaults to the active project)
119
130
  --method <M> HTTP method (default POST)
120
131
  --body <json> Request body (ignored for GET/HEAD)
121
132
  --idempotency-key <key>
@@ -151,13 +162,16 @@ Examples:
151
162
  logs: `run402 functions logs — Fetch or tail function logs
152
163
 
153
164
  Usage:
165
+ run402 functions logs <name> [--project <id>] [options]
166
+
167
+ Legacy (still supported):
154
168
  run402 functions logs <project_id> <name> [options]
155
169
 
156
170
  Arguments:
157
- <project_id> Target project ID
158
171
  <name> Function name
159
172
 
160
173
  Options:
174
+ --project <id> Target project ID (defaults to the active project)
161
175
  --tail <n> Number of most-recent entries (default 50, max 1000)
162
176
  --since <ts> ISO timestamp or epoch ms; only entries after this
163
177
  --request-id <id> Only entries correlated to this req_, fnrun_, or fnatt_ id
@@ -175,12 +189,15 @@ Examples:
175
189
  runs: `run402 functions runs — Manage durable function runs
176
190
 
177
191
  Usage:
178
- run402 functions runs create <project_id> <function_name> --event-type <type> --idempotency-key <key> [options]
179
- run402 functions runs list <project_id> <function_name> [options]
180
- run402 functions runs get <project_id> <run_id>
181
- run402 functions runs logs <project_id> <run_id> [--tail <n>] [--since <ts>]
182
- run402 functions runs cancel <project_id> <run_id>
183
- run402 functions runs redrive <project_id> <run_id> [options]
192
+ run402 functions runs create <function_name> --event-type <type> --idempotency-key <key> [--project <id>] [options]
193
+ run402 functions runs list <function_name> [--project <id>] [options]
194
+ run402 functions runs get <run_id> [--project <id>]
195
+ run402 functions runs logs <run_id> [--project <id>] [--tail <n>] [--since <ts>]
196
+ run402 functions runs cancel <run_id> [--project <id>]
197
+ run402 functions runs redrive <run_id> [--project <id>] [options]
198
+
199
+ Legacy (still supported): a leading prj_... positional selects the project,
200
+ e.g. run402 functions runs get <project_id> <run_id>
184
201
 
185
202
  Create options:
186
203
  --payload-json <json> Inline JSON object payload
@@ -211,13 +228,16 @@ Examples:
211
228
  update: `run402 functions update — Update function config without re-deploying
212
229
 
213
230
  Usage:
231
+ run402 functions update <name> [--project <id>] [options]
232
+
233
+ Legacy (still supported):
214
234
  run402 functions update <project_id> <name> [options]
215
235
 
216
236
  Arguments:
217
- <project_id> Target project ID
218
237
  <name> Function name
219
238
 
220
239
  Options:
240
+ --project <id> Target project ID (defaults to the active project)
221
241
  --schedule <cron> New cron schedule (pass '' to clear)
222
242
  --schedule-remove Explicitly remove the schedule
223
243
  --timeout <s> Runtime timeout in seconds
@@ -234,14 +254,18 @@ Examples:
234
254
  rebuild: `run402 functions rebuild — Refresh function(s) onto the current platform runtime
235
255
 
236
256
  Usage:
257
+ run402 functions rebuild <name> [--project <id>]
258
+ run402 functions rebuild --all [--project <id>]
259
+
260
+ Legacy (still supported):
237
261
  run402 functions rebuild <project_id> <name>
238
262
  run402 functions rebuild <project_id> --all
239
263
 
240
264
  Arguments:
241
- <project_id> Target project ID
242
265
  <name> Function name to rebuild (omit when using --all)
243
266
 
244
267
  Options:
268
+ --project <id> Target project ID (defaults to the active project)
245
269
  --all Rebuild every function in the project
246
270
 
247
271
  What it does:
@@ -273,25 +297,33 @@ Examples:
273
297
  list: `run402 functions list — List all functions for a project
274
298
 
275
299
  Usage:
300
+ run402 functions list [--project <id>]
301
+
302
+ Legacy (still supported):
276
303
  run402 functions list <project_id>
277
304
 
278
- Arguments:
279
- <project_id> Target project ID
305
+ Options:
306
+ --project <id> Target project ID (defaults to the active project)
280
307
 
281
308
  Examples:
282
- run402 functions list prj_abc123
309
+ run402 functions list --project prj_abc123
283
310
  `,
284
311
  delete: `run402 functions delete — Delete a function from a project
285
312
 
286
313
  Usage:
314
+ run402 functions delete <name> [--project <id>]
315
+
316
+ Legacy (still supported):
287
317
  run402 functions delete <project_id> <name>
288
318
 
289
319
  Arguments:
290
- <project_id> Target project ID
291
320
  <name> Function name to delete
292
321
 
322
+ Options:
323
+ --project <id> Target project ID (defaults to the active project)
324
+
293
325
  Examples:
294
- run402 functions delete prj_abc123 stripe-webhook
326
+ run402 functions delete stripe-webhook --project prj_abc123
295
327
  `,
296
328
  };
297
329
 
@@ -514,12 +546,21 @@ async function runs(action, args = []) {
514
546
  console.log(SUB_HELP.runs);
515
547
  process.exit(0);
516
548
  }
517
- if (action === "create") return runsCreate(args[0], args[1], args.slice(2));
518
- if (action === "list") return runsList(args[0], args[1], args.slice(2));
519
- if (action === "get") return runsGet(args[0], args[1], args.slice(2));
520
- if (action === "logs") return runsLogs(args[0], args[1], args.slice(2));
521
- if (action === "cancel") return runsCancel(args[0], args[1], args.slice(2));
522
- if (action === "redrive") return runsRedrive(args[0], args[1], args.slice(2));
549
+ const KNOWN_ACTIONS = new Set(["create", "list", "get", "logs", "cancel", "redrive"]);
550
+ if (!KNOWN_ACTIONS.has(action)) {
551
+ fail({
552
+ code: "BAD_USAGE",
553
+ message: `Unknown functions runs action: ${action}`,
554
+ hint: "run402 functions runs <create|list|get|logs|cancel|redrive> ...",
555
+ });
556
+ }
557
+ const { projectId, rest } = resolveProjectSelector(args);
558
+ if (action === "create") return runsCreate(projectId, rest[0], rest.slice(1));
559
+ if (action === "list") return runsList(projectId, rest[0], rest.slice(1));
560
+ if (action === "get") return runsGet(projectId, rest[0], rest.slice(1));
561
+ if (action === "logs") return runsLogs(projectId, rest[0], rest.slice(1));
562
+ if (action === "cancel") return runsCancel(projectId, rest[0], rest.slice(1));
563
+ if (action === "redrive") return runsRedrive(projectId, rest[0], rest.slice(1));
523
564
  fail({
524
565
  code: "BAD_USAGE",
525
566
  message: `Unknown functions runs action: ${action}`,
@@ -837,15 +878,19 @@ export async function run(sub, args) {
837
878
  console.log(SUB_HELP[sub] || HELP);
838
879
  process.exit(0);
839
880
  }
881
+ // Project selection (CLI-wide convention): `--project <id>` wins, else a
882
+ // legacy leading `prj_...` positional, else the active project. Computed
883
+ // lazily so unknown subcommands never trip project resolution.
884
+ const select = () => resolveProjectSelector(args);
840
885
  switch (sub) {
841
- case "deploy": await deploy(args[0], args[1], args.slice(2)); break;
842
- case "invoke": await invoke(args[0], args[1], args.slice(2)); break;
843
- case "logs": await logs(args[0], args[1], args.slice(2)); break;
886
+ case "deploy": { const { projectId, rest } = select(); await deploy(projectId, rest[0], rest.slice(1)); break; }
887
+ case "invoke": { const { projectId, rest } = select(); await invoke(projectId, rest[0], rest.slice(1)); break; }
888
+ case "logs": { const { projectId, rest } = select(); await logs(projectId, rest[0], rest.slice(1)); break; }
844
889
  case "runs": await runs(args[0], args.slice(1)); break;
845
- case "update": await update(args[0], args[1], args.slice(2)); break;
846
- case "rebuild": await rebuild(args[0], args.slice(1)); break;
847
- case "list": await list(args[0], args.slice(1)); break;
848
- case "delete": await deleteFunction(args[0], args[1], args.slice(2)); break;
890
+ case "update": { const { projectId, rest } = select(); await update(projectId, rest[0], rest.slice(1)); break; }
891
+ case "rebuild": { const { projectId, rest } = select(); await rebuild(projectId, rest); break; }
892
+ case "list": { const { projectId, rest } = select(); await list(projectId, rest); break; }
893
+ case "delete": { const { projectId, rest } = select(); await deleteFunction(projectId, rest[0], rest.slice(1)); break; }
849
894
  default:
850
895
  fail({ code: "UNKNOWN_SUBCOMMAND", message: `Unknown functions subcommand: ${sub}`, hint: "Run `run402 functions --help` for usage.", details: { command: "functions", subcommand: sub } });
851
896
  }
package/lib/grants.mjs CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  assertKnownFlags,
6
6
  flagValue,
7
7
  requirePositionalCount,
8
+ resolveProjectSelector,
8
9
  } from "./argparse.mjs";
9
10
 
10
11
  const HELP = `run402 grants — per-project capability grants (agent/CI principals)
@@ -13,11 +14,15 @@ Usage:
13
14
  run402 grants <subcommand> [args...]
14
15
 
15
16
  Subcommands:
16
- create <project_id> <wallet> <capability> [--policy <json>] [--expires <iso8601>]
17
+ create <wallet> --capability <cap> [--project <id>] [--policy <json>] [--expires <iso8601>]
17
18
  Issue a capability grant (owner of the project's org)
18
- revoke <project_id> <grant_id>
19
+ revoke <grant_id> [--project <id>]
19
20
  Revoke a capability grant
20
21
 
22
+ Legacy (still supported):
23
+ run402 grants create <project_id> <wallet> <capability> [...]
24
+ run402 grants revoke <project_id> <grant_id>
25
+
21
26
  Notes:
22
27
  - Grants let a non-member wallet (an agent or CI principal) act on ONE project,
23
28
  without making it a broad org member. Mutations require owner of the project's org.
@@ -25,23 +30,26 @@ Notes:
25
30
  - JSON in, JSON out.
26
31
 
27
32
  Examples:
28
- run402 grants create prj_abc 0xf39Fd6...92266 deploy
29
- run402 grants create prj_abc 0xf39Fd6...92266 functions:write --expires 2026-12-31T00:00:00Z
30
- run402 grants revoke prj_abc grt_xyz
33
+ run402 grants create 0xf39Fd6...92266 --capability deploy --project prj_abc
34
+ run402 grants create 0xf39Fd6...92266 --capability functions:write --expires 2026-12-31T00:00:00Z
35
+ run402 grants revoke grt_xyz --project prj_abc
31
36
  `;
32
37
 
33
38
  const SUB_HELP = {
34
39
  create: `run402 grants create — issue a per-project capability grant
35
40
 
36
41
  Usage:
37
- run402 grants create <project_id> <wallet> <capability> [--policy <json>] [--expires <iso8601>]
42
+ run402 grants create <wallet> --capability <cap> [--project <id>] [--policy <json>] [--expires <iso8601>]
43
+
44
+ Legacy (still supported):
45
+ run402 grants create <project_id> <wallet> <capability> [options]
38
46
 
39
47
  Arguments:
40
- <project_id> Project to grant access to
41
48
  <wallet> EVM address or named wallet the grant is issued to
42
- <capability> e.g. deploy, functions:write
43
49
 
44
50
  Options:
51
+ --project <id> Project to grant access to (defaults to the active project)
52
+ --capability <cap> e.g. deploy, functions:write (alternative to the legacy positional)
45
53
  --policy <json> Capability-scoping policy object (gateway-interpreted)
46
54
  --expires <iso8601> Expiry timestamp; omit for a non-expiring grant
47
55
 
@@ -50,23 +58,33 @@ Requires you to be an owner of the project's org.
50
58
  revoke: `run402 grants revoke — revoke a per-project capability grant
51
59
 
52
60
  Usage:
61
+ run402 grants revoke <grant_id> [--project <id>]
62
+
63
+ Legacy (still supported):
53
64
  run402 grants revoke <project_id> <grant_id>
54
65
 
55
66
  Requires you to be an owner of the project's org.
56
67
  `,
57
68
  };
58
69
 
70
+ const CREATE_VALUE_FLAGS = ["--project", "--capability", "--policy", "--expires"];
71
+
59
72
  async function create(args) {
60
73
  const a = normalizeArgv(args);
61
- assertKnownFlags(a, ["--policy", "--expires", "--help", "-h"], ["--policy", "--expires"]);
74
+ assertKnownFlags(a, [...CREATE_VALUE_FLAGS, "--help", "-h"], CREATE_VALUE_FLAGS);
62
75
  const policyRaw = flagValue(a, "--policy");
63
76
  const expiresAt = flagValue(a, "--expires");
64
- const [projectId, wallet, capability] = requirePositionalCount(a, ["--policy", "--expires"], {
65
- min: 3,
66
- max: 3,
67
- command: "run402 grants create <project_id> <wallet> <capability> [--policy <json>] [--expires <iso8601>]",
68
- missing: "Missing <project_id>, <wallet>, and/or <capability>.",
77
+ const capabilityFlag = flagValue(a, "--capability");
78
+ const { projectId, rest } = resolveProjectSelector(a, { valueFlags: CREATE_VALUE_FLAGS });
79
+ const expected = capabilityFlag ? 1 : 2;
80
+ const pos = requirePositionalCount(rest, CREATE_VALUE_FLAGS, {
81
+ min: expected,
82
+ max: expected,
83
+ command: "run402 grants create <wallet> --capability <cap> [--project <id>] [--policy <json>] [--expires <iso8601>]",
84
+ missing: capabilityFlag ? "Missing <wallet>." : "Missing <wallet> and/or <capability>.",
69
85
  });
86
+ const wallet = pos[0];
87
+ const capability = capabilityFlag ?? pos[1];
70
88
  const policy = policyRaw != null ? parseFlagJson("--policy", policyRaw) : undefined;
71
89
  try {
72
90
  const res = await getSdk().grants.create(projectId, {
@@ -83,12 +101,13 @@ async function create(args) {
83
101
 
84
102
  async function revoke(args) {
85
103
  const a = normalizeArgv(args);
86
- assertKnownFlags(a, ["--help", "-h"]);
87
- const [projectId, grantId] = requirePositionalCount(a, [], {
88
- min: 2,
89
- max: 2,
90
- command: "run402 grants revoke <project_id> <grant_id>",
91
- missing: "Missing <project_id> and/or <grant_id>.",
104
+ assertKnownFlags(a, ["--project", "--help", "-h"], ["--project"]);
105
+ const { projectId, rest } = resolveProjectSelector(a, { valueFlags: ["--project"] });
106
+ const [grantId] = requirePositionalCount(rest, ["--project"], {
107
+ min: 1,
108
+ max: 1,
109
+ command: "run402 grants revoke <grant_id> [--project <id>]",
110
+ missing: "Missing <grant_id>.",
92
111
  });
93
112
  try {
94
113
  console.log(JSON.stringify(await getSdk().grants.revoke(projectId, grantId), null, 2));
package/lib/jobs.mjs CHANGED
@@ -27,7 +27,7 @@ Subcommands:
27
27
  logs <job_id> Read job logs
28
28
  cancel <job_id> Cancel a queued or running job
29
29
  purge Purge all job runs for the project
30
- artifacts get <job_id> <file> Download a completed job's artifact
30
+ artifacts get <job_id> --file <name> Download a completed job's artifact (legacy: <job_id> <file>)
31
31
 
32
32
  Examples:
33
33
  run402 jobs submit --file job.json
@@ -120,6 +120,9 @@ recorded filenames on a given run.
120
120
  "artifacts get": `run402 jobs artifacts get — Download a completed job's artifact
121
121
 
122
122
  Usage:
123
+ run402 jobs artifacts get <job_id> --file <name> --output <path> [--project <id>]
124
+
125
+ Legacy (still supported):
123
126
  run402 jobs artifacts get <job_id> <file> --output <path> [--project <id>]
124
127
 
125
128
  Options:
@@ -355,24 +358,27 @@ async function artifactsGet(args = []) {
355
358
  process.exit(0);
356
359
  }
357
360
  const parsed = normalizeArgv(args);
358
- const valueFlags = ["--project", "--output", "-o"];
359
- assertKnownFlags(parsed, ["--project", "--output", "-o", "--help", "-h"], valueFlags);
361
+ const valueFlags = ["--project", "--output", "-o", "--file"];
362
+ assertKnownFlags(parsed, ["--project", "--output", "-o", "--file", "--help", "-h"], valueFlags);
363
+ const fileFlag = flagValue(parsed, "--file");
364
+ const expected = fileFlag ? 1 : 2;
360
365
  const positionals = positionalArgs(parsed, valueFlags);
361
- if (positionals.length < 2) {
366
+ if (positionals.length < expected) {
362
367
  fail({
363
368
  code: "BAD_USAGE",
364
369
  message: "Missing job_id and/or artifact filename.",
365
- hint: "Use `run402 jobs artifacts get <job_id> <file> --output <path>`.",
370
+ hint: "Use `run402 jobs artifacts get <job_id> --file <name> --output <path>`.",
366
371
  });
367
372
  }
368
- if (positionals.length > 2) {
373
+ if (positionals.length > expected) {
369
374
  fail({
370
375
  code: "BAD_USAGE",
371
- message: `Unexpected argument: ${positionals[2]}`,
372
- hint: "Use `run402 jobs artifacts get <job_id> <file> --output <path>`.",
376
+ message: `Unexpected argument: ${positionals[expected]}`,
377
+ hint: "Use `run402 jobs artifacts get <job_id> --file <name> --output <path>`.",
373
378
  });
374
379
  }
375
- const [jobId, filename] = positionals;
380
+ const jobId = positionals[0];
381
+ const filename = fileFlag ?? positionals[1];
376
382
  const output = flagValue(parsed, "--output") ?? flagValue(parsed, "-o");
377
383
  if (!output) {
378
384
  fail({