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/dist/health.js CHANGED
@@ -1,9 +1,6 @@
1
1
  import { listProviderRuntimeStatuses } from "./provider-status.js";
2
2
  /**
3
- * Check health status of PostgreSQL and Redis
4
- * - Both up → healthy
5
- * - Only PostgreSQL up → degraded (Redis down but DB works)
6
- * - PostgreSQL down → unhealthy (critical failure)
3
+ * Check health status of PostgreSQL.
7
4
  */
8
5
  export async function checkHealth(db) {
9
6
  const result = await db.healthCheck();
@@ -13,22 +10,9 @@ export async function checkHealth(db) {
13
10
  status: result.postgres.connected ? "up" : "down",
14
11
  latency: result.postgres.latency,
15
12
  },
16
- redis: {
17
- status: result.redis.connected ? "up" : "down",
18
- latency: result.redis.latency,
19
- },
20
13
  timestamp: new Date().toISOString(),
21
14
  };
22
- // Determine overall health status
23
- if (result.postgres.connected && result.redis.connected) {
24
- health.status = "healthy";
25
- }
26
- else if (result.postgres.connected && !result.redis.connected) {
27
- health.status = "degraded";
28
- }
29
- else {
30
- health.status = "unhealthy";
31
- }
15
+ health.status = result.postgres.connected ? "healthy" : "unhealthy";
32
16
  return health;
33
17
  }
