egaki 0.2.0 → 0.4.0

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,76 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## 0.4.0
6
+
7
+ 1. **ChatGPT login for OpenAI image generation** — use your ChatGPT subscription in `egaki` without a separate OpenAI platform API key:
8
+
9
+ ```bash
10
+ egaki login --provider chatgpt
11
+ egaki image "a dreamy studio ghibli style bakery at sunrise" -m gpt-image-1.5 -o bakery.png
12
+ ```
13
+
14
+ OpenAI image requests authenticated this way now follow the same Codex backend flow used by ChatGPT instead of the normal Image API path.
15
+
16
+ 2. **ChatGPT-backed image editing** — edit existing images with OpenAI image models through the ChatGPT/Codex backend:
17
+
18
+ ```bash
19
+ egaki image "change the red jacket to a blue jacket" -m gpt-image-1.5 --input portrait.png -o portrait-blue.png
20
+ egaki image "turn this product shot into a clay render" -m gpt-image-1.5 --input product.png -o product-clay.png
21
+ ```
22
+
23
+ Multiple input images are supported. For this backend path, `egaki` now explicitly rejects unsupported options like `--seed`, `--mask`, and multi-image output instead of pretending they work.
24
+
25
+ 3. **Aspect ratio support for ChatGPT image generation** — supported ChatGPT/OpenAI aspect ratios now map to the backend's real size controls:
26
+
27
+ ```bash
28
+ egaki image "wide landscape matte painting" -m gpt-image-1.5 --aspect-ratio 3:2 -o wide.png
29
+ egaki image "book cover concept art" -m gpt-image-1.5 --aspect-ratio 2:3 -o cover.png
30
+ ```
31
+
32
+ Supported ratios on this path are `1:1`, `3:2`, and `2:3`.
33
+
34
+ 4. **`egaki models` now shows login availability** — model discovery output includes whether each provider is currently usable from your configured credentials:
35
+
36
+ ```bash
37
+ egaki models
38
+ egaki models --json | jq '.[] | {id, provider, auth}'
39
+ ```
40
+
41
+ The output now includes `auth.available` and `auth.source` (`env`, `stored`, `oauth`, or `none`) so you can see which model families are ready to use.
42
+
43
+ ## 0.3.0
44
+
45
+ 1. **Google Vertex AI provider** — use Google Cloud billing instead of AI Studio by
46
+ prefixing model IDs with `vertex/`:
47
+
48
+ ```bash
49
+ egaki login --provider vertex --key AIza...
50
+ egaki image "product shot on marble" -m vertex/imagen-4.0-generate-001 -o product.png
51
+ egaki image "editorial portrait" -m vertex/gemini-3.1-flash-image-preview --aspect-ratio 4:5
52
+ egaki video "storm over mountains" -m vertex/veo-3.1-fast-generate-001 --duration 6 -o storm.mp4
53
+ ```
54
+
55
+ Bare model IDs (e.g. `imagen-4.0-generate-001`) continue to route through Google AI
56
+ Studio as before. `vertex/` prefix routes through `@ai-sdk/google-vertex` using your
57
+ `GOOGLE_VERTEX_API_KEY`. The two providers are fully independent — having one key does
58
+ not affect the other.
59
+
60
+ Supported Vertex models:
61
+ - `vertex/imagen-4.0-generate-001`, `vertex/imagen-4.0-ultra-generate-001`, `vertex/imagen-4.0-fast-generate-001`
62
+ - `vertex/gemini-2.5-flash-image`, `vertex/gemini-3-pro-image-preview`, `vertex/gemini-3.1-flash-image-preview`
63
+ - `vertex/veo-3.1-generate-001`, `vertex/veo-3.1-fast-generate-001`
64
+
65
+ 2. **`egaki models --provider vertex`** — list only Vertex models:
66
+
67
+ ```bash
68
+ egaki models --provider vertex
69
+ ```
70
+
71
+ 3. **Fixed confusing error for Vertex without a key** — if you attempt a `vertex/` model
72
+ without a `GOOGLE_VERTEX_API_KEY` configured, you now get a clear error pointing you
73
+ to set one up instead of a cryptic upstream failure.
74
+
5
75
  ## 0.2.0
6
76
 
7
77
  1. **New `egaki video` command** — generate videos from text prompts or still images.
package/README.md CHANGED
@@ -20,6 +20,14 @@ egaki image "a watercolor fox reading a map" -o fox.png
20
20
  egaki video "a paper boat drifting on a calm lake at sunrise" -o boat.mp4
