0agent 1.0.31 → 1.0.33

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
@@ -758,9 +758,76 @@ async function _safeJsonFetch(url, opts) {
758
758
  console.log(` ${fmt(C.yellow, '⚠')} LLM check failed: ${e.message}\n`);
759
759
  }
760
760
 
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;
767
+
768
+ if (currentVersion) {
769
+ const reg = await fetch('https://registry.npmjs.org/0agent/latest', {
770
+ signal: AbortSignal.timeout(4000),
771
+ }).then(r => r.json()).catch(() => null);
772
+
773
+ 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
+ };
803
+
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
812
+ }
813
+ }
814
+ } catch {
815
+ // Version check is non-fatal — never block startup
816
+ }
817
+
761
818
  rl.prompt();
762
819
  })();
763
820
 
821
+ function isNewerVersion(a, b) {
822
+ const pa = a.split('.').map(Number);
823
+ const pb = b.split('.').map(Number);
824
+ for (let i = 0; i < 3; i++) {
825
+ if ((pa[i] ?? 0) > (pb[i] ?? 0)) return true;
826
+ if ((pa[i] ?? 0) < (pb[i] ?? 0)) return false;
827
+ }
828
+ return false;
829
+ }
830
+
764
831
 
765
832
  rl.on('line', async (input) => {
766
833
  const line = input.trim();
package/dist/daemon.mjs CHANGED
@@ -2328,7 +2328,7 @@ var init_ShellCapability = __esm({
2328
2328
  description = "Execute shell commands in the working directory.";
2329
2329
  toolDefinition = {
2330
2330
  name: "shell_exec",
2331
- description: "Execute a shell command. Use & for background processes. Returns stdout+stderr.",
2331
+ description: "Execute a shell command. For background servers use: cmd > /tmp/0agent-server.log 2>&1 & Returns stdout+stderr.",
2332
2332
  input_schema: {
2333
2333
  type: "object",
2334
2334
  properties: {
@@ -2344,25 +2344,49 @@ var init_ShellCapability = __esm({
2344
2344
  const start = Date.now();
2345
2345
  return new Promise((resolve_) => {
2346
2346
  const chunks = [];
2347
- const proc = spawn("bash", ["-c", command], {
2348
- cwd,
2349
- env: { ...process.env, TERM: "dumb" },
2350
- timeout
2351
- });
2352
- proc.stdout.on("data", (d) => chunks.push(d.toString()));
2353
- proc.stderr.on("data", (d) => chunks.push(d.toString()));
2354
- proc.on("close", (code) => {
2347
+ let settled = false;
2348
+ const done = (code, signal) => {
2349
+ if (settled) return;
2350
+ settled = true;
2351
+ clearTimeout(timer);
2355
2352
  const output = chunks.join("").trim();
2353
+ const success = code === 0 || code === null && !!signal;
2356
2354
  resolve_({
2357
- success: code === 0,
2358
- output: output || (code === 0 ? "(no output)" : `exit ${code}`),
2355
+ success,
2356
+ output: output || (success ? "(no output)" : `exit ${code ?? signal}`),
2359
2357
  duration_ms: Date.now() - start,
2360
- ...code !== 0 && { error: `exit code ${code}` }
2358
+ ...!success && { error: `exit ${code ?? signal}` }
2361
2359
  });
2360
+ };
2361
+ const proc = spawn("bash", ["-c", command], {
2362
+ cwd,
2363
+ env: { ...process.env, TERM: "dumb" }
2364
+ // DO NOT set `timeout` here — we manage it manually via timer
2365
+ // so we can resolve on `exit` rather than waiting for `close`
2362
2366
  });
2367
+ proc.stdout.on("data", (d) => chunks.push(d.toString()));
2368
+ proc.stderr.on("data", (d) => chunks.push(d.toString()));
2369
+ proc.on("exit", (code) => done(code));
2363
2370
  proc.on("error", (err) => {
2371
+ settled = true;
2372
+ clearTimeout(timer);
2364
2373
  resolve_({ success: false, output: err.message, error: err.message, duration_ms: Date.now() - start });
2365
2374
  });
2375
+ const timer = setTimeout(() => {
2376
+ if (settled) return;
2377
+ try {
2378
+ proc.kill("SIGKILL");
2379
+ } catch {
2380
+ }
2381
+ settled = true;
2382
+ const output = chunks.join("").trim();
2383
+ resolve_({
2384
+ success: false,
2385
+ output: output || "(timed out)",
2386
+ error: `timed out after ${timeout}ms`,
2387
+ duration_ms: Date.now() - start
2388
+ });
2389
+ }, timeout);
2366
2390
  });
2367
2391
  }
2368
2392
  };
@@ -2858,7 +2882,11 @@ content = element.text if element else page.get_all_text()` : `content = page.ge
2858
2882
  ``,
2859
2883
  `Instructions:`,
2860
2884
  `- Use tools to actually accomplish tasks, don't just describe what to do`,
2861
- `- For web servers: write the files, then start the server with & (background)`,
2885
+ `- For web servers/background processes: ALWAYS redirect output to avoid hanging:`,
2886
+ ` cmd > /tmp/0agent-server.log 2>&1 &`,
2887
+ ` Example: python3 -m http.server 3000 > /tmp/0agent-server.log 2>&1 &`,
2888
+ ` Example: node server.js > /tmp/0agent-server.log 2>&1 &`,
2889
+ ` NEVER run background commands without redirecting output.`,
2862
2890
  `- For npm/node projects: check package.json first with read_file or list_dir`,
2863
2891
  `- After write_file, verify with read_file if needed`,
2864
2892
  `- After shell_exec, check output for errors and retry if needed`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0agent",
3
- "version": "1.0.31",
3
+ "version": "1.0.33",
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",