34
18
  export function checkProviderRuntimeHealth() {
package/dist/index.d.ts CHANGED
@@ -413,6 +413,8 @@ export declare function prepareMistralRequest(params: {
413
413
  maxTurns?: number;
414
414
  /** Phase 4 slice δ: Vibe `--max-price DOLLARS` cumulative-cost cap. */
415
415
  maxPrice?: number;
416
+ /** Vibe 2.x: `--max-tokens N` cumulative prompt + completion token cap. */
417
+ maxTokens?: number;
416
418
  /** Phase 4 slice ζ: Vibe `--workdir <DIR>` working-directory parity. */
417
419
  workingDir?: string;
418
420
  /** Phase 4 slice ζ: Vibe `--add-dir <DIR>` repeatable add-dir parity. */
@@ -429,7 +431,7 @@ export declare function prepareMistralRequest(params: {
429
431
  * through here, or a fresh-workspace / budgeted run can degrade on
430
432
  * the second attempt.
431
433
  */
432
- export declare function buildMistralRetryPrep(params: Pick<MistralRequestParams, "outputFormat" | "permissionMode" | "effort" | "reasoningEffort" | "allowedTools" | "disallowedTools" | "approvalStrategy" | "trust" | "maxTurns" | "maxPrice" | "workingDir" | "addDir"> & {
434
+ export declare function buildMistralRetryPrep(params: Pick<MistralRequestParams, "outputFormat" | "permissionMode" | "effort" | "reasoningEffort" | "allowedTools" | "disallowedTools" | "approvalStrategy" | "trust" | "maxTurns" | "maxPrice" | "maxTokens" | "workingDir" | "addDir"> & {
433
435
  effectivePrompt: string;
434
436
  }, recoveryModel: string): {
435
437
  args: string[];
@@ -557,6 +559,8 @@ export interface MistralRequestParams {
557
559
  maxTurns?: number;
558
560
  /** Phase 4 slice δ: Vibe `--max-price DOLLARS` cumulative-cost cap. */
559
561
  maxPrice?: number;
562
+ /** Vibe 2.x: `--max-tokens N` cumulative prompt + completion token cap. */
563
+ maxTokens?: number;
560
564
  /** Phase 4 slice ζ: Vibe `--workdir <DIR>` working-directory parity. */
561
565
  workingDir?: string;
562
566
  /** Phase 4 slice ζ: Vibe `--add-dir <DIR>` repeatable add-dir parity. */
package/dist/index.js CHANGED
@@ -165,7 +165,7 @@ Other: list_models, cli_versions, upstream_contracts, cli_upgrade, approval_list
165
165
 
166
166
  Key behaviors:
167
167
  - Sync auto-defers at ${SYNC_DEADLINE_MS}ms. Poll deferred jobs via llm_job_status/llm_job_result.
168
- - Sessions: Claude --continue, Gemini --resume, Grok --resume/--continue, Mistral --resume/--continue (requires session_logging.enabled=true in ~/.vibe/config.toml), Codex \`exec resume <ID>\` / \`exec resume --last\` (all real CLI continuity). For Codex, sessionId must be a real Codex UUID (from ~/.codex/sessions/); gateway-generated gw-* IDs are rejected.
168
+ - Sessions: Claude --continue, Gemini --resume, Grok --resume/--continue, Mistral --resume/--continue (current Vibe defaults session logging on; doctor flags explicit session_logging.enabled=false), Codex \`exec resume <ID>\` / \`exec resume --last\` (all real CLI continuity). For Codex, sessionId must be a real Codex UUID (from ~/.codex/sessions/); gateway-generated gw-* IDs are rejected.
169
169
  - Approval gates: opt-in via approvalStrategy:"mcp_managed".
170
170
  - Idle timeout kills stuck processes (default 10min, configurable via idleTimeoutMs).
171
171
 
@@ -1766,6 +1766,7 @@ export function prepareMistralRequest(params, runtime = resolveGatewayServerRunt
1766
1766
  trust: params.trust,
1767
1767
  maxTurns: params.maxTurns,
1768
1768
  maxPrice: params.maxPrice,
1769
+ maxTokens: params.maxTokens,
1769
1770
  workingDir: params.workingDir,
1770
1771
  addDir: params.addDir,
1771
1772
  });
@@ -1822,6 +1823,7 @@ export function buildMistralRetryPrep(params, recoveryModel) {
1822
1823
  trust: params.trust,
1823
1824
  maxTurns: params.maxTurns,
1824
1825
  maxPrice: params.maxPrice,
1826
+ maxTokens: params.maxTokens,
1825
1827
  workingDir: params.workingDir,
1826
1828
  addDir: params.addDir,
1827
1829
  });
@@ -2428,6 +2430,7 @@ export async function handleMistralRequest(deps, params) {
2428
2430
  trust: params.trust,
2429
2431
  maxTurns: params.maxTurns,
2430
2432
  maxPrice: params.maxPrice,
2433
+ maxTokens: params.maxTokens,
2431
2434
  workingDir: params.workingDir,
2432
2435
  addDir: params.addDir,
2433
2436
  }, runtime);
@@ -2578,6 +2581,7 @@ export async function handleMistralRequestAsync(deps, params) {
2578
2581
  trust: params.trust,
2579
2582
  maxTurns: params.maxTurns,
2580
2583
  maxPrice: params.maxPrice,
2584
+ maxTokens: params.maxTokens,
2581
2585
  workingDir: params.workingDir,
2582
2586
  addDir: params.addDir,
2583
2587
  }, runtime);
@@ -3761,13 +3765,13 @@ export function createGatewayServer(deps = {}) {
3761
3765
  .optional()
3762
3766
  .describe("Model alias (e.g. mistral-medium-3.5, latest). Resolved alias is injected via VIBE_ACTIVE_MODEL env var; Vibe has no --model flag."),
3763
3767
  outputFormat: z
3764
- .enum(["plain", "json", "stream-json"])
3768
+ .enum(["text", "plain", "json", "streaming", "stream-json"])
3765
3769
  .optional()
3766
- .describe("Output format (plain|json|stream-json). Vibe default is plain."),
3770
+ .describe("Output format for Vibe 2.x (text|json|streaming). Legacy aliases plain→text and stream-json→streaming are accepted."),
3767
3771
  sessionId: z
3768
3772
  .string()
3769
3773
  .optional()
3770
- .describe("Session ID (user-provided CLI handle for --resume). Requires [session_logging] enabled = true in ~/.vibe/config.toml."),
3774
+ .describe("Session ID (user-provided CLI handle for --resume). Current Vibe defaults session logging on; doctor flags explicit [session_logging] enabled = false."),
3771
3775
  resumeLatest: z
3772
3776
  .boolean()
3773
3777
  .default(false)
@@ -3822,6 +3826,7 @@ export function createGatewayServer(deps = {}) {
3822
3826
  .describe("Emit `--trust` so Vibe trusts the cwd for this invocation only (not persisted to trusted_folders.toml) and skips the interactive trust prompt (Phase 4 slice γ)."),
3823
3827
  maxTurns: MAX_TURNS_SCHEMA.optional().describe("Vibe `--max-turns N`: cap the agent-loop iteration count (programmatic mode only, Phase 4 slice δ). Bounded to safe integers ≤ 10000."),
3824
3828
  maxPrice: MAX_PRICE_SCHEMA.optional().describe("Vibe `--max-price DOLLARS`: interrupt the session when cumulative cost crosses this cap (programmatic mode only, Phase 4 slice δ). Bounded to finite values ≤ 10000 USD."),
3829
+ maxTokens: MAX_TURNS_SCHEMA.optional().describe("Vibe `--max-tokens N`: cap cumulative prompt + completion tokens for the session (programmatic mode only). Bounded to safe integers ≤ 10000."),
3825
3830
  // Phase 4 slice ζ — Vibe working-directory + additional-dirs parity.
3826
3831
  workingDir: z
3827
3832
  .string()
@@ -3833,7 +3838,7 @@ export function createGatewayServer(deps = {}) {
3833
3838
  .optional()
3834
3839
  .describe("Vibe --add-dir <DIR>: additional writable workspace directories. Each entry is emitted as its own --add-dir instance (Vibe states this flag may be specified multiple times)."),
3835
3840
  worktree: WORKTREE_SCHEMA.optional(),
3836
- }, async ({ prompt, promptParts, model, outputFormat, sessionId, resumeLatest, createNewSession, permissionMode, effort, reasoningEffort, approvalStrategy, approvalPolicy, mcpServers, allowedTools, disallowedTools, correlationId, optimizePrompt, optimizeResponse, idleTimeoutMs, forceRefresh, trust, maxTurns, maxPrice, workingDir, addDir, worktree, }) => {
3841
+ }, async ({ prompt, promptParts, model, outputFormat, sessionId, resumeLatest, createNewSession, permissionMode, effort, reasoningEffort, approvalStrategy, approvalPolicy, mcpServers, allowedTools, disallowedTools, correlationId, optimizePrompt, optimizeResponse, idleTimeoutMs, forceRefresh, trust, maxTurns, maxPrice, maxTokens, workingDir, addDir, worktree, }) => {
3837
3842
  return handleMistralRequest({ sessionManager, logger, runtime }, {
3838
3843
  prompt,
3839
3844
  promptParts,
@@ -3858,6 +3863,7 @@ export function createGatewayServer(deps = {}) {
3858
3863
  trust,
3859
3864
  maxTurns,
3860
3865
  maxPrice,
3866
+ maxTokens,
3861
3867
  workingDir,
3862
3868
  addDir,
3863
3869
  worktree,
@@ -4482,13 +4488,13 @@ export function createGatewayServer(deps = {}) {
4482
4488
  .optional()
4483
4489
  .describe("Model alias (resolved into VIBE_ACTIVE_MODEL env var — Vibe has no --model flag)"),
4484
4490
  outputFormat: z
4485
- .enum(["plain", "json", "stream-json"])
4491
+ .enum(["text", "plain", "json", "streaming", "stream-json"])
4486
4492
  .optional()
4487
- .describe("Output format (plain|json|stream-json). Vibe default is plain."),
4493
+ .describe("Output format for Vibe 2.x (text|json|streaming). Legacy aliases plain→text and stream-json→streaming are accepted."),
4488
4494
  sessionId: z
4489
4495
  .string()
4490
4496
  .optional()
4491
- .describe("Session ID (user-provided CLI handle for --resume). Requires [session_logging] enabled = true in ~/.vibe/config.toml."),
4497
+ .describe("Session ID (user-provided CLI handle for --resume). Current Vibe defaults session logging on; doctor flags explicit [session_logging] enabled = false."),
4492
4498
  resumeLatest: z
4493
4499
  .boolean()
4494
4500
  .default(false)
@@ -4542,6 +4548,7 @@ export function createGatewayServer(deps = {}) {
4542
4548
  .describe("Emit `--trust` so Vibe trusts the cwd for this invocation only (not persisted to trusted_folders.toml) and skips the interactive trust prompt (Phase 4 slice γ)."),
4543
4549
  maxTurns: MAX_TURNS_SCHEMA.optional().describe("Vibe `--max-turns N`: cap the agent-loop iteration count (programmatic mode only, Phase 4 slice δ). Bounded to safe integers ≤ 10000."),
4544
4550
  maxPrice: MAX_PRICE_SCHEMA.optional().describe("Vibe `--max-price DOLLARS`: interrupt the session when cumulative cost crosses this cap (programmatic mode only, Phase 4 slice δ). Bounded to finite values ≤ 10000 USD."),
4551
+ maxTokens: MAX_TURNS_SCHEMA.optional().describe("Vibe `--max-tokens N`: cap cumulative prompt + completion tokens for the session (programmatic mode only). Bounded to safe integers ≤ 10000."),
4545
4552
  // Phase 4 slice ζ — Vibe working-directory + additional-dirs parity.
4546
4553
  workingDir: z
4547
4554
  .string()
@@ -4553,7 +4560,7 @@ export function createGatewayServer(deps = {}) {
4553
4560
  .optional()
4554
4561
  .describe("Vibe --add-dir <DIR>: additional writable workspace directories. Each entry is emitted as its own --add-dir instance."),
4555
4562
  worktree: WORKTREE_SCHEMA.optional(),
4556
- }, async ({ prompt, promptParts, model, outputFormat, sessionId, resumeLatest, createNewSession, permissionMode, effort, reasoningEffort, approvalStrategy, approvalPolicy, mcpServers, allowedTools, disallowedTools, correlationId, optimizePrompt, idleTimeoutMs, forceRefresh, trust, maxTurns, maxPrice, workingDir, addDir, worktree, }) => {
4563
+ }, async ({ prompt, promptParts, model, outputFormat, sessionId, resumeLatest, createNewSession, permissionMode, effort, reasoningEffort, approvalStrategy, approvalPolicy, mcpServers, allowedTools, disallowedTools, correlationId, optimizePrompt, idleTimeoutMs, forceRefresh, trust, maxTurns, maxPrice, maxTokens, workingDir, addDir, worktree, }) => {
4557
4564
  return handleMistralRequestAsync({ sessionManager, asyncJobManager, logger, runtime }, {
4558
4565
  prompt,
4559
4566
  promptParts,
@@ -4577,6 +4584,7 @@ export function createGatewayServer(deps = {}) {
4577
4584
  trust,
4578
4585
  maxTurns,
4579
4586
  maxPrice,
4587
+ maxTokens,
4580
4588
  workingDir,
4581
4589
  addDir,
4582
4590
  worktree,
@@ -5101,8 +5109,8 @@ async function initializeSessionManager() {
5101
5109
  // own a single filesystem); revisit if/when worktree support extends
5102
5110
  // there.
5103
5111
  const worktreeCleanupHook = createWorktreeSessionCleanupHook(logger);
5104
- if (config.database && config.redis) {
5105
- logger.info("Initializing PostgreSQL + Redis session manager");
5112
+ if (config.database) {
5113
+ logger.info("Initializing PostgreSQL session manager");
5106
5114
  const { createDatabaseConnection } = await import("./db.js");
5107
5115
  db = await createDatabaseConnection(config, logger);
5108
5116
  sessionManager = await createSessionManager(config, db, logger);
@@ -82,7 +82,6 @@ Options:
82
82
 
83
83
  Environment Variables:
84
84
  DATABASE_URL PostgreSQL connection string (required)
85
- REDIS_URL Redis connection string (required)
86
85
  `);
87
86
  process.exit(args[0] === "--help" || args[0] === "-h" ? 0 : 1);
88
87
  }
@@ -97,18 +96,17 @@ Environment Variables:
97
96
  console.error(`Migration Configuration:`);
98
97
  console.error(` Source: ${filePath}`);
99
98
  console.error(` DATABASE_URL: ${process.env.DATABASE_URL ? "[set]" : "[not set]"}`);
100
- console.error(` REDIS_URL: ${process.env.REDIS_URL ? "[set]" : "[not set]"}`);
101
99
  console.error("");
102
100
  // Load config
103
101
  const config = loadConfig();
104
- if (!config.database || !config.redis) {
105
- console.error("ERROR: DATABASE_URL and REDIS_URL must be set");
102
+ if (!config.database) {
103
+ console.error("ERROR: DATABASE_URL must be set");
106
104
  process.exit(1);
107
105
  }
108
106
  // Connect to database
109
107
  console.error("Connecting to database...");
110
108
  const db = await createDatabaseConnection(config, logger);
111
- const pgManager = new PostgreSQLSessionManager(db.getPool(), db.getRedis(), config.cacheTtl, logger);
109
+ const pgManager = new PostgreSQLSessionManager(db.getPool());
112
110
  console.error("✓ Connected to database\n");
113
111
  try {
114
112
  // Run migration
@@ -76,17 +76,22 @@ const GUIDANCE = {
76
76
  displayName: "Mistral Vibe CLI",
77
77
  install: {
78
78
  summary: "Install Mistral Vibe CLI via pip, uv, or Homebrew (Vibe does not self-update; cli_upgrade dispatches to the installer it detects).",
79
- commands: ["pip install vibe-cli", "uv tool install vibe-cli", "brew install mistral-vibe"],
80
- documentationUrl: "https://docs.mistral.ai/agents/vibe-cli",
79
+ commands: [
80
+ "curl -LsSf https://mistral.ai/vibe/install.sh | bash",
81
+ "pip install mistral-vibe",
82
+ "uv tool install mistral-vibe",
83
+ "brew install mistral-vibe",
84
+ ],
85
+ documentationUrl: "https://docs.mistral.ai/mistral-vibe/overview",
81
86
  },
82
87
  login: {
83
- summary: "Sign in through Mistral's official auth flow and enable session_logging in ~/.vibe/config.toml.",
84
- commands: ["vibe auth login", "vibe config set session_logging.enabled true"],
88
+ summary: "Sign in through Mistral's official auth flow. Current Vibe defaults session logging to enabled; if an older config disabled it, edit ~/.vibe/config.toml and set [session_logging] enabled = true.",
89
+ commands: ["vibe auth login"],
85
90
  credentialHandling: "Do not paste Mistral API keys, OAuth tokens, or ~/.vibe/credentials into the gateway or a remote chat.",
86
91
  },
87
92
  verification: {
88
93
  command: "vibe --version",
89
- expected: "Vibe CLI is installed; doctor additionally checks ~/.vibe/config.toml for session_logging.enabled=true",
94
+ expected: "Vibe CLI is installed; doctor checks ~/.vibe/config.toml for an explicit session_logging.enabled=false override",
90
95
  },
91
96
  },
92
97
  };
@@ -12,7 +12,7 @@ const VERSION_ARGS = {
12
12
  grok: ["--version"],
13
13
  mistral: ["--version"],
14
14
  };
15
- // Mistral Vibe ships as the `vibe` binary (PyPI package vibe-cli); the gateway
15
+ // Mistral Vibe ships as the `vibe` binary (PyPI package mistral-vibe); the gateway
16
16
  // uses `mistral` as the provider key but invokes `vibe` on the shell.
17
17
  export const PROVIDER_COMMANDS = {
18
18
  claude: "claude",
@@ -71,9 +71,9 @@ export declare function resolveGrokSessionArgs(opts: {
71
71
  /**
72
72
  * Mistral Vibe-specific resume args.
73
73
  *
74
- * Vibe persists sessions only when `[session_logging] enabled = true` is set in
75
- * `~/.vibe/config.toml`. The doctor checks for that toggle and surfaces an
76
- * actionable error when it is missing; this pure helper just emits the args.
74
+ * Current Vibe defaults session logging on; older configs can explicitly set
75
+ * `[session_logging] enabled = false`. The doctor checks that toggle before
76
+ * callers rely on session continuity; this pure helper just emits the args.
77
77
  *
78
78
  * The args shape mirrors Grok (`--continue` for latest, `--resume <id>` for a
79
79
  * specific session) because Vibe exposes the same surface for its session log.
@@ -125,6 +125,11 @@ export interface PrepareMistralRequestInput {
125
125
  * only).
126
126
  */
127
127
  maxPrice?: number;
128
+ /**
129
+ * Vibe 2.x supports `--max-tokens N` in programmatic mode, wired through to
130
+ * `run_programmatic(max_session_tokens=...)`.
131
+ */
132
+ maxTokens?: number;
128
133
  /**
129
134
  * Phase 4 slice ζ: emit `--workdir <DIR>` so Vibe changes into the named
130
135
  * directory before running. Single value (Vibe accepts one --workdir).
@@ -148,6 +153,8 @@ export interface PrepareMistralRequestResult {
148
153
  * - Model is selected via `VIBE_ACTIVE_MODEL` env var (NOT a `--model` flag).
149
154
  * - Permission mode emits `--agent <mode>` (defaults to `auto-approve` when unset).
150
155
  * - Allowed tools emit `--enabled-tools <tool>` once per tool (allowlist only).
156
+ * - Output format emits `--output <text|json|streaming>` (legacy gateway
157
+ * aliases `plain` and `stream-json` are normalized before spawn).
151
158
  * - Disallowed tools are accepted but ignored at the CLI boundary.
152
159
  */
153
160
  export declare function prepareMistralRequest(input: PrepareMistralRequestInput): PrepareMistralRequestResult;
@@ -100,9 +100,9 @@ export function resolveGrokSessionArgs(opts) {
100
100
  /**
101
101
  * Mistral Vibe-specific resume args.
102
102
  *
103
- * Vibe persists sessions only when `[session_logging] enabled = true` is set in
104
- * `~/.vibe/config.toml`. The doctor checks for that toggle and surfaces an
105
- * actionable error when it is missing; this pure helper just emits the args.
103
+ * Current Vibe defaults session logging on; older configs can explicitly set
104
+ * `[session_logging] enabled = false`. The doctor checks that toggle before
105
+ * callers rely on session continuity; this pure helper just emits the args.
106
106
  *
107
107
  * The args shape mirrors Grok (`--continue` for latest, `--resume <id>` for a
108
108
  * specific session) because Vibe exposes the same surface for its session log.
@@ -151,6 +151,8 @@ export const MISTRAL_DEFAULT_AGENT_MODE = "auto-approve";
151
151
  * - Model is selected via `VIBE_ACTIVE_MODEL` env var (NOT a `--model` flag).
152
152
  * - Permission mode emits `--agent <mode>` (defaults to `auto-approve` when unset).
153
153
  * - Allowed tools emit `--enabled-tools <tool>` once per tool (allowlist only).
154
+ * - Output format emits `--output <text|json|streaming>` (legacy gateway
155
+ * aliases `plain` and `stream-json` are normalized before spawn).
154
156
  * - Disallowed tools are accepted but ignored at the CLI boundary.
155
157
  */
156
158
  export function prepareMistralRequest(input) {
@@ -160,7 +162,7 @@ export function prepareMistralRequest(input) {
160
162
  env.VIBE_ACTIVE_MODEL = input.resolvedModel;
161
163
  }
162
164
  if (input.outputFormat) {
163
- args.push("--output-format", input.outputFormat);
165
+ args.push("--output", normalizeMistralOutputFormat(input.outputFormat));
164
166
  }
165
167
  const mode = input.permissionMode ?? MISTRAL_DEFAULT_AGENT_MODE;
166
168
  args.push("--agent", mode);
@@ -185,6 +187,9 @@ export function prepareMistralRequest(input) {
185
187
  if (input.maxPrice !== undefined) {
186
188
  args.push("--max-price", String(input.maxPrice));
187
189
  }
190
+ if (input.maxTokens !== undefined) {
191
+ args.push("--max-tokens", String(input.maxTokens));
192
+ }
188
193
  if (input.workingDir) {
189
194
  args.push("--workdir", input.workingDir);
190
195
  }
@@ -196,6 +201,13 @@ export function prepareMistralRequest(input) {
196
201
  const ignoredDisallowedTools = Boolean(input.disallowedTools && input.disallowedTools.length > 0);
197
202
  return { args, env, ignoredDisallowedTools };
198
203
  }
204
+ function normalizeMistralOutputFormat(format) {
205
+ if (format === "plain")
206
+ return "text";
207
+ if (format === "stream-json")
208
+ return "streaming";
209
+ return format;
210
+ }
199
211
  //──────────────────────────────────────────────────────────────────────────────
200
212
  // U24: Permission / approval mode parity helpers
201
213
  //──────────────────────────────────────────────────────────────────────────────
@@ -1,77 +1,48 @@
1
1
  import type { Pool } from "pg";
2
- import type { Redis } from "ioredis";
3
2
  import { Session, CliType } from "./session-manager.js";
4
- import { CacheTtl } from "./config.js";
5
- import type { Logger } from "./logger.js";
6
3
  export type { Logger } from "./logger.js";
7
4
  /**
8
- * PostgreSQL-backed session manager with Redis caching
5
+ * PostgreSQL-backed session manager. PostgreSQL is the source of truth and
6
+ * the only required service for this backend.
9
7
  */
10
8
  export declare class PostgreSQLSessionManager {
11
9
  private pool;
12
- private redis;
13
- private cacheTtl;
14
- private logger;
15
- constructor(pool: Pool, redis: Redis, cacheTtl: CacheTtl, logger: Logger);
10
+ constructor(pool: Pool);
16
11
  /**
17
- * Acquire distributed lock using Redis SET NX EX
18
- * Returns [success, lockValue] tuple
19
- */
20
- private acquireLock;
21
- private sleep;
22
- /**
23
- * Acquire a distributed lock with bounded retries to smooth contention spikes.
24
- */
25
- private acquireLockWithRetry;
26
- /**
27
- * Release distributed lock with optimistic Redis transaction semantics.
28
- * Only releases if lockValue matches, which prevents releasing another
29
- * process's lock after expiry/reacquire.
30
- */
31
- private releaseLock;
32
- /**
33
- * Invalidate session cache
34
- */
35
- private invalidateCache;
36
- /**
37
- * Invalidate session list cache using SCAN (non-blocking)
38
- */
39
- private invalidateListCache;
40
- /**
41
- * Create a new session
12
+ * Create a new session.
42
13
  */
43
14
  createSession(cli: CliType, description?: string, sessionId?: string): Promise<Session>;
44
15
  /**
45
- * Get session by ID (cache-aside pattern)
16
+ * Get session by ID.
46
17
  */
47
18
  getSession(sessionId: string): Promise<Session | null>;
48
19
  /**
49
- * List all sessions, optionally filtered by CLI
20
+ * List all sessions, optionally filtered by CLI.
50
21
  */
51
22
  listSessions(cli?: CliType): Promise<Session[]>;
52
23
  /**
53
- * Delete a session
24
+ * Delete a session.
54
25
  */
55
26
  deleteSession(sessionId: string): Promise<boolean>;
56
27
  /**
57
- * Set active session for a CLI (with distributed locking)
28
+ * Set active session for a CLI. The row-level update is serialized by
29
+ * PostgreSQL and the session FK keeps stale IDs from being recorded.
58
30
  */
59
31
  setActiveSession(cli: CliType, sessionId: string | null): Promise<boolean>;
60
32
  /**
61
- * Get active session for a CLI
33
+ * Get active session for a CLI.
62
34
  */
63
35
  getActiveSession(cli: CliType): Promise<Session | null>;
64
36
  /**
65
- * Update session usage timestamp
37
+ * Update session usage timestamp.
66
38
  */
67
39
  updateSessionUsage(sessionId: string): Promise<void>;
68
40
  /**
69
- * Update session metadata (atomic JSONB merge)
41
+ * Update session metadata using PostgreSQL's atomic JSONB merge.
70
42
  */
71
43
  updateSessionMetadata(sessionId: string, metadata: Record<string, any>): Promise<boolean>;
72
44
  /**
73
- * Clear all sessions, optionally filtered by CLI
74
- * Invalidates all related caches (session, active, list)
45
+ * Clear all sessions, optionally filtered by CLI.
75
46
  */
76
47
  clearAllSessions(cli?: CliType): Promise<number>;
77
48
  }