limbo-ai 1.8.0 → 1.9.0

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.
Files changed (2) hide show
  1. package/cli.js +86 -24
  2. package/package.json +1 -1
package/cli.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // Orchestrates the Docker-based Limbo runtime.
4
4
  'use strict';
5
5
 
6
- const { execSync, spawnSync } = require('child_process');
6
+ const { execSync, spawn, spawnSync } = require('child_process');
7
7
  const crypto = require('crypto');
8
8
  const fs = require('fs');
9
9
  const os = require('os');
@@ -212,7 +212,7 @@ const TEXT = {
212
212
  modelQuestion: 'Model',
213
213
  customModel: 'Add another supported model name',
214
214
  customModelPrompt: ' Model name: ',
215
- invalidModel: 'That model is not in the current OpenClaw docs allowlist for this provider/auth path.',
215
+ invalidModel: 'That model is not supported for this provider and access method.',
216
216
  supportedModels: 'Supported models:',
217
217
  openAiApiKeyPrompt: ' OpenAI API key (sk-...): ',
218
218
  anthropicApiKeyPrompt: ' Anthropic API key (sk-ant-...): ',
@@ -252,15 +252,16 @@ const TEXT = {
252
252
  logsHint: 'Check logs with: limbo logs',
253
253
  healthy: 'Container is healthy.',
254
254
  subscriptionSetup: 'Provider authentication',
255
- openaiSubscriptionIntro: 'Limbo will open OpenClaw auth inside the container so you can complete Codex login.',
255
+ openaiSubscriptionIntro: 'Limbo will authenticate with your AI provider. A URL will appear — open it in your browser to complete login.',
256
256
  anthropicSubscriptionIntro: 'Generate a Claude setup-token on any machine with `claude setup-token`, then paste it into the next step.',
257
- authFlowStart: 'Starting provider auth flow...',
258
- authFlowDone: 'Provider auth completed.',
259
- authFlowFailed: 'Provider auth did not complete successfully.',
260
- authStatusFailed: 'OpenClaw still reports missing or invalid auth for the selected provider.',
261
- configFlowStart: 'Applying OpenClaw config...',
262
- configFlowDone: 'OpenClaw config updated.',
263
- configFlowFailed: 'Could not update the OpenClaw config for Limbo.',
257
+ authFlowStart: 'Starting authentication...',
258
+ authFlowDone: 'Authentication complete.',
259
+ authFlowFailed: 'Authentication did not complete successfully.',
260
+ authStatusFailed: 'Provider auth is still missing or invalid. Try running with --reconfigure.',
261
+ configFlowStart: 'Applying configuration...',
262
+ configFlowDone: 'Configuration applied.',
263
+ configFlowFailed: 'Could not apply configuration. Check your settings and try again.',
264
+ composing: 'Initializing...',
264
265
  success: 'Limbo is running!',
265
266
  gateway: 'Gateway',
266
267
  gatewayToken: 'Gateway token',
@@ -303,7 +304,7 @@ const TEXT = {
303
304
  modelQuestion: 'Modelo',
304
305
  customModel: 'Agregar otro nombre de modelo soportado',
305
306
  customModelPrompt: ' Nombre del modelo: ',
306
- invalidModel: 'Ese modelo no esta en la allowlist actual de OpenClaw para este provider y metodo.',
307
+ invalidModel: 'Ese modelo no esta soportado para este provider y metodo de acceso.',
307
308
  supportedModels: 'Modelos soportados:',
308
309
  openAiApiKeyPrompt: ' OpenAI API key (sk-...): ',
309
310
  anthropicApiKeyPrompt: ' Anthropic API key (sk-ant-...): ',
@@ -343,15 +344,16 @@ const TEXT = {
343
344
  logsHint: 'Mira los logs con: limbo logs',
344
345
  healthy: 'El container esta healthy.',
345
346
  subscriptionSetup: 'Autenticacion del provider',
346
- openaiSubscriptionIntro: 'Limbo va a abrir la autenticacion de OpenClaw dentro del container para que completes el login de Codex.',
347
+ openaiSubscriptionIntro: 'Limbo va a autenticarse con tu proveedor de IA. Aparecera una URL abrisla en el navegador para completar el login.',
347
348
  anthropicSubscriptionIntro: 'Genera un Claude setup-token en cualquier maquina con `claude setup-token` y pegalo en el siguiente paso.',
348
- authFlowStart: 'Iniciando autenticacion del provider...',
349
- authFlowDone: 'Autenticacion del provider completada.',
350
- authFlowFailed: 'La autenticacion del provider no termino correctamente.',
351
- authStatusFailed: 'OpenClaw sigue reportando auth faltante o invalida para el provider elegido.',
352
- configFlowStart: 'Aplicando configuracion de OpenClaw...',
353
- configFlowDone: 'Configuracion de OpenClaw actualizada.',
354
- configFlowFailed: 'No se pudo actualizar la configuracion de OpenClaw para Limbo.',
349
+ authFlowStart: 'Iniciando autenticacion...',
350
+ authFlowDone: 'Autenticacion completada.',
351
+ authFlowFailed: 'La autenticacion no termino correctamente.',
352
+ authStatusFailed: 'La autenticacion del provider sigue siendo invalida o no esta configurada. Proba con --reconfigure.',
353
+ configFlowStart: 'Aplicando configuracion...',
354
+ configFlowDone: 'Configuracion aplicada.',
355
+ configFlowFailed: 'No se pudo aplicar la configuracion. Revisa los ajustes e intenta de nuevo.',
356
+ composing: 'Inicializando...',
355
357
  success: 'Limbo esta corriendo!',
356
358
  gateway: 'Gateway',
357
359
  gatewayToken: 'Token del gateway',
@@ -807,7 +809,53 @@ function applyOpenClawConfig(cfg) {
807
809
  ok(t(cfg.language, 'configFlowDone'));
808
810
  }
809
811
 
810
- function runSubscriptionAuthFlow(cfg) {
812
+ // Spawn OpenClaw auth with filtered output: extract OAuth URLs, suppress branding.
813
+ // Uses async spawn so URLs appear in real-time (spawnSync would buffer until exit).
814
+ function streamFilteredAuth(dockerArgs) {
815
+ return new Promise((resolve) => {
816
+ const proc = spawn('docker', dockerArgs, {
817
+ cwd: LIMBO_DIR,
818
+ stdio: ['inherit', 'pipe', 'pipe'],
819
+ });
820
+
821
+ const urlRe = /https?:\/\/[^\s"'<>\]]+/g;
822
+ const seenUrls = new Set();
823
+ let buf = '';
824
+
825
+ const handleData = (data) => {
826
+ buf += data.toString();
827
+ const lines = buf.split('\n');
828
+ buf = lines.pop(); // hold incomplete last line
829
+ for (const line of lines) emitLine(line);
830
+ };
831
+
832
+ const emitLine = (line) => {
833
+ const urls = line.match(urlRe) || [];
834
+ if (urls.length > 0) {
835
+ for (const url of urls) {
836
+ if (!seenUrls.has(url)) {
837
+ seenUrls.add(url);
838
+ console.log(`\n ${c.cyan}${c.bold}→ ${url}${c.reset}\n`);
839
+ }
840
+ }
841
+ return;
842
+ }
843
+ // Suppress lines that only contain internal gateway/runtime branding
844
+ if (/openclaw/i.test(line)) return;
845
+ if (line.trim()) console.log(` ${line}`);
846
+ };
847
+
848
+ proc.stdout.on('data', handleData);
849
+ proc.stderr.on('data', handleData);
850
+ proc.on('close', (code) => {
851
+ if (buf.trim()) emitLine(buf);
852
+ resolve(code ?? 1);
853
+ });
854
+ proc.on('error', () => resolve(1));
855
+ });
856
+ }
857
+
858
+ async function runSubscriptionAuthFlow(cfg) {
811
859
  header(t(cfg.language, 'subscriptionSetup'));
812
860
  if (cfg.providerFamily === 'openai') {
813
861
  log(t(cfg.language, 'openaiSubscriptionIntro'));
@@ -820,8 +868,17 @@ function runSubscriptionAuthFlow(cfg) {
820
868
  ? ['models', 'auth', 'login', '--provider', 'openai-codex']
821
869
  : ['models', 'auth', 'paste-token', '--provider', 'anthropic'];
822
870
 
823
- const authResult = runOpenClaw(authArgs);
824
- if (authResult.status !== 0) die(t(cfg.language, 'authFlowFailed'));
871
+ let exitCode;
872
+ if (cfg.providerFamily === 'openai') {
873
+ // Stream output and extract OAuth URL so the user never sees "openclaw"
874
+ exitCode = await streamFilteredAuth(['compose', 'run', '--rm', '--entrypoint', 'openclaw', 'limbo', ...authArgs]);
875
+ } else {
876
+ // Anthropic paste-token is interactive (user pastes a token); keep stdio inherited
877
+ const authResult = runOpenClaw(authArgs);
878
+ exitCode = authResult.status;
879
+ }
880
+
881
+ if (exitCode !== 0) die(t(cfg.language, 'authFlowFailed'));
825
882
 
826
883
  const statusResult = runOpenClaw(
827
884
  ['models', 'status', '--check', '--probe-provider', cfg.provider],
@@ -912,7 +969,7 @@ async function cmdStart() {
912
969
  pullOrBuildImage(cfg.language);
913
970
 
914
971
  if (cfg.authMode === 'subscription' && (process.argv.includes('--reconfigure') || !alreadyHasEnv)) {
915
- runSubscriptionAuthFlow(cfg);
972
+ await runSubscriptionAuthFlow(cfg);
916
973
  }
917
974
 
918
975
  applyOpenClawConfig({
@@ -922,7 +979,12 @@ async function cmdStart() {
922
979
  });
923
980
 
924
981
  header(t(cfg.language, 'starting'));
925
- run('docker compose up -d --remove-orphans');
982
+ log(t(cfg.language, 'composing'));
983
+ const upResult = runDockerCompose(['up', '-d', '--remove-orphans'], { stdio: 'pipe' });
984
+ if (upResult.status !== 0) {
985
+ process.stderr.write(upResult.stderr || '');
986
+ die('Container failed to start. Run `limbo logs` to investigate.');
987
+ }
926
988
 
927
989
  header(t(cfg.language, 'verifying'));
928
990
  const healthy = waitForHealthy(cfg.language);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "limbo-ai",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "description": "Your personal AI memory agent — install and manage Limbo via npx",
5
5
  "type": "commonjs",
6
6
  "bin": {