image-skill 0.1.62 → 0.1.63

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
@@ -4,6 +4,16 @@ This changelog tracks the public `image-skill` CLI package and public skill
4
4
  mirror. The npm package metadata remains the authority for tarball integrity and
5
5
  provenance; this file is the human- and agent-readable release map.
6
6
 
7
+ ## 0.1.63 - 2026-06-17
8
+
9
+ - Release (activation/self-fund): make quota/payment error recovery top-up
10
+ commands copy-runnable from ephemeral `npx image-skill@latest` runs. When
11
+ hosted create/edit or payment commands return `error.recovery.top_up`, the
12
+ public CLI now prefixes `suggested_command`, `suggested_commands`,
13
+ `top_up.first_command`, `top_up.quote_command`, nested `top_up.commands.*`,
14
+ and workflow step commands with the same zero-install handoff used by
15
+ `usage quota --json` and `create --guide`.
16
+
7
17
  ## 0.1.62 - 2026-06-17
8
18
 
9
19
  - Release (activation/self-fund): make `usage quota --json` top-up handoffs
@@ -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.1.62";
18
+ const VERSION = "0.1.63";
19
19
  const PACKAGE_NAME = "image-skill";
20
20
  const DEFAULT_API_BASE_URL = "https://api.image-skill.com";
21
21
  const DEFAULT_DOCS_BASE_URL = "https://image-skill.com";
@@ -1228,23 +1228,24 @@ async function credits(argv) {
1228
1228
  payment_method: paymentMethod,
1229
1229
  idempotency_key: idempotency.value,
1230
1230
  };
1231
- const result = await apiRequest({
1232
- command: "image-skill credits quote",
1233
- method: "POST",
1234
- apiBaseUrl: apiBase(args),
1235
- path: "/v1/credit-quotes",
1236
- token: token.token,
1237
- body,
1238
- });
1231
+ const commandPrefix = createGuideCommandPrefix();
1232
+ const result = withCopyRunnableQuotaRecoveryCommands(
1233
+ await apiRequest({
1234
+ command: "image-skill credits quote",
1235
+ method: "POST",
1236
+ apiBaseUrl: apiBase(args),
1237
+ path: "/v1/credit-quotes",
1238
+ token: token.token,
1239
+ body,
1240
+ }),
1241
+ commandPrefix,
1242
+ );
1239
1243
  if (idempotency.generated) {
1240
1244
  result.envelope.warnings.push(
1241
1245
  `generated idempotency key ${idempotency.value}; pass --idempotency-key for stable retries`,
1242
1246
  );
1243
1247
  }
1244
- return withCopyRunnableCreditQuoteCommands(
1245
- result,
1246
- createGuideCommandPrefix(),
1247
- );
1248
+ return withCopyRunnableCreditQuoteCommands(result, commandPrefix);
1248
1249
  }
