jimeng-cli 0.3.1 → 0.3.3

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/dist/cli/index.js CHANGED
@@ -11,13 +11,14 @@ import {
11
11
  getTaskResponse,
12
12
  getTokenLiveStatus,
13
13
  logger_default,
14
+ maskToken,
14
15
  parseRegionCode,
15
16
  receiveCredit,
16
17
  refreshAllTokenModels,
17
18
  session_pool_default,
18
19
  upscaleImage,
19
20
  waitForTaskResponse
20
- } from "../chunk-2IIK4X7C.js";
21
+ } from "../chunk-ZMTQQZFH.js";
21
22
 
22
23
  // src/cli/app.ts
23
24
  import process2 from "process";
@@ -27,11 +28,6 @@ import { constants as fsConstants } from "fs";
27
28
  import path from "path";
28
29
  import { access, readFile } from "fs/promises";
29
30
  import minimist from "minimist";
30
- function maskToken(token) {
31
- const n = token.length;
32
- if (n <= 10) return "***";
33
- return `${token.slice(0, 4)}...${token.slice(-4)}`;
34
- }
35
31
  function formatUnixMs(value) {
36
32
  if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return "-";
37
33
  return new Date(value).toISOString();
@@ -44,14 +40,14 @@ function printTokenEntriesTable(items) {
44
40
  console.log("token region enabled live lastCredit lastCheckedAt failures");
45
41
  for (const item of items) {
46
42
  if (!item || typeof item !== "object") continue;
47
- const entry = item;
48
- const token = typeof entry.token === "string" ? entry.token : "-";
49
- const region = typeof entry.region === "string" ? entry.region : "-";
50
- const enabled = typeof entry.enabled === "boolean" ? String(entry.enabled) : "-";
51
- const live = typeof entry.live === "boolean" ? String(entry.live) : "-";
52
- const lastCredit = typeof entry.lastCredit === "number" ? String(entry.lastCredit) : "-";
53
- const lastCheckedAt = formatUnixMs(entry.lastCheckedAt);
54
- const failures = typeof entry.consecutiveFailures === "number" ? String(entry.consecutiveFailures) : "-";
43
+ const e = item;
44
+ const token = typeof e.token === "string" ? e.token : "-";
45
+ const region = typeof e.region === "string" ? e.region : "-";
46
+ const enabled = typeof e.enabled === "boolean" ? String(e.enabled) : "-";
47
+ const live = typeof e.live === "boolean" ? String(e.live) : "-";
48
+ const lastCredit = typeof e.lastCredit === "number" ? String(e.lastCredit) : "-";
49
+ const lastCheckedAt = formatUnixMs(e.lastCheckedAt);
50
+ const failures = typeof e.consecutiveFailures === "number" ? String(e.consecutiveFailures) : "-";
55
51
  console.log(`${token} ${region} ${enabled} ${live} ${lastCredit} ${lastCheckedAt} ${failures}`);
56
52
  }
57
53
  }
@@ -90,6 +86,30 @@ ${usage}`);
90
86
  }
91
87
  return deduped;
92
88
  }
89
+ function resolveTokenRegionPairs(explicitTokens, regionCode, deps, opts) {
90
+ if (explicitTokens.length > 0) {
91
+ return explicitTokens.map((token) => {
92
+ var _a;
93
+ const entryRegion = (_a = session_pool_default.getTokenEntry(token)) == null ? void 0 : _a.region;
94
+ const finalRegion = regionCode || entryRegion;
95
+ if (!finalRegion) {
96
+ deps.fail(`Missing region for token ${maskToken(token)}. Provide --region or register token in token-pool.`);
97
+ }
98
+ return { token, region: finalRegion };
99
+ });
100
+ }
101
+ const requireLive = (opts == null ? void 0 : opts.requireLive) ?? true;
102
+ const entries = session_pool_default.getEntries(false).filter((item) => {
103
+ if (!item.enabled || !item.region) return false;
104
+ if (requireLive && item.live === false) return false;
105
+ if (regionCode && item.region !== regionCode) return false;
106
+ return true;
107
+ });
108
+ if (entries.length === 0) {
109
+ deps.fail("No token available. Provide --token or configure token-pool.");
110
+ }
111
+ return entries.map((item) => ({ token: item.token, region: item.region }));
112
+ }
93
113
  function createTokenSubcommands(deps) {
94
114
  const handleTokenCheck = async (argv) => {
95
115
  const args = minimist(argv, {
@@ -101,74 +121,67 @@ function createTokenSubcommands(deps) {
101
121
  console.log(usage);
102
122
  return;
103
123
  }
104
- const region = deps.getRegionWithDefault(args);
105
- const regionCode = deps.parseRegionOrFail(region);
106
- if (!regionCode) {
107
- deps.fail("Missing region. Use --region cn/us/hk/jp/sg.");
108
- }
109
- const tokens = await collectTokensFromArgs(args, usage, deps, true);
110
- if (!args.json) {
111
- console.log(`Checking ${tokens.length} token(s)`);
112
- }
124
+ const explicitRegion = deps.getSingleString(args, "region");
125
+ const regionCode = explicitRegion ? deps.parseRegionOrFail(explicitRegion) : void 0;
113
126
  await deps.ensureTokenPoolReady();
114
- let invalid = 0;
115
- let requestErrors = 0;
116
- const results = [];
117
- for (const token of tokens) {
118
- const masked = maskToken(token);
119
- try {
120
- const live = await getTokenLiveStatus(token, buildRegionInfo(regionCode));
121
- await session_pool_default.syncTokenCheckResult(token, live);
122
- if (live === true) {
123
- if (!args.json) console.log(`[OK] ${masked} live=true`);
124
- } else {
125
- invalid += 1;
126
- if (!args.json) console.log(`[FAIL] ${masked} live=false`);
127
+ const explicitTokens = await collectTokensFromArgs(args, usage, deps, false);
128
+ const pairs = resolveTokenRegionPairs(explicitTokens, regionCode, deps, { requireLive: false });
129
+ if (!args.json) {
130
+ console.log(`Checking ${pairs.length} token(s)`);
131
+ }
132
+ const results = await Promise.all(
133
+ pairs.map(async ({ token, region }) => {
134
+ const masked = maskToken(token);
135
+ try {
136
+ const live = await getTokenLiveStatus(token, buildRegionInfo(region));
137
+ await session_pool_default.syncTokenCheckResult(token, live);
138
+ if (live) {
139
+ if (!args.json) console.log(`[OK] ${masked} (${region}) live=true`);
140
+ return { token_masked: masked, region, live: true };
141
+ } else {
142
+ if (!args.json) console.log(`[FAIL] ${masked} (${region}) live=false`);
143
+ return { token_masked: masked, region, live: false };
144
+ }
145
+ } catch (error) {
146
+ const message = error instanceof Error ? error.message : String(error);
147
+ if (!args.json) console.log(`[ERROR] ${masked} (${region}) ${message}`);
148
+ return { token_masked: masked, region, error: message };
127
149
  }
128
- results.push({ token_masked: masked, live: live === true });
129
- } catch (error) {
130
- requestErrors += 1;
131
- const message = error instanceof Error ? error.message : String(error);
132
- if (!args.json) console.log(`[ERROR] ${masked} ${message}`);
133
- results.push({ token_masked: masked, error: message });
134
- }
135
- }
150
+ })
151
+ );
152
+ const invalid = results.filter((r) => r.live === false).length;
153
+ const requestErrors = results.filter((r) => r.error).length;
136
154
  if (args.json) {
137
155
  deps.printCommandJson("token.check", results, {
138
- total: tokens.length,
156
+ total: pairs.length,
139
157
  invalid,
140
158
  request_errors: requestErrors
141
159
  });
142
160
  } else {
143
- console.log(`Summary: total=${tokens.length} invalid=${invalid} request_errors=${requestErrors}`);
161
+ console.log(`Summary: total=${pairs.length} invalid=${invalid} request_errors=${requestErrors}`);
144
162
  }
145
163
  if (requestErrors > 0) process.exit(3);
146
164
  if (invalid > 0) process.exit(2);
147
165
  };
148
166
  const handleTokenList = async (argv) => {
149
- const args = minimist(argv, {
150
- boolean: ["help", "json"]
151
- });
152
- const usage = deps.getUsage("list");
167
+ const args = minimist(argv, { boolean: ["help", "json"] });
153
168
  if (args.help) {
154
- console.log(usage);
169
+ console.log(deps.getUsage("list"));
155
170
  return;
156
171
  }
157
172
  await deps.ensureTokenPoolReady();
158
- const normalized = buildTokenPoolSnapshot();
173
+ const snapshot = buildTokenPoolSnapshot();
159
174
  if (args.json) {
160
- deps.printCommandJson("token.list", normalized);
175
+ deps.printCommandJson("token.list", snapshot);
161
176
  return;
162
177
  }
163
- const body = normalized && typeof normalized === "object" ? normalized : {};
164
- const summary = body.summary;
165
- if (summary && typeof summary === "object") {
178
+ const body = snapshot && typeof snapshot === "object" ? snapshot : {};
179
+ if (body.summary && typeof body.summary === "object") {
166
180
  console.log("Summary:");
167
- deps.printJson(summary);
181
+ deps.printJson(body.summary);
168
182
  }
169
- const items = Array.isArray(body.items) ? body.items : [];
170
183
  console.log("Entries:");
171
- printTokenEntriesTable(items);
184
+ printTokenEntriesTable(Array.isArray(body.items) ? body.items : []);
172
185
  };
173
186
  const handleTokenPointsOrReceive = async (argv, action) => {
174
187
  const args = minimist(argv, {
@@ -180,47 +193,42 @@ function createTokenSubcommands(deps) {
180
193
  console.log(usage);
181
194
  return;
182
195
  }
183
- const region = deps.getRegionWithDefault(args);
184
- const regionCode = deps.parseRegionOrFail(region);
196
+ const regionArg = deps.getSingleString(args, "region");
197
+ const regionCode = regionArg ? deps.parseRegionOrFail(regionArg) : void 0;
185
198
  await deps.ensureTokenPoolReady();
186
- const tokens = await collectTokensFromArgs(args, usage, deps, false);
187
- const resolvedTokens = tokens.length > 0 ? tokens.map((token) => {
188
- var _a;
189
- const entryRegion = (_a = session_pool_default.getTokenEntry(token)) == null ? void 0 : _a.region;
190
- const finalRegion = regionCode || entryRegion;
191
- if (!finalRegion) {
192
- deps.fail(`Missing region for token ${maskToken(token)}. Provide --region or register token region in token-pool.`);
199
+ const explicitTokens = await collectTokensFromArgs(args, usage, deps, false);
200
+ const pairs = resolveTokenRegionPairs(explicitTokens, regionCode, deps);
201
+ const toErrorResult = (token, region, error) => ({
202
+ token_masked: maskToken(token),
203
+ region,
204
+ error: error instanceof Error ? error.message : String(error)
205
+ });
206
+ const fetchPoints = async ({ token, region }) => {
207
+ try {
208
+ return { token_masked: maskToken(token), region, points: await getCredit(token, buildRegionInfo(region)) };
209
+ } catch (error) {
210
+ return toErrorResult(token, region, error);
193
211
  }
194
- return { token, region: finalRegion };
195
- }) : session_pool_default.getEntries(false).filter((item) => item.enabled && item.live !== false && item.region).filter((item) => regionCode ? item.region === regionCode : true).map((item) => ({ token: item.token, region: item.region }));
196
- if (resolvedTokens.length === 0) {
197
- deps.fail("No token available. Provide --token or configure token-pool.");
198
- }
199
- const payload = action === "points" ? await Promise.all(
200
- resolvedTokens.map(async (item) => ({
201
- token: item.token,
202
- points: await getCredit(item.token, buildRegionInfo(item.region))
203
- }))
204
- ) : await Promise.all(
205
- resolvedTokens.map(async (item) => {
206
- const currentCredit = await getCredit(item.token, buildRegionInfo(item.region));
207
- if (currentCredit.totalCredit <= 0) {
208
- try {
209
- await receiveCredit(item.token, buildRegionInfo(item.region));
210
- const updatedCredit = await getCredit(item.token, buildRegionInfo(item.region));
211
- return { token: item.token, credits: updatedCredit, received: true };
212
- } catch (error) {
213
- return {
214
- token: item.token,
215
- credits: currentCredit,
216
- received: false,
217
- error: (error == null ? void 0 : error.message) || String(error)
218
- };
219
- }
212
+ };
213
+ const processReceive = async ({ token, region }) => {
214
+ const regionInfo = buildRegionInfo(region);
215
+ try {
216
+ const currentCredit = await getCredit(token, regionInfo);
217
+ if (currentCredit.totalCredit > 0) {
218
+ return { token_masked: maskToken(token), region, credits: currentCredit, received: false };
220
219
  }
221
- return { token: item.token, credits: currentCredit, received: false };
222
- })
223
- );
220
+ try {
221
+ await receiveCredit(token, regionInfo);
222
+ const updatedCredit = await getCredit(token, regionInfo);
223
+ return { token_masked: maskToken(token), region, credits: updatedCredit, received: true };
224
+ } catch (error) {
225
+ return { token_masked: maskToken(token), region, credits: currentCredit, received: false, ...toErrorResult(token, region, error) };
226
+ }
227
+ } catch (error) {
228
+ return toErrorResult(token, region, error);
229
+ }
230
+ };
231
+ const payload = action === "points" ? await Promise.all(pairs.map(fetchPoints)) : await Promise.all(pairs.map(processReceive));
224
232
  if (args.json) {
225
233
  deps.printCommandJson(`token.${action}`, payload);
226
234
  return;
@@ -237,28 +245,32 @@ function createTokenSubcommands(deps) {
237
245
  console.log(usage);
238
246
  return;
239
247
  }
240
- const region = deps.getRegionWithDefault(args);
241
248
  await deps.ensureTokenPoolReady();
242
249
  const tokens = await collectTokensFromArgs(args, usage, deps, true);
243
- const regionCode = deps.parseRegionOrFail(region);
244
- const payload = action === "add" ? {
245
- ...await session_pool_default.addTokens(tokens, { defaultRegion: regionCode || void 0 }),
246
- summary: session_pool_default.getSummary()
247
- } : {
248
- ...await session_pool_default.removeTokens(tokens),
249
- summary: session_pool_default.getSummary()
250
- };
250
+ let payload;
251
+ let jsonMeta;
252
+ if (action === "add") {
253
+ const region = deps.getRegionWithDefault(args);
254
+ const regionCode = deps.parseRegionOrFail(region);
255
+ payload = {
256
+ ...await session_pool_default.addTokens(tokens, { defaultRegion: regionCode || void 0 }),
257
+ summary: session_pool_default.getSummary()
258
+ };
259
+ jsonMeta = { region };
260
+ } else {
261
+ payload = {
262
+ ...await session_pool_default.removeTokens(tokens),
263
+ summary: session_pool_default.getSummary()
264
+ };
265
+ }
251
266
  if (args.json) {
252
- deps.printCommandJson(`token.${action}`, deps.unwrapBody(payload), { region });
267
+ deps.printCommandJson(`token.${action}`, deps.unwrapBody(payload), jsonMeta);
253
268
  return;
254
269
  }
255
270
  deps.printJson(deps.unwrapBody(payload));
256
271
  };
257
272
  const handleTokenEnableOrDisable = async (argv, action) => {
258
- const args = minimist(argv, {
259
- string: ["token"],
260
- boolean: ["help", "json"]
261
- });
273
+ const args = minimist(argv, { string: ["token"], boolean: ["help", "json"] });
262
274
  const usage = deps.getUsage(action);
263
275
  if (args.help) {
264
276
  console.log(usage);
@@ -280,44 +292,37 @@ function createTokenSubcommands(deps) {
280
292
  deps.printJson(deps.unwrapBody(payload));
281
293
  };
282
294
  const handleTokenPool = async (argv) => {
283
- const args = minimist(argv, {
284
- boolean: ["help", "json"]
285
- });
286
- const usage = deps.getUsage("pool");
295
+ const args = minimist(argv, { boolean: ["help", "json"] });
287
296
  if (args.help) {
288
- console.log(usage);
297
+ console.log(deps.getUsage("pool"));
289
298
  return;
290
299
  }
291
300
  await deps.ensureTokenPoolReady();
292
- const normalized = buildTokenPoolSnapshot();
301
+ const snapshot = buildTokenPoolSnapshot();
293
302
  if (args.json) {
294
- deps.printCommandJson("token.pool", normalized);
303
+ deps.printCommandJson("token.pool", snapshot);
295
304
  return;
296
305
  }
297
- const body = normalized && typeof normalized === "object" ? normalized : {};
306
+ const body = snapshot && typeof snapshot === "object" ? snapshot : {};
298
307
  console.log("Summary:");
299
308
  deps.printJson(body.summary ?? {});
300
309
  console.log("Entries:");
301
310
  printTokenEntriesTable(Array.isArray(body.items) ? body.items : []);
302
311
  };
303
312
  const handleTokenPoolCheckOrReload = async (argv, action) => {
304
- const args = minimist(argv, {
305
- boolean: ["help", "json"]
306
- });
307
- const usage = deps.getUsage(action);
313
+ const args = minimist(argv, { boolean: ["help", "json"] });
308
314
  if (args.help) {
309
- console.log(usage);
315
+ console.log(deps.getUsage(action));
310
316
  return;
311
317
  }
312
318
  await deps.ensureTokenPoolReady();
313
- const payload = action === "pool-check" ? {
314
- ...await session_pool_default.runHealthCheck(),
315
- summary: session_pool_default.getSummary()
316
- } : (await session_pool_default.reloadFromDisk(), {
317
- reloaded: true,
318
- summary: session_pool_default.getSummary(),
319
- items: buildTokenPoolSnapshot().items
320
- });
319
+ let payload;
320
+ if (action === "pool-check") {
321
+ payload = { ...await session_pool_default.runHealthCheck(), summary: session_pool_default.getSummary() };
322
+ } else {
323
+ session_pool_default.reloadFromDisk();
324
+ payload = { reloaded: true, summary: session_pool_default.getSummary(), items: buildTokenPoolSnapshot().items };
325
+ }
321
326
  if (args.json) {
322
327
  deps.printCommandJson(`token.${action}`, deps.unwrapBody(payload));
323
328
  return;
@@ -334,12 +339,12 @@ function createTokenSubcommands(deps) {
334
339
  },
335
340
  {
336
341
  name: "check",
337
- description: "Validate tokens directly",
338
- usageLine: " jimeng token check --token <token> [--token <token> ...] [options]",
342
+ description: "Validate tokens",
343
+ usageLine: " jimeng token check [options]",
339
344
  options: [
340
- " --token <token> Token, can be repeated",
345
+ " --token <token> Token, can be repeated (default: all enabled tokens)",
341
346
  " --token-file <path> Read tokens from file (one per line, # for comments)",
342
- " --region <region> X-Region, default cn (cn/us/hk/jp/sg)",
347
+ " --region <region> Override region (default: token's registered region)",
343
348
  deps.jsonOption,
344
349
  deps.helpOption
345
350
  ],
@@ -347,12 +352,12 @@ function createTokenSubcommands(deps) {
347
352
  },
348
353
  {
349
354
  name: "points",
350
- description: "Query token points directly",
355
+ description: "Query token points",
351
356
  usageLine: " jimeng token points [options]",
352
357
  options: [
353
358
  " --token <token> Token, can be repeated",
354
359
  " --token-file <path> Read tokens from file (one per line, # for comments)",
355
- " --region <region> Filter tokens by X-Region, default cn (cn/us/hk/jp/sg)",
360
+ " --region <region> Filter tokens by region (cn/us/hk/jp/sg)",
356
361
  deps.jsonOption,
357
362
  deps.helpOption
358
363
  ],
@@ -360,12 +365,12 @@ function createTokenSubcommands(deps) {
360
365
  },
361
366
  {
362
367
  name: "receive",
363
- description: "Receive token credits directly",
368
+ description: "Receive token credits",
364
369
  usageLine: " jimeng token receive [options]",
365
370
  options: [
366
371
  " --token <token> Token, can be repeated",
367
372
  " --token-file <path> Read tokens from file (one per line, # for comments)",
368
- " --region <region> Filter tokens by X-Region, default cn (cn/us/hk/jp/sg)",
373
+ " --region <region> Filter tokens by region (cn/us/hk/jp/sg)",
369
374
  deps.jsonOption,
370
375
  deps.helpOption
371
376
  ],
@@ -497,11 +502,71 @@ function printTaskInfo(task, deps) {
497
502
  deps.printJson(task.data);
498
503
  }
499
504
  }
505
+ function outputTaskResult(command, normalized, isJson, deps) {
506
+ const taskInfo = collectTaskInfo(normalized, deps);
507
+ if (!taskInfo) {
508
+ const body = deps.unwrapBody(normalized);
509
+ if (isJson) deps.printCommandJson(command, body);
510
+ else deps.printJson(body);
511
+ return;
512
+ }
513
+ if (isJson) deps.printCommandJson(command, taskInfo);
514
+ else printTaskInfo(taskInfo, deps);
515
+ }
516
+ function resolveSingleQueryToken(explicitToken, explicitRegion, deps) {
517
+ var _a;
518
+ const regionCode = explicitRegion ? deps.parseRegionOrFail(explicitRegion) : void 0;
519
+ if (explicitToken) {
520
+ const poolRegion = (_a = session_pool_default.getTokenEntry(explicitToken)) == null ? void 0 : _a.region;
521
+ const region = regionCode || poolRegion;
522
+ if (!region) {
523
+ deps.fail("Missing region for token. Provide --region or register token in token-pool.");
524
+ }
525
+ return { token: explicitToken, region };
526
+ }
527
+ if (!regionCode) {
528
+ const entry = session_pool_default.getEntries(false).find(
529
+ (item) => item.enabled && item.live !== false && item.region
530
+ );
531
+ if (!entry) {
532
+ deps.fail("No token available. Provide --token, --region, or --all.");
533
+ }
534
+ return { token: entry.token, region: entry.region };
535
+ }
536
+ return { token: void 0, region: regionCode };
537
+ }
538
+ function printModelIds(models) {
539
+ for (const item of models) {
540
+ if (!item || typeof item !== "object") continue;
541
+ const id = item.id;
542
+ if (typeof id === "string" && id.length > 0) console.log(id);
543
+ }
544
+ }
545
+ function printModelVerbose(models) {
546
+ for (const item of models) {
547
+ if (!item || typeof item !== "object") continue;
548
+ const m = item;
549
+ const id = typeof m.id === "string" ? m.id : "";
550
+ if (!id) continue;
551
+ const type = typeof m.model_type === "string" ? m.model_type : "-";
552
+ const desc = typeof m.description === "string" ? m.description : "-";
553
+ const caps = Array.isArray(m.capabilities) ? m.capabilities.filter((c) => typeof c === "string").join(",") : "-";
554
+ console.log(`${id} [${type}] ${desc}`);
555
+ console.log(` capabilities: ${caps}`);
556
+ const params = m.params;
557
+ if (params && typeof params === "object") {
558
+ for (const [key, vals] of Object.entries(params)) {
559
+ if (Array.isArray(vals)) {
560
+ console.log(` ${key}: ${vals.join(", ")}`);
561
+ }
562
+ }
563
+ }
564
+ console.log("");
565
+ }
566
+ }
500
567
  function createQueryCommandHandlers(deps) {
501
568
  const handleModelsRefresh = async (argv) => {
502
- const args = minimist2(argv, {
503
- boolean: ["help", "json"]
504
- });
569
+ const args = minimist2(argv, { boolean: ["help", "json"] });
505
570
  if (args.help) {
506
571
  console.log(deps.usageModelsRefresh());
507
572
  return;
@@ -529,48 +594,72 @@ function createQueryCommandHandlers(deps) {
529
594
  const handleModelsList = async (argv) => {
530
595
  const args = minimist2(argv, {
531
596
  string: ["region", "token"],
532
- boolean: ["help", "json", "verbose"]
597
+ boolean: ["help", "json", "verbose", "all"]
533
598
  });
534
599
  if (args.help) {
535
600
  console.log(deps.usageModelsList());
536
601
  return;
537
602
  }
538
- const region = deps.getRegionWithDefault(args);
539
- const parsedRegion = deps.parseRegionOrFail(region);
540
- const token = deps.getSingleString(args, "token");
603
+ const isJson = Boolean(args.json);
604
+ const isVerbose = Boolean(args.verbose);
605
+ const explicitRegion = deps.getSingleString(args, "region");
606
+ const explicitToken = deps.getSingleString(args, "token");
541
607
  await deps.ensureTokenPoolReady();
542
- const auth = token ? `Bearer ${token}` : void 0;
543
- const direct = await getLiveModels(auth, parsedRegion || region);
544
- const normalized = { object: "list", data: direct.data };
545
- if (args.json) {
546
- deps.printCommandJson("models.list", normalized, { region: region || null });
608
+ if (args.all) {
609
+ const entries = session_pool_default.getEntries(false).filter(
610
+ (item) => item.enabled && item.live !== false && item.region
611
+ );
612
+ if (entries.length === 0) {
613
+ deps.fail("No enabled+live tokens with region found in pool.");
614
+ }
615
+ const results = await Promise.all(
616
+ entries.map(async (entry) => {
617
+ const masked = maskToken(entry.token);
618
+ try {
619
+ const direct2 = await getLiveModels(`Bearer ${entry.token}`, entry.region);
620
+ return {
621
+ token: masked,
622
+ region: entry.region,
623
+ source: direct2.source,
624
+ models: isVerbose ? direct2.data : direct2.data.map((m) => m.id)
625
+ };
626
+ } catch (error) {
627
+ return { token: masked, region: entry.region, error: error instanceof Error ? error.message : String(error) };
628
+ }
629
+ })
630
+ );
631
+ if (isJson) {
632
+ deps.printCommandJson("models.list", results);
633
+ return;
634
+ }
635
+ for (const r of results) {
636
+ console.log(`[${r.region}] ${r.token}`);
637
+ if (r.error) {
638
+ console.log(` error: ${r.error}`);
639
+ } else if (isVerbose) {
640
+ printModelVerbose(r.models);
641
+ } else {
642
+ for (const id of r.models) console.log(` ${id}`);
643
+ }
644
+ console.log("");
645
+ }
547
646
  return;
548
647
  }
549
- const data = normalized && typeof normalized === "object" && Array.isArray(normalized.data) ? normalized.data : [];
550
- if (data.length === 0) {
551
- deps.fail(`No models found in response: ${JSON.stringify(normalized)}`);
552
- }
553
- if (args.verbose) {
554
- console.log("id type desc capabilities");
555
- for (const item of data) {
556
- if (!item || typeof item !== "object") continue;
557
- const model = item;
558
- const id = typeof model.id === "string" ? model.id : "";
559
- if (!id) continue;
560
- const modelType = typeof model.model_type === "string" ? model.model_type : "-";
561
- const description = typeof model.description === "string" ? model.description : "-";
562
- const capabilities = Array.isArray(model.capabilities) ? model.capabilities.filter((cap) => typeof cap === "string").join(",") : "-";
563
- console.log(`${id} type=${modelType} desc=${description} capabilities=${capabilities}`);
564
- }
648
+ const { token, region } = resolveSingleQueryToken(explicitToken, explicitRegion, deps);
649
+ const direct = await getLiveModels(token ? `Bearer ${token}` : void 0, region);
650
+ const models = direct.data;
651
+ if (isJson) {
652
+ deps.printCommandJson("models.list", { object: "list", data: models }, {
653
+ region: region || null,
654
+ token: token ? `${token.slice(0, 4)}...` : null
655
+ });
565
656
  return;
566
657
  }
567
- for (const item of data) {
568
- if (!item || typeof item !== "object") continue;
569
- const id = item.id;
570
- if (typeof id === "string" && id.length > 0) {
571
- console.log(id);
572
- }
658
+ if (models.length === 0) {
659
+ deps.fail("No models found.");
573
660
  }
661
+ if (isVerbose) printModelVerbose(models);
662
+ else printModelIds(models);
574
663
  };
575
664
  const handleTaskGet = async (argv) => {
576
665
  const args = minimist2(argv, {
@@ -587,42 +676,13 @@ function createQueryCommandHandlers(deps) {
587
676
  ${deps.usageTaskGet()}`);
