luxin-cli 0.2.2 → 0.2.3

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/CHANGELOG.md CHANGED
@@ -6,6 +6,94 @@ provenance; this file is the human- and agent-readable release map.
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ ## 0.2.3 - 2026-08-04
10
+
11
+ - Release (self-fund/recovery): the wall now offers a human-funding handoff
12
+ instead of only a rail no external agent could walk (#2201). Both wall types
13
+ — credits depleted and daily job cap reached — route through
14
+ `QUOTA_EXCEEDED`, and the recovery envelope now carries
15
+ `error.recovery.human_handoff`: a copy-runnable `luxin claim code --json`,
16
+ typed `no_spend`, with the honest instruction to hand `data.dashboard_url`
17
+ (and nothing else — never the token, never the raw code) to your human, who
18
+ funds credits at the dashboard in about a minute. With no wallet evidence —
19
+ the external default — that handoff leads `error.recovery.suggested_command`
20
+ and `error.recovery.suggested_commands`; the agent-native x402 quote/buy rail
21
+ stays listed and `top_up.preferred_payment_method`
22
+ (`stripe_x402.exact.usdc`) is unchanged. New `error.recovery.delegated_spend`
23
+ (`state`, `per_tx_cap_usd`, `agent_day_remaining_usd`, `requires_wallet`)
24
+ lets an agent tell whether it can settle x402 itself before it stops at the
25
+ wall; it defaults to `state: "unknown"`, and when a caller proves delegated
26
+ spend is available the x402 quote leads instead. The credits-depleted wall
27
+ message — the majority wall — now names the price (a ~$5 top-up of 500
28
+ credits, pack `starter-500`), the concrete next step, and both paths, at the
29
+ quality the daily-cap message already had. The packaged CLI rewrites the
30
+ handoff command through your invocation prefix, so what the wall prints is
31
+ runnable as printed.
32
+ - Release (honest messaging): the `create --guide` / `edit --guide`
33
+ `quota_required` blocker is now trigger-aware (#2200). It used to always emit
34
+ the credits-shortfall line ("Selected first image requires N credits; current
35
+ remaining credits are M") even when the trigger was the daily job cap, so an
36
+ agent holding spare credits read a message that was simply wrong about why it
37
+ was blocked. The blocker now mirrors the stage's credit-first ordering:
38
+ credits only outrank the daily cap when they are genuinely short, and
39
+ otherwise the message names the real trigger — "You've reached today's job
40
+ allowance (X/day); a top-up raises your daily allowance so you can keep
41
+ creating now" — matching the hosted daily-cap copy.
42
+ - Release (no-spend mode): `create --guide` and `edit --guide` accept an opt-in
43
+ `--no-spend` output mode (#2194). A cold-agent no-spend study got a guide
44
+ response that repeatedly embedded live create, quote, buy, and payment
45
+ command templates, which buried the safe dry-run and raised the chance of
46
+ picking a prohibited action. With `--no-spend`,
47
+ `data.no_spend_output_mode.enabled` is `true` and the live funding templates
48
+ are omitted — `data.self_fund_next_command`,
49
+ `data.self_fund_next_command_label`, `data.self_fund_handoff`,
50
+ `data.self_fund_preparation`, and `data.checks.payments.suggested_commands`,
51
+ each named in `data.no_spend_output_mode.suppressed_fields`. The dry-run
52
+ command (`data.recommended_no_spend_command` / `data.no_spend_next_command`)
53
+ and the `provider_call` / `credit_debit` / `media_write` false proof in
54
+ `data.mutation` are retained. The funding path stays discoverable without
55
+ dominating via `data.no_spend_output_mode.self_fund_discovery`:
56
+ `rerun_with_funding_command` re-runs the same guide without `--no-spend`, and
57
+ `inspect_methods_command` is a read-only, no-spend payment-method
58
+ inspection. `--no-spend` is a guide output mode: outside `--guide` it is
59
+ rejected with the pointer to `create --dry-run` for a no-spend planned job.
60
+ `luxin create --help` and the packaged `cli.md` / `commands.json` carry the
61
+ flag.
62
+ - Release (trust/billing): a completed, charged job always surfaces an asset
63
+ (#2107). A live create/edit reserves credit before calling the provider and
64
+ settles on the provider's success envelope — but a provider that answered
65
+ SUCCESS with an empty or planned-only asset list used to settle the
66
+ reservation and commit a charged, asset-less job, so the agent was billed for
67
+ nothing and had no recoverable job or asset. The runner now requires at least
68
+ one real (non-planned) asset before settling: otherwise it releases the
69
+ reserved credit and returns a retryable `PROVIDER_COMPLETED_WITHOUT_ASSET`
70
+ failure instead of committing the charge. Nothing to change on your side —
71
+ the debit-without-media outcome is gone.
72
+ - Release (guide reliability): the `create --guide` executable-default read is
73
+ guarded against the shape the hosted registry actually returns (#2109).
74
+ `GET /v1/models` serves the compact model-summary rows, which carry
75
+ `model_execution_status` as a flat field rather than nested under
76
+ `execution`; a nested-only read failed every row's executable check and
77
+ dead-ended the guide at `no_executable_model` even though an executable
78
+ default existed and an explicit `create --dry-run --model fal.bagel` still
79
+ planned for zero credits. The flat-reading fix shipped earlier, but every
80
+ guide fixture used the nested shape, so a regression would have passed CI.
81
+ This release adds a faithful regression test serving the compact/flat shape
82
+ and asserting `ready_to_create` with the executable default selected.
83
+ - Resolved (0.2.2 known limitation): the `dashboard.claim` grant backfill
84
+ landed (#2184), so `luxin claim code` no longer answers `CAPABILITY_DENIED`
85
+ for agents whose tokens predate the hosted dashboard plane. That matters more
86
+ now that the wall itself recommends the command.
87
+ - Release (hosted parity): the Stripe reconciliation sweep is rail-aware and
88
+ transitions confirmed-unsettled pending attempts older than its abandonment
89
+ window to a terminal `expired` state with an audit trail (#2160). Settled
90
+ attempts are never abandoned and live-money retrieval failures still fail
91
+ loudly. No packaged CLI command changed for this; stale open quotes on your
92
+ account simply stop lingering as pending forever.
93
+ - No payment caps, wallet settlement, provider spend, dist-tag mutation, or
94
+ media generation behavior changed in this release bump beyond the
95
+ debited-no-asset release path above, which only ever refunds.
96
+
9
97
  ## 0.2.2 - 2026-07-30
10
98
 
11
99
  - Release (retention/self-fund): publish the human handoff from #2181. New verb
package/bin/luxin.mjs CHANGED
@@ -15,7 +15,7 @@ import { Readable } from "node:stream";
15
15
  import { pipeline } from "node:stream/promises";
16
16
  import os from "node:os";
17
17
 
18
- const VERSION = "0.2.2";
18
+ const VERSION = "0.2.3";
19
19
  const PACKAGE_NAME = "luxin";
20
20
  const DEFAULT_API_BASE_URL = "https://api.luxin.sh";
21
21
  const DEFAULT_DOCS_BASE_URL = "https://luxin.sh";
@@ -552,6 +552,7 @@ function commandHelpByKey(key) {
552
552
  docs_url: "https://luxin.sh/cli.md#luxin-create",
553
553
  optional_flags: [
554
554
  "--guide",
555
+ "--no-spend",
555
556
  "--dry-run",
556
557
  "--model",
557
558
  "--aspect-ratio",
@@ -1984,13 +1985,66 @@ async function createGuide(args, options = {}) {
1984
1985
  paymentSummary,
1985
1986
  selfFundPreparation,
1986
1987
  );
1988
+ // #2194: no-spend output mode. Omit the live self-fund and payment command
1989
+ // templates when the agent opts into a no-spend/dry-run study so the safe
1990
+ // dry-run is not buried under quote/buy/payment workflow commands. Retain the
1991
+ // dry-run command and the mutation proof, and keep the self-fund path
1992
+ // discoverable via self_fund_discovery instead of dominating the response.
1993
+ const noSpendOutputMode = flagBool(args, "no-spend");
1994
+ const paymentSummaryOutput = noSpendOutputMode
1995
+ ? { ...paymentSummary, suggested_commands: [] }
1996
+ : paymentSummary;
1997
+ const selfFundHandoffOutput = noSpendOutputMode ? null : selfFundHandoff;
1998
+ const selfFundPreparationOutput = noSpendOutputMode
1999
+ ? null
2000
+ : selfFundPreparation;
2001
+ const selfFundNextCommandOutput = noSpendOutputMode
2002
+ ? null
2003
+ : selfFundNextCommand;
2004
+ const selfFundNextCommandLabelOutput = noSpendOutputMode
2005
+ ? null
2006
+ : selfFundNextCommandLabel;
2007
+ const noSpendOutputModeData = noSpendOutputMode
2008
+ ? {
2009
+ enabled: true,
2010
+ suppressed_fields: [
2011
+ "self_fund_next_command",
2012
+ "self_fund_next_command_label",
2013
+ "self_fund_handoff",
2014
+ "self_fund_preparation",
2015
+ "checks.payments.suggested_commands",
2016
+ ],
2017
+ self_fund_discovery: {
2018
+ rerun_with_funding_command: renderGuideCommand(
2019
+ trimmedPrompt.length > 0 ? trimmedPrompt : "PROMPT",
2020
+ explicitApiBaseUrl(args),
2021
+ guideCommandPrefix,
2022
+ {
2023
+ operation: guideOperation,
2024
+ inputReference: options.inputReference,
2025
+ modelId: requestedModelId,
2026
+ providerId: requestedProviderId,
2027
+ intent: requestedIntentFlag,
2028
+ maxEstimatedUsdPerImage,
2029
+ modelParametersJson: requestedModelParametersJson,
2030
+ },
2031
+ ),
2032
+ inspect_methods_command: escapeHatches.payment_methods,
2033
+ note: "No-spend output mode omits live self-fund and payment command templates. Re-run this guide without --no-spend to surface them; data.escape_hatches.payment_methods stays available for read-only, no-spend payment-method inspection. provider_call, credit_debit, and media_write remain false (see data.mutation).",
2034
+ },
2035
+ }
2036
+ : {
2037
+ enabled: false,
2038
+ suppressed_fields: [],
2039
+ self_fund_discovery: null,
2040
+ };
1987
2041
  const guideRecovery = createGuideRecovery(stage, {
1988
2042
  blocker,
1989
2043
  nextCommand,
1990
2044
  noSpendNextCommand,
1991
2045
  afterNext,
1992
2046
  escapeHatches,
1993
- selfFundNextCommand,
2047
+ selfFundNextCommand: selfFundNextCommandOutput,
1994
2048
  });
1995
2049
  return createGuideSuccess(command, quota?.envelope.actor ?? null, {
1996
2050
  schema:
@@ -2040,7 +2094,7 @@ async function createGuide(args, options = {}) {
2040
2094
  ? null
2041
2095
  : (quota.envelope.error?.code ?? "quota_unavailable"),
2042
2096
  },
2043
- payments: paymentSummary,
2097
+ payments: paymentSummaryOutput,
2044
2098
  },
2045
2099
  selection:
2046
2100
  selected === null
@@ -2090,13 +2144,14 @@ async function createGuide(args, options = {}) {
2090
2144
  recommended_no_spend_command: noSpendNextCommand,
2091
2145
  recommended_no_spend_command_label: noSpendNextCommandLabel,
2092
2146
  recommended_no_spend_command_effect: noSpendNextCommandEffect,
2093
- self_fund_next_command: selfFundNextCommand,
2094
- self_fund_next_command_label: selfFundNextCommandLabel,
2095
- self_fund_handoff: selfFundHandoff,
2096
- self_fund_preparation: selfFundPreparation,
2147
+ self_fund_next_command: selfFundNextCommandOutput,
2148
+ self_fund_next_command_label: selfFundNextCommandLabelOutput,
2149
+ self_fund_handoff: selfFundHandoffOutput,
2150
+ self_fund_preparation: selfFundPreparationOutput,
2097
2151
  after_next: afterNext,
2098
2152
  auth_handoff: authHandoff,
2099
2153
  escape_hatches: escapeHatches,
2154
+ no_spend_output_mode: noSpendOutputModeData,
2100
2155
  mutation: {
2101
2156
  provider_call: false,
2102
2157
  hosted_create: false,
@@ -3389,7 +3444,24 @@ function createGuideBlocker(stage, input) {
3389
3444
  };
3390
3445
  }
3391
3446
  if (stage === "quota_required") {
3392
- const remaining = quotaRemainingCredits(input.quota?.envelope.data ?? null);
3447
+ const quotaData = input.quota?.envelope.data ?? null;
3448
+ const remaining = quotaRemainingCredits(quotaData);
3449
+ // Mirror createGuideStage's credit-first ordering: credits only outrank the
3450
+ // daily-job cap when they are genuinely short. Agents that hold spare
3451
+ // credits but hit the daily allowance (issues #2103, #2148) must be told the
3452
+ // honest trigger, not a credits-shortfall line that reads as wrong to them
3453
+ // (same confusion class as #1193).
3454
+ const creditsShort =
3455
+ input.estimatedCredits !== null &&
3456
+ remaining !== null &&
3457
+ remaining < input.estimatedCredits;
3458
+ const dailyJobs = quotaData?.daily_jobs;
3459
+ if (!creditsShort && dailyJobs !== undefined && dailyJobs.remaining <= 0) {
3460
+ return {
3461
+ code: "quota_required",
3462
+ message: `You've reached today's job allowance (${dailyJobs.cap}/day); a top-up raises your daily allowance so you can keep creating now.`,
3463
+ };
3464
+ }
3393
3465
  return {
3394
3466
  code: "quota_required",
3395
3467
  message: `Selected first image requires ${input.estimatedCredits ?? "unknown"} credits; current remaining credits are ${remaining ?? "unknown"}.`,
@@ -4439,6 +4511,12 @@ async function create(argv) {
4439
4511
  if (flagBool(args, "guide")) {
4440
4512
  return createGuide(args);
4441
4513
  }
4514
+ if (flagBool(args, "no-spend")) {
4515
+ return invalid(
4516
+ "luxin create",
4517
+ "create --no-spend is a guide output mode; combine it with --guide, or use create --dry-run for a no-spend planned job",
4518
+ );
4519
+ }
4442
4520
  const prompt = await promptValue(args);
4443
4521
  if (!prompt.ok) {
4444
4522
  return prompt.result;
@@ -4586,6 +4664,12 @@ async function edit(argv) {
4586
4664
  inputReference: input,
4587
4665
  });
4588
4666
  }
4667
+ if (flagBool(args, "no-spend")) {
4668
+ return invalid(
4669
+ "luxin edit",
4670
+ "edit --no-spend is a guide output mode; combine it with --guide, or use edit --dry-run for a no-spend planned job",
4671
+ );
4672
+ }
4589
4673
  if (input === undefined) {
4590
4674
  return invalid(
4591
4675
  "luxin edit",
@@ -6967,6 +7051,16 @@ function quotaRecoveryWithCopyRunnableCommands(recovery, commandPrefix) {
6967
7051
  ),
6968
7052
  }
6969
7053
  : {}),
7054
+ ...(recovery.human_handoff &&
7055
+ typeof recovery.human_handoff === "object" &&
7056
+ typeof recovery.human_handoff.command === "string"
7057
+ ? {
7058
+ human_handoff: {
7059
+ ...recovery.human_handoff,
7060
+ command: render(recovery.human_handoff.command),
7061
+ },
7062
+ }
7063
+ : {}),
6970
7064
  top_up: quotaTopUpWithCopyRunnableCommands(recovery.top_up, commandPrefix),
6971
7065
  };
6972
7066
  }
package/cli.md CHANGED
@@ -355,6 +355,26 @@ step.
355
355
  `data.auth_handoff.next_command.with_env` or
356
356
  `data.auth_handoff.next_command.with_stdin` so auth follows the create.
357
357
 
358
+ For a no-spend or dry-run study, add `--no-spend` to `create --guide` for a
359
+ compact output mode. `data.no_spend_output_mode.enabled` is then `true` and the
360
+ live self-fund and payment command templates are omitted:
361
+ `data.self_fund_next_command`, `data.self_fund_next_command_label`,
362
+ `data.self_fund_handoff`, `data.self_fund_preparation`, and
363
+ `data.checks.payments.suggested_commands` are suppressed (each is listed in
364
+ `data.no_spend_output_mode.suppressed_fields`), so the safe dry-run is not
365
+ buried under quote/buy/payment workflow commands. The response still centers on
366
+ the dry-run command (`data.recommended_no_spend_command`, aliased by
367
+ `data.no_spend_next_command`), and the provider-call, credit-debit, and
368
+ media-write false proof in `data.mutation` is retained. The self-fund path
369
+ stays discoverable without dominating via
370
+ `data.no_spend_output_mode.self_fund_discovery`: its
371
+ `rerun_with_funding_command` re-runs the guide without `--no-spend` to surface
372
+ the funding templates, and `inspect_methods_command` is a read-only, no-spend
373
+ payment-method inspection (the same command as
374
+ `data.escape_hatches.payment_methods`). `--no-spend` is a guide output mode; it
375
+ requires `--guide`, and for a no-spend planned job outside the guide use
376
+ `create --dry-run`.
377
+
358
378
  Manual escape hatches are not prerequisites. Use them only when
359
379
  `data.next_command` / `data.escape_hatches` asks, or when the task genuinely
360
380
  needs deeper capability, quota, payment, or planning detail:
package/commands.json CHANGED
@@ -421,6 +421,7 @@
421
421
  "docs_url": "https://luxin.sh/cli.md#luxin-create",
422
422
  "optional_flags": [
423
423
  "--guide",
424
+ "--no-spend",
424
425
  "--dry-run",
425
426
  "--model",
426
427
  "--aspect-ratio",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "luxin-cli",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Zero-setup durable creative-media CLI for agents (image + video + audio + 3D): guide-first creation, model and cost inspection, owned URLs, JSON recovery, payments, reusable assets, and feedback. Luxin is a creative-media runtime, unrelated to the luxon datetime library.",
5
5
  "type": "module",
6
6
  "private": false,
@@ -355,6 +355,26 @@ step.
355
355
  `data.auth_handoff.next_command.with_env` or
356
356
  `data.auth_handoff.next_command.with_stdin` so auth follows the create.
357
357
 
358
+ For a no-spend or dry-run study, add `--no-spend` to `create --guide` for a
359
+ compact output mode. `data.no_spend_output_mode.enabled` is then `true` and the
360
+ live self-fund and payment command templates are omitted:
361
+ `data.self_fund_next_command`, `data.self_fund_next_command_label`,
362
+ `data.self_fund_handoff`, `data.self_fund_preparation`, and
363
+ `data.checks.payments.suggested_commands` are suppressed (each is listed in
364
+ `data.no_spend_output_mode.suppressed_fields`), so the safe dry-run is not
365
+ buried under quote/buy/payment workflow commands. The response still centers on
366
+ the dry-run command (`data.recommended_no_spend_command`, aliased by
367
+ `data.no_spend_next_command`), and the provider-call, credit-debit, and
368
+ media-write false proof in `data.mutation` is retained. The self-fund path
369
+ stays discoverable without dominating via
370
+ `data.no_spend_output_mode.self_fund_discovery`: its
371
+ `rerun_with_funding_command` re-runs the guide without `--no-spend` to surface
372
+ the funding templates, and `inspect_methods_command` is a read-only, no-spend
373
+ payment-method inspection (the same command as
374
+ `data.escape_hatches.payment_methods`). `--no-spend` is a guide output mode; it
375
+ requires `--guide`, and for a no-spend planned job outside the guide use
376
+ `create --dry-run`.
377
+
358
378
  Manual escape hatches are not prerequisites. Use them only when
359
379
  `data.next_command` / `data.escape_hatches` asks, or when the task genuinely
360
380
  needs deeper capability, quota, payment, or planning detail:
@@ -421,6 +421,7 @@
421
421
  "docs_url": "https://luxin.sh/cli.md#luxin-create",
422
422
  "optional_flags": [
423
423
  "--guide",
424
+ "--no-spend",
424
425
  "--dry-run",
425
426
  "--model",
426
427
  "--aspect-ratio",