jimeng-cli 0.3.1 → 0.3.2

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
@@ -17,7 +17,7 @@ import {
17
17
  session_pool_default,
18
18
  upscaleImage,
19
19
  waitForTaskResponse
20
- } from "../chunk-2IIK4X7C.js";
20
+ } from "../chunk-FAXTAAQO.js";
21
21
 
22
22
  // src/cli/app.ts
23
23
  import process2 from "process";
@@ -28,8 +28,7 @@ import path from "path";
28
28
  import { access, readFile } from "fs/promises";
29
29
  import minimist from "minimist";
30
30
  function maskToken(token) {
31
- const n = token.length;
32
- if (n <= 10) return "***";
31
+ if (token.length <= 10) return "***";
33
32
  return `${token.slice(0, 4)}...${token.slice(-4)}`;
34
33
  }
35
34
  function formatUnixMs(value) {
@@ -44,14 +43,14 @@ function printTokenEntriesTable(items) {
44
43
  console.log("token region enabled live lastCredit lastCheckedAt failures");
45
44
  for (const item of items) {
46
45
  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) : "-";
46
+ const e = item;
47
+ const token = typeof e.token === "string" ? e.token : "-";
48
+ const region = typeof e.region === "string" ? e.region : "-";
49
+ const enabled = typeof e.enabled === "boolean" ? String(e.enabled) : "-";
50
+ const live = typeof e.live === "boolean" ? String(e.live) : "-";
51
+ const lastCredit = typeof e.lastCredit === "number" ? String(e.lastCredit) : "-";
52
+ const lastCheckedAt = formatUnixMs(e.lastCheckedAt);
53
+ const failures = typeof e.consecutiveFailures === "number" ? String(e.consecutiveFailures) : "-";
55
54
  console.log(`${token} ${region} ${enabled} ${live} ${lastCredit} ${lastCheckedAt} ${failures}`);
56
55
  }
57
56
  }