21
21
  ```
22
22
 
23
+ ### Quick start with ChatGPT auth
24
+
25
+ ```bash
26
+ egaki login --provider chatgpt
27
+ egaki image "a dreamy studio ghibli style bakery at sunrise" -m gpt-image-1.5 -o bakery.png
28
+ egaki image "change the red jacket to a blue jacket" -m gpt-image-1.5 --input portrait.png -o portrait-blue.png
29
+ ```
30
+
23
31
  ## CLI examples
24
32
 
25
33
  ### Generate an image from text
@@ -34,6 +42,7 @@ egaki image "isometric floating city, detailed, soft colors" -m imagen-4.0-gener
34
42
  ```bash
35
43
  egaki image "add a red scarf and make it winter" --input portrait.jpg -o portrait-winter.png
36
44
  egaki image "turn this into a manga panel" --input https://example.com/photo.jpg -o manga.png
45
+ egaki image "change the red square to a blue square" -m gpt-image-1.5 --input input.png -o output.png
37
46
  ```
38
47
 
39
48
  ### Inpainting with a mask
@@ -53,6 +62,15 @@ egaki image "minimal logo concepts for a cat cafe" -n 4 -o logo.png
53
62
  ```bash
54
63
  egaki image "cyberpunk alley at night" --aspect-ratio 16:9
55
64
  egaki image "polaroid-style travel photo" --aspect-ratio 4:5
65
+ egaki image "wide landscape matte painting" -m gpt-image-1.5 --aspect-ratio 3:2 -o wide.png
66
+ ```
67
+
68
+ ### Use Google Cloud billing via Vertex AI
69
+
70
+ ```bash
71
+ egaki login --provider vertex --key AIza...
72
+ egaki image "editorial sneaker photo on white seamless" -m vertex/imagen-4.0-generate-001 -o sneaker.png
73
+ egaki video "storm over mountains" -m vertex/veo-3.1-fast-generate-001 --duration 6 -o storm.mp4
56
74
  ```
57
75
 
58
76
  ### Pipe image output to other tools
@@ -67,7 +85,7 @@ egaki image "flat icon of a fox" --stdout | magick - -resize 512x512 fox-icon.pn
67
85
 
68
86
  ```bash
69
87
  egaki video "a paper boat drifting on a calm lake at sunrise" -o boat.mp4
70
- egaki video "timelapse of a stormy sea, cinematic" -m google/veo-3.1-generate-001 --duration 8 -o storm.mp4
88
+ egaki video "timelapse of a stormy sea, cinematic" -m veo-3.1-generate-001 --duration 8 -o storm.mp4
71
89
  ```
72
90
 
73
91
  ### Generate with a cheap model
@@ -88,7 +106,7 @@ egaki video "slowly animate the clouds" --input photo.jpg -m klingai/kling-v2.6-
88
106
 
89
107
  ```bash
90
108
  egaki video "aerial drone shot over a city grid" \
91
- -m google/veo-3.1-fast-generate-001 \
109
+ -m veo-3.1-fast-generate-001 \
92
110
  --aspect-ratio 16:9 \
93
111
  --resolution 1080p \
94
112
  --duration 6 \
@@ -175,8 +193,9 @@ egaki image "mascot variations, flat vector look" \
175
193
 
176
194
  | Model ID | Best for | Example command |
177
195
  | --- | --- | --- |
178
- | `google/veo-3.1-generate-001` | Highest quality video with audio, up to 4K | `egaki video "rainy Tokyo street at night" -m google/veo-3.1-generate-001 --duration 8 -o tokyo.mp4` |
179
- | `google/veo-3.1-fast-generate-001` | Fast Veo with 720p–4K, good for iteration | `egaki video "abstract paint patterns" -m google/veo-3.1-fast-generate-001 --duration 5 -o paint.mp4` |
196
+ | `veo-3.1-generate-001` | Highest quality video with audio, up to 4K | `egaki video "rainy Tokyo street at night" -m veo-3.1-generate-001 --duration 8 -o tokyo.mp4` |
197
+ | `veo-3.1-fast-generate-001` | Fast Veo with 720p–4K, good for iteration | `egaki video "abstract paint patterns" -m veo-3.1-fast-generate-001 --duration 5 -o paint.mp4` |
198
+ | `vertex/veo-3.1-generate-001` | Same as above, routed through Vertex AI | `egaki video "rainy Tokyo street" -m vertex/veo-3.1-generate-001 --duration 8 -o tokyo.mp4` |
180
199
  | `klingai/kling-v2.5-turbo-t2v` | Cheap, fast Kling text-to-video | `egaki video "a paper boat on a pond" -m klingai/kling-v2.5-turbo-t2v --duration 5 -o boat.mp4` |
