maoda-commander-tt 0.0.12 → 0.0.14

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
@@ -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((resolve6) => {
2082
2082
  child.on("error", (error) => {
2083
- resolve4(
2083
+ resolve6(
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
+ resolve6(this._makeOk());
2093
2093
  return;
2094
2094
  }
2095
2095
  const signalText = signal ? `, signal: ${signal}` : "";
2096
- resolve4(
2096
+ resolve6(
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((resolve6) => {
2174
2174
  child.on("error", (error) => {
2175
- resolve4(
2175
+ resolve6(
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
+ resolve6(this._makeOk());
2185
2185
  return;
2186
2186
  }
2187
2187
  const signalText = signal ? `, signal: ${signal}` : "";
2188
- resolve4(
2188
+ resolve6(
2189
2189
  this._makeError(
2190
2190
  code ?? 1,
2191
2191
  `\u6267\u884C ${command} ${args.join(" ")} \u5931\u8D25${signalText}`
@@ -2196,6 +2196,9 @@ 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
+
2199
2202
  // src/commands/ai/ai-websearch-command.ts
2200
2203
  var AiWebSearchCommand = class extends AiBaseCommand {
2201
2204
  _meta() {
@@ -2213,7 +2216,7 @@ var AiWebSearchCommand = class extends AiBaseCommand {
2213
2216
  return this._makeError(1, "\u8BF7\u8F93\u5165\u641C\u7D22\u5185\u5BB9");
2214
2217
  }
2215
2218
  const url = "https://ark.cn-beijing.volces.com/api/v3/responses";
2216
- const token = "45442605-446b-4184-aac4-9d577aa1764c";
2219
+ const token = ARK_AK;
2217
2220
  const response = await fetch(url, {
2218
2221
  method: "POST",
2219
2222
  headers: {
@@ -2423,7 +2426,7 @@ var AiRunCommand = class extends AiBaseCommand {
2423
2426
  }
2424
2427
  _createSystemReminder(referenceDir) {
2425
2428
  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
2429
+ \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
2430
  \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
2431
  \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
2432
  \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 +2436,525 @@ user_prompt:
2433
2436
  }
2434
2437
  };
2435
2438
 
2439
+ // src/commands/ai/ai-image-command.ts
2440
+ import * as fs6 from "fs/promises";
2441
+ import * as path7 from "path";
2442
+ import { Option as Option8 } from "commander";
2443
+
2444
+ // src/commands/ai/ai-image-reference.ts
2445
+ import * as fs5 from "fs/promises";
2446
+ import * as os2 from "os";
2447
+ import * as path6 from "path";
2448
+ import { execFile } from "child_process";
2449
+ import { promisify } from "util";
2450
+ var execFileAsync = promisify(execFile);
2451
+ var MAX_REFERENCE_IMAGE_BYTES = 2 * 1024 * 1024;
2452
+ var MAX_REFERENCE_IMAGE_COUNT = 14;
2453
+ var API_SUPPORTED_MIME_TYPES = /* @__PURE__ */ new Set([
2454
+ "image/jpeg",
2455
+ "image/png",
2456
+ "image/webp",
2457
+ "image/bmp",
2458
+ "image/tiff",
2459
+ "image/gif"
2460
+ ]);
2461
+ async function prepareReferenceImages(filePaths) {
2462
+ if (filePaths.length > MAX_REFERENCE_IMAGE_COUNT) {
2463
+ return makeError(
2464
+ 1,
2465
+ `\u53C2\u8003\u56FE\u6700\u591A\u652F\u6301 ${MAX_REFERENCE_IMAGE_COUNT} \u5F20\uFF0C\u5F53\u524D\u4F20\u5165 ${filePaths.length} \u5F20\u3002`
2466
+ );
2467
+ }
2468
+ const preparedImages = [];
2469
+ for (const filePath of filePaths) {
2470
+ const prepared = await prepareReferenceImage(filePath);
2471
+ if (!prepared.ok) {
2472
+ return prepared;
2473
+ }
2474
+ preparedImages.push(prepared.value);
2475
+ }
2476
+ return makeOkWith(preparedImages);
2477
+ }
2478
+ async function prepareReferenceImage(filePath) {
2479
+ const resolvedPath = path6.resolve(process.cwd(), filePath);
2480
+ let stats;
2481
+ try {
2482
+ stats = await fs5.stat(resolvedPath);
2483
+ } catch (error) {
2484
+ const message = error instanceof Error ? error.message : String(error);
2485
+ return makeError(1, `\u8BFB\u53D6\u53C2\u8003\u56FE\u5931\u8D25: ${resolvedPath}: ${message}`);
2486
+ }
2487
+ if (!stats.isFile()) {
2488
+ return makeError(1, `\u53C2\u8003\u56FE\u4E0D\u662F\u6587\u4EF6: ${resolvedPath}`);
2489
+ }
2490
+ let fileBytes;
2491
+ try {
2492
+ fileBytes = await fs5.readFile(resolvedPath);
2493
+ } catch (error) {
2494
+ const message = error instanceof Error ? error.message : String(error);
2495
+ return makeError(1, `\u8BFB\u53D6\u53C2\u8003\u56FE\u5185\u5BB9\u5931\u8D25: ${resolvedPath}: ${message}`);
2496
+ }
2497
+ const detectedType = detectMimeType(fileBytes, resolvedPath);
2498
+ if (!detectedType) {
2499
+ return makeError(1, `\u53C2\u8003\u56FE\u4E0D\u662F\u652F\u6301\u7684\u56FE\u7247\u683C\u5F0F: ${resolvedPath}`);
2500
+ }
2501
+ const needsTranscode = !API_SUPPORTED_MIME_TYPES.has(detectedType.mimeType) || fileBytes.byteLength > MAX_REFERENCE_IMAGE_BYTES;
2502
+ if (!needsTranscode) {
2503
+ return makeOkWith({
2504
+ inputPath: filePath,
2505
+ resolvedPath,
2506
+ sourceMimeType: detectedType.mimeType,
2507
+ requestMimeType: detectedType.mimeType,
2508
+ originalBytes: fileBytes.byteLength,
2509
+ finalBytes: fileBytes.byteLength,
2510
+ compressed: false,
2511
+ dataUrl: toDataUrl(detectedType.mimeType, fileBytes)
2512
+ });
2513
+ }
2514
+ const compressed = await compressImageForReference(resolvedPath);
2515
+ if (!compressed.ok) {
2516
+ return compressed;
2517
+ }
2518
+ return makeOkWith({
2519
+ inputPath: filePath,
2520
+ resolvedPath,
2521
+ sourceMimeType: detectedType.mimeType,
2522
+ requestMimeType: compressed.value.mimeType,
2523
+ originalBytes: fileBytes.byteLength,
2524
+ finalBytes: compressed.value.bytes.byteLength,
2525
+ compressed: true,
2526
+ dataUrl: toDataUrl(compressed.value.mimeType, compressed.value.bytes)
2527
+ });
2528
+ }
2529
+ function detectMimeType(fileBytes, filePath) {
2530
+ if (fileBytes.length >= 3 && fileBytes[0] === 255 && fileBytes[1] === 216 && fileBytes[2] === 255) {
2531
+ return { mimeType: "image/jpeg", extension: "jpeg" };
2532
+ }
2533
+ 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) {
2534
+ return { mimeType: "image/png", extension: "png" };
2535
+ }
2536
+ if (fileBytes.length >= 6) {
2537
+ const gifHeader = fileBytes.subarray(0, 6).toString("ascii");
2538
+ if (gifHeader === "GIF87a" || gifHeader === "GIF89a") {
2539
+ return { mimeType: "image/gif", extension: "gif" };
2540
+ }
2541
+ }
2542
+ if (fileBytes.length >= 12 && fileBytes.subarray(0, 4).toString("ascii") === "RIFF" && fileBytes.subarray(8, 12).toString("ascii") === "WEBP") {
2543
+ return { mimeType: "image/webp", extension: "webp" };
2544
+ }
2545
+ if (fileBytes.length >= 2 && fileBytes.subarray(0, 2).toString("ascii") === "BM") {
2546
+ return { mimeType: "image/bmp", extension: "bmp" };
2547
+ }
2548
+ 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)) {
2549
+ return { mimeType: "image/tiff", extension: "tiff" };
2550
+ }
2551
+ if (fileBytes.length >= 12 && fileBytes.subarray(4, 8).toString("ascii") === "ftyp") {
2552
+ const brand = fileBytes.subarray(8, 12).toString("ascii").trim();
2553
+ if (brand.startsWith("avif") || brand === "avis") {
2554
+ return { mimeType: "image/avif", extension: "avif" };
2555
+ }
2556
+ if (brand.startsWith("hei") || brand.startsWith("hev") || brand === "mif1" || brand === "msf1") {
2557
+ return { mimeType: "image/heic", extension: "heic" };
2558
+ }
2559
+ }
2560
+ const ext = path6.extname(filePath).toLowerCase();
2561
+ switch (ext) {
2562
+ case ".jpg":
2563
+ case ".jpeg":
2564
+ return { mimeType: "image/jpeg", extension: "jpeg" };
2565
+ case ".png":
2566
+ return { mimeType: "image/png", extension: "png" };
2567
+ case ".gif":
2568
+ return { mimeType: "image/gif", extension: "gif" };
2569
+ case ".webp":
2570
+ return { mimeType: "image/webp", extension: "webp" };
2571
+ case ".bmp":
2572
+ return { mimeType: "image/bmp", extension: "bmp" };
2573
+ case ".tif":
2574
+ case ".tiff":
2575
+ return { mimeType: "image/tiff", extension: "tiff" };
2576
+ case ".heic":
2577
+ case ".heif":
2578
+ return { mimeType: "image/heic", extension: "heic" };
2579
+ case ".avif":
2580
+ return { mimeType: "image/avif", extension: "avif" };
2581
+ default:
2582
+ return void 0;
2583
+ }
2584
+ }
2585
+ async function compressImageForReference(sourcePath) {
2586
+ if (process.platform !== "darwin") {
2587
+ return makeError(
2588
+ 1,
2589
+ `\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`
2590
+ );
2591
+ }
2592
+ const tempDir = await fs5.mkdtemp(path6.join(os2.tmpdir(), "tt-ai-image-"));
2593
+ try {
2594
+ const dimensions = await readImageDimensions(sourcePath);
2595
+ const maxDimension = Math.max(dimensions.width, dimensions.height);
2596
+ const resizeLimits = uniqueNumbers([
2597
+ maxDimension,
2598
+ Math.floor(maxDimension * 0.85),
2599
+ Math.floor(maxDimension * 0.7),
2600
+ Math.floor(maxDimension * 0.55),
2601
+ Math.floor(maxDimension * 0.4)
2602
+ ]).filter((value) => value >= 64);
2603
+ const qualityLevels = [85, 75, 65, 55, 45, 35];
2604
+ let attemptIndex = 0;
2605
+ for (const resizeLimit of resizeLimits) {
2606
+ for (const quality of qualityLevels) {
2607
+ const targetPath = path6.join(tempDir, `compressed-${attemptIndex}.jpeg`);
2608
+ attemptIndex += 1;
2609
+ await runSips([
2610
+ "--setProperty",
2611
+ "format",
2612
+ "jpeg",
2613
+ "--setProperty",
2614
+ "formatOptions",
2615
+ String(quality),
2616
+ sourcePath,
2617
+ "--out",
2618
+ targetPath
2619
+ ]);
2620
+ if (resizeLimit < maxDimension) {
2621
+ await runSips(["-Z", String(resizeLimit), targetPath]);
2622
+ }
2623
+ const compressedBytes = await fs5.readFile(targetPath);
2624
+ if (compressedBytes.byteLength <= MAX_REFERENCE_IMAGE_BYTES) {
2625
+ return makeOkWith({
2626
+ mimeType: "image/jpeg",
2627
+ bytes: compressedBytes
2628
+ });
2629
+ }
2630
+ }
2631
+ }
2632
+ return makeError(1, `\u53C2\u8003\u56FE\u538B\u7F29\u5931\u8D25\uFF0C\u65E0\u6CD5\u538B\u7F29\u5230 2MB \u4EE5\u5185: ${sourcePath}`);
2633
+ } catch (error) {
2634
+ const message = error instanceof Error ? error.message : String(error);
2635
+ return makeError(1, `\u5904\u7406\u53C2\u8003\u56FE\u5931\u8D25: ${sourcePath}: ${message}`);
2636
+ } finally {
2637
+ await fs5.rm(tempDir, { recursive: true, force: true });
2638
+ }
2639
+ }
2640
+ async function readImageDimensions(sourcePath) {
2641
+ const { stdout } = await runSips([
2642
+ "-g",
2643
+ "pixelWidth",
2644
+ "-g",
2645
+ "pixelHeight",
2646
+ sourcePath
2647
+ ]);
2648
+ const width = readSipsMetric(stdout, "pixelWidth");
2649
+ const height = readSipsMetric(stdout, "pixelHeight");
2650
+ if (!width || !height) {
2651
+ throw new Error("\u65E0\u6CD5\u8BFB\u53D6\u56FE\u7247\u5C3A\u5BF8");
2652
+ }
2653
+ return { width, height };
2654
+ }
2655
+ async function runSips(args) {
2656
+ return execFileAsync("/usr/bin/sips", [...args]);
2657
+ }
2658
+ function readSipsMetric(output, key) {
2659
+ const matcher = new RegExp(`${key}:\\s*(\\d+)`);
2660
+ const matched = output.match(matcher);
2661
+ if (!matched) {
2662
+ return void 0;
2663
+ }
2664
+ const value = Number.parseInt(matched[1], 10);
2665
+ return Number.isFinite(value) ? value : void 0;
2666
+ }
2667
+ function uniqueNumbers(values) {
2668
+ return [...new Set(values)];
2669
+ }
2670
+ function toDataUrl(mimeType, fileBytes) {
2671
+ const suffix = mimeType.replace("image/", "");
2672
+ return `data:image/${suffix};base64,${fileBytes.toString("base64")}`;
2673
+ }
2674
+
2675
+ // src/commands/ai/ai-image-command.ts
2676
+ var IMAGE_GENERATION_URL = "https://ark.cn-beijing.volces.com/api/v3/images/generations";
2677
+ var IMAGE_MODEL = "doubao-seedream-5-0-260128";
2678
+ var AiImageCommand = class extends AiBaseCommand {
2679
+ _meta() {
2680
+ return {
2681
+ name: "image",
2682
+ description: "\u8C03\u7528\u8C46\u5305 Seedream \u6A21\u578B\u751F\u6210\u56FE\u7247\u5E76\u4E0B\u8F7D\u5230\u672C\u5730"
2683
+ };
2684
+ }
2685
+ _configureOptions(cmd) {
2686
+ cmd.addOption(
2687
+ new Option8(
2688
+ "-r, --reference <path>",
2689
+ "\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"
2690
+ ).argParser(parseReferencePaths).default([])
2691
+ );
2692
+ cmd.addOption(
2693
+ new Option8(
2694
+ "-s, --size <size>",
2695
+ "\u8F93\u51FA\u5C3A\u5BF8\uFF0C\u4F8B\u5982 1024x1024\u30012048x2048\u30012K"
2696
+ ).default("2K")
2697
+ );
2698
+ cmd.addOption(
2699
+ new Option8("--output-format <format>", "\u751F\u6210\u56FE\u7247\u7F16\u7801\u683C\u5F0F").choices(["jpeg", "png", "webp"]).default("jpeg")
2700
+ );
2701
+ cmd.addOption(
2702
+ new Option8(
2703
+ "-o, --output <path>",
2704
+ "\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"
2705
+ )
2706
+ );
2707
+ }
2708
+ _configureArguments(cmd) {
2709
+ cmd.argument("[content...]", "\u751F\u56FE\u63D0\u793A\u8BCD");
2710
+ }
2711
+ async _execute(ctx) {
2712
+ const prompt = this._readPrompt(ctx);
2713
+ if (!prompt) {
2714
+ this._outputJsonError(1, "\u8BF7\u8F93\u5165\u751F\u56FE\u63D0\u793A\u8BCD");
2715
+ return this._makeOk();
2716
+ }
2717
+ const referenceResult = await prepareReferenceImages(ctx.options.reference);
2718
+ if (!referenceResult.ok) {
2719
+ this._outputJsonError(referenceResult.code, referenceResult.msg);
2720
+ return this._makeOk();
2721
+ }
2722
+ const requestBody = {
2723
+ model: IMAGE_MODEL,
2724
+ prompt,
2725
+ size: ctx.options.size ?? "2K",
2726
+ response_format: "url",
2727
+ output_format: ctx.options.outputFormat,
2728
+ watermark: false,
2729
+ ...referenceResult.value.length > 0 ? {
2730
+ image: referenceResult.value.map((item) => item.dataUrl)
2731
+ } : {}
2732
+ };
2733
+ const responseResult = await this._requestImage(requestBody);
2734
+ if (!responseResult.ok) {
2735
+ this._outputJsonError(responseResult.code, responseResult.msg);
2736
+ return this._makeOk();
2737
+ }
2738
+ const payload = responseResult.value;
2739
+ const remoteUrl = payload.data?.[0]?.url?.trim();
2740
+ if (!remoteUrl) {
2741
+ this._outputJsonError(1, "\u63A5\u53E3\u8C03\u7528\u6210\u529F\uFF0C\u4F46 data.[0].url \u4E3A\u7A7A");
2742
+ return this._makeOk();
2743
+ }
2744
+ const outputTargetResult = await resolveOutputTarget(
2745
+ ctx.options.output,
2746
+ ctx.options.outputFormat
2747
+ );
2748
+ if (!outputTargetResult.ok) {
2749
+ this._outputJsonError(outputTargetResult.code, outputTargetResult.msg);
2750
+ return this._makeOk();
2751
+ }
2752
+ const saveResult = await downloadImageToFile(
2753
+ remoteUrl,
2754
+ outputTargetResult.value
2755
+ );
2756
+ if (!saveResult.ok) {
2757
+ this._outputJsonError(saveResult.code, saveResult.msg);
2758
+ return this._makeOk();
2759
+ }
2760
+ this._outputJsonOk({
2761
+ image_path: saveResult.value
2762
+ });
2763
+ return this._makeOk();
2764
+ }
2765
+ async _requestImage(requestBody) {
2766
+ const token = process.env.ARK_AK?.trim() || ARK_AK;
2767
+ if (!token) {
2768
+ return makeError(1, "\u7F3A\u5C11 ARK_AK\uFF0C\u8BF7\u5148\u914D\u7F6E\u53EF\u7528\u7684 API Key");
2769
+ }
2770
+ const controller = new AbortController();
2771
+ const timer = setTimeout(() => controller.abort(), 12e4);
2772
+ try {
2773
+ const response = await fetch(IMAGE_GENERATION_URL, {
2774
+ method: "POST",
2775
+ headers: {
2776
+ Authorization: `Bearer ${token}`,
2777
+ "Content-Type": "application/json"
2778
+ },
2779
+ body: JSON.stringify(requestBody),
2780
+ signal: controller.signal
2781
+ });
2782
+ const bodyText = await response.text();
2783
+ const payload = parseJsonSafely(bodyText);
2784
+ if (!response.ok) {
2785
+ const suffix = extractErrorMessage(payload) ?? bodyText.trim();
2786
+ return makeError(
2787
+ response.status,
2788
+ suffix ? `\u751F\u56FE\u63A5\u53E3\u8BF7\u6C42\u5931\u8D25: HTTP ${response.status}: ${suffix}` : `\u751F\u56FE\u63A5\u53E3\u8BF7\u6C42\u5931\u8D25: HTTP ${response.status}`
2789
+ );
2790
+ }
2791
+ if (!payload) {
2792
+ return makeError(1, "\u751F\u56FE\u63A5\u53E3\u8FD4\u56DE\u975E JSON \u54CD\u5E94");
2793
+ }
2794
+ if (hasFailedCode(payload.code)) {
2795
+ return makeError(
2796
+ 1,
2797
+ extractErrorMessage(payload) ?? "\u751F\u56FE\u63A5\u53E3\u8FD4\u56DE\u9519\u8BEF"
2798
+ );
2799
+ }
2800
+ return makeOkWith(payload);
2801
+ } catch (error) {
2802
+ const message = error instanceof Error && error.name === "AbortError" ? "\u8BF7\u6C42\u8D85\u65F6" : error instanceof Error ? error.message : String(error);
2803
+ return makeError(1, `\u8C03\u7528\u751F\u56FE\u63A5\u53E3\u5931\u8D25: ${message}`);
2804
+ } finally {
2805
+ clearTimeout(timer);
2806
+ }
2807
+ }
2808
+ };
2809
+ async function resolveOutputTarget(outputPath, outputFormat) {
2810
+ if (!outputPath) {
2811
+ const directoryPath = process.cwd();
2812
+ const filePath = path7.join(directoryPath, buildAutoFileName(outputFormat));
2813
+ return makeOkWith({
2814
+ directoryPath,
2815
+ filePath,
2816
+ autoNamed: true
2817
+ });
2818
+ }
2819
+ const resolvedPath = path7.resolve(process.cwd(), outputPath);
2820
+ try {
2821
+ const stats = await fs6.stat(resolvedPath);
2822
+ if (stats.isDirectory()) {
2823
+ return makeOkWith({
2824
+ directoryPath: resolvedPath,
2825
+ filePath: path7.join(resolvedPath, buildAutoFileName(outputFormat)),
2826
+ autoNamed: true
2827
+ });
2828
+ }
2829
+ return makeOkWith({
2830
+ directoryPath: path7.dirname(resolvedPath),
2831
+ filePath: resolvedPath,
2832
+ autoNamed: false
2833
+ });
2834
+ } catch (error) {
2835
+ const nodeError = error;
2836
+ if (nodeError.code !== "ENOENT") {
2837
+ const message = error instanceof Error ? error.message : String(error);
2838
+ return makeError(1, `\u8BFB\u53D6\u8F93\u51FA\u8DEF\u5F84\u5931\u8D25: ${resolvedPath}: ${message}`);
2839
+ }
2840
+ if (path7.extname(resolvedPath)) {
2841
+ return makeOkWith({
2842
+ directoryPath: path7.dirname(resolvedPath),
2843
+ filePath: resolvedPath,
2844
+ autoNamed: false
2845
+ });
2846
+ }
2847
+ return makeOkWith({
2848
+ directoryPath: resolvedPath,
2849
+ filePath: path7.join(resolvedPath, buildAutoFileName(outputFormat)),
2850
+ autoNamed: true
2851
+ });
2852
+ }
2853
+ }
2854
+ async function downloadImageToFile(remoteUrl, target) {
2855
+ try {
2856
+ await fs6.mkdir(target.directoryPath, { recursive: true });
2857
+ } catch (error) {
2858
+ const message = error instanceof Error ? error.message : String(error);
2859
+ return makeError(
2860
+ 1,
2861
+ `\u521B\u5EFA\u8F93\u51FA\u76EE\u5F55\u5931\u8D25: ${target.directoryPath}: ${message}`
2862
+ );
2863
+ }
2864
+ let response;
2865
+ try {
2866
+ response = await fetch(remoteUrl);
2867
+ } catch (error) {
2868
+ const message = error instanceof Error ? error.message : String(error);
2869
+ return makeError(1, `\u4E0B\u8F7D\u56FE\u7247\u5931\u8D25: ${message}`);
2870
+ }
2871
+ if (!response.ok) {
2872
+ return makeError(response.status, `\u4E0B\u8F7D\u56FE\u7247\u5931\u8D25: HTTP ${response.status}`);
2873
+ }
2874
+ const bytes = Buffer.from(await response.arrayBuffer());
2875
+ const targetPath = target.autoNamed ? replaceFileExtension(
2876
+ target.filePath,
2877
+ inferImageExtension(remoteUrl, response)
2878
+ ) : target.filePath;
2879
+ try {
2880
+ await fs6.writeFile(targetPath, bytes);
2881
+ } catch (error) {
2882
+ const message = error instanceof Error ? error.message : String(error);
2883
+ return makeError(1, `\u5199\u5165\u56FE\u7247\u5931\u8D25: ${targetPath}: ${message}`);
2884
+ }
2885
+ return makeOkWith(path7.resolve(targetPath));
2886
+ }
2887
+ function parseReferencePaths(value, previous) {
2888
+ return previous.concat(
2889
+ value.split(",").map((item) => item.trim()).filter((item) => item.length > 0)
2890
+ );
2891
+ }
2892
+ function parseJsonSafely(text) {
2893
+ if (!text.trim()) {
2894
+ return void 0;
2895
+ }
2896
+ try {
2897
+ return JSON.parse(text);
2898
+ } catch {
2899
+ return void 0;
2900
+ }
2901
+ }
2902
+ function hasFailedCode(code) {
2903
+ if (code === void 0 || code === null) {
2904
+ return false;
2905
+ }
2906
+ if (typeof code === "number") {
2907
+ return code !== 0;
2908
+ }
2909
+ const normalized = code.trim();
2910
+ return normalized !== "0" && normalized !== "";
2911
+ }
2912
+ function extractErrorMessage(payload) {
2913
+ if (!payload) {
2914
+ return void 0;
2915
+ }
2916
+ const message = payload.msg?.trim() || payload.message?.trim();
2917
+ return message || void 0;
2918
+ }
2919
+ function buildAutoFileName(outputFormat) {
2920
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
2921
+ return `ai-image-${timestamp}.${outputFormat}`;
2922
+ }
2923
+ function replaceFileExtension(filePath, extension) {
2924
+ const ext = path7.extname(filePath);
2925
+ if (!ext) {
2926
+ return `${filePath}.${extension}`;
2927
+ }
2928
+ return `${filePath.slice(0, -ext.length)}.${extension}`;
2929
+ }
2930
+ function inferImageExtension(remoteUrl, response) {
2931
+ const contentType = response.headers.get("content-type")?.toLowerCase() ?? "";
2932
+ if (contentType.includes("png")) {
2933
+ return "png";
2934
+ }
2935
+ if (contentType.includes("webp")) {
2936
+ return "webp";
2937
+ }
2938
+ if (contentType.includes("jpeg") || contentType.includes("jpg")) {
2939
+ return "jpeg";
2940
+ }
2941
+ try {
2942
+ const url = new URL(remoteUrl);
2943
+ const ext = path7.extname(url.pathname).toLowerCase();
2944
+ if (ext === ".png") {
2945
+ return "png";
2946
+ }
2947
+ if (ext === ".webp") {
2948
+ return "webp";
2949
+ }
2950
+ if (ext === ".jpg" || ext === ".jpeg") {
2951
+ return "jpeg";
2952
+ }
2953
+ } catch {
2954
+ }
2955
+ return "jpeg";
2956
+ }
2957
+
2436
2958
  // src/commands/ai/ai-command.ts
2437
2959
  var AiCommand = class extends BaseSubcommandHost {
2438
2960
  _meta() {
@@ -2446,6 +2968,7 @@ var AiCommand = class extends BaseSubcommandHost {
2446
2968
  this._addSubcommand(new AiCursorCommand());
2447
2969
  this._addSubcommand(new AiCodexCommand());
2448
2970
  this._addSubcommand(new AiRunCommand());
2971
+ this._addSubcommand(new AiImageCommand());
2449
2972
  }
2450
2973
  };
2451
2974