run402 4.30.0 → 4.31.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/argparse.mjs CHANGED
@@ -20,10 +20,17 @@ export function hasHelp(args = []) {
20
20
  return args.includes("--help") || args.includes("-h");
21
21
  }
22
22
 
23
- // CLI-wide convention: every command accepts `--json`. Where stdout is already
24
- // JSON (the vast majority of commands) it is a no-op; commands with a human
25
- // default switch on it explicitly. Baking it into the baseline known set here
26
- // makes the convention self-maintaining for future commands.
23
+ // CLI-wide convention (cli-output-shape): JSON is ALWAYS the default on
24
+ // stdout, and `--json` is a universally-accepted NO-OP. Every command accepts
25
+ // it; passing it never changes the shape, content, or byte count of stdout.
26
+ // Baking it into the baseline known set here makes acceptance structural, so a
27
+ // newly added command inherits it without a per-command allowlist entry.
28
+ //
29
+ // No command may gate its stdout format on this flag. A command offering a
30
+ // human-readable view exposes it behind `--human` (see `up.mjs`, `errors.mjs`)
31
+ // and rejects `--human` combined with `--json`. The single sanctioned
32
+ // exception to the no-op rule is `assets put --json`, a preserved deprecated
33
+ // alias for `--stream` that selects NDJSON progress rather than a format.
27
34
  const ALWAYS_KNOWN_FLAGS = ["--json"];
28
35
 
29
36
  export function assertKnownFlags(args = [], knownFlags = [], flagsWithValues = []) {
package/lib/cloud.mjs CHANGED
@@ -92,7 +92,6 @@ async function create(rawArgs) {
92
92
  const output = flagValue(args, "--output");
93
93
  const wait = args.includes("--wait") || Boolean(output);
94
94
  const jsonStream = args.includes("--json-stream");
95
- const json = args.includes("--json") || jsonStream || true;
96
95
  const idempotencyKey = flagValue(args, "--idempotency-key") ?? undefined;
97
96
  const pollIntervalMs = parseIntegerFlag("--poll-interval", flagValue(args, "--poll-interval"), { min: 100, def: 1000 });
98
97
  const timeoutMs = parseIntegerFlag("--timeout", flagValue(args, "--timeout"), { min: 1000, def: 600000 });
@@ -156,7 +155,7 @@ async function create(rawArgs) {
156
155
  retryable: false,
157
156
  result,
158
157
  }));
159
- } else if (json) {
158
+ } else {
160
159
  console.log(JSON.stringify(result, null, 2));
161
160
  }
162
161
  if (archive.status !== "ready") process.exit(1);
package/lib/errors.mjs CHANGED
@@ -3,13 +3,16 @@
3
3
  * promote/revert verdict (gateway release-error-rollup).
4
4
  *
5
5
  * Two audiences from one wire envelope:
