ima2-gen 1.1.0 → 1.1.2

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.
Files changed (58) hide show
  1. package/README.md +47 -7
  2. package/assets/card-news/templates/academy-lesson-square/base.png +0 -0
  3. package/assets/card-news/templates/academy-lesson-square/preview.png +0 -0
  4. package/assets/card-news/templates/academy-lesson-square/template.json +20 -0
  5. package/assets/card-news/templates/clean-report-square/base.png +0 -0
  6. package/assets/card-news/templates/clean-report-square/preview.png +0 -0
  7. package/assets/card-news/templates/clean-report-square/template.json +20 -0
  8. package/bin/commands/cancel.js +45 -0
  9. package/bin/commands/edit.js +33 -4
  10. package/bin/commands/gen.js +26 -3
  11. package/bin/commands/ps.js +48 -16
  12. package/bin/ima2.js +56 -12
  13. package/bin/lib/client.js +4 -1
  14. package/bin/lib/error-hints.js +23 -0
  15. package/bin/lib/output.js +10 -0
  16. package/config.js +19 -1
  17. package/docs/API.md +67 -0
  18. package/docs/FAQ.ko.md +248 -0
  19. package/docs/FAQ.md +256 -0
  20. package/docs/README.ja.md +4 -0
  21. package/docs/README.ko.md +14 -1
  22. package/docs/README.zh-CN.md +4 -0
  23. package/docs/RECOVER_OLD_IMAGES.md +2 -0
  24. package/lib/cardNewsGenerator.js +162 -0
  25. package/lib/cardNewsJobStore.js +107 -0
  26. package/lib/cardNewsManifestStore.js +112 -0
  27. package/lib/cardNewsPlanner.js +180 -0
  28. package/lib/cardNewsPlannerClient.js +112 -0
  29. package/lib/cardNewsPlannerPrompt.js +60 -0
  30. package/lib/cardNewsPlannerSchema.js +259 -0
  31. package/lib/cardNewsRoleTemplateStore.js +47 -0
  32. package/lib/cardNewsTemplateStore.js +210 -0
  33. package/lib/db.js +20 -3
  34. package/lib/errorClassify.js +2 -2
  35. package/lib/generationErrors.js +51 -0
  36. package/lib/historyList.js +82 -8
  37. package/lib/inflight.js +117 -34
  38. package/lib/logger.js +37 -3
  39. package/lib/oauthLauncher.js +52 -19
  40. package/lib/oauthProxy.js +81 -14
  41. package/lib/requestLogger.js +48 -0
  42. package/lib/runtimePorts.js +93 -0
  43. package/lib/sessionStore.js +48 -7
  44. package/package.json +3 -2
  45. package/routes/cardNews.js +183 -0
  46. package/routes/edit.js +1 -1
  47. package/routes/generate.js +10 -10
  48. package/routes/health.js +27 -3
  49. package/routes/index.js +2 -0
  50. package/routes/nodes.js +93 -26
  51. package/server.js +91 -18
  52. package/ui/dist/assets/index-BjX_nzuK.js +23 -0
  53. package/ui/dist/assets/index-BjX_nzuK.js.map +1 -0
  54. package/ui/dist/assets/index-DHyUax4_.css +1 -0
  55. package/ui/dist/index.html +2 -2
  56. package/ui/dist/assets/index-CqpVoXpZ.css +0 -1
  57. package/ui/dist/assets/index-IHSd1z1a.js +0 -22
  58. package/ui/dist/assets/index-IHSd1z1a.js.map +0 -1
package/bin/lib/client.js CHANGED
@@ -5,7 +5,8 @@ import { homedir } from "node:os";
5
5
  export const DEFAULT_PORT = 3333;
6
6
 
