llm-cli-gateway 1.17.9 → 2.0.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.
- package/CHANGELOG.md +101 -0
- package/README.md +4 -2
- package/dist/flight-recorder.d.ts +3 -0
- package/dist/flight-recorder.js +22 -20
- package/dist/job-store.js +6 -12
- package/dist/sqlite-driver.d.ts +16 -0
- package/dist/sqlite-driver.js +149 -0
- package/npm-shrinkwrap.json +3 -348
- package/package.json +4 -5
- package/socket.yml +20 -11
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,107 @@ All notable changes to the llm-cli-gateway project.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## [2.0.0] - 2026-06-04: node:sqlite migration — native module out of the prod graph
|
|
8
|
+
|
|
9
|
+
Major release. Persistence moves from the native `better-sqlite3` binding to
|
|
10
|
+
Node's built-in `node:sqlite` module behind a thin adapter. The entire
|
|
11
|
+
1.17.6-1.17.8 supply-chain incident class — every one of which traced to
|
|
12
|
+
`better-sqlite3`'s install path (`prebuild-install → tar-fs → tar-stream`),
|
|
13
|
+
not its runtime — is now **structurally** gone: the production dependency
|
|
14
|
+
graph contains zero native modules, zero install scripts, and no
|
|
15
|
+
`prebuild-install`/`tar-fs`/`tar-stream` chain. Verified end to end against a
|
|
16
|
+
verdaccio registry reproduction (`scripts/verify-registry-install.sh`):
|
|
17
|
+
consumer tree reified at 94 packages (down from ~124 in 1.17.9), `npm ls`
|
|
18
|
+
exits 0, and no `better-sqlite3`/`tar-stream`/`prebuild-install` appears
|
|
19
|
+
anywhere in the consumer tree.
|
|
20
|
+
|
|
21
|
+
### BREAKING
|
|
22
|
+
|
|
23
|
+
- **`engines.node` is now `>=24.4.0`** (was `>=20.0.0`). Node 20 is EOL
|
|
24
|
+
(April 2026). The 24.4 floor is required because `node:sqlite`'s
|
|
25
|
+
`allowBareNamedParameters` defaults to `true` only from Node 24.4 — the
|
|
26
|
+
persistence layer binds bare `{ id: ... }` objects to `@id` placeholders
|
|
27
|
+
throughout, and on 24.0-24.3 that would need a per-statement
|
|
28
|
+
`setAllowBareNamedParameters(true)` call. The adapter unit tests assert
|
|
29
|
+
bare-name binding works, so a regression in either direction is caught.
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- `src/sqlite-driver.ts`: thin adapter over `node:sqlite`'s `DatabaseSync`.
|
|
34
|
+
Exports `openDatabase`, `openReadOnly`, and a `GatewayDatabase` /
|
|
35
|
+
`GatewayStatement` surface (`exec`/`prepare`/`run`/`get`/`all`/
|
|
36
|
+
`withTransaction`/`close`). It is the ONLY production module that touches
|
|
37
|
+
`node:sqlite`; the release security audit hard-fails if any other
|
|
38
|
+
production module references it. Preserves the flight recorder's
|
|
39
|
+
graceful-degradation path (constructor failure → recorder disabled, gateway
|
|
40
|
+
still runs).
|
|
41
|
+
- Read-only `queryRequests` connection: `openReadOnly` opens the DB with
|
|
42
|
+
`{ readOnly: true }`, so write-disguised-as-read SQL fails at the SQLite
|
|
43
|
+
engine level (`SQLITE_READONLY`). This is **stronger** than the old
|
|
44
|
+
better-sqlite3 `stmt.readonly` JS-property check it replaces — enforcement
|
|
45
|
+
is at the engine, not in JavaScript — with one belt-and-braces guard: the
|
|
46
|
+
read-only connection also rejects `VACUUM`/`VACUUM INTO`, the one statement
|
|
47
|
+
that writes a new file to disk despite `{ readOnly: true }` (and that
|
|
48
|
+
`stmt.readonly` previously blocked). ATTACH-then-write and
|
|
49
|
+
`writable_schema` schema edits are already engine-rejected.
|
|
50
|
+
- Cross-engine WAL crash-recovery fixtures in both directions
|
|
51
|
+
(`src/__tests__/cross-engine-wal.test.ts`): a `better-sqlite3`-written DB
|
|
52
|
+
(SQLite 3.53.1) with live `-wal`/`-shm` from a simulated unclean stop is
|
|
53
|
+
opened and exercised under `node:sqlite` (3.51.3), and the reverse for the
|
|
54
|
+
rollback direction. These gate the "zero data migration" claim across the
|
|
55
|
+
engine-version skew.
|
|
56
|
+
|
|
57
|
+
### Changed
|
|
58
|
+
|
|
59
|
+
- `better-sqlite3` **moved from `dependencies` to `devDependencies`** (same
|
|
60
|
+
`^12.10.0` range; `@types/better-sqlite3` stays in devDependencies). It is
|
|
61
|
+
retained at dev time deliberately: two suites seed legacy-schema DB files
|
|
62
|
+
with it (`src/__tests__/flight-recorder.test.ts`,
|
|
63
|
+
`src/__tests__/test-veracity-regressions-slice-kappa.test.ts`) to simulate
|
|
64
|
+
databases written by pre-2.0.0 gateways — that realism is the point, and it
|
|
65
|
+
makes them standing old-engine-writer → node:sqlite-reader coverage on every
|
|
66
|
+
CI run — and the cross-engine WAL fixtures need a better-sqlite3 writer.
|
|
67
|
+
Consumers never see it: devDependencies do not install transitively, and the
|
|
68
|
+
prod-only shrinkwrap excludes the whole subtree.
|
|
69
|
+
- `flight-recorder.ts` / `job-store.ts` now open SQLite through the adapter
|
|
70
|
+
(`openDatabase`/`openReadOnly`/`withTransaction`) instead of
|
|
71
|
+
`require("better-sqlite3")`. SQL, schema, migrations, and pragmas are
|
|
72
|
+
unchanged.
|
|
73
|
+
- `package.json#overrides`: the `tar-stream` pin is **removed** (the chain
|
|
74
|
+
that needed it is gone from the prod graph). The `type-is` and `content-type`
|
|
75
|
+
pins stay — unrelated to this chain.
|
|
76
|
+
- `scripts/release-security-audit.sh`: the `consumerAdvisory` carve-out is
|
|
77
|
+
**deleted** — blocked `tar-stream` versions are now hard-fail tripwires
|
|
78
|
+
everywhere (the chain no longer exists in any prod tree). The packed-consumer
|
|
79
|
+
policy now hard-fails on ANY `tar-stream` in the consumer tree (was an
|
|
80
|
+
advisory warning). The repo-lockfile tripwire skips dev-only entries so the
|
|
81
|
+
deliberate devDependency `tar-stream@2.2.0` does not false-fail, while still
|
|
82
|
+
hard-failing any blocked version that re-enters the prod graph. The
|
|
83
|
+
better-sqlite3 PRAGMA scan is repointed at the adapter: it now also asserts
|
|
84
|
+
`node:sqlite` is referenced only by `src/sqlite-driver.ts`.
|
|
85
|
+
- `scripts/pre-release.sh`: the better-sqlite3 native-binding sanity guard is
|
|
86
|
+
removed (the test suite exercises the binding as a devDep and fails loudly if
|
|
87
|
+
broken); the `npm ls tar-stream` step is replaced by an absence assertion
|
|
88
|
+
against the generated prod-only shrinkwrap
|
|
89
|
+
(`better-sqlite3`/`prebuild-install`/`tar-fs`/`tar-stream` must be absent).
|
|
90
|
+
- `scripts/verify-registry-install.sh`: assertions updated for 2.0.0 —
|
|
91
|
+
`tar-stream`/`better-sqlite3`/`prebuild-install` must be ABSENT from the
|
|
92
|
+
consumer tree; consumer `npm ls` must exit 0 (the out-of-range pin that
|
|
93
|
+
caused ELSPROBLEMS is gone); a `node:sqlite` runtime smoke
|
|
94
|
+
(`new DatabaseSync(':memory:')`) confirms the engine; and the reified package
|
|
95
|
+
count is asserted at 94 ±2.
|
|
96
|
+
- README, `socket.yml`, and `docs/personal-mcp/RELEASE_READINESS.md` updated to
|
|
97
|
+
reflect the node:sqlite reality (no native binding, no install scripts,
|
|
98
|
+
Node >=24.4.0, adapter-isolation audit replacing the PRAGMA-helper note).
|
|
99
|
+
|
|
100
|
+
### Rollback
|
|
101
|
+
|
|
102
|
+
Reverting the 2.0.0 commit re-adds `better-sqlite3` to `dependencies`, the
|
|
103
|
+
`tar-stream` override, and the audit advisory carve-out. DB files are
|
|
104
|
+
compatible in both directions — exactly what the cross-engine WAL fixtures
|
|
105
|
+
prove (the rollback claim inherits that gate; it is not asserted
|
|
106
|
+
independently).
|
|
107
|
+
|
|
7
108
|
## [1.17.9] - 2026-06-04: prod-only shrinkwrap + registry-fidelity verification
|
|
8
109
|
|
|
9
110
|
Patch release shipping a prod-only `npm-shrinkwrap.json` and correcting the
|
package/README.md
CHANGED
|
@@ -214,6 +214,8 @@ Opt-in flags (all default off) live under `[cache_awareness]` in `~/.llm-cli-gat
|
|
|
214
214
|
|
|
215
215
|
## Prerequisites
|
|
216
216
|
|
|
217
|
+
**Node.js >= 24.4.0** is required (`engines.node` in `package.json`). The gateway uses Node's built-in `node:sqlite` module for persistence — there is no native binding to compile and no install scripts run. The 24.4 floor is where `allowBareNamedParameters` defaults to `true`, which the persistence layer relies on.
|
|
218
|
+
|
|
217
219
|
Before using this gateway, you need to install the CLI tools you want to use:
|
|
218
220
|
|
|
219
221
|
### Claude Code CLI
|
|
@@ -1180,8 +1182,8 @@ If you're vetting `llm-cli-gateway` through [Socket](https://socket.dev/npm/pack
|
|
|
1180
1182
|
| **Network access** | `src/http-transport.ts` opens an HTTP MCP transport when started via `npm run start:http`. `src/endpoint-exposure.ts` issues a HEAD probe to verify configured public/tunnel URLs. Socket also flagged `dist/upstream-contracts.js` in v1.17.2 from descriptive text, not a network call. | The transport binds to `127.0.0.1` by default and requires `LLM_GATEWAY_AUTH_TOKEN` to be set. The default stdio MCP entry point (`npm start`) opens no sockets. `src/upstream-contracts.ts` stores provider CLI metadata and imports no HTTP client APIs. |
|
|
1181
1183
|
| **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`). |
|
|
1182
1184
|
| **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. |
|
|
1183
|
-
| **
|
|
1184
|
-
| **Dependency ownership** | A handful of small transitive packages (e.g. `
|
|
1185
|
+
| **SQLite adapter isolation** | Persistence uses Node's built-in `node:sqlite` module (no native binding, no install scripts) through a single adapter, `src/sqlite-driver.ts`. | `node:sqlite` is touched by exactly one production module (the adapter); every other module talks to SQLite through its typed surface. We never call any `db.pragma()` helper (it does not exist on `node:sqlite`); SQLite setup uses fixed literal `db.exec("PRAGMA ...")` statements. `npm run security:audit` fails the release if production code references `node:sqlite` outside the adapter or reintroduces a `.pragma()` call. |
|
|
1186
|
+
| **Dependency ownership** | A handful of small transitive packages (e.g. `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`. As of 2.0.0 the prod graph carries no native module (`better-sqlite3` moved to devDependencies; `node:sqlite` is built into Node), eliminating the entire `prebuild-install`/`tar-fs`/`tar-stream` install-time chain. Our earlier direct dependency on `toml@3.0.0` was replaced with `smol-toml`. |
|
|
1185
1187
|
|
|
1186
1188
|
See [`socket.yml`](./socket.yml) for the same context in machine-readable form.
|
|
1187
1189
|
|
|
@@ -34,6 +34,9 @@ interface LoggerLike {
|
|
|
34
34
|
export declare function resolveFlightRecorderDbPath(): string | null;
|
|
35
35
|
export declare class FlightRecorder {
|
|
36
36
|
private db;
|
|
37
|
+
private readOnlyDb;
|
|
38
|
+
private closed;
|
|
39
|
+
private readonly dbPath;
|
|
37
40
|
private insertStartTxn;
|
|
38
41
|
private updateCompleteTxn;
|
|
39
42
|
constructor(dbPath: string);
|
package/dist/flight-recorder.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { chmodSync
|
|
1
|
+
import { chmodSync } from "fs";
|
|
2
2
|
import os from "os";
|
|
3
3
|
import path from "path";
|
|
4
|
-
import {
|
|
4
|
+
import { openDatabase, openReadOnly } from "./sqlite-driver.js";
|
|
5
5
|
const MAX_THINKING_BYTES = 1_000_000;
|
|
6
6
|
function ensureRequestsCacheColumns(db) {
|
|
7
|
-
const rows = db.prepare("PRAGMA table_info(requests)").all
|
|
7
|
+
const rows = db.prepare("PRAGMA table_info(requests)").all();
|
|
8
8
|
const names = new Set(rows.map((row) => (row && typeof row.name === "string" ? row.name : "")));
|
|
9
9
|
if (!names.has("cache_read_tokens")) {
|
|
10
10
|
db.exec("ALTER TABLE requests ADD COLUMN cache_read_tokens INTEGER");
|
|
@@ -14,7 +14,7 @@ function ensureRequestsCacheColumns(db) {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
function ensureStablePrefixColumns(db) {
|
|
17
|
-
const rows = db.prepare("PRAGMA table_info(requests)").all
|
|
17
|
+
const rows = db.prepare("PRAGMA table_info(requests)").all();
|
|
18
18
|
const names = new Set(rows.map((row) => (row && typeof row.name === "string" ? row.name : "")));
|
|
19
19
|
if (!names.has("stable_prefix_hash")) {
|
|
20
20
|
db.exec("ALTER TABLE requests ADD COLUMN stable_prefix_hash TEXT");
|
|
@@ -25,7 +25,7 @@ function ensureStablePrefixColumns(db) {
|
|
|
25
25
|
db.exec("CREATE INDEX IF NOT EXISTS idx_requests_stable_hash ON requests(stable_prefix_hash)");
|
|
26
26
|
}
|
|
27
27
|
function ensureCacheControlBlocksColumn(db) {
|
|
28
|
-
const rows = db.prepare("PRAGMA table_info(requests)").all
|
|
28
|
+
const rows = db.prepare("PRAGMA table_info(requests)").all();
|
|
29
29
|
const names = new Set(rows.map((row) => (row && typeof row.name === "string" ? row.name : "")));
|
|
30
30
|
if (!names.has("cache_control_blocks")) {
|
|
31
31
|
db.exec("ALTER TABLE requests ADD COLUMN cache_control_blocks INTEGER");
|
|
@@ -77,16 +77,14 @@ function truncateThinkingBlocks(blocks) {
|
|
|
77
77
|
}
|
|
78
78
|
export class FlightRecorder {
|
|
79
79
|
db;
|
|
80
|
+
readOnlyDb = null;
|
|
81
|
+
closed = false;
|
|
82
|
+
dbPath;
|
|
80
83
|
insertStartTxn;
|
|
81
84
|
updateCompleteTxn;
|
|
82
85
|
constructor(dbPath) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const directory = path.dirname(dbPath);
|
|
86
|
-
if (!existsSync(directory)) {
|
|
87
|
-
mkdirSync(directory, { recursive: true });
|
|
88
|
-
}
|
|
89
|
-
this.db = new BetterSqlite3(dbPath);
|
|
86
|
+
this.dbPath = dbPath;
|
|
87
|
+
this.db = openDatabase(dbPath);
|
|
90
88
|
this.db.exec("PRAGMA journal_mode = WAL");
|
|
91
89
|
this.db.exec("PRAGMA foreign_keys = ON");
|
|
92
90
|
this.db.exec(`
|
|
@@ -165,7 +163,7 @@ export class FlightRecorder {
|
|
|
165
163
|
INSERT INTO gateway_metadata (request_id, async_job_id, status)
|
|
166
164
|
VALUES (@request_id, @async_job_id, 'started')
|
|
167
165
|
`);
|
|
168
|
-
this.insertStartTxn = this.db.
|
|
166
|
+
this.insertStartTxn = this.db.withTransaction((entry) => {
|
|
169
167
|
insertRequest.run({
|
|
170
168
|
id: entry.correlationId,
|
|
171
169
|
cli: entry.cli,
|
|
@@ -206,7 +204,7 @@ export class FlightRecorder {
|
|
|
206
204
|
status = @status
|
|
207
205
|
WHERE request_id = @id AND status = 'started'
|
|
208
206
|
`);
|
|
209
|
-
this.updateCompleteTxn = this.db.
|
|
207
|
+
this.updateCompleteTxn = this.db.withTransaction((correlationId, result) => {
|
|
210
208
|
const thinkingBlocks = result.thinkingBlocks && result.thinkingBlocks.length > 0
|
|
211
209
|
? JSON.stringify(truncateThinkingBlocks(result.thinkingBlocks))
|
|
212
210
|
: null;
|
|
@@ -240,18 +238,22 @@ export class FlightRecorder {
|
|
|
240
238
|
this.updateCompleteTxn(correlationId, result);
|
|
241
239
|
}
|
|
242
240
|
queryRequests(sql, ...params) {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
throw new Error("FlightRecorder.queryRequests refuses non-readonly SQL — use a transaction or a separate write surface for INSERT/UPDATE/DELETE.");
|
|
241
|
+
if (this.closed) {
|
|
242
|
+
throw new Error("flight recorder is closed");
|
|
246
243
|
}
|
|
247
|
-
if (!
|
|
248
|
-
|
|
244
|
+
if (!this.readOnlyDb) {
|
|
245
|
+
this.readOnlyDb = openReadOnly(this.dbPath);
|
|
249
246
|
}
|
|
250
|
-
return
|
|
247
|
+
return this.readOnlyDb.prepare(sql).all(...params);
|
|
251
248
|
}
|
|
252
249
|
flush() {
|
|
253
250
|
}
|
|
254
251
|
close() {
|
|
252
|
+
this.closed = true;
|
|
253
|
+
if (this.readOnlyDb) {
|
|
254
|
+
this.readOnlyDb.close();
|
|
255
|
+
this.readOnlyDb = null;
|
|
256
|
+
}
|
|
255
257
|
this.db.close();
|
|
256
258
|
}
|
|
257
259
|
}
|
package/dist/job-store.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { chmodSync
|
|
1
|
+
import { chmodSync } from "fs";
|
|
2
2
|
import os from "os";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { createHash } from "crypto";
|
|
5
|
-
import {
|
|
5
|
+
import { openDatabase } from "./sqlite-driver.js";
|
|
6
6
|
import { noopLogger } from "./logger.js";
|
|
7
7
|
export function resolveJobStoreDbPath() {
|
|
8
8
|
const configured = process.env.LLM_GATEWAY_JOBS_DB ?? process.env.LLM_GATEWAY_LOGS_DB;
|
|
@@ -74,13 +74,7 @@ export class SqliteJobStore {
|
|
|
74
74
|
deleteExpiredStmt;
|
|
75
75
|
constructor(dbPath, logger = noopLogger, options = {}) {
|
|
76
76
|
this.logger = logger;
|
|
77
|
-
|
|
78
|
-
const BetterSqlite3 = require("better-sqlite3");
|
|
79
|
-
const directory = path.dirname(dbPath);
|
|
80
|
-
if (!existsSync(directory)) {
|
|
81
|
-
mkdirSync(directory, { recursive: true });
|
|
82
|
-
}
|
|
83
|
-
this.db = new BetterSqlite3(dbPath);
|
|
77
|
+
this.db = openDatabase(dbPath);
|
|
84
78
|
this.db.exec("PRAGMA journal_mode = WAL");
|
|
85
79
|
this.db.exec("PRAGMA synchronous = NORMAL");
|
|
86
80
|
this.db.exec(`
|
|
@@ -211,7 +205,7 @@ export class SqliteJobStore {
|
|
|
211
205
|
markOrphanedOnStartup() {
|
|
212
206
|
const now = new Date().toISOString();
|
|
213
207
|
const expiresAt = new Date(Date.now() + this.retentionMs).toISOString();
|
|
214
|
-
const rows =
|
|
208
|
+
const rows = this.selectRunningOrphansStmt.all();
|
|
215
209
|
const orphaned = rows.map(row => ({
|
|
216
210
|
id: row.id,
|
|
217
211
|
correlationId: row.correlation_id,
|
|
@@ -221,12 +215,12 @@ export class SqliteJobStore {
|
|
|
221
215
|
exitCode: row.exit_code,
|
|
222
216
|
}));
|
|
223
217
|
const result = this.markOrphanedStmt.run(now, expiresAt);
|
|
224
|
-
return { count: result
|
|
218
|
+
return { count: Number(result.changes), orphaned };
|
|
225
219
|
}
|
|
226
220
|
evictExpired() {
|
|
227
221
|
const now = new Date().toISOString();
|
|
228
222
|
const result = this.deleteExpiredStmt.run(now);
|
|
229
|
-
return result
|
|
223
|
+
return Number(result.changes);
|
|
230
224
|
}
|
|
231
225
|
close() {
|
|
232
226
|
try {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface GatewayStatement {
|
|
2
|
+
run(...args: unknown[]): {
|
|
3
|
+
changes: number;
|
|
4
|
+
lastInsertRowid: number | bigint;
|
|
5
|
+
};
|
|
6
|
+
get(...args: unknown[]): unknown;
|
|
7
|
+
all(...args: unknown[]): unknown[];
|
|
8
|
+
}
|
|
9
|
+
export interface GatewayDatabase {
|
|
10
|
+
exec(sql: string): void;
|
|
11
|
+
prepare(sql: string): GatewayStatement;
|
|
12
|
+
withTransaction<A extends unknown[]>(fn: (...args: A) => void): (...args: A) => void;
|
|
13
|
+
close(): void;
|
|
14
|
+
}
|
|
15
|
+
export declare function openDatabase(dbPath: string): GatewayDatabase;
|
|
16
|
+
export declare function openReadOnly(dbPath: string): GatewayDatabase;
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { existsSync, mkdirSync } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { createRequire } from "module";
|
|
4
|
+
function loadNodeSqlite() {
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
return require("node:sqlite");
|
|
7
|
+
}
|
|
8
|
+
function wrapStatement(stmt) {
|
|
9
|
+
return {
|
|
10
|
+
run(...args) {
|
|
11
|
+
return stmt.run(...args);
|
|
12
|
+
},
|
|
13
|
+
get(...args) {
|
|
14
|
+
return stmt.get(...args);
|
|
15
|
+
},
|
|
16
|
+
all(...args) {
|
|
17
|
+
return stmt.all(...args);
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function statementLeadingKeywords(sql) {
|
|
22
|
+
const keywords = [];
|
|
23
|
+
let i = 0;
|
|
24
|
+
const skipTrivia = () => {
|
|
25
|
+
for (;;) {
|
|
26
|
+
while (i < sql.length && /\s|;/.test(sql[i] ?? ""))
|
|
27
|
+
i++;
|
|
28
|
+
if (sql.startsWith("--", i)) {
|
|
29
|
+
i += 2;
|
|
30
|
+
while (i < sql.length && sql[i] !== "\n")
|
|
31
|
+
i++;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (sql.startsWith("/*", i)) {
|
|
35
|
+
const end = sql.indexOf("*/", i + 2);
|
|
36
|
+
i = end === -1 ? sql.length : end + 2;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
const skipQuoted = (quote) => {
|
|
43
|
+
i++;
|
|
44
|
+
while (i < sql.length) {
|
|
45
|
+
if (sql[i] === quote) {
|
|
46
|
+
if (sql[i + 1] === quote) {
|
|
47
|
+
i += 2;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
i++;
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
i++;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
while (i < sql.length) {
|
|
57
|
+
skipTrivia();
|
|
58
|
+
const m = /^[a-zA-Z]+/.exec(sql.slice(i));
|
|
59
|
+
if (m) {
|
|
60
|
+
keywords.push(m[0].toUpperCase());
|
|
61
|
+
}
|
|
62
|
+
while (i < sql.length && sql[i] !== ";") {
|
|
63
|
+
if (sql.startsWith("--", i)) {
|
|
64
|
+
i += 2;
|
|
65
|
+
while (i < sql.length && sql[i] !== "\n")
|
|
66
|
+
i++;
|
|
67
|
+
}
|
|
68
|
+
else if (sql.startsWith("/*", i)) {
|
|
69
|
+
const end = sql.indexOf("*/", i + 2);
|
|
70
|
+
i = end === -1 ? sql.length : end + 2;
|
|
71
|
+
}
|
|
72
|
+
else if (sql[i] === "'" || sql[i] === '"' || sql[i] === "`") {
|
|
73
|
+
skipQuoted(sql[i]);
|
|
74
|
+
}
|
|
75
|
+
else if (sql[i] === "[") {
|
|
76
|
+
i++;
|
|
77
|
+
while (i < sql.length && sql[i] !== "]")
|
|
78
|
+
i++;
|
|
79
|
+
if (i < sql.length)
|
|
80
|
+
i++;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
i++;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return keywords;
|
|
88
|
+
}
|
|
89
|
+
class GatewayDatabaseImpl {
|
|
90
|
+
db;
|
|
91
|
+
readOnly;
|
|
92
|
+
inTransaction = false;
|
|
93
|
+
constructor(db, readOnly = false) {
|
|
94
|
+
this.db = db;
|
|
95
|
+
this.readOnly = readOnly;
|
|
96
|
+
}
|
|
97
|
+
guardReadOnly(sql) {
|
|
98
|
+
if (this.readOnly && statementLeadingKeywords(sql).includes("VACUUM")) {
|
|
99
|
+
throw new Error("read-only connection rejects VACUUM (writes to disk despite readOnly)");
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
exec(sql) {
|
|
103
|
+
this.guardReadOnly(sql);
|
|
104
|
+
this.db.exec(sql);
|
|
105
|
+
}
|
|
106
|
+
prepare(sql) {
|
|
107
|
+
this.guardReadOnly(sql);
|
|
108
|
+
return wrapStatement(this.db.prepare(sql));
|
|
109
|
+
}
|
|
110
|
+
withTransaction(fn) {
|
|
111
|
+
return (...args) => {
|
|
112
|
+
if (this.inTransaction) {
|
|
113
|
+
throw new Error("nested transaction");
|
|
114
|
+
}
|
|
115
|
+
this.db.exec("BEGIN");
|
|
116
|
+
this.inTransaction = true;
|
|
117
|
+
try {
|
|
118
|
+
fn(...args);
|
|
119
|
+
this.db.exec("COMMIT");
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
try {
|
|
123
|
+
this.db.exec("ROLLBACK");
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
}
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
this.inTransaction = false;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
close() {
|
|
135
|
+
this.db.close();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
export function openDatabase(dbPath) {
|
|
139
|
+
const { DatabaseSync } = loadNodeSqlite();
|
|
140
|
+
const directory = path.dirname(dbPath);
|
|
141
|
+
if (!existsSync(directory)) {
|
|
142
|
+
mkdirSync(directory, { recursive: true });
|
|
143
|
+
}
|
|
144
|
+
return new GatewayDatabaseImpl(new DatabaseSync(dbPath));
|
|
145
|
+
}
|
|
146
|
+
export function openReadOnly(dbPath) {
|
|
147
|
+
const { DatabaseSync } = loadNodeSqlite();
|
|
148
|
+
return new GatewayDatabaseImpl(new DatabaseSync(dbPath, { readOnly: true }), true);
|
|
149
|
+
}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "llm-cli-gateway",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "llm-cli-gateway",
|
|
9
|
-
"version": "
|
|
9
|
+
"version": "2.0.0",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
13
|
-
"better-sqlite3": "^12.10.0",
|
|
14
13
|
"content-type": "1.0.5",
|
|
15
14
|
"smol-toml": "^1.6.1",
|
|
16
15
|
"type-is": "2.0.1",
|
|
@@ -20,7 +19,7 @@
|
|
|
20
19
|
"llm-cli-gateway": "dist/index.js"
|
|
21
20
|
},
|
|
22
21
|
"engines": {
|
|
23
|
-
"node": ">=
|
|
22
|
+
"node": ">=24.4.0"
|
|
24
23
|
},
|
|
25
24
|
"peerDependencies": {
|
|
26
25
|
"pg": "^8.12.0"
|
|
@@ -129,35 +128,6 @@
|
|
|
129
128
|
}
|
|
130
129
|
}
|
|
131
130
|
},
|
|
132
|
-
"node_modules/b4a": {
|
|
133
|
-
"version": "1.6.4",
|
|
134
|
-
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz",
|
|
135
|
-
"integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==",
|
|
136
|
-
"license": "ISC"
|
|
137
|
-
},
|
|
138
|
-
"node_modules/better-sqlite3": {
|
|
139
|
-
"version": "12.10.0",
|
|
140
|
-
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.10.0.tgz",
|
|
141
|
-
"integrity": "sha512-CyzaZRQKyHkB2ZInfTTl2nvT33EbDpjkLEbE8/Zck3Ll6O0qqvuGdrJ45HgtH+HykRg88ITY3AdreBGN70aBSQ==",
|
|
142
|
-
"hasInstallScript": true,
|
|
143
|
-
"license": "MIT",
|
|
144
|
-
"dependencies": {
|
|
145
|
-
"bindings": "^1.5.0",
|
|
146
|
-
"prebuild-install": "^7.1.1"
|
|
147
|
-
},
|
|
148
|
-
"engines": {
|
|
149
|
-
"node": "20.x || 22.x || 23.x || 24.x || 25.x || 26.x"
|
|
150
|
-
}
|
|
151
|
-
},
|
|
152
|
-
"node_modules/bindings": {
|
|
153
|
-
"version": "1.5.0",
|
|
154
|
-
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
|
155
|
-
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
|
156
|
-
"license": "MIT",
|
|
157
|
-
"dependencies": {
|
|
158
|
-
"file-uri-to-path": "1.0.0"
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
131
|
"node_modules/body-parser": {
|
|
162
132
|
"version": "2.2.2",
|
|
163
133
|
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz",
|
|
@@ -220,12 +190,6 @@
|
|
|
220
190
|
"url": "https://github.com/sponsors/ljharb"
|
|
221
191
|
}
|
|
222
192
|
},
|
|
223
|
-
"node_modules/chownr": {
|
|
224
|
-
"version": "1.1.4",
|
|
225
|
-
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
|
226
|
-
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
|
|
227
|
-
"license": "ISC"
|
|
228
|
-
},
|
|
229
193
|
"node_modules/content-disposition": {
|
|
230
194
|
"version": "1.1.0",
|
|
231
195
|
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz",
|
|
@@ -314,30 +278,6 @@
|
|
|
314
278
|
}
|
|
315
279
|
}
|
|
316
280
|
},
|
|
317
|
-
"node_modules/decompress-response": {
|
|
318
|
-
"version": "6.0.0",
|
|
319
|
-
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
|
|
320
|
-
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
|
|
321
|
-
"license": "MIT",
|
|
322
|
-
"dependencies": {
|
|
323
|
-
"mimic-response": "^3.1.0"
|
|
324
|
-
},
|
|
325
|
-
"engines": {
|
|
326
|
-
"node": ">=10"
|
|
327
|
-
},
|
|
328
|
-
"funding": {
|
|
329
|
-
"url": "https://github.com/sponsors/sindresorhus"
|
|
330
|
-
}
|
|
331
|
-
},
|
|
332
|
-
"node_modules/deep-extend": {
|
|
333
|
-
"version": "0.6.0",
|
|
334
|
-
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
|
|
335
|
-
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
|
|
336
|
-
"license": "MIT",
|
|
337
|
-
"engines": {
|
|
338
|
-
"node": ">=4.0.0"
|
|
339
|
-
}
|
|
340
|
-
},
|
|
341
281
|
"node_modules/depd": {
|
|
342
282
|
"version": "2.0.0",
|
|
343
283
|
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
|
@@ -347,15 +287,6 @@
|
|
|
347
287
|
"node": ">= 0.8"
|
|
348
288
|
}
|
|
349
289
|
},
|
|
350
|
-
"node_modules/detect-libc": {
|
|
351
|
-
"version": "2.1.2",
|
|
352
|
-
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
|
353
|
-
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
|
|
354
|
-
"license": "Apache-2.0",
|
|
355
|
-
"engines": {
|
|
356
|
-
"node": ">=8"
|
|
357
|
-
}
|
|
358
|
-
},
|
|
359
290
|
"node_modules/dunder-proto": {
|
|
360
291
|
"version": "1.0.1",
|
|
361
292
|
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
|
@@ -385,15 +316,6 @@
|
|
|
385
316
|
"node": ">= 0.8"
|
|
386
317
|
}
|
|
387
318
|
},
|
|
388
|
-
"node_modules/end-of-stream": {
|
|
389
|
-
"version": "1.4.5",
|
|
390
|
-
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
|
|
391
|
-
"integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
|
|
392
|
-
"license": "MIT",
|
|
393
|
-
"dependencies": {
|
|
394
|
-
"once": "^1.4.0"
|
|
395
|
-
}
|
|
396
|
-
},
|
|
397
319
|
"node_modules/es-define-property": {
|
|
398
320
|
"version": "1.0.1",
|
|
399
321
|
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
|
@@ -460,15 +382,6 @@
|
|
|
460
382
|
"node": ">=18.0.0"
|
|
461
383
|
}
|
|
462
384
|
},
|
|
463
|
-
"node_modules/expand-template": {
|
|
464
|
-
"version": "2.0.3",
|
|
465
|
-
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
|
|
466
|
-
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
|
|
467
|
-
"license": "(MIT OR WTFPL)",
|
|
468
|
-
"engines": {
|
|
469
|
-
"node": ">=6"
|
|
470
|
-
}
|
|
471
|
-
},
|
|
472
385
|
"node_modules/express": {
|
|
473
386
|
"version": "5.2.1",
|
|
474
387
|
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
|
|
@@ -536,12 +449,6 @@
|
|
|
536
449
|
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
|
537
450
|
"license": "MIT"
|
|
538
451
|
},
|
|
539
|
-
"node_modules/fast-fifo": {
|
|
540
|
-
"version": "1.3.2",
|
|
541
|
-
"resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
|
|
542
|
-
"integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
|
|
543
|
-
"license": "MIT"
|
|
544
|
-
},
|
|
545
452
|
"node_modules/fast-uri": {
|
|
546
453
|
"version": "3.1.2",
|
|
547
454
|
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz",
|
|
@@ -558,12 +465,6 @@
|
|
|
558
465
|
],
|
|
559
466
|
"license": "BSD-3-Clause"
|
|
560
467
|
},
|
|
561
|
-
"node_modules/file-uri-to-path": {
|
|
562
|
-
"version": "1.0.0",
|
|
563
|
-
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
|
564
|
-
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
|
565
|
-
"license": "MIT"
|
|
566
|
-
},
|
|
567
468
|
"node_modules/finalhandler": {
|
|
568
469
|
"version": "2.1.1",
|
|
569
470
|
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz",
|
|
@@ -649,12 +550,6 @@
|
|
|
649
550
|
"node": ">= 0.4"
|
|
650
551
|
}
|
|
651
552
|
},
|
|
652
|
-
"node_modules/github-from-package": {
|
|
653
|
-
"version": "0.0.0",
|
|
654
|
-
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
|
|
655
|
-
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
|
|
656
|
-
"license": "MIT"
|
|
657
|
-
},
|
|
658
553
|
"node_modules/gopd": {
|
|
659
554
|
"version": "1.2.0",
|
|
660
555
|
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
|
@@ -742,12 +637,6 @@
|
|
|
742
637
|
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
|
743
638
|
"license": "ISC"
|
|
744
639
|
},
|
|
745
|
-
"node_modules/ini": {
|
|
746
|
-
"version": "1.3.8",
|
|
747
|
-
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
|
748
|
-
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
|
|
749
|
-
"license": "ISC"
|
|
750
|
-
},
|
|
751
640
|
"node_modules/ip-address": {
|
|
752
641
|
"version": "10.2.0",
|
|
753
642
|
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz",
|
|
@@ -854,45 +743,12 @@
|
|
|
854
743
|
"url": "https://opencollective.com/express"
|
|
855
744
|
}
|
|
856
745
|
},
|
|
857
|
-
"node_modules/mimic-response": {
|
|
858
|
-
"version": "3.1.0",
|
|
859
|
-
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
|
860
|
-
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
|
|
861
|
-
"license": "MIT",
|
|
862
|
-
"engines": {
|
|
863
|
-
"node": ">=10"
|
|
864
|
-
},
|
|
865
|
-
"funding": {
|
|
866
|
-
"url": "https://github.com/sponsors/sindresorhus"
|
|
867
|
-
}
|
|
868
|
-
},
|
|
869
|
-
"node_modules/minimist": {
|
|
870
|
-
"version": "1.2.8",
|
|
871
|
-
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
|
872
|
-
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
|
873
|
-
"license": "MIT",
|
|
874
|
-
"funding": {
|
|
875
|
-
"url": "https://github.com/sponsors/ljharb"
|
|
876
|
-
}
|
|
877
|
-
},
|
|
878
|
-
"node_modules/mkdirp-classic": {
|
|
879
|
-
"version": "0.5.3",
|
|
880
|
-
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
|
881
|
-
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
|
|
882
|
-
"license": "MIT"
|
|
883
|
-
},
|
|
884
746
|
"node_modules/ms": {
|
|
885
747
|
"version": "2.1.3",
|
|
886
748
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
|
887
749
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
|
888
750
|
"license": "MIT"
|
|
889
751
|
},
|
|
890
|
-
"node_modules/napi-build-utils": {
|
|
891
|
-
"version": "2.0.0",
|
|
892
|
-
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
|
|
893
|
-
"integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",
|
|
894
|
-
"license": "MIT"
|
|
895
|
-
},
|
|
896
752
|
"node_modules/negotiator": {
|
|
897
753
|
"version": "1.0.0",
|
|
898
754
|
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
|
|
@@ -902,18 +758,6 @@
|
|
|
902
758
|
"node": ">= 0.6"
|
|
903
759
|
}
|
|
904
760
|
},
|
|
905
|
-
"node_modules/node-abi": {
|
|
906
|
-
"version": "3.89.0",
|
|
907
|
-
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.89.0.tgz",
|
|
908
|
-
"integrity": "sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA==",
|
|
909
|
-
"license": "MIT",
|
|
910
|
-
"dependencies": {
|
|
911
|
-
"semver": "^7.3.5"
|
|
912
|
-
},
|
|
913
|
-
"engines": {
|
|
914
|
-
"node": ">=10"
|
|
915
|
-
}
|
|
916
|
-
},
|
|
917
761
|
"node_modules/object-assign": {
|
|
918
762
|
"version": "4.1.1",
|
|
919
763
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
|
@@ -993,33 +837,6 @@
|
|
|
993
837
|
"node": ">=16.20.0"
|
|
994
838
|
}
|
|
995
839
|
},
|
|
996
|
-
"node_modules/prebuild-install": {
|
|
997
|
-
"version": "7.1.3",
|
|
998
|
-
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
|
|
999
|
-
"integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
|
|
1000
|
-
"deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.",
|
|
1001
|
-
"license": "MIT",
|
|
1002
|
-
"dependencies": {
|
|
1003
|
-
"detect-libc": "^2.0.0",
|
|
1004
|
-
"expand-template": "^2.0.3",
|
|
1005
|
-
"github-from-package": "0.0.0",
|
|
1006
|
-
"minimist": "^1.2.3",
|
|
1007
|
-
"mkdirp-classic": "^0.5.3",
|
|
1008
|
-
"napi-build-utils": "^2.0.0",
|
|
1009
|
-
"node-abi": "^3.3.0",
|
|
1010
|
-
"pump": "^3.0.0",
|
|
1011
|
-
"rc": "^1.2.7",
|
|
1012
|
-
"simple-get": "^4.0.0",
|
|
1013
|
-
"tar-fs": "^2.0.0",
|
|
1014
|
-
"tunnel-agent": "^0.6.0"
|
|
1015
|
-
},
|
|
1016
|
-
"bin": {
|
|
1017
|
-
"prebuild-install": "bin.js"
|
|
1018
|
-
},
|
|
1019
|
-
"engines": {
|
|
1020
|
-
"node": ">=10"
|
|
1021
|
-
}
|
|
1022
|
-
},
|
|
1023
840
|
"node_modules/proxy-addr": {
|
|
1024
841
|
"version": "2.0.7",
|
|
1025
842
|
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
|
@@ -1033,16 +850,6 @@
|
|
|
1033
850
|
"node": ">= 0.10"
|
|
1034
851
|
}
|
|
1035
852
|
},
|
|
1036
|
-
"node_modules/pump": {
|
|
1037
|
-
"version": "3.0.4",
|
|
1038
|
-
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz",
|
|
1039
|
-
"integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==",
|
|
1040
|
-
"license": "MIT",
|
|
1041
|
-
"dependencies": {
|
|
1042
|
-
"end-of-stream": "^1.1.0",
|
|
1043
|
-
"once": "^1.3.1"
|
|
1044
|
-
}
|
|
1045
|
-
},
|
|
1046
853
|
"node_modules/qs": {
|
|
1047
854
|
"version": "6.15.2",
|
|
1048
855
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz",
|
|
@@ -1058,12 +865,6 @@
|
|
|
1058
865
|
"url": "https://github.com/sponsors/ljharb"
|
|
1059
866
|
}
|
|
1060
867
|
},
|
|
1061
|
-
"node_modules/queue-tick": {
|
|
1062
|
-
"version": "1.0.1",
|
|
1063
|
-
"resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz",
|
|
1064
|
-
"integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==",
|
|
1065
|
-
"license": "MIT"
|
|
1066
|
-
},
|
|
1067
868
|
"node_modules/range-parser": {
|
|
1068
869
|
"version": "1.2.1",
|
|
1069
870
|
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
|
@@ -1088,30 +889,6 @@
|
|
|
1088
889
|
"node": ">= 0.10"
|
|
1089
890
|
}
|
|
1090
891
|
},
|
|
1091
|
-
"node_modules/rc": {
|
|
1092
|
-
"version": "1.2.8",
|
|
1093
|
-
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
|
|
1094
|
-
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
|
|
1095
|
-
"license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
|
|
1096
|
-
"dependencies": {
|
|
1097
|
-
"deep-extend": "^0.6.0",
|
|
1098
|
-
"ini": "~1.3.0",
|
|
1099
|
-
"minimist": "^1.2.0",
|
|
1100
|
-
"strip-json-comments": "~2.0.1"
|
|
1101
|
-
},
|
|
1102
|
-
"bin": {
|
|
1103
|
-
"rc": "cli.js"
|
|
1104
|
-
}
|
|
1105
|
-
},
|
|
1106
|
-
"node_modules/rc/node_modules/strip-json-comments": {
|
|
1107
|
-
"version": "2.0.1",
|
|
1108
|
-
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
|
1109
|
-
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
|
|
1110
|
-
"license": "MIT",
|
|
1111
|
-
"engines": {
|
|
1112
|
-
"node": ">=0.10.0"
|
|
1113
|
-
}
|
|
1114
|
-
},
|
|
1115
892
|
"node_modules/require-from-string": {
|
|
1116
893
|
"version": "2.0.2",
|
|
1117
894
|
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
|
@@ -1137,44 +914,12 @@
|
|
|
1137
914
|
"node": ">= 18"
|
|
1138
915
|
}
|
|
1139
916
|
},
|
|
1140
|
-
"node_modules/safe-buffer": {
|
|
1141
|
-
"version": "5.2.1",
|
|
1142
|
-
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
|
1143
|
-
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
|
1144
|
-
"funding": [
|
|
1145
|
-
{
|
|
1146
|
-
"type": "github",
|
|
1147
|
-
"url": "https://github.com/sponsors/feross"
|
|
1148
|
-
},
|
|
1149
|
-
{
|
|
1150
|
-
"type": "patreon",
|
|
1151
|
-
"url": "https://www.patreon.com/feross"
|
|
1152
|
-
},
|
|
1153
|
-
{
|
|
1154
|
-
"type": "consulting",
|
|
1155
|
-
"url": "https://feross.org/support"
|
|
1156
|
-
}
|
|
1157
|
-
],
|
|
1158
|
-
"license": "MIT"
|
|
1159
|
-
},
|
|
1160
917
|
"node_modules/safer-buffer": {
|
|
1161
918
|
"version": "2.1.2",
|
|
1162
919
|
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
|
1163
920
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
|
1164
921
|
"license": "MIT"
|
|
1165
922
|
},
|
|
1166
|
-
"node_modules/semver": {
|
|
1167
|
-
"version": "7.7.3",
|
|
1168
|
-
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
|
|
1169
|
-
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
|
|
1170
|
-
"license": "ISC",
|
|
1171
|
-
"bin": {
|
|
1172
|
-
"semver": "bin/semver.js"
|
|
1173
|
-
},
|
|
1174
|
-
"engines": {
|
|
1175
|
-
"node": ">=10"
|
|
1176
|
-
}
|
|
1177
|
-
},
|
|
1178
923
|
"node_modules/send": {
|
|
1179
924
|
"version": "1.2.1",
|
|
1180
925
|
"resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz",
|
|
@@ -1319,51 +1064,6 @@
|
|
|
1319
1064
|
"url": "https://github.com/sponsors/ljharb"
|
|
1320
1065
|
}
|
|
1321
1066
|
},
|
|
1322
|
-
"node_modules/simple-concat": {
|
|
1323
|
-
"version": "1.0.1",
|
|
1324
|
-
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
|
|
1325
|
-
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
|
|
1326
|
-
"funding": [
|
|
1327
|
-
{
|
|
1328
|
-
"type": "github",
|
|
1329
|
-
"url": "https://github.com/sponsors/feross"
|
|
1330
|
-
},
|
|
1331
|
-
{
|
|
1332
|
-
"type": "patreon",
|
|
1333
|
-
"url": "https://www.patreon.com/feross"
|
|
1334
|
-
},
|
|
1335
|
-
{
|
|
1336
|
-
"type": "consulting",
|
|
1337
|
-
"url": "https://feross.org/support"
|
|
1338
|
-
}
|
|
1339
|
-
],
|
|
1340
|
-
"license": "MIT"
|
|
1341
|
-
},
|
|
1342
|
-
"node_modules/simple-get": {
|
|
1343
|
-
"version": "4.0.1",
|
|
1344
|
-
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
|
|
1345
|
-
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
|
|
1346
|
-
"funding": [
|
|
1347
|
-
{
|
|
1348
|
-
"type": "github",
|
|
1349
|
-
"url": "https://github.com/sponsors/feross"
|
|
1350
|
-
},
|
|
1351
|
-
{
|
|
1352
|
-
"type": "patreon",
|
|
1353
|
-
"url": "https://www.patreon.com/feross"
|
|
1354
|
-
},
|
|
1355
|
-
{
|
|
1356
|
-
"type": "consulting",
|
|
1357
|
-
"url": "https://feross.org/support"
|
|
1358
|
-
}
|
|
1359
|
-
],
|
|
1360
|
-
"license": "MIT",
|
|
1361
|
-
"dependencies": {
|
|
1362
|
-
"decompress-response": "^6.0.0",
|
|
1363
|
-
"once": "^1.3.1",
|
|
1364
|
-
"simple-concat": "^1.0.0"
|
|
1365
|
-
}
|
|
1366
|
-
},
|
|
1367
1067
|
"node_modules/smol-toml": {
|
|
1368
1068
|
"version": "1.6.1",
|
|
1369
1069
|
"resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.1.tgz",
|
|
@@ -1385,39 +1085,6 @@
|
|
|
1385
1085
|
"node": ">= 0.8"
|
|
1386
1086
|
}
|
|
1387
1087
|
},
|
|
1388
|
-
"node_modules/streamx": {
|
|
1389
|
-
"version": "2.15.0",
|
|
1390
|
-
"resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.0.tgz",
|
|
1391
|
-
"integrity": "sha512-HcxY6ncGjjklGs1xsP1aR71INYcsXFJet5CU1CHqihQ2J5nOsbd4OjgjHO42w/4QNv9gZb3BueV+Vxok5pLEXg==",
|
|
1392
|
-
"license": "MIT",
|
|
1393
|
-
"dependencies": {
|
|
1394
|
-
"fast-fifo": "^1.1.0",
|
|
1395
|
-
"queue-tick": "^1.0.1"
|
|
1396
|
-
}
|
|
1397
|
-
},
|
|
1398
|
-
"node_modules/tar-fs": {
|
|
1399
|
-
"version": "2.1.4",
|
|
1400
|
-
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
|
|
1401
|
-
"integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
|
|
1402
|
-
"license": "MIT",
|
|
1403
|
-
"dependencies": {
|
|
1404
|
-
"chownr": "^1.1.1",
|
|
1405
|
-
"mkdirp-classic": "^0.5.2",
|
|
1406
|
-
"pump": "^3.0.0",
|
|
1407
|
-
"tar-stream": "^2.1.4"
|
|
1408
|
-
}
|
|
1409
|
-
},
|
|
1410
|
-
"node_modules/tar-stream": {
|
|
1411
|
-
"version": "3.1.7",
|
|
1412
|
-
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz",
|
|
1413
|
-
"integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==",
|
|
1414
|
-
"license": "MIT",
|
|
1415
|
-
"dependencies": {
|
|
1416
|
-
"b4a": "^1.6.4",
|
|
1417
|
-
"fast-fifo": "^1.2.0",
|
|
1418
|
-
"streamx": "^2.15.0"
|
|
1419
|
-
}
|
|
1420
|
-
},
|
|
1421
1088
|
"node_modules/toidentifier": {
|
|
1422
1089
|
"version": "1.0.1",
|
|
1423
1090
|
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
|
@@ -1427,18 +1094,6 @@
|
|
|
1427
1094
|
"node": ">=0.6"
|
|
1428
1095
|
}
|
|
1429
1096
|
},
|
|
1430
|
-
"node_modules/tunnel-agent": {
|
|
1431
|
-
"version": "0.6.0",
|
|
1432
|
-
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
|
1433
|
-
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
|
|
1434
|
-
"license": "Apache-2.0",
|
|
1435
|
-
"dependencies": {
|
|
1436
|
-
"safe-buffer": "^5.0.1"
|
|
1437
|
-
},
|
|
1438
|
-
"engines": {
|
|
1439
|
-
"node": "*"
|
|
1440
|
-
}
|
|
1441
|
-
},
|
|
1442
1097
|
"node_modules/type-is": {
|
|
1443
1098
|
"version": "2.0.1",
|
|
1444
1099
|
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "llm-cli-gateway",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.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",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"llm-cli-gateway": "dist/index.js"
|
|
41
41
|
},
|
|
42
42
|
"engines": {
|
|
43
|
-
"node": ">=
|
|
43
|
+
"node": ">=24.4.0"
|
|
44
44
|
},
|
|
45
45
|
"files": [
|
|
46
46
|
"dist/**/*.js",
|
|
@@ -87,7 +87,6 @@
|
|
|
87
87
|
},
|
|
88
88
|
"dependencies": {
|
|
89
89
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
90
|
-
"better-sqlite3": "^12.10.0",
|
|
91
90
|
"content-type": "1.0.5",
|
|
92
91
|
"smol-toml": "^1.6.1",
|
|
93
92
|
"type-is": "2.0.1",
|
|
@@ -104,6 +103,7 @@
|
|
|
104
103
|
"devDependencies": {
|
|
105
104
|
"@eslint/js": "^10.0.1",
|
|
106
105
|
"@types/better-sqlite3": "^7.6.0",
|
|
106
|
+
"better-sqlite3": "^12.10.0",
|
|
107
107
|
"@types/node": "^25.9.1",
|
|
108
108
|
"@types/pg": "^8.11.10",
|
|
109
109
|
"@typescript-eslint/eslint-plugin": "^8.59.4",
|
|
@@ -120,8 +120,7 @@
|
|
|
120
120
|
},
|
|
121
121
|
"overrides": {
|
|
122
122
|
"type-is": "2.0.1",
|
|
123
|
-
"content-type": "1.0.5"
|
|
124
|
-
"tar-stream": "3.1.7"
|
|
123
|
+
"content-type": "1.0.5"
|
|
125
124
|
},
|
|
126
125
|
"directories": {
|
|
127
126
|
"doc": "docs"
|
package/socket.yml
CHANGED
|
@@ -25,10 +25,15 @@ version: 2
|
|
|
25
25
|
# imported or called from upstream-contracts.ts. The wording now uses
|
|
26
26
|
# "remote retrieval" to avoid that heuristic.
|
|
27
27
|
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
# only). v1.17.7
|
|
31
|
-
#
|
|
28
|
+
# Historical (resolved in 2.0.0): transitive tar-stream@2.2.0
|
|
29
|
+
# (better-sqlite3 → prebuild-install → tar-fs) triggered Socket "Potential
|
|
30
|
+
# vulnerability" (tar path traversal at install only). v1.17.7-1.17.9 worked
|
|
31
|
+
# around it with a tar-stream 3.1.7 override + prod-only shrinkwrap. As of
|
|
32
|
+
# 2.0.0 the gateway uses Node's built-in `node:sqlite` for persistence;
|
|
33
|
+
# better-sqlite3 is a devDependency only, so the prod graph has NO native
|
|
34
|
+
# module and NO tar-stream/prebuild-install/tar-fs install chain. The
|
|
35
|
+
# release security audit now hard-fails if any of those packages re-enter
|
|
36
|
+
# the prod graph (and still blocks the flagged tar-stream 2.x versions).
|
|
32
37
|
#
|
|
33
38
|
# shellAccess
|
|
34
39
|
# This alert fires on every module that imports node:child_process, and
|
|
@@ -69,12 +74,16 @@ version: 2
|
|
|
69
74
|
# This is ajv's standard codegen path; no caller-supplied data flows
|
|
70
75
|
# into the compiled function body.
|
|
71
76
|
#
|
|
72
|
-
#
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
#
|
|
77
|
+
# SQLite (node:sqlite) adapter isolation
|
|
78
|
+
# As of 2.0.0 persistence uses Node's built-in `node:sqlite` module (no
|
|
79
|
+
# native binding, no install scripts) through a single adapter,
|
|
80
|
+
# src/sqlite-driver.ts. No `db.pragma()` helper exists on node:sqlite and
|
|
81
|
+
# the gateway never calls one; SQLite setup uses fixed literal
|
|
82
|
+
# db.exec("PRAGMA ...") statements. The release security audit hard-fails
|
|
83
|
+
# if production code references node:sqlite outside the adapter or
|
|
84
|
+
# reintroduces a `.pragma()` call. (better-sqlite3 — and its
|
|
85
|
+
# lib/methods/pragma.js that older Socket scans flagged — is now a
|
|
86
|
+
# devDependency only and is absent from the published prod artifact.)
|
|
78
87
|
|
|
79
88
|
issueRules:
|
|
80
89
|
# Defaults from Socket. Listed explicitly so future contributors see what
|
|
@@ -84,7 +93,7 @@ issueRules:
|
|
|
84
93
|
didYouMean: true
|
|
85
94
|
installScripts: true
|
|
86
95
|
telemetry: true
|
|
87
|
-
hasNativeCode: true # better-sqlite3
|
|
96
|
+
hasNativeCode: true # devDependency-only as of 2.0.0 (better-sqlite3); prod artifact has no native code
|
|
88
97
|
shellAccess: false # reviewed gateway capability; see rationale above
|
|
89
98
|
shellScriptOverride: true
|
|
90
99
|
gitDependency: true
|