luxin-cli 0.2.5 → 0.2.7

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,43 @@ provenance; this file is the human- and agent-readable release map.
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ ## 0.2.7 - 2026-08-12
10
+
11
+ - Release (pricing): the guide's local credit quoting for xAI models moved from
12
+ a `startsWith("xai.grok-imagine-image")` prefix test to an explicit model-id
13
+ list. The prefix test would have priced any Grok Imagine model it had never
14
+ heard of off the 1.x table — for the new `xai.grok-imagine-image-2.0` that
15
+ meant quoting 4 credits for a 10-credit create. Models outside the list now
16
+ defer to the hosted registry's published debit instead of guessing.
17
+ - Adds the `xai.grok-imagine-image-2.0` quality×resolution credit matrix to
18
+ local guide pricing (low/1k through medium/2k), matching the registry the
19
+ hosted API serves since 2026-08-12. Every tier was verified against live
20
+ provider billing before release ($0.04/$0.06/$0.07/$0.08 receipts).
21
+ - The registry behind `models show` grew from 290 to 316 models server-side
22
+ (grok-imagine-image-2.0 create+edit executable and listed; 24 summer-wave
23
+ fal models cataloged with honest tier pricing before they are wired —
24
+ reachable via `models show MODEL_ID`, not yet in the `models list` output,
25
+ which serves executable models only). No CLI change was needed for that —
26
+ noted here because agents read this file to decide whether to upgrade:
27
+ upgrade for the pricing fix, not for model availability.
28
+
29
+ ## 0.2.6 - 2026-08-09
30
+
31
+ - Release (trust): `create --guide` now says when it cannot price the request it
32
+ is planning, instead of presenting the model's default-shape quote as the
33
+ planned debit. `selection.planned_debit_source` reports which of the two you
34
+ got, and the unpriceable case carries a warning pointing at the dry-run.
35
+ - This closes a gap that was invisible rather than wrong: the hosted API
36
+ published per-aspect-ratio create debits only when they differed from the
37
+ quote, so an absent field could mean either "the quote already is the debit"
38
+ or "this server is older than your CLI". The npm package and the hosted API
39
+ deploy independently, so that second case is permanent, not a one-off, and it
40
+ under-quoted silently during any deploy gap or rollback. The API now publishes
41
+ the debit for every create-capable model (107 of 107 live rows), so absence
42
+ means exactly one thing, and the CLI now treats it that way.
43
+ - Carries the correction to the 0.2.5 note below: the "known issue" that shipped
44
+ in the 0.2.5 tarball describes behaviour that does not exist.
45
+
9
46
  ## 0.2.5 - 2026-08-09
10
47
 
11
48
  - Release (correctness): `edit --guide` selects a model again. It gated on
@@ -19,12 +56,15 @@ provenance; this file is the human- and agent-readable release map.
19
56
  `selection.suggested_aspect_ratio` read the same unpublished block and
20
57
  returned null on every real video call unless the brief happened to name a
21
58
  ratio.
