llm-cli-gateway 1.1.0 → 1.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.
@@ -30,3 +30,44 @@ export declare function resolveSessionResumeArgs(opts: {
30
30
  resumeLatest?: boolean;
31
31
  createNewSession?: boolean;
32
32
  }): SessionResumeResult;
33
+ /**
34
+ * Codex-specific resume planning.
35
+ *
36
+ * Codex CLI ≥ 0.30 exposes session resume as a subcommand (`codex exec resume`),
37
+ * not a flag pair like Claude/Gemini/Grok. So we can't return a simple list of
38
+ * args — we describe the *mode* and let the caller branch when building argv:
39
+ *
40
+ * - "new" → `codex exec [...flags] PROMPT`
41
+ * - "resume-by-id" → `codex exec resume [...resume-safe flags] <SESSION_ID> PROMPT`
42
+ * - "resume-latest" → `codex exec resume --last [...resume-safe flags] PROMPT`
43
+ *
44
+ * `codex exec resume` rejects `--full-auto`; the original session's approval
45
+ * policy is inherited. Callers MUST filter `--full-auto` out of the flag set
46
+ * when mode is one of the resume forms (see `prepareCodexRequest`).
47
+ *
48
+ * `sessionId` MUST be a real Codex session UUID (as recorded under
49
+ * `~/.codex/sessions/`). Gateway-generated `gw-*` IDs are rejected, since
50
+ * they are bookkeeping handles and would 404 against `codex resume`.
51
+ */
52
+ export type CodexSessionMode = "new" | "resume-by-id" | "resume-latest";
53
+ export interface CodexSessionPlan {
54
+ mode: CodexSessionMode;
55
+ /** Real Codex session UUID. Present only when mode === "resume-by-id". */
56
+ sessionId?: string;
57
+ }
58
+ export declare function resolveCodexSessionArgs(opts: {
59
+ sessionId?: string;
60
+ resumeLatest?: boolean;
61
+ createNewSession?: boolean;
62
+ }): CodexSessionPlan;
63
+ /**
64
+ * Grok-specific resume args. Grok accepts `--resume <id>` to resume a named session,
65
+ * and `--continue` to resume the most recent session for the current working directory.
66
+ * Unlike `resolveSessionResumeArgs`, "resume latest" maps to `--continue` (not `--resume latest`)
67
+ * because Grok would interpret a literal "latest" as a session ID.
68
+ */
69
+ export declare function resolveGrokSessionArgs(opts: {
70
+ sessionId?: string;
71
+ resumeLatest?: boolean;
72
+ createNewSession?: boolean;
73
+ }): SessionResumeResult;
@@ -52,3 +52,43 @@ export function resolveSessionResumeArgs(opts) {
52
52
  }
53
53
  return { resumeArgs: [], effectiveSessionId: undefined, userProvidedSession: false };
54
54
  }
55
+ export function resolveCodexSessionArgs(opts) {
56
+ if (opts.createNewSession) {
57
+ return { mode: "new" };
58
+ }
59
+ if (opts.sessionId) {
60
+ validateSessionId(opts.sessionId);
61
+ return { mode: "resume-by-id", sessionId: opts.sessionId };
62
+ }
63
+ if (opts.resumeLatest) {
64
+ return { mode: "resume-latest" };
65
+ }
66
+ return { mode: "new" };
67
+ }
68
+ /**
69
+ * Grok-specific resume args. Grok accepts `--resume <id>` to resume a named session,
70
+ * and `--continue` to resume the most recent session for the current working directory.
71
+ * Unlike `resolveSessionResumeArgs`, "resume latest" maps to `--continue` (not `--resume latest`)
72
+ * because Grok would interpret a literal "latest" as a session ID.
73
+ */
74
+ export function resolveGrokSessionArgs(opts) {
75
+ if (opts.createNewSession) {
76
+ return { resumeArgs: [], effectiveSessionId: undefined, userProvidedSession: false };
77
+ }
78
+ if (opts.resumeLatest && !opts.sessionId) {
79
+ return {
80
+ resumeArgs: ["--continue"],
81
+ effectiveSessionId: undefined,
82
+ userProvidedSession: false,
83
+ };
84
+ }
85
+ if (opts.sessionId) {
86
+ validateSessionId(opts.sessionId);
87
+ return {
88
+ resumeArgs: ["--resume", opts.sessionId],
89
+ effectiveSessionId: opts.sessionId,
90
+ userProvidedSession: true,
91
+ };
92
+ }
93
+ return { resumeArgs: [], effectiveSessionId: undefined, userProvidedSession: false };
94
+ }
package/dist/resources.js CHANGED
@@ -54,6 +54,17 @@ export class ResourceProvider {
54
54
  priority: 0.6,
55
55
  },
56
56
  },
57
+ {
58
+ uri: "sessions://grok",
59
+ name: "Grok Sessions",
60
+ title: "⚡ Grok Sessions",
61
+ description: "List of Grok conversation sessions",
62
+ mimeType: "application/json",
63
+ annotations: {
64
+ audience: ["user", "assistant"],
65
+ priority: 0.6,
66
+ },
67
+ },
57
68
  {
58
69
  uri: "models://claude",
59
70
  name: "Claude Models",
@@ -87,6 +98,17 @@ export class ResourceProvider {
87
98
  priority: 0.8,
88
99
  },
89
100
  },
