llm-cli-gateway 1.15.3 → 1.16.1

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
@@ -4,6 +4,55 @@ All notable changes to the llm-cli-gateway project.
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## [1.16.1] - 2026-05-29 — align Mistral Vibe CLI contract
8
+
9
+ Patch release for the current `mistral-vibe` CLI surface.
10
+
11
+ ### Fixed
12
+
13
+ - Updated Mistral Vibe requests to emit `--output text|json|streaming` instead
14
+ of the removed `--output-format` flag.
15
+ - Kept legacy MCP aliases working by mapping `plain` to `text` and
16
+ `stream-json` to `streaming`.
17
+ - Added `maxTokens` support for Mistral Vibe via `--max-tokens`.
18
+ - Updated Vibe install, upgrade, and doctor guidance for the current
19
+ `mistral-vibe` package and default-on session logging.
20
+
21
+ ## [1.16.0] - 2026-05-29 — remove Redis session dependency
22
+
23
+ Feature release that removes the optional Redis/ioredis layer from the
24
+ PostgreSQL-backed session manager and tightens the public README around the
25
+ project's current demand and quality signals.
26
+
27
+ ### Removed
28
+
29
+ - Removed the optional `ioredis` peer/dev dependency and its transitive
30
+ packages from the install graph.
31
+ - Removed `REDIS_URL` as a requirement for PostgreSQL-backed sessions.
32
+ - Removed Redis from the PostgreSQL test Docker Compose stack and PG test
33
+ harness.
34
+
35
+ ### Changed
36
+
37
+ - PostgreSQL-backed sessions now require only `DATABASE_URL` plus the optional
38
+ `pg` peer dependency. PostgreSQL remains the source of truth for session
39
+ records and active-session state.
40
+ - Simplified database health reporting to PostgreSQL connectivity only.
41
+ - Simplified the PG session manager by removing Redis cache-aside reads/writes
42
+ and Redis lock handling.
43
+ - Updated migration and testing docs to describe the Postgres-only backend.
44
+ - Updated release-readiness and Socket-alert documentation now that the Redis
45
+ client dependency is no longer present.
46
+ - Refocused the README first screen around the strongest current trust and
47
+ demand signals: npm monthly downloads, passing CI/security workflows,
48
+ OpenSSF status, Sigstore-signed releases, and MIT licensing.
49
+
50
+ ### Added
51
+
52
+ - Added `docs/plans/provider-workflow-assets.dag.toml`, a machine-readable
53
+ implementation plan for provider-specific skill and DAG-TOML pairs for
54
+ Claude, Codex, Gemini, Grok, and Mistral Vibe.
55
+
7
56
  ## [1.15.3] - 2026-05-29 — remove retired PyPI plugin
8
57
 
9
58
  Patch release removing the retired Python `llm` plugin integration so the
