@elvatis_com/openclaw-cli-bridge-elvatis 0.2.7 → 0.2.9

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.
@@ -6,15 +6,15 @@ _Last updated: 2026-03-07_
6
6
 
7
7
  | Component | Version | Build | Tests | Status |
8
8
  |-----------|---------|-------|-------|--------|
9
- | openclaw-cli-bridge-elvatis | 0.2.6 | ✅ | 5/5 ✅ | ✅ Stable |
9
+ | openclaw-cli-bridge-elvatis | 0.2.7 | ✅ | 5/5 ✅ | ✅ Stable |
10
10
 
11
11
  ## 🚀 Release State
12
12
 
13
13
  | Platform | Version | Status |
14
14
  |----------|---------|--------|
15
- | GitHub | v0.2.6 | ✅ Tagged + Release |
16
- | npm | 0.2.6 | ✅ Published |
17
- | ClawHub | 0.2.6 | ✅ Published |
15
+ | GitHub | v0.2.7 | ✅ Tagged + Release |
16
+ | npm | 0.2.7 | ✅ Published |
17
+ | ClawHub | 0.2.7 | ✅ Published |
18
18
 
19
19
  ## 📋 Open Tasks
20
20
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  _Last updated: 2026-03-07 by Akido (claude-sonnet-4-6)_
4
4
 
5
- ## Current Version: 0.2.6 — STABLE
5
+ ## Current Version: 0.2.7 — STABLE
6
6
 
7
7
  ## What is done
8
8
 
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > OpenClaw plugin that bridges locally installed AI CLIs (Codex, Gemini, Claude Code) as model providers — with slash commands for instant model switching, restore, and health testing.
4
4
 
5
- **Current version:** `0.2.6`
5
+ **Current version:** `0.2.7`
6
6
 
7
7
  ---
8
8
 
package/index.ts CHANGED
@@ -354,9 +354,32 @@ const plugin = {
354
354
  let proxyServer: import("node:http").Server | null = null;
355
355
 
356
356
  if (enableProxy) {
357
- // Retry up to 3 times with 600ms delay to handle the race condition where
358
- // a previous plugin instance's server.close() hasn't released the port yet.
359
- const startWithRetry = async (attemptsLeft: number): Promise<void> => {
357
+ // Probe whether a healthy proxy is already listening on our port.
358
+ // This handles hot-reloads where the previous plugin instance's server.close()
359
+ // may not have completed yet — rather than killing anything (dangerous: fuser -k
360
+ // can kill the gateway process itself during in-process hot-reloads), we just
361
+ // check if the existing server still responds and reuse it if so.
362
+ const probeExisting = (): Promise<boolean> => {
363
+ return new Promise((resolve) => {
364
+ const req = http.request(
365
+ { hostname: "127.0.0.1", port, path: "/v1/models", method: "GET",
366
+ headers: { Authorization: `Bearer ${apiKey}` } },
367
+ (res) => { res.resume(); resolve(res.statusCode === 200); }
368
+ );
369
+ req.setTimeout(800, () => { req.destroy(); resolve(false); });
370
+ req.on("error", () => resolve(false));
371
+ req.end();
372
+ });
373
+ };
374
+
375
+ const startProxy = async (): Promise<void> => {
376
+ // If a healthy proxy is already up, reuse it — no need to rebind.
377
+ const alive = await probeExisting();
378
+ if (alive) {
379
+ api.logger.info(`[cli-bridge] proxy already running on :${port} — reusing`);
380
+ return;
381
+ }
382
+
360
383
  try {
361
384
  const server = await startProxyServer({
362
385
  port,
@@ -377,15 +400,29 @@ const plugin = {
377
400
  }
378
401
  } catch (err: unknown) {
379
402
  const msg = (err as Error).message ?? String(err);
380
- if (attemptsLeft > 1 && msg.includes("EADDRINUSE")) {
381
- api.logger.warn(`[cli-bridge] port ${port} busy, retrying in 600ms (${attemptsLeft - 1} left)…`);
382
- await new Promise((r) => setTimeout(r, 600));
383
- return startWithRetry(attemptsLeft - 1);
403
+ if (msg.includes("EADDRINUSE")) {
404
+ // Port is busy but probe didn't respond wait for the OS to release it
405
+ api.logger.warn(`[cli-bridge] port ${port} busy, waiting 1s for OS release…`);
406
+ await new Promise((r) => setTimeout(r, 1000));
407
+ // One final attempt
408
+ try {
409
+ const server = await startProxyServer({
410
+ port, apiKey, timeoutMs,
411
+ log: (msg) => api.logger.info(msg),
412
+ warn: (msg) => api.logger.warn(msg),
413
+ });
414
+ proxyServer = server;
415
+ api.logger.info(`[cli-bridge] proxy ready on :${port} (retry)`);
416
+ } catch (e2: unknown) {
417
+ api.logger.warn(`[cli-bridge] proxy unavailable after retry: ${(e2 as Error).message}`);
418
+ }
419
+ } else {
420
+ api.logger.warn(`[cli-bridge] proxy failed to start on port ${port}: ${msg}`);
384
421
  }
385
- api.logger.warn(`[cli-bridge] proxy failed to start on port ${port}: ${msg}`);
386
422
  }
387
423
  };
388
- startWithRetry(3).catch(() => {});
424
+
425
+ startProxy().catch(() => {});
389
426
  }
390
427
 
391
428
  // ── Cleanup: close proxy server on plugin stop (hot-reload / gateway restart) ──
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "openclaw-cli-bridge-elvatis",
3
3
  "name": "OpenClaw CLI Bridge",
4
- "version": "0.2.7",
4
+ "version": "0.2.9",
5
5
  "description": "Phase 1: openai-codex auth bridge. Phase 2: local HTTP proxy routing model calls through gemini/claude CLIs (vllm provider).",
6
6
  "providers": [
7
7
  "openai-codex"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elvatis_com/openclaw-cli-bridge-elvatis",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "description": "Bridges gemini, claude, and codex CLI tools as OpenClaw model providers. Reads existing CLI auth without re-login.",
5
5
  "type": "module",
6
6
  "openclaw": {