llm-cli-gateway 2.8.0 → 2.9.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.
@@ -1,4 +1,5 @@
1
1
  import { randomUUID } from "crypto";
2
+ import { getRequestContext, resolveOwnerPrincipal } from "./request-context.js";
2
3
  const DEFAULT_SESSION_DESCRIPTIONS = {
3
4
  claude: "Claude Session",
4
5
  codex: "Codex Session",
@@ -16,11 +17,12 @@ export class PostgreSQLSessionManager {
16
17
  const id = sessionId || randomUUID();
17
18
  const sessionDescription = description ?? DEFAULT_SESSION_DESCRIPTIONS[cli];
18
19
  const now = new Date().toISOString();
20
+ const ownerPrincipal = resolveOwnerPrincipal(getRequestContext());
19
21
  const client = await this.pool.connect();
20
22
  try {
21
23
  await client.query("BEGIN");
22
- await client.query(`INSERT INTO sessions (id, cli, description, created_at, last_used_at)
23
- VALUES ($1, $2, $3, $4, $5)`, [id, cli, sessionDescription, now, now]);
24
+ await client.query(`INSERT INTO sessions (id, cli, description, created_at, last_used_at, owner_principal)
25
+ VALUES ($1, $2, $3, $4, $5, $6)`, [id, cli, sessionDescription, now, now, ownerPrincipal]);
24
26
  await client.query(`INSERT INTO active_sessions (cli, session_id, updated_at)
25
27
  VALUES ($1, $2, $3)
26
28
  ON CONFLICT (cli) DO NOTHING`, [cli, id, now]);
@@ -31,6 +33,7 @@ export class PostgreSQLSessionManager {
31
33
  createdAt: now,
32
34
  lastUsedAt: now,
33
35
  description: sessionDescription,
36
+ ownerPrincipal,
34
37
  };
35
38
  }
36
39
  catch (error) {
@@ -42,18 +45,18 @@ export class PostgreSQLSessionManager {
42
45
  }
43
46
  }
44
47
  async getSession(sessionId) {
45
- const result = await this.pool.query(`SELECT id, cli, description, metadata, created_at AS "createdAt", last_used_at AS "lastUsedAt"
48
+ const result = await this.pool.query(`SELECT id, cli, description, metadata, created_at AS "createdAt", last_used_at AS "lastUsedAt", owner_principal AS "ownerPrincipal"
46
49
  FROM sessions
47
50
  WHERE id = $1`, [sessionId]);
48
51
  return result.rows[0] ?? null;
49
52
  }
50
53
  async listSessions(cli) {
51
54
  const query = cli
52
- ? `SELECT id, cli, description, metadata, created_at AS "createdAt", last_used_at AS "lastUsedAt"
55
+ ? `SELECT id, cli, description, metadata, created_at AS "createdAt", last_used_at AS "lastUsedAt", owner_principal AS "ownerPrincipal"
53
56
  FROM sessions
54
57
  WHERE cli = $1
55
58
  ORDER BY last_used_at DESC`
56
- : `SELECT id, cli, description, metadata, created_at AS "createdAt", last_used_at AS "lastUsedAt"
59
+ : `SELECT id, cli, description, metadata, created_at AS "createdAt", last_used_at AS "lastUsedAt", owner_principal AS "ownerPrincipal"
57
60
  FROM sessions
58
61
  ORDER BY last_used_at DESC`;
59
62
  const result = cli
@@ -14,6 +14,7 @@ export interface Session {
14
14
  lastUsedAt: string;
15
15
  description?: string;
16
16
  metadata?: Record<string, any>;
17
+ ownerPrincipal?: string | null;
17
18
  }
18
19
  export interface SessionStorage {
19
20
  sessions: Record<string, Session>;
@@ -4,6 +4,7 @@ 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
+ import { getRequestContext, resolveOwnerPrincipal } from "./request-context.js";
7
8
  export const CLI_TYPES = ["claude", "codex", "gemini", "grok", "mistral"];
8
9
  export const API_PROVIDER_TYPES = ["grok-api"];
9
10
  export const PROVIDER_TYPES = [...CLI_TYPES, ...API_PROVIDER_TYPES];
@@ -113,6 +114,7 @@ export class FileSessionManager {
113
114
  createdAt: new Date().toISOString(),
114
115
  lastUsedAt: new Date().toISOString(),
115
116
  description: sessionDescription,
117
+ ownerPrincipal: resolveOwnerPrincipal(getRequestContext()),
116
118
  };
117
119
  this.storage.sessions[id] = session;
118
120
  if (!this.storage.activeSession[cli]) {
@@ -0,0 +1,10 @@
1
+ -- F3: per-principal isolation. Add an ownership principal to PostgreSQL-backed
2
+ -- sessions, mirroring the file backend's `ownerPrincipal` and the job store's
3
+ -- `owner_principal`. Additive and nullable: rows created before this migration
4
+ -- keep NULL and are treated as legacy-unowned by F3b enforcement.
5
+
6
+ ALTER TABLE sessions ADD COLUMN IF NOT EXISTS owner_principal TEXT;
7
+
8
+ INSERT INTO schema_migrations (version, name)
9
+ VALUES (4, '004_session_owner_principal')
10
+ ON CONFLICT (version) DO NOTHING;
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "llm-cli-gateway",
3
- "version": "2.8.0",
3
+ "version": "2.9.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "llm-cli-gateway",
9
- "version": "2.8.0",
9
+ "version": "2.9.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@modelcontextprotocol/sdk": "^1.29.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "llm-cli-gateway",
3
- "version": "2.8.0",
3
+ "version": "2.9.0",
4
4
  "mcpName": "io.github.verivus-oss/llm-cli-gateway",
5
5
  "description": "MCP server providing unified access to Claude Code, Codex, Gemini, Grok, and Mistral Vibe CLIs with session management, retry logic, async job orchestration, durable job results, and cross-LLM validation.",
6
6
  "license": "MIT",