1249
1250
  if (subcommand === "buy") {
1250
1251
  const args = parseArgs(rest);
@@ -1285,20 +1286,24 @@ async function credits(argv) {
1285
1286
  provider === "stripe_x402"
1286
1287
  ? "/v1/credit-purchases/stripe-x402-deposits"
1287
1288
  : "/v1/credit-purchases/stripe-checkout-sessions";
1288
- const result = await apiRequest({
1289
- command: "image-skill credits buy",
1290
- method: "POST",
1291
- apiBaseUrl: apiBase(args),
1292
- path: purchasePath,
1293
- token: token.token,
1294
- body: {
1295
- quote_id: quoteId,
1296
- idempotency_key: idempotency.value,
1297
- },
1298
- });
1289
+ const commandPrefix = createGuideCommandPrefix();
1290
+ const result = withCopyRunnableQuotaRecoveryCommands(
1291
+ await apiRequest({
1292
+ command: "image-skill credits buy",
1293
+ method: "POST",
1294
+ apiBaseUrl: apiBase(args),
1295
+ path: purchasePath,
1296
+ token: token.token,
1297
+ body: {
1298
+ quote_id: quoteId,
1299
+ idempotency_key: idempotency.value,
1300
+ },
1301
+ }),
1302
+ commandPrefix,
1303
+ );
1299
1304
  return withCopyRunnablePaymentNextActionCommands(
1300
1305
  withStripeCheckoutCopyFallback(result),
1301
- createGuideCommandPrefix(),
1306
+ commandPrefix,
1302
1307
  );
1303
1308
  }
1304
1309
  if (subcommand === "status") {
@@ -1312,16 +1317,20 @@ async function credits(argv) {
1312
1317
  addQueryFlag(query, args, "payment-attempt-id", "payment_attempt_id");
1313
1318
  addQueryFlag(query, args, "checkout-session-id", "checkout_session_id");
1314
1319
  addQueryFlag(query, args, "receipt-id", "receipt_id");
1315
- const result = await apiRequest({
1316
- command: "image-skill credits status",
1317
- method: "GET",
1318
- apiBaseUrl: apiBase(args),
1319
- path: `/v1/credit-purchases/status?${query.toString()}`,
1320
- token: token.token,
1321
- });
1320
+ const commandPrefix = createGuideCommandPrefix();
1321
+ const result = withCopyRunnableQuotaRecoveryCommands(
1322
+ await apiRequest({
1323
+ command: "image-skill credits status",
1324
+ method: "GET",
1325
+ apiBaseUrl: apiBase(args),
1326
+ path: `/v1/credit-purchases/status?${query.toString()}`,
1327
+ token: token.token,
1328
+ }),
1329
+ commandPrefix,
1330
+ );
1322
1331
  return withCopyRunnablePaymentNextActionCommands(
1323
1332
  withStripeCheckoutCopyFallback(result),
1324
- createGuideCommandPrefix(),
1333
+ commandPrefix,
1325
1334
  );
1326
1335
  }
1327
1336
  return invalid(
@@ -4048,48 +4057,51 @@ async function create(argv) {
4048
4057
  argv,
4049
4058
  })
4050
4059
  : null;
4051
- const result = await apiRequest({
4052
- command: "image-skill create",
4053
- method: "POST",
4054
- apiBaseUrl: apiBase(args),
4055
- path: "/v1/create",
4056
- ...(token.token === null ? {} : { token: token.token }),
4057
- body: {
4058
- prompt: prompt.value,
4059
- ...(flagString(args, "provider") === null
4060
- ? {}
4061
- : { provider: flagString(args, "provider") }),
4062
- ...(flagString(args, "model") === null
4063
- ? {}
4064
- : { model: flagString(args, "model") }),
4065
- ...(flagString(args, "intent") === null
4066
- ? {}
4067
- : { intent: flagString(args, "intent") }),
4068
- aspect_ratio: flagString(args, "aspect-ratio") ?? "1:1",
4069
- ...(references.references.length === 0
4070
- ? {}
4071
- : { references: references.references }),
4072
- ...(outputCount.value === null
4073
- ? {}
4074
- : { output_count: outputCount.value }),
4075
- ...(flagNumber(args, "max-estimated-usd-per-image") === null
4076
- ? {}
4077
- : {
4078
- max_estimated_usd_per_image: flagNumber(
4079
- args,
4080
- "max-estimated-usd-per-image",
4081
- ),
4082
- }),
4083
- ...(modelParameters.value === null
4084
- ? {}
4085
- : { model_parameters: modelParameters.value }),
4086
- // Retry-safe dedupe (#1228/#1789): a live create always carries a key so a
4087
- // retry (or an interrupted-then-recovered run) dedupes to one charge.
4088
- ...(idempotencyKey === null ? {} : { idempotency_key: idempotencyKey }),
4089
- dry_run: flagBool(args, "dry-run"),
4090
- accept_unknown_cost: flagBool(args, "accept-unknown-cost"),
4091
- },
4092
- });
4060
+ const result = withCopyRunnableQuotaRecoveryCommands(
4061
+ await apiRequest({
4062
+ command: "image-skill create",
4063
+ method: "POST",
4064
+ apiBaseUrl: apiBase(args),
4065
+ path: "/v1/create",
4066
+ ...(token.token === null ? {} : { token: token.token }),
4067
+ body: {
4068
+ prompt: prompt.value,
4069
+ ...(flagString(args, "provider") === null
4070
+ ? {}
4071
+ : { provider: flagString(args, "provider") }),
4072
+ ...(flagString(args, "model") === null
4073
+ ? {}
4074
+ : { model: flagString(args, "model") }),
4075
+ ...(flagString(args, "intent") === null
4076
+ ? {}
4077
+ : { intent: flagString(args, "intent") }),
4078
+ aspect_ratio: flagString(args, "aspect-ratio") ?? "1:1",
4079
+ ...(references.references.length === 0
4080
+ ? {}
4081
+ : { references: references.references }),
4082
+ ...(outputCount.value === null
4083
+ ? {}
4084
+ : { output_count: outputCount.value }),
4085
+ ...(flagNumber(args, "max-estimated-usd-per-image") === null
4086
+ ? {}
4087
+ : {
4088
+ max_estimated_usd_per_image: flagNumber(
4089
+ args,
4090
+ "max-estimated-usd-per-image",
4091
+ ),
4092
+ }),
4093
+ ...(modelParameters.value === null
4094
+ ? {}
4095
+ : { model_parameters: modelParameters.value }),
4096
+ // Retry-safe dedupe (#1228/#1789): a live create always carries a key so a
4097
+ // retry (or an interrupted-then-recovered run) dedupes to one charge.
4098
+ ...(idempotencyKey === null ? {} : { idempotency_key: idempotencyKey }),
4099
+ dry_run: flagBool(args, "dry-run"),
4100
+ accept_unknown_cost: flagBool(args, "accept-unknown-cost"),
4101
+ },
4102
+ }),
4103
+ createGuideCommandPrefix(),
4104
+ );
4093
4105
  await clearInFlightSpendForResult(inFlight, result);
4094
4106
  return result;
4095
4107
  }
@@ -4182,45 +4194,48 @@ async function edit(argv) {
4182
4194
  argv,
4183
4195
  })