181
200
  | `bytedance/seedance-v1.5-pro` | Bytedance, audio support, three resolutions | `egaki video "timelapse of clouds above mountains" -m bytedance/seedance-v1.5-pro -o clouds.mp4` |
182
201
  | `xai/grok-imagine-video` | xAI video generation, cheap for short clips | `egaki video "a dog catching a frisbee" -m xai/grok-imagine-video --duration 3 -o dog.mp4` |
@@ -189,6 +208,7 @@ egaki image "mascot variations, flat vector look" \
189
208
  - **BFL image models (`flux-*`)**: Kontext/Pro variants via AI Gateway subscription
190
209
  - **Recraft models (`recraft-*`)**: v2/v3/v4 families available via AI Gateway subscription
191
210
  - **xAI image models (`grok-imagine-*`)**: Grok image generation via AI Gateway subscription
211
+ - **Vertex models (`vertex/*`)**: same models as Google AI Studio, routed through Vertex AI / Google Cloud billing
192
212
  - **Google Veo video models**: up to 4K, audio optional, duration 4–8s
193
213
  - **Kling video models**: mode (std/pro), audio on v2.6+, image-to-video support
194
214
  - **Bytedance Seedance**: 480p–1080p, audio support on v1.5-pro
@@ -199,7 +219,9 @@ egaki image "mascot variations, flat vector look" \
199
219
  egaki supports **both** authentication modes:
200
220
 
201
221
  - **BYOK (bring your own keys):** add provider keys with `egaki login` per provider.
222
+ - **ChatGPT auth:** log in with `egaki login --provider chatgpt` to use the ChatGPT/Codex backend for supported OpenAI image generation and editing flows.
202
223
  - **Egaki subscription:** use one `egaki_...` key to access all supported models without managing keys for each provider.
224
+ - **Google vs Vertex:** bare model IDs (e.g. `imagen-4.0-generate-001`) use Google AI Studio. Prefix with `vertex/` (e.g. `vertex/imagen-4.0-generate-001`) to route through Vertex AI / Google Cloud billing.
203
225
 
