imgx-cli 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.0 (2026-02-27)
4
+
5
+ ### Added
6
+
7
+ - **Output format selection** — `--format` flag (CLI) and `output_format` parameter (MCP) to choose between `png`, `jpeg`, or `webp` output. Currently supported by OpenAI provider (`gpt-image-1`). Gemini provider outputs PNG regardless of format setting.
8
+ - `OUTPUT_FORMAT` capability added to provider capability system
9
+
10
+ ## 0.6.2 (2026-02-27)
11
+
12
+ ### Added
13
+
14
+ - **Image preview in MCP responses** — MCP tool results now include inline image data (base64) alongside file paths. Claude Desktop and other MCP clients can display generated/edited images directly without opening files manually.
15
+
3
16
  ## 0.6.1 (2026-02-27)
4
17
 
5
18
  ### Fixed
package/README.md CHANGED
@@ -108,6 +108,7 @@ imgx edit --last -p "Crop to 16:9" -o final.png
108
108
  | `--aspect-ratio` | `-a` | `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `2:3`, `3:2` |
109
109
  | `--resolution` | `-r` | `1K`, `2K`, `4K` |
110
110
  | `--count` | `-n` | Number of images to generate |
111
+ | `--format` | `-f` | Output format: `png`, `jpeg`, `webp` (OpenAI only) |
111
112
  | `--model` | `-m` | Model name |
112
113
  | `--provider` | | Provider name (default: `gemini`) |
113
114
  | `--output-dir` | `-d` | Output directory |
@@ -315,13 +316,14 @@ Each provider declares its supported capabilities. The CLI dynamically enables o
315
316
  | `MULTIPLE_OUTPUTS` | Generate multiple images per request |
316
317
  | `REFERENCE_IMAGES` | Use reference images for guidance |
317
318
  | `PERSON_CONTROL` | Control person generation in output |
319
+ | `OUTPUT_FORMAT` | Choose output format (PNG, JPEG, WebP) |
318
320
 
319
321
  ### Current providers
320
322
 
321
323
  | Provider | Models | Capabilities |
322
324
  |----------|--------|-------------|
323
- | Gemini | `gemini-3-pro-image-preview`, `gemini-2.5-flash-image` | All 7 capabilities |
324
- | OpenAI | `gpt-image-1` | Generate, edit, aspect ratio, multi-output |
325
+ | Gemini | `gemini-3-pro-image-preview`, `gemini-2.5-flash-image` | All 7 base capabilities |
326
+ | OpenAI | `gpt-image-1` | Generate, edit, aspect ratio, multi-output, output format |
325
327
 
326
328
  ## Development
327
329
 
@@ -39252,6 +39252,7 @@ var Capability;
39252
39252
  Capability2["REFERENCE_IMAGES"] = "REFERENCE_IMAGES";
39253
39253
  Capability2["PERSON_CONTROL"] = "PERSON_CONTROL";
39254
39254
  Capability2["STYLE_CONTROL"] = "STYLE_CONTROL";
39255
+ Capability2["OUTPUT_FORMAT"] = "OUTPUT_FORMAT";
39255
39256
  })(Capability || (Capability = {}));
39256
39257
 
39257
39258
  // build/providers/gemini/capabilities.js
@@ -39384,7 +39385,8 @@ var OPENAI_PROVIDER_INFO = {
39384
39385
  Capability.TEXT_TO_IMAGE,
39385
39386
  Capability.ASPECT_RATIO,
39386
39387
  Capability.IMAGE_EDITING,
39387
- Capability.MULTIPLE_OUTPUTS
39388
+ Capability.MULTIPLE_OUTPUTS,
39389
+ Capability.OUTPUT_FORMAT
39388
39390
  ]),
39389
39391
  aspectRatios: ["1:1", "3:2", "2:3", "16:9", "9:16", "4:3", "3:4"],
39390
39392
  resolutions: ["1K", "2K", "4K"]
@@ -39465,7 +39467,8 @@ var OpenAIProvider = class {
39465
39467
  prompt: input.prompt,
39466
39468
  n: input.count || 1,
39467
39469
  size: mapSize(input.aspectRatio),
39468
- quality: mapQuality(input.resolution)
39470
+ quality: mapQuality(input.resolution),
39471
+ ...input.outputFormat ? { output_format: input.outputFormat } : {}
39469
39472
  })
39470
39473
  });
39471
39474
  const json = await response.json();
@@ -39476,7 +39479,7 @@ var OpenAIProvider = class {
39476
39479
  error: json.error?.message || `HTTP ${response.status}`
39477
39480
  };
39478
39481
  }
39479
- return this.parseResponse(json);
39482
+ return this.parseResponse(json, input.outputFormat);
39480
39483
  } catch (err) {
39481
39484
  const msg = err instanceof Error ? err.message : String(err);
39482
39485
  return { success: false, images: [], error: msg };
@@ -39493,7 +39496,8 @@ var OpenAIProvider = class {
39493
39496
  prompt: input.prompt,
39494
39497
  n: String(input.count || 1),
39495
39498
  size: mapSize(input.aspectRatio),
39496
- quality: mapQuality(input.resolution)
39499
+ quality: mapQuality(input.resolution),
39500
+ ...input.outputFormat ? { output_format: input.outputFormat } : {}
39497
39501
  };
39498
39502
  const { body, contentType: ct } = buildMultipart(fields, [
39499
39503
  {
@@ -39520,20 +39524,22 @@ var OpenAIProvider = class {
39520
39524
  error: json.error?.message || `HTTP ${response.status}`
39521
39525
  };
39522
39526
  }
39523
- return this.parseResponse(json);
39527
+ return this.parseResponse(json, input.outputFormat);
39524
39528
  } catch (err) {
39525
39529
  const msg = err instanceof Error ? err.message : String(err);
39526
39530
  return { success: false, images: [], error: msg };
39527
39531
  }
39528
39532
  }
39529
- parseResponse(json) {
39533
+ parseResponse(json, outputFormat) {
39534
+ const mimeMap = { png: "image/png", jpeg: "image/jpeg", webp: "image/webp" };
39535
+ const mimeType = mimeMap[outputFormat || "png"] || "image/png";
39530
39536
  const images = [];
39531
39537
  if (json.data) {
39532
39538
  for (const item of json.data) {
39533
39539
  if (item.b64_json) {
39534
39540
  images.push({
39535
39541
  data: Buffer.from(item.b64_json, "base64"),
39536
- mimeType: "image/png"
39542
+ mimeType
39537
39543
  });
39538
39544
  }
39539
39545
  }
@@ -39590,7 +39596,8 @@ async function runGenerate(provider, args) {
39590
39596
  prompt: args.prompt,
39591
39597
  aspectRatio: args.aspectRatio,
39592
39598
  count: args.count,
39593
- resolution: args.resolution
39599
+ resolution: args.resolution,
39600
+ outputFormat: args.outputFormat
39594
39601
  }, args.model);
39595
39602
  if (!result.success || result.images.length === 0) {
39596
39603
  fail(result.error || "Generation failed");
@@ -39618,7 +39625,8 @@ async function runEdit(provider, args) {
39618
39625
  inputImage: args.inputImage,
39619
39626
  prompt: args.prompt,
39620
39627
  aspectRatio: args.aspectRatio,
39621
- resolution: args.resolution
39628
+ resolution: args.resolution,
39629
+ outputFormat: args.outputFormat
39622
39630
  }, args.model);
39623
39631
  if (!result.success || result.images.length === 0) {
39624
39632
  fail(result.error || "Edit failed");
@@ -39769,7 +39777,7 @@ function showAll() {
39769
39777
  }
39770
39778
 
39771
39779
  // build/cli/index.js
39772
- var VERSION2 = "0.6.1";
39780
+ var VERSION2 = "0.7.0";
39773
39781
  var HELP = `imgx v${VERSION2} \u2014 AI image generation and editing CLI