7
7
  function readAdvertise() {
8
- const p = join(homedir(), ".ima2", "server.json");
8
+ const p = process.env.IMA2_ADVERTISE_FILE ||
9
+ join(process.env.IMA2_CONFIG_DIR || join(homedir(), ".ima2"), "server.json");
9
10
  if (!existsSync(p)) return null;
10
11
  try {
11
12
  return JSON.parse(readFileSync(p, "utf-8"));
@@ -36,6 +37,8 @@ export async function resolveServer({ serverFlag } = {}) {
36
37
  const candidates = [];
37
38
  if (process.env.IMA2_SERVER) candidates.push(process.env.IMA2_SERVER.replace(/\/$/, ""));
38
39
  const adv = readAdvertise();
40
+ if (adv?.backend?.url) candidates.push(String(adv.backend.url).replace(/\/$/, ""));
41
+ if (adv?.url) candidates.push(String(adv.url).replace(/\/$/, ""));
39
42
  if (adv?.port) candidates.push(`http://localhost:${adv.port}`);
40
43
  candidates.push(`http://localhost:${DEFAULT_PORT}`);
41
44
 
@@ -0,0 +1,23 @@
1
+ const HINTS = {
2
+ SERVER_UNREACHABLE: "Start `ima2 serve`, or pass `--server <url>`.",
3
+ APIKEY_DISABLED: "Image generation is OAuth-only. Use Codex login/OAuth.",
4
+ IMAGE_MODEL_UNSUPPORTED:
5
+ "This model is visible but cannot generate images here. Use gpt-5.4 or gpt-5.4-mini.",
6
+ INVALID_IMAGE_MODEL: "Use one of: gpt-5.5, gpt-5.4, gpt-5.4-mini.",
7
+ OAUTH_UNAVAILABLE: "OAuth proxy is unavailable. Check `ima2 doctor` and restart `ima2 serve`.",
8
+ NETWORK_FAILED: "Network/proxy failed. This is not a moderation refusal.",
9
+ SAFETY_REFUSAL: "The image backend refused this generation.",
10
+ MODERATION_REFUSED: "The prompt or image was rejected by moderation.",
11
+ AUTH_CHATGPT_EXPIRED: "Run `npx @openai/codex login`, then restart `ima2 serve`.",
12
+ REF_TOO_LARGE: "Reference image is too large. Resize/compress it and retry.",
13
+ REF_NOT_BASE64: "Reference payload is invalid. Use a normal PNG/JPEG/WebP file.",
14
+ };
15
+
16
+ export function hintForErrorCode(code) {
17
+ return code ? HINTS[code] || null : null;
18
+ }
19
+
20
+ export function formatErrorWithHint(message, code) {
21
+ const hint = hintForErrorCode(code);
22
+ return hint ? `${message}\nHint: ${hint}` : message;
23
+ }
package/bin/lib/output.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { formatErrorWithHint } from "./error-hints.js";
2
+
1
3
  const isTty = process.stdout.isTTY && !process.env.NO_COLOR;
2
4
 
3
5
  export const color = {
@@ -17,6 +19,10 @@ export function die(code, msg) {
17
19
  process.exit(code);
18
20
  }
19
21
 
22
+ export function dieWithError(e) {
23
+ die(exitCodeForError(e), formatErrorWithHint(e?.message || String(e), e?.code));
24
+ }
25
+
20
26
  export function json(obj) {
21
27
  process.stdout.write(JSON.stringify(obj) + "\n");
22
28
  }
@@ -40,7 +46,11 @@ export function table(rows, columns) {
40
46
  export function exitCodeForError(e) {
41
47
  if (e.code === "SERVER_UNREACHABLE") return 3;
42
48
  if (e.code === "APIKEY_DISABLED") return 4;
49
+ if (e.code === "AUTH_CHATGPT_EXPIRED" || e.code === "OAUTH_UNAVAILABLE") return 4;
50
+ if (e.code === "NETWORK_FAILED") return 6;
51
+ if (e.code === "REF_TOO_LARGE" || e.code === "REF_NOT_BASE64") return 5;
43
52
  if (e.code === "SAFETY_REFUSAL") return 7;
53
+ if (e.code === "MODERATION_REFUSED") return 7;
44
54
  if (e.name === "TimeoutError" || /abort/i.test(e.message || "")) return 8;
45
55
  if (e.status >= 500) return 6;
46
56
  if (e.status >= 400) return 5;
package/config.js CHANGED
@@ -61,6 +61,10 @@ function pickBool(envVal, fileVal, fallback) {
61
61
  return s === "1" || s === "true" || s === "yes";
62
62
  }
63
63
 
64
+ export function defaultLogLevelForEnv(runtimeEnv = env) {
65
+ return runtimeEnv.IMA2_DEV === "1" ? "debug" : "info";
66
+ }
67
+
64
68
  export const config = {
65
69
  server: {
66
70
  // Accept both IMA2_PORT and legacy PORT.
@@ -139,9 +143,22 @@ export const config = {
139
143
  unsupported: new Set(["gpt-5.3-codex-spark"]),
140
144
  },
141
145
  log: {
142
- level: pickStr(env.IMA2_LOG_LEVEL, fileCfg.log?.level, "info"),
146
+ level: pickStr(env.IMA2_LOG_LEVEL, fileCfg.log?.level, defaultLogLevelForEnv(env)),
143
147
  pretty: env.NODE_ENV !== "production",
144
148
  },
149
+ features: {
150
+ cardNews: pickBool(env.IMA2_CARD_NEWS, fileCfg.features?.cardNews, env.IMA2_DEV === "1"),
151
+ },
152
+ cardNewsPlanner: {
153
+ enabled: pickBool(env.IMA2_CARD_NEWS_PLANNER, fileCfg.cardNewsPlanner?.enabled, true),
154
+ model: pickStr(env.IMA2_CARD_NEWS_PLANNER_MODEL, fileCfg.cardNewsPlanner?.model, "gpt-5.4-mini"),
155
+ timeoutMs: pickInt(env.IMA2_CARD_NEWS_PLANNER_TIMEOUT_MS, fileCfg.cardNewsPlanner?.timeoutMs, 60_000),
156
+ deterministicFallback: pickBool(
157
+ env.IMA2_CARD_NEWS_PLANNER_FALLBACK,
158
+ fileCfg.cardNewsPlanner?.deterministicFallback,
159
+ false,
160
+ ),
161
+ },
145
162
  dev: {
146
163
  viteDevMode: pickBool(env.VITE_IMA2_DEV, fileCfg.dev?.viteDevMode, false),
147
164
  },
@@ -170,3 +187,4 @@ export const STYLE_SHEET_MAX_PREFIX = config.styleSheet.maxPrefix;
170
187
  export const LOG_LEVEL = config.log.level;
171
188
  export const NO_OAUTH_PROXY = !config.oauth.autoStart;
172
189
  export const DEV_MODE = config.dev.viteDevMode;
190
+ export const CARD_NEWS_ENABLED = config.features.cardNews;
package/docs/API.md CHANGED
@@ -25,6 +25,47 @@ Image generation is OAuth-only in the current build.
25
25
  | `GET` | `/api/oauth/status` | OAuth proxy status and visible models |
26
26
  | `GET` | `/api/billing` | Billing/status probe, including API key source when configured |
27
27
 
28
+ ## Storage
29
+
30
+ | Method | Path | Notes |
31
+ |---|---|---|
32
+ | `GET` | `/api/storage/status` | Summarized gallery storage status for support UI |
33
+ | `POST` | `/api/storage/open-generated-dir` | Ask the server process to open the generated image folder |
34
+
35
+ `GET /api/storage/status` returns a support-safe summary, not raw legacy path arrays by default.
36
+
37
+ ```json
38
+ {
39
+ "ok": true,
40
+ "data": {
41
+ "generatedDirLabel": "~/.ima2/generated",
42
+ "generatedCount": 0,
43
+ "legacyCandidatesScanned": 18,
44
+ "legacySourcesFound": 0,
45
+ "legacyFilesFound": 0,
46
+ "state": "not_found",
47
+ "messageKind": "apology",
48
+ "recoveryDocsPath": "docs/RECOVER_OLD_IMAGES.md",
49
+ "doctorCommand": "ima2 doctor",
50
+ "overrides": {
51
+ "generatedDir": false,
52
+ "configDir": false
53
+ }
54
+ }
55
+ }
56
+ ```
57
+
58
+ Storage `state` values:
59
+
60
+ | State | Meaning |
61
+ |---|---|
62
+ | `ok` | Current gallery has files or no recovery notice is needed |
63
+ | `recoverable` | Legacy folders/files are still present and may be recoverable |
64
+ | `not_found` | Current gallery is empty and no legacy folder was found |
65
+ | `unknown` | Storage status inspection failed or was incomplete |
66
+
67
+ `POST /api/storage/open-generated-dir` opens the generated image folder on the machine running `ima2 serve`. If the browser is connected to a remote server, VM, container, WSL instance, or another computer on the network, this action targets that server machine, not necessarily the browser device.
68
+
28
69
  ## In-Flight Jobs
29
70
 
30
71
  | Method | Path | Notes |
@@ -173,6 +214,7 @@ Style-sheet extraction can require an API key/openai client. This does not reope
173
214
  | `AUTH_API_KEY_INVALID` | API key is invalid, revoked, out of quota, or wrong org |
174
215
  | `NETWORK_FAILED` | Network, proxy, VPN, or firewall failure |
175
216
  | `OAUTH_UNAVAILABLE` | Local OAuth proxy is not available |
217
+ | `OPEN_GENERATED_DIR_FAILED` | The server could not open the generated image folder |
176
218
  | `GRAPH_VERSION_REQUIRED` | Missing graph `If-Match` header |
177
219
  | `GRAPH_VERSION_CONFLICT` | Stale graph version |
178
220
  | `GRAPH_TOO_LARGE` | Graph exceeds node/edge limits |
@@ -187,3 +229,28 @@ The server writes an advertisement file at:
187
229
  ```
188
230
 
189
231
  CLI commands such as `ima2 ping`, `ima2 gen`, and `ima2 ls` use this file unless `--server` or `IMA2_SERVER` is provided.
232
+
233
+ Current shape:
234
+
235
+ ```json
236
+ {
237
+ "port": 3334,
238
+ "url": "http://localhost:3334",
239
+ "pid": 12345,
240
+ "startedAt": 1777180000000,
241
+ "version": "1.0.0",
242
+ "backend": {
243
+ "configuredPort": 3333,
244
+ "actualPort": 3334,
245
+ "url": "http://localhost:3334"
246
+ },
247
+ "oauth": {
248
+ "configuredPort": 10531,
249
+ "actualPort": 10532,
250
+ "url": "http://127.0.0.1:10532",
251
+ "status": "ready"
252
+ }
253
+ }
254
+ ```
255
+
256
+ Top-level `port` and `url` are kept for older CLI clients. New code should prefer `backend.url`.
package/docs/FAQ.ko.md ADDED
@@ -0,0 +1,248 @@
1
+ # ima2-gen 자주 묻는 질문
2
+
3
+ 마지막 확인: 2026-04-25
4
+
5
+ 이 문서는 설치, 업데이트, OAuth, 갤러리, 레퍼런스 이미지 관련 질문을 모아둔 FAQ입니다. README는 짧게 유지하고, 자세한 설명은 이곳에 둡니다.
6
+
7
+ English version: [FAQ.md](FAQ.md)
8
+
9
+ ## 빠른 해결
10
+
11
+ | 증상 | 먼저 해볼 것 |
12
+ |---|---|
13
+ | 서버에 연결되지 않음 | `ima2 serve`를 켠 뒤 `ima2 ping`을 실행합니다. |
14
+ | OAuth 로그인이 안 됨 | `npx @openai/codex login`을 실행하고 `ima2 serve`를 다시 시작합니다. |
15
+ | API key generation disabled | 이미지 생성은 OAuth로 사용합니다. API 키는 일부 보조 기능에서만 쓰입니다. |
16
+ | 업데이트 후 예전 이미지가 안 보임 | `ima2 doctor`를 실행한 뒤 [예전 이미지 복구 안내](RECOVER_OLD_IMAGES.md)를 확인합니다. |
17
+ | `gpt-5.5`만 실패함 | Codex CLI를 업데이트하고, 안정 대안으로 `gpt-5.4`를 사용합니다. |
18
+ | 레퍼런스 업로드 실패 | JPEG/PNG로 변환하고 해상도를 낮춰 보세요. 레퍼런스는 최대 5장입니다. |
19
+ | Windows에서 `10531` 포트 관련 OAuth/proxy 오류가 남 | `ima2 doctor`를 실행하고, 필요하면 `IMA2_OAUTH_PROXY_PORT=11531 ima2 serve`로 시작하세요. |
20
+
21
+ ## 설치와 업데이트
22
+
23
+ ### Node.js 버전은 무엇이 필요한가요?
24
+
25
+ Node.js 20 이상을 권장합니다. 패키지 요구사항은 Node `>=20`입니다.
26
+
27
+ ### `npx`와 전역 설치 중 무엇을 쓰면 되나요?
28
+
29
+ 둘 다 가능합니다.
30
+
31
+ ```bash
32
+ npx ima2-gen serve
33
+ ```
34
+
35
+ 또는:
36
+
37
+ ```bash
38
+ npm install -g ima2-gen
39
+ ima2 serve
40
+ ```
41
+
42
+ 예전 전역 설치가 이상하게 동작하면 먼저 최신 버전으로 올려 주세요.
43
+
44
+ ```bash
45
+ npm install -g ima2-gen@latest
46
+ ima2 doctor
47
+ ```
48
+
49
+ ### Windows에서 `spawn EINVAL`이 보여요.
50
+
51
+ 최신 버전으로 업데이트하세요. 예전 버전에서는 Windows의 npm/npx shim 실행에서 문제가 날 수 있었습니다. 현재 버전은 Windows에서 더 안전한 실행 경로를 사용합니다.
52
+
53
+ Codex 로그인 자체가 Windows 네이티브 환경에서 불안정하다면 WSL이 더 예측 가능한 선택일 수 있습니다.
54
+
55
+ ### Windows 업데이트 중 `EBUSY` 또는 `resource busy or locked`가 떠요.
56
+
57
+ 대부분 실행 중인 `ima2 serve`, 남아 있는 `node.exe`, 터미널, Explorer, 백신,
58
+ 인덱서가 global package 폴더를 잡고 있어서 생깁니다. ima2 서버와 관련
59
+ 터미널을 닫고, 필요하면 작업 관리자에서 남은 `node.exe`를 종료한 뒤 다시
60
+ 시도하세요.
61
+
62
+ ```bash
63
+ npm install -g ima2-gen@latest
64
+ ```
65
+
66
+ 계속 실패하면 Windows를 재부팅한 뒤 ima2를 실행하기 전에 바로 업데이트하세요.
67
+
68
+ ## 인증과 provider
69
+
70
+ ### OpenAI API 키가 필요한가요?
71
+
72
+ 이미지 생성에는 필요하지 않습니다. 기본 생성 경로는 로컬 Codex/ChatGPT OAuth 세션을 사용합니다.
73
+
74
+ 설정 화면에서 API 키가 감지될 수는 있습니다. 하지만 이미지 생성 엔드포인트는 `provider: "api"`를 받으면 `APIKEY_DISABLED`로 거절합니다. API 키는 billing 확인이나 style-sheet 추출 같은 보조 기능에만 쓰일 수 있습니다.
75
+
76
+ ### 설정 화면의 "Configured but disabled"는 무슨 뜻인가요?
77
+
78
+ env/config에 API 키가 있지만, 현재 빌드에서 API-key 이미지 생성은 비활성화되어 있다는 뜻입니다. 이미지는 OAuth로 생성하세요.
79
+
80
+ ### Codex CLI에 이미 로그인되어 있으면 자동으로 잡히나요?
81
+
82
+ 네. `ima2-gen`은 기존 Codex 로그인 상태를 확인하고 로컬 OAuth 경로를 사용합니다. 감지에 실패하거나 토큰이 만료되면 다음을 실행하세요.
83
+
84
+ ```bash
85
+ npx @openai/codex login
86
+ ima2 doctor
87
+ ```
88
+
89
+ 그다음 `ima2 serve`를 다시 시작합니다.
90
+
91
+ ### `Provided authentication token is expired`가 떠요.
92
+
93
+ Codex/ChatGPT OAuth 세션을 다시 로그인해야 합니다.
94
+
95
+ ```bash
96
+ npx @openai/codex login
97
+ ima2 serve
98
+ ```
99
+
100
+ 회사 네트워크라면 방화벽, VPN, 프록시, 보안 프로그램이 OAuth 흐름을 막고 있을 수도 있습니다.
101
+
102
+ ## 모델과 한도
103
+
104
+ ### 어떤 모델부터 쓰면 좋나요?
105
+
106
+ 안정적인 균형을 원하면 `gpt-5.4`부터 쓰는 것을 추천합니다.
107
+
108
+ - `gpt-5.4`: 추천 기본 선택지.
109
+ - `gpt-5.4-mini`: 현재 앱 기본값이며 빠른 초안에 적합합니다.
110
+ - `gpt-5.5`: 지원되는 환경에서는 가장 강한 품질 선택지입니다.
111
+
112
+ ### `gpt-5.5`만 실패하는 이유는 뭔가요?
113
+
114
+ `gpt-5.5`는 최신 Codex CLI, 백엔드 capability, 계정 또는 quota 상태의 영향을 받을 수 있습니다. 먼저 Codex CLI를 업데이트하세요. 그래도 실패하면 안정 대안으로 `gpt-5.4`를 사용하세요.
115
+
116
+ ### Plus/Pro는 몇 장까지 생성할 수 있나요?
117
+
118
+ 커뮤니티에서 말하는 숫자를 보장으로 받아들이면 안 됩니다. OAuth 생성은 계정, 백엔드 capability, 트래픽, 정책 변경의 영향을 받을 수 있습니다. `ima2-gen` 문서에서는 고정된 Plus/Pro 생성 횟수를 약속하지 않습니다.
119
+
120
+ ## 갤러리와 생성 파일
121
+
122
+ ### 생성 이미지는 어디에 저장되나요?
123
+
124
+ 현재 버전은 사용자 데이터 폴더에 저장합니다.
125
+
126
+ ```text
127
+ macOS / Linux: ~/.ima2/generated
128
+ Windows: %USERPROFILE%\.ima2\generated
129
+ ```
130
+
131
+ `IMA2_GENERATED_DIR`로 다른 위치를 지정할 수 있습니다.
132
+
133
+ ### 업데이트 후 예전 갤러리 이미지가 안 보여요.
134
+
135
+ 예전 버전은 생성 이미지를 설치된 패키지 폴더 안에 저장했습니다. 최근 버전은 패키지 업데이트와 사용자 파일이 섞이지 않도록 갤러리 저장 위치를 사용자 데이터 폴더로 옮겼습니다.
136
+
137
+ 놀라게 해드려 죄송합니다. 업데이트 중 예전 전역 설치 폴더가 교체되었다면 이전 `generated/` 폴더가 디스크에 남아 있지 않을 수 있습니다. `ima2-gen`은 예전 폴더가 아직 있을 때만 파일을 복사해 복구할 수 있습니다.
138
+
139
+ 먼저 실행하세요.
140
+
141
+ ```bash
142
+ ima2 doctor
143
+ ```
144
+
145
+ 그다음 [예전 이미지 복구 안내](RECOVER_OLD_IMAGES.md)를 확인하세요.
146
+
147
+ ### 이 마이그레이션이 예전 이미지를 삭제하나요?
148
+
149
+ 아니요. 마이그레이션은 copy-only입니다. 예전 폴더를 삭제하거나 이동하지 않습니다. 예전 파일을 찾지 못했다면, 예전 전역 설치 폴더가 이미 디스크에 남아 있지 않은 상황일 수 있습니다.
150
+
151
+ ### "Open folder"는 어떤 폴더를 여나요?
152
+
153
+ 갤러리의 **Open folder** 버튼은 `ima2 serve`가 실행 중인 머신의 생성 이미지 폴더를 엽니다.
154
+
155
+ 보통은 내 컴퓨터입니다. 하지만 원격 서버, SSH, VM, 컨테이너, WSL, 같은 네트워크의 다른 머신에서 서버를 돌리고 있다면 브라우저를 보고 있는 기기가 아니라 서버 머신 기준으로 열리거나 처리됩니다.
156
+
157
+ ### Card News는 공개 안정 기능인가요?
158
+
159
+ 아직 아닙니다. Card News는 dev-only / experimental 작업면입니다. 기본 배포
160
+ 런타임에서는 명시적으로 개발용 플래그를 켜지 않는 한 숨겨져 있어야 하며,
161
+ 공개 문서에서도 안정 기능처럼 다루지 않습니다.
162
+
163
+ ## 레퍼런스 이미지
164
+
165
+ ### 레퍼런스 이미지는 몇 장까지 붙일 수 있나요?
166
+
167
+ 최대 5장입니다.
168
+
169
+ ### 어떤 형식이 좋나요?
170
+
171
+ JPEG 또는 PNG가 가장 안전합니다. 브라우저 경로에서는 HEIC/HEIF를 직접 지원하지 않으므로 먼저 변환해 주세요.
172
+
173
+ ### 이미지가 너무 크다고 나와요.
174
+
175
+ 앱이 큰 JPEG/PNG를 업로드 전에 자동 압축합니다. 그래도 실패하면 해상도를 낮추거나 JPEG/PNG로 변환해 다시 시도하세요.
176
+
177
+ API에서는 `REF_TOO_MANY`, `REF_TOO_LARGE`, `REF_NOT_BASE64`, `REF_EMPTY` 같은 reference 오류가 나올 수 있습니다.
178
+
179
+ ## 네트워크와 OAuth 오류
180
+
181
+ ### 백엔드나 OAuth 프록시가 왜 다른 포트로 열리나요?
182
+
183
+ `ima2-gen`은 로컬 앱입니다. 기본 백엔드 포트 `3333` 또는 OAuth 프록시 포트 `10531`이 이미 사용 중이면 다음 사용 가능한 포트로 fallback할 수 있고, 실제 URL은 아래 파일에 기록됩니다.
184
+
185
+ ```text
186
+ ~/.ima2/server.json
187
+ ```
188
+
189
+ 아래 명령으로 configured/actual 포트를 확인하세요.
190
+
191
+ ```bash
192
+ ima2 doctor
193
+ ```
194
+
195
+ ### Windows에서 `AnySign4PC.exe`가 `10531`을 쓰면 어떻게 하나요?
196
+
197
+ 일부 Windows 보안 프로그램이 기본 OAuth 프록시 포트 `10531`을 점유할 수 있습니다. 현재 빌드는 fallback된 실제 포트를 추적하지만, 원하면 포트를 직접 바꿀 수 있습니다.
198
+
199
+ ```bash
200
+ IMA2_OAUTH_PROXY_PORT=11531 ima2 serve
201
+ ```
202
+
203
+ 프론트엔드만 따로 개발 서버로 띄우는 경우에는 Vite가 실제 백엔드를 보게 지정하세요.
204
+
205
+ ```bash
206
+ VITE_IMA2_API_TARGET=http://localhost:3334 npm run ui:dev
207
+ ```
208
+
209
+ ### `failed to fetch`는 무슨 뜻인가요?
210
+
211
+ 보통 아래 중 하나입니다.
212
+
213
+ - 로컬 OAuth 프록시가 아직 준비되지 않았습니다.
214
+ - 서버가 재시작되었습니다.
215
+ - VPN, 프록시, 방화벽이 요청을 막았습니다.
216
+ - Codex/ChatGPT OAuth 사용 중 네트워크가 끊겼습니다.
217
+
218
+ 먼저 확인하세요.
219
+
220
+ ```bash
221
+ ima2 doctor
222
+ ima2 ping
223
+ ```
224
+
225
+ 필요하면 `ima2 serve`를 다시 시작합니다.
226
+
227
+ ### 회사 컴퓨터에서는 무엇을 확인해야 하나요?
228
+
229
+ OAuth는 OpenAI와 ChatGPT/Codex 관련 호스트 접근이 필요할 수 있습니다. 회사 방화벽, TLS 검사, VPN, 프록시가 흐름을 깨뜨릴 수 있습니다. 로그인 실패와 `failed to fetch`가 반복되면 다른 네트워크에서도 시도해 보세요.
230
+
231
+ ## CLI 점검 순서
232
+
233
+ 아래 순서대로 확인해 보세요.
234
+
235
+ ```bash
236
+ ima2 doctor
237
+ ima2 status
238
+ ima2 ping
239
+ ima2 ps
240
+ npx @openai/codex login
241
+ npm install -g ima2-gen@latest
242
+ ```
243
+
244
+ 서버를 기본 포트가 아닌 곳에서 실행 중이라면:
245
+
246
+ ```bash
247
+ IMA2_SERVER=http://localhost:3333 ima2 ping
248
+ ```