ima2-gen 1.1.20 → 1.1.22

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 (239) hide show
  1. package/README.md +42 -26
  2. package/bin/commands/capabilities.js +2 -2
  3. package/bin/commands/defaults.js +2 -2
  4. package/bin/commands/doctor.js +3 -3
  5. package/bin/commands/edit.js +1 -1
  6. package/bin/commands/gen.js +1 -1
  7. package/bin/commands/grok.js +16 -11
  8. package/bin/commands/multimode.js +1 -1
  9. package/bin/commands/observability.js +2 -2
  10. package/bin/commands/video.js +335 -13
  11. package/bin/ima2.js +23 -13
  12. package/bin/lib/error-hints.js +2 -2
  13. package/bin/lib/platform.js +34 -5
  14. package/docs/API.md +112 -3
  15. package/docs/CLI.md +61 -7
  16. package/docs/FAQ.ko.md +15 -20
  17. package/docs/FAQ.md +14 -19
  18. package/docs/NPX_QUICKSTART.md +40 -0
  19. package/docs/PROMPT_STUDIO.ko.md +1 -1
  20. package/docs/PROMPT_STUDIO.md +1 -1
  21. package/docs/README.ja.md +6 -16
  22. package/docs/README.ko.md +35 -14
  23. package/docs/README.zh-CN.md +7 -17
  24. package/docs/migration/runtime-test-inventory.md +8 -1
  25. package/lib/agentQueueWorker.js +6 -0
  26. package/lib/agentRuntime.js +20 -5
  27. package/lib/atomicWrite.js +14 -0
  28. package/lib/capabilities.js +1 -1
  29. package/lib/generationErrors.js +1 -1
  30. package/lib/grokProxyLauncher.js +31 -6
  31. package/lib/grokVideoAdapter.js +18 -89
  32. package/lib/grokVideoCanvas.js +25 -0
  33. package/lib/grokVideoDownload.js +58 -0
  34. package/lib/grokVideoPlannerPrompt.js +64 -0
  35. package/lib/historyList.js +7 -1
  36. package/lib/inflight.js +1 -1
  37. package/lib/oauthLauncher.js +26 -6
  38. package/lib/videoContinuity.js +149 -0
  39. package/lib/videoFrameExtract.js +80 -0
  40. package/node_modules/progrok/dist/index.js +187 -88
  41. package/node_modules/progrok/dist/index.js.map +1 -1
  42. package/node_modules/progrok/package.json +1 -1
  43. package/node_modules/progrok/skills/progrok/SKILL.md +33 -4
  44. package/package.json +6 -8
  45. package/routes/edit.js +2 -1
  46. package/routes/generate.js +4 -3
  47. package/routes/health.js +4 -3
  48. package/routes/index.js +4 -0
  49. package/routes/multimode.js +2 -1
  50. package/routes/quota.js +66 -0
  51. package/routes/video.js +80 -16
  52. package/routes/videoExtended.js +293 -0
  53. package/server.js +35 -4
  54. package/skills/ima2/SKILL.md +320 -7
  55. package/ui/dist/.vite/manifest.json +12 -12
  56. package/ui/dist/assets/{AgentWorkspace-DS8uvoLI.js → AgentWorkspace-COxQ5TjU.js} +2 -2
  57. package/ui/dist/assets/{CardNewsWorkspace-CYxMsE67.js → CardNewsWorkspace-B0OkcuVz.js} +1 -1
  58. package/ui/dist/assets/{NodeCanvas-DccIc347.js → NodeCanvas-BSsclEBh.js} +1 -1
  59. package/ui/dist/assets/{PromptBuilderPanel-BvxxwSJp.js → PromptBuilderPanel-DpC9A5Rz.js} +1 -1
  60. package/ui/dist/assets/{PromptImportDialog-u1_BFDRd.js → PromptImportDialog-CVwT0rLd.js} +2 -2
  61. package/ui/dist/assets/{PromptImportDiscoverySection-C5uvkVSz.js → PromptImportDiscoverySection-BDCkRCRs.js} +1 -1
  62. package/ui/dist/assets/{PromptImportFolderSection-D3E_O1SD.js → PromptImportFolderSection-QoKbZD83.js} +1 -1
  63. package/ui/dist/assets/{PromptLibraryPanel-4gyf9CB9.js → PromptLibraryPanel-BhFgeKnY.js} +2 -2
  64. package/ui/dist/assets/SettingsWorkspace-CfjrlH5R.js +1 -0
  65. package/ui/dist/assets/index-C-mur7pa.css +1 -0
  66. package/ui/dist/assets/index-CCP5nUOj.js +42 -0
  67. package/ui/dist/assets/{index-DoKtXbod.js → index-Cxhzi3bs.js} +1 -1
  68. package/ui/dist/index.html +2 -2
  69. package/vendor/progrok-0.2.0.tgz +0 -0
  70. package/bin/commands/annotate.ts +0 -119
  71. package/bin/commands/cancel.ts +0 -48
  72. package/bin/commands/canvas-versions.ts +0 -80
  73. package/bin/commands/capabilities.ts +0 -110
  74. package/bin/commands/cardnews.ts +0 -249
  75. package/bin/commands/comfy.ts +0 -54
  76. package/bin/commands/config.ts +0 -186
  77. package/bin/commands/defaults.ts +0 -192
  78. package/bin/commands/doctor.ts +0 -202
  79. package/bin/commands/edit.ts +0 -150
  80. package/bin/commands/gen.ts +0 -214
  81. package/bin/commands/grok.ts +0 -85
  82. package/bin/commands/history.ts +0 -146
  83. package/bin/commands/ls.ts +0 -64
  84. package/bin/commands/metadata.ts +0 -39
  85. package/bin/commands/multimode.ts +0 -196
  86. package/bin/commands/node.ts +0 -166
  87. package/bin/commands/observability.ts +0 -176
  88. package/bin/commands/ping.ts +0 -31
  89. package/bin/commands/prompt-sub/build.ts +0 -101
  90. package/bin/commands/prompt.ts +0 -492
  91. package/bin/commands/ps.ts +0 -81
  92. package/bin/commands/session.ts +0 -266
  93. package/bin/commands/show.ts +0 -72
  94. package/bin/commands/skill.ts +0 -70
  95. package/bin/commands/video.ts +0 -205
  96. package/bin/ima2.ts +0 -430
  97. package/bin/lib/args.ts +0 -92
  98. package/bin/lib/browser-id.ts +0 -16
  99. package/bin/lib/client.ts +0 -122
  100. package/bin/lib/config-store.ts +0 -120
  101. package/bin/lib/destructive-confirm.ts +0 -19
  102. package/bin/lib/doctor-checks.ts +0 -91
  103. package/bin/lib/error-hints.ts +0 -23
  104. package/bin/lib/files.ts +0 -39
  105. package/bin/lib/output.ts +0 -73
  106. package/bin/lib/platform.ts +0 -99
  107. package/bin/lib/recover-output.ts +0 -139
  108. package/bin/lib/sse.ts +0 -73
  109. package/bin/lib/star-prompt.ts +0 -97
  110. package/bin/lib/storage-doctor.ts +0 -39
  111. package/bin/lib/ui-build.ts +0 -85
  112. package/config.ts +0 -354
  113. package/lib/agentCommandParser.ts +0 -69
  114. package/lib/agentGenerationPlanner.ts +0 -273
  115. package/lib/agentQuestionResponder.ts +0 -266
  116. package/lib/agentQueueStore.ts +0 -270
  117. package/lib/agentQueueWorker.ts +0 -89
  118. package/lib/agentRuntime.ts +0 -592
  119. package/lib/agentSettings.ts +0 -72
  120. package/lib/agentStore.ts +0 -422
  121. package/lib/agentStoreRows.ts +0 -136
  122. package/lib/agentTypes.ts +0 -154
  123. package/lib/apiCachePolicy.ts +0 -11
  124. package/lib/assetLifecycle.ts +0 -146
  125. package/lib/canvasVersionStore.ts +0 -223
  126. package/lib/capabilities.ts +0 -126
  127. package/lib/cardNewsGenerator.ts +0 -271
  128. package/lib/cardNewsJobStore.ts +0 -142
  129. package/lib/cardNewsManifestStore.ts +0 -154
  130. package/lib/cardNewsPlanner.ts +0 -236
  131. package/lib/cardNewsPlannerClient.ts +0 -155
  132. package/lib/cardNewsPlannerPrompt.ts +0 -62
  133. package/lib/cardNewsPlannerSchema.ts +0 -321
  134. package/lib/cardNewsRoleTemplateStore.ts +0 -47
  135. package/lib/cardNewsTemplateStore.ts +0 -252
  136. package/lib/codexDetect.ts +0 -71
  137. package/lib/comfyBridge.ts +0 -235
  138. package/lib/composerSnapshot.ts +0 -33
  139. package/lib/configKeys.ts +0 -62
  140. package/lib/db.ts +0 -295
  141. package/lib/errInfo.ts +0 -43
  142. package/lib/errorClassify.ts +0 -100
  143. package/lib/generationCancel.ts +0 -28
  144. package/lib/generationErrors.ts +0 -238
  145. package/lib/grokImageAdapter.ts +0 -513
  146. package/lib/grokMultimodeAdapter.ts +0 -84
  147. package/lib/grokProxyLauncher.ts +0 -129
  148. package/lib/grokRuntime.ts +0 -23
  149. package/lib/grokSizeMapper.ts +0 -71
  150. package/lib/grokVideoAdapter.ts +0 -519
  151. package/lib/historyIndex.ts +0 -51
  152. package/lib/historyList.ts +0 -177
  153. package/lib/imageMetadata.ts +0 -113
  154. package/lib/imageMetadataStore.ts +0 -67
  155. package/lib/imageModels.ts +0 -165
  156. package/lib/inflight.ts +0 -281
  157. package/lib/localImportStore.ts +0 -114
  158. package/lib/logger.ts +0 -161
  159. package/lib/nodeStore.ts +0 -91
  160. package/lib/oauthLauncher.ts +0 -78
  161. package/lib/oauthNormalize.ts +0 -30
  162. package/lib/oauthProxy/errors.ts +0 -128
  163. package/lib/oauthProxy/generators.ts +0 -494
  164. package/lib/oauthProxy/index.ts +0 -28
  165. package/lib/oauthProxy/prompts.ts +0 -123
  166. package/lib/oauthProxy/references.ts +0 -45
  167. package/lib/oauthProxy/runtime.ts +0 -115
  168. package/lib/oauthProxy/streams.ts +0 -232
  169. package/lib/oauthProxy/types.ts +0 -9
  170. package/lib/oauthProxy.ts +0 -3
  171. package/lib/openDirectory.ts +0 -47
  172. package/lib/pngInfo.ts +0 -26
  173. package/lib/promptBuilder/attachments.ts +0 -74
  174. package/lib/promptBuilder/client.ts +0 -130
  175. package/lib/promptBuilder/constants.ts +0 -9
  176. package/lib/promptBuilder/context.ts +0 -36
  177. package/lib/promptBuilder/errors.ts +0 -12
  178. package/lib/promptBuilder/requestSchema.ts +0 -56
  179. package/lib/promptBuilder/responseParser.ts +0 -219
  180. package/lib/promptBuilder/systemPrompt.ts +0 -135
  181. package/lib/promptBuilder/transport.ts +0 -94
  182. package/lib/promptBuilder/types.ts +0 -109
  183. package/lib/promptImport/curatedSources.ts +0 -141
  184. package/lib/promptImport/discoveryRegistry.ts +0 -329
  185. package/lib/promptImport/errors.ts +0 -18
  186. package/lib/promptImport/githubDiscovery.ts +0 -309
  187. package/lib/promptImport/githubFolder.ts +0 -397
  188. package/lib/promptImport/githubSource.ts +0 -257
  189. package/lib/promptImport/gptImageHints.ts +0 -70
  190. package/lib/promptImport/parsePromptCandidates.ts +0 -179
  191. package/lib/promptImport/promptIndex.ts +0 -326
  192. package/lib/promptImport/rankPromptCandidates.ts +0 -65
  193. package/lib/promptImport/types.ts +0 -103
  194. package/lib/promptSafetyPolicy.ts +0 -5
  195. package/lib/providerOptions.ts +0 -56
  196. package/lib/referenceImageCompress.ts +0 -84
  197. package/lib/refs.ts +0 -133
  198. package/lib/requestLogger.ts +0 -49
  199. package/lib/responsesDoctor.ts +0 -456
  200. package/lib/responsesErrors.ts +0 -83
  201. package/lib/responsesFallback.ts +0 -114
  202. package/lib/responsesImageAdapter.ts +0 -466
  203. package/lib/responsesParse.ts +0 -452
  204. package/lib/responsesTools.ts +0 -28
  205. package/lib/runtimeContext.ts +0 -146
  206. package/lib/runtimePorts.ts +0 -105
  207. package/lib/sessionStore.ts +0 -308
  208. package/lib/storageMigration.ts +0 -310
  209. package/lib/styleSheet.ts +0 -139
  210. package/lib/systemTrash.ts +0 -20
  211. package/lib/videoSeriesChain.ts +0 -29
  212. package/lib/visibleTextLanguagePolicy.ts +0 -7
  213. package/routes/agent.ts +0 -308
  214. package/routes/annotations.ts +0 -118
  215. package/routes/canvasVersions.ts +0 -69
  216. package/routes/capabilities.ts +0 -18
  217. package/routes/cardNews.ts +0 -211
  218. package/routes/comfy.ts +0 -43
  219. package/routes/edit.ts +0 -352
  220. package/routes/generate.ts +0 -492
  221. package/routes/grok.ts +0 -24
  222. package/routes/health.ts +0 -123
  223. package/routes/history.ts +0 -221
  224. package/routes/imageImport.ts +0 -37
  225. package/routes/index.ts +0 -48
  226. package/routes/metadata.ts +0 -77
  227. package/routes/multimode.ts +0 -499
  228. package/routes/nodes.ts +0 -578
  229. package/routes/promptBuilder.ts +0 -37
  230. package/routes/promptImport.ts +0 -379
  231. package/routes/prompts.ts +0 -428
  232. package/routes/sessions.ts +0 -317
  233. package/routes/storage.ts +0 -47
  234. package/routes/video.ts +0 -232
  235. package/server.ts +0 -290
  236. package/ui/dist/assets/SettingsWorkspace-F3eNu3mJ.js +0 -1
  237. package/ui/dist/assets/index-B6tcw_UF.css +0 -1
  238. package/ui/dist/assets/index-DYOh6gQD.js +0 -32
  239. package/vendor/progrok-0.1.1.tgz +0 -0