package/README.md CHANGED
@@ -3,19 +3,38 @@
3
3
  [![CI](https://github.com/verivus-oss/llm-cli-gateway/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/verivus-oss/llm-cli-gateway/actions/workflows/ci.yml)
4
4
  [![Security](https://github.com/verivus-oss/llm-cli-gateway/actions/workflows/security.yml/badge.svg?branch=main)](https://github.com/verivus-oss/llm-cli-gateway/actions/workflows/security.yml)
5
5
  [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/verivus-oss/llm-cli-gateway/badge)](https://scorecard.dev/viewer/?uri=github.com/verivus-oss/llm-cli-gateway)
6
- [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/13025/badge)](https://www.bestpractices.dev/projects/13025)
7
6
  [![npm](https://img.shields.io/npm/v/llm-cli-gateway.svg)](https://www.npmjs.com/package/llm-cli-gateway)
8
- [![npm weekly downloads](https://img.shields.io/npm/dw/llm-cli-gateway.svg)](https://www.npmjs.com/package/llm-cli-gateway)
9
7
  [![npm monthly downloads](https://img.shields.io/npm/dm/llm-cli-gateway.svg)](https://www.npmjs.com/package/llm-cli-gateway)
10
- [![GitHub release downloads](https://img.shields.io/github/downloads/verivus-oss/llm-cli-gateway/total.svg)](https://github.com/verivus-oss/llm-cli-gateway/releases)
11
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
12
- [![Releases: Sigstore signed](https://img.shields.io/badge/releases-Sigstore%20signed-2e7d32.svg)](SECURITY.md#release-signing)
13
9
 
14
10
  > _"Without consultation, plans are frustrated, but with many counselors they succeed."_
15
11
  > — Proverbs 15:22 (LSB)
16
12
 
17
13
  A Model Context Protocol (MCP) gateway for running Claude Code, Codex, Gemini, Grok, and Mistral (Vibe) CLIs from one MCP endpoint, with durable async jobs, session continuity, cache-aware prompting, observability, and personal-appliance setup tooling.
18
14
 
15
+ **Why developers try it:** one local MCP endpoint for cross-LLM validation, multi-agent coding workflows, and repeatable assistant-led setup across five provider CLIs.
16
+
17
+ **Current signals:** crossed 5k monthly npm downloads in May 2026; live npm downloads are shown above. CI and security workflows pass on `main`, OpenSSF Scorecard is published, OpenSSF Best Practices is passing, releases use Sigstore signing, and the package is MIT licensed.
18
+
19
+ ## Quick Start
20
+
21
+ ```bash
22
+ npm install -g llm-cli-gateway
23
+ ```
24
+
25
+ Or use directly with `npx` from an MCP client:
26
+
27
+ ```json
28
+ {
29
+ "mcpServers": {
30
+ "llm-gateway": {
31
+ "command": "npx",
32
+ "args": ["-y", "llm-cli-gateway"]
33
+ }
34
+ }
35
+ }
36
+ ```
37
+
19
38
  ## What It Provides Today
20
39
 
21
40
  `llm-cli-gateway` is a single-user MCP gateway for cross-LLM validation and multi-agent coding workflows. It is more than a thin CLI wrapper:
@@ -27,6 +46,24 @@ A Model Context Protocol (MCP) gateway for running Claude Code, Codex, Gemini, G
27
46
  - Can run requests inside gateway-managed git worktrees for isolated multi-agent review and implementation loops.
28
47
  - Ships personal-appliance setup surfaces: HTTP transport with bearer-token auth, `doctor --json`, setup UI artifacts, provider setup snippets, Docker fallback, and checked release bundles.
29
48
 
49
+ ## Workflow Assets
50
+
51
+ The repo ships agent-ready workflow skills under [`.agents/skills`](.agents/skills) for async orchestration, session continuity, multi-LLM review, implement-review-fix loops, and secure approval-gated dispatch. Machine-readable DAG-TOML plans live under [`docs/plans`](docs/plans) and [`setup/install-plan.dag.toml`](setup/install-plan.dag.toml) for workflows that need deterministic sequencing and verification gates.
52
+
53
+ The next documentation focus is provider-specific skill and DAG-TOML pairs for each outbound CLI: Claude, Codex, Gemini, Grok, and Mistral Vibe. The implementation plan is tracked in [`docs/plans/provider-workflow-assets.dag.toml`](docs/plans/provider-workflow-assets.dag.toml), with each provider asset expected to cover install/login checks, session behavior, approval modes, cache/telemetry surfaces, failure modes, and a smoke-test gate.
54
+
55
+ ## Trust & Supply Chain
56
+
57
+ [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/13025/badge)](https://www.bestpractices.dev/projects/13025)
58
+ [![npm weekly downloads](https://img.shields.io/npm/dw/llm-cli-gateway.svg)](https://www.npmjs.com/package/llm-cli-gateway)
59
+ [![GitHub release downloads](https://img.shields.io/github/downloads/verivus-oss/llm-cli-gateway/total.svg)](https://github.com/verivus-oss/llm-cli-gateway/releases)
60
+ [![Releases: Sigstore signed](https://img.shields.io/badge/releases-Sigstore%20signed-2e7d32.svg)](SECURITY.md#release-signing)
61
+
62
+ - CI runs build, lint, format, tests, package checks, and npm audit.
63
+ - Security CI runs actionlint, zizmor, shellcheck, typos, osv-scanner, gitleaks, and lychee.
64
+ - GitHub release installer artifacts are checksummed and signed with Sigstore keyless signing.
65
+ - npm releases use provenance through OIDC trusted publishing.
66
+
30
67
  ## Personal MCP Appliance
31
68
 
32
69
  The personal-appliance contract keeps that surface intentionally narrow: one trusted user runs the gateway on a machine or volume they own, connects one MCP endpoint, and asks any connected client for cross-LLM validation.
@@ -216,13 +253,16 @@ grok login # OAuth flow, or set GROK_CODE_XAI_API_KEY
216
253
 
217
254
  ```bash
218
255
  # Pick one — the gateway's cli_upgrade auto-detects which one you used.
219
- pip install vibe-cli
220
- uv tool install vibe-cli
256
+ curl -LsSf https://mistral.ai/vibe/install.sh | bash
257
+ pip install mistral-vibe
258
+ uv tool install mistral-vibe
221
259
  brew install mistral-vibe
222
260
 
223
261
  vibe auth login
224
- # Required for `mistral_request --resume` / `--continue` to persist sessions:
225
- vibe config set session_logging.enabled true # or edit ~/.vibe/config.toml
262
+ # Current Vibe defaults session logging to enabled. If an older config disabled it,
263
+ # edit ~/.vibe/config.toml and set:
264
+ # [session_logging]
265
+ # enabled = true
226
266
  ```
227
267
 
228
268
  Vibe-specific notes:
@@ -699,7 +739,8 @@ Run a Mistral Vibe agentic coding request. Like `grok_request` in shape, but wit
699
739
  - `permissionMode`: `default | plan | accept-edits | auto-approve | chat | explore | lean` — emitted as `--agent <mode>`. Defaults to `auto-approve` in programmatic mode.
700
740
  - `allowedTools` (string[], optional): One `--enabled-tools <tool>` flag per entry (allow-list only).
701
741
  - `disallowedTools` (string[], optional): Accepted for parity with the other providers; ignored at the CLI boundary with a logged warning.
702
- - `sessionId` / `resumeLatest` / `createNewSession`: standard session controls. Continuity requires `[session_logging] enabled = true` in `~/.vibe/config.toml` `doctor --json` surfaces an actionable next-action when the toggle is missing.
742
+ - `outputFormat` (string, optional): Vibe 2.x values are `"text"`, `"json"`, or `"streaming"`; legacy aliases `"plain"` and `"stream-json"` are accepted and normalized before spawn.
743
+ - `sessionId` / `resumeLatest` / `createNewSession`: standard session controls. Current Vibe defaults session logging to enabled; if an older config has `[session_logging] enabled = false`, `doctor --json` surfaces an actionable next-action.
703
744
 
704
745
  ##### `claude_request_async` / `codex_request_async` / `gemini_request_async` / `grok_request_async` / `mistral_request_async`
705
746
 
@@ -1143,7 +1184,6 @@ If you're vetting `llm-cli-gateway` through [Socket](https://socket.dev/npm/pack
1143
1184
  | **Shell access** | `src/executor.ts` uses `child_process.spawn(cmd, args, …)` to invoke the underlying LLM CLIs. | `spawn` is called with an argument array and **never** `shell: true`, so there is no shell interpolation path for caller input. The command name is restricted to an allow-list of known CLI binaries (`claude`, `codex`, `gemini`, `grok`, `vibe`). |
1144
1185
  | **Uses eval** | None in our source. Transitive: `@modelcontextprotocol/sdk` → `ajv@8` uses `new Function(...)` in `ajv/dist/compile/index.js` to compile JSON Schema validators. | This is ajv's standard codegen path. Only known schemas (defined in our source and the MCP SDK) flow into it; no caller-supplied data ever reaches the compiled function body. |
1145
1186
  | **better-sqlite3 PRAGMA helper** | Transitive: `better-sqlite3/lib/methods/pragma.js` interpolates its caller-provided `source` into a `PRAGMA ${source}` statement. | We do not call `db.pragma()` from production source. Internal SQLite setup uses fixed literal `db.exec("PRAGMA ...")` statements, and `npm run security:audit` fails the release if production code reintroduces `.pragma()` calls. |
1146
- | **ioredis obfuscated code** | Optional peer/dev dependency: `ioredis@5.10.1` may be flagged at `built/constants/TLSProfiles.js` for base64-looking strings. | Reviewed as a false positive. The file is a Redis Cloud TLS CA certificate bundle in PEM format, which is base64 by design. It contains no decoder loop, dynamic evaluation, network call, or hidden execution path. The same file is byte-for-byte identical in `ioredis@5.9.2`; our default production install does not install `ioredis`, and our code does not pass ioredis TLS profile options. |
1147
1187
  | **Dependency ownership** | A handful of small transitive packages (e.g. `bindings` via `better-sqlite3`, `media-typer` via `@modelcontextprotocol/sdk`) trip Socket's "unstable ownership" or "obfuscated code" heuristics. | These are pinned, well-known micro-deps in the Node ecosystem with no known issues. We pin direct override versions of `content-type` and `type-is` in `package.json#overrides`. Our previous direct dependency on `toml@3.0.0` (also single-maintainer, last released 2020) was replaced with the actively-maintained `smol-toml` to reduce inherited risk. |
1148
1188
 
1149
1189
  See [`socket.yml`](./socket.yml) for the same context in machine-readable form.
@@ -1,6 +1,8 @@
1
1
  import { spawnSync } from "node:child_process";
2
2
  import { executeCli } from "./executor.js";
3
3
  import { getProviderRuntimeStatus } from "./provider-status.js";
4
+ const MISTRAL_VIBE_PACKAGE = "mistral-vibe";
5
+ const LEGACY_VIBE_PACKAGE = "vibe-cli";
4
6
  /**
5
7
  * Detect how Vibe was installed on this machine. Vibe does not self-update, so
6
8
  * cli_upgrade has to dispatch to the package manager that owns the binary.
@@ -16,15 +18,19 @@ export function detectMistralInstallMethod(exec = (cmd, args) => {
16
18
  stdout: result.stdout || "",
17
19
  };
18
20
  }) {
19
- const pip = exec("pip", ["show", "vibe-cli"]);
20
- if (pip.exitCode === 0 && /Name:\s*vibe-cli/i.test(pip.stdout)) {
21
+ const pip = exec("pip", ["show", MISTRAL_VIBE_PACKAGE]);
22
+ if (pip.exitCode === 0 && /Name:\s*mistral-vibe/i.test(pip.stdout)) {
23
+ return "pip";
24
+ }
25
+ const legacyPip = exec("pip", ["show", LEGACY_VIBE_PACKAGE]);
26
+ if (legacyPip.exitCode === 0 && /Name:\s*vibe-cli/i.test(legacyPip.stdout)) {
21
27
  return "pip";
22
28
  }
23
29
  const uv = exec("uv", ["tool", "list"]);
24
- if (uv.exitCode === 0 && /\bvibe(?:-cli)?\b/i.test(uv.stdout)) {
30
+ if (uv.exitCode === 0 && /\b(?:mistral-vibe|vibe-cli|vibe)\b/i.test(uv.stdout)) {
25
31
  return "uv";
26
32
  }
27
- const brew = exec("brew", ["list", "mistral-vibe"]);
33
+ const brew = exec("brew", ["list", MISTRAL_VIBE_PACKAGE]);
28
34
  if (brew.exitCode === 0) {
29
35
  return "brew";
30
36
  }
@@ -154,7 +160,9 @@ function buildMistralUpgradePlan(normalizedTarget, detectMistral) {
154
160
  // (we surface it as a no-op plan with `command: ""` so runCliUpgrade can
155
161
  // throw before spawning anything).
156
162
  if (method === "pip") {
157
- const pkg = normalizedTarget === "latest" ? "vibe-cli" : `vibe-cli==${normalizedTarget}`;
163
+ const pkg = normalizedTarget === "latest"
164
+ ? MISTRAL_VIBE_PACKAGE
165
+ : `${MISTRAL_VIBE_PACKAGE}==${normalizedTarget}`;
158
166
  return {
159
167
  cli: "mistral",
160
168
  target: normalizedTarget,
@@ -170,7 +178,7 @@ function buildMistralUpgradePlan(normalizedTarget, detectMistral) {
170
178
  cli: "mistral",
171
179
  target: normalizedTarget,
172
180
  command: "uv",
173
- args: ["tool", "upgrade", "vibe-cli"],
181
+ args: ["tool", "upgrade", MISTRAL_VIBE_PACKAGE],
174
182
  strategy: "uv-tool-upgrade",
175
183
  requiresNetwork: true,
176
184
  note: normalizedTarget === "latest"
@@ -183,7 +191,7 @@ function buildMistralUpgradePlan(normalizedTarget, detectMistral) {
183
191
  cli: "mistral",
184
192
  target: normalizedTarget,
185
193
  command: "brew",
186
- args: ["upgrade", "mistral-vibe"],
194
+ args: ["upgrade", MISTRAL_VIBE_PACKAGE],
187
195
  strategy: "brew-upgrade",
188
196
  requiresNetwork: true,
189
197
  note: normalizedTarget === "latest"
@@ -191,7 +199,7 @@ function buildMistralUpgradePlan(normalizedTarget, detectMistral) {
191
199
  : "brew upgrade does not honour explicit version targets; running upgrade to latest.",
192
200
  };
193
201
  }
194
- throw new Error("Could not detect how Mistral Vibe was installed. Install it via pip (`pip install vibe-cli`), uv (`uv tool install vibe-cli`), or Homebrew (`brew install mistral-vibe`) before running cli_upgrade.");
202
+ throw new Error("Could not detect how Mistral Vibe was installed. Install it via pip (`pip install mistral-vibe`), uv (`uv tool install mistral-vibe`), or Homebrew (`brew install mistral-vibe`) before running cli_upgrade.");
195
203
  }
196
204
  async function fallbackCliVersion(cli, args) {
197
205
  try {
package/dist/config.d.ts CHANGED
@@ -1,9 +1,4 @@
1
1
  import type { Logger } from "./logger.js";
2
- export interface CacheTtl {
3
- session: number;
4
- activeSession: number;
5
- sessionList: number;
6
- }
7
2
  export interface DatabaseConfig {
8
3
  connectionString: string;
9
4
  pool: {
@@ -13,25 +8,15 @@ export interface DatabaseConfig {
13
8
  statementTimeout: number;
14
9
  };
15
10
  }
16
- export interface RedisConfig {
17
- url: string;
18
- retryStrategy: {
19
- maxRetries: number;
20
- initialDelay: number;
21
- maxDelay: number;
22
- };
23
- }
24
11
  export declare const DEFAULT_SESSION_TTL_SECONDS = 2592000;
25
12
  export interface Config {
26
13
  database?: DatabaseConfig;
27
- redis?: RedisConfig;
28
- cacheTtl: CacheTtl;
29
14
  sessionTtl: number;
30
15
  }
31
16
  /**
32
17
  * Load configuration from environment variables.
33
- * Always returns a Config object with base fields (cacheTtl, sessionTtl).
34
- * Database and Redis fields are populated only when both env vars are set.
18
+ * Always returns a Config object with base fields.
19
+ * Database fields are populated when DATABASE_URL is set.
35
20
  */
36
21
  export declare function loadConfig(): Config;
37
22
  export declare const PERSISTENCE_BACKENDS: readonly ["sqlite", "postgres", "memory", "none"];
package/dist/config.js CHANGED
@@ -11,37 +11,28 @@ const DatabaseUrlSchema = z
11
11
  .refine(url => url.startsWith("postgresql://") || url.startsWith("postgres://"), {
12
12
  message: "Database URL must start with postgresql:// or postgres://",
13
13
  });
14
- const RedisUrlSchema = z.string().url().startsWith("redis://");
15
14
  export const DEFAULT_SESSION_TTL_SECONDS = 2592000; // 30 days
16
15
  /**
17
16
  * Load configuration from environment variables.
18
- * Always returns a Config object with base fields (cacheTtl, sessionTtl).
19
- * Database and Redis fields are populated only when both env vars are set.
17
+ * Always returns a Config object with base fields.
18
+ * Database fields are populated when DATABASE_URL is set.
20
19
  */
21
20
  export function loadConfig() {
22
21
  const databaseUrl = process.env.DATABASE_URL;
23
- const redisUrl = process.env.REDIS_URL;
24
- // Default cache TTLs
25
- const cacheTtl = {
26
- session: 3600, // 1 hour
27
- activeSession: 1800, // 30 minutes
28
- sessionList: 120, // 2 minutes
29
- };
30
22
  const rawSessionTtl = parseInt(process.env.SESSION_TTL || String(DEFAULT_SESSION_TTL_SECONDS), 10);
31
23
  const sessionTtl = Number.isFinite(rawSessionTtl) && rawSessionTtl > 0
32
24
  ? rawSessionTtl
33
25
  : DEFAULT_SESSION_TTL_SECONDS;
34
26
  // If no database config, return base config (file-based storage)
35
- if (!databaseUrl || !redisUrl) {
36
- return { cacheTtl, sessionTtl };
27
+ if (!databaseUrl) {
28
+ return { sessionTtl };
37
29
  }
38
- // Validate URLs
30
+ // Validate URL
39
31
  try {
40
32
  DatabaseUrlSchema.parse(databaseUrl);
41
- RedisUrlSchema.parse(redisUrl);
42
33
  }
43
34
  catch (error) {
44
- throw new Error(`Invalid database or redis URL: ${error instanceof Error ? error.message : String(error)}`);
35
+ throw new Error(`Invalid database URL: ${error instanceof Error ? error.message : String(error)}`);
45
36
  }
46
37
  return {
47
38
  database: {
@@ -53,15 +44,6 @@ export function loadConfig() {
53
44
  statementTimeout: 10000,
54
45
  },
55
46
  },
56
- redis: {
57
- url: redisUrl,
58
- retryStrategy: {
59
- maxRetries: 3,
60
- initialDelay: 50,
61
- maxDelay: 2000,
62
- },
63
- },
64
- cacheTtl,
65
47
  sessionTtl,
66
48
  };
67
49
  }
package/dist/db.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import type { Pool } from "pg";
2
- import type { Redis } from "ioredis";
3
2
  import { Config } from "./config.js";
4
3
  import type { Logger } from "./logger.js";
5
4
  export interface HealthCheckResult {
@@ -7,22 +6,17 @@ export interface HealthCheckResult {
7
6
  connected: boolean;
8
7
  latency: number;
9
8
  };
10
- redis: {
11
- connected: boolean;
12
- latency: number;
13
- };
14
9
  }
15
10
  /**
16
- * Database connection manager for PostgreSQL and Redis
11
+ * Database connection manager for PostgreSQL-backed sessions.
17
12
  */
18
13
  export declare class DatabaseConnection {
19
14
  private logger;
20
15
  private pool;
21
- private redis;
22
16
  private config;
23
17
  constructor(config: Config, logger?: Logger);
24
18
  /**
25
- * Initialize connections to PostgreSQL and Redis
19
+ * Initialize connection to PostgreSQL.
26
20
  */
27
21
  connect(): Promise<void>;
28
22
  /**
@@ -30,17 +24,13 @@ export declare class DatabaseConnection {
30
24
  */
31
25
  disconnect(): Promise<void>;
32
26
  /**
33
- * Health check for PostgreSQL and Redis
27
+ * Health check for PostgreSQL.
34
28
  */
35
29
  healthCheck(): Promise<HealthCheckResult>;
36
30
  /**
37
31
  * Get PostgreSQL pool
38
32
  */
39
33
  getPool(): Pool;
40
- /**
41
- * Get Redis client
42
- */
43
- getRedis(): Redis;
44
34
  }
45
35
  /**
46
36
  * Factory function to create and connect DatabaseConnection
package/dist/db.js CHANGED
@@ -1,25 +1,23 @@
1
1
  import { noopLogger } from "./logger.js";
2
2
  /**
3
- * Database connection manager for PostgreSQL and Redis
3
+ * Database connection manager for PostgreSQL-backed sessions.
4
4
  */
5
5
  export class DatabaseConnection {
6
6
  logger;
7
7
  pool = null;
8
- redis = null;
9
8
  config;
10
9
  constructor(config, logger = noopLogger) {
11
10
  this.logger = logger;
12
- if (!config.database || !config.redis) {
13
- throw new Error("Database and Redis configuration required");
11
+ if (!config.database) {
12
+ throw new Error("Database configuration required");
14
13
  }
15
14
  this.config = config;
16
15
  }
17
16
  /**
18
- * Initialize connections to PostgreSQL and Redis
17
+ * Initialize connection to PostgreSQL.
19
18
  */
20
19
  async connect() {
21
20
  const { Pool } = await importOptionalPg();
22
- const Redis = await importOptionalRedis();
23
21
  // Initialize PostgreSQL pool
24
22
  const poolConfig = {
25
23
  connectionString: this.config.database.connectionString,
@@ -40,32 +38,6 @@ export class DatabaseConnection {
40
38
  this.logger.error("Failed to connect to PostgreSQL", { error });
41
39
  throw new Error(`Failed to connect to PostgreSQL: ${error instanceof Error ? error.message : String(error)}`);
42
40
  }
43
- // Initialize Redis client
44
- const redisOptions = {
45
- retryStrategy: (times) => {
46
- const { maxRetries, initialDelay, maxDelay } = this.config.redis.retryStrategy;
47
- if (times > maxRetries) {
48
- return null; // Stop retrying
49
- }
50
- return Math.min(initialDelay * times, maxDelay);
51
- },
52
- lazyConnect: false,
53
- reconnectOnError: (err) => {
54
- // Reconnect on READONLY and ECONNRESET errors
55
- const targetErrors = ["READONLY", "ECONNRESET"];
56
- return targetErrors.some(targetError => err.message.includes(targetError));
57
- },
58
- };
59
- this.redis = new Redis(this.config.redis.url, redisOptions);
60
- // Test Redis connection
61
- try {
62
- await this.redis.ping();
63
- this.logger.info("Redis connection established");
64
- }
65
- catch (error) {
66
- this.logger.error("Failed to connect to Redis", { error });
67
- throw new Error(`Failed to connect to Redis: ${error instanceof Error ? error.message : String(error)}`);
68
- }
69
41
  }
70
42
  /**
71
43
  * Graceful shutdown - close all connections
@@ -82,26 +54,16 @@ export class DatabaseConnection {
82
54
  errors.push(new Error(`PostgreSQL disconnect error: ${error instanceof Error ? error.message : String(error)}`));
83
55
  }
84
56
  }
85
- if (this.redis) {
86
- try {
87
- this.redis.disconnect();
88
- this.redis = null;
89
- }
90
- catch (error) {
91
- errors.push(new Error(`Redis disconnect error: ${error instanceof Error ? error.message : String(error)}`));
92
- }
93
- }
94
57
  if (errors.length > 0) {
95
58
  throw new Error(`Disconnect errors: ${errors.map(e => e.message).join("; ")}`);
96
59
  }
97
60
  }
98
61
  /**
99
- * Health check for PostgreSQL and Redis
62
+ * Health check for PostgreSQL.
100
63
  */
101
64
  async healthCheck() {
102
65
  const result = {
103
66
  postgres: { connected: false, latency: 0 },
104
- redis: { connected: false, latency: 0 },
105
67
  };
106
68
  // Check PostgreSQL
107
69
  if (this.pool) {
@@ -123,21 +85,8 @@ export class DatabaseConnection {
123
85
  }
124
86
  }
125
87
  }
126
- // Check Redis
127
- if (this.redis) {
128
- const redisStart = Date.now();
129
- try {
130
- await this.redis.ping();
131
- result.redis.connected = true;
132
- result.redis.latency = Date.now() - redisStart;
133
- }
134
- catch (error) {
135
- result.redis.connected = false;
136
- }
137
- }
138
88
  this.logger.debug("Health check completed", {
139
89
  postgres: result.postgres.connected,
140
- redis: result.redis.connected,
141
90
  });
142
91
  return result;
143
92
  }
@@ -150,15 +99,6 @@ export class DatabaseConnection {
150
99
  }
151
100
  return this.pool;
152
101
  }
153
- /**
154
- * Get Redis client
155
- */
156
- getRedis() {
157
- if (!this.redis) {
158
- throw new Error("Redis client not initialized");
159
- }
160
- return this.redis;
161
- }
162
102
  }
163
103
  async function importOptionalPg() {
164
104
  try {
@@ -166,19 +106,7 @@ async function importOptionalPg() {
166
106
  }
167
107
  catch (error) {
168
108
  if (error?.code === "ERR_MODULE_NOT_FOUND" || error?.code === "MODULE_NOT_FOUND") {
169
- throw new Error("PostgreSQL sessions require optional peer dependency 'pg'. Install it alongside llm-cli-gateway to use DATABASE_URL/REDIS_URL-backed sessions.");
170
- }
171
- throw error;
172
- }
173
- }
174
- async function importOptionalRedis() {
175
- try {
176
- const mod = await import("ioredis");
177
- return mod.Redis ?? mod.default;
178
- }
179
- catch (error) {
180
- if (error?.code === "ERR_MODULE_NOT_FOUND" || error?.code === "MODULE_NOT_FOUND") {
181
- throw new Error("PostgreSQL sessions require optional peer dependency 'ioredis'. Install it alongside llm-cli-gateway to use DATABASE_URL/REDIS_URL-backed sessions.");
109
+ throw new Error("PostgreSQL sessions require optional peer dependency 'pg'. Install it alongside llm-cli-gateway to use DATABASE_URL-backed sessions.");
182
110
  }
183
111
  throw error;
184
112
  }
package/dist/doctor.d.ts CHANGED
@@ -51,10 +51,10 @@ export interface GeminiConfigStatus {
51
51
  next_actions: string[];
52
52
  }
53
53
  /**
54
- * Probe ~/.vibe/config.toml to see whether session_logging is enabled. Vibe
55
- * persists session logs (which sessionId/--continue depends on) only when
56
- * `[session_logging] enabled = true` is set. The probe is read-only: the
57
- * gateway never mutates this file.
54
+ * Probe ~/.vibe/config.toml to see whether session_logging is enabled. Current
55
+ * Mistral Vibe defaults session logging to enabled; an explicit
56
+ * `[session_logging] enabled = false` disables `--continue` / `--resume`.
57
+ * The probe is read-only: the gateway never mutates this file.
58
58
  */
59
59
  export declare function checkVibeSessionLogging(home?: string): VibeSessionLoggingStatus;
60
60
  /**
package/dist/doctor.js CHANGED
@@ -10,10 +10,10 @@ import { loadCacheAwarenessConfig } from "./config.js";
10
10
  import { computeGlobalCacheStats } from "./cache-stats.js";
11
11
  import { FlightRecorder, resolveFlightRecorderDbPath } from "./flight-recorder.js";
12
12
  /**
13
- * Probe ~/.vibe/config.toml to see whether session_logging is enabled. Vibe
14
- * persists session logs (which sessionId/--continue depends on) only when
15
- * `[session_logging] enabled = true` is set. The probe is read-only: the
16
- * gateway never mutates this file.
13
+ * Probe ~/.vibe/config.toml to see whether session_logging is enabled. Current
14
+ * Mistral Vibe defaults session logging to enabled; an explicit
15
+ * `[session_logging] enabled = false` disables `--continue` / `--resume`.
16
+ * The probe is read-only: the gateway never mutates this file.
17
17
  */
18
18
  export function checkVibeSessionLogging(home = homedir()) {
19
19
  const configPath = join(home, ".vibe", "config.toml");
@@ -21,26 +21,28 @@ export function checkVibeSessionLogging(home = homedir()) {
21
21
  return {
22
22
  config_path: configPath,
23
23
  config_present: false,
24
- session_logging_enabled: false,
25
- note: "~/.vibe/config.toml not found. Run `vibe config set session_logging.enabled true` or create the file with a [session_logging]\\nenabled = true block.",
24
+ session_logging_enabled: true,
25
+ note: "~/.vibe/config.toml not found; current Vibe defaults session_logging.enabled to true. If resume fails, create ~/.vibe/config.toml with [session_logging]\\nenabled = true.",
26
26
  };
27
27
  }
28
28
  try {
29
29
  const text = readFileSync(configPath, "utf8");
30
30
  const enabled = parseVibeSessionLoggingEnabled(text);
31
- if (enabled) {
31
+ if (enabled !== false) {
32
32
  return {
33
33
  config_path: configPath,
34
34
  config_present: true,
35
35
  session_logging_enabled: true,
36
- note: "session_logging.enabled is true; --continue/--resume will work for mistral_request.",
36
+ note: enabled === true
37
+ ? "session_logging.enabled is true; --continue/--resume will work for mistral_request."
38
+ : "session_logging.enabled is not set; current Vibe defaults it to true.",
37
39
  };
38
40
  }
39
41
  return {
40
42
  config_path: configPath,
41
43
  config_present: true,
42
44
  session_logging_enabled: false,
43
- note: "[session_logging] enabled = false (or missing). Run `vibe config set session_logging.enabled true` or edit ~/.vibe/config.toml so mistral_request --resume / --continue can persist sessions.",
45
+ note: "[session_logging] enabled = false. Edit ~/.vibe/config.toml so the [session_logging] block sets enabled = true before using mistral_request --resume / --continue.",
44
46
  };
45
47
  }
46
48
  catch (err) {
@@ -54,7 +56,7 @@ export function checkVibeSessionLogging(home = homedir()) {
54
56
  }
55
57
  }
56
58
  /**
57
- * Tiny TOML probe focused on `[session_logging] enabled = true`. Avoids pulling
59
+ * Tiny TOML probe focused on `[session_logging] enabled = ...`. Avoids pulling
58
60
  * in the full `toml` parser when only one boolean is needed.
59
61
  */
60
62
  function parseVibeSessionLoggingEnabled(text) {
@@ -73,7 +75,11 @@ function parseVibeSessionLoggingEnabled(text) {
73
75
  const kv = line.match(/^enabled\s*=\s*(.+)$/);
74
76
  if (kv) {
75
77
  const value = kv[1].trim().toLowerCase();
76
- return value === "true";
78
+ if (value === "true")
79
+ return true;
80
+ if (value === "false")
81
+ return false;
82
+ return undefined;
77
83
  }
78
84
  }
79
85
  else {
@@ -81,11 +87,15 @@ function parseVibeSessionLoggingEnabled(text) {
81
87
  const dotted = line.match(/^session_logging\.enabled\s*=\s*(.+)$/);
82
88
  if (dotted) {
83
89
  const value = dotted[1].trim().toLowerCase();
84
- return value === "true";
90
+ if (value === "true")
91
+ return true;
92
+ if (value === "false")
93
+ return false;
94
+ return undefined;
85
95
  }
86
96
  }
87
97
  }
88
- return false;
98
+ return undefined;
89
99
  }
90
100
  /**
91
101
  * U27: Probe Gemini's project/user config locations.
package/dist/health.d.ts CHANGED
@@ -6,10 +6,6 @@ export interface HealthStatus {
6
6
  status: "up" | "down";
7
7
  latency: number;
8
8
  };
9
- redis: {
10
- status: "up" | "down";
11
- latency: number;
12
- };
13
9
  timestamp: string;
14
10
  }
15
11
  export interface ProviderRuntimeHealth {
@@ -18,10 +14,7 @@ export interface ProviderRuntimeHealth {
18
14
  timestamp: string;
19
15
  }
20
16
  /**
21
- * Check health status of PostgreSQL and Redis
22
- * - Both up → healthy
23
- * - Only PostgreSQL up → degraded (Redis down but DB works)
24
- * - PostgreSQL down → unhealthy (critical failure)
17
+ * Check health status of PostgreSQL.
25
18
  */
26
19
  export declare function checkHealth(db: DatabaseConnection): Promise<HealthStatus>;
27
20
  export declare function checkProviderRuntimeHealth(): ProviderRuntimeHealth;