101
+ {
102
+ uri: "models://grok",
103
+ name: "Grok Models",
104
+ title: "⚡ Grok Models & Capabilities",
105
+ description: "Available Grok models and their capabilities",
106
+ mimeType: "application/json",
107
+ annotations: {
108
+ audience: ["user", "assistant"],
109
+ priority: 0.8,
110
+ },
111
+ },
90
112
  {
91
113
  uri: "metrics://performance",
92
114
  name: "Performance Metrics",
@@ -121,6 +143,7 @@ export class ResourceProvider {
121
143
  claude: (await this.sessionManager.getActiveSession("claude"))?.id || null,
122
144
  codex: (await this.sessionManager.getActiveSession("codex"))?.id || null,
123
145
  gemini: (await this.sessionManager.getActiveSession("gemini"))?.id || null,
146
+ grok: (await this.sessionManager.getActiveSession("grok"))?.id || null,
124
147
  },
125
148
  }, null, 2),
126
149
  };
@@ -164,6 +187,19 @@ export class ResourceProvider {
164
187
  }, null, 2),
165
188
  };
166
189
  }
190
+ if (uri === "sessions://grok") {
191
+ const sessions = await this.sessionManager.listSessions("grok");
192
+ return {
193
+ uri,
194
+ mimeType: "application/json",
195
+ text: JSON.stringify({
196
+ cli: "grok",
197
+ total: sessions.length,
198
+ sessions,
199
+ activeSession: (await this.sessionManager.getActiveSession("grok"))?.id || null,
200
+ }, null, 2),
201
+ };
202
+ }
167
203
  // Model capability resources
168
204
  if (uri === "models://claude") {
169
205
  const cliInfo = getCliInfo();
@@ -189,6 +225,14 @@ export class ResourceProvider {
189
225
  text: JSON.stringify(cliInfo.gemini, null, 2),
190
226
  };
191
227
  }
228
+ if (uri === "models://grok") {
229
+ const cliInfo = getCliInfo();
230
+ return {
231
+ uri,
232
+ mimeType: "application/json",
233
+ text: JSON.stringify(cliInfo.grok, null, 2),
234
+ };
235
+ }
192
236
  if (uri === "metrics://performance") {
193
237
  return {
194
238
  uri,
@@ -3,6 +3,7 @@ const DEFAULT_SESSION_DESCRIPTIONS = {
3
3
  claude: "Claude Session",
4
4
  codex: "Codex Session",
5
5
  gemini: "Gemini Session",
6
+ grok: "Grok Session",
6
7
  };
7
8
  /**
8
9
  * PostgreSQL-backed session manager with Redis caching
@@ -1,7 +1,7 @@
1
1
  import type { Config } from "./config.js";
2
2
  import type { DatabaseConnection } from "./db.js";
3
3
  import type { Logger } from "./logger.js";
4
- export declare const CLI_TYPES: readonly ["claude", "codex", "gemini"];
4
+ export declare const CLI_TYPES: readonly ["claude", "codex", "gemini", "grok"];
5
5
  export type CliType = (typeof CLI_TYPES)[number];
6
6
  export interface Session {
7
7
  id: string;
@@ -4,12 +4,13 @@ import { join, dirname } from "path";
4
4
  import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, openSync, fsyncSync, closeSync, chmodSync, } from "fs";
5
5
  import { DEFAULT_SESSION_TTL_SECONDS } from "./config.js";
6
6
  import { noopLogger } from "./logger.js";
7
- export const CLI_TYPES = ["claude", "codex", "gemini"];
7
+ export const CLI_TYPES = ["claude", "codex", "gemini", "grok"];
8
8
  const createEmptyActiveSessions = () => Object.fromEntries(CLI_TYPES.map(cli => [cli, null]));
9
9
  const DEFAULT_SESSION_DESCRIPTIONS = {
10
10
  claude: "Claude Session",
11
11
  codex: "Codex Session",
12
12
  gemini: "Gemini Session",
13
+ grok: "Grok Session",
13
14
  };
14
15
  export class FileSessionManager {
15
16
  storagePath;
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "llm-cli-gateway",
3
- "version": "1.1.0",
3
+ "version": "1.4.0",
4
4
  "mcpName": "io.github.verivus-oss/llm-cli-gateway",
5
- "description": "MCP server providing unified access to Claude Code, Codex, and Gemini CLIs with session management, retry logic, and async job orchestration.",
5
+ "description": "MCP server providing unified access to Claude Code, Codex, Gemini, and Grok CLIs with session management, retry logic, async job orchestration, and durable job results.",
6
6
  "license": "MIT",
7
7
  "author": {
8
8
  "name": "VerivusAI Labs",
@@ -72,7 +72,7 @@
72
72
  },
73
73
  "dependencies": {
74
74
  "@modelcontextprotocol/sdk": "^1.0.0",
75
- "better-sqlite3": "^11.0.0",
75
+ "better-sqlite3": "^12.9.0",
76
76
  "ioredis": "^5.4.1",
77
77
  "pg": "^8.12.0",
78
78
  "toml": "^3.0.0",