@elvatis_com/openclaw-cli-bridge-elvatis 1.3.2 → 1.3.4
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/STATUS.md +28 -19
- package/README.md +15 -1
- package/index.ts +89 -6
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/.ai/handoff/STATUS.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# STATUS — openclaw-cli-bridge-elvatis
|
|
2
2
|
|
|
3
|
-
## Current Version: 1.
|
|
3
|
+
## Current Version: 1.3.3 (npm + ClawHub + GitHub) ✅ RELEASED
|
|
4
4
|
|
|
5
|
-
## All 4 Providers
|
|
5
|
+
## All 4 Providers Available — on-demand via /xxx-login
|
|
6
6
|
| Provider | Status | Models | Command |
|
|
7
7
|
|---|---|---|---|
|
|
8
8
|
| Grok | ✅ | web-grok/grok-3, grok-3-fast, grok-3-mini, grok-3-mini-fast | /grok-login |
|
|
@@ -10,26 +10,35 @@
|
|
|
10
10
|
| Gemini | ✅ | web-gemini/gemini-2-5-pro, gemini-2-5-flash, gemini-3-pro, gemini-3-flash | /gemini-login |
|
|
11
11
|
| ChatGPT | ✅ | web-chatgpt/gpt-4o, gpt-4o-mini, gpt-o3, gpt-o4-mini, gpt-5 | /chatgpt-login |
|
|
12
12
|
|
|
13
|
-
Live test: "What is the capital of France?"
|
|
14
|
-
- Grok: "Paris" ✅
|
|
15
|
-
- Claude: "Paris" ✅
|
|
16
|
-
- Gemini: "Paris" ✅
|
|
17
|
-
- ChatGPT: "Paris" ✅
|
|
18
|
-
|
|
19
13
|
## Stats
|
|
20
14
|
- 22 total models, 16 web-session models
|
|
21
15
|
- 96/96 tests green (8 test files)
|
|
22
|
-
- 0 zombie Chromium processes
|
|
16
|
+
- 0 zombie Chromium processes at startup (browsers on-demand only)
|
|
23
17
|
- Cookie expiry tracking for all 4 providers
|
|
18
|
+
- Singleton guard on ensureAllProviderContexts (no concurrent spawns)
|
|
19
|
+
|
|
20
|
+
## Architecture: Browser Lifecycle
|
|
21
|
+
- **On plugin start:** NO browser launched automatically
|
|
22
|
+
- **On /xxx-login:** launches persistent Chromium for that provider only
|
|
23
|
+
- **On request (no context):** returns null → caller sees "not logged in" error
|
|
24
|
+
- **On /xxx-logout:** closes context + deletes session file
|
|
25
|
+
|
|
26
|
+
## Known Issues
|
|
27
|
+
- Cloudflare may block headless Chromium for Claude/Gemini without a valid CDP session
|
|
28
|
+
→ Workaround: have OpenClaw browser open on the provider's page, then /xxx-login
|
|
24
29
|
|
|
25
|
-
##
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
## Release History
|
|
31
|
+
- v1.3.3 (2026-03-12): Remove startup auto-connect — browsers on-demand only (OOM fix)
|
|
32
|
+
- v1.3.2 (2026-03-12): Singleton guard on ensureAllProviderContexts (resource leak fix)
|
|
33
|
+
- v1.3.1 (2026-03-11): Cookie baking into persistent profiles on login
|
|
34
|
+
- v1.3.0 (2026-03-11): Browser auto-reconnect after gateway restart
|
|
35
|
+
- v1.2.0 (2026-03-11): Fresh page per request + ChatGPT model switching
|
|
36
|
+
- v1.1.0 (2026-03-11): Auto-connect on startup + /bridge-status
|
|
37
|
+
- v1.0.0 (2026-03-11): All 4 providers headless (Grok/Claude/Gemini/ChatGPT) — 96/96 tests
|
|
38
|
+
- v0.2.x: Grok (v0.2.26-28), Claude (v0.2.29), Gemini (v0.2.30)
|
|
39
|
+
- v0.2.25: Sleep-resilient token refresh + staged /cli-* switching
|
|
29
40
|
|
|
30
|
-
## Next Steps
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
- Handle model-switching within chatgpt.com (dropdown selector)
|
|
35
|
-
- Handle Gemini model switching (2.5 Pro vs Flash vs 3)
|
|
41
|
+
## Next Steps
|
|
42
|
+
- Context-window management for long conversations
|
|
43
|
+
- Gemini model switching (2.5 Pro vs Flash vs 3) via UI
|
|
44
|
+
- /bridge-status: show per-provider login state + cookie expiry
|
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, health testing, and model listing.
|
|
4
4
|
|
|
5
|
-
**Current version:** `1.3.
|
|
5
|
+
**Current version:** `1.3.4`
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -287,6 +287,20 @@ npm test # vitest run (45 tests)
|
|
|
287
287
|
|
|
288
288
|
## Changelog
|
|
289
289
|
|
|
290
|
+
### v1.3.4
|
|
291
|
+
- **feat:** Safe sequential session restore on startup — if a saved profile exists, providers are reconnected automatically after gateway restart (one at a time, 3s delay between each, headless)
|
|
292
|
+
- **fix:** No manual `/xxx-login` needed after reboot if profile is already saved
|
|
293
|
+
- **safety:** Profile-gated — only restores if `~/.openclaw/<provider>-profile/` or cookie file exists; never spawns a browser for an uninitialized provider
|
|
294
|
+
|
|
295
|
+
### v1.3.3
|
|
296
|
+
- **fix:** Removed auto-connect of all browser providers on plugin startup — caused OOM (load 195, 30GB RAM) by spawning 4+ persistent Chromium instances on every gateway start
|
|
297
|
+
- **fix:** Removed Grok session restore on startup — same root cause
|
|
298
|
+
- **behavior change:** Browsers are now started **on-demand only** via `/grok-login`, `/claude-login`, `/gemini-login`, `/chatgpt-login`
|
|
299
|
+
|
|
300
|
+
### v1.3.2
|
|
301
|
+
- **fix:** Singleton promise guard on `ensureAllProviderContexts()` — concurrent requests no longer each spawn their own Chromium; extra callers await the existing run
|
|
302
|
+
- **fix:** Removed recursive `ensureAllProviderContexts()` fallback from all `connect*Context` proxy callbacks — no more exponential browser spawn on CDP failure
|
|
303
|
+
|
|
290
304
|
### v1.3.1
|
|
291
305
|
- **fix:** /claude-login, /gemini-login, /chatgpt-login now bake cookies into persistent profile dirs
|
|
292
306
|
- **fix:** After gateway restart, providers auto-reconnect from saved profile (no browser tabs needed)
|
package/index.ts
CHANGED
|
@@ -746,13 +746,96 @@ const plugin = {
|
|
|
746
746
|
const codexAuthPath = cfg.codexAuthPath ?? DEFAULT_CODEX_AUTH_PATH;
|
|
747
747
|
const grokSessionPath = cfg.grokSessionPath ?? DEFAULT_SESSION_PATH;
|
|
748
748
|
|
|
749
|
-
// ──
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
//
|
|
749
|
+
// ── Safe session restore on startup (sequential, profile-gated, non-blocking) ──
|
|
750
|
+
// Restores provider sessions from saved persistent profiles — but ONLY if the
|
|
751
|
+
// profile directory already exists (i.e. user has logged in before).
|
|
752
|
+
// Providers are launched one at a time with a delay to avoid OOM.
|
|
753
753
|
void (async () => {
|
|
754
|
-
await new Promise(r => setTimeout(r,
|
|
755
|
-
|
|
754
|
+
await new Promise(r => setTimeout(r, 5000)); // wait for proxy + gateway to settle
|
|
755
|
+
const { chromium } = await import("playwright");
|
|
756
|
+
const { existsSync } = await import("node:fs");
|
|
757
|
+
|
|
758
|
+
const profileProviders: Array<{
|
|
759
|
+
name: string;
|
|
760
|
+
profileDir: string;
|
|
761
|
+
cookieFile: string;
|
|
762
|
+
verifySelector: string;
|
|
763
|
+
homeUrl: string;
|
|
764
|
+
setCtx: (c: BrowserContext) => void;
|
|
765
|
+
getCtx: () => BrowserContext | null;
|
|
766
|
+
}> = [
|
|
767
|
+
{
|
|
768
|
+
name: "grok",
|
|
769
|
+
profileDir: GROK_PROFILE_DIR,
|
|
770
|
+
cookieFile: join(homedir(), ".openclaw", "grok-session.json"),
|
|
771
|
+
verifySelector: "textarea",
|
|
772
|
+
homeUrl: "https://grok.com",
|
|
773
|
+
getCtx: () => grokContext,
|
|
774
|
+
setCtx: (c) => { grokContext = c; },
|
|
775
|
+
},
|
|
776
|
+
{
|
|
777
|
+
name: "claude",
|
|
778
|
+
profileDir: join(homedir(), ".openclaw", "claude-profile"),
|
|
779
|
+
cookieFile: join(homedir(), ".openclaw", "claude-cookie-expiry.json"),
|
|
780
|
+
verifySelector: ".ProseMirror",
|
|
781
|
+
homeUrl: "https://claude.ai/new",
|
|
782
|
+
getCtx: () => claudeContext,
|
|
783
|
+
setCtx: (c) => { claudeContext = c; },
|
|
784
|
+
},
|
|
785
|
+
{
|
|
786
|
+
name: "gemini",
|
|
787
|
+
profileDir: join(homedir(), ".openclaw", "gemini-profile"),
|
|
788
|
+
cookieFile: join(homedir(), ".openclaw", "gemini-cookie-expiry.json"),
|
|
789
|
+
verifySelector: ".ql-editor",
|
|
790
|
+
homeUrl: "https://gemini.google.com/app",
|
|
791
|
+
getCtx: () => geminiContext,
|
|
792
|
+
setCtx: (c) => { geminiContext = c; },
|
|
793
|
+
},
|
|
794
|
+
{
|
|
795
|
+
name: "chatgpt",
|
|
796
|
+
profileDir: join(homedir(), ".openclaw", "chatgpt-profile"),
|
|
797
|
+
cookieFile: join(homedir(), ".openclaw", "chatgpt-cookie-expiry.json"),
|
|
798
|
+
verifySelector: "#prompt-textarea",
|
|
799
|
+
homeUrl: "https://chatgpt.com",
|
|
800
|
+
getCtx: () => chatgptContext,
|
|
801
|
+
setCtx: (c) => { chatgptContext = c; },
|
|
802
|
+
},
|
|
803
|
+
];
|
|
804
|
+
|
|
805
|
+
for (const p of profileProviders) {
|
|
806
|
+
// Skip if no saved profile/session exists
|
|
807
|
+
if (!existsSync(p.profileDir) && !existsSync(p.cookieFile)) {
|
|
808
|
+
api.logger.info(`[cli-bridge:${p.name}] no saved profile — skipping startup restore`);
|
|
809
|
+
continue;
|
|
810
|
+
}
|
|
811
|
+
if (p.getCtx()) continue; // already connected
|
|
812
|
+
|
|
813
|
+
try {
|
|
814
|
+
api.logger.info(`[cli-bridge:${p.name}] restoring session from profile…`);
|
|
815
|
+
const ctx = await chromium.launchPersistentContext(p.profileDir, {
|
|
816
|
+
headless: true,
|
|
817
|
+
args: ["--no-sandbox", "--disable-setuid-sandbox"],
|
|
818
|
+
});
|
|
819
|
+
const page = await ctx.newPage();
|
|
820
|
+
await page.goto(p.homeUrl, { waitUntil: "domcontentloaded", timeout: 20_000 });
|
|
821
|
+
await new Promise(r => setTimeout(r, 3000));
|
|
822
|
+
const ok = await page.locator(p.verifySelector).isVisible().catch(() => false);
|
|
823
|
+
await page.close().catch(() => {});
|
|
824
|
+
if (ok) {
|
|
825
|
+
p.setCtx(ctx);
|
|
826
|
+
ctx.on("close", () => { p.setCtx(null as unknown as BrowserContext); });
|
|
827
|
+
api.logger.info(`[cli-bridge:${p.name}] session restored from profile ✅`);
|
|
828
|
+
} else {
|
|
829
|
+
await ctx.close().catch(() => {});
|
|
830
|
+
api.logger.info(`[cli-bridge:${p.name}] profile exists but not logged in — skipping`);
|
|
831
|
+
}
|
|
832
|
+
} catch (err) {
|
|
833
|
+
api.logger.warn(`[cli-bridge:${p.name}] startup restore failed: ${(err as Error).message}`);
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
// Sequential delay — avoid spawning all 4 Chromium instances at once
|
|
837
|
+
await new Promise(r => setTimeout(r, 3000));
|
|
838
|
+
}
|
|
756
839
|
})();
|
|
757
840
|
|
|
758
841
|
// ── Phase 1: openai-codex auth bridge ─────────────────────────────────────
|
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": "1.3.
|
|
4
|
+
"version": "1.3.4",
|
|
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": "1.3.
|
|
3
|
+
"version": "1.3.4",
|
|
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": {
|