@@ -90,6 +89,30 @@ ${usage}`);
90
89
  }
91
90
  return deduped;
92
91
  }
92
+ function resolveTokenRegionPairs(explicitTokens, regionCode, deps, opts) {
93
+ if (explicitTokens.length > 0) {
94
+ return explicitTokens.map((token) => {
95
+ var _a;
96
+ const entryRegion = (_a = session_pool_default.getTokenEntry(token)) == null ? void 0 : _a.region;
97
+ const finalRegion = regionCode || entryRegion;
98
+ if (!finalRegion) {
99
+ deps.fail(`Missing region for token ${maskToken(token)}. Provide --region or register token in token-pool.`);
100
+ }
101
+ return { token, region: finalRegion };
102
+ });
103
+ }
104
+ const requireLive = (opts == null ? void 0 : opts.requireLive) ?? true;
105
+ const entries = session_pool_default.getEntries(false).filter((item) => {
106
+ if (!item.enabled || !item.region) return false;
107
+ if (requireLive && item.live === false) return false;
108
+ if (regionCode && item.region !== regionCode) return false;
109
+ return true;
110
+ });
111
+ if (entries.length === 0) {
112
+ deps.fail("No token available. Provide --token or configure token-pool.");
113
+ }
114
+ return entries.map((item) => ({ token: item.token, region: item.region }));
115
+ }
93
116
  function createTokenSubcommands(deps) {
94
117
  const handleTokenCheck = async (argv) => {
95
118
  const args = minimist(argv, {
@@ -101,74 +124,68 @@ function createTokenSubcommands(deps) {
101
124
  console.log(usage);
102
125
  return;
103
126
  }
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);
127
+ const explicitRegion = deps.getSingleString(args, "region");
128
+ const regionCode = explicitRegion ? deps.parseRegionOrFail(explicitRegion) : void 0;
129
+ await deps.ensureTokenPoolReady();
130
+ const explicitTokens = await collectTokensFromArgs(args, usage, deps, false);
131
+ const pairs = resolveTokenRegionPairs(explicitTokens, regionCode, deps, { requireLive: false });
110
132
  if (!args.json) {
111
- console.log(`Checking ${tokens.length} token(s)`);
133
+ console.log(`Checking ${pairs.length} token(s)`);
112
134
  }
113
- await deps.ensureTokenPoolReady();
114
135
  let invalid = 0;
115
136
  let requestErrors = 0;
116
137
  const results = [];
117
- for (const token of tokens) {
138
+ for (const { token, region } of pairs) {
118
139
  const masked = maskToken(token);
119
140
  try {
120
- const live = await getTokenLiveStatus(token, buildRegionInfo(regionCode));
141
+ const live = await getTokenLiveStatus(token, buildRegionInfo(region));
121
142
  await session_pool_default.syncTokenCheckResult(token, live);
122
- if (live === true) {
123
- if (!args.json) console.log(`[OK] ${masked} live=true`);
143
+ if (live) {
144
+ if (!args.json) console.log(`[OK] ${masked} (${region}) live=true`);
145
+ results.push({ token_masked: masked, region, live: true });
124
146
  } else {
125
147
  invalid += 1;
126
- if (!args.json) console.log(`[FAIL] ${masked} live=false`);
148
+ if (!args.json) console.log(`[FAIL] ${masked} (${region}) live=false`);
149
+ results.push({ token_masked: masked, region, live: false });
127
150
  }
128
- results.push({ token_masked: masked, live: live === true });
129
151
  } catch (error) {
130
152
  requestErrors += 1;
131
153
  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 });
154
+ if (!args.json) console.log(`[ERROR] ${masked} (${region}) ${message}`);
155
+ results.push({ token_masked: masked, region, error: message });
134
156
  }
135
157
  }
136
158
  if (args.json) {
137
159
  deps.printCommandJson("token.check", results, {
138
- total: tokens.length,
160
+ total: pairs.length,
139
161
  invalid,
140
162
  request_errors: requestErrors
141
163
  });
142
164
  } else {
143
- console.log(`Summary: total=${tokens.length} invalid=${invalid} request_errors=${requestErrors}`);
165
+ console.log(`Summary: total=${pairs.length} invalid=${invalid} request_errors=${requestErrors}`);
144
166
  }
145
167
  if (requestErrors > 0) process.exit(3);
146
168
  if (invalid > 0) process.exit(2);
147
169
  };
148
170
  const handleTokenList = async (argv) => {
149
- const args = minimist(argv, {
150
- boolean: ["help", "json"]
151
- });
152
- const usage = deps.getUsage("list");
171
+ const args = minimist(argv, { boolean: ["help", "json"] });
153
172
  if (args.help) {
154
- console.log(usage);
173
+ console.log(deps.getUsage("list"));
155
174
  return;
156
175
  }
157
176
  await deps.ensureTokenPoolReady();
158
- const normalized = buildTokenPoolSnapshot();
177
+ const snapshot = buildTokenPoolSnapshot();
159
178
  if (args.json) {
160
- deps.printCommandJson("token.list", normalized);
179
+ deps.printCommandJson("token.list", snapshot);
161
180
  return;
162
181
  }
163
- const body = normalized && typeof normalized === "object" ? normalized : {};
164
- const summary = body.summary;
165
- if (summary && typeof summary === "object") {
182
+ const body = snapshot && typeof snapshot === "object" ? snapshot : {};
183
+ if (body.summary && typeof body.summary === "object") {
166
184
  console.log("Summary:");
167
- deps.printJson(summary);
185
+ deps.printJson(body.summary);
168
186
  }
169
- const items = Array.isArray(body.items) ? body.items : [];
170
187
  console.log("Entries:");
171
- printTokenEntriesTable(items);
188
+ printTokenEntriesTable(Array.isArray(body.items) ? body.items : []);
172
189
  };
173
190
  const handleTokenPointsOrReceive = async (argv, action) => {
174
191
  const args = minimist(argv, {
@@ -180,45 +197,30 @@ function createTokenSubcommands(deps) {
180
197
  console.log(usage);
181
198
  return;
182
199
  }
183
- const region = deps.getRegionWithDefault(args);
184
- const regionCode = deps.parseRegionOrFail(region);
200
+ const regionArg = deps.getSingleString(args, "region");
201
+ const regionCode = regionArg ? deps.parseRegionOrFail(regionArg) : void 0;
185
202
  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.`);
