codex-xai-oauth 0.1.0 → 0.2.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.
@@ -30948,7 +30948,7 @@ var StdioServerTransport = class {
30948
30948
  };
30949
30949
 
30950
30950
  // src/version.ts
30951
- var PACKAGE_VERSION = "0.1.0";
30951
+ var PACKAGE_VERSION = "0.2.0";
30952
30952
 
30953
30953
  // src/xai/constants.ts
30954
30954
  var XAI_BASE_URL = "https://api.x.ai/v1";
@@ -32241,7 +32241,7 @@ var Ky = class _Ky {
32241
32241
  }
32242
32242
  #getNormalizedOptions() {
32243
32243
  if (!this.#cachedNormalizedOptions) {
32244
- const { hooks, json: json2, parseJson, stringifyJson, searchParams, timeout: timeout2, totalTimeout, throwHttpErrors, fetch, ...normalizedOptions } = this.#options;
32244
+ const { hooks, json: json2, parseJson, stringifyJson, searchParams, timeout: timeout2, totalTimeout, throwHttpErrors, fetch: fetch2, ...normalizedOptions } = this.#options;
32245
32245
  this.#cachedNormalizedOptions = Object.freeze(normalizedOptions);
32246
32246
  }
32247
32247
  return this.#cachedNormalizedOptions;
@@ -32623,6 +32623,80 @@ async function xaiRequest(path, options) {
32623
32623
  });
32624
32624
  }
32625
32625
 
32626
+ // src/xai/image-artifacts.ts
32627
+ import { mkdir, writeFile } from "node:fs/promises";
32628
+ import { join as join3 } from "node:path";
32629
+ async function artifactImageGenerationResult(result, options) {
32630
+ const artifacts = [];
32631
+ const images = result.data ?? [];
32632
+ for (let index = 0; index < images.length; index += 1) {
32633
+ const image = images[index];
32634
+ if (!image) {
32635
+ continue;
32636
+ }
32637
+ const artifact = await imageArtifactForPayload(image, index, options);
32638
+ if (artifact) {
32639
+ artifacts.push(artifact);
32640
+ }
32641
+ }
32642
+ return { ...result, artifacts };
32643
+ }
32644
+ async function imageArtifactForPayload(image, index, options) {
32645
+ if (image.b64_json) {
32646
+ const mimeType = image.mime_type ?? "image/png";
32647
+ const path = artifactPath(options.artifactDir, index, mimeType);
32648
+ await writeArtifact(path, Buffer.from(image.b64_json, "base64"));
32649
+ return {
32650
+ index,
32651
+ mime_type: mimeType,
32652
+ path,
32653
+ source: "base64",
32654
+ status: "saved"
32655
+ };
32656
+ }
32657
+ if (!image.url) {
32658
+ return void 0;
32659
+ }
32660
+ return downloadImageArtifact({ ...image, url: image.url }, index, options);
32661
+ }
32662
+ async function downloadImageArtifact(image, index, options) {
32663
+ try {
32664
+ const response = await (options.fetchImage ?? fetch)(image.url);
32665
+ if (!response.ok) {
32666
+ throw new Error(`download failed with status ${response.status}`);
32667
+ }
32668
+ const mimeType = image.mime_type ?? response.headers.get("content-type") ?? "image/png";
32669
+ const path = artifactPath(options.artifactDir, index, mimeType);
32670
+ await writeArtifact(path, Buffer.from(await response.arrayBuffer()));
32671
+ return {
32672
+ index,
32673
+ mime_type: mimeType,
32674
+ path,
32675
+ source: "url",
32676
+ status: "saved",
32677
+ url: image.url
32678
+ };
32679
+ } catch (error51) {
32680
+ return {
32681
+ error: error51 instanceof Error ? error51.message : String(error51),
32682
+ index,
32683
+ source: "url",
32684
+ status: "remote",
32685
+ url: image.url
32686
+ };
32687
+ }
32688
+ }
32689
+ async function writeArtifact(path, bytes) {
32690
+ await mkdir(join3(path, ".."), { recursive: true });
32691
+ await writeFile(path, bytes);
32692
+ }
32693
+ function artifactPath(artifactDir, index, mimeType) {
32694
+ return join3(artifactDir, `image-${index + 1}.${extensionForMime(mimeType)}`);
32695
+ }
32696
+ function extensionForMime(mimeType) {
32697
+ return mimeType.includes("jpeg") || mimeType.includes("jpg") ? "jpg" : "png";
32698
+ }
32699
+
32626
32700
  // src/xai/media.ts
