open-agents-ai 0.73.0 → 0.75.0

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 (34) hide show
  1. package/dist/index.js +639 -1119
  2. package/dist/launcher.cjs +12 -12
  3. package/dist/preinstall.cjs +12 -12
  4. package/package.json +5 -3
  5. package/prompts/agentic/system-large.md +304 -0
  6. package/prompts/agentic/system-medium.md +43 -0
  7. package/prompts/agentic/system-small.md +17 -0
  8. package/prompts/compaction/context-compaction.md +9 -0
  9. package/prompts/personality/level-1-minimal.md +3 -0
  10. package/prompts/personality/level-2-concise.md +3 -0
  11. package/prompts/personality/level-4-explanatory.md +3 -0
  12. package/prompts/personality/level-5-thorough.md +3 -0
  13. package/prompts/runners/dispatcher.md +24 -0
  14. package/prompts/runners/editor.md +44 -0
  15. package/prompts/runners/evaluator.md +30 -0
  16. package/prompts/runners/merge-summary.md +9 -0
  17. package/prompts/runners/normalizer.md +23 -0
  18. package/prompts/runners/planner.md +33 -0
  19. package/prompts/runners/scout.md +39 -0
  20. package/prompts/runners/verifier.md +36 -0
  21. package/prompts/templates/analysis.md +14 -0
  22. package/prompts/templates/code-review.md +16 -0
  23. package/prompts/templates/code.md +13 -0
  24. package/prompts/templates/document.md +13 -0
  25. package/prompts/templates/error-diagnosis.md +14 -0
  26. package/prompts/templates/general.md +9 -0
  27. package/prompts/templates/plan.md +15 -0
  28. package/prompts/templates/system.md +16 -0
  29. package/prompts/tui/dmn-gather.md +128 -0
  30. package/prompts/tui/dream-lucid-eval.md +17 -0
  31. package/prompts/tui/dream-lucid-implement.md +14 -0
  32. package/prompts/tui/dream-stages.md +19 -0
  33. package/prompts/tui/emotion-behavioral.md +2 -0
  34. package/prompts/tui/emotion-center.md +12 -0
package/dist/index.js CHANGED
@@ -281,10 +281,10 @@ function loadCache() {
281
281
  }
282
282
  return { lastCheck: 0, latestVersion: null };
283
283
  }
284
- function saveCache(cache) {
284
+ function saveCache(cache4) {
285
285
  try {
286
286
  mkdirSync2(CACHE_DIR, { recursive: true });
287
- writeFileSync2(CACHE_FILE, JSON.stringify(cache), "utf8");
287
+ writeFileSync2(CACHE_FILE, JSON.stringify(cache4), "utf8");
288
288
  } catch {
289
289
  }
290
290
  }
@@ -303,10 +303,10 @@ async function fetchLatestVersion() {
303
303
  }
304
304
  }
