limbo-ai 1.9.2 → 1.9.3
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/cli.js +24 -7
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -20,6 +20,8 @@ const COMPOSE_FILE = path.join(LIMBO_DIR, 'docker-compose.yml');
|
|
|
20
20
|
const GHCR_IMAGE = 'ghcr.io/tomasward1/limbo';
|
|
21
21
|
const DEFAULT_TAG = require('./package.json').version;
|
|
22
22
|
const PORT = 18789;
|
|
23
|
+
// OpenClaw's OAuth callback server port — must be exposed when running auth inside Docker
|
|
24
|
+
const OPENCLAW_AUTH_PORT = 1453;
|
|
23
25
|
|
|
24
26
|
// OpenClaw compatibility snapshots from official docs:
|
|
25
27
|
// - https://docs.openclaw.ai/providers/openai
|
|
@@ -817,7 +819,8 @@ const stripAnsi = (str) => str.replace(/\x1b\[[0-9;]*[A-Za-z]/g, '').replace(/\r
|
|
|
817
819
|
// Spawn OpenClaw auth with filtered output: extract OAuth URLs, suppress branding.
|
|
818
820
|
// --tty is required so openclaw sees a TTY inside the container and runs the auth wizard.
|
|
819
821
|
// We pipe stdout/stderr to filter content while the container gets a proper PTY allocation.
|
|
820
|
-
|
|
822
|
+
// onUrl: optional callback invoked with each unique URL as it appears (e.g. to auto-open browser).
|
|
823
|
+
function streamFilteredAuth(dockerArgs, onUrl = null) {
|
|
821
824
|
return new Promise((resolve) => {
|
|
822
825
|
const proc = spawn('docker', dockerArgs, {
|
|
823
826
|
cwd: LIMBO_DIR,
|
|
@@ -839,13 +842,19 @@ function streamFilteredAuth(dockerArgs) {
|
|
|
839
842
|
const emitLine = (rawLine) => {
|
|
840
843
|
const line = stripAnsi(rawLine);
|
|
841
844
|
const urls = line.match(urlRe) || [];
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
845
|
+
if (urls.length > 0) {
|
|
846
|
+
for (const url of urls) {
|
|
847
|
+
if (!seenUrls.has(url)) {
|
|
848
|
+
seenUrls.add(url);
|
|
849
|
+
console.log(`\n ${c.cyan}${c.bold}→ ${url}${c.reset}\n`);
|
|
850
|
+
if (onUrl) onUrl(url);
|
|
851
|
+
}
|
|
847
852
|
}
|
|
853
|
+
return; // don't double-print the line containing the URL
|
|
848
854
|
}
|
|
855
|
+
// Suppress OpenClaw branding; show everything else (prompts, status, interactive questions)
|
|
856
|
+
if (/openclaw/i.test(line)) return;
|
|
857
|
+
if (line.trim()) console.log(` ${line}`);
|
|
849
858
|
};
|
|
850
859
|
|
|
851
860
|
proc.stdout.on('data', handleData);
|
|
@@ -874,8 +883,16 @@ async function runSubscriptionAuthFlow(cfg) {
|
|
|
874
883
|
let exitCode;
|
|
875
884
|
if (cfg.providerFamily === 'openai') {
|
|
876
885
|
// --tty allocates a PTY inside the container so openclaw's auth wizard runs correctly.
|
|
886
|
+
// -p exposes the OAuth callback port so the browser redirect reaches the in-container server.
|
|
877
887
|
// We still pipe stdout/stderr to filter out branding and highlight the OAuth URL.
|
|
878
|
-
|
|
888
|
+
const opener = process.platform === 'darwin' ? 'open' : 'xdg-open';
|
|
889
|
+
exitCode = await streamFilteredAuth(
|
|
890
|
+
['compose', 'run', '--tty', '--rm', '-p', `${OPENCLAW_AUTH_PORT}:${OPENCLAW_AUTH_PORT}`, '--entrypoint', 'openclaw', 'limbo', ...authArgs],
|
|
891
|
+
(url) => {
|
|
892
|
+
// Auto-open the browser so the user doesn't need to copy/paste the URL
|
|
893
|
+
try { spawnSync(opener, [url], { stdio: 'ignore', timeout: 3000 }); } catch {}
|
|
894
|
+
},
|
|
895
|
+
);
|
|
879
896
|
} else {
|
|
880
897
|
// Anthropic paste-token is interactive (user pastes a token); keep stdio inherited
|
|
881
898
|
const authResult = runOpenClaw(authArgs);
|