ima2-gen 1.0.6 → 1.0.7
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/.env.example +49 -2
- package/README.md +192 -152
- package/bin/commands/edit.js +1 -1
- package/bin/commands/gen.js +1 -1
- package/bin/ima2.js +15 -7
- package/bin/lib/star-prompt.js +97 -0
- package/config.js +167 -0
- package/lib/assetLifecycle.js +4 -3
- package/lib/db.js +11 -6
- package/lib/errorClassify.js +62 -0
- package/lib/historyList.js +66 -0
- package/lib/inflight.js +70 -6
- package/lib/logger.js +116 -0
- package/lib/nodeStore.js +3 -2
- package/lib/oauthLauncher.js +31 -0
- package/lib/oauthNormalize.js +30 -0
- package/lib/oauthProxy.js +271 -0
- package/lib/refs.js +35 -0
- package/lib/sessionStore.js +49 -0
- package/lib/styleSheet.js +128 -0
- package/package.json +4 -2
- package/routes/edit.js +171 -0
- package/routes/generate.js +254 -0
- package/routes/health.js +89 -0
- package/routes/history.js +102 -0
- package/routes/index.js +16 -0
- package/routes/nodes.js +272 -0
- package/routes/sessions.js +273 -0
- package/server.js +119 -1083
- package/ui/dist/assets/index-D1MUxZaB.js +16 -0
- package/ui/dist/assets/index-D1MUxZaB.js.map +1 -0
- package/ui/dist/assets/index-Jcs5Q1sj.css +1 -0
- package/ui/dist/index.html +18 -2
- package/ui/dist/assets/index-B66MK5qN.css +0 -1
- package/ui/dist/assets/index-BIwLnT0j.js +0 -16
- package/ui/dist/assets/index-BIwLnT0j.js.map +0 -1
package/.env.example
CHANGED
|
@@ -1,2 +1,49 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# ima2-gen runtime configuration (see config.js).
|
|
2
|
+
# Copy to .env or export in your shell. All keys are optional; defaults live in config.js.
|
|
3
|
+
# Priority: env var > ${IMA2_CONFIG_DIR}/config.json > built-in default.
|
|
4
|
+
|
|
5
|
+
# ── Server ─────────────────────────────────────────────────────────────
|
|
6
|
+
# IMA2_PORT=3333 # also accepted: PORT
|
|
7
|
+
# IMA2_HOST=127.0.0.1
|
|
8
|
+
# IMA2_BODY_LIMIT=50mb
|
|
9
|
+
|
|
10
|
+
# ── OAuth proxy (openai-oauth subprocess) ──────────────────────────────
|
|
11
|
+
# IMA2_OAUTH_PROXY_PORT=10531 # also accepted: OAUTH_PORT
|
|
12
|
+
# IMA2_NO_OAUTH_PROXY=1 # disable auto-start (unit tests / CI)
|
|
13
|
+
# IMA2_OAUTH_STATUS_TIMEOUT_MS=3000
|
|
14
|
+
# IMA2_OAUTH_RESTART_DELAY_MS=5000
|
|
15
|
+
# IMA2_RESEARCH_SUFFIX="..." # appended to every image prompt
|
|
16
|
+
|
|
17
|
+
# ── Paths ──────────────────────────────────────────────────────────────
|
|
18
|
+
# IMA2_CONFIG_DIR=/custom/path # defaults to ~/.ima2
|
|
19
|
+
# IMA2_DB_PATH=/custom/sessions.db
|
|
20
|
+
# IMA2_GENERATED_DIR=/custom/generated
|
|
21
|
+
# IMA2_TRASH_DIR=/custom/generated/.trash
|
|
22
|
+
# IMA2_ADVERTISE_FILE=/custom/server.json
|
|
23
|
+
# IMA2_STATIC_MAX_AGE=1y
|
|
24
|
+
|
|
25
|
+
# ── Limits ─────────────────────────────────────────────────────────────
|
|
26
|
+
# IMA2_MAX_REF_B64_BYTES=7340032 # ~5.2MB decoded
|
|
27
|
+
# IMA2_MAX_REF_COUNT=5
|
|
28
|
+
# IMA2_MAX_PARALLEL=8
|
|
29
|
+
# IMA2_HISTORY_PAGE_SIZE=50
|
|
30
|
+
# IMA2_HISTORY_MAX_PAGE=500
|
|
31
|
+
# IMA2_GRAPH_MAX_NODES=500
|
|
32
|
+
# IMA2_GRAPH_MAX_EDGES=1000
|
|
33
|
+
|
|
34
|
+
# ── IDs & TTLs ─────────────────────────────────────────────────────────
|
|
35
|
+
# IMA2_GENERATED_HEX_BYTES=4
|
|
36
|
+
# IMA2_NODE_HEX_BYTES=5
|
|
37
|
+
# IMA2_INFLIGHT_TTL_MS=600000
|
|
38
|
+
# IMA2_INFLIGHT_REAP_MS=60000
|
|
39
|
+
# IMA2_TRASH_TTL_MS=10000
|
|
40
|
+
|
|
41
|
+
# ── Style sheet (0.10) ─────────────────────────────────────────────────
|
|
42
|
+
# IMA2_STYLE_SHEET_MAX_PREFIX=4000
|
|
43
|
+
# IMA2_STYLE_MODEL=gpt-5.4-mini
|
|
44
|
+
|
|
45
|
+
# ── Logging ────────────────────────────────────────────────────────────
|
|
46
|
+
# IMA2_LOG_LEVEL=info # trace|debug|info|warn|error|fatal
|
|
47
|
+
|
|
48
|
+
# ── Secrets (not merged from config.json, env only) ────────────────────
|
|
49
|
+
# OPENAI_API_KEY=sk-...
|
package/README.md
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# ima2-gen
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/ima2-gen)
|
|
4
|
-
[](https://nodejs.org/)
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
|
|
7
7
|
> **Read in other languages**: [한국어](docs/README.ko.md) · [日本語](docs/README.ja.md) · [简体中文](docs/README.zh-CN.md)
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
`ima2-gen` is a local CLI + web studio for OpenAI image generation through the ChatGPT/Codex OAuth route. It includes a React UI, headless CLI commands, persistent history, reference uploads, production node-mode branching, and safe request observability.
|
|
10
|
+
|
|
11
|
+
Generation is currently **OAuth-only**. API keys can still be configured for auxiliary developer paths such as billing/status checks and style-sheet extraction, but image generation endpoints reject `provider: "api"` with `APIKEY_DISABLED` unless the provider policy is intentionally changed in code.
|
|
10
12
|
|
|
11
13
|

|
|
12
14
|
|
|
@@ -15,7 +17,7 @@ Minimal CLI + web UI for OpenAI **GPT Image 2** (`gpt-image-2`) image generation
|
|
|
15
17
|
## Quick Start
|
|
16
18
|
|
|
17
19
|
```bash
|
|
18
|
-
# Run instantly with npx
|
|
20
|
+
# Run instantly with npx
|
|
19
21
|
npx ima2-gen serve
|
|
20
22
|
|
|
21
23
|
# Or install globally
|
|
@@ -23,178 +25,218 @@ npm install -g ima2-gen
|
|
|
23
25
|
ima2 serve
|
|
24
26
|
```
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
The first run opens setup:
|
|
27
29
|
|
|
30
|
+
```text
|
|
31
|
+
1) API Key — save an OpenAI API key for supported auxiliary paths
|
|
32
|
+
2) OAuth — log in with a ChatGPT/Codex account for image generation
|
|
28
33
|
```
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
|
|
35
|
+
For the current release, choose OAuth for generation. If Codex is not logged in yet, run:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx @openai/codex login
|
|
39
|
+
ima2 serve
|
|
32
40
|
```
|
|
33
41
|
|
|
34
|
-
|
|
42
|
+
The web UI opens at `http://localhost:3333` by default.
|
|
35
43
|
|
|
36
44
|
---
|
|
37
45
|
|
|
38
|
-
##
|
|
46
|
+
## What Works Now
|
|
39
47
|
|
|
40
|
-
|
|
48
|
+
### OAuth Generation
|
|
41
49
|
|
|
42
|
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
50
|
+
- Text-to-image through `/api/generate`
|
|
51
|
+
- Image edit / image-to-image through `/api/edit`
|
|
52
|
+
- Up to 5 reference images per root generation
|
|
53
|
+
- Quality controls: `low`, `medium`, `high`
|
|
54
|
+
- Moderation controls: `low`, `auto`
|
|
55
|
+
- PNG/JPEG/WebP output
|
|
56
|
+
- Parallel count: 1, 2, or 4 from the UI; CLI/server cap is 8
|
|
57
|
+
- Size presets aligned to `gpt-image-2` constraints
|
|
45
58
|
|
|
46
|
-
|
|
59
|
+
### UI Workflow
|
|
47
60
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
61
|
+
- Prompt composer with drag/drop and Cmd/Ctrl+V image paste
|
|
62
|
+
- Current-image reuse from the canvas
|
|
63
|
+
- Gallery strip and full gallery modal
|
|
64
|
+
- Delete/restore for generated assets
|
|
65
|
+
- Settings workspace opened from the header gear
|
|
66
|
+
- Theme and account/status settings moved out of the crowded sidebar
|
|
67
|
+
- Right sidebar now contains only generation details
|
|
68
|
+
- In-flight jobs survive refresh and reconcile back into the UI
|
|
56
69
|
|
|
57
|
-
|
|
70
|
+
### Node Mode
|
|
58
71
|
|
|
59
|
-
|
|
60
|
-
- **Multi-reference** — attach up to 5 reference images, drag & drop anywhere on the left panel
|
|
61
|
-
- **Prompt-with-context** — mixes text + reference images in one request
|
|
62
|
-
- **Use current** — one-click re-use of the selected image as a new reference
|
|
63
|
-
- **Download** · **Copy to clipboard** · **Copy prompt** directly from the canvas
|
|
64
|
-
- **Sticky gallery strip** at the bottom, fixed-position so it never scrolls away
|
|
65
|
-
- **Gallery modal (+)** — grid view of everything in history
|
|
66
|
-
- **Session persistence** — refresh mid-generation and your pending jobs reconcile automatically
|
|
72
|
+
Node mode is available in the packaged web UI and can be opened from the mode switch next to the composer.
|
|
67
73
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
- SQLite-backed graph sessions
|
|
75
|
+
- Branching child generations
|
|
76
|
+
- Duplicate branch / new-from-here flows
|
|
77
|
+
- Node-local reference attachments for root nodes with drag/drop, paste, and file picker support
|
|
78
|
+
- Reference count metadata in node sidecars and history responses
|
|
79
|
+
- Session style sheets that can prepend a house style to node/classic prompts
|
|
80
|
+
- Gallery grouping by session title instead of raw server IDs
|
|
81
|
+
|
|
82
|
+
### Observability
|
|
76
83
|
|
|
77
|
-
|
|
84
|
+
- Safe structured logs for generation, edit, node, OAuth, session, history, and in-flight lifecycle
|
|
85
|
+
- Correlation by `requestId`
|
|
86
|
+
- Active-only `/api/inflight` by default
|
|
87
|
+
- Optional recent terminal jobs via `/api/inflight?includeTerminal=1`
|
|
88
|
+
- Logs avoid raw prompts, effective prompts, revised prompts, tokens, auth headers, cookies, request bodies, reference data URLs, generated base64, and raw upstream response bodies
|
|
78
89
|
|
|
79
90
|
---
|
|
80
91
|
|
|
81
92
|
## CLI Commands
|
|
82
93
|
|
|
83
|
-
### Server
|
|
94
|
+
### Server Commands
|
|
95
|
+
|
|
84
96
|
| Command | Alias | Description |
|
|
85
|
-
|
|
86
|
-
| `ima2 serve` | — | Start the web server
|
|
87
|
-
| `ima2 setup` | `login` | Reconfigure
|
|
88
|
-
| `ima2 status` | — | Show
|
|
89
|
-
| `ima2 doctor` | — | Diagnose
|
|
90
|
-
| `ima2 open` | — | Open web UI
|
|
91
|
-
| `ima2 reset` | — |
|
|
92
|
-
| `ima2 --version` | `-v` |
|
|
93
|
-
| `ima2 --help` | `-h` |
|
|
94
|
-
|
|
95
|
-
### Client
|
|
97
|
+
|---|---|---|
|
|
98
|
+
| `ima2 serve` | — | Start the local web server |
|
|
99
|
+
| `ima2 setup` | `login` | Reconfigure saved auth |
|
|
100
|
+
| `ima2 status` | — | Show config and OAuth session status |
|
|
101
|
+
| `ima2 doctor` | — | Diagnose Node, package, config, and auth state |
|
|
102
|
+
| `ima2 open` | — | Open the web UI |
|
|
103
|
+
| `ima2 reset` | — | Remove saved config |
|
|
104
|
+
| `ima2 --version` | `-v` | Print package version |
|
|
105
|
+
| `ima2 --help` | `-h` | Print help |
|
|
106
|
+
|
|
107
|
+
### Client Commands
|
|
108
|
+
|
|
109
|
+
These require a running `ima2 serve`.
|
|
110
|
+
|
|
96
111
|
| Command | Description |
|
|
97
|
-
|
|
112
|
+
|---|---|
|
|
98
113
|
| `ima2 gen <prompt>` | Generate image(s) from the CLI |
|
|
99
|
-
| `ima2 edit <file>` | Edit an existing image
|
|
100
|
-
| `ima2 ls` | List
|
|
101
|
-
| `ima2 show <name>` |
|
|
102
|
-
| `ima2 ps` | List active jobs
|
|
114
|
+
| `ima2 edit <file> --prompt <text>` | Edit an existing image |
|
|
115
|
+
| `ima2 ls` | List history, table or `--json` |
|
|
116
|
+
| `ima2 show <name>` | Show/reveal a generated asset |
|
|
117
|
+
| `ima2 ps` | List active in-flight jobs |
|
|
103
118
|
| `ima2 ping` | Health-check the running server |
|
|
104
119
|
|
|
105
|
-
The
|
|
120
|
+
The server advertises its port at `~/.ima2/server.json`. Client commands auto-discover it. Override with `--server <url>` or `IMA2_SERVER=http://localhost:3333`.
|
|
121
|
+
|
|
122
|
+
### Exit Codes
|
|
106
123
|
|
|
107
|
-
|
|
108
|
-
`0` ok · `2` bad args · `3` server unreachable · `4` APIKEY_DISABLED · `5` 4xx · `6` 5xx · `7` safety refusal · `8` timeout.
|
|
124
|
+
`0` OK · `2` bad arguments · `3` server unreachable · `4` `APIKEY_DISABLED` · `5` 4xx · `6` 5xx · `7` safety refusal · `8` timeout.
|
|
109
125
|
|
|
110
126
|
---
|
|
111
127
|
|
|
112
|
-
##
|
|
128
|
+
## API Endpoints
|
|
129
|
+
|
|
130
|
+
```text
|
|
131
|
+
GET /api/health
|
|
132
|
+
GET /api/providers
|
|
133
|
+
GET /api/oauth/status
|
|
134
|
+
GET /api/billing
|
|
135
|
+
GET /api/inflight
|
|
136
|
+
GET /api/inflight?includeTerminal=1
|
|
137
|
+
POST /api/generate
|
|
138
|
+
POST /api/edit
|
|
139
|
+
GET /api/history
|
|
140
|
+
GET /api/history?groupBy=session
|
|
141
|
+
DELETE /api/history/:filename
|
|
142
|
+
POST /api/history/:filename/restore
|
|
143
|
+
GET /api/sessions
|
|
144
|
+
POST /api/sessions
|
|
145
|
+
GET /api/sessions/:id
|
|
146
|
+
PATCH /api/sessions/:id
|
|
147
|
+
DELETE /api/sessions/:id
|
|
148
|
+
PUT /api/sessions/:id/graph
|
|
149
|
+
GET /api/node/:nodeId
|
|
150
|
+
POST /api/node/generate
|
|
151
|
+
```
|
|
113
152
|
|
|
114
|
-
|
|
153
|
+
### OAuth Generation Request
|
|
115
154
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
-
|
|
119
|
-
-
|
|
120
|
-
|
|
121
|
-
|
|
155
|
+
```bash
|
|
156
|
+
curl -X POST http://localhost:3333/api/generate \
|
|
157
|
+
-H 'Content-Type: application/json' \
|
|
158
|
+
-d '{
|
|
159
|
+
"prompt": "a shiba in space",
|
|
160
|
+
"quality": "medium",
|
|
161
|
+
"size": "1024x1024",
|
|
162
|
+
"moderation": "low",
|
|
163
|
+
"provider": "oauth"
|
|
164
|
+
}'
|
|
165
|
+
```
|
|
122
166
|
|
|
123
|
-
###
|
|
124
|
-
- **F3 Prompt presets** — save/apply `{prompt, refs, quality, size}` bundles
|
|
125
|
-
- **F3 Gallery groupBy** — `preset / date / compareRun` grouping
|
|
126
|
-
- **F2 Batch A/B compare** — spawn 2–6 parallel variants from one prompt, keyboard-driven judging (`1-6`, `Space`=winner, `V`=variation, `P`=save preset)
|
|
127
|
-
- **F4 Export bundle** — zip selected images with `manifest.json` + per-image prompt `.txt`
|
|
128
|
-
- Every server verb ships with its CLI mirror (`ima2 preset / compare / export`)
|
|
167
|
+
### API-Key Configuration And Activation Notes
|
|
129
168
|
|
|
130
|
-
|
|
131
|
-
- Instagram carousel generation (4 / 6 / 10 cards)
|
|
132
|
-
- Style consistency via `file_id` fan-out (not `previous_response_id`, not seed)
|
|
133
|
-
- Parallel card regeneration without breaking the style chain
|
|
169
|
+
Current behavior:
|
|
134
170
|
|
|
135
|
-
|
|
136
|
-
-
|
|
137
|
-
-
|
|
171
|
+
- `provider: "oauth"` is the supported generation path.
|
|
172
|
+
- `provider: "api"` returns `403` / `APIKEY_DISABLED` in `routes/generate.js`, `routes/edit.js`, and `routes/nodes.js`.
|
|
173
|
+
- `OPENAI_API_KEY` or `~/.ima2/config.json` can still be used for non-generation helpers such as billing probes and style-sheet extraction.
|
|
138
174
|
|
|
139
|
-
|
|
140
|
-
- Web UI dark/light toggle
|
|
141
|
-
- Keyboard shortcuts cheat-sheet overlay
|
|
142
|
-
- Collaborative sessions (shared SQLite over WebSocket)
|
|
143
|
-
- Plugin system for custom post-processing
|
|
175
|
+
Configure an API key for those auxiliary paths:
|
|
144
176
|
|
|
145
|
-
|
|
177
|
+
```bash
|
|
178
|
+
export OPENAI_API_KEY="sk-..."
|
|
179
|
+
ima2 serve
|
|
180
|
+
```
|
|
146
181
|
|
|
147
|
-
|
|
182
|
+
or:
|
|
148
183
|
|
|
184
|
+
```json
|
|
185
|
+
{
|
|
186
|
+
"provider": "api",
|
|
187
|
+
"apiKey": "sk-..."
|
|
188
|
+
}
|
|
149
189
|
```
|
|
150
|
-
ima2 serve
|
|
151
|
-
├── Express server (:3333)
|
|
152
|
-
│ ├── GET /api/health — version, uptime, activeJobs, pid
|
|
153
|
-
│ ├── GET /api/providers — available auth methods
|
|
154
|
-
│ ├── GET /api/oauth/status — OAuth proxy health check
|
|
155
|
-
│ ├── POST /api/generate — text+ref → image (parallel via n)
|
|
156
|
-
│ ├── POST /api/edit — ref-heavy edit path
|
|
157
|
-
│ ├── GET /api/history — paginated sidecar listing
|
|
158
|
-
│ ├── GET /api/inflight — in-progress jobs (kind/session filters)
|
|
159
|
-
│ ├── GET /api/sessions/* — node-graph sessions (dev-only)
|
|
160
|
-
│ ├── GET /api/billing — API credit / cost info
|
|
161
|
-
│ └── Static files (public/) — web UI
|
|
162
|
-
│
|
|
163
|
-
├── openai-oauth proxy (:10531) — embedded OAuth relay
|
|
164
|
-
└── ~/.ima2/server.json — port advertisement for CLI auto-discovery
|
|
165
|
-
```
|
|
166
190
|
|
|
167
|
-
|
|
191
|
+
saved at `~/.ima2/config.json`.
|
|
192
|
+
|
|
193
|
+
To intentionally reopen API-key image generation as a developer, audit and change the explicit `provider === "api"` guards in:
|
|
194
|
+
|
|
195
|
+
- `routes/generate.js`
|
|
196
|
+
- `routes/edit.js`
|
|
197
|
+
- `routes/nodes.js`
|
|
198
|
+
|
|
199
|
+
Then wire the OpenAI SDK generation/edit implementation, update tests for both OAuth and API-key paths, and update this README. Do not simply remove the guards without adding the API implementation and billing/error tests.
|
|
168
200
|
|
|
169
201
|
---
|
|
170
202
|
|
|
171
203
|
## Configuration
|
|
172
204
|
|
|
173
|
-
Config
|
|
205
|
+
Config priority is:
|
|
174
206
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|----------|---------|-------------|
|
|
178
|
-
| `OPENAI_API_KEY` | — | OpenAI API key (skips OAuth) |
|
|
179
|
-
| `PORT` | `3333` | Web server port |
|
|
180
|
-
| `OAUTH_PORT` | `10531` | OAuth proxy port |
|
|
181
|
-
| `IMA2_SERVER` | — | Client: override target server URL |
|
|
182
|
-
|
|
183
|
-
```bash
|
|
184
|
-
cp .env.example .env
|
|
207
|
+
```text
|
|
208
|
+
environment variables > ~/.ima2/config.json > built-in defaults
|
|
185
209
|
```
|
|
186
210
|
|
|
211
|
+
| Variable | Default | Description |
|
|
212
|
+
|---|---:|---|
|
|
213
|
+
| `IMA2_PORT` / `PORT` | `3333` | Web server port |
|
|
214
|
+
| `IMA2_OAUTH_PROXY_PORT` / `OAUTH_PORT` | `10531` | OAuth proxy port |
|
|
215
|
+
| `IMA2_SERVER` | — | CLI target override |
|
|
216
|
+
| `IMA2_CONFIG_DIR` | `~/.ima2` | Config and SQLite location |
|
|
217
|
+
| `IMA2_GENERATED_DIR` | `generated/` | Generated image directory |
|
|
218
|
+
| `IMA2_NO_OAUTH_PROXY` | — | Set `1` to disable auto-starting the OAuth proxy |
|
|
219
|
+
| `IMA2_INFLIGHT_TERMINAL_TTL_MS` | `30000` | Retention for opt-in terminal in-flight debug jobs |
|
|
220
|
+
| `VITE_IMA2_NODE_MODE` | enabled | Set `0` at UI build time to hide node mode |
|
|
221
|
+
| `OPENAI_API_KEY` | — | API key for supported auxiliary paths |
|
|
222
|
+
|
|
187
223
|
---
|
|
188
224
|
|
|
189
|
-
##
|
|
225
|
+
## Architecture
|
|
190
226
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
227
|
+
```text
|
|
228
|
+
ima2 serve
|
|
229
|
+
├── Express server (:3333)
|
|
230
|
+
│ ├── route modules in routes/
|
|
231
|
+
│ ├── OAuth image calls via lib/oauthProxy.js
|
|
232
|
+
│ ├── generated/ image + sidecar JSON storage
|
|
233
|
+
│ ├── SQLite sessions via better-sqlite3
|
|
234
|
+
│ └── ui/dist React app
|
|
235
|
+
├── openai-oauth proxy (:10531)
|
|
236
|
+
└── ~/.ima2/server.json for CLI discovery
|
|
237
|
+
```
|
|
196
238
|
|
|
197
|
-
|
|
239
|
+
The server uses ES modules, centralized config in `config.js`, and route helpers under `lib/`.
|
|
198
240
|
|
|
199
241
|
---
|
|
200
242
|
|
|
@@ -204,50 +246,48 @@ cp .env.example .env
|
|
|
204
246
|
git clone https://github.com/lidge-jun/ima2-gen.git
|
|
205
247
|
cd ima2-gen
|
|
206
248
|
npm install
|
|
207
|
-
npm run dev
|
|
208
|
-
npm test
|
|
249
|
+
npm run dev
|
|
250
|
+
npm test
|
|
251
|
+
npm run build
|
|
209
252
|
```
|
|
210
253
|
|
|
211
|
-
|
|
212
|
-
- Vanilla HTML/CSS/JS (no framework in the published build)
|
|
213
|
-
- Vite + React for the Node-mode canvas (dev-only, gated)
|
|
214
|
-
- Fonts: Outfit + Geist Mono
|
|
254
|
+
`npm run dev` builds the UI and starts `server.js` with `--watch`. Node mode is now a normal product surface in both dev and packaged builds. Set `VITE_IMA2_NODE_MODE=0` only when you intentionally need a classic-only bundle.
|
|
215
255
|
|
|
216
|
-
|
|
217
|
-
- **Runtime**: Node.js ≥18
|
|
218
|
-
- **Server**: Express 5, SQLite (better-sqlite3)
|
|
219
|
-
- **API**: OpenAI SDK v5
|
|
220
|
-
- **OAuth**: `openai-oauth` proxy
|
|
221
|
-
- **Tests**: Node built-in test runner
|
|
256
|
+
Test coverage currently includes CLI behavior, config loading, history pagination/delete/restore, reference validation, OAuth parameter normalization, prompt fidelity, in-flight tracking, safe logging, and route health checks.
|
|
222
257
|
|
|
223
258
|
---
|
|
224
259
|
|
|
225
260
|
## Troubleshooting
|
|
226
261
|
|
|
227
|
-
|
|
228
|
-
|
|
262
|
+
**`ima2 ping` says the server is unreachable**
|
|
263
|
+
Start `ima2 serve`, then check `~/.ima2/server.json`. You can override discovery with `ima2 ping --server http://localhost:3333`.
|
|
229
264
|
|
|
230
|
-
|
|
231
|
-
|
|
265
|
+
**OAuth login does not work**
|
|
266
|
+
Run `npx @openai/codex login`, confirm `ima2 status`, then restart `ima2 serve`.
|
|
232
267
|
|
|
233
|
-
**
|
|
234
|
-
|
|
268
|
+
**Images fail with `APIKEY_DISABLED`**
|
|
269
|
+
You are trying to generate with `provider: "api"`. Use OAuth for generation in the current release.
|
|
235
270
|
|
|
236
|
-
|
|
237
|
-
|
|
271
|
+
**An API key is configured but generation still uses OAuth**
|
|
272
|
+
That is expected. API keys are currently recognized for auxiliary status/extraction paths, not for image generation.
|
|
238
273
|
|
|
239
|
-
**
|
|
240
|
-
|
|
274
|
+
**Port is unexpectedly `3457`**
|
|
275
|
+
Your shell may have inherited `PORT=3457` from another local tool. Run `unset PORT` or start with `IMA2_PORT=3333 ima2 serve`.
|
|
241
276
|
|
|
242
277
|
---
|
|
243
278
|
|
|
244
|
-
##
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
npm
|
|
250
|
-
|
|
279
|
+
## Recent Changelog Highlights
|
|
280
|
+
|
|
281
|
+
- Node mode enabled in packaged builds
|
|
282
|
+
- Node-local references and branch duplication for node mode
|
|
283
|
+
- `refsCount` metadata for node reference usage
|
|
284
|
+
- npm package includes modular `routes/` server files
|
|
285
|
+
- Settings workspace with account/theme controls
|
|
286
|
+
- Prompt fidelity and revised prompt capture
|
|
287
|
+
- OAuth quality handling for `low`, `medium`, `high`
|
|
288
|
+
- Safer structured request logs and terminal in-flight debug snapshots
|
|
289
|
+
- Session-title gallery grouping
|
|
290
|
+
- Cross-platform CLI fixes for Windows process spawning
|
|
251
291
|
|
|
252
292
|
## License
|
|
253
293
|
|
package/bin/commands/edit.js
CHANGED
package/bin/commands/gen.js
CHANGED
|
@@ -27,7 +27,7 @@ const HELP = `
|
|
|
27
27
|
Generate image(s) via the running ima2 server.
|
|
28
28
|
|
|
29
29
|
Options:
|
|
30
|
-
-q, --quality <low|medium|high
|
|
30
|
+
-q, --quality <low|medium|high> Default: low
|
|
31
31
|
-s, --size <WxH | auto> Default: 1024x1024
|
|
32
32
|
-n, --count <1..8> Default: 1
|
|
33
33
|
--ref <file> Attach reference image (repeatable, max 5)
|
package/bin/ima2.js
CHANGED
|
@@ -6,16 +6,18 @@ import { fileURLToPath } from "url";
|
|
|
6
6
|
import { spawn, execSync } from "child_process";
|
|
7
7
|
import { networkInterfaces, homedir } from "os";
|
|
8
8
|
import { openUrl, resolveBin } from "./lib/platform.js";
|
|
9
|
+
import { maybePromptGithubStar } from "./lib/star-prompt.js";
|
|
9
10
|
import { detectCodexAuth } from "../lib/codexDetect.js";
|
|
11
|
+
import { config as runtimeConfig } from "../config.js";
|
|
10
12
|
|
|
11
13
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
14
|
const ROOT = join(__dirname, "..");
|
|
13
15
|
const HOME = homedir();
|
|
14
|
-
// Config lives
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
const CONFIG_DIR =
|
|
18
|
-
const CONFIG_FILE =
|
|
16
|
+
// Config lives under runtimeConfig.storage.configDir (honors IMA2_CONFIG_DIR).
|
|
17
|
+
// Legacy installs that stored config at <packageRoot>/.ima2/config.json will be
|
|
18
|
+
// migrated on first write.
|
|
19
|
+
const CONFIG_DIR = runtimeConfig.storage.configDir;
|
|
20
|
+
const CONFIG_FILE = runtimeConfig.storage.configFile;
|
|
19
21
|
const LEGACY_CONFIG_FILE = join(ROOT, ".ima2", "config.json");
|
|
20
22
|
|
|
21
23
|
// Load package.json for version
|
|
@@ -100,6 +102,12 @@ async function setup() {
|
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
async function serve() {
|
|
105
|
+
try {
|
|
106
|
+
await maybePromptGithubStar();
|
|
107
|
+
} catch (err) {
|
|
108
|
+
console.error(`[ima2] Star prompt skipped: ${err?.message || err}`);
|
|
109
|
+
}
|
|
110
|
+
|
|
103
111
|
let config = loadConfig();
|
|
104
112
|
|
|
105
113
|
if (!config.provider) {
|
|
@@ -234,7 +242,7 @@ async function doctor() {
|
|
|
234
242
|
}
|
|
235
243
|
|
|
236
244
|
// Port availability (simple check)
|
|
237
|
-
const port =
|
|
245
|
+
const port = runtimeConfig.server.port;
|
|
238
246
|
console.log(` ℹ Default port: ${port}`);
|
|
239
247
|
|
|
240
248
|
console.log(`\n ${ok} passed, ${fail} failed\n`);
|
|
@@ -242,7 +250,7 @@ async function doctor() {
|
|
|
242
250
|
}
|
|
243
251
|
|
|
244
252
|
function openBrowser() {
|
|
245
|
-
const port =
|
|
253
|
+
const port = runtimeConfig.server.port;
|
|
246
254
|
const url = `http://localhost:${port}`;
|
|
247
255
|
const res = openUrl(url);
|
|
248
256
|
if (res.ok) {
|