39774
39782
 
39775
39783
  Commands:
@@ -39794,6 +39802,7 @@ Options:
39794
39802
  -a, --aspect-ratio <ratio> Aspect ratio (e.g., 16:9, 1:1)
39795
39803
  -n, --count <number> Number of images to generate
39796
39804
  -r, --resolution <size> Resolution: 1K, 2K, 4K
39805
+ -f, --format <type> Output format: png, jpeg, webp (OpenAI only)
39797
39806
  -m, --model <model> Model name
39798
39807
  --provider <name> Provider: gemini, openai (default: gemini)
39799
39808
  -d, --output-dir <dir> Output directory
@@ -39861,6 +39870,7 @@ function main() {
39861
39870
  "aspect-ratio": { type: "string", short: "a" },
39862
39871
  count: { type: "string", short: "n" },
39863
39872
  resolution: { type: "string", short: "r" },
39873
+ format: { type: "string", short: "f" },
39864
39874
  model: { type: "string", short: "m" },
39865
39875
  provider: { type: "string" },
39866
39876
  "output-dir": { type: "string", short: "d" },
@@ -39895,6 +39905,7 @@ function main() {
39895
39905
  outputDir: values["output-dir"] || resolveDefault("outputDir") || void 0,
39896
39906
  aspectRatio: values["aspect-ratio"] || resolveDefault("aspectRatio") || void 0,
39897
39907
  resolution: values.resolution || resolveDefault("resolution") || void 0,
39908
+ outputFormat: values.format || void 0,
39898
39909
  model,
39899
39910
  count: values.count ? parseInt(values.count, 10) : void 0
39900
39911
  };
@@ -69290,6 +69290,7 @@ var Capability;
69290
69290
  Capability2["REFERENCE_IMAGES"] = "REFERENCE_IMAGES";
69291
69291
  Capability2["PERSON_CONTROL"] = "PERSON_CONTROL";
69292
69292
  Capability2["STYLE_CONTROL"] = "STYLE_CONTROL";
69293
+ Capability2["OUTPUT_FORMAT"] = "OUTPUT_FORMAT";
69293
69294
  })(Capability || (Capability = {}));
