@clickraft/cli 0.1.7 → 0.2.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 +3 -3
- package/README.md +4 -0
- package/dist/cli.js +294 -123
- package/dist/cli.js.map +1 -1
- package/dist/index.js +294 -123
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
## [0.
|
|
1
|
+
## [0.2.0](https://github.com/clickraft/cli/compare/v0.1.8...v0.2.0) (2026-05-24)
|
|
2
2
|
|
|
3
|
-
###
|
|
3
|
+
### Features
|
|
4
4
|
|
|
5
|
-
* **
|
|
5
|
+
* **commands:** add balance and brand-model list commands ([19e27a2](https://github.com/clickraft/cli/commit/19e27a2c5cebe3f19954a80c64139f9e5d6bbd22))
|
|
6
6
|
|
|
7
7
|
# Changelog
|
|
8
8
|
|
package/README.md
CHANGED
|
@@ -17,6 +17,8 @@ Requires Node.js 20 or later.
|
|
|
17
17
|
```bash
|
|
18
18
|
clickraft login
|
|
19
19
|
clickraft generate create --prompt "a serene mountain landscape at dawn"
|
|
20
|
+
clickraft balance
|
|
21
|
+
clickraft brand-model list
|
|
20
22
|
```
|
|
21
23
|
|
|
22
24
|
Full documentation: [docs.clickraft.ai/cli](https://docs.clickraft.ai/cli) _(coming soon)_
|
|
@@ -30,6 +32,8 @@ export CLOUDFLARE_ACCESS_CLIENT_ID="<client-id>.access"
|
|
|
30
32
|
export CLOUDFLARE_ACCESS_CLIENT_SECRET="<client-secret>"
|
|
31
33
|
|
|
32
34
|
clickraft tokens list --profile staging
|
|
35
|
+
clickraft balance --profile staging
|
|
36
|
+
clickraft brand-model list --profile staging
|
|
33
37
|
```
|
|
34
38
|
|
|
35
39
|
Both env vars must be set together — if only one is set the CLI exits with a configuration error. Production usage (the default) does not require these env vars.
|
package/dist/cli.js
CHANGED
|
@@ -170,6 +170,12 @@ var EXIT_CODE_MAP = {
|
|
|
170
170
|
retryable: false,
|
|
171
171
|
hint: "Resource not found."
|
|
172
172
|
},
|
|
173
|
+
FEATURE_DISABLED: {
|
|
174
|
+
exitCode: 2,
|
|
175
|
+
category: "usage",
|
|
176
|
+
retryable: false,
|
|
177
|
+
hint: "This endpoint is not enabled. Contact support if you believe this is in error."
|
|
178
|
+
},
|
|
173
179
|
FORBIDDEN: {
|
|
174
180
|
exitCode: 4,
|
|
175
181
|
category: "permission",
|
|
@@ -848,65 +854,8 @@ function buildPayload(args) {
|
|
|
848
854
|
return payload;
|
|
849
855
|
}
|
|
850
856
|
|
|
851
|
-
// src/
|
|
852
|
-
import { z as
|
|
853
|
-
var GenerateCreateRequestSchema = z3.object({
|
|
854
|
-
modelSlug: z3.string().min(1).max(100),
|
|
855
|
-
input: z3.object({
|
|
856
|
-
prompt: z3.string().max(1e4).optional(),
|
|
857
|
-
referenceImageUrl: z3.string().url().optional(),
|
|
858
|
-
referenceImages: z3.array(z3.string().url()).max(8).optional(),
|
|
859
|
-
aspectRatio: z3.string().regex(/^\d+:\d+$/).optional(),
|
|
860
|
-
resolution: z3.string().regex(/^\d+x\d+$/).optional(),
|
|
861
|
-
durationSeconds: z3.number().int().min(1).max(60).optional(),
|
|
862
|
-
providerParams: z3.record(z3.string(), z3.unknown()).optional()
|
|
863
|
-
}).strict(),
|
|
864
|
-
options: z3.object({
|
|
865
|
-
workflowId: z3.string().uuid().optional(),
|
|
866
|
-
nodeId: z3.string().optional()
|
|
867
|
-
}).strict().optional()
|
|
868
|
-
}).strict();
|
|
869
|
-
var GenerateCreateResponseSchema = z3.object({
|
|
870
|
-
jobId: z3.string().uuid(),
|
|
871
|
-
status: z3.enum(["queued", "processing", "completed", "failed"]),
|
|
872
|
-
estimatedSeconds: z3.number().int().nonnegative().nullable(),
|
|
873
|
-
creditsCharged: z3.number().int().nonnegative()
|
|
874
|
-
}).strict();
|
|
875
|
-
var GenerationStatusSchema = z3.enum([
|
|
876
|
-
"queued",
|
|
877
|
-
"processing",
|
|
878
|
-
"uploading",
|
|
879
|
-
"completed",
|
|
880
|
-
"failed",
|
|
881
|
-
"cancelled"
|
|
882
|
-
]);
|
|
883
|
-
var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
884
|
-
"completed",
|
|
885
|
-
"failed",
|
|
886
|
-
"cancelled"
|
|
887
|
-
]);
|
|
888
|
-
function isTerminalStatus(status) {
|
|
889
|
-
return TERMINAL_STATUSES.has(status);
|
|
890
|
-
}
|
|
891
|
-
var GenerationResultSchema = z3.object({
|
|
892
|
-
jobId: z3.string().uuid(),
|
|
893
|
-
status: GenerationStatusSchema,
|
|
894
|
-
modelSlug: z3.string(),
|
|
895
|
-
resultUrl: z3.string().url().nullable(),
|
|
896
|
-
thumbnailUrl: z3.string().url().nullable(),
|
|
897
|
-
errorCode: z3.string().nullable(),
|
|
898
|
-
errorMessage: z3.string().nullable(),
|
|
899
|
-
creditsCharged: z3.number().int().nonnegative(),
|
|
900
|
-
creditsRefunded: z3.boolean(),
|
|
901
|
-
startedAt: z3.string().nullable(),
|
|
902
|
-
completedAt: z3.string().nullable()
|
|
903
|
-
}).strict();
|
|
904
|
-
|
|
905
|
-
// src/commands/upload.ts
|
|
906
|
-
import { createHash as createHash2 } from "crypto";
|
|
907
|
-
import { readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
908
|
-
import { basename } from "path";
|
|
909
|
-
import { request as undiciRequest2 } from "undici";
|
|
857
|
+
// src/commands/balance.ts
|
|
858
|
+
import { z as z4 } from "zod";
|
|
910
859
|
|
|
911
860
|
// src/auth/credentials.ts
|
|
912
861
|
import {
|
|
@@ -950,31 +899,31 @@ function getCredentialsPath(ctx = {}) {
|
|
|
950
899
|
}
|
|
951
900
|
|
|
952
901
|
// src/auth/types.ts
|
|
953
|
-
import { z as
|
|
954
|
-
var DeviceAuthorizationRequestSchema =
|
|
955
|
-
client_id:
|
|
956
|
-
scope:
|
|
902
|
+
import { z as z3 } from "zod";
|
|
903
|
+
var DeviceAuthorizationRequestSchema = z3.object({
|
|
904
|
+
client_id: z3.string(),
|
|
905
|
+
scope: z3.string()
|
|
957
906
|
});
|
|
958
|
-
var DeviceAuthorizationResponseSchema =
|
|
959
|
-
device_code:
|
|
960
|
-
user_code:
|
|
961
|
-
verification_uri:
|
|
962
|
-
verification_uri_complete:
|
|
963
|
-
expires_in:
|
|
964
|
-
interval:
|
|
907
|
+
var DeviceAuthorizationResponseSchema = z3.object({
|
|
908
|
+
device_code: z3.string(),
|
|
909
|
+
user_code: z3.string().min(1),
|
|
910
|
+
verification_uri: z3.string().url(),
|
|
911
|
+
verification_uri_complete: z3.string().url().optional(),
|
|
912
|
+
expires_in: z3.number().int().positive(),
|
|
913
|
+
interval: z3.number().int().positive().default(5)
|
|
965
914
|
});
|
|
966
|
-
var DeviceTokenPollRequestSchema =
|
|
967
|
-
client_id:
|
|
968
|
-
device_code:
|
|
969
|
-
grant_type:
|
|
915
|
+
var DeviceTokenPollRequestSchema = z3.object({
|
|
916
|
+
client_id: z3.string(),
|
|
917
|
+
device_code: z3.string(),
|
|
918
|
+
grant_type: z3.literal("urn:ietf:params:oauth:grant-type:device_code")
|
|
970
919
|
});
|
|
971
|
-
var TokenResponseSchema =
|
|
972
|
-
access_token:
|
|
973
|
-
token_type:
|
|
974
|
-
expires_in:
|
|
975
|
-
scope:
|
|
920
|
+
var TokenResponseSchema = z3.object({
|
|
921
|
+
access_token: z3.string(),
|
|
922
|
+
token_type: z3.literal("Bearer"),
|
|
923
|
+
expires_in: z3.number().int().positive(),
|
|
924
|
+
scope: z3.string()
|
|
976
925
|
});
|
|
977
|
-
var DeviceTokenPollErrorCodeSchema =
|
|
926
|
+
var DeviceTokenPollErrorCodeSchema = z3.enum([
|
|
978
927
|
"authorization_pending",
|
|
979
928
|
"slow_down",
|
|
980
929
|
"access_denied",
|
|
@@ -985,27 +934,27 @@ var DeviceTokenPollErrorCodeSchema = z4.enum([
|
|
|
985
934
|
"unsupported_grant_type",
|
|
986
935
|
"invalid_scope"
|
|
987
936
|
]);
|
|
988
|
-
var DeviceTokenPollErrorSchema =
|
|
937
|
+
var DeviceTokenPollErrorSchema = z3.object({
|
|
989
938
|
error: DeviceTokenPollErrorCodeSchema,
|
|
990
|
-
error_description:
|
|
939
|
+
error_description: z3.string().optional()
|
|
991
940
|
});
|
|
992
|
-
var CredentialsProfileSchema =
|
|
993
|
-
apiBaseUrl:
|
|
994
|
-
accessToken:
|
|
995
|
-
tokenType:
|
|
996
|
-
tokenPrefix:
|
|
997
|
-
organizationId:
|
|
998
|
-
organizationSlug:
|
|
999
|
-
userId:
|
|
1000
|
-
scopes:
|
|
1001
|
-
expiresAt:
|
|
1002
|
-
issuedAt:
|
|
1003
|
-
clientId:
|
|
941
|
+
var CredentialsProfileSchema = z3.object({
|
|
942
|
+
apiBaseUrl: z3.string().url(),
|
|
943
|
+
accessToken: z3.string(),
|
|
944
|
+
tokenType: z3.literal("Bearer"),
|
|
945
|
+
tokenPrefix: z3.string(),
|
|
946
|
+
organizationId: z3.string().uuid(),
|
|
947
|
+
organizationSlug: z3.string(),
|
|
948
|
+
userId: z3.string().uuid(),
|
|
949
|
+
scopes: z3.array(z3.string()),
|
|
950
|
+
expiresAt: z3.string().datetime(),
|
|
951
|
+
issuedAt: z3.string().datetime(),
|
|
952
|
+
clientId: z3.string()
|
|
1004
953
|
}).strict();
|
|
1005
|
-
var CredentialsFileSchema =
|
|
1006
|
-
version:
|
|
1007
|
-
defaultProfile:
|
|
1008
|
-
profiles:
|
|
954
|
+
var CredentialsFileSchema = z3.object({
|
|
955
|
+
version: z3.literal(1),
|
|
956
|
+
defaultProfile: z3.string(),
|
|
957
|
+
profiles: z3.record(z3.string(), CredentialsProfileSchema)
|
|
1009
958
|
}).strict();
|
|
1010
959
|
|
|
1011
960
|
// src/auth/credentials.ts
|
|
@@ -1237,20 +1186,158 @@ function trim(value) {
|
|
|
1237
1186
|
return t.length === 0 ? void 0 : t;
|
|
1238
1187
|
}
|
|
1239
1188
|
|
|
1240
|
-
// src/
|
|
1189
|
+
// src/commands/balance.ts
|
|
1190
|
+
var BalanceResponseSchema = z4.object({
|
|
1191
|
+
totalCredits: z4.number(),
|
|
1192
|
+
subscriptionCredits: z4.number(),
|
|
1193
|
+
purchasedCredits: z4.number(),
|
|
1194
|
+
promotionalCredits: z4.number(),
|
|
1195
|
+
rateLimit: z4.object({
|
|
1196
|
+
apiBurstPerMinute: z4.number()
|
|
1197
|
+
}).strict()
|
|
1198
|
+
}).strict();
|
|
1199
|
+
async function getBalance(options) {
|
|
1200
|
+
const config = await loadConfig({
|
|
1201
|
+
flagProfile: options.profile,
|
|
1202
|
+
credentialsPath: options.credentialsPath
|
|
1203
|
+
});
|
|
1204
|
+
if (!config.accessToken) {
|
|
1205
|
+
throw new AuthError("AUTH_TOKEN_MISSING", `Not authenticated. Run \`clickraft login\` first.`);
|
|
1206
|
+
}
|
|
1207
|
+
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) => new ApiClient({
|
|
1208
|
+
apiBaseUrl,
|
|
1209
|
+
accessToken,
|
|
1210
|
+
signal: options.signal,
|
|
1211
|
+
cloudflareAccess: config.cloudflareAccess
|
|
1212
|
+
}));
|
|
1213
|
+
const client = factory(config.apiBaseUrl, config.accessToken);
|
|
1214
|
+
const data = await client.request({
|
|
1215
|
+
method: "GET",
|
|
1216
|
+
path: "/balance",
|
|
1217
|
+
responseSchema: BalanceResponseSchema,
|
|
1218
|
+
signal: options.signal
|
|
1219
|
+
});
|
|
1220
|
+
return data;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
// src/commands/brand-model/list.ts
|
|
1241
1224
|
import { z as z5 } from "zod";
|
|
1225
|
+
var BrandModelSummarySchema = z5.object({
|
|
1226
|
+
id: z5.string().uuid(),
|
|
1227
|
+
source: z5.enum(["system", "user"]),
|
|
1228
|
+
slug: z5.string().nullable(),
|
|
1229
|
+
name: z5.string(),
|
|
1230
|
+
description: z5.string().nullable(),
|
|
1231
|
+
thumbnailUrl: z5.string().nullable(),
|
|
1232
|
+
tags: z5.array(z5.string()),
|
|
1233
|
+
category: z5.string().nullable(),
|
|
1234
|
+
isPremium: z5.boolean().nullable(),
|
|
1235
|
+
isFeatured: z5.boolean().nullable(),
|
|
1236
|
+
badgeText: z5.string().nullable(),
|
|
1237
|
+
usageCount: z5.number().nullable(),
|
|
1238
|
+
createdAt: z5.string()
|
|
1239
|
+
}).strict();
|
|
1240
|
+
var BrandModelsListResponseSchema = z5.object({
|
|
1241
|
+
brandModels: z5.array(BrandModelSummarySchema)
|
|
1242
|
+
}).strict();
|
|
1243
|
+
async function listBrandModels(options) {
|
|
1244
|
+
const config = await loadConfig({
|
|
1245
|
+
flagProfile: options.profile,
|
|
1246
|
+
credentialsPath: options.credentialsPath
|
|
1247
|
+
});
|
|
1248
|
+
if (!config.accessToken) {
|
|
1249
|
+
throw new AuthError("AUTH_TOKEN_MISSING", `Not authenticated. Run \`clickraft login\` first.`);
|
|
1250
|
+
}
|
|
1251
|
+
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) => new ApiClient({
|
|
1252
|
+
apiBaseUrl,
|
|
1253
|
+
accessToken,
|
|
1254
|
+
signal: options.signal,
|
|
1255
|
+
cloudflareAccess: config.cloudflareAccess
|
|
1256
|
+
}));
|
|
1257
|
+
const client = factory(config.apiBaseUrl, config.accessToken);
|
|
1258
|
+
const data = await client.request({
|
|
1259
|
+
method: "GET",
|
|
1260
|
+
path: "/brand-models",
|
|
1261
|
+
responseSchema: BrandModelsListResponseSchema,
|
|
1262
|
+
signal: options.signal
|
|
1263
|
+
});
|
|
1264
|
+
return data.brandModels;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
// src/schemas/jobs.ts
|
|
1268
|
+
import { z as z6 } from "zod";
|
|
1269
|
+
var GenerateCreateRequestSchema = z6.object({
|
|
1270
|
+
modelSlug: z6.string().min(1).max(100),
|
|
1271
|
+
input: z6.object({
|
|
1272
|
+
prompt: z6.string().max(1e4).optional(),
|
|
1273
|
+
referenceImageUrl: z6.string().url().optional(),
|
|
1274
|
+
referenceImages: z6.array(z6.string().url()).max(8).optional(),
|
|
1275
|
+
aspectRatio: z6.string().regex(/^\d+:\d+$/).optional(),
|
|
1276
|
+
resolution: z6.string().regex(/^\d+x\d+$/).optional(),
|
|
1277
|
+
durationSeconds: z6.number().int().min(1).max(60).optional(),
|
|
1278
|
+
providerParams: z6.record(z6.string(), z6.unknown()).optional()
|
|
1279
|
+
}).strict(),
|
|
1280
|
+
options: z6.object({
|
|
1281
|
+
workflowId: z6.string().uuid().optional(),
|
|
1282
|
+
nodeId: z6.string().optional()
|
|
1283
|
+
}).strict().optional()
|
|
1284
|
+
}).strict();
|
|
1285
|
+
var GenerateCreateResponseSchema = z6.object({
|
|
1286
|
+
jobId: z6.string().uuid(),
|
|
1287
|
+
status: z6.enum(["queued", "processing", "completed", "failed"]),
|
|
1288
|
+
estimatedSeconds: z6.number().int().nonnegative().nullable(),
|
|
1289
|
+
creditsCharged: z6.number().int().nonnegative()
|
|
1290
|
+
}).strict();
|
|
1291
|
+
var GenerationStatusSchema = z6.enum([
|
|
1292
|
+
"queued",
|
|
1293
|
+
"processing",
|
|
1294
|
+
"uploading",
|
|
1295
|
+
"completed",
|
|
1296
|
+
"failed",
|
|
1297
|
+
"cancelled"
|
|
1298
|
+
]);
|
|
1299
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
1300
|
+
"completed",
|
|
1301
|
+
"failed",
|
|
1302
|
+
"cancelled"
|
|
1303
|
+
]);
|
|
1304
|
+
function isTerminalStatus(status) {
|
|
1305
|
+
return TERMINAL_STATUSES.has(status);
|
|
1306
|
+
}
|
|
1307
|
+
var GenerationResultSchema = z6.object({
|
|
1308
|
+
jobId: z6.string().uuid(),
|
|
1309
|
+
status: GenerationStatusSchema,
|
|
1310
|
+
modelSlug: z6.string(),
|
|
1311
|
+
resultUrl: z6.string().url().nullable(),
|
|
1312
|
+
thumbnailUrl: z6.string().url().nullable(),
|
|
1313
|
+
errorCode: z6.string().nullable(),
|
|
1314
|
+
errorMessage: z6.string().nullable(),
|
|
1315
|
+
creditsCharged: z6.number().int().nonnegative(),
|
|
1316
|
+
creditsRefunded: z6.boolean(),
|
|
1317
|
+
startedAt: z6.string().nullable(),
|
|
1318
|
+
completedAt: z6.string().nullable()
|
|
1319
|
+
}).strict();
|
|
1320
|
+
|
|
1321
|
+
// src/commands/upload.ts
|
|
1322
|
+
import { createHash as createHash2 } from "crypto";
|
|
1323
|
+
import { readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
1324
|
+
import { basename } from "path";
|
|
1325
|
+
import { request as undiciRequest2 } from "undici";
|
|
1326
|
+
|
|
1327
|
+
// src/schemas/assets.ts
|
|
1328
|
+
import { z as z7 } from "zod";
|
|
1242
1329
|
var MAX_UPLOAD_SIZE_BYTES = 15 * 1024 * 1024;
|
|
1243
|
-
var UploadRequestSchema =
|
|
1244
|
-
filename:
|
|
1245
|
-
contentType:
|
|
1246
|
-
sizeBytes:
|
|
1247
|
-
contentHash:
|
|
1330
|
+
var UploadRequestSchema = z7.object({
|
|
1331
|
+
filename: z7.string().min(1).max(255),
|
|
1332
|
+
contentType: z7.string().regex(/^[\w-]+\/[\w+.-]+$/),
|
|
1333
|
+
sizeBytes: z7.number().int().positive().max(MAX_UPLOAD_SIZE_BYTES),
|
|
1334
|
+
contentHash: z7.string().regex(/^sha256:[0-9a-f]{64}$/)
|
|
1248
1335
|
}).strict();
|
|
1249
|
-
var UploadResponseSchema =
|
|
1250
|
-
assetId:
|
|
1251
|
-
uploadUrl:
|
|
1252
|
-
publicUrl:
|
|
1253
|
-
deduplicated:
|
|
1336
|
+
var UploadResponseSchema = z7.object({
|
|
1337
|
+
assetId: z7.string().uuid(),
|
|
1338
|
+
uploadUrl: z7.string().url(),
|
|
1339
|
+
publicUrl: z7.string().url(),
|
|
1340
|
+
deduplicated: z7.boolean()
|
|
1254
1341
|
}).strict();
|
|
1255
1342
|
|
|
1256
1343
|
// src/commands/upload.ts
|
|
@@ -2219,20 +2306,20 @@ function inspectTelemetry(options = {}) {
|
|
|
2219
2306
|
}
|
|
2220
2307
|
|
|
2221
2308
|
// src/commands/tokens/list.ts
|
|
2222
|
-
import { z as
|
|
2223
|
-
var TokenRowSchema =
|
|
2224
|
-
id:
|
|
2225
|
-
organizationId:
|
|
2226
|
-
userId:
|
|
2227
|
-
clientId:
|
|
2228
|
-
tokenPrefix:
|
|
2229
|
-
name:
|
|
2230
|
-
scopes:
|
|
2231
|
-
lastUsedAt:
|
|
2232
|
-
expiresAt:
|
|
2233
|
-
createdAt:
|
|
2309
|
+
import { z as z8 } from "zod";
|
|
2310
|
+
var TokenRowSchema = z8.object({
|
|
2311
|
+
id: z8.string().uuid(),
|
|
2312
|
+
organizationId: z8.string().uuid(),
|
|
2313
|
+
userId: z8.string().uuid(),
|
|
2314
|
+
clientId: z8.string().nullable(),
|
|
2315
|
+
tokenPrefix: z8.string(),
|
|
2316
|
+
name: z8.string().nullable(),
|
|
2317
|
+
scopes: z8.array(z8.string()),
|
|
2318
|
+
lastUsedAt: z8.string().nullable(),
|
|
2319
|
+
expiresAt: z8.string(),
|
|
2320
|
+
createdAt: z8.string()
|
|
2234
2321
|
}).strict();
|
|
2235
|
-
var TokensListResponseSchema =
|
|
2322
|
+
var TokensListResponseSchema = z8.array(TokenRowSchema);
|
|
2236
2323
|
async function listTokens(options) {
|
|
2237
2324
|
const config = await loadConfig({
|
|
2238
2325
|
flagProfile: options.profile,
|
|
@@ -2592,6 +2679,44 @@ function renderTelemetryState(state, out) {
|
|
|
2592
2679
|
];
|
|
2593
2680
|
out.write(lines.join("\n") + "\n");
|
|
2594
2681
|
}
|
|
2682
|
+
var fmtNum = new Intl.NumberFormat("en-US");
|
|
2683
|
+
function renderBalance(data, out) {
|
|
2684
|
+
const pad = 22;
|
|
2685
|
+
const lines = [
|
|
2686
|
+
`${"Total credits:".padEnd(pad)}${fmtNum.format(data.totalCredits).padStart(12)}`,
|
|
2687
|
+
`${"\u251C\u2500 Subscription:".padEnd(pad)}${fmtNum.format(data.subscriptionCredits).padStart(12)}`,
|
|
2688
|
+
`${"\u251C\u2500 Purchased:".padEnd(pad)}${fmtNum.format(data.purchasedCredits).padStart(12)}`,
|
|
2689
|
+
`${"\u2514\u2500 Promotional:".padEnd(pad)}${fmtNum.format(data.promotionalCredits).padStart(12)}`,
|
|
2690
|
+
"",
|
|
2691
|
+
`${"Rate limit:".padEnd(pad)}${fmtNum.format(data.rateLimit.apiBurstPerMinute).padStart(12)} req/min`
|
|
2692
|
+
];
|
|
2693
|
+
out.write(lines.join("\n") + "\n");
|
|
2694
|
+
}
|
|
2695
|
+
function renderBrandModelsList(models, out) {
|
|
2696
|
+
if (models.length === 0) {
|
|
2697
|
+
out.write("No brand models.\n");
|
|
2698
|
+
return;
|
|
2699
|
+
}
|
|
2700
|
+
const MAX_TAGS = 3;
|
|
2701
|
+
const headers = ["SOURCE", "NAME", "SLUG", "CATEGORY", "TAGS"];
|
|
2702
|
+
const data = models.map((m) => {
|
|
2703
|
+
const shown = m.tags.slice(0, MAX_TAGS).join(", ");
|
|
2704
|
+
const extra = m.tags.length > MAX_TAGS ? ` +${m.tags.length - MAX_TAGS} more` : "";
|
|
2705
|
+
return [
|
|
2706
|
+
m.source,
|
|
2707
|
+
m.name,
|
|
2708
|
+
m.slug ?? "\u2014",
|
|
2709
|
+
m.category ?? "\u2014",
|
|
2710
|
+
m.tags.length > 0 ? shown + extra : "\u2014"
|
|
2711
|
+
];
|
|
2712
|
+
});
|
|
2713
|
+
const widths = headers.map(
|
|
2714
|
+
(header, i) => Math.max(header.length, ...data.map((cells) => cells[i].length))
|
|
2715
|
+
);
|
|
2716
|
+
const padRow = (cells) => cells.map((cell, i) => cell.padEnd(widths[i])).join(" ").trimEnd();
|
|
2717
|
+
out.write(padRow(headers) + "\n");
|
|
2718
|
+
for (const cells of data) out.write(padRow(cells) + "\n");
|
|
2719
|
+
}
|
|
2595
2720
|
function formatExpiresAt(iso) {
|
|
2596
2721
|
const ms = Date.parse(iso);
|
|
2597
2722
|
if (Number.isNaN(ms)) return iso;
|
|
@@ -2685,6 +2810,22 @@ async function runCommand(parsed, ctx, rc) {
|
|
|
2685
2810
|
emit(state, renderTelemetryState, ctx, rc);
|
|
2686
2811
|
return 0;
|
|
2687
2812
|
}
|
|
2813
|
+
case "balance": {
|
|
2814
|
+
const data = await getBalance({
|
|
2815
|
+
profile: stringFlag(parsed.flags.profile),
|
|
2816
|
+
signal: rc.signal
|
|
2817
|
+
});
|
|
2818
|
+
emit(data, renderBalance, ctx, rc);
|
|
2819
|
+
return 0;
|
|
2820
|
+
}
|
|
2821
|
+
case "brand-model.list": {
|
|
2822
|
+
const models = await listBrandModels({
|
|
2823
|
+
profile: stringFlag(parsed.flags.profile),
|
|
2824
|
+
signal: rc.signal
|
|
2825
|
+
});
|
|
2826
|
+
emit(models, renderBrandModelsList, ctx, rc);
|
|
2827
|
+
return 0;
|
|
2828
|
+
}
|
|
2688
2829
|
default:
|
|
2689
2830
|
throw new ApiError(
|
|
2690
2831
|
"INPUT_INVALID_FORMAT",
|
|
@@ -2757,7 +2898,9 @@ var COMMAND_FLAGS = {
|
|
|
2757
2898
|
},
|
|
2758
2899
|
logout: { profile: "string", all: "boolean", revoke: "boolean", json: "boolean" },
|
|
2759
2900
|
"tokens.list": { profile: "string", json: "boolean" },
|
|
2760
|
-
"telemetry.inspect": { json: "boolean" }
|
|
2901
|
+
"telemetry.inspect": { json: "boolean" },
|
|
2902
|
+
balance: { profile: "string", json: "boolean" },
|
|
2903
|
+
"brand-model.list": { profile: "string", json: "boolean" }
|
|
2761
2904
|
};
|
|
2762
2905
|
function validateFlags(parsed) {
|
|
2763
2906
|
const allowed = COMMAND_FLAGS[parsed.command.join(".")];
|
|
@@ -2798,6 +2941,8 @@ function renderRootHelp(version) {
|
|
|
2798
2941
|
" login Authenticate via OAuth device flow",
|
|
2799
2942
|
" logout Remove credentials (optional server-side revoke)",
|
|
2800
2943
|
" tokens list List the caller's API tokens",
|
|
2944
|
+
" balance Show credit balance and rate limits",
|
|
2945
|
+
" brand-model list List available brand models",
|
|
2801
2946
|
" telemetry inspect Show current telemetry state and payload shape",
|
|
2802
2947
|
" generate create Submit a generation job and wait for completion",
|
|
2803
2948
|
" generate wait Wait for an existing job to reach a terminal state",
|
|
@@ -2848,6 +2993,32 @@ function renderCommandHelp(command) {
|
|
|
2848
2993
|
" --json Emit JSON envelope instead of human output",
|
|
2849
2994
|
""
|
|
2850
2995
|
].join("\n");
|
|
2996
|
+
case "balance":
|
|
2997
|
+
return [
|
|
2998
|
+
"Usage: clickraft balance [options]",
|
|
2999
|
+
"",
|
|
3000
|
+
"Options:",
|
|
3001
|
+
" --profile <name> Read credentials from a specific profile",
|
|
3002
|
+
" --json Emit JSON envelope instead of human output",
|
|
3003
|
+
""
|
|
3004
|
+
].join("\n");
|
|
3005
|
+
case "brand-model":
|
|
3006
|
+
return [
|
|
3007
|
+
"Usage: clickraft brand-model <subcommand> [options]",
|
|
3008
|
+
"",
|
|
3009
|
+
"Subcommands:",
|
|
3010
|
+
" list List available brand models",
|
|
3011
|
+
""
|
|
3012
|
+
].join("\n");
|
|
3013
|
+
case "brand-model list":
|
|
3014
|
+
return [
|
|
3015
|
+
"Usage: clickraft brand-model list [options]",
|
|
3016
|
+
"",
|
|
3017
|
+
"Options:",
|
|
3018
|
+
" --profile <name> Read credentials from a specific profile",
|
|
3019
|
+
" --json Emit JSON envelope instead of human output",
|
|
3020
|
+
""
|
|
3021
|
+
].join("\n");
|
|
2851
3022
|
case "telemetry inspect":
|
|
2852
3023
|
return [
|
|
2853
3024
|
"Usage: clickraft telemetry inspect [options]",
|