0agent 1.0.33 → 1.0.35

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/bin/chat.js CHANGED
@@ -354,8 +354,23 @@ async function runTask(input) {
354
354
  // Catches completion when WS is disconnected (e.g. daemon just restarted).
355
355
  let lastPolledStep = 0;
356
356
  const sid = sessionId;
357
+ const sessionStart = Date.now();
357
358
  const pollTimer = setInterval(async () => {
358
359
  if (!pendingResolve || sessionId !== sid) { clearInterval(pollTimer); return; }
360
+
361
+ // Hard cap: if session runs for > 2 minutes, force-unblock the chat.
362
+ // The daemon session may still run in background, but the user gets their prompt back.
363
+ if (Date.now() - sessionStart > 120_000) {
364
+ clearInterval(pollTimer);
365
+ spinner.stop();
366
+ console.log(`\n \x1b[33m⚠\x1b[0m Session still running in background (> 2min). Chat unblocked.\n`);
367
+ const res = pendingResolve;
368
+ pendingResolve = null;
369
+ sessionId = null;
370
+ res();
371
+ rl.prompt();
372
+ return;
373
+ }
359
374
  try {
360
375
  const r = await fetch(`${BASE_URL}/api/sessions/${sid}`, { signal: AbortSignal.timeout(2000) });
361
376
  const session = await r.json();
@@ -391,7 +406,7 @@ async function runTask(input) {
391
406
  rl.prompt();
392
407
  }
393
408
  } catch {}
394
- }, 1500);
409
+ }, 800);
395
410
 
396
411
  return new Promise(resolve => { pendingResolve = resolve; });
