open-agents-ai 0.187.365 → 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 +210 -79
  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
  }
@@ -569010,12 +569147,12 @@ async function loadScheduled() {
569010
569147
  const rows = tasks.map(t => {
569011
569148
  const enabled = !!t.enabled;
569012
569149
  const btn = enabled
569013
- ? '<button onclick="toggleScheduled('' + t.id + '',false)" style="background:#2a2a30;border:1px solid #5a2a2a;color:#b25f5f;padding:2px 6px;border-radius:3px;font-size:0.65rem;cursor:pointer">disable</button>'
569014
- : '<button onclick="toggleScheduled('' + t.id + '',true)" style="background:#2a2a30;border:1px solid #2a3a2a;color:#4ec94e;padding:2px 6px;border-radius:3px;font-size:0.65rem;cursor:pointer">enable</button>';
569150
+ ? '<button onclick="toggleScheduled(\\'' + t.id + '\\',false)" style="background:#2a2a30;border:1px solid #5a2a2a;color:#b25f5f;padding:2px 6px;border-radius:3px;font-size:0.65rem;cursor:pointer">disable</button>'
569151
+ : '<button onclick="toggleScheduled(\\'' + t.id + '\\',true)" style="background:#2a2a30;border:1px solid #2a3a2a;color:#4ec94e;padding:2px 6px;border-radius:3px;font-size:0.65rem;cursor:pointer">enable</button>';
569015
569152
  const color = enabled ? '#4ec94e' : '#5a2a2a';
569016
569153
  const procInfo = t.procs && t.procs.length ? (' (' + t.procs.length + ' proc)') : '';
569017
569154
  const up = t.procs && t.procs[0] && t.procs[0].uptime_s ? (' • up ' + Math.max(1, Math.round(t.procs[0].uptime_s/60)) + 'm') : '';
569018
- const killBtn = '<button onclick="killScheduledTask('' + t.id + '')" style="background:#2a2a30;border:1px solid #5a2a2a;color:#b25f5f;padding:2px 6px;border-radius:3px;font-size:0.65rem;cursor:pointer">kill</button>';
569155
+ const killBtn = '<button onclick="killScheduledTask(\\'' + t.id + '\\')" style="background:#2a2a30;border:1px solid #5a2a2a;color:#b25f5f;padding:2px 6px;border-radius:3px;font-size:0.65rem;cursor:pointer">kill</button>';
569019
569156
  const row = '<div style="background:#1e1e22;border-left:2px solid ' + color + ';padding:6px 10px;margin:4px 0;font-size:0.72rem">'
569020
569157
  + '<div style="color:#b0b0b0">' + (t.name || '(task)') + ' <span style="color:#555">' + (t.schedule || '') + '</span>' + procInfo + up + '</div>'
569021
569158
  + '<div style="color:#555;font-size:0.6rem">' + t.file + '#' + t.index + '</div>'
@@ -569035,14 +569172,14 @@ async function loadScheduled() {
569035
569172
  } catch {}
569036
569173
  }
569037
569174
 
569038
- (window as any).toggleScheduled = async function(id: string, enabled: boolean) {
569175
+ window.toggleScheduled = async function(id, enabled) {
569039
569176
  try {
569040
569177
  await fetch('/v1/scheduled/' + encodeURIComponent(id), { method:'POST', headers: headers(), body: JSON.stringify({enabled}) });
569041
569178
  loadScheduled();
569042
569179
  } catch {}
569043
569180
  }
569044
569181
 
569045
- (window as any).killScheduled = async function() {
569182
+ window.killScheduled = async function() {
569046
569183
  try {
569047
569184
  const r = await fetch('/v1/scheduled/kill', { method:'POST', headers: headers(), body: JSON.stringify({}) });
569048
569185
  const j = await r.json();
@@ -569053,18 +569190,15 @@ async function loadScheduled() {
569053
569190
  const rem = Array.isArray(j.procs_after) ? j.procs_after.length : 0;
569054
569191
  let msg = 'Killed ' + (kb + ka) + ' processes.';
569055
569192
  if (before && after) {
569056
- msg += '
569057
- GPU util: ' + before.gpu_pct + '% → ' + after.gpu_pct + '%, VRAM: ' + before.vram_used_gb + '/' + before.vram_total_gb + ' GB → ' + after.vram_used_gb + '/' + after.vram_total_gb + ' GB';
569193
+ msg += '\\nGPU util: ' + before.gpu_pct + '% → ' + after.gpu_pct + '%, VRAM: ' + before.vram_used_gb + '/' + before.vram_total_gb + ' GB → ' + after.vram_used_gb + '/' + after.vram_total_gb + ' GB';
569058
569194
  }
569059
- msg += rem > 0 ? ('
569060
- Remaining matched processes: ' + rem) : '
569061
- No remaining matched processes.';
569195
+ msg += rem > 0 ? ('\\nRemaining matched processes: ' + rem) : '\\nNo remaining matched processes.';
569062
569196
  alert(msg);
569063
569197
  loadScheduled();
569064
569198
  } catch (e) { alert('Kill failed: ' + (e && e.message || String(e))); }
569065
569199
  }
569066
569200
 
569067
- (window as any).disableAllScheduled = async function() {
569201
+ window.disableAllScheduled = async function() {
569068
569202
  try {
569069
569203
  const r = await fetch('/v1/scheduled', { headers: headers() });
569070
569204
  const d = await r.json();
@@ -569081,7 +569215,7 @@ No remaining matched processes.';
569081
569215
  } catch {}
569082
569216
  }
569083
569217
 
569084
- (window as any).enableAllScheduled = async function() {
569218
+ window.enableAllScheduled = async function() {
569085
569219
  try {
569086
569220
  const r = await fetch('/v1/scheduled', { headers: headers() });
569087
569221
  const d = await r.json();
@@ -569098,7 +569232,7 @@ No remaining matched processes.';
569098
569232
  } catch {}
569099
569233
  }
569100
569234
 
569101
- (window as any).adoptScheduled = async function() {
569235
+ window.adoptScheduled = async function() {
569102
569236
  try {
569103
569237
  const r = await fetch('/v1/scheduled/reconcile', { method:'POST', headers: headers(), body: JSON.stringify({ apply: true }) });
569104
569238
  const j = await r.json();
@@ -569110,7 +569244,7 @@ No remaining matched processes.';
569110
569244
  } catch (e) { alert('Adopt failed: ' + (e && e.message || String(e))); }
569111
569245
  }
569112
569246
 
569113
- (window as any).fixupScheduled = async function() {
569247
+ window.fixupScheduled = async function() {
569114
569248
  try {
569115
569249
  if (!confirm('Rewrite OA cron entries to canonical launcher?')) return;
569116
569250
  const r = await fetch('/v1/scheduled/fixup', { method:'POST', headers: headers(), body: JSON.stringify({ mode: 'cron', dryRun: false }) });
@@ -569120,7 +569254,7 @@ No remaining matched processes.';
569120
569254
  } catch (e) { alert('Fixup failed: ' + (e && e.message || String(e))); }
569121
569255
  }
569122
569256
 
569123
- (window as any).migrateScheduled = async function() {
569257
+ window.migrateScheduled = async function() {
569124
569258
  try {
569125
569259
  if (!confirm('Migrate OA cron entries to systemd user timers?')) return;
569126
569260
  const r = await fetch('/v1/scheduled/fixup', { method:'POST', headers: headers(), body: JSON.stringify({ mode: 'migrate', dryRun: false }) });
@@ -569130,7 +569264,7 @@ No remaining matched processes.';
569130
569264
  } catch (e) { alert('Migrate failed: ' + (e && e.message || String(e))); }
569131
569265
  }
569132
569266
 
569133
- (window as any).killScheduledTask = async function(id) {
569267
+ window.killScheduledTask = async function(id) {
569134
569268
  try {
569135
569269
  // Fetch task to derive a pattern (directory of tasks.json)
569136
569270
  const r = await fetch('/v1/scheduled/status', { headers: headers() });
@@ -569141,20 +569275,20 @@ No remaining matched processes.';
569141
569275
  const dir = (t.file || '').split('/').slice(0, -1).join('/') || t.file;
569142
569276
  // Escape for regex without using a character class that includes brace/dollar combo (parser quirk)
569143
569277
  const safe = dir
569144
- .replace(/\\/g, "\\\\")
569145
- .replace(/[/g, "\\[")
569146
- .replace(/]/g, "\\]")
569147
- .replace(/{/g, "\\{")
569148
- .replace(/}/g, "\\}")
569149
- .replace(/(/g, "\\(")
569150
- .replace(/)/g, "\\)")
569151
- .replace(/*/g, "\\*")
569152
- .replace(/+/g, "\\+")
569153
- .replace(/?/g, "\\?")
569154
- .replace(/^/g, "\\^")
569155
- .replace(/$/g, "\\$")
569156
- .replace(/|/g, "\\|")
569157
- .replace(/./g, "\\.");
569278
+ .replace(/\\\\/g, "\\\\\\\\")
569279
+ .replace(/\\[/g, "\\\\[")
569280
+ .replace(/\\]/g, "\\\\]")
569281
+ .replace(/\\{/g, "\\\\{")
569282
+ .replace(/\\}/g, "\\\\}")
569283
+ .replace(/\\(/g, "\\\\(")
569284
+ .replace(/\\)/g, "\\\\)")
569285
+ .replace(/\\*/g, "\\\\*")
569286
+ .replace(/\\+/g, "\\\\+")
569287
+ .replace(/\\?/g, "\\\\?")
569288
+ .replace(/\\^/g, "\\\\^")
569289
+ .replace(/\\$/g, "\\\\$")
569290
+ .replace(/\\|/g, "\\\\|")
569291
+ .replace(/\\./g, "\\\\.");
569158
569292
  const body = { pattern: safe };
569159
569293
  const resp = await fetch('/v1/scheduled/kill', { method:'POST', headers: headers(), body: JSON.stringify(body) });
569160
569294
  const j = await resp.json();
@@ -569164,11 +569298,8 @@ No remaining matched processes.';
569164
569298
  const after = j.gpu_after && j.gpu_after[0] ? j.gpu_after[0] : null;
569165
569299
  const rem = Array.isArray(j.procs_after) ? j.procs_after.length : 0;
569166
569300
  let msg = 'Killed ' + (kb + ka) + ' processes for task.';
569167
- if (before && after) msg += '
569168
- GPU util: ' + before.gpu_pct + '% ' + after.gpu_pct + '%';
569169
- msg += rem > 0 ? ('
569170
- Remaining matched processes: ' + rem) : '
569171
- No remaining matched processes.';
569301
+ if (before && after) msg += '\\nGPU util: ' + before.gpu_pct + '% → ' + after.gpu_pct + '%';
569302
+ msg += rem > 0 ? ('\\nRemaining matched processes: ' + rem) : '\\nNo remaining matched processes.';
569172
569303
  alert(msg);
569173
569304
  loadScheduled();
569174
569305
  } catch (e) { alert('Kill failed: ' + (e && e.message || String(e))); }
@@ -569183,8 +569314,8 @@ async function loadServices() {
569183
569314
  const svcs = Array.isArray(d.services) ? d.services : [];
569184
569315
  if (!svcs.length) { el.innerHTML = ''; return; }
569185
569316
  const rows = svcs.map(s => {
569186
- const stopBtn = '<button onclick="svcAction('' + s.name + '','stop')" style="background:#2a2a30;border:1px solid #5a2a2a;color:#b25f5f;padding:2px 6px;border-radius:3px;font-size:0.65rem;cursor:pointer">stop</button>';
569187
- const disBtn = '<button onclick="svcAction('' + s.name + '','disable')" style="background:#2a2a30;border:1px solid #5a2a2a;color:#b25f5f;padding:2px 6px;border-radius:3px;font-size:0.65rem;cursor:pointer">disable</button>';
569317
+ const stopBtn = '<button onclick="svcAction(\\'' + s.name + '\\',\\'stop\\')" style="background:#2a2a30;border:1px solid #5a2a2a;color:#b25f5f;padding:2px 6px;border-radius:3px;font-size:0.65rem;cursor:pointer">stop</button>';
569318
+ const disBtn = '<button onclick="svcAction(\\'' + s.name + '\\',\\'disable\\')" style="background:#2a2a30;border:1px solid #5a2a2a;color:#b25f5f;padding:2px 6px;border-radius:3px;font-size:0.65rem;cursor:pointer">disable</button>';
569188
569319
  return '<div style="background:#1e1e22;border-left:2px solid #3a3a42;padding:6px 10px;margin:4px 0;font-size:0.72rem">'
569189
569320
  + '<div style="color:#b0b0b0">' + s.name + '</div>'
569190
569321
  + '<div style="color:#555;font-size:0.6rem">enabled: ' + s.enabled + ' • active: ' + s.active + '</div>'
@@ -569195,7 +569326,7 @@ async function loadServices() {
569195
569326
  } catch {}
569196
569327
  }
569197
569328
 
569198
- (window as any).svcAction = async function(name, action) {
569329
+ window.svcAction = async function(name, action) {
569199
569330
  try {
569200
569331
  await fetch('/v1/services/systemd/' + encodeURIComponent(name), { method:'POST', headers: headers(), body: JSON.stringify({ action }) });
569201
569332
  loadServices();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.365",
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",