open-agents-ai 0.185.72 → 0.185.73

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 +831 -261
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -13782,9 +13782,9 @@ print("${sentinel}")
13782
13782
  if (!this.proc || this.proc.killed) {
13783
13783
  return { success: false, path: "" };
13784
13784
  }
13785
- const { mkdirSync: mkdirSync31, writeFileSync: writeFileSync30 } = await import("node:fs");
13785
+ const { mkdirSync: mkdirSync32, writeFileSync: writeFileSync30 } = await import("node:fs");
13786
13786
  const sessionDir = join22(this.cwd, ".oa", "rlm");
13787
- mkdirSync31(sessionDir, { recursive: true });
13787
+ mkdirSync32(sessionDir, { recursive: true });
13788
13788
  const sessionPath = join22(sessionDir, "session.json");
13789
13789
  try {
13790
13790
  const inspectCode = `
@@ -13820,11 +13820,11 @@ print("__SESSION__" + json.dumps(_session) + "__SESSION__")
13820
13820
  * what was previously computed. */
13821
13821
  async loadSessionInfo() {
13822
13822
  try {
13823
- const { readFileSync: readFileSync45, existsSync: existsSync57 } = await import("node:fs");
13823
+ const { readFileSync: readFileSync46, existsSync: existsSync58 } = await import("node:fs");
13824
13824
  const sessionPath = join22(this.cwd, ".oa", "rlm", "session.json");
13825
- if (!existsSync57(sessionPath))
13825
+ if (!existsSync58(sessionPath))
13826
13826
  return null;
13827
- return JSON.parse(readFileSync45(sessionPath, "utf8"));
13827
+ return JSON.parse(readFileSync46(sessionPath, "utf8"));
13828
13828
  } catch {
13829
13829
  return null;
13830
13830
  }
@@ -14001,10 +14001,10 @@ var init_memory_metabolism = __esm({
14001
14001
  const trajDir = join23(this.cwd, ".oa", "rlm-trajectories");
14002
14002
  let lessons = [];
14003
14003
  try {
14004
- const { readdirSync: readdirSync24, readFileSync: readFileSync45 } = await import("node:fs");
14004
+ const { readdirSync: readdirSync24, readFileSync: readFileSync46 } = await import("node:fs");
14005
14005
  const files = readdirSync24(trajDir).filter((f) => f.endsWith(".jsonl")).sort().reverse().slice(0, 3);
14006
14006
  for (const file of files) {
14007
- const lines = readFileSync45(join23(trajDir, file), "utf8").split("\n").filter((l) => l.trim());
14007
+ const lines = readFileSync46(join23(trajDir, file), "utf8").split("\n").filter((l) => l.trim());
14008
14008
  for (const line of lines) {
14009
14009
  try {
14010
14010
  const entry = JSON.parse(line);
@@ -14388,14 +14388,14 @@ ${issues.map((i) => ` - ${i}`).join("\n")}` : " No issues found."),
14388
14388
  * Optionally filter by task type for phase-aware context (FSM paper insight).
14389
14389
  */
14390
14390
  getTopMemoriesSync(k = 5, taskType) {
14391
- const { readFileSync: readFileSync45, existsSync: existsSync57 } = __require("node:fs");
14391
+ const { readFileSync: readFileSync46, existsSync: existsSync58 } = __require("node:fs");
14392
14392
  const metaDir = join23(this.cwd, ".oa", "memory", "metabolism");
14393
14393
  const storeFile = join23(metaDir, "store.json");
14394
- if (!existsSync57(storeFile))
14394
+ if (!existsSync58(storeFile))
14395
14395
  return "";
14396
14396
  let store = [];
14397
14397
  try {
14398
- store = JSON.parse(readFileSync45(storeFile, "utf8"));
14398
+ store = JSON.parse(readFileSync46(storeFile, "utf8"));
14399
14399
  } catch {
14400
14400
  return "";
14401
14401
  }
@@ -14417,14 +14417,14 @@ ${issues.map((i) => ` - ${i}`).join("\n")}` : " No issues found."),
14417
14417
  /** Update memory scores based on task outcome. Called after task completion.
14418
14418
  * Memories used in successful tasks get boosted. Memories present during failures get decayed. */
14419
14419
  updateFromOutcomeSync(surfacedMemoryText, succeeded) {
14420
- const { readFileSync: readFileSync45, writeFileSync: writeFileSync30, existsSync: existsSync57, mkdirSync: mkdirSync31 } = __require("node:fs");
14420
+ const { readFileSync: readFileSync46, writeFileSync: writeFileSync30, existsSync: existsSync58, mkdirSync: mkdirSync32 } = __require("node:fs");
14421
14421
  const metaDir = join23(this.cwd, ".oa", "memory", "metabolism");
14422
14422
  const storeFile = join23(metaDir, "store.json");
14423
- if (!existsSync57(storeFile))
14423
+ if (!existsSync58(storeFile))
14424
14424
  return;
14425
14425
  let store = [];
14426
14426
  try {
14427
- store = JSON.parse(readFileSync45(storeFile, "utf8"));
14427
+ store = JSON.parse(readFileSync46(storeFile, "utf8"));
14428
14428
  } catch {
14429
14429
  return;
14430
14430
  }
@@ -14448,7 +14448,7 @@ ${issues.map((i) => ` - ${i}`).join("\n")}` : " No issues found."),
14448
14448
  updated = true;
14449
14449
  }
14450
14450
  if (updated) {
14451
- mkdirSync31(metaDir, { recursive: true });
14451
+ mkdirSync32(metaDir, { recursive: true });
14452
14452
  writeFileSync30(storeFile, JSON.stringify(store, null, 2));
14453
14453
  }
14454
14454
  }
@@ -14871,13 +14871,13 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
14871
14871
  // Per EvoSkill (arXiv:2603.02766): retrieve relevant strategies from archive.
14872
14872
  /** Retrieve top-K strategies for context injection. Returns "" if none. */
14873
14873
  getRelevantStrategiesSync(k = 3, taskType) {
14874
- const { readFileSync: readFileSync45, existsSync: existsSync57 } = __require("node:fs");
14874
+ const { readFileSync: readFileSync46, existsSync: existsSync58 } = __require("node:fs");
14875
14875
  const archiveFile = join25(this.cwd, ".oa", "arche", "variants.json");
14876
- if (!existsSync57(archiveFile))
14876
+ if (!existsSync58(archiveFile))
14877
14877
  return "";
14878
14878
  let variants = [];
14879
14879
  try {
14880
- variants = JSON.parse(readFileSync45(archiveFile, "utf8"));
14880
+ variants = JSON.parse(readFileSync46(archiveFile, "utf8"));
14881
14881
  } catch {
14882
14882
  return "";
14883
14883
  }
@@ -14895,13 +14895,13 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
14895
14895
  }
14896
14896
  /** Archive a strategy variant synchronously (for task completion path) */
14897
14897
  archiveVariantSync(strategy, outcome, tags = []) {
14898
- const { readFileSync: readFileSync45, writeFileSync: writeFileSync30, existsSync: existsSync57, mkdirSync: mkdirSync31 } = __require("node:fs");
14898
+ const { readFileSync: readFileSync46, writeFileSync: writeFileSync30, existsSync: existsSync58, mkdirSync: mkdirSync32 } = __require("node:fs");
14899
14899
  const dir = join25(this.cwd, ".oa", "arche");
14900
14900
  const archiveFile = join25(dir, "variants.json");
14901
14901
  let variants = [];
14902
14902
  try {
14903
- if (existsSync57(archiveFile))
14904
- variants = JSON.parse(readFileSync45(archiveFile, "utf8"));
14903
+ if (existsSync58(archiveFile))
14904
+ variants = JSON.parse(readFileSync46(archiveFile, "utf8"));
14905
14905
  } catch {
14906
14906
  }
14907
14907
  variants.push({
@@ -14916,7 +14916,7 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
14916
14916
  });
14917
14917
  if (variants.length > 50)
14918
14918
  variants = variants.slice(-50);
14919
- mkdirSync31(dir, { recursive: true });
14919
+ mkdirSync32(dir, { recursive: true });
14920
14920
  writeFileSync30(archiveFile, JSON.stringify(variants, null, 2));
14921
14921
  }
14922
14922
  async saveArchive(variants) {
@@ -27422,10 +27422,10 @@ ${marker}` : marker);
27422
27422
  if (!this._workingDirectory)
27423
27423
  return;
27424
27424
  try {
27425
- const { mkdirSync: mkdirSync31, writeFileSync: writeFileSync30 } = __require("node:fs");
27426
- const { join: join77 } = __require("node:path");
27427
- const sessionDir = join77(this._workingDirectory, ".oa", "session", this._sessionId);
27428
- mkdirSync31(sessionDir, { recursive: true });
27425
+ const { mkdirSync: mkdirSync32, writeFileSync: writeFileSync30 } = __require("node:fs");
27426
+ const { join: join78 } = __require("node:path");
27427
+ const sessionDir = join78(this._workingDirectory, ".oa", "session", this._sessionId);
27428
+ mkdirSync32(sessionDir, { recursive: true });
27429
27429
  const checkpoint = {
27430
27430
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
27431
27431
  sessionId: this._sessionId,
@@ -27437,7 +27437,7 @@ ${marker}` : marker);
27437
27437
  memexEntryCount: this._memexArchive.size,
27438
27438
  fileRegistrySize: this._fileRegistry.size
27439
27439
  };