397
412
  } catch (e) {
@@ -758,62 +773,61 @@ async function _safeJsonFetch(url, opts) {
758
773
  console.log(` ${fmt(C.yellow, '⚠')} LLM check failed: ${e.message}\n`);
759
774
  }
760
775
 
761
- // ── Version check ask to update if newer version is on npm ──────────────
762
- try {
763
- const pkgPath = resolve(new URL(import.meta.url).pathname, '..', '..', 'package.json');
764
- const currentVersion = existsSync(pkgPath)
765
- ? JSON.parse(readFileSync(pkgPath, 'utf8')).version
766
- : null;
776
+ // ── Auto-update: check npm, update silently, restart ─────────────────────
777
+ // Runs in background after prompt — never blocks startup.
778
+ // If update found: counts down 3s (press any key to skip), then auto-installs.
779
+ (async () => {
780
+ try {
781
+ const pkgPath = resolve(new URL(import.meta.url).pathname, '..', '..', 'package.json');
782
+ const currentVersion = existsSync(pkgPath)
783
+ ? JSON.parse(readFileSync(pkgPath, 'utf8')).version
784
+ : null;
785
+ if (!currentVersion) return;
767
786
 
768
- if (currentVersion) {
769
787
  const reg = await fetch('https://registry.npmjs.org/0agent/latest', {
770
- signal: AbortSignal.timeout(4000),
788
+ signal: AbortSignal.timeout(5000),
771
789
  }).then(r => r.json()).catch(() => null);
772
790
 
773
791
  const latest = reg?.version;
774
- if (latest && latest !== currentVersion && isNewerVersion(latest, currentVersion)) {
775
- console.log(`\n ${fmt(C.yellow, '↑')} Update available: ${fmt(C.dim, currentVersion)} → ${fmt(C.bold + C.green, latest)}`);
776
- process.stdout.write(` Update now? ${fmt(C.bold, '[y/N]')} `);
777
-
778
- await new Promise((res) => {
779
- const handler = async (buf) => {
780
- const answer = buf.toString().trim().toLowerCase();
781
- process.stdout.write(answer + '\n');
782
- if (answer === 'y') {
783
- process.stdout.write(`\n ${fmt(C.dim, 'Installing 0agent@latest...')}\n`);
784
- try {
785
- const { execSync: exs } = await import('node:child_process');
786
- exs('npm install -g 0agent@latest', { stdio: 'inherit', timeout: 120_000 });
787
- process.stdout.write(`\n ${fmt(C.green, '✓')} Updated to ${latest} — restarting...\n\n`);
788
- // Restart: spawn new instance, exit current
789
- const { spawn: sp } = await import('node:child_process');
790
- const child = sp(process.argv[0], process.argv.slice(1), { stdio: 'inherit' });
791
- child.on('close', (code) => process.exit(code ?? 0));
792
- process.stdin.pause();
793
- } catch (e) {
794
- process.stdout.write(`\n ${fmt(C.red, '✗')} Update failed: ${e.message}\n Try manually: npm install -g 0agent@latest\n\n`);
795
- rl.prompt();
796
- }
797
- } else {
798
- process.stdout.write(` ${fmt(C.dim, `Skipping — run: npm install -g 0agent@${latest} to update later`)}\n\n`);
799
- rl.prompt();
800
- }
801
- res();
802
- };
792
+ if (!latest || !isNewerVersion(latest, currentVersion)) return;
803
793
 
804
- // Single keypress if TTY, line otherwise
805
- if (process.stdin.isTTY) {
806
- process.stdin.once('data', handler);
807
- } else {
808
- rl.once('line', (line) => handler(Buffer.from(line)));
809
- }
810
- });
811
- return; // rl.prompt() already called in handler
794
+ // Show banner immediately above current prompt line
795
+ process.stdout.write(`\n ${fmt(C.yellow, '↑')} New version ${fmt(C.bold, latest)} available (you have ${currentVersion})\n`);
796
+
797
+ // 3-second countdown — press any key to skip, otherwise auto-updates
798
+ let skipped = false;
799
+ const skipHandler = () => { skipped = true; };
800
+ process.stdin.once('data', skipHandler);
801
+
802
+ for (let i = 3; i > 0; i--) {
803
+ if (skipped) break;
804
+ process.stdout.write(`\r ${fmt(C.dim, `Auto-updating in ${i}s — press any key to skip... `)}`);
805
+ await new Promise(r => setTimeout(r, 1000));
806
+ }
807
+ process.stdin.removeListener('data', skipHandler);
808
+ process.stdout.write('\r\x1b[2K'); // clear countdown line
809
+
810
+ if (skipped) {
811
+ console.log(` ${fmt(C.dim, `Skipped. Run: npm install -g 0agent@${latest}`)}`);
812
+ rl.prompt(true);
813
+ return;
812
814
  }
815
+
816
+ // Auto-install
817
+ console.log(` ${fmt(C.cyan, '↑')} Updating to ${latest}...`);
818
+ const { execSync: exs } = await import('node:child_process');
819
+ exs('npm install -g 0agent@latest --silent', { stdio: 'ignore', timeout: 120_000 });
820
+ process.stdout.write(` ${fmt(C.green, '✓')} Updated to ${latest} — restarting...\n\n`);
821
+
822
+ // Restart cleanly
823
+ const { spawn: sp } = await import('node:child_process');
824
+ const child = sp(process.argv[0], process.argv.slice(1), { stdio: 'inherit' });
825
+ child.on('close', (code) => process.exit(code ?? 0));
826
+ process.stdin.pause();
827
+ } catch {
828
+ // Non-fatal — update failure never crashes the agent
813
829
  }
814
- } catch {
815
- // Version check is non-fatal — never block startup
816
- }
830
+ })();
817
831
 
818
832
  rl.prompt();
819
833
  })();
package/dist/daemon.mjs CHANGED
@@ -2339,9 +2339,13 @@ var init_ShellCapability = __esm({
2339
2339
  }
2340
2340
  };
2341
2341
  async execute(input, cwd) {
2342
- const command = String(input.command ?? "");
2342
+ let command = String(input.command ?? "");
2343
2343
  const timeout = Number(input.timeout_ms ?? 3e4);
2344
2344
  const start = Date.now();
2345
+ if (/&\s*$/.test(command) && !/[>|].*&\s*$/.test(command)) {
2346
+ const logFile = `/tmp/0agent-bg-${Date.now()}.log`;
2347
+ command = command.replace(/\s*&\s*$/, ` > ${logFile} 2>&1 &`);
2348
+ }
2345
2349
  return new Promise((resolve_) => {
2346
2350
  const chunks = [];
2347
2351
  let settled = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0agent",
3
- "version": "1.0.33",
3
+ "version": "1.0.35",
4
4
  "description": "A persistent, learning AI agent that runs on your machine. An agent that learns.",
5
5
  "private": false,
6
6
  "license": "Apache-2.0",