0agent 1.0.36 → 1.0.38

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/bin/chat.js +57 -12
  2. package/package.json +1 -1
package/bin/chat.js CHANGED
@@ -39,6 +39,18 @@ class Spinner {
39
39
  if (clearIt) process.stdout.write('\r\x1b[2K');
40
40
  }
41
41
  get active() { return this._active; }
42
+
43
+ /**
44
+ * Pause spinner, run fn() (which may print lines), then resume.
45
+ * Prevents spinner from overwriting printed content.
46
+ */
47
+ pauseFor(fn) {
48
+ const wasActive = this._active;
49
+ const savedMsg = this._msg;
50
+ if (wasActive) this.stop(true);
51
+ fn();
52
+ if (wasActive) this.start(savedMsg);
53
+ }
42
54
  }
43
55
 
44
56
  // ─── ANSI helpers ─────────────────────────────────────────────────────────────
@@ -371,7 +383,9 @@ async function runTask(input) {
371
383
  });
372
384
  const s = await res.json();
373
385
  sessionId = s.session_id ?? s.id;
374
- spinner.start('Thinking'); // show immediately after session created
386
+ // Show affordance so user knows they can queue messages while agent works
387
+ process.stdout.write(`\n \x1b[2m(type and press Enter to queue next message)\x1b[0m\n`);
388
+ spinner.start('Thinking');
375
389
 
376
390
  // Polling fallback — runs concurrently with WS events.
377
391
  // Catches completion when WS is disconnected (e.g. daemon just restarted).
@@ -549,10 +563,7 @@ async function handleCommand(input) {
549
563
  const { execSync: exs } = await import('node:child_process');
550
564
  exs('npm install -g 0agent@latest --silent', { stdio: 'ignore', timeout: 120_000 });
551
565
  process.stdout.write(` ${fmt(C.green, '✓')} Updated to ${latest} — restarting...\n\n`);
552
- const { spawn: sp } = await import('node:child_process');
553
- const child = sp(process.argv[0], process.argv.slice(1), { stdio: 'inherit' });
554
- child.on('close', (code) => process.exit(code ?? 0));
555
- process.stdin.pause();
566
+ await restartWithLatest();
556
567
  } catch (e) {
557
568
  console.log(` ${fmt(C.red, '✗')} Update failed: ${e.message}\n`);
558
569
  }
@@ -873,11 +884,7 @@ async function _safeJsonFetch(url, opts) {
873
884
  exs('npm install -g 0agent@latest --silent', { stdio: 'ignore', timeout: 120_000 });
874
885
  process.stdout.write(` ${fmt(C.green, '✓')} Updated to ${latest} — restarting...\n\n`);
875
886
 
876
- // Restart cleanly
877
- const { spawn: sp } = await import('node:child_process');
878
- const child = sp(process.argv[0], process.argv.slice(1), { stdio: 'inherit' });
879
- child.on('close', (code) => process.exit(code ?? 0));
880
- process.stdin.pause();
887
+ await restartWithLatest();
881
888
  } catch {
882
889
  // Non-fatal — update failure never crashes the agent
883
890
  }
@@ -886,6 +893,35 @@ async function _safeJsonFetch(url, opts) {
886
893
  rl.prompt();
887
894
  })();
888
895
 
896
+ // Restart using the GLOBAL install, not the npx cache that's currently running.
897
+ // After `npm install -g 0agent@latest`, the new binary is in npm's global bin dir.
898
+ // Using process.argv would re-run the OLD npx-cached file → infinite loop.
899
+ async function restartWithLatest() {
900
+ try {
901
+ const { execSync: ex } = await import('node:child_process');
902
+ const { resolve: res } = await import('node:path');
903
+ const { existsSync: ef } = await import('node:fs');
904
+ const { spawn: sp } = await import('node:child_process');
905
+
906
+ // Find the global npm bin directory (e.g. ~/.nvm/.../bin or /usr/local/bin)
907
+ const globalBin = ex('npm bin -g 2>/dev/null || true', { encoding: 'utf8' }).trim().split('\n')[0];
908
+ const newBin = globalBin ? res(globalBin, '0agent') : null;
909
+
910
+ let child;
911
+ if (newBin && ef(newBin)) {
912
+ // Run the freshly installed global script
913
+ child = sp(process.execPath, [newBin], { stdio: 'inherit' });
914
+ } else {
915
+ // Fallback: let the shell find 0agent in PATH
916
+ child = sp('0agent', [], { stdio: 'inherit', shell: true });
917
+ }
918
+ child.on('close', (code) => process.exit(code ?? 0));
919
+ process.stdin.pause();
920
+ } catch {
921
+ process.exit(0); // just exit; user can re-open
922
+ }
923
+ }
924
+
889
925
  function isNewerVersion(a, b) {
890
926
  const pa = a.split('.').map(Number);
891
927
  const pb = b.split('.').map(Number);
@@ -926,11 +962,20 @@ rl.on('line', async (input) => {
926
962
  const line = input.trim();
927
963
  if (!line) { rl.prompt(); return; }
928
964
 
929
- // If a session is already running, queue the message
965
+ // If a session is already running, queue the message.
966
+ // pauseFor() stops the spinner briefly so the user can see the confirmation,
967
+ // then resumes — prevents spinner from overwriting their typed text.
930
968
  if (pendingResolve) {
931
969
  messageQueue.push(line);
932
970
  const qLen = messageQueue.length;
933
- process.stdout.write(`\n ${fmt(C.dim, `↳ queued [${qLen}]`)} ${fmt(C.dim, line.slice(0, 60))}\n`);
971
+ spinner.pauseFor(() => {
972
+ process.stdout.write(
973
+ ` ${fmt(C.magenta, '↳')} ${fmt(C.bold, `[queued #${qLen}]`)} ${fmt(C.dim, line.slice(0, 70))}\n`
974
+ );
975
+ if (qLen > 1) {
976
+ process.stdout.write(` ${fmt(C.dim, `${qLen} tasks waiting`)}\n`);
977
+ }
978
+ });
934
979
  return;
935
980
  }
936
981
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0agent",
3
- "version": "1.0.36",
3
+ "version": "1.0.38",
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",