305
305
  async function checkForUpdate(currentVersion, forceCheck = false) {
306
- const cache = loadCache();
306
+ const cache4 = loadCache();
307
307
  const now = Date.now();
308
- let latest = cache.latestVersion;
309
- if (forceCheck || now - cache.lastCheck > CHECK_INTERVAL_MS) {
308
+ let latest = cache4.latestVersion;
309
+ if (forceCheck || now - cache4.lastCheck > CHECK_INTERVAL_MS) {
310
310
  latest = await fetchLatestVersion();
311
311
  saveCache({ lastCheck: now, latestVersion: latest });
312
312
  }
@@ -8394,9 +8394,9 @@ import { fileURLToPath as fileURLToPath4 } from "node:url";
8394
8394
  import { homedir as homedir7, tmpdir as tmpdir5 } from "node:os";
8395
8395
  function findOcrScript() {
8396
8396
  const thisDir = dirname7(fileURLToPath4(import.meta.url));
8397
- const devPath = resolve19(thisDir, "../../scripts/ocr-advanced.py");
8398
- if (existsSync17(devPath))
8399
- return devPath;
8397
+ const devPath3 = resolve19(thisDir, "../../scripts/ocr-advanced.py");
8398
+ if (existsSync17(devPath3))
8399
+ return devPath3;
8400
8400
  const bundledPath = resolve19(thisDir, "../scripts/ocr-advanced.py");
8401
8401
  if (existsSync17(bundledPath))
8402
8402
  return bundledPath;
@@ -8949,9 +8949,9 @@ import { join as join22, resolve as resolve20, dirname as dirname9 } from "node:
8949
8949
  import { fileURLToPath as fileURLToPath6 } from "node:url";
8950
8950
  function findAutoresearchScript(scriptName) {
8951
8951
  const thisDir = dirname9(fileURLToPath6(import.meta.url));
8952
- const devPath = resolve20(thisDir, "../../scripts", scriptName);
8953
- if (existsSync19(devPath))
8954
- return devPath;
8952
+ const devPath3 = resolve20(thisDir, "../../scripts", scriptName);
8953
+ if (existsSync19(devPath3))
8954
+ return devPath3;
8955
8955
  const bundledPath = resolve20(thisDir, "../scripts", scriptName);
8956
8956
  if (existsSync19(bundledPath))
8957
8957
  return bundledPath;
@@ -11202,15 +11202,6 @@ var init_nexus = __esm({
11202
11202
  * Usage: node nexus-daemon.mjs <nexus-dir> <agent-name> [agent-type]
11203
11203
  */
11204
11204
 
11205
- // Polyfill for Node <22 (libp2p's it-queue/mortice depends on this)
11206
- if (typeof Promise.withResolvers === 'undefined') {
11207
- Promise.withResolvers = function withResolvers() {
11208
- let resolve, reject;
11209
- const promise = new Promise((res, rej) => { resolve = res; reject = rej; });
11210
- return { promise, resolve, reject };
11211
- };
11212
- }
11213
-
11214
11205
  import { NexusClient } from 'open-agents-nexus';
11215
11206
  import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync, readdirSync } from 'node:fs';
11216
11207
  import { join } from 'node:path';
@@ -11237,6 +11228,10 @@ const nexus = new NexusClient({
11237
11228
  role: 'light',
11238
11229
  enableMdns: true,
11239
11230
  enablePubsubDiscovery: true,
11231
+ enableNats: true,
11232
+ natsServers: ['wss://demo.nats.io:8443'],
11233
+ enableCircuitRelay: true,
11234
+ usePublicBootstrap: true,
11240
11235
  });
11241
11236
 
11242
11237
  const rooms = new Map();
@@ -11315,6 +11310,43 @@ async function handleCmd(cmd) {
11315
11310
  writeResp(id, { ok: true, output: joined.length ? 'Rooms: ' + joined.join(', ') : 'No rooms joined.' });
11316
11311
  break;
11317
11312
  }
11313
+ case 'send_dm': {
11314
+ const peerId = args.target_peer;
11315
+ if (!peerId) { writeResp(id, { ok: false, output: 'target_peer is required' }); return; }
11316
+ await nexus.sendDM(peerId, args.message || '');
11317
+ writeResp(id, { ok: true, output: 'DM sent to ' + peerId.slice(0, 20) + '...' });
11318
+ break;
11319
+ }
11320
+ case 'find_agent': {
11321
+ const peerId = args.peer_id;
11322
+ if (!peerId) { writeResp(id, { ok: false, output: 'peer_id is required' }); return; }
11323
+ const profile = await nexus.findAgent(peerId);
11324
+ writeResp(id, { ok: true, output: profile ? JSON.stringify(profile, null, 2) : 'Agent not found: ' + peerId });
11325
+ break;
11326
+ }
11327
+ case 'invoke_capability': {
11328
+ const peerId = args.target_peer;
11329
+ const capability = args.capability || 'text-generation';
11330
+ const input = args.input || {};
11331
+ if (!peerId) { writeResp(id, { ok: false, output: 'target_peer is required' }); return; }
11332
+ const result = await nexus.invokeCapability(peerId, capability, typeof input === 'string' ? { prompt: input } : input, { stream: false, maxDurationMs: 60000 });
11333
+ writeResp(id, { ok: true, output: JSON.stringify(result, null, 2) });
11334
+ break;
11335
+ }
11336
+ case 'store_content': {
11337
+ const data = args.data;
11338
+ if (!data) { writeResp(id, { ok: false, output: 'data is required' }); return; }
11339
+ const cid = await nexus.store(typeof data === 'string' ? { data } : data);
11340
+ writeResp(id, { ok: true, output: 'Stored. CID: ' + cid });
11341
+ break;
11342
+ }
11343
+ case 'retrieve_content': {
11344
+ const cid = args.cid;
11345
+ if (!cid) { writeResp(id, { ok: false, output: 'cid is required' }); return; }
11346
+ const data = await nexus.retrieve(cid);
11347
+ writeResp(id, { ok: true, output: JSON.stringify(data, null, 2) });
11348
+ break;
11349
+ }
11318
11350
  case 'ping': {
11319
11351
  writeResp(id, { ok: true, output: 'pong' });
11320
11352
  break;
@@ -11377,7 +11409,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
11377
11409
  ];
11378
11410
  NexusTool = class {
11379
11411
  name = "nexus";
11380
- description = "Decentralized agent-to-agent communication via open-agents-nexus. Spawns a background Node.js process with real network sockets for libp2p P2P mesh. Simple flow: connect \u2192 join room \u2192 send messages. Auto-installs nexus if needed. Also supports peer discovery, x402 micropayments, and inference proofs.";
11412
+ description = "Decentralized agent-to-agent communication via open-agents-nexus v1.2.1. Spawns a background Node.js process with real network sockets for libp2p + NATS P2P mesh. Simple flow: connect \u2192 join room \u2192 send messages. Auto-installs nexus if needed. Also supports direct peer invoke (streaming inference), IPFS content storage, direct messages, peer discovery, x402 micropayments, and inference proofs.";
11381
11413
  parameters = {
11382
11414
  type: "object",
11383
11415
  properties: {
@@ -11393,6 +11425,11 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
11393
11425
  "read_messages",
11394
11426
  "discover_peers",
11395
11427
  "list_rooms",
11428
+ "send_dm",
11429
+ "find_agent",
11430
+ "invoke_capability",
11431
+ "store_content",
11432
+ "retrieve_content",
11396
11433
  "wallet_status",
11397
11434
  "wallet_create",
11398
11435
  "inference_proof"
@@ -11418,6 +11455,30 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
11418
11455
  wallet_address: {
11419
11456
  type: "string",
11420
11457
  description: "Wallet address for wallet_create (user-provided receive address)"
11458
+ },
11459
+ target_peer: {
11460
+ type: "string",
11461
+ description: "Target peer ID for send_dm, find_agent, invoke_capability (e.g. '12D3KooW...')"
11462
+ },
11463
+ peer_id: {
11464
+ type: "string",
11465
+ description: "Peer ID for find_agent"
11466
+ },
11467
+ capability: {
11468
+ type: "string",
11469
+ description: "Capability name for invoke_capability (e.g. 'text-generation')"
11470
+ },
11471
+ input: {
11472
+ type: "string",
11473
+ description: "Input data for invoke_capability (prompt text or JSON string)"
11474
+ },
11475
+ data: {
11476
+ type: "string",
11477
+ description: "Data to store for store_content"
11478
+ },
11479
+ cid: {
11480
+ type: "string",
11481
+ description: "Content ID for retrieve_content"
11421
11482
  }
11422
11483
  },
11423
11484
  required: ["action"],
@@ -11467,6 +11528,21 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
11467
11528
  case "list_rooms":
11468
11529
  result = await this.sendDaemonCmd("list_rooms", args);
11469
11530
  break;
11531
+ case "send_dm":
11532
+ result = await this.doSendDM(args);
11533
+ break;
11534
+ case "find_agent":
11535
+ result = await this.sendDaemonCmd("find_agent", args);
11536
+ break;
11537
+ case "invoke_capability":
11538
+ result = await this.sendDaemonCmd("invoke_capability", args);
11539
+ break;
11540
+ case "store_content":
11541
+ result = await this.sendDaemonCmd("store_content", args);
11542
+ break;
11543
+ case "retrieve_content":
11544
+ result = await this.sendDaemonCmd("retrieve_content", args);
11545
+ break;
11470
11546
  case "wallet_status":
11471
11547
  result = await this.doWalletStatus();
11472
11548
  break;
@@ -11711,6 +11787,21 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
11711
11787
  }
11712
11788
  return this.sendDaemonCmd("send_message", args);
11713
11789
  }
11790
+ async doSendDM(args) {
11791
+ const message = args.message;
11792
+ if (!message)
11793
+ throw new Error("message is required");
11794
+ if (!args.target_peer)
11795
+ throw new Error("target_peer is required");
11796
+ if (containsKeyMaterial(message)) {
11797
+ return [
11798
+ "BLOCKED: Message contains potential key material or secrets.",
11799
+ "Messages containing private keys or sensitive cryptographic material",
11800
+ "cannot be sent over the network. Remove the sensitive content and retry."
11801
+ ].join("\n");
11802
+ }
11803
+ return this.sendDaemonCmd("send_dm", args);
11804
+ }
11714
11805
  async doReadMessages(args) {
11715
11806
  const roomId = args.room_id;
11716
11807
  const inboxDir = join28(this.nexusDir, "inbox");
@@ -12672,6 +12763,35 @@ var init_dist3 = __esm({
12672
12763
  }
12673
12764
  });
12674
12765
 
12766
+ // packages/orchestrator/dist/promptLoader.js
12767
+ import { readFileSync as readFileSync15, existsSync as existsSync22 } from "node:fs";
12768
+ import { join as join29, dirname as dirname10 } from "node:path";
12769
+ import { fileURLToPath as fileURLToPath7 } from "node:url";
12770
+ function loadPrompt(promptPath, vars) {
12771
+ let content = cache.get(promptPath);
12772
+ if (content === void 0) {
12773
+ const fullPath = join29(PROMPTS_DIR, promptPath);
12774
+ if (!existsSync22(fullPath)) {
12775
+ throw new Error(`Prompt file not found: ${fullPath}`);
12776
+ }
12777
+ content = readFileSync15(fullPath, "utf-8");
12778
+ cache.set(promptPath, content);
12779
+ }
12780
+ if (!vars)
12781
+ return content;
12782
+ return content.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] ?? `{{${key}}}`);
12783
+ }
12784
+ var __filename, __dirname3, PROMPTS_DIR, cache;
12785
+ var init_promptLoader = __esm({
12786
+ "packages/orchestrator/dist/promptLoader.js"() {
12787
+ "use strict";
12788
+ __filename = fileURLToPath7(import.meta.url);
12789
+ __dirname3 = dirname10(__filename);
12790
+ PROMPTS_DIR = join29(__dirname3, "..", "prompts");
12791
+ cache = /* @__PURE__ */ new Map();
12792
+ }
12793
+ });
12794
+
12675
12795
  // packages/orchestrator/dist/taskNormalizer.js
12676
12796
  function parseJsonFromContent(content) {
12677
12797
  const fencedMatch = content.match(/```(?:json)?\s*([\s\S]*?)```/);
@@ -12683,35 +12803,14 @@ function parseJsonFromContent(content) {
12683
12803
  }
12684
12804
  }
12685
12805
  function normalizationPrompt(rawRequest, repoRoot) {
12686
- return `You are a task-normalizer agent. Convert the following user request into a structured JSON object that conforms exactly to the schema below.
12687
-
12688
- SCHEMA:
12689
- {
12690
- "id": "<unique string - generate a short UUID-like identifier>",
12691
- "goal": "<single concise goal sentence>",
12692
- "constraints": ["<constraint string>", ...],
12693
- "successCriteria": ["<criterion string>", ...],
12694
- "repoRoot": "<absolute path to repo root>",
12695
- "urgency": "low" | "medium" | "high" | "critical",
12696
- "taskClass": "bugfix" | "feature" | "refactor" | "migration" | "dependency-upgrade" | "test" | "docs" | "infra",
12697
- "rawRequest": "<original user request verbatim>",
12698
- "createdAt": "<ISO-8601 timestamp>"
12699
- }
12700
-
12701
- RULES:
12702
- - "repoRoot" MUST be: ${repoRoot}
12703
- - "rawRequest" MUST be the exact request text provided below.
12704
- - "createdAt" MUST be the current UTC datetime in ISO-8601 format.
12705
- - Respond ONLY with the JSON object, no additional text.
12706
-
12707
- USER REQUEST:
12708
- ${rawRequest}`;
12806
+ return loadPrompt("runners/normalizer.md", { rawRequest, repoRoot });
12709
12807
  }
12710
12808
  var TaskNormalizer;
12711
12809
  var init_taskNormalizer = __esm({
12712
12810
  "packages/orchestrator/dist/taskNormalizer.js"() {
12713
12811
  "use strict";
12714
12812
  init_dist3();
12813
+ init_promptLoader();
12715
12814
  TaskNormalizer = class {
12716
12815
  backend;
12717
12816
  constructor(backend) {
@@ -12814,30 +12913,7 @@ function heuristicDecision(task) {
12814
12913
  };
12815
12914
  }
12816
12915
  function dispatchPrompt(task) {
12817
- return `You are a dispatch-planning agent. Given the following normalised task, produce a dispatch decision JSON.
12818
-
12819
- TASK:
12820
- ${JSON.stringify(task, null, 2)}
12821
-
12822
- SCHEMA:
12823
- {
12824
- "mode": "single_pass" | "multi_agent" | "hybrid",
12825
- "taskComplexity": "low" | "medium" | "high",
12826
- "splitRecommended": boolean,
12827
- "initialAgents": ["planner" | "scout" | "editor" | "verifier" | "researcher", ...],
12828
- "budgets": {
12829
- "promptTokens": <positive integer>,
12830
- "retries": <non-negative integer>,
12831
- "wallClockSec": <positive number>
12832
- }
12833
- }
12834
-
12835
- RULES:
12836
- - Use "single_pass" only for small, well-scoped changes.
12837
- - Use "multi_agent" when the task touches many independent subsystems.
12838
- - "splitRecommended" should be true only when "multi_agent" is chosen.
12839
- - "initialAgents" must always include "scout", "editor", and "verifier".
12840
- - Respond ONLY with the JSON object, no additional text.`;
12916
+ return loadPrompt("runners/dispatcher.md", { task: JSON.stringify(task, null, 2) });
12841
12917
  }
12842
12918
  function parseJsonFromContent2(content) {
12843
12919
  const fencedMatch = content.match(/```(?:json)?\s*([\s\S]*?)```/);
@@ -12853,6 +12929,7 @@ var init_dispatcher = __esm({
12853
12929
  "packages/orchestrator/dist/dispatcher.js"() {
12854
12930
  "use strict";
12855
12931
  init_dist3();
12932
+ init_promptLoader();
12856
12933
  Dispatcher = class {
12857
12934
  backend;
12858
12935
  /**
@@ -12917,39 +12994,7 @@ ${JSON.stringify(repoProfile, null, 2)}` : "REPOSITORY PROFILE: (not available)"
12917
12994
  Architecture note: ${retrievalPacket.architectureNote ?? "n/a"}
12918
12995
  Prior attempt note: ${retrievalPacket.priorAttemptNote ?? "n/a"}
12919
12996
  Files available: ${Object.keys(retrievalPacket.files).join(", ")}` : "RETRIEVAL CONTEXT: (not available)";
12920
- return `You are a planning agent. Decompose the following task into an ordered DAG of subtasks.
12921
-
12922
- TASK:
12923
- ${JSON.stringify(task, null, 2)}
12924
-
12925
- ${profileSection}
12926
-
12927
- ${retrievalSection}
12928
-
12929
- SCHEMA for your response:
12930
- {
12931
- "goal": "<restate the goal concisely>",
12932
- "subtasks": [
12933
- {
12934
- "id": "<short unique id, e.g. 'st-1'>",
12935
- "kind": "inspect" | "patch" | "test" | "migrate" | "verify" | "merge",
12936
- "targets": ["<file or symbol>", ...],
12937
- "dependsOn": ["<subtask id>", ...],
12938
- "reason": "<why this subtask is needed>",
12939
- "validation": ["<shell command or assertion>", ...]
12940
- }
12941
- ],
12942
- "riskAreas": ["<file or module at risk>", ...],
12943
- "unknowns": ["<ambiguity or missing information>", ...]
12944
- }
12945
-
12946
- RULES:
12947
- - Every subtask must have a unique "id".
12948
- - "dependsOn" references must be ids of earlier subtasks in the array.
12949
- - Include at least one "verify" subtask at the end.
12950
- - The first subtask should usually be an "inspect" of the most relevant file.
12951
- - Keep the plan pragmatic: do not exceed 12 subtasks.
12952
- - Respond ONLY with the JSON object, no additional text.`;
12997
+ return loadPrompt("runners/planner.md", { task: JSON.stringify(task, null, 2), profileSection, retrievalSection });
12953
12998
  }
12954
12999
  function parseJsonFromContent3(content) {
12955
13000
  const fencedMatch = content.match(/```(?:json)?\s*([\s\S]*?)```/);
@@ -12965,6 +13010,7 @@ var init_plannerRunner = __esm({
12965
13010
  "packages/orchestrator/dist/plannerRunner.js"() {
12966
13011
  "use strict";
12967
13012
  init_dist3();
13013
+ init_promptLoader();
12968
13014
  PlannerRunner = class {
12969
13015
  backend;
12970
13016
  constructor(backend) {
@@ -13121,7 +13167,7 @@ var init_code_retriever = __esm({
13121
13167
  import { execFile as execFile5 } from "node:child_process";
13122
13168
  import { promisify as promisify4 } from "node:util";
13123
13169
  import { readFile as readFile14, readdir as readdir4, stat as stat3 } from "node:fs/promises";
13124
- import { join as join29, extname as extname7 } from "node:path";
13170
+ import { join as join30, extname as extname7 } from "node:path";
13125
13171
  async function searchByPath(pathPattern, options) {
13126
13172
  const allFiles = await collectFiles(options.rootDir, options.includeGlobs ?? DEFAULT_INCLUDE_GLOBS, options.excludeGlobs ?? DEFAULT_EXCLUDE_GLOBS);
13127
13173
  const pattern = options.caseInsensitive ? pathPattern.toLowerCase() : pathPattern;
@@ -13263,7 +13309,7 @@ async function walkForFiles(rootDir, dir, excludeGlobs, results) {
13263
13309
  continue;
13264
13310
  if (excludeGlobs.some((g) => entry.name === g || matchesGlob(entry.name, g)))
13265
13311
  continue;
13266
- const absPath = join29(dir, entry.name);
13312
+ const absPath = join30(dir, entry.name);
13267
13313
  if (entry.isDirectory()) {
13268
13314
  await walkForFiles(rootDir, absPath, excludeGlobs, results);
13269
13315
  } else if (entry.isFile()) {
@@ -13570,7 +13616,7 @@ var init_graphExpand = __esm({
13570
13616
 
13571
13617
  // packages/retrieval/dist/snippetPacker.js
13572
13618
  import { readFile as readFile15 } from "node:fs/promises";
13573
- import { join as join30 } from "node:path";
13619
+ import { join as join31 } from "node:path";
13574
13620
  async function packSnippets(requests, opts = {}) {
13575
13621
  const maxTokens = opts.maxTokens ?? DEFAULT_MAX_TOKENS;
13576
13622
  const contextLines = opts.contextLines ?? DEFAULT_CONTEXT_LINES;
@@ -13596,7 +13642,7 @@ async function packSnippets(requests, opts = {}) {
13596
13642
  return { packed, dropped, totalTokens };
13597
13643
  }
13598
13644
  async function extractSnippet(req, repoRoot, contextLines = DEFAULT_CONTEXT_LINES) {
13599
- const absPath = req.filePath.startsWith("/") ? req.filePath : join30(repoRoot, req.filePath);
13645
+ const absPath = req.filePath.startsWith("/") ? req.filePath : join31(repoRoot, req.filePath);
13600
13646
  let content;
13601
13647
  try {
13602
13648
  content = await readFile15(absPath, "utf-8");
@@ -13862,51 +13908,19 @@ function scoutPrompt(task, repoProfile, candidateFiles, subtasks) {
13862
13908
  const fileList = Object.keys(candidateFiles).join("\n - ");
13863
13909
  const profileNote = repoProfile ? `The repo uses ${repoProfile.languages.join(", ")} with ${repoProfile.frameworks.join(", ")}.` : "No repo profile available.";
13864
13910
  const subtaskTargets = subtasks.flatMap((s) => s.targets).filter((t, i, arr) => arr.indexOf(t) === i);
13865
- return `You are a scout agent. Your job is to identify the most relevant source files for the task below.
13866
-
13867
- TASK:
13868
- ${JSON.stringify(task, null, 2)}
13869
-
13870
- REPO NOTE: ${profileNote}
13871
-
13872
- SUBTASK TARGETS (from planner, if available):
13873
- ${subtaskTargets.length ? subtaskTargets.map((t) => ` - ${t}`).join("\n") : " (none yet)"}
13874
-
13875
- CANDIDATE FILES FOUND BY SEARCH:
13876
- - ${fileList || "(none found)"}
13877
-
13878
- Produce a RetrievalPacket JSON with the following schema:
13879
- {
13880
- "request": {
13881
- "query": "<what you searched for>",
13882
- "pathsHint": ["<high-priority paths>"],
13883
- "symbolHint": ["<symbol names>"],
13884
- "errorHint": [],
13885
- "maxFiles": 10,
13886
- "maxSnippets": 20,
13887
- "includeTests": true,
13888
- "includeConfigs": false
13889
- },
13890
- "files": {
13891
- "<repo-relative path>": "<short excerpt or empty string>"
13892
- },
13893
- "snippets": [],
13894
- "architectureNote": "<one-line architecture insight>",
13895
- "priorAttemptNote": null,
13896
- "assembledAt": "<ISO-8601 now>"
13897
- }
13898
-
13899
- RULES:
13900
- - Include only the top 10 most relevant files in "files".
13901
- - The keys of "files" must be repo-relative paths present in the candidate list above.
13902
- - "assembledAt" must be a current ISO-8601 datetime.
13903
- - Respond ONLY with the JSON object, no additional text.`;
13911
+ return loadPrompt("runners/scout.md", {
13912
+ task: JSON.stringify(task, null, 2),
13913
+ profileNote,
13914
+ subtaskTargets: subtaskTargets.length ? subtaskTargets.map((t) => ` - ${t}`).join("\n") : " (none yet)",
13915
+ fileList: fileList || "(none found)"
13916
+ });
13904
13917
  }
13905
13918
  var ScoutRunner;
13906
13919
  var init_scoutRunner = __esm({
13907
13920
  "packages/orchestrator/dist/scoutRunner.js"() {
13908
13921
  "use strict";
13909
13922
  init_dist3();
13923
+ init_promptLoader();
13910
13924
  ScoutRunner = class {
13911
13925
  backend;
13912
13926
  constructor(backend) {
@@ -14019,50 +14033,12 @@ Evidence:
14019
14033
  ${previousVerification.evidence.map((e) => ` - ${e}`).join("\n")}
14020
14034
  Focus files: ${previousVerification.focusFiles.join(", ")}
14021
14035
  Failure fingerprint: ${previousVerification.failureFingerprint ?? "none"}` : "";
14022
- return `You are an editor agent. Your job is to produce a precise code patch to address the subtask below.
14023
-
14024
- FULL TASK:
14025
- ${JSON.stringify(task, null, 2)}
14026
-
14027
- CURRENT SUBTASK:
14028
- ${JSON.stringify(subtask, null, 2)}
14029
-
14030
- RETRIEVED SOURCE FILES:
14031
- ${filesSection || "(no files retrieved)"}
14032
-
14033
- ${retrySection}
14034
-
14035
- Produce a PatchProposal JSON with the following schema:
14036
- {
14037
- "summary": "<one paragraph: what changed and why>",
14038
- "edits": [
14039
- {
14040
- "file": "<repo-relative path>",
14041
- "operation": "diff" | "rewrite" | "append" | "create",
14042
- "content": "<unified diff, full file content, or new content>"
14043
- }
14044
- ],
14045
- "testsToRun": ["<shell command or test file path>"],
14046
- "assumptions": ["<assumption made>"],
14047
- "risks": ["<known risk>"],
14048
- "needsMoreContext": null
14049
- }
14050
-
14051
- If you CANNOT safely produce a patch without more information, set "needsMoreContext":
14052
- {
14053
- "reason": "<why you need more info>",
14054
- "requestedPaths": ["<paths to read>"],
14055
- "requestedSymbols": ["<symbol names>"]
14056
- }
14057
- and set "edits" to an empty array.
14058
-
14059
- RULES:
14060
- - Prefer "diff" operation with proper unified diff format when modifying existing files.
14061
- - Use "rewrite" only for small files or when the diff would be confusing.
14062
- - Use "create" for new files that do not yet exist.
14063
- - Include at least one entry in "testsToRun" unless the subtask kind is "inspect".
14064
- - Be conservative: only change what is required by the subtask.
14065
- - Respond ONLY with the JSON object, no additional text.`;
14036
+ return loadPrompt("runners/editor.md", {
14037
+ task: JSON.stringify(task, null, 2),
14038
+ subtask: JSON.stringify(subtask, null, 2),
14039
+ filesSection: filesSection || "(no files retrieved)",
14040
+ retrySection
14041
+ });
14066
14042
  }
14067
14043
  function parseJsonFromContent5(content) {
14068
14044
  const fencedMatch = content.match(/```(?:json)?\s*([\s\S]*?)```/);
@@ -14078,6 +14054,7 @@ var init_editorRunner = __esm({
14078
14054
  "packages/orchestrator/dist/editorRunner.js"() {
14079
14055
  "use strict";
14080
14056
  init_dist3();
14057
+ init_promptLoader();
14081
14058
  EditorRunner = class {
14082
14059
  backend;
14083
14060
  constructor(backend) {
@@ -14138,42 +14115,16 @@ function verifierPrompt(task, subtask, patch, toolOutput) {
14138
14115
  ${toolOutput}` : "TOOL EXECUTION OUTPUT: (not executed)";
14139
14116
  const editsSection = patch.edits.map((e) => `--- ${e.file} [${e.operation}] ---
14140
14117
  ${e.content.slice(0, 800)}`).join("\n\n");
14141
- return `You are a verifier agent. Review the patch proposal below against the task requirements and produce a verification decision.
14142
-
14143
- FULL TASK:
14144
- ${JSON.stringify(task, null, 2)}
14145
-
14146
- SUBTASK:
14147
- ${JSON.stringify(subtask, null, 2)}
14148
-
14149
- PATCH PROPOSAL:
14150
- Summary: ${patch.summary}
14151
- Assumptions: ${patch.assumptions.join("; ") || "none"}
14152
- Risks: ${patch.risks.join("; ") || "none"}
14153
- Tests to run: ${patch.testsToRun.join(", ") || "none"}
14154
-
14155
- EDITS:
14156
- ${editsSection || "(no edits)"}
14157
-
14158
- ${toolSection}
14159
-
14160
- Produce a VerificationDecision JSON:
14161
- {
14162
- "status": "pass" | "fail" | "partial",
14163
- "evidence": ["<concrete evidence line from output or code review>", ...],
14164
- "nextAction": "finish" | "retry" | "rollback" | "inspect_more",
14165
- "focusFiles": ["<file to focus on in next round>", ...],
14166
- "failureFingerprint": "<short stable failure identifier, or null if status is pass>"
14167
- }
14168
-
14169
- DECISION RULES:
14170
- - "pass" + "finish": all success criteria addressed, no regressions visible.
14171
- - "fail" + "retry": fixable issue; leave a precise "failureFingerprint".
14172
- - "fail" + "rollback": irreversible regression or destructive change detected.
14173
- - "partial" + "inspect_more": patch is incomplete; more context needed.
14174
- - "failureFingerprint" must be null (omit the field) when status is "pass".
14175
- - "evidence" must have at least one entry.
14176
- - Respond ONLY with the JSON object, no additional text.`;
14118
+ return loadPrompt("runners/verifier.md", {
14119
+ task: JSON.stringify(task, null, 2),
14120
+ subtask: JSON.stringify(subtask, null, 2),
14121
+ patchSummary: patch.summary,
14122
+ patchAssumptions: patch.assumptions.join("; ") || "none",
14123
+ patchRisks: patch.risks.join("; ") || "none",
14124
+ patchTests: patch.testsToRun.join(", ") || "none",
14125
+ editsSection: editsSection || "(no edits)",
14126
+ toolSection
14127
+ });
14177
14128
  }
14178
14129
  function parseJsonFromContent6(content) {
14179
14130
  const fencedMatch = content.match(/```(?:json)?\s*([\s\S]*?)```/);
@@ -14189,6 +14140,7 @@ var init_verifierRunner = __esm({
14189
14140
  "packages/orchestrator/dist/verifierRunner.js"() {
14190
14141
  "use strict";
14191
14142
  init_dist3();
14143
+ init_promptLoader();
14192
14144
  VerifierRunner = class {
14193
14145
  backend;
14194
14146
  options;
@@ -14285,6 +14237,7 @@ var MergeRunner;
14285
14237
  var init_mergeRunner = __esm({
14286
14238
  "packages/orchestrator/dist/mergeRunner.js"() {
14287
14239
  "use strict";
14240
+ init_promptLoader();
14288
14241
  MergeRunner = class {
14289
14242
  backend;
14290
14243
  /**
@@ -14345,15 +14298,13 @@ var init_mergeRunner = __esm({
14345
14298
  if (!this.backend || mergedEdits.length === 0) {
14346
14299
  return basicSummary;
14347
14300
  }
14348
- const prompt = `You are a merge-summary agent. Summarise the following merge result in 2\u20133 sentences for a developer.
14349
-
14350
- TASK GOAL: ${task.goal}
14351
- SUCCESSFUL SUBTASKS: ${successfulSubtasks.join(", ")}
14352
- FAILED SUBTASKS: ${failedSubtasks.join(", ") || "none"}
14353
- FILES CHANGED: ${[...new Set(mergedEdits.map((e) => e.file))].join(", ")}
14354
- CONFLICTS: ${conflicts.map((c3) => `${c3.filePath} (${c3.conflictingSubtasks.join(" vs ")})`).join(", ") || "none"}
14355
-
14356
- Write a concise developer-facing merge summary. No JSON, just plain text.`;
14301
+ const prompt = loadPrompt("runners/merge-summary.md", {
14302
+ taskGoal: task.goal,
14303
+ successfulSubtasks: successfulSubtasks.join(", "),
14304
+ failedSubtasks: failedSubtasks.join(", ") || "none",
14305
+ filesChanged: [...new Set(mergedEdits.map((e) => e.file))].join(", "),
14306
+ conflicts: conflicts.map((c3) => c3.filePath + " (" + c3.conflictingSubtasks.join(" vs ") + ")").join(", ") || "none"
14307
+ });
14357
14308
  try {
14358
14309
  const response = await this.backend.complete({
14359
14310
  messages: [{ role: "user", content: prompt }],
@@ -14804,26 +14755,18 @@ var init_ralphLoop = __esm({
14804
14755
  function compilePersonalityPrompt(profile) {
14805
14756
  const avg = (profile.frequency + profile.depth + profile.threshold + profile.effort + profile.willingness) / 5;
14806
14757
  if (avg <= 1.5) {
14807
- return `
14808
- ## Response Style
14809
- Be extremely concise. Act silently \u2014 only speak when results are surprising or errors occur. No preamble, no summaries. Raw results and tool calls only.`;
14758
+ return loadPrompt("personality/level-1-minimal.md");
14810
14759
  }
14811
14760
  if (avg <= 2.5) {
14812
- return `
14813
- ## Response Style
14814
- Be concise and direct. Brief status updates between tool calls. Skip reasoning explanation unless the approach is non-obvious. No markdown headers for short answers.`;
14761
+ return loadPrompt("personality/level-2-concise.md");
14815
14762
  }
14816
14763
  if (avg <= 3.5) {
14817
14764
  return "";
14818
14765
  }
14819
14766
  if (avg <= 4.5) {
14820
- return `
14821
- ## Response Style
14822
- Explain your reasoning as you work. Describe what you're looking for and why. Summarize findings. Use structured formatting for complex output.`;
14767
+ return loadPrompt("personality/level-4-explanatory.md");
14823
14768
  }
14824
- return `
14825
- ## Response Style
14826
- Provide thorough explanations of your reasoning at each step. Describe alternatives you considered. Offer suggestions beyond the immediate task. Use well-structured markdown with headers and examples.`;
14769
+ return loadPrompt("personality/level-5-thorough.md");
14827
14770
  }
14828
14771
  function getPreset(name) {
14829
14772
  return PERSONALITY_PRESETS[name];
@@ -14832,6 +14775,7 @@ var PERSONALITY_PRESETS, PRESET_NAMES;
14832
14775
  var init_personality = __esm({
14833
14776
  "packages/orchestrator/dist/personality.js"() {
14834
14777
  "use strict";
14778
+ init_promptLoader();
14835
14779
  PERSONALITY_PRESETS = {
14836
14780
  /** Silent operator — acts, doesn't explain */
14837
14781
  concise: { frequency: 1, depth: 1, threshold: 1, effort: 2, willingness: 1 },
@@ -14863,325 +14807,10 @@ var init_agenticRunner = __esm({
14863
14807
  "use strict";
14864
14808
  init_dist();
14865
14809
  init_personality();
14866
- SYSTEM_PROMPT = `You are Open Agent, an autonomous AI agent with full access to the local machine. You can read/write files, execute shell commands, browse the web, control the desktop (open applications, click UI elements, take screenshots), and interact with any software on the system. You solve tasks by using your tools iteratively until complete.
14867
-
14868
- ## NEVER REFUSE \u2014 ALWAYS ATTEMPT
14869
-
14870
- You have a comprehensive set of tools. NEVER say "I can't do that" or "I don't have the ability to...". Instead, ALWAYS attempt the task using your tools:
14871
- - Need to open Firefox? Use shell: \`firefox https://example.com &\`
14872
- - Need to click a button? Use desktop_click or shell with xdotool
14873
- - Need to see the screen? Use screenshot or desktop_describe
14874
- - Need to type text? Use shell with xdotool: \`xdotool type "text"\` (to target a specific window: \`xdotool type --window $WID "text"\`)
14875
- - Need to install software? Use shell: \`sudo apt install ...\`
14876
- - Need to interact with a website? Use web_fetch, or open the browser and use desktop tools
14877
-
14878
- If a tool fails, try a different approach. If you're unsure, explore with your tools first. Do NOT give a text-only response when tools could accomplish the task.
14879
-
14880
- ## Available Tools
14881
-
14882
- - file_read: Read file contents (always read before editing). Supports path, offset, limit.
14883
- - file_write: Create or overwrite a file with complete content
14884
- - file_edit: Make a precise string replacement in a file (preferred over rewriting). Uses old_string/new_string. old_string must be unique unless replace_all=true. Use replace_all for variable renames.
14885
- - file_patch: Edit specific line ranges in large files. Modes: replace (swap lines), insert_before, insert_after, delete. Use dry_run to preview. Best for large files (500+ lines) where string matching is fragile.
14886
- - find_files: Find files by name pattern (glob). Searches recursively, excludes node_modules/.git.
14887
- - grep_search: Search file contents with regex. Returns matching lines with paths and line numbers.
14888
- - shell: Execute any shell command (tests, builds, git, npm, etc.). Supports stdin parameter for input. Commands run with CI=true for non-interactive mode.
14889
- - list_directory: List files in a directory with types and sizes
14890
- - web_search: Search the web for documentation or solutions
14891
- - web_fetch: Fetch a web page and extract text content (for docs, MDN, w3schools.com, etc.)
14892
- - memory_read: Read from persistent memory (learned patterns, solutions)
14893
- - memory_write: Store a fact, pattern, or solution in persistent memory for future tasks
14894
- - task_complete: Signal task completion with a summary
14895
-
14896
- ## Parallel Execution & Sub-Agents
14897
-
14898
- - background_run: Run a shell command in the background. Returns a task ID immediately.
14899
- - task_status: Check status of background tasks (or list all)
14900
- - task_output: Read stdout/stderr from a background task
14901
- - task_stop: Kill a running background task
14902
- - sub_agent: Delegate a sub-task to an independent agent with its own context
14903
-
14904
- IMPORTANT \u2014 True Parallelism:
14905
- When you issue MULTIPLE tool calls in a SINGLE response, read-only tools (file_read, grep_search,
14906
- find_files, list_directory, web_fetch, web_search, memory_read, task_status, task_output) execute
14907
- IN PARALLEL automatically. Use this to dramatically speed up exploration \u2014 call 3-5 file_reads or
14908
- greps at once instead of one at a time.
14909
-
14910
- For sub-agents: use background=true and launch MULTIPLE sub_agent calls in one response to run
14911
- them concurrently against the backend. Each sub-agent gets its own independent context window and
14912
- makes its own API requests. Check results with task_status/task_output when done.
14913
-
14914
- PARALLEL SUB-AGENT PATTERN (preferred for independent tasks):
14915
- 1. Call sub_agent({task: "task A", background: true}) AND sub_agent({task: "task B", background: true}) in ONE response
14916
- 2. Both sub-agents run simultaneously against the backend
14917
- 3. Use task_status() to poll, then task_output() to read results
14918
-
14919
- ## Skills (AIWG)
14920
-
14921
- - skill_list: Discover available skills \u2014 shows descriptions and trigger patterns. Use filter param to search.
14922
- - skill_execute: Load a skill's full instructions by name. Returns the SKILL.md content with detailed behavioral guidance.
14923
-
14924
- When a user request matches a skill trigger pattern (listed in your context or discovered via skill_list), call skill_execute to load the skill instructions, then follow them.
14925
-
14926
- Use background_run for long-running commands (builds, test suites) so you can continue other work.
14927
- Use sub_agent to parallelize independent sub-tasks or explore different approaches simultaneously.
14928
- Check task_status periodically and read task_output when tasks complete.
14929
-
14930
- ## Desktop Automation & Vision
14931
-
14932
- - desktop_click: Click a UI element by natural language description. Takes a screenshot, finds the element with vision, clicks it. Example: desktop_click({target: "the Save button"})
14933
- - desktop_describe: Take a screenshot and describe what's on screen (or ask a question about it). Use this to "see" the desktop.
14934
- - vision: Analyze any image with Moondream VLM \u2014 caption, query, detect objects, find click targets
14935
- - screenshot: Capture the screen or active window
14936
- - image_read: Read an image file (returns base64, dimensions, OCR text)
14937
- - ocr: Extract text from an image using OCR (supports region cropping/zoom)
14938
-
14939
- ### Desktop Interaction Workflow
14940
-
14941
- When asked to interact with desktop applications (open browsers, click buttons, fill forms, etc.):
14942
- 1. Use shell to launch applications: \`firefox https://example.com &\`
14943
- 2. Use screenshot or desktop_describe to see what's on screen
14944
- 3. Use desktop_click to click UI elements: \`desktop_click({target: "Sign Up button"})\`
14945
- 4. Use shell with xdotool for keyboard input: \`xdotool type "username"\` and \`xdotool key Return\`
14946
- To target a specific window by ID: \`xdotool type --window $WID "text"\` and \`xdotool key --window $WID Return\`
14947
- IMPORTANT: xdotool type/key use \`--window WID\` flag, NOT positional args. \`xdotool type -- $WID "text"\` is WRONG (types the WID as text).
14948
- 5. Use shell with xdotool for navigation: \`xdotool key Tab\`, \`xdotool key ctrl+l\`
14949
- 6. Take screenshots between steps to verify progress
14950
-
14951
- You CAN open Firefox, Chrome, or any application. You CAN click buttons, fill forms, and navigate websites.
14952
- You CAN use xdotool for keyboard/mouse control. These are real capabilities, not hypothetical.
14953
-
14954
- ### Self-Guided Image Exploration
14955
-
14956
- When you discover image files (png, jpg, gif, svg, webp, bmp) during codebase exploration:
14957
- - Proactively read them with image_read to understand visual assets, diagrams, and screenshots
14958
- - Use ocr to extract text from images containing code, diagrams, or documentation
14959
- - Use ocr with region cropping to zoom into specific areas of large images
14960
- - If you find architecture diagrams, UI mockups, or annotated screenshots, read and integrate their content
14961
- - Report what you find in images \u2014 they often contain critical context not in code files
14962
- - For directories with many images, prioritize: README images, diagrams, screenshots, then decorative assets
14963
-
14964
- ## Workflow
14965
-
14966
- 1. EXPLORE: Use find_files and grep_search to locate relevant code. Read specific files.
14967
- 2. PLAN: Determine what changes are needed based on the code you've read.
14968
- 3. IMPLEMENT: Make changes using file_edit (preferred) or file_write for new files.
14969
- 4. VALIDATE: Run tests/build/lint using shell. Read the FULL output.
14970
- 5. FIX: If validation fails, read the error carefully. Fix the SPECIFIC issue. Re-validate.
14971
- 6. ITERATE: Repeat steps 4-5 until all tests pass. Do NOT give up.
14972
- 7. LEARN: If you discovered something useful, store it with memory_write.
14973
- 8. COMPLETE: Call task_complete ONLY when validation passes.
14974
-
14975
- ## Critical Rules
14976
-
14977
- - ALWAYS read a file before modifying it \u2014 never guess at file contents
14978
- - ALWAYS run validation (tests, build, lint) after making changes
14979
- - If tests fail, read the FULL error output. Fix the exact failing assertion or error.
14980
- - Do NOT give up after a failure. Iterate: fix \u2192 test \u2192 fix \u2192 test until it passes.
14981
- - Use grep_search and find_files for efficient exploration (don't dump entire directories)
14982
- - Use file_edit for small changes instead of rewriting entire files
14983
- - Keep tool calls focused \u2014 read only what you need
14984
- - You MUST call task_complete when the task is done
14985
-
14986
- ## Project Awareness
14987
-
14988
- Your system prompt is dynamically enriched with project context. Before each task:
14989
- - AGENTS.md, OA.md, CLAUDE.md, and README.md are auto-discovered and loaded
14990
- - The .oa/ directory stores per-project artifacts (memory, index, session history)
14991
- - Git state (branch, dirty files, recent commits) is injected
14992
- - Persistent memories from previous sessions are loaded
14993
- - Recent session history shows what was worked on before
14994
-
14995
- When working in a new project, use codebase_map first to orient yourself.
14996
- Store important discoveries with memory_write for future sessions.
14997
-
14998
- ## Self-Learning
14999
-
15000
- When you encounter an unfamiliar API, language feature, or runtime behavior:
15001
- 1. Use web_search to find documentation (prefer w3schools.com, MDN, official docs)
15002
- 2. Use web_fetch to read the relevant page
15003
- 3. Use memory_write to store the learned pattern for future reference
15004
- 4. Check memory_read at the start of tasks for previously learned solutions
15005
-
15006
- ## Error Recovery
15007
-
15008
- When a test or build fails:
15009
- 1. Read the COMPLETE error output from shell \u2014 don't skip lines
15010
- 2. Identify the EXACT file, line, and assertion that failed
15011
- 3. Read that file section with file_read
15012
- 4. Understand WHY it failed (wrong value, missing import, syntax error, etc.)
15013
- 5. Fix with file_edit (precise replacement)
15014
- 6. Re-run the SAME validation command
15015
- 7. If it fails again with a DIFFERENT error, that's progress \u2014 fix the new error
15016
- 8. If it fails with the SAME error, try a different approach
15017
- 9. After 3 failed attempts at the same error, use web_search for solutions
15018
-
15019
- ## Interactive Commands
15020
-
15021
- Commands run non-interactively (CI=true). When running scaffolding tools:
15022
- - ALWAYS add non-interactive flags: --yes, --no-input, --defaults, etc.
15023
- - For npx create-next-app: use --yes (skips all prompts, uses defaults)
15024
- - For npm init: use -y
15025
- - If a command needs specific answers, use the stdin parameter
15026
- - If a command times out, it likely hit an interactive prompt \u2014 retry with --yes
15027
-
15028
- ## Custom Tools
15029
-
15030
- - create_tool: Create a reusable custom tool from a repeated multi-step workflow. Saves to .oa/tools/ (project) or ~/.open-agents/tools/ (global).
15031
- - manage_tools: List, inspect, or delete custom tools.
15032
-
15033
- Custom tools are agent-created shell command sequences that automate repeated workflows.
15034
- They appear alongside core tools and can be invoked just like any built-in tool.
15035
-
15036
- ### When to Create a Custom Tool
15037
-
15038
- If you notice you're performing the SAME multi-step sequence for the 3rd time or more:
15039
- 1. Recognize the repeated pattern (e.g., "bump version \u2192 build \u2192 publish \u2192 commit \u2192 push")
15040
- 2. Identify what varies between runs (these become parameters)
15041
- 3. Call create_tool with the steps and parameters
15042
- 4. Choose scope: 'project' for project-specific workflows, 'global' for cross-project patterns
15043
-
15044
- ### Custom Tool Guidelines
15045
-
15046
- - Name tools descriptively in snake_case (e.g., run_full_validation, deploy_to_staging)
15047
- - Use {{param}} syntax in step commands for interpolation
15048
- - Set continueOnError=true on steps that may fail but shouldn't stop the pipeline
15049
- - Test the tool mentally before creating \u2014 ensure the steps would work in order
15050
- - Prefer 'project' scope unless the pattern genuinely applies to all projects
15051
-
15052
- ## Nexus P2P Networking & x402 Micropayments
15053
-
15054
- - nexus: Decentralized agent-to-agent communication via open-agents-nexus.
15055
-
15056
- open-agents-nexus is auto-installed on first use \u2014 just call connect and it handles the rest.
15057
- The core flow is simple \u2014 connect, join a room, send/receive messages:
15058
- nexus(action='connect', agent_name='MyAgent')
15059
- nexus(action='join_room', room_id='general')
15060
- nexus(action='send_message', room_id='general', message='Hello from MyAgent!')
15061
- Everything else (peer discovery, IPFS storage, x402 payments) is automatic.
15062
-
15063
- Additional actions: disconnect, status, list_rooms, discover_peers, find_agent,
15064
- register_service, list_services, wallet_status, wallet_create, inference_proof,
15065
- store_content, retrieve_content.
15066
-
15067
- SECURITY: Wallet private keys are AES-256-GCM encrypted and NEVER accessible to you.
15068
- You can see the public address and balance, but NEVER the private key. All outbound messages
15069
- are scanned for key material leaks. Payment operations use the key internally.
15070
-
15071
- When the user asks about expanding capabilities or connecting with other agents, suggest
15072
- enabling nexus networking. Use inference_proof to benchmark and advertise capabilities.
15073
-
15074
- ## Temporal Agency \u2014 Scheduling, Reminders & Long-Horizon Tasks
15075
-
15076
- You have 4 temporal tools for persistent, cross-session time management:
15077
-
15078
- - scheduler: Create OS-level cron jobs that launch the agent on a schedule.
15079
- scheduler(action='schedule', task='Run full test suite', schedule='daily')
15080
- scheduler(action='list') \u2014 see all scheduled tasks
15081
- Presets: 'every 5 minutes', 'every hour', 'daily', 'weekly', 'monthly', or raw cron.
15082
-
15083
- - cron_agent: Like scheduler but with goal tracking, completion criteria, and execution history.
15084
- cron_agent(action='create', task='Check for dependency updates', goal='Keep deps current',
15085
- schedule='weekly', completion_criteria='No outdated packages', verify_command='npm outdated')
15086
- Use for long-horizon autonomous workflows: periodic reviews, monitoring, updates.
15087
-
15088
- - reminder: Leave a message for your future self across sessions.
15089
- reminder(action='create', message='Follow up on PR review', due='in 2 hours', priority='high')
15090
- Reminders surface automatically at agent startup. Use for deferred attention.
15091
-
15092
- - agenda: View and manage attention directives \u2014 what to focus on across sessions.
15093
- agenda(action='view') \u2014 see active focus items
15094
- agenda(action='set', focus='Finish migration before Friday', priority='critical')
15095
-
15096
- These tools use OS cron (survives process death) and persist state to .oa/ for cross-session continuity.
15097
- Use cron_agent for recurring autonomous tasks, scheduler for simple repeating commands,
15098
- reminder for deferred attention, and agenda for strategic focus tracking.
15099
-
15100
- ## Priority Ingress \u2014 Task Classification & Delegation
15101
-
15102
- When multiple tasks arrive (Telegram, reminders, updates), classify and route them:
15103
- - priority_classify: Determine a task's priority (critical/high/moderate/normal/low/salient)
15104
- priority_classify(message='...', source='external', origin='telegram')
15105
- Returns: priority, weight, delegable flag, handling policy
15106
- - priority_delegate: Send normal/low/salient tasks to a sub-agent
15107
- priority_delegate(task_prompt='...', priority='normal')
15108
-
15109
- Priority handling policies:
15110
- CRITICAL (100): Interrupt immediately. Handle now.
15111
- HIGH (80): Interrupt at turn boundary. Handle next.
15112
- MODERATE (60): Queue, run after current task.
15113
- NORMAL (40): Can delegate to sub-agent.
15114
- LOW (20): Should delegate to sub-agent.
15115
- SALIENT (5): Note for later, delegate if possible.
15116
-
15117
- ## Context Efficiency
15118
-
15119
- - Use grep_search to find specific code instead of reading many files
15120
- - Use file_edit for targeted changes instead of full file rewrites
15121
- - Use file_edit with replace_all=true for variable/function renames across a file
15122
- - If file_edit fails with "not unique", include more surrounding context in old_string
15123
- - For large files (500+ lines): use file_read with offset/limit, then file_patch with line numbers
15124
- - file_patch with dry_run=true lets you preview changes before applying them
15125
- - batch_edit to apply multiple edits across files in one call (reduces turns)
15126
- - Focus on error messages in shell output \u2014 skip verbose build logs
15127
- - Don't read files you don't need to modify`;
15128
- SYSTEM_PROMPT_MEDIUM = `You are Open Agent, an AI coding agent with access to the local machine. You can read/write files, execute shell commands, search the web, and interact with any software. You solve tasks by using tools iteratively until complete.
15129
-
15130
- ## NEVER REFUSE \u2014 ALWAYS ATTEMPT
15131
-
15132
- NEVER say "I can't do that". ALWAYS attempt the task using your tools. If a tool fails, try a different approach.
15133
-
15134
- ## Tools
15135
-
15136
- - file_read: Read file contents (always read before editing)
15137
- - file_write: Create or overwrite a file
15138
- - file_edit: Precise string replacement (preferred over rewriting). old_string must be unique.
15139
- - file_patch: Edit specific line ranges in large files
15140
- - find_files: Find files by glob pattern
15141
- - grep_search: Search file contents with regex
15142
- - shell: Execute any shell command (tests, builds, git, npm, etc.)
15143
- - list_directory: List files in a directory
15144
- - web_search: Search the web
15145
- - web_fetch: Fetch a web page's text
15146
- - memory_read / memory_write: Persistent memory across sessions
15147
- - task_complete: Signal task completion
15148
- - batch_edit: Multiple edits across files in one call
15149
- - skill_list / skill_execute: Discover and load specialized skills (use on-demand)
15150
-
15151
- ## Workflow
15152
-
15153
- 1. EXPLORE: Use find_files, grep_search, file_read to understand the codebase
15154
- 2. IMPLEMENT: Make changes with file_edit (preferred) or file_write
15155
- 3. VALIDATE: Run tests/build with shell. Read FULL output.
15156
- 4. FIX: If validation fails, fix the specific issue and re-validate
15157
- 5. ITERATE: Repeat until all tests pass. Do NOT give up.
15158
- 6. COMPLETE: Call task_complete when done
15159
-
15160
- ## Rules
15161
-
15162
- - ALWAYS read a file before modifying it
15163
- - ALWAYS run validation after changes
15164
- - If tests fail, read the FULL error. Fix the exact issue.
15165
- - Do NOT give up after failure. Iterate until it passes.
15166
- - Use file_edit for small changes, not full file rewrites
15167
- - You MUST call task_complete when done
15168
- - Do NOT output long explanations. Focus on tool calls.`;
15169
- SYSTEM_PROMPT_SMALL = `You are a coding agent. You MUST call tools in EVERY response. NEVER reply with only text.
15170
-
15171
- Tools: file_read, file_write, file_edit, shell, task_complete, find_files, grep_search, web_search, web_fetch
15172
-
15173
- Steps:
15174
- 1. file_read the source files AND test files
15175
- 2. file_edit or file_write to make changes
15176
- 3. shell to run tests (npm test, etc.)
15177
- 4. If tests fail: read error, fix, retest
15178
- 5. task_complete when tests pass
15179
-
15180
- Rules:
15181
- - ALWAYS call tools. NEVER just write text.
15182
- - Read files before editing them.
15183
- - Run tests after every change.
15184
- - Call task_complete when done.`;
14810
+ init_promptLoader();
14811
+ SYSTEM_PROMPT = loadPrompt("agentic/system-large.md");
14812
+ SYSTEM_PROMPT_MEDIUM = loadPrompt("agentic/system-medium.md");
14813
+ SYSTEM_PROMPT_SMALL = loadPrompt("agentic/system-small.md");
15185
14814
  AgenticRunner = class {
15186
14815
  backend;
15187
14816
  tools = /* @__PURE__ */ new Map();
@@ -15206,6 +14835,8 @@ Rules:
15206
14835
  _fileRegistry = /* @__PURE__ */ new Map();
15207
14836
  // -- Memex Experience Archive (arXiv:2603.04257 inspired) --
15208
14837
  _memexArchive = /* @__PURE__ */ new Map();
14838
+ // -- Consecutive ENOENT tracker (prevents path-guessing spirals) --
14839
+ _consecutiveEnoent = 0;
15209
14840
  // -- Session Checkpointing (Priority 5) --
15210
14841
  _sessionId = `session-${Date.now()}`;
15211
14842
  _workingDirectory = "";
@@ -15719,6 +15350,19 @@ ${result.output.length > maxLen ? this.foldOutput(result.output, maxLen) : resul
15719
15350
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
15720
15351
  });
15721
15352
  }
15353
+ const enoentTools = /* @__PURE__ */ new Set(["file_read", "list_directory", "find_files"]);
15354
+ if (!result.success && enoentTools.has(tc.name) && /ENOENT|no such file|does not exist/i.test(result.error ?? result.output)) {
15355
+ this._consecutiveEnoent++;
15356
+ if (this._consecutiveEnoent >= 2) {
15357
+ this.pendingUserMessages.push(`[SYSTEM] You have hit ${this._consecutiveEnoent} consecutive ENOENT errors. STOP guessing paths. Instead:
15358
+ 1. Use list_directory on the PROJECT ROOT to discover what actually exists
15359
+ 2. If the missing path came from memory, use memory_write to remove the stale reference
15360
+ 3. Navigate from the root to find the correct location
15361
+ Do NOT continue walking up parent directories.`);
15362
+ }
15363
+ } else {
15364
+ this._consecutiveEnoent = 0;
15365
+ }
15722
15366
  return { tc, output };
15723
15367
  };
15724
15368
  const parallelBatch = [];
@@ -15940,6 +15584,19 @@ Integrate this guidance into your current approach. Continue working on the task
15940
15584
  ...(truncated)` : result.output : `Error: ${result.error || "unknown error"}
15941
15585
  ${result.output}`;
15942
15586
  this.emit({ type: "tool_result", toolName: tc.name, content: output.slice(0, 200), success: result.success, turn, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
15587
+ const enoentTools2 = /* @__PURE__ */ new Set(["file_read", "list_directory", "find_files"]);
15588
+ if (!result.success && enoentTools2.has(tc.name) && /ENOENT|no such file|does not exist/i.test(result.error ?? result.output)) {
15589
+ this._consecutiveEnoent++;
15590
+ if (this._consecutiveEnoent >= 2) {
15591
+ this.pendingUserMessages.push(`[SYSTEM] You have hit ${this._consecutiveEnoent} consecutive ENOENT errors. STOP guessing paths. Instead:
15592
+ 1. Use list_directory on the PROJECT ROOT to discover what actually exists
15593
+ 2. If the missing path came from memory, use memory_write to remove the stale reference
15594
+ 3. Navigate from the root to find the correct location
15595
+ Do NOT continue walking up parent directories.`);
15596
+ }
15597
+ } else {
15598
+ this._consecutiveEnoent = 0;
15599
+ }
15943
15600
  const toolMsg = this.buildToolMessage(output, tc.id);
15944
15601
  messages.push(toolMsg);
15945
15602
  if (tc.name === "task_complete") {
@@ -16122,8 +15779,8 @@ ${marker}` : marker);
16122
15779
  return;
16123
15780
  try {
16124
15781
  const { mkdirSync: mkdirSync17, writeFileSync: writeFileSync15 } = __require("node:fs");
16125
- const { join: join49 } = __require("node:path");
16126
- const sessionDir = join49(this._workingDirectory, ".oa", "session", this._sessionId);
15782
+ const { join: join52 } = __require("node:path");
15783
+ const sessionDir = join52(this._workingDirectory, ".oa", "session", this._sessionId);
16127
15784
  mkdirSync17(sessionDir, { recursive: true });
16128
15785
  const checkpoint = {
16129
15786
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -16136,7 +15793,7 @@ ${marker}` : marker);
16136
15793
  memexEntryCount: this._memexArchive.size,
16137
15794
  fileRegistrySize: this._fileRegistry.size
16138
15795
  };
16139
- writeFileSync15(join49(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
15796
+ writeFileSync15(join52(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
16140
15797
  } catch {
16141
15798
  }
16142
15799
  }
@@ -16864,7 +16521,7 @@ Last analysis: ${lastAssistantText.slice(0, 300)}${lastAssistantText.length > 30
16864
16521
  const summaryPrompt = [
16865
16522
  {
16866
16523
  role: "system",
16867
- content: "You are a context compaction assistant. Given a transcript of agent-tool interactions, produce a structured markdown summary that preserves:\n1. **Goal**: What the agent was trying to accomplish\n2. **Completed Steps**: Specific actions taken and their outcomes\n3. **Files Modified**: List of files changed with what was done\n4. **Key Findings**: Important information discovered during exploration\n5. **Errors & Fixes**: Any errors encountered and how they were resolved\n6. **Current Status**: Where things stand right now\n\nBe concise. Use bullet points. Preserve file paths and error messages verbatim. Do NOT include the raw transcript \u2014 only the structured summary."
16524
+ content: loadPrompt("compaction/context-compaction.md")
16868
16525
  },
16869
16526
  {
16870
16527
  role: "user",
@@ -17374,41 +17031,22 @@ function getRubric(taskType) {
17374
17031
  }
17375
17032
  function buildEvaluationPrompt(task, summary, rubric) {
17376
17033
  const dimensionList = rubric.dimensions.map((d, i) => `${i + 1}. **${d.name}** (${Math.round(d.weight * 100)}%): ${d.criteria}`).join("\n");
17377
- return `You are a quality evaluator. Score the following completed work on these dimensions.
17378
-
17379
- ## Task
17380
- ${task}
17381
-
17382
- ## Completed Work Summary
17383
- ${summary}
17384
-
17385
- ## Scoring Dimensions (${rubric.label} task)
17386
- ${dimensionList}
17387
-
17388
- ## Instructions
17389
- For each dimension, provide:
17390
- 1. A score from 0-10 (0 = completely missing, 5 = adequate, 10 = exceptional)
17391
- 2. A brief explanation (1-2 sentences)
17392
-
17393
- Then provide an overall summary of the work quality.
17394
-
17395
- Respond in EXACTLY this JSON format:
17396
- {
17397
- "dimensions": [
17398
- {"name": "${rubric.dimensions[0].name}", "score": <0-10>, "feedback": "<explanation>"},
17399
- {"name": "${rubric.dimensions[1].name}", "score": <0-10>, "feedback": "<explanation>"},
17400
- {"name": "${rubric.dimensions[2].name}", "score": <0-10>, "feedback": "<explanation>"},
17401
- {"name": "${rubric.dimensions[3].name}", "score": <0-10>, "feedback": "<explanation>"}
17402
- ],
17403
- "summary": "<2-3 sentence overall assessment>"
17404
- }
17405
-
17406
- Respond with ONLY the JSON object, no other text.`;
17034
+ return loadPrompt("runners/evaluator.md", {
17035
+ task,
17036
+ summary,
17037
+ rubricLabel: rubric.label,
17038
+ dimensionList,
17039
+ dim0: rubric.dimensions[0].name,
17040
+ dim1: rubric.dimensions[1].name,
17041
+ dim2: rubric.dimensions[2].name,
17042
+ dim3: rubric.dimensions[3].name
17043
+ });
17407
17044
  }
17408
17045
  var RUBRICS, TASK_TYPE_PATTERNS, WorkEvaluator;
17409
17046
  var init_workEvaluator = __esm({
17410
17047
  "packages/orchestrator/dist/workEvaluator.js"() {
17411
17048
  "use strict";
17049
+ init_promptLoader();
17412
17050
  RUBRICS = {
17413
17051
  code: {
17414
17052
  type: "code",
@@ -17719,10 +17357,10 @@ __export(listen_exports, {
17719
17357
  waitForTranscribeCli: () => waitForTranscribeCli
17720
17358
  });
17721
17359
  import { spawn as spawn11, execSync as execSync22 } from "node:child_process";
17722
- import { existsSync as existsSync22, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6, readdirSync as readdirSync6 } from "node:fs";
17723
- import { join as join31, dirname as dirname10 } from "node:path";
17360
+ import { existsSync as existsSync23, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6, readdirSync as readdirSync6 } from "node:fs";
17361
+ import { join as join32, dirname as dirname11 } from "node:path";
17724
17362
  import { homedir as homedir8 } from "node:os";
17725
- import { fileURLToPath as fileURLToPath7 } from "node:url";
17363
+ import { fileURLToPath as fileURLToPath8 } from "node:url";
17726
17364
  import { EventEmitter } from "node:events";
17727
17365
  import { createInterface as createInterface2 } from "node:readline";
17728
17366
  function isAudioPath(path) {
@@ -17804,17 +17442,17 @@ function findMicCaptureCommand() {
17804
17442
  return null;
17805
17443
  }
17806
17444
  function findLiveWhisperScript() {
17807
- const thisDir = dirname10(fileURLToPath7(import.meta.url));
17445
+ const thisDir = dirname11(fileURLToPath8(import.meta.url));
17808
17446
  const candidates = [
17809
- join31(thisDir, "../../../../packages/execution/scripts/live-whisper.py"),
17810
- join31(thisDir, "../../../packages/execution/scripts/live-whisper.py"),
17811
- join31(thisDir, "../../execution/scripts/live-whisper.py"),
17447
+ join32(thisDir, "../../../../packages/execution/scripts/live-whisper.py"),
17448
+ join32(thisDir, "../../../packages/execution/scripts/live-whisper.py"),
17449
+ join32(thisDir, "../../execution/scripts/live-whisper.py"),
17812
17450
  // npm install layout — scripts bundled alongside dist
17813
- join31(thisDir, "../scripts/live-whisper.py"),
17814
- join31(thisDir, "../../scripts/live-whisper.py")
17451
+ join32(thisDir, "../scripts/live-whisper.py"),
17452
+ join32(thisDir, "../../scripts/live-whisper.py")
17815
17453
  ];
17816
17454
  for (const p of candidates) {
17817
- if (existsSync22(p))
17455
+ if (existsSync23(p))
17818
17456
  return p;
17819
17457
  }
17820
17458
  try {
@@ -17824,21 +17462,21 @@ function findLiveWhisperScript() {
17824
17462
  stdio: ["pipe", "pipe", "pipe"]
17825
17463
  }).trim();
17826
17464
  const candidates2 = [
17827
- join31(globalRoot, "open-agents-ai", "dist", "scripts", "live-whisper.py"),
17828
- join31(globalRoot, "open-agents-ai", "scripts", "live-whisper.py")
17465
+ join32(globalRoot, "open-agents-ai", "dist", "scripts", "live-whisper.py"),
17466
+ join32(globalRoot, "open-agents-ai", "scripts", "live-whisper.py")
17829
17467
  ];
17830
17468
  for (const p of candidates2) {
17831
- if (existsSync22(p))
17469
+ if (existsSync23(p))
17832
17470
  return p;
17833
17471
  }
17834
17472
  } catch {
17835
17473
  }
17836
- const nvmBase = join31(homedir8(), ".nvm", "versions", "node");
17837
- if (existsSync22(nvmBase)) {
17474
+ const nvmBase = join32(homedir8(), ".nvm", "versions", "node");
17475
+ if (existsSync23(nvmBase)) {
17838
17476
  try {
17839
17477
  for (const ver of readdirSync6(nvmBase)) {
17840
- const p = join31(nvmBase, ver, "lib", "node_modules", "open-agents-ai", "dist", "scripts", "live-whisper.py");
17841
- if (existsSync22(p))
17478
+ const p = join32(nvmBase, ver, "lib", "node_modules", "open-agents-ai", "dist", "scripts", "live-whisper.py");
17479
+ if (existsSync23(p))
17842
17480
  return p;
17843
17481
  }
17844
17482
  } catch {
@@ -17856,7 +17494,7 @@ function ensureTranscribeCliBackground() {
17856
17494
  timeout: 5e3,
17857
17495
  stdio: ["pipe", "pipe", "pipe"]
17858
17496
  }).trim();
17859
- if (existsSync22(join31(globalRoot, "transcribe-cli", "dist", "index.js"))) {
17497
+ if (existsSync23(join32(globalRoot, "transcribe-cli", "dist", "index.js"))) {
17860
17498
  return true;
17861
17499
  }
17862
17500
  } catch {
@@ -18079,24 +17717,24 @@ var init_listen = __esm({
18079
17717
  timeout: 5e3,
18080
17718
  stdio: ["pipe", "pipe", "pipe"]
18081
17719
  }).trim();
18082
- const tcPath = join31(globalRoot, "transcribe-cli");
18083
- if (existsSync22(join31(tcPath, "dist", "index.js"))) {
17720
+ const tcPath = join32(globalRoot, "transcribe-cli");
17721
+ if (existsSync23(join32(tcPath, "dist", "index.js"))) {
18084
17722
  const { createRequire: createRequire4 } = await import("node:module");
18085
17723
  const req = createRequire4(import.meta.url);
18086
- return req(join31(tcPath, "dist", "index.js"));
17724
+ return req(join32(tcPath, "dist", "index.js"));
18087
17725
  }
18088
17726
  } catch {
18089
17727
  }
18090
- const nvmBase = join31(homedir8(), ".nvm", "versions", "node");
18091
- if (existsSync22(nvmBase)) {
17728
+ const nvmBase = join32(homedir8(), ".nvm", "versions", "node");
17729
+ if (existsSync23(nvmBase)) {
18092
17730
  try {
18093
17731
  const { readdirSync: readdirSync15 } = await import("node:fs");
18094
17732
  for (const ver of readdirSync15(nvmBase)) {
18095
- const tcPath = join31(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
18096
- if (existsSync22(join31(tcPath, "dist", "index.js"))) {
17733
+ const tcPath = join32(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
17734
+ if (existsSync23(join32(tcPath, "dist", "index.js"))) {
18097
17735
  const { createRequire: createRequire4 } = await import("node:module");
18098
17736
  const req = createRequire4(import.meta.url);
18099
- return req(join31(tcPath, "dist", "index.js"));
17737
+ return req(join32(tcPath, "dist", "index.js"));
18100
17738
  }
18101
17739
  }
18102
17740
  } catch {
@@ -18378,9 +18016,9 @@ transcribe-cli error: ${transcribeCliError}` : "";
18378
18016
  });
18379
18017
  if (outputDir) {
18380
18018
  const { basename: basename16 } = await import("node:path");
18381
- const transcriptDir = join31(outputDir, ".oa", "transcripts");
18019
+ const transcriptDir = join32(outputDir, ".oa", "transcripts");
18382
18020
  mkdirSync6(transcriptDir, { recursive: true });
18383
- const outFile = join31(transcriptDir, `${basename16(filePath)}.txt`);
18021
+ const outFile = join32(transcriptDir, `${basename16(filePath)}.txt`);
18384
18022
  writeFileSync6(outFile, result.text, "utf-8");
18385
18023
  }
18386
18024
  return {
@@ -23955,8 +23593,8 @@ var init_types = __esm({
23955
23593
 
23956
23594
  // packages/cli/dist/tui/p2p/secret-vault.js
23957
23595
  import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes8, scryptSync as scryptSync2, createHash as createHash2 } from "node:crypto";
23958
- import { readFileSync as readFileSync15, writeFileSync as writeFileSync7, existsSync as existsSync23, mkdirSync as mkdirSync7 } from "node:fs";
23959
- import { join as join32, dirname as dirname11 } from "node:path";
23596
+ import { readFileSync as readFileSync16, writeFileSync as writeFileSync7, existsSync as existsSync24, mkdirSync as mkdirSync7 } from "node:fs";
23597
+ import { join as join33, dirname as dirname12 } from "node:path";
23960
23598
  var PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, CIPHER_ALGO, SALT_LEN, IV_LEN, KEY_LEN, SecretVault;
23961
23599
  var init_secret_vault = __esm({
23962
23600
  "packages/cli/dist/tui/p2p/secret-vault.js"() {
@@ -24167,8 +23805,8 @@ var init_secret_vault = __esm({
24167
23805
  const encrypted = Buffer.concat([cipher.update(data, "utf8"), cipher.final()]);
24168
23806
  const tag = cipher.getAuthTag();
24169
23807
  const blob = Buffer.concat([salt, iv, tag, encrypted]);
24170
- const dir = dirname11(this.storePath);
24171
- if (!existsSync23(dir))
23808
+ const dir = dirname12(this.storePath);
23809
+ if (!existsSync24(dir))
24172
23810
  mkdirSync7(dir, { recursive: true });
24173
23811
  writeFileSync7(this.storePath, blob, { mode: 384 });
24174
23812
  }
@@ -24177,9 +23815,9 @@ var init_secret_vault = __esm({
24177
23815
  * Returns the number of secrets loaded.
24178
23816
  */
24179
23817
  load(passphrase) {
24180
- if (!this.storePath || !existsSync23(this.storePath))
23818
+ if (!this.storePath || !existsSync24(this.storePath))
24181
23819
  return 0;
24182
- const blob = readFileSync15(this.storePath);
23820
+ const blob = readFileSync16(this.storePath);
24183
23821
  if (blob.length < SALT_LEN + IV_LEN + 16) {
24184
23822
  throw new Error("Vault file is corrupted (too small)");
24185
23823
  }
@@ -25389,6 +25027,37 @@ var init_render2 = __esm({
25389
25027
  }
25390
25028
  });
25391
25029
 
25030
+ // packages/prompts/dist/promptLoader.js
25031
+ import { readFileSync as readFileSync17, existsSync as existsSync25 } from "node:fs";
25032
+ import { join as join34, dirname as dirname13 } from "node:path";
25033
+ import { fileURLToPath as fileURLToPath9 } from "node:url";
25034
+ function loadPrompt2(promptPath, vars) {
25035
+ let content = cache2.get(promptPath);
25036
+ if (content === void 0) {
25037
+ const fullPath = join34(PROMPTS_DIR2, promptPath);
25038
+ if (!existsSync25(fullPath)) {
25039
+ throw new Error(`Prompt file not found: ${fullPath}`);
25040
+ }
25041
+ content = readFileSync17(fullPath, "utf-8");
25042
+ cache2.set(promptPath, content);
25043
+ }
25044
+ if (!vars)
25045
+ return content;
25046
+ return content.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] ?? `{{${key}}}`);
25047
+ }
25048
+ var __filename2, __dirname4, devPath, publishedPath, PROMPTS_DIR2, cache2;
25049
+ var init_promptLoader2 = __esm({
25050
+ "packages/prompts/dist/promptLoader.js"() {
25051
+ "use strict";
25052
+ __filename2 = fileURLToPath9(import.meta.url);
25053
+ __dirname4 = dirname13(__filename2);
25054
+ devPath = join34(__dirname4, "..", "templates");
25055
+ publishedPath = join34(__dirname4, "..", "prompts", "templates");
25056
+ PROMPTS_DIR2 = existsSync25(devPath) ? devPath : publishedPath;
25057
+ cache2 = /* @__PURE__ */ new Map();
25058
+ }
25059
+ });
25060
+
25392
25061
  // packages/prompts/dist/task-templates.js
25393
25062
  function getTaskTemplate(type) {
25394
25063
  return TEMPLATES[type];
@@ -25407,24 +25076,13 @@ var TEMPLATES;
25407
25076
  var init_task_templates = __esm({
25408
25077
  "packages/prompts/dist/task-templates.js"() {
25409
25078
  "use strict";
25079
+ init_promptLoader2();
25410
25080
  TEMPLATES = {
25411
25081
  code: {
25412
25082
  type: "code",
25413
25083
  label: "Software Development",
25414
25084
  description: "Writing, debugging, refactoring, or reviewing code.",
25415
- systemPromptAddition: `
25416
- ## Task Context: Software Development
25417
-
25418
- You are working on a software development task. Follow these principles:
25419
-
25420
- - **Read before writing**: Always read the existing code and understand the context before making changes.
25421
- - **Test-driven approach**: Run existing tests first, make changes, then verify tests still pass.
25422
- - **Minimal changes**: Make the smallest change that solves the problem. Avoid refactoring unrelated code.
25423
- - **Convention adherence**: Match the existing code style, naming conventions, and patterns in the project.
25424
- - **Error handling**: Ensure proper error handling and edge case coverage.
25425
- - **File organization**: Follow the existing project structure when adding new files.
25426
-
25427
- When the task is complete, verify by running tests and/or type-checking where available.`,
25085
+ systemPromptAddition: loadPrompt2("code.md"),
25428
25086
  recommendedTools: [
25429
25087
  "file_read",
25430
25088
  "file_write",
@@ -25441,19 +25099,7 @@ When the task is complete, verify by running tests and/or type-checking where av
25441
25099
  type: "document",
25442
25100
  label: "Document Drafting",
25443
25101
  description: "Creating reports, specifications, guides, proposals, or other professional documents.",
25444
- systemPromptAddition: `
25445
- ## Task Context: Document Drafting
25446
-
25447
- You are working on a professional document. Follow these principles:
25448
-
25449
- - **Audience awareness**: Tailor language, depth, and terminology to the intended audience.
25450
- - **Structure first**: Create a clear outline before filling in content. Use headings, sections, and lists.
25451
- - **Completeness**: Cover all aspects the user requested. Flag any areas where you need clarification.
25452
- - **Clarity**: Use clear, concise language. Avoid jargon unless appropriate for the audience.
25453
- - **Formatting**: Use appropriate markdown formatting \u2014 tables for data, code blocks for technical content, lists for enumerations.
25454
- - **Citations**: When referencing external information, note sources or indicate where citations are needed.
25455
-
25456
- Use the create_structured_file tool for spreadsheets, CSV, or formatted output. Use file_write for documents.`,
25102
+ systemPromptAddition: loadPrompt2("document.md"),
25457
25103
  recommendedTools: [
25458
25104
  "file_read",
25459
25105
  "file_write",
@@ -25468,20 +25114,7 @@ Use the create_structured_file tool for spreadsheets, CSV, or formatted output.
25468
25114
  type: "analysis",
25469
25115
  label: "Analysis & Research",
25470
25116
  description: "Analyzing data, evaluating options, conducting research, or producing insights.",
25471
- systemPromptAddition: `
25472
- ## Task Context: Analysis & Research
25473
-
25474
- You are working on an analytical task. Follow these principles:
25475
-
25476
- - **Evidence-based**: Ground conclusions in data, code, or verifiable sources. Avoid speculation.
25477
- - **Methodology**: State your analytical approach clearly. When comparing options, define criteria upfront.
25478
- - **Quantify**: Use numbers, metrics, and measurements wherever possible. Avoid vague qualifiers.
25479
- - **Visualization**: Present data in tables or structured formats for clarity.
25480
- - **Limitations**: Acknowledge limitations in your analysis \u2014 data gaps, assumptions, scope boundaries.
25481
- - **Actionable conclusions**: End with clear recommendations or next steps.
25482
-
25483
- Use web_search for external research. Use grep_search and codebase_map for codebase analysis.
25484
- Use create_structured_file to output data as CSV, JSON, or markdown tables.`,
25117
+ systemPromptAddition: loadPrompt2("analysis.md"),
25485
25118
  recommendedTools: [
25486
25119
  "file_read",
25487
25120
  "grep_search",
@@ -25498,21 +25131,7 @@ Use create_structured_file to output data as CSV, JSON, or markdown tables.`,
25498
25131
  type: "plan",
25499
25132
  label: "Planning & Design",
25500
25133
  description: "Creating project plans, system designs, architecture proposals, or roadmaps.",
25501
- systemPromptAddition: `
25502
- ## Task Context: Planning & Design
25503
-
25504
- You are working on a planning or design task. Follow these principles:
25505
-
25506
- - **Scope clarity**: Define what is in-scope and out-of-scope explicitly.
25507
- - **Phased approach**: Break work into phases or milestones with clear dependencies.
25508
- - **Risk identification**: Identify key risks, assumptions, and dependencies for each phase.
25509
- - **Resource awareness**: Consider team size, skill requirements, and tool/infrastructure needs.
25510
- - **Alternatives**: When making design decisions, briefly note alternatives considered and why the chosen approach is preferred.
25511
- - **Actionable items**: Every section should include concrete next steps or action items.
25512
- - **Traceability**: Link plan items to requirements or goals where applicable.
25513
-
25514
- Use codebase_map and grep_search to understand existing architecture.
25515
- Use create_structured_file for timeline/schedule output.`,
25134
+ systemPromptAddition: loadPrompt2("plan.md"),
25516
25135
  recommendedTools: [
25517
25136
  "file_read",
25518
25137
  "grep_search",
@@ -25529,15 +25148,7 @@ Use create_structured_file for timeline/schedule output.`,
25529
25148
  type: "general",
25530
25149
  label: "General Task",
25531
25150
  description: "Tasks that don't clearly fit another category.",
25532
- systemPromptAddition: `
25533
- ## Task Context: General
25534
-
25535
- Approach this task thoughtfully:
25536
-
25537
- - **Clarify intent**: If the task is ambiguous, use available tools to gather context before proceeding.
25538
- - **Appropriate tools**: Select the right tools for the job \u2014 file tools for file work, search for research, shell for commands.
25539
- - **Quality output**: Regardless of task type, produce clear, complete, and well-organized output.
25540
- - **Verify results**: After completing work, verify the results are correct and complete.`,
25151
+ systemPromptAddition: loadPrompt2("general.md"),
25541
25152
  recommendedTools: [
25542
25153
  "file_read",
25543
25154
  "file_write",
@@ -25553,8 +25164,8 @@ Approach this task thoughtfully:
25553
25164
  });
25554
25165
 
25555
25166
  // packages/prompts/dist/index.js
25556
- import { join as join33, dirname as dirname12 } from "node:path";
25557
- import { fileURLToPath as fileURLToPath8 } from "node:url";
25167
+ import { join as join35, dirname as dirname14 } from "node:path";
25168
+ import { fileURLToPath as fileURLToPath10 } from "node:url";
25558
25169
  var _dir, _packageRoot;
25559
25170
  var init_dist6 = __esm({
25560
25171
  "packages/prompts/dist/index.js"() {
@@ -25563,25 +25174,25 @@ var init_dist6 = __esm({
25563
25174
  init_render2();
25564
25175
  init_task_templates();
25565
25176
  init_render2();
25566
- _dir = dirname12(fileURLToPath8(import.meta.url));
25567
- _packageRoot = join33(_dir, "..");
25177
+ _dir = dirname14(fileURLToPath10(import.meta.url));
25178
+ _packageRoot = join35(_dir, "..");
25568
25179
  }
25569
25180
  });
25570
25181
 
25571
25182
  // packages/cli/dist/tui/oa-directory.js
25572
- import { existsSync as existsSync24, mkdirSync as mkdirSync8, readFileSync as readFileSync16, writeFileSync as writeFileSync8, readdirSync as readdirSync7, statSync as statSync9, unlinkSync as unlinkSync3 } from "node:fs";
25573
- import { join as join34, relative as relative2, basename as basename9, extname as extname8 } from "node:path";
25183
+ import { existsSync as existsSync26, mkdirSync as mkdirSync8, readFileSync as readFileSync18, writeFileSync as writeFileSync8, readdirSync as readdirSync7, statSync as statSync9, unlinkSync as unlinkSync3 } from "node:fs";
25184
+ import { join as join36, relative as relative2, basename as basename9, extname as extname8 } from "node:path";
25574
25185
  import { homedir as homedir9 } from "node:os";
25575
25186
  function initOaDirectory(repoRoot) {
25576
- const oaPath = join34(repoRoot, OA_DIR);
25187
+ const oaPath = join36(repoRoot, OA_DIR);
25577
25188
  for (const sub of SUBDIRS) {
25578
- mkdirSync8(join34(oaPath, sub), { recursive: true });
25189
+ mkdirSync8(join36(oaPath, sub), { recursive: true });
25579
25190
  }
25580
25191
  try {
25581
- const gitignorePath = join34(repoRoot, ".gitignore");
25192
+ const gitignorePath = join36(repoRoot, ".gitignore");
25582
25193
  const settingsPattern = ".oa/settings.json";
25583
- if (existsSync24(gitignorePath)) {
25584
- const content = readFileSync16(gitignorePath, "utf-8");
25194
+ if (existsSync26(gitignorePath)) {
25195
+ const content = readFileSync18(gitignorePath, "utf-8");
25585
25196
  if (!content.includes(settingsPattern)) {
25586
25197
  writeFileSync8(gitignorePath, content.trimEnd() + "\n" + settingsPattern + "\n", "utf-8");
25587
25198
  }
@@ -25591,41 +25202,41 @@ function initOaDirectory(repoRoot) {
25591
25202
  return oaPath;
25592
25203
  }
25593
25204
  function hasOaDirectory(repoRoot) {
25594
- return existsSync24(join34(repoRoot, OA_DIR, "index"));
25205
+ return existsSync26(join36(repoRoot, OA_DIR, "index"));
25595
25206
  }
25596
25207
  function loadProjectSettings(repoRoot) {
25597
- const settingsPath = join34(repoRoot, OA_DIR, "settings.json");
25208
+ const settingsPath = join36(repoRoot, OA_DIR, "settings.json");
25598
25209
  try {
25599
- if (existsSync24(settingsPath)) {
25600
- return JSON.parse(readFileSync16(settingsPath, "utf-8"));
25210
+ if (existsSync26(settingsPath)) {
25211
+ return JSON.parse(readFileSync18(settingsPath, "utf-8"));
25601
25212
  }
25602
25213
  } catch {
25603
25214
  }
25604
25215
  return {};
25605
25216
  }
25606
25217
  function saveProjectSettings(repoRoot, settings) {
25607
- const oaPath = join34(repoRoot, OA_DIR);
25218
+ const oaPath = join36(repoRoot, OA_DIR);
25608
25219
  mkdirSync8(oaPath, { recursive: true });
25609
25220
  const existing = loadProjectSettings(repoRoot);
25610
25221
  const merged = { ...existing, ...settings };
25611
- writeFileSync8(join34(oaPath, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
25222
+ writeFileSync8(join36(oaPath, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
25612
25223
  }
25613
25224
  function loadGlobalSettings() {
25614
- const settingsPath = join34(homedir9(), ".open-agents", "settings.json");
25225
+ const settingsPath = join36(homedir9(), ".open-agents", "settings.json");
25615
25226
  try {
25616
- if (existsSync24(settingsPath)) {
25617
- return JSON.parse(readFileSync16(settingsPath, "utf-8"));
25227
+ if (existsSync26(settingsPath)) {
25228
+ return JSON.parse(readFileSync18(settingsPath, "utf-8"));
25618
25229
  }
25619
25230
  } catch {
25620
25231
  }
25621
25232
  return {};
25622
25233
  }
25623
25234
  function saveGlobalSettings(settings) {
25624
- const dir = join34(homedir9(), ".open-agents");
25235
+ const dir = join36(homedir9(), ".open-agents");
25625
25236
  mkdirSync8(dir, { recursive: true });
25626
25237
  const existing = loadGlobalSettings();
25627
25238
  const merged = { ...existing, ...settings };
25628
- writeFileSync8(join34(dir, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
25239
+ writeFileSync8(join36(dir, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
25629
25240
  }
25630
25241
  function resolveSettings(repoRoot) {
25631
25242
  const global = loadGlobalSettings();
@@ -25640,12 +25251,12 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
25640
25251
  while (dir && !visited.has(dir)) {
25641
25252
  visited.add(dir);
25642
25253
  for (const name of CONTEXT_FILES) {
25643
- const filePath = join34(dir, name);
25254
+ const filePath = join36(dir, name);
25644
25255
  const normalizedName = name.toLowerCase();
25645
- if (existsSync24(filePath) && !seen.has(filePath)) {
25256
+ if (existsSync26(filePath) && !seen.has(filePath)) {
25646
25257
  seen.add(filePath);
25647
25258
  try {
25648
- let content = readFileSync16(filePath, "utf-8");
25259
+ let content = readFileSync18(filePath, "utf-8");
25649
25260
  if (content.length > maxContentLen) {
25650
25261
  content = content.slice(0, maxContentLen) + "\n\n...(truncated)";
25651
25262
  }
@@ -25659,11 +25270,11 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
25659
25270
  }
25660
25271
  }
25661
25272
  }
25662
- const projectMap = join34(dir, OA_DIR, "context", "project-map.md");
25663
- if (existsSync24(projectMap) && !seen.has(projectMap)) {
25273
+ const projectMap = join36(dir, OA_DIR, "context", "project-map.md");
25274
+ if (existsSync26(projectMap) && !seen.has(projectMap)) {
25664
25275
  seen.add(projectMap);
25665
25276
  try {
25666
- let content = readFileSync16(projectMap, "utf-8");
25277
+ let content = readFileSync18(projectMap, "utf-8");
25667
25278
  if (content.length > maxContentLen) {
25668
25279
  content = content.slice(0, maxContentLen) + "\n\n...(truncated)";
25669
25280
  }
@@ -25675,7 +25286,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
25675
25286
  } catch {
25676
25287
  }
25677
25288
  }
25678
- const parent = join34(dir, "..");
25289
+ const parent = join36(dir, "..");
25679
25290
  if (parent === dir)
25680
25291
  break;
25681
25292
  dir = parent;
@@ -25693,9 +25304,9 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
25693
25304
  return found;
25694
25305
  }
25695
25306
  function readIndexMeta(repoRoot) {
25696
- const metaPath = join34(repoRoot, OA_DIR, "index", "meta.json");
25307
+ const metaPath = join36(repoRoot, OA_DIR, "index", "meta.json");
25697
25308
  try {
25698
- return JSON.parse(readFileSync16(metaPath, "utf-8"));
25309
+ return JSON.parse(readFileSync18(metaPath, "utf-8"));
25699
25310
  } catch {
25700
25311
  return null;
25701
25312
  }
@@ -25746,28 +25357,28 @@ ${tree}\`\`\`
25746
25357
  sections.push("");
25747
25358
  }
25748
25359
  const content = sections.join("\n");
25749
- const contextDir = join34(repoRoot, OA_DIR, "context");
25360
+ const contextDir = join36(repoRoot, OA_DIR, "context");
25750
25361
  mkdirSync8(contextDir, { recursive: true });
25751
- writeFileSync8(join34(contextDir, "project-map.md"), content, "utf-8");
25362
+ writeFileSync8(join36(contextDir, "project-map.md"), content, "utf-8");
25752
25363
  return content;
25753
25364
  }
25754
25365
  function saveSession(repoRoot, session) {
25755
- const historyDir = join34(repoRoot, OA_DIR, "history");
25366
+ const historyDir = join36(repoRoot, OA_DIR, "history");
25756
25367
  mkdirSync8(historyDir, { recursive: true });
25757
- writeFileSync8(join34(historyDir, `${session.id}.json`), JSON.stringify(session, null, 2), "utf-8");
25368
+ writeFileSync8(join36(historyDir, `${session.id}.json`), JSON.stringify(session, null, 2), "utf-8");
25758
25369
  }
25759
25370
  function loadRecentSessions(repoRoot, limit = 5) {
25760
- const historyDir = join34(repoRoot, OA_DIR, "history");
25761
- if (!existsSync24(historyDir))
25371
+ const historyDir = join36(repoRoot, OA_DIR, "history");
25372
+ if (!existsSync26(historyDir))
25762
25373
  return [];
25763
25374
  try {
25764
25375
  const files = readdirSync7(historyDir).filter((f) => f.endsWith(".json") && f !== "pending-task.json").map((f) => {
25765
- const stat5 = statSync9(join34(historyDir, f));
25376
+ const stat5 = statSync9(join36(historyDir, f));
25766
25377
  return { file: f, mtime: stat5.mtimeMs };
25767
25378
  }).sort((a, b) => b.mtime - a.mtime).slice(0, limit);
25768
25379
  return files.map((f) => {
25769
25380
  try {
25770
- return JSON.parse(readFileSync16(join34(historyDir, f.file), "utf-8"));
25381
+ return JSON.parse(readFileSync18(join36(historyDir, f.file), "utf-8"));
25771
25382
  } catch {
25772
25383
  return null;
25773
25384
  }
@@ -25777,16 +25388,16 @@ function loadRecentSessions(repoRoot, limit = 5) {
25777
25388
  }
25778
25389
  }
25779
25390
  function savePendingTask(repoRoot, task) {
25780
- const historyDir = join34(repoRoot, OA_DIR, "history");
25391
+ const historyDir = join36(repoRoot, OA_DIR, "history");
25781
25392
  mkdirSync8(historyDir, { recursive: true });
25782
- writeFileSync8(join34(historyDir, PENDING_TASK_FILE), JSON.stringify(task, null, 2) + "\n", "utf-8");
25393
+ writeFileSync8(join36(historyDir, PENDING_TASK_FILE), JSON.stringify(task, null, 2) + "\n", "utf-8");
25783
25394
  }
25784
25395
  function loadPendingTask(repoRoot) {
25785
- const filePath = join34(repoRoot, OA_DIR, "history", PENDING_TASK_FILE);
25396
+ const filePath = join36(repoRoot, OA_DIR, "history", PENDING_TASK_FILE);
25786
25397
  try {
25787
- if (!existsSync24(filePath))
25398
+ if (!existsSync26(filePath))
25788
25399
  return null;
25789
- const data = JSON.parse(readFileSync16(filePath, "utf-8"));
25400
+ const data = JSON.parse(readFileSync18(filePath, "utf-8"));
25790
25401
  try {
25791
25402
  unlinkSync3(filePath);
25792
25403
  } catch {
@@ -25797,13 +25408,13 @@ function loadPendingTask(repoRoot) {
25797
25408
  }
25798
25409
  }
25799
25410
  function saveSessionContext(repoRoot, entry) {
25800
- const contextDir = join34(repoRoot, OA_DIR, "context");
25411
+ const contextDir = join36(repoRoot, OA_DIR, "context");
25801
25412
  mkdirSync8(contextDir, { recursive: true });
25802
- const filePath = join34(contextDir, CONTEXT_SAVE_FILE);
25413
+ const filePath = join36(contextDir, CONTEXT_SAVE_FILE);
25803
25414
  let ctx;
25804
25415
  try {
25805
- if (existsSync24(filePath)) {
25806
- ctx = JSON.parse(readFileSync16(filePath, "utf-8"));
25416
+ if (existsSync26(filePath)) {
25417
+ ctx = JSON.parse(readFileSync18(filePath, "utf-8"));
25807
25418
  } else {
25808
25419
  ctx = { entries: [], maxEntries: MAX_CONTEXT_ENTRIES, updatedAt: "" };
25809
25420
  }
@@ -25818,11 +25429,11 @@ function saveSessionContext(repoRoot, entry) {
25818
25429
  writeFileSync8(filePath, JSON.stringify(ctx, null, 2) + "\n", "utf-8");
25819
25430
  }
25820
25431
  function loadSessionContext(repoRoot) {
25821
- const filePath = join34(repoRoot, OA_DIR, "context", CONTEXT_SAVE_FILE);
25432
+ const filePath = join36(repoRoot, OA_DIR, "context", CONTEXT_SAVE_FILE);
25822
25433
  try {
25823
- if (!existsSync24(filePath))
25434
+ if (!existsSync26(filePath))
25824
25435
  return null;
25825
- return JSON.parse(readFileSync16(filePath, "utf-8"));
25436
+ return JSON.parse(readFileSync18(filePath, "utf-8"));
25826
25437
  } catch {
25827
25438
  return null;
25828
25439
  }
@@ -25869,12 +25480,12 @@ function detectManifests(repoRoot) {
25869
25480
  { file: "docker-compose.yaml", type: "Docker Compose" }
25870
25481
  ];
25871
25482
  for (const check of checks) {
25872
- const filePath = join34(repoRoot, check.file);
25873
- if (existsSync24(filePath)) {
25483
+ const filePath = join36(repoRoot, check.file);
25484
+ if (existsSync26(filePath)) {
25874
25485
  let name;
25875
25486
  if (check.nameField) {
25876
25487
  try {
25877
- const data = JSON.parse(readFileSync16(filePath, "utf-8"));
25488
+ const data = JSON.parse(readFileSync18(filePath, "utf-8"));
25878
25489
  name = data[check.nameField];
25879
25490
  } catch {
25880
25491
  }
@@ -25903,7 +25514,7 @@ function findKeyFiles(repoRoot) {
25903
25514
  { pattern: "CLAUDE.md", description: "Claude Code context" }
25904
25515
  ];
25905
25516
  for (const check of checks) {
25906
- if (existsSync24(join34(repoRoot, check.pattern))) {
25517
+ if (existsSync26(join36(repoRoot, check.pattern))) {
25907
25518
  keyFiles.push({ path: check.pattern, description: check.description });
25908
25519
  }
25909
25520
  }
@@ -25929,12 +25540,12 @@ function buildDirTree(root, maxDepth, prefix = "", depth = 0) {
25929
25540
  if (entry.isDirectory()) {
25930
25541
  let fileCount = 0;
25931
25542
  try {
25932
- fileCount = readdirSync7(join34(root, entry.name)).filter((f) => !f.startsWith(".")).length;
25543
+ fileCount = readdirSync7(join36(root, entry.name)).filter((f) => !f.startsWith(".")).length;
25933
25544
  } catch {
25934
25545
  }
25935
25546
  result += `${prefix}${connector}${entry.name}/ (${fileCount})
25936
25547
  `;
25937
- result += buildDirTree(join34(root, entry.name), maxDepth, childPrefix, depth + 1);
25548
+ result += buildDirTree(join36(root, entry.name), maxDepth, childPrefix, depth + 1);
25938
25549
  } else if (depth < maxDepth) {
25939
25550
  result += `${prefix}${connector}${entry.name}
25940
25551
  `;
@@ -25988,8 +25599,8 @@ var init_oa_directory = __esm({
25988
25599
  // packages/cli/dist/tui/setup.js
25989
25600
  import * as readline from "node:readline";
25990
25601
  import { execSync as execSync24, spawn as spawn14 } from "node:child_process";
25991
- import { existsSync as existsSync25, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9 } from "node:fs";
25992
- import { join as join35 } from "node:path";
25602
+ import { existsSync as existsSync27, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9 } from "node:fs";
25603
+ import { join as join37 } from "node:path";
25993
25604
  import { homedir as homedir10, platform } from "node:os";
25994
25605
  function detectSystemSpecs() {
25995
25606
  let totalRamGB = 0;
@@ -26222,7 +25833,7 @@ async function installOllamaMac(_rl) {
26222
25833
  execSync24('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"', { stdio: "inherit", timeout: 6e5 });
26223
25834
  if (!hasCmd("brew")) {
26224
25835
  try {
26225
- const brewPrefix = existsSync25("/opt/homebrew/bin/brew") ? "/opt/homebrew" : "/usr/local";
25836
+ const brewPrefix = existsSync27("/opt/homebrew/bin/brew") ? "/opt/homebrew" : "/usr/local";
26226
25837
  process.env["PATH"] = `${brewPrefix}/bin:${process.env["PATH"]}`;
26227
25838
  } catch {
26228
25839
  }
@@ -26976,9 +26587,9 @@ async function doSetup(config, rl) {
26976
26587
  `PARAMETER num_predict ${numPredict}`,
26977
26588
  `PARAMETER stop "<|endoftext|>"`
26978
26589
  ].join("\n");
26979
- const modelDir2 = join35(homedir10(), ".open-agents", "models");
26590
+ const modelDir2 = join37(homedir10(), ".open-agents", "models");
26980
26591
  mkdirSync9(modelDir2, { recursive: true });
26981
- const modelfilePath = join35(modelDir2, `Modelfile.${customName}`);
26592
+ const modelfilePath = join37(modelDir2, `Modelfile.${customName}`);
26982
26593
  writeFileSync9(modelfilePath, modelfileContent + "\n", "utf8");
26983
26594
  process.stdout.write(` ${c2.dim("Creating model...")} `);
26984
26595
  execSync24(`ollama create ${customName} -f ${modelfilePath}`, {
@@ -27024,7 +26635,7 @@ async function isModelAvailable(config) {
27024
26635
  }
27025
26636
  function isFirstRun() {
27026
26637
  try {
27027
- return !existsSync25(join35(homedir10(), ".open-agents", "config.json"));
26638
+ return !existsSync27(join37(homedir10(), ".open-agents", "config.json"));
27028
26639
  } catch {
27029
26640
  return true;
27030
26641
  }
@@ -27061,7 +26672,7 @@ function detectPkgManager() {
27061
26672
  return null;
27062
26673
  }
27063
26674
  function getVenvDir() {
27064
- return join35(homedir10(), ".open-agents", "venv");
26675
+ return join37(homedir10(), ".open-agents", "venv");
27065
26676
  }
27066
26677
  function hasVenvModule() {
27067
26678
  try {
@@ -27073,8 +26684,8 @@ function hasVenvModule() {
27073
26684
  }
27074
26685
  function ensureVenv(log) {
27075
26686
  const venvDir = getVenvDir();
27076
- const venvPip = join35(venvDir, "bin", "pip");
27077
- if (existsSync25(venvPip))
26687
+ const venvPip = join37(venvDir, "bin", "pip");
26688
+ if (existsSync27(venvPip))
27078
26689
  return venvDir;
27079
26690
  log("Creating Python venv for vision deps...");
27080
26691
  if (!hasCmd("python3")) {
@@ -27086,9 +26697,9 @@ function ensureVenv(log) {
27086
26697
  return null;
27087
26698
  }
27088
26699
  try {
27089
- mkdirSync9(join35(homedir10(), ".open-agents"), { recursive: true });
26700
+ mkdirSync9(join37(homedir10(), ".open-agents"), { recursive: true });
27090
26701
  execSync24(`python3 -m venv "${venvDir}"`, { stdio: "pipe", timeout: 3e4 });
27091
- execSync24(`"${join35(venvDir, "bin", "pip")}" install --upgrade pip`, {
26702
+ execSync24(`"${join37(venvDir, "bin", "pip")}" install --upgrade pip`, {
27092
26703
  stdio: "pipe",
27093
26704
  timeout: 6e4
27094
26705
  });
@@ -27297,15 +26908,15 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
27297
26908
  }
27298
26909
  }
27299
26910
  const venvDir = getVenvDir();
27300
- const venvBin = join35(venvDir, "bin");
27301
- const venvMoondream = join35(venvBin, "moondream-station");
26911
+ const venvBin = join37(venvDir, "bin");
26912
+ const venvMoondream = join37(venvBin, "moondream-station");
27302
26913
  const venv = ensureVenv(log);
27303
- if (venv && !hasCmd("moondream-station") && !existsSync25(venvMoondream)) {
27304
- const venvPip = join35(venvBin, "pip");
26914
+ if (venv && !hasCmd("moondream-station") && !existsSync27(venvMoondream)) {
26915
+ const venvPip = join37(venvBin, "pip");
27305
26916
  log("Installing moondream-station in ~/.open-agents/venv...");
27306
26917
  try {
27307
26918
  execSync24(`"${venvPip}" install moondream-station`, { stdio: "pipe", timeout: 3e5 });
27308
- if (existsSync25(venvMoondream)) {
26919
+ if (existsSync27(venvMoondream)) {
27309
26920
  log("moondream-station installed successfully.");
27310
26921
  } else {
27311
26922
  try {
@@ -27322,8 +26933,8 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
27322
26933
  }
27323
26934
  }
27324
26935
  if (venv) {
27325
- const venvPython = join35(venvBin, "python");
27326
- const venvPip2 = join35(venvBin, "pip");
26936
+ const venvPython = join37(venvBin, "python");
26937
+ const venvPip2 = join37(venvBin, "pip");
27327
26938
  let ocrStackInstalled = false;
27328
26939
  try {
27329
26940
  execSync24(`"${venvPython}" -c "import cv2, pytesseract, numpy, PIL"`, { stdio: "pipe", timeout: 1e4 });
@@ -27436,9 +27047,9 @@ function createExpandedVariant(baseModel, specs, sizeGB) {
27436
27047
  `PARAMETER num_predict ${numPredict}`,
27437
27048
  `PARAMETER stop "<|endoftext|>"`
27438
27049
  ].join("\n");
27439
- const modelDir2 = join35(homedir10(), ".open-agents", "models");
27050
+ const modelDir2 = join37(homedir10(), ".open-agents", "models");
27440
27051
  mkdirSync9(modelDir2, { recursive: true });
27441
- const modelfilePath = join35(modelDir2, `Modelfile.${customName}`);
27052
+ const modelfilePath = join37(modelDir2, `Modelfile.${customName}`);
27442
27053
  writeFileSync9(modelfilePath, modelfileContent + "\n", "utf8");
27443
27054
  execSync24(`ollama create ${customName} -f ${modelfilePath}`, {
27444
27055
  stdio: "pipe",
@@ -28730,18 +28341,18 @@ async function handleUpdate(subcommand, ctx) {
28730
28341
  let currentVersion = "0.0.0";
28731
28342
  try {
28732
28343
  const { createRequire: createRequire4 } = await import("node:module");
28733
- const { fileURLToPath: fileURLToPath11 } = await import("node:url");
28734
- const { dirname: dirname15, join: join49 } = await import("node:path");
28735
- const { existsSync: existsSync35 } = await import("node:fs");
28344
+ const { fileURLToPath: fileURLToPath14 } = await import("node:url");
28345
+ const { dirname: dirname18, join: join52 } = await import("node:path");
28346
+ const { existsSync: existsSync38 } = await import("node:fs");
28736
28347
  const req = createRequire4(import.meta.url);
28737
- const thisDir = dirname15(fileURLToPath11(import.meta.url));
28348
+ const thisDir = dirname18(fileURLToPath14(import.meta.url));
28738
28349
  const candidates = [
28739
- join49(thisDir, "..", "package.json"),
28740
- join49(thisDir, "..", "..", "package.json"),
28741
- join49(thisDir, "..", "..", "..", "package.json")
28350
+ join52(thisDir, "..", "package.json"),
28351
+ join52(thisDir, "..", "..", "package.json"),
28352
+ join52(thisDir, "..", "..", "..", "package.json")
28742
28353
  ];
28743
28354
  for (const pkgPath of candidates) {
28744
- if (existsSync35(pkgPath)) {
28355
+ if (existsSync38(pkgPath)) {
28745
28356
  const pkg = req(pkgPath);
28746
28357
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
28747
28358
  currentVersion = pkg.version ?? "0.0.0";
@@ -28964,8 +28575,8 @@ var init_commands = __esm({
28964
28575
  });
28965
28576
 
28966
28577
  // packages/cli/dist/tui/project-context.js
28967
- import { existsSync as existsSync26, readFileSync as readFileSync17, readdirSync as readdirSync8 } from "node:fs";
28968
- import { join as join36, basename as basename10 } from "node:path";
28578
+ import { existsSync as existsSync28, readFileSync as readFileSync19, readdirSync as readdirSync8 } from "node:fs";
28579
+ import { join as join38, basename as basename10 } from "node:path";
28969
28580
  import { execSync as execSync25 } from "node:child_process";
28970
28581
  import { homedir as homedir11, platform as platform2, release } from "node:os";
28971
28582
  function getModelTier(modelName) {
@@ -29000,10 +28611,10 @@ function loadProjectMap(repoRoot) {
29000
28611
  if (!hasOaDirectory(repoRoot)) {
29001
28612
  initOaDirectory(repoRoot);
29002
28613
  }
29003
- const mapPath = join36(repoRoot, OA_DIR, "context", "project-map.md");
29004
- if (existsSync26(mapPath)) {
28614
+ const mapPath = join38(repoRoot, OA_DIR, "context", "project-map.md");
28615
+ if (existsSync28(mapPath)) {
29005
28616
  try {
29006
- const content = readFileSync17(mapPath, "utf-8");
28617
+ const content = readFileSync19(mapPath, "utf-8");
29007
28618
  return content;
29008
28619
  } catch {
29009
28620
  }
@@ -29044,31 +28655,31 @@ ${log}`);
29044
28655
  }
29045
28656
  function loadMemoryContext(repoRoot) {
29046
28657
  const sections = [];
29047
- const oaMemDir = join36(repoRoot, OA_DIR, "memory");
28658
+ const oaMemDir = join38(repoRoot, OA_DIR, "memory");
29048
28659
  const oaEntries = loadMemoryDir(oaMemDir, "project");
29049
28660
  if (oaEntries)
29050
28661
  sections.push(oaEntries);
29051
- const legacyMemDir = join36(repoRoot, ".open-agents", "memory");
29052
- if (legacyMemDir !== oaMemDir && existsSync26(legacyMemDir)) {
28662
+ const legacyMemDir = join38(repoRoot, ".open-agents", "memory");
28663
+ if (legacyMemDir !== oaMemDir && existsSync28(legacyMemDir)) {
29053
28664
  const legacyEntries = loadMemoryDir(legacyMemDir, "project/legacy");
29054
28665
  if (legacyEntries)
29055
28666
  sections.push(legacyEntries);
29056
28667
  }
29057
- const globalMemDir = join36(homedir11(), ".open-agents", "memory");
28668
+ const globalMemDir = join38(homedir11(), ".open-agents", "memory");
29058
28669
  const globalEntries = loadMemoryDir(globalMemDir, "global");
29059
28670
  if (globalEntries)
29060
28671
  sections.push(globalEntries);
29061
28672
  return sections.join("\n\n");
29062
28673
  }
29063
28674
  function loadMemoryDir(memDir, scope) {
29064
- if (!existsSync26(memDir))
28675
+ if (!existsSync28(memDir))
29065
28676
  return "";
29066
28677
  const lines = [];
29067
28678
  try {
29068
28679
  const files = readdirSync8(memDir).filter((f) => f.endsWith(".json"));
29069
28680
  for (const file of files.slice(0, 10)) {
29070
28681
  try {
29071
- const raw = readFileSync17(join36(memDir, file), "utf-8");
28682
+ const raw = readFileSync19(join38(memDir, file), "utf-8");
29072
28683
  const entries = JSON.parse(raw);
29073
28684
  const topic = basename10(file, ".json");
29074
28685
  const keys = Object.keys(entries);
@@ -30095,22 +29706,22 @@ var init_carousel = __esm({
30095
29706
  });
30096
29707
 
30097
29708
  // packages/cli/dist/tui/carousel-descriptors.js
30098
- import { existsSync as existsSync27, readFileSync as readFileSync18, writeFileSync as writeFileSync10, mkdirSync as mkdirSync10, readdirSync as readdirSync9 } from "node:fs";
30099
- import { join as join37, basename as basename11 } from "node:path";
29709
+ import { existsSync as existsSync29, readFileSync as readFileSync20, writeFileSync as writeFileSync10, mkdirSync as mkdirSync10, readdirSync as readdirSync9 } from "node:fs";
29710
+ import { join as join39, basename as basename11 } from "node:path";
30100
29711
  function loadToolProfile(repoRoot) {
30101
- const filePath = join37(repoRoot, OA_DIR, "context", TOOL_PROFILE_FILE);
29712
+ const filePath = join39(repoRoot, OA_DIR, "context", TOOL_PROFILE_FILE);
30102
29713
  try {
30103
- if (!existsSync27(filePath))
29714
+ if (!existsSync29(filePath))
30104
29715
  return null;
30105
- return JSON.parse(readFileSync18(filePath, "utf-8"));
29716
+ return JSON.parse(readFileSync20(filePath, "utf-8"));
30106
29717
  } catch {
30107
29718
  return null;
30108
29719
  }
30109
29720
  }
30110
29721
  function saveToolProfile(repoRoot, profile) {
30111
- const contextDir = join37(repoRoot, OA_DIR, "context");
29722
+ const contextDir = join39(repoRoot, OA_DIR, "context");
30112
29723
  mkdirSync10(contextDir, { recursive: true });
30113
- writeFileSync10(join37(contextDir, TOOL_PROFILE_FILE), JSON.stringify(profile, null, 2), "utf-8");
29724
+ writeFileSync10(join39(contextDir, TOOL_PROFILE_FILE), JSON.stringify(profile, null, 2), "utf-8");
30114
29725
  }
30115
29726
  function categorizeToolCall(toolName) {
30116
29727
  for (const cat of TOOL_CATEGORIES) {
@@ -30168,25 +29779,25 @@ function weightedColor(profile) {
30168
29779
  return selectedCat.colors[Math.floor(Math.random() * selectedCat.colors.length)];
30169
29780
  }
30170
29781
  function loadCachedDescriptors(repoRoot) {
30171
- const filePath = join37(repoRoot, OA_DIR, "context", DESCRIPTOR_FILE);
29782
+ const filePath = join39(repoRoot, OA_DIR, "context", DESCRIPTOR_FILE);
30172
29783
  try {
30173
- if (!existsSync27(filePath))
29784
+ if (!existsSync29(filePath))
30174
29785
  return null;
30175
- const cached = JSON.parse(readFileSync18(filePath, "utf-8"));
29786
+ const cached = JSON.parse(readFileSync20(filePath, "utf-8"));
30176
29787
  return cached.phrases.length > 0 ? cached.phrases : null;
30177
29788
  } catch {
30178
29789
  return null;
30179
29790
  }
30180
29791
  }
30181
29792
  function saveCachedDescriptors(repoRoot, phrases, sourceHash) {
30182
- const contextDir = join37(repoRoot, OA_DIR, "context");
29793
+ const contextDir = join39(repoRoot, OA_DIR, "context");
30183
29794
  mkdirSync10(contextDir, { recursive: true });
30184
29795
  const cached = {
30185
29796
  phrases,
30186
29797
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
30187
29798
  sourceHash
30188
29799
  };
30189
- writeFileSync10(join37(contextDir, DESCRIPTOR_FILE), JSON.stringify(cached, null, 2), "utf-8");
29800
+ writeFileSync10(join39(contextDir, DESCRIPTOR_FILE), JSON.stringify(cached, null, 2), "utf-8");
30190
29801
  }
30191
29802
  function generateDescriptors(repoRoot) {
30192
29803
  const profile = loadToolProfile(repoRoot);
@@ -30234,11 +29845,11 @@ function generateDescriptors(repoRoot) {
30234
29845
  return phrases;
30235
29846
  }
30236
29847
  function extractFromPackageJson(repoRoot, tags) {
30237
- const pkgPath = join37(repoRoot, "package.json");
29848
+ const pkgPath = join39(repoRoot, "package.json");
30238
29849
  try {
30239
- if (!existsSync27(pkgPath))
29850
+ if (!existsSync29(pkgPath))
30240
29851
  return;
30241
- const pkg = JSON.parse(readFileSync18(pkgPath, "utf-8"));
29852
+ const pkg = JSON.parse(readFileSync20(pkgPath, "utf-8"));
30242
29853
  if (pkg.name && typeof pkg.name === "string") {
30243
29854
  const parts = pkg.name.replace(/^@/, "").split("/");
30244
29855
  for (const p of parts)
@@ -30282,7 +29893,7 @@ function extractFromManifests(repoRoot, tags) {
30282
29893
  { file: ".github/workflows", tag: "ci/cd" }
30283
29894
  ];
30284
29895
  for (const check of manifestChecks) {
30285
- if (existsSync27(join37(repoRoot, check.file))) {
29896
+ if (existsSync29(join39(repoRoot, check.file))) {
30286
29897
  tags.push(check.tag);
30287
29898
  }
30288
29899
  }
@@ -30304,16 +29915,16 @@ function extractFromSessions(repoRoot, tags) {
30304
29915
  }
30305
29916
  }
30306
29917
  function extractFromMemory(repoRoot, tags) {
30307
- const memoryDir = join37(repoRoot, OA_DIR, "memory");
29918
+ const memoryDir = join39(repoRoot, OA_DIR, "memory");
30308
29919
  try {
30309
- if (!existsSync27(memoryDir))
29920
+ if (!existsSync29(memoryDir))
30310
29921
  return;
30311
29922
  const files = readdirSync9(memoryDir).filter((f) => f.endsWith(".json"));
30312
29923
  for (const file of files) {
30313
29924
  const topic = file.replace(/\.json$/, "").replace(/[-_]/g, " ");
30314
29925
  tags.push(topic);
30315
29926
  try {
30316
- const data = JSON.parse(readFileSync18(join37(memoryDir, file), "utf-8"));
29927
+ const data = JSON.parse(readFileSync20(join39(memoryDir, file), "utf-8"));
30317
29928
  if (data && typeof data === "object") {
30318
29929
  const keys = Object.keys(data).slice(0, 3);
30319
29930
  for (const key of keys) {
@@ -30448,25 +30059,25 @@ var init_carousel_descriptors = __esm({
30448
30059
  });
30449
30060
 
30450
30061
  // packages/cli/dist/tui/voice.js
30451
- import { existsSync as existsSync28, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11, readFileSync as readFileSync19, unlinkSync as unlinkSync4 } from "node:fs";
30452
- import { join as join38 } from "node:path";
30062
+ import { existsSync as existsSync30, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11, readFileSync as readFileSync21, unlinkSync as unlinkSync4 } from "node:fs";
30063
+ import { join as join40 } from "node:path";
30453
30064
  import { homedir as homedir12, tmpdir as tmpdir6, platform as platform3 } from "node:os";
30454
30065
  import { execSync as execSync26, spawn as nodeSpawn } from "node:child_process";
30455
30066
  import { createRequire } from "node:module";
30456
30067
  function voiceDir() {
30457
- return join38(homedir12(), ".open-agents", "voice");
30068
+ return join40(homedir12(), ".open-agents", "voice");
30458
30069
  }
30459
30070
  function modelsDir() {
30460
- return join38(voiceDir(), "models");
30071
+ return join40(voiceDir(), "models");
30461
30072
  }
30462
30073
  function modelDir(id) {
30463
- return join38(modelsDir(), id);
30074
+ return join40(modelsDir(), id);
30464
30075
  }
30465
30076
  function modelOnnxPath(id) {
30466
- return join38(modelDir(id), "model.onnx");
30077
+ return join40(modelDir(id), "model.onnx");
30467
30078
  }
30468
30079
  function modelConfigPath(id) {
30469
- return join38(modelDir(id), "config.json");
30080
+ return join40(modelDir(id), "config.json");
30470
30081
  }
30471
30082
  function resetNarrationContext() {
30472
30083
  narration.toolCount = 0;
@@ -31144,7 +30755,7 @@ var init_voice = __esm({
31144
30755
  }
31145
30756
  this.onPCMOutput(Buffer.from(int16.buffer), this.config.audio.sample_rate);
31146
30757
  }
31147
- const wavPath = join38(tmpdir6(), `oa-voice-${Date.now()}.wav`);
30758
+ const wavPath = join40(tmpdir6(), `oa-voice-${Date.now()}.wav`);
31148
30759
  this.writeWav(audioData, this.config.audio.sample_rate, wavPath);
31149
30760
  await this.playWav(wavPath);
31150
30761
  try {
@@ -31302,14 +30913,14 @@ var init_voice = __esm({
31302
30913
  return;
31303
30914
  const arch = process.arch;
31304
30915
  mkdirSync11(voiceDir(), { recursive: true });
31305
- const pkgPath = join38(voiceDir(), "package.json");
30916
+ const pkgPath = join40(voiceDir(), "package.json");
31306
30917
  const expectedDeps = {
31307
30918
  "onnxruntime-node": "^1.21.0",
31308
30919
  "phonemizer": "^1.2.1"
31309
30920
  };
31310
- if (existsSync28(pkgPath)) {
30921
+ if (existsSync30(pkgPath)) {
31311
30922
  try {
31312
- const existing = JSON.parse(readFileSync19(pkgPath, "utf8"));
30923
+ const existing = JSON.parse(readFileSync21(pkgPath, "utf8"));
31313
30924
  if (!existing.dependencies?.["phonemizer"]) {
31314
30925
  existing.dependencies = { ...existing.dependencies, ...expectedDeps };
31315
30926
  writeFileSync11(pkgPath, JSON.stringify(existing, null, 2));
@@ -31317,14 +30928,38 @@ var init_voice = __esm({
31317
30928
  } catch {
31318
30929
  }
31319
30930
  }
31320
- if (!existsSync28(pkgPath)) {
30931
+ if (!existsSync30(pkgPath)) {
31321
30932
  writeFileSync11(pkgPath, JSON.stringify({
31322
30933
  name: "open-agents-voice",
31323
30934
  private: true,
31324
30935
  dependencies: expectedDeps
31325
30936
  }, null, 2));
31326
30937
  }
31327
- const voiceRequire = createRequire(join38(voiceDir(), "index.js"));
30938
+ const voiceRequire = createRequire(join40(voiceDir(), "index.js"));
30939
+ const probeOnnx = () => {
30940
+ try {
30941
+ const result = execSync26(`node -e "try { require('onnxruntime-node'); console.log('OK'); } catch(e) { console.log('FAIL:' + e.message); }"`, { cwd: voiceDir(), stdio: "pipe", timeout: 15e3, env: { ...process.env, NODE_PATH: join40(voiceDir(), "node_modules") } });
30942
+ const output = result.toString().trim();
30943
+ if (output === "OK")
30944
+ return true;
30945
+ if (output.startsWith("FAIL:")) {
30946
+ renderWarning(`ONNX runtime probe failed: ${output.slice(5)}`);
30947
+ return false;
30948
+ }
30949
+ return false;
30950
+ } catch (err) {
30951
+ const msg = err instanceof Error ? err.message : String(err);
30952
+ if (msg.includes("CPUID") || msg.includes("unknown cpu") || msg.includes("signal")) {
30953
+ renderWarning(`ONNX runtime is not compatible with this CPU (${process.platform}-${arch}).`);
30954
+ }
30955
+ return false;
30956
+ }
30957
+ };
30958
+ const onnxNodeModules = join40(voiceDir(), "node_modules", "onnxruntime-node");
30959
+ const onnxInstalled = existsSync30(onnxNodeModules);
30960
+ if (onnxInstalled && !probeOnnx()) {
30961
+ throw new Error(`Voice synthesis unavailable: ONNX runtime crashes on this CPU (${process.platform}-${arch}). This is a known issue with some ARM SoCs where the CPU vendor is not recognized. Voice feedback will be disabled but all other features work normally.`);
30962
+ }
31328
30963
  try {
31329
30964
  this.ort = voiceRequire("onnxruntime-node");
31330
30965
  } catch {
@@ -31335,12 +30970,19 @@ var init_voice = __esm({
31335
30970
  stdio: "pipe",
31336
30971
  timeout: 12e4
31337
30972
  });
31338
- this.ort = voiceRequire("onnxruntime-node");
31339
30973
  } catch (err) {
31340
30974
  const archHint = arch !== "x64" ? ` onnxruntime-node may not have prebuilt binaries for ${process.platform}-${arch}.` : "";
31341
30975
  throw new Error(`Failed to install voice dependencies.${archHint} Try manually: cd ${voiceDir()} && npm install
31342
30976
  Error: ${err instanceof Error ? err.message : String(err)}`);
31343
30977
  }
30978
+ if (!probeOnnx()) {
30979
+ throw new Error(`Voice synthesis unavailable: ONNX runtime crashes on this CPU (${process.platform}-${arch}). This is a known issue with some ARM SoCs where the CPU vendor is not recognized. Voice feedback will be disabled but all other features work normally.`);
30980
+ }
30981
+ try {
30982
+ this.ort = voiceRequire("onnxruntime-node");
30983
+ } catch (err) {
30984
+ throw new Error(`Failed to load ONNX runtime after install. Error: ${err instanceof Error ? err.message : String(err)}`);
30985
+ }
31344
30986
  }
31345
30987
  try {
31346
30988
  const phonemizerMod = voiceRequire("phonemizer");
@@ -31372,10 +31014,10 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
31372
31014
  const dir = modelDir(id);
31373
31015
  const onnxPath = modelOnnxPath(id);
31374
31016
  const configPath = modelConfigPath(id);
31375
- if (existsSync28(onnxPath) && existsSync28(configPath))
31017
+ if (existsSync30(onnxPath) && existsSync30(configPath))
31376
31018
  return;
31377
31019
  mkdirSync11(dir, { recursive: true });
31378
- if (!existsSync28(configPath)) {
31020
+ if (!existsSync30(configPath)) {
31379
31021
  renderInfo(`Downloading ${model.label} voice config...`);
31380
31022
  const configResp = await fetch(model.configUrl);
31381
31023
  if (!configResp.ok)
@@ -31383,7 +31025,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
31383
31025
  const configText = await configResp.text();
31384
31026
  writeFileSync11(configPath, configText);
31385
31027
  }
31386
- if (!existsSync28(onnxPath)) {
31028
+ if (!existsSync30(onnxPath)) {
31387
31029
  renderInfo(`Downloading ${model.label} voice model (this may take a minute)...`);
31388
31030
  const onnxResp = await fetch(model.onnxUrl);
31389
31031
  if (!onnxResp.ok)
@@ -31419,10 +31061,10 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
31419
31061
  throw new Error("ONNX runtime not loaded");
31420
31062
  const onnxPath = modelOnnxPath(this.modelId);
31421
31063
  const configPath = modelConfigPath(this.modelId);
31422
- if (!existsSync28(onnxPath) || !existsSync28(configPath)) {
31064
+ if (!existsSync30(onnxPath) || !existsSync30(configPath)) {
31423
31065
  throw new Error(`Model files not found for ${this.modelId}`);
31424
31066
  }
31425
- this.config = JSON.parse(readFileSync19(configPath, "utf8"));
31067
+ this.config = JSON.parse(readFileSync21(configPath, "utf8"));
31426
31068
  renderInfo("Loading voice model...");
31427
31069
  this.session = await this.ort.InferenceSession.create(onnxPath, {
31428
31070
  executionProviders: ["cpu"],
@@ -32286,10 +31928,10 @@ var init_stream_renderer = __esm({
32286
31928
 
32287
31929
  // packages/cli/dist/tui/edit-history.js
32288
31930
  import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync12 } from "node:fs";
32289
- import { join as join39 } from "node:path";
31931
+ import { join as join41 } from "node:path";
32290
31932
  function createEditHistoryLogger(repoRoot, sessionId) {
32291
- const historyDir = join39(repoRoot, ".oa", "history");
32292
- const logPath = join39(historyDir, "edits.jsonl");
31933
+ const historyDir = join41(repoRoot, ".oa", "history");
31934
+ const logPath = join41(historyDir, "edits.jsonl");
32293
31935
  try {
32294
31936
  mkdirSync12(historyDir, { recursive: true });
32295
31937
  } catch {
@@ -32399,16 +32041,47 @@ var init_edit_history = __esm({
32399
32041
  }
32400
32042
  });
32401
32043
 
32044
+ // packages/cli/dist/tui/promptLoader.js
32045
+ import { readFileSync as readFileSync22, existsSync as existsSync31 } from "node:fs";
32046
+ import { join as join42, dirname as dirname15 } from "node:path";
32047
+ import { fileURLToPath as fileURLToPath11 } from "node:url";
32048
+ function loadPrompt3(promptPath, vars) {
32049
+ let content = cache3.get(promptPath);
32050
+ if (content === void 0) {
32051
+ const fullPath = join42(PROMPTS_DIR3, promptPath);
32052
+ if (!existsSync31(fullPath)) {
32053
+ throw new Error(`Prompt file not found: ${fullPath}`);
32054
+ }
32055
+ content = readFileSync22(fullPath, "utf-8");
32056
+ cache3.set(promptPath, content);
32057
+ }
32058
+ if (!vars)
32059
+ return content;
32060
+ return content.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] ?? `{{${key}}}`);
32061
+ }
32062
+ var __filename3, __dirname5, devPath2, publishedPath2, PROMPTS_DIR3, cache3;
32063
+ var init_promptLoader3 = __esm({
32064
+ "packages/cli/dist/tui/promptLoader.js"() {
32065
+ "use strict";
32066
+ __filename3 = fileURLToPath11(import.meta.url);
32067
+ __dirname5 = dirname15(__filename3);
32068
+ devPath2 = join42(__dirname5, "..", "..", "prompts");
32069
+ publishedPath2 = join42(__dirname5, "..", "prompts");
32070
+ PROMPTS_DIR3 = existsSync31(devPath2) ? devPath2 : publishedPath2;
32071
+ cache3 = /* @__PURE__ */ new Map();
32072
+ }
32073
+ });
32074
+
32402
32075
  // packages/cli/dist/tui/dream-engine.js
32403
- import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync12, readFileSync as readFileSync20, existsSync as existsSync29, cpSync, rmSync, readdirSync as readdirSync10 } from "node:fs";
32404
- import { join as join40, basename as basename12 } from "node:path";
32076
+ import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync12, readFileSync as readFileSync23, existsSync as existsSync32, cpSync, rmSync, readdirSync as readdirSync10 } from "node:fs";
32077
+ import { join as join43, basename as basename12 } from "node:path";
32405
32078
  import { execSync as execSync27 } from "node:child_process";
32406
32079
  function loadAutoresearchMemory(repoRoot) {
32407
- const memoryPath = join40(repoRoot, ".oa", "memory", "autoresearch.json");
32408
- if (!existsSync29(memoryPath))
32080
+ const memoryPath = join43(repoRoot, ".oa", "memory", "autoresearch.json");
32081
+ if (!existsSync32(memoryPath))
32409
32082
  return "";
32410
32083
  try {
32411
- const raw = readFileSync20(memoryPath, "utf-8");
32084
+ const raw = readFileSync23(memoryPath, "utf-8");
32412
32085
  const data = JSON.parse(raw);
32413
32086
  const sections = [];
32414
32087
  for (const key of AUTORESEARCH_MEMORY_KEYS) {
@@ -32447,62 +32120,31 @@ function buildDreamPrompt(mode, stage, cycleNum, totalCycles, previousFindings,
32447
32120
  "NREM-3": `DEEP CONSOLIDATION (Stage 3/${SLEEP_STAGES.length}): Synthesize your findings into concrete, actionable proposals. For each proposal, write: (1) problem statement, (2) proposed solution with implementation plan, (3) estimated effort, (4) expected impact. Create clean entrypoint files.`,
32448
32121
  "REM": `CREATIVE EXPANSION (Stage 4/${SLEEP_STAGES.length}): Think boldly and creatively. What novel features could transform this project? Cross-domain inspiration? Unconventional approaches? Generate at least 3 wild ideas alongside 3 practical innovations. Write detailed vision documents.`
32449
32122
  }[stage.name];
32450
- return `${modeDesc}
32451
-
32452
- You are in dream cycle ${cycleNum}/${totalCycles}, stage: ${stage.name} \u2014 ${stage.label}
32453
- ${stage.description}
32454
-
32455
- ${stageInstruction}
32456
-
32457
- ${previousFindings ? `PREVIOUS FINDINGS FROM EARLIER STAGES:
32123
+ return loadPrompt3("tui/dream-stages.md", {
32124
+ modeDesc,
32125
+ cycleNum: String(cycleNum),
32126
+ totalCycles: String(totalCycles),
32127
+ stageName: stage.name,
32128
+ stageLabel: stage.label,
32129
+ stageDescription: stage.description,
32130
+ stageInstruction: stageInstruction || "",
32131
+ stageNameLower: stage.name.toLowerCase(),
32132
+ previousFindings: previousFindings ? `PREVIOUS FINDINGS FROM EARLIER STAGES:
32458
32133
  ${previousFindings}
32459
- ` : ""}
32460
-
32461
- RULES:
32462
- - Read any file in the workspace freely for analysis
32463
- - ALL written output goes to .oa/dreams/ using file_write (path relative to .oa/dreams/)
32464
- - Use codebase_map, file_read, grep_search, find_files, list_directory to explore
32465
- - Create well-structured markdown proposals with clear sections
32466
- - Name files descriptively: cycle-${cycleNum}-${stage.name.toLowerCase()}-{topic}.md
32467
- - For proposals, include a PROPOSAL-INDEX.md that catalogs all proposals with status and priority
32468
- - Include implementation entrypoints: specific file paths, function signatures, step-by-step plans
32469
-
32470
- When done with this stage, call task_complete with a summary of findings.`;
32134
+ ` : ""
32135
+ });
32471
32136
  }
32472
32137
  function buildLucidImplementPrompt(proposal, cycleNum) {
32473
- return `LUCID DREAM \u2014 IMPLEMENTATION PHASE (Cycle ${cycleNum})
32474
-
32475
- You are now implementing a dream proposal. You have full write access to the workspace.
32476
-
32477
- PROPOSAL TO IMPLEMENT:
32478
- ${proposal}
32479
-
32480
- INSTRUCTIONS:
32481
- 1. Implement the proposal carefully, following the plan
32482
- 2. Run tests after implementation to verify nothing breaks
32483
- 3. If tests fail, fix the issues
32484
- 4. Write a brief evaluation of the implementation to .oa/dreams/cycle-${cycleNum}-implementation-report.md
32485
-
32486
- After implementation and testing, call task_complete with a summary of what was implemented and test results.`;
32138
+ return loadPrompt3("tui/dream-lucid-implement.md", {
32139
+ cycleNum: String(cycleNum),
32140
+ proposal
32141
+ });
32487
32142
  }
32488
32143
  function buildLucidEvalPrompt(implementationSummary, cycleNum) {
32489
- return `LUCID DREAM \u2014 EVALUATION & SELF-PLAY PHASE (Cycle ${cycleNum})
32490
-
32491
- You implemented changes in the previous phase. Now evaluate them.
32492
-
32493
- IMPLEMENTATION SUMMARY:
32494
- ${implementationSummary}
32495
-
32496
- EVALUATION TASKS:
32497
- 1. Review the changes you made \u2014 are they clean, well-structured, properly tested?
32498
- 2. Self-play: Try to use the features as an end-user would. Test edge cases.
32499
- 3. Rate the implementation: usefulness (1-10), code quality (1-10), test coverage (1-10)
32500
- 4. Identify any issues, regressions, or improvements needed
32501
- 5. Write evaluation report to .oa/dreams/cycle-${cycleNum}-evaluation.md
32502
-
32503
- SELF-PLAY: Actually exercise the code paths \u2014 run commands, read outputs, verify behavior.
32504
-
32505
- After evaluation, call task_complete with your ratings and findings.`;
32144
+ return loadPrompt3("tui/dream-lucid-eval.md", {
32145
+ cycleNum: String(cycleNum),
32146
+ implementationSummary
32147
+ });
32506
32148
  }
32507
32149
  function renderDreamCycleHeader(cycle, total, mode) {
32508
32150
  const modeLabel = mode === "lucid" ? "LUCID" : mode === "deep" ? "DEEP" : "DREAM";
@@ -32600,6 +32242,7 @@ var init_dream_engine = __esm({
32600
32242
  init_project_context();
32601
32243
  init_setup();
32602
32244
  init_render();
32245
+ init_promptLoader3();
32603
32246
  SWARM_ROLE_CONFIG = {
32604
32247
  researcher: { maxTurns: 25, temperature: 0.4 },
32605
32248
  monitor: { maxTurns: 5, temperature: 0.1 },
@@ -32628,12 +32271,12 @@ var init_dream_engine = __esm({
32628
32271
  const content = String(args["content"] ?? "");
32629
32272
  if (!rawPath)
32630
32273
  return { success: false, output: "", error: "path is required", durationMs: Date.now() - start };
32631
- const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/autoresearch") ? join40(this.autoresearchDir, basename12(rawPath)) : join40(this.autoresearchDir, rawPath);
32274
+ const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/autoresearch") ? join43(this.autoresearchDir, basename12(rawPath)) : join43(this.autoresearchDir, rawPath);
32632
32275
  if (!targetPath.startsWith(this.autoresearchDir)) {
32633
32276
  return { success: false, output: "", error: "Autoresearch mode: writes are confined to .oa/autoresearch/", durationMs: Date.now() - start };
32634
32277
  }
32635
32278
  try {
32636
- const dir = join40(targetPath, "..");
32279
+ const dir = join43(targetPath, "..");
32637
32280
  mkdirSync13(dir, { recursive: true });
32638
32281
  writeFileSync12(targetPath, content, "utf-8");
32639
32282
  return { success: true, output: `Wrote ${content.length} bytes to ${rawPath}`, durationMs: Date.now() - start };
@@ -32663,15 +32306,15 @@ var init_dream_engine = __esm({
32663
32306
  const rawPath = String(args["path"] ?? "");
32664
32307
  const oldStr = String(args["old_string"] ?? "");
32665
32308
  const newStr = String(args["new_string"] ?? "");
32666
- const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/autoresearch") ? join40(this.autoresearchDir, basename12(rawPath)) : join40(this.autoresearchDir, rawPath);
32309
+ const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/autoresearch") ? join43(this.autoresearchDir, basename12(rawPath)) : join43(this.autoresearchDir, rawPath);
32667
32310
  if (!targetPath.startsWith(this.autoresearchDir)) {
32668
32311
  return { success: false, output: "", error: "Autoresearch mode: edits are confined to .oa/autoresearch/", durationMs: Date.now() - start };
32669
32312
  }
32670
32313
  try {
32671
- if (!existsSync29(targetPath)) {
32314
+ if (!existsSync32(targetPath)) {
32672
32315
  return { success: false, output: "", error: `File not found: ${rawPath}`, durationMs: Date.now() - start };
32673
32316
  }
32674
- let content = readFileSync20(targetPath, "utf-8");
32317
+ let content = readFileSync23(targetPath, "utf-8");
32675
32318
  if (!content.includes(oldStr)) {
32676
32319
  return { success: false, output: "", error: "old_string not found in file", durationMs: Date.now() - start };
32677
32320
  }
@@ -32717,12 +32360,12 @@ var init_dream_engine = __esm({
32717
32360
  const content = String(args["content"] ?? "");
32718
32361
  if (!rawPath)
32719
32362
  return { success: false, output: "", error: "path is required", durationMs: Date.now() - start };
32720
- const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join40(this.dreamsDir, basename12(rawPath)) : join40(this.dreamsDir, rawPath);
32363
+ const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join43(this.dreamsDir, basename12(rawPath)) : join43(this.dreamsDir, rawPath);
32721
32364
  if (!targetPath.startsWith(this.dreamsDir)) {
32722
32365
  return { success: false, output: "", error: "Dream mode: writes are confined to .oa/dreams/", durationMs: Date.now() - start };
32723
32366
  }
32724
32367
  try {
32725
- const dir = join40(targetPath, "..");
32368
+ const dir = join43(targetPath, "..");
32726
32369
  mkdirSync13(dir, { recursive: true });
32727
32370
  writeFileSync12(targetPath, content, "utf-8");
32728
32371
  return { success: true, output: `Wrote ${content.length} bytes to ${rawPath}`, durationMs: Date.now() - start };
@@ -32752,15 +32395,15 @@ var init_dream_engine = __esm({
32752
32395
  const rawPath = String(args["path"] ?? "");
32753
32396
  const oldStr = String(args["old_string"] ?? "");
32754
32397
  const newStr = String(args["new_string"] ?? "");
32755
- const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join40(this.dreamsDir, basename12(rawPath)) : join40(this.dreamsDir, rawPath);
32398
+ const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join43(this.dreamsDir, basename12(rawPath)) : join43(this.dreamsDir, rawPath);
32756
32399
  if (!targetPath.startsWith(this.dreamsDir)) {
32757
32400
  return { success: false, output: "", error: "Dream mode: edits are confined to .oa/dreams/", durationMs: Date.now() - start };
32758
32401
  }
32759
32402
  try {
32760
- if (!existsSync29(targetPath)) {
32403
+ if (!existsSync32(targetPath)) {
32761
32404
  return { success: false, output: "", error: `File not found: ${rawPath}`, durationMs: Date.now() - start };
32762
32405
  }
32763
- let content = readFileSync20(targetPath, "utf-8");
32406
+ let content = readFileSync23(targetPath, "utf-8");
32764
32407
  if (!content.includes(oldStr)) {
32765
32408
  return { success: false, output: "", error: "old_string not found in file", durationMs: Date.now() - start };
32766
32409
  }
@@ -32819,7 +32462,7 @@ var init_dream_engine = __esm({
32819
32462
  constructor(config, repoRoot) {
32820
32463
  this.config = config;
32821
32464
  this.repoRoot = repoRoot;
32822
- this.dreamsDir = join40(repoRoot, ".oa", "dreams");
32465
+ this.dreamsDir = join43(repoRoot, ".oa", "dreams");
32823
32466
  this.state = {
32824
32467
  mode: "default",
32825
32468
  active: false,
@@ -32903,7 +32546,7 @@ ${result.summary}`;
32903
32546
  if (mode !== "default" || cycle === totalCycles) {
32904
32547
  renderDreamContraction(cycle);
32905
32548
  const cycleSummary = this.buildCycleSummary(cycle, previousFindings);
32906
- const summaryPath = join40(this.dreamsDir, `cycle-${cycle}-summary.md`);
32549
+ const summaryPath = join43(this.dreamsDir, `cycle-${cycle}-summary.md`);
32907
32550
  writeFileSync12(summaryPath, cycleSummary, "utf-8");
32908
32551
  }
32909
32552
  if (mode === "lucid" && !this.abortController.signal.aborted) {
@@ -33116,7 +32759,7 @@ After synthesis, call task_complete with the final prioritized summary.`, toolMo
33116
32759
  }
33117
32760
  /** Build role-specific tool sets for swarm agents */
33118
32761
  buildSwarmTools(role, _workspace) {
33119
- const autoresearchDir = join40(this.repoRoot, ".oa", "autoresearch");
32762
+ const autoresearchDir = join43(this.repoRoot, ".oa", "autoresearch");
33120
32763
  const taskComplete = this.createSwarmTaskCompleteTool(role);
33121
32764
  switch (role) {
33122
32765
  case "researcher": {
@@ -33480,7 +33123,7 @@ INSTRUCTIONS:
33480
33123
  2. Summarize the key learnings and next steps
33481
33124
 
33482
33125
  Call task_complete with a human-readable summary of the autoresearch session.`, workspace, onEvent);
33483
- const reportPath = join40(this.dreamsDir, `cycle-${cycleNum}-autoresearch-report.md`);
33126
+ const reportPath = join43(this.dreamsDir, `cycle-${cycleNum}-autoresearch-report.md`);
33484
33127
  const report = `# Autoresearch Swarm Report \u2014 Cycle ${cycleNum}
33485
33128
 
33486
33129
  **Date**: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}
@@ -33569,7 +33212,7 @@ ${summaryResult}
33569
33212
  }
33570
33213
  /** Save workspace backup for lucid mode */
33571
33214
  saveVersionCheckpoint(cycle) {
33572
- const checkpointDir = join40(this.dreamsDir, "checkpoints", `cycle-${cycle}`);
33215
+ const checkpointDir = join43(this.dreamsDir, "checkpoints", `cycle-${cycle}`);
33573
33216
  try {
33574
33217
  mkdirSync13(checkpointDir, { recursive: true });
33575
33218
  try {
@@ -33588,10 +33231,10 @@ ${summaryResult}
33588
33231
  encoding: "utf-8",
33589
33232
  timeout: 5e3
33590
33233
  }).trim();
33591
- writeFileSync12(join40(checkpointDir, "git-status.txt"), gitStatus, "utf-8");
33592
- writeFileSync12(join40(checkpointDir, "git-diff.patch"), gitDiff, "utf-8");
33593
- writeFileSync12(join40(checkpointDir, "git-hash.txt"), gitHash, "utf-8");
33594
- writeFileSync12(join40(checkpointDir, "checkpoint.json"), JSON.stringify({
33234
+ writeFileSync12(join43(checkpointDir, "git-status.txt"), gitStatus, "utf-8");
33235
+ writeFileSync12(join43(checkpointDir, "git-diff.patch"), gitDiff, "utf-8");
33236
+ writeFileSync12(join43(checkpointDir, "git-hash.txt"), gitHash, "utf-8");
33237
+ writeFileSync12(join43(checkpointDir, "checkpoint.json"), JSON.stringify({
33595
33238
  cycle,
33596
33239
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
33597
33240
  gitHash,
@@ -33599,7 +33242,7 @@ ${summaryResult}
33599
33242
  }, null, 2), "utf-8");
33600
33243
  renderInfo(`Checkpoint saved: cycle ${cycle} (${gitHash.slice(0, 8)})`);
33601
33244
  } catch {
33602
- writeFileSync12(join40(checkpointDir, "checkpoint.json"), JSON.stringify({ cycle, timestamp: (/* @__PURE__ */ new Date()).toISOString(), mode: this.state.mode }, null, 2), "utf-8");
33245
+ writeFileSync12(join43(checkpointDir, "checkpoint.json"), JSON.stringify({ cycle, timestamp: (/* @__PURE__ */ new Date()).toISOString(), mode: this.state.mode }, null, 2), "utf-8");
33603
33246
  renderInfo(`Checkpoint saved: cycle ${cycle} (no git)`);
33604
33247
  }
33605
33248
  } catch (err) {
@@ -33657,14 +33300,14 @@ ${files.map((f) => `- [\`${f}\`](./${f})`).join("\n")}
33657
33300
  ---
33658
33301
  *Auto-generated by open-agents dream engine*
33659
33302
  `;
33660
- writeFileSync12(join40(this.dreamsDir, "PROPOSAL-INDEX.md"), index, "utf-8");
33303
+ writeFileSync12(join43(this.dreamsDir, "PROPOSAL-INDEX.md"), index, "utf-8");
33661
33304
  } catch {
33662
33305
  }
33663
33306
  }
33664
33307
  /** Save dream state for resume/inspection */
33665
33308
  saveDreamState() {
33666
33309
  try {
33667
- writeFileSync12(join40(this.dreamsDir, "dream-state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
33310
+ writeFileSync12(join43(this.dreamsDir, "dream-state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
33668
33311
  } catch {
33669
33312
  }
33670
33313
  }
@@ -34038,143 +33681,23 @@ var init_bless_engine = __esm({
34038
33681
  });
34039
33682
 
34040
33683
  // packages/cli/dist/tui/dmn-engine.js
34041
- import { existsSync as existsSync30, readFileSync as readFileSync21, writeFileSync as writeFileSync13, mkdirSync as mkdirSync14, readdirSync as readdirSync11, unlinkSync as unlinkSync5 } from "node:fs";
34042
- import { join as join41, basename as basename13 } from "node:path";
33684
+ import { existsSync as existsSync33, readFileSync as readFileSync24, writeFileSync as writeFileSync13, mkdirSync as mkdirSync14, readdirSync as readdirSync11, unlinkSync as unlinkSync5 } from "node:fs";
33685
+ import { join as join44, basename as basename13 } from "node:path";
34043
33686
  function buildDMNGatherPrompt(recentTaskSummaries, dueReminders, attentionItems, memoryTopics, capabilities, competence, reflectionBuffer) {
34044
33687
  const competenceReport = competence.length > 0 ? competence.map((c3) => {
34045
33688
  const rate = c3.attempts > 0 ? Math.round(c3.successes / c3.attempts * 100) : 0;
34046
33689
  return ` - ${c3.taskType}: ${c3.attempts} attempts, ${rate}% success`;
34047
33690
  }).join("\n") : " (no data yet \u2014 this is a fresh start)";
34048
33691
  const reflectionsText = reflectionBuffer.length > 0 ? reflectionBuffer.map((r, i) => ` ${i + 1}. ${r}`).join("\n") : " (none)";
34049
- return `DEFAULT MODE NETWORK \u2014 SELF-REFLECTION CYCLE
34050
-
34051
- You are the agent's Default Mode Network. You activate between tasks to reflect,
34052
- consolidate, and determine the most valuable next action.
34053
-
34054
- YOUR PURPOSE: Examine all available context \u2014 memories, recent history, directives,
34055
- capabilities, and environmental signals \u2014 then reason about the single most valuable
34056
- task to pursue next. Think like a brain at rest: consolidating, planning, connecting dots.
34057
-
34058
- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
34059
-
34060
- PHASE 1: GATHER CONTEXT
34061
-
34062
- Use memory_search and memory_read to explore ALL stored knowledge. Be thorough.
34063
- Look for:
34064
- - Standing directives ("always do X", "seek Y", "monitor Z")
34065
- - Unfinished goals or partially completed missions
34066
- - Knowledge gaps that could be filled
34067
- - Patterns in recent task history that suggest momentum direction
34068
- - Environmental signals (reminders, attention items)
34069
-
34070
- IMPORTANT: Start by searching memory broadly. Use memory_search with terms like
34071
- "goal", "directive", "plan", "todo", "important" to find standing orders. Then
34072
- read specific topics that seem relevant. The richness of your reasoning depends
34073
- on how well you explore what you already know.
34074
-
34075
- Recent task history (last completed tasks):
34076
- ${recentTaskSummaries.length > 0 ? recentTaskSummaries.map((s, i) => ` ${i + 1}. ${s}`).join("\n") : " (no recent tasks)"}
34077
-
34078
- Recent failures (Reflexion buffer \u2014 learn from these):
34079
- ${reflectionsText}
34080
-
34081
- Competence tracker (attempts and success rate by category):
34082
- ${competenceReport}
34083
-
34084
- Due reminders:
34085
- ${dueReminders.length > 0 ? dueReminders.map((r) => ` - ${r}`).join("\n") : " (none)"}
34086
-
34087
- Active attention items:
34088
- ${attentionItems.length > 0 ? attentionItems.map((a) => ` - ${a}`).join("\n") : " (none)"}
34089
-
34090
- Known memory topics:
34091
- ${memoryTopics.length > 0 ? memoryTopics.map((t) => ` - ${t}`).join("\n") : " (none \u2014 fresh start)"}
34092
-
34093
- Available capabilities:
34094
- ${capabilities.map((c3) => ` - ${c3}`).join("\n")}
34095
-
34096
- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
34097
-
34098
- PHASE 2: REFLECT, CONSOLIDATE & REASON (Generative Agents + Reflexion)
34099
-
34100
- After gathering context, consolidate and reason:
34101
-
34102
- Memory consolidation:
34103
- - Are there overlapping or redundant memories that should be merged?
34104
- - Are there new insights from recent tasks worth writing to memory?
34105
- - Write any new insights to memory NOW using memory_write.
34106
-
34107
- Self-evaluation (answer these questions in your reasoning):
34108
- 1. What directives or goals have been set that still need work?
34109
- 2. What was the momentum of recent tasks \u2014 what logically comes next?
34110
- 3. Are there capabilities I haven't exercised that could be valuable?
34111
- 4. What knowledge gaps exist that exploration could fill?
34112
- 5. Are there environmental signals (reminders, attention items) to address?
34113
- 6. What can I learn from recent failures? (Check the Reflexion buffer above)
34114
- 7. Where is my learning progress fastest? (Check competence tracker \u2014 pursue
34115
- categories where success rate is RISING, avoid categories where it's flat)
34116
-
34117
- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
34118
-
34119
- PHASE 3: GENERATE CANDIDATES (Voyager-style curriculum)
34120
-
34121
- Propose 2-4 candidate next tasks. Use the "Goldilocks" principle from Voyager:
34122
- propose tasks at the FRONTIER of current capabilities \u2014 neither too easy
34123
- (already mastered) nor too hard (no chance of success). Check the competence
34124
- tracker to calibrate difficulty.
34125
-
34126
- For each candidate, specify:
34127
- - The task description (specific, actionable, measurable)
34128
- - Rationale (why this task, what led you to it)
34129
- - Provenance (which memories, directives, or signals informed this)
34130
- - Category: directive | exploration | capability | maintenance | social
34131
- - Confidence (0-1, calibrated against competence data)
34132
-
34133
- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
34134
-
34135
- PHASE 4: ADVERSARIAL CHALLENGE (Self-Rewarding + Constitutional AI)
34136
-
34137
- For each candidate, run a rigorous adversarial review:
34138
- - Is this actually useful or just busywork?
34139
- - Does it align with stored directives and goals?
34140
- - Is it achievable with available tools and current competence?
34141
- - Could it cause harm or waste resources?
34142
- - Is there a higher-priority alternative?
34143
- - Would this task help or hinder the agent's long-term growth?
34144
- - Challenge your own confidence rating \u2014 are you overconfident?
34145
-
34146
- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
34147
-
34148
- PHASE 5: SELECT & FORMAT
34149
-
34150
- Pick the single highest-value task. If NO task is genuinely worth doing
34151
- (all candidates are low-value or risky), respond with "NO_TASK" \u2014 it's
34152
- better to rest than to waste cycles on meaningless work.
34153
-
34154
- When you have decided, call task_complete with a JSON summary in this format:
34155
- {
34156
- "selectedTask": {
34157
- "task": "the specific task to execute",
34158
- "rationale": "why this is the best next action",
34159
- "provenance": ["memory:topic/key", "reminder:xyz", "attention:abc"],
34160
- "category": "directive",
34161
- "confidence": 0.85,
34162
- "challengeResult": "survived adversarial review because..."
34163
- },
34164
- "reasoning": "full chain of thought that led to this decision",
34165
- "alternativesConsidered": ["task A (rejected because...)", "task B (rejected because...)"]
34166
- }
34167
-
34168
- Or if nothing is worth doing:
34169
- {
34170
- "selectedTask": null,
34171
- "reasoning": "why no task is worth pursuing right now"
34172
- }
34173
-
34174
- REMEMBER: Use memory_read, memory_write, and memory_search EXTENSIVELY.
34175
- Write consolidation insights and new reflections to memory before selecting a task.
34176
- The next DMN cycle (and the main agent) will benefit from anything you store now.
34177
- `;
33692
+ return loadPrompt3("tui/dmn-gather.md", {
33693
+ recentTaskSummaries: recentTaskSummaries.length > 0 ? recentTaskSummaries.map((s, i) => ` ${i + 1}. ${s}`).join("\n") : " (no recent tasks)",
33694
+ reflectionsText,
33695
+ competenceReport,
33696
+ dueReminders: dueReminders.length > 0 ? dueReminders.map((r) => ` - ${r}`).join("\n") : " (none)",
33697
+ attentionItems: attentionItems.length > 0 ? attentionItems.map((a) => ` - ${a}`).join("\n") : " (none)",
33698
+ memoryTopics: memoryTopics.length > 0 ? memoryTopics.map((t) => ` - ${t}`).join("\n") : " (none \u2014 fresh start)",
33699
+ capabilities: capabilities.map((c3) => ` - ${c3}`).join("\n")
33700
+ });
34178
33701
  }
34179
33702
  function adaptTool3(tool) {
34180
33703
  return {
@@ -34251,6 +33774,7 @@ var init_dmn_engine = __esm({
34251
33774
  init_dist2();
34252
33775
  init_project_context();
34253
33776
  init_render();
33777
+ init_promptLoader3();
34254
33778
  DMNEngine = class {
34255
33779
  config;
34256
33780
  repoRoot;
@@ -34271,8 +33795,8 @@ var init_dmn_engine = __esm({
34271
33795
  constructor(config, repoRoot) {
34272
33796
  this.config = config;
34273
33797
  this.repoRoot = repoRoot;
34274
- this.stateDir = join41(repoRoot, ".oa", "dmn");
34275
- this.historyDir = join41(repoRoot, ".oa", "dmn", "cycles");
33798
+ this.stateDir = join44(repoRoot, ".oa", "dmn");
33799
+ this.historyDir = join44(repoRoot, ".oa", "dmn", "cycles");
34276
33800
  mkdirSync14(this.historyDir, { recursive: true });
34277
33801
  this.loadState();
34278
33802
  }
@@ -34862,11 +34386,11 @@ OUTPUT: Call task_complete with JSON:
34862
34386
  async gatherMemoryTopics() {
34863
34387
  const topics = [];
34864
34388
  const dirs = [
34865
- join41(this.repoRoot, ".oa", "memory"),
34866
- join41(this.repoRoot, ".open-agents", "memory")
34389
+ join44(this.repoRoot, ".oa", "memory"),
34390
+ join44(this.repoRoot, ".open-agents", "memory")
34867
34391
  ];
34868
34392
  for (const dir of dirs) {
34869
- if (!existsSync30(dir))
34393
+ if (!existsSync33(dir))
34870
34394
  continue;
34871
34395
  try {
34872
34396
  const files = readdirSync11(dir).filter((f) => f.endsWith(".json"));
@@ -34882,29 +34406,29 @@ OUTPUT: Call task_complete with JSON:
34882
34406
  }
34883
34407
  // ── State persistence ─────────────────────────────────────────────────
34884
34408
  loadState() {
34885
- const path = join41(this.stateDir, "state.json");
34886
- if (existsSync30(path)) {
34409
+ const path = join44(this.stateDir, "state.json");
34410
+ if (existsSync33(path)) {
34887
34411
  try {
34888
- this.state = JSON.parse(readFileSync21(path, "utf-8"));
34412
+ this.state = JSON.parse(readFileSync24(path, "utf-8"));
34889
34413
  } catch {
34890
34414
  }
34891
34415
  }
34892
34416
  }
34893
34417
  saveState() {
34894
34418
  try {
34895
- writeFileSync13(join41(this.stateDir, "state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
34419
+ writeFileSync13(join44(this.stateDir, "state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
34896
34420
  } catch {
34897
34421
  }
34898
34422
  }
34899
34423
  saveCycleResult(result) {
34900
34424
  try {
34901
34425
  const filename = `cycle-${result.cycleNumber}-${Date.now()}.json`;
34902
- writeFileSync13(join41(this.historyDir, filename), JSON.stringify(result, null, 2) + "\n", "utf-8");
34426
+ writeFileSync13(join44(this.historyDir, filename), JSON.stringify(result, null, 2) + "\n", "utf-8");
34903
34427
  const files = readdirSync11(this.historyDir).filter((f) => f.startsWith("cycle-") && f.endsWith(".json")).sort();
34904
34428
  if (files.length > 50) {
34905
34429
  for (const old of files.slice(0, files.length - 50)) {
34906
34430
  try {
34907
- unlinkSync5(join41(this.historyDir, old));
34431
+ unlinkSync5(join44(this.historyDir, old));
34908
34432
  } catch {
34909
34433
  }
34910
34434
  }
@@ -34917,8 +34441,8 @@ OUTPUT: Call task_complete with JSON:
34917
34441
  });
34918
34442
 
34919
34443
  // packages/cli/dist/tui/snr-engine.js
34920
- import { existsSync as existsSync31, readdirSync as readdirSync12, readFileSync as readFileSync22 } from "node:fs";
34921
- import { join as join42, basename as basename14 } from "node:path";
34444
+ import { existsSync as existsSync34, readdirSync as readdirSync12, readFileSync as readFileSync25 } from "node:fs";
34445
+ import { join as join45, basename as basename14 } from "node:path";
34922
34446
  function computeDPrime(signalScores, noiseScores) {
34923
34447
  if (signalScores.length === 0 || noiseScores.length === 0)
34924
34448
  return 0;
@@ -34974,13 +34498,6 @@ function adaptTool4(tool) {
34974
34498
  }
34975
34499
  };
34976
34500
  }
34977
- function renderSNRUpdate(score) {
34978
- const pct = Math.round(score.ratio * 100);
34979
- const color = pct >= 70 ? c2.green : pct >= 40 ? c2.yellow : c2.red;
34980
- const capWarn = score.capacityWarning ? c2.red(" [CAPACITY]") : "";
34981
- process.stdout.write(` ${color("\u25C8")} SNR: ${color(`${pct}%`)} (d'=${score.dPrime.toFixed(1)}, signal=${score.signalCount}/${score.entriesEvaluated}, sparsity=${Math.round(score.sparsity * 100)}%) [${score.evaluators.join("+")}]${capWarn}
34982
- `);
34983
- }
34984
34501
  var SNREngine;
34985
34502
  var init_snr_engine = __esm({
34986
34503
  "packages/cli/dist/tui/snr-engine.js"() {
@@ -35165,11 +34682,11 @@ Call task_complete with the JSON array when done.`, onEvent)
35165
34682
  loadMemoryEntries(topics) {
35166
34683
  const entries = [];
35167
34684
  const dirs = [
35168
- join42(this.repoRoot, ".oa", "memory"),
35169
- join42(this.repoRoot, ".open-agents", "memory")
34685
+ join45(this.repoRoot, ".oa", "memory"),
34686
+ join45(this.repoRoot, ".open-agents", "memory")
35170
34687
  ];
35171
34688
  for (const dir of dirs) {
35172
- if (!existsSync31(dir))
34689
+ if (!existsSync34(dir))
35173
34690
  continue;
35174
34691
  try {
35175
34692
  const files = readdirSync12(dir).filter((f) => f.endsWith(".json"));
@@ -35178,7 +34695,7 @@ Call task_complete with the JSON array when done.`, onEvent)
35178
34695
  if (topics.length > 0 && !topics.includes(topic))
35179
34696
  continue;
35180
34697
  try {
35181
- const data = JSON.parse(readFileSync22(join42(dir, f), "utf-8"));
34698
+ const data = JSON.parse(readFileSync25(join45(dir, f), "utf-8"));
35182
34699
  for (const [key, val] of Object.entries(data)) {
35183
34700
  const value = typeof val === "object" && val !== null && "value" in val ? String(val.value) : String(val);
35184
34701
  entries.push({ topic, key, value });
@@ -35322,6 +34839,7 @@ var init_emotion_engine = __esm({
35322
34839
  "packages/cli/dist/tui/emotion-engine.js"() {
35323
34840
  "use strict";
35324
34841
  init_dist5();
34842
+ init_promptLoader3();
35325
34843
  BASELINE_VALENCE = 0.1;
35326
34844
  BASELINE_AROUSAL = 0.3;
35327
34845
  DECAY_HALF_LIFE_MS = 3e5;
@@ -35390,8 +34908,13 @@ var init_emotion_engine = __esm({
35390
34908
  } else {
35391
34909
  behavioralHint = "You are in a balanced state. Proceed with measured confidence.";
35392
34910
  }
35393
- return `[Emotional State: ${emoji} ${label} | valence=${valence.toFixed(2)} arousal=${arousal.toFixed(2)}]
35394
- ${behavioralHint}`;
34911
+ return loadPrompt3("tui/emotion-behavioral.md", {
34912
+ emoji: this.state.emoji,
34913
+ label: this.state.label,
34914
+ valence: valence.toFixed(2),
34915
+ arousal: arousal.toFixed(2),
34916
+ behavioralHint
34917
+ });
35395
34918
  }
35396
34919
  /**
35397
34920
  * Appraise an agent event and update emotional state.
@@ -35512,18 +35035,11 @@ ${behavioralHint}`;
35512
35035
  }
35513
35036
  };
35514
35037
  runner.registerTools([taskComplete]);
35515
- const prompt = `You are an emotion center. Given the current emotional coordinates, output EXACTLY one emoji and one word (the emotion felt).
35516
-
35517
- Valence: ${this.state.valence.toFixed(2)} (range: -1 distress to +1 joy)
35518
- Arousal: ${this.state.arousal.toFixed(2)} (range: 0 calm to 1 energized)
35519
- Recent streak: ${this.consecutiveSuccesses > 0 ? `${this.consecutiveSuccesses} successes` : this.consecutiveFailures > 0 ? `${this.consecutiveFailures} failures` : "mixed"}
35520
-
35521
- You tend to use face emojis (\u{1F60A} \u{1F624} \u{1F914} \u{1F630} \u{1F929} \u{1F60C} \u{1F97A} \u{1F608}) but you can break off to animals, objects, or esoteric emojis when the mood strikes you. The word should be a single evocative emotion word \u2014 not from a fixed list, choose freely. Be creative and authentic.
35522
-
35523
- Respond with ONLY: <emoji> <word>
35524
- Example: \u{1F525} exhilarated
35525
- Example: \u{1F98A} cunning
35526
- Example: \u{1F30A} flowing`;
35038
+ const prompt = loadPrompt3("tui/emotion-center.md", {
35039
+ valence: this.state.valence.toFixed(2),
35040
+ arousal: this.state.arousal.toFixed(2),
35041
+ recentStreak: this.consecutiveSuccesses > 0 ? `${this.consecutiveSuccesses} successes` : this.consecutiveFailures > 0 ? `${this.consecutiveFailures} failures` : "mixed"
35042
+ });
35527
35043
  const result = await runner.run(prompt, "Emotion center \u2014 respond with one emoji and one word only.");
35528
35044
  const output = (result.summary || "").trim();
35529
35045
  const match = output.match(new RegExp("^(\\p{Emoji_Presentation}|\\p{Emoji}\\uFE0F?)\\s+(\\S+)", "u"));
@@ -35730,8 +35246,8 @@ var init_tool_policy = __esm({
35730
35246
  });
35731
35247
 
35732
35248
  // packages/cli/dist/tui/telegram-bridge.js
35733
- import { mkdirSync as mkdirSync15, existsSync as existsSync32, unlinkSync as unlinkSync6, readdirSync as readdirSync13, statSync as statSync10 } from "node:fs";
35734
- import { join as join43, resolve as resolve27 } from "node:path";
35249
+ import { mkdirSync as mkdirSync15, existsSync as existsSync35, unlinkSync as unlinkSync6, readdirSync as readdirSync13, statSync as statSync10 } from "node:fs";
35250
+ import { join as join46, resolve as resolve27 } from "node:path";
35735
35251
  import { writeFile as writeFileAsync } from "node:fs/promises";
35736
35252
  function convertMarkdownToTelegramHTML(md) {
35737
35253
  let html = md;
@@ -36483,7 +35999,7 @@ Telegram admin: @${msg.username}` : `Telegram ${isGroup ? "group" : "public"} ch
36483
35999
  return null;
36484
36000
  const buffer = Buffer.from(await res.arrayBuffer());
36485
36001
  const fileName = `${Date.now()}-${fileId.slice(0, 8)}${extension}`;
36486
- const localPath = join43(this.mediaCacheDir, fileName);
36002
+ const localPath = join46(this.mediaCacheDir, fileName);
36487
36003
  await writeFileAsync(localPath, buffer);
36488
36004
  return localPath;
36489
36005
  } catch {
@@ -38205,11 +37721,11 @@ var init_status_bar = __esm({
38205
37721
  import * as readline2 from "node:readline";
38206
37722
  import { Writable } from "node:stream";
38207
37723
  import { cwd } from "node:process";
38208
- import { resolve as resolve28, join as join44, dirname as dirname13, extname as extname9 } from "node:path";
37724
+ import { resolve as resolve28, join as join47, dirname as dirname16, extname as extname9 } from "node:path";
38209
37725
  import { createRequire as createRequire2 } from "node:module";
38210
- import { fileURLToPath as fileURLToPath9 } from "node:url";
38211
- import { readFileSync as readFileSync23, rmSync as rmSync2, readdirSync as readdirSync14 } from "node:fs";
38212
- import { existsSync as existsSync33 } from "node:fs";
37726
+ import { fileURLToPath as fileURLToPath12 } from "node:url";
37727
+ import { readFileSync as readFileSync26, rmSync as rmSync2, readdirSync as readdirSync14 } from "node:fs";
37728
+ import { existsSync as existsSync36 } from "node:fs";
38213
37729
  function formatTimeAgo(date) {
38214
37730
  const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
38215
37731
  if (seconds < 60)
@@ -38226,14 +37742,14 @@ function formatTimeAgo(date) {
38226
37742
  function getVersion2() {
38227
37743
  try {
38228
37744
  const require2 = createRequire2(import.meta.url);
38229
- const thisDir = dirname13(fileURLToPath9(import.meta.url));
37745
+ const thisDir = dirname16(fileURLToPath12(import.meta.url));
38230
37746
  const candidates = [
38231
- join44(thisDir, "..", "package.json"),
38232
- join44(thisDir, "..", "..", "package.json"),
38233
- join44(thisDir, "..", "..", "..", "package.json")
37747
+ join47(thisDir, "..", "package.json"),
37748
+ join47(thisDir, "..", "..", "package.json"),
37749
+ join47(thisDir, "..", "..", "..", "package.json")
38234
37750
  ];
38235
37751
  for (const pkgPath of candidates) {
38236
- if (existsSync33(pkgPath)) {
37752
+ if (existsSync36(pkgPath)) {
38237
37753
  const pkg = require2(pkgPath);
38238
37754
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
38239
37755
  return pkg.version ?? "0.0.0";
@@ -38432,15 +37948,15 @@ Use task_status("${taskId}") or task_output("${taskId}") to check progress.`
38432
37948
  function gatherMemorySnippets(root) {
38433
37949
  const snippets = [];
38434
37950
  const dirs = [
38435
- join44(root, ".oa", "memory"),
38436
- join44(root, ".open-agents", "memory")
37951
+ join47(root, ".oa", "memory"),
37952
+ join47(root, ".open-agents", "memory")
38437
37953
  ];
38438
37954
  for (const dir of dirs) {
38439
- if (!existsSync33(dir))
37955
+ if (!existsSync36(dir))
38440
37956
  continue;
38441
37957
  try {
38442
37958
  for (const f of readdirSync14(dir).filter((f2) => f2.endsWith(".json"))) {
38443
- const data = JSON.parse(readFileSync23(join44(dir, f), "utf-8"));
37959
+ const data = JSON.parse(readFileSync26(join47(dir, f), "utf-8"));
38444
37960
  for (const val of Object.values(data)) {
38445
37961
  const v = typeof val === "object" && val !== null && "value" in val ? String(val.value) : String(val);
38446
37962
  if (v.length > 10)
@@ -39075,12 +38591,17 @@ async function startInteractive(config, repoPath) {
39075
38591
  let exposeGateway = null;
39076
38592
  let peerMesh = null;
39077
38593
  let inferenceRouter = null;
39078
- const secretVault = new SecretVault(join44(repoRoot, ".oa", "vault.enc"));
38594
+ const secretVault = new SecretVault(join47(repoRoot, ".oa", "vault.enc"));
39079
38595
  let adminSessionKey = null;
39080
38596
  const callSubAgents = /* @__PURE__ */ new Map();
39081
38597
  const streamRenderer = new StreamRenderer();
39082
38598
  if (savedSettings.voice) {
39083
- voiceEngine.toggle().catch(() => {
38599
+ voiceEngine.toggle().catch((err) => {
38600
+ const msg = err instanceof Error ? err.message : String(err);
38601
+ if (msg.includes("ONNX runtime crashes") || msg.includes("unavailable")) {
38602
+ renderWarning(`Voice disabled: ${msg}`);
38603
+ renderInfo("All other features work normally. Use /voice to retry later.");
38604
+ }
39084
38605
  });
39085
38606
  if (savedSettings.voiceModel) {
39086
38607
  voiceEngine.setModel(savedSettings.voiceModel).catch(() => {
@@ -39109,7 +38630,6 @@ async function startInteractive(config, repoPath) {
39109
38630
  try {
39110
38631
  const score = await snrEngine.evaluateWithAgents(taskPrompt, []);
39111
38632
  statusBar.setSNR(score.ratio, score.dPrime, score.capacityWarning);
39112
- renderSNRUpdate(score);
39113
38633
  } catch {
39114
38634
  } finally {
39115
38635
  pendingSNREval = null;
@@ -40120,8 +39640,8 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
40120
39640
  return true;
40121
39641
  },
40122
39642
  destroyProject() {
40123
- const oaPath = join44(repoRoot, OA_DIR);
40124
- if (existsSync33(oaPath)) {
39643
+ const oaPath = join47(repoRoot, OA_DIR);
39644
+ if (existsSync36(oaPath)) {
40125
39645
  try {
40126
39646
  rmSync2(oaPath, { recursive: true, force: true });
40127
39647
  writeContent(() => renderInfo(`Removed ${OA_DIR}/ directory.`));
@@ -40407,13 +39927,13 @@ Execute this skill now. Follow the behavioral guidance above.`;
40407
39927
  }
40408
39928
  }
40409
39929
  const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
40410
- const isImage = isImagePath(cleanPath) && existsSync33(resolve28(repoRoot, cleanPath));
40411
- const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync33(resolve28(repoRoot, cleanPath));
39930
+ const isImage = isImagePath(cleanPath) && existsSync36(resolve28(repoRoot, cleanPath));
39931
+ const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync36(resolve28(repoRoot, cleanPath));
40412
39932
  if (activeTask) {
40413
39933
  if (isImage) {
40414
39934
  try {
40415
39935
  const imgPath = resolve28(repoRoot, cleanPath);
40416
- const imgBuffer = readFileSync23(imgPath);
39936
+ const imgBuffer = readFileSync26(imgPath);
40417
39937
  const base64 = imgBuffer.toString("base64");
40418
39938
  const ext = extname9(cleanPath).toLowerCase();
40419
39939
  const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/jpeg";
@@ -40908,7 +40428,7 @@ import { glob } from "glob";
40908
40428
  import ignore from "ignore";
40909
40429
  import { readFile as readFile16, stat as stat4 } from "node:fs/promises";
40910
40430
  import { createHash as createHash4 } from "node:crypto";
40911
- import { join as join45, relative as relative3, extname as extname10, basename as basename15 } from "node:path";
40431
+ import { join as join48, relative as relative3, extname as extname10, basename as basename15 } from "node:path";
40912
40432
  var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
40913
40433
  var init_codebase_indexer = __esm({
40914
40434
  "packages/indexer/dist/codebase-indexer.js"() {
@@ -40952,7 +40472,7 @@ var init_codebase_indexer = __esm({
40952
40472
  const ig = ignore.default();
40953
40473
  if (this.config.respectGitignore) {
40954
40474
  try {
40955
- const gitignoreContent = await readFile16(join45(this.config.rootDir, ".gitignore"), "utf-8");
40475
+ const gitignoreContent = await readFile16(join48(this.config.rootDir, ".gitignore"), "utf-8");
40956
40476
  ig.add(gitignoreContent);
40957
40477
  } catch {
40958
40478
  }
@@ -40967,7 +40487,7 @@ var init_codebase_indexer = __esm({
40967
40487
  for (const relativePath of files) {
40968
40488
  if (ig.ignores(relativePath))
40969
40489
  continue;
40970
- const fullPath = join45(this.config.rootDir, relativePath);
40490
+ const fullPath = join48(this.config.rootDir, relativePath);
40971
40491
  try {
40972
40492
  const fileStat = await stat4(fullPath);
40973
40493
  if (fileStat.size > this.config.maxFileSize)
@@ -41013,7 +40533,7 @@ var init_codebase_indexer = __esm({
41013
40533
  if (!child) {
41014
40534
  child = {
41015
40535
  name: part,
41016
- path: join45(current.path, part),
40536
+ path: join48(current.path, part),
41017
40537
  type: "directory",
41018
40538
  children: []
41019
40539
  };
@@ -41096,13 +40616,13 @@ __export(index_repo_exports, {
41096
40616
  indexRepoCommand: () => indexRepoCommand
41097
40617
  });
41098
40618
  import { resolve as resolve29 } from "node:path";
41099
- import { existsSync as existsSync34, statSync as statSync11 } from "node:fs";
40619
+ import { existsSync as existsSync37, statSync as statSync11 } from "node:fs";
41100
40620
  import { cwd as cwd2 } from "node:process";
41101
40621
  async function indexRepoCommand(opts, _config) {
41102
40622
  const repoRoot = resolve29(opts.repoPath ?? cwd2());
41103
40623
  printHeader("Index Repository");
41104
40624
  printInfo(`Indexing: ${repoRoot}`);
41105
- if (!existsSync34(repoRoot)) {
40625
+ if (!existsSync37(repoRoot)) {
41106
40626
  printError(`Path does not exist: ${repoRoot}`);
41107
40627
  process.exit(1);
41108
40628
  }
@@ -41354,7 +40874,7 @@ var config_exports = {};
41354
40874
  __export(config_exports, {
41355
40875
  configCommand: () => configCommand
41356
40876
  });
41357
- import { join as join46, resolve as resolve30 } from "node:path";
40877
+ import { join as join49, resolve as resolve30 } from "node:path";
41358
40878
  import { homedir as homedir13 } from "node:os";
41359
40879
  import { cwd as cwd3 } from "node:process";
41360
40880
  function redactIfSensitive(key, value) {
@@ -41413,7 +40933,7 @@ function handleShow(opts, config) {
41413
40933
  }
41414
40934
  }
41415
40935
  printSection("Config File");
41416
- printInfo(`~/.open-agents/config.json (${join46(homedir13(), ".open-agents", "config.json")})`);
40936
+ printInfo(`~/.open-agents/config.json (${join49(homedir13(), ".open-agents", "config.json")})`);
41417
40937
  printSection("Priority Chain");
41418
40938
  printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
41419
40939
  printInfo(" 2. Project .oa/settings.json (--local)");
@@ -41452,7 +40972,7 @@ function handleSet(opts, _config) {
41452
40972
  const coerced = coerceForSettings(key, value);
41453
40973
  saveProjectSettings(repoRoot, { [key]: coerced });
41454
40974
  printSuccess(`Project override set: ${key} = ${redactIfSensitive(key, value)}`);
41455
- printInfo(`Saved to ${join46(repoRoot, ".oa", "settings.json")}`);
40975
+ printInfo(`Saved to ${join49(repoRoot, ".oa", "settings.json")}`);
41456
40976
  printInfo("This override applies only when running in this workspace.");
41457
40977
  } catch (err) {
41458
40978
  printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
@@ -41672,7 +41192,7 @@ __export(eval_exports, {
41672
41192
  });
41673
41193
  import { tmpdir as tmpdir7 } from "node:os";
41674
41194
  import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync14 } from "node:fs";
41675
- import { join as join47 } from "node:path";
41195
+ import { join as join50 } from "node:path";
41676
41196
  async function evalCommand(opts, config) {
41677
41197
  const suiteName = opts.suite ?? "basic";
41678
41198
  const suite = SUITES[suiteName];
@@ -41793,9 +41313,9 @@ async function evalCommand(opts, config) {
41793
41313
  process.exit(failed > 0 ? 1 : 0);
41794
41314
  }
41795
41315
  function createTempEvalRepo() {
41796
- const dir = join47(tmpdir7(), `open-agents-eval-${Date.now()}`);
41316
+ const dir = join50(tmpdir7(), `open-agents-eval-${Date.now()}`);
41797
41317
  mkdirSync16(dir, { recursive: true });
41798
- writeFileSync14(join47(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
41318
+ writeFileSync14(join50(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
41799
41319
  return dir;
41800
41320
  }
41801
41321
  var BASIC_SUITE, FULL_SUITE, SUITES;
@@ -41854,8 +41374,8 @@ init_output();
41854
41374
  init_updater();
41855
41375
  import { parseArgs as nodeParseArgs2 } from "node:util";
41856
41376
  import { createRequire as createRequire3 } from "node:module";
41857
- import { fileURLToPath as fileURLToPath10 } from "node:url";
41858
- import { dirname as dirname14, join as join48 } from "node:path";
41377
+ import { fileURLToPath as fileURLToPath13 } from "node:url";
41378
+ import { dirname as dirname17, join as join51 } from "node:path";
41859
41379
 
41860
41380
  // packages/cli/dist/cli.js
41861
41381
  import { createInterface } from "node:readline";
@@ -41962,7 +41482,7 @@ init_output();
41962
41482
  function getVersion3() {
41963
41483
  try {
41964
41484
  const require2 = createRequire3(import.meta.url);
41965
- const pkgPath = join48(dirname14(fileURLToPath10(import.meta.url)), "..", "package.json");
41485
+ const pkgPath = join51(dirname17(fileURLToPath13(import.meta.url)), "..", "package.json");
41966
41486
  const pkg = require2(pkgPath);
41967
41487
  return pkg.version;
41968
41488
  } catch {