32627
32701
  async function xaiImageGenerate(args) {
32628
32702
  const body = {
@@ -32644,6 +32718,12 @@ async function xaiImageGenerate(args) {
32644
32718
  const parsed = await response.json();
32645
32719
  return isRecord(parsed) ? parsed : {};
32646
32720
  }
32721
+ async function xaiImageGenerateWithArtifacts(args) {
32722
+ const result = await xaiImageGenerate(args);
32723
+ return artifactImageGenerationResult(result, {
32724
+ artifactDir: args.artifactDir
32725
+ });
32726
+ }
32647
32727
  async function xaiTts(args) {
32648
32728
  const codec2 = args.codec || args.format;
32649
32729
  const body = {
@@ -32897,19 +32977,34 @@ function registerMediaTools(server) {
32897
32977
  n: external_exports.number().int().min(1).max(10).optional(),
32898
32978
  resolution: external_exports.enum(["1k", "2k"]).optional(),
32899
32979
  response_format: external_exports.enum(["url", "b64_json"]).optional(),
32900
- size: external_exports.string().optional()
32980
+ size: external_exports.string().optional(),
32981
+ artifact_dir: external_exports.string().optional()
32901
32982
  })
32902
32983
  },
32903
- async ({ prompt, model, n, resolution, response_format, size }) => textJson(
32904
- await xaiImageGenerate({
32984
+ async ({
32985
+ prompt,
32986
+ model,
32987
+ n,
32988
+ resolution,
32989
+ response_format,
32990
+ size,
32991
+ artifact_dir
32992
+ }) => {
32993
+ const args = {
32905
32994
  prompt,
32906
32995
  ...model ? { model } : {},
32907
32996
  ...n ? { n } : {},
32908
32997
  ...resolution ? { resolution } : {},
32909
32998
  ...response_format ? { response_format } : {},
32910
32999
  ...size ? { size } : {}
32911
- })
32912
- )
33000
+ };
33001
+ return textJson(
33002
+ artifact_dir ? await xaiImageGenerateWithArtifacts({
33003
+ ...args,
33004
+ artifactDir: artifact_dir
33005
+ }) : await xaiImageGenerate(args)
33006
+ );
33007
+ }
32913
33008
  );
32914
33009
  server.registerTool(
32915
33010
  "xai_tts",
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const PACKAGE_VERSION = "0.1.0";
1
+ export declare const PACKAGE_VERSION = "0.2.0";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -12,6 +12,6 @@ export declare const XAI_REDIRECT_PATH = "/callback";
12
12
  export declare const OPENAI_COMPAT_HOST = "127.0.0.1";
13
13
  export declare const OPENAI_COMPAT_PORT = 8787;
14
14
  export declare const REFRESH_SKEW_MS: number;
15
- export declare const USER_AGENT = "codex-xai-oauth/0.1.0";
15
+ export declare const USER_AGENT = "codex-xai-oauth/0.2.0";
16
16
  export declare function xaiBaseUrl(): string;
17
17
  //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1,33 @@
1
+ export type ImagePayload = {
2
+ readonly b64_json?: string;
3
+ readonly mime_type?: string;
4
+ readonly url?: string;
5
+ };
6
+ export type ImageGenerationWithData = {
7
+ readonly data?: readonly ImagePayload[];
8
+ readonly [key: string]: unknown;
9
+ };
10
+ export type SavedImageArtifact = {
11
+ readonly index: number;
12
+ readonly mime_type: string;
13
+ readonly path: string;
14
+ readonly source: "base64" | "url";
15
+ readonly status: "saved";
16
+ readonly url?: string;
17
+ };
18
+ export type RemoteImageArtifact = {
19
+ readonly error: string;
20
+ readonly index: number;
21
+ readonly source: "url";
22
+ readonly status: "remote";
23
+ readonly url: string;
24
+ };
25
+ export type ImageArtifact = SavedImageArtifact | RemoteImageArtifact;
26
+ export type ImageArtifactGenerationResult = ImageGenerationWithData & {
27
+ readonly artifacts: readonly ImageArtifact[];
28
+ };
29
+ export declare function artifactImageGenerationResult(result: ImageGenerationWithData, options: {
30
+ readonly artifactDir: string;
31
+ readonly fetchImage?: (url: string) => Promise<Response>;
32
+ }): Promise<ImageArtifactGenerationResult>;
33
+ //# sourceMappingURL=image-artifacts.d.ts.map
@@ -1,7 +1,7 @@
1
1
  export { beginOAuth, startCallbackServer } from "./browser-oauth.js";
2
2
  export { credentialStatus, resolveXaiCredentials } from "./credentials.js";
3
3
  export { beginDeviceOAuth, pollDeviceToken, requestDeviceCode, } from "./device-oauth.js";
4
- export { xaiImageGenerate, xaiTts, xaiVideoGenerate } from "./media.js";
4
+ export { xaiImageGenerate, xaiImageGenerateWithArtifacts, xaiTts, xaiVideoGenerate, } from "./media.js";
5
5
  export { buildAuthorizeUrl, discoverXaiOAuth, exchangeCodeForToken, pkcePair, refreshAccessToken, storedAuthFromToken, } from "./oauth.js";
6
6
  export { xaiChatCompletions, xaiResponses } from "./responses.js";
7
7
  export { authPath, defaultAuthPath, defaultGrokAuthPath, grokAuthPath, readGrokStoredAuth, readStoredAuth, writeStoredAuth, } from "./storage.js";
@@ -1,3 +1,4 @@
1
+ import { type ImageArtifactGenerationResult } from "./image-artifacts.js";
1
2
  export declare function xaiImageGenerate(args: {
2
3
  readonly model?: string;
3
4
  readonly n?: number;
@@ -6,6 +7,15 @@ export declare function xaiImageGenerate(args: {
6
7
  readonly response_format?: "url" | "b64_json";
7
8
  readonly size?: string;
8
9
  }): Promise<Record<string, unknown>>;
10
+ export declare function xaiImageGenerateWithArtifacts(args: {
11
+ readonly artifactDir: string;
12
+ readonly model?: string;
13
+ readonly n?: number;
14
+ readonly prompt: string;
15
+ readonly resolution?: "1k" | "2k";
16
+ readonly response_format?: "url" | "b64_json";
17
+ readonly size?: string;
18
+ }): Promise<ImageArtifactGenerationResult>;
9
19
  export declare function xaiTts(args: {
10
20
  readonly bit_rate?: number;
11
21
  readonly codec?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-xai-oauth",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Codex plugin exposing xAI/Grok OAuth and API-key tools through a local MCP server.",
5
5
  "type": "module",
6
6
  "main": "./dist/mcp/server.js",
@@ -14,7 +14,7 @@ Use the bundled MCP tools when the user asks for xAI, Grok, Grok Imagine, xAI im
14
14
  - `xai_generate_text`: generate text with Grok through xAI Responses.
15
15
  - `xai_web_search`: answer with xAI server-side web search.
16
16
  - `xai_x_search`: answer with xAI server-side X search. Do not pass both allowed and excluded handles.
17
- - `xai_image_generate`: generate images with xAI `/images/generations`.
17
+ - `xai_image_generate`: generate images with xAI `/images/generations`. Pass `artifact_dir` when the user wants local files; URL and `b64_json` images are saved there and returned in `artifacts`.
18
18
  - `xai_tts`: generate speech audio.
19
19
  - `xai_video_generate`: generate video.
20
20
 
@@ -47,3 +47,18 @@ To check status:
47
47
  ```bash
48
48
  codex-xai-oauth status
49
49
  ```
50
+
51
+ ## Image Generation
52
+
53
+ Use `xai_image_generate` when the user asks to generate an image, Grok Imagine image, or xAI image. Defaults are `model: grok-imagine-image`, `response_format: url`, and `n: 1`.
54
+
55
+ Supported image options:
56
+
57
+ - `prompt`: required image prompt.
58
+ - `n`: number of images.
59
+ - `resolution`: `1k` or `2k`.
60
+ - `response_format`: `url` or `b64_json`.
61
+ - `size`: provider-specific size string.
62
+ - `artifact_dir`: local directory for saved image artifacts.
63
+
64
+ When `artifact_dir` is provided, return both the upstream JSON and the `artifacts` metadata. Each saved artifact includes a local `path`, `mime_type`, `source`, and `status`. If a remote URL cannot be downloaded, preserve the upstream `url` with `status: remote` instead of hiding it.