69294
69295
 
69295
69296
  // build/providers/gemini/capabilities.js
@@ -69422,7 +69423,8 @@ var OPENAI_PROVIDER_INFO = {
69422
69423
  Capability.TEXT_TO_IMAGE,
69423
69424
  Capability.ASPECT_RATIO,
69424
69425
  Capability.IMAGE_EDITING,
69425
- Capability.MULTIPLE_OUTPUTS
69426
+ Capability.MULTIPLE_OUTPUTS,
69427
+ Capability.OUTPUT_FORMAT
69426
69428
  ]),
69427
69429
  aspectRatios: ["1:1", "3:2", "2:3", "16:9", "9:16", "4:3", "3:4"],
69428
69430
  resolutions: ["1K", "2K", "4K"]
@@ -69503,7 +69505,8 @@ var OpenAIProvider = class {
69503
69505
  prompt: input.prompt,
69504
69506
  n: input.count || 1,
69505
69507
  size: mapSize(input.aspectRatio),
69506
- quality: mapQuality(input.resolution)
69508
+ quality: mapQuality(input.resolution),
69509
+ ...input.outputFormat ? { output_format: input.outputFormat } : {}
69507
69510
  })
69508
69511
  });
69509
69512
  const json2 = await response.json();
@@ -69514,7 +69517,7 @@ var OpenAIProvider = class {
69514
69517
  error: json2.error?.message || `HTTP ${response.status}`
69515
69518
  };
69516
69519
  }
