@elvatis_com/openclaw-cli-bridge-elvatis 0.2.8 → 0.2.10
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/.ai/handoff/DASHBOARD.md +6 -5
- package/.ai/handoff/LOG.md +24 -0
- package/.ai/handoff/NEXT_ACTIONS.md +2 -1
- package/.ai/handoff/STATUS.md +19 -7
- package/README.md +19 -1
- package/SKILL.md +5 -1
- package/index.ts +39 -28
- package/openclaw.plugin.json +2 -2
- package/package.json +2 -2
- package/tsconfig.check.json +7 -0
package/.ai/handoff/DASHBOARD.md
CHANGED
|
@@ -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.
|
|
9
|
+
| openclaw-cli-bridge-elvatis | 0.2.9 | ✅ | 5/5 ✅ | ✅ Stable |
|
|
10
10
|
|
|
11
11
|
## 🚀 Release State
|
|
12
12
|
|
|
13
13
|
| Platform | Version | Status |
|
|
14
14
|
|----------|---------|--------|
|
|
15
|
-
| GitHub | v0.2.
|
|
16
|
-
| npm | 0.2.
|
|
17
|
-
| ClawHub | 0.2.
|
|
15
|
+
| GitHub | v0.2.9 | ✅ Tagged + Release |
|
|
16
|
+
| npm | 0.2.9 | ✅ Published |
|
|
17
|
+
| ClawHub | 0.2.9 | ✅ Published |
|
|
18
18
|
|
|
19
19
|
## 📋 Open Tasks
|
|
20
20
|
|
|
@@ -28,7 +28,8 @@ _Last updated: 2026-03-07_
|
|
|
28
28
|
|
|
29
29
|
| Task | Title | Version |
|
|
30
30
|
|------|-------|---------|
|
|
31
|
-
| T-
|
|
31
|
+
| T-007 | Critical: remove fuser -k, replace with safe health probe | 0.2.9 |
|
|
32
|
+
| T-006 | Fix port leak: registerService stop() hook + closeAllConnections | 0.2.7 |
|
|
32
33
|
| T-005 | Add openclaw.extensions to package.json | 0.2.6 |
|
|
33
34
|
| T-004 | /cli-codex + /cli-codex-mini slash commands | 0.2.5 |
|
|
34
35
|
| T-003 | /cli-back restore + /cli-test health check | 0.2.3 |
|
package/.ai/handoff/LOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# LOG.md — openclaw-cli-bridge-elvatis
|
|
2
2
|
|
|
3
|
+
## 2026-03-08 — Session 3 (Akido / claude-sonnet-4-6)
|
|
4
|
+
|
|
5
|
+
**Critical bug: Gateway SIGKILL via fuser (fixed in v0.2.9)**
|
|
6
|
+
|
|
7
|
+
Root cause: `fuser -k 31337/tcp` (added in v0.2.8) sent SIGKILL to the gateway
|
|
8
|
+
process itself during in-process hot-reloads. In hybrid reload mode, the same gateway
|
|
9
|
+
process reloads the plugin. At that point, the gateway holds port 31337 (via the proxy
|
|
10
|
+
it spawned earlier). `fuser -k` found the current gateway process as the port owner and
|
|
11
|
+
killed it with SIGKILL — visible in systemd journal as `code=killed, status=9/KILL` with
|
|
12
|
+
a 1.9G memory peak.
|
|
13
|
+
|
|
14
|
+
Fix: replaced `fuser -k` with a safe health probe. Before binding, `GET /v1/models` is
|
|
15
|
+
sent to the existing proxy. If it responds with 200, the proxy is reused silently
|
|
16
|
+
(`[cli-bridge] proxy already running on :31337 — reusing`). If EADDRINUSE but no
|
|
17
|
+
response (genuinely stale process), wait 1s and retry once. No process killing.
|
|
18
|
+
|
|
19
|
+
**Release pipeline:**
|
|
20
|
+
- v0.2.9 committed, tagged, pushed to GitHub
|
|
21
|
+
- GitHub release: https://github.com/elvatis/openclaw-cli-bridge-elvatis/releases/tag/v0.2.9
|
|
22
|
+
- npm: `@elvatis_com/openclaw-cli-bridge-elvatis@0.2.9`
|
|
23
|
+
- ClawHub: `openclaw-cli-bridge-elvatis@0.2.9`
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
3
27
|
## 2026-03-07 — Session 2 (Akido / claude-sonnet-4-6)
|
|
4
28
|
|
|
5
29
|
**Bug: Port leak on gateway hot-reload (fixed in v0.2.6)**
|
|
@@ -33,7 +33,8 @@ _Last updated: 2026-03-07_
|
|
|
33
33
|
|
|
34
34
|
| Task | Title | Date |
|
|
35
35
|
|------|-------|------|
|
|
36
|
-
| T-
|
|
36
|
+
| T-007 | Critical: remove fuser -k, safe proxy reuse via health probe | 2026-03-08 |
|
|
37
|
+
| T-006 | Fix port leak: registerService stop() hook + closeAllConnections | 2026-03-07 |
|
|
37
38
|
| T-005 | Add openclaw.extensions to package.json | 2026-03-07 |
|
|
38
39
|
| T-004 | /cli-codex + /cli-codex-mini | 2026-03-07 |
|
|
39
40
|
| T-003 | /cli-back + /cli-test | 2026-03-07 |
|
package/.ai/handoff/STATUS.md
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
_Last updated: 2026-03-07 by Akido (claude-sonnet-4-6)_
|
|
4
4
|
|
|
5
|
-
## Current Version: 0.2.
|
|
5
|
+
## Current Version: 0.2.9 — STABLE
|
|
6
6
|
|
|
7
7
|
## What is done
|
|
8
8
|
|
|
9
9
|
- ✅ Repo: `https://github.com/elvatis/openclaw-cli-bridge-elvatis`
|
|
10
|
-
- ✅ npm: `@elvatis_com/openclaw-cli-bridge-elvatis@0.2.
|
|
11
|
-
- ✅ ClawHub: `openclaw-cli-bridge-elvatis@0.2.
|
|
10
|
+
- ✅ npm: `@elvatis_com/openclaw-cli-bridge-elvatis@0.2.9`
|
|
11
|
+
- ✅ ClawHub: `openclaw-cli-bridge-elvatis@0.2.9`
|
|
12
12
|
- ✅ Phase 1: `openai-codex` provider via `~/.codex/auth.json` (no re-login)
|
|
13
13
|
- ✅ Phase 2: Local OpenAI-compatible proxy on `127.0.0.1:31337` (Gemini + Claude CLI)
|
|
14
14
|
- ✅ Phase 3: 10 slash commands (`/cli-sonnet`, `/cli-opus`, `/cli-haiku`, `/cli-gemini`, `/cli-gemini-flash`, `/cli-gemini3`, `/cli-codex`, `/cli-codex-mini`, `/cli-back`, `/cli-test`)
|
|
@@ -17,11 +17,23 @@ _Last updated: 2026-03-07 by Akido (claude-sonnet-4-6)_
|
|
|
17
17
|
- ✅ `registerService` stop() hook: closes proxy server on plugin teardown (fixes EADDRINUSE on hot-reload)
|
|
18
18
|
- ✅ `openclaw.extensions` added to `package.json` (required for `openclaw plugins install`)
|
|
19
19
|
|
|
20
|
-
##
|
|
20
|
+
## Bugs Fixed
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
### v0.2.9 — Critical: Gateway SIGKILL via fuser
|
|
23
|
+
`fuser -k 31337/tcp` was sending SIGKILL to the gateway process itself during
|
|
24
|
+
in-process hot-reloads. The gateway holds port 31337 (via the proxy it spawned),
|
|
25
|
+
so `fuser` found it and killed it — explaining `status=9/KILL` in systemd journal.
|
|
26
|
+
Fixed by replacing `fuser -k` with a safe health probe (`GET /v1/models`): if the
|
|
27
|
+
existing proxy responds, reuse it silently. If EADDRINUSE but no response, wait 1s
|
|
28
|
+
and retry once. No process killing involved.
|
|
29
|
+
|
|
30
|
+
### v0.2.7–v0.2.8 — EADDRINUSE on hot-reload (partially fixed, superseded by v0.2.9)
|
|
31
|
+
Added `closeAllConnections()` + `registerService` stop() hook. Port still leaked
|
|
32
|
+
during systemd restarts due to race condition. v0.2.9 health-probe approach is the
|
|
33
|
+
definitive fix.
|
|
34
|
+
|
|
35
|
+
### v0.2.6 — Port leak on gateway hot-reload
|
|
36
|
+
HTTP proxy server had no cleanup handler. Fixed with `registerService` stop() callback.
|
|
25
37
|
|
|
26
38
|
## Open Risks
|
|
27
39
|
|
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.
|
|
5
|
+
**Current version:** `0.2.9`
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -234,6 +234,24 @@ npm test # vitest run (5 unit tests for formatPrompt)
|
|
|
234
234
|
|
|
235
235
|
## Changelog
|
|
236
236
|
|
|
237
|
+
### v0.2.10
|
|
238
|
+
- **docs:** Fix version labels in SKILL.md and README changelog (were stuck at 0.2.2/0.2.5)
|
|
239
|
+
|
|
240
|
+
### v0.2.9
|
|
241
|
+
- **fix:** Critical — replace `fuser -k 31337/tcp` with safe health probe (`GET /v1/models`)
|
|
242
|
+
- Prevents gateway SIGKILL on in-process hot-reloads (systemd `status=9/KILL` was caused by `fuser` finding gateway itself holding the port)
|
|
243
|
+
- If proxy responds → reuse it; if EADDRINUSE but no response → wait 1s, retry once
|
|
244
|
+
|
|
245
|
+
### v0.2.8
|
|
246
|
+
- **fix:** EADDRINUSE on every gateway restart — `closeAllConnections()` + `registerService` stop() hook (partially; superseded by v0.2.9 health-probe approach)
|
|
247
|
+
|
|
248
|
+
### v0.2.7
|
|
249
|
+
- **fix:** Port leak on gateway hot-reload — added `registerService` stop() callback to close proxy server on plugin teardown
|
|
250
|
+
|
|
251
|
+
### v0.2.6
|
|
252
|
+
- **fix:** `openclaw.extensions` added to `package.json` (required for `openclaw plugins install`)
|
|
253
|
+
- Config patcher: auto-adds vllm provider to `openclaw.json` on first startup
|
|
254
|
+
|
|
237
255
|
### v0.2.5
|
|
238
256
|
- **feat:** `/cli-codex` → `openai-codex/gpt-5.3-codex`
|
|
239
257
|
- **feat:** `/cli-codex-mini` → `openai-codex/gpt-5.1-codex-mini`
|
package/SKILL.md
CHANGED
|
@@ -38,6 +38,10 @@ Six instant model-switch commands (authorized senders only):
|
|
|
38
38
|
| `/cli-gemini` | `vllm/cli-gemini/gemini-2.5-pro` |
|
|
39
39
|
| `/cli-gemini-flash` | `vllm/cli-gemini/gemini-2.5-flash` |
|
|
40
40
|
| `/cli-gemini3` | `vllm/cli-gemini/gemini-3-pro` |
|
|
41
|
+
| `/cli-codex` | `openai-codex/gpt-5.3-codex` |
|
|
42
|
+
| `/cli-codex-mini` | `openai-codex/gpt-5.1-codex-mini` |
|
|
43
|
+
| `/cli-back` | Restore previous model |
|
|
44
|
+
| `/cli-test [model]` | Health check (no model switch) |
|
|
41
45
|
|
|
42
46
|
Each command runs `openclaw models set <model>` atomically and replies with a confirmation.
|
|
43
47
|
|
|
@@ -49,4 +53,4 @@ Each command runs `openclaw models set <model>` atomically and replies with a co
|
|
|
49
53
|
|
|
50
54
|
See `README.md` for full configuration reference and architecture diagram.
|
|
51
55
|
|
|
52
|
-
**Version:** 0.2.
|
|
56
|
+
**Version:** 0.2.10
|
package/index.ts
CHANGED
|
@@ -354,24 +354,32 @@ const plugin = {
|
|
|
354
354
|
let proxyServer: import("node:http").Server | null = null;
|
|
355
355
|
|
|
356
356
|
if (enableProxy) {
|
|
357
|
-
//
|
|
358
|
-
//
|
|
359
|
-
//
|
|
360
|
-
//
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
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
|
+
});
|
|
372
373
|
};
|
|
373
374
|
|
|
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
|
+
|
|
375
383
|
try {
|
|
376
384
|
const server = await startProxyServer({
|
|
377
385
|
port,
|
|
@@ -393,25 +401,28 @@ const plugin = {
|
|
|
393
401
|
} catch (err: unknown) {
|
|
394
402
|
const msg = (err as Error).message ?? String(err);
|
|
395
403
|
if (msg.includes("EADDRINUSE")) {
|
|
396
|
-
//
|
|
397
|
-
api.logger.warn(`[cli-bridge] port ${port}
|
|
398
|
-
await new Promise((r) => setTimeout(r,
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
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
|
+
}
|
|
408
419
|
} else {
|
|
409
420
|
api.logger.warn(`[cli-bridge] proxy failed to start on port ${port}: ${msg}`);
|
|
410
421
|
}
|
|
411
422
|
}
|
|
412
423
|
};
|
|
413
424
|
|
|
414
|
-
|
|
425
|
+
startProxy().catch(() => {});
|
|
415
426
|
}
|
|
416
427
|
|
|
417
428
|
// ── Cleanup: close proxy server on plugin stop (hot-reload / gateway restart) ──
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "openclaw-cli-bridge-elvatis",
|
|
3
3
|
"name": "OpenClaw CLI Bridge",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.10",
|
|
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"
|
|
@@ -36,4 +36,4 @@
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
}
|
|
39
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elvatis_com/openclaw-cli-bridge-elvatis",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.10",
|
|
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": {
|
|
@@ -19,4 +19,4 @@
|
|
|
19
19
|
"typescript": "^5.9.3",
|
|
20
20
|
"vitest": "^4.0.18"
|
|
21
21
|
}
|
|
22
|
-
}
|
|
22
|
+
}
|