imgx-cli 0.6.0 → 0.6.1

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,30 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.1 (2026-02-27)
4
+
5
+ ### Fixed
6
+
7
+ - Default output directory changed from process cwd to `~/Pictures/imgx` — fixes images being saved to AppData when used via MCP (Claude Desktop, etc.)
8
+
9
+ ## 0.6.0 (2026-02-27)
10
+
11
+ ### Added
12
+
13
+ - **OpenAI provider** — `gpt-image-1` model with generate and edit support
14
+ - Native `fetch` implementation (no `openai` npm dependency)
15
+ - Aspect ratio mapping to OpenAI size strings, resolution mapping to quality parameter
16
+ - Manual multipart/form-data construction for Node 18 compatibility
17
+ - `OPENAI_API_KEY` environment variable support
18
+ - `--provider` flag for `imgx config set api-key` — manage API keys per provider
19
+ - `imgx config set api-key <key> --provider openai`
20
+ - `imgx config list` now shows all configured provider keys
21
+
22
+ ### Changed
23
+
24
+ - CLI and MCP server now initialize both Gemini and OpenAI providers at startup
25
+ - `imgx providers` and error messages updated for multi-provider context
26
+ - Help text updated with OpenAI provider info and env var
27
+
3
28
  ## 0.5.2 (2026-02-26)
4
29
 
5
30
  ### Fixed
package/README.md CHANGED
@@ -48,16 +48,25 @@ Requires Node.js 18+.
48
48
 
49
49
  ## Setup
50
50
 
