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
@@ -1247,101 +1247,200 @@ function imageToDataUri(filePath) {
1247
1247
  const ext = abs.toLowerCase().endsWith(".png") ? "png" : "jpeg";
1248
1248
  return `data:image/${ext};base64,${buf.toString("base64")}`;
1249
1249
  }
1250
+ async function pollUntilDone(requestId, bearer, timeout, json) {
1251
+ const deadline = Date.now() + timeout;
1252
+ let lastProgress = -1;
1253
+ while (Date.now() < deadline) {
1254
+ await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
1255
+ const poll = await fetch(`${XAI_API_BASE_URL}/videos/${requestId}`, {
1256
+ headers: { Authorization: `Bearer ${bearer}` }
1257
+ });
1258
+ if (!poll.ok) {
1259
+ throw new Error(`Poll HTTP ${poll.status}: ${(await poll.text()).slice(0, 200)}`);
1260
+ }
1261
+ const data = await poll.json();
1262
+ const status = data.status;
1263
+ if (status === "done") return data;
1264
+ if (status === "failed") {
1265
+ const err = data.error;
1266
+ throw new Error(`Generation failed: ${err?.code ?? "unknown"} \u2014 ${err?.message ?? ""}`);
1267
+ }
1268
+ if (status === "expired") throw new Error("Generation expired");
1269
+ if (!json && typeof data.progress === "number" && data.progress !== lastProgress) {
1270
+ lastProgress = data.progress;
1271
+ process.stdout.write(`\r Progress: ${Math.round(lastProgress * 100)}%`);
1272
+ }
1273
+ }
1274
+ throw new Error(`Timeout after ${timeout / 1e3}s \u2014 video still pending`);
1275
+ }
1276
+ async function downloadAndSave(videoUrl, outPath) {
1277
+ const videoRes = await fetch(videoUrl);
1278
+ if (!videoRes.ok) throw new Error(`Download failed: HTTP ${videoRes.status}`);
1279
+ const videoBuffer = Buffer.from(await videoRes.arrayBuffer());
1280
+ writeFileSync2(outPath, videoBuffer);
1281
+ }
1250
1282
  function videoCommand() {
1251
- return new Command10("video").description(
1252
- `Generate video with Grok Imagine Video (T2V / I2V).
1253
- Async: submits generation, polls until done, downloads result.
1283
+ const cmd = new Command10("video").description(
1284
+ `Generate, edit, or extend video with Grok Imagine Video.
1285
+
1286
+ Subcommands:
1287
+ generate (default) Text-to-video or image-to-video
1288
+ edit Edit existing video with text prompt (V2V)
1289
+ extend Continue video from its last frame
1254
1290
 
1255
1291
  Examples:
1256
1292
  $ progrok video "A cat playing piano"
1257
- $ progrok video "Animate this photo" --image photo.jpg
1258
- $ progrok video "prompt" --model grok-imagine-video-1.5-preview --duration 10`
1259
- ).argument("<prompt>", "video generation prompt").option("--model <id>", "video model", DEFAULT_VIDEO_MODEL).option("--duration <s>", "duration in seconds (1-15)", "5").option("--aspect <ratio>", "aspect ratio", "16:9").option("--resolution <r>", "480p or 720p", "480p").option("--image <path>", "source image for image-to-video").option("--output <path>", "output file path").option("--json", "output structured JSON").option("--timeout <s>", "polling timeout in seconds", "600").action(async (prompt, opts) => {
1260
- try {
1261
- const bearer = await getValidBearer();
1262
- const duration = parseInt(opts.duration ?? "5", 10);
1263
- const timeout = parseInt(opts.timeout ?? "600", 10) * 1e3;
1264
- const body = {
1265
- model: opts.model ?? DEFAULT_VIDEO_MODEL,
1266
- prompt,
1267
- duration,
1268
- aspect_ratio: opts.aspect ?? "16:9",
1269
- resolution: opts.resolution ?? "480p"
1270
- };
1271
- if (opts.image) {
1272
- const uri = opts.image.startsWith("data:") ? opts.image : imageToDataUri(opts.image);
1273
- body.image = { url: uri };
1274
- } else if (opts.model?.includes("1.5") && !opts.image) {
1275
- body.image = { url: WHITE_PIXEL_PNG };
1276
- body.prompt = `${prompt}
1293
+ $ progrok video "Animate this" --image photo.jpg
1294
+ $ progrok video edit "Make it sunset colors" --video input.mp4
1295
+ $ progrok video extend "Camera pulls back slowly" --video input.mp4 --duration 5`
1296
+ );
1297
+ cmd.argument("[prompt]", "video generation prompt").option("--model <id>", "video model", DEFAULT_VIDEO_MODEL).option("--duration <s>", "duration in seconds (1-15)", "5").option("--aspect <ratio>", "aspect ratio", "16:9").option("--resolution <r>", "480p or 720p", "480p").option("--image <path>", "source image for image-to-video").option("--output <path>", "output file path").option("--json", "output structured JSON").option("--timeout <s>", "polling timeout in seconds", "600").action(async (prompt, opts) => {
1298
+ if (!prompt) {
1299
+ cmd.help();
1300
+ return;
1301
+ }
1302
+ await generateAction(prompt, opts);
1303
+ });
1304
+ cmd.command("edit <prompt>").description("Edit existing video with a text prompt (real V2V). Model: grok-imagine-video only.").requiredOption("--video <url-or-path>", "source video URL or local .mp4 path").option("--model <id>", "video model (must be grok-imagine-video)", DEFAULT_VIDEO_MODEL).option("--output <path>", "output file path").option("--json", "output structured JSON").option("--timeout <s>", "polling timeout in seconds", "600").action(async (prompt, opts) => {
1305
+ await editAction(prompt, opts);
1306
+ });
1307
+ cmd.command("extend <prompt>").description("Extend video from its last frame. Model: grok-imagine-video only.").requiredOption("--video <url-or-path>", "source video URL or local .mp4 path").option("--model <id>", "video model (must be grok-imagine-video)", DEFAULT_VIDEO_MODEL).option("--duration <s>", "extension duration 2-10s (default 6)", "6").option("--output <path>", "output file path").option("--json", "output structured JSON").option("--timeout <s>", "polling timeout in seconds", "600").action(async (prompt, opts) => {
1308
+ await extendAction(prompt, opts);
1309
+ });
1310
+ return cmd;
1311
+ }
1312
+ async function generateAction(prompt, opts) {
1313
+ try {
1314
+ const bearer = await getValidBearer();
1315
+ const duration = parseInt(opts.duration ?? "5", 10);
1316
+ const timeout = parseInt(opts.timeout ?? "600", 10) * 1e3;
1317
+ const body = {
1318
+ model: opts.model ?? DEFAULT_VIDEO_MODEL,
1319
+ prompt,
1320
+ duration,
1321
+ aspect_ratio: opts.aspect ?? "16:9",
1322
+ resolution: opts.resolution ?? "480p"
1323
+ };
1324
+ if (opts.image) {
1325
+ const uri = opts.image.startsWith("data:") ? opts.image : imageToDataUri(opts.image);
1326
+ body.image = { url: uri };
1327
+ } else if (opts.model?.includes("1.5") && !opts.image) {
1328
+ body.image = { url: WHITE_PIXEL_PNG };
1329
+ body.prompt = `${prompt}
1277
1330
 
1278
1331
  This is not a start frame \u2014 generate freely as a new video.`;
1279
- }
1280
- const res = await fetch(`${XAI_API_BASE_URL}/videos/generations`, {
1281
- method: "POST",
1282
- headers: {
1283
- Authorization: `Bearer ${bearer}`,
1284
- "Content-Type": "application/json"
1285
- },
1286
- body: JSON.stringify(body)
1287
- });
1288
- if (!res.ok) {
1289
- const errBody = await res.text();
1290
- throw new Error(`HTTP ${res.status}: ${errBody.slice(0, 300)}`);
1291
- }
1292
- const { request_id } = await res.json();
1293
- if (!opts.json) {
1294
- log.info(`Video generation started (${request_id})`);
1295
- log.dim(`Model: ${body.model} | ${duration}s | ${opts.aspect} | ${opts.resolution}`);
1296
- }
1297
- const deadline = Date.now() + timeout;
1298
- let lastProgress = -1;
1299
- while (Date.now() < deadline) {
1300
- await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
1301
- const poll = await fetch(`${XAI_API_BASE_URL}/videos/${request_id}`, {
1302
- headers: { Authorization: `Bearer ${bearer}` }
1303
- });
1304
- if (!poll.ok) {
1305
- throw new Error(`Poll HTTP ${poll.status}: ${(await poll.text()).slice(0, 200)}`);
1306
- }
1307
- const data = await poll.json();
1308
- if (data.status === "done" && data.video) {
1309
- if (opts.json) {
1310
- console.log(JSON.stringify(data, null, 2));
1311
- return;
1312
- }
1313
- const videoRes = await fetch(data.video.url);
1314
- if (!videoRes.ok) throw new Error(`Download failed: HTTP ${videoRes.status}`);
1315
- const videoBuffer = Buffer.from(await videoRes.arrayBuffer());
1316
- const outPath = opts.output ?? `progrok-video-${request_id.slice(0, 8)}.mp4`;
1317
- writeFileSync2(outPath, videoBuffer);
1318
- log.success(`
1319
- Video saved: ${outPath}`);
1320
- log.info(`Duration: ${data.video.duration}s`);
1321
- if (data.usage?.cost_in_usd_ticks) {
1322
- log.dim(`Cost: $${(data.usage.cost_in_usd_ticks / 1e10).toFixed(4)}`);
1323
- }
1324
- return;
1325
- }
1326
- if (data.status === "failed") {
1327
- throw new Error(
1328
- `Generation failed: ${data.error?.code ?? "unknown"} \u2014 ${data.error?.message ?? ""}`
1329
- );
1330
- }
1331
- if (data.status === "expired") {
1332
- throw new Error("Generation expired");
1333
- }
1334
- if (!opts.json && data.progress !== void 0 && data.progress !== lastProgress) {
1335
- lastProgress = data.progress;
1336
- process.stdout.write(`\r Progress: ${Math.round(data.progress * 100)}%`);
1337
- }
1338
- }
1339
- throw new Error(`Timeout after ${timeout / 1e3}s \u2014 video still pending`);
1340
- } catch (err) {
1341
- log.error(err.message);
1342
- process.exit(1);
1343
1332
  }
1344
- });
1333
+ const res = await fetch(`${XAI_API_BASE_URL}/videos/generations`, {
1334
+ method: "POST",
1335
+ headers: { Authorization: `Bearer ${bearer}`, "Content-Type": "application/json" },
1336
+ body: JSON.stringify(body)
1337
+ });
1338
+ if (!res.ok) throw new Error(`HTTP ${res.status}: ${(await res.text()).slice(0, 300)}`);
1339
+ const { request_id } = await res.json();
1340
+ if (!opts.json) {
1341
+ log.info(`Video generation started (${request_id})`);
1342
+ log.dim(`Model: ${body.model} | ${duration}s | ${opts.aspect} | ${opts.resolution}`);
1343
+ }
1344
+ const data = await pollUntilDone(request_id, bearer, timeout, opts.json);
1345
+ if (opts.json) {
1346
+ console.log(JSON.stringify(data, null, 2));
1347
+ return;
1348
+ }
1349
+ const video = data.video;
1350
+ if (!video) throw new Error("No video in response");
1351
+ const outPath = opts.output ?? `progrok-video-${request_id.slice(0, 8)}.mp4`;
1352
+ await downloadAndSave(video.url, outPath);
1353
+ if (!opts.json) process.stdout.write("\n");
1354
+ log.success(`Video saved: ${outPath}`);
1355
+ log.info(`Duration: ${video.duration}s`);
1356
+ const usage = data.usage;
1357
+ if (usage?.cost_in_usd_ticks) log.dim(`Cost: $${(usage.cost_in_usd_ticks / 1e10).toFixed(4)}`);
1358
+ } catch (err) {
1359
+ log.error(err.message);
1360
+ process.exit(1);
1361
+ }
1362
+ }
1363
+ async function editAction(prompt, opts) {
1364
+ try {
1365
+ const bearer = await getValidBearer();
1366
+ const timeout = parseInt(opts.timeout ?? "600", 10) * 1e3;
1367
+ const model = opts.model ?? DEFAULT_VIDEO_MODEL;
1368
+ if (model.includes("1.5")) {
1369
+ throw new Error("Video editing is only supported by grok-imagine-video (not 1.5-preview).");
1370
+ }
1371
+ const videoUrl = opts.video.startsWith("http") ? opts.video : (() => {
1372
+ throw new Error("--video must be a URL (local file upload not yet supported for editing).");
1373
+ })();
1374
+ const res = await fetch(`${XAI_API_BASE_URL}/videos/edits`, {
1375
+ method: "POST",
1376
+ headers: { Authorization: `Bearer ${bearer}`, "Content-Type": "application/json" },
1377
+ body: JSON.stringify({ model, prompt, video: { url: videoUrl } })
1378
+ });
1379
+ if (!res.ok) throw new Error(`HTTP ${res.status}: ${(await res.text()).slice(0, 300)}`);
1380
+ const { request_id } = await res.json();
1381
+ if (!opts.json) {
1382
+ log.info(`Video edit started (${request_id})`);
1383
+ log.dim(`Model: ${model} | Edit: "${prompt.slice(0, 60)}"`);
1384
+ }
1385
+ const data = await pollUntilDone(request_id, bearer, timeout, opts.json);
1386
+ if (opts.json) {
1387
+ console.log(JSON.stringify(data, null, 2));
1388
+ return;
1389
+ }
1390
+ const video = data.video;
1391
+ if (!video) throw new Error("No video in response");
1392
+ const outPath = opts.output ?? `progrok-edit-${request_id.slice(0, 8)}.mp4`;
1393
+ await downloadAndSave(video.url, outPath);
1394
+ if (!opts.json) process.stdout.write("\n");
1395
+ log.success(`Edited video saved: ${outPath}`);
1396
+ log.info(`Duration: ${video.duration}s`);
1397
+ } catch (err) {
1398
+ log.error(err.message);
1399
+ process.exit(1);
1400
+ }
1401
+ }
1402
+ async function extendAction(prompt, opts) {
1403
+ try {
1404
+ const bearer = await getValidBearer();
1405
+ const timeout = parseInt(opts.timeout ?? "600", 10) * 1e3;
1406
+ const duration = parseInt(opts.duration ?? "6", 10);
1407
+ const model = opts.model ?? DEFAULT_VIDEO_MODEL;
1408
+ if (model.includes("1.5")) {
1409
+ throw new Error("Video extension is only supported by grok-imagine-video (not 1.5-preview).");
1410
+ }
1411
+ if (duration < 2 || duration > 10) {
1412
+ throw new Error("Extension duration must be 2-10 seconds.");
1413
+ }
1414
+ const videoUrl = opts.video.startsWith("http") ? opts.video : (() => {
1415
+ throw new Error("--video must be a URL (local file upload not yet supported for extension).");
1416
+ })();
1417
+ const res = await fetch(`${XAI_API_BASE_URL}/videos/extensions`, {
1418
+ method: "POST",
1419
+ headers: { Authorization: `Bearer ${bearer}`, "Content-Type": "application/json" },
1420
+ body: JSON.stringify({ model, prompt, duration, video: { url: videoUrl } })
1421
+ });
1422
+ if (!res.ok) throw new Error(`HTTP ${res.status}: ${(await res.text()).slice(0, 300)}`);
1423
+ const { request_id } = await res.json();
1424
+ if (!opts.json) {
1425
+ log.info(`Video extension started (${request_id})`);
1426
+ log.dim(`Model: ${model} | Extend: +${duration}s | "${prompt.slice(0, 60)}"`);
1427
+ }
1428
+ const data = await pollUntilDone(request_id, bearer, timeout, opts.json);
1429
+ if (opts.json) {
1430
+ console.log(JSON.stringify(data, null, 2));
1431
+ return;
1432
+ }
1433
+ const video = data.video;
1434
+ if (!video) throw new Error("No video in response");
1435
+ const outPath = opts.output ?? `progrok-extend-${request_id.slice(0, 8)}.mp4`;
1436
+ await downloadAndSave(video.url, outPath);
1437
+ if (!opts.json) process.stdout.write("\n");
1438
+ log.success(`Extended video saved: ${outPath}`);
1439
+ log.info(`Total duration: ${video.duration}s (original + ${duration}s extension)`);
1440
+ } catch (err) {
1441
+ log.error(err.message);
1442
+ process.exit(1);
1443
+ }
1345
1444
  }
1346
1445
 
1347
1446
  // src/commands/image.ts