feat(grok): add image command for grok.com image generation#906
feat(grok): add image command for grok.com image generation#906flizzywine wants to merge 1 commit intojackwener:mainfrom
Conversation
Add `opencli grok image <prompt>` which submits a prompt via the existing grok.com browser session and returns the generated image URLs from the latest assistant bubble. Because assets.grok.com URLs are gated by Cloudflare and cannot be downloaded with a plain HTTP client, the --out flag triggers an in-page fetch(credentials: 'include') so the browser session's cookies and referer are attached, then writes the decoded blob to disk. Flags: - --new start a fresh chat before sending - --timeout max seconds to wait for the image (default 240) - --count minimum number of images to wait for before returning - --out directory to save downloaded images Ships with unit tests for the helpers (isOnGrok, normalizeBooleanFlag, dedupeBySrc, imagesSignature, extFromContentType, buildFilename).
|
I think On a cold session right after |
|
I think Right now the image loop polls I would capture a baseline bubble count/signature before |
Summary
Adds
opencli grok image <prompt>, a new command that submits a prompt via the existing grok.com browser session and returns the generated image URLs from the latest assistant message bubble. Optionally downloads the images to a local directory.This is a natural complement to the existing
grok askcommand: the currentaskonly extractsinnerTextfrom the latest bubble, so when Grok's response is an image the command silently returns an empty / truncated string.grok imagescrapes<img>elements from the same bubble instead.Design notes
ask.ts— it prefers the ProseMirror composer (.ProseMirror[contenteditable="true"]) when available and falls back to the legacy<textarea>flow otherwise.readLastBubbleImages(page)every ~3s and returns once the set of image URLs has been stable across two consecutive reads. This mirrors theaskstabilization logic.assets.grok.com/users/.../image.jpgis gated by Cloudflare; plain HTTP clients (curl, node-fetch) receiveHTTP 403. When--out <dir>is provided, the command performs the fetch inside the page viafetch(url, { credentials: 'include', referrer: 'https://grok.com/' }), converts the blob to base64, and writes the decoded bytes to disk from Node. This is the minimal-viable way to bypass the auth without juggling cookie jars.naturalWidth < 128are dropped so UI chrome inside the bubble doesn't pollute the output.Flags
prompt(positional)--newfalse--timeout240--count1--out""Columns:
url,width,height,path.Test plan
npx tsc --noEmit— cleannpx vitest run --project unit— 579 passed, 1 skipped (no regressions)npx vitest run clis/grok/image.test.ts— 9 passed (new tests forisOnGrok,normalizeBooleanFlag,dedupeBySrc,imagesSignature,extFromContentType,buildFilename)opencli grok image "a cyberpunk mechanical owl, neon purple and blue" --new true --out /tmp/grok-img --timeout 300 --format json— returned apathpointing at a valid 784×1168 JPEG on disk.No new runtime dependencies.