image-skill 0.1.27 → 0.1.29
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 +58 -1
- package/CONTRIBUTING.md +1 -1
- package/PROVENANCE.md +1 -1
- package/README.md +49 -10
- package/SECURITY.md +1 -1
- package/bin/image-skill.mjs +953 -79
- package/cli.md +237 -60
- package/llms.txt +18 -13
- package/package.json +1 -1
- package/skill.md +226 -561
- package/skills/ai-audio-generation/SKILL.md +78 -0
- package/skills/ai-image-generation/SKILL.md +78 -0
- package/skills/ai-video-generation/SKILL.md +78 -0
- package/skills/creative-media/SKILL.md +78 -0
- package/skills/image-edit/SKILL.md +78 -0
- package/skills/image-generation/SKILL.md +78 -0
- package/skills/image-skill/SKILL.md +226 -561
- package/skills/image-skill/references/cli.md +237 -60
- package/skills/image-skill/references/llms.txt +18 -13
- package/skills/image-to-3d/SKILL.md +78 -0
package/bin/image-skill.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import { Readable } from "node:stream";
|
|
|
7
7
|
import { pipeline } from "node:stream/promises";
|
|
8
8
|
import os from "node:os";
|
|
9
9
|
|
|
10
|
-
const VERSION = "0.1.
|
|
10
|
+
const VERSION = "0.1.29";
|
|
11
11
|
const PACKAGE_NAME = "image-skill";
|
|
12
12
|
const DEFAULT_API_BASE_URL = "https://api.image-skill.com";
|
|
13
13
|
const DEFAULT_DOCS_BASE_URL = "https://image-skill.com";
|
|
@@ -27,13 +27,15 @@ const DEFAULT_CONFIG_PATH = join(
|
|
|
27
27
|
"image-skill",
|
|
28
28
|
"config.json",
|
|
29
29
|
);
|
|
30
|
+
const LOCAL_WRITABLE_CONFIG_PATH = "$PWD/.image-skill/config.json";
|
|
30
31
|
const SIGNUP_SUGGESTED_COMMAND =
|
|
31
32
|
"image-skill signup --agent --agent-contact AGENT_OR_OPERATOR_INBOX --agent-name NAME --runtime RUNTIME --json";
|
|
32
33
|
const SIGNUP_CONTACT_GUIDANCE =
|
|
33
34
|
"Preview signup currently requires an email-shaped durable contact inbox, not an individual human email. Use an agent-owned inbox when available; otherwise use an operator, team, or sponsor inbox that can receive future claim, billing, or abuse notices. Do not block waiting for a person, invent a person, or use a throwaway inbox. --human-email remains a compatibility alias.";
|
|
34
35
|
const HOSTED_SIGNUP_TOKEN_RETURNED_WARNING =
|
|
35
36
|
"hosted restricted token is returned once; store it in the agent runtime secret store and never paste it into prompts, logs, issues, or product feedback";
|
|
36
|
-
const PUBLIC_NPX_COMMAND_PREFIX =
|
|
37
|
+
const PUBLIC_NPX_COMMAND_PREFIX =
|
|
38
|
+
"npm_config_update_notifier=false npx -y image-skill@latest";
|
|
37
39
|
const CREDIT_UNIT_USD = 0.01;
|
|
38
40
|
const PAYMENT_CREDENTIAL_FLAGS = new Set([
|
|
39
41
|
"payment-token",
|
|
@@ -301,8 +303,8 @@ function commandHelpByKey(key) {
|
|
|
301
303
|
usage:
|
|
302
304
|
"image-skill credits quote --pack PACK_ID --payment-method stripe_x402.exact.usdc --json",
|
|
303
305
|
docs_url: "https://image-skill.com/cli.md#image-skill-credits",
|
|
304
|
-
required_flags: ["--pack or --credits"],
|
|
305
|
-
optional_flags: ["--
|
|
306
|
+
required_flags: ["--pack or --credits", "--payment-method"],
|
|
307
|
+
optional_flags: ["--idempotency-key"],
|
|
306
308
|
},
|
|
307
309
|
"credits buy": {
|
|
308
310
|
command: "image-skill credits buy help",
|
|
@@ -378,6 +380,7 @@ function commandHelpByKey(key) {
|
|
|
378
380
|
docs_url: "https://image-skill.com/cli.md#image-skill-edit",
|
|
379
381
|
required_flags: ["--input"],
|
|
380
382
|
optional_flags: [
|
|
383
|
+
"--dry-run",
|
|
381
384
|
"--prompt",
|
|
382
385
|
"--model",
|
|
383
386
|
"--mask",
|
|
@@ -496,7 +499,7 @@ async function doctor(argv) {
|
|
|
496
499
|
async function trust(argv) {
|
|
497
500
|
const args = parseArgs(argv);
|
|
498
501
|
const unsupportedFlags = [...args.flags.keys()].filter(
|
|
499
|
-
(flag) => !["json", "api-base-url"].includes(flag),
|
|
502
|
+
(flag) => !["json", "api-base-url", "token", "token-stdin"].includes(flag),
|
|
500
503
|
);
|
|
501
504
|
if (args.positionals.length > 0 || unsupportedFlags.length > 0) {
|
|
502
505
|
return invalid(
|
|
@@ -506,6 +509,13 @@ async function trust(argv) {
|
|
|
506
509
|
: "trust does not accept positional arguments",
|
|
507
510
|
);
|
|
508
511
|
}
|
|
512
|
+
const tokenHandoff = await acceptNoAuthTokenHandoff(
|
|
513
|
+
args,
|
|
514
|
+
"image-skill trust",
|
|
515
|
+
);
|
|
516
|
+
if (tokenHandoff !== null) {
|
|
517
|
+
return tokenHandoff;
|
|
518
|
+
}
|
|
509
519
|
|
|
510
520
|
const checkedAt = new Date().toISOString();
|
|
511
521
|
const apiBaseUrl = apiBase(args);
|
|
@@ -972,12 +982,17 @@ async function credits(argv) {
|
|
|
972
982
|
);
|
|
973
983
|
}
|
|
974
984
|
const idempotency = optionalIdempotencyKey(args, "quote");
|
|
975
|
-
const paymentMethod =
|
|
976
|
-
flagString(args, "payment-method") ?? "stripe_checkout";
|
|
985
|
+
const paymentMethod = flagString(args, "payment-method");
|
|
977
986
|
const PUBLIC_QUOTE_PAYMENT_METHODS = [
|
|
978
987
|
"stripe_checkout",
|
|
979
988
|
"stripe_x402.exact.usdc",
|
|
980
989
|
];
|
|
990
|
+
if (paymentMethod === null) {
|
|
991
|
+
return invalid(
|
|
992
|
+
"image-skill credits quote",
|
|
993
|
+
"credits quote requires --payment-method from credits methods --json; use stripe_x402.exact.usdc for an agent-settleable browserless rail or stripe_checkout for a human Checkout handoff",
|
|
994
|
+
);
|
|
995
|
+
}
|
|
981
996
|
if (!PUBLIC_QUOTE_PAYMENT_METHODS.includes(paymentMethod)) {
|
|
982
997
|
return invalid(
|
|
983
998
|
"image-skill credits quote",
|
|
@@ -1144,13 +1159,14 @@ async function models(argv) {
|
|
|
1144
1159
|
query.message,
|
|
1145
1160
|
);
|
|
1146
1161
|
}
|
|
1147
|
-
|
|
1162
|
+
const result = await apiRequest({
|
|
1148
1163
|
command:
|
|
1149
1164
|
subcommand === "list" ? "image-skill models list" : "image-skill models",
|
|
1150
1165
|
method: "GET",
|
|
1151
1166
|
apiBaseUrl: apiBase(args),
|
|
1152
1167
|
path: query.path,
|
|
1153
1168
|
});
|
|
1169
|
+
return flagBool(args, "summary") ? withModelSummary(result) : result;
|
|
1154
1170
|
}
|
|
1155
1171
|
|
|
1156
1172
|
function modelListQuery(args) {
|
|
@@ -1175,6 +1191,7 @@ function modelListQuery(args) {
|
|
|
1175
1191
|
params.set("catalog_only", "true");
|
|
1176
1192
|
}
|
|
1177
1193
|
addQueryValue(params, "operation", flagString(args, "operation"));
|
|
1194
|
+
addQueryValue(params, "modality", flagString(args, "modality"));
|
|
1178
1195
|
addQueryValue(params, "provider", flagString(args, "provider"));
|
|
1179
1196
|
const query = params.toString();
|
|
1180
1197
|
return {
|
|
@@ -1183,6 +1200,133 @@ function modelListQuery(args) {
|
|
|
1183
1200
|
};
|
|
1184
1201
|
}
|
|
1185
1202
|
|
|
1203
|
+
function withModelSummary(result) {
|
|
1204
|
+
const data = result.envelope.data;
|
|
1205
|
+
if (!isRecord(data) || !Array.isArray(data.models)) {
|
|
1206
|
+
return result;
|
|
1207
|
+
}
|
|
1208
|
+
return {
|
|
1209
|
+
...result,
|
|
1210
|
+
envelope: {
|
|
1211
|
+
...result.envelope,
|
|
1212
|
+
data: {
|
|
1213
|
+
...data,
|
|
1214
|
+
summary: {
|
|
1215
|
+
...(isRecord(data.summary) ? data.summary : {}),
|
|
1216
|
+
result_shape: "compact_model_summary",
|
|
1217
|
+
full_list_command: "image-skill models list --json",
|
|
1218
|
+
},
|
|
1219
|
+
models: data.models.map(modelSummaryRow),
|
|
1220
|
+
},
|
|
1221
|
+
},
|
|
1222
|
+
};
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
function modelSummaryRow(model) {
|
|
1226
|
+
return {
|
|
1227
|
+
id: model.id,
|
|
1228
|
+
display_name: model.display_name,
|
|
1229
|
+
provider_id: model.provider_id,
|
|
1230
|
+
mode: model.mode,
|
|
1231
|
+
status: model.status,
|
|
1232
|
+
availability_reason: model.availability_reason ?? null,
|
|
1233
|
+
supports: Array.isArray(model.supports) ? [...model.supports] : [],
|
|
1234
|
+
operations: Array.isArray(model.operations) ? [...model.operations] : [],
|
|
1235
|
+
task_tags: modelSummaryTaskTags(model),
|
|
1236
|
+
estimated_usd_per_image: model.economics?.estimated_usd_per_image ?? null,
|
|
1237
|
+
credits_required: model.economics?.credit_pricing?.credits_required ?? null,
|
|
1238
|
+
pricing_confidence:
|
|
1239
|
+
model.economics?.credit_pricing?.pricing_confidence ?? null,
|
|
1240
|
+
cost_known: model.economics?.cost_known ?? false,
|
|
1241
|
+
budget_required_for_live:
|
|
1242
|
+
model.economics?.budget_required_for_live ?? false,
|
|
1243
|
+
max_outputs_per_request:
|
|
1244
|
+
model.media?.output?.max_outputs_per_request ?? null,
|
|
1245
|
+
max_resolution: model.media?.output?.max_resolution ?? null,
|
|
1246
|
+
artifact_storage: model.execution?.artifact_storage ?? null,
|
|
1247
|
+
model_execution_status: model.execution?.model_execution_status ?? null,
|
|
1248
|
+
grants_required: Array.isArray(model.capability?.grants_required)
|
|
1249
|
+
? [...model.capability.grants_required]
|
|
1250
|
+
: [],
|
|
1251
|
+
show_command:
|
|
1252
|
+
typeof model.id === "string"
|
|
1253
|
+
? `image-skill models show ${model.id} --json`
|
|
1254
|
+
: "image-skill models show MODEL_ID --json",
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
function modelSummaryTaskTags(model) {
|
|
1259
|
+
const tags = [];
|
|
1260
|
+
const seen = new Set();
|
|
1261
|
+
const add = (tag) => {
|
|
1262
|
+
if (!seen.has(tag)) {
|
|
1263
|
+
seen.add(tag);
|
|
1264
|
+
tags.push(tag);
|
|
1265
|
+
}
|
|
1266
|
+
};
|
|
1267
|
+
for (const support of Array.isArray(model.supports) ? model.supports : []) {
|
|
1268
|
+
add(support);
|
|
1269
|
+
}
|
|
1270
|
+
for (const operation of Array.isArray(model.operations)
|
|
1271
|
+
? model.operations
|
|
1272
|
+
: []) {
|
|
1273
|
+
add(operationTag(operation));
|
|
1274
|
+
}
|
|
1275
|
+
for (const intent of Array.isArray(model.capability?.intents)
|
|
1276
|
+
? model.capability.intents
|
|
1277
|
+
: []) {
|
|
1278
|
+
add(intent);
|
|
1279
|
+
}
|
|
1280
|
+
if (
|
|
1281
|
+
model.operations?.includes("image.generate") &&
|
|
1282
|
+
model.media?.input?.images?.required !== true &&
|
|
1283
|
+
model.media?.input?.references?.required !== true
|
|
1284
|
+
) {
|
|
1285
|
+
add("text-to-image");
|
|
1286
|
+
}
|
|
1287
|
+
if (model.media?.input?.images?.required === true) {
|
|
1288
|
+
add("input-image");
|
|
1289
|
+
add("image-to-image");
|
|
1290
|
+
}
|
|
1291
|
+
if (model.media?.input?.mask?.supported === true) {
|
|
1292
|
+
add(model.media?.input?.mask?.required === true ? "mask-required" : "mask");
|
|
1293
|
+
}
|
|
1294
|
+
if (model.media?.input?.references?.supported === true) {
|
|
1295
|
+
add("reference-image");
|
|
1296
|
+
if ((model.media?.input?.references?.max ?? 0) > 1) {
|
|
1297
|
+
add("multi-reference");
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
if (model.media?.output?.transparent_background === true) {
|
|
1301
|
+
add("transparent-background");
|
|
1302
|
+
}
|
|
1303
|
+
if ((model.media?.output?.max_outputs_per_request ?? 0) > 1) {
|
|
1304
|
+
add("multi-output");
|
|
1305
|
+
}
|
|
1306
|
+
if (
|
|
1307
|
+
String(model.id ?? "").includes("video") ||
|
|
1308
|
+
String(model.display_name ?? "")
|
|
1309
|
+
.toLowerCase()
|
|
1310
|
+
.includes("video")
|
|
1311
|
+
) {
|
|
1312
|
+
add("video");
|
|
1313
|
+
}
|
|
1314
|
+
if (model.execution?.artifact_storage === "image_skill_owned") {
|
|
1315
|
+
add("downloadable");
|
|
1316
|
+
}
|
|
1317
|
+
return tags;
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
function operationTag(operation) {
|
|
1321
|
+
if (operation === "image.generate") return "generate";
|
|
1322
|
+
if (operation === "image.edit") return "edit";
|
|
1323
|
+
if (operation === "image.variation") return "variation";
|
|
1324
|
+
if (operation === "image.upscale") return "upscale";
|
|
1325
|
+
if (operation === "image.utility") return "utility";
|
|
1326
|
+
if (operation === "image.vision") return "vision";
|
|
1327
|
+
return "inspect";
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1186
1330
|
function addQueryValue(params, name, value) {
|
|
1187
1331
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
1188
1332
|
params.set(name, value.trim());
|
|
@@ -1284,9 +1428,12 @@ async function createGuide(args) {
|
|
|
1284
1428
|
const selected =
|
|
1285
1429
|
models.envelope.ok && models.envelope.data?.models
|
|
1286
1430
|
? selectCreateGuideModel(models.envelope.data.models, requestedModelId, {
|
|
1431
|
+
prompt: trimmedPrompt,
|
|
1432
|
+
intent: requestedIntent,
|
|
1287
1433
|
maxEstimatedUsdPerImage,
|
|
1288
1434
|
})
|
|
1289
1435
|
: null;
|
|
1436
|
+
const selectedAspectRatio = createGuideSuggestedAspectRatio(selected);
|
|
1290
1437
|
const pricing = selected?.economics?.credit_pricing ?? null;
|
|
1291
1438
|
const estimatedCredits = pricing?.credits_required ?? null;
|
|
1292
1439
|
const estimatedProviderUsdPerImage =
|
|
@@ -1310,6 +1457,9 @@ async function createGuide(args) {
|
|
|
1310
1457
|
path: "/v1/quota",
|
|
1311
1458
|
token: token.token,
|
|
1312
1459
|
});
|
|
1460
|
+
const authenticated = quota?.envelope.data?.authenticated === true;
|
|
1461
|
+
const publicTokenSource =
|
|
1462
|
+
token.source === "anonymous" ? "none" : token.source;
|
|
1313
1463
|
const paymentSummary = createGuidePaymentSummary(payments.envelope.data);
|
|
1314
1464
|
const stage = createGuideStage({
|
|
1315
1465
|
prompt: trimmedPrompt,
|
|
@@ -1333,11 +1483,50 @@ async function createGuide(args) {
|
|
|
1333
1483
|
requestedProviderId,
|
|
1334
1484
|
requestedIntent,
|
|
1335
1485
|
budgetGuard,
|
|
1486
|
+
aspectRatio: selectedAspectRatio,
|
|
1336
1487
|
apiBaseUrl: explicitApiBaseUrl(args),
|
|
1337
1488
|
paymentSummary,
|
|
1338
1489
|
commandPrefix: PUBLIC_NPX_COMMAND_PREFIX,
|
|
1339
1490
|
authConfigWritable: authConfigWrite?.ok ?? true,
|
|
1340
1491
|
});
|
|
1492
|
+
const escapeHatches = createGuideEscapeHatches({
|
|
1493
|
+
prompt: trimmedPrompt,
|
|
1494
|
+
selected,
|
|
1495
|
+
requestedProviderId,
|
|
1496
|
+
requestedIntent,
|
|
1497
|
+
budgetGuard,
|
|
1498
|
+
aspectRatio: selectedAspectRatio,
|
|
1499
|
+
apiBaseUrl: explicitApiBaseUrl(args),
|
|
1500
|
+
commandPrefix: PUBLIC_NPX_COMMAND_PREFIX,
|
|
1501
|
+
});
|
|
1502
|
+
const nextCommandEffect = createGuideNextCommandEffect(stage, {
|
|
1503
|
+
estimatedCredits,
|
|
1504
|
+
estimatedDebitUsdPerImage,
|
|
1505
|
+
});
|
|
1506
|
+
const noSpendNextCommand =
|
|
1507
|
+
stage === "ready_to_create" ? escapeHatches.dry_run : null;
|
|
1508
|
+
const noSpendNextCommandLabel =
|
|
1509
|
+
noSpendNextCommand === null
|
|
1510
|
+
? null
|
|
1511
|
+
: "dry_run_plan_no_provider_call_no_credit_debit_no_media_write";
|
|
1512
|
+
const noSpendNextCommandEffect = createGuideNoSpendNextCommandEffect(stage, {
|
|
1513
|
+
estimatedCredits,
|
|
1514
|
+
estimatedDebitUsdPerImage,
|
|
1515
|
+
});
|
|
1516
|
+
const noSpendEvaluation = createGuideNoSpendEvaluation(stage, {
|
|
1517
|
+
noSpendNextCommand,
|
|
1518
|
+
noSpendNextCommandLabel,
|
|
1519
|
+
noSpendNextCommandEffect,
|
|
1520
|
+
});
|
|
1521
|
+
const guideWarning = createGuideWarning(stage, {
|
|
1522
|
+
nextCommandEffect,
|
|
1523
|
+
paymentSummary,
|
|
1524
|
+
});
|
|
1525
|
+
const selfFundNextCommand = stage === "quota_required" ? nextCommand : null;
|
|
1526
|
+
const selfFundNextCommandLabel = createGuideSelfFundNextCommandLabel(
|
|
1527
|
+
stage,
|
|
1528
|
+
paymentSummary,
|
|
1529
|
+
);
|
|
1341
1530
|
const afterNext =
|
|
1342
1531
|
stage === "auth_required" || stage === "quota_required"
|
|
1343
1532
|
? renderGuideCommand(
|
|
@@ -1352,7 +1541,18 @@ async function createGuide(args) {
|
|
|
1352
1541
|
afterNext,
|
|
1353
1542
|
authConfigWrite,
|
|
1354
1543
|
});
|
|
1355
|
-
|
|
1544
|
+
const authReady = createGuideAuthReady(stage, {
|
|
1545
|
+
authenticated,
|
|
1546
|
+
tokenSource: publicTokenSource,
|
|
1547
|
+
savedConfigPath: configPath(),
|
|
1548
|
+
});
|
|
1549
|
+
const selfFundHandoff = createGuideSelfFundHandoff(stage, {
|
|
1550
|
+
paymentSummary,
|
|
1551
|
+
nextCommand,
|
|
1552
|
+
afterNext,
|
|
1553
|
+
tokenSource: publicTokenSource,
|
|
1554
|
+
});
|
|
1555
|
+
return createGuideSuccess(quota?.envelope.actor ?? null, {
|
|
1356
1556
|
schema: "image-skill.create-guide.v1",
|
|
1357
1557
|
ready: stage === "ready_to_create",
|
|
1358
1558
|
stage,
|
|
@@ -1364,8 +1564,8 @@ async function createGuide(args) {
|
|
|
1364
1564
|
error_code: health.envelope.error?.code ?? null,
|
|
1365
1565
|
},
|
|
1366
1566
|
auth: {
|
|
1367
|
-
source:
|
|
1368
|
-
authenticated
|
|
1567
|
+
source: publicTokenSource,
|
|
1568
|
+
authenticated,
|
|
1369
1569
|
claim_state: quota?.envelope.data?.claim_state ?? null,
|
|
1370
1570
|
token_status: quota?.envelope.data?.token_status ?? null,
|
|
1371
1571
|
saved_config_path: configPath(),
|
|
@@ -1404,14 +1604,24 @@ async function createGuide(args) {
|
|
|
1404
1604
|
selected === null
|
|
1405
1605
|
? null
|
|
1406
1606
|
: {
|
|
1407
|
-
operation:
|
|
1607
|
+
operation: createGuideSelectedModelRequiresInputImage(selected)
|
|
1608
|
+
? "edit"
|
|
1609
|
+
: "create",
|
|
1408
1610
|
model_id: selected.id,
|
|
1409
1611
|
model_status: selected.status,
|
|
1410
1612
|
model_execution_status: selected.execution.model_execution_status,
|
|
1613
|
+
modality: selected.modality ?? null,
|
|
1614
|
+
suggested_aspect_ratio: selectedAspectRatio,
|
|
1411
1615
|
reason:
|
|
1412
1616
|
requestedModelId === null
|
|
1413
|
-
?
|
|
1414
|
-
|
|
1617
|
+
? createGuideSelectionReason(
|
|
1618
|
+
selected,
|
|
1619
|
+
trimmedPrompt,
|
|
1620
|
+
requestedIntent,
|
|
1621
|
+
)
|
|
1622
|
+
: createGuideSelectedModelRequiresInputImage(selected)
|
|
1623
|
+
? "requested executable image-to-3D model"
|
|
1624
|
+
: "requested executable create model",
|
|
1415
1625
|
},
|
|
1416
1626
|
cost: {
|
|
1417
1627
|
estimated_credits: estimatedCredits,
|
|
@@ -1422,49 +1632,23 @@ async function createGuide(args) {
|
|
|
1422
1632
|
pricing_confidence: pricing?.pricing_confidence ?? null,
|
|
1423
1633
|
},
|
|
1424
1634
|
blocker,
|
|
1635
|
+
guide_warning: guideWarning,
|
|
1636
|
+
auth_ready: authReady,
|
|
1425
1637
|
next_command: nextCommand,
|
|
1638
|
+
next_command_effect: nextCommandEffect,
|
|
1639
|
+
no_spend_next_command: noSpendNextCommand,
|
|
1640
|
+
no_spend_next_command_label: noSpendNextCommandLabel,
|
|
1641
|
+
no_spend_next_command_effect: noSpendNextCommandEffect,
|
|
1642
|
+
no_spend_evaluation: noSpendEvaluation,
|
|
1643
|
+
recommended_no_spend_command: noSpendNextCommand,
|
|
1644
|
+
recommended_no_spend_command_label: noSpendNextCommandLabel,
|
|
1645
|
+
recommended_no_spend_command_effect: noSpendNextCommandEffect,
|
|
1646
|
+
self_fund_next_command: selfFundNextCommand,
|
|
1647
|
+
self_fund_next_command_label: selfFundNextCommandLabel,
|
|
1648
|
+
self_fund_handoff: selfFundHandoff,
|
|
1426
1649
|
after_next: afterNext,
|
|
1427
1650
|
auth_handoff: authHandoff,
|
|
1428
|
-
escape_hatches:
|
|
1429
|
-
doctor: renderGuidePrefixedCommand(
|
|
1430
|
-
PUBLIC_NPX_COMMAND_PREFIX,
|
|
1431
|
-
"doctor --json",
|
|
1432
|
-
),
|
|
1433
|
-
model_inspection:
|
|
1434
|
-
selected === null
|
|
1435
|
-
? renderGuidePrefixedCommand(
|
|
1436
|
-
PUBLIC_NPX_COMMAND_PREFIX,
|
|
1437
|
-
"models list --json",
|
|
1438
|
-
)
|
|
1439
|
-
: renderGuidePrefixedCommand(
|
|
1440
|
-
PUBLIC_NPX_COMMAND_PREFIX,
|
|
1441
|
-
`models show ${shellQuote(selected.id)} --json`,
|
|
1442
|
-
),
|
|
1443
|
-
payment_methods: renderGuidePrefixedCommand(
|
|
1444
|
-
PUBLIC_NPX_COMMAND_PREFIX,
|
|
1445
|
-
"credits methods --json",
|
|
1446
|
-
),
|
|
1447
|
-
quota: renderGuidePrefixedCommand(
|
|
1448
|
-
PUBLIC_NPX_COMMAND_PREFIX,
|
|
1449
|
-
"usage quota --json",
|
|
1450
|
-
),
|
|
1451
|
-
dry_run:
|
|
1452
|
-
selected === null || trimmedPrompt.length === 0
|
|
1453
|
-
? renderGuidePrefixedCommand(
|
|
1454
|
-
PUBLIC_NPX_COMMAND_PREFIX,
|
|
1455
|
-
"create --dry-run --prompt PROMPT --json",
|
|
1456
|
-
)
|
|
1457
|
-
: renderCreateCommand({
|
|
1458
|
-
prompt: trimmedPrompt,
|
|
1459
|
-
modelId: selected.id,
|
|
1460
|
-
providerId: requestedProviderId,
|
|
1461
|
-
intent: requestedIntent,
|
|
1462
|
-
budgetGuard,
|
|
1463
|
-
dryRun: true,
|
|
1464
|
-
apiBaseUrl: explicitApiBaseUrl(args),
|
|
1465
|
-
commandPrefix: PUBLIC_NPX_COMMAND_PREFIX,
|
|
1466
|
-
}),
|
|
1467
|
-
},
|
|
1651
|
+
escape_hatches: escapeHatches,
|
|
1468
1652
|
mutation: {
|
|
1469
1653
|
provider_call: false,
|
|
1470
1654
|
hosted_create: false,
|
|
@@ -1476,31 +1660,126 @@ async function createGuide(args) {
|
|
|
1476
1660
|
});
|
|
1477
1661
|
}
|
|
1478
1662
|
|
|
1663
|
+
function createGuideSuccess(actor, data) {
|
|
1664
|
+
const result = success("image-skill create --guide", data);
|
|
1665
|
+
result.envelope.actor = actor;
|
|
1666
|
+
return result;
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1479
1669
|
function selectCreateGuideModel(
|
|
1480
1670
|
models,
|
|
1481
1671
|
requestedModelId,
|
|
1482
|
-
{ maxEstimatedUsdPerImage = null } = {},
|
|
1672
|
+
{ prompt = "", intent = undefined, maxEstimatedUsdPerImage = null } = {},
|
|
1483
1673
|
) {
|
|
1484
1674
|
const isExecutableCreate = (model) =>
|
|
1485
1675
|
model?.status === "available" &&
|
|
1486
1676
|
model?.execution?.model_execution_status === "executable" &&
|
|
1487
1677
|
Array.isArray(model?.supports) &&
|
|
1488
1678
|
model.supports.includes("create");
|
|
1679
|
+
const isExecutableImageTo3d = (model) =>
|
|
1680
|
+
model?.status === "available" &&
|
|
1681
|
+
model?.execution?.model_execution_status === "executable" &&
|
|
1682
|
+
model?.modality === "3d" &&
|
|
1683
|
+
Array.isArray(model?.supports) &&
|
|
1684
|
+
model.supports.includes("variation") &&
|
|
1685
|
+
createGuideSelectedModelRequiresInputImage(model);
|
|
1686
|
+
const isExecutableGuideModel = (model) =>
|
|
1687
|
+
isExecutableCreate(model) || isExecutableImageTo3d(model);
|
|
1489
1688
|
if (requestedModelId !== null) {
|
|
1490
1689
|
const requested = models.find((model) => model.id === requestedModelId);
|
|
1491
|
-
return requested !== undefined &&
|
|
1690
|
+
return requested !== undefined && isExecutableGuideModel(requested)
|
|
1492
1691
|
? requested
|
|
1493
1692
|
: null;
|
|
1494
1693
|
}
|
|
1495
1694
|
const candidates = models.filter(isExecutableCreate);
|
|
1695
|
+
if (createGuideImplies3d({ prompt, intent })) {
|
|
1696
|
+
const eligible3d = guideCandidatesWithinBudget({
|
|
1697
|
+
candidates: models.filter(isExecutableImageTo3d),
|
|
1698
|
+
maxEstimatedUsdPerImage,
|
|
1699
|
+
});
|
|
1700
|
+
const threeDimensional = eligible3d[0];
|
|
1701
|
+
if (threeDimensional !== undefined) {
|
|
1702
|
+
return threeDimensional;
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
const eligible = guideCandidatesWithinBudget({
|
|
1706
|
+
candidates,
|
|
1707
|
+
maxEstimatedUsdPerImage,
|
|
1708
|
+
});
|
|
1709
|
+
if (createGuideImpliesAudio({ prompt, intent })) {
|
|
1710
|
+
const audio = eligible.find((model) => model?.modality === "audio");
|
|
1711
|
+
if (audio !== undefined) {
|
|
1712
|
+
return audio;
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
if (createGuideImpliesVideo({ prompt, intent })) {
|
|
1716
|
+
const video = eligible.find((model) => model?.modality === "video");
|
|
1717
|
+
if (video !== undefined) {
|
|
1718
|
+
return video;
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
const intentClass = createGuideIntentClass(intent);
|
|
1722
|
+
for (const modelId of preferredCreateGuideModelIds(intentClass)) {
|
|
1723
|
+
const preferred = eligible.find((model) => model?.id === modelId);
|
|
1724
|
+
if (preferred !== undefined) {
|
|
1725
|
+
return preferred;
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
return eligible[0] ?? null;
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
function guideCandidatesWithinBudget({
|
|
1732
|
+
candidates,
|
|
1733
|
+
maxEstimatedUsdPerImage = null,
|
|
1734
|
+
}) {
|
|
1496
1735
|
if (maxEstimatedUsdPerImage === null) {
|
|
1497
|
-
return candidates
|
|
1736
|
+
return candidates;
|
|
1498
1737
|
}
|
|
1499
1738
|
const capped = candidates.filter((model) => {
|
|
1500
1739
|
const estimatedUsd = guideBudgetUsdForModel(model);
|
|
1501
1740
|
return estimatedUsd === null || estimatedUsd <= maxEstimatedUsdPerImage;
|
|
1502
1741
|
});
|
|
1503
|
-
return
|
|
1742
|
+
return capped.length === 0 ? candidates : capped;
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
function createGuideIntentClass(intent) {
|
|
1746
|
+
const normalized = String(intent ?? "")
|
|
1747
|
+
.trim()
|
|
1748
|
+
.toLowerCase();
|
|
1749
|
+
if (["cheap", "budget", "draft", "test"].includes(normalized)) {
|
|
1750
|
+
return "budget_draft";
|
|
1751
|
+
}
|
|
1752
|
+
if (
|
|
1753
|
+
[
|
|
1754
|
+
"final",
|
|
1755
|
+
"finalize",
|
|
1756
|
+
"hero",
|
|
1757
|
+
"product",
|
|
1758
|
+
"product-shot",
|
|
1759
|
+
"campaign",
|
|
1760
|
+
"publication",
|
|
1761
|
+
"deliverable",
|
|
1762
|
+
].includes(normalized)
|
|
1763
|
+
) {
|
|
1764
|
+
return "final";
|
|
1765
|
+
}
|
|
1766
|
+
return "general";
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
function preferredCreateGuideModelIds(intentClass) {
|
|
1770
|
+
return intentClass === "budget_draft"
|
|
1771
|
+
? [
|
|
1772
|
+
"fal.flux-dev",
|
|
1773
|
+
"xai.grok-imagine-image-quality",
|
|
1774
|
+
"xai.grok-imagine-image",
|
|
1775
|
+
"openai.gpt-image-2",
|
|
1776
|
+
]
|
|
1777
|
+
: [
|
|
1778
|
+
"xai.grok-imagine-image-quality",
|
|
1779
|
+
"fal.flux-dev",
|
|
1780
|
+
"xai.grok-imagine-image",
|
|
1781
|
+
"openai.gpt-image-2",
|
|
1782
|
+
];
|
|
1504
1783
|
}
|
|
1505
1784
|
|
|
1506
1785
|
function guideBudgetUsdForModel(model) {
|
|
@@ -1514,6 +1793,81 @@ function guideBudgetUsdForModel(model) {
|
|
|
1514
1793
|
);
|
|
1515
1794
|
}
|
|
1516
1795
|
|
|
1796
|
+
function createGuideImplies3d(input) {
|
|
1797
|
+
const searchable =
|
|
1798
|
+
`${input?.intent ?? ""} ${input?.prompt ?? ""}`.toLowerCase();
|
|
1799
|
+
return /\b(?:glb|gltf|mesh|model\s+asset|asset\s+model|textured\s+model|image-to-3d|(?:3d|three-d)\s+(?:\w+\s+){0,3}(?:model|asset|mesh|object)|(?:model|asset|mesh|object)\s+(?:in|as)\s+(?:3d|three-d))\b/.test(
|
|
1800
|
+
searchable,
|
|
1801
|
+
);
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1804
|
+
function createGuideImpliesAudio(input) {
|
|
1805
|
+
const searchable =
|
|
1806
|
+
`${input?.intent ?? ""} ${input?.prompt ?? ""}`.toLowerCase();
|
|
1807
|
+
if (/\bmusic\s+video\b/.test(searchable)) {
|
|
1808
|
+
return false;
|
|
1809
|
+
}
|
|
1810
|
+
return /\b(?:audio|sound|music|soundtrack|wav|text-to-audio)\b/.test(
|
|
1811
|
+
searchable,
|
|
1812
|
+
);
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
function createGuideImpliesVideo(input) {
|
|
1816
|
+
const searchable =
|
|
1817
|
+
`${input?.intent ?? ""} ${input?.prompt ?? ""}`.toLowerCase();
|
|
1818
|
+
return /\b(?:video|clip|footage|animation|animated|mp4|b-roll|timelapse|time-lapse)\b/.test(
|
|
1819
|
+
searchable,
|
|
1820
|
+
);
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1823
|
+
function createGuideSuggestedAspectRatio(model) {
|
|
1824
|
+
if (model?.modality !== "video") {
|
|
1825
|
+
return null;
|
|
1826
|
+
}
|
|
1827
|
+
const values = model?.media?.input?.aspect_ratios?.values;
|
|
1828
|
+
if (!Array.isArray(values)) {
|
|
1829
|
+
return null;
|
|
1830
|
+
}
|
|
1831
|
+
return values.includes("16:9") ? "16:9" : (values[0] ?? null);
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
function createGuideSelectedModelRequiresInputImage(model) {
|
|
1835
|
+
return (
|
|
1836
|
+
model?.modality === "3d" && model?.media?.input?.images?.required === true
|
|
1837
|
+
);
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
function createGuideSelectionReason(model, prompt, intent) {
|
|
1841
|
+
if (
|
|
1842
|
+
createGuideSelectedModelRequiresInputImage(model) &&
|
|
1843
|
+
createGuideImplies3d({ prompt, intent })
|
|
1844
|
+
) {
|
|
1845
|
+
return "3D intent matched executable image-to-3D model; provide one Image Skill-owned image_... input asset";
|
|
1846
|
+
}
|
|
1847
|
+
if (
|
|
1848
|
+
model?.modality === "audio" &&
|
|
1849
|
+
createGuideImpliesAudio({ prompt, intent })
|
|
1850
|
+
) {
|
|
1851
|
+
return "audio intent matched executable audio create model";
|
|
1852
|
+
}
|
|
1853
|
+
if (
|
|
1854
|
+
model?.modality === "video" &&
|
|
1855
|
+
createGuideImpliesVideo({ prompt, intent })
|
|
1856
|
+
) {
|
|
1857
|
+
return "video intent matched executable video create model";
|
|
1858
|
+
}
|
|
1859
|
+
if (
|
|
1860
|
+
preferredCreateGuideModelIds(createGuideIntentClass(intent)).includes(
|
|
1861
|
+
model?.id,
|
|
1862
|
+
)
|
|
1863
|
+
) {
|
|
1864
|
+
return createGuideIntentClass(intent) === "budget_draft"
|
|
1865
|
+
? "guide selected a draft/budget create model with high-definition defaults"
|
|
1866
|
+
: "guide selected the strongest currently available quality-first create model for this intent";
|
|
1867
|
+
}
|
|
1868
|
+
return "guide selected the first available executable create model";
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1517
1871
|
function createGuidePaymentSummary(data) {
|
|
1518
1872
|
const methods = Array.isArray(data?.methods)
|
|
1519
1873
|
? data.methods.filter((method) => method.live_money)
|
|
@@ -1562,6 +1916,10 @@ function createGuidePaymentSummary(data) {
|
|
|
1562
1916
|
(method) => method.method_id,
|
|
1563
1917
|
),
|
|
1564
1918
|
preferred_method: preferredMethod?.method_id ?? null,
|
|
1919
|
+
preferred_method_summary:
|
|
1920
|
+
preferredMethod === undefined
|
|
1921
|
+
? null
|
|
1922
|
+
: createGuidePreferredPaymentSummary(preferredMethod),
|
|
1565
1923
|
buyer_modes: [
|
|
1566
1924
|
...new Set(methods.flatMap((method) => method.buyer_modes ?? [])),
|
|
1567
1925
|
],
|
|
@@ -1572,6 +1930,64 @@ function createGuidePaymentSummary(data) {
|
|
|
1572
1930
|
};
|
|
1573
1931
|
}
|
|
1574
1932
|
|
|
1933
|
+
function createGuidePreferredPaymentSummary(method) {
|
|
1934
|
+
const buyerModes = Array.isArray(method.buyer_modes)
|
|
1935
|
+
? method.buyer_modes.filter((mode) => typeof mode === "string")
|
|
1936
|
+
: [];
|
|
1937
|
+
const liveMoney = method.live_money !== false;
|
|
1938
|
+
const browserless = method.requires_browser === false;
|
|
1939
|
+
const requiresBrowser = method.requires_browser === true;
|
|
1940
|
+
const agentInitiated = method.agent_initiated === true;
|
|
1941
|
+
const agentSettleable = method.agent_settleable === true;
|
|
1942
|
+
const humanHandoffRequired =
|
|
1943
|
+
requiresBrowser || buyerModes.includes("human_only");
|
|
1944
|
+
const topUpPath =
|
|
1945
|
+
agentSettleable && browserless
|
|
1946
|
+
? "browserless_agent_self_fund"
|
|
1947
|
+
: humanHandoffRequired
|
|
1948
|
+
? "human_payment_handoff"
|
|
1949
|
+
: "payment_method_inspection";
|
|
1950
|
+
return {
|
|
1951
|
+
method_id: method.method_id,
|
|
1952
|
+
live_money: liveMoney,
|
|
1953
|
+
requires_browser: requiresBrowser,
|
|
1954
|
+
browserless,
|
|
1955
|
+
agent_initiated: agentInitiated,
|
|
1956
|
+
agent_settleable: agentSettleable,
|
|
1957
|
+
human_handoff_required: humanHandoffRequired,
|
|
1958
|
+
buyer_modes: buyerModes,
|
|
1959
|
+
settlement_blocker:
|
|
1960
|
+
typeof method.settlement_blocker === "string"
|
|
1961
|
+
? method.settlement_blocker
|
|
1962
|
+
: null,
|
|
1963
|
+
default_pack_id:
|
|
1964
|
+
typeof method.default_pack_id === "string"
|
|
1965
|
+
? method.default_pack_id
|
|
1966
|
+
: null,
|
|
1967
|
+
min_amount_cents:
|
|
1968
|
+
typeof method.limits?.min_amount_cents === "number"
|
|
1969
|
+
? method.limits.min_amount_cents
|
|
1970
|
+
: null,
|
|
1971
|
+
max_amount_cents:
|
|
1972
|
+
typeof method.limits?.max_amount_cents === "number"
|
|
1973
|
+
? method.limits.max_amount_cents
|
|
1974
|
+
: null,
|
|
1975
|
+
top_up_path: topUpPath,
|
|
1976
|
+
next_step:
|
|
1977
|
+
topUpPath === "browserless_agent_self_fund"
|
|
1978
|
+
? "quote_buy_status_then_rerun_after_next"
|
|
1979
|
+
: topUpPath === "human_payment_handoff"
|
|
1980
|
+
? "quote_buy_open_checkout_status_then_rerun_after_next"
|
|
1981
|
+
: "inspect_credits_methods",
|
|
1982
|
+
warning:
|
|
1983
|
+
topUpPath === "browserless_agent_self_fund"
|
|
1984
|
+
? "Preferred rail is browserless live money that a wallet-equipped agent can initiate and settle inside delegated caps."
|
|
1985
|
+
: topUpPath === "human_payment_handoff"
|
|
1986
|
+
? "Preferred rail starts a live-money payment handoff and requires human or browser completion before credits are granted."
|
|
1987
|
+
: "Preferred payment rail needs inspection before an agent can choose the next top-up action.",
|
|
1988
|
+
};
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1575
1991
|
function createGuidePaymentCommands(preferredMethod, fallbackMethods) {
|
|
1576
1992
|
const commands = [
|
|
1577
1993
|
"image-skill credits methods --json",
|
|
@@ -1676,6 +2092,10 @@ function createGuideBlocker(stage, input) {
|
|
|
1676
2092
|
function createGuideAuthHandoff(stage, input) {
|
|
1677
2093
|
if (stage === "auth_required") {
|
|
1678
2094
|
const authConfigWritable = input.authConfigWrite?.ok ?? true;
|
|
2095
|
+
const recovery =
|
|
2096
|
+
input.authConfigWrite?.ok === false
|
|
2097
|
+
? configWriteRecovery("image-skill create --guide")
|
|
2098
|
+
: null;
|
|
1679
2099
|
return {
|
|
1680
2100
|
required: true,
|
|
1681
2101
|
token_source: "none",
|
|
@@ -1683,16 +2103,21 @@ function createGuideAuthHandoff(stage, input) {
|
|
|
1683
2103
|
accepted_methods: ["IMAGE_SKILL_TOKEN", "--token-stdin", "config"],
|
|
1684
2104
|
signup: {
|
|
1685
2105
|
returns_token_once: true,
|
|
1686
|
-
public_cli_saves_config:
|
|
2106
|
+
public_cli_saves_config: true,
|
|
1687
2107
|
store_token_in: authConfigWritable
|
|
1688
2108
|
? "public_cli_config_by_default"
|
|
1689
|
-
: "
|
|
2109
|
+
: "public_cli_config_after_setting_IMAGE_SKILL_CONFIG_PATH",
|
|
1690
2110
|
config_path: configPath(),
|
|
1691
2111
|
config_writable: authConfigWritable,
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
?
|
|
1695
|
-
:
|
|
2112
|
+
preferred_save_config:
|
|
2113
|
+
recovery === null
|
|
2114
|
+
? null
|
|
2115
|
+
: {
|
|
2116
|
+
config_path_env: recovery.config_path_env,
|
|
2117
|
+
config_path: recovery.suggested_config_path,
|
|
2118
|
+
command: input.nextCommand,
|
|
2119
|
+
},
|
|
2120
|
+
recovery,
|
|
1696
2121
|
},
|
|
1697
2122
|
rerun_guide:
|
|
1698
2123
|
input.afterNext === null
|
|
@@ -1704,7 +2129,7 @@ function createGuideAuthHandoff(stage, input) {
|
|
|
1704
2129
|
next_command: null,
|
|
1705
2130
|
};
|
|
1706
2131
|
}
|
|
1707
|
-
if (stage === "ready_to_create") {
|
|
2132
|
+
if (stage === "quota_required" || stage === "ready_to_create") {
|
|
1708
2133
|
return {
|
|
1709
2134
|
required: true,
|
|
1710
2135
|
token_source: input.tokenSource,
|
|
@@ -1723,6 +2148,344 @@ function createGuideAuthHandoff(stage, input) {
|
|
|
1723
2148
|
return null;
|
|
1724
2149
|
}
|
|
1725
2150
|
|
|
2151
|
+
function createGuideAuthReady(stage, input) {
|
|
2152
|
+
const nextCommandRequiresAuth =
|
|
2153
|
+
stage === "quota_required" || stage === "ready_to_create";
|
|
2154
|
+
const ready = input.authenticated;
|
|
2155
|
+
return {
|
|
2156
|
+
ready,
|
|
2157
|
+
authenticated: input.authenticated,
|
|
2158
|
+
source: input.tokenSource,
|
|
2159
|
+
saved_config_path: input.savedConfigPath,
|
|
2160
|
+
next_command_requires_auth: nextCommandRequiresAuth,
|
|
2161
|
+
next_command_auth_ready: nextCommandRequiresAuth ? ready : null,
|
|
2162
|
+
secret_value_included: false,
|
|
2163
|
+
accepted_methods: ["config", "IMAGE_SKILL_TOKEN", "--token-stdin"],
|
|
2164
|
+
warning: ready
|
|
2165
|
+
? "Current hosted auth is ready; data.next_command can reuse this auth context without exposing a raw token."
|
|
2166
|
+
: stage === "auth_required"
|
|
2167
|
+
? "Auth is not ready yet; run data.next_command to create a restricted agent identity, then rerun the guide."
|
|
2168
|
+
: null,
|
|
2169
|
+
};
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
function createGuideSelfFundNextCommandLabel(stage, paymentSummary) {
|
|
2173
|
+
if (stage !== "quota_required") {
|
|
2174
|
+
return null;
|
|
2175
|
+
}
|
|
2176
|
+
const preferredMethod = paymentSummary.preferred_method;
|
|
2177
|
+
if (
|
|
2178
|
+
preferredMethod !== null &&
|
|
2179
|
+
paymentSummary.browserless_methods.includes(preferredMethod) &&
|
|
2180
|
+
paymentSummary.agent_settleable_methods.includes(preferredMethod)
|
|
2181
|
+
) {
|
|
2182
|
+
return "browserless_agent_payable_quote";
|
|
2183
|
+
}
|
|
2184
|
+
if (
|
|
2185
|
+
preferredMethod !== null &&
|
|
2186
|
+
paymentSummary.human_handoff_methods.includes(preferredMethod)
|
|
2187
|
+
) {
|
|
2188
|
+
return "human_handoff_payment_quote";
|
|
2189
|
+
}
|
|
2190
|
+
return "payment_or_quota_action";
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
function createGuideSelfFundHandoff(stage, input) {
|
|
2194
|
+
if (stage !== "quota_required") {
|
|
2195
|
+
return null;
|
|
2196
|
+
}
|
|
2197
|
+
const preferredMethod = input.paymentSummary.preferred_method;
|
|
2198
|
+
const browserless =
|
|
2199
|
+
preferredMethod !== null &&
|
|
2200
|
+
input.paymentSummary.browserless_methods.includes(preferredMethod);
|
|
2201
|
+
const agentInitiated =
|
|
2202
|
+
preferredMethod !== null &&
|
|
2203
|
+
input.paymentSummary.agent_initiated_methods.includes(preferredMethod);
|
|
2204
|
+
const agentSettleable =
|
|
2205
|
+
preferredMethod !== null &&
|
|
2206
|
+
input.paymentSummary.agent_settleable_methods.includes(preferredMethod);
|
|
2207
|
+
const humanHandoffRequired =
|
|
2208
|
+
preferredMethod !== null &&
|
|
2209
|
+
input.paymentSummary.human_handoff_methods.includes(preferredMethod);
|
|
2210
|
+
const statusCommand = guidePaymentCommandByKind(
|
|
2211
|
+
input.paymentSummary.suggested_commands,
|
|
2212
|
+
"status",
|
|
2213
|
+
);
|
|
2214
|
+
|
|
2215
|
+
return {
|
|
2216
|
+
required: true,
|
|
2217
|
+
preferred_method: preferredMethod,
|
|
2218
|
+
live_money:
|
|
2219
|
+
preferredMethod !== null &&
|
|
2220
|
+
input.paymentSummary.live_money_methods.includes(preferredMethod),
|
|
2221
|
+
browserless,
|
|
2222
|
+
agent_initiated: agentInitiated,
|
|
2223
|
+
agent_settleable: agentSettleable,
|
|
2224
|
+
human_handoff_required: humanHandoffRequired,
|
|
2225
|
+
payment_commands: {
|
|
2226
|
+
quote: guidePaymentCommandByKind(
|
|
2227
|
+
input.paymentSummary.suggested_commands,
|
|
2228
|
+
"quote",
|
|
2229
|
+
),
|
|
2230
|
+
buy: guidePaymentCommandByKind(
|
|
2231
|
+
input.paymentSummary.suggested_commands,
|
|
2232
|
+
"buy",
|
|
2233
|
+
),
|
|
2234
|
+
status: statusCommand,
|
|
2235
|
+
},
|
|
2236
|
+
wallet_settlement: createGuideWalletSettlementHandoff({
|
|
2237
|
+
preferredMethod,
|
|
2238
|
+
browserless,
|
|
2239
|
+
agentSettleable,
|
|
2240
|
+
statusCommand,
|
|
2241
|
+
}),
|
|
2242
|
+
after_next: input.afterNext,
|
|
2243
|
+
auth: {
|
|
2244
|
+
token_source: input.tokenSource,
|
|
2245
|
+
secret_value_included: false,
|
|
2246
|
+
accepted_methods: ["IMAGE_SKILL_TOKEN", "--token-stdin", "config"],
|
|
2247
|
+
next_command: {
|
|
2248
|
+
requires_auth: true,
|
|
2249
|
+
reuse_current_auth_context: input.tokenSource,
|
|
2250
|
+
with_env: `IMAGE_SKILL_TOKEN="$IMAGE_SKILL_TOKEN" ${input.nextCommand}`,
|
|
2251
|
+
with_stdin: renderTokenStdinCommand(input.nextCommand),
|
|
2252
|
+
},
|
|
2253
|
+
},
|
|
2254
|
+
warning: agentSettleable
|
|
2255
|
+
? "data.self_fund_next_command starts a browserless live-money quote. Preserve auth with data.self_fund_handoff.auth.next_command, then follow payment_commands.buy, pay exactly what wallet_settlement points to, run payment_commands.status, and rerun after_next."
|
|
2256
|
+
: "data.self_fund_next_command starts a live-money payment handoff. Preserve auth with data.self_fund_handoff.auth.next_command, complete the payment, then rerun after_next.",
|
|
2257
|
+
};
|
|
2258
|
+
}
|
|
2259
|
+
|
|
2260
|
+
function createGuideWalletSettlementHandoff({
|
|
2261
|
+
preferredMethod,
|
|
2262
|
+
browserless,
|
|
2263
|
+
agentSettleable,
|
|
2264
|
+
statusCommand,
|
|
2265
|
+
}) {
|
|
2266
|
+
if (
|
|
2267
|
+
preferredMethod !== "stripe_x402.exact.usdc" ||
|
|
2268
|
+
!browserless ||
|
|
2269
|
+
!agentSettleable
|
|
2270
|
+
) {
|
|
2271
|
+
return null;
|
|
2272
|
+
}
|
|
2273
|
+
return {
|
|
2274
|
+
method_id: "stripe_x402.exact.usdc",
|
|
2275
|
+
wallet_required: true,
|
|
2276
|
+
browser_required: false,
|
|
2277
|
+
network: "base",
|
|
2278
|
+
token_currency: "usdc",
|
|
2279
|
+
exact_amount_required: true,
|
|
2280
|
+
secret_value_included: false,
|
|
2281
|
+
payable_instructions_fields: {
|
|
2282
|
+
buy_response: "data.stripe_x402.payable_instructions",
|
|
2283
|
+
status_response: "data.payment_attempt.stripe_x402.payable_instructions",
|
|
2284
|
+
},
|
|
2285
|
+
amount_atomic_field: "token_amount_atomic",
|
|
2286
|
+
destination_field: "deposit_address",
|
|
2287
|
+
status_command_after_payment: statusCommand,
|
|
2288
|
+
next_step:
|
|
2289
|
+
"Run payment_commands.buy, pay payable_instructions.token_amount_atomic USDC atomic units to payable_instructions.deposit_address on Base from a delegated wallet, then run status_command_after_payment until credits are granted before rerunning after_next.",
|
|
2290
|
+
credential_boundary:
|
|
2291
|
+
"Never send wallet private keys, seed phrases, x402 authorization payloads, Stripe secrets, client secrets, card data, provider receipts, or raw wallet credentials to Image Skill.",
|
|
2292
|
+
warning:
|
|
2293
|
+
"This is live money. Pay exactly the returned Base/USDC amount to the returned deposit address and stay within the delegated cap.",
|
|
2294
|
+
};
|
|
2295
|
+
}
|
|
2296
|
+
|
|
2297
|
+
function createGuideNextCommandEffect(stage, input) {
|
|
2298
|
+
const base = {
|
|
2299
|
+
label: "read_only_or_no_media_setup",
|
|
2300
|
+
no_spend: true,
|
|
2301
|
+
provider_call: false,
|
|
2302
|
+
hosted_create: false,
|
|
2303
|
+
hosted_signup: false,
|
|
2304
|
+
payment_object: false,
|
|
2305
|
+
credit_debit: false,
|
|
2306
|
+
media_write: false,
|
|
2307
|
+
estimated_credits: null,
|
|
2308
|
+
estimated_debit_usd_per_image: null,
|
|
2309
|
+
warning: null,
|
|
2310
|
+
};
|
|
2311
|
+
if (stage === "auth_required") {
|
|
2312
|
+
return {
|
|
2313
|
+
...base,
|
|
2314
|
+
label: "hosted_signup_restricted_agent_identity",
|
|
2315
|
+
hosted_signup: true,
|
|
2316
|
+
warning:
|
|
2317
|
+
"This signs up a restricted Image Skill agent identity but does not create media, call a provider, open payment, or debit credits.",
|
|
2318
|
+
};
|
|
2319
|
+
}
|
|
2320
|
+
if (stage === "quota_required") {
|
|
2321
|
+
return {
|
|
2322
|
+
...base,
|
|
2323
|
+
label: "payment_or_quota_action",
|
|
2324
|
+
no_spend: false,
|
|
2325
|
+
payment_object: true,
|
|
2326
|
+
warning:
|
|
2327
|
+
"This may create or inspect a payment quote/attempt. Stay within the delegated cap, or use escape_hatches for read-only checks.",
|
|
2328
|
+
};
|
|
2329
|
+
}
|
|
2330
|
+
if (stage === "ready_to_create") {
|
|
2331
|
+
return {
|
|
2332
|
+
label: "live_media_create_credit_debit",
|
|
2333
|
+
no_spend: false,
|
|
2334
|
+
provider_call: true,
|
|
2335
|
+
hosted_create: true,
|
|
2336
|
+
hosted_signup: false,
|
|
2337
|
+
payment_object: false,
|
|
2338
|
+
credit_debit: true,
|
|
2339
|
+
media_write: true,
|
|
2340
|
+
estimated_credits: input.estimatedCredits,
|
|
2341
|
+
estimated_debit_usd_per_image: input.estimatedDebitUsdPerImage,
|
|
2342
|
+
warning:
|
|
2343
|
+
"data.next_command creates hosted media and can debit credits. For no-spend verification, run data.recommended_no_spend_command (same value as data.no_spend_next_command) instead.",
|
|
2344
|
+
};
|
|
2345
|
+
}
|
|
2346
|
+
if (stage === "prompt_required") {
|
|
2347
|
+
return {
|
|
2348
|
+
...base,
|
|
2349
|
+
label: "rerun_guide_with_prompt",
|
|
2350
|
+
};
|
|
2351
|
+
}
|
|
2352
|
+
return base;
|
|
2353
|
+
}
|
|
2354
|
+
|
|
2355
|
+
function createGuideNoSpendNextCommandEffect(stage, input) {
|
|
2356
|
+
if (stage !== "ready_to_create") {
|
|
2357
|
+
return null;
|
|
2358
|
+
}
|
|
2359
|
+
return {
|
|
2360
|
+
label:
|
|
2361
|
+
"dry_run_planned_job_no_provider_call_no_credit_debit_no_media_write",
|
|
2362
|
+
no_spend: true,
|
|
2363
|
+
provider_call: false,
|
|
2364
|
+
hosted_create: false,
|
|
2365
|
+
hosted_create_dry_run: true,
|
|
2366
|
+
hosted_signup: false,
|
|
2367
|
+
payment_object: false,
|
|
2368
|
+
credit_debit: false,
|
|
2369
|
+
media_write: false,
|
|
2370
|
+
planned_job: true,
|
|
2371
|
+
plan_receipt: true,
|
|
2372
|
+
activity_event: "job.planned",
|
|
2373
|
+
estimated_credits: input.estimatedCredits,
|
|
2374
|
+
estimated_debit_usd_per_image: input.estimatedDebitUsdPerImage,
|
|
2375
|
+
warning:
|
|
2376
|
+
"data.no_spend_next_command may create a recoverable planned job/activity receipt (job.planned), but it does not call a provider, debit credits, or create downloadable media.",
|
|
2377
|
+
};
|
|
2378
|
+
}
|
|
2379
|
+
|
|
2380
|
+
function createGuideNoSpendEvaluation(stage, input) {
|
|
2381
|
+
if (stage !== "ready_to_create") {
|
|
2382
|
+
return {
|
|
2383
|
+
stop_here: false,
|
|
2384
|
+
stop_stage: "ready_to_create",
|
|
2385
|
+
stop_reason: null,
|
|
2386
|
+
next_command_is_live_create: false,
|
|
2387
|
+
live_create_command_field: null,
|
|
2388
|
+
live_create_allowed_when: null,
|
|
2389
|
+
recommended_command_field: null,
|
|
2390
|
+
recommended_command: null,
|
|
2391
|
+
recommended_command_label: null,
|
|
2392
|
+
recommended_command_effect: null,
|
|
2393
|
+
warning: null,
|
|
2394
|
+
};
|
|
2395
|
+
}
|
|
2396
|
+
return {
|
|
2397
|
+
stop_here: true,
|
|
2398
|
+
stop_stage: "ready_to_create",
|
|
2399
|
+
stop_reason:
|
|
2400
|
+
"ready_to_create means data.next_command is a live media create; no-spend evaluators should stop before it unless media spend is allowed.",
|
|
2401
|
+
next_command_is_live_create: true,
|
|
2402
|
+
live_create_command_field: "next_command",
|
|
2403
|
+
live_create_allowed_when: "media_spend_allowed",
|
|
2404
|
+
recommended_command_field: "recommended_no_spend_command",
|
|
2405
|
+
recommended_command: input.noSpendNextCommand,
|
|
2406
|
+
recommended_command_label: input.noSpendNextCommandLabel,
|
|
2407
|
+
recommended_command_effect: input.noSpendNextCommandEffect,
|
|
2408
|
+
warning:
|
|
2409
|
+
"For no-spend verification at ready_to_create, run data.recommended_no_spend_command instead of data.next_command.",
|
|
2410
|
+
};
|
|
2411
|
+
}
|
|
2412
|
+
|
|
2413
|
+
function createGuideWarning(stage, input) {
|
|
2414
|
+
const effect = input.nextCommandEffect;
|
|
2415
|
+
const base = {
|
|
2416
|
+
stage,
|
|
2417
|
+
no_spend_safe:
|
|
2418
|
+
effect.no_spend &&
|
|
2419
|
+
!effect.provider_call &&
|
|
2420
|
+
!effect.payment_object &&
|
|
2421
|
+
!effect.credit_debit &&
|
|
2422
|
+
!effect.media_write,
|
|
2423
|
+
live_money_action: false,
|
|
2424
|
+
spend_required: false,
|
|
2425
|
+
provider_call: effect.provider_call,
|
|
2426
|
+
payment_object: effect.payment_object,
|
|
2427
|
+
credit_debit: effect.credit_debit,
|
|
2428
|
+
media_write: effect.media_write,
|
|
2429
|
+
payment_top_up_path: null,
|
|
2430
|
+
};
|
|
2431
|
+
|
|
2432
|
+
if (stage === "prompt_required") {
|
|
2433
|
+
return {
|
|
2434
|
+
...base,
|
|
2435
|
+
next_command_safety: "rerun_guide_no_spend",
|
|
2436
|
+
recommended_command_field: "next_command",
|
|
2437
|
+
warning:
|
|
2438
|
+
"data.next_command reruns the free guide with a real prompt; it does not call a provider, open payment, debit credits, or create media.",
|
|
2439
|
+
};
|
|
2440
|
+
}
|
|
2441
|
+
if (stage === "no_executable_model" || stage === "service_unreachable") {
|
|
2442
|
+
return {
|
|
2443
|
+
...base,
|
|
2444
|
+
next_command_safety: "read_only_inspection_no_spend",
|
|
2445
|
+
recommended_command_field: "next_command",
|
|
2446
|
+
warning:
|
|
2447
|
+
"data.next_command is read-only inspection/recovery; it does not call a provider, open payment, debit credits, or create media.",
|
|
2448
|
+
};
|
|
2449
|
+
}
|
|
2450
|
+
if (stage === "auth_required") {
|
|
2451
|
+
return {
|
|
2452
|
+
...base,
|
|
2453
|
+
next_command_safety: "hosted_signup_no_spend_setup",
|
|
2454
|
+
recommended_command_field: "next_command",
|
|
2455
|
+
warning:
|
|
2456
|
+
"data.next_command is no-spend hosted signup/setup; it creates a restricted agent identity but does not call a provider, open payment, debit credits, or create media.",
|
|
2457
|
+
};
|
|
2458
|
+
}
|
|
2459
|
+
if (stage === "quota_required") {
|
|
2460
|
+
const paymentTopUpPath =
|
|
2461
|
+
input.paymentSummary.preferred_method_summary?.top_up_path ?? null;
|
|
2462
|
+
return {
|
|
2463
|
+
...base,
|
|
2464
|
+
next_command_safety: "live_money_payment_action",
|
|
2465
|
+
no_spend_safe: false,
|
|
2466
|
+
live_money_action: true,
|
|
2467
|
+
spend_required: true,
|
|
2468
|
+
recommended_command_field: "escape_hatches",
|
|
2469
|
+
payment_top_up_path: paymentTopUpPath,
|
|
2470
|
+
warning:
|
|
2471
|
+
paymentTopUpPath === "browserless_agent_self_fund"
|
|
2472
|
+
? "data.next_command starts the browserless live-money top-up path; stay within the delegated cap, or use data.escape_hatches.payment_methods for read-only payment inspection."
|
|
2473
|
+
: paymentTopUpPath === "human_payment_handoff"
|
|
2474
|
+
? "data.next_command starts a live-money payment handoff that needs human or browser completion; stay within the delegated cap, or use data.escape_hatches.payment_methods for read-only inspection."
|
|
2475
|
+
: "data.next_command starts payment or quota recovery; inspect data.checks.payments before attempting live money, or use data.escape_hatches.payment_methods for read-only inspection.",
|
|
2476
|
+
};
|
|
2477
|
+
}
|
|
2478
|
+
return {
|
|
2479
|
+
...base,
|
|
2480
|
+
next_command_safety: "live_media_create_credit_debit",
|
|
2481
|
+
no_spend_safe: false,
|
|
2482
|
+
spend_required: true,
|
|
2483
|
+
recommended_command_field: "recommended_no_spend_command",
|
|
2484
|
+
warning:
|
|
2485
|
+
"data.next_command is a live media create that can call a provider, debit credits, and create media. Run it only when media spend is allowed; otherwise run data.recommended_no_spend_command.",
|
|
2486
|
+
};
|
|
2487
|
+
}
|
|
2488
|
+
|
|
1726
2489
|
function createGuideNextCommand(stage, input) {
|
|
1727
2490
|
if (stage === "prompt_required") {
|
|
1728
2491
|
return renderGuideCommand("PROMPT", input.apiBaseUrl, input.commandPrefix);
|
|
@@ -1734,11 +2497,7 @@ function createGuideNextCommand(stage, input) {
|
|
|
1734
2497
|
);
|
|
1735
2498
|
}
|
|
1736
2499
|
if (stage === "auth_required") {
|
|
1737
|
-
|
|
1738
|
-
input.authConfigWritable === false
|
|
1739
|
-
? "signup --agent --agent-contact AGENT_OR_OPERATOR_INBOX --agent-name AGENT_NAME --runtime RUNTIME_NAME --show-token --no-save --json"
|
|
1740
|
-
: "signup --agent --agent-contact AGENT_OR_OPERATOR_INBOX --agent-name AGENT_NAME --runtime RUNTIME_NAME --json";
|
|
1741
|
-
return renderGuidePrefixedCommand(input.commandPrefix, signupCommand);
|
|
2500
|
+
return renderGuideSignupCommand(input);
|
|
1742
2501
|
}
|
|
1743
2502
|
if (stage === "quota_required") {
|
|
1744
2503
|
return renderGuidePrefixedCommand(
|
|
@@ -1748,12 +2507,23 @@ function createGuideNextCommand(stage, input) {
|
|
|
1748
2507
|
),
|
|
1749
2508
|
);
|
|
1750
2509
|
}
|
|
2510
|
+
if (createGuideSelectedModelRequiresInputImage(input.selected)) {
|
|
2511
|
+
return renderImageTo3dGuideCommand({
|
|
2512
|
+
modelId: input.selected.id,
|
|
2513
|
+
budgetGuard: input.budgetGuard,
|
|
2514
|
+
dryRun: false,
|
|
2515
|
+
idempotencyKey: `edit-guide-${Date.now()}-${randomBytes(4).toString("hex")}`,
|
|
2516
|
+
apiBaseUrl: input.apiBaseUrl,
|
|
2517
|
+
commandPrefix: input.commandPrefix,
|
|
2518
|
+
});
|
|
2519
|
+
}
|
|
1751
2520
|
return renderCreateCommand({
|
|
1752
2521
|
prompt: input.prompt,
|
|
1753
2522
|
modelId: input.selected.id,
|
|
1754
2523
|
providerId: input.requestedProviderId,
|
|
1755
2524
|
intent: input.requestedIntent,
|
|
1756
2525
|
budgetGuard: input.budgetGuard,
|
|
2526
|
+
aspectRatio: input.aspectRatio,
|
|
1757
2527
|
dryRun: false,
|
|
1758
2528
|
// Retry-safe by default (#1228): bake a stable idempotency key into the
|
|
1759
2529
|
// advertised create command so an agent that copies it and retries after a
|
|
@@ -1764,6 +2534,52 @@ function createGuideNextCommand(stage, input) {
|
|
|
1764
2534
|
});
|
|
1765
2535
|
}
|
|
1766
2536
|
|
|
2537
|
+
function createGuideEscapeHatches(input) {
|
|
2538
|
+
return {
|
|
2539
|
+
doctor: renderGuidePrefixedCommand(input.commandPrefix, "doctor --json"),
|
|
2540
|
+
model_inspection:
|
|
2541
|
+
input.selected === null
|
|
2542
|
+
? renderGuidePrefixedCommand(input.commandPrefix, "models list --json")
|
|
2543
|
+
: renderGuidePrefixedCommand(
|
|
2544
|
+
input.commandPrefix,
|
|
2545
|
+
`models show ${shellQuote(input.selected.id)} --json`,
|
|
2546
|
+
),
|
|
2547
|
+
payment_methods: renderGuidePrefixedCommand(
|
|
2548
|
+
input.commandPrefix,
|
|
2549
|
+
"credits methods --json",
|
|
2550
|
+
),
|
|
2551
|
+
quota: renderGuidePrefixedCommand(
|
|
2552
|
+
input.commandPrefix,
|
|
2553
|
+
"usage quota --json",
|
|
2554
|
+
),
|
|
2555
|
+
dry_run:
|
|
2556
|
+
input.selected === null || input.prompt.length === 0
|
|
2557
|
+
? renderGuidePrefixedCommand(
|
|
2558
|
+
input.commandPrefix,
|
|
2559
|
+
"create --dry-run --prompt PROMPT --json",
|
|
2560
|
+
)
|
|
2561
|
+
: createGuideSelectedModelRequiresInputImage(input.selected)
|
|
2562
|
+
? renderImageTo3dGuideCommand({
|
|
2563
|
+
modelId: input.selected.id,
|
|
2564
|
+
budgetGuard: input.budgetGuard,
|
|
2565
|
+
dryRun: true,
|
|
2566
|
+
apiBaseUrl: input.apiBaseUrl,
|
|
2567
|
+
commandPrefix: input.commandPrefix,
|
|
2568
|
+
})
|
|
2569
|
+
: renderCreateCommand({
|
|
2570
|
+
prompt: input.prompt,
|
|
2571
|
+
modelId: input.selected.id,
|
|
2572
|
+
providerId: input.requestedProviderId,
|
|
2573
|
+
intent: input.requestedIntent,
|
|
2574
|
+
budgetGuard: input.budgetGuard,
|
|
2575
|
+
aspectRatio: input.aspectRatio,
|
|
2576
|
+
dryRun: true,
|
|
2577
|
+
apiBaseUrl: input.apiBaseUrl,
|
|
2578
|
+
commandPrefix: input.commandPrefix,
|
|
2579
|
+
}),
|
|
2580
|
+
};
|
|
2581
|
+
}
|
|
2582
|
+
|
|
1767
2583
|
function renderGuideCommand(prompt, apiBaseUrl, commandPrefix = "image-skill") {
|
|
1768
2584
|
return [
|
|
1769
2585
|
commandPrefix,
|
|
@@ -1774,6 +2590,23 @@ function renderGuideCommand(prompt, apiBaseUrl, commandPrefix = "image-skill") {
|
|
|
1774
2590
|
].join(" ");
|
|
1775
2591
|
}
|
|
1776
2592
|
|
|
2593
|
+
function renderGuideSignupCommand(input) {
|
|
2594
|
+
const signupCommand = [
|
|
2595
|
+
"signup --agent --agent-contact AGENT_OR_OPERATOR_INBOX --agent-name AGENT_NAME --runtime RUNTIME_NAME",
|
|
2596
|
+
...(input.apiBaseUrl === null
|
|
2597
|
+
? []
|
|
2598
|
+
: ["--api-base-url", shellQuote(input.apiBaseUrl)]),
|
|
2599
|
+
"--json",
|
|
2600
|
+
].join(" ");
|
|
2601
|
+
const command = renderGuidePrefixedCommand(
|
|
2602
|
+
input.commandPrefix,
|
|
2603
|
+
signupCommand,
|
|
2604
|
+
);
|
|
2605
|
+
return input.authConfigWritable === false
|
|
2606
|
+
? renderWritableConfigCommand(command)
|
|
2607
|
+
: command;
|
|
2608
|
+
}
|
|
2609
|
+
|
|
1777
2610
|
function renderTokenStdinCommand(command) {
|
|
1778
2611
|
return `printf '%s\\n' "$IMAGE_SKILL_TOKEN" | ${command} --token-stdin`;
|
|
1779
2612
|
}
|
|
@@ -1788,6 +2621,37 @@ function firstPaymentActionCommand(commands) {
|
|
|
1788
2621
|
);
|
|
1789
2622
|
}
|
|
1790
2623
|
|
|
2624
|
+
function guidePaymentCommandByKind(commands, kind) {
|
|
2625
|
+
const pattern =
|
|
2626
|
+
kind === "quote"
|
|
2627
|
+
? /\bcredits\s+quote\b/
|
|
2628
|
+
: kind === "buy"
|
|
2629
|
+
? /\bcredits\s+buy\b/
|
|
2630
|
+
: /\bcredits\s+status\b/;
|
|
2631
|
+
return commands.find((command) => pattern.test(command)) ?? null;
|
|
2632
|
+
}
|
|
2633
|
+
|
|
2634
|
+
function renderImageTo3dGuideCommand(input) {
|
|
2635
|
+
return [
|
|
2636
|
+
input.commandPrefix ?? "image-skill",
|
|
2637
|
+
"edit",
|
|
2638
|
+
...(input.dryRun ? ["--dry-run"] : []),
|
|
2639
|
+
"--input",
|
|
2640
|
+
"image_...",
|
|
2641
|
+
"--model",
|
|
2642
|
+
shellQuote(input.modelId),
|
|
2643
|
+
"--max-estimated-usd-per-image",
|
|
2644
|
+
shellQuote(formatUsd(input.budgetGuard)),
|
|
2645
|
+
...(input.idempotencyKey === undefined || input.idempotencyKey === null
|
|
2646
|
+
? []
|
|
2647
|
+
: ["--idempotency-key", shellQuote(input.idempotencyKey)]),
|
|
2648
|
+
...(input.apiBaseUrl === null
|
|
2649
|
+
? []
|
|
2650
|
+
: ["--api-base-url", shellQuote(input.apiBaseUrl)]),
|
|
2651
|
+
"--json",
|
|
2652
|
+
].join(" ");
|
|
2653
|
+
}
|
|
2654
|
+
|
|
1791
2655
|
function renderCreateCommand(input) {
|
|
1792
2656
|
return [
|
|
1793
2657
|
input.commandPrefix ?? "image-skill",
|
|
@@ -1802,6 +2666,9 @@ function renderCreateCommand(input) {
|
|
|
1802
2666
|
shellQuote(input.prompt),
|
|
1803
2667
|
"--intent",
|
|
1804
2668
|
shellQuote(input.intent),
|
|
2669
|
+
...(input.aspectRatio === null || input.aspectRatio === undefined
|
|
2670
|
+
? []
|
|
2671
|
+
: ["--aspect-ratio", shellQuote(input.aspectRatio)]),
|
|
1805
2672
|
"--max-estimated-usd-per-image",
|
|
1806
2673
|
shellQuote(formatUsd(input.budgetGuard)),
|
|
1807
2674
|
...(input.idempotencyKey === undefined || input.idempotencyKey === null
|
|
@@ -1818,6 +2685,10 @@ function renderGuidePrefixedCommand(commandPrefix, command) {
|
|
|
1818
2685
|
return `${commandPrefix} ${stripImageSkillCommandPrefix(command)}`;
|
|
1819
2686
|
}
|
|
1820
2687
|
|
|
2688
|
+
function renderWritableConfigCommand(command) {
|
|
2689
|
+
return `IMAGE_SKILL_CONFIG_PATH="${LOCAL_WRITABLE_CONFIG_PATH}" ${command}`;
|
|
2690
|
+
}
|
|
2691
|
+
|
|
1821
2692
|
function stripImageSkillCommandPrefix(command) {
|
|
1822
2693
|
return String(command ?? "").replace(/^image-skill\s+/, "");
|
|
1823
2694
|
}
|
|
@@ -2043,6 +2914,7 @@ async function edit(argv) {
|
|
|
2043
2914
|
...(modelParameters.value === null
|
|
2044
2915
|
? {}
|
|
2045
2916
|
: { model_parameters: modelParameters.value }),
|
|
2917
|
+
...(flagBool(args, "dry-run") ? { dry_run: true } : {}),
|
|
2046
2918
|
// Retry-safe dedupe (#1228): see create — same key dedupes a retry that
|
|
2047
2919
|
// follows a transient 502 which already debited a credit.
|
|
2048
2920
|
...(flagString(args, "idempotency-key") === null
|
|
@@ -2951,20 +3823,19 @@ function trustSafeCommands() {
|
|
|
2951
3823
|
return [
|
|
2952
3824
|
{
|
|
2953
3825
|
purpose: "trust_packet",
|
|
2954
|
-
command:
|
|
3826
|
+
command: `${PUBLIC_NPX_COMMAND_PREFIX} trust --json`,
|
|
2955
3827
|
mutation: false,
|
|
2956
3828
|
spend: false,
|
|
2957
3829
|
},
|
|
2958
3830
|
{
|
|
2959
3831
|
purpose: "first_image_guide",
|
|
2960
|
-
command:
|
|
2961
|
-
'npx -y image-skill@latest create --guide --prompt "a compact field camera on a stainless workbench" --json',
|
|
3832
|
+
command: `${PUBLIC_NPX_COMMAND_PREFIX} create --guide --prompt "a compact field camera on a stainless workbench" --json`,
|
|
2962
3833
|
mutation: false,
|
|
2963
3834
|
spend: false,
|
|
2964
3835
|
},
|
|
2965
3836
|
{
|
|
2966
3837
|
purpose: "model_inspection",
|
|
2967
|
-
command:
|
|
3838
|
+
command: `${PUBLIC_NPX_COMMAND_PREFIX} models list --json`,
|
|
2968
3839
|
mutation: false,
|
|
2969
3840
|
spend: false,
|
|
2970
3841
|
},
|
|
@@ -3582,19 +4453,22 @@ function configWriteErrorMessage(error) {
|
|
|
3582
4453
|
}
|
|
3583
4454
|
|
|
3584
4455
|
function configWriteRecovery(command) {
|
|
3585
|
-
const
|
|
3586
|
-
|
|
4456
|
+
const baseSignupCommand = renderWritableConfigCommand(
|
|
4457
|
+
SIGNUP_SUGGESTED_COMMAND,
|
|
4458
|
+
);
|
|
3587
4459
|
if (command === "image-skill auth save") {
|
|
3588
4460
|
return {
|
|
3589
4461
|
config_path_env: "IMAGE_SKILL_CONFIG_PATH",
|
|
3590
|
-
suggested_config_path:
|
|
3591
|
-
suggested_command:
|
|
4462
|
+
suggested_config_path: LOCAL_WRITABLE_CONFIG_PATH,
|
|
4463
|
+
suggested_command: renderWritableConfigCommand(
|
|
4464
|
+
"image-skill auth save --json",
|
|
4465
|
+
),
|
|
3592
4466
|
docs_url: "https://image-skill.com/cli.md#local-config-and-install",
|
|
3593
4467
|
};
|
|
3594
4468
|
}
|
|
3595
4469
|
return {
|
|
3596
4470
|
config_path_env: "IMAGE_SKILL_CONFIG_PATH",
|
|
3597
|
-
suggested_config_path:
|
|
4471
|
+
suggested_config_path: LOCAL_WRITABLE_CONFIG_PATH,
|
|
3598
4472
|
suggested_command: baseSignupCommand,
|
|
3599
4473
|
fallback_command: `${SIGNUP_SUGGESTED_COMMAND} --show-token --no-save`,
|
|
3600
4474
|
fallback_auth_method: "--token-stdin",
|