51
- Get a Gemini API key from [Google AI Studio](https://aistudio.google.com/apikey) (free tier available), then save it:
51
+ Set up at least one provider:
52
+
53
+ **Gemini** — get a key from [Google AI Studio](https://aistudio.google.com/apikey) (free tier available):
54
+
55
+ ```bash
56
+ imgx config set api-key YOUR_GEMINI_API_KEY --provider gemini
57
+ ```
58
+
59
+ **OpenAI** — get a key from [OpenAI Platform](https://platform.openai.com/api-keys):
52
60
 
53
61
  ```bash
54
- imgx config set api-key YOUR_GEMINI_API_KEY
62
+ imgx config set api-key YOUR_OPENAI_API_KEY --provider openai
55
63
  ```
56
64
 
57
- This stores the key in `~/.config/imgx/config.json` (Linux/macOS) or `%APPDATA%\imgx\config.json` (Windows). Alternatively, set an environment variable:
65
+ Keys are stored in `~/.config/imgx/config.json` (Linux/macOS) or `%APPDATA%\imgx\config.json` (Windows). Alternatively, set environment variables:
58
66
 
59
67
  ```bash
60
68
  export GEMINI_API_KEY="your-api-key"
69
+ export OPENAI_API_KEY="your-api-key"
61
70
  ```
62
71
 
63
72
  Environment variables take precedence over the config file.
@@ -106,7 +115,8 @@ imgx edit --last -p "Crop to 16:9" -o final.png
106
115
  ### Configuration
107
116
 
108
117
  ```bash
109
- imgx config set api-key <key> # Save Gemini API key
118
+ imgx config set api-key <key> --provider gemini # Save Gemini API key
119
+ imgx config set api-key <key> --provider openai # Save OpenAI API key
110
120
  imgx config set model <name> # Set default model
111
121
  imgx config set output-dir <dir> # Set default output directory
112
122
  imgx config set aspect-ratio 16:9 # Set default aspect ratio
@@ -162,7 +172,8 @@ Environment variables override config file settings.
162
172
 
163
173
  | Variable | Description |
164
174
  |----------|-------------|
165
- | `GEMINI_API_KEY` | Gemini API key (overrides `imgx config set api-key`) |
175
+ | `GEMINI_API_KEY` | Gemini API key |
176
+ | `OPENAI_API_KEY` | OpenAI API key |
166
177
  | `IMGX_PROVIDER` | Default provider |
167
178
  | `IMGX_MODEL` | Default model |
168
179
  | `IMGX_OUTPUT_DIR` | Default output directory |
@@ -206,7 +217,7 @@ Add to your tool's MCP config. The `env` section is optional if you have already
206
217
  "imgx": {
207
218
  "command": "npx",
208
219
  "args": ["--package=imgx-cli", "-y", "imgx-mcp"],
209
- "env": { "GEMINI_API_KEY": "your-api-key" }
220
+ "env": { "GEMINI_API_KEY": "your-key", "OPENAI_API_KEY": "your-key" }
210
221
  }
211
222
  }
212
223
  }
@@ -224,7 +235,7 @@ Or install as a [Claude Code plugin](#install) for automatic MCP registration.
224
235
  "imgx": {
225
236
  "command": "npx",
226
237
  "args": ["--package=imgx-cli", "-y", "imgx-mcp"],
227
- "env": { "GEMINI_API_KEY": "your-api-key" }
238
+ "env": { "GEMINI_API_KEY": "your-key", "OPENAI_API_KEY": "your-key" }
228
239
  }
229
240
  }
230
241
  }
@@ -240,7 +251,7 @@ macOS / Linux:
240
251
  "imgx": {
241
252
  "command": "npx",
242
253
  "args": ["--package=imgx-cli", "-y", "imgx-mcp"],
243
- "env": { "GEMINI_API_KEY": "your-api-key" }
254
+ "env": { "GEMINI_API_KEY": "your-key", "OPENAI_API_KEY": "your-key" }
244
255
  }
245
256
  }
246
257
  }
@@ -254,7 +265,7 @@ Windows:
254
265
  "imgx": {
255
266
  "command": "cmd",
256
267
  "args": ["/c", "npx", "--package=imgx-cli", "-y", "imgx-mcp"],
257
- "env": { "GEMINI_API_KEY": "your-api-key" }
268
+ "env": { "GEMINI_API_KEY": "your-key", "OPENAI_API_KEY": "your-key" }
258
269
  }
259
270
  }
260
271
  }
@@ -270,11 +281,13 @@ Config file location: `%APPDATA%\Claude\claude_desktop_config.json` (Windows) or
270
281
  [mcp_servers.imgx]
271
282
  command = "npx"
272
283
  args = ["--package=imgx-cli", "-y", "imgx-mcp"]
273
- env = { GEMINI_API_KEY = "your-api-key" }
284
+ env = { GEMINI_API_KEY = "your-key", OPENAI_API_KEY = "your-key" }
274
285
  ```
275
286
 
276
287
  The same `npx` pattern works with Cursor, Windsurf, Continue.dev, Cline, Zed, and other MCP-compatible tools. On Windows, use `cmd /c npx` instead of `npx` directly.
277
288
 
289
+ Only include the API keys for providers you want to use. At least one is required.
290
+
278
291
  ## Architecture
279
292
 
280
293
  imgx separates **model-independent** and **model-dependent** concerns:
@@ -308,6 +321,7 @@ Each provider declares its supported capabilities. The CLI dynamically enables o
308
321
  | Provider | Models | Capabilities |
309
322
  |----------|--------|-------------|
310
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 |
311
325
 
312
326
  ## Development
313
327
 
@@ -39210,8 +39210,9 @@ function getApiKeyFromEnv() {
39210
39210
 
39211
39211
  // build/core/storage.js
39212
39212
  import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "node:fs";
39213
- import { dirname, resolve as resolve2 } from "node:path";
39213
+ import { dirname, join as join2, resolve as resolve2 } from "node:path";
39214
39214
  import { randomUUID } from "node:crypto";
39215
+ import { homedir as homedir2 } from "node:os";
39215
39216
  var MIME_TO_EXT = {
39216
39217
  "image/png": ".png",
39217
39218
  "image/jpeg": ".jpg",
@@ -39224,9 +39225,17 @@ function readImageAsBase64(filePath) {
39224
39225
  const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : ext === "webp" ? "image/webp" : "image/png";
39225
39226
  return { data: buffer.toString("base64"), mimeType };
39226
39227
  }
39228
+ function fallbackOutputDir(outputDir) {
39229
+ if (outputDir)
39230
+ return outputDir;
39231
+ const configured = resolveDefault("outputDir");
39232
+ if (configured)
39233
+ return configured;
39234
+ return join2(homedir2(), "Pictures", "imgx");
39235
+ }
39227
39236
  function saveImage(image, outputPath, outputDir) {
39228
39237
  const ext = MIME_TO_EXT[image.mimeType] || ".png";
39229
- const filePath = outputPath ? resolve2(outputPath) : resolve2(outputDir || ".", `imgx-${randomUUID().slice(0, 8)}${ext}`);
39238
+ const filePath = outputPath ? resolve2(outputPath) : resolve2(fallbackOutputDir(outputDir), `imgx-${randomUUID().slice(0, 8)}${ext}`);
39230
39239
  mkdirSync2(dirname(filePath), { recursive: true });
39231
39240
  writeFileSync2(filePath, image.data);
39232
39241
  return filePath;
@@ -39760,7 +39769,7 @@ function showAll() {
39760
39769
  }
39761
39770
 
39762
39771
  // build/cli/index.js
39763
- var VERSION2 = "0.6.0";
39772
+ var VERSION2 = "0.6.1";
39764
39773
  var HELP = `imgx v${VERSION2} \u2014 AI image generation and editing CLI
39765
39774
 
39766
39775
  Commands:
@@ -52131,6 +52131,28 @@ function resolveApiKey(providerName) {
52131
52131
  const config2 = loadConfig();
52132
52132
  return config2.providers?.[providerName]?.apiKey;
52133
52133
  }
52134
+ function loadProjectConfig() {
52135
+ try {
52136
+ const raw = readFileSync(resolve(".imgxrc"), "utf-8");
52137
+ return JSON.parse(raw);
52138
+ } catch {
52139
+ return {};
52140
+ }
52141
+ }
52142
+ function resolveDefault(key) {
52143
+ const envMap = {
52144
+ provider: process.env.IMGX_PROVIDER,
52145
+ model: process.env.IMGX_MODEL,
52146
+ outputDir: process.env.IMGX_OUTPUT_DIR
52147
+ };
52148
+ if (envMap[key])
52149
+ return envMap[key];
52150
+ const project = loadProjectConfig();
52151
+ if (project.defaults?.[key])
52152
+ return project.defaults[key];
52153
+ const config2 = loadConfig();
52154
+ return config2.defaults?.[key];
52155
+ }
52134
52156
  function saveLastOutput(filePaths) {
52135
52157
  const dir = configDir();
52136
52158
  mkdirSync(dir, { recursive: true });
@@ -69226,8 +69248,9 @@ function getApiKeyFromEnv() {
69226
69248
 
69227
69249
  // build/core/storage.js
69228
69250
  import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "node:fs";
69229
- import { dirname, resolve as resolve2 } from "node:path";
69251
+ import { dirname, join as join2, resolve as resolve2 } from "node:path";
69230
69252
  import { randomUUID } from "node:crypto";
69253
+ import { homedir as homedir2 } from "node:os";
69231
69254
  var MIME_TO_EXT = {
69232
69255
  "image/png": ".png",
69233
69256
  "image/jpeg": ".jpg",
@@ -69240,9 +69263,17 @@ function readImageAsBase64(filePath) {
69240
69263
  const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : ext === "webp" ? "image/webp" : "image/png";
69241
69264
  return { data: buffer.toString("base64"), mimeType };
69242
69265
  }
69266
+ function fallbackOutputDir(outputDir) {
69267
+ if (outputDir)
69268
+ return outputDir;
69269
+ const configured = resolveDefault("outputDir");
69270
+ if (configured)
69271
+ return configured;
69272
+ return join2(homedir2(), "Pictures", "imgx");
69273
+ }
69243
69274
  function saveImage(image, outputPath, outputDir) {
69244
69275
  const ext = MIME_TO_EXT[image.mimeType] || ".png";
69245
- const filePath = outputPath ? resolve2(outputPath) : resolve2(outputDir || ".", `imgx-${randomUUID().slice(0, 8)}${ext}`);
69276
+ const filePath = outputPath ? resolve2(outputPath) : resolve2(fallbackOutputDir(outputDir), `imgx-${randomUUID().slice(0, 8)}${ext}`);
69246
69277
  mkdirSync2(dirname(filePath), { recursive: true });
69247
69278
  writeFileSync2(filePath, image.data);
69248
69279
  return filePath;
@@ -69563,7 +69594,7 @@ function initOpenAI() {
69563
69594
  // build/mcp/server.js
69564
69595
  var server = new McpServer({
69565
69596
  name: "imgx",
69566
- version: "0.6.0"
69597
+ version: "0.6.1"
69567
69598
  });
69568
69599
  initGemini();
69569
69600
  initOpenAI();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imgx-cli",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "mcpName": "io.github.somacoffeekyoto/imgx",
5
5
  "description": "AI image generation and editing CLI with provider abstraction",
6
6
  "type": "module",