llm-cli-gateway 1.5.33 → 1.5.35

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
@@ -2,6 +2,18 @@
2
2
 
3
3
  All notable changes to the llm-cli-gateway project.
4
4
 
5
+ ## [1.5.35] - 2026-05-25
6
+
7
+ ### Fixed
8
+
9
+ - Keep metadata-only CLI commands quiet by avoiding flight-recorder and job-persistence startup before `--version`, help, `doctor --json`, and `contracts --json`; machine-readable JSON commands now emit JSON without startup log lines.
10
+
11
+ ## [1.5.34] - 2026-05-25
12
+
13
+ ### Security
14
+
15
+ - Pin the development Redis client fixture back to `ioredis@5.9.2` and reject the Socket-flagged `ioredis@5.10.1` / `@ioredis/commands@1.5.1` lockfile pair in the release security audit. The runtime Redis integration remains an optional peer dependency.
16
+
5
17
  ## [1.5.33] - 2026-05-25
6
18
 
7
19
  ### Security
package/dist/index.js CHANGED
@@ -108,6 +108,22 @@ const SYNC_DEADLINE_MS = (() => {
108
108
  const __filename = fileURLToPath(import.meta.url);
109
109
  const __dirname = dirname(__filename);
110
110
  const SKILLS_DIR = join(__dirname, "..", ".agents", "skills");
111
+ function packageVersion() {
112
+ const candidates = [
113
+ join(__dirname, "..", "package.json"),
114
+ join(__dirname, "..", "..", "package.json"),
115
+ ];
116
+ for (const candidate of candidates) {
117
+ try {
118
+ const parsed = JSON.parse(readFileSync(candidate, "utf8"));
119
+ return parsed.version || "unknown";
120
+ }
121
+ catch {
122
+ // Try next candidate.
123
+ }
124
+ }
125
+ return "unknown";
126
+ }
111
127
  function loadSkills() {
112
128
  const skills = [];
113
129
  try {
@@ -158,29 +174,51 @@ let sessionManager;
158
174
  let db = null;
159
175
  const performanceMetrics = new PerformanceMetrics();
160
176
  let resourceProvider;
161
- const flightRecorder = createFlightRecorder(logger);
177
+ let flightRecorder = null;
162
178
  // Resolved persistence config — single source of truth for the async-job backend.
163
179
  // Driven by ~/.llm-cli-gateway/config.toml (+ deprecated env-var overrides).
164
180
  // When backend = "none", the JobStore is null AND *_request_async tools are not
165
181
  // registered (see createGatewayServer), making silent in-memory loss
166
182
  // structurally impossible.
167
- const persistenceConfig = loadPersistenceConfig(logger);
168
- const jobStore = (() => {
183
+ let persistenceConfig = null;
184
+ let jobStore = null;
185
+ let jobStoreInitialized = false;
186
+ let asyncJobManager = null;
187
+ let approvalManager = null;
188
+ function getFlightRecorder(runtimeLogger = logger) {
189
+ flightRecorder ??= createFlightRecorder(runtimeLogger);
190
+ return flightRecorder;
191
+ }
192
+ function getPersistenceConfig(runtimeLogger = logger) {
193
+ persistenceConfig ??= loadPersistenceConfig(runtimeLogger);
194
+ return persistenceConfig;
195
+ }
196
+ function getJobStore(runtimeLogger = logger) {
197
+ if (jobStoreInitialized)
198
+ return jobStore;
199
+ jobStoreInitialized = true;
169
200
  try {
170
- return createJobStore(persistenceConfig, logger);
201
+ jobStore = createJobStore(getPersistenceConfig(runtimeLogger), runtimeLogger);
171
202
  }
172
203
  catch (err) {
173
- logger.error("Failed to open durable job store; async tools will be unavailable", err);
174
- return null;
204
+ runtimeLogger.error("Failed to open durable job store; async tools will be unavailable", err);
205
+ jobStore = null;
175
206
  }
176
- })();
177
- function newAsyncJobManager(metrics, runtimeLogger, store = jobStore) {
207
+ return jobStore;
208
+ }
209
+ function newAsyncJobManager(metrics, runtimeLogger, store = getJobStore(runtimeLogger)) {
178
210
  return new AsyncJobManager(runtimeLogger, (cli, durationMs, success) => {
179
211
  metrics.recordRequest(cli, durationMs, success);
180
212
  }, store);
181
213
  }
182
- const asyncJobManager = newAsyncJobManager(performanceMetrics, logger);
183
- const approvalManager = new ApprovalManager(undefined, logger);
214
+ function getAsyncJobManager(runtimeLogger = logger) {
215
+ asyncJobManager ??= newAsyncJobManager(performanceMetrics, runtimeLogger);
216
+ return asyncJobManager;
217
+ }
218
+ function getApprovalManager(runtimeLogger = logger) {
219
+ approvalManager ??= new ApprovalManager(undefined, runtimeLogger);
220
+ return approvalManager;
221
+ }
184
222
  const MCP_SERVER_ENUM = z.enum(CLAUDE_MCP_SERVER_NAMES);
185
223
  // U22: Session-provider enum extended to five providers. The storage layer's
186
224
  // CLI_TYPES already includes "mistral"; the MCP-tool layer mirrors that here so
@@ -199,9 +237,11 @@ function resolveGatewayServerRuntime(deps = {}, options = {}) {
199
237
  ? // Factory-created test/HTTP session servers must not mark another instance's
200
238
  // durable jobs orphaned. Stdio startup injects the process-global manager.
201
239
  newAsyncJobManager(runtimePerformanceMetrics, runtimeLogger, null)
202
- : asyncJobManager);
240
+ : getAsyncJobManager(runtimeLogger));
203
241
  const runtimeApprovalManager = deps.approvalManager ??
204
- (options.isolateState ? new ApprovalManager(undefined, runtimeLogger) : approvalManager);
242
+ (options.isolateState
243
+ ? new ApprovalManager(undefined, runtimeLogger)
244
+ : getApprovalManager(runtimeLogger));
205
245
  return {
206
246
  sessionManager: runtimeSessionManager,
207
247
  resourceProvider: deps.resourceProvider ??
@@ -212,9 +252,9 @@ function resolveGatewayServerRuntime(deps = {}, options = {}) {
212
252
  performanceMetrics: runtimePerformanceMetrics,
213
253
  asyncJobManager: runtimeAsyncJobManager,
214
254
  approvalManager: runtimeApprovalManager,
215
- flightRecorder: deps.flightRecorder ?? flightRecorder,
255
+ flightRecorder: deps.flightRecorder ?? getFlightRecorder(runtimeLogger),
216
256
  logger: runtimeLogger,
217
- persistence: deps.persistence ?? persistenceConfig,
257
+ persistence: deps.persistence ?? getPersistenceConfig(runtimeLogger),
218
258
  };
219
259
  }
220
260
  // Per-CLI idle timeouts: kill process if no stdout/stderr activity for this duration.
@@ -3944,7 +3984,7 @@ function registerHealthResource(server) {
3944
3984
  description: "Async job health (CPU, memory, zombie detection)",
3945
3985
  mimeType: "application/json",
3946
3986
  }, async (uri) => {
3947
- const health = asyncJobManager.getJobHealth();
3987
+ const health = getAsyncJobManager().getJobHealth();
3948
3988
  return {
3949
3989
  contents: [
3950
3990
  {
@@ -3980,8 +4020,10 @@ async function shutdown(signal) {
3980
4020
  await db.disconnect();
3981
4021
  logger.info("Database connections closed");
3982
4022
  }
3983
- flightRecorder.close();
3984
- logger.info("Flight recorder closed");
4023
+ if (flightRecorder) {
4024
+ flightRecorder.close();
4025
+ logger.info("Flight recorder closed");
4026
+ }
3985
4027
  process.exit(0);
3986
4028
  }
3987
4029
  catch (error) {
@@ -3997,6 +4039,20 @@ process.on("SIGINT", () => shutdown("SIGINT"));
3997
4039
  async function main() {
3998
4040
  startWindowsBootstrapperSelfHeal();
3999
4041
  const args = process.argv.slice(2);
4042
+ if (args[0] === "--version" || args[0] === "-version" || args[0] === "version") {
4043
+ process.stdout.write(`${packageVersion()}\n`);
4044
+ return;
4045
+ }
4046
+ if (args[0] === "--help" || args[0] === "-help" || args[0] === "/?" || args[0] === "help") {
4047
+ process.stdout.write([
4048
+ "llm-cli-gateway MCP server",
4049
+ "",
4050
+ "Usage:",
4051
+ " llm-cli-gateway [doctor --json|contracts --json|--transport=http|--version]",
4052
+ "",
4053
+ ].join("\n"));
4054
+ return;
4055
+ }
4000
4056
  if (args[0] === "doctor") {
4001
4057
  if (args.includes("--json")) {
4002
4058
  printDoctorJson();
@@ -4035,9 +4091,9 @@ async function main() {
4035
4091
  resourceProvider,
4036
4092
  db,
4037
4093
  performanceMetrics,
4038
- asyncJobManager,
4039
- approvalManager,
4040
- flightRecorder,
4094
+ asyncJobManager: getAsyncJobManager(logger),
4095
+ approvalManager: getApprovalManager(logger),
4096
+ flightRecorder: getFlightRecorder(logger),
4041
4097
  logger,
4042
4098
  };
4043
4099
  if (transportMode === "http") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "llm-cli-gateway",
3
- "version": "1.5.33",
3
+ "version": "1.5.35",
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",
@@ -109,7 +109,7 @@
109
109
  "@vitest/coverage-v8": "^4.1.2",
110
110
  "eslint": "^8.57.1",
111
111
  "eslint-config-prettier": "^9.0.0",
112
- "ioredis": "^5.4.1",
112
+ "ioredis": "5.9.2",
113
113
  "pg": "^8.12.0",
114
114
  "prettier": "^3.0.0",
115
115
  "typescript": "^5.0.0",