6
- * --json → the gateway envelope VERBATIM (list page, detail row, or the
7
- * watch triggering/final page). No reshaping — CLI-JSON and HTTP
8
- * consumers see one contract.
9
- * default → a rendered read: the verdict first (so "0 errors over 0 traffic"
6
+ * default → the gateway envelope VERBATIM as JSON (list page, detail row, or
7
+ * the watch triggering/final page). No reshaping — CLI-JSON and
8
+ * HTTP consumers see one contract.
9
+ * --human → a rendered read: the verdict first (so "0 errors over 0 traffic"
10
10
  * is never mistaken for health), then one line per fingerprint,
11
11
  * then a runnable logs drill-down.
12
12
  *
13
+ * JSON is ALWAYS the default (cli-output-shape). `--json` is a universally
14
+ * accepted no-op; stdout shape is never gated on it.
15
+ *
13
16
  * The promote gate: `--new-in <release> --fail-on-new` exits 0 when no error
14
17
  * identity was first seen under that release, 1 when new fingerprints appear,
15
18
  * and 2 when a verdict could not be produced (outage / auth / gate misuse) —
@@ -40,9 +43,9 @@ export const DEFAULT_INTERVAL_MS = 15000;
40
43
  const HELP = `run402 errors — grouped error fingerprints + a promote/revert verdict
41
44
 
42
45
  Usage:
43
- run402 errors [--project <id>] [filters] [--json]
44
- run402 errors <fingerprint_id> [--project <id>] [--json]
45
- run402 errors --new-in <release_id|active> --fail-on-new [--json]
46
+ run402 errors [--project <id>] [filters] [--human]
47
+ run402 errors <fingerprint_id> [--project <id>] [--human]
48
+ run402 errors --new-in <release_id|active> --fail-on-new [--human]
46
49
  run402 errors --new-in <release_id|active> --watch <dur> [--fail-on-new]
47
50
 
48
51
  What this is:
@@ -76,7 +79,9 @@ Filters (each maps 1:1 to a query param):
76
79
  Never parse or compare it — pass it back as-is.
77
80
 
78
81
  Output:
79
- --json Emit the gateway envelope verbatim (never reshaped)
82
+ --human Render the human-readable view instead of JSON.
83
+ Cannot be combined with --json.
84
+ --json Accepted no-op (JSON is already the default).
80
85
  --watch <dur> Poll the release for new identities for <dur>, then
81
86
  stop. Requires --new-in. Durations: 90s, 10m, 2h, or a
82
87
  bare number of seconds. Progress ticks go to stderr so
@@ -136,7 +141,7 @@ export async function run(sub, args = []) {
136
141
  "--project", "--since", "--until", "--function", "--kind",
137
142
  "--fingerprint", "--new-in", "--limit", "--cursor", "--watch", "--interval",
138
143
  ];
139
- const boolFlags = ["--json", "--fail-on-new", "--help", "-h"];
144
+ const boolFlags = ["--json", "--human", "--fail-on-new", "--help", "-h"];
140
145
  assertKnownFlags(a, [...valueFlags, ...boolFlags], valueFlags);
141
146
 
142
147
  const positionals = positionalArgs(a, valueFlags);
@@ -148,7 +153,18 @@ export async function run(sub, args = []) {
148
153
  });
149
154
  }
150
155
  const fingerprintId = positionals[0] ?? null;
151
- const json = a.includes("--json");
156
+ // Output contract (cli-output-shape): JSON is ALWAYS the default. `--json`
157
+ // is a universally-accepted no-op; human rendering is the `--human`
158
+ // opt-out, matching `run402 up`. Never gate stdout shape on `--json`.
159
+ const human = a.includes("--human");
160
+ if (human && a.includes("--json")) {
161
+ fail({
162
+ code: "BAD_USAGE",
163
+ message: "--human cannot be combined with --json.",
164
+ details: { flags: a.filter((arg) => arg === "--human" || arg === "--json") },
165
+ hint: "JSON is the default; drop --json to keep it, or keep --human alone for the rendered view.",
166
+ });
167
+ }
152
168
  const failOnNew = a.includes("--fail-on-new");
153
169
  const project = flagValue(a, "--project");
154
170
  const newIn = flagValue(a, "--new-in");
@@ -166,7 +182,7 @@ export async function run(sub, args = []) {
166
182
  fail({
167
183
  code: "BAD_USAGE",
168
184
  message: `${offending} is not valid with a <fingerprint_id> (detail view).`,
169
- hint: "Detail view accepts only --project and --json. Drop the fingerprint id to list + get a verdict.",
185
+ hint: "Detail view accepts only --project and --human. Drop the fingerprint id to list + get a verdict.",
170
186
  });
171
187
  }
172
188
  const projectId = resolveProjectId(project);
@@ -177,7 +193,7 @@ export async function run(sub, args = []) {
177
193
  reportSdkError(err);
178
194
  return;
179
195
  }
180
- if (json) {
196
+ if (!human) {
181
197
  console.log(JSON.stringify(detail, null, 2));
182
198
  return;
183
199
  }
@@ -277,19 +293,19 @@ export async function run(sub, args = []) {
277
293
  return;
278
294
  }
279
295
 
280
- if (json) console.log(JSON.stringify(page, null, 2));
296
+ if (!human) console.log(JSON.stringify(page, null, 2));
281
297
 
282
298
  if (failOnNew) {
283
299
  const totalNew = Number(page?.verdict?.new_fingerprints ?? 0);
284
300
  if (totalNew > 0) {
285
- if (!json) console.log(renderFailOnNewList(page?.errors ?? [], newIn, totalNew));
301
+ if (human) console.log(renderFailOnNewList(page?.errors ?? [], newIn, totalNew));
286
302
  process.exit(1);
287
303
  }
288
- if (!json) console.log(renderCleanGate(page?.verdict, newIn));
304
+ if (human) console.log(renderCleanGate(page?.verdict, newIn));
289
305
  process.exit(0);
290
306
  }
291
307
 
292
- if (!json) console.log(renderHumanList(page));
308
+ if (human) console.log(renderHumanList(page));
293
309
  }
294
310
 
295
311
  // ─── Watch driver ────────────────────────────────────────────────────────────
@@ -327,7 +343,7 @@ async function runWatch({ projectId, newIn, durationMs, intervalMs, failOnNew, j
327
343
  const newErrors = Array.isArray(result?.new_errors) ? result.new_errors : [];
328
344
  const totalNew = Number(result?.verdict?.new_fingerprints ?? newErrors.length);
329
345
 
330
- if (json) {
346
+ if (!human) {
331
347
  // The triggering page if we fired early, else the last poll's page. Fall
332
348
  // back to a page-shaped envelope only if no poll ever ran (edge case).
333
349
  const page = triggeringPage ?? lastPage ?? {
@@ -340,17 +356,17 @@ async function runWatch({ projectId, newIn, durationMs, intervalMs, failOnNew, j
340
356
 
341
357
  if (failOnNew) {
342
358
  if (!clean) {
343
- if (!json) console.log(renderFailOnNewList(newErrors, newIn, totalNew));
359
+ if (human) console.log(renderFailOnNewList(newErrors, newIn, totalNew));
344
360
  process.exit(1);
345
361
  }
346
- if (!json) {
362
+ if (human) {
347
363
  console.log(renderCleanGate(result?.verdict, newIn, { watched: true, durationMs, polls: result?.polls }));
348
364
  }
349
365
  process.exit(0);
350
366
  }
351
367
 
352
368
  // --watch without --fail-on-new: report and exit 0.
353
- if (!json) {
369
+ if (human) {
354
370
  const page = triggeringPage ?? lastPage;
355
371
  if (page) console.log(renderHumanList(page));
356
372
  else console.log(renderVerdict(result?.verdict));
@@ -532,7 +548,7 @@ export function renderHumanList(page) {
532
548
 
533
549
  if (p.has_more) {
534
550
  parts.push("");
535
- parts.push(`More rows available — page with --cursor ${p.next_cursor ?? "<next_cursor from --json>"} (cursors are opaque; pass as-is).`);
551
+ parts.push(`More rows available — page with --cursor ${p.next_cursor ?? "<next_cursor from the JSON output>"} (cursors are opaque; pass as-is).`);
536
552
  }
537
553
 
538
554
  const top = errors[0];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "run402",
3
- "version": "4.30.0",
3
+ "version": "4.31.0",
4
4
  "description": "CLI for Run402 — provision Postgres databases, deploy static sites, generate images, and manage wallets via x402 and MPP micropayments.",
5
5
  "type": "module",
6
6
  "bin": {