204
226
  ```bash
205
227
  # Subscribe and get a checkout URL
@@ -211,8 +233,13 @@ egaki subscribe --plan pro
211
233
  # Save your Egaki key after checkout
212
234
  egaki login --provider egaki --key egaki_...
213
235
 
214
- # BYOK example (direct provider key)
236
+ # BYOK examples (direct provider keys)
215
237
  egaki login --provider google --key AIza...
238
+ egaki login --provider vertex --key AIza...
239
+
240
+ # ChatGPT OAuth for Codex-backed image generation/editing
241
+ egaki login --provider chatgpt
242
+ egaki image "turn this product shot into a clay render" -m gpt-image-1.5 --input product.png -o product-clay.png
216
243
 
217
244
  # Check subscription usage / cancel
218
245
  egaki usage
@@ -0,0 +1,25 @@
1
+ export type ChatGptAuth = {
2
+ email?: string;
3
+ accountId?: string;
4
+ plan?: string;
5
+ refresh: string;
6
+ access: string;
7
+ expires: number;
8
+ };
9
+ /** Extract the ChatGPT plan type (e.g. "plus", "pro") from the access token. */
10
+ export declare function extractPlanType(auth: ChatGptAuth): string | undefined;
11
+ /**
12
+ * Run the full ChatGPT OAuth browser flow with clack UI.
13
+ * Returns the ChatGptAuth object to be stored in credentials.json.
14
+ */
15
+ export declare function chatGptOAuthLogin(): Promise<ChatGptAuth>;
16
+ /**
17
+ * Refresh an expired ChatGPT access token using the refresh token.
18
+ * Returns the updated auth object, or an Error if refresh fails.
19
+ */
20
+ export declare function refreshChatGptToken(auth: ChatGptAuth): Promise<ChatGptAuth | Error>;
21
+ /**
22
+ * Refresh the auth object if needed and return the full updated state.
23
+ */
24
+ export declare function getValidChatGptAuth(auth: ChatGptAuth, onRefresh?: (updated: ChatGptAuth) => void): Promise<ChatGptAuth | Error>;
25
+ //# sourceMappingURL=chatgpt-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chatgpt-auth.d.ts","sourceRoot":"","sources":["../src/chatgpt-auth.ts"],"names":[],"mappings":"AAmBA,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAgGD,gFAAgF;AAChF,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAOrE;AA8JD;;;GAGG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,WAAW,CAAC,CA8C9D;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC,CAyBzF;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,WAAW,EACjB,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,GACzC,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC,CAS9B"}
@@ -3,8 +3,8 @@
3
3
  // Tokens are stored inside credentials.json under the 'chatgpt' key as a
4
4
  // structured object (not a plain string like other providers).
5
5
  //
6
- // The access token is a standard OpenAI bearer token that works with the
7
- // Image API, so we can inject it as OPENAI_API_KEY for the SDK to pick up.
6
+ // Tokens are stored so egaki can reuse the ChatGPT login for Codex-style
7
+ // backend requests and refresh them when needed.
8
8
  import { createServer } from 'node:http';
9
9
  import { spawn } from 'node:child_process';
10
10
  import { spinner, log, note } from '@clack/prompts';
@@ -55,6 +55,13 @@ function extractEmail(tokens) {
55
55
  return ((typeof idClaims?.email === 'string' ? idClaims.email : undefined) ??
56
56
  (typeof accessClaims?.email === 'string' ? accessClaims.email : undefined));
57
57
  }
58
+ function extractPlanTypeFromTokens(tokens) {
59
+ const idClaims = tokens.id_token ? parseJwtClaims(tokens.id_token) : undefined;
60
+ const accessClaims = parseJwtClaims(tokens.access_token);
61
+ const idAuth = idClaims?.['https://api.openai.com/auth'];
62
+ const accessAuth = accessClaims?.['https://api.openai.com/auth'];
63
+ return idAuth?.chatgpt_plan_type ?? accessAuth?.chatgpt_plan_type;
64
+ }
58
65
  function extractAccountId(tokens) {
59
66
  const idClaims = tokens.id_token ? parseJwtClaims(tokens.id_token) : undefined;
60
67
  const accessClaims = parseJwtClaims(tokens.access_token);
@@ -71,6 +78,8 @@ function extractAccountId(tokens) {
71
78
  }
72
79
  /** Extract the ChatGPT plan type (e.g. "plus", "pro") from the access token. */
73
80
  export function extractPlanType(auth) {
81
+ if (auth.plan)
82
+ return auth.plan;
74
83
  const claims = parseJwtClaims(auth.access);
75
84
  const authClaim = claims?.['https://api.openai.com/auth'];
76
85
  return authClaim?.chatgpt_plan_type;
@@ -81,7 +90,7 @@ function buildAuthorizeUrl(pkce, state) {
81
90
  response_type: 'code',
82
91
  client_id: CLIENT_ID,
83
92
  redirect_uri: REDIRECT_URI,
84
- scope: 'openid profile email offline_access',
93
+ scope: 'openid profile email offline_access api.connectors.read api.connectors.invoke',
85
94
  code_challenge: pkce.challenge,
86
95
  code_challenge_method: 'S256',
87
96
  id_token_add_organizations: 'true',
@@ -236,6 +245,7 @@ export async function chatGptOAuthLogin() {
236
245
  const auth = {
237
246
  email: extractEmail(tokens),
238
247
  accountId: extractAccountId(tokens),
248
+ plan: extractPlanTypeFromTokens(tokens),
239
249
  refresh: tokens.refresh_token,
240
250
  access: tokens.access_token,
241
251
  expires: now + (tokens.expires_in ?? 3600) * 1000,
@@ -266,6 +276,7 @@ export async function refreshChatGptToken(auth) {
266
276
  const json = (await response.json());
267
277
  return {
268
278
  ...auth,
279
+ plan: extractPlanTypeFromTokens(json) ?? auth.plan,
269
280
  access: json.access_token,
270
281
  refresh: json.refresh_token ?? auth.refresh,
271
282
  expires: Date.now() + (json.expires_in ?? 3600) * 1000,
@@ -276,19 +287,15 @@ export async function refreshChatGptToken(auth) {
276
287
  }
277
288
  }
278
289
  /**
279
- * Get a valid access token from a ChatGptAuth object.
280
- * Auto-refreshes if expired. Returns the token string or an Error.
281
- * If the auth was refreshed, the `onRefresh` callback is called with
282
- * the updated auth so the caller can persist it.
290
+ * Refresh the auth object if needed and return the full updated state.
283
291
  */
284
- export async function getValidAccessToken(auth, onRefresh) {
285
- // Token still valid (with 60s buffer)
292
+ export async function getValidChatGptAuth(auth, onRefresh) {
286
293
  if (auth.expires > Date.now() + 60_000) {
287
- return auth.access;
294
+ return auth;
288
295
  }
289
296
  const refreshed = await refreshChatGptToken(auth);
290
297
  if (refreshed instanceof Error)
291
298
  return refreshed;
292
299
  onRefresh?.(refreshed);
293
- return refreshed.access;
300
+ return refreshed;
294
301
  }