22
- - Known issue (#2259): `create --guide` can quote a different credit figure than
23
- the `--dry-run` it hands you, because it prices the model's catalog default
24
- shape rather than the ratio the command actually sends. Measured against the
25
- live API: 4 vs 5 with no ratio stated, 4 vs 3 at 16:9. The dry-run figure is
26
- the authoritative one; budget from it, not from the guide. Unchanged from
27
- 0.2.4; the fix landed server-side but not in this package.
59
+ - Correction (added after 0.2.5 shipped): the 0.2.5 tarball carries a "known
60
+ issue" note claiming `create --guide` can quote a different credit figure than
61
+ the `--dry-run` it hands you. **That note is wrong and the behaviour it
62
+ describes does not exist.** It was written from a measurement taken during a
63
+ deploy-skew window, minutes after the fix merged and before the hosted API had
64
+ deployed its half. Measured after both halves landed, the guide and the dry-run
65
+ agree: 5 and 5 with no ratio stated, 3 and 3 at 16:9. #2259 is fixed and
66
+ closed. Budgeting from the dry-run figure remains sound advice, but it is not a
67
+ workaround for anything.
28
68
 
29
69
  ## 0.2.4 - 2026-08-09
30
70
 
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.5";
18
+ const VERSION = "0.2.7";
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";
@@ -101,12 +101,28 @@ const ACCEPTED_PUBLIC_MEDIA_HOSTS = [
101
101
  // price. These are prices, not costs: the CLI never computes or publishes
102
102
  // provider cost or margin.
103
103
  const XAI_IMAGE_CREDIT_PRICES = {
104
- source_image: { standard: 1 / 3, quality: 5 / 3 },
104
+ source_image: { standard: 1 / 3, quality: 5 / 3, image_2: 5 / 3 },
105
105
  output_image: {
106
106
  standard: 10 / 3,
107
107
  quality: { "1k": 25 / 3, "2k": 35 / 3 },
108
+ image_2: {
109
+ low: { "1k": 20 / 3, "2k": 10 },
110
+ medium: { "1k": 10, "2k": 40 / 3 },
111
+ },
108
112
  },
109
113
  };
114
+ // Mirrors src/credit-pricing.ts XAI_IMAGE_MODEL_IDS. This is an explicit list,
115
+ // not a prefix test: a Grok Imagine image model this CLI has never heard of is
116
+ // priced by the hosted registry's published debit, not by guessing it onto the
117
+ // 1.x price table.
118
+ const XAI_LOCALLY_PRICED_IMAGE_MODEL_IDS = new Set([
119
+ "xai.grok-imagine-image",
120
+ "xai.grok-imagine-image-edit",
121
+ "xai.grok-imagine-image-quality",
122
+ "xai.grok-imagine-image-quality-edit",
123
+ "xai.grok-imagine-image-2.0",
124
+ "xai.grok-imagine-image-2.0-edit",
125
+ ]);
110
126
  const MODALITY_COMMAND_ALIASES = new Map([
111
127
  ["image", { command: "create", intent: null }],
112
128
  ["video", { command: "create", intent: "video" }],
@@ -2007,6 +2023,16 @@ async function createGuide(args, options = {}) {
2007
2023
  defaultedModelParameters.modelParameters,
2008
2024
  pricingContext,
2009
2025
  );
2026
+ // The quote is not the debit, and against a server that does not publish
2027
+ // debits this CLI cannot compute one -- it has no pricing engine, by design.
2028
+ // Say that plainly instead of letting the caller budget against a number the
2029
+ // product does not charge (#2259, #2272).
2030
+ const plannedDebitUnavailable =
2031
+ selected !== null &&
2032
+ createGuideModelSupportsCreate(selected) &&
2033
+ !createGuideSelectedModelRequiresInputImage(selected) &&
2034
+ !createGuideCanPriceModelParameters(selected) &&
2035
+ !createGuideRegistryPublishesCreditDebit(selected);
2010
2036
  const estimatedCredits = pricing?.credits_required ?? null;
2011
2037
  // The guide publishes what the caller will be charged, never our provider
2012
2038
  // cost. `economics.estimated_usd_per_image` is the hosted charge per image.
@@ -2406,6 +2432,9 @@ async function createGuide(args, options = {}) {
2406
2432
  pricing_source: pricing?.pricing_source ?? null,
2407
2433
  model_parameter_defaults_applied:
2408
2434
  defaultedModelParameters.defaultsApplied,
2435
+ planned_debit_source: plannedDebitUnavailable
2436
+ ? "create_credit_debit_unavailable"
2437
+ : "registry_create_credit_debit",
2409
2438
  },
2410
2439
  blocker,
2411
2440
  guide_warning: guideWarning,
@@ -2443,11 +2472,20 @@ async function createGuide(args, options = {}) {
2443
2472
  for (const field of compactOmittedFields) {
2444
2473
  delete guideData[field];
2445
2474
  }
2446
- return createGuideSuccess(command, quota?.envelope.actor ?? null, guideData);
2475
+ return createGuideSuccess(
2476
+ command,
2477
+ quota?.envelope.actor ?? null,
2478
+ guideData,
2479
+ plannedDebitUnavailable
2480
+ ? [
2481
+ "create_credit_debit_unavailable: this hosted API does not publish per-aspect-ratio create debits, so the credits above are the model's default-shape quote and may not be what create debits. Run the dry_run command in escape_hatches for the exact figure before budgeting.",
2482
+ ]
2483
+ : [],
2484
+ );
2447
2485
  }
2448
2486
 
2449
- function createGuideSuccess(command, actor, data) {
2450
- const result = success(command, data);
2487
+ function createGuideSuccess(command, actor, data, warnings = []) {
2488
+ const result = success(command, data, warnings);
2451
2489
  result.envelope.actor = actor;
2452
2490
  return result;
2453
2491
  }
@@ -2968,6 +3006,26 @@ function createGuidePricingForModel(model, modelParameters, context = {}) {
2968
3006
  // this CLI has no pricing engine to recompute it -- so the registry publishes
2969
3007
  // the answer and this reads it. Absent field means the quote already is the
2970
3008
  // debit.
3009
+ // Does this registry response publish create debits at all?
3010
+ //
3011
+ // The hosted API and this CLI ship independently, so a client can always be
3012
+ // talking to a server older than itself. `create_credit_debit_by_aspect_ratio`
3013
+ // is published for EVERY create-capable model precisely so that absence has one
3014
+ // meaning -- "this server cannot tell me the debit" -- rather than being
3015
+ // confusable with "the debit happens to equal the quote". When it is absent the
3016
+ // honest answer is to say so and point at the dry-run, not to present the
3017
+ // model's default-shape quote as the planned debit (#2259, #2272).
3018
+ function createGuideRegistryPublishesCreditDebit(model) {
3019
+ return (
3020
+ isRecord(model?.economics?.create_credit_debit_by_aspect_ratio) ||
3021
+ isRecord(model?.create_credit_debit_by_aspect_ratio)
3022
+ );
3023
+ }
3024
+
3025
+ function createGuideModelSupportsCreate(model) {
3026
+ return Array.isArray(model?.supports) && model.supports.includes("create");
3027
+ }
3028
+
2971
3029
  function createGuideAspectRatioCreditPricing(model, context) {
2972
3030
  // Both shapes: `GET /v1/models` serves the COMPACT summary, which flattens
2973
3031
  // economics onto the row, and only `?details=true` (or a fixture built from
@@ -2997,14 +3055,16 @@ function createGuideAspectRatioCreditPricing(model, context) {
2997
3055
  }
2998
3056
 
2999
3057
  function createGuideCanPriceModelParameters(model) {
3000
- return String(model?.id ?? "").startsWith("xai.grok-imagine-image");
3058
+ return XAI_LOCALLY_PRICED_IMAGE_MODEL_IDS.has(String(model?.id ?? ""));
3001
3059
  }
3002
3060
 
3003
3061
  function createGuideXaiImagePricing(model, modelParameters, context) {
3004
3062
  const modelId = String(model?.id ?? "");
3005
3063
  const quality = modelId.includes("-quality");
3064
+ const image2 = modelId.startsWith("xai.grok-imagine-image-2.0");
3006
3065
  const edit = modelId.endsWith("-edit");
3007
3066
  const resolution = modelParameters?.resolution === "2k" ? "2k" : "1k";
3067
+ const image2Quality = modelParameters?.quality === "low" ? "low" : "medium";
3008
3068
  const outputImageCount =
3009
3069
  Number.isInteger(context?.outputCount) && context.outputCount > 0
3010
3070
  ? context.outputCount
@@ -3015,12 +3075,16 @@ function createGuideXaiImagePricing(model, modelParameters, context) {
3015
3075
  ? context.referenceAssetCount
3016
3076
  : 0;
3017
3077
  const sourceImageCount = edit ? 1 + referenceAssetCount : 0;
3018
- const sourceCredits = quality
3019
- ? XAI_IMAGE_CREDIT_PRICES.source_image.quality
3020
- : XAI_IMAGE_CREDIT_PRICES.source_image.standard;
3021
- const outputCredits = quality
3022
- ? XAI_IMAGE_CREDIT_PRICES.output_image.quality[resolution]
3023
- : XAI_IMAGE_CREDIT_PRICES.output_image.standard;
3078
+ const sourceCredits = image2
3079
+ ? XAI_IMAGE_CREDIT_PRICES.source_image.image_2
3080
+ : quality
3081
+ ? XAI_IMAGE_CREDIT_PRICES.source_image.quality
3082
+ : XAI_IMAGE_CREDIT_PRICES.source_image.standard;
3083
+ const outputCredits = image2
3084
+ ? XAI_IMAGE_CREDIT_PRICES.output_image.image_2[image2Quality][resolution]
3085
+ : quality
3086
+ ? XAI_IMAGE_CREDIT_PRICES.output_image.quality[resolution]
3087
+ : XAI_IMAGE_CREDIT_PRICES.output_image.standard;
3024
3088
  const creditsRequired = Math.max(
3025
3089
  1,
3026
3090
  Math.ceil(
@@ -3033,8 +3097,14 @@ function createGuideXaiImagePricing(model, modelParameters, context) {
3033
3097
  modelParameters?.resolution === undefined ||
3034
3098
  modelParameters?.resolution === null ||
3035
3099
  modelParameters?.resolution === "1k";
3100
+ const defaultQuality =
3101
+ !image2 ||
3102
+ modelParameters?.quality === undefined ||
3103
+ modelParameters?.quality === null ||
3104
+ modelParameters?.quality === "medium";
3036
3105
  const defaultShape =
3037
3106
  defaultResolution &&
3107
+ defaultQuality &&
3038
3108
  outputImageCount === 1 &&
3039
3109
  sourceImageCount === (edit ? 1 : 0);
3040
3110
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "luxin-cli",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "Image generation, image editing, video, audio, and image-to-3D for agents, with no API key to obtain first. The agent signs itself up, starts on free preview credits, and gets hosted media URLs, recoverable jobs, and cost receipts.",
5
5
  "type": "module",
6
6
  "private": false,