4184
4196
  : null;
4185
- const result = await apiRequest({
4186
- command: "image-skill edit",
4187
- method: "POST",
4188
- apiBaseUrl: apiBase(args),
4189
- path: "/v1/edit",
4190
- token: token.token,
4191
- body: {
4192
- input_asset_id: assetId.assetId,
4193
- ...(maskAssetId === null ? {} : { mask_asset_id: maskAssetId.assetId }),
4194
- ...(references.references.length === 0
4195
- ? {}
4196
- : { references: references.references }),
4197
- ...(prompt.value.length === 0 ? {} : { prompt: prompt.value }),
4198
- ...(flagString(args, "provider") === null
4199
- ? {}
4200
- : { provider: flagString(args, "provider") }),
4201
- ...(modelId === null ? {} : { model: modelId }),
4202
- ...(flagString(args, "intent") === null
4203
- ? {}
4204
- : { intent: flagString(args, "intent") }),
4205
- aspect_ratio: flagString(args, "aspect-ratio") ?? "auto",
4206
- ...(flagNumber(args, "max-estimated-usd-per-image") === null
4207
- ? {}
4208
- : {
4209
- max_estimated_usd_per_image: flagNumber(
4210
- args,
4211
- "max-estimated-usd-per-image",
4212
- ),
4213
- }),
4214
- ...(modelParameters.value === null
4215
- ? {}
4216
- : { model_parameters: modelParameters.value }),
4217
- ...(flagBool(args, "dry-run") ? { dry_run: true } : {}),
4218
- // Retry-safe dedupe (#1228/#1789): a live edit always carries a key so a
4219
- // retry (or an interrupted-then-recovered run) dedupes to one charge.
4220
- ...(idempotencyKey === null ? {} : { idempotency_key: idempotencyKey }),
4221
- accept_unknown_cost: flagBool(args, "accept-unknown-cost"),
4222
- },
4223
- });
4197
+ const result = withCopyRunnableQuotaRecoveryCommands(
4198
+ await apiRequest({
4199
+ command: "image-skill edit",
4200
+ method: "POST",
4201
+ apiBaseUrl: apiBase(args),
4202
+ path: "/v1/edit",
4203
+ token: token.token,
4204
+ body: {
4205
+ input_asset_id: assetId.assetId,
4206
+ ...(maskAssetId === null ? {} : { mask_asset_id: maskAssetId.assetId }),
4207
+ ...(references.references.length === 0
4208
+ ? {}
4209
+ : { references: references.references }),
4210
+ ...(prompt.value.length === 0 ? {} : { prompt: prompt.value }),
4211
+ ...(flagString(args, "provider") === null
4212
+ ? {}
4213
+ : { provider: flagString(args, "provider") }),
4214
+ ...(modelId === null ? {} : { model: modelId }),
4215
+ ...(flagString(args, "intent") === null
4216
+ ? {}
4217
+ : { intent: flagString(args, "intent") }),
4218
+ aspect_ratio: flagString(args, "aspect-ratio") ?? "auto",
4219
+ ...(flagNumber(args, "max-estimated-usd-per-image") === null
4220
+ ? {}
4221
+ : {
4222
+ max_estimated_usd_per_image: flagNumber(
4223
+ args,
4224
+ "max-estimated-usd-per-image",
4225
+ ),
4226
+ }),
4227
+ ...(modelParameters.value === null
4228
+ ? {}
4229
+ : { model_parameters: modelParameters.value }),
4230
+ ...(flagBool(args, "dry-run") ? { dry_run: true } : {}),
4231
+ // Retry-safe dedupe (#1228/#1789): a live edit always carries a key so a
4232
+ // retry (or an interrupted-then-recovered run) dedupes to one charge.
4233
+ ...(idempotencyKey === null ? {} : { idempotency_key: idempotencyKey }),
4234
+ accept_unknown_cost: flagBool(args, "accept-unknown-cost"),
4235
+ },
4236
+ }),
4237
+ createGuideCommandPrefix(),
4238
+ );
4224
4239
  await clearInFlightSpendForResult(inFlight, result);
