open-agents-ai 0.185.78 → 0.185.80

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 +583 -244
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -11957,8 +11957,8 @@ async function loadTranscribeCli() {
11957
11957
  const nvmBase = join19(homedir7(), ".nvm", "versions", "node");
11958
11958
  if (existsSync16(nvmBase)) {
11959
11959
  try {
11960
- const { readdirSync: readdirSync24 } = await import("node:fs");
11961
- for (const ver of readdirSync24(nvmBase)) {
11960
+ const { readdirSync: readdirSync25 } = await import("node:fs");
11961
+ for (const ver of readdirSync25(nvmBase)) {
11962
11962
  const tcPath = join19(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
11963
11963
  if (existsSync16(join19(tcPath, "dist", "index.js"))) {
11964
11964
  const { createRequire: createRequire6 } = await import("node:module");
@@ -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: readFileSync47, existsSync: existsSync59 } = await import("node:fs");
13823
+ const { readFileSync: readFileSync48, existsSync: existsSync60 } = await import("node:fs");
13824
13824
  const sessionPath = join22(this.cwd, ".oa", "rlm", "session.json");
13825
- if (!existsSync59(sessionPath))
13825
+ if (!existsSync60(sessionPath))
13826
13826
  return null;
13827
- return JSON.parse(readFileSync47(sessionPath, "utf8"));
13827
+ return JSON.parse(readFileSync48(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: readFileSync47 } = await import("node:fs");
14005
- const files = readdirSync24(trajDir).filter((f) => f.endsWith(".jsonl")).sort().reverse().slice(0, 3);
14004
+ const { readdirSync: readdirSync25, readFileSync: readFileSync48 } = await import("node:fs");
14005
+ const files = readdirSync25(trajDir).filter((f) => f.endsWith(".jsonl")).sort().reverse().slice(0, 3);
14006
14006
  for (const file of files) {
14007
- const lines = readFileSync47(join23(trajDir, file), "utf8").split("\n").filter((l) => l.trim());
14007
+ const lines = readFileSync48(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: readFileSync47, existsSync: existsSync59 } = __require("node:fs");
14391
+ const { readFileSync: readFileSync48, existsSync: existsSync60 } = __require("node:fs");
14392
14392
  const metaDir = join23(this.cwd, ".oa", "memory", "metabolism");
14393
14393
  const storeFile = join23(metaDir, "store.json");
14394
- if (!existsSync59(storeFile))
14394
+ if (!existsSync60(storeFile))
14395
14395
  return "";
14396
14396
  let store2 = [];
14397
14397
  try {
14398
- store2 = JSON.parse(readFileSync47(storeFile, "utf8"));
14398
+ store2 = JSON.parse(readFileSync48(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: readFileSync47, writeFileSync: writeFileSync31, existsSync: existsSync59, mkdirSync: mkdirSync33 } = __require("node:fs");
14420
+ const { readFileSync: readFileSync48, writeFileSync: writeFileSync31, existsSync: existsSync60, mkdirSync: mkdirSync33 } = __require("node:fs");
14421
14421
  const metaDir = join23(this.cwd, ".oa", "memory", "metabolism");
14422
14422
  const storeFile = join23(metaDir, "store.json");
14423
- if (!existsSync59(storeFile))
14423
+ if (!existsSync60(storeFile))
14424
14424
  return;
14425
14425
  let store2 = [];
14426
14426
  try {
14427
- store2 = JSON.parse(readFileSync47(storeFile, "utf8"));
14427
+ store2 = JSON.parse(readFileSync48(storeFile, "utf8"));
14428
14428
  } catch {
14429
14429
  return;
14430
14430
  }
@@ -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: readFileSync47, existsSync: existsSync59 } = __require("node:fs");
14874
+ const { readFileSync: readFileSync48, existsSync: existsSync60 } = __require("node:fs");
14875
14875
  const archiveFile = join25(this.cwd, ".oa", "arche", "variants.json");
14876
- if (!existsSync59(archiveFile))
14876
+ if (!existsSync60(archiveFile))
14877
14877
  return "";
14878
14878
  let variants = [];
14879
14879
  try {
14880
- variants = JSON.parse(readFileSync47(archiveFile, "utf8"));
14880
+ variants = JSON.parse(readFileSync48(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: readFileSync47, writeFileSync: writeFileSync31, existsSync: existsSync59, mkdirSync: mkdirSync33 } = __require("node:fs");
14898
+ const { readFileSync: readFileSync48, writeFileSync: writeFileSync31, existsSync: existsSync60, mkdirSync: mkdirSync33 } = __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 (existsSync59(archiveFile))
14904
- variants = JSON.parse(readFileSync47(archiveFile, "utf8"));
14903
+ if (existsSync60(archiveFile))
14904
+ variants = JSON.parse(readFileSync48(archiveFile, "utf8"));
14905
14905
  } catch {
14906
14906
  }
14907
14907
  variants.push({
@@ -27423,8 +27423,8 @@ ${marker}` : marker);
27423
27423
  return;
27424
27424
  try {
27425
27425
  const { mkdirSync: mkdirSync33, writeFileSync: writeFileSync31 } = __require("node:fs");
27426
- const { join: join79 } = __require("node:path");
27427
- const sessionDir = join79(this._workingDirectory, ".oa", "session", this._sessionId);
27426
+ const { join: join80 } = __require("node:path");
27427
+ const sessionDir = join80(this._workingDirectory, ".oa", "session", this._sessionId);
27428
27428
  mkdirSync33(sessionDir, { recursive: true });
27429
27429
  const checkpoint = {
27430
27430
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -27437,7 +27437,7 @@ ${marker}` : marker);
27437
27437
  memexEntryCount: this._memexArchive.size,
27438
27438
  fileRegistrySize: this._fileRegistry.size
27439
27439
  };
27440
- writeFileSync31(join79(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
27440
+ writeFileSync31(join80(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: writeFileSync31, readFileSync: readFileSync47, unlinkSync: unlinkSync13 } = await import("node:fs");
28579
- const { join: join79 } = await import("node:path");
28578
+ const { writeFileSync: writeFileSync31, readFileSync: readFileSync48, unlinkSync: unlinkSync13 } = await import("node:fs");
28579
+ const { join: join80 } = await import("node:path");
28580
28580
  const { tmpdir: tmpdir11 } = await import("node:os");
28581
- const tmpIn = join79(tmpdir11(), `oa_img_in_${Date.now()}.png`);
28582
- const tmpOut = join79(tmpdir11(), `oa_img_out_${Date.now()}.jpg`);
28581
+ const tmpIn = join80(tmpdir11(), `oa_img_in_${Date.now()}.png`);
28582
+ const tmpOut = join80(tmpdir11(), `oa_img_out_${Date.now()}.jpg`);
28583
28583
  writeFileSync31(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 = readFileSync47(tmpOut);
28588
+ const resizedBuf = readFileSync48(tmpOut);
28589
28589
  resizedBase64 = `data:image/jpeg;base64,${resizedBuf.toString("base64")}`;
28590
28590
  try {
28591
28591
  unlinkSync13(tmpIn);
@@ -30716,8 +30716,8 @@ var init_listen = __esm({
30716
30716
  const nvmBase = join48(homedir11(), ".nvm", "versions", "node");
30717
30717
  if (existsSync32(nvmBase)) {
30718
30718
  try {
30719
- const { readdirSync: readdirSync24 } = await import("node:fs");
30720
- for (const ver of readdirSync24(nvmBase)) {
30719
+ const { readdirSync: readdirSync25 } = await import("node:fs");
30720
+ for (const ver of readdirSync25(nvmBase)) {
30721
30721
  const tcPath = join48(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
30722
30722
  if (existsSync32(join48(tcPath, "dist", "index.js"))) {
30723
30723
  const { createRequire: createRequire6 } = await import("node:module");
@@ -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: existsSync59, readFileSync: readFileSync47 } = await import("node:fs");
39561
- const { join: join79 } = await import("node:path");
39560
+ const { existsSync: existsSync60, readFileSync: readFileSync48 } = await import("node:fs");
39561
+ const { join: join80 } = 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 = join79(nexusDir, "status.json");
39568
- if (existsSync59(statusPath)) {
39569
- const status = JSON.parse(readFileSync47(statusPath, "utf8"));
39567
+ const statusPath = join80(nexusDir, "status.json");
39568
+ if (existsSync60(statusPath)) {
39569
+ const status = JSON.parse(readFileSync48(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 = join79(nexusDir, "pricing.json");
39577
- if (existsSync59(pricingPath)) {
39576
+ const pricingPath = join80(nexusDir, "pricing.json");
39577
+ if (existsSync60(pricingPath)) {
39578
39578
  try {
39579
- const pricing = JSON.parse(readFileSync47(pricingPath, "utf8"));
39579
+ const pricing = JSON.parse(readFileSync48(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 = join79(nexusDir, "peer-models-cache.json");
39594
- if (existsSync59(cachePath)) {
39593
+ const cachePath = join80(nexusDir, "peer-models-cache.json");
39594
+ if (existsSync60(cachePath)) {
39595
39595
  try {
39596
- const cache4 = JSON.parse(readFileSync47(cachePath, "utf8"));
39596
+ const cache4 = JSON.parse(readFileSync48(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 = join79(nexusDir, "pricing.json");
39712
- if (existsSync59(pricingPath)) {
39711
+ const pricingPath = join80(nexusDir, "pricing.json");
39712
+ if (existsSync60(pricingPath)) {
39713
39713
  try {
39714
- const pricing = JSON.parse(readFileSync47(pricingPath, "utf8"));
39714
+ const pricing = JSON.parse(readFileSync48(pricingPath, "utf8"));
39715
39715
  return (pricing.models || []).map((m) => ({
39716
39716
  name: m.model || "unknown",
39717
39717
  size: m.parameterSize || "",
@@ -52966,8 +52966,8 @@ async function handlePeerEndpoint(peerId, authKey, ctx, local) {
52966
52966
  if (models.length > 0) {
52967
52967
  try {
52968
52968
  const { writeFileSync: writeFileSync31, mkdirSync: mkdirSync33 } = await import("node:fs");
52969
- const { join: join79, dirname: dirname24 } = await import("node:path");
52970
- const cachePath = join79(ctx.repoRoot || process.cwd(), ".oa", "nexus", "peer-models-cache.json");
52969
+ const { join: join80, dirname: dirname24 } = await import("node:path");
52970
+ const cachePath = join80(ctx.repoRoot || process.cwd(), ".oa", "nexus", "peer-models-cache.json");
52971
52971
  mkdirSync33(dirname24(cachePath), { recursive: true });
52972
52972
  writeFileSync31(cachePath, JSON.stringify({
52973
52973
  peerId,
@@ -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: join79 } = await import("node:path");
53172
- const { existsSync: existsSync59 } = await import("node:fs");
53171
+ const { dirname: dirname24, join: join80 } = await import("node:path");
53172
+ const { existsSync: existsSync60 } = 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
- join79(thisDir, "..", "package.json"),
53177
- join79(thisDir, "..", "..", "package.json"),
53178
- join79(thisDir, "..", "..", "..", "package.json")
53176
+ join80(thisDir, "..", "package.json"),
53177
+ join80(thisDir, "..", "..", "package.json"),
53178
+ join80(thisDir, "..", "..", "..", "package.json")
53179
53179
  ];
53180
53180
  for (const pkgPath of candidates) {
53181
- if (existsSync59(pkgPath)) {
53181
+ if (existsSync60(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";
@@ -54151,11 +54151,11 @@ function loadMemoryDir(memDir, scope) {
54151
54151
  return lines.join("\n");
54152
54152
  }
54153
54153
  function loadSessionHistory(repoRoot) {
54154
- const sessions = loadRecentSessions(repoRoot, 5);
54155
- if (sessions.length === 0)
54154
+ const sessions2 = loadRecentSessions(repoRoot, 5);
54155
+ if (sessions2.length === 0)
54156
54156
  return "";
54157
54157
  const lines = ["Recent tasks in this project:"];
54158
- for (const s of sessions) {
54158
+ for (const s of sessions2) {
54159
54159
  if (!s.startedAt || !s.task)
54160
54160
  continue;
54161
54161
  const status = s.completed ? "completed" : "incomplete";
@@ -55490,8 +55490,8 @@ function listBannerDesigns(workDir) {
55490
55490
  if (!existsSync45(dir))
55491
55491
  return [];
55492
55492
  try {
55493
- const { readdirSync: readdirSync24 } = __require("node:fs");
55494
- return readdirSync24(dir).filter((f) => f.endsWith(".json")).map((f) => f.replace(".json", ""));
55493
+ const { readdirSync: readdirSync25 } = __require("node:fs");
55494
+ return readdirSync25(dir).filter((f) => f.endsWith(".json")).map((f) => f.replace(".json", ""));
55495
55495
  } catch {
55496
55496
  return [];
55497
55497
  }
@@ -56039,8 +56039,8 @@ function extractFromManifests(repoRoot, tags) {
56039
56039
  }
56040
56040
  function extractFromSessions(repoRoot, tags) {
56041
56041
  try {
56042
- const sessions = loadRecentSessions(repoRoot, 10);
56043
- for (const session of sessions) {
56042
+ const sessions2 = loadRecentSessions(repoRoot, 10);
56043
+ for (const session of sessions2) {
56044
56044
  if (session.task) {
56045
56045
  const words = session.task.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length > 3 && !STOP_WORDS.has(w));
56046
56046
  tags.push(...words.slice(0, 4));
@@ -65508,6 +65508,13 @@ body {
65508
65508
  outline: none;
65509
65509
  margin-bottom: 12px;
65510
65510
  }
65511
+ /* WO-E21: Responsive design */
65512
+ @media (max-width: 768px) {
65513
+ #workspace-sidebar { position:fixed !important; top:0; left:0; bottom:0; z-index:50; width:80vw !important; box-shadow:4px 0 20px rgba(0,0,0,0.5); }
65514
+ #header select { display:none; }
65515
+ #header .key-btn:first-of-type { display:none; }
65516
+ .tab { padding:6px 10px !important; font-size:0.6rem !important; }
65517
+ }
65511
65518
  #key-modal .modal button {
65512
65519
  background: #2a2a30;
65513
65520
  border: 1px solid #b2920a;
@@ -65527,6 +65534,8 @@ body {
65527
65534
  <span class="accent">OA</span>
65528
65535
  <span class="status" id="status">connecting...</span>
65529
65536
  <select id="model-select"><option>loading...</option></select>
65537
+ <button class="key-btn" onclick="toggleWorkspace()" title="Toggle workspace sidebar">files</button>
65538
+ <button class="key-btn" id="sandbox-toggle" onclick="toggleSandbox()" title="Toggle Docker sandbox" style="opacity:0.5">sandbox: off</button>
65530
65539
  <button class="key-btn" id="key-btn" title="Set API key">key</button>
65531
65540
  </div>
65532
65541
 
@@ -65542,7 +65551,17 @@ body {
65542
65551
  <button class="tab" onclick="switchTab('activity')" id="tab-activity" style="background:none;border:none;border-bottom:2px solid transparent;color:#555;padding:6px 16px;font-family:inherit;font-size:0.7rem;cursor:pointer">activity</button>
65543
65552
  <span id="token-counter" style="margin-left:auto;font-size:0.6rem;color:#555">0 tokens</span>
65544
65553
  </div>
65545
- <div id="conversation"></div>
65554
+ <div style="display:flex;flex:1;overflow:hidden">
65555
+ <div id="workspace-sidebar" style="display:none;width:250px;background:#1e1e22;border-right:1px solid #2a2a30;overflow-y:auto;padding:8px;flex-shrink:0;font-size:0.7rem">
65556
+ <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px">
65557
+ <span style="color:#b2920a;font-size:0.7rem;font-weight:bold">Workspace</span>
65558
+ <button onclick="toggleWorkspace()" style="background:none;border:none;color:#555;cursor:pointer;font-size:0.8rem">x</button>
65559
+ </div>
65560
+ <div id="workspace-cwd" style="color:#555;font-size:0.6rem;margin-bottom:8px;word-break:break-all"></div>
65561
+ <div id="workspace-tree" style="color:#b0b0b0"></div>
65562
+ </div>
65563
+ <div id="conversation" style="flex:1;overflow-y:auto;padding:12px 16px;display:flex;flex-direction:column;gap:4px"></div>
65564
+ </div>
65546
65565
  <div id="agent-panel" style="display:none;flex:1;overflow-y:auto;padding:12px 16px">
65547
65566
  <textarea id="agent-task" placeholder="Describe the task for the agent..." style="width:100%;min-height:80px;background:#2a2a30;border:1px solid #3a3a42;border-radius:3px;padding:8px 12px;color:#b0b0b0;font-family:inherit;font-size:0.82rem;resize:vertical;outline:none;margin-bottom:8px"></textarea>
65548
65567
  <div style="display:flex;gap:8px;margin-bottom:12px;align-items:center">
@@ -65617,6 +65636,7 @@ const statusEl = document.getElementById('status');
65617
65636
  let apiKey = localStorage.getItem('oa-api-key') || '';
65618
65637
  let streaming = false;
65619
65638
  let messages = [];
65639
+ let chatSessionId = null; // stateful session for /v1/chat
65620
65640
 
65621
65641
  // Auto-resize textarea
65622
65642
  input.addEventListener('input', () => {
@@ -65722,22 +65742,25 @@ async function sendMessage() {
65722
65742
  let fullContent = '';
65723
65743
 
65724
65744
  try {
65745
+ // Use stateful /v1/chat endpoint (maintains OA identity + context)
65725
65746
  const body = {
65747
+ session_id: chatSessionId,
65726
65748
  model: modelSelect.value,
65727
- messages: [
65728
- ...(sysPrompt ? [{ role: 'system', content: sysPrompt }] : []),
65729
- ...messages,
65730
- ],
65749
+ message: text,
65731
65750
  stream: true,
65732
65751
  max_tokens: 4096,
65733
65752
  };
65734
65753
 
65735
- const response = await fetch('/v1/chat/completions', {
65754
+ const response = await fetch('/v1/chat', {
65736
65755
  method: 'POST',
65737
65756
  headers: headers(),
65738
65757
  body: JSON.stringify(body),
65739
65758
  });
65740
65759
 
65760
+ // Capture session ID from response header
65761
+ const sid = response.headers.get('x-session-id');
65762
+ if (sid) chatSessionId = sid;
65763
+
65741
65764
  const reader = response.body.getReader();
65742
65765
  const decoder = new TextDecoder();
65743
65766
  let buffer = '';
@@ -66061,6 +66084,25 @@ async function loadDashboard() {
66061
66084
  '<div style="color:#555;font-size:0.6rem">VERSION</div>' +
66062
66085
  '<div style="color:#b0b0b0;font-size:0.8rem">' + d.version + '</div></div>';
66063
66086
  } catch {}
66087
+ // System info + model recommendations
66088
+ try {
66089
+ const sr = await fetch('/v1/system', { headers: headers() });
66090
+ const sys = await sr.json();
66091
+ const gpuHtml = (sys.gpu || []).map(g => g.name + ' (' + g.vram_gb + 'GB)').join(', ') || 'No GPU detected';
66092
+ const healthEl = document.getElementById('dashboard-health');
66093
+ healthEl.innerHTML +=
66094
+ '<div style="background:#1e1e22;border:1px solid #2a2a30;border-radius:3px;padding:8px 12px;flex:1;min-width:120px">' +
66095
+ '<div style="color:#555;font-size:0.6rem">GPU</div>' +
66096
+ '<div style="color:#b0b0b0;font-size:0.7rem">' + gpuHtml + '</div></div>' +
66097
+ '<div style="background:#1e1e22;border:1px solid #2a2a30;border-radius:3px;padding:8px 12px;flex:1;min-width:120px">' +
66098
+ '<div style="color:#555;font-size:0.6rem">RAM</div>' +
66099
+ '<div style="color:#b0b0b0;font-size:0.8rem">' + sys.ram_gb + 'GB</div></div>' +
66100
+ '<div style="background:#1e1e22;border:1px solid #2a2a30;border-radius:3px;padding:8px 12px;flex:1;min-width:120px">' +
66101
+ '<div style="color:#555;font-size:0.6rem">MAX MODEL</div>' +
66102
+ '<div style="color:#b2920a;font-size:0.8rem">' + sys.recommended_max_params + '</div></div>';
66103
+ // Store for model badges
66104
+ window._sysMaxParams = sys.recommended_max_params;
66105
+ } catch {}
66064
66106
  // Usage \u2014 per-provider breakdown with persistent totals
66065
66107
  try {
66066
66108
  const r = await fetch('/v1/usage', { headers: headers() });
@@ -66120,6 +66162,33 @@ async function loadJobs() {
66120
66162
  } catch { list.innerHTML = '<div style="color:#ff4444">Failed to load jobs</div>'; }
66121
66163
  }
66122
66164
 
66165
+ // Workspace sidebar
66166
+ function toggleWorkspace() {
66167
+ const sb = document.getElementById('workspace-sidebar');
66168
+ sb.style.display = sb.style.display === 'none' ? 'block' : 'none';
66169
+ if (sb.style.display === 'block') loadWorkspaceTree();
66170
+ }
66171
+ async function loadWorkspaceTree() {
66172
+ try {
66173
+ const r = await fetch('/v1/system', { headers: headers() });
66174
+ const d = await r.json();
66175
+ document.getElementById('workspace-cwd').textContent = d.cwd || process.cwd?.() || '.';
66176
+ } catch {}
66177
+ // Placeholder tree \u2014 full implementation requires a directory listing endpoint
66178
+ document.getElementById('workspace-tree').innerHTML =
66179
+ '<div style="color:#555;font-size:0.65rem">File tree requires /v1/files endpoint (future WO)</div>';
66180
+ }
66181
+
66182
+ // Docker sandbox toggle
66183
+ let sandboxMode = 'none';
66184
+ function toggleSandbox() {
66185
+ sandboxMode = sandboxMode === 'none' ? 'container' : 'none';
66186
+ const btn = document.getElementById('sandbox-toggle');
66187
+ btn.textContent = 'sandbox: ' + (sandboxMode === 'none' ? 'off' : 'docker');
66188
+ btn.style.opacity = sandboxMode === 'none' ? '0.5' : '1';
66189
+ btn.style.borderColor = sandboxMode === 'none' ? '#3a3a42' : '#b2920a';
66190
+ }
66191
+
66123
66192
  // Init
66124
66193
  checkHealth();
66125
66194
  loadModels();
@@ -66259,16 +66328,137 @@ var init_auth_oidc = __esm({
66259
66328
  }
66260
66329
  });
66261
66330
 
66262
- // packages/cli/dist/api/usage-tracker.js
66263
- import { mkdirSync as mkdirSync27, readFileSync as readFileSync42, writeFileSync as writeFileSync25, existsSync as existsSync53 } from "node:fs";
66331
+ // packages/cli/dist/api/chat-session.js
66332
+ import { randomUUID as randomUUID4 } from "node:crypto";
66333
+ import { existsSync as existsSync53, readFileSync as readFileSync42, readdirSync as readdirSync20 } from "node:fs";
66264
66334
  import { join as join70 } from "node:path";
66335
+ function buildSystemPrompt(cwd4) {
66336
+ const parts = [];
66337
+ parts.push("You are Open Agent (OA), an AI coding assistant running locally via Ollama. You have access to the user's workspace and can discuss code, files, and projects. Be helpful, concise, and technically precise. When asked about files or code, describe what you know from the conversation context.");
66338
+ parts.push(`\\nEnvironment: ${process.platform}, Node ${process.version}, CWD: ${cwd4}`);
66339
+ const diaryPath = join70(cwd4, ".oa", "context", "session-diary.md");
66340
+ if (existsSync53(diaryPath)) {
66341
+ try {
66342
+ const diary = readFileSync42(diaryPath, "utf-8").slice(0, 1e3);
66343
+ parts.push(`\\nPrevious session history:\\n${diary}`);
66344
+ } catch {
66345
+ }
66346
+ }
66347
+ const memDir = join70(cwd4, ".oa", "memory");
66348
+ if (existsSync53(memDir)) {
66349
+ try {
66350
+ const files = readdirSync20(memDir).filter((f) => f.endsWith(".json")).slice(0, 5);
66351
+ if (files.length > 0) {
66352
+ parts.push("\\nPersistent memory topics: " + files.map((f) => f.replace(".json", "")).join(", "));
66353
+ for (const f of files.slice(0, 3)) {
66354
+ try {
66355
+ const data = JSON.parse(readFileSync42(join70(memDir, f), "utf-8"));
66356
+ const entries = Object.entries(data).slice(0, 3);
66357
+ if (entries.length > 0) {
66358
+ parts.push(`\\nMemory [${f.replace(".json", "")}]: ` + entries.map(([k, v]) => `${k}: ${String(v.value ?? v).slice(0, 100)}`).join("; "));
66359
+ }
66360
+ } catch {
66361
+ }
66362
+ }
66363
+ }
66364
+ } catch {
66365
+ }
66366
+ }
66367
+ for (const name of ["AGENTS.md", "OA.md", ".open-agents.md"]) {
66368
+ const p = join70(cwd4, name);
66369
+ if (existsSync53(p)) {
66370
+ try {
66371
+ const content = readFileSync42(p, "utf-8").slice(0, 500);
66372
+ parts.push(`\\nProject instructions (${name}):\\n${content}`);
66373
+ } catch {
66374
+ }
66375
+ }
66376
+ }
66377
+ return parts.join("");
66378
+ }
66379
+ function getSession(sessionId, model, cwd4) {
66380
+ if (sessionId && sessions.has(sessionId)) {
66381
+ const s = sessions.get(sessionId);
66382
+ s.lastActivity = Date.now();
66383
+ return s;
66384
+ }
66385
+ const id = sessionId || randomUUID4();
66386
+ const systemPrompt = buildSystemPrompt(cwd4);
66387
+ const session = {
66388
+ id,
66389
+ messages: [{ role: "system", content: systemPrompt }],
66390
+ model,
66391
+ createdAt: Date.now(),
66392
+ lastActivity: Date.now(),
66393
+ tokensIn: 0,
66394
+ tokensOut: 0
66395
+ };
66396
+ sessions.set(id, session);
66397
+ return session;
66398
+ }
66399
+ function addUserMessage(session, content) {
66400
+ session.messages.push({ role: "user", content });
66401
+ session.lastActivity = Date.now();
66402
+ return [...session.messages];
66403
+ }
66404
+ function addAssistantMessage(session, content) {
66405
+ session.messages.push({ role: "assistant", content });
66406
+ session.lastActivity = Date.now();
66407
+ }
66408
+ function trackSessionTokens(session, tokensIn, tokensOut) {
66409
+ session.tokensIn += tokensIn;
66410
+ session.tokensOut += tokensOut;
66411
+ }
66412
+ function listSessions() {
66413
+ return Array.from(sessions.values()).map((s) => ({
66414
+ id: s.id,
66415
+ model: s.model,
66416
+ messages: s.messages.length - 1,
66417
+ // exclude system prompt
66418
+ tokensIn: s.tokensIn,
66419
+ tokensOut: s.tokensOut,
66420
+ lastActivity: new Date(s.lastActivity).toISOString()
66421
+ }));
66422
+ }
66423
+ function compactSession(session, maxMessages = 40) {
66424
+ if (session.messages.length <= maxMessages)
66425
+ return;
66426
+ const system = session.messages[0];
66427
+ const recent = session.messages.slice(-20);
66428
+ const middle = session.messages.slice(1, -20);
66429
+ const summary = `[Earlier conversation: ${middle.length} messages discussed ` + middle.filter((m) => m.role === "user").map((m) => m.content.slice(0, 50)).slice(0, 5).join(", ") + "...]";
66430
+ session.messages = [
66431
+ system,
66432
+ { role: "system", content: summary },
66433
+ ...recent
66434
+ ];
66435
+ }
66436
+ var sessions, SESSION_TTL_MS;
66437
+ var init_chat_session = __esm({
66438
+ "packages/cli/dist/api/chat-session.js"() {
66439
+ "use strict";
66440
+ sessions = /* @__PURE__ */ new Map();
66441
+ SESSION_TTL_MS = 30 * 60 * 1e3;
66442
+ setInterval(() => {
66443
+ const now = Date.now();
66444
+ for (const [id, s] of sessions) {
66445
+ if (now - s.lastActivity > SESSION_TTL_MS)
66446
+ sessions.delete(id);
66447
+ }
66448
+ }, 5 * 60 * 1e3);
66449
+ }
66450
+ });
66451
+
66452
+ // packages/cli/dist/api/usage-tracker.js
66453
+ import { mkdirSync as mkdirSync27, readFileSync as readFileSync43, writeFileSync as writeFileSync25, existsSync as existsSync54 } from "node:fs";
66454
+ import { join as join71 } from "node:path";
66265
66455
  function initUsageTracker(oaDir) {
66266
- const dir = join70(oaDir, "usage");
66456
+ const dir = join71(oaDir, "usage");
66267
66457
  mkdirSync27(dir, { recursive: true });
66268
- usageFile = join70(dir, "token-usage.json");
66458
+ usageFile = join71(dir, "token-usage.json");
66269
66459
  try {
66270
- if (existsSync53(usageFile)) {
66271
- store = JSON.parse(readFileSync42(usageFile, "utf-8"));
66460
+ if (existsSync54(usageFile)) {
66461
+ store = JSON.parse(readFileSync43(usageFile, "utf-8"));
66272
66462
  }
66273
66463
  } catch {
66274
66464
  store = { providers: {}, lastSaved: "" };
@@ -66336,24 +66526,24 @@ var init_usage_tracker = __esm({
66336
66526
  });
66337
66527
 
66338
66528
  // packages/cli/dist/api/profiles.js
66339
- import { existsSync as existsSync54, readFileSync as readFileSync43, writeFileSync as writeFileSync26, mkdirSync as mkdirSync28, readdirSync as readdirSync20, unlinkSync as unlinkSync12 } from "node:fs";
66340
- import { join as join71 } from "node:path";
66529
+ import { existsSync as existsSync55, readFileSync as readFileSync44, writeFileSync as writeFileSync26, mkdirSync as mkdirSync28, readdirSync as readdirSync21, unlinkSync as unlinkSync12 } from "node:fs";
66530
+ import { join as join72 } from "node:path";
66341
66531
  import { homedir as homedir18 } from "node:os";
66342
66532
  import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, randomBytes as randomBytes15, scryptSync as scryptSync3, createHash as createHash5 } from "node:crypto";
66343
66533
  function globalProfileDir() {
66344
- return join71(homedir18(), ".open-agents", "profiles");
66534
+ return join72(homedir18(), ".open-agents", "profiles");
66345
66535
  }
66346
66536
  function projectProfileDir(projectDir) {
66347
- return join71(projectDir || process.cwd(), ".oa", "profiles");
66537
+ return join72(projectDir || process.cwd(), ".oa", "profiles");
66348
66538
  }
66349
66539
  function listProfiles(projectDir) {
66350
66540
  const result = [];
66351
66541
  const seen = /* @__PURE__ */ new Set();
66352
66542
  const projDir = projectProfileDir(projectDir);
66353
- if (existsSync54(projDir)) {
66354
- for (const f of readdirSync20(projDir).filter((f2) => f2.endsWith(".json"))) {
66543
+ if (existsSync55(projDir)) {
66544
+ for (const f of readdirSync21(projDir).filter((f2) => f2.endsWith(".json"))) {
66355
66545
  try {
66356
- const raw = JSON.parse(readFileSync43(join71(projDir, f), "utf8"));
66546
+ const raw = JSON.parse(readFileSync44(join72(projDir, f), "utf8"));
66357
66547
  const name = f.replace(".json", "");
66358
66548
  seen.add(name);
66359
66549
  result.push({
@@ -66367,13 +66557,13 @@ function listProfiles(projectDir) {
66367
66557
  }
66368
66558
  }
66369
66559
  const globDir = globalProfileDir();
66370
- if (existsSync54(globDir)) {
66371
- for (const f of readdirSync20(globDir).filter((f2) => f2.endsWith(".json"))) {
66560
+ if (existsSync55(globDir)) {
66561
+ for (const f of readdirSync21(globDir).filter((f2) => f2.endsWith(".json"))) {
66372
66562
  const name = f.replace(".json", "");
66373
66563
  if (seen.has(name))
66374
66564
  continue;
66375
66565
  try {
66376
- const raw = JSON.parse(readFileSync43(join71(globDir, f), "utf8"));
66566
+ const raw = JSON.parse(readFileSync44(join72(globDir, f), "utf8"));
66377
66567
  result.push({
66378
66568
  name,
66379
66569
  description: raw.description || "",
@@ -66388,12 +66578,12 @@ function listProfiles(projectDir) {
66388
66578
  }
66389
66579
  function loadProfile(name, password, projectDir) {
66390
66580
  const sanitized = name.replace(/[^a-zA-Z0-9_-]/g, "");
66391
- const projPath = join71(projectProfileDir(projectDir), `${sanitized}.json`);
66392
- const globPath = join71(globalProfileDir(), `${sanitized}.json`);
66393
- const filePath = existsSync54(projPath) ? projPath : existsSync54(globPath) ? globPath : null;
66581
+ const projPath = join72(projectProfileDir(projectDir), `${sanitized}.json`);
66582
+ const globPath = join72(globalProfileDir(), `${sanitized}.json`);
66583
+ const filePath = existsSync55(projPath) ? projPath : existsSync55(globPath) ? globPath : null;
66394
66584
  if (!filePath)
66395
66585
  return null;
66396
- const raw = JSON.parse(readFileSync43(filePath, "utf8"));
66586
+ const raw = JSON.parse(readFileSync44(filePath, "utf8"));
66397
66587
  if (raw.encrypted === true) {
66398
66588
  if (!password)
66399
66589
  return null;
@@ -66405,7 +66595,7 @@ function saveProfile(profile, password, scope = "global", projectDir) {
66405
66595
  const dir = scope === "project" ? projectProfileDir(projectDir) : globalProfileDir();
66406
66596
  mkdirSync28(dir, { recursive: true });
66407
66597
  const sanitized = profile.name.replace(/[^a-zA-Z0-9_-]/g, "");
66408
- const filePath = join71(dir, `${sanitized}.json`);
66598
+ const filePath = join72(dir, `${sanitized}.json`);
66409
66599
  profile.modified = (/* @__PURE__ */ new Date()).toISOString();
66410
66600
  if (password) {
66411
66601
  const encrypted = encryptProfile(profile, password);
@@ -66418,8 +66608,8 @@ function saveProfile(profile, password, scope = "global", projectDir) {
66418
66608
  function deleteProfile(name, scope = "global", projectDir) {
66419
66609
  const sanitized = name.replace(/[^a-zA-Z0-9_-]/g, "");
66420
66610
  const dir = scope === "project" ? projectProfileDir(projectDir) : globalProfileDir();
66421
- const filePath = join71(dir, `${sanitized}.json`);
66422
- if (existsSync54(filePath)) {
66611
+ const filePath = join72(dir, `${sanitized}.json`);
66612
+ if (existsSync55(filePath)) {
66423
66613
  unlinkSync12(filePath);
66424
66614
  return true;
66425
66615
  }
@@ -66512,22 +66702,22 @@ import * as http from "node:http";
66512
66702
  import * as https from "node:https";
66513
66703
  import { createRequire as createRequire3 } from "node:module";
66514
66704
  import { fileURLToPath as fileURLToPath13 } from "node:url";
66515
- import { dirname as dirname21, join as join72, resolve as resolve31 } from "node:path";
66705
+ import { dirname as dirname21, join as join73, resolve as resolve31 } from "node:path";
66516
66706
  import { spawn as spawn21 } from "node:child_process";
66517
- import { mkdirSync as mkdirSync29, writeFileSync as writeFileSync27, readFileSync as readFileSync44, readdirSync as readdirSync21, existsSync as existsSync55 } from "node:fs";
66518
- import { randomBytes as randomBytes16, randomUUID as randomUUID4 } from "node:crypto";
66707
+ import { mkdirSync as mkdirSync29, writeFileSync as writeFileSync27, readFileSync as readFileSync45, readdirSync as readdirSync22, existsSync as existsSync56 } from "node:fs";
66708
+ import { randomBytes as randomBytes16, randomUUID as randomUUID5 } from "node:crypto";
66519
66709
  function getVersion3() {
66520
66710
  try {
66521
66711
  const require2 = createRequire3(import.meta.url);
66522
66712
  const thisDir = dirname21(fileURLToPath13(import.meta.url));
66523
66713
  const candidates = [
66524
- join72(thisDir, "..", "package.json"),
66525
- join72(thisDir, "..", "..", "package.json"),
66526
- join72(thisDir, "..", "..", "..", "package.json")
66714
+ join73(thisDir, "..", "package.json"),
66715
+ join73(thisDir, "..", "..", "package.json"),
66716
+ join73(thisDir, "..", "..", "..", "package.json")
66527
66717
  ];
66528
66718
  for (const pkgPath of candidates) {
66529
66719
  try {
66530
- if (!existsSync55(pkgPath))
66720
+ if (!existsSync56(pkgPath))
66531
66721
  continue;
66532
66722
  const pkg = require2(pkgPath);
66533
66723
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli" || pkg.name === "@open-agents/monorepo") {
@@ -66828,29 +67018,29 @@ function ollamaStream(ollamaUrl, path, method, body, onData, onEnd, onError) {
66828
67018
  }
66829
67019
  function jobsDir() {
66830
67020
  const root = resolve31(process.cwd());
66831
- const dir = join72(root, ".oa", "jobs");
67021
+ const dir = join73(root, ".oa", "jobs");
66832
67022
  mkdirSync29(dir, { recursive: true });
66833
67023
  return dir;
66834
67024
  }
66835
67025
  function loadJob(id) {
66836
- const file = join72(jobsDir(), `${id}.json`);
66837
- if (!existsSync55(file))
67026
+ const file = join73(jobsDir(), `${id}.json`);
67027
+ if (!existsSync56(file))
66838
67028
  return null;
66839
67029
  try {
66840
- return JSON.parse(readFileSync44(file, "utf-8"));
67030
+ return JSON.parse(readFileSync45(file, "utf-8"));
66841
67031
  } catch {
66842
67032
  return null;
66843
67033
  }
66844
67034
  }
66845
67035
  function listJobs() {
66846
67036
  const dir = jobsDir();
66847
- if (!existsSync55(dir))
67037
+ if (!existsSync56(dir))
66848
67038
  return [];
66849
- const files = readdirSync21(dir).filter((f) => f.endsWith(".json")).sort();
67039
+ const files = readdirSync22(dir).filter((f) => f.endsWith(".json")).sort();
66850
67040
  const jobs = [];
66851
67041
  for (const file of files) {
66852
67042
  try {
66853
- jobs.push(JSON.parse(readFileSync44(join72(dir, file), "utf-8")));
67043
+ jobs.push(JSON.parse(readFileSync45(join73(dir, file), "utf-8")));
66854
67044
  } catch {
66855
67045
  }
66856
67046
  }
@@ -67298,7 +67488,7 @@ async function handleV1Run(req, res) {
67298
67488
  if (workingDir) {
67299
67489
  cwd4 = resolve31(workingDir);
67300
67490
  } else if (isolate) {
67301
- const wsDir = join72(dir, "..", "workspaces", id);
67491
+ const wsDir = join73(dir, "..", "workspaces", id);
67302
67492
  mkdirSync29(wsDir, { recursive: true });
67303
67493
  cwd4 = wsDir;
67304
67494
  } else {
@@ -67371,7 +67561,7 @@ async function handleV1Run(req, res) {
67371
67561
  });
67372
67562
  child.unref();
67373
67563
  job.pid = child.pid ?? 0;
67374
- writeFileSync27(join72(dir, `${id}.json`), JSON.stringify(job, null, 2));
67564
+ writeFileSync27(join73(dir, `${id}.json`), JSON.stringify(job, null, 2));
67375
67565
  runningProcesses.set(id, child);
67376
67566
  if (streamMode) {
67377
67567
  res.writeHead(200, {
@@ -67398,7 +67588,7 @@ async function handleV1Run(req, res) {
67398
67588
  job.status = code === 0 ? "completed" : "failed";
67399
67589
  job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
67400
67590
  try {
67401
- writeFileSync27(join72(dir, `${id}.json`), JSON.stringify(job, null, 2));
67591
+ writeFileSync27(join73(dir, `${id}.json`), JSON.stringify(job, null, 2));
67402
67592
  } catch {
67403
67593
  }
67404
67594
  runningProcesses.delete(id);
@@ -67429,7 +67619,7 @@ async function handleV1Run(req, res) {
67429
67619
  job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
67430
67620
  }
67431
67621
  try {
67432
- writeFileSync27(join72(dir, `${id}.json`), JSON.stringify(job, null, 2));
67622
+ writeFileSync27(join73(dir, `${id}.json`), JSON.stringify(job, null, 2));
67433
67623
  } catch {
67434
67624
  }
67435
67625
  runningProcesses.delete(id);
@@ -67478,7 +67668,7 @@ function handleV1RunsDelete(res, id) {
67478
67668
  job.error = "Aborted via API";
67479
67669
  const dir = jobsDir();
67480
67670
  try {
67481
- writeFileSync27(join72(dir, `${id}.json`), JSON.stringify(job, null, 2));
67671
+ writeFileSync27(join73(dir, `${id}.json`), JSON.stringify(job, null, 2));
67482
67672
  } catch {
67483
67673
  }
67484
67674
  runningProcesses.delete(id);
@@ -67623,7 +67813,7 @@ async function handleRequest(req, res, ollamaUrl, verbose) {
67623
67813
  const urlObj = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
67624
67814
  const pathname = urlObj.pathname;
67625
67815
  const startMs = performance.now();
67626
- const requestId = req.headers["x-request-id"] || randomUUID4();
67816
+ const requestId = req.headers["x-request-id"] || randomUUID5();
67627
67817
  res.setHeader("X-Request-ID", requestId);
67628
67818
  if (method === "OPTIONS") {
67629
67819
  if (!corsHeaders(req, res))
@@ -67698,6 +67888,154 @@ async function handleRequest(req, res, ollamaUrl, verbose) {
67698
67888
  return;
67699
67889
  }
67700
67890
  }
67891
+ if (pathname === "/v1/system" && method === "GET") {
67892
+ const os = __require("node:os");
67893
+ const { execSync: es } = __require("node:child_process");
67894
+ let gpus = [];
67895
+ try {
67896
+ const nv = es("nvidia-smi --query-gpu=name,memory.total --format=csv,noheader,nounits", { encoding: "utf8", timeout: 5e3, stdio: "pipe" });
67897
+ for (const line of nv.trim().split("\n")) {
67898
+ const [name, mem] = line.split(",").map((s) => s.trim());
67899
+ if (name && mem)
67900
+ gpus.push({ name, vram_gb: Math.round(parseInt(mem, 10) / 1024) });
67901
+ }
67902
+ } catch {
67903
+ }
67904
+ const totalVram = gpus.reduce((s, g) => s + g.vram_gb, 0);
67905
+ jsonResponse(res, 200, {
67906
+ gpu: gpus,
67907
+ total_vram_gb: totalVram,
67908
+ ram_gb: Math.round(os.totalmem() / 1024 ** 3),
67909
+ cpu: os.cpus()[0]?.model ?? "unknown",
67910
+ cores: os.cpus().length,
67911
+ platform: process.platform,
67912
+ node: process.version,
67913
+ // Model compatibility recommendations
67914
+ recommended_max_params: totalVram >= 80 ? "120B+" : totalVram >= 48 ? "70B" : totalVram >= 24 ? "27B" : totalVram >= 8 ? "9B" : "4B"
67915
+ });
67916
+ return;
67917
+ }
67918
+ if (pathname === "/v1/chat" && method === "POST") {
67919
+ if (!checkAuth(req, res, "run")) {
67920
+ status = 401;
67921
+ return;
67922
+ }
67923
+ const chatBody = await parseJsonBody(req);
67924
+ if (!chatBody?.message || typeof chatBody.message !== "string") {
67925
+ jsonResponse(res, 400, { error: "Missing required field: message" });
67926
+ return;
67927
+ }
67928
+ const sessionId = chatBody.session_id;
67929
+ const model = chatBody.model || loadConfig().model;
67930
+ const session = getSession(sessionId, model, resolve31(process.cwd()));
67931
+ const messages = addUserMessage(session, chatBody.message);
67932
+ compactSession(session);
67933
+ const streamMode = chatBody.stream !== false;
67934
+ const chatRequest = {
67935
+ model: session.model,
67936
+ messages,
67937
+ stream: streamMode,
67938
+ max_tokens: chatBody.max_tokens || 4096
67939
+ };
67940
+ const route = resolveModelEndpoint(session.model);
67941
+ const targetUrl = route?.endpoint?.url || loadConfig().backendUrl;
67942
+ if (streamMode) {
67943
+ res.writeHead(200, {
67944
+ "Content-Type": "text/event-stream",
67945
+ "Cache-Control": "no-cache",
67946
+ "Connection": "keep-alive",
67947
+ "X-Session-ID": session.id
67948
+ });
67949
+ let fullContent = "";
67950
+ try {
67951
+ const url = new URL("/api/chat", targetUrl);
67952
+ const isHttps = url.protocol === "https:";
67953
+ const transport = isHttps ? https : http;
67954
+ const reqBody = JSON.stringify({
67955
+ model: session.model.replace(/^local\//, ""),
67956
+ messages: messages.map((m) => ({ role: m.role, content: m.content })),
67957
+ stream: true
67958
+ });
67959
+ await new Promise((resolve36, reject) => {
67960
+ const proxyReq = transport.request({
67961
+ hostname: url.hostname,
67962
+ port: url.port || (isHttps ? 443 : 80),
67963
+ path: url.pathname,
67964
+ method: "POST",
67965
+ headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(reqBody) }
67966
+ }, (proxyRes) => {
67967
+ let buffer = "";
67968
+ proxyRes.on("data", (chunk) => {
67969
+ buffer += chunk.toString();
67970
+ const lines = buffer.split("\n");
67971
+ buffer = lines.pop() || "";
67972
+ for (const line of lines) {
67973
+ if (!line.trim())
67974
+ continue;
67975
+ try {
67976
+ const parsed = JSON.parse(line);
67977
+ if (parsed.message?.content) {
67978
+ fullContent += parsed.message.content;
67979
+ const sseChunk = {
67980
+ id: `chatcmpl-${session.id.slice(0, 8)}`,
67981
+ object: "chat.completion.chunk",
67982
+ choices: [{ index: 0, delta: { content: parsed.message.content }, finish_reason: null }]
67983
+ };
67984
+ res.write("data: " + JSON.stringify(sseChunk) + "\n\n");
67985
+ }
67986
+ if (parsed.done) {
67987
+ trackSessionTokens(session, parsed.prompt_eval_count ?? 0, parsed.eval_count ?? 0);
67988
+ trackTokens("local", parsed.prompt_eval_count ?? 0, parsed.eval_count ?? 0);
67989
+ metrics.totalTokensIn += parsed.prompt_eval_count ?? 0;
67990
+ metrics.totalTokensOut += parsed.eval_count ?? 0;
67991
+ res.write("data: [DONE]\n\n");
67992
+ }
67993
+ } catch {
67994
+ }
67995
+ }
67996
+ });
67997
+ proxyRes.on("end", resolve36);
67998
+ proxyRes.on("error", reject);
67999
+ });
68000
+ proxyReq.setTimeout(12e4, () => proxyReq.destroy(new Error("Chat stream timeout")));
68001
+ proxyReq.on("error", reject);
68002
+ proxyReq.write(reqBody);
68003
+ proxyReq.end();
68004
+ });
68005
+ } catch (e) {
68006
+ res.write("data: " + JSON.stringify({ error: e.message }) + "\n\n");
68007
+ }
68008
+ addAssistantMessage(session, fullContent);
68009
+ res.end();
68010
+ } else {
68011
+ try {
68012
+ const result = await ollamaRequest(targetUrl, "/api/chat", "POST", JSON.stringify({
68013
+ model: session.model.replace(/^local\//, ""),
68014
+ messages: messages.map((m) => ({ role: m.role, content: m.content })),
68015
+ stream: false
68016
+ }));
68017
+ const parsed = JSON.parse(result.body);
68018
+ const content = parsed.message?.content ?? "";
68019
+ addAssistantMessage(session, content);
68020
+ trackSessionTokens(session, parsed.prompt_eval_count ?? 0, parsed.eval_count ?? 0);
68021
+ trackTokens("local", parsed.prompt_eval_count ?? 0, parsed.eval_count ?? 0);
68022
+ jsonResponse(res, 200, {
68023
+ session_id: session.id,
68024
+ message: { role: "assistant", content },
68025
+ usage: { prompt_tokens: parsed.prompt_eval_count ?? 0, completion_tokens: parsed.eval_count ?? 0 }
68026
+ });
68027
+ } catch (e) {
68028
+ jsonResponse(res, 500, { error: "Chat failed", message: e.message });
68029
+ }
68030
+ }
68031
+ return;
68032
+ }
68033
+ if (pathname === "/v1/chat/sessions" && method === "GET") {
68034
+ if (!checkAuth(req, res, "read"))
68035
+ return;
68036
+ jsonResponse(res, 200, { sessions: listSessions() });
68037
+ return;
68038
+ }
67701
68039
  if (pathname === "/v1/models" && method === "GET") {
67702
68040
  await handleV1Models(res, ollamaUrl);
67703
68041
  return;
@@ -67920,20 +68258,20 @@ function startApiServer(options = {}) {
67920
68258
  const config = loadConfig();
67921
68259
  const ollamaUrl = options.ollamaUrl ?? config.backendUrl;
67922
68260
  const cwd4 = process.cwd();
67923
- initAuditLog(join72(cwd4, ".oa"));
67924
- initUsageTracker(join72(cwd4, ".oa"));
68261
+ initAuditLog(join73(cwd4, ".oa"));
68262
+ initUsageTracker(join73(cwd4, ".oa"));
67925
68263
  const retentionDays = parseInt(process.env["OA_JOB_RETENTION_DAYS"] ?? "30", 10);
67926
68264
  if (retentionDays > 0) {
67927
68265
  try {
67928
- const jobsDir3 = join72(cwd4, ".oa", "jobs");
67929
- if (existsSync55(jobsDir3)) {
68266
+ const jobsDir3 = join73(cwd4, ".oa", "jobs");
68267
+ if (existsSync56(jobsDir3)) {
67930
68268
  const cutoff = Date.now() - retentionDays * 864e5;
67931
- for (const f of readdirSync21(jobsDir3)) {
68269
+ for (const f of readdirSync22(jobsDir3)) {
67932
68270
  if (!f.endsWith(".json"))
67933
68271
  continue;
67934
68272
  try {
67935
- const jobPath = join72(jobsDir3, f);
67936
- const job = JSON.parse(readFileSync44(jobPath, "utf-8"));
68273
+ const jobPath = join73(jobsDir3, f);
68274
+ const job = JSON.parse(readFileSync45(jobPath, "utf-8"));
67937
68275
  const jobTime = new Date(job.startedAt ?? job.completedAt ?? 0).getTime();
67938
68276
  if (jobTime > 0 && jobTime < cutoff && job.status !== "running") {
67939
68277
  const { unlinkSync: unlinkSync13 } = __require("node:fs");
@@ -67953,8 +68291,8 @@ function startApiServer(options = {}) {
67953
68291
  if (useTls) {
67954
68292
  try {
67955
68293
  tlsOpts = {
67956
- cert: readFileSync44(resolve31(tlsCert)),
67957
- key: readFileSync44(resolve31(tlsKey))
68294
+ cert: readFileSync45(resolve31(tlsCert)),
68295
+ key: readFileSync45(resolve31(tlsKey))
67958
68296
  };
67959
68297
  } catch (e) {
67960
68298
  log2(`
@@ -68104,6 +68442,7 @@ var init_serve = __esm({
68104
68442
  init_logger();
68105
68443
  init_openapi();
68106
68444
  init_auth_oidc();
68445
+ init_chat_session();
68107
68446
  init_usage_tracker();
68108
68447
  init_oa_directory();
68109
68448
  init_render();
@@ -68127,11 +68466,11 @@ var init_serve = __esm({
68127
68466
 
68128
68467
  // packages/cli/dist/tui/interactive.js
68129
68468
  import { cwd } from "node:process";
68130
- import { resolve as resolve32, join as join73, dirname as dirname22, extname as extname11 } from "node:path";
68469
+ import { resolve as resolve32, join as join74, dirname as dirname22, extname as extname11 } from "node:path";
68131
68470
  import { createRequire as createRequire4 } from "node:module";
68132
68471
  import { fileURLToPath as fileURLToPath14 } from "node:url";
68133
- import { readFileSync as readFileSync45, writeFileSync as writeFileSync28, appendFileSync as appendFileSync5, rmSync as rmSync3, readdirSync as readdirSync22, mkdirSync as mkdirSync30 } from "node:fs";
68134
- import { existsSync as existsSync56 } from "node:fs";
68472
+ import { readFileSync as readFileSync46, writeFileSync as writeFileSync28, appendFileSync as appendFileSync5, rmSync as rmSync3, readdirSync as readdirSync23, mkdirSync as mkdirSync30 } from "node:fs";
68473
+ import { existsSync as existsSync57 } from "node:fs";
68135
68474
  import { execSync as execSync35 } from "node:child_process";
68136
68475
  import { homedir as homedir19 } from "node:os";
68137
68476
  function formatTimeAgo(date) {
@@ -68152,12 +68491,12 @@ function getVersion4() {
68152
68491
  const require2 = createRequire4(import.meta.url);
68153
68492
  const thisDir = dirname22(fileURLToPath14(import.meta.url));
68154
68493
  const candidates = [
68155
- join73(thisDir, "..", "package.json"),
68156
- join73(thisDir, "..", "..", "package.json"),
68157
- join73(thisDir, "..", "..", "..", "package.json")
68494
+ join74(thisDir, "..", "package.json"),
68495
+ join74(thisDir, "..", "..", "package.json"),
68496
+ join74(thisDir, "..", "..", "..", "package.json")
68158
68497
  ];
68159
68498
  for (const pkgPath of candidates) {
68160
- if (existsSync56(pkgPath)) {
68499
+ if (existsSync57(pkgPath)) {
68161
68500
  const pkg = require2(pkgPath);
68162
68501
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli" || pkg.name === "@open-agents/monorepo") {
68163
68502
  return pkg.version ?? "0.0.0";
@@ -68396,15 +68735,15 @@ Use task_status("${taskId}") or task_output("${taskId}") to check progress.`
68396
68735
  function gatherMemorySnippets(root) {
68397
68736
  const snippets = [];
68398
68737
  const dirs = [
68399
- join73(root, ".oa", "memory"),
68400
- join73(root, ".open-agents", "memory")
68738
+ join74(root, ".oa", "memory"),
68739
+ join74(root, ".open-agents", "memory")
68401
68740
  ];
68402
68741
  for (const dir of dirs) {
68403
- if (!existsSync56(dir))
68742
+ if (!existsSync57(dir))
68404
68743
  continue;
68405
68744
  try {
68406
- for (const f of readdirSync22(dir).filter((f2) => f2.endsWith(".json"))) {
68407
- const data = JSON.parse(readFileSync45(join73(dir, f), "utf-8"));
68745
+ for (const f of readdirSync23(dir).filter((f2) => f2.endsWith(".json"))) {
68746
+ const data = JSON.parse(readFileSync46(join74(dir, f), "utf-8"));
68408
68747
  for (const val of Object.values(data)) {
68409
68748
  const v = typeof val === "object" && val !== null && "value" in val ? String(val.value) : String(val);
68410
68749
  if (v.length > 10)
@@ -68561,9 +68900,9 @@ ${metabolismMemories}
68561
68900
  } catch {
68562
68901
  }
68563
68902
  try {
68564
- const archeFile = join73(repoRoot, ".oa", "arche", "variants.json");
68565
- if (existsSync56(archeFile)) {
68566
- const variants = JSON.parse(readFileSync45(archeFile, "utf8"));
68903
+ const archeFile = join74(repoRoot, ".oa", "arche", "variants.json");
68904
+ if (existsSync57(archeFile)) {
68905
+ const variants = JSON.parse(readFileSync46(archeFile, "utf8"));
68567
68906
  if (variants.length > 0) {
68568
68907
  let filtered = variants;
68569
68908
  if (taskType) {
@@ -68732,9 +69071,9 @@ RULES:
68732
69071
  const compactionThreshold = modelTier === "small" ? 12e3 : modelTier === "medium" ? 24e3 : 4e4;
68733
69072
  let identityInjection = "";
68734
69073
  try {
68735
- const ikStateFile = join73(repoRoot, ".oa", "identity", "self-state.json");
68736
- if (existsSync56(ikStateFile)) {
68737
- const selfState = JSON.parse(readFileSync45(ikStateFile, "utf8"));
69074
+ const ikStateFile = join74(repoRoot, ".oa", "identity", "self-state.json");
69075
+ if (existsSync57(ikStateFile)) {
69076
+ const selfState = JSON.parse(readFileSync46(ikStateFile, "utf8"));
68738
69077
  const lines = [
68739
69078
  `[Identity State v${selfState.version}]`,
68740
69079
  `Self: ${selfState.narrative_summary}`,
@@ -69378,11 +69717,11 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
69378
69717
  });
69379
69718
  }
69380
69719
  try {
69381
- const ikDir = join73(repoRoot, ".oa", "identity");
69382
- const ikFile = join73(ikDir, "self-state.json");
69720
+ const ikDir = join74(repoRoot, ".oa", "identity");
69721
+ const ikFile = join74(ikDir, "self-state.json");
69383
69722
  let ikState;
69384
- if (existsSync56(ikFile)) {
69385
- ikState = JSON.parse(readFileSync45(ikFile, "utf8"));
69723
+ if (existsSync57(ikFile)) {
69724
+ ikState = JSON.parse(readFileSync46(ikFile, "utf8"));
69386
69725
  } else {
69387
69726
  mkdirSync30(ikDir, { recursive: true });
69388
69727
  const machineId = Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
@@ -69425,9 +69764,9 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
69425
69764
  } else {
69426
69765
  renderTaskIncomplete(result.turns, result.toolCalls, result.durationMs, tokens);
69427
69766
  try {
69428
- const ikFile = join73(repoRoot, ".oa", "identity", "self-state.json");
69429
- if (existsSync56(ikFile)) {
69430
- const ikState = JSON.parse(readFileSync45(ikFile, "utf8"));
69767
+ const ikFile = join74(repoRoot, ".oa", "identity", "self-state.json");
69768
+ if (existsSync57(ikFile)) {
69769
+ const ikState = JSON.parse(readFileSync46(ikFile, "utf8"));
69431
69770
  ikState.homeostasis.uncertainty = Math.min(1, ikState.homeostasis.uncertainty + 0.1);
69432
69771
  ikState.homeostasis.coherence = Math.max(0, ikState.homeostasis.coherence - 0.05);
69433
69772
  ikState.session_count = (ikState.session_count || 0) + 1;
@@ -69529,10 +69868,10 @@ async function startInteractive(config, repoPath) {
69529
69868
  process.stdin.pause();
69530
69869
  }
69531
69870
  try {
69532
- const oaDir = join73(repoRoot, ".oa");
69533
- const nexusPidFile = join73(oaDir, "nexus", "daemon.pid");
69534
- if (existsSync56(nexusPidFile)) {
69535
- const pid = parseInt(readFileSync45(nexusPidFile, "utf8").trim(), 10);
69871
+ const oaDir = join74(repoRoot, ".oa");
69872
+ const nexusPidFile = join74(oaDir, "nexus", "daemon.pid");
69873
+ if (existsSync57(nexusPidFile)) {
69874
+ const pid = parseInt(readFileSync46(nexusPidFile, "utf8").trim(), 10);
69536
69875
  if (pid > 0) {
69537
69876
  try {
69538
69877
  process.kill(pid, 0);
@@ -69869,7 +70208,7 @@ Review its full output in the [${id}] tab or via full_sub_agent(action='output',
69869
70208
  let p2pGateway = null;
69870
70209
  let peerMesh = null;
69871
70210
  let inferenceRouter = null;
69872
- const secretVault = new SecretVault(join73(repoRoot, ".oa", "vault.enc"));
70211
+ const secretVault = new SecretVault(join74(repoRoot, ".oa", "vault.enc"));
69873
70212
  let adminSessionKey = null;
69874
70213
  const callSubAgents = /* @__PURE__ */ new Map();
69875
70214
  const streamRenderer = new StreamRenderer();
@@ -70092,13 +70431,13 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
70092
70431
  const hits = allCompletions.filter((c3) => c3.toLowerCase().startsWith(lower));
70093
70432
  return [hits, line];
70094
70433
  }
70095
- const HISTORY_DIR = join73(homedir19(), ".open-agents");
70096
- const HISTORY_FILE = join73(HISTORY_DIR, "repl-history");
70434
+ const HISTORY_DIR = join74(homedir19(), ".open-agents");
70435
+ const HISTORY_FILE = join74(HISTORY_DIR, "repl-history");
70097
70436
  const MAX_HISTORY_LINES = 500;
70098
70437
  let savedHistory = [];
70099
70438
  try {
70100
- if (existsSync56(HISTORY_FILE)) {
70101
- const raw = readFileSync45(HISTORY_FILE, "utf8").trim();
70439
+ if (existsSync57(HISTORY_FILE)) {
70440
+ const raw = readFileSync46(HISTORY_FILE, "utf8").trim();
70102
70441
  if (raw)
70103
70442
  savedHistory = raw.split("\n").reverse();
70104
70443
  }
@@ -70204,7 +70543,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
70204
70543
  mkdirSync30(HISTORY_DIR, { recursive: true });
70205
70544
  appendFileSync5(HISTORY_FILE, line + "\n", "utf8");
70206
70545
  if (Math.random() < 0.02) {
70207
- const all = readFileSync45(HISTORY_FILE, "utf8").trim().split("\n");
70546
+ const all = readFileSync46(HISTORY_FILE, "utf8").trim().split("\n");
70208
70547
  if (all.length > MAX_HISTORY_LINES) {
70209
70548
  writeFileSync28(HISTORY_FILE, all.slice(-MAX_HISTORY_LINES).join("\n") + "\n", "utf8");
70210
70549
  }
@@ -70390,7 +70729,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
70390
70729
  } catch {
70391
70730
  }
70392
70731
  try {
70393
- const oaDir = join73(repoRoot, ".oa");
70732
+ const oaDir = join74(repoRoot, ".oa");
70394
70733
  const reconnected = await ExposeGateway.checkAndReconnect(oaDir, {
70395
70734
  onInfo: (msg) => writeContent(() => renderInfo(msg)),
70396
70735
  onError: (msg) => writeContent(() => renderWarning(msg))
@@ -70422,7 +70761,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
70422
70761
  } catch {
70423
70762
  }
70424
70763
  try {
70425
- const oaDir = join73(repoRoot, ".oa");
70764
+ const oaDir = join74(repoRoot, ".oa");
70426
70765
  const reconnectedP2P = await ExposeP2PGateway.checkAndReconnect(oaDir, new NexusTool(repoRoot), {
70427
70766
  onInfo: (msg) => writeContent(() => renderInfo(msg)),
70428
70767
  onError: (msg) => writeContent(() => renderWarning(msg))
@@ -70463,11 +70802,11 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
70463
70802
  }
70464
70803
  try {
70465
70804
  const { homedir: _hd, hostname: _hn, userInfo: _ui } = await import("node:os");
70466
- const globalNamePath = join73(_hd(), ".open-agents", "agent-name");
70805
+ const globalNamePath = join74(_hd(), ".open-agents", "agent-name");
70467
70806
  let agName = "";
70468
70807
  try {
70469
- if (existsSync56(globalNamePath))
70470
- agName = readFileSync45(globalNamePath, "utf8").trim();
70808
+ if (existsSync57(globalNamePath))
70809
+ agName = readFileSync46(globalNamePath, "utf8").trim();
70471
70810
  } catch {
70472
70811
  }
70473
70812
  if (!agName) {
@@ -71443,7 +71782,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
71443
71782
  kind,
71444
71783
  targetUrl,
71445
71784
  authKey,
71446
- stateDir: join73(repoRoot, ".oa"),
71785
+ stateDir: join74(repoRoot, ".oa"),
71447
71786
  passthrough: passthrough ?? false,
71448
71787
  loadbalance: loadbalance ?? false,
71449
71788
  endpointAuth: passthrough ? currentConfig.apiKey : void 0,
@@ -71489,7 +71828,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
71489
71828
  await tunnelGateway.stop();
71490
71829
  tunnelGateway = null;
71491
71830
  }
71492
- const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir: join73(repoRoot, ".oa") });
71831
+ const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir: join74(repoRoot, ".oa") });
71493
71832
  newTunnel.on("stats", (stats) => {
71494
71833
  statusBar.setExposeStatus({
71495
71834
  status: stats.status,
@@ -71578,9 +71917,9 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
71578
71917
  if (!result.success)
71579
71918
  throw new Error(result.error || "Connect failed");
71580
71919
  try {
71581
- const nexusPidFile = join73(repoRoot, ".oa", "nexus", "daemon.pid");
71582
- if (existsSync56(nexusPidFile)) {
71583
- const pid = parseInt(readFileSync45(nexusPidFile, "utf8").trim(), 10);
71920
+ const nexusPidFile = join74(repoRoot, ".oa", "nexus", "daemon.pid");
71921
+ if (existsSync57(nexusPidFile)) {
71922
+ const pid = parseInt(readFileSync46(nexusPidFile, "utf8").trim(), 10);
71584
71923
  if (pid > 0) {
71585
71924
  registry.register({
71586
71925
  name: "Nexus",
@@ -71776,10 +72115,10 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
71776
72115
  writeContent(() => renderInfo(`Killed ${bgKilled} background task(s).`));
71777
72116
  }
71778
72117
  try {
71779
- const nexusDir = join73(repoRoot, OA_DIR, "nexus");
71780
- const pidFile = join73(nexusDir, "daemon.pid");
71781
- if (existsSync56(pidFile)) {
71782
- const pid = parseInt(readFileSync45(pidFile, "utf8").trim(), 10);
72118
+ const nexusDir = join74(repoRoot, OA_DIR, "nexus");
72119
+ const pidFile = join74(nexusDir, "daemon.pid");
72120
+ if (existsSync57(pidFile)) {
72121
+ const pid = parseInt(readFileSync46(pidFile, "utf8").trim(), 10);
71783
72122
  if (pid > 0) {
71784
72123
  try {
71785
72124
  if (process.platform === "win32") {
@@ -71801,13 +72140,13 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
71801
72140
  } catch {
71802
72141
  }
71803
72142
  try {
71804
- const voiceDir2 = join73(homedir19(), ".open-agents", "voice");
72143
+ const voiceDir2 = join74(homedir19(), ".open-agents", "voice");
71805
72144
  const voicePidFiles = ["luxtts-daemon.pid", "piper-daemon.pid"];
71806
72145
  for (const pf of voicePidFiles) {
71807
- const pidPath = join73(voiceDir2, pf);
71808
- if (existsSync56(pidPath)) {
72146
+ const pidPath = join74(voiceDir2, pf);
72147
+ if (existsSync57(pidPath)) {
71809
72148
  try {
71810
- const pid = parseInt(readFileSync45(pidPath, "utf8").trim(), 10);
72149
+ const pid = parseInt(readFileSync46(pidPath, "utf8").trim(), 10);
71811
72150
  if (pid > 0) {
71812
72151
  if (process.platform === "win32") {
71813
72152
  try {
@@ -71831,8 +72170,8 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
71831
72170
  execSync35(process.platform === "win32" ? "timeout /t 1 /nobreak >nul" : "sleep 0.5", { timeout: 3e3, stdio: "ignore" });
71832
72171
  } catch {
71833
72172
  }
71834
- const oaPath = join73(repoRoot, OA_DIR);
71835
- if (existsSync56(oaPath)) {
72173
+ const oaPath = join74(repoRoot, OA_DIR);
72174
+ if (existsSync57(oaPath)) {
71836
72175
  let deleted = false;
71837
72176
  for (let attempt = 0; attempt < 3; attempt++) {
71838
72177
  try {
@@ -71915,19 +72254,19 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
71915
72254
  try {
71916
72255
  const { isPersonaPlexRunning: isPersonaPlexRunning2 } = await Promise.resolve().then(() => (init_personaplex(), personaplex_exports));
71917
72256
  if (isPersonaPlexRunning2()) {
71918
- const ppPidFile = join73(homedir19(), ".open-agents", "voice", "personaplex", "daemon.pid");
71919
- const ppPortFile = join73(homedir19(), ".open-agents", "voice", "personaplex", "daemon.port");
71920
- if (existsSync56(ppPidFile)) {
71921
- const ppPid = parseInt(readFileSync45(ppPidFile, "utf8").trim(), 10);
71922
- const ppPort = existsSync56(ppPortFile) ? parseInt(readFileSync45(ppPortFile, "utf8").trim(), 10) : void 0;
72257
+ const ppPidFile = join74(homedir19(), ".open-agents", "voice", "personaplex", "daemon.pid");
72258
+ const ppPortFile = join74(homedir19(), ".open-agents", "voice", "personaplex", "daemon.port");
72259
+ if (existsSync57(ppPidFile)) {
72260
+ const ppPid = parseInt(readFileSync46(ppPidFile, "utf8").trim(), 10);
72261
+ const ppPort = existsSync57(ppPortFile) ? parseInt(readFileSync46(ppPortFile, "utf8").trim(), 10) : void 0;
71923
72262
  if (ppPid > 0 && !registry.daemons.has("PersonaPlex")) {
71924
72263
  registry.register({ name: "PersonaPlex", pid: ppPid, port: ppPort, startedAt: Date.now(), status: "running" });
71925
72264
  }
71926
72265
  }
71927
72266
  }
71928
- const nexusPidFile = join73(repoRoot, ".oa", "nexus", "daemon.pid");
71929
- if (existsSync56(nexusPidFile)) {
71930
- const nPid = parseInt(readFileSync45(nexusPidFile, "utf8").trim(), 10);
72267
+ const nexusPidFile = join74(repoRoot, ".oa", "nexus", "daemon.pid");
72268
+ if (existsSync57(nexusPidFile)) {
72269
+ const nPid = parseInt(readFileSync46(nexusPidFile, "utf8").trim(), 10);
71931
72270
  if (nPid > 0 && !registry.daemons.has("Nexus")) {
71932
72271
  try {
71933
72272
  process.kill(nPid, 0);
@@ -72269,8 +72608,8 @@ Execute this skill now. Follow the behavioral guidance above.`;
72269
72608
  }
72270
72609
  }
72271
72610
  const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
72272
- const isImage = isImagePath(cleanPath) && existsSync56(resolve32(repoRoot, cleanPath));
72273
- const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync56(resolve32(repoRoot, cleanPath));
72611
+ const isImage = isImagePath(cleanPath) && existsSync57(resolve32(repoRoot, cleanPath));
72612
+ const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync57(resolve32(repoRoot, cleanPath));
72274
72613
  if (activeTask) {
72275
72614
  if (activeTask.runner.isPaused) {
72276
72615
  activeTask.runner.resume();
@@ -72279,7 +72618,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
72279
72618
  if (isImage) {
72280
72619
  try {
72281
72620
  const imgPath = resolve32(repoRoot, cleanPath);
72282
- const imgBuffer = readFileSync45(imgPath);
72621
+ const imgBuffer = readFileSync46(imgPath);
72283
72622
  const base64 = imgBuffer.toString("base64");
72284
72623
  const ext = extname11(cleanPath).toLowerCase();
72285
72624
  const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/jpeg";
@@ -72494,7 +72833,7 @@ Summarize or analyze this transcription as appropriate.`;
72494
72833
 
72495
72834
  NEW TASK: ${fullInput}`;
72496
72835
  restoredSessionContext = null;
72497
- } else if (existsSync56(join73(repoRoot, ".oa", "context", "session-diary.md"))) {
72836
+ } else if (existsSync57(join74(repoRoot, ".oa", "context", "session-diary.md"))) {
72498
72837
  taskInput = `[Previous sessions exist \u2014 file_read(".oa/context/session-diary.md") to recall]
72499
72838
 
72500
72839
  ${fullInput}`;
@@ -72811,11 +73150,11 @@ async function runWithTUI(task, config, repoPath) {
72811
73150
  const handle = startTask(task, config, repoRoot);
72812
73151
  await handle.promise;
72813
73152
  try {
72814
- const ikDir = join73(repoRoot, ".oa", "identity");
72815
- const ikFile = join73(ikDir, "self-state.json");
73153
+ const ikDir = join74(repoRoot, ".oa", "identity");
73154
+ const ikFile = join74(ikDir, "self-state.json");
72816
73155
  let ikState;
72817
- if (existsSync56(ikFile)) {
72818
- ikState = JSON.parse(readFileSync45(ikFile, "utf8"));
73156
+ if (existsSync57(ikFile)) {
73157
+ ikState = JSON.parse(readFileSync46(ikFile, "utf8"));
72819
73158
  } else {
72820
73159
  mkdirSync30(ikDir, { recursive: true });
72821
73160
  ikState = {
@@ -72848,12 +73187,12 @@ async function runWithTUI(task, config, repoPath) {
72848
73187
  ec.archiveVariantSync(`Task: ${task.slice(0, 200)}`, "success \u2014 completed", ["general"]);
72849
73188
  } catch {
72850
73189
  try {
72851
- const archeDir = join73(repoRoot, ".oa", "arche");
72852
- const archeFile = join73(archeDir, "variants.json");
73190
+ const archeDir = join74(repoRoot, ".oa", "arche");
73191
+ const archeFile = join74(archeDir, "variants.json");
72853
73192
  let variants = [];
72854
73193
  try {
72855
- if (existsSync56(archeFile))
72856
- variants = JSON.parse(readFileSync45(archeFile, "utf8"));
73194
+ if (existsSync57(archeFile))
73195
+ variants = JSON.parse(readFileSync46(archeFile, "utf8"));
72857
73196
  } catch {
72858
73197
  }
72859
73198
  variants.push({
@@ -72874,9 +73213,9 @@ async function runWithTUI(task, config, repoPath) {
72874
73213
  }
72875
73214
  }
72876
73215
  try {
72877
- const metaFile = join73(repoRoot, ".oa", "memory", "metabolism", "store.json");
72878
- if (existsSync56(metaFile)) {
72879
- const store2 = JSON.parse(readFileSync45(metaFile, "utf8"));
73216
+ const metaFile = join74(repoRoot, ".oa", "memory", "metabolism", "store.json");
73217
+ if (existsSync57(metaFile)) {
73218
+ const store2 = JSON.parse(readFileSync46(metaFile, "utf8"));
72880
73219
  const surfaced = store2.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);
72881
73220
  let updated = false;
72882
73221
  for (const item of surfaced) {
@@ -72940,9 +73279,9 @@ Rules:
72940
73279
  try {
72941
73280
  const { initDb: initDb2 } = __require("@open-agents/memory");
72942
73281
  const { ProceduralMemoryStore: ProceduralMemoryStore2 } = __require("@open-agents/memory");
72943
- const dbDir = join73(repoRoot, ".oa", "memory");
73282
+ const dbDir = join74(repoRoot, ".oa", "memory");
72944
73283
  mkdirSync30(dbDir, { recursive: true });
72945
- const db = initDb2(join73(dbDir, "structured.db"));
73284
+ const db = initDb2(join74(dbDir, "structured.db"));
72946
73285
  const memStore = new ProceduralMemoryStore2(db);
72947
73286
  memStore.createWithEmbedding({
72948
73287
  content: content.slice(0, 600),
@@ -72957,12 +73296,12 @@ Rules:
72957
73296
  db.close();
72958
73297
  } catch {
72959
73298
  }
72960
- const metaDir = join73(repoRoot, ".oa", "memory", "metabolism");
72961
- const storeFile = join73(metaDir, "store.json");
73299
+ const metaDir = join74(repoRoot, ".oa", "memory", "metabolism");
73300
+ const storeFile = join74(metaDir, "store.json");
72962
73301
  let store2 = [];
72963
73302
  try {
72964
- if (existsSync56(storeFile))
72965
- store2 = JSON.parse(readFileSync45(storeFile, "utf8"));
73303
+ if (existsSync57(storeFile))
73304
+ store2 = JSON.parse(readFileSync46(storeFile, "utf8"));
72966
73305
  } catch {
72967
73306
  }
72968
73307
  store2.push({
@@ -72985,19 +73324,19 @@ Rules:
72985
73324
  } catch {
72986
73325
  }
72987
73326
  try {
72988
- const cohereSettingsFile = join73(repoRoot, ".oa", "settings.json");
73327
+ const cohereSettingsFile = join74(repoRoot, ".oa", "settings.json");
72989
73328
  let cohereActive = false;
72990
73329
  try {
72991
- if (existsSync56(cohereSettingsFile)) {
72992
- const settings = JSON.parse(readFileSync45(cohereSettingsFile, "utf8"));
73330
+ if (existsSync57(cohereSettingsFile)) {
73331
+ const settings = JSON.parse(readFileSync46(cohereSettingsFile, "utf8"));
72993
73332
  cohereActive = settings.cohere === true;
72994
73333
  }
72995
73334
  } catch {
72996
73335
  }
72997
73336
  if (cohereActive) {
72998
- const metaFile = join73(repoRoot, ".oa", "memory", "metabolism", "store.json");
72999
- if (existsSync56(metaFile)) {
73000
- const store2 = JSON.parse(readFileSync45(metaFile, "utf8"));
73337
+ const metaFile = join74(repoRoot, ".oa", "memory", "metabolism", "store.json");
73338
+ if (existsSync57(metaFile)) {
73339
+ const store2 = JSON.parse(readFileSync46(metaFile, "utf8"));
73001
73340
  const latest = store2.filter((m) => m.sourceTrace === "trajectory-extraction" || m.sourceTrace === "llm-trajectory-extraction").slice(-1)[0];
73002
73341
  if (latest && latest.scores?.confidence >= 0.6) {
73003
73342
  try {
@@ -73022,18 +73361,18 @@ Rules:
73022
73361
  }
73023
73362
  } catch (err) {
73024
73363
  try {
73025
- const ikFile = join73(repoRoot, ".oa", "identity", "self-state.json");
73026
- if (existsSync56(ikFile)) {
73027
- const ikState = JSON.parse(readFileSync45(ikFile, "utf8"));
73364
+ const ikFile = join74(repoRoot, ".oa", "identity", "self-state.json");
73365
+ if (existsSync57(ikFile)) {
73366
+ const ikState = JSON.parse(readFileSync46(ikFile, "utf8"));
73028
73367
  ikState.homeostasis.uncertainty = Math.min(1, ikState.homeostasis.uncertainty + 0.1);
73029
73368
  ikState.homeostasis.coherence = Math.max(0, ikState.homeostasis.coherence - 0.05);
73030
73369
  ikState.session_count = (ikState.session_count || 0) + 1;
73031
73370
  ikState.updated_at = (/* @__PURE__ */ new Date()).toISOString();
73032
73371
  writeFileSync28(ikFile, JSON.stringify(ikState, null, 2));
73033
73372
  }
73034
- const metaFile = join73(repoRoot, ".oa", "memory", "metabolism", "store.json");
73035
- if (existsSync56(metaFile)) {
73036
- const store2 = JSON.parse(readFileSync45(metaFile, "utf8"));
73373
+ const metaFile = join74(repoRoot, ".oa", "memory", "metabolism", "store.json");
73374
+ if (existsSync57(metaFile)) {
73375
+ const store2 = JSON.parse(readFileSync46(metaFile, "utf8"));
73037
73376
  const surfaced = store2.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);
73038
73377
  for (const item of surfaced) {
73039
73378
  item.accessCount = (item.accessCount || 0) + 1;
@@ -73044,12 +73383,12 @@ Rules:
73044
73383
  writeFileSync28(metaFile, JSON.stringify(store2, null, 2));
73045
73384
  }
73046
73385
  try {
73047
- const archeDir = join73(repoRoot, ".oa", "arche");
73048
- const archeFile = join73(archeDir, "variants.json");
73386
+ const archeDir = join74(repoRoot, ".oa", "arche");
73387
+ const archeFile = join74(archeDir, "variants.json");
73049
73388
  let variants = [];
73050
73389
  try {
73051
- if (existsSync56(archeFile))
73052
- variants = JSON.parse(readFileSync45(archeFile, "utf8"));
73390
+ if (existsSync57(archeFile))
73391
+ variants = JSON.parse(readFileSync46(archeFile, "utf8"));
73053
73392
  } catch {
73054
73393
  }
73055
73394
  variants.push({
@@ -73135,12 +73474,12 @@ __export(run_exports, {
73135
73474
  });
73136
73475
  import { resolve as resolve33 } from "node:path";
73137
73476
  import { spawn as spawn22 } from "node:child_process";
73138
- import { mkdirSync as mkdirSync31, writeFileSync as writeFileSync29, readFileSync as readFileSync46, readdirSync as readdirSync23, existsSync as existsSync57 } from "node:fs";
73477
+ import { mkdirSync as mkdirSync31, writeFileSync as writeFileSync29, readFileSync as readFileSync47, readdirSync as readdirSync24, existsSync as existsSync58 } from "node:fs";
73139
73478
  import { randomBytes as randomBytes17 } from "node:crypto";
73140
- import { join as join74 } from "node:path";
73479
+ import { join as join75 } from "node:path";
73141
73480
  function jobsDir2(repoPath) {
73142
73481
  const root = resolve33(repoPath ?? process.cwd());
73143
- const dir = join74(root, ".oa", "jobs");
73482
+ const dir = join75(root, ".oa", "jobs");
73144
73483
  mkdirSync31(dir, { recursive: true });
73145
73484
  return dir;
73146
73485
  }
@@ -73226,7 +73565,7 @@ async function runBackground(task, config, opts) {
73226
73565
  });
73227
73566
  child.unref();
73228
73567
  job.pid = child.pid ?? 0;
73229
- writeFileSync29(join74(dir, `${id}.json`), JSON.stringify(job, null, 2));
73568
+ writeFileSync29(join75(dir, `${id}.json`), JSON.stringify(job, null, 2));
73230
73569
  let output = "";
73231
73570
  child.stdout?.on("data", (chunk) => {
73232
73571
  output += chunk.toString();
@@ -73242,7 +73581,7 @@ async function runBackground(task, config, opts) {
73242
73581
  job.summary = result.summary;
73243
73582
  job.durationMs = result.durationMs;
73244
73583
  job.error = result.error;
73245
- writeFileSync29(join74(dir, `${id}.json`), JSON.stringify(job, null, 2));
73584
+ writeFileSync29(join75(dir, `${id}.json`), JSON.stringify(job, null, 2));
73246
73585
  } catch {
73247
73586
  }
73248
73587
  });
@@ -73258,13 +73597,13 @@ async function runBackground(task, config, opts) {
73258
73597
  }
73259
73598
  function statusCommand(jobId, repoPath) {
73260
73599
  const dir = jobsDir2(repoPath);
73261
- const file = join74(dir, `${jobId}.json`);
73262
- if (!existsSync57(file)) {
73600
+ const file = join75(dir, `${jobId}.json`);
73601
+ if (!existsSync58(file)) {
73263
73602
  console.error(`Job not found: ${jobId}`);
73264
73603
  console.log(`Available jobs: oa jobs`);
73265
73604
  process.exit(1);
73266
73605
  }
73267
- const job = JSON.parse(readFileSync46(file, "utf-8"));
73606
+ const job = JSON.parse(readFileSync47(file, "utf-8"));
73268
73607
  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`;
73269
73608
  const icon = job.status === "completed" ? "\u2713" : job.status === "failed" ? "\u2717" : "\u25CF";
73270
73609
  console.log(`${icon} ${job.id} [${job.status}] ${runtime}`);
@@ -73279,7 +73618,7 @@ function statusCommand(jobId, repoPath) {
73279
73618
  }
73280
73619
  function jobsCommand(repoPath) {
73281
73620
  const dir = jobsDir2(repoPath);
73282
- const files = readdirSync23(dir).filter((f) => f.endsWith(".json")).sort();
73621
+ const files = readdirSync24(dir).filter((f) => f.endsWith(".json")).sort();
73283
73622
  if (files.length === 0) {
73284
73623
  console.log("No jobs found.");
73285
73624
  return;
@@ -73287,7 +73626,7 @@ function jobsCommand(repoPath) {
73287
73626
  console.log("Jobs:");
73288
73627
  for (const file of files) {
73289
73628
  try {
73290
- const job = JSON.parse(readFileSync46(join74(dir, file), "utf-8"));
73629
+ const job = JSON.parse(readFileSync47(join75(dir, file), "utf-8"));
73291
73630
  const icon = job.status === "completed" ? "\u2713" : job.status === "failed" ? "\u2717" : "\u25CF";
73292
73631
  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`;
73293
73632
  console.log(` ${icon} ${job.id} [${job.status}] ${runtime} \u2014 ${job.task.slice(0, 60)}`);
@@ -73307,7 +73646,7 @@ import { glob } from "glob";
73307
73646
  import ignore from "ignore";
73308
73647
  import { readFile as readFile23, stat as stat4 } from "node:fs/promises";
73309
73648
  import { createHash as createHash6 } from "node:crypto";
73310
- import { join as join75, relative as relative4, extname as extname12, basename as basename17 } from "node:path";
73649
+ import { join as join76, relative as relative4, extname as extname12, basename as basename17 } from "node:path";
73311
73650
  var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
73312
73651
  var init_codebase_indexer = __esm({
73313
73652
  "packages/indexer/dist/codebase-indexer.js"() {
@@ -73351,7 +73690,7 @@ var init_codebase_indexer = __esm({
73351
73690
  const ig = ignore.default();
73352
73691
  if (this.config.respectGitignore) {
73353
73692
  try {
73354
- const gitignoreContent = await readFile23(join75(this.config.rootDir, ".gitignore"), "utf-8");
73693
+ const gitignoreContent = await readFile23(join76(this.config.rootDir, ".gitignore"), "utf-8");
73355
73694
  ig.add(gitignoreContent);
73356
73695
  } catch {
73357
73696
  }
@@ -73366,7 +73705,7 @@ var init_codebase_indexer = __esm({
73366
73705
  for (const relativePath of files) {
73367
73706
  if (ig.ignores(relativePath))
73368
73707
  continue;
73369
- const fullPath = join75(this.config.rootDir, relativePath);
73708
+ const fullPath = join76(this.config.rootDir, relativePath);
73370
73709
  try {
73371
73710
  const fileStat = await stat4(fullPath);
73372
73711
  if (fileStat.size > this.config.maxFileSize)
@@ -73412,7 +73751,7 @@ var init_codebase_indexer = __esm({
73412
73751
  if (!child) {
73413
73752
  child = {
73414
73753
  name: part,
73415
- path: join75(current.path, part),
73754
+ path: join76(current.path, part),
73416
73755
  type: "directory",
73417
73756
  children: []
73418
73757
  };
@@ -73495,13 +73834,13 @@ __export(index_repo_exports, {
73495
73834
  indexRepoCommand: () => indexRepoCommand
73496
73835
  });
73497
73836
  import { resolve as resolve34 } from "node:path";
73498
- import { existsSync as existsSync58, statSync as statSync17 } from "node:fs";
73837
+ import { existsSync as existsSync59, statSync as statSync17 } from "node:fs";
73499
73838
  import { cwd as cwd2 } from "node:process";
73500
73839
  async function indexRepoCommand(opts, _config) {
73501
73840
  const repoRoot = resolve34(opts.repoPath ?? cwd2());
73502
73841
  printHeader("Index Repository");
73503
73842
  printInfo(`Indexing: ${repoRoot}`);
73504
- if (!existsSync58(repoRoot)) {
73843
+ if (!existsSync59(repoRoot)) {
73505
73844
  printError(`Path does not exist: ${repoRoot}`);
73506
73845
  process.exit(1);
73507
73846
  }
@@ -73753,7 +74092,7 @@ var config_exports2 = {};
73753
74092
  __export(config_exports2, {
73754
74093
  configCommand: () => configCommand
73755
74094
  });
73756
- import { join as join76, resolve as resolve35 } from "node:path";
74095
+ import { join as join77, resolve as resolve35 } from "node:path";
73757
74096
  import { homedir as homedir20 } from "node:os";
73758
74097
  import { cwd as cwd3 } from "node:process";
73759
74098
  function redactIfSensitive(key, value) {
@@ -73836,7 +74175,7 @@ function handleShow(opts, config) {
73836
74175
  }
73837
74176
  }
73838
74177
  printSection("Config File");
73839
- printInfo(`~/.open-agents/config.json (${join76(homedir20(), ".open-agents", "config.json")})`);
74178
+ printInfo(`~/.open-agents/config.json (${join77(homedir20(), ".open-agents", "config.json")})`);
73840
74179
  printSection("Priority Chain");
73841
74180
  printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
73842
74181
  printInfo(" 2. Project .oa/settings.json (--local)");
@@ -73875,7 +74214,7 @@ function handleSet(opts, _config) {
73875
74214
  const coerced = coerceForSettings(key, value);
73876
74215
  saveProjectSettings(repoRoot, { [key]: coerced });
73877
74216
  printSuccess(`Project override set: ${key} = ${redactIfSensitive(key, value)}`);
73878
- printInfo(`Saved to ${join76(repoRoot, ".oa", "settings.json")}`);
74217
+ printInfo(`Saved to ${join77(repoRoot, ".oa", "settings.json")}`);
73879
74218
  printInfo("This override applies only when running in this workspace.");
73880
74219
  } catch (err) {
73881
74220
  printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
@@ -74019,7 +74358,7 @@ __export(eval_exports, {
74019
74358
  });
74020
74359
  import { tmpdir as tmpdir10 } from "node:os";
74021
74360
  import { mkdirSync as mkdirSync32, writeFileSync as writeFileSync30 } from "node:fs";
74022
- import { join as join77 } from "node:path";
74361
+ import { join as join78 } from "node:path";
74023
74362
  async function evalCommand(opts, config) {
74024
74363
  const suiteName = opts.suite ?? "basic";
74025
74364
  const suite = SUITES[suiteName];
@@ -74144,9 +74483,9 @@ async function evalCommand(opts, config) {
74144
74483
  process.exit(failed > 0 ? 1 : 0);
74145
74484
  }
74146
74485
  function createTempEvalRepo() {
74147
- const dir = join77(tmpdir10(), `open-agents-eval-${Date.now()}`);
74486
+ const dir = join78(tmpdir10(), `open-agents-eval-${Date.now()}`);
74148
74487
  mkdirSync32(dir, { recursive: true });
74149
- writeFileSync30(join77(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
74488
+ writeFileSync30(join78(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
74150
74489
  return dir;
74151
74490
  }
74152
74491
  var BASIC_SUITE, FULL_SUITE, SUITES;
@@ -74206,7 +74545,7 @@ init_updater();
74206
74545
  import { parseArgs as nodeParseArgs2 } from "node:util";
74207
74546
  import { createRequire as createRequire5 } from "node:module";
74208
74547
  import { fileURLToPath as fileURLToPath15 } from "node:url";
74209
- import { dirname as dirname23, join as join78 } from "node:path";
74548
+ import { dirname as dirname23, join as join79 } from "node:path";
74210
74549
 
74211
74550
  // packages/cli/dist/cli.js
74212
74551
  import { createInterface } from "node:readline";
@@ -74313,7 +74652,7 @@ init_output();
74313
74652
  function getVersion5() {
74314
74653
  try {
74315
74654
  const require2 = createRequire5(import.meta.url);
74316
- const pkgPath = join78(dirname23(fileURLToPath15(import.meta.url)), "..", "package.json");
74655
+ const pkgPath = join79(dirname23(fileURLToPath15(import.meta.url)), "..", "package.json");
74317
74656
  const pkg = require2(pkgPath);
74318
74657
  return pkg.version;
74319
74658
  } catch {
@@ -74589,11 +74928,11 @@ function crashLog(label, err) {
74589
74928
  `;
74590
74929
  try {
74591
74930
  const { appendFileSync: appendFileSync6, mkdirSync: mkdirSync33 } = __require("node:fs");
74592
- const { join: join79 } = __require("node:path");
74931
+ const { join: join80 } = __require("node:path");
74593
74932
  const { homedir: homedir21 } = __require("node:os");
74594
- const logDir = join79(homedir21(), ".open-agents");
74933
+ const logDir = join80(homedir21(), ".open-agents");
74595
74934
  mkdirSync33(logDir, { recursive: true });
74596
- appendFileSync6(join79(logDir, "crash.log"), logLine);
74935
+ appendFileSync6(join80(logDir, "crash.log"), logLine);
74597
74936
  } catch {
74598
74937
  }
74599
74938
  try {