588
677
  const type = parseTaskTypeOrFail(deps.getSingleString(args, "type"), deps);
589
678
  const responseFormat = parseResponseFormatOrFail(deps.getSingleString(args, "response-format"), deps);
590
- const token = deps.getSingleString(args, "token");
591
- const region = deps.getRegionWithDefault(args);
592
- const isJson = Boolean(args.json);
593
- const pick = await deps.pickDirectTokenForTask(token, region);
594
- const normalized = await getTaskResponse(
595
- taskId,
596
- pick.token,
597
- buildRegionInfo(pick.region),
598
- {
599
- type,
600
- responseFormat
601
- }
602
- );
603
- const taskInfo = collectTaskInfo(normalized, deps);
604
- if (!taskInfo) {
605
- if (isJson) {
606
- deps.printCommandJson("task.get", deps.unwrapBody(normalized));
607
- } else {
608
- deps.printJson(deps.unwrapBody(normalized));
609
- }
610
- return;
611
- }
612
- if (isJson) deps.printCommandJson("task.get", taskInfo);
613
- else printTaskInfo(taskInfo, deps);
679
+ const pick = await deps.pickDirectTokenForTask(deps.getSingleString(args, "token"), deps.getSingleString(args, "region"));
680
+ const normalized = await getTaskResponse(taskId, pick.token, buildRegionInfo(pick.region), { type, responseFormat });
681
+ outputTaskResult("task.get", normalized, Boolean(args.json), deps);
614
682
  };
