maoda-commander-tt 0.0.12 → 0.0.16

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/main.js CHANGED
@@ -1823,7 +1823,7 @@ var PippitCommand = class extends BaseSubcommandHost {
1823
1823
  import { spawnSync } from "child_process";
1824
1824
  var GitBaseCommand = class extends BaseCommand {
1825
1825
  _configureArguments(cmd) {
1826
- cmd.argument("[msg]", "\u63D0\u4EA4\u6D88\u606F", "update");
1826
+ cmd.argument("[msg]", "\u63D0\u4EA4\u6D88\u606F", "feat: update");
1827
1827
  }
1828
1828
  _configureOptions(cmd) {
1829
1829
  cmd.option("-n, --no-verify", "\u8DF3\u8FC7 git hook \u6821\u9A8C");
@@ -1854,7 +1854,10 @@ var GitBaseCommand = class extends BaseCommand {
1854
1854
  encoding: "utf8"
1855
1855
  });
1856
1856
  if (result.error) {
1857
- return makeError(1, `\u6267\u884C git ${args.join(" ")} \u5931\u8D25: ${result.error.message}`);
1857
+ return makeError(
1858
+ 1,
1859
+ `\u6267\u884C git ${args.join(" ")} \u5931\u8D25: ${result.error.message}`
1860
+ );
1858
1861
  }
1859
1862
  if (result.status !== 0) {
1860
1863
  const signalText = result.signal ? `, signal: ${result.signal}` : "";
@@ -1936,10 +1939,7 @@ var GitBaseCommand = class extends BaseCommand {
1936
1939
  }
1937
1940
  if (result.status !== 0) {
1938
1941
  const signalText = result.signal ? `, signal: ${result.signal}` : "";
1939
- return this._makeError(
1940
- result.status ?? 1,
1941
- `\u6253\u5F00\u6D4F\u89C8\u5668\u5931\u8D25${signalText}`
1942
- );
1942
+ return this._makeError(result.status ?? 1, `\u6253\u5F00\u6D4F\u89C8\u5668\u5931\u8D25${signalText}`);
1943
1943
  }
1944
1944
  return this._makeOk();
1945
1945
  }
@@ -2078,9 +2078,9 @@ var ShortcutBaseCommand = class extends BaseCommand {
2078
2078
  stdio: "inherit",
2079
2079
  shell: true
2080
2080
  });
2081
- return new Promise((resolve4) => {
2081
+ return new Promise((resolve8) => {
2082
2082
  child.on("error", (error) => {
2083
- resolve4(
2083
+ resolve8(
2084
2084
  this._makeError(
2085
2085
  1,
2086
2086
  `\u6267\u884C ${cmdLine} \u5931\u8D25: ${error.message}`
@@ -2089,11 +2089,11 @@ var ShortcutBaseCommand = class extends BaseCommand {
2089
2089
  });
2090
2090
  child.on("close", (code, signal) => {
2091
2091
  if (code === 0) {
2092
- resolve4(this._makeOk());
2092
+ resolve8(this._makeOk());
2093
2093
  return;
2094
2094
  }
2095
2095
  const signalText = signal ? `, signal: ${signal}` : "";
2096
- resolve4(
2096
+ resolve8(
2097
2097
  this._makeError(
2098
2098
  code ?? 1,
2099
2099
  `\u6267\u884C ${cmdLine} \u5931\u8D25${signalText}`
@@ -2170,9 +2170,9 @@ var AiBaseCommand = class extends BaseCommand {
2170
2170
  cwd: process.cwd(),
2171
2171
  stdio: "inherit"
2172
2172
  });
2173
- return new Promise((resolve4) => {
2173
+ return new Promise((resolve8) => {
2174
2174
  child.on("error", (error) => {
2175
- resolve4(
2175
+ resolve8(
2176
2176
  this._makeError(
2177
2177
  1,
2178
2178
  `\u6267\u884C ${command} ${args.join(" ")} \u5931\u8D25: ${error.message}`
@@ -2181,11 +2181,11 @@ var AiBaseCommand = class extends BaseCommand {
2181
2181
  });
2182
2182
  child.on("close", (code, signal) => {
2183
2183
  if (code === 0) {
2184
- resolve4(this._makeOk());
2184
+ resolve8(this._makeOk());
2185
2185
  return;
2186
2186
  }
2187
2187
  const signalText = signal ? `, signal: ${signal}` : "";
2188
- resolve4(
2188
+ resolve8(
2189
2189
  this._makeError(
2190
2190
  code ?? 1,
2191
2191
  `\u6267\u884C ${command} ${args.join(" ")} \u5931\u8D25${signalText}`
@@ -2196,6 +2196,10 @@ var AiBaseCommand = class extends BaseCommand {
2196
2196
  }
2197
2197
  };
2198
2198
 
2199
+ // src/constants/ak.ts
2200
+ var ARK_AK = "6990de07-83be-487d-930d-f5dd3b6d5993";
2201
+ var OPENROUTER_AK = "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";
2202
+
2199
2203
  // src/commands/ai/ai-websearch-command.ts
2200
2204
  var AiWebSearchCommand = class extends AiBaseCommand {
2201
2205
  _meta() {
@@ -2213,7 +2217,7 @@ var AiWebSearchCommand = class extends AiBaseCommand {
2213
2217
  return this._makeError(1, "\u8BF7\u8F93\u5165\u641C\u7D22\u5185\u5BB9");
2214
2218
  }
2215
2219
  const url = "https://ark.cn-beijing.volces.com/api/v3/responses";
2216
- const token = "45442605-446b-4184-aac4-9d577aa1764c";
2220
+ const token = ARK_AK;
2217
2221
  const response = await fetch(url, {
2218
2222
  method: "POST",
2219
2223
  headers: {
@@ -2423,7 +2427,7 @@ var AiRunCommand = class extends AiBaseCommand {
2423
2427
  }
2424
2428
  _createSystemReminder(referenceDir) {
2425
2429
  return `<system-reminder>
2426
- \u53C2\u8003\u6587\u4EF6\u8DEF\u5F84 ${referenceDir} \u6587\u4EF6\u5939\u7684\u5185\u5BB9\uFF0C\u6267\u884C\u7528\u6237\u7684\u8981\u6C42\uFF0C\u82E5\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\uFF0C\u4E0D\u8981\u5BF9\u8BE5\u6587\u4EF6\u5939\u7684\u5185\u5BB9\u8FDB\u884C\u4FEE\u6539\uFF0C\u800C\u662F\u67E5\u9605\u91CC\u9762\u7684\u5185\u5BB9\u4F5C\u4E3A\u4E0A\u4E0B\u6587\u8865\u5145\u6BD4\u5982\u4F5C\u4E3A\u4FE1\u606F\u53C2\u8003\uFF0C\u6216\u8005\u6267\u884C\u6307\u5F15\uFF1B
2430
+ \u53C2\u8003\u6587\u4EF6\u8DEF\u5F84 ${referenceDir} \u4E0B\uFF0C\u6587\u4EF6\u5939\u91CC\u7684\u5185\u5BB9\uFF0C\u6267\u884C\u7528\u6237\u7684\u8981\u6C42\uFF0C\u82E5\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\uFF0C\u4E0D\u8981\u5BF9\u8BE5\u6587\u4EF6\u5939\u7684\u5185\u5BB9\u8FDB\u884C\u4FEE\u6539\uFF0C\u800C\u662F\u67E5\u9605\u91CC\u9762\u7684\u5185\u5BB9\u4F5C\u4E3A\u4E0A\u4E0B\u6587\u8865\u5145\u6BD4\u5982\u4F5C\u4E3A\u4FE1\u606F\u53C2\u8003\uFF0C\u6216\u8005\u6267\u884C\u6307\u5F15\uFF1B
2427
2431
  \u5982\u679C user_prompt \u91CC\uFF0C\u7ED9\u51FA\u4E00\u4E9B\u6587\u4EF6\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u662F\u5F53\u524D\u6267\u884C\u547D\u4EE4\u8DEF\u5F84 (cwd) \u4E0B\u7684\u6587\u4EF6\uFF0C\u63D0\u4F9B\u7684\u662F\u672C\u6B21\u8981\u6C42\u7684\u8BE6\u7EC6\u6307\u4EE4\u6216\u8005\u91CD\u8981\u7684\u53C2\u8003\u4FE1\u606F
2428
2432
  \u82E5\u7528\u6237\u672A\u63D0\u53CA\u4EFB\u4F55\u6587\u4EF6\u548C\u76EE\u5F55\uFF0C\u4F60\u65E0\u9700\u8BFB\u53D6\u547D\u4EE4\u6267\u884C\u76EE\u5F55\u4E0B\u7684\u4EFB\u4F55\u5185\u5BB9\uFF0C\u53EA\u9700\u5728\u53C2\u8003\u6587\u4EF6\u8DEF\u5F84\u4E0B\u641C\u7D22\u76F8\u5173\u7684\u4FE1\u606F\u5373\u53EF
2429
2433
  \u6700\u540E\u7ED9\u51FA\u7684\u7528\u6237\u56DE\u590D\uFF0C\u65E0\u9700\u5F15\u7528\u53C2\u8003\u6587\u4EF6\u76EE\u5F55\u4E0B\u7684\u5177\u4F53\u6587\u4EF6\uFF0C\u56E0\u4E3A\u7528\u6237\u4E0D\u4F1A\u53BB\u770B\u5BF9\u5E94\u7684\u6587\u4EF6\uFF0C\u800C\u4E14\u8FD9\u4E5F\u662F\u5185\u90E8\u79C1\u6709\u4FE1\u606F
@@ -2433,6 +2437,1210 @@ user_prompt:
2433
2437
  }
2434
2438
  };
2435
2439
 
2440
+ // src/commands/ai/ai-image-command.ts
2441
+ import * as fs6 from "fs/promises";
2442
+ import * as path7 from "path";
2443
+ import { Option as Option8 } from "commander";
2444
+
2445
+ // src/commands/ai/ai-image-reference.ts
2446
+ import * as fs5 from "fs/promises";
2447
+ import * as os2 from "os";
2448
+ import * as path6 from "path";
2449
+ import { execFile } from "child_process";
2450
+ import { promisify } from "util";
2451
+ var execFileAsync = promisify(execFile);
2452
+ var MAX_REFERENCE_IMAGE_BYTES = 2 * 1024 * 1024;
2453
+ var MAX_REFERENCE_IMAGE_COUNT = 14;
2454
+ var API_SUPPORTED_MIME_TYPES = /* @__PURE__ */ new Set([
2455
+ "image/jpeg",
2456
+ "image/png",
2457
+ "image/webp",
2458
+ "image/bmp",
2459
+ "image/tiff",
2460
+ "image/gif"
2461
+ ]);
2462
+ async function prepareReferenceImages(filePaths) {
2463
+ if (filePaths.length > MAX_REFERENCE_IMAGE_COUNT) {
2464
+ return makeError(
2465
+ 1,
2466
+ `\u53C2\u8003\u56FE\u6700\u591A\u652F\u6301 ${MAX_REFERENCE_IMAGE_COUNT} \u5F20\uFF0C\u5F53\u524D\u4F20\u5165 ${filePaths.length} \u5F20\u3002`
2467
+ );
2468
+ }
2469
+ const preparedImages = [];
2470
+ for (const filePath of filePaths) {
2471
+ const prepared = await prepareReferenceImage(filePath);
2472
+ if (!prepared.ok) {
2473
+ return prepared;
2474
+ }
2475
+ preparedImages.push(prepared.value);
2476
+ }
2477
+ return makeOkWith(preparedImages);
2478
+ }
2479
+ async function prepareReferenceImage(filePath) {
2480
+ const resolvedPath = path6.resolve(process.cwd(), filePath);
2481
+ let stats;
2482
+ try {
2483
+ stats = await fs5.stat(resolvedPath);
2484
+ } catch (error) {
2485
+ const message = error instanceof Error ? error.message : String(error);
2486
+ return makeError(1, `\u8BFB\u53D6\u53C2\u8003\u56FE\u5931\u8D25: ${resolvedPath}: ${message}`);
2487
+ }
2488
+ if (!stats.isFile()) {
2489
+ return makeError(1, `\u53C2\u8003\u56FE\u4E0D\u662F\u6587\u4EF6: ${resolvedPath}`);
2490
+ }
2491
+ let fileBytes;
2492
+ try {
2493
+ fileBytes = await fs5.readFile(resolvedPath);
2494
+ } catch (error) {
2495
+ const message = error instanceof Error ? error.message : String(error);
2496
+ return makeError(1, `\u8BFB\u53D6\u53C2\u8003\u56FE\u5185\u5BB9\u5931\u8D25: ${resolvedPath}: ${message}`);
2497
+ }
2498
+ const detectedType = detectMimeType(fileBytes, resolvedPath);
2499
+ if (!detectedType) {
2500
+ return makeError(1, `\u53C2\u8003\u56FE\u4E0D\u662F\u652F\u6301\u7684\u56FE\u7247\u683C\u5F0F: ${resolvedPath}`);
2501
+ }
2502
+ const needsTranscode = !API_SUPPORTED_MIME_TYPES.has(detectedType.mimeType) || fileBytes.byteLength > MAX_REFERENCE_IMAGE_BYTES;
2503
+ if (!needsTranscode) {
2504
+ return makeOkWith({
2505
+ inputPath: filePath,
2506
+ resolvedPath,
2507
+ sourceMimeType: detectedType.mimeType,
2508
+ requestMimeType: detectedType.mimeType,
2509
+ originalBytes: fileBytes.byteLength,
2510
+ finalBytes: fileBytes.byteLength,
2511
+ compressed: false,
2512
+ dataUrl: toDataUrl(detectedType.mimeType, fileBytes)
2513
+ });
2514
+ }
2515
+ const compressed = await compressImageForReference(resolvedPath);
2516
+ if (!compressed.ok) {
2517
+ return compressed;
2518
+ }
2519
+ return makeOkWith({
2520
+ inputPath: filePath,
2521
+ resolvedPath,
2522
+ sourceMimeType: detectedType.mimeType,
2523
+ requestMimeType: compressed.value.mimeType,
2524
+ originalBytes: fileBytes.byteLength,
2525
+ finalBytes: compressed.value.bytes.byteLength,
2526
+ compressed: true,
2527
+ dataUrl: toDataUrl(compressed.value.mimeType, compressed.value.bytes)
2528
+ });
2529
+ }
2530
+ function detectMimeType(fileBytes, filePath) {
2531
+ if (fileBytes.length >= 3 && fileBytes[0] === 255 && fileBytes[1] === 216 && fileBytes[2] === 255) {
2532
+ return { mimeType: "image/jpeg", extension: "jpeg" };
2533
+ }
2534
+ if (fileBytes.length >= 8 && fileBytes[0] === 137 && fileBytes[1] === 80 && fileBytes[2] === 78 && fileBytes[3] === 71 && fileBytes[4] === 13 && fileBytes[5] === 10 && fileBytes[6] === 26 && fileBytes[7] === 10) {
2535
+ return { mimeType: "image/png", extension: "png" };
2536
+ }
2537
+ if (fileBytes.length >= 6) {
2538
+ const gifHeader = fileBytes.subarray(0, 6).toString("ascii");
2539
+ if (gifHeader === "GIF87a" || gifHeader === "GIF89a") {
2540
+ return { mimeType: "image/gif", extension: "gif" };
2541
+ }
2542
+ }
2543
+ if (fileBytes.length >= 12 && fileBytes.subarray(0, 4).toString("ascii") === "RIFF" && fileBytes.subarray(8, 12).toString("ascii") === "WEBP") {
2544
+ return { mimeType: "image/webp", extension: "webp" };
2545
+ }
2546
+ if (fileBytes.length >= 2 && fileBytes.subarray(0, 2).toString("ascii") === "BM") {
2547
+ return { mimeType: "image/bmp", extension: "bmp" };
2548
+ }
2549
+ if (fileBytes.length >= 4 && (fileBytes[0] === 73 && fileBytes[1] === 73 && fileBytes[2] === 42 && fileBytes[3] === 0 || fileBytes[0] === 77 && fileBytes[1] === 77 && fileBytes[2] === 0 && fileBytes[3] === 42)) {
2550
+ return { mimeType: "image/tiff", extension: "tiff" };
2551
+ }
2552
+ if (fileBytes.length >= 12 && fileBytes.subarray(4, 8).toString("ascii") === "ftyp") {
2553
+ const brand = fileBytes.subarray(8, 12).toString("ascii").trim();
2554
+ if (brand.startsWith("avif") || brand === "avis") {
2555
+ return { mimeType: "image/avif", extension: "avif" };
2556
+ }
2557
+ if (brand.startsWith("hei") || brand.startsWith("hev") || brand === "mif1" || brand === "msf1") {
2558
+ return { mimeType: "image/heic", extension: "heic" };
2559
+ }
2560
+ }
2561
+ const ext = path6.extname(filePath).toLowerCase();
2562
+ switch (ext) {
2563
+ case ".jpg":
2564
+ case ".jpeg":
2565
+ return { mimeType: "image/jpeg", extension: "jpeg" };
2566
+ case ".png":
2567
+ return { mimeType: "image/png", extension: "png" };
2568
+ case ".gif":
2569
+ return { mimeType: "image/gif", extension: "gif" };
2570
+ case ".webp":
2571
+ return { mimeType: "image/webp", extension: "webp" };
2572
+ case ".bmp":
2573
+ return { mimeType: "image/bmp", extension: "bmp" };
2574
+ case ".tif":
2575
+ case ".tiff":
2576
+ return { mimeType: "image/tiff", extension: "tiff" };
2577
+ case ".heic":
2578
+ case ".heif":
2579
+ return { mimeType: "image/heic", extension: "heic" };
2580
+ case ".avif":
2581
+ return { mimeType: "image/avif", extension: "avif" };
2582
+ default:
2583
+ return void 0;
2584
+ }
2585
+ }
2586
+ async function compressImageForReference(sourcePath) {
2587
+ if (process.platform !== "darwin") {
2588
+ return makeError(
2589
+ 1,
2590
+ `\u53C2\u8003\u56FE\u9700\u8981\u538B\u7F29\u6216\u8F6C\u7801\uFF0C\u4F46\u5F53\u524D\u5E73\u53F0 ${process.platform} \u672A\u5B9E\u73B0\u81EA\u52A8\u5904\u7406\u3002`
2591
+ );
2592
+ }
2593
+ const tempDir = await fs5.mkdtemp(path6.join(os2.tmpdir(), "tt-ai-image-"));
2594
+ try {
2595
+ const dimensions = await readImageDimensions(sourcePath);
2596
+ const maxDimension = Math.max(dimensions.width, dimensions.height);
2597
+ const resizeLimits = uniqueNumbers([
2598
+ maxDimension,
2599
+ Math.floor(maxDimension * 0.85),
2600
+ Math.floor(maxDimension * 0.7),
2601
+ Math.floor(maxDimension * 0.55),
2602
+ Math.floor(maxDimension * 0.4)
2603
+ ]).filter((value) => value >= 64);
2604
+ const qualityLevels = [85, 75, 65, 55, 45, 35];
2605
+ let attemptIndex = 0;
2606
+ for (const resizeLimit of resizeLimits) {
2607
+ for (const quality of qualityLevels) {
2608
+ const targetPath = path6.join(tempDir, `compressed-${attemptIndex}.jpeg`);
2609
+ attemptIndex += 1;
2610
+ await runSips([
2611
+ "--setProperty",
2612
+ "format",
2613
+ "jpeg",
2614
+ "--setProperty",
2615
+ "formatOptions",
2616
+ String(quality),
2617
+ sourcePath,
2618
+ "--out",
2619
+ targetPath
2620
+ ]);
2621
+ if (resizeLimit < maxDimension) {
2622
+ await runSips(["-Z", String(resizeLimit), targetPath]);
2623
+ }
2624
+ const compressedBytes = await fs5.readFile(targetPath);
2625
+ if (compressedBytes.byteLength <= MAX_REFERENCE_IMAGE_BYTES) {
2626
+ return makeOkWith({
2627
+ mimeType: "image/jpeg",
2628
+ bytes: compressedBytes
2629
+ });
2630
+ }
2631
+ }
2632
+ }
2633
+ return makeError(1, `\u53C2\u8003\u56FE\u538B\u7F29\u5931\u8D25\uFF0C\u65E0\u6CD5\u538B\u7F29\u5230 2MB \u4EE5\u5185: ${sourcePath}`);
2634
+ } catch (error) {
2635
+ const message = error instanceof Error ? error.message : String(error);
2636
+ return makeError(1, `\u5904\u7406\u53C2\u8003\u56FE\u5931\u8D25: ${sourcePath}: ${message}`);
2637
+ } finally {
2638
+ await fs5.rm(tempDir, { recursive: true, force: true });
2639
+ }
2640
+ }
2641
+ async function readImageDimensions(sourcePath) {
2642
+ const { stdout } = await runSips([
2643
+ "-g",
2644
+ "pixelWidth",
2645
+ "-g",
2646
+ "pixelHeight",
2647
+ sourcePath
2648
+ ]);
2649
+ const width = readSipsMetric(stdout, "pixelWidth");
2650
+ const height = readSipsMetric(stdout, "pixelHeight");
2651
+ if (!width || !height) {
2652
+ throw new Error("\u65E0\u6CD5\u8BFB\u53D6\u56FE\u7247\u5C3A\u5BF8");
2653
+ }
2654
+ return { width, height };
2655
+ }
2656
+ async function runSips(args) {
2657
+ return execFileAsync("/usr/bin/sips", [...args]);
2658
+ }
2659
+ function readSipsMetric(output, key) {
2660
+ const matcher = new RegExp(`${key}:\\s*(\\d+)`);
2661
+ const matched = output.match(matcher);
2662
+ if (!matched) {
2663
+ return void 0;
2664
+ }
2665
+ const value = Number.parseInt(matched[1], 10);
2666
+ return Number.isFinite(value) ? value : void 0;
2667
+ }
2668
+ function uniqueNumbers(values) {
2669
+ return [...new Set(values)];
2670
+ }
2671
+ function toDataUrl(mimeType, fileBytes) {
2672
+ const suffix = mimeType.replace("image/", "");
2673
+ return `data:image/${suffix};base64,${fileBytes.toString("base64")}`;
2674
+ }
2675
+
2676
+ // src/commands/ai/ai-image-command.ts
2677
+ var IMAGE_GENERATION_URL = "https://ark.cn-beijing.volces.com/api/v3/images/generations";
2678
+ var IMAGE_MODEL = "doubao-seedream-5-0-260128";
2679
+ var AiImageCommand = class extends AiBaseCommand {
2680
+ _meta() {
2681
+ return {
2682
+ name: "image",
2683
+ description: "\u8C03\u7528\u8C46\u5305 Seedream \u6A21\u578B\u751F\u6210\u56FE\u7247\u5E76\u4E0B\u8F7D\u5230\u672C\u5730"
2684
+ };
2685
+ }
2686
+ _configureOptions(cmd) {
2687
+ cmd.addOption(
2688
+ new Option8(
2689
+ "-r, --reference <path>",
2690
+ "\u53C2\u8003\u56FE\u8DEF\u5F84\uFF0C\u53EF\u91CD\u590D\u4F20\u5165\uFF0C\u4E5F\u652F\u6301\u7528\u82F1\u6587\u9017\u53F7\u5206\u9694\u591A\u4E2A\u8DEF\u5F84"
2691
+ ).argParser(parseReferencePaths).default([])
2692
+ );
2693
+ cmd.addOption(
2694
+ new Option8(
2695
+ "-s, --size <size>",
2696
+ "\u8F93\u51FA\u5C3A\u5BF8\uFF0C\u4F8B\u5982 1024x1024\u30012048x2048\u30012K"
2697
+ ).default("2K")
2698
+ );
2699
+ cmd.addOption(
2700
+ new Option8("--output-format <format>", "\u751F\u6210\u56FE\u7247\u7F16\u7801\u683C\u5F0F").choices(["jpeg", "png", "webp"]).default("jpeg")
2701
+ );
2702
+ cmd.addOption(
2703
+ new Option8(
2704
+ "-o, --output <path>",
2705
+ "\u8F93\u51FA\u8DEF\u5F84\uFF0C\u53EF\u4F20\u6587\u4EF6\u8DEF\u5F84\u6216\u76EE\u5F55\u8DEF\u5F84\uFF1B\u672A\u4F20\u65F6\u9ED8\u8BA4\u5199\u5165\u5F53\u524D\u76EE\u5F55\u5E76\u81EA\u52A8\u547D\u540D"
2706
+ )
2707
+ );
2708
+ }
2709
+ _configureArguments(cmd) {
2710
+ cmd.argument("[content...]", "\u751F\u56FE\u63D0\u793A\u8BCD");
2711
+ }
2712
+ async _execute(ctx) {
2713
+ const prompt = this._readPrompt(ctx);
2714
+ if (!prompt) {
2715
+ this._outputJsonError(1, "\u8BF7\u8F93\u5165\u751F\u56FE\u63D0\u793A\u8BCD");
2716
+ return this._makeOk();
2717
+ }
2718
+ const referenceResult = await prepareReferenceImages(ctx.options.reference);
2719
+ if (!referenceResult.ok) {
2720
+ this._outputJsonError(referenceResult.code, referenceResult.msg);
2721
+ return this._makeOk();
2722
+ }
2723
+ const requestBody = {
2724
+ model: IMAGE_MODEL,
2725
+ prompt,
2726
+ size: ctx.options.size ?? "2K",
2727
+ response_format: "url",
2728
+ output_format: ctx.options.outputFormat,
2729
+ watermark: false,
2730
+ ...referenceResult.value.length > 0 ? {
2731
+ image: referenceResult.value.map((item) => item.dataUrl)
2732
+ } : {}
2733
+ };
2734
+ const responseResult = await this._requestImage(requestBody);
2735
+ if (!responseResult.ok) {
2736
+ this._outputJsonError(responseResult.code, responseResult.msg);
2737
+ return this._makeOk();
2738
+ }
2739
+ const payload = responseResult.value;
2740
+ const remoteUrl = payload.data?.[0]?.url?.trim();
2741
+ if (!remoteUrl) {
2742
+ this._outputJsonError(1, "\u63A5\u53E3\u8C03\u7528\u6210\u529F\uFF0C\u4F46 data.[0].url \u4E3A\u7A7A");
2743
+ return this._makeOk();
2744
+ }
2745
+ const outputTargetResult = await resolveOutputTarget(
2746
+ ctx.options.output,
2747
+ ctx.options.outputFormat
2748
+ );
2749
+ if (!outputTargetResult.ok) {
2750
+ this._outputJsonError(outputTargetResult.code, outputTargetResult.msg);
2751
+ return this._makeOk();
2752
+ }
2753
+ const saveResult = await downloadImageToFile(
2754
+ remoteUrl,
2755
+ outputTargetResult.value
2756
+ );
2757
+ if (!saveResult.ok) {
2758
+ this._outputJsonError(saveResult.code, saveResult.msg);
2759
+ return this._makeOk();
2760
+ }
2761
+ this._outputJsonOk({
2762
+ image_path: saveResult.value
2763
+ });
2764
+ return this._makeOk();
2765
+ }
2766
+ async _requestImage(requestBody) {
2767
+ const token = process.env.ARK_AK?.trim() || ARK_AK;
2768
+ if (!token) {
2769
+ return makeError(1, "\u7F3A\u5C11 ARK_AK\uFF0C\u8BF7\u5148\u914D\u7F6E\u53EF\u7528\u7684 API Key");
2770
+ }
2771
+ const controller = new AbortController();
2772
+ const timer = setTimeout(() => controller.abort(), 12e4);
2773
+ try {
2774
+ const response = await fetch(IMAGE_GENERATION_URL, {
2775
+ method: "POST",
2776
+ headers: {
2777
+ Authorization: `Bearer ${token}`,
2778
+ "Content-Type": "application/json"
2779
+ },
2780
+ body: JSON.stringify(requestBody),
2781
+ signal: controller.signal
2782
+ });
2783
+ const bodyText = await response.text();
2784
+ const payload = parseJsonSafely(bodyText);
2785
+ if (!response.ok) {
2786
+ const suffix = extractErrorMessage(payload) ?? bodyText.trim();
2787
+ return makeError(
2788
+ response.status,
2789
+ suffix ? `\u751F\u56FE\u63A5\u53E3\u8BF7\u6C42\u5931\u8D25: HTTP ${response.status}: ${suffix}` : `\u751F\u56FE\u63A5\u53E3\u8BF7\u6C42\u5931\u8D25: HTTP ${response.status}`
2790
+ );
2791
+ }
2792
+ if (!payload) {
2793
+ return makeError(1, "\u751F\u56FE\u63A5\u53E3\u8FD4\u56DE\u975E JSON \u54CD\u5E94");
2794
+ }
2795
+ if (hasFailedCode(payload.code)) {
2796
+ return makeError(
2797
+ 1,
2798
+ extractErrorMessage(payload) ?? "\u751F\u56FE\u63A5\u53E3\u8FD4\u56DE\u9519\u8BEF"
2799
+ );
2800
+ }
2801
+ return makeOkWith(payload);
2802
+ } catch (error) {
2803
+ const message = error instanceof Error && error.name === "AbortError" ? "\u8BF7\u6C42\u8D85\u65F6" : error instanceof Error ? error.message : String(error);
2804
+ return makeError(1, `\u8C03\u7528\u751F\u56FE\u63A5\u53E3\u5931\u8D25: ${message}`);
2805
+ } finally {
2806
+ clearTimeout(timer);
2807
+ }
2808
+ }
2809
+ };
2810
+ async function resolveOutputTarget(outputPath, outputFormat) {
2811
+ if (!outputPath) {
2812
+ const directoryPath = process.cwd();
2813
+ const filePath = path7.join(directoryPath, buildAutoFileName(outputFormat));
2814
+ return makeOkWith({
2815
+ directoryPath,
2816
+ filePath,
2817
+ autoNamed: true
2818
+ });
2819
+ }
2820
+ const resolvedPath = path7.resolve(process.cwd(), outputPath);
2821
+ try {
2822
+ const stats = await fs6.stat(resolvedPath);
2823
+ if (stats.isDirectory()) {
2824
+ return makeOkWith({
2825
+ directoryPath: resolvedPath,
2826
+ filePath: path7.join(resolvedPath, buildAutoFileName(outputFormat)),
2827
+ autoNamed: true
2828
+ });
2829
+ }
2830
+ return makeOkWith({
2831
+ directoryPath: path7.dirname(resolvedPath),
2832
+ filePath: resolvedPath,
2833
+ autoNamed: false
2834
+ });
2835
+ } catch (error) {
2836
+ const nodeError = error;
2837
+ if (nodeError.code !== "ENOENT") {
2838
+ const message = error instanceof Error ? error.message : String(error);
2839
+ return makeError(1, `\u8BFB\u53D6\u8F93\u51FA\u8DEF\u5F84\u5931\u8D25: ${resolvedPath}: ${message}`);
2840
+ }
2841
+ if (path7.extname(resolvedPath)) {
2842
+ return makeOkWith({
2843
+ directoryPath: path7.dirname(resolvedPath),
2844
+ filePath: resolvedPath,
2845
+ autoNamed: false
2846
+ });
2847
+ }
2848
+ return makeOkWith({
2849
+ directoryPath: resolvedPath,
2850
+ filePath: path7.join(resolvedPath, buildAutoFileName(outputFormat)),
2851
+ autoNamed: true
2852
+ });
2853
+ }
2854
+ }
2855
+ async function downloadImageToFile(remoteUrl, target) {
2856
+ try {
2857
+ await fs6.mkdir(target.directoryPath, { recursive: true });
2858
+ } catch (error) {
2859
+ const message = error instanceof Error ? error.message : String(error);
2860
+ return makeError(
2861
+ 1,
2862
+ `\u521B\u5EFA\u8F93\u51FA\u76EE\u5F55\u5931\u8D25: ${target.directoryPath}: ${message}`
2863
+ );
2864
+ }
2865
+ let response;
2866
+ try {
2867
+ response = await fetch(remoteUrl);
2868
+ } catch (error) {
2869
+ const message = error instanceof Error ? error.message : String(error);
2870
+ return makeError(1, `\u4E0B\u8F7D\u56FE\u7247\u5931\u8D25: ${message}`);
2871
+ }
2872
+ if (!response.ok) {
2873
+ return makeError(response.status, `\u4E0B\u8F7D\u56FE\u7247\u5931\u8D25: HTTP ${response.status}`);
2874
+ }
2875
+ const bytes = Buffer.from(await response.arrayBuffer());
2876
+ const targetPath = target.autoNamed ? replaceFileExtension(
2877
+ target.filePath,
2878
+ inferImageExtension(remoteUrl, response)
2879
+ ) : target.filePath;
2880
+ try {
2881
+ await fs6.writeFile(targetPath, bytes);
2882
+ } catch (error) {
2883
+ const message = error instanceof Error ? error.message : String(error);
2884
+ return makeError(1, `\u5199\u5165\u56FE\u7247\u5931\u8D25: ${targetPath}: ${message}`);
2885
+ }
2886
+ return makeOkWith(path7.resolve(targetPath));
2887
+ }
2888
+ function parseReferencePaths(value, previous) {
2889
+ return previous.concat(
2890
+ value.split(",").map((item) => item.trim()).filter((item) => item.length > 0)
2891
+ );
2892
+ }
2893
+ function parseJsonSafely(text) {
2894
+ if (!text.trim()) {
2895
+ return void 0;
2896
+ }
2897
+ try {
2898
+ return JSON.parse(text);
2899
+ } catch {
2900
+ return void 0;
2901
+ }
2902
+ }
2903
+ function hasFailedCode(code) {
2904
+ if (code === void 0 || code === null) {
2905
+ return false;
2906
+ }
2907
+ if (typeof code === "number") {
2908
+ return code !== 0;
2909
+ }
2910
+ const normalized = code.trim();
2911
+ return normalized !== "0" && normalized !== "";
2912
+ }
2913
+ function extractErrorMessage(payload) {
2914
+ if (!payload) {
2915
+ return void 0;
2916
+ }
2917
+ const message = payload.msg?.trim() || payload.message?.trim();
2918
+ return message || void 0;
2919
+ }
2920
+ function buildAutoFileName(outputFormat) {
2921
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
2922
+ return `ai-image-${timestamp}.${outputFormat}`;
2923
+ }
2924
+ function replaceFileExtension(filePath, extension) {
2925
+ const ext = path7.extname(filePath);
2926
+ if (!ext) {
2927
+ return `${filePath}.${extension}`;
2928
+ }
2929
+ return `${filePath.slice(0, -ext.length)}.${extension}`;
2930
+ }
2931
+ function inferImageExtension(remoteUrl, response) {
2932
+ const contentType = response.headers.get("content-type")?.toLowerCase() ?? "";
2933
+ if (contentType.includes("png")) {
2934
+ return "png";
2935
+ }
2936
+ if (contentType.includes("webp")) {
2937
+ return "webp";
2938
+ }
2939
+ if (contentType.includes("jpeg") || contentType.includes("jpg")) {
2940
+ return "jpeg";
2941
+ }
2942
+ try {
2943
+ const url = new URL(remoteUrl);
2944
+ const ext = path7.extname(url.pathname).toLowerCase();
2945
+ if (ext === ".png") {
2946
+ return "png";
2947
+ }
2948
+ if (ext === ".webp") {
2949
+ return "webp";
2950
+ }
2951
+ if (ext === ".jpg" || ext === ".jpeg") {
2952
+ return "jpeg";
2953
+ }
2954
+ } catch {
2955
+ }
2956
+ return "jpeg";
2957
+ }
2958
+
2959
+ // src/commands/ai/ai-video-command.ts
2960
+ import * as path8 from "path";
2961
+ import { Option as Option9 } from "commander";
2962
+
2963
+ // src/bedrock/uuid/uuid.ts
2964
+ var generateUuid = (() => {
2965
+ if (typeof crypto === "object" && typeof crypto.randomUUID === "function") {
2966
+ return crypto.randomUUID.bind(crypto);
2967
+ }
2968
+ let getRandomValues;
2969
+ if (typeof crypto === "object" && typeof crypto.getRandomValues === "function") {
2970
+ getRandomValues = crypto.getRandomValues.bind(crypto);
2971
+ } else {
2972
+ getRandomValues = function(bucket) {
2973
+ for (let i = 0; i < bucket.length; i++) {
2974
+ bucket[i] = Math.floor(Math.random() * 256);
2975
+ }
2976
+ return bucket;
2977
+ };
2978
+ }
2979
+ const data = new Uint8Array(16);
2980
+ const hex = [];
2981
+ for (let i = 0; i < 256; i++) {
2982
+ hex.push(i.toString(16).padStart(2, "0"));
2983
+ }
2984
+ return () => {
2985
+ getRandomValues(data);
2986
+ data[6] = data[6] & 15 | 64;
2987
+ data[8] = data[8] & 63 | 128;
2988
+ let i = 0;
2989
+ let result = "";
2990
+ result += hex[data[i++]];
2991
+ result += hex[data[i++]];
2992
+ result += hex[data[i++]];
2993
+ result += hex[data[i++]];
2994
+ result += "-";
2995
+ result += hex[data[i++]];
2996
+ result += hex[data[i++]];
2997
+ result += "-";
2998
+ result += hex[data[i++]];
2999
+ result += hex[data[i++]];
3000
+ result += "-";
3001
+ result += hex[data[i++]];
3002
+ result += hex[data[i++]];
3003
+ result += "-";
3004
+ result += hex[data[i++]];
3005
+ result += hex[data[i++]];
3006
+ result += hex[data[i++]];
3007
+ result += hex[data[i++]];
3008
+ result += hex[data[i++]];
3009
+ result += hex[data[i++]];
3010
+ return result;
3011
+ };
3012
+ })();
3013
+
3014
+ // src/commands/pippit/modules/submit-direct/submit-direct-cn.ts
3015
+ var SUBMIT_DIRECT_URL = "https://xyq.jianying.com/api/biz/v1/agent/submit_run";
3016
+ function normalizeToken4(token) {
3017
+ const trimmed = token.trim();
3018
+ const prefix = "sessionid_pippitcn_web=";
3019
+ if (trimmed.startsWith(prefix)) {
3020
+ return trimmed.slice(prefix.length).trim();
3021
+ }
3022
+ return trimmed;
3023
+ }
3024
+ function createCookieHeader3(token) {
3025
+ return `sessionid_pippitcn_web=${normalizeToken4(token)}`;
3026
+ }
3027
+ function parseErrorCode2(ret) {
3028
+ const parsed = typeof ret === "number" ? ret : typeof ret === "string" ? Number.parseInt(ret, 10) : Number.NaN;
3029
+ return Number.isFinite(parsed) ? parsed : 1;
3030
+ }
3031
+ function createUserInfo() {
3032
+ return readWebContext("cn" /* CN */).then((webContextResult) => {
3033
+ if (!webContextResult.ok) {
3034
+ return webContextResult;
3035
+ }
3036
+ const webContext = webContextResult.value;
3037
+ if (!webContext.uid || !webContext.workspaceId || !webContext.spaceId) {
3038
+ return missingWebContextError();
3039
+ }
3040
+ return makeOkWith({
3041
+ uid: webContext.uid,
3042
+ workspace_id: webContext.workspaceId,
3043
+ space_id: webContext.spaceId
3044
+ });
3045
+ });
3046
+ }
3047
+ async function submitDirectCn(options) {
3048
+ const userInfoResult = await createUserInfo();
3049
+ if (!userInfoResult.ok) {
3050
+ return userInfoResult;
3051
+ }
3052
+ const { durationSec, imageAssetIds, prompt } = options;
3053
+ const tokenResult = await readWebToken("cn" /* CN */);
3054
+ if (!tokenResult.ok) {
3055
+ return tokenResult;
3056
+ }
3057
+ const token = tokenResult.value?.trim();
3058
+ if (!token) {
3059
+ return missingWebTokenError();
3060
+ }
3061
+ const threadId = generateUuid();
3062
+ const runId = generateUuid();
3063
+ let duration = 5;
3064
+ if (durationSec && durationSec <= 8 && durationSec >= 2) {
3065
+ duration = Math.round(durationSec);
3066
+ }
3067
+ const message = {
3068
+ message_id: "",
3069
+ role: "user",
3070
+ thread_id: threadId,
3071
+ run_id: runId,
3072
+ created_at: Date.now(),
3073
+ content: [
3074
+ {
3075
+ type: "data",
3076
+ sub_type: "biz/x_data_direct_tool_call_req",
3077
+ data: JSON.stringify({
3078
+ param: JSON.stringify({
3079
+ prompt,
3080
+ images: [
3081
+ imageAssetIds?.map((assetId) => ({
3082
+ asset_id: assetId
3083
+ }))
3084
+ ],
3085
+ duration_sec: duration,
3086
+ language: "zh",
3087
+ resolution: "720p",
3088
+ imitation_videos: [],
3089
+ videos: [],
3090
+ audios: [],
3091
+ model: "seedance2.0_vision"
3092
+ }),
3093
+ tool_name: "biz/x_tool_name_video_part"
3094
+ }),
3095
+ hidden: false,
3096
+ is_thought: false
3097
+ }
3098
+ ]
3099
+ };
3100
+ const userInfo = {
3101
+ app_id: "795647",
3102
+ consumer_uid: userInfoResult.value.uid,
3103
+ workspace_id: userInfoResult.value.workspace_id,
3104
+ space_id: userInfoResult.value.space_id
3105
+ };
3106
+ const responseResult = await requestJson(
3107
+ SUBMIT_DIRECT_URL,
3108
+ {
3109
+ method: "POST",
3110
+ headers: {
3111
+ accept: "application/json, text/plain, */*",
3112
+ "content-type": "application/json",
3113
+ cookie: createCookieHeader3(token),
3114
+ Referer: "https://xyq.jianying.com/"
3115
+ },
3116
+ body: JSON.stringify({
3117
+ user_info: userInfo,
3118
+ message,
3119
+ agent_name: "pippit_video_part_agent",
3120
+ entrance_from: "web",
3121
+ run_extra: "{}"
3122
+ })
3123
+ },
3124
+ {
3125
+ networkRequestFailed: (message2) => networkRequestFailedError3(message2),
3126
+ responseParseFailed: (message2) => responseParseFailedError2(message2)
3127
+ }
3128
+ );
3129
+ if (!responseResult.ok) {
3130
+ return responseResult;
3131
+ }
3132
+ const response = responseResult.value;
3133
+ console.log("=====response", response);
3134
+ if (String(response.ret) !== "0") {
3135
+ return makeError(
3136
+ parseErrorCode2(response.ret),
3137
+ response.errmsg?.trim() || "\u76F4\u63A5\u63D0\u4EA4\u5931\u8D25\u3002"
3138
+ );
3139
+ }
3140
+ return makeOkWith(response.data);
3141
+ }
3142
+
3143
+ // src/commands/ai/ai-video-command.ts
3144
+ var AiVideoCommand = class extends AiBaseCommand {
3145
+ _meta() {
3146
+ return {
3147
+ name: "video",
3148
+ description: "\u4E0A\u4F20\u53C2\u8003\u7D20\u6750\u5E76\u8C03\u7528\u89C6\u9891\u751F\u6210\u63A5\u53E3"
3149
+ };
3150
+ }
3151
+ _configureOptions(cmd) {
3152
+ cmd.addOption(
3153
+ new Option9(
3154
+ "-r, --reference <path>",
3155
+ "\u53C2\u8003\u56FE\u7247\u6216\u89C6\u9891\u8DEF\u5F84\uFF0C\u53EF\u91CD\u590D\u4F20\u5165\uFF0C\u4E5F\u652F\u6301\u7528\u82F1\u6587\u9017\u53F7\u5206\u9694\u591A\u4E2A\u8DEF\u5F84"
3156
+ ).argParser(parseReferencePaths2).default([])
3157
+ );
3158
+ }
3159
+ _configureArguments(cmd) {
3160
+ cmd.argument("[content...]", "\u89C6\u9891\u751F\u6210\u63D0\u793A\u8BCD");
3161
+ }
3162
+ async _execute(ctx) {
3163
+ const prompt = this._readPrompt(ctx);
3164
+ if (!prompt) {
3165
+ this._outputJsonError(1, "\u8BF7\u8F93\u5165\u89C6\u9891\u751F\u6210\u63D0\u793A\u8BCD");
3166
+ return this._makeOk();
3167
+ }
3168
+ const uploadResult = await this._uploadReferences(ctx.options.reference);
3169
+ if (!uploadResult.ok) {
3170
+ this._outputJsonError(uploadResult.code, uploadResult.msg);
3171
+ return this._makeOk();
3172
+ }
3173
+ const generationResult = await this._requestVideoGeneration(
3174
+ prompt,
3175
+ uploadResult.value
3176
+ );
3177
+ if (!generationResult.ok) {
3178
+ this._outputJsonError(generationResult.code, generationResult.msg);
3179
+ return this._makeOk();
3180
+ }
3181
+ this._outputJsonOk({
3182
+ prompt,
3183
+ assets: uploadResult.value,
3184
+ generation: generationResult.value
3185
+ });
3186
+ return this._makeOk();
3187
+ }
3188
+ async _uploadReferences(references) {
3189
+ if (references.length === 0) {
3190
+ return makeOkWith([]);
3191
+ }
3192
+ const uploadResults = await Promise.all(
3193
+ references.map(async (referencePath) => {
3194
+ const result = await uploadAsset({
3195
+ filePath: referencePath,
3196
+ region: "cn" /* CN */
3197
+ });
3198
+ if (!result.ok) {
3199
+ return result;
3200
+ }
3201
+ return makeOkWith({
3202
+ asset_id: result.value.assetId,
3203
+ asset_type: result.value.fileInfo.assetType,
3204
+ file_path: path8.resolve(process.cwd(), referencePath),
3205
+ region: result.value.region
3206
+ });
3207
+ })
3208
+ );
3209
+ for (const result of uploadResults) {
3210
+ if (!result.ok) {
3211
+ return result;
3212
+ }
3213
+ }
3214
+ return makeOkWith(uploadResults.map((result) => result.value));
3215
+ }
3216
+ async _requestVideoGeneration(prompt, assets) {
3217
+ return submitDirectCn({
3218
+ prompt,
3219
+ imageAssetIds: assets.map((asset) => asset.asset_id),
3220
+ durationSec: 5
3221
+ });
3222
+ }
3223
+ };
3224
+ function parseReferencePaths2(value, previous) {
3225
+ return previous.concat(
3226
+ value.split(",").map((item) => item.trim()).filter((item) => item.length > 0)
3227
+ );
3228
+ }
3229
+
3230
+ // src/commands/ai/ai-vid-command.ts
3231
+ import * as fs7 from "fs/promises";
3232
+ import * as path9 from "path";
3233
+ import { Option as Option10 } from "commander";
3234
+ var VIDEO_GENERATION_URL = "https://openrouter.ai/api/v1/videos";
3235
+ var VIDEO_MODEL = "bytedance/seedance-2.0";
3236
+ var POLLING_LOG_FILE_NAME = "ai-vid-polling.log";
3237
+ var POLL_INTERVAL_MS = 3e3;
3238
+ var POLL_STATUS_LOG_INTERVAL_MS = 1e4;
3239
+ var POLL_TIMEOUT_MS = 5 * 60 * 1e3;
3240
+ var SUBMIT_TIMEOUT_MS = 3e4;
3241
+ var AiVidCommand = class extends AiBaseCommand {
3242
+ _meta() {
3243
+ return {
3244
+ name: "vid",
3245
+ description: "\u901A\u8FC7 OpenRouter \u8C03\u7528 bytedance/seedance-2.0 \u751F\u6210\u89C6\u9891"
3246
+ };
3247
+ }
3248
+ _configureOptions(cmd) {
3249
+ cmd.addOption(
3250
+ new Option10(
3251
+ "-r, --reference <path>",
3252
+ "\u53C2\u8003\u56FE\u7247\u672C\u5730\u8DEF\u5F84\uFF0C\u53EF\u91CD\u590D\u4F20\u5165\uFF0C\u4E5F\u652F\u6301\u7528\u82F1\u6587\u9017\u53F7\u5206\u9694\u591A\u4E2A\u8DEF\u5F84\uFF1B\u6700\u7EC8\u8F6C\u4E3A base64 data URL"
3253
+ ).argParser(parseReferencePaths3).default([])
3254
+ );
3255
+ cmd.addOption(
3256
+ new Option10("--resolution <resolution>", "\u89C6\u9891\u5206\u8FA8\u7387").choices(["480p", "720p"]).default("480p")
3257
+ );
3258
+ cmd.addOption(
3259
+ new Option10(
3260
+ "--aspect-ratio <ratio>",
3261
+ "\u89C6\u9891\u957F\u5BBD\u6BD4\uFF0C\u4F8B\u5982 16:9\u30019:16\u30011:1\uFF0C\u7F3A\u7701\u4E0D\u6307\u5B9A"
3262
+ )
3263
+ );
3264
+ cmd.addOption(
3265
+ new Option10("--duration <seconds>", "\u89C6\u9891\u65F6\u957F\uFF08\u79D2\uFF09\uFF0C\u7F3A\u7701\u4E0D\u6307\u5B9A").argParser(
3266
+ parseDuration
3267
+ )
3268
+ );
3269
+ cmd.addOption(
3270
+ new Option10(
3271
+ "--polling-only",
3272
+ "\u4EC5\u63D0\u4EA4\u5E76\u8FD4\u56DE polling_url\uFF0C\u4E0D\u5728\u672C\u5730\u8F6E\u8BE2\u7ED3\u679C"
3273
+ ).default(false)
3274
+ );
3275
+ cmd.addOption(
3276
+ new Option10(
3277
+ "-o, --output <path>",
3278
+ "\u89C6\u9891\u4E0B\u8F7D\u8F93\u51FA\u8DEF\u5F84\uFF0C\u53EF\u4F20\u6587\u4EF6\u8DEF\u5F84\u6216\u76EE\u5F55\u8DEF\u5F84\uFF1B\u672A\u4F20\u65F6\u9ED8\u8BA4\u5199\u5165\u5F53\u524D\u76EE\u5F55\u5E76\u81EA\u52A8\u547D\u540D"
3279
+ )
3280
+ );
3281
+ }
3282
+ _configureArguments(cmd) {
3283
+ cmd.argument("[content...]", "\u89C6\u9891\u751F\u6210\u63D0\u793A\u8BCD");
3284
+ }
3285
+ async _execute(ctx) {
3286
+ const prompt = this._readPrompt(ctx);
3287
+ if (!prompt) {
3288
+ this._outputJsonError(1, "\u8BF7\u8F93\u5165\u89C6\u9891\u751F\u6210\u63D0\u793A\u8BCD");
3289
+ return this._makeOk();
3290
+ }
3291
+ const referenceResult = await prepareReferenceImages(ctx.options.reference);
3292
+ if (!referenceResult.ok) {
3293
+ this._outputJsonError(referenceResult.code, referenceResult.msg);
3294
+ return this._makeOk();
3295
+ }
3296
+ const requestBody = {
3297
+ model: VIDEO_MODEL,
3298
+ prompt,
3299
+ resolution: ctx.options.resolution
3300
+ };
3301
+ if (ctx.options.aspectRatio) {
3302
+ requestBody.aspect_ratio = ctx.options.aspectRatio;
3303
+ }
3304
+ if (typeof ctx.options.duration === "number") {
3305
+ requestBody.duration = ctx.options.duration;
3306
+ }
3307
+ if (referenceResult.value.length > 0) {
3308
+ requestBody.input_references = referenceResult.value.map((item) => ({
3309
+ type: "image_url",
3310
+ image_url: { url: item.dataUrl }
3311
+ }));
3312
+ }
3313
+ const submitResult = await this._submitGeneration(requestBody);
3314
+ if (!submitResult.ok) {
3315
+ this._outputJsonError(submitResult.code, submitResult.msg);
3316
+ return this._makeOk();
3317
+ }
3318
+ const submitPayload = submitResult.value;
3319
+ const pollingUrl = submitPayload.polling_url?.trim();
3320
+ if (!pollingUrl) {
3321
+ this._outputJsonError(1, "\u63D0\u4EA4\u6210\u529F\u4F46\u8FD4\u56DE\u6570\u636E\u7F3A\u5C11 polling_url");
3322
+ return this._makeOk();
3323
+ }
3324
+ const logPathResult = await appendPollingUrl(pollingUrl, submitPayload.id);
3325
+ const pollingLogPath = logPathResult.ok ? logPathResult.value : void 0;
3326
+ if (!logPathResult.ok) {
3327
+ this._debug(`\u8BB0\u5F55 polling_url \u5931\u8D25: ${logPathResult.msg}`);
3328
+ }
3329
+ if (ctx.options.pollingOnly) {
3330
+ this._outputJsonOk({
3331
+ polling_url: pollingUrl,
3332
+ generation_id: submitPayload.id,
3333
+ polling_log_path: pollingLogPath
3334
+ });
3335
+ return this._makeOk();
3336
+ }
3337
+ const pollResult = await this._pollUntilComplete(pollingUrl);
3338
+ if (!pollResult.ok) {
3339
+ this._outputJsonError(pollResult.code, pollResult.msg);
3340
+ return this._makeOk();
3341
+ }
3342
+ const videoUrl = pollResult.value.unsigned_urls?.[0];
3343
+ if (!videoUrl) {
3344
+ this._outputJsonError(1, "\u89C6\u9891\u751F\u6210\u5B8C\u6210\uFF0C\u4F46\u672A\u62FF\u5230 unsigned_urls[0]");
3345
+ return this._makeOk();
3346
+ }
3347
+ const outputTargetResult = await resolveOutputTarget2(ctx.options.output);
3348
+ if (!outputTargetResult.ok) {
3349
+ this._outputJsonError(outputTargetResult.code, outputTargetResult.msg);
3350
+ return this._makeOk();
3351
+ }
3352
+ const downloadResult = await downloadVideoToFile(
3353
+ videoUrl,
3354
+ outputTargetResult.value
3355
+ );
3356
+ if (!downloadResult.ok) {
3357
+ this._outputJsonError(downloadResult.code, downloadResult.msg);
3358
+ return this._makeOk();
3359
+ }
3360
+ this._outputJsonOk({
3361
+ video_path: downloadResult.value,
3362
+ video_url: videoUrl,
3363
+ polling_url: pollingUrl,
3364
+ generation_id: submitPayload.id,
3365
+ polling_log_path: pollingLogPath
3366
+ });
3367
+ return this._makeOk();
3368
+ }
3369
+ async _submitGeneration(requestBody) {
3370
+ const token = process.env.OPENROUTER_AK?.trim() || OPENROUTER_AK;
3371
+ if (!token) {
3372
+ return makeError(1, "\u7F3A\u5C11 OPENROUTER_AK\uFF0C\u8BF7\u5148\u914D\u7F6E\u53EF\u7528\u7684 API Key");
3373
+ }
3374
+ const controller = new AbortController();
3375
+ const timer = setTimeout(() => controller.abort(), SUBMIT_TIMEOUT_MS);
3376
+ let response;
3377
+ try {
3378
+ response = await fetch(VIDEO_GENERATION_URL, {
3379
+ method: "POST",
3380
+ headers: {
3381
+ Authorization: `Bearer ${token}`,
3382
+ "Content-Type": "application/json"
3383
+ },
3384
+ body: JSON.stringify(requestBody),
3385
+ signal: controller.signal
3386
+ });
3387
+ } catch (error) {
3388
+ const message = error instanceof Error && error.name === "AbortError" ? "\u8BF7\u6C42\u8D85\u65F6" : error instanceof Error ? error.message : String(error);
3389
+ return makeError(1, `\u63D0\u4EA4\u89C6\u9891\u751F\u6210\u8BF7\u6C42\u5931\u8D25: ${message}`);
3390
+ } finally {
3391
+ clearTimeout(timer);
3392
+ }
3393
+ const bodyText = await response.text().catch(() => "");
3394
+ const payload = parseJsonSafely2(bodyText);
3395
+ if (!response.ok) {
3396
+ const detail = extractErrorText(payload) ?? bodyText.trim();
3397
+ const suffix = detail ? `: ${detail}` : "";
3398
+ return makeError(
3399
+ response.status,
3400
+ `\u89C6\u9891\u751F\u6210\u8BF7\u6C42\u5931\u8D25: HTTP ${response.status}${suffix}`
3401
+ );
3402
+ }
3403
+ if (!payload) {
3404
+ return makeError(1, "\u89C6\u9891\u751F\u6210\u63A5\u53E3\u8FD4\u56DE\u975E JSON \u54CD\u5E94");
3405
+ }
3406
+ if (payload.error) {
3407
+ return makeError(1, `\u89C6\u9891\u751F\u6210\u8BF7\u6C42\u88AB\u62D2\u7EDD: ${payload.error}`);
3408
+ }
3409
+ if (!payload.id || !payload.polling_url) {
3410
+ return makeError(
3411
+ 1,
3412
+ `\u89C6\u9891\u751F\u6210\u63A5\u53E3\u8FD4\u56DE\u6570\u636E\u5F02\u5E38: ${bodyText.slice(0, 500)}`
3413
+ );
3414
+ }
3415
+ return makeOkWith(payload);
3416
+ }
3417
+ async _pollUntilComplete(pollingUrl) {
3418
+ const token = process.env.OPENROUTER_AK?.trim() || OPENROUTER_AK;
3419
+ const startedAt = Date.now();
3420
+ let lastStatusLogAt = 0;
3421
+ while (true) {
3422
+ const elapsed = Date.now() - startedAt;
3423
+ if (elapsed >= POLL_TIMEOUT_MS) {
3424
+ return makeError(
3425
+ 1,
3426
+ `\u8F6E\u8BE2\u8D85\u65F6\uFF0C\u8D85\u8FC7 ${Math.round(POLL_TIMEOUT_MS / 1e3)}s \u4ECD\u672A\u5B8C\u6210\uFF0C\u53EF\u4F7F\u7528 --polling-only \u62FF\u5230 polling_url \u540E\u7A0D\u540E\u91CD\u8BD5`
3427
+ );
3428
+ }
3429
+ let response;
3430
+ try {
3431
+ response = await fetch(pollingUrl, {
3432
+ headers: { Authorization: `Bearer ${token}` }
3433
+ });
3434
+ } catch (error) {
3435
+ const message = error instanceof Error ? error.message : String(error);
3436
+ this._debug(`\u8F6E\u8BE2\u8BF7\u6C42\u5931\u8D25\uFF0C\u5C06\u91CD\u8BD5: ${message}`);
3437
+ await delay(POLL_INTERVAL_MS);
3438
+ continue;
3439
+ }
3440
+ const bodyText = await response.text().catch(() => "");
3441
+ const payload = parseJsonSafely2(bodyText);
3442
+ if (!response.ok) {
3443
+ const detail = extractErrorText(payload) ?? bodyText.trim();
3444
+ return makeError(
3445
+ response.status,
3446
+ `\u8F6E\u8BE2\u8BF7\u6C42\u5931\u8D25: HTTP ${response.status}${detail ? `: ${detail}` : ""}`
3447
+ );
3448
+ }
3449
+ if (!payload) {
3450
+ this._debug("\u8F6E\u8BE2\u8FD4\u56DE\u975E JSON \u6570\u636E\uFF0C\u5C06\u91CD\u8BD5");
3451
+ await delay(POLL_INTERVAL_MS);
3452
+ continue;
3453
+ }
3454
+ const status = payload.status;
3455
+ if (status === "completed") {
3456
+ return makeOkWith(payload);
3457
+ }
3458
+ if (status === "failed" || status === "cancelled" || status === "expired") {
3459
+ const errorText = payload.error?.trim() || `\u89C6\u9891\u751F\u6210\u7ED3\u675F\u4E8E\u72B6\u6001 ${status}`;
3460
+ return makeError(1, errorText);
3461
+ }
3462
+ const now = Date.now();
3463
+ if (now - lastStatusLogAt >= POLL_STATUS_LOG_INTERVAL_MS) {
3464
+ this._debug(
3465
+ `\u89C6\u9891\u751F\u6210\u72B6\u6001: ${status ?? "unknown"} (\u5DF2\u7B49\u5F85 ${Math.round(elapsed / 1e3)}s)`
3466
+ );
3467
+ lastStatusLogAt = now;
3468
+ }
3469
+ await delay(POLL_INTERVAL_MS);
3470
+ }
3471
+ }
3472
+ };
3473
+ function parseReferencePaths3(value, previous) {
3474
+ return previous.concat(
3475
+ value.split(",").map((item) => item.trim()).filter((item) => item.length > 0)
3476
+ );
3477
+ }
3478
+ function parseDuration(value) {
3479
+ const parsed = Number.parseInt(value, 10);
3480
+ if (!Number.isFinite(parsed) || parsed <= 0) {
3481
+ throw new Error(`duration \u9700\u8981\u662F\u6B63\u6574\u6570\uFF0C\u6536\u5230: ${value}`);
3482
+ }
3483
+ return parsed;
3484
+ }
3485
+ function parseJsonSafely2(text) {
3486
+ if (!text.trim()) {
3487
+ return void 0;
3488
+ }
3489
+ try {
3490
+ return JSON.parse(text);
3491
+ } catch {
3492
+ return void 0;
3493
+ }
3494
+ }
3495
+ function extractErrorText(payload) {
3496
+ if (!payload || typeof payload !== "object") {
3497
+ return void 0;
3498
+ }
3499
+ const record = payload;
3500
+ if (typeof record.error === "string" && record.error.trim().length > 0) {
3501
+ return record.error.trim();
3502
+ }
3503
+ if (record.error && typeof record.error === "object") {
3504
+ const inner = record.error;
3505
+ if (typeof inner.message === "string" && inner.message.trim().length > 0) {
3506
+ return inner.message.trim();
3507
+ }
3508
+ }
3509
+ if (typeof record.message === "string" && record.message.trim().length > 0) {
3510
+ return record.message.trim();
3511
+ }
3512
+ return void 0;
3513
+ }
3514
+ function delay(ms) {
3515
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
3516
+ }
3517
+ async function appendPollingUrl(pollingUrl, generationId) {
3518
+ const locationResult = await resolveConfigLocation();
3519
+ if (!locationResult.ok) {
3520
+ return locationResult;
3521
+ }
3522
+ const logFilePath = path9.join(
3523
+ locationResult.value.configDir,
3524
+ POLLING_LOG_FILE_NAME
3525
+ );
3526
+ try {
3527
+ await fs7.mkdir(locationResult.value.configDir, { recursive: true });
3528
+ const line = `${(/* @__PURE__ */ new Date()).toISOString()} ${generationId} ${pollingUrl}
3529
+ `;
3530
+ await fs7.appendFile(logFilePath, line, "utf8");
3531
+ return makeOkWith(logFilePath);
3532
+ } catch (error) {
3533
+ const message = error instanceof Error ? error.message : String(error);
3534
+ return makeError(1, `\u5199\u5165 polling \u65E5\u5FD7\u5931\u8D25 ${logFilePath}: ${message}`);
3535
+ }
3536
+ }
3537
+ async function resolveOutputTarget2(outputPath) {
3538
+ if (!outputPath) {
3539
+ const directoryPath = process.cwd();
3540
+ return makeOkWith({
3541
+ directoryPath,
3542
+ filePath: path9.join(directoryPath, buildAutoFileName2()),
3543
+ autoNamed: true
3544
+ });
3545
+ }
3546
+ const resolvedPath = path9.resolve(process.cwd(), outputPath);
3547
+ try {
3548
+ const stats = await fs7.stat(resolvedPath);
3549
+ if (stats.isDirectory()) {
3550
+ return makeOkWith({
3551
+ directoryPath: resolvedPath,
3552
+ filePath: path9.join(resolvedPath, buildAutoFileName2()),
3553
+ autoNamed: true
3554
+ });
3555
+ }
3556
+ return makeOkWith({
3557
+ directoryPath: path9.dirname(resolvedPath),
3558
+ filePath: resolvedPath,
3559
+ autoNamed: false
3560
+ });
3561
+ } catch (error) {
3562
+ const nodeError = error;
3563
+ if (nodeError.code !== "ENOENT") {
3564
+ const message = error instanceof Error ? error.message : String(error);
3565
+ return makeError(1, `\u8BFB\u53D6\u8F93\u51FA\u8DEF\u5F84\u5931\u8D25: ${resolvedPath}: ${message}`);
3566
+ }
3567
+ if (path9.extname(resolvedPath)) {
3568
+ return makeOkWith({
3569
+ directoryPath: path9.dirname(resolvedPath),
3570
+ filePath: resolvedPath,
3571
+ autoNamed: false
3572
+ });
3573
+ }
3574
+ return makeOkWith({
3575
+ directoryPath: resolvedPath,
3576
+ filePath: path9.join(resolvedPath, buildAutoFileName2()),
3577
+ autoNamed: true
3578
+ });
3579
+ }
3580
+ }
3581
+ async function downloadVideoToFile(remoteUrl, target) {
3582
+ try {
3583
+ await fs7.mkdir(target.directoryPath, { recursive: true });
3584
+ } catch (error) {
3585
+ const message = error instanceof Error ? error.message : String(error);
3586
+ return makeError(
3587
+ 1,
3588
+ `\u521B\u5EFA\u8F93\u51FA\u76EE\u5F55\u5931\u8D25: ${target.directoryPath}: ${message}`
3589
+ );
3590
+ }
3591
+ let response;
3592
+ try {
3593
+ response = await fetch(remoteUrl);
3594
+ } catch (error) {
3595
+ const message = error instanceof Error ? error.message : String(error);
3596
+ return makeError(1, `\u4E0B\u8F7D\u89C6\u9891\u5931\u8D25: ${message}`);
3597
+ }
3598
+ if (!response.ok) {
3599
+ return makeError(response.status, `\u4E0B\u8F7D\u89C6\u9891\u5931\u8D25: HTTP ${response.status}`);
3600
+ }
3601
+ const bytes = Buffer.from(await response.arrayBuffer());
3602
+ const targetPath = target.autoNamed ? replaceFileExtension2(target.filePath, inferVideoExtension(remoteUrl, response)) : target.filePath;
3603
+ try {
3604
+ await fs7.writeFile(targetPath, bytes);
3605
+ } catch (error) {
3606
+ const message = error instanceof Error ? error.message : String(error);
3607
+ return makeError(1, `\u5199\u5165\u89C6\u9891\u5931\u8D25: ${targetPath}: ${message}`);
3608
+ }
3609
+ return makeOkWith(path9.resolve(targetPath));
3610
+ }
3611
+ function buildAutoFileName2() {
3612
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3613
+ return `ai-vid-${timestamp}.mp4`;
3614
+ }
3615
+ function replaceFileExtension2(filePath, extension) {
3616
+ const ext = path9.extname(filePath);
3617
+ if (!ext) {
3618
+ return `${filePath}.${extension}`;
3619
+ }
3620
+ return `${filePath.slice(0, -ext.length)}.${extension}`;
3621
+ }
3622
+ function inferVideoExtension(remoteUrl, response) {
3623
+ const contentType = response.headers.get("content-type")?.toLowerCase() ?? "";
3624
+ if (contentType.includes("mp4")) {
3625
+ return "mp4";
3626
+ }
3627
+ if (contentType.includes("webm")) {
3628
+ return "webm";
3629
+ }
3630
+ if (contentType.includes("quicktime") || contentType.includes("mov")) {
3631
+ return "mov";
3632
+ }
3633
+ try {
3634
+ const url = new URL(remoteUrl);
3635
+ const ext = path9.extname(url.pathname).toLowerCase();
3636
+ if (ext === ".mp4" || ext === ".webm" || ext === ".mov") {
3637
+ return ext.slice(1);
3638
+ }
3639
+ } catch {
3640
+ }
3641
+ return "mp4";
3642
+ }
3643
+
2436
3644
  // src/commands/ai/ai-command.ts
2437
3645
  var AiCommand = class extends BaseSubcommandHost {
2438
3646
  _meta() {
@@ -2446,6 +3654,9 @@ var AiCommand = class extends BaseSubcommandHost {
2446
3654
  this._addSubcommand(new AiCursorCommand());
2447
3655
  this._addSubcommand(new AiCodexCommand());
2448
3656
  this._addSubcommand(new AiRunCommand());
3657
+ this._addSubcommand(new AiImageCommand());
3658
+ this._addSubcommand(new AiVideoCommand());
3659
+ this._addSubcommand(new AiVidCommand());
2449
3660
  }
2450
3661
  };
2451
3662