image-skill 0.1.28 → 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 +38 -0
- package/CONTRIBUTING.md +1 -1
- package/PROVENANCE.md +1 -1
- package/README.md +36 -10
- package/SECURITY.md +1 -1
- package/bin/image-skill.mjs +851 -54
- package/cli.md +235 -64
- package/llms.txt +18 -13
- package/package.json +1 -1
- package/skill.md +226 -565
- package/skills/ai-audio-generation/SKILL.md +16 -3
- package/skills/ai-image-generation/SKILL.md +16 -3
- package/skills/ai-video-generation/SKILL.md +16 -3
- package/skills/creative-media/SKILL.md +16 -3
- package/skills/image-edit/SKILL.md +16 -3
- package/skills/image-generation/SKILL.md +78 -0
- package/skills/image-skill/SKILL.md +226 -565
- package/skills/image-skill/references/cli.md +235 -64
- package/skills/image-skill/references/llms.txt +18 -13
- package/skills/image-to-3d/SKILL.md +16 -3
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,6 +1483,7 @@ 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,
|
|
@@ -1344,6 +1495,7 @@ async function createGuide(args) {
|
|
|
1344
1495
|
requestedProviderId,
|
|
1345
1496
|
requestedIntent,
|
|
1346
1497
|
budgetGuard,
|
|
1498
|
+
aspectRatio: selectedAspectRatio,
|
|
1347
1499
|
apiBaseUrl: explicitApiBaseUrl(args),
|
|
1348
1500
|
commandPrefix: PUBLIC_NPX_COMMAND_PREFIX,
|
|
1349
1501
|
});
|
|
@@ -1353,6 +1505,28 @@ async function createGuide(args) {
|
|
|
1353
1505
|
});
|
|
1354
1506
|
const noSpendNextCommand =
|
|
1355
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
|
+
);
|
|
1356
1530
|
const afterNext =
|
|
1357
1531
|
stage === "auth_required" || stage === "quota_required"
|
|
1358
1532
|
? renderGuideCommand(
|
|
@@ -1367,7 +1541,18 @@ async function createGuide(args) {
|
|
|
1367
1541
|
afterNext,
|
|
1368
1542
|
authConfigWrite,
|
|
1369
1543
|
});
|
|
1370
|
-
|
|
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, {
|
|
1371
1556
|
schema: "image-skill.create-guide.v1",
|
|
1372
1557
|
ready: stage === "ready_to_create",
|
|
1373
1558
|
stage,
|
|
@@ -1379,8 +1564,8 @@ async function createGuide(args) {
|
|
|
1379
1564
|
error_code: health.envelope.error?.code ?? null,
|
|
1380
1565
|
},
|
|
1381
1566
|
auth: {
|
|
1382
|
-
source:
|
|
1383
|
-
authenticated
|
|
1567
|
+
source: publicTokenSource,
|
|
1568
|
+
authenticated,
|
|
1384
1569
|
claim_state: quota?.envelope.data?.claim_state ?? null,
|
|
1385
1570
|
token_status: quota?.envelope.data?.token_status ?? null,
|
|
1386
1571
|
saved_config_path: configPath(),
|
|
@@ -1419,14 +1604,24 @@ async function createGuide(args) {
|
|
|
1419
1604
|
selected === null
|
|
1420
1605
|
? null
|
|
1421
1606
|
: {
|
|
1422
|
-
operation:
|
|
1607
|
+
operation: createGuideSelectedModelRequiresInputImage(selected)
|
|
1608
|
+
? "edit"
|
|
1609
|
+
: "create",
|
|
1423
1610
|
model_id: selected.id,
|
|
1424
1611
|
model_status: selected.status,
|
|
1425
1612
|
model_execution_status: selected.execution.model_execution_status,
|
|
1613
|
+
modality: selected.modality ?? null,
|
|
1614
|
+
suggested_aspect_ratio: selectedAspectRatio,
|
|
1426
1615
|
reason:
|
|
1427
1616
|
requestedModelId === null
|
|
1428
|
-
?
|
|
1429
|
-
|
|
1617
|
+
? createGuideSelectionReason(
|
|
1618
|
+
selected,
|
|
1619
|
+
trimmedPrompt,
|
|
1620
|
+
requestedIntent,
|
|
1621
|
+
)
|
|
1622
|
+
: createGuideSelectedModelRequiresInputImage(selected)
|
|
1623
|
+
? "requested executable image-to-3D model"
|
|
1624
|
+
: "requested executable create model",
|
|
1430
1625
|
},
|
|
1431
1626
|
cost: {
|
|
1432
1627
|
estimated_credits: estimatedCredits,
|
|
@@ -1437,13 +1632,20 @@ async function createGuide(args) {
|
|
|
1437
1632
|
pricing_confidence: pricing?.pricing_confidence ?? null,
|
|
1438
1633
|
},
|
|
1439
1634
|
blocker,
|
|
1635
|
+
guide_warning: guideWarning,
|
|
1636
|
+
auth_ready: authReady,
|
|
1440
1637
|
next_command: nextCommand,
|
|
1441
1638
|
next_command_effect: nextCommandEffect,
|
|
1442
1639
|
no_spend_next_command: noSpendNextCommand,
|
|
1443
|
-
no_spend_next_command_label:
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
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,
|
|
1447
1649
|
after_next: afterNext,
|
|
1448
1650
|
auth_handoff: authHandoff,
|
|
1449
1651
|
escape_hatches: escapeHatches,
|
|
@@ -1458,31 +1660,126 @@ async function createGuide(args) {
|
|
|
1458
1660
|
});
|
|
1459
1661
|
}
|
|
1460
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
|
+
|
|
1461
1669
|
function selectCreateGuideModel(
|
|
1462
1670
|
models,
|
|
1463
1671
|
requestedModelId,
|
|
1464
|
-
{ maxEstimatedUsdPerImage = null } = {},
|
|
1672
|
+
{ prompt = "", intent = undefined, maxEstimatedUsdPerImage = null } = {},
|
|
1465
1673
|
) {
|
|
1466
1674
|
const isExecutableCreate = (model) =>
|
|
1467
1675
|
model?.status === "available" &&
|
|
1468
1676
|
model?.execution?.model_execution_status === "executable" &&
|
|
1469
1677
|
Array.isArray(model?.supports) &&
|
|
1470
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);
|
|
1471
1688
|
if (requestedModelId !== null) {
|
|
1472
1689
|
const requested = models.find((model) => model.id === requestedModelId);
|
|
1473
|
-
return requested !== undefined &&
|
|
1690
|
+
return requested !== undefined && isExecutableGuideModel(requested)
|
|
1474
1691
|
? requested
|
|
1475
1692
|
: null;
|
|
1476
1693
|
}
|
|
1477
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
|
+
}) {
|
|
1478
1735
|
if (maxEstimatedUsdPerImage === null) {
|
|
1479
|
-
return candidates
|
|
1736
|
+
return candidates;
|
|
1480
1737
|
}
|
|
1481
1738
|
const capped = candidates.filter((model) => {
|
|
1482
1739
|
const estimatedUsd = guideBudgetUsdForModel(model);
|
|
1483
1740
|
return estimatedUsd === null || estimatedUsd <= maxEstimatedUsdPerImage;
|
|
1484
1741
|
});
|
|
1485
|
-
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
|
+
];
|
|
1486
1783
|
}
|
|
1487
1784
|
|
|
1488
1785
|
function guideBudgetUsdForModel(model) {
|
|
@@ -1496,6 +1793,81 @@ function guideBudgetUsdForModel(model) {
|
|
|
1496
1793
|
);
|
|
1497
1794
|
}
|
|
1498
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
|
+
|
|
1499
1871
|
function createGuidePaymentSummary(data) {
|
|
1500
1872
|
const methods = Array.isArray(data?.methods)
|
|
1501
1873
|
? data.methods.filter((method) => method.live_money)
|
|
@@ -1544,6 +1916,10 @@ function createGuidePaymentSummary(data) {
|
|
|
1544
1916
|
(method) => method.method_id,
|
|
1545
1917
|
),
|
|
1546
1918
|
preferred_method: preferredMethod?.method_id ?? null,
|
|
1919
|
+
preferred_method_summary:
|
|
1920
|
+
preferredMethod === undefined
|
|
1921
|
+
? null
|
|
1922
|
+
: createGuidePreferredPaymentSummary(preferredMethod),
|
|
1547
1923
|
buyer_modes: [
|
|
1548
1924
|
...new Set(methods.flatMap((method) => method.buyer_modes ?? [])),
|
|
1549
1925
|
],
|
|
@@ -1554,6 +1930,64 @@ function createGuidePaymentSummary(data) {
|
|
|
1554
1930
|
};
|
|
1555
1931
|
}
|
|
1556
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
|
+
|
|
1557
1991
|
function createGuidePaymentCommands(preferredMethod, fallbackMethods) {
|
|
1558
1992
|
const commands = [
|
|
1559
1993
|
"image-skill credits methods --json",
|
|
@@ -1658,6 +2092,10 @@ function createGuideBlocker(stage, input) {
|
|
|
1658
2092
|
function createGuideAuthHandoff(stage, input) {
|
|
1659
2093
|
if (stage === "auth_required") {
|
|
1660
2094
|
const authConfigWritable = input.authConfigWrite?.ok ?? true;
|
|
2095
|
+
const recovery =
|
|
2096
|
+
input.authConfigWrite?.ok === false
|
|
2097
|
+
? configWriteRecovery("image-skill create --guide")
|
|
2098
|
+
: null;
|
|
1661
2099
|
return {
|
|
1662
2100
|
required: true,
|
|
1663
2101
|
token_source: "none",
|
|
@@ -1665,16 +2103,21 @@ function createGuideAuthHandoff(stage, input) {
|
|
|
1665
2103
|
accepted_methods: ["IMAGE_SKILL_TOKEN", "--token-stdin", "config"],
|
|
1666
2104
|
signup: {
|
|
1667
2105
|
returns_token_once: true,
|
|
1668
|
-
public_cli_saves_config:
|
|
2106
|
+
public_cli_saves_config: true,
|
|
1669
2107
|
store_token_in: authConfigWritable
|
|
1670
2108
|
? "public_cli_config_by_default"
|
|
1671
|
-
: "
|
|
2109
|
+
: "public_cli_config_after_setting_IMAGE_SKILL_CONFIG_PATH",
|
|
1672
2110
|
config_path: configPath(),
|
|
1673
2111
|
config_writable: authConfigWritable,
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
?
|
|
1677
|
-
:
|
|
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,
|
|
1678
2121
|
},
|
|
1679
2122
|
rerun_guide:
|
|
1680
2123
|
input.afterNext === null
|
|
@@ -1686,7 +2129,7 @@ function createGuideAuthHandoff(stage, input) {
|
|
|
1686
2129
|
next_command: null,
|
|
1687
2130
|
};
|
|
1688
2131
|
}
|
|
1689
|
-
if (stage === "ready_to_create") {
|
|
2132
|
+
if (stage === "quota_required" || stage === "ready_to_create") {
|
|
1690
2133
|
return {
|
|
1691
2134
|
required: true,
|
|
1692
2135
|
token_source: input.tokenSource,
|
|
@@ -1705,6 +2148,152 @@ function createGuideAuthHandoff(stage, input) {
|
|
|
1705
2148
|
return null;
|
|
1706
2149
|
}
|
|
1707
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
|
+
|
|
1708
2297
|
function createGuideNextCommandEffect(stage, input) {
|
|
1709
2298
|
const base = {
|
|
1710
2299
|
label: "read_only_or_no_media_setup",
|
|
@@ -1751,7 +2340,7 @@ function createGuideNextCommandEffect(stage, input) {
|
|
|
1751
2340
|
estimated_credits: input.estimatedCredits,
|
|
1752
2341
|
estimated_debit_usd_per_image: input.estimatedDebitUsdPerImage,
|
|
1753
2342
|
warning:
|
|
1754
|
-
"data.next_command creates hosted media and can debit credits. For no-spend verification, run data.no_spend_next_command instead.",
|
|
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.",
|
|
1755
2344
|
};
|
|
1756
2345
|
}
|
|
1757
2346
|
if (stage === "prompt_required") {
|
|
@@ -1763,6 +2352,140 @@ function createGuideNextCommandEffect(stage, input) {
|
|
|
1763
2352
|
return base;
|
|
1764
2353
|
}
|
|
1765
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
|
+
|
|
1766
2489
|
function createGuideNextCommand(stage, input) {
|
|
1767
2490
|
if (stage === "prompt_required") {
|
|
1768
2491
|
return renderGuideCommand("PROMPT", input.apiBaseUrl, input.commandPrefix);
|
|
@@ -1774,11 +2497,7 @@ function createGuideNextCommand(stage, input) {
|
|
|
1774
2497
|
);
|
|
1775
2498
|
}
|
|
1776
2499
|
if (stage === "auth_required") {
|
|
1777
|
-
|
|
1778
|
-
input.authConfigWritable === false
|
|
1779
|
-
? "signup --agent --agent-contact AGENT_OR_OPERATOR_INBOX --agent-name AGENT_NAME --runtime RUNTIME_NAME --show-token --no-save --json"
|
|
1780
|
-
: "signup --agent --agent-contact AGENT_OR_OPERATOR_INBOX --agent-name AGENT_NAME --runtime RUNTIME_NAME --json";
|
|
1781
|
-
return renderGuidePrefixedCommand(input.commandPrefix, signupCommand);
|
|
2500
|
+
return renderGuideSignupCommand(input);
|
|
1782
2501
|
}
|
|
1783
2502
|
if (stage === "quota_required") {
|
|
1784
2503
|
return renderGuidePrefixedCommand(
|
|
@@ -1788,12 +2507,23 @@ function createGuideNextCommand(stage, input) {
|
|
|
1788
2507
|
),
|
|
1789
2508
|
);
|
|
1790
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
|
+
}
|
|
1791
2520
|
return renderCreateCommand({
|
|
1792
2521
|
prompt: input.prompt,
|
|
1793
2522
|
modelId: input.selected.id,
|
|
1794
2523
|
providerId: input.requestedProviderId,
|
|
1795
2524
|
intent: input.requestedIntent,
|
|
1796
2525
|
budgetGuard: input.budgetGuard,
|
|
2526
|
+
aspectRatio: input.aspectRatio,
|
|
1797
2527
|
dryRun: false,
|
|
1798
2528
|
// Retry-safe by default (#1228): bake a stable idempotency key into the
|
|
1799
2529
|
// advertised create command so an agent that copies it and retries after a
|
|
@@ -1828,16 +2558,25 @@ function createGuideEscapeHatches(input) {
|
|
|
1828
2558
|
input.commandPrefix,
|
|
1829
2559
|
"create --dry-run --prompt PROMPT --json",
|
|
1830
2560
|
)
|
|
1831
|
-
:
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
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
|
+
}),
|
|
1841
2580
|
};
|
|
1842
2581
|
}
|
|
1843
2582
|
|
|
@@ -1851,6 +2590,23 @@ function renderGuideCommand(prompt, apiBaseUrl, commandPrefix = "image-skill") {
|
|
|
1851
2590
|
].join(" ");
|
|
1852
2591
|
}
|
|
1853
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
|
+
|
|
1854
2610
|
function renderTokenStdinCommand(command) {
|
|
1855
2611
|
return `printf '%s\\n' "$IMAGE_SKILL_TOKEN" | ${command} --token-stdin`;
|
|
1856
2612
|
}
|
|
@@ -1865,6 +2621,37 @@ function firstPaymentActionCommand(commands) {
|
|
|
1865
2621
|
);
|
|
1866
2622
|
}
|
|
1867
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
|
+
|
|
1868
2655
|
function renderCreateCommand(input) {
|
|
1869
2656
|
return [
|
|
1870
2657
|
input.commandPrefix ?? "image-skill",
|
|
@@ -1879,6 +2666,9 @@ function renderCreateCommand(input) {
|
|
|
1879
2666
|
shellQuote(input.prompt),
|
|
1880
2667
|
"--intent",
|
|
1881
2668
|
shellQuote(input.intent),
|
|
2669
|
+
...(input.aspectRatio === null || input.aspectRatio === undefined
|
|
2670
|
+
? []
|
|
2671
|
+
: ["--aspect-ratio", shellQuote(input.aspectRatio)]),
|
|
1882
2672
|
"--max-estimated-usd-per-image",
|
|
1883
2673
|
shellQuote(formatUsd(input.budgetGuard)),
|
|
1884
2674
|
...(input.idempotencyKey === undefined || input.idempotencyKey === null
|
|
@@ -1895,6 +2685,10 @@ function renderGuidePrefixedCommand(commandPrefix, command) {
|
|
|
1895
2685
|
return `${commandPrefix} ${stripImageSkillCommandPrefix(command)}`;
|
|
1896
2686
|
}
|
|
1897
2687
|
|
|
2688
|
+
function renderWritableConfigCommand(command) {
|
|
2689
|
+
return `IMAGE_SKILL_CONFIG_PATH="${LOCAL_WRITABLE_CONFIG_PATH}" ${command}`;
|
|
2690
|
+
}
|
|
2691
|
+
|
|
1898
2692
|
function stripImageSkillCommandPrefix(command) {
|
|
1899
2693
|
return String(command ?? "").replace(/^image-skill\s+/, "");
|
|
1900
2694
|
}
|
|
@@ -2120,6 +2914,7 @@ async function edit(argv) {
|
|
|
2120
2914
|
...(modelParameters.value === null
|
|
2121
2915
|
? {}
|
|
2122
2916
|
: { model_parameters: modelParameters.value }),
|
|
2917
|
+
...(flagBool(args, "dry-run") ? { dry_run: true } : {}),
|
|
2123
2918
|
// Retry-safe dedupe (#1228): see create — same key dedupes a retry that
|
|
2124
2919
|
// follows a transient 502 which already debited a credit.
|
|
2125
2920
|
...(flagString(args, "idempotency-key") === null
|
|
@@ -3028,20 +3823,19 @@ function trustSafeCommands() {
|
|
|
3028
3823
|
return [
|
|
3029
3824
|
{
|
|
3030
3825
|
purpose: "trust_packet",
|
|
3031
|
-
command:
|
|
3826
|
+
command: `${PUBLIC_NPX_COMMAND_PREFIX} trust --json`,
|
|
3032
3827
|
mutation: false,
|
|
3033
3828
|
spend: false,
|
|
3034
3829
|
},
|
|
3035
3830
|
{
|
|
3036
3831
|
purpose: "first_image_guide",
|
|
3037
|
-
command:
|
|
3038
|
-
'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`,
|
|
3039
3833
|
mutation: false,
|
|
3040
3834
|
spend: false,
|
|
3041
3835
|
},
|
|
3042
3836
|
{
|
|
3043
3837
|
purpose: "model_inspection",
|
|
3044
|
-
command:
|
|
3838
|
+
command: `${PUBLIC_NPX_COMMAND_PREFIX} models list --json`,
|
|
3045
3839
|
mutation: false,
|
|
3046
3840
|
spend: false,
|
|
3047
3841
|
},
|
|
@@ -3659,19 +4453,22 @@ function configWriteErrorMessage(error) {
|
|
|
3659
4453
|
}
|
|
3660
4454
|
|
|
3661
4455
|
function configWriteRecovery(command) {
|
|
3662
|
-
const
|
|
3663
|
-
|
|
4456
|
+
const baseSignupCommand = renderWritableConfigCommand(
|
|
4457
|
+
SIGNUP_SUGGESTED_COMMAND,
|
|
4458
|
+
);
|
|
3664
4459
|
if (command === "image-skill auth save") {
|
|
3665
4460
|
return {
|
|
3666
4461
|
config_path_env: "IMAGE_SKILL_CONFIG_PATH",
|
|
3667
|
-
suggested_config_path:
|
|
3668
|
-
suggested_command:
|
|
4462
|
+
suggested_config_path: LOCAL_WRITABLE_CONFIG_PATH,
|
|
4463
|
+
suggested_command: renderWritableConfigCommand(
|
|
4464
|
+
"image-skill auth save --json",
|
|
4465
|
+
),
|
|
3669
4466
|
docs_url: "https://image-skill.com/cli.md#local-config-and-install",
|
|
3670
4467
|
};
|
|
3671
4468
|
}
|
|
3672
4469
|
return {
|
|
3673
4470
|
config_path_env: "IMAGE_SKILL_CONFIG_PATH",
|
|
3674
|
-
suggested_config_path:
|
|
4471
|
+
suggested_config_path: LOCAL_WRITABLE_CONFIG_PATH,
|
|
3675
4472
|
suggested_command: baseSignupCommand,
|
|
3676
4473
|
fallback_command: `${SIGNUP_SUGGESTED_COMMAND} --show-token --no-save`,
|
|
3677
4474
|
fallback_auth_method: "--token-stdin",
|