open-agents-ai 0.187.367 → 0.187.369

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 +154 -102
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -544273,77 +544273,84 @@ async function handleSlashCommand(input, ctx3) {
544273
544273
  await showColorMenu(ctx3);
544274
544274
  return "handled";
544275
544275
  }
544276
- case "apikey": {
544277
- registerSlashCommand({
544278
- name: "apikey",
544279
- description: "Show/copy/rotate API key (show|copy|new)",
544280
- handler: async ({ arg: arg2 }) => {
544281
- const action = (arg2 || "show").trim().toLowerCase();
544282
- let key = process.env["OA_API_KEY"] || "";
544283
- if (!key) {
544284
- try {
544285
- const { homedir: homedir41 } = await import("node:os");
544286
- const { readFileSync: readFileSync72, existsSync: existsSync91 } = await import("node:fs");
544287
- const { join: join110 } = await import("node:path");
544288
- const p2 = join110(homedir41(), ".open-agents", "api.key");
544289
- if (existsSync91(p2)) key = readFileSync72(p2, "utf8").trim();
544290
- } catch {
544291
- }
544276
+ case "apikey":
544277
+ case "key": {
544278
+ const apiKeyHandler = async ({ arg: a2 }) => {
544279
+ const action = (a2 || "show").trim().toLowerCase();
544280
+ let key = process.env["OA_API_KEY"] || "";
544281
+ if (!key) {
544282
+ try {
544283
+ const { homedir: homedir41 } = await import("node:os");
544284
+ const { readFileSync: readFileSync72, existsSync: existsSync91 } = await import("node:fs");
544285
+ const { join: join110 } = await import("node:path");
544286
+ const p2 = join110(homedir41(), ".open-agents", "api.key");
544287
+ if (existsSync91(p2)) key = readFileSync72(p2, "utf8").trim();
544288
+ } catch {
544292
544289
  }
544293
- if (action === "show") {
544294
- if (!key) {
544295
- renderWarning2("No API key set. Use /access any to generate one.");
544296
- return "handled";
544297
- }
544298
- renderInfo2(`API key: ${c3.bold(c3.yellow(key))}`);
544299
- renderInfo2("Use Authorization: Bearer <key> or paste in the Web UI key modal.");
544290
+ }
544291
+ if (action === "show") {
544292
+ if (!key) {
544293
+ renderWarning2("No API key set. Use /access any to generate one.");
544300
544294
  return "handled";
544301
544295
  }
544302
- if (action === "copy") {
544303
- if (!key) {
544304
- renderWarning2("No API key set. Use /access any to generate one.");
544305
- return "handled";
544306
- }
544307
- try {
544308
- const { spawnSync: spawnSync6 } = await import("node:child_process");
544309
- const tryCmd = (cmd2, args) => spawnSync6(cmd2, args, { input: key, encoding: "utf8" });
544310
- let ok2 = false;
544311
- if (process.platform === "darwin") {
544312
- ok2 = tryCmd("pbcopy", []).status === 0;
544313
- } else if (process.platform === "win32") {
544314
- ok2 = tryCmd("clip", []).status === 0;
544315
- } else {
544316
- ok2 = tryCmd("wl-copy", []).status === 0 || tryCmd("xclip", ["-selection", "clipboard"]).status === 0;
544317
- }
544318
- renderInfo2(ok2 ? "Copied API key to clipboard." : "Copy failed — printed above, select to copy.");
544319
- } catch {
544320
- renderInfo2("Copy failed — printed above, select to copy.");
544321
- }
544296
+ renderInfo2(`API key: ${c3.bold(c3.yellow(key))}`);
544297
+ renderInfo2("Use Authorization: Bearer <key> or paste in the Web UI key modal.");
544298
+ return "handled";
544299
+ }
544300
+ if (action === "copy") {
544301
+ if (!key) {
544302
+ renderWarning2("No API key set. Use /access any to generate one.");
544322
544303
  return "handled";
544323
544304
  }
544324
- if (action === "new") {
544325
- try {
544326
- const { randomBytes: randomBytes23 } = await import("node:crypto");
544327
- const { homedir: homedir41 } = await import("node:os");
544328
- const { mkdirSync: mkdirSync58, writeFileSync: writeFileSync51 } = await import("node:fs");
544329
- const { join: join110 } = await import("node:path");
544330
- const newKey = randomBytes23(16).toString("hex");
544331
- process.env["OA_API_KEY"] = newKey;
544332
- const dir = join110(homedir41(), ".open-agents");
544333
- mkdirSync58(dir, { recursive: true });
544334
- writeFileSync51(join110(dir, "api.key"), newKey + "\n", "utf8");
544335
- renderInfo2(`New API key: ${c3.bold(c3.yellow(newKey))}`);
544336
- renderInfo2("Restart the daemon to apply if needed. Use /access any to restart quickly.");
544337
- } catch (e2) {
544338
- renderError2(`Failed to rotate key: ${e2 instanceof Error ? e2.message : String(e2)}`);
544305
+ try {
544306
+ const { spawnSync: spawnSync6 } = await import("node:child_process");
544307
+ const tryCmd = (cmd2, args) => spawnSync6(cmd2, args, { input: key, encoding: "utf8" });
544308
+ let ok2 = false;
544309
+ if (process.platform === "darwin") {
544310
+ ok2 = tryCmd("pbcopy", []).status === 0;
544311
+ } else if (process.platform === "win32") {
544312
+ ok2 = tryCmd("clip", []).status === 0;
544313
+ } else {
544314
+ ok2 = tryCmd("wl-copy", []).status === 0 || tryCmd("xclip", ["-selection", "clipboard"]).status === 0;
544339
544315
  }
544340
- return "handled";
544316
+ renderInfo2(ok2 ? "Copied API key to clipboard." : "Copy failed — printed above, select to copy.");
544317
+ } catch {
544318
+ renderInfo2("Copy failed — printed above, select to copy.");
544319
+ }
544320
+ return "handled";
544321
+ }
544322
+ if (action === "new") {
544323
+ try {
544324
+ const { randomBytes: randomBytes23 } = await import("node:crypto");
544325
+ const { homedir: homedir41 } = await import("node:os");
544326
+ const { mkdirSync: mkdirSync58, writeFileSync: writeFileSync51 } = await import("node:fs");
544327
+ const { join: join110 } = await import("node:path");
544328
+ const newKey = randomBytes23(16).toString("hex");
544329
+ process.env["OA_API_KEY"] = newKey;
544330
+ const dir = join110(homedir41(), ".open-agents");
544331
+ mkdirSync58(dir, { recursive: true });
544332
+ writeFileSync51(join110(dir, "api.key"), newKey + "\n", "utf8");
544333
+ renderInfo2(`New API key: ${c3.bold(c3.yellow(newKey))}`);
544334
+ renderInfo2("Restart the daemon to apply if needed. Use /access any to restart quickly.");
544335
+ } catch (e2) {
544336
+ renderError2(`Failed to rotate key: ${e2 instanceof Error ? e2.message : String(e2)}`);
544341
544337
  }
544342
- renderInfo2("Usage: /apikey [show|copy|new]");
544343
544338
  return "handled";
544344
544339
  }
544340
+ renderInfo2("Usage: /apikey [show|copy|new] aliases: /key");
544341
+ return "handled";
544342
+ };
544343
+ registerSlashCommand({
544344
+ name: "apikey",
544345
+ description: "Show/copy/rotate API key (show|copy|new)",
544346
+ handler: async (opts) => apiKeyHandler({ arg: opts.arg })
544345
544347
  });
544346
- return "handled";
544348
+ registerSlashCommand({
544349
+ name: "key",
544350
+ description: "Alias for /apikey",
544351
+ handler: async (opts) => apiKeyHandler({ arg: opts.arg })
544352
+ });
544353
+ return apiKeyHandler({ arg });
544347
544354
  }
544348
544355
  case "sessions":
544349
544356
  case "session": {
@@ -551406,16 +551413,17 @@ var init_commands = __esm({
551406
551413
  if (findSlashCommand("access")) return;
551407
551414
  registerSlashCommand({
551408
551415
  name: "access",
551409
- description: "Show/set OA_ACCESS (loopback|lan|any) and restart daemon",
551416
+ description: "Show/set OA_ACCESS (loopback|lan|any). Live-mutates the daemon; auto-generates API key on 'any'.",
551410
551417
  handler: async ({ arg, hasLocal, ctx: ctx3 }) => {
551411
551418
  const normalize2 = (v) => v.toLowerCase().trim();
551419
+ const normalizeMode = (v) => v === "all" ? "any" : v;
551412
551420
  const curAccess = normalize2(process.env["OA_ACCESS"] ?? "");
551413
551421
  const curHost = process.env["OA_HOST"] ?? "0.0.0.0:11435";
551414
551422
  const allowed = /* @__PURE__ */ new Set(["loopback", "lan", "any"]);
551415
- const val = normalize2(arg);
551423
+ const val = normalizeMode(normalize2(arg));
551416
551424
  if (!val) {
551417
551425
  renderInfo2(`Access: ${curAccess || "(default)"} Host: ${curHost}`);
551418
- renderInfo2("Use /access loopback|lan|any to change (restarts daemon).\n");
551426
+ renderInfo2("Use /access loopback|lan|any to change.\n");
551419
551427
  return "handled";
551420
551428
  }
551421
551429
  if (!allowed.has(val)) {
@@ -551423,16 +551431,90 @@ var init_commands = __esm({
551423
551431
  return "handled";
551424
551432
  }
551425
551433
  process.env["OA_ACCESS"] = val;
551434
+ if (val === "any" && !process.env["OA_API_KEY"]) {
551435
+ try {
551436
+ const { randomBytes: randomBytes23 } = await import("node:crypto");
551437
+ const { homedir: homedir41 } = await import("node:os");
551438
+ const { mkdirSync: mkdirSync58, writeFileSync: writeFileSync51 } = await import("node:fs");
551439
+ const { join: join110 } = await import("node:path");
551440
+ const apiKey = randomBytes23(16).toString("hex");
551441
+ process.env["OA_API_KEY"] = apiKey;
551442
+ const dir = join110(homedir41(), ".open-agents");
551443
+ mkdirSync58(dir, { recursive: true });
551444
+ writeFileSync51(join110(dir, "api.key"), apiKey + "\n", "utf8");
551445
+ renderInfo2(`Generated API key: ${c3.bold(c3.yellow(apiKey))}`);
551446
+ renderInfo2("Use Authorization: Bearer <key> or click 'key' in the Web UI header to paste it.");
551447
+ } catch (e2) {
551448
+ renderWarning2(`Failed to generate API key: ${e2 instanceof Error ? e2.message : String(e2)}`);
551449
+ }
551450
+ }
551426
551451
  if (hasLocal) {
551427
551452
  ctx3.saveLocalSettings({ oaAccess: val });
551428
551453
  } else {
551429
551454
  ctx3.saveSettings({ oaAccess: val });
551430
551455
  }
551431
- const { stopDaemon: stopDaemon2, ensureDaemon: ensureDaemon2 } = await Promise.resolve().then(() => (init_daemon(), daemon_exports));
551432
- stopDaemon2();
551433
- await new Promise((r2) => setTimeout(r2, 800));
551456
+ const port = parseInt(process.env["OA_PORT"] || "11435", 10);
551457
+ try {
551458
+ const { homedir: homedir41 } = await import("node:os");
551459
+ const { mkdirSync: mkdirSync58, writeFileSync: writeFileSync51 } = await import("node:fs");
551460
+ const { join: join110 } = await import("node:path");
551461
+ const dir = join110(homedir41(), ".open-agents");
551462
+ mkdirSync58(dir, { recursive: true });
551463
+ writeFileSync51(join110(dir, "access"), `${val}
551464
+ `, "utf8");
551465
+ } catch {
551466
+ }
551467
+ const baseUrl = `http://127.0.0.1:${port}`;
551468
+ const authHeaders = () => {
551469
+ const token = process.env["OA_API_KEY"] || "";
551470
+ return token ? { Authorization: `Bearer ${token}` } : {};
551471
+ };
551472
+ let liveOk = false;
551473
+ try {
551474
+ const resp = await fetch(`${baseUrl}/v1/admin/access`, {
551475
+ method: "POST",
551476
+ headers: { "Content-Type": "application/json", ...authHeaders() },
551477
+ body: JSON.stringify({ mode: val }),
551478
+ signal: AbortSignal.timeout(3e3)
551479
+ });
551480
+ liveOk = resp.ok;
551481
+ } catch {
551482
+ }
551483
+ const readCurrent = async () => {
551484
+ try {
551485
+ const r2 = await fetch(`${baseUrl}/v1/admin/access`, { headers: authHeaders(), signal: AbortSignal.timeout(2e3) });
551486
+ if (!r2.ok) return null;
551487
+ const j = await r2.json();
551488
+ return typeof j.mode === "string" ? j.mode : null;
551489
+ } catch {
551490
+ return null;
551491
+ }
551492
+ };
551493
+ const current = await readCurrent();
551494
+ if (liveOk && current === val) {
551495
+ renderInfo2(`Access policy now '${val}' (live, no restart). Persisted to ~/.open-agents/access.`);
551496
+ return "handled";
551497
+ }
551498
+ renderInfo2(`Live switch did not take effect (daemon reports ${current ?? "unreachable"}). Force-restarting daemon...`);
551499
+ const { forceKillDaemon: forceKillDaemon2, ensureDaemon: ensureDaemon2 } = await Promise.resolve().then(() => (init_daemon(), daemon_exports));
551500
+ const killed = await forceKillDaemon2(port);
551501
+ if (killed > 0) renderInfo2(`Force-killed ${killed} process(es) bound to port ${port}.`);
551434
551502
  const ok2 = await ensureDaemon2();
551435
- renderInfo2(ok2 ? "Daemon restarted to apply access policy." : "Failed to restart daemon.");
551503
+ if (!ok2) {
551504
+ renderError2("Failed to start a fresh daemon after force-kill.");
551505
+ return "handled";
551506
+ }
551507
+ let finalMode = null;
551508
+ for (let i2 = 0; i2 < 10; i2++) {
551509
+ finalMode = await readCurrent();
551510
+ if (finalMode) break;
551511
+ await new Promise((r2) => setTimeout(r2, 250));
551512
+ }
551513
+ if (finalMode === val) {
551514
+ renderInfo2(`Access policy now '${val}' (daemon restarted, verified).`);
551515
+ } else {
551516
+ renderWarning2(`Daemon restarted but reports mode='${finalMode ?? "unreachable"}'. Expected '${val}'.`);
551517
+ }
551436
551518
  return "handled";
551437
551519
  }
551438
551520
  });
@@ -552609,6 +552691,10 @@ var init_render2 = __esm({
552609
552691
  ["/scheduler menu", "Interactive scheduler menu (toggle/kill)"],
552610
552692
  ["/scheduler list", "List all scheduled tasks and timers"],
552611
552693
  ["/scheduler kill", "Kill schedulers + active runs (with escalation if needed)"],
552694
+ ["/apikey", "Show current API key (for pasting into Web UI / clients)"],
552695
+ ["/apikey copy", "Copy the API key to clipboard"],
552696
+ ["/apikey new", "Rotate to a new API key (regenerate)"],
552697
+ ["/key", "Alias for /apikey"],
552612
552698
  ["/codegraph", "Code-graph snapshot: stats, top files, recent activity"],
552613
552699
  ["/codegraph watch [N]", "Subscribe to live code-graph events for N seconds (default 30)"],
552614
552700
  ["/cg", "Alias for /codegraph"],
@@ -580185,40 +580271,6 @@ async function startInteractive(config, repoPath) {
580185
580271
  const repoRoot = resolve36(repoPath ?? cwd());
580186
580272
  try {
580187
580273
  const { registerSlashCommand: registerSlashCommand2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
580188
- registerSlashCommand2({
580189
- name: "access",
580190
- description: "Show/set OA_ACCESS (loopback|lan|any) and restart daemon",
580191
- handler: async ({ arg, hasLocal, ctx: ctx3 }) => {
580192
- const normalize2 = (v) => v.toLowerCase().trim();
580193
- const curAccess = normalize2(process.env["OA_ACCESS"] ?? "");
580194
- const curHost = process.env["OA_HOST"] ?? "0.0.0.0:11435";
580195
- const allowed = /* @__PURE__ */ new Set(["loopback", "lan", "any"]);
580196
- const val = normalize2(arg || "");
580197
- if (!val) {
580198
- process.stdout.write(`
580199
- Access: ${curAccess || "(default)"} Host: ${curHost}
580200
-
580201
- `);
580202
- return "handled";
580203
- }
580204
- if (!allowed.has(val)) {
580205
- process.stdout.write("\n Invalid access mode. Use: loopback, lan, or any.\n\n");
580206
- return "handled";
580207
- }
580208
- process.env["OA_ACCESS"] = val;
580209
- if (hasLocal) {
580210
- ctx3.saveLocalSettings({ oaAccess: val });
580211
- } else {
580212
- ctx3.saveSettings({ oaAccess: val });
580213
- }
580214
- const { stopDaemon: stopDaemon2, ensureDaemon: ensureDaemon2 } = await Promise.resolve().then(() => (init_daemon(), daemon_exports));
580215
- stopDaemon2();
580216
- await new Promise((r2) => setTimeout(r2, 800));
580217
- const ok2 = await ensureDaemon2();
580218
- process.stdout.write(ok2 ? "\n Daemon restarted to apply access policy.\n\n" : "\n Failed to restart daemon.\n\n");
580219
- return "handled";
580220
- }
580221
- });
580222
580274
  registerSlashCommand2({
580223
580275
  name: "host",
580224
580276
  description: "Set OA_HOST host:port and restart daemon",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.367",
3
+ "version": "0.187.369",
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",