ima2-gen 1.1.21 → 1.1.23

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 (214) hide show
  1. package/README.md +44 -7
  2. package/bin/commands/video.js +14 -0
  3. package/bin/ima2.js +14 -4
  4. package/bin/lib/platform.js +34 -5
  5. package/docs/README.ko.md +43 -2
  6. package/lib/agentQueueWorker.js +6 -0
  7. package/lib/agentRuntime.js +3 -2
  8. package/lib/atomicWrite.js +14 -0
  9. package/lib/grokImageAdapter.js +6 -0
  10. package/lib/grokProxyLauncher.js +5 -3
  11. package/lib/grokVideoAdapter.js +1 -1
  12. package/lib/grokVideoPlannerPrompt.js +10 -0
  13. package/lib/inflight.js +1 -1
  14. package/lib/oauthLauncher.js +5 -0
  15. package/lib/videoFrameExtract.js +3 -3
  16. package/package.json +5 -7
  17. package/routes/capabilities.js +13 -0
  18. package/routes/edit.js +2 -1
  19. package/routes/generate.js +32 -6
  20. package/routes/health.js +4 -3
  21. package/routes/multimode.js +2 -1
  22. package/routes/video.js +35 -3
  23. package/server.js +29 -2
  24. package/skills/ima2/SKILL.md +48 -6
  25. package/ui/dist/.vite/manifest.json +12 -12
  26. package/ui/dist/assets/{AgentWorkspace-B_hq9CLg.js → AgentWorkspace-C21zqdTZ.js} +1 -1
  27. package/ui/dist/assets/{CardNewsWorkspace-wD12J7qk.js → CardNewsWorkspace-BN-ga1lG.js} +1 -1
  28. package/ui/dist/assets/{NodeCanvas-CI_wuPMf.js → NodeCanvas-BbMa4IhI.js} +1 -1
  29. package/ui/dist/assets/{PromptBuilderPanel-CUTujJUV.js → PromptBuilderPanel-DRwBJRDQ.js} +1 -1
  30. package/ui/dist/assets/{PromptImportDialog-CUi66jPK.js → PromptImportDialog-Dp85kHCq.js} +2 -2
  31. package/ui/dist/assets/{PromptImportDiscoverySection-Cm3vrjY4.js → PromptImportDiscoverySection-BE8Q8MLD.js} +1 -1
  32. package/ui/dist/assets/{PromptImportFolderSection-DOtWTD9n.js → PromptImportFolderSection-PtH5x0sc.js} +1 -1
  33. package/ui/dist/assets/{PromptLibraryPanel-BMjQegRa.js → PromptLibraryPanel-FnM9tHI9.js} +2 -2
  34. package/ui/dist/assets/SettingsWorkspace-MARPGyBL.js +1 -0
  35. package/ui/dist/assets/index-BAFI6htx.js +42 -0
  36. package/ui/dist/assets/{index-31uVIdt4.js → index-BSXxr_Bt.js} +1 -1
  37. package/ui/dist/assets/index-DS-ADE7U.css +1 -0
  38. package/ui/dist/index.html +2 -2
  39. package/bin/commands/annotate.ts +0 -119
  40. package/bin/commands/cancel.ts +0 -48
  41. package/bin/commands/canvas-versions.ts +0 -80
  42. package/bin/commands/capabilities.ts +0 -110
  43. package/bin/commands/cardnews.ts +0 -249
  44. package/bin/commands/comfy.ts +0 -54
  45. package/bin/commands/config.ts +0 -186
  46. package/bin/commands/defaults.ts +0 -192
  47. package/bin/commands/doctor.ts +0 -202
  48. package/bin/commands/edit.ts +0 -150
  49. package/bin/commands/gen.ts +0 -214
  50. package/bin/commands/grok.ts +0 -90
  51. package/bin/commands/history.ts +0 -146
  52. package/bin/commands/ls.ts +0 -64
  53. package/bin/commands/metadata.ts +0 -39
  54. package/bin/commands/multimode.ts +0 -196
  55. package/bin/commands/node.ts +0 -166
  56. package/bin/commands/observability.ts +0 -176
  57. package/bin/commands/ping.ts +0 -31
  58. package/bin/commands/prompt-sub/build.ts +0 -101
  59. package/bin/commands/prompt.ts +0 -492
  60. package/bin/commands/ps.ts +0 -81
  61. package/bin/commands/session.ts +0 -266
  62. package/bin/commands/show.ts +0 -72
  63. package/bin/commands/skill.ts +0 -70
  64. package/bin/commands/video.ts +0 -442
  65. package/bin/ima2.ts +0 -430
  66. package/bin/lib/args.ts +0 -92
  67. package/bin/lib/browser-id.ts +0 -16
  68. package/bin/lib/client.ts +0 -122
  69. package/bin/lib/config-store.ts +0 -120
  70. package/bin/lib/destructive-confirm.ts +0 -19
  71. package/bin/lib/doctor-checks.ts +0 -91
  72. package/bin/lib/error-hints.ts +0 -23
  73. package/bin/lib/files.ts +0 -39
  74. package/bin/lib/output.ts +0 -73
  75. package/bin/lib/platform.ts +0 -99
  76. package/bin/lib/recover-output.ts +0 -139
  77. package/bin/lib/sse.ts +0 -73
  78. package/bin/lib/star-prompt.ts +0 -97
  79. package/bin/lib/storage-doctor.ts +0 -39
  80. package/bin/lib/ui-build.ts +0 -85
  81. package/config.ts +0 -354
  82. package/lib/agentCommandParser.ts +0 -69
  83. package/lib/agentGenerationPlanner.ts +0 -273
  84. package/lib/agentQuestionResponder.ts +0 -266
  85. package/lib/agentQueueStore.ts +0 -270
  86. package/lib/agentQueueWorker.ts +0 -89
  87. package/lib/agentRuntime.ts +0 -604
  88. package/lib/agentSettings.ts +0 -72
  89. package/lib/agentStore.ts +0 -422
  90. package/lib/agentStoreRows.ts +0 -136
  91. package/lib/agentTypes.ts +0 -154
  92. package/lib/apiCachePolicy.ts +0 -11
  93. package/lib/assetLifecycle.ts +0 -146
  94. package/lib/canvasVersionStore.ts +0 -223
  95. package/lib/capabilities.ts +0 -126
  96. package/lib/cardNewsGenerator.ts +0 -271
  97. package/lib/cardNewsJobStore.ts +0 -142
  98. package/lib/cardNewsManifestStore.ts +0 -154
  99. package/lib/cardNewsPlanner.ts +0 -236
  100. package/lib/cardNewsPlannerClient.ts +0 -155
  101. package/lib/cardNewsPlannerPrompt.ts +0 -62
  102. package/lib/cardNewsPlannerSchema.ts +0 -321
  103. package/lib/cardNewsRoleTemplateStore.ts +0 -47
  104. package/lib/cardNewsTemplateStore.ts +0 -252
  105. package/lib/codexDetect.ts +0 -71
  106. package/lib/comfyBridge.ts +0 -235
  107. package/lib/composerSnapshot.ts +0 -33
  108. package/lib/configKeys.ts +0 -62
  109. package/lib/db.ts +0 -295
  110. package/lib/errInfo.ts +0 -43
  111. package/lib/errorClassify.ts +0 -100
  112. package/lib/generationCancel.ts +0 -28
  113. package/lib/generationErrors.ts +0 -238
  114. package/lib/grokImageAdapter.ts +0 -513
  115. package/lib/grokMultimodeAdapter.ts +0 -84
  116. package/lib/grokProxyLauncher.ts +0 -153
  117. package/lib/grokRuntime.ts +0 -23
  118. package/lib/grokSizeMapper.ts +0 -71
  119. package/lib/grokVideoAdapter.ts +0 -458
  120. package/lib/grokVideoCanvas.ts +0 -26
  121. package/lib/grokVideoDownload.ts +0 -59
  122. package/lib/grokVideoPlannerPrompt.ts +0 -67
  123. package/lib/historyIndex.ts +0 -51
  124. package/lib/historyList.ts +0 -181
  125. package/lib/imageMetadata.ts +0 -113
  126. package/lib/imageMetadataStore.ts +0 -67
  127. package/lib/imageModels.ts +0 -165
  128. package/lib/inflight.ts +0 -281
  129. package/lib/localImportStore.ts +0 -114
  130. package/lib/logger.ts +0 -161
  131. package/lib/nodeStore.ts +0 -91
  132. package/lib/oauthLauncher.ts +0 -94
  133. package/lib/oauthNormalize.ts +0 -30
  134. package/lib/oauthProxy/errors.ts +0 -128
  135. package/lib/oauthProxy/generators.ts +0 -494
  136. package/lib/oauthProxy/index.ts +0 -28
  137. package/lib/oauthProxy/prompts.ts +0 -123
  138. package/lib/oauthProxy/references.ts +0 -45
  139. package/lib/oauthProxy/runtime.ts +0 -115
  140. package/lib/oauthProxy/streams.ts +0 -232
  141. package/lib/oauthProxy/types.ts +0 -9
  142. package/lib/oauthProxy.ts +0 -3
  143. package/lib/openDirectory.ts +0 -47
  144. package/lib/pngInfo.ts +0 -26
  145. package/lib/promptBuilder/attachments.ts +0 -74
  146. package/lib/promptBuilder/client.ts +0 -130
  147. package/lib/promptBuilder/constants.ts +0 -9
  148. package/lib/promptBuilder/context.ts +0 -36
  149. package/lib/promptBuilder/errors.ts +0 -12
  150. package/lib/promptBuilder/requestSchema.ts +0 -56
  151. package/lib/promptBuilder/responseParser.ts +0 -219
  152. package/lib/promptBuilder/systemPrompt.ts +0 -135
  153. package/lib/promptBuilder/transport.ts +0 -94
  154. package/lib/promptBuilder/types.ts +0 -109
  155. package/lib/promptImport/curatedSources.ts +0 -141
  156. package/lib/promptImport/discoveryRegistry.ts +0 -329
  157. package/lib/promptImport/errors.ts +0 -18
  158. package/lib/promptImport/githubDiscovery.ts +0 -309
  159. package/lib/promptImport/githubFolder.ts +0 -397
  160. package/lib/promptImport/githubSource.ts +0 -257
  161. package/lib/promptImport/gptImageHints.ts +0 -70
  162. package/lib/promptImport/parsePromptCandidates.ts +0 -179
  163. package/lib/promptImport/promptIndex.ts +0 -326
  164. package/lib/promptImport/rankPromptCandidates.ts +0 -65
  165. package/lib/promptImport/types.ts +0 -103
  166. package/lib/promptSafetyPolicy.ts +0 -5
  167. package/lib/providerOptions.ts +0 -56
  168. package/lib/referenceImageCompress.ts +0 -84
  169. package/lib/refs.ts +0 -133
  170. package/lib/requestLogger.ts +0 -49
  171. package/lib/responsesDoctor.ts +0 -456
  172. package/lib/responsesErrors.ts +0 -83
  173. package/lib/responsesFallback.ts +0 -114
  174. package/lib/responsesImageAdapter.ts +0 -466
  175. package/lib/responsesParse.ts +0 -452
  176. package/lib/responsesTools.ts +0 -28
  177. package/lib/runtimeContext.ts +0 -146
  178. package/lib/runtimePorts.ts +0 -105
  179. package/lib/sessionStore.ts +0 -308
  180. package/lib/storageMigration.ts +0 -310
  181. package/lib/styleSheet.ts +0 -139
  182. package/lib/systemTrash.ts +0 -20
  183. package/lib/videoContinuity.ts +0 -180
  184. package/lib/videoFrameExtract.ts +0 -78
  185. package/lib/videoSeriesChain.ts +0 -29
  186. package/lib/visibleTextLanguagePolicy.ts +0 -7
  187. package/routes/agent.ts +0 -308
  188. package/routes/annotations.ts +0 -118
  189. package/routes/canvasVersions.ts +0 -69
  190. package/routes/capabilities.ts +0 -18
  191. package/routes/cardNews.ts +0 -211
  192. package/routes/comfy.ts +0 -43
  193. package/routes/edit.ts +0 -352
  194. package/routes/generate.ts +0 -492
  195. package/routes/grok.ts +0 -24
  196. package/routes/health.ts +0 -123
  197. package/routes/history.ts +0 -221
  198. package/routes/imageImport.ts +0 -37
  199. package/routes/index.ts +0 -52
  200. package/routes/metadata.ts +0 -77
  201. package/routes/multimode.ts +0 -499
  202. package/routes/nodes.ts +0 -578
  203. package/routes/promptBuilder.ts +0 -37
  204. package/routes/promptImport.ts +0 -379
  205. package/routes/prompts.ts +0 -428
  206. package/routes/quota.ts +0 -89
  207. package/routes/sessions.ts +0 -317
  208. package/routes/storage.ts +0 -47
  209. package/routes/video.ts +0 -300
  210. package/routes/videoExtended.ts +0 -284
  211. package/server.ts +0 -293
  212. package/ui/dist/assets/SettingsWorkspace-PiaVnsdA.js +0 -1
  213. package/ui/dist/assets/index-CjgnNtgt.css +0 -1
  214. package/ui/dist/assets/index-Da2s4_-5.js +0 -36