@@ -1,266 +0,0 @@
1
- import { readFile } from "fs/promises";
2
- import { parseArgs, type ParsedArgs } from "../lib/args.js";
3
- import { resolveServer, request } from "../lib/client.js";
4
- import { out, die, color, json, exitCodeForError, table } from "../lib/output.js";
5
-
6
- const HELP = `
7
- ima2 session <subcommand> [options]
8
-
9
- Subcommands:
10
- ls [--json] List sessions
11
- show <id> [--json] Show session details
12
- create <title> Create a new session
13
- rm <id> [--yes] Delete a session
14
- rename <id> <title> Rename a session
15
- graph save <id> <file> Save graph JSON (uses If-Match for concurrency)
16
- graph load <id> [--out <file>] Load graph JSON (stdout or --out)
17
- style-sheet get <id> [--json]
18
- style-sheet put <id> <file> Replace full style sheet
19
- style-sheet enable <id>
20
- style-sheet disable <id>
21
- style-sheet extract <id> LLM-extract style sheet from session content
22
-
23
- Common options:
24
- --server <url> Override server URL
25
- --json JSON output
26
- --yes Skip destructive confirmation
27
- `;
28
-
29
- const COMMON_FLAGS = {
30
- json: { type: "boolean" },
31
- server: { type: "string" },
32
- yes: { type: "boolean" },
33
- out: { type: "string" },
34
- help: { short: "h", type: "boolean" },
35
- };
36
-
37
- async function getServer(args: ParsedArgs) {
38
- try { return await resolveServer({ serverFlag: args.server }); }
39
- catch (e: any) { die(exitCodeForError(e), e.message); throw e; }
40
- }
41
-
42
- async function lsSub(argv: string[]) {
43
- const args = parseArgs(argv, { flags: COMMON_FLAGS });
44
- const server = await getServer(args);
45
- const resp = await request(server.base, "/api/sessions").catch(handle);
46
- const sessions = resp.sessions || [];
47
- if (args.json) { json({ sessions }); return; }
48
- if (sessions.length === 0) { out(color.dim("(no sessions)")); return; }
49
- table(sessions, [
50
- { key: "id", label: "ID" },
51
- { key: "title", label: "TITLE" },
52
- { key: "createdAt", label: "WHEN", format: (v: unknown) => v ? new Date(v as string | number).toISOString().slice(0, 19) : "" },
53
- ]);
54
- }
55
-
56
- async function showSub(argv: string[]) {
57
- const args = parseArgs(argv, { flags: COMMON_FLAGS });
58
- const id = args.positional[0];
59
- if (!id) die(2, "session id required");
60
- const server = await getServer(args);
61
- const resp = await request(server.base, `/api/sessions/${encodeURIComponent(id)}`).catch(handle);
62
- if (args.json) { json(resp); return; }
63
- const s = resp.session || resp;
64
- out(color.bold(s.id || id));
65
- out(color.dim(" title: ") + (s.title || ""));
66
- if (s.graph) out(color.dim(" graph: ") + `${s.graph.nodes?.length ?? 0} nodes, ${s.graph.edges?.length ?? 0} edges, version ${s.graph.version}`);
67
- if (s.styleSheet) out(color.dim(" styleSheet: ") + (s.styleSheet.enabled ? "enabled" : "disabled"));
68
- }
69
-
70
- async function createSub(argv: string[]) {
71
- const args = parseArgs(argv, { flags: COMMON_FLAGS });
72
- const title = args.positional.join(" ").trim();
73
- if (!title) die(2, "title required");
74
- const server = await getServer(args);
75
- const resp = await request(server.base, "/api/sessions", {
76
- method: "POST",
77
- body: { title },
78
- }).catch(handle);
79
- if (args.json) { json(resp); return; }
80
- out(color.green("✓ ") + (resp.session?.id || "(no id returned)"));
81
- }
82
-
83
- async function rmSub(argv: string[]) {
84
- const args = parseArgs(argv, { flags: COMMON_FLAGS });
85
- const id = args.positional[0];
86
- if (!id) die(2, "session id required");
87
- if (!args.yes && !process.stdin.isTTY) die(2, "destructive: pass --yes for non-TTY");
88
- if (!args.yes) {
89
- process.stdout.write(`Delete session ${id}? [y/N] `);
90
- const ans = await readLine();
91
- if (!/^y(es)?$/i.test(ans.trim())) { out("(canceled)"); return; }
92
- }
93
- const server = await getServer(args);
94
- await request(server.base, `/api/sessions/${encodeURIComponent(id)}`, { method: "DELETE" }).catch(handle);
95
- out(color.green("✓ deleted"));
96
- }
97
-
98
- async function renameSub(argv: string[]) {
99
- const args = parseArgs(argv, { flags: COMMON_FLAGS });
100
- const [id, ...rest] = args.positional;
101
- const title = rest.join(" ").trim();
102
- if (!id || !title) die(2, "usage: session rename <id> <title>");
103
- const server = await getServer(args);
104
- await request(server.base, `/api/sessions/${encodeURIComponent(id)}`, {
105
- method: "PATCH",
106
- body: { title },
107
- }).catch(handle);
108
- out(color.green("✓ renamed"));
109
- }
110
-
111
- async function graphSub(argv: string[]) {
112
- const action = argv[0];
113
- const rest = argv.slice(1);
114
- if (action === "save") return graphSave(rest);
115
- if (action === "load") return graphLoad(rest);
116
- die(2, "usage: session graph <save|load> ...");
117
- }
118
-
119
- async function graphSave(argv: string[]) {
120
- const args = parseArgs(argv, { flags: COMMON_FLAGS });
121
- const [id, file] = args.positional;
122
- if (!id || !file) die(2, "usage: session graph save <id> <file>");
123
- const buf = await readFile(file, "utf-8");
124
- let parsed;
125
- try { parsed = JSON.parse(buf); } catch { die(2, "graph file is not valid JSON"); }
126
- const { nodes, edges } = parsed;
127
- if (!Array.isArray(nodes) || !Array.isArray(edges))
128
- die(2, "graph file must contain { nodes: [], edges: [] }");
129
- const server = await getServer(args);
130
- // Step 1: fetch current version
131
- const current: any = await request(server.base, `/api/sessions/${encodeURIComponent(id)}`).catch(handle);
132
- const version = current?.session?.graph?.version;
133
- if (typeof version !== "number") die(1, "could not resolve current graph version");
134
- // Step 2: PUT with If-Match
135
- try {
136
- const result: any = await request(server.base, `/api/sessions/${encodeURIComponent(id)}/graph`, {
137
- method: "PUT",
138
- body: { nodes, edges },
139
- headers: { "If-Match": `"${version}"` },
140
- });
141
- if (args.json) { json(result); return; }
142
- out(color.green(`✓ saved (graphVersion: ${result.graphVersion})`));
143
- } catch (e: any) {
144
- if (e.status === 412 || e.code === "GRAPH_VERSION_CONFLICT") die(1, "graph version conflict — fetch latest and retry");
145
- if (e.status === 413) die(1, e.message);
146
- handle(e);
147
- }
148
- }
149
-
150
- async function graphLoad(argv: string[]) {
151
- const args = parseArgs(argv, { flags: COMMON_FLAGS });
152
- const id = args.positional[0];
153
- if (!id) die(2, "usage: session graph load <id>");
154
- const server = await getServer(args);
155
- const resp: any = await request(server.base, `/api/sessions/${encodeURIComponent(id)}`).catch(handle);
156
- const graph = resp?.session?.graph;
157
- if (!graph) die(1, "no graph for session");
158
- const text = JSON.stringify(graph, null, 2);
159
- if (args.out) {
160
- const { writeFile } = await import("fs/promises");
161
- await writeFile(String(args.out), text);
162
- out(color.green("✓ ") + String(args.out));
163
- } else {
164
- process.stdout.write(text + "\n");
165
- }
166
- }
167
-
168
- async function styleSheetSub(argv: string[]) {
169
- const action = argv[0];
170
- const rest = argv.slice(1);
171
- if (action === "get") return ssGet(rest);
172
- if (action === "put") return ssPut(rest);
173
- if (action === "enable") return ssEnable(rest, true);
174
- if (action === "disable") return ssEnable(rest, false);
175
- if (action === "extract") return ssExtract(rest);
176
- die(2, "usage: session style-sheet <get|put|enable|disable|extract> ...");
177
- }
178
-
179
- async function ssGet(argv: string[]) {
180
- const args = parseArgs(argv, { flags: COMMON_FLAGS });
181
- const id = args.positional[0];
182
- if (!id) die(2, "session id required");
183
- const server = await getServer(args);
184
- const resp = await request(server.base, `/api/sessions/${encodeURIComponent(id)}/style-sheet`).catch(handle);
185
- json(resp);
186
- }
187
-
188
- async function ssPut(argv: string[]) {
189
- const args = parseArgs(argv, { flags: COMMON_FLAGS });
190
- const [id, file] = args.positional;
191
- if (!id || !file) die(2, "usage: session style-sheet put <id> <file>");
192
- const buf = await readFile(file, "utf-8");
193
- let parsed;
194
- try { parsed = JSON.parse(buf); } catch { die(2, "style-sheet file is not valid JSON"); }
195
- const server = await getServer(args);
196
- await request(server.base, `/api/sessions/${encodeURIComponent(id)}/style-sheet`, {
197
- method: "PUT",
198
- body: parsed,
199
- }).catch(handle);
200
- out(color.green("✓ style-sheet updated"));
201
- }
202
-
203
- async function ssEnable(argv: string[], enabled: boolean) {
204
- const args = parseArgs(argv, { flags: COMMON_FLAGS });
205
- const id = args.positional[0];
206
- if (!id) die(2, "session id required");
207
- const server = await getServer(args);
208
- await request(server.base, `/api/sessions/${encodeURIComponent(id)}/style-sheet/enabled`, {
209
- method: "PATCH",
210
- body: { enabled },
211
- }).catch(handle);
212
- out(color.green(enabled ? "✓ enabled" : "✓ disabled"));
213
- }
214
-
215
- async function ssExtract(argv: string[]) {
216
- const args = parseArgs(argv, { flags: COMMON_FLAGS });
217
- const id = args.positional[0];
218
- if (!id) die(2, "session id required");
219
- const server = await getServer(args);
220
- const resp = await request(server.base, `/api/sessions/${encodeURIComponent(id)}/style-sheet/extract`, {
221
- method: "POST",
222
- timeoutMs: 120_000,
223
- }).catch(handle);
224
- json(resp);
225
- }
226
-
227
- function handle(e: unknown) {
228
- const err = e as { message?: string; code?: string };
229
- die(exitCodeForError(e), `${err.message}${err.code ? ` (${err.code})` : ""}`);
230
- }
231
-
232
- async function readLine(): Promise<string> {
233
- return new Promise((resolve) => {
234
- let buf = "";
235
- process.stdin.setEncoding("utf-8");
236
- const onData = (chunk: Buffer | string) => {
237
- buf += chunk;
238
- const nl = buf.indexOf("\n");
239
- if (nl !== -1) {
240
- process.stdin.removeListener("data", onData);
241
- process.stdin.pause();
242
- resolve(buf.slice(0, nl));
243
- }
244
- };
245
- process.stdin.resume();
246
- process.stdin.on("data", onData);
247
- });
248
- }
249
-
250
- const SUB: Record<string, (argv: any[]) => Promise<void>> = {
251
- ls: lsSub,
252
- show: showSub,
253
- create: createSub,
254
- rm: rmSub,
255
- rename: renameSub,
256
- graph: graphSub,
257
- "style-sheet": styleSheetSub,
258
- };
259
-
260
- export default async function sessionCmd(argv: string[]) {
261
- const sub = argv[0];
262
- if (!sub || sub === "--help" || sub === "-h") { out(HELP); return; }
263
- const handler = SUB[sub];
264
- if (!handler) die(2, `unknown subcommand: ${sub}\n${HELP}`);
265
- return handler(argv.slice(1));
266
- }
@@ -1,72 +0,0 @@
1
- import { parseArgs } from "../lib/args.js";
2
- import { resolveServer, request } from "../lib/client.js";
3
- import { openUrl } from "../lib/platform.js";
4
- import { out, die, color, json, exitCodeForError } from "../lib/output.js";
5
- import { fileToDataUri } from "../lib/files.js";
6
- import { config } from "../../config.js";
7
-
8
- import { errInfo } from "../../lib/errInfo.js";
9
- const SPEC = {
10
- flags: {
11
- json: { type: "boolean" },
12
- reveal: { type: "boolean" },
13
- metadata: { type: "boolean" },
14
- server: { type: "string" },
15
- help: { short: "h", type: "boolean" },
16
- },
17
- };
18
-
19
- export default async function showCmd(argv: string[]) {
20
- const args = parseArgs(argv, SPEC);
21
- if (args.help) { out("ima2 show <filename> [--json] [--reveal] [--metadata]"); return; }
22
- const name = args.positional[0];
23
- if (!name) die(2, "filename required");
24
-
25
- let server;
26
- try { server = await resolveServer({ serverFlag: args.server }); }
27
- catch (e) {
28
- const err = errInfo(e); die(exitCodeForError(e), err.message); }
29
-
30
- let resp;
31
- try { resp = await request(server.base, "/api/history"); }
32
- catch (e) {
33
- const err = errInfo(e); die(exitCodeForError(e), err.message); }
34
-
35
- const items: Record<string, any>[] = resp.items || resp.history || [];
36
- const item = items.find((it: Record<string, any>) => it.filename === name || (it.filename && it.filename.endsWith(name)));
37
- if (!item) die(1, `not found: ${name}`);
38
-
39
- let metadata: any = null;
40
- if (args.metadata) {
41
- try {
42
- const dataUrl = await fileToDataUri(`${config.storage.generatedDir}/${item.filename}`);
43
- metadata = await request(server.base, "/api/metadata/read", {
44
- method: "POST",
45
- body: { dataUrl },
46
- });
47
- } catch (e: any) {
48
- out(color.dim(`(metadata unavailable: ${e?.message || e})`));
49
- }
50
- }
51
-
52
- if (args.json) { json(args.metadata ? { ...item, metadata } : item); }
53
- else {
54
- out(color.bold(item.filename));
55
- out(color.dim(` prompt:`) + ` ${item.prompt || ""}`);
56
- out(color.dim(` size:`) + ` ${item.size || ""} quality: ${item.quality || ""}`);
57
- if (item.createdAt) out(color.dim(` when:`) + ` ${new Date(item.createdAt).toISOString()}`);
58
- if (item.url) out(color.dim(` url:`) + ` ${server.base}${item.url}`);
59
- if (metadata) {
60
- out(color.dim(` metadata:`));
61
- const dump = JSON.stringify(metadata, null, 2).split("\n").map(l => " " + l).join("\n");
62
- out(dump);
63
- }
64
- }
65
-
66
- if (args.reveal) {
67
- const url = item.url ? `${server.base}${item.url}` : null;
68
- if (!url) { out(color.yellow("(no url)")); return; }
69
- const res = openUrl(url);
70
- if (!res.ok) out(color.yellow("(could not reveal)"));
71
- }
72
- }
@@ -1,70 +0,0 @@
1
- import { existsSync, readFileSync } from "fs";
2
- import { dirname, join, relative } from "path";
3
- import { fileURLToPath } from "url";
4
- import { parseArgs } from "../lib/args.js";
5
- import { die, json, out } from "../lib/output.js";
6
-
7
- const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
8
- const SKILL_PATH = join(ROOT, "skills", "ima2", "SKILL.md");
9
- const PACKAGE_PATH = join(ROOT, "package.json");
10
-
11
- const HELP = `
12
- ima2 skill [path] [--json]
13
-
14
- Print the packaged ima2 Markdown skill for agents.
15
-
16
- Commands:
17
- ima2 skill Print skills/ima2/SKILL.md
18
- ima2 skill path Print resolved skill path
19
- ima2 skill --json Print a JSON wrapper around the Markdown skill
20
- `;
21
-
22
- const FLAGS = {
23
- json: { type: "boolean" },
24
- help: { short: "h", type: "boolean" },
25
- };
26
-
27
- function readPackageVersion(): string {
28
- try {
29
- const pkg = JSON.parse(readFileSync(PACKAGE_PATH, "utf-8")) as { version?: string };
30
- return pkg.version || "?";
31
- } catch {
32
- return "?";
33
- }
34
- }
35
-
36
- function readSkill(): string {
37
- if (!existsSync(SKILL_PATH)) {
38
- die(5, `packaged skill not found: ${SKILL_PATH}`);
39
- }
40
- return readFileSync(SKILL_PATH, "utf-8");
41
- }
42
-
43
- export default async function skillCmd(argv: string[]) {
44
- const args = parseArgs(argv, { flags: FLAGS });
45
- if (args.help) {
46
- out(HELP);
47
- return;
48
- }
49
-
50
- if (args.positional[0] === "path") {
51
- out(SKILL_PATH);
52
- return;
53
- }
54
-
55
- const content = readSkill();
56
- if (args.json) {
57
- json({
58
- name: "ima2",
59
- format: "markdown-skill",
60
- formatVersion: "1",
61
- packageVersion: readPackageVersion(),
62
- path: relative(ROOT, SKILL_PATH),
63
- source: "package",
64
- content,
65
- });
66
- return;
67
- }
68
-
69
- out(content.replace(/\n$/, ""));
70
- }
@@ -1,205 +0,0 @@
1
- import { parseArgs } from "../lib/args.js";
2
- import { resolveServer } from "../lib/client.js";
3
- import { streamSse } from "../lib/sse.js";
4
- import { out, die, color, json, exitCodeForError } from "../lib/output.js";
5
- import { config } from "../../config.js";
6
- import { readFile, writeFile, mkdir } from "node:fs/promises";
7
- import { dirname, join } from "node:path";
8
-
9
- const VALID_RESOLUTIONS = new Set(["480p", "720p"]);
10
- const VALID_ASPECT_RATIOS = new Set(["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3", "auto"]);
11
- const VALID_MODELS = new Set(["grok-imagine-video", "grok-imagine-video-1.5-preview"]);
12
-
13
- const SPEC = {
14
- flags: {
15
- duration: { type: "string", default: "5" },
16
- resolution: { type: "string", default: "480p" },
17
- "aspect-ratio": { type: "string", default: "auto" },
18
- model: { type: "string" },
19
- topic: { type: "string" },
20
- ref: { type: "string", repeatable: true },
21
- out: { short: "o", type: "string" },
22
- "out-dir": { short: "d", type: "string" },
23
- json: { type: "boolean" },
24
- timeout: { type: "string", default: "600" },
25
- server: { type: "string" },
26
- session: { type: "string" },
27
- help: { short: "h", type: "boolean" },
28
- },
29
- };
30
-
31
- const HELP = `
32
- ima2 video <prompt...> [options]
33
-
34
- Generate a video via the Grok video provider (SSE streaming).
35
-
36
- Options:
37
- --duration <1..15> Duration in seconds. Default: 5
38
- --resolution <480p|720p> Default: 480p
39
- --aspect-ratio <ratio|auto> 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, auto. Default: auto
40
- --model <name> grok-imagine-video, grok-imagine-video-1.5-preview
41
- --topic <text> Series topic for prompt chain continuity
42
- --ref <file> Attach source/reference image (repeatable, max 7)
43
- -o, --out <file> Output file path
44
- -d, --out-dir <dir> Output directory
45
- --json Print JSON result to stdout
46
- --timeout <sec> Default: 600
47
- --server <url> Override server URL
48
- --session <id> Session ID
49
-
50
- Modes (auto-detected from --ref count):
51
- 0 refs → text-to-video
52
- 1 ref → image-to-video
53
- 2-7 refs → reference-to-video (max 10s duration)
54
-
55
- Examples:
56
- ima2 video "a cat playing piano"
57
- ima2 video "animate this" --ref photo.png --duration 10
58
- ima2 video "cinematic" --resolution 720p --aspect-ratio 16:9 -o out.mp4
59
- `;
60
-
61
- export default async function videoCmd(argv: string[]) {
62
- const args = parseArgs(argv, SPEC);
63
- if (args.help) { out(HELP); return; }
64
-
65
- const prompt = args.positional.join(" ");
66
- if (!prompt) die(2, "prompt is required");
67
-
68
- const duration = parseInt(String(args.duration)) || 5;
69
- if (duration < 1 || duration > 15) die(2, "--duration must be between 1 and 15");
70
-
71
- const resolution = String(args.resolution);
72
- if (!VALID_RESOLUTIONS.has(resolution)) die(2, "--resolution must be one of: 480p, 720p");
73
-
74
- const aspectRatio = String(args["aspect-ratio"]);
75
- if (!VALID_ASPECT_RATIOS.has(aspectRatio)) die(2, "--aspect-ratio must be one of: 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, auto");
76
-
77
- if (args.model && !VALID_MODELS.has(String(args.model))) {
78
- die(2, "--model must be one of: grok-imagine-video, grok-imagine-video-1.5-preview");
79
- }
80
-
81
- const refs = (Array.isArray(args.ref) ? args.ref : []) as string[];
82
- if (refs.length > 7) die(2, "max 7 --ref attachments for video");
83
-
84
- let server;
85
- try { server = await resolveServer({ serverFlag: args.server }); }
86
- catch (e: unknown) { die(exitCodeForError(e), (e as Error).message); throw e; }
87
-
88
- const referenceImages = await Promise.all(refs.map(async (p: string) => {
89
- const buf = await readFile(p);
90
- return buf.toString("base64");
91
- }));
92
-
93
- const timeoutMs = (parseInt(String(args.timeout)) || 600) * 1000;
94
- const requestId = `req_cli_video_${Date.now().toString(36)}`;
95
-
96
- const body: Record<string, unknown> = {
97
- prompt,
98
- provider: "grok",
99
- duration,
100
- resolution,
101
- aspectRatio,
102
- requestId,
103
- };
104
- if (args.model) body.model = args.model;
105
- if (args.session) body.sessionId = args.session;
106
- if (args.topic) body.topic = args.topic;
107
- if (referenceImages.length === 1) {
108
- body.sourceImage = referenceImages[0];
109
- } else if (referenceImages.length > 1) {
110
- body.referenceImages = referenceImages;
111
- }
112
-
113
- const ac = new AbortController();
114
- let timedOut = false;
115
- const timeoutTimer = setTimeout(() => { timedOut = true; ac.abort(); }, timeoutMs);
116
- const onSig = () => { ac.abort(); process.exit(130); };
117
- process.once("SIGINT", onSig);
118
- process.once("SIGTERM", onSig);
119
-
120
- const url = `${server.base}/api/video/generate`;
121
- let doneData: Record<string, unknown> | null = null;
122
- let lastProgress = -1;
123
-
124
- try {
125
- for await (const ev of streamSse(url, { body, signal: ac.signal, headers: { "X-Request-Id": requestId } })) {
126
- switch (ev.event) {
127
- case "planning":
128
- if (!args.json) out(color.dim("[planning] preparing video generation..."));
129
- break;
130
- case "submitted":
131
- if (!args.json) out(color.dim(`[submitted] xai request: ${ev.data.xaiVideoRequestId || "..."}`));
132
- break;
133
- case "progress": {
134
- const pct = typeof ev.data.progress === "number" ? Math.round(ev.data.progress * 100) : null;
135
- if (pct !== null && pct !== lastProgress && !args.json) {
136
- const bar = renderBar(pct);
137
- process.stdout.write(`\r ${bar} ${pct}%`);
138
- lastProgress = pct;
139
- }
140
- break;
141
- }
142
- case "done":
143
- if (!args.json && lastProgress >= 0) process.stdout.write("\n");
144
- doneData = ev.data;
145
- break;
146
- case "error":
147
- if (!args.json && lastProgress >= 0) process.stdout.write("\n");
148
- die(1, `video error: ${ev.data.error || ev.data}${ev.data.code ? ` (${ev.data.code})` : ""}`);
149
- }
150
- }
151
- } catch (e: unknown) {
152
- if ((e as Error).name === "AbortError" && !timedOut) return;
153
- if (!args.json && lastProgress >= 0) process.stdout.write("\n");
154
- die(exitCodeForError(e), (e as Error).message);
155
- } finally {
156
- clearTimeout(timeoutTimer);
157
- process.off("SIGINT", onSig);
158
- process.off("SIGTERM", onSig);
159
- }
160
-
161
- if (!doneData?.filename) die(1, "server did not return a video filename");
162
-
163
- // Determine output path
164
- const filename = String(doneData.filename);
165
- const explicitOut = args.out ? String(args.out) : null;
166
- const outDir = args["out-dir"] ? String(args["out-dir"]) : null;
167
- let target: string;
168
- if (explicitOut) {
169
- target = explicitOut;
170
- } else if (outDir) {
171
- target = join(outDir, filename);
172
- } else {
173
- target = join(config.storage.generatedDir, filename);
174
- }
175
-
176
- // Download the video file from server
177
- const videoUrl = `${server.base}${doneData.url || `/generated/${encodeURIComponent(filename)}`}`;
178
- const dlRes = await fetch(videoUrl, { signal: AbortSignal.timeout(30_000) });
179
- if (!dlRes.ok) die(1, `failed to download video: HTTP ${dlRes.status}`);
180
- const videoBuf = Buffer.from(await dlRes.arrayBuffer());
181
- await mkdir(dirname(target), { recursive: true }).catch(() => {});
182
- await writeFile(target, videoBuf);
183
-
184
- if (args.json) {
185
- json({
186
- ok: true,
187
- requestId: doneData.requestId,
188
- path: target,
189
- filename,
190
- elapsed: doneData.elapsed,
191
- video: doneData.video,
192
- revisedPrompt: doneData.revisedPrompt,
193
- });
194
- } else {
195
- out(color.green("✓ ") + target);
196
- if (doneData.elapsed) out(color.dim(`elapsed ${doneData.elapsed}s`));
197
- if (doneData.revisedPrompt) out(color.dim(`revised: ${String(doneData.revisedPrompt).slice(0, 80)}`));
198
- }
199
- }
200
-
201
- function renderBar(pct: number): string {
202
- const width = 20;
203
- const filled = Math.round((pct / 100) * width);
204
- return color.green("█".repeat(filled)) + color.dim("░".repeat(width - filled));
205
- }