open-agents-ai 0.187.366 → 0.187.367

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 +178 -41
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -539097,6 +539097,7 @@ var init_neovim_mode = __esm({
539097
539097
  var daemon_exports = {};
539098
539098
  __export(daemon_exports, {
539099
539099
  ensureDaemon: () => ensureDaemon,
539100
+ forceKillDaemon: () => forceKillDaemon,
539100
539101
  getDaemonPid: () => getDaemonPid,
539101
539102
  getDaemonStatus: () => getDaemonStatus,
539102
539103
  isDaemonRunning: () => isDaemonRunning,
@@ -539200,6 +539201,67 @@ function stopDaemon() {
539200
539201
  return false;
539201
539202
  }
539202
539203
  }
539204
+ async function forceKillDaemon(port) {
539205
+ const p2 = port ?? getDaemonPort();
539206
+ let killed = 0;
539207
+ const pid = getDaemonPid();
539208
+ if (pid) {
539209
+ try {
539210
+ process.kill(pid, "SIGTERM");
539211
+ killed++;
539212
+ } catch {
539213
+ }
539214
+ for (let i2 = 0; i2 < 20; i2++) {
539215
+ await new Promise((r2) => setTimeout(r2, 100));
539216
+ try {
539217
+ process.kill(pid, 0);
539218
+ } catch {
539219
+ break;
539220
+ }
539221
+ }
539222
+ try {
539223
+ process.kill(pid, 0);
539224
+ process.kill(pid, "SIGKILL");
539225
+ killed++;
539226
+ } catch {
539227
+ }
539228
+ try {
539229
+ unlinkSync16(PID_FILE2);
539230
+ } catch {
539231
+ }
539232
+ }
539233
+ try {
539234
+ const { execSync: execSync57 } = await import("node:child_process");
539235
+ const out = execSync57(
539236
+ `lsof -ti :${p2} 2>/dev/null || fuser ${p2}/tcp 2>/dev/null || true`,
539237
+ { encoding: "utf8", timeout: 3e3 }
539238
+ ).trim();
539239
+ const pids = out.split(/[\s\n]+/).map((s2) => parseInt(s2, 10)).filter((n2) => Number.isFinite(n2) && n2 > 0 && n2 !== process.pid);
539240
+ for (const otherPid of pids) {
539241
+ try {
539242
+ process.kill(otherPid, "SIGTERM");
539243
+ killed++;
539244
+ } catch {
539245
+ }
539246
+ }
539247
+ if (pids.length > 0) {
539248
+ await new Promise((r2) => setTimeout(r2, 1e3));
539249
+ for (const otherPid of pids) {
539250
+ try {
539251
+ process.kill(otherPid, 0);
539252
+ process.kill(otherPid, "SIGKILL");
539253
+ } catch {
539254
+ }
539255
+ }
539256
+ }
539257
+ } catch {
539258
+ }
539259
+ for (let i2 = 0; i2 < 50; i2++) {
539260
+ if (!await isDaemonRunning(p2)) return killed;
539261
+ await new Promise((r2) => setTimeout(r2, 100));
539262
+ }
539263
+ return killed;
539264
+ }
539203
539265
  async function ensureDaemon() {
539204
539266
  const port = getDaemonPort();
539205
539267
  if (await isDaemonRunning(port)) {
@@ -544447,12 +544509,12 @@ async function handleSlashCommand(input, ctx3) {
544447
544509
  renderInfo2(`Generated API key: ${c3.bold(c3.yellow(apiKey))}`);
544448
544510
  renderInfo2("Use the Web UI ‘key’ button to paste this token, or set Authorization: Bearer <key> in your client.");
544449
544511
  try {
544450
- const { homedir: homedir41 } = await import("node:os");
544451
- const { mkdirSync: mkdirSync58, writeFileSync: writeFileSync51 } = await import("node:fs");
544452
- const { join: join110 } = await import("node:path");
544453
- const dir = join110(homedir41(), ".open-agents");
544454
- mkdirSync58(dir, { recursive: true });
544455
- writeFileSync51(join110(dir, "api.key"), apiKey + "\n", "utf8");
544512
+ const { homedir: homedir42 } = await import("node:os");
544513
+ const { mkdirSync: mkdirSync59, writeFileSync: writeFileSync52 } = await import("node:fs");
544514
+ const { join: join111 } = await import("node:path");
544515
+ const dir = join111(homedir42(), ".open-agents");
544516
+ mkdirSync59(dir, { recursive: true });
544517
+ writeFileSync52(join111(dir, "api.key"), apiKey + "\n", "utf8");
544456
544518
  } catch {
544457
544519
  }
544458
544520
  }
@@ -544462,29 +544524,66 @@ async function handleSlashCommand(input, ctx3) {
544462
544524
  ctx4.saveSettings({ oaAccess: val2 });
544463
544525
  }
544464
544526
  const port2 = parseInt(process.env["OA_PORT"] || "11435", 10);
544465
- let switched2 = false;
544466
544527
  try {
544467
- const resp = await fetch(`http://127.0.0.1:${port2}/v1/admin/access`, {
544528
+ const { homedir: homedir42 } = await import("node:os");
544529
+ const { mkdirSync: mkdirSync59, writeFileSync: writeFileSync52 } = await import("node:fs");
544530
+ const { join: join111 } = await import("node:path");
544531
+ const dir = join111(homedir42(), ".open-agents");
544532
+ mkdirSync59(dir, { recursive: true });
544533
+ writeFileSync52(join111(dir, "access"), `${val2}
544534
+ `, "utf8");
544535
+ } catch {
544536
+ }
544537
+ const baseUrl2 = `http://127.0.0.1:${port2}`;
544538
+ const authHeaders2 = () => {
544539
+ const token = process.env["OA_API_KEY"] || "";
544540
+ return token ? { Authorization: `Bearer ${token}` } : {};
544541
+ };
544542
+ let liveOk2 = false;
544543
+ try {
544544
+ const resp = await fetch(`${baseUrl2}/v1/admin/access`, {
544468
544545
  method: "POST",
544469
- headers: { "Content-Type": "application/json" },
544546
+ headers: { "Content-Type": "application/json", ...authHeaders2() },
544470
544547
  body: JSON.stringify({ mode: val2 }),
544471
544548
  signal: AbortSignal.timeout(3e3)
544472
544549
  });
544473
- switched2 = resp.ok;
544550
+ liveOk2 = resp.ok;
544474
544551
  } catch {
544475
544552
  }
544476
- if (switched2) {
544553
+ const readCurrent2 = async () => {
544554
+ try {
544555
+ const r2 = await fetch(`${baseUrl2}/v1/admin/access`, { headers: authHeaders2(), signal: AbortSignal.timeout(2e3) });
544556
+ if (!r2.ok) return null;
544557
+ const j = await r2.json();
544558
+ return typeof j.mode === "string" ? j.mode : null;
544559
+ } catch {
544560
+ return null;
544561
+ }
544562
+ };
544563
+ const current2 = await readCurrent2();
544564
+ if (liveOk2 && current2 === val2) {
544477
544565
  renderInfo2(`Access policy now '${val2}' (live, no restart). Persisted to ~/.open-agents/access.`);
544566
+ return "handled";
544567
+ }
544568
+ renderInfo2(`Live switch did not take effect (daemon reports ${current2 ?? "unreachable"}). Force-restarting...`);
544569
+ const { forceKillDaemon: forceKillDaemon3, ensureDaemon: ensureDaemon3 } = await Promise.resolve().then(() => (init_daemon(), daemon_exports));
544570
+ const killed2 = await forceKillDaemon3(port2);
544571
+ if (killed2 > 0) renderInfo2(`Force-killed ${killed2} process(es) bound to port ${port2}.`);
544572
+ const ok3 = await ensureDaemon3();
544573
+ if (!ok3) {
544574
+ renderError2("Failed to start a fresh daemon after force-kill.");
544575
+ return "handled";
544576
+ }
544577
+ let finalMode2 = null;
544578
+ for (let i2 = 0; i2 < 10; i2++) {
544579
+ finalMode2 = await readCurrent2();
544580
+ if (finalMode2) break;
544581
+ await new Promise((r2) => setTimeout(r2, 250));
544582
+ }
544583
+ if (finalMode2 === val2) {
544584
+ renderInfo2(`Access policy now '${val2}' (daemon restarted, verified).`);
544478
544585
  } else {
544479
- const { stopDaemon: stopDaemon2, ensureDaemon: ensureDaemon2, isDaemonRunning: isDaemonRunning2 } = await Promise.resolve().then(() => (init_daemon(), daemon_exports));
544480
- stopDaemon2();
544481
- const deadline = Date.now() + 4e3;
544482
- while (Date.now() < deadline) {
544483
- if (!await isDaemonRunning2(port2)) break;
544484
- await new Promise((r2) => setTimeout(r2, 200));
544485
- }
544486
- const ok2 = await ensureDaemon2();
544487
- renderInfo2(ok2 ? "Daemon restarted to apply access policy." : "Failed to restart daemon.");
544586
+ renderWarning2(`Daemon restarted but reports mode='${finalMode2 ?? "unreachable"}'. Expected '${val2}'.`);
544488
544587
  }
544489
544588
  return "handled";
544490
544589
  }
@@ -544512,12 +544611,12 @@ async function handleSlashCommand(input, ctx3) {
544512
544611
  renderInfo2(`Generated API key: ${c3.bold(c3.yellow(apiKey))}`);
544513
544612
  renderInfo2("Use the Web UI ‘key’ button to paste this token, or set Authorization: Bearer <key> in your client.");
544514
544613
  try {
544515
- const { homedir: homedir41 } = await import("node:os");
544516
- const { mkdirSync: mkdirSync58, writeFileSync: writeFileSync51 } = await import("node:fs");
544517
- const { join: join110 } = await import("node:path");
544518
- const dir = join110(homedir41(), ".open-agents");
544519
- mkdirSync58(dir, { recursive: true });
544520
- writeFileSync51(join110(dir, "api.key"), apiKey + "\n", "utf8");
544614
+ const { homedir: homedir42 } = await import("node:os");
544615
+ const { mkdirSync: mkdirSync59, writeFileSync: writeFileSync52 } = await import("node:fs");
544616
+ const { join: join111 } = await import("node:path");
544617
+ const dir = join111(homedir42(), ".open-agents");
544618
+ mkdirSync59(dir, { recursive: true });
544619
+ writeFileSync52(join111(dir, "api.key"), apiKey + "\n", "utf8");
544521
544620
  } catch {
544522
544621
  }
544523
544622
  }
@@ -544527,34 +544626,72 @@ async function handleSlashCommand(input, ctx3) {
544527
544626
  ctx3.saveSettings({ oaAccess: val });
544528
544627
  }
544529
544628
  const port = parseInt(process.env["OA_PORT"] || "11435", 10);
544530
- let switched = false;
544629
+ const { homedir: homedir41 } = await import("node:os");
544630
+ const { mkdirSync: mkdirSync58, writeFileSync: writeFileSync51 } = await import("node:fs");
544631
+ const { join: join110 } = await import("node:path");
544531
544632
  try {
544532
- const resp = await fetch(`http://127.0.0.1:${port}/v1/admin/access`, {
544633
+ const dir = join110(homedir41(), ".open-agents");
544634
+ mkdirSync58(dir, { recursive: true });
544635
+ writeFileSync51(join110(dir, "access"), `${val}
544636
+ `, "utf8");
544637
+ } catch (e2) {
544638
+ renderWarning2(`Could not persist ~/.open-agents/access: ${e2 instanceof Error ? e2.message : String(e2)}`);
544639
+ }
544640
+ const baseUrl = `http://127.0.0.1:${port}`;
544641
+ const authHeaders = () => {
544642
+ const token = process.env["OA_API_KEY"] || "";
544643
+ return token ? { Authorization: `Bearer ${token}` } : {};
544644
+ };
544645
+ let liveOk = false;
544646
+ try {
544647
+ const resp = await fetch(`${baseUrl}/v1/admin/access`, {
544533
544648
  method: "POST",
544534
- headers: { "Content-Type": "application/json" },
544649
+ headers: { "Content-Type": "application/json", ...authHeaders() },
544535
544650
  body: JSON.stringify({ mode: val }),
544536
544651
  signal: AbortSignal.timeout(3e3)
544537
544652
  });
544538
- switched = resp.ok;
544653
+ liveOk = resp.ok;
544539
544654
  if (!resp.ok) {
544540
544655
  const txt = await resp.text().catch(() => "");
544541
544656
  renderWarning2(`Live access switch HTTP ${resp.status}: ${txt.slice(0, 120)}`);
544542
544657
  }
544543
544658
  } catch (e2) {
544544
- renderWarning2(`Live access switch failed (${e2 instanceof Error ? e2.message : String(e2)}); falling back to daemon restart.`);
544659
+ renderWarning2(`Live access switch fetch failed: ${e2 instanceof Error ? e2.message : String(e2)}`);
544545
544660
  }
544546
- if (switched) {
544661
+ const readCurrent = async () => {
544662
+ try {
544663
+ const r2 = await fetch(`${baseUrl}/v1/admin/access`, { headers: authHeaders(), signal: AbortSignal.timeout(2e3) });
544664
+ if (!r2.ok) return null;
544665
+ const j = await r2.json();
544666
+ return typeof j.mode === "string" ? j.mode : null;
544667
+ } catch {
544668
+ return null;
544669
+ }
544670
+ };
544671
+ let current = await readCurrent();
544672
+ if (liveOk && current === val) {
544547
544673
  renderInfo2(`Access policy now '${val}' (live, no restart). Persisted to ~/.open-agents/access.`);
544674
+ return "handled";
544675
+ }
544676
+ renderInfo2(`Live switch did not take effect (daemon reports ${current ?? "unreachable"}). Force-restarting daemon...`);
544677
+ const { forceKillDaemon: forceKillDaemon2, ensureDaemon: ensureDaemon2 } = await Promise.resolve().then(() => (init_daemon(), daemon_exports));
544678
+ const killed = await forceKillDaemon2(port);
544679
+ if (killed > 0) renderInfo2(`Force-killed ${killed} process(es) bound to port ${port}.`);
544680
+ const ok2 = await ensureDaemon2();
544681
+ if (!ok2) {
544682
+ renderError2("Failed to start a fresh daemon after force-kill. Try: `oa serve --quiet --daemon &` manually.");
544683
+ return "handled";
544684
+ }
544685
+ let finalMode = null;
544686
+ for (let i2 = 0; i2 < 10; i2++) {
544687
+ finalMode = await readCurrent();
544688
+ if (finalMode) break;
544689
+ await new Promise((r2) => setTimeout(r2, 250));
544690
+ }
544691
+ if (finalMode === val) {
544692
+ renderInfo2(`Access policy now '${val}' (daemon restarted, verified via /v1/admin/access).`);
544548
544693
  } else {
544549
- const { stopDaemon: stopDaemon2, ensureDaemon: ensureDaemon2, isDaemonRunning: isDaemonRunning2 } = await Promise.resolve().then(() => (init_daemon(), daemon_exports));
544550
- stopDaemon2();
544551
- const deadline = Date.now() + 4e3;
544552
- while (Date.now() < deadline) {
544553
- if (!await isDaemonRunning2(port)) break;
544554
- await new Promise((r2) => setTimeout(r2, 200));
544555
- }
544556
- const ok2 = await ensureDaemon2();
544557
- renderInfo2(ok2 ? "Daemon restarted to apply access policy." : "Failed to restart daemon.");
544694
+ renderWarning2(`Daemon restarted but reports mode='${finalMode ?? "unreachable"}'. Expected '${val}'. Check ~/.open-agents/access.`);
544558
544695
  }
544559
544696
  return "handled";
544560
544697
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.366",
3
+ "version": "0.187.367",
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",