package/bin/ima2.ts DELETED
@@ -1,430 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createInterface } from "readline/promises";
3
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
4
- import { join, dirname } from "path";
5
- import { fileURLToPath } from "url";
6
- import { spawn, execSync } from "child_process";
7
- import { confirmDestructiveAction } from "./lib/destructive-confirm.js";
8
- import { doctor } from "./commands/doctor.js";
9
- import { openUrl, resolveBin } from "./lib/platform.js";
10
- import { maybePromptGithubStar } from "./lib/star-prompt.js";
11
- import { ensureFreshUiDist } from "./lib/ui-build.js";
12
- import { detectCodexAuth } from "../lib/codexDetect.js";
13
- import { config as runtimeConfig } from "../config.js";
14
-
15
- import { errInfo } from "../lib/errInfo.js";
16
- const __dirname = dirname(fileURLToPath(import.meta.url));
17
- const ROOT = join(__dirname, "..");
18
- // Config lives under runtimeConfig.storage.configDir (honors IMA2_CONFIG_DIR).
19
- // Legacy installs that stored config at <packageRoot>/.ima2/config.json will be
20
- // migrated on first write.
21
- const CONFIG_DIR = runtimeConfig.storage.configDir;
22
- const CONFIG_FILE = runtimeConfig.storage.configFile;
23
- const LEGACY_CONFIG_FILE = join(ROOT, ".ima2", "config.json");
24
-
25
- // Load package.json for version
26
- let pkg = { version: "?", name: "ima2-gen" };
27
- try {
28
- pkg = JSON.parse(readFileSync(join(ROOT, "package.json"), "utf-8"));
29
- } catch {}
30
-
31
- function loadConfig() {
32
- if (existsSync(CONFIG_FILE)) {
33
- return JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
34
- }
35
- // One-time read from legacy location so users who set up on <1.0.4 don't lose auth.
36
- if (existsSync(LEGACY_CONFIG_FILE)) {
37
- try { return JSON.parse(readFileSync(LEGACY_CONFIG_FILE, "utf-8")); } catch {}
38
- }
39
- return {};
40
- }
41
-
42
- function saveConfig(config: Record<string, unknown>) {
43
- mkdirSync(CONFIG_DIR, { recursive: true });
44
- writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
45
- }
46
-
47
- function loadAdvertisement() {
48
- const p = runtimeConfig.storage.advertiseFile;
49
- if (!existsSync(p)) return null;
50
- try {
51
- return JSON.parse(readFileSync(p, "utf-8"));
52
- } catch {
53
- return null;
54
- }
55
- }
56
-
57
- function advertisedServerUrl() {
58
- const adv = loadAdvertisement();
59
- return adv?.backend?.url || adv?.url || (adv?.port ? `http://localhost:${adv.port}` : null);
60
- }
61
-
62
- async function setup() {
63
- const rl = createInterface({ input: process.stdin, output: process.stdout });
64
-
65
- console.log("\n ima2-gen — GPT Image 2 Generator\n");
66
- console.log(" Choose authentication method:\n");
67
- console.log(" 1) GPT OAuth — login with ChatGPT account (free, images only)");
68
- console.log(" 2) Grok OAuth — login with xAI/Grok account (images + video)");
69
- console.log(" 3) Both — GPT OAuth + Grok OAuth");
70
- console.log(" 4) API Key — paste your OpenAI API key (paid)\n");
71
-
72
- const choice = await rl.question(" Enter 1-4: ");
73
- const config = loadConfig();
74
-
75
- if (choice.trim() === "4") {
76
- const key = await rl.question(" OpenAI API Key: ");
77
- if (!key.startsWith("sk-")) {
78
- console.log(" Invalid API key format. Expected sk-...");
79
- rl.close();
80
- process.exit(1);
81
- }
82
- config.provider = "api";
83
- config.apiKey = key.trim();
84
- saveConfig(config);
85
- console.log("\n API key saved. Starting server...\n");
86
- } else if (choice.trim() === "2") {
87
- config.provider = "grok";
88
- config.oauth = config.oauth || {};
89
- config.oauth.disableAutoStart = true;
90
- delete config.apiKey;
91
- saveConfig(config);
92
- console.log("\n Starting Grok OAuth login...\n");
93
- try {
94
- execSync(`node ${JSON.stringify(join(ROOT, "bin", "ima2.js"))} grok login --manual-paste`, { stdio: "inherit" });
95
- } catch {
96
- console.log("\n Grok login failed or cancelled. You can retry with 'ima2 grok login'.\n");
97
- rl.close();
98
- process.exit(1);
99
- }
100
- console.log(" Grok configured. Run 'ima2 serve' to start.\n");
101
- } else if (choice.trim() === "3") {
102
- config.provider = "oauth";
103
- delete config.apiKey;
104
- if (config.oauth) delete config.oauth.disableAutoStart;
105
- saveConfig(config);
106
- console.log("\n Setting up both GPT OAuth + Grok OAuth...\n");
107
- // GPT OAuth
108
- const auth = detectCodexAuth();
109
- if (!auth.authed) {
110
- console.log(" Running GPT OAuth login...\n");
111
- try {
112
- execSync(`${resolveBin("npx")} @openai/codex login`, { stdio: "inherit" });
113
- } catch {
114
- console.log("\n GPT login failed. Continuing with Grok...\n");
115
- }
116
- } else {
117
- console.log(` GPT OAuth session found.\n`);
118
- }
119
- // Grok OAuth
120
- console.log(" Running Grok OAuth login...\n");
121
- try {
122
- execSync(`node ${JSON.stringify(join(ROOT, "bin", "ima2.js"))} grok login --manual-paste`, { stdio: "inherit" });
123
- } catch {
124
- console.log("\n Grok login failed. You can retry with 'ima2 grok login'.\n");
125
- }
126
- console.log(" Both providers configured.\n");
127
- } else {
128
- // Default: GPT OAuth (choice 1 or anything else)
129
- config.provider = "oauth";
130
- config.oauth = config.oauth || {};
131
- config.oauth.disableAutoStart = false;
132
- delete config.apiKey;
133
- saveConfig(config);
134
- console.log("\n Starting GPT OAuth login...\n");
135
-
136
- const auth = detectCodexAuth();
137
- const hasAuth = auth.authed;
138
-
139
- if (!hasAuth) {
140
- if (auth.platform === "win32") {
141
- console.log(
142
- " Windows note: OpenAI Codex has no documented native installer. Use WSL2 for best results.\n",
143
- );
144
- }
145
- console.log(" Running 'codex login' — follow the browser prompt.\n");
146
- try {
147
- execSync(`${resolveBin("npx")} @openai/codex login`, { stdio: "inherit" });
148
- } catch {
149
- console.log("\n Login failed or cancelled. You can retry with 'ima2 serve'.\n");
150
- rl.close();
151
- process.exit(1);
152
- }
153
- } else {
154
- const how = auth.probe === "authed" ? "codex CLI" : "auth file";
155
- console.log(` Existing GPT OAuth session found (${how}).\n`);
156
- }
157
-
158
- saveConfig(config);
159
- console.log(" GPT OAuth configured. Starting server...\n");
160
- }
161
-
162
- rl.close();
163
- return config;
164
- }
165
-
166
- async function serve(serveArgs: string[] = []) {
167
- try {
168
- await maybePromptGithubStar();
169
- } catch (e) {
170
- const err = errInfo(e);
171
- console.error(`[ima2] Star prompt skipped: ${err.message || err.raw}`);
172
- }
173
-
174
- let config = loadConfig();
175
-
176
- if (!config.provider) {
177
- config = await setup();
178
- }
179
-
180
- const uiDist = ensureFreshUiDist(ROOT);
181
- if (!uiDist.ok) {
182
- console.log(`\n ${uiDist.error}`);
183
- console.log(
184
- uiDist.reason === "missing-source-and-dist"
185
- ? " This installation appears broken. Reinstall: npm i -g ima2-gen\n"
186
- : "",
187
- );
188
- process.exit(1);
189
- }
190
-
191
- const env = { ...process.env };
192
- const serveDev = serveArgs.includes("--dev");
193
- if (serveDev) {
194
- env.IMA2_DEV = "1";
195
- env.IMA2_LOG_LEVEL = env.IMA2_LOG_LEVEL || "debug";
196
- }
197
-
198
- if (config.provider === "api" && config.apiKey) {
199
- env.OPENAI_API_KEY = config.apiKey;
200
- }
201
-
202
- const serverPath = join(ROOT, "server.js");
203
- const child = spawn("node", [serverPath], {
204
- stdio: "inherit",
205
- env,
206
- cwd: ROOT,
207
- });
208
-
209
- child.on("exit", (code) => process.exit(code));
210
-
211
- process.on("SIGINT", () => child.kill("SIGINT"));
212
- process.on("SIGTERM", () => child.kill("SIGTERM"));
213
- }
214
-
215
- async function showStatus() {
216
- const config = loadConfig();
217
- console.log(`\n ${pkg.name} v${pkg.version}\n`);
218
- console.log(` Config file: ${CONFIG_FILE}`);
219
- console.log(` Exists: ${existsSync(CONFIG_FILE) ? "yes" : "no"}\n`);
220
- console.log(` Generated dir: ${runtimeConfig.storage.generatedDir}`);
221
- console.log(` Advertised server: ${advertisedServerUrl() || "none"}\n`);
222
-
223
- if (config.provider) {
224
- console.log(` Provider: ${config.provider}`);
225
- if (config.provider === "api") {
226
- const key = config.apiKey || "";
227
- console.log(` API Key: ${key ? key.slice(0, 8) + "..." + key.slice(-4) : "not set"}`);
228
- }
229
- console.log("");
230
- } else {
231
- console.log(" Status: not configured");
232
- console.log(" Run 'ima2 setup' to configure.\n");
233
- }
234
-
235
- // Check OAuth auth files + codex CLI probe
236
- const auth = detectCodexAuth();
237
- console.log(` GPT OAuth sessions:`);
238
- console.log(` ${auth.files.codex} ${auth.fileHits.codex ? "✓" : "✗"}`);
239
- console.log(` ${auth.files.chatgpt} ${auth.fileHits.chatgpt ? "✓" : "✗"}`);
240
- if (auth.fileHits.xdgCodex) {
241
- console.log(` ${auth.files.xdgCodex} ✓`);
242
- }
243
- const probeLabel =
244
- auth.probe === "authed" ? "✓ authed"
245
- : auth.probe === "unauthed" ? "✗ not logged in"
246
- : "– codex CLI not found";
247
- console.log(` codex login status ${probeLabel}`);
248
- if (auth.platform === "win32") {
249
- console.log(" (Windows: no native codex installer — use WSL2)");
250
- }
251
- console.log("");
252
- }
253
-
254
- function openBrowser() {
255
- const url = advertisedServerUrl() || `http://localhost:${runtimeConfig.server.port}`;
256
- const res = openUrl(url);
257
- if (res.ok) {
258
- console.log(`\n Opening ${url} ...\n`);
259
- } else {
260
- console.log(`\n Could not open browser. Visit: ${url}\n`);
261
- }
262
- }
263
-
264
- function showHelp() {
265
- console.log(`
266
- ${pkg.name} v${pkg.version} — GPT Image 2 Generator
267
-
268
- Usage: ima2 <command> [options]
269
-
270
- Server commands:
271
- serve [--dev] Start the image generation server
272
- setup, login Configure API key or GPT OAuth (interactive)
273
- status Show current configuration status
274
- doctor Diagnose environment and setup
275
- open Open web UI in browser
276
- reset Reset configuration
277
-
278
- Client commands (require a running 'ima2 serve'):
279
- gen <prompt> Generate image(s) from prompt (ima2 gen --help)
280
- video <prompt> Generate video via Grok (ima2 video --help)
281
- edit <file> Edit an existing image (ima2 edit --help)
282
- ls List recent history (ima2 ls --help)
283
- show <name> Show one history item (ima2 show --help)
284
- session <sub> Session/graph CRUD (ima2 session --help)
285
- history <sub> History write-ops (ima2 history --help)
286
- prompt <sub> Prompt library + folders + import (ima2 prompt --help)
287
- multimode <prompt> Multi-image SSE generation (ima2 multimode --help)
288
- node <sub> Node-mode generate/show (ima2 node --help)
289
- annotate <sub> Image annotations CRUD (ima2 annotate --help)
290
- canvas-versions <sub> Canvas version save/update (ima2 canvas-versions --help)
291
- metadata <file> Read embedded metadata
292
- comfy <sub> ComfyUI workflow export (ima2 comfy --help)
293
- cardnews <sub> Card News templates/jobs/export (ima2 cardnews --help)
294
- ps List active jobs (ima2 ps --help)
295
- cancel <id> Mark an in-flight job canceled (ima2 cancel --help)
296
- inflight <sub> Inflight jobs (ls / rm) (ima2 inflight --help)
297
- storage <sub> Storage status / open-dir (ima2 storage --help)
298
- billing API usage / quota
299
- providers Configured providers
300
- oauth <sub> GPT OAuth proxy status (ima2 oauth --help)
301
- grok <sub> Bundled Grok auth/status (ima2 grok --help)
302
- config <sub> Config get/set/ls/path/rm (ima2 config --help)
303
- defaults <sub> Inspect/change model defaults (ima2 defaults --help)
304
- capabilities Agent capability metadata (ima2 capabilities --help)
305
- skill Print packaged agent skill (ima2 skill --help)
306
- ping Ping running server / check health
307
-
308
- Options:
309
- -v, --version Show version
310
- -h, --help Show help
311
-
312
- Server-aware subcommands accept:
313
- --server <url> Override discovered server URL
314
- IMA2_SERVER Same as --server for client commands
315
- ~/.ima2/server.json Auto-discovery file written by 'ima2 serve'
316
- IMA2_CONFIG_DIR Override config directory
317
- IMA2_GENERATED_DIR Override generated images directory
318
- IMA2_CARD_NEWS=1 Enable Card News routes
319
- IMA2_LOG_LEVEL debug|info|warn|error
320
-
321
- Examples:
322
- ima2 serve Start server
323
- ima2 serve --dev Start with verbose server diagnostics
324
- ima2 gen "a shiba in space" Generate from CLI
325
- ima2 gen "merge" --ref a.png --ref b.png -q high -o out.png
326
- ima2 video "a cat playing piano" --duration 10
327
- ima2 ls -n 10 Last 10 generations
328
- ima2 skill Print agent usage skill
329
- ima2 capabilities --json Inspect supported models/options
330
- ima2 defaults --json Inspect running server defaults
331
- ima2 ping Health check
332
- `);
333
- }
334
-
335
- // ── CLI ──
336
- const args = process.argv.slice(2);
337
- const command = args[0];
338
-
339
- if (args.includes("-v") || args.includes("--version")) {
340
- console.log(pkg.version);
341
- process.exit(0);
342
- }
343
-
344
- if ((!command || args.includes("-h") || args.includes("--help"))
345
- && !["doctor", "gen", "video", "edit", "ls", "show", "ps", "cancel", "session", "history", "prompt", "multimode", "node", "annotate", "canvas-versions", "metadata", "comfy", "cardnews", "inflight", "storage", "billing", "providers", "oauth", "grok", "config", "defaults", "capabilities", "skill", "ping"].includes(command)) {
346
- showHelp();
347
- process.exit(command ? 0 : 1);
348
- }
349
-
350
- switch (command) {
351
- case "serve":
352
- serve(args.slice(1));
353
- break;
354
- case "setup":
355
- case "login":
356
- setup().then(() => console.log(" Done. Run 'ima2 serve' to start."));
357
- break;
358
- case "status":
359
- showStatus();
360
- break;
361
- case "doctor":
362
- await doctor(args.slice(1));
363
- break;
364
- case "open":
365
- openBrowser();
366
- break;
367
- case "reset":
368
- if (existsSync(CONFIG_FILE)) {
369
- try {
370
- const yes = args.includes("--yes") || args.includes("-y");
371
- const confirmed = await confirmDestructiveAction("Reset all ima2 config?", yes);
372
- if (!confirmed) {
373
- console.log(" Aborted.");
374
- break;
375
- }
376
- } catch (err) {
377
- console.error(` ${err instanceof Error ? err.message : String(err)}`);
378
- process.exit(2);
379
- }
380
- writeFileSync(CONFIG_FILE, "{}");
381
- console.log(" Config reset. Run 'ima2 serve' to reconfigure.");
382
- } else {
383
- console.log(" No config to reset.");
384
- }
385
- break;
386
- case "gen":
387
- case "video":
388
- case "edit":
389
- case "ls":
390
- case "show":
391
- case "ps":
392
- case "cancel":
393
- case "session":
394
- case "history":
395
- case "prompt":
396
- case "multimode":
397
- case "node":
398
- case "annotate":
399
- case "canvas-versions":
400
- case "metadata":
401
- case "comfy":
402
- case "cardnews":
403
- case "config":
404
- case "defaults":
405
- case "capabilities":
406
- case "skill":
407
- case "grok":
408
- case "ping": {
409
- const { setCliVersion } = await import("./lib/client.js");
410
- setCliVersion(pkg.version);
411
- const mod = await import(`./commands/${command}.js`);
412
- await mod.default(args.slice(1));
413
- break;
414
- }
415
- case "storage":
416
- case "billing":
417
- case "providers":
418
- case "oauth":
419
- case "inflight": {
420
- const { setCliVersion } = await import("./lib/client.js");
421
- setCliVersion(pkg.version);
422
- const mod = await import("./commands/observability.js");
423
- await mod.default([command, ...args.slice(1)]);
424
- break;
425
- }
426
- default:
427
- console.log(` Unknown command: "${command}"`);
428
- console.log(" Run 'ima2 --help' for usage.\n");
429
- process.exit(1);
430
- }
package/bin/lib/args.ts DELETED
@@ -1,92 +0,0 @@
1
- // Tiny argv parser — no dependencies.
2
- // Supports: --long, --long=val, --long val, -s, -s val, repeatable flags, positional, --.
3
-
4
- export type FlagValue = string | string[] | boolean | undefined;
5
-
6
- export interface FlagDef {
7
- type?: "string" | "boolean";
8
- short?: string;
9
- default?: string | boolean;
10
- repeatable?: boolean;
11
- }
12
-
13
- export interface ParseSpec {
14
- flags?: Record<string, FlagDef>;
15
- }
16
-
17
- export interface ParsedArgs {
18
- positional: string[];
19
- _unknown: string[];
20
- [key: string]: FlagValue;
21
- }
22
-
23
- export function parseArgs(argv: string[], spec: any = {}): ParsedArgs {
24
- const shortMap: any = {};
25
- for (const [name, def] of Object.entries<any>(spec.flags || {})) {
26
- if (def.short) shortMap[def.short] = name;
27
- }
28
-
29
- const out: any = { positional: [], _unknown: [] };
30
- for (const [name, def] of Object.entries<any>(spec.flags || {})) {
31
- if (def.repeatable) out[name] = [];
32
- else if ("default" in def) out[name] = def.default;
33
- }
34
-
35
- let i = 0;
36
- let doubleDashSeen = false;
37
- while (i < argv.length) {
38
- const a = argv[i];
39
- if (doubleDashSeen) {
40
- out.positional.push(a);
41
- i++;
42
- continue;
43
- }
44
- if (a === "--") {
45
- doubleDashSeen = true;
46
- i++;
47
- continue;
48
- }
49
- if (a.startsWith("--")) {
50
- const eq = a.indexOf("=");
51
- const name = eq > -1 ? a.slice(2, eq) : a.slice(2);
52
- const def = (spec.flags || {})[name];
53
- if (!def) {
54
- out._unknown.push(a);
55
- i++;
56
- continue;
57
- }
58
- if (def.type === "boolean") {
59
- out[name] = true;
60
- i++;
61
- } else {
62
- const val = eq > -1 ? a.slice(eq + 1) : argv[i + 1];
63
- if (eq === -1) i++;
64
- if (def.repeatable) out[name].push(val);
65
- else out[name] = val;
66
- i++;
67
- }
68
- } else if (a.startsWith("-") && a.length > 1 && !/^-\d/.test(a)) {
69
- const short = a.slice(1);
70
- const name = shortMap[short];
71
- if (!name) {
72
- out._unknown.push(a);
73
- i++;
74
- continue;
75
- }
76
- const def = spec.flags[name];
77
- if (def.type === "boolean") {
78
- out[name] = true;
79
- i++;
80
- } else {
81
- const val = argv[i + 1];
82
- if (def.repeatable) out[name].push(val);
83
- else out[name] = val;
84
- i += 2;
85
- }
86
- } else {
87
- out.positional.push(a);
88
- i++;
89
- }
90
- }
91
- return out;
92
- }
@@ -1,16 +0,0 @@
1
- import { createHash } from "crypto";
2
- import { config } from "../../config.js";
3
-
4
- let cached: string | null = null;
5
-
6
- /**
7
- * Stable per-machine browser-id for CLI flows that share storage with the UI
8
- * but do not have a real browser. Derived from the config dir so two CLIs on
9
- * the same install share favorites/annotations, but different installs (e.g.
10
- * different IMA2_CONFIG_DIR) stay isolated.
11
- */
12
- export function getCliBrowserId(): string {
13
- if (cached) return cached;
14
- cached = "cli-" + createHash("sha1").update(config.storage.configDir).digest("hex").slice(0, 16);
15
- return cached;
16
- }
package/bin/lib/client.ts DELETED
@@ -1,122 +0,0 @@
1
- import { readFileSync, existsSync } from "node:fs";
2
- import { join } from "node:path";
3
- import { homedir } from "node:os";
4
-
5
- export const DEFAULT_PORT = 3333;
6
-
7
- function readAdvertise() {
8
- const p = process.env.IMA2_ADVERTISE_FILE ||
9
- join(process.env.IMA2_CONFIG_DIR || join(homedir(), ".ima2"), "server.json");
10
- if (!existsSync(p)) return null;
11
- try {
12
- return JSON.parse(readFileSync(p, "utf-8"));
13
- } catch {
14
- return null;
15
- }
16
- }
17
-
18
- async function probe(base: string, timeoutMs = 600) {
19
- try {
20
- const r = await fetch(`${base}/api/health`, { signal: AbortSignal.timeout(timeoutMs) });
21
- if (!r.ok) return null;
22
- return await r.json();
23
- } catch {
24
- return null;
25
- }
26
- }
27
-
28
- export async function resolveServer({ serverFlag }: any = {}) {
29
- if (serverFlag) {
30
- const base = serverFlag.replace(/\/$/, "");
31
- const health = await probe(base);
32
- if (health) return { base, health };
33
- const err: any = new Error(`server unreachable at ${base}`);
34
- err.code = "SERVER_UNREACHABLE";
35
- throw err;
36
- }
37
- const candidates: string[] = [];
38
- if (process.env.IMA2_SERVER) candidates.push(process.env.IMA2_SERVER.replace(/\/$/, ""));
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(/\/$/, ""));
42
- if (adv?.port) candidates.push(`http://localhost:${adv.port}`);
43
- candidates.push(`http://localhost:${DEFAULT_PORT}`);
44
-
45
- const seen = new Set<string>();
46
- const uniq = candidates.filter((c) => !seen.has(c) && seen.add(c));
47
-
48
- for (const base of uniq) {
49
- const health = await probe(base);
50
- if (health) return { base, health };
51
- }
52
- const err: any = new Error("server unreachable — is 'ima2 serve' running?");
53
- err.code = "SERVER_UNREACHABLE";
54
- throw err;
55
- }
56
-
57
- export async function request(base: string, path: string, {
58
- method = "GET",
59
- body,
60
- headers: extraHeaders,
61
- raw = false,
62
- timeoutMs = 180_000,
63
- }: any = {}) {
64
- const baseHeaders: Record<string, string> = raw
65
- ? { "X-ima2-client": `cli/${CLI_VERSION}` }
66
- : { "Content-Type": "application/json", "X-ima2-client": `cli/${CLI_VERSION}` };
67
- const finalHeaders = { ...baseHeaders, ...(extraHeaders || {}) };
68
- const res = await fetch(base + path, {
69
- method,
70
- headers: finalHeaders,
71
- body: body === undefined ? undefined
72
- : raw ? body
73
- : JSON.stringify(body),
74
- signal: AbortSignal.timeout(timeoutMs),
75
- });
76
- const text = await res.text();
77
- let json: any = null;
78
- try { json = JSON.parse(text); } catch {}
79
- if (!res.ok) {
80
- const err: any = new Error(json?.error?.message || json?.error || `HTTP ${res.status}`);
81
- err.status = res.status;
82
- err.code = json?.error?.code || json?.code || null;
83
- err.body = json || text;
84
- throw err;
85
- }
86
- return json;
87
- }
88
-
89
- interface RawImageItem {
90
- image?: string;
91
- filename?: string | null;
92
- }
93
- interface RawGenerateResponse {
94
- image?: string;
95
- images?: RawImageItem[];
96
- filename?: string | null;
97
- elapsed?: number | string | null;
98
- requestId?: string | null;
99
- [key: string]: unknown;
100
- }
101
-
102
- export function normalizeGenerate(resp: RawGenerateResponse | null | undefined) {
103
- if (!resp) return { images: [], elapsed: null, requestId: null };
104
- if (Array.isArray(resp.images)) {
105
- return {
106
- images: resp.images.map((it: RawImageItem) => ({ image: it.image, filename: it.filename })),
107
- elapsed: resp.elapsed ?? null,
108
- requestId: resp.requestId ?? null,
109
- };
110
- }
111
- if (resp.image) {
112
- return {
113
- images: [{ image: resp.image, filename: resp.filename || null }],
114
- elapsed: resp.elapsed ?? null,
115
- requestId: resp.requestId ?? null,
116
- };
117
- }
118
- return { images: [], elapsed: resp.elapsed ?? null, requestId: resp.requestId ?? null };
119
- }
120
-
121
- export let CLI_VERSION = "dev";
122
- export function setCliVersion(v: string) { CLI_VERSION = v; }