open-agents-ai 0.93.0 → 0.94.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/dist/index.js +78 -15
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -320,23 +320,39 @@ async function checkForUpdate(currentVersion, forceCheck = false) {
320
320
  latestVersion: latest
321
321
  };
322
322
  }
323
+ function cleanStaleNpmTempDirs(sudo) {
324
+ try {
325
+ const prefix = execSync("npm prefix -g", { encoding: "utf-8", stdio: "pipe", timeout: 5e3 }).trim();
326
+ const globalModules = prefix.endsWith("/lib") ? prefix + "/node_modules" : prefix + "/lib/node_modules";
327
+ const sudoCmd = sudo ? "sudo " : "";
328
+ execSync(`${sudoCmd}find "${globalModules}" -maxdepth 1 -name ".${PACKAGE_NAME}-*" -type d -exec rm -rf {} + 2>/dev/null || true`, { stdio: "pipe", timeout: 15e3 });
329
+ execSync(`${sudoCmd}rm -rf "${globalModules}/${PACKAGE_NAME}" 2>/dev/null || true`, { stdio: "pipe", timeout: 15e3 });
330
+ } catch {
331
+ }
332
+ }
323
333
  function performSilentUpdate() {
324
334
  const installCmd = `npm install -g ${PACKAGE_NAME}@latest --prefer-online`;
325
- try {
326
- execSync(installCmd, { stdio: "pipe", timeout: 12e4 });
327
- return true;
328
- } catch (err) {
329
- const msg = err instanceof Error ? err.message : String(err);
330
- if (/EACCES|permission denied/i.test(msg)) {
331
- try {
332
- execSync(`sudo -n ${installCmd}`, { stdio: "pipe", timeout: 12e4 });
333
- return true;
334
- } catch {
335
- return false;
335
+ const trySilent = (cmd, sudo) => {
336
+ try {
337
+ execSync(cmd, { stdio: "pipe", timeout: 12e4 });
338
+ return true;
339
+ } catch (err) {
340
+ const msg = err instanceof Error ? err.message : String(err);
341
+ if (/ENOTEMPTY|errno -39/i.test(msg)) {
342
+ cleanStaleNpmTempDirs(sudo);
343
+ try {
344
+ execSync(cmd, { stdio: "pipe", timeout: 12e4 });
345
+ return true;
346
+ } catch {
347
+ return false;
348
+ }
336
349
  }
350
+ return false;
337
351
  }
338
- return false;
339
- }
352
+ };
353
+ if (trySilent(installCmd, false))
354
+ return true;
355
+ return trySilent(`sudo -n ${installCmd}`, true);
340
356
  }
341
357
  function formatUpdateBanner(info) {
342
358
  return `
@@ -30370,14 +30386,33 @@ async function handleUpdate(subcommand, ctx) {
30370
30386
  const installCmd = `${sudoPrefix}npm install -g open-agents-ai@latest --prefer-online`;
30371
30387
  let installOk = false;
30372
30388
  let installError = "";
30373
- installOk = await new Promise((resolve31) => {
30374
- const child = exec(installCmd, { timeout: 18e4 }, (err, _stdout, stderr) => {
30389
+ const runInstall2 = (cmd) => new Promise((resolve31) => {
30390
+ const child = exec(cmd, { timeout: 18e4 }, (err, _stdout, stderr) => {
30375
30391
  if (err)
30376
30392
  installError = (stderr || err.message || "").trim();
30377
30393
  resolve31(!err);
30378
30394
  });
30379
30395
  child.stdout?.resume();
30380
30396
  });
30397
+ installOk = await runInstall2(installCmd);
30398
+ if (!installOk && /ENOTEMPTY|errno -39/i.test(installError)) {
30399
+ installSpinner.stop("Cleaning stale npm temp files...");
30400
+ try {
30401
+ const prefix = es2("npm prefix -g", { encoding: "utf8", timeout: 5e3 }).trim();
30402
+ const globalModules = prefix.endsWith("/lib") ? prefix + "/node_modules" : prefix + "/lib/node_modules";
30403
+ es2(`${sudoPrefix}find "${globalModules}" -maxdepth 1 -name ".open-agents-ai-*" -type d -exec rm -rf {} + 2>/dev/null || true`, { timeout: 15e3 });
30404
+ es2(`${sudoPrefix}rm -rf "${globalModules}/open-agents-ai" 2>/dev/null || true`, { timeout: 15e3 });
30405
+ } catch {
30406
+ }
30407
+ const retrySpinner = startInlineSpinner("Retrying install");
30408
+ installError = "";
30409
+ installOk = await runInstall2(installCmd);
30410
+ if (!installOk) {
30411
+ retrySpinner.stop("Retry failed.");
30412
+ } else {
30413
+ retrySpinner.stop(`Update installed (v${info.latestVersion}).`);
30414
+ }
30415
+ }
30381
30416
  if (!installOk) {
30382
30417
  installSpinner.stop("Update install failed.");
30383
30418
  const errPreview = installError.split("\n").filter((l) => l.trim()).slice(-3).join("\n ");
@@ -38948,6 +38983,8 @@ var init_status_bar = __esm({
38948
38983
  _currentFooterHeight = 5;
38949
38984
  /** Timestamp when streaming started (for token rate calculation) */
38950
38985
  _streamStartTime = 0;
38986
+ /** Current package version (shown in metrics row, rightmost) */
38987
+ _version = "";
38951
38988
  /**
38952
38989
  * Provide a callback that returns readline's current input state.
38953
38990
  * StatusBar uses this to render typed text and position the cursor
@@ -39049,6 +39086,12 @@ var init_status_bar = __esm({
39049
39086
  setContextWindowSize(size) {
39050
39087
  this.metrics.contextWindowSize = size;
39051
39088
  }
39089
+ /** Set the current package version for display in the metrics row */
39090
+ setVersion(version) {
39091
+ this._version = version;
39092
+ if (this.active)
39093
+ this.renderFooterPreserveCursor();
39094
+ }
39052
39095
  /** Human expert speed ratio tracker */
39053
39096
  _speedTracker = new HumanSpeedTracker();
39054
39097
  /** Record a tool call for speed ratio tracking */
@@ -39495,6 +39538,12 @@ var init_status_bar = __esm({
39495
39538
  const recW = 1 + 4 + (this._countdown > 0 ? 1 + `${this._countdown}s`.length : 0);
39496
39539
  sections.push({ expanded: recStr, compact: recStr, expandedW: recW, compactW: recW, empty: false });
39497
39540
  }
39541
+ if (this._version) {
39542
+ const vExpanded = pastel2(245, "v" + this._version);
39543
+ const vCompact = pastel2(245, "v" + this._version);
39544
+ const vW = 1 + this._version.length;
39545
+ sections.push({ expanded: vExpanded, compact: vCompact, expandedW: vW, compactW: vW, empty: false });
39546
+ }
39498
39547
  const activeIndices = sections.map((s, i) => !s.empty ? i : -1).filter((i) => i >= 0);
39499
39548
  const isCompact = new Array(sections.length).fill(false);
39500
39549
  const calcTotalWidth = () => {
@@ -40613,6 +40662,7 @@ async function startInteractive(config, repoPath) {
40613
40662
  });
40614
40663
  }
40615
40664
  const statusBar = new StatusBar();
40665
+ statusBar.setVersion(version);
40616
40666
  if (process.stdout.isTTY) {
40617
40667
  const scrollTop = carouselLines > 0 ? carouselLines + 1 : 1;
40618
40668
  statusBar.activate(scrollTop);
@@ -40703,6 +40753,19 @@ async function startInteractive(config, repoPath) {
40703
40753
  }).catch(() => {
40704
40754
  });
40705
40755
  }
40756
+ const AUTO_UPDATE_INTERVAL_MS = 30 * 60 * 1e3;
40757
+ const autoUpdateTimer = setInterval(() => {
40758
+ const updateMode = savedSettings.updateMode ?? "auto";
40759
+ if (updateMode === "manual")
40760
+ return;
40761
+ checkForUpdate(version).then((updateInfo) => {
40762
+ if (updateInfo) {
40763
+ performSilentUpdate();
40764
+ }
40765
+ }).catch(() => {
40766
+ });
40767
+ }, AUTO_UPDATE_INTERVAL_MS);
40768
+ autoUpdateTimer.unref();
40706
40769
  const voiceEngine = new VoiceEngine();
40707
40770
  let voiceSession = null;
40708
40771
  let exposeGateway = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.93.0",
3
+ "version": "0.94.0",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",