193
- }
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
- }
203
+ const explicitTokens = await collectTokensFromArgs(args, usage, deps, false);
204
+ const pairs = resolveTokenRegionPairs(explicitTokens, regionCode, deps);
199
205
  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))
206
+ pairs.map(async ({ token, region }) => ({
207
+ token,
208
+ points: await getCredit(token, buildRegionInfo(region))
203
209
  }))
204
210
  ) : await Promise.all(
205
- resolvedTokens.map(async (item) => {
206
- const currentCredit = await getCredit(item.token, buildRegionInfo(item.region));
211
+ pairs.map(async ({ token, region }) => {
212
+ const regionInfo = buildRegionInfo(region);
213
+ const currentCredit = await getCredit(token, regionInfo);
207
214
  if (currentCredit.totalCredit <= 0) {
208
215
  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 };
216
+ await receiveCredit(token, regionInfo);
217
+ const updatedCredit = await getCredit(token, regionInfo);
218
+ return { token, credits: updatedCredit, received: true };
212
219
  } 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
- };
220
+ return { token, credits: currentCredit, received: false, error: (error == null ? void 0 : error.message) || String(error) };
219
221
  }
220
222
  }
221
- return { token: item.token, credits: currentCredit, received: false };
223
+ return { token, credits: currentCredit, received: false };
222
224
  })
223
225
  );
224
226
  if (args.json) {
@@ -237,28 +239,32 @@ function createTokenSubcommands(deps) {
237
239
  console.log(usage);
238
240
  return;
239
241
  }
240
- const region = deps.getRegionWithDefault(args);
241
242
  await deps.ensureTokenPoolReady();
242
243
  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
- };
244
+ let payload;
245
+ let jsonMeta;
246
+ if (action === "add") {
247
+ const region = deps.getRegionWithDefault(args);
248
+ const regionCode = deps.parseRegionOrFail(region);
249
+ payload = {
250
+ ...await session_pool_default.addTokens(tokens, { defaultRegion: regionCode || void 0 }),
251
+ summary: session_pool_default.getSummary()
252
+ };
253
+ jsonMeta = { region };
254
+ } else {
255
+ payload = {
256
+ ...await session_pool_default.removeTokens(tokens),
257
+ summary: session_pool_default.getSummary()
258
+ };
259
+ }
251
260
  if (args.json) {
252
- deps.printCommandJson(`token.${action}`, deps.unwrapBody(payload), { region });
261
+ deps.printCommandJson(`token.${action}`, deps.unwrapBody(payload), jsonMeta);
253
262
  return;
254
263
  }
255
264
  deps.printJson(deps.unwrapBody(payload));
256
265
  };
