@clickraft/cli 0.3.0 → 0.5.0
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 +2 -2
- package/README.md +22 -0
- package/dist/cli.js +480 -141
- package/dist/cli.js.map +1 -1
- package/dist/index.js +480 -141
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -285,6 +285,55 @@ var EXIT_CODE_MAP = {
|
|
|
285
285
|
retryable: false,
|
|
286
286
|
hint: "No such profile. Use `clickraft auth profiles` to list available profiles."
|
|
287
287
|
},
|
|
288
|
+
// --- 8 brand model resolution codes -----------------------------------------
|
|
289
|
+
BRAND_MODEL_NOT_FOUND: {
|
|
290
|
+
exitCode: 1,
|
|
291
|
+
category: "runtime",
|
|
292
|
+
retryable: false,
|
|
293
|
+
hint: "No brand model with that ID. Run `clickraft brand-model list`."
|
|
294
|
+
},
|
|
295
|
+
BRAND_MODEL_NOT_A_MODEL: {
|
|
296
|
+
exitCode: 1,
|
|
297
|
+
category: "runtime",
|
|
298
|
+
retryable: false,
|
|
299
|
+
hint: "The specified asset is not a brand model."
|
|
300
|
+
},
|
|
301
|
+
BRAND_MODEL_NOT_ACTIVE: {
|
|
302
|
+
exitCode: 1,
|
|
303
|
+
category: "runtime",
|
|
304
|
+
retryable: false,
|
|
305
|
+
hint: "Brand model is not active. Check its status in the dashboard."
|
|
306
|
+
},
|
|
307
|
+
BRAND_MODEL_NO_REFERENCES: {
|
|
308
|
+
exitCode: 1,
|
|
309
|
+
category: "runtime",
|
|
310
|
+
retryable: false,
|
|
311
|
+
hint: "Brand model has no reference images. Upload references first."
|
|
312
|
+
},
|
|
313
|
+
BRAND_MODEL_POSE_NOT_FOUND: {
|
|
314
|
+
exitCode: 1,
|
|
315
|
+
category: "runtime",
|
|
316
|
+
retryable: false,
|
|
317
|
+
hint: "Requested pose not found. Valid: front, 3/4-right, right, left, 3/4-left, back, approved."
|
|
318
|
+
},
|
|
319
|
+
BRAND_MODEL_DUPLICATE_ID: {
|
|
320
|
+
exitCode: 2,
|
|
321
|
+
category: "usage",
|
|
322
|
+
retryable: false,
|
|
323
|
+
hint: "Same brand model ID appears more than once."
|
|
324
|
+
},
|
|
325
|
+
MODEL_DOES_NOT_SUPPORT_REFERENCES: {
|
|
326
|
+
exitCode: 2,
|
|
327
|
+
category: "usage",
|
|
328
|
+
retryable: false,
|
|
329
|
+
hint: "This model does not support brand model references."
|
|
330
|
+
},
|
|
331
|
+
REFERENCE_LIMIT_EXCEEDED: {
|
|
332
|
+
exitCode: 2,
|
|
333
|
+
category: "usage",
|
|
334
|
+
retryable: false,
|
|
335
|
+
hint: "Too many reference images. Check model limits."
|
|
336
|
+
},
|
|
288
337
|
// --- 4 CLI-synthetic codes --------------------------------------------------
|
|
289
338
|
NETWORK_ERROR: {
|
|
290
339
|
exitCode: 6,
|
|
@@ -697,7 +746,8 @@ function apiErrorFromServerBody(args) {
|
|
|
697
746
|
requestId: error.correlationId ?? args.requestId,
|
|
698
747
|
retryable,
|
|
699
748
|
retryAfterMs,
|
|
700
|
-
redactedBody: args.redactedBody
|
|
749
|
+
redactedBody: args.redactedBody,
|
|
750
|
+
details: error.details
|
|
701
751
|
});
|
|
702
752
|
}
|
|
703
753
|
function parseRetryAfterHeader(headerValue) {
|
|
@@ -826,7 +876,8 @@ function errorToEnvelopePayload(err) {
|
|
|
826
876
|
message: err.message,
|
|
827
877
|
retryable: err.meta.retryable,
|
|
828
878
|
retryAfterMs: err.meta.retryAfterMs,
|
|
829
|
-
requestId: err.meta.requestId
|
|
879
|
+
requestId: err.meta.requestId,
|
|
880
|
+
details: err.meta.details
|
|
830
881
|
});
|
|
831
882
|
}
|
|
832
883
|
if (err instanceof AuthError || err instanceof CredentialsError) {
|
|
@@ -855,6 +906,7 @@ function buildPayload(args) {
|
|
|
855
906
|
if (typeof args.retryAfterMs === "number") payload.retry_after_ms = args.retryAfterMs;
|
|
856
907
|
if (args.requestId) payload.request_id = args.requestId;
|
|
857
908
|
if (mapping?.hint) payload.hint = mapping.hint;
|
|
909
|
+
if (args.details != null) payload.details = args.details;
|
|
858
910
|
return payload;
|
|
859
911
|
}
|
|
860
912
|
|
|
@@ -1736,7 +1788,15 @@ function buildRequestBody(args) {
|
|
|
1736
1788
|
if (args.aspectRatio !== void 0) input.aspectRatio = args.aspectRatio;
|
|
1737
1789
|
if (args.resolution !== void 0) input.resolution = args.resolution;
|
|
1738
1790
|
if (args.durationSeconds !== void 0) input.durationSeconds = args.durationSeconds;
|
|
1739
|
-
if (args.
|
|
1791
|
+
if (args.brandModels !== void 0 && args.brandModels.length > 0) {
|
|
1792
|
+
input.providerParams = {
|
|
1793
|
+
brandModels: args.brandModels.map((spec) => {
|
|
1794
|
+
const entry = { id: spec.id };
|
|
1795
|
+
if (spec.imageType) entry.imageType = spec.imageType;
|
|
1796
|
+
return entry;
|
|
1797
|
+
})
|
|
1798
|
+
};
|
|
1799
|
+
}
|
|
1740
1800
|
const body = {
|
|
1741
1801
|
modelSlug: args.modelSlug,
|
|
1742
1802
|
input
|
|
@@ -1773,6 +1833,152 @@ function projectCreateToResult(response, modelSlug) {
|
|
|
1773
1833
|
};
|
|
1774
1834
|
}
|
|
1775
1835
|
|
|
1836
|
+
// src/cli/args.ts
|
|
1837
|
+
var ArgError = class extends Error {
|
|
1838
|
+
constructor(message) {
|
|
1839
|
+
super(message);
|
|
1840
|
+
this.name = "ArgError";
|
|
1841
|
+
}
|
|
1842
|
+
};
|
|
1843
|
+
function parseArgs(argv, spec) {
|
|
1844
|
+
const result = {
|
|
1845
|
+
positional: [],
|
|
1846
|
+
string: {},
|
|
1847
|
+
boolean: {},
|
|
1848
|
+
array: {}
|
|
1849
|
+
};
|
|
1850
|
+
const stringFlags = new Set(spec.string ?? []);
|
|
1851
|
+
const booleanFlags = new Set(spec.boolean ?? []);
|
|
1852
|
+
const arrayFlags = new Set(spec.array ?? []);
|
|
1853
|
+
const aliases = spec.aliases ?? {};
|
|
1854
|
+
let i = 0;
|
|
1855
|
+
let stopFlags = false;
|
|
1856
|
+
while (i < argv.length) {
|
|
1857
|
+
const raw = argv[i];
|
|
1858
|
+
if (raw === void 0) {
|
|
1859
|
+
i += 1;
|
|
1860
|
+
continue;
|
|
1861
|
+
}
|
|
1862
|
+
if (stopFlags) {
|
|
1863
|
+
result.positional.push(raw);
|
|
1864
|
+
i += 1;
|
|
1865
|
+
continue;
|
|
1866
|
+
}
|
|
1867
|
+
if (raw === "--") {
|
|
1868
|
+
stopFlags = true;
|
|
1869
|
+
i += 1;
|
|
1870
|
+
continue;
|
|
1871
|
+
}
|
|
1872
|
+
if (!raw.startsWith("--")) {
|
|
1873
|
+
result.positional.push(raw);
|
|
1874
|
+
i += 1;
|
|
1875
|
+
continue;
|
|
1876
|
+
}
|
|
1877
|
+
const eqIdx = raw.indexOf("=");
|
|
1878
|
+
const flagToken = eqIdx >= 0 ? raw.slice(2, eqIdx) : raw.slice(2);
|
|
1879
|
+
const inlineValue = eqIdx >= 0 ? raw.slice(eqIdx + 1) : void 0;
|
|
1880
|
+
const canonical = resolveCanonical(flagToken, { booleanFlags, aliases });
|
|
1881
|
+
if (booleanFlags.has(canonical)) {
|
|
1882
|
+
if (inlineValue !== void 0) {
|
|
1883
|
+
result.boolean[canonical] = parseBool(inlineValue);
|
|
1884
|
+
} else if (flagToken.startsWith("no-") && booleanFlags.has(flagToken.slice(3))) {
|
|
1885
|
+
result.boolean[flagToken.slice(3)] = false;
|
|
1886
|
+
} else {
|
|
1887
|
+
result.boolean[canonical] = true;
|
|
1888
|
+
}
|
|
1889
|
+
i += 1;
|
|
1890
|
+
continue;
|
|
1891
|
+
}
|
|
1892
|
+
if (stringFlags.has(canonical) || arrayFlags.has(canonical)) {
|
|
1893
|
+
let value;
|
|
1894
|
+
if (inlineValue !== void 0) {
|
|
1895
|
+
value = inlineValue;
|
|
1896
|
+
} else {
|
|
1897
|
+
const next = argv[i + 1];
|
|
1898
|
+
if (next === void 0 || next.startsWith("--")) {
|
|
1899
|
+
throw new ArgError(`Flag --${canonical} requires a value.`);
|
|
1900
|
+
}
|
|
1901
|
+
value = next;
|
|
1902
|
+
i += 1;
|
|
1903
|
+
}
|
|
1904
|
+
if (arrayFlags.has(canonical)) {
|
|
1905
|
+
const existing = result.array[canonical] ?? [];
|
|
1906
|
+
existing.push(value);
|
|
1907
|
+
result.array[canonical] = existing;
|
|
1908
|
+
} else {
|
|
1909
|
+
result.string[canonical] = value;
|
|
1910
|
+
}
|
|
1911
|
+
i += 1;
|
|
1912
|
+
continue;
|
|
1913
|
+
}
|
|
1914
|
+
throw new ArgError(`Unknown flag --${flagToken}`);
|
|
1915
|
+
}
|
|
1916
|
+
return result;
|
|
1917
|
+
}
|
|
1918
|
+
function resolveCanonical(flagToken, ctx) {
|
|
1919
|
+
if (ctx.aliases[flagToken]) return ctx.aliases[flagToken];
|
|
1920
|
+
if (flagToken.startsWith("no-") && ctx.booleanFlags.has(flagToken.slice(3))) {
|
|
1921
|
+
return flagToken.slice(3);
|
|
1922
|
+
}
|
|
1923
|
+
return flagToken;
|
|
1924
|
+
}
|
|
1925
|
+
function parseBool(value) {
|
|
1926
|
+
if (value === "true" || value === "1") return true;
|
|
1927
|
+
if (value === "false" || value === "0") return false;
|
|
1928
|
+
throw new ArgError(`Expected boolean value (true/false), got "${value}".`);
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
// src/commands/generate/parse-brand-model-spec.ts
|
|
1932
|
+
var VALID_POSES = [
|
|
1933
|
+
"front",
|
|
1934
|
+
"3/4-right",
|
|
1935
|
+
"right",
|
|
1936
|
+
"left",
|
|
1937
|
+
"3/4-left",
|
|
1938
|
+
"back",
|
|
1939
|
+
"approved"
|
|
1940
|
+
];
|
|
1941
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1942
|
+
function parseBrandModelSpec(raw) {
|
|
1943
|
+
if (!raw) throw new ArgError("--brand-model value cannot be empty.");
|
|
1944
|
+
const colonIdx = raw.indexOf(":");
|
|
1945
|
+
const uuid = colonIdx >= 0 ? raw.slice(0, colonIdx) : raw;
|
|
1946
|
+
const poseRaw = colonIdx >= 0 ? raw.slice(colonIdx + 1) : void 0;
|
|
1947
|
+
if (!UUID_RE.test(uuid)) {
|
|
1948
|
+
throw new ArgError(
|
|
1949
|
+
`Invalid brand model ID: '${uuid}'. Expected a UUID (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).`
|
|
1950
|
+
);
|
|
1951
|
+
}
|
|
1952
|
+
if (poseRaw !== void 0) {
|
|
1953
|
+
if (!poseRaw) {
|
|
1954
|
+
throw new ArgError(
|
|
1955
|
+
`Empty pose for brand model ${uuid}. Valid poses: ${VALID_POSES.join(", ")}.`
|
|
1956
|
+
);
|
|
1957
|
+
}
|
|
1958
|
+
if (!VALID_POSES.includes(poseRaw)) {
|
|
1959
|
+
throw new ArgError(
|
|
1960
|
+
`Unknown pose '${poseRaw}' for brand model ${uuid}. Valid poses: ${VALID_POSES.join(", ")}.`
|
|
1961
|
+
);
|
|
1962
|
+
}
|
|
1963
|
+
return { id: uuid.toLowerCase(), imageType: poseRaw };
|
|
1964
|
+
}
|
|
1965
|
+
return { id: uuid.toLowerCase() };
|
|
1966
|
+
}
|
|
1967
|
+
function validateBrandModelSpecs(specs) {
|
|
1968
|
+
if (specs.length > 3) {
|
|
1969
|
+
throw new ArgError(`Too many --brand-model flags (${specs.length}). Maximum is 3.`);
|
|
1970
|
+
}
|
|
1971
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1972
|
+
for (const spec of specs) {
|
|
1973
|
+
if (seen.has(spec.id)) {
|
|
1974
|
+
throw new ArgError(
|
|
1975
|
+
`Duplicate brand model ID: ${spec.id}. Each --brand-model must reference a different model.`
|
|
1976
|
+
);
|
|
1977
|
+
}
|
|
1978
|
+
seen.add(spec.id);
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1776
1982
|
// src/auth/device-flow.ts
|
|
1777
1983
|
import { setTimeout as delay } from "timers/promises";
|
|
1778
1984
|
import { request } from "undici";
|
|
@@ -2235,6 +2441,77 @@ function formatRevokeFailure(err, token) {
|
|
|
2235
2441
|
return `warning: server-side revoke failed (${reason}). Local profile removed; token ${redactTokenLikeValue(token)} remains server-valid until expiry.`;
|
|
2236
2442
|
}
|
|
2237
2443
|
|
|
2444
|
+
// src/schemas/models.ts
|
|
2445
|
+
import { z as z8 } from "zod";
|
|
2446
|
+
var ModelSummarySchema = z8.object({
|
|
2447
|
+
id: z8.string().uuid(),
|
|
2448
|
+
slug: z8.string(),
|
|
2449
|
+
displayName: z8.string(),
|
|
2450
|
+
description: z8.string().nullable(),
|
|
2451
|
+
shortDescription: z8.string().nullable(),
|
|
2452
|
+
providerSlug: z8.string(),
|
|
2453
|
+
providerName: z8.string(),
|
|
2454
|
+
modelType: z8.string(),
|
|
2455
|
+
category: z8.string(),
|
|
2456
|
+
costTier: z8.string(),
|
|
2457
|
+
creditCost: z8.number(),
|
|
2458
|
+
pricingStrategy: z8.string(),
|
|
2459
|
+
estimatedSeconds: z8.object({
|
|
2460
|
+
typical: z8.number(),
|
|
2461
|
+
range: z8.array(z8.number())
|
|
2462
|
+
}).passthrough().nullable(),
|
|
2463
|
+
status: z8.string(),
|
|
2464
|
+
modalities: z8.object({
|
|
2465
|
+
input: z8.array(z8.string()),
|
|
2466
|
+
output: z8.array(z8.string())
|
|
2467
|
+
}).passthrough().nullable(),
|
|
2468
|
+
bestFor: z8.array(z8.string()),
|
|
2469
|
+
badges: z8.array(z8.string()),
|
|
2470
|
+
isFeatured: z8.boolean(),
|
|
2471
|
+
isDefault: z8.boolean(),
|
|
2472
|
+
docsUrl: z8.string().nullable(),
|
|
2473
|
+
llmContext: z8.string().nullable(),
|
|
2474
|
+
constraints: z8.record(z8.unknown()).nullable(),
|
|
2475
|
+
modelFamily: z8.string().nullable(),
|
|
2476
|
+
isFamilyPrimary: z8.boolean().nullable()
|
|
2477
|
+
}).strict();
|
|
2478
|
+
var ModelsListResponseSchema = z8.object({
|
|
2479
|
+
models: z8.array(ModelSummarySchema)
|
|
2480
|
+
}).strict();
|
|
2481
|
+
|
|
2482
|
+
// src/commands/models/internal.ts
|
|
2483
|
+
async function buildModelClient(opts) {
|
|
2484
|
+
const cfg = await loadConfig({
|
|
2485
|
+
flagProfile: opts.profile,
|
|
2486
|
+
flagApiBaseUrl: opts.apiBaseUrl,
|
|
2487
|
+
flagToken: opts.token
|
|
2488
|
+
});
|
|
2489
|
+
return new ApiClient({
|
|
2490
|
+
apiBaseUrl: cfg.apiBaseUrl,
|
|
2491
|
+
accessToken: cfg.accessToken,
|
|
2492
|
+
signal: opts.signal,
|
|
2493
|
+
cloudflareAccess: cfg.cloudflareAccess
|
|
2494
|
+
});
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2497
|
+
// src/commands/models/list.ts
|
|
2498
|
+
async function listModels(opts) {
|
|
2499
|
+
const client = opts.client ?? await buildModelClient(opts);
|
|
2500
|
+
const data = await client.request({
|
|
2501
|
+
method: "GET",
|
|
2502
|
+
path: "/models",
|
|
2503
|
+
query: {
|
|
2504
|
+
category: opts.category,
|
|
2505
|
+
tier: opts.tier,
|
|
2506
|
+
type: opts.type,
|
|
2507
|
+
featured: opts.featured !== void 0 ? String(opts.featured) : void 0
|
|
2508
|
+
},
|
|
2509
|
+
responseSchema: ModelsListResponseSchema,
|
|
2510
|
+
signal: opts.signal
|
|
2511
|
+
});
|
|
2512
|
+
return data;
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2238
2515
|
// src/telemetry/detect.ts
|
|
2239
2516
|
var AGENT_SIGNALS = [
|
|
2240
2517
|
{ envVar: "CLAUDE_CODE_SESSION_ID", agent: "claude-code" },
|
|
@@ -2325,33 +2602,33 @@ async function buildTemplateClient(opts) {
|
|
|
2325
2602
|
}
|
|
2326
2603
|
|
|
2327
2604
|
// src/schemas/templates.ts
|
|
2328
|
-
import { z as
|
|
2329
|
-
var DeclaredParamSchema =
|
|
2330
|
-
name:
|
|
2331
|
-
type:
|
|
2332
|
-
required:
|
|
2333
|
-
defaultValue:
|
|
2334
|
-
enumValues:
|
|
2335
|
-
description:
|
|
2605
|
+
import { z as z9 } from "zod";
|
|
2606
|
+
var DeclaredParamSchema = z9.object({
|
|
2607
|
+
name: z9.string(),
|
|
2608
|
+
type: z9.string(),
|
|
2609
|
+
required: z9.boolean(),
|
|
2610
|
+
defaultValue: z9.string().nullable().optional(),
|
|
2611
|
+
enumValues: z9.array(z9.string()).nullable().optional(),
|
|
2612
|
+
description: z9.string().nullable().optional()
|
|
2336
2613
|
}).strict();
|
|
2337
|
-
var TemplateSummarySchema =
|
|
2338
|
-
id:
|
|
2339
|
-
source:
|
|
2340
|
-
name:
|
|
2341
|
-
description:
|
|
2342
|
-
category:
|
|
2343
|
-
thumbnailUrl:
|
|
2344
|
-
tags:
|
|
2345
|
-
createdAt:
|
|
2614
|
+
var TemplateSummarySchema = z9.object({
|
|
2615
|
+
id: z9.string().uuid(),
|
|
2616
|
+
source: z9.enum(["own", "system"]),
|
|
2617
|
+
name: z9.string(),
|
|
2618
|
+
description: z9.string().nullable(),
|
|
2619
|
+
category: z9.string().nullable(),
|
|
2620
|
+
thumbnailUrl: z9.string().nullable(),
|
|
2621
|
+
tags: z9.array(z9.string()),
|
|
2622
|
+
createdAt: z9.string()
|
|
2346
2623
|
}).strict();
|
|
2347
2624
|
var TemplateDetailSchema = TemplateSummarySchema.extend({
|
|
2348
|
-
declaredParams:
|
|
2349
|
-
timesUsed:
|
|
2625
|
+
declaredParams: z9.array(DeclaredParamSchema),
|
|
2626
|
+
timesUsed: z9.number()
|
|
2350
2627
|
}).strict();
|
|
2351
|
-
var TemplatesListResponseSchema =
|
|
2352
|
-
templates:
|
|
2353
|
-
cursor:
|
|
2354
|
-
hasMore:
|
|
2628
|
+
var TemplatesListResponseSchema = z9.object({
|
|
2629
|
+
templates: z9.array(TemplateSummarySchema),
|
|
2630
|
+
cursor: z9.string().nullable(),
|
|
2631
|
+
hasMore: z9.boolean()
|
|
2355
2632
|
}).strict();
|
|
2356
2633
|
|
|
2357
2634
|
// src/commands/template/list.ts
|
|
@@ -2401,20 +2678,20 @@ async function getTemplate(opts) {
|
|
|
2401
2678
|
}
|
|
2402
2679
|
|
|
2403
2680
|
// src/commands/tokens/list.ts
|
|
2404
|
-
import { z as
|
|
2405
|
-
var TokenRowSchema =
|
|
2406
|
-
id:
|
|
2407
|
-
organizationId:
|
|
2408
|
-
userId:
|
|
2409
|
-
clientId:
|
|
2410
|
-
tokenPrefix:
|
|
2411
|
-
name:
|
|
2412
|
-
scopes:
|
|
2413
|
-
lastUsedAt:
|
|
2414
|
-
expiresAt:
|
|
2415
|
-
createdAt:
|
|
2681
|
+
import { z as z10 } from "zod";
|
|
2682
|
+
var TokenRowSchema = z10.object({
|
|
2683
|
+
id: z10.string().uuid(),
|
|
2684
|
+
organizationId: z10.string().uuid(),
|
|
2685
|
+
userId: z10.string().uuid(),
|
|
2686
|
+
clientId: z10.string().nullable(),
|
|
2687
|
+
tokenPrefix: z10.string(),
|
|
2688
|
+
name: z10.string().nullable(),
|
|
2689
|
+
scopes: z10.array(z10.string()),
|
|
2690
|
+
lastUsedAt: z10.string().nullable(),
|
|
2691
|
+
expiresAt: z10.string(),
|
|
2692
|
+
createdAt: z10.string()
|
|
2416
2693
|
}).strict();
|
|
2417
|
-
var TokensListResponseSchema =
|
|
2694
|
+
var TokensListResponseSchema = z10.array(TokenRowSchema);
|
|
2418
2695
|
async function listTokens(options) {
|
|
2419
2696
|
const config = await loadConfig({
|
|
2420
2697
|
flagProfile: options.profile,
|
|
@@ -2443,23 +2720,33 @@ async function listTokens(options) {
|
|
|
2443
2720
|
var FALLBACK_HINT = "See `clickraft --help` or contact support.";
|
|
2444
2721
|
function formatHumanError(err) {
|
|
2445
2722
|
const view = errorToView(err);
|
|
2446
|
-
|
|
2723
|
+
const lines = [
|
|
2447
2724
|
`Error: ${view.message}`,
|
|
2448
2725
|
`Code: ${view.code}`,
|
|
2449
2726
|
`Try: ${view.hint}`,
|
|
2450
2727
|
`Request ID: ${view.requestId ?? "n/a"}`
|
|
2451
|
-
]
|
|
2728
|
+
];
|
|
2729
|
+
if (view.details) lines.push(`Details: ${view.details}`);
|
|
2730
|
+
return lines.join("\n");
|
|
2452
2731
|
}
|
|
2453
2732
|
function formatJsonError(err, ctx) {
|
|
2454
2733
|
return JSON.stringify(wrapError(err, ctx));
|
|
2455
2734
|
}
|
|
2735
|
+
function formatDetails(details) {
|
|
2736
|
+
if (details == null) return void 0;
|
|
2737
|
+
if (typeof details !== "object") return String(details);
|
|
2738
|
+
const entries = Object.entries(details);
|
|
2739
|
+
if (entries.length === 0) return void 0;
|
|
2740
|
+
return entries.map(([k, v]) => `${k}=${v}`).join(", ");
|
|
2741
|
+
}
|
|
2456
2742
|
function errorToView(err) {
|
|
2457
2743
|
if (err instanceof ApiError) {
|
|
2458
2744
|
return {
|
|
2459
2745
|
code: toEnvelopeCode(err.code),
|
|
2460
2746
|
message: err.message,
|
|
2461
2747
|
hint: EXIT_CODE_MAP[err.code]?.hint ?? FALLBACK_HINT,
|
|
2462
|
-
requestId: err.meta.requestId
|
|
2748
|
+
requestId: err.meta.requestId,
|
|
2749
|
+
details: formatDetails(err.meta.details)
|
|
2463
2750
|
};
|
|
2464
2751
|
}
|
|
2465
2752
|
if (err instanceof AuthError || err instanceof CredentialsError) {
|
|
@@ -2477,101 +2764,6 @@ function errorToView(err) {
|
|
|
2477
2764
|
};
|
|
2478
2765
|
}
|
|
2479
2766
|
|
|
2480
|
-
// src/cli/args.ts
|
|
2481
|
-
var ArgError = class extends Error {
|
|
2482
|
-
constructor(message) {
|
|
2483
|
-
super(message);
|
|
2484
|
-
this.name = "ArgError";
|
|
2485
|
-
}
|
|
2486
|
-
};
|
|
2487
|
-
function parseArgs(argv, spec) {
|
|
2488
|
-
const result = {
|
|
2489
|
-
positional: [],
|
|
2490
|
-
string: {},
|
|
2491
|
-
boolean: {},
|
|
2492
|
-
array: {}
|
|
2493
|
-
};
|
|
2494
|
-
const stringFlags = new Set(spec.string ?? []);
|
|
2495
|
-
const booleanFlags = new Set(spec.boolean ?? []);
|
|
2496
|
-
const arrayFlags = new Set(spec.array ?? []);
|
|
2497
|
-
const aliases = spec.aliases ?? {};
|
|
2498
|
-
let i = 0;
|
|
2499
|
-
let stopFlags = false;
|
|
2500
|
-
while (i < argv.length) {
|
|
2501
|
-
const raw = argv[i];
|
|
2502
|
-
if (raw === void 0) {
|
|
2503
|
-
i += 1;
|
|
2504
|
-
continue;
|
|
2505
|
-
}
|
|
2506
|
-
if (stopFlags) {
|
|
2507
|
-
result.positional.push(raw);
|
|
2508
|
-
i += 1;
|
|
2509
|
-
continue;
|
|
2510
|
-
}
|
|
2511
|
-
if (raw === "--") {
|
|
2512
|
-
stopFlags = true;
|
|
2513
|
-
i += 1;
|
|
2514
|
-
continue;
|
|
2515
|
-
}
|
|
2516
|
-
if (!raw.startsWith("--")) {
|
|
2517
|
-
result.positional.push(raw);
|
|
2518
|
-
i += 1;
|
|
2519
|
-
continue;
|
|
2520
|
-
}
|
|
2521
|
-
const eqIdx = raw.indexOf("=");
|
|
2522
|
-
const flagToken = eqIdx >= 0 ? raw.slice(2, eqIdx) : raw.slice(2);
|
|
2523
|
-
const inlineValue = eqIdx >= 0 ? raw.slice(eqIdx + 1) : void 0;
|
|
2524
|
-
const canonical = resolveCanonical(flagToken, { booleanFlags, aliases });
|
|
2525
|
-
if (booleanFlags.has(canonical)) {
|
|
2526
|
-
if (inlineValue !== void 0) {
|
|
2527
|
-
result.boolean[canonical] = parseBool(inlineValue);
|
|
2528
|
-
} else if (flagToken.startsWith("no-") && booleanFlags.has(flagToken.slice(3))) {
|
|
2529
|
-
result.boolean[flagToken.slice(3)] = false;
|
|
2530
|
-
} else {
|
|
2531
|
-
result.boolean[canonical] = true;
|
|
2532
|
-
}
|
|
2533
|
-
i += 1;
|
|
2534
|
-
continue;
|
|
2535
|
-
}
|
|
2536
|
-
if (stringFlags.has(canonical) || arrayFlags.has(canonical)) {
|
|
2537
|
-
let value;
|
|
2538
|
-
if (inlineValue !== void 0) {
|
|
2539
|
-
value = inlineValue;
|
|
2540
|
-
} else {
|
|
2541
|
-
const next = argv[i + 1];
|
|
2542
|
-
if (next === void 0 || next.startsWith("--")) {
|
|
2543
|
-
throw new ArgError(`Flag --${canonical} requires a value.`);
|
|
2544
|
-
}
|
|
2545
|
-
value = next;
|
|
2546
|
-
i += 1;
|
|
2547
|
-
}
|
|
2548
|
-
if (arrayFlags.has(canonical)) {
|
|
2549
|
-
const existing = result.array[canonical] ?? [];
|
|
2550
|
-
existing.push(value);
|
|
2551
|
-
result.array[canonical] = existing;
|
|
2552
|
-
} else {
|
|
2553
|
-
result.string[canonical] = value;
|
|
2554
|
-
}
|
|
2555
|
-
i += 1;
|
|
2556
|
-
continue;
|
|
2557
|
-
}
|
|
2558
|
-
throw new ArgError(`Unknown flag --${flagToken}`);
|
|
2559
|
-
}
|
|
2560
|
-
return result;
|
|
2561
|
-
}
|
|
2562
|
-
function resolveCanonical(flagToken, ctx) {
|
|
2563
|
-
if (ctx.aliases[flagToken]) return ctx.aliases[flagToken];
|
|
2564
|
-
if (flagToken.startsWith("no-") && ctx.booleanFlags.has(flagToken.slice(3))) {
|
|
2565
|
-
return flagToken.slice(3);
|
|
2566
|
-
}
|
|
2567
|
-
return flagToken;
|
|
2568
|
-
}
|
|
2569
|
-
function parseBool(value) {
|
|
2570
|
-
if (value === "true" || value === "1") return true;
|
|
2571
|
-
if (value === "false" || value === "0") return false;
|
|
2572
|
-
throw new ArgError(`Expected boolean value (true/false), got "${value}".`);
|
|
2573
|
-
}
|
|
2574
|
-
|
|
2575
2767
|
// src/cli/parse-args.ts
|
|
2576
2768
|
var SHORT_ALIASES = {
|
|
2577
2769
|
h: "help",
|
|
@@ -2867,6 +3059,72 @@ function renderTemplateDetail(detail, out) {
|
|
|
2867
3059
|
}
|
|
2868
3060
|
out.write(lines.join("\n") + "\n");
|
|
2869
3061
|
}
|
|
3062
|
+
var TIER_ORDER = { premium: 0, pro: 1, standard: 2 };
|
|
3063
|
+
function renderModelsList(result, out, options) {
|
|
3064
|
+
const { models } = result;
|
|
3065
|
+
if (models.length === 0) {
|
|
3066
|
+
out.write("No models match your filters.\n");
|
|
3067
|
+
return;
|
|
3068
|
+
}
|
|
3069
|
+
const sorted = [...models].sort((a, b) => {
|
|
3070
|
+
const catCmp = a.category.localeCompare(b.category);
|
|
3071
|
+
if (catCmp !== 0) return catCmp;
|
|
3072
|
+
const tierA = TIER_ORDER[a.costTier] ?? 99;
|
|
3073
|
+
const tierB = TIER_ORDER[b.costTier] ?? 99;
|
|
3074
|
+
if (tierA !== tierB) return tierA - tierB;
|
|
3075
|
+
return a.slug.localeCompare(b.slug);
|
|
3076
|
+
});
|
|
3077
|
+
const filterParts = [];
|
|
3078
|
+
if (options?.filters) {
|
|
3079
|
+
for (const [k, v] of Object.entries(options.filters)) {
|
|
3080
|
+
if (v) filterParts.push(`${k}=${v}`);
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
const filterSuffix = filterParts.length > 0 ? ` (filters: ${filterParts.join(", ")})` : "";
|
|
3084
|
+
out.write(`${sorted.length} models${filterSuffix}
|
|
3085
|
+
|
|
3086
|
+
`);
|
|
3087
|
+
const headers = ["SLUG", "NAME", "CATEGORY", "TIER", "CREDITS", "DEFAULT"];
|
|
3088
|
+
const data = sorted.map((m) => [
|
|
3089
|
+
m.slug,
|
|
3090
|
+
m.displayName,
|
|
3091
|
+
m.category,
|
|
3092
|
+
m.costTier,
|
|
3093
|
+
String(m.creditCost),
|
|
3094
|
+
m.isDefault ? "\u2713" : ""
|
|
3095
|
+
]);
|
|
3096
|
+
const widths = headers.map(
|
|
3097
|
+
(header, i) => Math.max(header.length, ...data.map((cells) => cells[i].length))
|
|
3098
|
+
);
|
|
3099
|
+
const padRow = (cells) => cells.map((cell, i) => cell.padEnd(widths[i])).join(" ").trimEnd();
|
|
3100
|
+
out.write(padRow(headers) + "\n");
|
|
3101
|
+
for (const cells of data) out.write(padRow(cells) + "\n");
|
|
3102
|
+
out.write(
|
|
3103
|
+
`
|
|
3104
|
+
Showing all ${sorted.length} models. Use --json for full details including constraints.
|
|
3105
|
+
`
|
|
3106
|
+
);
|
|
3107
|
+
if (options?.verbose) {
|
|
3108
|
+
out.write("\n");
|
|
3109
|
+
for (const m of sorted) {
|
|
3110
|
+
const pad = 16;
|
|
3111
|
+
out.write(`${m.slug} (${m.displayName})
|
|
3112
|
+
`);
|
|
3113
|
+
out.write(`${" Provider:".padEnd(pad)}${m.providerName}
|
|
3114
|
+
`);
|
|
3115
|
+
out.write(`${" Category:".padEnd(pad)}${m.category} / ${m.modelType}
|
|
3116
|
+
`);
|
|
3117
|
+
out.write(`${" Tier:".padEnd(pad)}${m.costTier} (${m.creditCost} credits)
|
|
3118
|
+
`);
|
|
3119
|
+
if (m.llmContext) {
|
|
3120
|
+
const ctx = m.llmContext.length > 100 ? m.llmContext.slice(0, 100) + "..." : m.llmContext;
|
|
3121
|
+
out.write(`${" Context:".padEnd(pad)}${ctx}
|
|
3122
|
+
`);
|
|
3123
|
+
}
|
|
3124
|
+
out.write("\n");
|
|
3125
|
+
}
|
|
3126
|
+
}
|
|
3127
|
+
}
|
|
2870
3128
|
function formatExpiresAt(iso) {
|
|
2871
3129
|
const ms = Date.parse(iso);
|
|
2872
3130
|
if (Number.isNaN(ms)) return iso;
|
|
@@ -3093,6 +3351,7 @@ function renderRootHelp(version) {
|
|
|
3093
3351
|
" tokens list List the caller's API tokens",
|
|
3094
3352
|
" balance Show credit balance and rate limits",
|
|
3095
3353
|
" brand-model list List available brand models",
|
|
3354
|
+
" models list List available AI models",
|
|
3096
3355
|
" telemetry inspect Show current telemetry state and payload shape",
|
|
3097
3356
|
" template list List available templates",
|
|
3098
3357
|
" template get Fetch a template by ID",
|
|
@@ -3172,6 +3431,38 @@ function renderCommandHelp(command) {
|
|
|
3172
3431
|
" --json Emit JSON envelope instead of human output",
|
|
3173
3432
|
""
|
|
3174
3433
|
].join("\n");
|
|
3434
|
+
case "models":
|
|
3435
|
+
return [
|
|
3436
|
+
"Usage: clickraft models <subcommand> [options]",
|
|
3437
|
+
"",
|
|
3438
|
+
"Subcommands:",
|
|
3439
|
+
" list List available AI models",
|
|
3440
|
+
""
|
|
3441
|
+
].join("\n");
|
|
3442
|
+
case "models list":
|
|
3443
|
+
return [
|
|
3444
|
+
"Usage: clickraft models list [options]",
|
|
3445
|
+
"",
|
|
3446
|
+
"List AI models available for generation. By default shows a summary table;",
|
|
3447
|
+
"use --json for full details including constraints and llmContext.",
|
|
3448
|
+
"",
|
|
3449
|
+
"Options:",
|
|
3450
|
+
" --category <name> Filter by category (image, video, audio, chat, edit)",
|
|
3451
|
+
" --tier <name> Filter by cost tier (standard, pro, premium)",
|
|
3452
|
+
" --type <name> Filter by model type (e.g. text-to-image)",
|
|
3453
|
+
" --featured Show only featured models",
|
|
3454
|
+
" --verbose Show expanded per-model details after the table",
|
|
3455
|
+
" --profile <name>",
|
|
3456
|
+
" --api-base-url <url>",
|
|
3457
|
+
" --token <token>",
|
|
3458
|
+
" --json",
|
|
3459
|
+
"",
|
|
3460
|
+
"Examples:",
|
|
3461
|
+
" clickraft models list",
|
|
3462
|
+
" clickraft models list --category image --tier pro",
|
|
3463
|
+
" clickraft models list --featured --json",
|
|
3464
|
+
""
|
|
3465
|
+
].join("\n");
|
|
3175
3466
|
case "telemetry inspect":
|
|
3176
3467
|
return [
|
|
3177
3468
|
"Usage: clickraft telemetry inspect [options]",
|
|
@@ -3256,7 +3547,9 @@ function renderCommandHelp(command) {
|
|
|
3256
3547
|
"Options:",
|
|
3257
3548
|
" --prompt <text> Text prompt (or pass as the positional argument)",
|
|
3258
3549
|
" --model-slug <slug> Required model identifier",
|
|
3259
|
-
" --brand-model <
|
|
3550
|
+
" --brand-model <spec> Brand Model reference (repeatable, max 3)",
|
|
3551
|
+
" Format: <uuid> or <uuid>:<pose>",
|
|
3552
|
+
" Poses: front, 3/4-right, right, left, 3/4-left, back, approved",
|
|
3260
3553
|
" --reference-image <v> URL or local path (repeatable, max 8)",
|
|
3261
3554
|
" --aspect-ratio <a:b> e.g. 16:9",
|
|
3262
3555
|
" --resolution <WxH> e.g. 1024x768",
|
|
@@ -3365,6 +3658,12 @@ function matchNewCommand(argv) {
|
|
|
3365
3658
|
if (sub === void 0 || sub.startsWith("-")) return { kind: "sub-help", verb: "template" };
|
|
3366
3659
|
return { kind: "unknown-sub", verb: "template", sub };
|
|
3367
3660
|
}
|
|
3661
|
+
if (verb === "models") {
|
|
3662
|
+
const sub = argv[1];
|
|
3663
|
+
if (sub === "list") return { kind: "cmd", path: "models.list", verbTokenCount: 2 };
|
|
3664
|
+
if (sub === void 0 || sub.startsWith("-")) return { kind: "sub-help", verb: "models" };
|
|
3665
|
+
return { kind: "unknown-sub", verb: "models", sub };
|
|
3666
|
+
}
|
|
3368
3667
|
return null;
|
|
3369
3668
|
}
|
|
3370
3669
|
async function runNewCommand(newCmd, options, stdout, stderr) {
|
|
@@ -3421,6 +3720,8 @@ async function runNewCommand(newCmd, options, stdout, stderr) {
|
|
|
3421
3720
|
return await runTemplateGet(argvAfterVerb, ctx, rc);
|
|
3422
3721
|
case "template.find":
|
|
3423
3722
|
return await runTemplateFind(argvAfterVerb, ctx, rc);
|
|
3723
|
+
case "models.list":
|
|
3724
|
+
return await runModelsList(argvAfterVerb, ctx, rc);
|
|
3424
3725
|
}
|
|
3425
3726
|
} catch (err) {
|
|
3426
3727
|
if (isAbortedError(err, options.signal)) {
|
|
@@ -3451,7 +3752,6 @@ async function runGenerateCreate(argv, ctx, rc) {
|
|
|
3451
3752
|
...COMMON_RICH_STRING_FLAGS,
|
|
3452
3753
|
"prompt",
|
|
3453
3754
|
"model-slug",
|
|
3454
|
-
"brand-model",
|
|
3455
3755
|
"aspect-ratio",
|
|
3456
3756
|
"resolution",
|
|
3457
3757
|
"duration-seconds",
|
|
@@ -3460,10 +3760,13 @@ async function runGenerateCreate(argv, ctx, rc) {
|
|
|
3460
3760
|
"timeout"
|
|
3461
3761
|
],
|
|
3462
3762
|
boolean: [...COMMON_RICH_BOOL_FLAGS, "wait", "async"],
|
|
3463
|
-
array: ["reference-image"]
|
|
3763
|
+
array: ["reference-image", "brand-model"]
|
|
3464
3764
|
});
|
|
3465
3765
|
const modelSlug = parsed.string["model-slug"];
|
|
3466
3766
|
if (!modelSlug) throw new ArgError("--model-slug is required.");
|
|
3767
|
+
const rawBrandModels = parsed.array["brand-model"] ?? [];
|
|
3768
|
+
const brandModels = rawBrandModels.length > 0 ? rawBrandModels.map(parseBrandModelSpec) : void 0;
|
|
3769
|
+
if (brandModels) validateBrandModelSpecs(brandModels);
|
|
3467
3770
|
const result = await generateCreate({
|
|
3468
3771
|
prompt: parsed.string.prompt ?? parsed.positional[0],
|
|
3469
3772
|
modelSlug,
|
|
@@ -3471,7 +3774,7 @@ async function runGenerateCreate(argv, ctx, rc) {
|
|
|
3471
3774
|
aspectRatio: parsed.string["aspect-ratio"],
|
|
3472
3775
|
resolution: parsed.string.resolution,
|
|
3473
3776
|
durationSeconds: optionalInt(parsed.string["duration-seconds"], "duration-seconds"),
|
|
3474
|
-
|
|
3777
|
+
brandModels,
|
|
3475
3778
|
workflowId: parsed.string["workflow-id"],
|
|
3476
3779
|
nodeId: parsed.string["node-id"],
|
|
3477
3780
|
wait: computeWaitFlag(parsed),
|
|
@@ -3696,6 +3999,42 @@ function emitTemplateDetail(detail, ctx, rc) {
|
|
|
3696
3999
|
}
|
|
3697
4000
|
renderTemplateDetail(detail, rc.stdout);
|
|
3698
4001
|
}
|
|
4002
|
+
async function runModelsList(argv, ctx, rc) {
|
|
4003
|
+
const parsed = parseArgs(argv, {
|
|
4004
|
+
string: [...COMMON_RICH_STRING_FLAGS, "category", "tier", "type"],
|
|
4005
|
+
boolean: [...COMMON_RICH_BOOL_FLAGS, "featured", "verbose"]
|
|
4006
|
+
});
|
|
4007
|
+
const result = await listModels({
|
|
4008
|
+
category: parsed.string.category,
|
|
4009
|
+
tier: parsed.string.tier,
|
|
4010
|
+
type: parsed.string.type,
|
|
4011
|
+
featured: parsed.boolean.featured,
|
|
4012
|
+
profile: parsed.string.profile,
|
|
4013
|
+
apiBaseUrl: parsed.string["api-base-url"],
|
|
4014
|
+
token: parsed.string.token,
|
|
4015
|
+
signal: rc.signal
|
|
4016
|
+
});
|
|
4017
|
+
emitModelsList(result, ctx, rc, parsed);
|
|
4018
|
+
return 0;
|
|
4019
|
+
}
|
|
4020
|
+
function emitModelsList(result, ctx, rc, parsed) {
|
|
4021
|
+
if (rc.signal?.aborted) {
|
|
4022
|
+
throw new AuthError("AUTH_FLOW_CANCELLED", "Cancelled.");
|
|
4023
|
+
}
|
|
4024
|
+
if (rc.jsonMode) {
|
|
4025
|
+
rc.stdout.write(JSON.stringify(wrapSuccess(result, ctx)) + "\n");
|
|
4026
|
+
return;
|
|
4027
|
+
}
|
|
4028
|
+
renderModelsList(result, rc.stdout, {
|
|
4029
|
+
verbose: parsed.boolean.verbose === true,
|
|
4030
|
+
filters: {
|
|
4031
|
+
category: parsed.string.category ?? "",
|
|
4032
|
+
tier: parsed.string.tier ?? "",
|
|
4033
|
+
type: parsed.string.type ?? "",
|
|
4034
|
+
featured: parsed.boolean.featured !== void 0 ? String(parsed.boolean.featured) : ""
|
|
4035
|
+
}
|
|
4036
|
+
});
|
|
4037
|
+
}
|
|
3699
4038
|
|
|
3700
4039
|
// src/index.ts
|
|
3701
4040
|
var __filename2 = fileURLToPath(import.meta.url);
|