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 +88 -0
- package/bin/luxin.mjs +102 -8
- package/cli.md +20 -0
- package/commands.json +1 -0
- package/package.json +1 -1
- package/skills/luxin/references/cli.md +20 -0
- package/skills/luxin/references/commands.json +1 -0
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.
|
|
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:
|
|
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:
|
|
2094
|
-
self_fund_next_command_label:
|
|
2095
|
-
self_fund_handoff:
|
|
2096
|
-
self_fund_preparation:
|
|
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
|
|
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "luxin-cli",
|
|
3
|
-
"version": "0.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:
|