4225
4240
  return result;
4226
4241
  }
@@ -6437,6 +6452,54 @@ function quotaTopUpWithCopyRunnableCommands(topUp, commandPrefix) {
6437
6452
  };
6438
6453
  }
6439
6454
 
6455
+ function withCopyRunnableQuotaRecoveryCommands(
6456
+ result,
6457
+ commandPrefix = createGuideCommandPrefix(),
6458
+ ) {
6459
+ const recovery = result.envelope?.error?.recovery;
6460
+ if (
6461
+ result.envelope?.ok === true ||
6462
+ recovery === null ||
6463
+ typeof recovery !== "object" ||
6464
+ recovery.top_up === undefined ||
6465
+ recovery.top_up === null
6466
+ ) {
6467
+ return result;
6468
+ }
6469
+ return {
6470
+ ...result,
6471
+ envelope: {
6472
+ ...result.envelope,
6473
+ error: {
6474
+ ...result.envelope.error,
6475
+ recovery: quotaRecoveryWithCopyRunnableCommands(
6476
+ recovery,
6477
+ commandPrefix,
6478
+ ),
6479
+ },
6480
+ },
6481
+ };
6482
+ }
6483
+
6484
+ function quotaRecoveryWithCopyRunnableCommands(recovery, commandPrefix) {
6485
+ const render = (command) =>
6486
+ renderCopyRunnablePaymentCommand(commandPrefix, command);
6487
+ return {
6488
+ ...recovery,
6489
+ ...(typeof recovery.suggested_command === "string"
6490
+ ? { suggested_command: render(recovery.suggested_command) }
6491
+ : {}),
6492
+ ...(Array.isArray(recovery.suggested_commands)
6493
+ ? {
6494
+ suggested_commands: recovery.suggested_commands.map((command) =>
6495
+ typeof command === "string" ? render(command) : command,
6496
+ ),
6497
+ }
6498
+ : {}),
6499
+ top_up: quotaTopUpWithCopyRunnableCommands(recovery.top_up, commandPrefix),
6500
+ };
6501
+ }
6502
+
6440
6503
  function quotaTopUpNextActions(topUp) {
6441
6504
  const commands = topUp?.commands;
6442
6505
  if (
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "image-skill",
3
- "version": "0.1.62",
3
+ "version": "0.1.63",
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.",
5
5
  "type": "module",
6
6
  "private": false,