27440
- writeFileSync30(join77(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
27440
+ writeFileSync30(join78(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
27441
27441
  } catch {
27442
27442
  }
27443
27443
  }
@@ -28575,17 +28575,17 @@ ${transcript}`
28575
28575
  let resizedBase64 = null;
28576
28576
  try {
28577
28577
  const { execSync: execSync36 } = await import("node:child_process");
28578
- const { writeFileSync: writeFileSync30, readFileSync: readFileSync45, unlinkSync: unlinkSync13 } = await import("node:fs");
28579
- const { join: join77 } = await import("node:path");
28578
+ const { writeFileSync: writeFileSync30, readFileSync: readFileSync46, unlinkSync: unlinkSync13 } = await import("node:fs");
28579
+ const { join: join78 } = await import("node:path");
28580
28580
  const { tmpdir: tmpdir11 } = await import("node:os");
28581
- const tmpIn = join77(tmpdir11(), `oa_img_in_${Date.now()}.png`);
28582
- const tmpOut = join77(tmpdir11(), `oa_img_out_${Date.now()}.jpg`);
28581
+ const tmpIn = join78(tmpdir11(), `oa_img_in_${Date.now()}.png`);
28582
+ const tmpOut = join78(tmpdir11(), `oa_img_out_${Date.now()}.jpg`);
28583
28583
  writeFileSync30(tmpIn, buffer);
28584
28584
  const pyBin = process.platform === "win32" ? "python" : "python3";
28585
28585
  const escapedIn = tmpIn.replace(/\\/g, "\\\\");
28586
28586
  const escapedOut = tmpOut.replace(/\\/g, "\\\\");
28587
28587
  execSync36(`${pyBin} -c "from PIL import Image; img = Image.open('${escapedIn}'); img.thumbnail((512, 512), Image.LANCZOS); img = img.convert('RGB'); img.save('${escapedOut}', 'JPEG', quality=75)"`, { timeout: 1e4, stdio: "pipe" });
28588
- const resizedBuf = readFileSync45(tmpOut);
28588
+ const resizedBuf = readFileSync46(tmpOut);
28589
28589
  resizedBase64 = `data:image/jpeg;base64,${resizedBuf.toString("base64")}`;
28590
28590
  try {
28591
28591
  unlinkSync13(tmpIn);
@@ -39557,26 +39557,26 @@ async function fetchOpenAIModels(baseUrl, apiKey) {
39557
39557
  async function fetchPeerModels(peerId, authKey) {
39558
39558
  try {
39559
39559
  const { NexusTool: NexusTool2 } = await Promise.resolve().then(() => (init_dist2(), dist_exports));
39560
- const { existsSync: existsSync57, readFileSync: readFileSync45 } = await import("node:fs");
39561
- const { join: join77 } = await import("node:path");
39560
+ const { existsSync: existsSync58, readFileSync: readFileSync46 } = await import("node:fs");
39561
+ const { join: join78 } = await import("node:path");
39562
39562
  const cwd4 = process.cwd();
39563
39563
  const nexusTool = new NexusTool2(cwd4);
39564
39564
  const nexusDir = nexusTool.getNexusDir();
39565
39565
  let isLocalPeer = false;
39566
39566
  try {
39567
- const statusPath = join77(nexusDir, "status.json");
39568
- if (existsSync57(statusPath)) {
39569
- const status = JSON.parse(readFileSync45(statusPath, "utf8"));
39567
+ const statusPath = join78(nexusDir, "status.json");
39568
+ if (existsSync58(statusPath)) {
39569
+ const status = JSON.parse(readFileSync46(statusPath, "utf8"));
39570
39570
  if (status.peerId === peerId)
39571
39571
  isLocalPeer = true;
39572
39572
  }
39573
39573
  } catch {
39574
39574
  }
39575
39575
  if (isLocalPeer) {
39576
- const pricingPath = join77(nexusDir, "pricing.json");
39577
- if (existsSync57(pricingPath)) {
39576
+ const pricingPath = join78(nexusDir, "pricing.json");
39577
+ if (existsSync58(pricingPath)) {
39578
39578
  try {
39579
- const pricing = JSON.parse(readFileSync45(pricingPath, "utf8"));
39579
+ const pricing = JSON.parse(readFileSync46(pricingPath, "utf8"));
39580
39580
  const localModels = (pricing.models || []).map((m) => ({
39581
39581
  name: m.model || "unknown",
39582
39582
  size: m.parameterSize || "",
@@ -39590,10 +39590,10 @@ async function fetchPeerModels(peerId, authKey) {
39590
39590
  }
39591
39591
  }
39592
39592
  }
39593
- const cachePath = join77(nexusDir, "peer-models-cache.json");
39594
- if (existsSync57(cachePath)) {
39593
+ const cachePath = join78(nexusDir, "peer-models-cache.json");
39594
+ if (existsSync58(cachePath)) {
39595
39595
  try {
39596
- const cache4 = JSON.parse(readFileSync45(cachePath, "utf8"));
39596
+ const cache4 = JSON.parse(readFileSync46(cachePath, "utf8"));
39597
39597
  if (cache4.peerId === peerId && cache4.models?.length > 0) {
39598
39598
  const age = Date.now() - new Date(cache4.cachedAt).getTime();
39599
39599
  if (age < 5 * 60 * 1e3) {
@@ -39708,10 +39708,10 @@ async function fetchPeerModels(peerId, authKey) {
39708
39708
  } catch {
39709
39709
  }
39710
39710
  if (isLocalPeer) {
39711
- const pricingPath = join77(nexusDir, "pricing.json");
39712
- if (existsSync57(pricingPath)) {
39711
+ const pricingPath = join78(nexusDir, "pricing.json");
39712
+ if (existsSync58(pricingPath)) {
39713
39713
  try {
39714
- const pricing = JSON.parse(readFileSync45(pricingPath, "utf8"));
39714
+ const pricing = JSON.parse(readFileSync46(pricingPath, "utf8"));
39715
39715
  return (pricing.models || []).map((m) => ({
39716
39716
  name: m.model || "unknown",
39717
39717
  size: m.parameterSize || "",
@@ -52121,12 +52121,12 @@ async function handleVoiceMenu(ctx, save, hasLocal) {
52121
52121
  continue;
52122
52122
  }
52123
52123
  const { basename: basename18, join: pathJoin } = await import("node:path");
52124
- const { copyFileSync: copyFileSync3, mkdirSync: mkdirSync31, existsSync: exists } = await import("node:fs");
52124
+ const { copyFileSync: copyFileSync3, mkdirSync: mkdirSync32, existsSync: exists } = await import("node:fs");
52125
52125
  const { homedir: homedir21 } = await import("node:os");
52126
52126
  const modelName = basename18(onnxDrop.path, ".onnx").replace(/[^a-zA-Z0-9_-]/g, "-");
52127
52127
  const destDir = pathJoin(homedir21(), ".open-agents", "voice", "models", modelName);
52128
52128
  if (!exists(destDir))
52129
- mkdirSync31(destDir, { recursive: true });
52129
+ mkdirSync32(destDir, { recursive: true });
52130
52130
  copyFileSync3(onnxDrop.path, pathJoin(destDir, "model.onnx"));
52131
52131
  copyFileSync3(jsonDrop.path, pathJoin(destDir, "config.json"));
52132
52132
  const { registerCustomOnnxModel: registerCustomOnnxModel2 } = await Promise.resolve().then(() => (init_voice(), voice_exports));
@@ -52965,10 +52965,10 @@ async function handlePeerEndpoint(peerId, authKey, ctx, local) {
52965
52965
  const models = await fetchModels(peerUrl, authKey);
52966
52966
  if (models.length > 0) {
52967
52967
  try {
52968
- const { writeFileSync: writeFileSync30, mkdirSync: mkdirSync31 } = await import("node:fs");
52969
- const { join: join77, dirname: dirname24 } = await import("node:path");
52970
- const cachePath = join77(ctx.repoRoot || process.cwd(), ".oa", "nexus", "peer-models-cache.json");
52971
- mkdirSync31(dirname24(cachePath), { recursive: true });
52968
+ const { writeFileSync: writeFileSync30, mkdirSync: mkdirSync32 } = await import("node:fs");
52969
+ const { join: join78, dirname: dirname24 } = await import("node:path");
52970
+ const cachePath = join78(ctx.repoRoot || process.cwd(), ".oa", "nexus", "peer-models-cache.json");
52971
+ mkdirSync32(dirname24(cachePath), { recursive: true });
52972
52972
  writeFileSync30(cachePath, JSON.stringify({
52973
52973
  peerId,
52974
52974
  cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -53168,17 +53168,17 @@ async function handleUpdate(subcommand, ctx) {
53168
53168
  try {
53169
53169
  const { createRequire: createRequire6 } = await import("node:module");
53170
53170
  const { fileURLToPath: fileURLToPath16 } = await import("node:url");
53171
- const { dirname: dirname24, join: join77 } = await import("node:path");
53172
- const { existsSync: existsSync57 } = await import("node:fs");
53171
+ const { dirname: dirname24, join: join78 } = await import("node:path");
53172
+ const { existsSync: existsSync58 } = await import("node:fs");
53173
53173
  const req = createRequire6(import.meta.url);
53174
53174
  const thisDir = dirname24(fileURLToPath16(import.meta.url));
53175
53175
  const candidates = [
53176
- join77(thisDir, "..", "package.json"),
53177
- join77(thisDir, "..", "..", "package.json"),
53178
- join77(thisDir, "..", "..", "..", "package.json")
53176
+ join78(thisDir, "..", "package.json"),
53177
+ join78(thisDir, "..", "..", "package.json"),
53178
+ join78(thisDir, "..", "..", "..", "package.json")
53179
53179
  ];
53180
53180
  for (const pkgPath of candidates) {
53181
- if (existsSync57(pkgPath)) {
53181
+ if (existsSync58(pkgPath)) {
53182
53182
  const pkg = req(pkgPath);
53183
53183
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
53184
53184
  currentVersion = pkg.version ?? "0.0.0";
@@ -65238,25 +65238,561 @@ var init_direct_input = __esm({
65238
65238
  }
65239
65239
  });
65240
65240
 
65241
- // packages/cli/dist/api/profiles.js
65242
- import { existsSync as existsSync52, readFileSync as readFileSync41, writeFileSync as writeFileSync25, mkdirSync as mkdirSync26, readdirSync as readdirSync20, unlinkSync as unlinkSync12 } from "node:fs";
65241
+ // packages/cli/dist/api/audit-log.js
65242
+ import { mkdirSync as mkdirSync26, appendFileSync as appendFileSync4, readFileSync as readFileSync41, existsSync as existsSync52 } from "node:fs";
65243
65243
  import { join as join69 } from "node:path";
65244
+ function initAuditLog(oaDir) {
65245
+ auditDir = join69(oaDir, "audit");
65246
+ auditFile = join69(auditDir, "audit.jsonl");
65247
+ try {
65248
+ mkdirSync26(auditDir, { recursive: true });
65249
+ initialized = true;
65250
+ } catch {
65251
+ }
65252
+ }
65253
+ function recordAudit(record) {
65254
+ if (!initialized)
65255
+ return;
65256
+ try {
65257
+ const line = JSON.stringify(record) + "\n";
65258
+ appendFileSync4(auditFile, line, "utf-8");
65259
+ } catch {
65260
+ }
65261
+ }
65262
+ function queryAudit(opts) {
65263
+ if (!initialized || !existsSync52(auditFile))
65264
+ return [];
65265
+ try {
65266
+ const raw = readFileSync41(auditFile, "utf-8");
65267
+ const lines = raw.split("\n").filter(Boolean);
65268
+ let records = lines.map((l) => {
65269
+ try {
65270
+ return JSON.parse(l);
65271
+ } catch {
65272
+ return null;
65273
+ }
65274
+ }).filter(Boolean);
65275
+ if (opts.since) {
65276
+ const sinceTs = new Date(opts.since).getTime();
65277
+ records = records.filter((r) => new Date(r.ts).getTime() >= sinceTs);
65278
+ }
65279
+ if (opts.user) {
65280
+ records = records.filter((r) => r.user === opts.user);
65281
+ }
65282
+ records.reverse();
65283
+ if (opts.limit && opts.limit > 0) {
65284
+ records = records.slice(0, opts.limit);
65285
+ }
65286
+ return records;
65287
+ } catch {
65288
+ return [];
65289
+ }
65290
+ }
65291
+ var auditDir, auditFile, initialized;
65292
+ var init_audit_log = __esm({
65293
+ "packages/cli/dist/api/audit-log.js"() {
65294
+ "use strict";
65295
+ auditDir = "";
65296
+ auditFile = "";
65297
+ initialized = false;
65298
+ }
65299
+ });
65300
+
65301
+ // packages/cli/dist/api/web-ui.js
65302
+ function getWebUI() {
65303
+ return `<!DOCTYPE html>
65304
+ <html lang="en">
65305
+ <head>
65306
+ <meta charset="UTF-8">
65307
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
65308
+ <title>Open Agents</title>
65309
+ <style>
65310
+ * { margin: 0; padding: 0; box-sizing: border-box; }
65311
+ body {
65312
+ font-family: 'SF Mono', 'Cascadia Code', 'Fira Code', monospace;
65313
+ background: #1a1a1e;
65314
+ color: #b0b0b0;
65315
+ display: flex;
65316
+ flex-direction: column;
65317
+ height: 100vh;
65318
+ overflow: hidden;
65319
+ }
65320
+ #header {
65321
+ display: flex;
65322
+ align-items: center;
65323
+ gap: 12px;
65324
+ padding: 8px 16px;
65325
+ background: #1e1e22;
65326
+ border-bottom: 1px solid #2a2a30;
65327
+ flex-shrink: 0;
65328
+ }
65329
+ #header .accent { color: #b2920a; font-weight: bold; font-size: 0.8rem; }
65330
+ #header .status { font-size: 0.7rem; color: #555; }
65331
+ #header .status.live { color: #b2920a; }
65332
+ #header select {
65333
+ background: #2a2a30;
65334
+ border: 1px solid #3a3a42;
65335
+ color: #b0b0b0;
65336
+ padding: 4px 8px;
65337
+ border-radius: 3px;
65338
+ font-family: inherit;
65339
+ font-size: 0.7rem;
65340
+ margin-left: auto;
65341
+ }
65342
+ #header .key-btn {
65343
+ background: #2a2a30;
65344
+ border: 1px solid #3a3a42;
65345
+ color: #b2920a;
65346
+ padding: 4px 10px;
65347
+ border-radius: 3px;
65348
+ font-family: inherit;
65349
+ font-size: 0.7rem;
65350
+ cursor: pointer;
65351
+ transition: background 0.15s;
65352
+ }
65353
+ #header .key-btn:hover { background: #3a3a42; }
65354
+ #conversation {
65355
+ flex: 1;
65356
+ overflow-y: auto;
65357
+ padding: 12px 16px;
65358
+ display: flex;
65359
+ flex-direction: column;
65360
+ gap: 4px;
65361
+ }
65362
+ .msg { padding: 6px 0; font-size: 0.82rem; line-height: 1.5; white-space: pre-wrap; word-break: break-word; }
65363
+ .msg.user { color: #888; }
65364
+ .msg.user::before { content: '\\25B8 '; color: #555; }
65365
+ .msg.assistant { color: #b2920a; }
65366
+ .msg.assistant::before { content: '\\25B9 '; color: #b2920a; }
65367
+ .msg.system { color: #555; font-size: 0.7rem; }
65368
+ .msg code {
65369
+ background: #2a2a30;
65370
+ padding: 1px 4px;
65371
+ border-radius: 2px;
65372
+ font-size: 0.78rem;
65373
+ }
65374
+ .msg pre {
65375
+ background: #1e1e22;
65376
+ border: 1px solid #2a2a30;
65377
+ border-radius: 3px;
65378
+ padding: 8px 12px;
65379
+ margin: 6px 0;
65380
+ overflow-x: auto;
65381
+ font-size: 0.78rem;
65382
+ line-height: 1.4;
65383
+ position: relative;
65384
+ }
65385
+ .msg pre .copy-btn {
65386
+ position: absolute;
65387
+ top: 4px;
65388
+ right: 4px;
65389
+ background: #2a2a30;
65390
+ border: 1px solid #3a3a42;
65391
+ color: #b2920a;
65392
+ padding: 2px 8px;
65393
+ border-radius: 2px;
65394
+ font-family: inherit;
65395
+ font-size: 0.6rem;
65396
+ cursor: pointer;
65397
+ opacity: 0.5;
65398
+ transition: opacity 0.15s;
65399
+ }
65400
+ .msg pre:hover .copy-btn { opacity: 1; }
65401
+ .msg-actions {
65402
+ display: flex;
65403
+ gap: 8px;
65404
+ margin-top: 2px;
65405
+ }
65406
+ .msg-actions button {
65407
+ background: none;
65408
+ border: none;
65409
+ color: #555;
65410
+ font-family: inherit;
65411
+ font-size: 0.6rem;
65412
+ cursor: pointer;
65413
+ padding: 0;
65414
+ }
65415
+ .msg-actions button:hover { color: #b2920a; }
65416
+ #footer {
65417
+ display: flex;
65418
+ align-items: flex-end;
65419
+ gap: 10px;
65420
+ padding: 8px 16px;
65421
+ background: #1e1e22;
65422
+ border-top: 1px solid #2a2a30;
65423
+ flex-shrink: 0;
65424
+ }
65425
+ #input-area {
65426
+ flex: 1;
65427
+ background: #2a2a30;
65428
+ border: 1px solid #3a3a42;
65429
+ border-radius: 3px;
65430
+ padding: 8px 12px;
65431
+ color: #b0b0b0;
65432
+ font-family: inherit;
65433
+ font-size: 0.82rem;
65434
+ resize: none;
65435
+ min-height: 36px;
65436
+ max-height: 120px;
65437
+ line-height: 1.4;
65438
+ outline: none;
65439
+ }
65440
+ #input-area:focus { border-color: #b2920a; }
65441
+ #send-btn {
65442
+ background: #2a2a30;
65443
+ border: 1px solid #3a3a42;
65444
+ color: #b2920a;
65445
+ padding: 8px 16px;
65446
+ border-radius: 3px;
65447
+ font-family: inherit;
65448
+ font-size: 0.75rem;
65449
+ cursor: pointer;
65450
+ transition: background 0.15s;
65451
+ flex-shrink: 0;
65452
+ }
65453
+ #send-btn:hover { background: #3a3a42; }
65454
+ #send-btn:disabled { opacity: 0.3; cursor: default; }
65455
+ #system-prompt-toggle {
65456
+ font-size: 0.65rem;
65457
+ color: #444;
65458
+ cursor: pointer;
65459
+ padding: 4px 0;
65460
+ }
65461
+ #system-prompt-toggle:hover { color: #b2920a; }
65462
+ #system-prompt-area {
65463
+ display: none;
65464
+ padding: 0 16px 8px;
65465
+ background: #1e1e22;
65466
+ }
65467
+ #system-prompt-area textarea {
65468
+ width: 100%;
65469
+ background: #2a2a30;
65470
+ border: 1px solid #3a3a42;
65471
+ border-radius: 3px;
65472
+ padding: 6px 10px;
65473
+ color: #b0b0b0;
65474
+ font-family: inherit;
65475
+ font-size: 0.7rem;
65476
+ resize: vertical;
65477
+ min-height: 48px;
65478
+ outline: none;
65479
+ }
65480
+ #key-modal {
65481
+ display: none;
65482
+ position: fixed;
65483
+ top: 0; left: 0; right: 0; bottom: 0;
65484
+ background: rgba(0,0,0,0.7);
65485
+ z-index: 100;
65486
+ align-items: center;
65487
+ justify-content: center;
65488
+ }
65489
+ #key-modal.visible { display: flex; }
65490
+ #key-modal .modal {
65491
+ background: #1e1e22;
65492
+ border: 1px solid #2a2a30;
65493
+ border-radius: 6px;
65494
+ padding: 20px;
65495
+ width: 360px;
65496
+ max-width: 90vw;
65497
+ }
65498
+ #key-modal .modal h3 { color: #b2920a; font-size: 0.8rem; margin-bottom: 12px; }
65499
+ #key-modal .modal input {
65500
+ width: 100%;
65501
+ background: #2a2a30;
65502
+ border: 1px solid #3a3a42;
65503
+ border-radius: 3px;
65504
+ padding: 8px 10px;
65505
+ color: #b0b0b0;
65506
+ font-family: inherit;
65507
+ font-size: 0.75rem;
65508
+ outline: none;
65509
+ margin-bottom: 12px;
65510
+ }
65511
+ #key-modal .modal button {
65512
+ background: #2a2a30;
65513
+ border: 1px solid #b2920a;
65514
+ color: #b2920a;
65515
+ padding: 6px 16px;
65516
+ border-radius: 3px;
65517
+ font-family: inherit;
65518
+ font-size: 0.75rem;
65519
+ cursor: pointer;
65520
+ margin-right: 8px;
65521
+ }
65522
+ </style>
65523
+ </head>
65524
+ <body>
65525
+
65526
+ <div id="header">
65527
+ <span class="accent">OA</span>
65528
+ <span class="status" id="status">connecting...</span>
65529
+ <select id="model-select"><option>loading...</option></select>
65530
+ <button class="key-btn" id="key-btn" title="Set API key">key</button>
65531
+ </div>
65532
+
65533
+ <div id="system-prompt-area">
65534
+ <textarea id="system-prompt" placeholder="System prompt (optional)"></textarea>
65535
+ </div>
65536
+
65537
+ <div id="conversation"></div>
65538
+
65539
+ <div id="footer">
65540
+ <span id="system-prompt-toggle" onclick="toggleSystemPrompt()">sys</span>
65541
+ <textarea id="input-area" placeholder="Type a message..." rows="1"></textarea>
65542
+ <button id="send-btn" onclick="sendMessage()">send</button>
65543
+ </div>
65544
+
65545
+ <div id="key-modal">
65546
+ <div class="modal">
65547
+ <h3>API Key</h3>
65548
+ <input id="key-input" type="password" placeholder="Bearer token (leave empty if auth disabled)">
65549
+ <div>
65550
+ <button onclick="saveKey()">save</button>
65551
+ <button onclick="clearKey()">clear</button>
65552
+ <button onclick="closeKeyModal()">cancel</button>
65553
+ </div>
65554
+ </div>
65555
+ </div>
65556
+
65557
+ <script>
65558
+ const conv = document.getElementById('conversation');
65559
+ const input = document.getElementById('input-area');
65560
+ const sendBtn = document.getElementById('send-btn');
65561
+ const modelSelect = document.getElementById('model-select');
65562
+ const statusEl = document.getElementById('status');
65563
+ let apiKey = localStorage.getItem('oa-api-key') || '';
65564
+ let streaming = false;
65565
+ let messages = [];
65566
+
65567
+ // Auto-resize textarea
65568
+ input.addEventListener('input', () => {
65569
+ input.style.height = 'auto';
65570
+ input.style.height = Math.min(input.scrollHeight, 120) + 'px';
65571
+ });
65572
+ input.addEventListener('keydown', (e) => {
65573
+ if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); }
65574
+ });
65575
+
65576
+ function headers() {
65577
+ const h = { 'Content-Type': 'application/json' };
65578
+ if (apiKey) h['Authorization'] = 'Bearer ' + apiKey;
65579
+ return h;
65580
+ }
65581
+
65582
+ // Health check
65583
+ async function checkHealth() {
65584
+ try {
65585
+ const r = await fetch('/health');
65586
+ const d = await r.json();
65587
+ statusEl.textContent = 'connected (' + d.version + ')';
65588
+ statusEl.className = 'status live';
65589
+ } catch {
65590
+ statusEl.textContent = 'disconnected';
65591
+ statusEl.className = 'status';
65592
+ }
65593
+ }
65594
+
65595
+ // Load models
65596
+ async function loadModels() {
65597
+ try {
65598
+ const r = await fetch('/v1/models', { headers: headers() });
65599
+ const d = await r.json();
65600
+ modelSelect.innerHTML = '';
65601
+ for (const m of (d.data || [])) {
65602
+ const opt = document.createElement('option');
65603
+ // Strip "local/" prefix for cleaner display
65604
+ opt.value = m.id.replace(/^local\\//, '');
65605
+ opt.textContent = m.id.replace(/^local\\//, '');
65606
+ modelSelect.appendChild(opt);
65607
+ }
65608
+ // Default to first model with "9b" in name, or first overall
65609
+ const preferred = Array.from(modelSelect.options).find(o => /9b/i.test(o.value));
65610
+ if (preferred) modelSelect.value = preferred.value;
65611
+ } catch { modelSelect.innerHTML = '<option>error loading models</option>'; }
65612
+ }
65613
+
65614
+ function addMessage(role, content) {
65615
+ const div = document.createElement('div');
65616
+ div.className = 'msg ' + role;
65617
+ div.innerHTML = renderMarkdown(content);
65618
+ // Copy button
65619
+ if (role === 'assistant') {
65620
+ const actions = document.createElement('div');
65621
+ actions.className = 'msg-actions';
65622
+ const copyBtn = document.createElement('button');
65623
+ copyBtn.textContent = 'copy';
65624
+ copyBtn.onclick = () => { navigator.clipboard.writeText(content); copyBtn.textContent = 'copied'; setTimeout(() => copyBtn.textContent = 'copy', 1500); };
65625
+ actions.appendChild(copyBtn);
65626
+ div.appendChild(actions);
65627
+ }
65628
+ conv.appendChild(div);
65629
+ conv.scrollTop = conv.scrollHeight;
65630
+ return div;
65631
+ }
65632
+
65633
+ function renderMarkdown(text) {
65634
+ // Code blocks
65635
+ text = text.replace(/\`\`\`(\\w*)\\n([\\s\\S]*?)\`\`\`/g, (_, lang, code) => {
65636
+ const id = 'cb' + Math.random().toString(36).slice(2,8);
65637
+ return '<pre><button class="copy-btn" onclick="navigator.clipboard.writeText(document.getElementById(\\'' + id + '\\').textContent);this.textContent=\\'copied\\';setTimeout(()=>this.textContent=\\'copy\\',1500)">copy</button><code id="' + id + '">' + escHtml(code) + '</code></pre>';
65638
+ });
65639
+ // Inline code
65640
+ text = text.replace(/\`([^\`]+)\`/g, '<code>$1</code>');
65641
+ // Bold
65642
+ text = text.replace(/\\*\\*(.+?)\\*\\*/g, '<strong>$1</strong>');
65643
+ return text;
65644
+ }
65645
+
65646
+ function escHtml(s) {
65647
+ return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
65648
+ }
65649
+
65650
+ async function sendMessage() {
65651
+ const text = input.value.trim();
65652
+ if (!text || streaming) return;
65653
+ input.value = '';
65654
+ input.style.height = 'auto';
65655
+
65656
+ // Add user message
65657
+ messages.push({ role: 'user', content: text });
65658
+ addMessage('user', text);
65659
+
65660
+ // System prompt
65661
+ const sysPrompt = document.getElementById('system-prompt').value.trim();
65662
+
65663
+ streaming = true;
65664
+ sendBtn.disabled = true;
65665
+ sendBtn.textContent = '...';
65666
+
65667
+ const msgDiv = addMessage('assistant', '');
65668
+ let fullContent = '';
65669
+
65670
+ try {
65671
+ const body = {
65672
+ model: modelSelect.value,
65673
+ messages: [
65674
+ ...(sysPrompt ? [{ role: 'system', content: sysPrompt }] : []),
65675
+ ...messages,
65676
+ ],
65677
+ stream: true,
65678
+ max_tokens: 4096,
65679
+ };
65680
+
65681
+ const response = await fetch('/v1/chat/completions', {
65682
+ method: 'POST',
65683
+ headers: headers(),
65684
+ body: JSON.stringify(body),
65685
+ });
65686
+
65687
+ const reader = response.body.getReader();
65688
+ const decoder = new TextDecoder();
65689
+ let buffer = '';
65690
+
65691
+ while (true) {
65692
+ const { done, value } = await reader.read();
65693
+ if (done) break;
65694
+ buffer += decoder.decode(value, { stream: true });
65695
+
65696
+ const lines = buffer.split('\\n');
65697
+ buffer = lines.pop() || '';
65698
+
65699
+ for (const line of lines) {
65700
+ if (!line.startsWith('data: ')) continue;
65701
+ const data = line.slice(6);
65702
+ if (data === '[DONE]') continue;
65703
+ try {
65704
+ const chunk = JSON.parse(data);
65705
+ const delta = chunk.choices?.[0]?.delta?.content || '';
65706
+ if (delta) {
65707
+ fullContent += delta;
65708
+ msgDiv.innerHTML = renderMarkdown(fullContent);
65709
+ conv.scrollTop = conv.scrollHeight;
65710
+ }
65711
+ } catch {}
65712
+ }
65713
+ }
65714
+
65715
+ messages.push({ role: 'assistant', content: fullContent });
65716
+ // Re-render with copy button
65717
+ msgDiv.innerHTML = renderMarkdown(fullContent);
65718
+ const actions = document.createElement('div');
65719
+ actions.className = 'msg-actions';
65720
+ const copyBtn = document.createElement('button');
65721
+ copyBtn.textContent = 'copy';
65722
+ copyBtn.onclick = () => { navigator.clipboard.writeText(fullContent); copyBtn.textContent = 'copied'; setTimeout(() => copyBtn.textContent = 'copy', 1500); };
65723
+ actions.appendChild(copyBtn);
65724
+ msgDiv.appendChild(actions);
65725
+ } catch (err) {
65726
+ msgDiv.innerHTML = '<span style="color:#ff4444">Error: ' + escHtml(err.message) + '</span>';
65727
+ }
65728
+
65729
+ streaming = false;
65730
+ sendBtn.disabled = false;
65731
+ sendBtn.textContent = 'send';
65732
+ conv.scrollTop = conv.scrollHeight;
65733
+ }
65734
+
65735
+ function toggleSystemPrompt() {
65736
+ const area = document.getElementById('system-prompt-area');
65737
+ area.style.display = area.style.display === 'none' ? 'block' : 'none';
65738
+ }
65739
+
65740
+ // Key modal
65741
+ document.getElementById('key-btn').onclick = () => {
65742
+ document.getElementById('key-modal').classList.add('visible');
65743
+ document.getElementById('key-input').value = apiKey;
65744
+ };
65745
+ function saveKey() {
65746
+ apiKey = document.getElementById('key-input').value;
65747
+ localStorage.setItem('oa-api-key', apiKey);
65748
+ closeKeyModal();
65749
+ loadModels();
65750
+ }
65751
+ function clearKey() {
65752
+ apiKey = '';
65753
+ localStorage.removeItem('oa-api-key');
65754
+ document.getElementById('key-input').value = '';
65755
+ closeKeyModal();
65756
+ loadModels();
65757
+ }
65758
+ function closeKeyModal() {
65759
+ document.getElementById('key-modal').classList.remove('visible');
65760
+ }
65761
+
65762
+ // Init
65763
+ checkHealth();
65764
+ loadModels();
65765
+ setInterval(checkHealth, 30000);
65766
+ input.focus();
65767
+ </script>
65768
+ </body>
65769
+ </html>`;
65770
+ }
65771
+ var init_web_ui = __esm({
65772
+ "packages/cli/dist/api/web-ui.js"() {
65773
+ "use strict";
65774
+ }
65775
+ });
65776
+
65777
+ // packages/cli/dist/api/profiles.js
65778
+ import { existsSync as existsSync53, readFileSync as readFileSync42, writeFileSync as writeFileSync25, mkdirSync as mkdirSync27, readdirSync as readdirSync20, unlinkSync as unlinkSync12 } from "node:fs";
65779
+ import { join as join70 } from "node:path";
65244
65780
  import { homedir as homedir18 } from "node:os";
65245
65781
  import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, randomBytes as randomBytes15, scryptSync as scryptSync3, createHash as createHash5 } from "node:crypto";
65246
65782
  function globalProfileDir() {
65247
- return join69(homedir18(), ".open-agents", "profiles");
65783
+ return join70(homedir18(), ".open-agents", "profiles");
65248
65784
  }
65249
65785
  function projectProfileDir(projectDir) {
65250
- return join69(projectDir || process.cwd(), ".oa", "profiles");
65786
+ return join70(projectDir || process.cwd(), ".oa", "profiles");
65251
65787
  }
65252
65788
  function listProfiles(projectDir) {
65253
65789
  const result = [];
65254
65790
  const seen = /* @__PURE__ */ new Set();
65255
65791
  const projDir = projectProfileDir(projectDir);
65256
- if (existsSync52(projDir)) {
65792
+ if (existsSync53(projDir)) {
65257
65793
  for (const f of readdirSync20(projDir).filter((f2) => f2.endsWith(".json"))) {
65258
65794
  try {
65259
- const raw = JSON.parse(readFileSync41(join69(projDir, f), "utf8"));
65795
+ const raw = JSON.parse(readFileSync42(join70(projDir, f), "utf8"));
65260
65796
  const name = f.replace(".json", "");
65261
65797
  seen.add(name);
65262
65798
  result.push({
@@ -65270,13 +65806,13 @@ function listProfiles(projectDir) {
65270
65806
  }
65271
65807
  }
65272
65808
  const globDir = globalProfileDir();
65273
- if (existsSync52(globDir)) {
65809
+ if (existsSync53(globDir)) {
65274
65810
  for (const f of readdirSync20(globDir).filter((f2) => f2.endsWith(".json"))) {
65275
65811
  const name = f.replace(".json", "");
65276
65812
  if (seen.has(name))
65277
65813
  continue;
65278
65814
  try {
65279
- const raw = JSON.parse(readFileSync41(join69(globDir, f), "utf8"));
65815
+ const raw = JSON.parse(readFileSync42(join70(globDir, f), "utf8"));
65280
65816
  result.push({
65281
65817
  name,
65282
65818
  description: raw.description || "",
@@ -65291,12 +65827,12 @@ function listProfiles(projectDir) {
65291
65827
  }
65292
65828
  function loadProfile(name, password, projectDir) {
65293
65829
  const sanitized = name.replace(/[^a-zA-Z0-9_-]/g, "");
65294
- const projPath = join69(projectProfileDir(projectDir), `${sanitized}.json`);
65295
- const globPath = join69(globalProfileDir(), `${sanitized}.json`);
65296
- const filePath = existsSync52(projPath) ? projPath : existsSync52(globPath) ? globPath : null;
65830
+ const projPath = join70(projectProfileDir(projectDir), `${sanitized}.json`);
65831
+ const globPath = join70(globalProfileDir(), `${sanitized}.json`);
65832
+ const filePath = existsSync53(projPath) ? projPath : existsSync53(globPath) ? globPath : null;
65297
65833
  if (!filePath)
65298
65834
  return null;
65299
- const raw = JSON.parse(readFileSync41(filePath, "utf8"));
65835
+ const raw = JSON.parse(readFileSync42(filePath, "utf8"));
65300
65836
  if (raw.encrypted === true) {
65301
65837
  if (!password)
65302
65838
  return null;
@@ -65306,9 +65842,9 @@ function loadProfile(name, password, projectDir) {
65306
65842
  }
65307
65843
  function saveProfile(profile, password, scope = "global", projectDir) {
65308
65844
  const dir = scope === "project" ? projectProfileDir(projectDir) : globalProfileDir();
65309
- mkdirSync26(dir, { recursive: true });
65845
+ mkdirSync27(dir, { recursive: true });
65310
65846
  const sanitized = profile.name.replace(/[^a-zA-Z0-9_-]/g, "");
65311
- const filePath = join69(dir, `${sanitized}.json`);
65847
+ const filePath = join70(dir, `${sanitized}.json`);
65312
65848
  profile.modified = (/* @__PURE__ */ new Date()).toISOString();
65313
65849
  if (password) {
65314
65850
  const encrypted = encryptProfile(profile, password);
@@ -65321,8 +65857,8 @@ function saveProfile(profile, password, scope = "global", projectDir) {
65321
65857
  function deleteProfile(name, scope = "global", projectDir) {
65322
65858
  const sanitized = name.replace(/[^a-zA-Z0-9_-]/g, "");
65323
65859
  const dir = scope === "project" ? projectProfileDir(projectDir) : globalProfileDir();
65324
- const filePath = join69(dir, `${sanitized}.json`);
65325
- if (existsSync52(filePath)) {
65860
+ const filePath = join70(dir, `${sanitized}.json`);
65861
+ if (existsSync53(filePath)) {
65326
65862
  unlinkSync12(filePath);
65327
65863
  return true;
65328
65864
  }
@@ -65415,22 +65951,22 @@ import * as http from "node:http";
65415
65951
  import * as https from "node:https";
65416
65952
  import { createRequire as createRequire3 } from "node:module";
65417
65953
  import { fileURLToPath as fileURLToPath13 } from "node:url";
65418
- import { dirname as dirname21, join as join70, resolve as resolve31 } from "node:path";
65954
+ import { dirname as dirname21, join as join71, resolve as resolve31 } from "node:path";
65419
65955
  import { spawn as spawn21 } from "node:child_process";
65420
- import { mkdirSync as mkdirSync27, writeFileSync as writeFileSync26, readFileSync as readFileSync42, readdirSync as readdirSync21, existsSync as existsSync53 } from "node:fs";
65421
- import { randomBytes as randomBytes16 } from "node:crypto";
65956
+ import { mkdirSync as mkdirSync28, writeFileSync as writeFileSync26, readFileSync as readFileSync43, readdirSync as readdirSync21, existsSync as existsSync54 } from "node:fs";
65957
+ import { randomBytes as randomBytes16, randomUUID as randomUUID4 } from "node:crypto";
65422
65958
  function getVersion3() {
65423
65959
  try {
65424
65960
  const require2 = createRequire3(import.meta.url);
65425
65961
  const thisDir = dirname21(fileURLToPath13(import.meta.url));
65426
65962
  const candidates = [
65427
- join70(thisDir, "..", "package.json"),
65428
- join70(thisDir, "..", "..", "package.json"),
65429
- join70(thisDir, "..", "..", "..", "package.json")
65963
+ join71(thisDir, "..", "package.json"),
65964
+ join71(thisDir, "..", "..", "package.json"),
65965
+ join71(thisDir, "..", "..", "..", "package.json")
65430
65966
  ];
65431
65967
  for (const pkgPath of candidates) {
65432
65968
  try {
65433
- if (!existsSync53(pkgPath))
65969
+ if (!existsSync54(pkgPath))
65434
65970
  continue;
65435
65971
  const pkg = require2(pkgPath);
65436
65972
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli" || pkg.name === "@open-agents/monorepo") {
@@ -65613,27 +66149,33 @@ function formatMetrics() {
65613
66149
  }
65614
66150
  function jsonResponse(res, status, body) {
65615
66151
  const payload = JSON.stringify(body);
65616
- res.writeHead(status, {
65617
- "Content-Type": "application/json",
65618
- "Access-Control-Allow-Origin": "*",
65619
- "Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
65620
- "Access-Control-Allow-Headers": "Content-Type, Authorization"
65621
- });
66152
+ res.writeHead(status, { "Content-Type": "application/json" });
65622
66153
  res.end(payload);
65623
66154
  }
65624
66155
  function textResponse(res, status, body, contentType = "text/plain") {
65625
- res.writeHead(status, {
65626
- "Content-Type": contentType,
65627
- "Access-Control-Allow-Origin": "*",
65628
- "Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
65629
- "Access-Control-Allow-Headers": "Content-Type, Authorization"
65630
- });
66156
+ res.writeHead(status, { "Content-Type": contentType });
65631
66157
  res.end(body);
65632
66158
  }
65633
- function corsHeaders(res) {
65634
- res.setHeader("Access-Control-Allow-Origin", "*");
66159
+ function isOriginAllowed(origin) {
66160
+ if (!origin)
66161
+ return true;
66162
+ if (_corsOrigins.includes("*"))
66163
+ return true;
66164
+ if (_corsLocalOnly)
66165
+ return /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/.test(origin);
66166
+ return _corsOrigins.some((p) => origin === p || p.includes("*") && new RegExp("^" + p.replace(/\*/g, ".*") + "$").test(origin));
66167
+ }
66168
+ function corsHeaders(req, res) {
66169
+ const origin = req.headers["origin"];
66170
+ if (!isOriginAllowed(origin)) {
66171
+ res.writeHead(403, { "Content-Type": "application/json" });
66172
+ res.end(JSON.stringify({ error: "Forbidden", message: `Origin '${origin}' not allowed. Set OA_CORS_ORIGINS to allow.` }));
66173
+ return false;
66174
+ }
66175
+ res.setHeader("Access-Control-Allow-Origin", origin || "*");
65635
66176
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
65636
- res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
66177
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Request-ID, X-Working-Directory, X-Tool-Profile, X-Profile-Password");
66178
+ return true;
65637
66179
  }
65638
66180
  function readBody(req) {
65639
66181
  return new Promise((resolve36, reject) => {
@@ -65725,29 +66267,29 @@ function ollamaStream(ollamaUrl, path, method, body, onData, onEnd, onError) {
65725
66267
  }
65726
66268
  function jobsDir() {
65727
66269
  const root = resolve31(process.cwd());
65728
- const dir = join70(root, ".oa", "jobs");
65729
- mkdirSync27(dir, { recursive: true });
66270
+ const dir = join71(root, ".oa", "jobs");
66271
+ mkdirSync28(dir, { recursive: true });
65730
66272
  return dir;
65731
66273
  }
65732
66274
  function loadJob(id) {
65733
- const file = join70(jobsDir(), `${id}.json`);
65734
- if (!existsSync53(file))
66275
+ const file = join71(jobsDir(), `${id}.json`);
66276
+ if (!existsSync54(file))
65735
66277
  return null;
65736
66278
  try {
65737
- return JSON.parse(readFileSync42(file, "utf-8"));
66279
+ return JSON.parse(readFileSync43(file, "utf-8"));
65738
66280
  } catch {
65739
66281
  return null;
65740
66282
  }
65741
66283
  }
65742
66284
  function listJobs() {
65743
66285
  const dir = jobsDir();
65744
- if (!existsSync53(dir))
66286
+ if (!existsSync54(dir))
65745
66287
  return [];
65746
66288
  const files = readdirSync21(dir).filter((f) => f.endsWith(".json")).sort();
65747
66289
  const jobs = [];
65748
66290
  for (const file of files) {
65749
66291
  try {
65750
- jobs.push(JSON.parse(readFileSync42(join70(dir, file), "utf-8")));
66292
+ jobs.push(JSON.parse(readFileSync43(join71(dir, file), "utf-8")));
65751
66293
  } catch {
65752
66294
  }
65753
66295
  }
@@ -65874,10 +66416,7 @@ async function handleV1ChatCompletions(req, res, ollamaUrl) {
65874
66416
  res.writeHead(200, {
65875
66417
  "Content-Type": "text/event-stream",
65876
66418
  "Cache-Control": "no-cache",
65877
- "Connection": "keep-alive",
65878
- "Access-Control-Allow-Origin": "*",
65879
- "Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
65880
- "Access-Control-Allow-Headers": "Content-Type, Authorization"
66419
+ "Connection": "keep-alive"
65881
66420
  });
65882
66421
  ollamaStream(targetUrl, "/v1/chat/completions", "POST", payload, (chunk) => {
65883
66422
  res.write(chunk);
@@ -65923,10 +66462,7 @@ async function handleV1ChatCompletions(req, res, ollamaUrl) {
65923
66462
  res.writeHead(200, {
65924
66463
  "Content-Type": "text/event-stream",
65925
66464
  "Cache-Control": "no-cache",
65926
- "Connection": "keep-alive",
65927
- "Access-Control-Allow-Origin": "*",
65928
- "Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
65929
- "Access-Control-Allow-Headers": "Content-Type, Authorization"
66465
+ "Connection": "keep-alive"
65930
66466
  });
65931
66467
  const chatId = `chatcmpl-${randomBytes16(12).toString("hex")}`;
65932
66468
  let buffer = "";
@@ -66140,8 +66676,8 @@ async function handleV1Run(req, res) {
66140
66676
  if (workingDir) {
66141
66677
  cwd4 = resolve31(workingDir);
66142
66678
  } else if (isolate) {
66143
- const wsDir = join70(dir, "..", "workspaces", id);
66144
- mkdirSync27(wsDir, { recursive: true });
66679
+ const wsDir = join71(dir, "..", "workspaces", id);
66680
+ mkdirSync28(wsDir, { recursive: true });
66145
66681
  cwd4 = wsDir;
66146
66682
  } else {
66147
66683
  cwd4 = resolve31(process.cwd());
@@ -66213,16 +66749,13 @@ async function handleV1Run(req, res) {
66213
66749
  });
66214
66750
  child.unref();
66215
66751
  job.pid = child.pid ?? 0;
66216
- writeFileSync26(join70(dir, `${id}.json`), JSON.stringify(job, null, 2));
66752
+ writeFileSync26(join71(dir, `${id}.json`), JSON.stringify(job, null, 2));
66217
66753
  runningProcesses.set(id, child);
66218
66754
  if (streamMode) {
66219
66755
  res.writeHead(200, {
66220
66756
  "Content-Type": "text/event-stream",
66221
66757
  "Cache-Control": "no-cache",
66222
- "Connection": "keep-alive",
66223
- "Access-Control-Allow-Origin": "*",
66224
- "Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
66225
- "Access-Control-Allow-Headers": "Content-Type, Authorization"
66758
+ "Connection": "keep-alive"
66226
66759
  });
66227
66760
  res.write(`data: ${JSON.stringify({ type: "run_started", run_id: id, pid: job.pid })}
66228
66761
 
@@ -66243,7 +66776,7 @@ async function handleV1Run(req, res) {
66243
66776
  job.status = code === 0 ? "completed" : "failed";
66244
66777
  job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
66245
66778
  try {
66246
- writeFileSync26(join70(dir, `${id}.json`), JSON.stringify(job, null, 2));
66779
+ writeFileSync26(join71(dir, `${id}.json`), JSON.stringify(job, null, 2));
66247
66780
  } catch {
66248
66781
  }
66249
66782
  runningProcesses.delete(id);
@@ -66274,7 +66807,7 @@ async function handleV1Run(req, res) {
66274
66807
  job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
66275
66808
  }
66276
66809
  try {
66277
- writeFileSync26(join70(dir, `${id}.json`), JSON.stringify(job, null, 2));
66810
+ writeFileSync26(join71(dir, `${id}.json`), JSON.stringify(job, null, 2));
66278
66811
  } catch {
66279
66812
  }
66280
66813
  runningProcesses.delete(id);
@@ -66315,7 +66848,7 @@ function handleV1RunsDelete(res, id) {
66315
66848
  job.error = "Aborted via API";
66316
66849
  const dir = jobsDir();
66317
66850
  try {
66318
- writeFileSync26(join70(dir, `${id}.json`), JSON.stringify(job, null, 2));
66851
+ writeFileSync26(join71(dir, `${id}.json`), JSON.stringify(job, null, 2));
66319
66852
  } catch {
66320
66853
  }
66321
66854
  runningProcesses.delete(id);
@@ -66459,17 +66992,23 @@ async function handleRequest(req, res, ollamaUrl, verbose) {
66459
66992
  const method = req.method ?? "GET";
66460
66993
  const urlObj = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
66461
66994
  const pathname = urlObj.pathname;
66995
+ const startMs = performance.now();
66996
+ const requestId = req.headers["x-request-id"] || randomUUID4();
66997
+ res.setHeader("X-Request-ID", requestId);
66462
66998
  if (verbose) {
66463
66999
  const ts = (/* @__PURE__ */ new Date()).toISOString().split("T")[1]?.slice(0, 8) ?? "";
66464
- process.stderr.write(`[${ts}] ${method} ${pathname}
67000
+ process.stderr.write(`[${ts}] ${requestId.slice(0, 8)} ${method} ${pathname}
66465
67001
  `);
66466
67002
  }
66467
67003
  if (method === "OPTIONS") {
66468
- corsHeaders(res);
67004
+ if (!corsHeaders(req, res))
67005
+ return;
66469
67006
  res.writeHead(204);
66470
67007
  res.end();
66471
67008
  return;
66472
67009
  }
67010
+ if (!corsHeaders(req, res))
67011
+ return;
66473
67012
  let status = 200;
66474
67013
  try {
66475
67014
  if (pathname === "/health" && method === "GET") {
@@ -66492,6 +67031,11 @@ async function handleRequest(req, res, ollamaUrl, verbose) {
66492
67031
  handleMetrics(res);
66493
67032
  return;
66494
67033
  }
67034
+ if (pathname === "/" && method === "GET" && req.headers.accept?.includes("text/html")) {
67035
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
67036
+ res.end(getWebUI());
67037
+ return;
67038
+ }
66495
67039
  if (pathname.startsWith("/v1/")) {
66496
67040
  const isWrite = method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE";
66497
67041
  const isRun = pathname === "/v1/run" || pathname.startsWith("/v1/runs");
@@ -66650,6 +67194,15 @@ async function handleRequest(req, res, ollamaUrl, verbose) {
66650
67194
  jsonResponse(res, deleted ? 200 : 404, deleted ? { status: "deleted", name } : { error: "Profile not found", name });
66651
67195
  return;
66652
67196
  }
67197
+ if (pathname === "/v1/audit" && method === "GET") {
67198
+ if (!checkAuth(req, res, "read"))
67199
+ return;
67200
+ const since = urlObj.searchParams.get("since") ?? void 0;
67201
+ const user = urlObj.searchParams.get("user") ?? void 0;
67202
+ const limit = parseInt(urlObj.searchParams.get("limit") ?? "100", 10);
67203
+ jsonResponse(res, 200, { records: queryAudit({ since, user, limit }) });
67204
+ return;
67205
+ }
66653
67206
  status = 404;
66654
67207
  jsonResponse(res, 404, { error: "Not found", path: pathname });
66655
67208
  } catch (err) {
@@ -66661,6 +67214,17 @@ async function handleRequest(req, res, ollamaUrl, verbose) {
66661
67214
  });
66662
67215
  } finally {
66663
67216
  recordMetric(method, pathname, status);
67217
+ recordAudit({
67218
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
67219
+ requestId,
67220
+ method,
67221
+ path: pathname,
67222
+ status,
67223
+ user: req._authUser ?? "anonymous",
67224
+ scope: req._authScope ?? "none",
67225
+ latencyMs: Math.round(performance.now() - startMs),
67226
+ ip: req.socket?.remoteAddress ?? ""
67227
+ });
66664
67228
  }
66665
67229
  }
66666
67230
  function startApiServer(options = {}) {
@@ -66687,6 +67251,8 @@ function startApiServer(options = {}) {
66687
67251
  const verbose = options.verbose ?? false;
66688
67252
  const config = loadConfig();
66689
67253
  const ollamaUrl = options.ollamaUrl ?? config.backendUrl;
67254
+ const cwd4 = process.cwd();
67255
+ initAuditLog(join71(cwd4, ".oa"));
66690
67256
  const server = http.createServer((req, res) => {
66691
67257
  handleRequest(req, res, ollamaUrl, verbose).catch((err) => {
66692
67258
  metrics.totalErrors++;
@@ -66816,11 +67382,13 @@ async function apiServeCommand(opts, config) {
66816
67382
  server.on("close", resolve36);
66817
67383
  });
66818
67384
  }
66819
- var endpointRegistry, modelRouteMap, endpointUsage, metrics, startedAt, runningProcesses;
67385
+ var endpointRegistry, modelRouteMap, endpointUsage, metrics, startedAt, _corsOrigins, _corsLocalOnly, runningProcesses;
66820
67386
  var init_serve = __esm({
66821
67387
  "packages/cli/dist/api/serve.js"() {
66822
67388
  "use strict";
66823
67389
  init_config();
67390
+ init_audit_log();
67391
+ init_web_ui();
66824
67392
  init_oa_directory();
66825
67393
  init_render();
66826
67394
  init_profiles();
@@ -66834,17 +67402,19 @@ var init_serve = __esm({
66834
67402
  totalErrors: 0
66835
67403
  };
66836
67404
  startedAt = Date.now();
67405
+ _corsOrigins = (process.env["OA_CORS_ORIGINS"] || "").split(",").filter(Boolean);
67406
+ _corsLocalOnly = _corsOrigins.length === 0;
66837
67407
  runningProcesses = /* @__PURE__ */ new Map();
66838
67408
  }
66839
67409
  });
66840
67410
 
66841
67411
  // packages/cli/dist/tui/interactive.js
66842
67412
  import { cwd } from "node:process";
66843
- import { resolve as resolve32, join as join71, dirname as dirname22, extname as extname11 } from "node:path";
67413
+ import { resolve as resolve32, join as join72, dirname as dirname22, extname as extname11 } from "node:path";
66844
67414
  import { createRequire as createRequire4 } from "node:module";
66845
67415
  import { fileURLToPath as fileURLToPath14 } from "node:url";
66846
- import { readFileSync as readFileSync43, writeFileSync as writeFileSync27, appendFileSync as appendFileSync4, rmSync as rmSync3, readdirSync as readdirSync22, mkdirSync as mkdirSync28 } from "node:fs";
66847
- import { existsSync as existsSync54 } from "node:fs";
67416
+ import { readFileSync as readFileSync44, writeFileSync as writeFileSync27, appendFileSync as appendFileSync5, rmSync as rmSync3, readdirSync as readdirSync22, mkdirSync as mkdirSync29 } from "node:fs";
67417
+ import { existsSync as existsSync55 } from "node:fs";
66848
67418
  import { execSync as execSync35 } from "node:child_process";
66849
67419
  import { homedir as homedir19 } from "node:os";
66850
67420
  function formatTimeAgo(date) {
@@ -66865,12 +67435,12 @@ function getVersion4() {
66865
67435
  const require2 = createRequire4(import.meta.url);
66866
67436
  const thisDir = dirname22(fileURLToPath14(import.meta.url));
66867
67437
  const candidates = [
66868
- join71(thisDir, "..", "package.json"),
66869
- join71(thisDir, "..", "..", "package.json"),
66870
- join71(thisDir, "..", "..", "..", "package.json")
67438
+ join72(thisDir, "..", "package.json"),
67439
+ join72(thisDir, "..", "..", "package.json"),
67440
+ join72(thisDir, "..", "..", "..", "package.json")
66871
67441
  ];
66872
67442
  for (const pkgPath of candidates) {
66873
- if (existsSync54(pkgPath)) {
67443
+ if (existsSync55(pkgPath)) {
66874
67444
  const pkg = require2(pkgPath);
66875
67445
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli" || pkg.name === "@open-agents/monorepo") {
66876
67446
  return pkg.version ?? "0.0.0";
@@ -67109,15 +67679,15 @@ Use task_status("${taskId}") or task_output("${taskId}") to check progress.`
67109
67679
  function gatherMemorySnippets(root) {
67110
67680
  const snippets = [];
67111
67681
  const dirs = [
67112
- join71(root, ".oa", "memory"),
67113
- join71(root, ".open-agents", "memory")
67682
+ join72(root, ".oa", "memory"),
67683
+ join72(root, ".open-agents", "memory")
67114
67684
  ];
67115
67685
  for (const dir of dirs) {
67116
- if (!existsSync54(dir))
67686
+ if (!existsSync55(dir))
67117
67687
  continue;
67118
67688
  try {
67119
67689
  for (const f of readdirSync22(dir).filter((f2) => f2.endsWith(".json"))) {
67120
- const data = JSON.parse(readFileSync43(join71(dir, f), "utf-8"));
67690
+ const data = JSON.parse(readFileSync44(join72(dir, f), "utf-8"));
67121
67691
  for (const val of Object.values(data)) {
67122
67692
  const v = typeof val === "object" && val !== null && "value" in val ? String(val.value) : String(val);
67123
67693
  if (v.length > 10)
@@ -67274,9 +67844,9 @@ ${metabolismMemories}
67274
67844
  } catch {
67275
67845
  }
67276
67846
  try {
67277
- const archeFile = join71(repoRoot, ".oa", "arche", "variants.json");
67278
- if (existsSync54(archeFile)) {
67279
- const variants = JSON.parse(readFileSync43(archeFile, "utf8"));
67847
+ const archeFile = join72(repoRoot, ".oa", "arche", "variants.json");
67848
+ if (existsSync55(archeFile)) {
67849
+ const variants = JSON.parse(readFileSync44(archeFile, "utf8"));
67280
67850
  if (variants.length > 0) {
67281
67851
  let filtered = variants;
67282
67852
  if (taskType) {
@@ -67445,9 +68015,9 @@ RULES:
67445
68015
  const compactionThreshold = modelTier === "small" ? 12e3 : modelTier === "medium" ? 24e3 : 4e4;
67446
68016
  let identityInjection = "";
67447
68017
  try {
67448
- const ikStateFile = join71(repoRoot, ".oa", "identity", "self-state.json");
67449
- if (existsSync54(ikStateFile)) {
67450
- const selfState = JSON.parse(readFileSync43(ikStateFile, "utf8"));
68018
+ const ikStateFile = join72(repoRoot, ".oa", "identity", "self-state.json");
68019
+ if (existsSync55(ikStateFile)) {
68020
+ const selfState = JSON.parse(readFileSync44(ikStateFile, "utf8"));
67451
68021
  const lines = [
67452
68022
  `[Identity State v${selfState.version}]`,
67453
68023
  `Self: ${selfState.narrative_summary}`,
@@ -68091,13 +68661,13 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
68091
68661
  });
68092
68662
  }
68093
68663
  try {
68094
- const ikDir = join71(repoRoot, ".oa", "identity");
68095
- const ikFile = join71(ikDir, "self-state.json");
68664
+ const ikDir = join72(repoRoot, ".oa", "identity");
68665
+ const ikFile = join72(ikDir, "self-state.json");
68096
68666
  let ikState;
68097
- if (existsSync54(ikFile)) {
68098
- ikState = JSON.parse(readFileSync43(ikFile, "utf8"));
68667
+ if (existsSync55(ikFile)) {
68668
+ ikState = JSON.parse(readFileSync44(ikFile, "utf8"));
68099
68669
  } else {
68100
- mkdirSync28(ikDir, { recursive: true });
68670
+ mkdirSync29(ikDir, { recursive: true });
68101
68671
  const machineId = Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
68102
68672
  ikState = {
68103
68673
  self_id: `oa-${machineId}`,
@@ -68138,9 +68708,9 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
68138
68708
  } else {
68139
68709
  renderTaskIncomplete(result.turns, result.toolCalls, result.durationMs, tokens);
68140
68710
  try {
68141
- const ikFile = join71(repoRoot, ".oa", "identity", "self-state.json");
68142
- if (existsSync54(ikFile)) {
68143
- const ikState = JSON.parse(readFileSync43(ikFile, "utf8"));
68711
+ const ikFile = join72(repoRoot, ".oa", "identity", "self-state.json");
68712
+ if (existsSync55(ikFile)) {
68713
+ const ikState = JSON.parse(readFileSync44(ikFile, "utf8"));
68144
68714
  ikState.homeostasis.uncertainty = Math.min(1, ikState.homeostasis.uncertainty + 0.1);
68145
68715
  ikState.homeostasis.coherence = Math.max(0, ikState.homeostasis.coherence - 0.05);
68146
68716
  ikState.session_count = (ikState.session_count || 0) + 1;
@@ -68242,10 +68812,10 @@ async function startInteractive(config, repoPath) {
68242
68812
  process.stdin.pause();
68243
68813
  }
68244
68814
  try {
68245
- const oaDir = join71(repoRoot, ".oa");
68246
- const nexusPidFile = join71(oaDir, "nexus", "daemon.pid");
68247
- if (existsSync54(nexusPidFile)) {
68248
- const pid = parseInt(readFileSync43(nexusPidFile, "utf8").trim(), 10);
68815
+ const oaDir = join72(repoRoot, ".oa");
68816
+ const nexusPidFile = join72(oaDir, "nexus", "daemon.pid");
68817
+ if (existsSync55(nexusPidFile)) {
68818
+ const pid = parseInt(readFileSync44(nexusPidFile, "utf8").trim(), 10);
68249
68819
  if (pid > 0) {
68250
68820
  try {
68251
68821
  process.kill(pid, 0);
@@ -68582,7 +69152,7 @@ Review its full output in the [${id}] tab or via full_sub_agent(action='output',
68582
69152
  let p2pGateway = null;
68583
69153
  let peerMesh = null;
68584
69154
  let inferenceRouter = null;
68585
- const secretVault = new SecretVault(join71(repoRoot, ".oa", "vault.enc"));
69155
+ const secretVault = new SecretVault(join72(repoRoot, ".oa", "vault.enc"));
68586
69156
  let adminSessionKey = null;
68587
69157
  const callSubAgents = /* @__PURE__ */ new Map();
68588
69158
  const streamRenderer = new StreamRenderer();
@@ -68805,13 +69375,13 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
68805
69375
  const hits = allCompletions.filter((c3) => c3.toLowerCase().startsWith(lower));
68806
69376
  return [hits, line];
68807
69377
  }
68808
- const HISTORY_DIR = join71(homedir19(), ".open-agents");
68809
- const HISTORY_FILE = join71(HISTORY_DIR, "repl-history");
69378
+ const HISTORY_DIR = join72(homedir19(), ".open-agents");
69379
+ const HISTORY_FILE = join72(HISTORY_DIR, "repl-history");
68810
69380
  const MAX_HISTORY_LINES = 500;
68811
69381
  let savedHistory = [];
68812
69382
  try {
68813
- if (existsSync54(HISTORY_FILE)) {
68814
- const raw = readFileSync43(HISTORY_FILE, "utf8").trim();
69383
+ if (existsSync55(HISTORY_FILE)) {
69384
+ const raw = readFileSync44(HISTORY_FILE, "utf8").trim();
68815
69385
  if (raw)
68816
69386
  savedHistory = raw.split("\n").reverse();
68817
69387
  }
@@ -68914,10 +69484,10 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
68914
69484
  if (!line.trim())
68915
69485
  return;
68916
69486
  try {
68917
- mkdirSync28(HISTORY_DIR, { recursive: true });
68918
- appendFileSync4(HISTORY_FILE, line + "\n", "utf8");
69487
+ mkdirSync29(HISTORY_DIR, { recursive: true });
69488
+ appendFileSync5(HISTORY_FILE, line + "\n", "utf8");
68919
69489
  if (Math.random() < 0.02) {
68920
- const all = readFileSync43(HISTORY_FILE, "utf8").trim().split("\n");
69490
+ const all = readFileSync44(HISTORY_FILE, "utf8").trim().split("\n");
68921
69491
  if (all.length > MAX_HISTORY_LINES) {
68922
69492
  writeFileSync27(HISTORY_FILE, all.slice(-MAX_HISTORY_LINES).join("\n") + "\n", "utf8");
68923
69493
  }
@@ -69103,7 +69673,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
69103
69673
  } catch {
69104
69674
  }
69105
69675
  try {
69106
- const oaDir = join71(repoRoot, ".oa");
69676
+ const oaDir = join72(repoRoot, ".oa");
69107
69677
  const reconnected = await ExposeGateway.checkAndReconnect(oaDir, {
69108
69678
  onInfo: (msg) => writeContent(() => renderInfo(msg)),
69109
69679
  onError: (msg) => writeContent(() => renderWarning(msg))
@@ -69135,7 +69705,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
69135
69705
  } catch {
69136
69706
  }
69137
69707
  try {
69138
- const oaDir = join71(repoRoot, ".oa");
69708
+ const oaDir = join72(repoRoot, ".oa");
69139
69709
  const reconnectedP2P = await ExposeP2PGateway.checkAndReconnect(oaDir, new NexusTool(repoRoot), {
69140
69710
  onInfo: (msg) => writeContent(() => renderInfo(msg)),
69141
69711
  onError: (msg) => writeContent(() => renderWarning(msg))
@@ -69176,11 +69746,11 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
69176
69746
  }
69177
69747
  try {
69178
69748
  const { homedir: _hd, hostname: _hn, userInfo: _ui } = await import("node:os");
69179
- const globalNamePath = join71(_hd(), ".open-agents", "agent-name");
69749
+ const globalNamePath = join72(_hd(), ".open-agents", "agent-name");
69180
69750
  let agName = "";
69181
69751
  try {
69182
- if (existsSync54(globalNamePath))
69183
- agName = readFileSync43(globalNamePath, "utf8").trim();
69752
+ if (existsSync55(globalNamePath))
69753
+ agName = readFileSync44(globalNamePath, "utf8").trim();
69184
69754
  } catch {
69185
69755
  }
69186
69756
  if (!agName) {
@@ -70156,7 +70726,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
70156
70726
  kind,
70157
70727
  targetUrl,
70158
70728
  authKey,
70159
- stateDir: join71(repoRoot, ".oa"),
70729
+ stateDir: join72(repoRoot, ".oa"),
70160
70730
  passthrough: passthrough ?? false,
70161
70731
  loadbalance: loadbalance ?? false,
70162
70732
  endpointAuth: passthrough ? currentConfig.apiKey : void 0,
@@ -70202,7 +70772,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
70202
70772
  await tunnelGateway.stop();
70203
70773
  tunnelGateway = null;
70204
70774
  }
70205
- const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir: join71(repoRoot, ".oa") });
70775
+ const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir: join72(repoRoot, ".oa") });
70206
70776
  newTunnel.on("stats", (stats) => {
70207
70777
  statusBar.setExposeStatus({
70208
70778
  status: stats.status,
@@ -70291,9 +70861,9 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
70291
70861
  if (!result.success)
70292
70862
  throw new Error(result.error || "Connect failed");
70293
70863
  try {
70294
- const nexusPidFile = join71(repoRoot, ".oa", "nexus", "daemon.pid");
70295
- if (existsSync54(nexusPidFile)) {
70296
- const pid = parseInt(readFileSync43(nexusPidFile, "utf8").trim(), 10);
70864
+ const nexusPidFile = join72(repoRoot, ".oa", "nexus", "daemon.pid");
70865
+ if (existsSync55(nexusPidFile)) {
70866
+ const pid = parseInt(readFileSync44(nexusPidFile, "utf8").trim(), 10);
70297
70867
  if (pid > 0) {
70298
70868
  registry.register({
70299
70869
  name: "Nexus",
@@ -70489,10 +71059,10 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
70489
71059
  writeContent(() => renderInfo(`Killed ${bgKilled} background task(s).`));
70490
71060
  }
70491
71061
  try {
70492
- const nexusDir = join71(repoRoot, OA_DIR, "nexus");
70493
- const pidFile = join71(nexusDir, "daemon.pid");
70494
- if (existsSync54(pidFile)) {
70495
- const pid = parseInt(readFileSync43(pidFile, "utf8").trim(), 10);
71062
+ const nexusDir = join72(repoRoot, OA_DIR, "nexus");
71063
+ const pidFile = join72(nexusDir, "daemon.pid");
71064
+ if (existsSync55(pidFile)) {
71065
+ const pid = parseInt(readFileSync44(pidFile, "utf8").trim(), 10);
70496
71066
  if (pid > 0) {
70497
71067
  try {
70498
71068
  if (process.platform === "win32") {
@@ -70514,13 +71084,13 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
70514
71084
  } catch {
70515
71085
  }
70516
71086
  try {
70517
- const voiceDir2 = join71(homedir19(), ".open-agents", "voice");
71087
+ const voiceDir2 = join72(homedir19(), ".open-agents", "voice");
70518
71088
  const voicePidFiles = ["luxtts-daemon.pid", "piper-daemon.pid"];
70519
71089
  for (const pf of voicePidFiles) {
70520
- const pidPath = join71(voiceDir2, pf);
70521
- if (existsSync54(pidPath)) {
71090
+ const pidPath = join72(voiceDir2, pf);
71091
+ if (existsSync55(pidPath)) {
70522
71092
  try {
70523
- const pid = parseInt(readFileSync43(pidPath, "utf8").trim(), 10);
71093
+ const pid = parseInt(readFileSync44(pidPath, "utf8").trim(), 10);
70524
71094
  if (pid > 0) {
70525
71095
  if (process.platform === "win32") {
70526
71096
  try {
@@ -70544,8 +71114,8 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
70544
71114
  execSync35(process.platform === "win32" ? "timeout /t 1 /nobreak >nul" : "sleep 0.5", { timeout: 3e3, stdio: "ignore" });
70545
71115
  } catch {
70546
71116
  }
70547
- const oaPath = join71(repoRoot, OA_DIR);
70548
- if (existsSync54(oaPath)) {
71117
+ const oaPath = join72(repoRoot, OA_DIR);
71118
+ if (existsSync55(oaPath)) {
70549
71119
  let deleted = false;
70550
71120
  for (let attempt = 0; attempt < 3; attempt++) {
70551
71121
  try {
@@ -70628,19 +71198,19 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
70628
71198
  try {
70629
71199
  const { isPersonaPlexRunning: isPersonaPlexRunning2 } = await Promise.resolve().then(() => (init_personaplex(), personaplex_exports));
70630
71200
  if (isPersonaPlexRunning2()) {
70631
- const ppPidFile = join71(homedir19(), ".open-agents", "voice", "personaplex", "daemon.pid");
70632
- const ppPortFile = join71(homedir19(), ".open-agents", "voice", "personaplex", "daemon.port");
70633
- if (existsSync54(ppPidFile)) {
70634
- const ppPid = parseInt(readFileSync43(ppPidFile, "utf8").trim(), 10);
70635
- const ppPort = existsSync54(ppPortFile) ? parseInt(readFileSync43(ppPortFile, "utf8").trim(), 10) : void 0;
71201
+ const ppPidFile = join72(homedir19(), ".open-agents", "voice", "personaplex", "daemon.pid");
71202
+ const ppPortFile = join72(homedir19(), ".open-agents", "voice", "personaplex", "daemon.port");
71203
+ if (existsSync55(ppPidFile)) {
71204
+ const ppPid = parseInt(readFileSync44(ppPidFile, "utf8").trim(), 10);
71205
+ const ppPort = existsSync55(ppPortFile) ? parseInt(readFileSync44(ppPortFile, "utf8").trim(), 10) : void 0;
70636
71206
  if (ppPid > 0 && !registry.daemons.has("PersonaPlex")) {
70637
71207
  registry.register({ name: "PersonaPlex", pid: ppPid, port: ppPort, startedAt: Date.now(), status: "running" });
70638
71208
  }
70639
71209
  }
70640
71210
  }
70641
- const nexusPidFile = join71(repoRoot, ".oa", "nexus", "daemon.pid");
70642
- if (existsSync54(nexusPidFile)) {
70643
- const nPid = parseInt(readFileSync43(nexusPidFile, "utf8").trim(), 10);
71211
+ const nexusPidFile = join72(repoRoot, ".oa", "nexus", "daemon.pid");
71212
+ if (existsSync55(nexusPidFile)) {
71213
+ const nPid = parseInt(readFileSync44(nexusPidFile, "utf8").trim(), 10);
70644
71214
  if (nPid > 0 && !registry.daemons.has("Nexus")) {
70645
71215
  try {
70646
71216
  process.kill(nPid, 0);
@@ -70982,8 +71552,8 @@ Execute this skill now. Follow the behavioral guidance above.`;
70982
71552
  }
70983
71553
  }
70984
71554
  const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
70985
- const isImage = isImagePath(cleanPath) && existsSync54(resolve32(repoRoot, cleanPath));
70986
- const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync54(resolve32(repoRoot, cleanPath));
71555
+ const isImage = isImagePath(cleanPath) && existsSync55(resolve32(repoRoot, cleanPath));
71556
+ const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync55(resolve32(repoRoot, cleanPath));
70987
71557
  if (activeTask) {
70988
71558
  if (activeTask.runner.isPaused) {
70989
71559
  activeTask.runner.resume();
@@ -70992,7 +71562,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
70992
71562
  if (isImage) {
70993
71563
  try {
70994
71564
  const imgPath = resolve32(repoRoot, cleanPath);
70995
- const imgBuffer = readFileSync43(imgPath);
71565
+ const imgBuffer = readFileSync44(imgPath);
70996
71566
  const base64 = imgBuffer.toString("base64");
70997
71567
  const ext = extname11(cleanPath).toLowerCase();
70998
71568
  const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/jpeg";
@@ -71207,7 +71777,7 @@ Summarize or analyze this transcription as appropriate.`;
71207
71777
 
71208
71778
  NEW TASK: ${fullInput}`;
71209
71779
  restoredSessionContext = null;
71210
- } else if (existsSync54(join71(repoRoot, ".oa", "context", "session-diary.md"))) {
71780
+ } else if (existsSync55(join72(repoRoot, ".oa", "context", "session-diary.md"))) {
71211
71781
  taskInput = `[Previous sessions exist \u2014 file_read(".oa/context/session-diary.md") to recall]
71212
71782
 
71213
71783
  ${fullInput}`;
@@ -71524,13 +72094,13 @@ async function runWithTUI(task, config, repoPath) {
71524
72094
  const handle = startTask(task, config, repoRoot);
71525
72095
  await handle.promise;
71526
72096
  try {
71527
- const ikDir = join71(repoRoot, ".oa", "identity");
71528
- const ikFile = join71(ikDir, "self-state.json");
72097
+ const ikDir = join72(repoRoot, ".oa", "identity");
72098
+ const ikFile = join72(ikDir, "self-state.json");
71529
72099
  let ikState;
71530
- if (existsSync54(ikFile)) {
71531
- ikState = JSON.parse(readFileSync43(ikFile, "utf8"));
72100
+ if (existsSync55(ikFile)) {
72101
+ ikState = JSON.parse(readFileSync44(ikFile, "utf8"));
71532
72102
  } else {
71533
- mkdirSync28(ikDir, { recursive: true });
72103
+ mkdirSync29(ikDir, { recursive: true });
71534
72104
  ikState = {
71535
72105
  self_id: `oa-${Date.now().toString(36)}`,
71536
72106
  version: 1,
@@ -71561,12 +72131,12 @@ async function runWithTUI(task, config, repoPath) {
71561
72131
  ec.archiveVariantSync(`Task: ${task.slice(0, 200)}`, "success \u2014 completed", ["general"]);
71562
72132
  } catch {
71563
72133
  try {
71564
- const archeDir = join71(repoRoot, ".oa", "arche");
71565
- const archeFile = join71(archeDir, "variants.json");
72134
+ const archeDir = join72(repoRoot, ".oa", "arche");
72135
+ const archeFile = join72(archeDir, "variants.json");
71566
72136
  let variants = [];
71567
72137
  try {
71568
- if (existsSync54(archeFile))
71569
- variants = JSON.parse(readFileSync43(archeFile, "utf8"));
72138
+ if (existsSync55(archeFile))
72139
+ variants = JSON.parse(readFileSync44(archeFile, "utf8"));
71570
72140
  } catch {
71571
72141
  }
71572
72142
  variants.push({
@@ -71581,15 +72151,15 @@ async function runWithTUI(task, config, repoPath) {
71581
72151
  });
71582
72152
  if (variants.length > 50)
71583
72153
  variants = variants.slice(-50);
71584
- mkdirSync28(archeDir, { recursive: true });
72154
+ mkdirSync29(archeDir, { recursive: true });
71585
72155
  writeFileSync27(archeFile, JSON.stringify(variants, null, 2));
71586
72156
  } catch {
71587
72157
  }
71588
72158
  }
71589
72159
  try {
71590
- const metaFile = join71(repoRoot, ".oa", "memory", "metabolism", "store.json");
71591
- if (existsSync54(metaFile)) {
71592
- const store = JSON.parse(readFileSync43(metaFile, "utf8"));
72160
+ const metaFile = join72(repoRoot, ".oa", "memory", "metabolism", "store.json");
72161
+ if (existsSync55(metaFile)) {
72162
+ const store = JSON.parse(readFileSync44(metaFile, "utf8"));
71593
72163
  const surfaced = store.filter((m) => m.type !== "quarantine" && m.scores?.confidence > 0.15).sort((a, b) => b.scores.utility * b.scores.confidence - a.scores.utility * a.scores.confidence).slice(0, 5);
71594
72164
  let updated = false;
71595
72165
  for (const item of surfaced) {
@@ -71653,9 +72223,9 @@ Rules:
71653
72223
  try {
71654
72224
  const { initDb: initDb2 } = __require("@open-agents/memory");
71655
72225
  const { ProceduralMemoryStore: ProceduralMemoryStore2 } = __require("@open-agents/memory");
71656
- const dbDir = join71(repoRoot, ".oa", "memory");
71657
- mkdirSync28(dbDir, { recursive: true });
71658
- const db = initDb2(join71(dbDir, "structured.db"));
72226
+ const dbDir = join72(repoRoot, ".oa", "memory");
72227
+ mkdirSync29(dbDir, { recursive: true });
72228
+ const db = initDb2(join72(dbDir, "structured.db"));
71659
72229
  const memStore = new ProceduralMemoryStore2(db);
71660
72230
  memStore.createWithEmbedding({
71661
72231
  content: content.slice(0, 600),
@@ -71670,12 +72240,12 @@ Rules:
71670
72240
  db.close();
71671
72241
  } catch {
71672
72242
  }
71673
- const metaDir = join71(repoRoot, ".oa", "memory", "metabolism");
71674
- const storeFile = join71(metaDir, "store.json");
72243
+ const metaDir = join72(repoRoot, ".oa", "memory", "metabolism");
72244
+ const storeFile = join72(metaDir, "store.json");
71675
72245
  let store = [];
71676
72246
  try {
71677
- if (existsSync54(storeFile))
71678
- store = JSON.parse(readFileSync43(storeFile, "utf8"));
72247
+ if (existsSync55(storeFile))
72248
+ store = JSON.parse(readFileSync44(storeFile, "utf8"));
71679
72249
  } catch {
71680
72250
  }
71681
72251
  store.push({
@@ -71691,26 +72261,26 @@ Rules:
71691
72261
  });
71692
72262
  if (store.length > 100)
71693
72263
  store = store.slice(-100);
71694
- mkdirSync28(metaDir, { recursive: true });
72264
+ mkdirSync29(metaDir, { recursive: true });
71695
72265
  writeFileSync27(storeFile, JSON.stringify(store, null, 2));
71696
72266
  }
71697
72267
  }
71698
72268
  } catch {
71699
72269
  }
71700
72270
  try {
71701
- const cohereSettingsFile = join71(repoRoot, ".oa", "settings.json");
72271
+ const cohereSettingsFile = join72(repoRoot, ".oa", "settings.json");
71702
72272
  let cohereActive = false;
71703
72273
  try {
71704
- if (existsSync54(cohereSettingsFile)) {
71705
- const settings = JSON.parse(readFileSync43(cohereSettingsFile, "utf8"));
72274
+ if (existsSync55(cohereSettingsFile)) {
72275
+ const settings = JSON.parse(readFileSync44(cohereSettingsFile, "utf8"));
71706
72276
  cohereActive = settings.cohere === true;
71707
72277
  }
71708
72278
  } catch {
71709
72279
  }
71710
72280
  if (cohereActive) {
71711
- const metaFile = join71(repoRoot, ".oa", "memory", "metabolism", "store.json");
71712
- if (existsSync54(metaFile)) {
71713
- const store = JSON.parse(readFileSync43(metaFile, "utf8"));
72281
+ const metaFile = join72(repoRoot, ".oa", "memory", "metabolism", "store.json");
72282
+ if (existsSync55(metaFile)) {
72283
+ const store = JSON.parse(readFileSync44(metaFile, "utf8"));
71714
72284
  const latest = store.filter((m) => m.sourceTrace === "trajectory-extraction" || m.sourceTrace === "llm-trajectory-extraction").slice(-1)[0];
71715
72285
  if (latest && latest.scores?.confidence >= 0.6) {
71716
72286
  try {
@@ -71735,18 +72305,18 @@ Rules:
71735
72305
  }
71736
72306
  } catch (err) {
71737
72307
  try {
71738
- const ikFile = join71(repoRoot, ".oa", "identity", "self-state.json");
71739
- if (existsSync54(ikFile)) {
71740
- const ikState = JSON.parse(readFileSync43(ikFile, "utf8"));
72308
+ const ikFile = join72(repoRoot, ".oa", "identity", "self-state.json");
72309
+ if (existsSync55(ikFile)) {
72310
+ const ikState = JSON.parse(readFileSync44(ikFile, "utf8"));
71741
72311
  ikState.homeostasis.uncertainty = Math.min(1, ikState.homeostasis.uncertainty + 0.1);
71742
72312
  ikState.homeostasis.coherence = Math.max(0, ikState.homeostasis.coherence - 0.05);
71743
72313
  ikState.session_count = (ikState.session_count || 0) + 1;
71744
72314
  ikState.updated_at = (/* @__PURE__ */ new Date()).toISOString();
71745
72315
  writeFileSync27(ikFile, JSON.stringify(ikState, null, 2));
71746
72316
  }
71747
- const metaFile = join71(repoRoot, ".oa", "memory", "metabolism", "store.json");
71748
- if (existsSync54(metaFile)) {
71749
- const store = JSON.parse(readFileSync43(metaFile, "utf8"));
72317
+ const metaFile = join72(repoRoot, ".oa", "memory", "metabolism", "store.json");
72318
+ if (existsSync55(metaFile)) {
72319
+ const store = JSON.parse(readFileSync44(metaFile, "utf8"));
71750
72320
  const surfaced = store.filter((m) => m.type !== "quarantine" && m.scores?.confidence > 0.15).sort((a, b) => b.scores.utility * b.scores.confidence - a.scores.utility * a.scores.confidence).slice(0, 5);
71751
72321
  for (const item of surfaced) {
71752
72322
  item.accessCount = (item.accessCount || 0) + 1;
@@ -71757,12 +72327,12 @@ Rules:
71757
72327
  writeFileSync27(metaFile, JSON.stringify(store, null, 2));
71758
72328
  }
71759
72329
  try {
71760
- const archeDir = join71(repoRoot, ".oa", "arche");
71761
- const archeFile = join71(archeDir, "variants.json");
72330
+ const archeDir = join72(repoRoot, ".oa", "arche");
72331
+ const archeFile = join72(archeDir, "variants.json");
71762
72332
  let variants = [];
71763
72333
  try {
71764
- if (existsSync54(archeFile))
71765
- variants = JSON.parse(readFileSync43(archeFile, "utf8"));
72334
+ if (existsSync55(archeFile))
72335
+ variants = JSON.parse(readFileSync44(archeFile, "utf8"));
71766
72336
  } catch {
71767
72337
  }
71768
72338
  variants.push({
@@ -71777,7 +72347,7 @@ Rules:
71777
72347
  });
71778
72348
  if (variants.length > 50)
71779
72349
  variants = variants.slice(-50);
71780
- mkdirSync28(archeDir, { recursive: true });
72350
+ mkdirSync29(archeDir, { recursive: true });
71781
72351
  writeFileSync27(archeFile, JSON.stringify(variants, null, 2));
71782
72352
  } catch {
71783
72353
  }
@@ -71848,13 +72418,13 @@ __export(run_exports, {
71848
72418
  });
71849
72419
  import { resolve as resolve33 } from "node:path";
71850
72420
  import { spawn as spawn22 } from "node:child_process";
71851
- import { mkdirSync as mkdirSync29, writeFileSync as writeFileSync28, readFileSync as readFileSync44, readdirSync as readdirSync23, existsSync as existsSync55 } from "node:fs";
72421
+ import { mkdirSync as mkdirSync30, writeFileSync as writeFileSync28, readFileSync as readFileSync45, readdirSync as readdirSync23, existsSync as existsSync56 } from "node:fs";
71852
72422
  import { randomBytes as randomBytes17 } from "node:crypto";
71853
- import { join as join72 } from "node:path";
72423
+ import { join as join73 } from "node:path";
71854
72424
  function jobsDir2(repoPath) {
71855
72425
  const root = resolve33(repoPath ?? process.cwd());
71856
- const dir = join72(root, ".oa", "jobs");
71857
- mkdirSync29(dir, { recursive: true });
72426
+ const dir = join73(root, ".oa", "jobs");
72427
+ mkdirSync30(dir, { recursive: true });
71858
72428
  return dir;
71859
72429
  }
71860
72430
  async function runCommand(opts, config) {
@@ -71939,7 +72509,7 @@ async function runBackground(task, config, opts) {
71939
72509
  });
71940
72510
  child.unref();
71941
72511
  job.pid = child.pid ?? 0;
71942
- writeFileSync28(join72(dir, `${id}.json`), JSON.stringify(job, null, 2));
72512
+ writeFileSync28(join73(dir, `${id}.json`), JSON.stringify(job, null, 2));
71943
72513
  let output = "";
71944
72514
  child.stdout?.on("data", (chunk) => {
71945
72515
  output += chunk.toString();
@@ -71955,7 +72525,7 @@ async function runBackground(task, config, opts) {
71955
72525
  job.summary = result.summary;
71956
72526
  job.durationMs = result.durationMs;
71957
72527
  job.error = result.error;
71958
- writeFileSync28(join72(dir, `${id}.json`), JSON.stringify(job, null, 2));
72528
+ writeFileSync28(join73(dir, `${id}.json`), JSON.stringify(job, null, 2));
71959
72529
  } catch {
71960
72530
  }
71961
72531
  });
@@ -71971,13 +72541,13 @@ async function runBackground(task, config, opts) {
71971
72541
  }
71972
72542
  function statusCommand(jobId, repoPath) {
71973
72543
  const dir = jobsDir2(repoPath);
71974
- const file = join72(dir, `${jobId}.json`);
71975
- if (!existsSync55(file)) {
72544
+ const file = join73(dir, `${jobId}.json`);
72545
+ if (!existsSync56(file)) {
71976
72546
  console.error(`Job not found: ${jobId}`);
71977
72547
  console.log(`Available jobs: oa jobs`);
71978
72548
  process.exit(1);
71979
72549
  }
71980
- const job = JSON.parse(readFileSync44(file, "utf-8"));
72550
+ const job = JSON.parse(readFileSync45(file, "utf-8"));
71981
72551
  const runtime = job.completedAt ? `${((new Date(job.completedAt).getTime() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s` : `${((Date.now() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s`;
71982
72552
  const icon = job.status === "completed" ? "\u2713" : job.status === "failed" ? "\u2717" : "\u25CF";
71983
72553
  console.log(`${icon} ${job.id} [${job.status}] ${runtime}`);
@@ -72000,7 +72570,7 @@ function jobsCommand(repoPath) {
72000
72570
  console.log("Jobs:");
72001
72571
  for (const file of files) {
72002
72572
  try {
72003
- const job = JSON.parse(readFileSync44(join72(dir, file), "utf-8"));
72573
+ const job = JSON.parse(readFileSync45(join73(dir, file), "utf-8"));
72004
72574
  const icon = job.status === "completed" ? "\u2713" : job.status === "failed" ? "\u2717" : "\u25CF";
72005
72575
  const runtime = job.completedAt ? `${((new Date(job.completedAt).getTime() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s` : `${((Date.now() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s`;
72006
72576
  console.log(` ${icon} ${job.id} [${job.status}] ${runtime} \u2014 ${job.task.slice(0, 60)}`);
@@ -72020,7 +72590,7 @@ import { glob } from "glob";
72020
72590
  import ignore from "ignore";
72021
72591
  import { readFile as readFile23, stat as stat4 } from "node:fs/promises";
72022
72592
  import { createHash as createHash6 } from "node:crypto";
72023
- import { join as join73, relative as relative4, extname as extname12, basename as basename17 } from "node:path";
72593
+ import { join as join74, relative as relative4, extname as extname12, basename as basename17 } from "node:path";
72024
72594
  var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
72025
72595
  var init_codebase_indexer = __esm({
72026
72596
  "packages/indexer/dist/codebase-indexer.js"() {
@@ -72064,7 +72634,7 @@ var init_codebase_indexer = __esm({
72064
72634
  const ig = ignore.default();
72065
72635
  if (this.config.respectGitignore) {
72066
72636
  try {
72067
- const gitignoreContent = await readFile23(join73(this.config.rootDir, ".gitignore"), "utf-8");
72637
+ const gitignoreContent = await readFile23(join74(this.config.rootDir, ".gitignore"), "utf-8");
72068
72638
  ig.add(gitignoreContent);
72069
72639
  } catch {
72070
72640
  }
@@ -72079,7 +72649,7 @@ var init_codebase_indexer = __esm({
72079
72649
  for (const relativePath of files) {
72080
72650
  if (ig.ignores(relativePath))
72081
72651
  continue;
72082
- const fullPath = join73(this.config.rootDir, relativePath);
72652
+ const fullPath = join74(this.config.rootDir, relativePath);
72083
72653
  try {
72084
72654
  const fileStat = await stat4(fullPath);
72085
72655
  if (fileStat.size > this.config.maxFileSize)
@@ -72125,7 +72695,7 @@ var init_codebase_indexer = __esm({
72125
72695
  if (!child) {
72126
72696
  child = {
72127
72697
  name: part,
72128
- path: join73(current.path, part),
72698
+ path: join74(current.path, part),
72129
72699
  type: "directory",
72130
72700
  children: []
72131
72701
  };
@@ -72208,13 +72778,13 @@ __export(index_repo_exports, {
72208
72778
  indexRepoCommand: () => indexRepoCommand
72209
72779
  });
72210
72780
  import { resolve as resolve34 } from "node:path";
72211
- import { existsSync as existsSync56, statSync as statSync17 } from "node:fs";
72781
+ import { existsSync as existsSync57, statSync as statSync17 } from "node:fs";
72212
72782
  import { cwd as cwd2 } from "node:process";
72213
72783
  async function indexRepoCommand(opts, _config) {
72214
72784
  const repoRoot = resolve34(opts.repoPath ?? cwd2());
72215
72785
  printHeader("Index Repository");
72216
72786
  printInfo(`Indexing: ${repoRoot}`);
72217
- if (!existsSync56(repoRoot)) {
72787
+ if (!existsSync57(repoRoot)) {
72218
72788
  printError(`Path does not exist: ${repoRoot}`);
72219
72789
  process.exit(1);
72220
72790
  }
@@ -72466,7 +73036,7 @@ var config_exports2 = {};
72466
73036
  __export(config_exports2, {
72467
73037
  configCommand: () => configCommand
72468
73038
  });
72469
- import { join as join74, resolve as resolve35 } from "node:path";
73039
+ import { join as join75, resolve as resolve35 } from "node:path";
72470
73040
  import { homedir as homedir20 } from "node:os";
72471
73041
  import { cwd as cwd3 } from "node:process";
72472
73042
  function redactIfSensitive(key, value) {
@@ -72549,7 +73119,7 @@ function handleShow(opts, config) {
72549
73119
  }
72550
73120
  }
72551
73121
  printSection("Config File");
72552
- printInfo(`~/.open-agents/config.json (${join74(homedir20(), ".open-agents", "config.json")})`);
73122
+ printInfo(`~/.open-agents/config.json (${join75(homedir20(), ".open-agents", "config.json")})`);
72553
73123
  printSection("Priority Chain");
72554
73124
  printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
72555
73125
  printInfo(" 2. Project .oa/settings.json (--local)");
@@ -72588,7 +73158,7 @@ function handleSet(opts, _config) {
72588
73158
  const coerced = coerceForSettings(key, value);
72589
73159
  saveProjectSettings(repoRoot, { [key]: coerced });
72590
73160
  printSuccess(`Project override set: ${key} = ${redactIfSensitive(key, value)}`);
72591
- printInfo(`Saved to ${join74(repoRoot, ".oa", "settings.json")}`);
73161
+ printInfo(`Saved to ${join75(repoRoot, ".oa", "settings.json")}`);
72592
73162
  printInfo("This override applies only when running in this workspace.");
72593
73163
  } catch (err) {
72594
73164
  printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
@@ -72731,8 +73301,8 @@ __export(eval_exports, {
72731
73301
  evalCommand: () => evalCommand
72732
73302
  });
72733
73303
  import { tmpdir as tmpdir10 } from "node:os";
72734
- import { mkdirSync as mkdirSync30, writeFileSync as writeFileSync29 } from "node:fs";
72735
- import { join as join75 } from "node:path";
73304
+ import { mkdirSync as mkdirSync31, writeFileSync as writeFileSync29 } from "node:fs";
73305
+ import { join as join76 } from "node:path";
72736
73306
  async function evalCommand(opts, config) {
72737
73307
  const suiteName = opts.suite ?? "basic";
72738
73308
  const suite = SUITES[suiteName];
@@ -72857,9 +73427,9 @@ async function evalCommand(opts, config) {
72857
73427
  process.exit(failed > 0 ? 1 : 0);
72858
73428
  }
72859
73429
  function createTempEvalRepo() {
72860
- const dir = join75(tmpdir10(), `open-agents-eval-${Date.now()}`);
72861
- mkdirSync30(dir, { recursive: true });
72862
- writeFileSync29(join75(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
73430
+ const dir = join76(tmpdir10(), `open-agents-eval-${Date.now()}`);
73431
+ mkdirSync31(dir, { recursive: true });
73432
+ writeFileSync29(join76(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
72863
73433
  return dir;
72864
73434
  }
72865
73435
  var BASIC_SUITE, FULL_SUITE, SUITES;
@@ -72919,7 +73489,7 @@ init_updater();
72919
73489
  import { parseArgs as nodeParseArgs2 } from "node:util";
72920
73490
  import { createRequire as createRequire5 } from "node:module";
72921
73491
  import { fileURLToPath as fileURLToPath15 } from "node:url";
72922
- import { dirname as dirname23, join as join76 } from "node:path";
73492
+ import { dirname as dirname23, join as join77 } from "node:path";
72923
73493
 
72924
73494
  // packages/cli/dist/cli.js
72925
73495
  import { createInterface } from "node:readline";
@@ -73026,7 +73596,7 @@ init_output();
73026
73596
  function getVersion5() {
73027
73597
  try {
73028
73598
  const require2 = createRequire5(import.meta.url);
73029
- const pkgPath = join76(dirname23(fileURLToPath15(import.meta.url)), "..", "package.json");
73599
+ const pkgPath = join77(dirname23(fileURLToPath15(import.meta.url)), "..", "package.json");
73030
73600
  const pkg = require2(pkgPath);
73031
73601
  return pkg.version;
73032
73602
  } catch {
@@ -73301,12 +73871,12 @@ function crashLog(label, err) {
73301
73871
  const logLine = `[${timestamp}] ${label}: ${msg}
73302
73872
  `;
73303
73873
  try {
73304
- const { appendFileSync: appendFileSync5, mkdirSync: mkdirSync31 } = __require("node:fs");
73305
- const { join: join77 } = __require("node:path");
73874
+ const { appendFileSync: appendFileSync6, mkdirSync: mkdirSync32 } = __require("node:fs");
73875
+ const { join: join78 } = __require("node:path");
73306
73876
  const { homedir: homedir21 } = __require("node:os");
73307
- const logDir = join77(homedir21(), ".open-agents");
73308
- mkdirSync31(logDir, { recursive: true });
73309
- appendFileSync5(join77(logDir, "crash.log"), logLine);
73877
+ const logDir = join78(homedir21(), ".open-agents");
73878
+ mkdirSync32(logDir, { recursive: true });
73879
+ appendFileSync6(join78(logDir, "crash.log"), logLine);
73310
73880
  } catch {
73311
73881
  }
73312
73882
  try {