257
266
  const handleTokenEnableOrDisable = async (argv, action) => {
258
- const args = minimist(argv, {
259
- string: ["token"],
260
- boolean: ["help", "json"]
261
- });
267
+ const args = minimist(argv, { string: ["token"], boolean: ["help", "json"] });
262
268
  const usage = deps.getUsage(action);
263
269
  if (args.help) {
264
270
  console.log(usage);
@@ -280,44 +286,34 @@ function createTokenSubcommands(deps) {
280
286
  deps.printJson(deps.unwrapBody(payload));
281
287
  };
282
288
  const handleTokenPool = async (argv) => {
283
- const args = minimist(argv, {
284
- boolean: ["help", "json"]
285
- });
286
- const usage = deps.getUsage("pool");
289
+ const args = minimist(argv, { boolean: ["help", "json"] });
287
290
  if (args.help) {
288
- console.log(usage);
291
+ console.log(deps.getUsage("pool"));
289
292
  return;
290
293
  }
291
294
  await deps.ensureTokenPoolReady();
292
- const normalized = buildTokenPoolSnapshot();
295
+ const snapshot = buildTokenPoolSnapshot();
293
296
  if (args.json) {
294
- deps.printCommandJson("token.pool", normalized);
297
+ deps.printCommandJson("token.pool", snapshot);
295
298
  return;
296
299
  }
297
- const body = normalized && typeof normalized === "object" ? normalized : {};
300
+ const body = snapshot && typeof snapshot === "object" ? snapshot : {};
298
301
  console.log("Summary:");
299
302
  deps.printJson(body.summary ?? {});
300
303
  console.log("Entries:");
301
304
  printTokenEntriesTable(Array.isArray(body.items) ? body.items : []);
302
305
  };
303
306
  const handleTokenPoolCheckOrReload = async (argv, action) => {
304
- const args = minimist(argv, {
305
- boolean: ["help", "json"]
306
- });
307
- const usage = deps.getUsage(action);
307
+ const args = minimist(argv, { boolean: ["help", "json"] });
308
308
  if (args.help) {
309
- console.log(usage);
309
+ console.log(deps.getUsage(action));
310
310
  return;
311
311
  }
312
312
  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
- });
313
+ const payload = action === "pool-check" ? { ...await session_pool_default.runHealthCheck(), summary: session_pool_default.getSummary() } : (() => {
314
+ session_pool_default.reloadFromDisk();
315
+ return { reloaded: true, summary: session_pool_default.getSummary(), items: buildTokenPoolSnapshot().items };
316
+ })();
321
317
  if (args.json) {
322
318
  deps.printCommandJson(`token.${action}`, deps.unwrapBody(payload));
323
319
  return;
@@ -334,12 +330,12 @@ function createTokenSubcommands(deps) {
334
330
  },
335
331
  {
336
332
  name: "check",
337
- description: "Validate tokens directly",
338
- usageLine: " jimeng token check --token <token> [--token <token> ...] [options]",
333
+ description: "Validate tokens",
334
+ usageLine: " jimeng token check [options]",
339
335
  options: [
340
- " --token <token> Token, can be repeated",
336
+ " --token <token> Token, can be repeated (default: all enabled tokens)",
341
337
  " --token-file <path> Read tokens from file (one per line, # for comments)",
342
- " --region <region> X-Region, default cn (cn/us/hk/jp/sg)",
338
+ " --region <region> Override region (default: token's registered region)",
343
339
  deps.jsonOption,
344
340
  deps.helpOption
345
341
  ],
@@ -347,12 +343,12 @@ function createTokenSubcommands(deps) {
347
343
  },
348
344
  {
349
345
  name: "points",
350
- description: "Query token points directly",
346
+ description: "Query token points",
351
347
  usageLine: " jimeng token points [options]",
352
348
  options: [
353
349
  " --token <token> Token, can be repeated",
354
350
  " --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)",
351
+ " --region <region> Filter tokens by region (cn/us/hk/jp/sg)",
356
352
  deps.jsonOption,
357
353
  deps.helpOption
358
354
  ],
@@ -360,12 +356,12 @@ function createTokenSubcommands(deps) {
360
356
  },
361
357
  {
362
358
  name: "receive",
363
- description: "Receive token credits directly",
359
+ description: "Receive token credits",
364
360
  usageLine: " jimeng token receive [options]",
365
361
  options: [
366
362
  " --token <token> Token, can be repeated",
367
363
  " --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)",
364
+ " --region <region> Filter tokens by region (cn/us/hk/jp/sg)",
369
365
  deps.jsonOption,
370
366
  deps.helpOption
371
367
  ],
@@ -497,11 +493,62 @@ function printTaskInfo(task, deps) {
497
493
  deps.printJson(task.data);
498
494
  }
499
495
  }
496
+ function outputTaskResult(command, normalized, isJson, deps) {
497
+ const taskInfo = collectTaskInfo(normalized, deps);
498
+ if (!taskInfo) {
499
+ const body = deps.unwrapBody(normalized);
500
+ if (isJson) deps.printCommandJson(command, body);
501
+ else deps.printJson(body);
502
+ return;
503
+ }
504
+ if (isJson) deps.printCommandJson(command, taskInfo);
505
+ else printTaskInfo(taskInfo, deps);
506
+ }
507
+ function resolveSingleQueryToken(explicitToken, explicitRegion, deps) {
508
+ var _a;
509
+ const regionCode = explicitRegion ? deps.parseRegionOrFail(explicitRegion) : void 0;
510
+ if (explicitToken) {
511
+ const poolRegion = (_a = session_pool_default.getTokenEntry(explicitToken)) == null ? void 0 : _a.region;
512
+ const region = regionCode || poolRegion;
513
+ if (!region) {
514
+ deps.fail("Missing region for token. Provide --region or register token in token-pool.");
515
+ }
516
+ return { token: explicitToken, region };
517
+ }
518
+ if (!regionCode) {
519
+ const entry = session_pool_default.getEntries(false).find(
520
+ (item) => item.enabled && item.live !== false && item.region
521
+ );
522
+ if (!entry) {
523
+ deps.fail("No token available. Provide --token, --region, or --all.");
524
+ }
525
+ return { token: entry.token, region: entry.region };
526
+ }
527
+ return { token: void 0, region: regionCode };
528
+ }
529
+ function printModelIds(models) {
530
+ for (const item of models) {
531
+ if (!item || typeof item !== "object") continue;
532
+ const id = item.id;
533
+ if (typeof id === "string" && id.length > 0) console.log(id);
534
+ }
535
+ }
536
+ function printModelVerbose(models) {
537
+ console.log("id type desc capabilities");
538
+ for (const item of models) {
539
+ if (!item || typeof item !== "object") continue;
540
+ const m = item;
541
+ const id = typeof m.id === "string" ? m.id : "";
542
+ if (!id) continue;
543
+ const type = typeof m.model_type === "string" ? m.model_type : "-";
544
+ const desc = typeof m.description === "string" ? m.description : "-";
545
+ const caps = Array.isArray(m.capabilities) ? m.capabilities.filter((c) => typeof c === "string").join(",") : "-";
546
+ console.log(`${id} type=${type} desc=${desc} capabilities=${caps}`);
547
+ }
548
+ }
500
549
  function createQueryCommandHandlers(deps) {
501
550
  const handleModelsRefresh = async (argv) => {
502
- const args = minimist2(argv, {
503
- boolean: ["help", "json"]
504
- });
551
+ const args = minimist2(argv, { boolean: ["help", "json"] });
505
552
  if (args.help) {
506
553
  console.log(deps.usageModelsRefresh());
507
554
  return;
@@ -529,48 +576,68 @@ function createQueryCommandHandlers(deps) {
529
576
  const handleModelsList = async (argv) => {
530
577
  const args = minimist2(argv, {
531
578
  string: ["region", "token"],
532
- boolean: ["help", "json", "verbose"]
579
+ boolean: ["help", "json", "verbose", "all"]
533
580
  });
534
581
  if (args.help) {
535
582
  console.log(deps.usageModelsList());
536
583
  return;
537
584
  }
538
- const region = deps.getRegionWithDefault(args);
539
- const parsedRegion = deps.parseRegionOrFail(region);
540
- const token = deps.getSingleString(args, "token");
585
+ const isJson = Boolean(args.json);
586
+ const isVerbose = Boolean(args.verbose);
587
+ const explicitRegion = deps.getSingleString(args, "region");
588
+ const explicitToken = deps.getSingleString(args, "token");
541
589
  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 });
590
+ if (args.all) {
591
+ const entries = session_pool_default.getEntries(false).filter(
592
+ (item) => item.enabled && item.live !== false && item.region
593
+ );
594
+ if (entries.length === 0) {
595
+ deps.fail("No enabled+live tokens with region found in pool.");
596
+ }
597
+ const results = [];
598
+ for (const entry of entries) {
599
+ const masked = entry.token.length <= 10 ? "***" : `${entry.token.slice(0, 4)}...${entry.token.slice(-4)}`;
600
+ try {
601
+ const direct2 = await getLiveModels(`Bearer ${entry.token}`, entry.region);
602
+ results.push({
603
+ token: masked,
604
+ region: entry.region,
605
+ models: direct2.data.map((m) => m.id)
606
+ });
607
+ } catch (error) {
608
+ results.push({ token: masked, region: entry.region, error: error.message });
609
+ }
610
+ }
611
+ if (isJson) {
612
+ deps.printCommandJson("models.list", results);
613
+ return;
614
+ }
615
+ for (const r of results) {
616
+ console.log(`[${r.region}] ${r.token}`);
617
+ if (r.error) {
618
+ console.log(` error: ${r.error}`);
619
+ } else {
620
+ for (const id of r.models) console.log(` ${id}`);
621
+ }
622
+ console.log("");
623
+ }
547
624
  return;
548
625
  }
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
- }
626
+ const { token, region } = resolveSingleQueryToken(explicitToken, explicitRegion, deps);
627
+ const direct = await getLiveModels(token ? `Bearer ${token}` : void 0, region);
628
+ const models = direct.data;
629
+ if (isJson) {
630
+ deps.printCommandJson("models.list", { object: "list", data: models }, {
631
+ region: region || null,
632
+ token: token ? `${token.slice(0, 4)}...` : null
633
+ });
565
634
  return;
566
635
  }
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
- }
636
+ if (models.length === 0) {
637
+ deps.fail("No models found.");
573
638
  }
639
+ if (isVerbose) printModelVerbose(models);
640
+ else printModelIds(models);
574
641
  };
575
642
  const handleTaskGet = async (argv) => {
576
643
  const args = minimist2(argv, {
@@ -587,42 +654,13 @@ function createQueryCommandHandlers(deps) {
587
654
  ${deps.usageTaskGet()}`);
588
655
  const type = parseTaskTypeOrFail(deps.getSingleString(args, "type"), deps);
589
656
  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);
657
+ const pick = await deps.pickDirectTokenForTask(deps.getSingleString(args, "token"), deps.getSingleString(args, "region"));
658
+ const normalized = await getTaskResponse(taskId, pick.token, buildRegionInfo(pick.region), { type, responseFormat });
659
+ outputTaskResult("task.get", normalized, Boolean(args.json), deps);
614
660
  };
615
661
  const handleTaskWait = async (argv) => {
616
662
  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
- ],
663
+ string: ["token", "region", "task-id", "type", "response-format", "wait-timeout-seconds", "poll-interval-ms"],
626
664
  boolean: ["help", "json"]
627
665
  });
628
666
  if (args.help) {
@@ -633,41 +671,18 @@ ${deps.usageTaskGet()}`);
633
671
  if (!taskId) deps.fail(`Missing required --task-id.
634
672
 
635
673
  ${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
674
  const type = parseTaskTypeOrFail(deps.getSingleString(args, "type"), deps);
641
675
  const responseFormat = parseResponseFormatOrFail(deps.getSingleString(args, "response-format"), deps);
642
- if (type) body.type = type;
643
- body.response_format = responseFormat;
644
676
  const waitTimeoutSeconds = parsePositiveNumberOption(args, "wait-timeout-seconds", deps);
645
- if (waitTimeoutSeconds !== void 0) body.wait_timeout_seconds = waitTimeoutSeconds;
646
677
  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);
678
+ const pick = await deps.pickDirectTokenForTask(deps.getSingleString(args, "token"), deps.getSingleString(args, "region"));
679
+ const normalized = await waitForTaskResponse(taskId, pick.token, buildRegionInfo(pick.region), {
680
+ type,
681
+ responseFormat,
682
+ waitTimeoutSeconds,
683
+ pollIntervalMs
684
+ });
685
+ outputTaskResult("task.wait", normalized, Boolean(args.json), deps);
671
686
  };
672
687
  const handleTaskList = async (argv) => {
673
688
  const args = minimist2(argv, {
@@ -678,24 +693,18 @@ ${deps.usageTaskWait()}`);
678
693
  console.log(deps.usageTaskList());
679
694
  return;
680
695
  }
681
- const token = deps.getSingleString(args, "token");
682
- const region = deps.getRegionWithDefault(args);
683
696
  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
697
  if (type && type !== "image" && type !== "video" && type !== "all") {
688
698
  deps.fail(`Invalid --type: ${type}. Use image, video, or all.`);
689
699
  }
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
- );
700
+ const countRaw = deps.getSingleString(args, "count");
701
+ const count = countRaw ? Number(countRaw) : 20;
702
+ const isJson = Boolean(args.json);
703
+ const pick = await deps.pickDirectTokenForTask(deps.getSingleString(args, "token"), deps.getSingleString(args, "region"));
704
+ const result = await getAssetList(pick.token, buildRegionInfo(pick.region), {
705
+ count: Number.isFinite(count) && count > 0 ? count : 20,
706
+ type
707
+ });
699
708
  if (isJson) {
700
709
  deps.printCommandJson("task.list", {
701
710
  has_more: result.hasMore,
@@ -714,9 +723,7 @@ ${deps.usageTaskWait()}`);
714
723
  const modelShort = item.modelName || item.modelReqKey || "-";
715
724
  const promptShort = item.prompt.length > 50 ? item.prompt.slice(0, 50) + "..." : item.prompt;
716
725
  console.log(`${item.id} ${typeLabel} ${statusLabel.padEnd(4)} ${time} ${modelShort.padEnd(20)} ${promptShort}`);
717
- if (item.imageUrl) {
718
- console.log(` ${item.imageUrl}`);
719
- }
726
+ if (item.imageUrl) console.log(` ${item.imageUrl}`);
720
727
  }
721
728
  };
722
729
  return {
@@ -726,12 +733,12 @@ ${deps.usageTaskWait()}`);
726
733
  handleTaskWait,
727
734
  handleTaskList,
728
735
  printTaskInfo: (task) => {
729
- const normalized = collectTaskInfo(task, deps);
730
- if (!normalized) {
736
+ const info = collectTaskInfo(task, deps);
737
+ if (!info) {
731
738
  deps.printJson(task);
732
739
  return;
733
740
  }
734
- printTaskInfo(normalized, deps);
741
+ printTaskInfo(info, deps);
735
742
  }
736
743
  };
737
744
  }
@@ -965,7 +972,19 @@ function applyWaitOptionsToBody(body, args, deps, includeWaitFlag = true) {
965
972
  return wait;
966
973
  }
967
974
  async function downloadBinary(url, deps) {
968
- const response = await fetch(url);
975
+ const controller = new AbortController();
976
+ const timeout = setTimeout(() => controller.abort(), 12e4);
977
+ let response;
978
+ try {
979
+ response = await fetch(url, { signal: controller.signal });
980
+ } catch (err) {
981
+ clearTimeout(timeout);
982
+ if (err.name === "AbortError") {
983
+ deps.fail(`Download timed out after 120s: ${url}`);
984
+ }
985
+ throw err;
986
+ }
987
+ clearTimeout(timeout);
969
988
  if (!response.ok) {
970
989
  deps.fail(`Download failed (${response.status}): ${url}`);
971
990
  }
@@ -1034,6 +1053,9 @@ function createMediaCommandHandlers(deps) {
1034
1053
  if (!Number.isFinite(parsed)) {
1035
1054
  deps.fail(`Invalid --sample-strength: ${sampleStrengthRaw}`);
1036
1055
  }
1056
+ if (parsed < 0 || parsed > 1) {
1057
+ deps.fail(`Invalid --sample-strength: ${sampleStrengthRaw} (must be between 0 and 1)`);
1058
+ }
1037
1059
  body.sample_strength = parsed;
1038
1060
  }
1039
1061
  const pick = await deps.pickDirectTokenForGeneration(
@@ -1350,11 +1372,14 @@ import { execSync, spawn } from "child_process";
1350
1372
  import { existsSync } from "fs";
1351
1373
  import path4 from "path";
1352
1374
  import os from "os";
1353
- import { fileURLToPath } from "url";
1354
1375
  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");
1376
+ var LOGIN_SCRIPT = path4.join(
1377
+ path4.dirname(new URL(import.meta.url).pathname),
1378
+ "..",
1379
+ "..",
1380
+ "scripts",
1381
+ "jimeng_login_helper.py"
1382
+ );
1358
1383
  function createLoginCommandHandler(deps) {
1359
1384
  return async (argv) => {
1360
1385
  const args = minimist4(argv, {
@@ -1558,10 +1583,20 @@ function usageRoot() {
1558
1583
  }
1559
1584
  function usageModelsList() {
1560
1585
  return buildUsageText(" jimeng models list [options]", [
1561
- " --region <region> X-Region header, default cn (cn/us/hk/jp/sg)",
1586
+ " --token <token> Query with specific token",
1587
+ " --region <region> Query with specific region (cn/us/hk/jp/sg)",
1588
+ " --all Query all tokens in pool, grouped by token/region",
1562
1589
  " --verbose Print rich model fields",
1563
1590
  " --json Print full JSON response",
1564
1591
  HELP_OPTION
1592
+ ], [
1593
+ {
1594
+ title: "Notes:",
1595
+ lines: [
1596
+ " Without --token, --region, or --all, uses the first available token in pool.",
1597
+ " With --all, queries every enabled+live token and groups results by token/region."
1598
+ ]
1599
+ }
1565
1600
  ]);
1566
1601
  }
1567
1602
  function usageModelsRefresh() {
@@ -1721,7 +1756,7 @@ function usageVideoGenerate() {
1721
1756
  function usageTaskGet() {
1722
1757
  return buildUsageText(" jimeng task get --task-id <id> [options]", [
1723
1758
  " --token <token> Optional, override token-pool selection",
1724
- " --region <region> X-Region header, default cn (cn/us/hk/jp/sg)",
1759
+ " --region <region> Filter token by region (cn/us/hk/jp/sg)",
1725
1760
  " --task-id <id> Required history/task id",
1726
1761
  " --type <type> Optional image or video",
1727
1762
  " --response-format <fmt> Optional url or b64_json",
@@ -1732,7 +1767,7 @@ function usageTaskGet() {
1732
1767
  function usageTaskWait() {
1733
1768
  return buildUsageText(" jimeng task wait --task-id <id> [options]", [
1734
1769
  " --token <token> Optional, override token-pool selection",
1735
- " --region <region> X-Region header, default cn (cn/us/hk/jp/sg)",
1770
+ " --region <region> Filter token by region (cn/us/hk/jp/sg)",
1736
1771
  " --task-id <id> Required history/task id",
1737
1772
  " --type <type> Optional image or video",
1738
1773
  " --response-format <fmt> Optional url or b64_json",
@@ -1745,7 +1780,7 @@ function usageTaskWait() {
1745
1780
  function usageTaskList() {
1746
1781
  return buildUsageText(" jimeng task list [options]", [
1747
1782
  " --token <token> Optional, override token-pool selection",
1748
- " --region <region> X-Region header, default cn (cn/us/hk/jp/sg)",
1783
+ " --region <region> Filter token by region (cn/us/hk/jp/sg)",
1749
1784
  " --type <type> Filter by type: image, video, or all (default all)",
1750
1785
  " --count <num> Number of items per page (default 20)",
1751
1786
  JSON_OPTION,
@@ -1890,7 +1925,6 @@ var queryHandlers = createQueryCommandHandlers({
1890
1925
  usageTaskWait,
1891
1926
  usageTaskList,
1892
1927
  getSingleString,
1893
- getRegionWithDefault,
1894
1928
  parseRegionOrFail,
1895
1929
  ensureTokenPoolReady,
1896
1930
  pickDirectTokenForTask,