615
683
  const handleTaskWait = async (argv) => {
616
684
  const args = minimist2(argv, {
617
- string: [
618
- "token",
619
- "region",
620
- "task-id",
621
- "type",
622
- "response-format",
623
- "wait-timeout-seconds",
624
- "poll-interval-ms"
625
- ],
685
+ string: ["token", "region", "task-id", "type", "response-format", "wait-timeout-seconds", "poll-interval-ms"],
626
686
  boolean: ["help", "json"]
627
687
  });
628
688
  if (args.help) {
@@ -633,41 +693,18 @@ ${deps.usageTaskGet()}`);
633
693
  if (!taskId) deps.fail(`Missing required --task-id.
634
694
 
635
695
  ${deps.usageTaskWait()}`);
636
- const token = deps.getSingleString(args, "token");
637
- const region = deps.getRegionWithDefault(args);
638
- const isJson = Boolean(args.json);
639
- const body = {};
640
696
  const type = parseTaskTypeOrFail(deps.getSingleString(args, "type"), deps);
641
697
  const responseFormat = parseResponseFormatOrFail(deps.getSingleString(args, "response-format"), deps);
642
- if (type) body.type = type;
643
- body.response_format = responseFormat;
644
698
  const waitTimeoutSeconds = parsePositiveNumberOption(args, "wait-timeout-seconds", deps);
645
- if (waitTimeoutSeconds !== void 0) body.wait_timeout_seconds = waitTimeoutSeconds;
646
699
  const pollIntervalMs = parsePositiveNumberOption(args, "poll-interval-ms", deps);
647
- if (pollIntervalMs !== void 0) body.poll_interval_ms = pollIntervalMs;
648
- const pick = await deps.pickDirectTokenForTask(token, region);
649
- const normalized = await waitForTaskResponse(
650
- taskId,
651
- pick.token,
652
- buildRegionInfo(pick.region),
653
- {
654
- type,
655
- responseFormat,
656
- waitTimeoutSeconds: typeof body.wait_timeout_seconds === "number" ? body.wait_timeout_seconds : void 0,
657
- pollIntervalMs: typeof body.poll_interval_ms === "number" ? body.poll_interval_ms : void 0
658
- }
659
- );
660
- const taskInfo = collectTaskInfo(normalized, deps);
661
- if (!taskInfo) {
662
- if (isJson) {
663
- deps.printCommandJson("task.wait", deps.unwrapBody(normalized));
664
- } else {
665
- deps.printJson(deps.unwrapBody(normalized));
666
- }
667
- return;
668
- }
669
- if (isJson) deps.printCommandJson("task.wait", taskInfo);
670
- else printTaskInfo(taskInfo, deps);
700
+ const pick = await deps.pickDirectTokenForTask(deps.getSingleString(args, "token"), deps.getSingleString(args, "region"));
701
+ const normalized = await waitForTaskResponse(taskId, pick.token, buildRegionInfo(pick.region), {
702
+ type,
703
+ responseFormat,
704
+ waitTimeoutSeconds,
705
+ pollIntervalMs
706
+ });
707
+ outputTaskResult("task.wait", normalized, Boolean(args.json), deps);
671
708
  };
672
709
  const handleTaskList = async (argv) => {
673
710
  const args = minimist2(argv, {
@@ -678,24 +715,18 @@ ${deps.usageTaskWait()}`);
678
715
  console.log(deps.usageTaskList());
679
716
  return;
680
717
  }