69517
- return this.parseResponse(json2);
69520
+ return this.parseResponse(json2, input.outputFormat);
69518
69521
  } catch (err) {
69519
69522
  const msg = err instanceof Error ? err.message : String(err);
69520
69523
  return { success: false, images: [], error: msg };
@@ -69531,7 +69534,8 @@ var OpenAIProvider = class {
69531
69534
  prompt: input.prompt,
69532
69535
  n: String(input.count || 1),
69533
69536
  size: mapSize(input.aspectRatio),
69534
- quality: mapQuality(input.resolution)
69537
+ quality: mapQuality(input.resolution),
69538
+ ...input.outputFormat ? { output_format: input.outputFormat } : {}
69535
69539
  };
69536
69540
  const { body, contentType: ct } = buildMultipart(fields, [
69537
69541
  {
@@ -69558,20 +69562,22 @@ var OpenAIProvider = class {
69558
69562
  error: json2.error?.message || `HTTP ${response.status}`
69559
69563
  };
69560
69564
  }
69561
- return this.parseResponse(json2);
69565
+ return this.parseResponse(json2, input.outputFormat);
69562
69566
  } catch (err) {
69563
69567
  const msg = err instanceof Error ? err.message : String(err);
69564
69568
  return { success: false, images: [], error: msg };
69565
69569
  }
69566
69570
  }
69567
- parseResponse(json2) {
69571
+ parseResponse(json2, outputFormat) {
69572
+ const mimeMap = { png: "image/png", jpeg: "image/jpeg", webp: "image/webp" };
69573
+ const mimeType = mimeMap[outputFormat || "png"] || "image/png";
69568
69574
  const images = [];
69569
69575
  if (json2.data) {
69570
69576
  for (const item of json2.data) {
69571
69577
  if (item.b64_json) {
69572
69578
  images.push({
69573
69579
  data: Buffer.from(item.b64_json, "base64"),
69574
- mimeType: "image/png"
69580
+ mimeType
69575
69581
  });
69576
69582
  }
69577
69583
  }
@@ -69592,9 +69598,17 @@ function initOpenAI() {
69592
69598
  }
69593
69599
 
69594
69600
  // build/mcp/server.js
69601
+ function buildImageContent(images, paths, extra) {
69602
+ const content = [];
69603
+ for (const img of images) {
69604
+ content.push({ type: "image", data: img.data.toString("base64"), mimeType: img.mimeType });
69605
+ }
69606
+ content.push({ type: "text", text: JSON.stringify({ success: true, filePaths: paths, ...extra }) });
69607
+ return content;
69608
+ }
69595
69609
  var server = new McpServer({
69596
69610
  name: "imgx",
69597
- version: "0.6.1"
69611
+ version: "0.7.0"
69598
69612
  });
69599
69613
  initGemini();
69600
69614
  initOpenAI();
@@ -69614,6 +69628,7 @@ server.tool("generate_image", "Generate an image from a text prompt", {
69614
69628
  aspect_ratio: external_exports3.enum(["1:1", "2:3", "3:2", "3:4", "4:3", "9:16", "16:9"]).optional().describe("Aspect ratio"),
69615
69629
  resolution: external_exports3.enum(["1K", "2K", "4K"]).optional().describe("Output resolution"),
69616
69630
  count: external_exports3.number().int().min(1).max(4).optional().describe("Number of images"),
69631
+ output_format: external_exports3.enum(["png", "jpeg", "webp"]).optional().describe("Output format"),
69617
69632
  model: external_exports3.string().optional().describe("Model name"),
69618
69633
  provider: external_exports3.string().optional().describe("Provider name")
69619
69634
  }, async (args) => {
@@ -69623,7 +69638,8 @@ server.tool("generate_image", "Generate an image from a text prompt", {
69623
69638
  prompt: args.prompt,
69624
69639
  aspectRatio: args.aspect_ratio,
69625
69640
  resolution: args.resolution,
69626
- count: args.count
69641
+ count: args.count,
69642
+ outputFormat: args.output_format
69627
69643
  };
69628
69644
  const result = await prov.generate(input, args.model);
69629
69645
  if (!result.success || result.images.length === 0) {
@@ -69636,9 +69652,7 @@ server.tool("generate_image", "Generate an image from a text prompt", {
69636
69652
  paths.push(saved);
69637
69653
  }
69638
69654
  saveLastOutput(paths);
69639
- return {
69640
- content: [{ type: "text", text: JSON.stringify({ success: true, filePaths: paths }) }]
69641
- };
69655
+ return { content: buildImageContent(result.images, paths) };
69642
69656
  } catch (err) {
69643
69657
  const msg = err instanceof Error ? err.message : String(err);
69644
69658
  return { content: [{ type: "text", text: `Error: ${msg}` }] };
@@ -69651,6 +69665,7 @@ server.tool("edit_image", "Edit an existing image with text instructions", {
69651
69665
  output_dir: external_exports3.string().optional().describe("Output directory"),
69652
69666
  aspect_ratio: external_exports3.enum(["1:1", "2:3", "3:2", "3:4", "4:3", "9:16", "16:9"]).optional().describe("Aspect ratio"),
69653
69667
  resolution: external_exports3.enum(["1K", "2K", "4K"]).optional().describe("Output resolution"),
69668
+ output_format: external_exports3.enum(["png", "jpeg", "webp"]).optional().describe("Output format"),
69654
69669
  model: external_exports3.string().optional().describe("Model name"),
69655
69670
  provider: external_exports3.string().optional().describe("Provider name")
69656
69671
  }, async (args) => {
@@ -69665,7 +69680,8 @@ server.tool("edit_image", "Edit an existing image with text instructions", {
69665
69680
  prompt: args.prompt,
69666
69681
  inputImage: args.input,
69667
69682
  aspectRatio: args.aspect_ratio,
69668
- resolution: args.resolution
69683
+ resolution: args.resolution,
69684
+ outputFormat: args.output_format
69669
69685
  };
69670
69686
  const result = await prov.edit(input, args.model);
69671
69687
  if (!result.success || result.images.length === 0) {
@@ -69673,9 +69689,7 @@ server.tool("edit_image", "Edit an existing image with text instructions", {
69673
69689
  }
69674
69690
  const saved = saveImage(result.images[0], args.output, args.output_dir);
69675
69691
  saveLastOutput([saved]);
69676
- return {
69677
- content: [{ type: "text", text: JSON.stringify({ success: true, filePaths: [saved] }) }]
69678
- };
69692
+ return { content: buildImageContent(result.images, [saved]) };
69679
69693
  } catch (err) {
69680
69694
  const msg = err instanceof Error ? err.message : String(err);
69681
69695
  return { content: [{ type: "text", text: `Error: ${msg}` }] };
@@ -69687,6 +69701,7 @@ server.tool("edit_last", "Edit the last generated/edited image with new text ins
69687
69701
  output_dir: external_exports3.string().optional().describe("Output directory"),
69688
69702
  aspect_ratio: external_exports3.enum(["1:1", "2:3", "3:2", "3:4", "4:3", "9:16", "16:9"]).optional().describe("Aspect ratio"),
69689
69703
  resolution: external_exports3.enum(["1K", "2K", "4K"]).optional().describe("Output resolution"),
69704
+ output_format: external_exports3.enum(["png", "jpeg", "webp"]).optional().describe("Output format"),
69690
69705
  model: external_exports3.string().optional().describe("Model name"),
69691
69706
  provider: external_exports3.string().optional().describe("Provider name")
69692
69707
  }, async (args) => {
@@ -69707,7 +69722,8 @@ server.tool("edit_last", "Edit the last generated/edited image with new text ins
69707
69722
  prompt: args.prompt,
69708
69723
  inputImage: lastPaths[0],
69709
69724
  aspectRatio: args.aspect_ratio,
69710
- resolution: args.resolution
69725
+ resolution: args.resolution,
69726
+ outputFormat: args.output_format
69711
69727
  };
69712
69728
  const result = await prov.edit(input, args.model);
69713
69729
  if (!result.success || result.images.length === 0) {
@@ -69715,9 +69731,7 @@ server.tool("edit_last", "Edit the last generated/edited image with new text ins
69715
69731
  }
69716
69732
  const saved = saveImage(result.images[0], args.output, args.output_dir);
69717
69733
  saveLastOutput([saved]);
69718
- return {
69719
- content: [{ type: "text", text: JSON.stringify({ success: true, filePaths: [saved], inputUsed: lastPaths[0] }) }]
69720
- };
69734
+ return { content: buildImageContent(result.images, [saved], { inputUsed: lastPaths[0] }) };
69721
69735
  } catch (err) {
69722
69736
  const msg = err instanceof Error ? err.message : String(err);
69723
69737
  return { content: [{ type: "text", text: `Error: ${msg}` }] };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imgx-cli",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "mcpName": "io.github.somacoffeekyoto/imgx",
5
5
  "description": "AI image generation and editing CLI with provider abstraction",
6
6
  "type": "module",