limbo-ai 1.23.5 → 1.24.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 +56 -17
  2. package/package.json +1 -1
package/cli.js CHANGED
@@ -1481,7 +1481,7 @@ function installDocker() {
1481
1481
  }
1482
1482
  }
1483
1483
 
1484
- function extractWizardUrl(maxWaitSecs = 15) {
1484
+ function extractWizardUrl(maxWaitSecs = 30) {
1485
1485
  const deadline = Date.now() + maxWaitSecs * 1000;
1486
1486
  while (Date.now() < deadline) {
1487
1487
  try {
@@ -1514,7 +1514,7 @@ ${c.green}${c.bold}╚═══════════════════
1514
1514
  `);
1515
1515
 
1516
1516
  if (tunnel) {
1517
- const tunnelUrl = `${tunnel.url}/?token=${token}`;
1517
+ const tunnelUrl = token ? `${tunnel.url}/?token=${token}` : tunnel.url;
1518
1518
  console.log(` ${c.green}Public URL (works from any browser):${c.reset}
1519
1519
  ${c.cyan}${c.bold}${tunnelUrl}${c.reset}
1520
1520
  `);
@@ -1670,21 +1670,20 @@ async function cmdStart() {
1670
1670
  // ── Route: Wizard reconfigure (--reconfigure, no --cli) ───────────────────
1671
1671
  if (reconfig && hasProviderConfig) {
1672
1672
  log('Resetting configuration for setup wizard...');
1673
- // Remove provider config from .env so container enters setup mode
1674
- const minimalContent = `CLI_LANGUAGE=${existingEnv.CLI_LANGUAGE || 'en'}\nLIMBO_PORT=${PORT}\n`;
1673
+ // Write minimal .env with FORCE_SETUP_MODE the entrypoint will handle
1674
+ // clearing internal config files. This is more reliable than running
1675
+ // `docker compose run` to delete files inside the volume, which can fail
1676
+ // silently due to permissions or Docker state issues.
1677
+ const minimalContent = `CLI_LANGUAGE=${existingEnv.CLI_LANGUAGE || 'en'}\nLIMBO_PORT=${PORT}\nFORCE_SETUP_MODE=true\n`;
1675
1678
  fs.writeFileSync(ENV_FILE, minimalContent, { mode: 0o600 });
1676
1679
  // Keep gateway token secret intact
1677
1680
  ensureGatewayToken(existingEnv);
1678
- // Clean config inside the Docker volume so entrypoint re-enters setup mode
1679
- try {
1680
- runDockerCompose(['run', '--rm', '--no-deps', '--entrypoint', 'sh', 'limbo',
1681
- '-c', 'rm -f /data/config/.env /home/limbo/.zeroclaw/config.toml'], { stdio: 'pipe' });
1682
- } catch {}
1683
1681
  }
1684
1682
 
1685
1683
  // ── Route: Wizard (default for fresh install or wizard reconfigure) ───────
1686
1684
  log('Starting Limbo with setup wizard...');
1687
- if (!alreadyHasEnv || (reconfig && hasProviderConfig)) {
1685
+ if (!alreadyHasEnv && !reconfig) {
1686
+ // Fresh install only — reconfigure already wrote its own .env above
1688
1687
  writeMinimalEnv();
1689
1688
  }
1690
1689
 
@@ -1711,7 +1710,20 @@ async function cmdStart() {
1711
1710
  // Always show the wizard URL with tunnel/SSH info, even if we couldn't
1712
1711
  // extract the token-authenticated URL from logs.
1713
1712
  const displayUrl = wizardUrl || `http://127.0.0.1:${PORT}`;
1713
+ if (!wizardUrl) {
1714
+ warn('Could not extract setup token from container logs. The wizard may need a moment to start.');
1715
+ warn(`If the URL below doesn't work, try: ${c.cyan}limbo logs${c.reset} to check container status.`);
1716
+ }
1714
1717
  printWizardUrl(displayUrl, tunnel);
1718
+
1719
+ // Remove FORCE_SETUP_MODE from .env so the container doesn't re-enter setup
1720
+ // mode on restart after the wizard completes. The entrypoint uses a marker
1721
+ // file as a safety net, but cleaning the env is the primary mechanism.
1722
+ try {
1723
+ const envContent = fs.readFileSync(ENV_FILE, 'utf8');
1724
+ const cleaned = envContent.replace(/^FORCE_SETUP_MODE=.*\n?/m, '');
1725
+ if (cleaned !== envContent) fs.writeFileSync(ENV_FILE, cleaned, { mode: 0o600 });
1726
+ } catch {}
1715
1727
  }
1716
1728
 
1717
1729
  // Shared path for headless, CLI-prompt, and existing-config routes
@@ -1770,20 +1782,40 @@ function selfUpdateCli() {
1770
1782
  (lat[0] === cur[0] && lat[1] === cur[1] && lat[2] > cur[2]);
1771
1783
  if (!isNewer) return;
1772
1784
 
1773
- log(`Updating CLI: ${pkg.version} ${latest}...`);
1774
- execSync('npm install -g limbo-ai@latest', { stdio: 'inherit', timeout: 60000 });
1775
- ok(`CLI updated to ${latest}.`);
1785
+ const isGlobal = !process.argv[1].includes('npx') && !process.argv[1].includes('node_modules/.cache');
1786
+
1787
+ if (isGlobal) {
1788
+ log(`Updating CLI: ${pkg.version} → ${latest}...`);
1789
+ execSync('npm install -g limbo-ai@latest', { stdio: 'inherit', timeout: 60000 });
1790
+ ok(`CLI updated to ${latest}.`);
1791
+ } else {
1792
+ // npx served a stale cached version — clear it
1793
+ warn(`CLI is outdated (${pkg.version} → ${latest}). npx served a cached version.`);
1794
+ try {
1795
+ const npxCacheBase = path.join(os.homedir(), '.npm', '_npx');
1796
+ if (fs.existsSync(npxCacheBase)) {
1797
+ for (const entry of fs.readdirSync(npxCacheBase)) {
1798
+ const pkgPath = path.join(npxCacheBase, entry, 'node_modules', 'limbo-ai');
1799
+ if (fs.existsSync(pkgPath)) {
1800
+ fs.rmSync(path.join(npxCacheBase, entry), { recursive: true, force: true });
1801
+ log('Cleared stale npx cache.');
1802
+ break;
1803
+ }
1804
+ }
1805
+ }
1806
+ } catch {}
1807
+ log(`Re-run: ${c.cyan}npx limbo-ai@latest update${c.reset}`);
1808
+ }
1776
1809
  } catch {
1777
- warn('Could not self-update CLI. Run: npm install -g limbo-ai@latest');
1810
+ warn('Could not check for CLI updates. Run: npm install -g limbo-ai@latest');
1778
1811
  }
1779
1812
  }
1780
1813
 
1781
1814
  function cmdUpdate() {
1782
1815
  if (!fs.existsSync(COMPOSE_FILE)) die(t('en', 'installMissing'));
1783
1816
 
1784
- // Self-update the CLI if installed globally
1785
- const isGlobal = !process.argv[1].includes('npx') && !process.argv[1].includes('node_modules/.cache');
1786
- if (isGlobal) selfUpdateCli();
1817
+ // Always attempt CLI self-update, regardless of install method
1818
+ selfUpdateCli();
1787
1819
 
1788
1820
  // Patch image tag to :latest in existing compose files (handles upgrades from pinned tags)
1789
1821
  let compose = fs.readFileSync(COMPOSE_FILE, 'utf8');
@@ -1801,6 +1833,10 @@ function cmdUpdate() {
1801
1833
  run(`docker compose -f "${COMPOSE_FILE}" pull -q`);
1802
1834
  log('Restarting...');
1803
1835
  run(`docker compose -f "${COMPOSE_FILE}" up -d --remove-orphans`);
1836
+
1837
+ // Clear update-check cache so the banner doesn't persist after a successful update
1838
+ try { fs.unlinkSync(UPDATE_CHECK_FILE); } catch {}
1839
+
1804
1840
  ok('Updated and restarted.');
1805
1841
  }
1806
1842
 
@@ -2042,6 +2078,9 @@ if (require.main === module) {
2042
2078
  case 'update': cmdUpdate(); break;
2043
2079
  case 'status': cmdStatus(); break;
2044
2080
  case 'config': cmdConfig(); break;
2081
+ case 'version':
2082
+ case '--version':
2083
+ case '-v': console.log(require('./package.json').version); break;
2045
2084
  case 'help':
2046
2085
  case '--help':
2047
2086
  case '-h': cmdHelp(); break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "limbo-ai",
3
- "version": "1.23.5",
3
+ "version": "1.24.0",
4
4
  "description": "Your personal AI memory agent — install and manage Limbo via npx",
5
5
  "type": "commonjs",
6
6
  "bin": {