681
- const token = deps.getSingleString(args, "token");
682
- const region = deps.getRegionWithDefault(args);
683
718
  const type = deps.getSingleString(args, "type");
684
- const countRaw = deps.getSingleString(args, "count");
685
- const count = countRaw ? Number(countRaw) : 20;
686
- const isJson = Boolean(args.json);
687
719
  if (type && type !== "image" && type !== "video" && type !== "all") {
688
720
  deps.fail(`Invalid --type: ${type}. Use image, video, or all.`);
689
721
  }
690
- const pick = await deps.pickDirectTokenForTask(token, region);
691
- const result = await getAssetList(
692
- pick.token,
693
- buildRegionInfo(pick.region),
694
- {
695
- count: Number.isFinite(count) && count > 0 ? count : 20,
696
- type
697
- }
698
- );
722
+ const countRaw = deps.getSingleString(args, "count");
723
+ const count = countRaw ? Number(countRaw) : 20;
724
+ const isJson = Boolean(args.json);
725
+ const pick = await deps.pickDirectTokenForTask(deps.getSingleString(args, "token"), deps.getSingleString(args, "region"));
726
+ const result = await getAssetList(pick.token, buildRegionInfo(pick.region), {
727
+ count: Number.isFinite(count) && count > 0 ? count : 20,
728
+ type
729
+ });
699
730
  if (isJson) {
700
731
  deps.printCommandJson("task.list", {
701
732
  has_more: result.hasMore,
@@ -714,9 +745,7 @@ ${deps.usageTaskWait()}`);
714
745
  const modelShort = item.modelName || item.modelReqKey || "-";
715
746
  const promptShort = item.prompt.length > 50 ? item.prompt.slice(0, 50) + "..." : item.prompt;
716
747
  console.log(`${item.id} ${typeLabel} ${statusLabel.padEnd(4)} ${time} ${modelShort.padEnd(20)} ${promptShort}`);
717
- if (item.imageUrl) {
718
- console.log(` ${item.imageUrl}`);
719
- }
748
+ if (item.imageUrl) console.log(` ${item.imageUrl}`);
720
749
  }
721
750
  };
722
751
  return {
@@ -726,12 +755,12 @@ ${deps.usageTaskWait()}`);
726
755
  handleTaskWait,
727
756
  handleTaskList,
728
757
  printTaskInfo: (task) => {
729
- const normalized = collectTaskInfo(task, deps);
730
- if (!normalized) {
758
+ const info = collectTaskInfo(task, deps);
759
+ if (!info) {
731
760
  deps.printJson(task);
732
761
  return;
733
762
  }
734
- printTaskInfo(normalized, deps);
763
+ printTaskInfo(info, deps);
735
764
  }
736
765
  };
737
766
  }
@@ -965,7 +994,19 @@ function applyWaitOptionsToBody(body, args, deps, includeWaitFlag = true) {
965
994
  return wait;
966
995
  }
967
996
  async function downloadBinary(url, deps) {
968
- const response = await fetch(url);
997
+ const controller = new AbortController();
998
+ const timeout = setTimeout(() => controller.abort(), 12e4);
999
+ let response;
1000
+ try {
1001
+ response = await fetch(url, { signal: controller.signal });
1002
+ } catch (err) {
1003
+ clearTimeout(timeout);
1004
+ if (err.name === "AbortError") {
1005
+ deps.fail(`Download timed out after 120s: ${url}`);
1006
+ }
1007
+ throw err;
1008
+ }
1009
+ clearTimeout(timeout);
969
1010
  if (!response.ok) {
970
1011
  deps.fail(`Download failed (${response.status}): ${url}`);
971
1012
  }
@@ -1034,6 +1075,9 @@ function createMediaCommandHandlers(deps) {
1034
1075
  if (!Number.isFinite(parsed)) {
1035
1076
  deps.fail(`Invalid --sample-strength: ${sampleStrengthRaw}`);
1036
1077
  }
1078
+ if (parsed < 0 || parsed > 1) {
1079
+ deps.fail(`Invalid --sample-strength: ${sampleStrengthRaw} (must be between 0 and 1)`);
1080
+ }
1037
1081
  body.sample_strength = parsed;
1038
1082
  }
1039
1083
  const pick = await deps.pickDirectTokenForGeneration(
@@ -1350,11 +1394,14 @@ import { execSync, spawn } from "child_process";
1350
1394
  import { existsSync } from "fs";
1351
1395
  import path4 from "path";
1352
1396
  import os from "os";
1353
- import { fileURLToPath } from "url";
1354
1397
  import minimist4 from "minimist";
1355
- var __filename = fileURLToPath(import.meta.url);
1356
- var __dirname = path4.dirname(__filename);
1357
- var LOGIN_SCRIPT = path4.join(__dirname, "..", "..", "scripts", "jimeng_login_helper.py");
1398
+ var LOGIN_SCRIPT = path4.join(
1399
+ path4.dirname(new URL(import.meta.url).pathname),
1400
+ "..",
1401
+ "..",
1402
+ "scripts",
1403
+ "jimeng_login_helper.py"
1404
+ );
1358
1405
  function createLoginCommandHandler(deps) {
1359
1406
  return async (argv) => {
1360
1407
  const args = minimist4(argv, {
@@ -1558,10 +1605,20 @@ function usageRoot() {
1558
1605
  }
1559
1606
  function usageModelsList() {
1560
1607
  return buildUsageText(" jimeng models list [options]", [
1561
- " --region <region> X-Region header, default cn (cn/us/hk/jp/sg)",
1608
+ " --token <token> Query with specific token",
1609
+ " --region <region> Query with specific region (cn/us/hk/jp/sg)",
1610
+ " --all Query all tokens in pool, grouped by token/region",
1562
1611
  " --verbose Print rich model fields",
1563
1612
  " --json Print full JSON response",
1564
1613
  HELP_OPTION
1614
+ ], [
1615
+ {
1616
+ title: "Notes:",
1617
+ lines: [
1618
+ " Without --token, --region, or --all, uses the first available token in pool.",
1619
+ " With --all, queries every enabled+live token and groups results by token/region."
1620
+ ]
1621
+ }
1565
1622
  ]);
1566
1623
  }
1567
1624
  function usageModelsRefresh() {
@@ -1721,7 +1778,7 @@ function usageVideoGenerate() {
1721
1778
  function usageTaskGet() {
1722
1779
  return buildUsageText(" jimeng task get --task-id <id> [options]", [
1723
1780
  " --token <token> Optional, override token-pool selection",
1724
- " --region <region> X-Region header, default cn (cn/us/hk/jp/sg)",
1781
+ " --region <region> Filter token by region (cn/us/hk/jp/sg)",
1725
1782
  " --task-id <id> Required history/task id",
1726
1783
  " --type <type> Optional image or video",
1727
1784
  " --response-format <fmt> Optional url or b64_json",
@@ -1732,7 +1789,7 @@ function usageTaskGet() {
1732
1789
  function usageTaskWait() {
1733
1790
  return buildUsageText(" jimeng task wait --task-id <id> [options]", [
1734
1791
  " --token <token> Optional, override token-pool selection",
1735
- " --region <region> X-Region header, default cn (cn/us/hk/jp/sg)",
1792
+ " --region <region> Filter token by region (cn/us/hk/jp/sg)",
1736
1793
  " --task-id <id> Required history/task id",
1737
1794
  " --type <type> Optional image or video",
1738
1795
  " --response-format <fmt> Optional url or b64_json",
@@ -1745,7 +1802,7 @@ function usageTaskWait() {
1745
1802
  function usageTaskList() {
1746
1803
  return buildUsageText(" jimeng task list [options]", [
1747
1804
  " --token <token> Optional, override token-pool selection",
1748
- " --region <region> X-Region header, default cn (cn/us/hk/jp/sg)",
1805
+ " --region <region> Filter token by region (cn/us/hk/jp/sg)",
1749
1806
  " --type <type> Filter by type: image, video, or all (default all)",
1750
1807
  " --count <num> Number of items per page (default 20)",
1751
1808
  JSON_OPTION,
@@ -1890,7 +1947,6 @@ var queryHandlers = createQueryCommandHandlers({
1890
1947
  usageTaskWait,
1891
1948
  usageTaskList,
1892
1949
  getSingleString,
1893
- getRegionWithDefault,
1894
1950
  parseRegionOrFail,
1895
1951
  ensureTokenPoolReady,
1896
1952
  pickDirectTokenForTask,