open-agents-ai 0.32.2 → 0.34.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 (2) hide show
  1. package/dist/index.js +1067 -468
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1285,7 +1285,7 @@ ${stdinInput ?? ""}`);
1285
1285
  }
1286
1286
  runCommand(command, timeout, stdinInput) {
1287
1287
  const start = performance.now();
1288
- return new Promise((resolve22) => {
1288
+ return new Promise((resolve23) => {
1289
1289
  const child = spawn("bash", ["-c", command], {
1290
1290
  cwd: this.workingDir,
1291
1291
  env: {
@@ -1313,7 +1313,7 @@ ${stdinInput ?? ""}`);
1313
1313
  clearTimeout(timer);
1314
1314
  if (exitFlushTimer)
1315
1315
  clearTimeout(exitFlushTimer);
1316
- resolve22(result);
1316
+ resolve23(result);
1317
1317
  };
1318
1318
  const timer = setTimeout(() => {
1319
1319
  killed = true;
@@ -2317,7 +2317,7 @@ Meta: ${metaKeys.map((k) => `${k}="${meta[k]?.slice(0, 80)}"`).join(", ")}`);
2317
2317
  return null;
2318
2318
  }
2319
2319
  runProcess(cmd, args, timeoutMs) {
2320
- return new Promise((resolve22, reject) => {
2320
+ return new Promise((resolve23, reject) => {
2321
2321
  const proc = execFile3(cmd, args, {
2322
2322
  timeout: timeoutMs,
2323
2323
  maxBuffer: 10 * 1024 * 1024,
@@ -2327,7 +2327,7 @@ Meta: ${metaKeys.map((k) => `${k}="${meta[k]?.slice(0, 80)}"`).join(", ")}`);
2327
2327
  reject(new Error(`Process timeout after ${timeoutMs}ms`));
2328
2328
  return;
2329
2329
  }
2330
- resolve22({
2330
+ resolve23({
2331
2331
  stdout: String(stdout),
2332
2332
  stderr: String(stderr),
2333
2333
  exitCode: error ? error.code ?? 1 : 0
@@ -2639,9 +2639,402 @@ var init_memory_write = __esm({
2639
2639
  }
2640
2640
  });
2641
2641
 
2642
+ // packages/execution/dist/tools/memory-search.js
2643
+ import { readFile as readFile5, readdir } from "node:fs/promises";
2644
+ import { resolve as resolve8, join as join6, basename } from "node:path";
2645
+ import { existsSync as existsSync4 } from "node:fs";
2646
+ import { homedir as homedir3 } from "node:os";
2647
+ function termMatchScore(query, document) {
2648
+ const queryTerms = tokenize(query);
2649
+ const docTerms = tokenize(document);
2650
+ if (queryTerms.length === 0 || docTerms.length === 0)
2651
+ return 0;
2652
+ const docSet = new Set(docTerms);
2653
+ const docBigrams = /* @__PURE__ */ new Set();
2654
+ for (let i = 0; i < docTerms.length - 1; i++) {
2655
+ docBigrams.add(`${docTerms[i]} ${docTerms[i + 1]}`);
2656
+ }
2657
+ let matchedTerms = 0;
2658
+ let matchedBigrams = 0;
2659
+ let totalWeight = 0;
2660
+ for (const term of queryTerms) {
2661
+ totalWeight += 1;
2662
+ if (docSet.has(term)) {
2663
+ matchedTerms += 1;
2664
+ } else if ([...docSet].some((d) => d.startsWith(term) || term.startsWith(d))) {
2665
+ matchedTerms += 0.5;
2666
+ }
2667
+ }
2668
+ for (let i = 0; i < queryTerms.length - 1; i++) {
2669
+ const bigram = `${queryTerms[i]} ${queryTerms[i + 1]}`;
2670
+ totalWeight += 1;
2671
+ if (docBigrams.has(bigram)) {
2672
+ matchedBigrams += 1;
2673
+ }
2674
+ }
2675
+ return totalWeight > 0 ? (matchedTerms + matchedBigrams * 2) / (totalWeight * 2) : 0;
2676
+ }
2677
+ function tokenize(text) {
2678
+ const STOP_WORDS2 = /* @__PURE__ */ new Set([
2679
+ "a",
2680
+ "an",
2681
+ "the",
2682
+ "is",
2683
+ "are",
2684
+ "was",
2685
+ "were",
2686
+ "be",
2687
+ "been",
2688
+ "being",
2689
+ "have",
2690
+ "has",
2691
+ "had",
2692
+ "do",
2693
+ "does",
2694
+ "did",
2695
+ "will",
2696
+ "would",
2697
+ "could",
2698
+ "should",
2699
+ "may",
2700
+ "might",
2701
+ "can",
2702
+ "shall",
2703
+ "to",
2704
+ "of",
2705
+ "in",
2706
+ "for",
2707
+ "on",
2708
+ "with",
2709
+ "at",
2710
+ "by",
2711
+ "from",
2712
+ "as",
2713
+ "into",
2714
+ "through",
2715
+ "during",
2716
+ "before",
2717
+ "after",
2718
+ "above",
2719
+ "below",
2720
+ "and",
2721
+ "but",
2722
+ "or",
2723
+ "not",
2724
+ "no",
2725
+ "if",
2726
+ "then",
2727
+ "else",
2728
+ "when",
2729
+ "up",
2730
+ "out",
2731
+ "so",
2732
+ "than",
2733
+ "too",
2734
+ "very",
2735
+ "just",
2736
+ "about",
2737
+ "this",
2738
+ "that",
2739
+ "these",
2740
+ "those",
2741
+ "it",
2742
+ "its"
2743
+ ]);
2744
+ return text.toLowerCase().replace(/[^a-z0-9_\-\.]+/g, " ").split(/\s+/).filter((t) => t.length > 1 && !STOP_WORDS2.has(t));
2745
+ }
2746
+ var MemorySearchTool;
2747
+ var init_memory_search = __esm({
2748
+ "packages/execution/dist/tools/memory-search.js"() {
2749
+ "use strict";
2750
+ MemorySearchTool = class {
2751
+ name = "memory_search";
2752
+ description = "Search across all memory entries by relevance. Unlike memory_read (exact topic+key), this finds relevant memories using text matching. Use when you don't know the exact topic or key, or want to find all memories related to a concept.";
2753
+ parameters = {
2754
+ type: "object",
2755
+ properties: {
2756
+ query: {
2757
+ type: "string",
2758
+ description: "Natural language search query (e.g. 'authentication bug fix', 'React patterns')"
2759
+ },
2760
+ max_results: {
2761
+ type: "number",
2762
+ description: "Maximum number of results to return (default: 10)"
2763
+ }
2764
+ },
2765
+ required: ["query"]
2766
+ };
2767
+ workingDir;
2768
+ constructor(workingDir) {
2769
+ this.workingDir = workingDir;
2770
+ }
2771
+ async execute(args) {
2772
+ const query = args["query"];
2773
+ const maxResults = args["max_results"] ?? 10;
2774
+ const start = performance.now();
2775
+ try {
2776
+ const allEntries = await this.loadAllMemories();
2777
+ if (allEntries.length === 0) {
2778
+ return {
2779
+ success: true,
2780
+ output: "No memory entries found. Use memory_write to store insights.",
2781
+ durationMs: performance.now() - start
2782
+ };
2783
+ }
2784
+ const scored = allEntries.map((entry) => ({
2785
+ ...entry,
2786
+ score: termMatchScore(query, `${entry.topic} ${entry.key} ${entry.value}`)
2787
+ }));
2788
+ const results = scored.filter((e) => e.score > 0).sort((a, b) => b.score - a.score).slice(0, maxResults);
2789
+ if (results.length === 0) {
2790
+ return {
2791
+ success: true,
2792
+ output: `No memories matched query: "${query}"
2793
+
2794
+ Try broader terms or use memory_read with a specific topic.`,
2795
+ durationMs: performance.now() - start
2796
+ };
2797
+ }
2798
+ const lines = [
2799
+ `Found ${results.length} relevant memories for: "${query}"
2800
+ `
2801
+ ];
2802
+ for (const r of results) {
2803
+ const score = Math.round(r.score * 100);
2804
+ lines.push(`[${r.topic}/${r.key}] (relevance: ${score}%)`);
2805
+ lines.push(` ${r.value.slice(0, 300)}${r.value.length > 300 ? "..." : ""}`);
2806
+ if (r.timestamp)
2807
+ lines.push(` (saved: ${r.timestamp.split("T")[0]})`);
2808
+ lines.push("");
2809
+ }
2810
+ return {
2811
+ success: true,
2812
+ output: lines.join("\n"),
2813
+ durationMs: performance.now() - start
2814
+ };
2815
+ } catch (error) {
2816
+ return {
2817
+ success: false,
2818
+ output: "",
2819
+ error: error instanceof Error ? error.message : String(error),
2820
+ durationMs: performance.now() - start
2821
+ };
2822
+ }
2823
+ }
2824
+ /**
2825
+ * Load all memory entries from all memory directories.
2826
+ */
2827
+ async loadAllMemories() {
2828
+ const entries = [];
2829
+ const dirs = [
2830
+ resolve8(this.workingDir, ".oa", "memory"),
2831
+ resolve8(this.workingDir, ".open-agents", "memory"),
2832
+ resolve8(homedir3(), ".open-agents", "memory")
2833
+ ];
2834
+ const seen = /* @__PURE__ */ new Set();
2835
+ for (const dir of dirs) {
2836
+ if (!existsSync4(dir))
2837
+ continue;
2838
+ try {
2839
+ const files = await readdir(dir);
2840
+ for (const file of files.filter((f) => f.endsWith(".json"))) {
2841
+ try {
2842
+ const raw = await readFile5(join6(dir, file), "utf-8");
2843
+ const data = JSON.parse(raw);
2844
+ const topic = basename(file, ".json");
2845
+ for (const [key, entry] of Object.entries(data)) {
2846
+ const dedup = `${topic}:${key}`;
2847
+ if (seen.has(dedup))
2848
+ continue;
2849
+ seen.add(dedup);
2850
+ if (entry?.value) {
2851
+ entries.push({
2852
+ topic,
2853
+ key,
2854
+ value: String(entry.value),
2855
+ timestamp: entry.timestamp,
2856
+ score: 0
2857
+ });
2858
+ }
2859
+ }
2860
+ } catch {
2861
+ }
2862
+ }
2863
+ } catch {
2864
+ }
2865
+ }
2866
+ return entries;
2867
+ }
2868
+ };
2869
+ }
2870
+ });
2871
+
2872
+ // packages/execution/dist/tools/explore-tools.js
2873
+ var TOOL_CATALOG, ExploreToolsTool;
2874
+ var init_explore_tools = __esm({
2875
+ "packages/execution/dist/tools/explore-tools.js"() {
2876
+ "use strict";
2877
+ TOOL_CATALOG = {
2878
+ grep_search: "Search file contents with regex patterns",
2879
+ find_files: "Find files by glob pattern (e.g. **/*.ts)",
2880
+ list_directory: "List contents of a directory",
2881
+ web_search: "Search the web via DuckDuckGo",
2882
+ web_fetch: "Fetch and read a web page URL",
2883
+ web_crawl: "Crawl a website following links",
2884
+ memory_read: "Read from persistent memory (exact topic+key)",
2885
+ memory_write: "Store a fact in persistent memory",
2886
+ memory_search: "Search all memories by relevance",
2887
+ batch_edit: "Apply multiple file edits atomically",
2888
+ file_patch: "Apply unified diff patches to files",
2889
+ git_info: "Get git status, branch, recent commits",
2890
+ codebase_map: "Generate overview of project structure",
2891
+ diagnostic: "Run project diagnostics (build, test, lint)",
2892
+ image_read: "Read and describe image contents",
2893
+ screenshot: "Capture a screenshot of the desktop",
2894
+ ocr_image: "Extract text from images via OCR",
2895
+ ocr_pdf: "Extract text from PDF pages via OCR",
2896
+ pdf_to_text: "Convert PDF to plain text",
2897
+ vision: "Describe what's on screen using Moondream",
2898
+ desktop_click: "Click at coordinates on the desktop",
2899
+ desktop_describe: "Describe a region of the desktop",
2900
+ transcribe_file: "Transcribe audio/video files to text",
2901
+ create_tool: "Create a new custom tool from a workflow",
2902
+ manage_tools: "List, inspect, or remove custom tools",
2903
+ skill_list: "List available AIWG skills",
2904
+ skill_execute: "Execute an AIWG skill",
2905
+ structured_file: "Generate structured files (CSV, JSON, MD)",
2906
+ code_sandbox: "Run code in an isolated sandbox",
2907
+ structured_read: "Read structured data files (CSV, JSON)",
2908
+ sub_agent: "Delegate a subtask to a new agent instance",
2909
+ background_run: "Run a shell command in the background",
2910
+ task_status: "Check status of background tasks",
2911
+ task_output: "Read output from a background task",
2912
+ task_stop: "Stop a running background task"
2913
+ };
2914
+ ExploreToolsTool = class {
2915
+ name = "explore_tools";
2916
+ description = "Discover and enable additional tools. Call with no arguments to see all available tools. Call with enable='tool_name' to unlock a tool for this session. Call with search='query' to find tools matching your need.";
2917
+ parameters = {
2918
+ type: "object",
2919
+ properties: {
2920
+ enable: {
2921
+ type: "string",
2922
+ description: "Tool name to unlock for this session (omit to list available)"
2923
+ },
2924
+ search: {
2925
+ type: "string",
2926
+ description: "Search query to find relevant tools (e.g. 'search files', 'web')"
2927
+ }
2928
+ },
2929
+ required: []
2930
+ };
2931
+ /** Set of currently unlocked tool names (managed by the runner) */
2932
+ unlockedTools = /* @__PURE__ */ new Set();
2933
+ /** Callback to signal tool unlock to the runner */
2934
+ onUnlock;
2935
+ /**
2936
+ * Set the unlock callback. The runner calls this to wire up the unlock mechanism.
2937
+ * The callback should return true if the tool was successfully unlocked.
2938
+ */
2939
+ setUnlockCallback(cb) {
2940
+ this.onUnlock = cb;
2941
+ }
2942
+ /** Mark a tool as already unlocked (called by runner during init) */
2943
+ markUnlocked(name) {
2944
+ this.unlockedTools.add(name);
2945
+ }
2946
+ async execute(args) {
2947
+ const start = performance.now();
2948
+ const enableName = args["enable"]?.trim();
2949
+ const searchQuery = args["search"]?.trim();
2950
+ if (enableName) {
2951
+ if (!(enableName in TOOL_CATALOG)) {
2952
+ return {
2953
+ success: false,
2954
+ output: "",
2955
+ error: `Unknown tool '${enableName}'. Call explore_tools() to see available tools.`,
2956
+ durationMs: performance.now() - start
2957
+ };
2958
+ }
2959
+ if (this.unlockedTools.has(enableName)) {
2960
+ return {
2961
+ success: true,
2962
+ output: `Tool '${enableName}' is already unlocked. You can use it now.`,
2963
+ durationMs: performance.now() - start
2964
+ };
2965
+ }
2966
+ if (this.onUnlock) {
2967
+ const success = this.onUnlock(enableName);
2968
+ if (success) {
2969
+ this.unlockedTools.add(enableName);
2970
+ return {
2971
+ success: true,
2972
+ output: `Tool '${enableName}' is now unlocked and available. You can use it in your next response.`,
2973
+ durationMs: performance.now() - start
2974
+ };
2975
+ }
2976
+ }
2977
+ return {
2978
+ success: true,
2979
+ output: `UNLOCK_TOOL:${enableName}`,
2980
+ durationMs: performance.now() - start
2981
+ };
2982
+ }
2983
+ if (searchQuery) {
2984
+ const terms = searchQuery.toLowerCase().split(/\s+/);
2985
+ const matches = [];
2986
+ for (const [name, desc] of Object.entries(TOOL_CATALOG)) {
2987
+ const text = `${name} ${desc}`.toLowerCase();
2988
+ const score = terms.reduce((s, t) => s + (text.includes(t) ? 1 : 0), 0);
2989
+ if (score > 0)
2990
+ matches.push([name, desc, score]);
2991
+ }
2992
+ matches.sort((a, b) => b[2] - a[2]);
2993
+ if (matches.length === 0) {
2994
+ return {
2995
+ success: true,
2996
+ output: `No tools match "${searchQuery}". Try broader terms or call explore_tools() to list all.`,
2997
+ durationMs: performance.now() - start
2998
+ };
2999
+ }
3000
+ const lines2 = [`Tools matching "${searchQuery}":
3001
+ `];
3002
+ for (const [name, desc] of matches.slice(0, 8)) {
3003
+ const status = this.unlockedTools.has(name) ? " [unlocked]" : "";
3004
+ lines2.push(` ${name}: ${desc}${status}`);
3005
+ }
3006
+ lines2.push(`
3007
+ Use explore_tools(enable='name') to unlock a tool.`);
3008
+ return {
3009
+ success: true,
3010
+ output: lines2.join("\n"),
3011
+ durationMs: performance.now() - start
3012
+ };
3013
+ }
3014
+ const lines = ["Available tools (call explore_tools with enable='name' to unlock):\n"];
3015
+ for (const [name, desc] of Object.entries(TOOL_CATALOG)) {
3016
+ const status = this.unlockedTools.has(name) ? " [unlocked]" : "";
3017
+ lines.push(` ${name}: ${desc}${status}`);
3018
+ }
3019
+ lines.push(`
3020
+ ${this.unlockedTools.size} of ${Object.keys(TOOL_CATALOG).length} tools currently unlocked.`);
3021
+ lines.push(`
3022
+ Examples:`);
3023
+ lines.push(` explore_tools({enable: 'grep_search'})`);
3024
+ lines.push(` explore_tools({search: 'search files'})`);
3025
+ return {
3026
+ success: true,
3027
+ output: lines.join("\n"),
3028
+ durationMs: performance.now() - start
3029
+ };
3030
+ }
3031
+ };
3032
+ }
3033
+ });
3034
+
2642
3035
  // packages/execution/dist/tools/list-directory.js
2643
3036
  import { readdirSync, statSync } from "node:fs";
2644
- import { resolve as resolve8, join as join6 } from "node:path";
3037
+ import { resolve as resolve9, join as join7 } from "node:path";
2645
3038
  var EXCLUDED, MAX_ENTRIES, ListDirectoryTool;
2646
3039
  var init_list_directory = __esm({
2647
3040
  "packages/execution/dist/tools/list-directory.js"() {
@@ -2669,7 +3062,7 @@ var init_list_directory = __esm({
2669
3062
  const dirPath = args["path"] ?? ".";
2670
3063
  const start = performance.now();
2671
3064
  try {
2672
- const fullPath = resolve8(this.workingDir, dirPath);
3065
+ const fullPath = resolve9(this.workingDir, dirPath);
2673
3066
  const entries = readdirSync(fullPath, { withFileTypes: true });
2674
3067
  const visible = entries.filter((e) => !EXCLUDED.has(e.name));
2675
3068
  const limited = visible.slice(0, MAX_ENTRIES);
@@ -2680,7 +3073,7 @@ var init_list_directory = __esm({
2680
3073
  }
2681
3074
  let size = 0;
2682
3075
  try {
2683
- size = statSync(join6(fullPath, entry.name)).size;
3076
+ size = statSync(join7(fullPath, entry.name)).size;
2684
3077
  } catch {
2685
3078
  }
2686
3079
  return `${prefix} ${entry.name} ${size}`;
@@ -2783,8 +3176,8 @@ ${output}`,
2783
3176
 
2784
3177
  // packages/execution/dist/tools/aiwg-health.js
2785
3178
  import { execSync as execSync2 } from "node:child_process";
2786
- import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync3, statSync as statSync2 } from "node:fs";
2787
- import { join as join7 } from "node:path";
3179
+ import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync3, statSync as statSync2 } from "node:fs";
3180
+ import { join as join8 } from "node:path";
2788
3181
  var AiwgHealthTool;
2789
3182
  var init_aiwg_health = __esm({
2790
3183
  "packages/execution/dist/tools/aiwg-health.js"() {
@@ -2816,8 +3209,8 @@ var init_aiwg_health = __esm({
2816
3209
  const detailed = args["detailed"] ?? false;
2817
3210
  const report = [];
2818
3211
  report.push("# SDLC Health Report\n");
2819
- const aiwgDir = join7(projectDir, ".aiwg");
2820
- const hasAiwg = existsSync4(aiwgDir);
3212
+ const aiwgDir = join8(projectDir, ".aiwg");
3213
+ const hasAiwg = existsSync5(aiwgDir);
2821
3214
  report.push(`## AIWG Framework: ${hasAiwg ? "DEPLOYED" : "NOT DEPLOYED"}`);
2822
3215
  if (hasAiwg) {
2823
3216
  const aiwgArtifacts = this.scanAiwgArtifacts(aiwgDir);
@@ -2885,7 +3278,7 @@ var init_aiwg_health = __esm({
2885
3278
  const entries = readdirSync2(aiwgDir, { withFileTypes: true });
2886
3279
  for (const entry of entries) {
2887
3280
  if (entry.isDirectory()) {
2888
- const subDir = join7(aiwgDir, entry.name);
3281
+ const subDir = join8(aiwgDir, entry.name);
2889
3282
  try {
2890
3283
  const files = readdirSync2(subDir).filter((f) => !f.startsWith("."));
2891
3284
  categories[entry.name] = files.length;
@@ -2899,7 +3292,7 @@ var init_aiwg_health = __esm({
2899
3292
  return { total, categories };
2900
3293
  }
2901
3294
  analyzeStructure(dir) {
2902
- const has = (p) => existsSync4(join7(dir, p));
3295
+ const has = (p) => existsSync5(join8(dir, p));
2903
3296
  return {
2904
3297
  packageManager: has("pnpm-lock.yaml") ? "pnpm" : has("yarn.lock") ? "yarn" : has("package-lock.json") ? "npm" : has("Cargo.toml") ? "cargo" : has("go.mod") ? "go" : "unknown",
2905
3298
  language: has("tsconfig.json") ? "TypeScript" : has("package.json") ? "JavaScript" : has("Cargo.toml") ? "Rust" : has("go.mod") ? "Go" : has("pyproject.toml") || has("setup.py") ? "Python" : "unknown",
@@ -2912,8 +3305,8 @@ var init_aiwg_health = __esm({
2912
3305
  }
2913
3306
  analyzeDocumentation(dir) {
2914
3307
  let readmeQuality = "missing";
2915
- const readmePath = join7(dir, "README.md");
2916
- if (existsSync4(readmePath)) {
3308
+ const readmePath = join8(dir, "README.md");
3309
+ if (existsSync5(readmePath)) {
2917
3310
  try {
2918
3311
  const content = readFileSync3(readmePath, "utf8");
2919
3312
  const len = content.length;
@@ -2922,12 +3315,12 @@ var init_aiwg_health = __esm({
2922
3315
  readmeQuality = "unreadable";
2923
3316
  }
2924
3317
  }
2925
- const has = (p) => existsSync4(join7(dir, p));
3318
+ const has = (p) => existsSync5(join8(dir, p));
2926
3319
  const hasApiDocs = has("docs/api") || has("api-docs") || has("swagger.json") || has("openapi.yaml");
2927
3320
  const hasArchDocs = has("docs/architecture") || has(".aiwg/architecture") || has("ARCHITECTURE.md");
2928
3321
  let docFileCount = 0;
2929
- const docsDir = join7(dir, "docs");
2930
- if (existsSync4(docsDir)) {
3322
+ const docsDir = join8(dir, "docs");
3323
+ if (existsSync5(docsDir)) {
2931
3324
  try {
2932
3325
  docFileCount = this.countFiles(docsDir);
2933
3326
  } catch {
@@ -2943,7 +3336,7 @@ var init_aiwg_health = __esm({
2943
3336
  if (entry.isFile())
2944
3337
  count++;
2945
3338
  else if (entry.isDirectory() && entry.name !== "node_modules") {
2946
- count += this.countFiles(join7(dir, entry.name));
3339
+ count += this.countFiles(join8(dir, entry.name));
2947
3340
  }
2948
3341
  }
2949
3342
  } catch {
@@ -3079,8 +3472,8 @@ var init_aiwg_workflow = __esm({
3079
3472
  });
3080
3473
 
3081
3474
  // packages/execution/dist/tools/batch-edit.js
3082
- import { readFile as readFile5, writeFile as writeFile4 } from "node:fs/promises";
3083
- import { resolve as resolve9 } from "node:path";
3475
+ import { readFile as readFile6, writeFile as writeFile4 } from "node:fs/promises";
3476
+ import { resolve as resolve10 } from "node:path";
3084
3477
  function countOccurrences2(haystack, needle) {
3085
3478
  let count = 0;
3086
3479
  let pos = 0;
@@ -3146,7 +3539,7 @@ var init_batch_edit = __esm({
3146
3539
  }
3147
3540
  const byFile = /* @__PURE__ */ new Map();
3148
3541
  for (const edit of edits) {
3149
- const fullPath = resolve9(this.workingDir, edit.path);
3542
+ const fullPath = resolve10(this.workingDir, edit.path);
3150
3543
  if (!byFile.has(fullPath))
3151
3544
  byFile.set(fullPath, []);
3152
3545
  byFile.get(fullPath).push({
@@ -3161,7 +3554,7 @@ var init_batch_edit = __esm({
3161
3554
  let failCount = 0;
3162
3555
  for (const [fullPath, fileEdits] of byFile) {
3163
3556
  try {
3164
- let content = await readFile5(fullPath, "utf-8");
3557
+ let content = await readFile6(fullPath, "utf-8");
3165
3558
  for (const edit of fileEdits) {
3166
3559
  const occurrences = countOccurrences2(content, edit.old_string);
3167
3560
  if (occurrences === 0) {
@@ -3205,8 +3598,8 @@ ${results.join("\n")}`,
3205
3598
  });
3206
3599
 
3207
3600
  // packages/execution/dist/tools/file-patch.js
3208
- import { readFile as readFile6, writeFile as writeFile5, copyFile } from "node:fs/promises";
3209
- import { resolve as resolve10 } from "node:path";
3601
+ import { readFile as readFile7, writeFile as writeFile5, copyFile } from "node:fs/promises";
3602
+ import { resolve as resolve11 } from "node:path";
3210
3603
  var FilePatchTool;
3211
3604
  var init_file_patch = __esm({
3212
3605
  "packages/execution/dist/tools/file-patch.js"() {
@@ -3274,8 +3667,8 @@ var init_file_patch = __esm({
3274
3667
  durationMs: performance.now() - start
3275
3668
  };
3276
3669
  }
3277
- const fullPath = resolve10(this.workingDir, filePath);
3278
- const content = await readFile6(fullPath, "utf-8");
3670
+ const fullPath = resolve11(this.workingDir, filePath);
3671
+ const content = await readFile7(fullPath, "utf-8");
3279
3672
  const lines = content.split("\n");
3280
3673
  const totalLines = lines.length;
3281
3674
  if (startLine > totalLines) {
@@ -3377,8 +3770,8 @@ ${diff}`,
3377
3770
  });
3378
3771
 
3379
3772
  // packages/execution/dist/tools/codebase-map.js
3380
- import { readdirSync as readdirSync3, statSync as statSync3, readFileSync as readFileSync4, existsSync as existsSync5 } from "node:fs";
3381
- import { join as join8, relative, extname } from "node:path";
3773
+ import { readdirSync as readdirSync3, statSync as statSync3, readFileSync as readFileSync4, existsSync as existsSync6 } from "node:fs";
3774
+ import { join as join9, relative, extname } from "node:path";
3382
3775
  var CodebaseMapTool;
3383
3776
  var init_codebase_map = __esm({
3384
3777
  "packages/execution/dist/tools/codebase-map.js"() {
@@ -3462,8 +3855,8 @@ var init_codebase_map = __esm({
3462
3855
  }
3463
3856
  detectProjectInfo(dir) {
3464
3857
  const info = {};
3465
- const pkgPath = join8(dir, "package.json");
3466
- if (existsSync5(pkgPath)) {
3858
+ const pkgPath = join9(dir, "package.json");
3859
+ if (existsSync6(pkgPath)) {
3467
3860
  try {
3468
3861
  const pkg = JSON.parse(readFileSync4(pkgPath, "utf8"));
3469
3862
  info.name = pkg.name;
@@ -3471,15 +3864,15 @@ var init_codebase_map = __esm({
3471
3864
  } catch {
3472
3865
  }
3473
3866
  }
3474
- if (existsSync5(join8(dir, "tsconfig.json")))
3867
+ if (existsSync6(join9(dir, "tsconfig.json")))
3475
3868
  info.language = "TypeScript";
3476
- else if (existsSync5(join8(dir, "package.json")))
3869
+ else if (existsSync6(join9(dir, "package.json")))
3477
3870
  info.language = "JavaScript";
3478
- else if (existsSync5(join8(dir, "Cargo.toml")))
3871
+ else if (existsSync6(join9(dir, "Cargo.toml")))
3479
3872
  info.language = "Rust";
3480
- else if (existsSync5(join8(dir, "go.mod")))
3873
+ else if (existsSync6(join9(dir, "go.mod")))
3481
3874
  info.language = "Go";
3482
- else if (existsSync5(join8(dir, "pyproject.toml")))
3875
+ else if (existsSync6(join9(dir, "pyproject.toml")))
3483
3876
  info.language = "Python";
3484
3877
  return info;
3485
3878
  }
@@ -3507,7 +3900,7 @@ var init_codebase_map = __esm({
3507
3900
  ];
3508
3901
  const found = [];
3509
3902
  for (const kf of KEY_FILES) {
3510
- if (existsSync5(join8(dir, kf))) {
3903
+ if (existsSync6(join9(dir, kf))) {
3511
3904
  found.push(kf);
3512
3905
  }
3513
3906
  }
@@ -3545,7 +3938,7 @@ var init_codebase_map = __esm({
3545
3938
  const dirs = entries.filter((e) => e.isDirectory() && !this.SKIP_DIRS.has(e.name));
3546
3939
  const files = entries.filter((e) => e.isFile());
3547
3940
  for (const d of dirs) {
3548
- const subPath = join8(dir, d.name);
3941
+ const subPath = join9(dir, d.name);
3549
3942
  const fileCount = this.countFilesShallow(subPath);
3550
3943
  lines.push(`${indent}${d.name}/ (${fileCount} files)`);
3551
3944
  const subtree = this.buildTree(subPath, rootDir, depth + 1, maxDepth, showFiles);
@@ -3586,7 +3979,7 @@ var init_codebase_map = __esm({
3586
3979
  if (lang)
3587
3980
  counts.set(lang, (counts.get(lang) ?? 0) + 1);
3588
3981
  } else if (entry.isDirectory() && !this.SKIP_DIRS.has(entry.name) && !entry.name.startsWith(".")) {
3589
- const sub = this.countLanguages(join8(dir, entry.name), depth + 1, maxDepth);
3982
+ const sub = this.countLanguages(join9(dir, entry.name), depth + 1, maxDepth);
3590
3983
  for (const [lang, count] of sub) {
3591
3984
  counts.set(lang, (counts.get(lang) ?? 0) + count);
3592
3985
  }
@@ -3644,13 +4037,13 @@ var init_codebase_map = __esm({
3644
4037
  if (entry.isFile()) {
3645
4038
  files++;
3646
4039
  try {
3647
- const size = statSync3(join8(dir, entry.name)).size;
4040
+ const size = statSync3(join9(dir, entry.name)).size;
3648
4041
  estimatedLines += Math.ceil(size / 40);
3649
4042
  } catch {
3650
4043
  }
3651
4044
  } else if (entry.isDirectory() && !this.SKIP_DIRS.has(entry.name)) {
3652
4045
  dirs++;
3653
- const sub = this.countStats(join8(dir, entry.name), depth + 1, maxDepth);
4046
+ const sub = this.countStats(join9(dir, entry.name), depth + 1, maxDepth);
3654
4047
  files += sub.files;
3655
4048
  dirs += sub.dirs;
3656
4049
  estimatedLines += sub.estimatedLines;
@@ -3666,8 +4059,8 @@ var init_codebase_map = __esm({
3666
4059
 
3667
4060
  // packages/execution/dist/tools/diagnostic.js
3668
4061
  import { execSync as execSync4 } from "node:child_process";
3669
- import { existsSync as existsSync6, readFileSync as readFileSync5 } from "node:fs";
3670
- import { join as join9 } from "node:path";
4062
+ import { existsSync as existsSync7, readFileSync as readFileSync5 } from "node:fs";
4063
+ import { join as join10 } from "node:path";
3671
4064
  var DiagnosticTool;
3672
4065
  var init_diagnostic = __esm({
3673
4066
  "packages/execution/dist/tools/diagnostic.js"() {
@@ -3746,7 +4139,7 @@ var init_diagnostic = __esm({
3746
4139
  }
3747
4140
  detectSteps(dir) {
3748
4141
  const steps = /* @__PURE__ */ new Map();
3749
- const has = (p) => existsSync6(join9(dir, p));
4142
+ const has = (p) => existsSync7(join10(dir, p));
3750
4143
  if (has(".eslintrc.json") || has(".eslintrc.js") || has(".eslintrc.yml") || has("eslint.config.js") || has("eslint.config.mjs")) {
3751
4144
  steps.set("lint", "npx eslint . --max-warnings 0");
3752
4145
  } else if (has("biome.json") || has("biome.jsonc")) {
@@ -3761,7 +4154,7 @@ var init_diagnostic = __esm({
3761
4154
  steps.set("test", "npx jest --passWithNoTests");
3762
4155
  } else {
3763
4156
  try {
3764
- const pkg = JSON.parse(readFileSync5(join9(dir, "package.json"), "utf8"));
4157
+ const pkg = JSON.parse(readFileSync5(join10(dir, "package.json"), "utf8"));
3765
4158
  if (pkg.scripts?.test && pkg.scripts.test !== 'echo "Error: no test specified" && exit 1') {
3766
4159
  steps.set("test", "npm test");
3767
4160
  }
@@ -3769,7 +4162,7 @@ var init_diagnostic = __esm({
3769
4162
  }
3770
4163
  }
3771
4164
  try {
3772
- const pkg = JSON.parse(readFileSync5(join9(dir, "package.json"), "utf8"));
4165
+ const pkg = JSON.parse(readFileSync5(join10(dir, "package.json"), "utf8"));
3773
4166
  if (pkg.scripts?.build) {
3774
4167
  steps.set("build", "npm run build");
3775
4168
  }
@@ -3811,8 +4204,8 @@ ${err.stderr ?? ""}`.trim(),
3811
4204
 
3812
4205
  // packages/execution/dist/tools/git-info.js
3813
4206
  import { execSync as execSync5 } from "node:child_process";
3814
- import { existsSync as existsSync7 } from "node:fs";
3815
- import { join as join10 } from "node:path";
4207
+ import { existsSync as existsSync8 } from "node:fs";
4208
+ import { join as join11 } from "node:path";
3816
4209
  var GitInfoTool;
3817
4210
  var init_git_info = __esm({
3818
4211
  "packages/execution/dist/tools/git-info.js"() {
@@ -3847,7 +4240,7 @@ var init_git_info = __esm({
3847
4240
  const repoDir = args["path"] || this.workingDir;
3848
4241
  const showDiff = args["show_diff"] ?? false;
3849
4242
  const logCount = args["log_count"] ?? 5;
3850
- if (!existsSync7(join10(repoDir, ".git"))) {
4243
+ if (!existsSync8(join11(repoDir, ".git"))) {
3851
4244
  return {
3852
4245
  success: false,
3853
4246
  output: "",
@@ -4421,11 +4814,11 @@ var init_system_deps = __esm({
4421
4814
  });
4422
4815
 
4423
4816
  // packages/execution/dist/tools/image.js
4424
- import { existsSync as existsSync8, readFileSync as readFileSync6, statSync as statSync4 } from "node:fs";
4425
- import { resolve as resolve11, extname as extname2, basename } from "node:path";
4817
+ import { existsSync as existsSync9, readFileSync as readFileSync6, statSync as statSync4 } from "node:fs";
4818
+ import { resolve as resolve12, extname as extname2, basename as basename2 } from "node:path";
4426
4819
  import { execSync as execSync7 } from "node:child_process";
4427
4820
  import { tmpdir } from "node:os";
4428
- import { join as join11 } from "node:path";
4821
+ import { join as join12 } from "node:path";
4429
4822
  function isImagePath(path) {
4430
4823
  return IMAGE_EXTENSIONS.has(extname2(path).toLowerCase());
4431
4824
  }
@@ -4547,8 +4940,8 @@ var init_image = __esm({
4547
4940
  if (!rawPath) {
4548
4941
  return { success: false, output: "", error: "path is required", durationMs: 0 };
4549
4942
  }
4550
- const fullPath = resolve11(this.workingDir, rawPath);
4551
- if (!existsSync8(fullPath)) {
4943
+ const fullPath = resolve12(this.workingDir, rawPath);
4944
+ if (!existsSync9(fullPath)) {
4552
4945
  return { success: false, output: "", error: `File not found: ${rawPath}`, durationMs: Date.now() - start };
4553
4946
  }
4554
4947
  const stat5 = statSync4(fullPath);
@@ -4568,7 +4961,7 @@ var init_image = __esm({
4568
4961
  const dims = getImageDimensions(fullPath);
4569
4962
  const sizeKb = (stat5.size / 1024).toFixed(1);
4570
4963
  const parts = [
4571
- `File: ${basename(fullPath)}`,
4964
+ `File: ${basename2(fullPath)}`,
4572
4965
  `Size: ${sizeKb}KB`,
4573
4966
  `Format: ${mime}`
4574
4967
  ];
@@ -4616,7 +5009,7 @@ ${ocrText}`);
4616
5009
  }
4617
5010
  async execute(args) {
4618
5011
  const start = Date.now();
4619
- const outputPath = args["output_path"] ? resolve11(this.workingDir, String(args["output_path"])) : join11(tmpdir(), `oa-screenshot-${Date.now()}.png`);
5012
+ const outputPath = args["output_path"] ? resolve12(this.workingDir, String(args["output_path"])) : join12(tmpdir(), `oa-screenshot-${Date.now()}.png`);
4620
5013
  const delayMs = typeof args["delay_ms"] === "number" ? args["delay_ms"] : 0;
4621
5014
  const region = String(args["region"] ?? "full");
4622
5015
  if (delayMs > 0) {
@@ -4641,7 +5034,7 @@ ${ocrText}`);
4641
5034
  durationMs: Date.now() - start
4642
5035
  };
4643
5036
  }
4644
- if (!existsSync8(outputPath)) {
5037
+ if (!existsSync9(outputPath)) {
4645
5038
  return { success: false, output: "", error: "Screenshot file not created", durationMs: Date.now() - start };
4646
5039
  }
4647
5040
  const stat5 = statSync4(outputPath);
@@ -4749,8 +5142,8 @@ ${ocrText}`);
4749
5142
  if (!rawPath) {
4750
5143
  return { success: false, output: "", error: "path is required", durationMs: 0 };
4751
5144
  }
4752
- const fullPath = resolve11(this.workingDir, rawPath);
4753
- if (!existsSync8(fullPath)) {
5145
+ const fullPath = resolve12(this.workingDir, rawPath);
5146
+ if (!existsSync9(fullPath)) {
4754
5147
  return { success: false, output: "", error: `File not found: ${rawPath}`, durationMs: Date.now() - start };
4755
5148
  }
4756
5149
  if (!hasTesseract()) {
@@ -4765,7 +5158,7 @@ ${ocrText}`);
4765
5158
  if (region) {
4766
5159
  const [x, y, w, h] = region.split(",").map(Number);
4767
5160
  if (x != null && y != null && w != null && h != null) {
4768
- const croppedPath = join11(tmpdir(), `oa-ocr-crop-${Date.now()}.png`);
5161
+ const croppedPath = join12(tmpdir(), `oa-ocr-crop-${Date.now()}.png`);
4769
5162
  try {
4770
5163
  execSync7(`convert ${JSON.stringify(fullPath)} -crop ${w}x${h}+${x}+${y} +repage ${JSON.stringify(croppedPath)}`, { stdio: "pipe", timeout: 1e4 });
4771
5164
  inputPath = croppedPath;
@@ -4781,7 +5174,7 @@ ${ocrText}`);
4781
5174
  const lineCount = text.split("\n").length;
4782
5175
  return {
4783
5176
  success: true,
4784
- output: `OCR extracted ${lineCount} lines from ${basename(fullPath)}${region ? ` (region: ${region})` : ""}:
5177
+ output: `OCR extracted ${lineCount} lines from ${basename2(fullPath)}${region ? ` (region: ${region})` : ""}:
4785
5178
 
4786
5179
  ${text}`,
4787
5180
  durationMs: Date.now() - start
@@ -4809,15 +5202,15 @@ __export(custom_tool_exports, {
4809
5202
  loadCustomTools: () => loadCustomTools,
4810
5203
  saveCustomToolDefinition: () => saveCustomToolDefinition
4811
5204
  });
4812
- import { existsSync as existsSync9, readdirSync as readdirSync4, readFileSync as readFileSync7, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "node:fs";
4813
- import { join as join12 } from "node:path";
4814
- import { homedir as homedir3 } from "node:os";
5205
+ import { existsSync as existsSync10, readdirSync as readdirSync4, readFileSync as readFileSync7, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "node:fs";
5206
+ import { join as join13 } from "node:path";
5207
+ import { homedir as homedir4 } from "node:os";
4815
5208
  import { spawn as spawn3 } from "node:child_process";
4816
5209
  function globalToolsDir() {
4817
- return join12(homedir3(), ".open-agents", "tools");
5210
+ return join13(homedir4(), ".open-agents", "tools");
4818
5211
  }
4819
5212
  function projectToolsDir(repoRoot) {
4820
- return join12(repoRoot, ".oa", "tools");
5213
+ return join13(repoRoot, ".oa", "tools");
4821
5214
  }
4822
5215
  function loadCustomTools(repoRoot) {
4823
5216
  const definitions = /* @__PURE__ */ new Map();
@@ -4837,14 +5230,14 @@ function buildCustomTools(repoRoot) {
4837
5230
  function saveCustomToolDefinition(definition, scope, repoRoot) {
4838
5231
  const dir = scope === "project" && repoRoot ? projectToolsDir(repoRoot) : globalToolsDir();
4839
5232
  mkdirSync3(dir, { recursive: true });
4840
- const filePath = join12(dir, `${definition.name}.json`);
5233
+ const filePath = join13(dir, `${definition.name}.json`);
4841
5234
  writeFileSync3(filePath, JSON.stringify(definition, null, 2), "utf-8");
4842
5235
  return filePath;
4843
5236
  }
4844
5237
  function deleteCustomToolDefinition(name, scope, repoRoot) {
4845
5238
  const dir = scope === "project" && repoRoot ? projectToolsDir(repoRoot) : globalToolsDir();
4846
- const filePath = join12(dir, `${name}.json`);
4847
- if (existsSync9(filePath)) {
5239
+ const filePath = join13(dir, `${name}.json`);
5240
+ if (existsSync10(filePath)) {
4848
5241
  const { unlinkSync: unlinkSync5 } = __require("node:fs");
4849
5242
  unlinkSync5(filePath);
4850
5243
  return true;
@@ -4878,14 +5271,14 @@ function listCustomToolFiles(repoRoot) {
4878
5271
  return result;
4879
5272
  }
4880
5273
  function loadFromDirectory(dir) {
4881
- if (!existsSync9(dir))
5274
+ if (!existsSync10(dir))
4882
5275
  return [];
4883
5276
  const definitions = [];
4884
5277
  try {
4885
5278
  const files = readdirSync4(dir).filter((f) => f.endsWith(".json"));
4886
5279
  for (const file of files) {
4887
5280
  try {
4888
- const content = readFileSync7(join12(dir, file), "utf-8");
5281
+ const content = readFileSync7(join13(dir, file), "utf-8");
4889
5282
  const def = JSON.parse(content);
4890
5283
  if (def.name && def.description && Array.isArray(def.steps) && def.steps.length > 0) {
4891
5284
  if (!def.parameters || typeof def.parameters !== "object") {
@@ -4964,7 +5357,7 @@ var init_custom_tool = __esm({
4964
5357
  }
4965
5358
  /** Execute a single shell command and return output */
4966
5359
  runCommand(command) {
4967
- return new Promise((resolve22) => {
5360
+ return new Promise((resolve23) => {
4968
5361
  const child = spawn3("bash", ["-c", command], {
4969
5362
  cwd: this.workingDir,
4970
5363
  env: { ...process.env, CI: "true", NO_COLOR: "1" },
@@ -4989,11 +5382,11 @@ var init_custom_tool = __esm({
4989
5382
  child.kill("SIGTERM");
4990
5383
  } catch {
4991
5384
  }
4992
- resolve22({ success: false, output: stdout, error: "Command timed out after 60s" });
5385
+ resolve23({ success: false, output: stdout, error: "Command timed out after 60s" });
4993
5386
  }, 6e4);
4994
5387
  child.on("close", (code) => {
4995
5388
  clearTimeout(timer);
4996
- resolve22({
5389
+ resolve23({
4997
5390
  success: code === 0,
4998
5391
  output: stdout + (stderr && code === 0 ? `
4999
5392
  STDERR:
@@ -5003,7 +5396,7 @@ ${stderr}` : ""),
5003
5396
  });
5004
5397
  child.on("error", (err) => {
5005
5398
  clearTimeout(timer);
5006
- resolve22({ success: false, output: stdout, error: err.message });
5399
+ resolve23({ success: false, output: stdout, error: err.message });
5007
5400
  });
5008
5401
  });
5009
5402
  }
@@ -5306,16 +5699,16 @@ var init_tool_creator = __esm({
5306
5699
  });
5307
5700
 
5308
5701
  // packages/execution/dist/tools/skill-tools.js
5309
- import { existsSync as existsSync10, readdirSync as readdirSync5, readFileSync as readFileSync8 } from "node:fs";
5310
- import { join as join13, basename as basename2, dirname as dirname3 } from "node:path";
5311
- import { homedir as homedir4 } from "node:os";
5702
+ import { existsSync as existsSync11, readdirSync as readdirSync5, readFileSync as readFileSync8 } from "node:fs";
5703
+ import { join as join14, basename as basename3, dirname as dirname3 } from "node:path";
5704
+ import { homedir as homedir5 } from "node:os";
5312
5705
  import { execSync as execSync8 } from "node:child_process";
5313
5706
  function getAiwgPaths() {
5314
- const dataDir = join13(homedir4(), ".local", "share", "ai-writing-guide");
5707
+ const dataDir = join14(homedir5(), ".local", "share", "ai-writing-guide");
5315
5708
  return {
5316
- frameworksDir: join13(dataDir, "agentic", "code", "frameworks"),
5317
- addonsDir: join13(dataDir, "agentic", "code", "addons"),
5318
- pluginsDir: join13(dataDir, "plugins")
5709
+ frameworksDir: join14(dataDir, "agentic", "code", "frameworks"),
5710
+ addonsDir: join14(dataDir, "agentic", "code", "addons"),
5711
+ pluginsDir: join14(dataDir, "plugins")
5319
5712
  };
5320
5713
  }
5321
5714
  function findAiwgPackageRoot() {
@@ -5327,8 +5720,8 @@ function findAiwgPackageRoot() {
5327
5720
  timeout: 5e3,
5328
5721
  stdio: ["pipe", "pipe", "pipe"]
5329
5722
  }).trim();
5330
- const candidate = join13(globalRoot, "aiwg");
5331
- if (existsSync10(join13(candidate, "package.json"))) {
5723
+ const candidate = join14(globalRoot, "aiwg");
5724
+ if (existsSync11(join14(candidate, "package.json"))) {
5332
5725
  _cachedAiwgPkgRoot = candidate;
5333
5726
  return candidate;
5334
5727
  }
@@ -5337,18 +5730,18 @@ function findAiwgPackageRoot() {
5337
5730
  const candidates = [
5338
5731
  "/usr/local/lib/node_modules/aiwg",
5339
5732
  "/usr/lib/node_modules/aiwg",
5340
- join13(homedir4(), ".nvm", "versions")
5733
+ join14(homedir5(), ".nvm", "versions")
5341
5734
  // nvm — need to search deeper
5342
5735
  ];
5343
5736
  for (const c3 of candidates) {
5344
5737
  if (c3.includes(".nvm")) {
5345
- if (existsSync10(c3)) {
5738
+ if (existsSync11(c3)) {
5346
5739
  try {
5347
- for (const ver of readdirSync5(join13(c3, "node"), { withFileTypes: true })) {
5740
+ for (const ver of readdirSync5(join14(c3, "node"), { withFileTypes: true })) {
5348
5741
  if (!ver.isDirectory())
5349
5742
  continue;
5350
- const nvmPath = join13(c3, "node", ver.name, "lib", "node_modules", "aiwg");
5351
- if (existsSync10(join13(nvmPath, "package.json"))) {
5743
+ const nvmPath = join14(c3, "node", ver.name, "lib", "node_modules", "aiwg");
5744
+ if (existsSync11(join14(nvmPath, "package.json"))) {
5352
5745
  _cachedAiwgPkgRoot = nvmPath;
5353
5746
  return nvmPath;
5354
5747
  }
@@ -5356,7 +5749,7 @@ function findAiwgPackageRoot() {
5356
5749
  } catch {
5357
5750
  }
5358
5751
  }
5359
- } else if (existsSync10(join13(c3, "package.json"))) {
5752
+ } else if (existsSync11(join14(c3, "package.json"))) {
5360
5753
  _cachedAiwgPkgRoot = c3;
5361
5754
  return c3;
5362
5755
  }
@@ -5368,49 +5761,49 @@ function discoverSkills(repoRoot) {
5368
5761
  const skills = /* @__PURE__ */ new Map();
5369
5762
  const { frameworksDir, addonsDir, pluginsDir } = getAiwgPaths();
5370
5763
  const loadComponent = (componentDir, source) => {
5371
- loadSkillsFromDir(join13(componentDir, "skills"), source, skills);
5372
- loadCommandsFromDir(join13(componentDir, "commands"), source, skills);
5764
+ loadSkillsFromDir(join14(componentDir, "skills"), source, skills);
5765
+ loadCommandsFromDir(join14(componentDir, "commands"), source, skills);
5373
5766
  };
5374
5767
  const pkgRoot = findAiwgPackageRoot();
5375
5768
  if (pkgRoot) {
5376
- const pkgFrameworks = join13(pkgRoot, "agentic", "code", "frameworks");
5377
- if (existsSync10(pkgFrameworks)) {
5769
+ const pkgFrameworks = join14(pkgRoot, "agentic", "code", "frameworks");
5770
+ if (existsSync11(pkgFrameworks)) {
5378
5771
  for (const fw of safeReaddir(pkgFrameworks)) {
5379
- loadComponent(join13(pkgFrameworks, fw), `framework:${fw}`);
5772
+ loadComponent(join14(pkgFrameworks, fw), `framework:${fw}`);
5380
5773
  }
5381
5774
  }
5382
- const pkgAddons = join13(pkgRoot, "agentic", "code", "addons");
5383
- if (existsSync10(pkgAddons)) {
5775
+ const pkgAddons = join14(pkgRoot, "agentic", "code", "addons");
5776
+ if (existsSync11(pkgAddons)) {
5384
5777
  for (const addon of safeReaddir(pkgAddons)) {
5385
- loadComponent(join13(pkgAddons, addon), `addon:${addon}`);
5778
+ loadComponent(join14(pkgAddons, addon), `addon:${addon}`);
5386
5779
  }
5387
5780
  }
5388
- const pkgPlugins = join13(pkgRoot, "plugins");
5389
- if (existsSync10(pkgPlugins)) {
5781
+ const pkgPlugins = join14(pkgRoot, "plugins");
5782
+ if (existsSync11(pkgPlugins)) {
5390
5783
  for (const plugin of safeReaddir(pkgPlugins)) {
5391
- loadComponent(join13(pkgPlugins, plugin), `plugin:${plugin}`);
5784
+ loadComponent(join14(pkgPlugins, plugin), `plugin:${plugin}`);
5392
5785
  }
5393
5786
  }
5394
5787
  }
5395
- if (existsSync10(frameworksDir)) {
5788
+ if (existsSync11(frameworksDir)) {
5396
5789
  for (const framework of safeReaddir(frameworksDir)) {
5397
- loadComponent(join13(frameworksDir, framework), `framework:${framework}`);
5790
+ loadComponent(join14(frameworksDir, framework), `framework:${framework}`);
5398
5791
  }
5399
5792
  }
5400
- if (existsSync10(addonsDir)) {
5793
+ if (existsSync11(addonsDir)) {
5401
5794
  for (const addon of safeReaddir(addonsDir)) {
5402
- loadComponent(join13(addonsDir, addon), `addon:${addon}`);
5795
+ loadComponent(join14(addonsDir, addon), `addon:${addon}`);
5403
5796
  }
5404
5797
  }
5405
- if (existsSync10(pluginsDir)) {
5798
+ if (existsSync11(pluginsDir)) {
5406
5799
  for (const plugin of safeReaddir(pluginsDir)) {
5407
- loadComponent(join13(pluginsDir, plugin), `plugin:${plugin}`);
5800
+ loadComponent(join14(pluginsDir, plugin), `plugin:${plugin}`);
5408
5801
  }
5409
5802
  }
5410
- const projectAiwg = join13(repoRoot, ".aiwg");
5411
- loadSkillsFromDir(join13(projectAiwg, "skills"), "project", skills);
5412
- loadCommandsFromDir(join13(projectAiwg, "commands"), "project", skills);
5413
- const projectOaSkills = join13(repoRoot, ".oa", "skills");
5803
+ const projectAiwg = join14(repoRoot, ".aiwg");
5804
+ loadSkillsFromDir(join14(projectAiwg, "skills"), "project", skills);
5805
+ loadCommandsFromDir(join14(projectAiwg, "commands"), "project", skills);
5806
+ const projectOaSkills = join14(repoRoot, ".oa", "skills");
5414
5807
  loadSkillsFromDir(projectOaSkills, "local", skills);
5415
5808
  return Array.from(skills.values());
5416
5809
  }
@@ -5456,13 +5849,13 @@ function safeReaddir(dir) {
5456
5849
  }
5457
5850
  }
5458
5851
  function loadSkillsFromDir(dir, source, out) {
5459
- if (!existsSync10(dir))
5852
+ if (!existsSync11(dir))
5460
5853
  return;
5461
5854
  const manifest = loadManifest(dir);
5462
5855
  const entries = safeReaddir(dir);
5463
5856
  for (const entry of entries) {
5464
- const skillMd = join13(dir, entry, "SKILL.md");
5465
- if (!existsSync10(skillMd))
5857
+ const skillMd = join14(dir, entry, "SKILL.md");
5858
+ if (!existsSync11(skillMd))
5466
5859
  continue;
5467
5860
  const manifestEntry = manifest.get(entry);
5468
5861
  const info = {
@@ -5476,7 +5869,7 @@ function loadSkillsFromDir(dir, source, out) {
5476
5869
  }
5477
5870
  }
5478
5871
  function loadCommandsFromDir(dir, source, out) {
5479
- if (!existsSync10(dir))
5872
+ if (!existsSync11(dir))
5480
5873
  return;
5481
5874
  let entries;
5482
5875
  try {
@@ -5486,7 +5879,7 @@ function loadCommandsFromDir(dir, source, out) {
5486
5879
  }
5487
5880
  for (const file of entries) {
5488
5881
  const name = file.replace(/\.md$/, "");
5489
- const filePath = join13(dir, file);
5882
+ const filePath = join14(dir, file);
5490
5883
  if (out.has(name))
5491
5884
  continue;
5492
5885
  const info = {
@@ -5522,8 +5915,8 @@ function parseCommandTriggers(name) {
5522
5915
  }
5523
5916
  function loadManifest(dir) {
5524
5917
  const result = /* @__PURE__ */ new Map();
5525
- const manifestPath = join13(dir, "manifest.json");
5526
- if (!existsSync10(manifestPath))
5918
+ const manifestPath = join14(dir, "manifest.json");
5919
+ if (!existsSync11(manifestPath))
5527
5920
  return result;
5528
5921
  try {
5529
5922
  const content = readFileSync8(manifestPath, "utf-8");
@@ -5706,9 +6099,9 @@ ${content}`,
5706
6099
  });
5707
6100
 
5708
6101
  // packages/execution/dist/tools/transcribe-tool.js
5709
- import { existsSync as existsSync11, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4, readFileSync as readFileSync9, unlinkSync } from "node:fs";
5710
- import { join as join14, basename as basename3, extname as extname3, resolve as resolve12 } from "node:path";
5711
- import { homedir as homedir5 } from "node:os";
6102
+ import { existsSync as existsSync12, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4, readFileSync as readFileSync9, unlinkSync } from "node:fs";
6103
+ import { join as join15, basename as basename4, extname as extname3, resolve as resolve13 } from "node:path";
6104
+ import { homedir as homedir6 } from "node:os";
5712
6105
  import { execSync as execSync9, spawn as spawn4 } from "node:child_process";
5713
6106
  function isTranscribable(path) {
5714
6107
  const ext = extname3(path).toLowerCase();
@@ -5724,25 +6117,25 @@ async function loadTranscribeCli() {
5724
6117
  timeout: 5e3,
5725
6118
  stdio: ["pipe", "pipe", "pipe"]
5726
6119
  }).trim();
5727
- const tcPath = join14(globalRoot, "transcribe-cli");
5728
- if (existsSync11(join14(tcPath, "dist", "index.js"))) {
6120
+ const tcPath = join15(globalRoot, "transcribe-cli");
6121
+ if (existsSync12(join15(tcPath, "dist", "index.js"))) {
5729
6122
  const { createRequire: createRequire4 } = await import("node:module");
5730
6123
  const req = createRequire4(import.meta.url);
5731
- _tcModule = req(join14(tcPath, "dist", "index.js"));
6124
+ _tcModule = req(join15(tcPath, "dist", "index.js"));
5732
6125
  return _tcModule;
5733
6126
  }
5734
6127
  } catch {
5735
6128
  }
5736
- const nvmBase = join14(homedir5(), ".nvm", "versions", "node");
5737
- if (existsSync11(nvmBase)) {
6129
+ const nvmBase = join15(homedir6(), ".nvm", "versions", "node");
6130
+ if (existsSync12(nvmBase)) {
5738
6131
  try {
5739
6132
  const { readdirSync: readdirSync11 } = await import("node:fs");
5740
6133
  for (const ver of readdirSync11(nvmBase)) {
5741
- const tcPath = join14(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
5742
- if (existsSync11(join14(tcPath, "dist", "index.js"))) {
6134
+ const tcPath = join15(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
6135
+ if (existsSync12(join15(tcPath, "dist", "index.js"))) {
5743
6136
  const { createRequire: createRequire4 } = await import("node:module");
5744
6137
  const req = createRequire4(import.meta.url);
5745
- _tcModule = req(join14(tcPath, "dist", "index.js"));
6138
+ _tcModule = req(join15(tcPath, "dist", "index.js"));
5746
6139
  return _tcModule;
5747
6140
  }
5748
6141
  }
@@ -5811,10 +6204,10 @@ var init_transcribe_tool = __esm({
5811
6204
  }
5812
6205
  async execute(args) {
5813
6206
  const start = performance.now();
5814
- const filePath = resolve12(this.workingDir, String(args["path"] ?? ""));
6207
+ const filePath = resolve13(this.workingDir, String(args["path"] ?? ""));
5815
6208
  const model = String(args["model"] ?? "base");
5816
6209
  const diarize = Boolean(args["diarize"] ?? false);
5817
- if (!existsSync11(filePath)) {
6210
+ if (!existsSync12(filePath)) {
5818
6211
  return {
5819
6212
  success: false,
5820
6213
  output: "",
@@ -5841,12 +6234,12 @@ var init_transcribe_tool = __esm({
5841
6234
  diarize,
5842
6235
  wordTimestamps: false
5843
6236
  });
5844
- const transcriptDir = join14(this.workingDir, ".oa", "transcripts");
6237
+ const transcriptDir = join15(this.workingDir, ".oa", "transcripts");
5845
6238
  mkdirSync4(transcriptDir, { recursive: true });
5846
- const outFile = join14(transcriptDir, `${basename3(filePath)}.txt`);
6239
+ const outFile = join15(transcriptDir, `${basename4(filePath)}.txt`);
5847
6240
  writeFileSync4(outFile, result.text, "utf-8");
5848
6241
  const lines = [
5849
- `Transcription of: ${basename3(filePath)}`,
6242
+ `Transcription of: ${basename4(filePath)}`,
5850
6243
  `Model: ${model} | Language: ${result.language} | Duration: ${result.duration ? `${result.duration.toFixed(1)}s` : "unknown"}`,
5851
6244
  `Words: ${result.wordCount} | Saved to: ${outFile}`,
5852
6245
  ""
@@ -5941,14 +6334,14 @@ var init_transcribe_tool = __esm({
5941
6334
  durationMs: performance.now() - start
5942
6335
  };
5943
6336
  }
5944
- const tmpDir = join14(this.workingDir, ".oa", "tmp");
6337
+ const tmpDir = join15(this.workingDir, ".oa", "tmp");
5945
6338
  mkdirSync4(tmpDir, { recursive: true });
5946
6339
  const urlPath = new URL(url).pathname;
5947
6340
  let ext = extname3(urlPath).toLowerCase();
5948
6341
  if (!ext || !AUDIO_EXTS.has(ext) && !VIDEO_EXTS.has(ext)) {
5949
6342
  ext = ".mp3";
5950
6343
  }
5951
- const tmpFile = join14(tmpDir, `download-${Date.now()}${ext}`);
6344
+ const tmpFile = join15(tmpDir, `download-${Date.now()}${ext}`);
5952
6345
  try {
5953
6346
  try {
5954
6347
  execSync9(`curl -sL -o "${tmpFile}" "${url}"`, {
@@ -5961,7 +6354,7 @@ var init_transcribe_tool = __esm({
5961
6354
  stdio: ["pipe", "pipe", "pipe"]
5962
6355
  });
5963
6356
  }
5964
- if (!existsSync11(tmpFile)) {
6357
+ if (!existsSync12(tmpFile)) {
5965
6358
  return {
5966
6359
  success: false,
5967
6360
  output: "",
@@ -6001,7 +6394,7 @@ ${result.output}`,
6001
6394
 
6002
6395
  // packages/execution/dist/tools/structured-file.js
6003
6396
  import { writeFile as writeFile6, mkdir as mkdir3 } from "node:fs/promises";
6004
- import { resolve as resolve13, dirname as dirname4, extname as extname4 } from "node:path";
6397
+ import { resolve as resolve14, dirname as dirname4, extname as extname4 } from "node:path";
6005
6398
  function jsonToCSV(data, separator = ",") {
6006
6399
  if (!Array.isArray(data) || data.length === 0)
6007
6400
  return "";
@@ -6115,7 +6508,7 @@ var init_structured_file = __esm({
6115
6508
  }
6116
6509
  }
6117
6510
  try {
6118
- const fullPath = resolve13(this.workingDir, filePath);
6511
+ const fullPath = resolve14(this.workingDir, filePath);
6119
6512
  await mkdir3(dirname4(fullPath), { recursive: true });
6120
6513
  let content;
6121
6514
  let byteInfo = "";
@@ -6181,11 +6574,11 @@ var init_structured_file = __esm({
6181
6574
 
6182
6575
  // packages/execution/dist/tools/code-sandbox.js
6183
6576
  import { spawn as spawn5 } from "node:child_process";
6184
- import { writeFile as writeFile7, mkdtemp, rm, readdir, stat } from "node:fs/promises";
6185
- import { join as join15 } from "node:path";
6577
+ import { writeFile as writeFile7, mkdtemp, rm, readdir as readdir2, stat } from "node:fs/promises";
6578
+ import { join as join16 } from "node:path";
6186
6579
  import { tmpdir as tmpdir2 } from "node:os";
6187
6580
  function runProcess(cmd, args, options) {
6188
- return new Promise((resolve22) => {
6581
+ return new Promise((resolve23) => {
6189
6582
  const proc = spawn5(cmd, args, {
6190
6583
  cwd: options.cwd,
6191
6584
  timeout: options.timeout,
@@ -6215,7 +6608,7 @@ function runProcess(cmd, args, options) {
6215
6608
  }
6216
6609
  });
6217
6610
  proc.on("error", (err) => {
6218
- resolve22({
6611
+ resolve23({
6219
6612
  stdout,
6220
6613
  stderr: stderr || err.message,
6221
6614
  exitCode: 1,
@@ -6227,7 +6620,7 @@ function runProcess(cmd, args, options) {
6227
6620
  if (signal === "SIGTERM" || signal === "SIGKILL") {
6228
6621
  timedOut = true;
6229
6622
  }
6230
- resolve22({
6623
+ resolve23({
6231
6624
  stdout,
6232
6625
  stderr,
6233
6626
  exitCode: code ?? (timedOut ? 124 : 1),
@@ -6244,11 +6637,11 @@ function runProcess(cmd, args, options) {
6244
6637
  async function listCreatedFiles(dir) {
6245
6638
  const files = [];
6246
6639
  try {
6247
- const entries = await readdir(dir);
6640
+ const entries = await readdir2(dir);
6248
6641
  for (const entry of entries) {
6249
6642
  if (entry.startsWith("_sandbox_script"))
6250
6643
  continue;
6251
- const fullPath = join15(dir, entry);
6644
+ const fullPath = join16(dir, entry);
6252
6645
  const s = await stat(fullPath);
6253
6646
  if (s.isFile()) {
6254
6647
  files.push(entry);
@@ -6368,9 +6761,9 @@ ${result.filesCreated.join("\n")}`);
6368
6761
  // Subprocess mode — temp directory + separate process
6369
6762
  // -------------------------------------------------------------------------
6370
6763
  async #runSubprocess(code, langConfig, timeoutMs, stdin) {
6371
- const sandboxDir = await mkdtemp(join15(tmpdir2(), "oa-sandbox-"));
6764
+ const sandboxDir = await mkdtemp(join16(tmpdir2(), "oa-sandbox-"));
6372
6765
  try {
6373
- const scriptFile = join15(sandboxDir, `_sandbox_script${langConfig.ext}`);
6766
+ const scriptFile = join16(sandboxDir, `_sandbox_script${langConfig.ext}`);
6374
6767
  await writeFile7(scriptFile, code, "utf-8");
6375
6768
  const result = await runProcess(langConfig.cmd, langConfig.args(scriptFile), {
6376
6769
  cwd: sandboxDir,
@@ -6395,10 +6788,10 @@ ${result.filesCreated.join("\n")}`);
6395
6788
  bash: "bash:5"
6396
6789
  };
6397
6790
  const image = images[language] ?? "node:22-slim";
6398
- const sandboxDir = await mkdtemp(join15(tmpdir2(), "oa-docker-sandbox-"));
6791
+ const sandboxDir = await mkdtemp(join16(tmpdir2(), "oa-docker-sandbox-"));
6399
6792
  try {
6400
6793
  const scriptFile = `_sandbox_script${langConfig.ext}`;
6401
- await writeFile7(join15(sandboxDir, scriptFile), code, "utf-8");
6794
+ await writeFile7(join16(sandboxDir, scriptFile), code, "utf-8");
6402
6795
  const dockerArgs = [
6403
6796
  "run",
6404
6797
  "--rm",
@@ -6433,8 +6826,8 @@ ${result.filesCreated.join("\n")}`);
6433
6826
  });
6434
6827
 
6435
6828
  // packages/execution/dist/tools/structured-read.js
6436
- import { readFile as readFile7, stat as stat2 } from "node:fs/promises";
6437
- import { resolve as resolve14, extname as extname5 } from "node:path";
6829
+ import { readFile as readFile8, stat as stat2 } from "node:fs/promises";
6830
+ import { resolve as resolve15, extname as extname5 } from "node:path";
6438
6831
  function parseCSV(text, separator = ",") {
6439
6832
  const lines = text.split("\n").filter((l) => l.trim() !== "");
6440
6833
  if (lines.length < 2)
@@ -6575,7 +6968,7 @@ var init_structured_read = __esm({
6575
6968
  if (!filePath) {
6576
6969
  return { success: false, output: "", error: "path is required", durationMs: 0 };
6577
6970
  }
6578
- const fullPath = resolve14(this.workingDir, filePath);
6971
+ const fullPath = resolve15(this.workingDir, filePath);
6579
6972
  try {
6580
6973
  const fileStat = await stat2(fullPath);
6581
6974
  if (!fileStat.isFile()) {
@@ -6628,7 +7021,7 @@ var init_structured_read = __esm({
6628
7021
  }
6629
7022
  }
6630
7023
  if (format === "xlsx" || format === "pdf" || format === "docx" || format === "auto") {
6631
- const buffer = await readFile7(fullPath);
7024
+ const buffer = await readFile8(fullPath);
6632
7025
  const detected = detectBinaryFormat(buffer);
6633
7026
  if (detected === "xlsx") {
6634
7027
  return {
@@ -6673,7 +7066,7 @@ Or install mammoth for programmatic access.`,
6673
7066
  }
6674
7067
  }
6675
7068
  }
6676
- const text = await readFile7(fullPath, "utf-8");
7069
+ const text = await readFile8(fullPath, "utf-8");
6677
7070
  switch (format) {
6678
7071
  case "csv": {
6679
7072
  const rows = parseCSV(text, ",");
@@ -6768,9 +7161,9 @@ ${parts.join("\n\n")}`,
6768
7161
  });
6769
7162
 
6770
7163
  // packages/execution/dist/tools/vision.js
6771
- import { readFileSync as readFileSync10, existsSync as existsSync12, statSync as statSync5 } from "node:fs";
7164
+ import { readFileSync as readFileSync10, existsSync as existsSync13, statSync as statSync5 } from "node:fs";
6772
7165
  import { execSync as execSync10, spawn as spawn6 } from "node:child_process";
6773
- import { resolve as resolve15, extname as extname6, basename as basename4, dirname as dirname5, join as join16 } from "node:path";
7166
+ import { resolve as resolve16, extname as extname6, basename as basename5, dirname as dirname5, join as join17 } from "node:path";
6774
7167
  import { fileURLToPath as fileURLToPath2 } from "node:url";
6775
7168
  async function probeStation(endpoint) {
6776
7169
  try {
@@ -6785,24 +7178,24 @@ async function probeStation(endpoint) {
6785
7178
  }
6786
7179
  }
6787
7180
  function findStationBinary() {
6788
- const oaVenvPython = join16(process.env["HOME"] || "/root", ".open-agents", "venv", "bin", "python");
6789
- if (existsSync12(oaVenvPython)) {
7181
+ const oaVenvPython = join17(process.env["HOME"] || "/root", ".open-agents", "venv", "bin", "python");
7182
+ if (existsSync13(oaVenvPython)) {
6790
7183
  try {
6791
7184
  execSync10(`${JSON.stringify(oaVenvPython)} -c "import moondream_station"`, { stdio: "pipe", timeout: 5e3 });
6792
7185
  return oaVenvPython;
6793
7186
  } catch {
6794
7187
  }
6795
7188
  }
6796
- const oaVenvBin = join16(process.env["HOME"] || "/root", ".open-agents", "venv", "bin", "moondream-station");
6797
- if (existsSync12(oaVenvBin))
7189
+ const oaVenvBin = join17(process.env["HOME"] || "/root", ".open-agents", "venv", "bin", "moondream-station");
7190
+ if (existsSync13(oaVenvBin))
6798
7191
  return oaVenvBin;
6799
7192
  const thisDir = dirname5(fileURLToPath2(import.meta.url));
6800
7193
  const localVenvPaths = [
6801
- resolve15(thisDir, "../../../../.moondream-venv/bin/python"),
6802
- resolve15(thisDir, "../../../.moondream-venv/bin/python")
7194
+ resolve16(thisDir, "../../../../.moondream-venv/bin/python"),
7195
+ resolve16(thisDir, "../../../.moondream-venv/bin/python")
6803
7196
  ];
6804
7197
  for (const p of localVenvPaths) {
6805
- if (existsSync12(p)) {
7198
+ if (existsSync13(p)) {
6806
7199
  try {
6807
7200
  execSync10(`${JSON.stringify(p)} -c "import moondream_station"`, { stdio: "pipe", timeout: 5e3 });
6808
7201
  return p;
@@ -6823,8 +7216,8 @@ async function autoLaunchStation(port = 2020) {
6823
7216
  if (!pythonBin)
6824
7217
  return false;
6825
7218
  const thisDir = dirname5(fileURLToPath2(import.meta.url));
6826
- const launcherScript = resolve15(thisDir, "../../scripts/start-moondream.py");
6827
- if (!existsSync12(launcherScript))
7219
+ const launcherScript = resolve16(thisDir, "../../scripts/start-moondream.py");
7220
+ if (!existsSync13(launcherScript))
6828
7221
  return false;
6829
7222
  return new Promise((resolvePromise) => {
6830
7223
  const child = spawn6(pythonBin, [launcherScript, "--port", String(port)], {
@@ -6898,8 +7291,8 @@ Details: ${err.message}` : "");
6898
7291
  }
6899
7292
  }
6900
7293
  function loadImageBuffer(workingDir, rawPath) {
6901
- const fullPath = resolve15(workingDir, rawPath);
6902
- if (!existsSync12(fullPath)) {
7294
+ const fullPath = resolve16(workingDir, rawPath);
7295
+ if (!existsSync13(fullPath)) {
6903
7296
  throw new Error(`File not found: ${rawPath}`);
6904
7297
  }
6905
7298
  const stat5 = statSync5(fullPath);
@@ -6988,7 +7381,7 @@ var init_vision = __esm({
6988
7381
  }
6989
7382
  try {
6990
7383
  const { buffer, fullPath } = loadImageBuffer(this.workingDir, rawPath);
6991
- const filename = basename4(fullPath);
7384
+ const filename = basename5(fullPath);
6992
7385
  let client = null;
6993
7386
  try {
6994
7387
  client = await getMoondreamClient();
@@ -7138,10 +7531,10 @@ ${response}`, durationMs: performance.now() - start };
7138
7531
  });
7139
7532
 
7140
7533
  // packages/execution/dist/tools/desktop-click.js
7141
- import { readFileSync as readFileSync11, existsSync as existsSync13 } from "node:fs";
7534
+ import { readFileSync as readFileSync11, existsSync as existsSync14 } from "node:fs";
7142
7535
  import { execSync as execSync11 } from "node:child_process";
7143
7536
  import { tmpdir as tmpdir3 } from "node:os";
7144
- import { join as join17, dirname as dirname6 } from "node:path";
7537
+ import { join as join18, dirname as dirname6 } from "node:path";
7145
7538
  import { fileURLToPath as fileURLToPath3 } from "node:url";
7146
7539
  function hasCommand2(cmd) {
7147
7540
  try {
@@ -7203,7 +7596,7 @@ function captureScreenshot(outputPath) {
7203
7596
  } else {
7204
7597
  try {
7205
7598
  execSync11(`DISPLAY=:0 python3 -c "from PIL import ImageGrab; ImageGrab.grab().save(${JSON.stringify(outputPath)})"`, { stdio: "pipe", timeout: 1e4 });
7206
- if (existsSync13(outputPath))
7599
+ if (existsSync14(outputPath))
7207
7600
  return;
7208
7601
  } catch {
7209
7602
  }
@@ -7214,7 +7607,7 @@ function captureScreenshot(outputPath) {
7214
7607
  throw new Error("No screenshot tool found. Auto-install failed. Try manually: sudo apt install scrot");
7215
7608
  }
7216
7609
  execSync11(cmd, { stdio: "pipe", timeout: 1e4 });
7217
- if (!existsSync13(outputPath)) {
7610
+ if (!existsSync14(outputPath)) {
7218
7611
  throw new Error("Screenshot file was not created");
7219
7612
  }
7220
7613
  }
@@ -7265,7 +7658,7 @@ for i in range(${clicks}):
7265
7658
  } catch {
7266
7659
  }
7267
7660
  try {
7268
- const venvPy = join17(__dirname, "../../../../.moondream-venv/bin/python");
7661
+ const venvPy = join18(__dirname, "../../../../.moondream-venv/bin/python");
7269
7662
  execSync11(`DISPLAY=:0 ${JSON.stringify(venvPy)} -c "${pyScript}"`, { stdio: "pipe", timeout: 5e3 });
7270
7663
  return;
7271
7664
  } catch {
@@ -7357,7 +7750,7 @@ var init_desktop_click = __esm({
7357
7750
  if (delayMs > 0) {
7358
7751
  await new Promise((r) => setTimeout(r, delayMs));
7359
7752
  }
7360
- const screenshotPath = join17(tmpdir3(), `oa-desktop-click-${Date.now()}.png`);
7753
+ const screenshotPath = join18(tmpdir3(), `oa-desktop-click-${Date.now()}.png`);
7361
7754
  captureScreenshot(screenshotPath);
7362
7755
  const dims = getImageDimensions2(screenshotPath);
7363
7756
  if (!dims) {
@@ -7532,7 +7925,7 @@ Screenshot: ${screenshotPath}`,
7532
7925
  if (delayMs > 0) {
7533
7926
  await new Promise((r) => setTimeout(r, delayMs));
7534
7927
  }
7535
- const screenshotPath = join17(tmpdir3(), `oa-desktop-describe-${Date.now()}.png`);
7928
+ const screenshotPath = join18(tmpdir3(), `oa-desktop-describe-${Date.now()}.png`);
7536
7929
  captureScreenshot(screenshotPath);
7537
7930
  const dims = getImageDimensions2(screenshotPath);
7538
7931
  const imageBuffer = readFileSync11(screenshotPath);
@@ -7647,8 +8040,8 @@ Screen: ${dims.width}x${dims.height}`);
7647
8040
  });
7648
8041
 
7649
8042
  // packages/execution/dist/tools/ocr-pdf.js
7650
- import { existsSync as existsSync14, statSync as statSync6 } from "node:fs";
7651
- import { resolve as resolve16, basename as basename5 } from "node:path";
8043
+ import { existsSync as existsSync15, statSync as statSync6 } from "node:fs";
8044
+ import { resolve as resolve17, basename as basename6 } from "node:path";
7652
8045
  import { execSync as execSync12 } from "node:child_process";
7653
8046
  var OcrPdfTool;
7654
8047
  var init_ocr_pdf = __esm({
@@ -7698,8 +8091,8 @@ var init_ocr_pdf = __esm({
7698
8091
  if (!rawInput) {
7699
8092
  return { success: false, output: "", error: "input path is required", durationMs: 0 };
7700
8093
  }
7701
- const inputPath = resolve16(this.workingDir, rawInput);
7702
- if (!existsSync14(inputPath)) {
8094
+ const inputPath = resolve17(this.workingDir, rawInput);
8095
+ if (!existsSync15(inputPath)) {
7703
8096
  return { success: false, output: "", error: `File not found: ${rawInput}`, durationMs: performance.now() - start };
7704
8097
  }
7705
8098
  const stat5 = statSync6(inputPath);
@@ -7722,7 +8115,7 @@ var init_ocr_pdf = __esm({
7722
8115
  durationMs: performance.now() - start
7723
8116
  };
7724
8117
  }
7725
- const outputPath = rawOutput ? resolve16(this.workingDir, rawOutput) : inputPath;
8118
+ const outputPath = rawOutput ? resolve17(this.workingDir, rawOutput) : inputPath;
7726
8119
  const cmdParts = ["ocrmypdf"];
7727
8120
  cmdParts.push("-l", language);
7728
8121
  if (deskew)
@@ -7747,7 +8140,7 @@ var init_ocr_pdf = __esm({
7747
8140
  const sizeMB = (outputStat.size / 1024 / 1024).toFixed(1);
7748
8141
  return {
7749
8142
  success: true,
7750
- output: `OCR completed for ${basename5(inputPath)}
8143
+ output: `OCR completed for ${basename6(inputPath)}
7751
8144
  Output: ${outputPath === inputPath ? "(in-place)" : outputPath}
7752
8145
  Size: ${sizeMB}MB
7753
8146
  Language: ${language}
@@ -7770,8 +8163,8 @@ Language: ${language}
7770
8163
  });
7771
8164
 
7772
8165
  // packages/execution/dist/tools/pdf-to-text.js
7773
- import { existsSync as existsSync15, statSync as statSync7, readFileSync as readFileSync12, unlinkSync as unlinkSync2 } from "node:fs";
7774
- import { resolve as resolve17, basename as basename6, join as join18 } from "node:path";
8166
+ import { existsSync as existsSync16, statSync as statSync7, readFileSync as readFileSync12, unlinkSync as unlinkSync2 } from "node:fs";
8167
+ import { resolve as resolve18, basename as basename7, join as join19 } from "node:path";
7775
8168
  import { execSync as execSync13 } from "node:child_process";
7776
8169
  import { tmpdir as tmpdir4 } from "node:os";
7777
8170
  var PdfToTextTool;
@@ -7822,8 +8215,8 @@ var init_pdf_to_text = __esm({
7822
8215
  if (!rawPath) {
7823
8216
  return { success: false, output: "", error: "path is required", durationMs: 0 };
7824
8217
  }
7825
- const fullPath = resolve17(this.workingDir, rawPath);
7826
- if (!existsSync15(fullPath)) {
8218
+ const fullPath = resolve18(this.workingDir, rawPath);
8219
+ if (!existsSync16(fullPath)) {
7827
8220
  return { success: false, output: "", error: `File not found: ${rawPath}`, durationMs: performance.now() - start };
7828
8221
  }
7829
8222
  const fileStat = statSync7(fullPath);
@@ -7881,7 +8274,7 @@ var init_pdf_to_text = __esm({
7881
8274
  const pageInfo2 = pages ? ` (pages: ${pages})` : "";
7882
8275
  return {
7883
8276
  success: true,
7884
- output: `Extracted ${lineCount2} lines from ${basename6(fullPath)}${pageInfo2} (via OCR):
8277
+ output: `Extracted ${lineCount2} lines from ${basename7(fullPath)}${pageInfo2} (via OCR):
7885
8278
 
7886
8279
  ${text}`,
7887
8280
  durationMs: performance.now() - start
@@ -7889,14 +8282,14 @@ ${text}`,
7889
8282
  }
7890
8283
  return {
7891
8284
  success: true,
7892
- output: `No text found in ${basename6(fullPath)} \u2014 appears to be a scanned/image PDF with no extractable text. OCR also returned no results.`,
8285
+ output: `No text found in ${basename7(fullPath)} \u2014 appears to be a scanned/image PDF with no extractable text. OCR also returned no results.`,
7893
8286
  durationMs: performance.now() - start
7894
8287
  };
7895
8288
  }
7896
8289
  if (!text) {
7897
8290
  return {
7898
8291
  success: true,
7899
- output: `No text found in ${basename6(fullPath)} \u2014 may be a scanned/image PDF. Use ocr_pdf tool to add a text layer first.`,
8292
+ output: `No text found in ${basename7(fullPath)} \u2014 may be a scanned/image PDF. Use ocr_pdf tool to add a text layer first.`,
7900
8293
  durationMs: performance.now() - start
7901
8294
  };
7902
8295
  }
@@ -7904,7 +8297,7 @@ ${text}`,
7904
8297
  const pageInfo = pages ? ` (pages: ${pages})` : "";
7905
8298
  return {
7906
8299
  success: true,
7907
- output: `Extracted ${lineCount} lines from ${basename6(fullPath)}${pageInfo}:
8300
+ output: `Extracted ${lineCount} lines from ${basename7(fullPath)}${pageInfo}:
7908
8301
 
7909
8302
  ${text}`,
7910
8303
  durationMs: performance.now() - start
@@ -7925,7 +8318,7 @@ ${text}`,
7925
8318
  if (!ocrCheck.available || !tesCheck.available || !gsCheck.available) {
7926
8319
  return null;
7927
8320
  }
7928
- const tmpPdf = join18(tmpdir4(), `oa-ocr-${Date.now()}.pdf`);
8321
+ const tmpPdf = join19(tmpdir4(), `oa-ocr-${Date.now()}.pdf`);
7929
8322
  try {
7930
8323
  const ocrCmd = `ocrmypdf -l ${language} --skip-text ${JSON.stringify(inputPath)} ${JSON.stringify(tmpPdf)}`;
7931
8324
  execSync13(ocrCmd, { stdio: "pipe", timeout: 6e5 });
@@ -7955,27 +8348,27 @@ ${text}`,
7955
8348
  });
7956
8349
 
7957
8350
  // packages/execution/dist/tools/ocr-image-advanced.js
7958
- import { existsSync as existsSync16, statSync as statSync8 } from "node:fs";
7959
- import { resolve as resolve18, basename as basename7, dirname as dirname7, join as join19 } from "node:path";
8351
+ import { existsSync as existsSync17, statSync as statSync8 } from "node:fs";
8352
+ import { resolve as resolve19, basename as basename8, dirname as dirname7, join as join20 } from "node:path";
7960
8353
  import { execSync as execSync14 } from "node:child_process";
7961
8354
  import { fileURLToPath as fileURLToPath4 } from "node:url";
7962
- import { homedir as homedir6, tmpdir as tmpdir5 } from "node:os";
8355
+ import { homedir as homedir7, tmpdir as tmpdir5 } from "node:os";
7963
8356
  function findOcrScript() {
7964
8357
  const thisDir = dirname7(fileURLToPath4(import.meta.url));
7965
- const devPath = resolve18(thisDir, "../../scripts/ocr-advanced.py");
7966
- if (existsSync16(devPath))
8358
+ const devPath = resolve19(thisDir, "../../scripts/ocr-advanced.py");
8359
+ if (existsSync17(devPath))
7967
8360
  return devPath;
7968
- const bundledPath = resolve18(thisDir, "../scripts/ocr-advanced.py");
7969
- if (existsSync16(bundledPath))
8361
+ const bundledPath = resolve19(thisDir, "../scripts/ocr-advanced.py");
8362
+ if (existsSync17(bundledPath))
7970
8363
  return bundledPath;
7971
- const sameDirPath = resolve18(thisDir, "ocr-advanced.py");
7972
- if (existsSync16(sameDirPath))
8364
+ const sameDirPath = resolve19(thisDir, "ocr-advanced.py");
8365
+ if (existsSync17(sameDirPath))
7973
8366
  return sameDirPath;
7974
8367
  return null;
7975
8368
  }
7976
8369
  function findPython() {
7977
- const venvPython = join19(homedir6(), ".open-agents", "venv", "bin", "python");
7978
- if (existsSync16(venvPython)) {
8370
+ const venvPython = join20(homedir7(), ".open-agents", "venv", "bin", "python");
8371
+ if (existsSync17(venvPython)) {
7979
8372
  try {
7980
8373
  execSync14(`${JSON.stringify(venvPython)} -c "import cv2, pytesseract, numpy, PIL"`, {
7981
8374
  stdio: "pipe",
@@ -8058,8 +8451,8 @@ var init_ocr_image_advanced = __esm({
8058
8451
  if (!rawPath) {
8059
8452
  return { success: false, output: "", error: "image path is required", durationMs: 0 };
8060
8453
  }
8061
- const fullPath = resolve18(this.workingDir, rawPath);
8062
- if (!existsSync16(fullPath)) {
8454
+ const fullPath = resolve19(this.workingDir, rawPath);
8455
+ if (!existsSync17(fullPath)) {
8063
8456
  return { success: false, output: "", error: `File not found: ${rawPath}`, durationMs: performance.now() - start };
8064
8457
  }
8065
8458
  if (!batch) {
@@ -8117,10 +8510,10 @@ var init_ocr_image_advanced = __esm({
8117
8510
  if (batch)
8118
8511
  cmdParts.push("--batch");
8119
8512
  if (outputDir)
8120
- cmdParts.push("--output-dir", JSON.stringify(resolve18(this.workingDir, outputDir)));
8513
+ cmdParts.push("--output-dir", JSON.stringify(resolve19(this.workingDir, outputDir)));
8121
8514
  let debugDir;
8122
8515
  if (debug) {
8123
- debugDir = join19(tmpdir5(), `oa-ocr-debug-${Date.now()}`);
8516
+ debugDir = join20(tmpdir5(), `oa-ocr-debug-${Date.now()}`);
8124
8517
  cmdParts.push("--debug-dir", debugDir);
8125
8518
  }
8126
8519
  try {
@@ -8160,7 +8553,7 @@ var init_ocr_image_advanced = __esm({
8160
8553
  };
8161
8554
  }
8162
8555
  const parts = [];
8163
- parts.push(`OCR extracted from ${basename7(imagePath)} (${result.image_size})`);
8556
+ parts.push(`OCR extracted from ${basename8(imagePath)} (${result.image_size})`);
8164
8557
  parts.push(`Best variant: ${result.variant} (confidence: ${result.confidence}%, ${result.chars} chars, ${result.lines} lines, score: ${result.score})`);
8165
8558
  parts.push(`Variants tested: ${result.variants_tested}`);
8166
8559
  if (result.output_files) {
@@ -8219,7 +8612,7 @@ var init_ocr_image_advanced = __esm({
8219
8612
  if (region) {
8220
8613
  try {
8221
8614
  const [x, y, w, h] = region.split(",").map(Number);
8222
- const croppedPath = join19(tmpdir5(), `oa-ocr-crop-${Date.now()}.png`);
8615
+ const croppedPath = join20(tmpdir5(), `oa-ocr-crop-${Date.now()}.png`);
8223
8616
  execSync14(`convert ${JSON.stringify(imagePath)} -crop ${w}x${h}+${x}+${y} +repage ${JSON.stringify(croppedPath)}`, { stdio: "pipe", timeout: 1e4 });
8224
8617
  inputPath = croppedPath;
8225
8618
  } catch {
@@ -8231,14 +8624,14 @@ var init_ocr_image_advanced = __esm({
8231
8624
  if (!text) {
8232
8625
  return {
8233
8626
  success: true,
8234
- output: `(no text detected in ${basename7(imagePath)} \u2014 try the advanced Python OCR pipeline for better results)`,
8627
+ output: `(no text detected in ${basename8(imagePath)} \u2014 try the advanced Python OCR pipeline for better results)`,
8235
8628
  durationMs: performance.now() - start
8236
8629
  };
8237
8630
  }
8238
8631
  const lineCount = text.split("\n").length;
8239
8632
  return {
8240
8633
  success: true,
8241
- output: `OCR extracted ${lineCount} lines from ${basename7(imagePath)} (basic tesseract, PSM ${psmArg}):
8634
+ output: `OCR extracted ${lineCount} lines from ${basename8(imagePath)} (basic tesseract, PSM ${psmArg}):
8242
8635
  Note: Advanced Python pipeline not available \u2014 install pytesseract, opencv-python-headless, Pillow, numpy for better results.
8243
8636
 
8244
8637
  ` + text,
@@ -8347,6 +8740,8 @@ var init_dist2 = __esm({
8347
8740
  init_file_edit();
8348
8741
  init_memory_read();
8349
8742
  init_memory_write();
8743
+ init_memory_search();
8744
+ init_explore_tools();
8350
8745
  init_list_directory();
8351
8746
  init_aiwg_setup();
8352
8747
  init_aiwg_health();
@@ -9485,8 +9880,8 @@ var init_code_retriever = __esm({
9485
9880
  });
9486
9881
  }
9487
9882
  async getFileContent(filePath, startLine, endLine) {
9488
- const { readFile: readFile11 } = await import("node:fs/promises");
9489
- const content = await readFile11(filePath, "utf-8");
9883
+ const { readFile: readFile12 } = await import("node:fs/promises");
9884
+ const content = await readFile12(filePath, "utf-8");
9490
9885
  if (startLine === void 0)
9491
9886
  return content;
9492
9887
  const lines = content.split("\n");
@@ -9501,8 +9896,8 @@ var init_code_retriever = __esm({
9501
9896
  // packages/retrieval/dist/lexicalSearch.js
9502
9897
  import { execFile as execFile5 } from "node:child_process";
9503
9898
  import { promisify as promisify4 } from "node:util";
9504
- import { readFile as readFile8, readdir as readdir2, stat as stat3 } from "node:fs/promises";
9505
- import { join as join20, extname as extname7 } from "node:path";
9899
+ import { readFile as readFile9, readdir as readdir3, stat as stat3 } from "node:fs/promises";
9900
+ import { join as join21, extname as extname7 } from "node:path";
9506
9901
  async function searchByPath(pathPattern, options) {
9507
9902
  const allFiles = await collectFiles(options.rootDir, options.includeGlobs ?? DEFAULT_INCLUDE_GLOBS, options.excludeGlobs ?? DEFAULT_EXCLUDE_GLOBS);
9508
9903
  const pattern = options.caseInsensitive ? pathPattern.toLowerCase() : pathPattern;
@@ -9607,7 +10002,7 @@ async function searchWithNodeFallback(pattern, kind, options) {
9607
10002
  if (results.length >= maxMatches)
9608
10003
  break;
9609
10004
  try {
9610
- const content = await readFile8(filePath, "utf-8");
10005
+ const content = await readFile9(filePath, "utf-8");
9611
10006
  const contentLines = content.split("\n");
9612
10007
  for (let i = 0; i < contentLines.length; i++) {
9613
10008
  if (results.length >= maxMatches)
@@ -9635,7 +10030,7 @@ async function collectFiles(rootDir, includeGlobs, excludeGlobs) {
9635
10030
  async function walkForFiles(rootDir, dir, excludeGlobs, results) {
9636
10031
  let entries;
9637
10032
  try {
9638
- entries = await readdir2(dir, { withFileTypes: true, encoding: "utf-8" });
10033
+ entries = await readdir3(dir, { withFileTypes: true, encoding: "utf-8" });
9639
10034
  } catch {
9640
10035
  return;
9641
10036
  }
@@ -9644,7 +10039,7 @@ async function walkForFiles(rootDir, dir, excludeGlobs, results) {
9644
10039
  continue;
9645
10040
  if (excludeGlobs.some((g) => entry.name === g || matchesGlob(entry.name, g)))
9646
10041
  continue;
9647
- const absPath = join20(dir, entry.name);
10042
+ const absPath = join21(dir, entry.name);
9648
10043
  if (entry.isDirectory()) {
9649
10044
  await walkForFiles(rootDir, absPath, excludeGlobs, results);
9650
10045
  } else if (entry.isFile()) {
@@ -9688,6 +10083,55 @@ var init_lexicalSearch = __esm({
9688
10083
  });
9689
10084
 
9690
10085
  // packages/retrieval/dist/semanticSearch.js
10086
+ function parseTagFilter(query) {
10087
+ const required = [];
10088
+ const anyOf = [];
10089
+ const excluded = [];
10090
+ const cleanParts = [];
10091
+ for (const token of query.split(/\s+/)) {
10092
+ if (token.startsWith("+") && token.length > 1) {
10093
+ required.push(token.slice(1).toLowerCase());
10094
+ } else if (token.startsWith("~") && token.length > 1) {
10095
+ anyOf.push(token.slice(1).toLowerCase());
10096
+ } else if (token.startsWith("-") && token.length > 1 && !/^\d/.test(token.slice(1))) {
10097
+ excluded.push(token.slice(1).toLowerCase());
10098
+ } else {
10099
+ cleanParts.push(token);
10100
+ }
10101
+ }
10102
+ const hasFilter = required.length > 0 || anyOf.length > 0 || excluded.length > 0;
10103
+ return {
10104
+ cleanQuery: cleanParts.join(" "),
10105
+ tagFilter: hasFilter ? { required, anyOf, excluded } : null
10106
+ };
10107
+ }
10108
+ function matchesTagFilter(text, filter) {
10109
+ const lowerText = text.toLowerCase();
10110
+ const clusteringTags = /* @__PURE__ */ new Set();
10111
+ for (const match of lowerText.matchAll(/clustering:(\S+)/g)) {
10112
+ clusteringTags.add(match[1]);
10113
+ }
10114
+ const domainMatch = lowerText.match(/domain:\s*(\S+)/);
10115
+ if (domainMatch)
10116
+ clusteringTags.add(domainMatch[1]);
10117
+ const riskMatch = lowerText.match(/risk:\s*(\S+)/);
10118
+ if (riskMatch)
10119
+ clusteringTags.add(riskMatch[1]);
10120
+ for (const tag of filter.required) {
10121
+ if (!clusteringTags.has(tag) && !lowerText.includes(tag))
10122
+ return false;
10123
+ }
10124
+ if (filter.anyOf.length > 0) {
10125
+ const hasAny = filter.anyOf.some((tag) => clusteringTags.has(tag) || lowerText.includes(tag));
10126
+ if (!hasAny)
10127
+ return false;
10128
+ }
10129
+ for (const tag of filter.excluded) {
10130
+ if (clusteringTags.has(tag))
10131
+ return false;
10132
+ }
10133
+ return true;
10134
+ }
9691
10135
  function cosineSimilarity(a, b) {
9692
10136
  if (a.length !== b.length || a.length === 0)
9693
10137
  return 0;
@@ -9713,7 +10157,7 @@ function makePlaceholderSummary(filePath) {
9713
10157
  lastIndexed: (/* @__PURE__ */ new Date()).toISOString()
9714
10158
  };
9715
10159
  }
9716
- var StubSemanticSearchEngine, IndexBackedSemanticSearchEngine;
10160
+ var StubSemanticSearchEngine, IndexBackedSemanticSearchEngine, LazySemanticSearchEngine;
9717
10161
  var init_semanticSearch = __esm({
9718
10162
  "packages/retrieval/dist/semanticSearch.js"() {
9719
10163
  "use strict";
@@ -9734,11 +10178,26 @@ var init_semanticSearch = __esm({
9734
10178
  if (!this.isAvailable)
9735
10179
  return [];
9736
10180
  const queryVector = await this.options.embedQuery(query);
10181
+ const { cleanQuery, tagFilter } = parseTagFilter(query);
10182
+ const searchVector = cleanQuery !== query ? await this.options.embedQuery(cleanQuery) : queryVector;
9737
10183
  const scored = this.options.index.map((item) => ({
9738
10184
  filePath: item.filePath,
9739
- score: cosineSimilarity(queryVector, item.vector)
10185
+ score: cosineSimilarity(searchVector, item.vector),
10186
+ text: item.text
9740
10187
  }));
9741
- return scored.sort((a, b) => b.score - a.score).slice(0, topK).map(({ filePath, score }) => {
10188
+ let filtered = scored;
10189
+ if (tagFilter) {
10190
+ filtered = scored.filter((item) => matchesTagFilter(item.text, tagFilter));
10191
+ }
10192
+ const byFile = /* @__PURE__ */ new Map();
10193
+ for (const item of filtered) {
10194
+ const existing = byFile.get(item.filePath);
10195
+ if (!existing || item.score > existing.score) {
10196
+ byFile.set(item.filePath, item);
10197
+ }
10198
+ }
10199
+ const deduped = Array.from(byFile.values());
10200
+ return deduped.sort((a, b) => b.score - a.score).slice(0, topK).map(({ filePath, score }) => {
9742
10201
  const summary = this.options.summaryMap.get(filePath);
9743
10202
  return {
9744
10203
  filePath,
@@ -9748,6 +10207,74 @@ var init_semanticSearch = __esm({
9748
10207
  };
9749
10208
  });
9750
10209
  }
10210
+ /**
10211
+ * Pattern 7: Find semantically related items in the index.
10212
+ * Returns pairs of items with >threshold similarity.
10213
+ * Useful for auto-linking related memories/files.
10214
+ */
10215
+ findRelated(filePath, threshold = 0.7, maxResults = 5) {
10216
+ const sourceItem = this.options.index.find((i) => i.filePath === filePath);
10217
+ if (!sourceItem)
10218
+ return [];
10219
+ const scored = this.options.index.filter((i) => i.filePath !== filePath).map((item) => ({
10220
+ filePath: item.filePath,
10221
+ score: cosineSimilarity(sourceItem.vector, item.vector)
10222
+ })).filter((r) => r.score >= threshold).sort((a, b) => b.score - a.score).slice(0, maxResults);
10223
+ return scored;
10224
+ }
10225
+ };
10226
+ LazySemanticSearchEngine = class {
10227
+ inner = null;
10228
+ buildPromise = null;
10229
+ buildFailed = false;
10230
+ opts;
10231
+ constructor(opts) {
10232
+ this.opts = opts;
10233
+ }
10234
+ get isAvailable() {
10235
+ return this.inner?.isAvailable ?? false;
10236
+ }
10237
+ /**
10238
+ * Trigger index building in the background.
10239
+ * Call this during idle time to pre-warm the index.
10240
+ */
10241
+ warmUp() {
10242
+ if (!this.buildPromise && !this.inner && !this.buildFailed) {
10243
+ this.buildPromise = this.build();
10244
+ }
10245
+ }
10246
+ async search(query, topK = 10) {
10247
+ if (this.inner)
10248
+ return this.inner.search(query, topK);
10249
+ if (this.buildFailed)
10250
+ return [];
10251
+ if (!this.buildPromise) {
10252
+ this.buildPromise = this.build();
10253
+ }
10254
+ const timeoutMs = this.opts.timeoutMs ?? 6e4;
10255
+ try {
10256
+ await Promise.race([
10257
+ this.buildPromise,
10258
+ new Promise((_, reject) => setTimeout(() => reject(new Error("Index build timeout")), timeoutMs))
10259
+ ]);
10260
+ } catch {
10261
+ return [];
10262
+ }
10263
+ return this.searchInner(query, topK);
10264
+ }
10265
+ searchInner(query, topK) {
10266
+ if (this.inner)
10267
+ return this.inner.search(query, topK);
10268
+ return Promise.resolve([]);
10269
+ }
10270
+ async build() {
10271
+ try {
10272
+ const options = await this.opts.buildIndex();
10273
+ this.inner = new IndexBackedSemanticSearchEngine(options);
10274
+ } catch {
10275
+ this.buildFailed = true;
10276
+ }
10277
+ }
9751
10278
  };
9752
10279
  }
9753
10280
  });
@@ -9818,8 +10345,8 @@ var init_graphExpand = __esm({
9818
10345
  });
9819
10346
 
9820
10347
  // packages/retrieval/dist/snippetPacker.js
9821
- import { readFile as readFile9 } from "node:fs/promises";
9822
- import { join as join21 } from "node:path";
10348
+ import { readFile as readFile10 } from "node:fs/promises";
10349
+ import { join as join22 } from "node:path";
9823
10350
  async function packSnippets(requests, opts = {}) {
9824
10351
  const maxTokens = opts.maxTokens ?? DEFAULT_MAX_TOKENS;
9825
10352
  const contextLines = opts.contextLines ?? DEFAULT_CONTEXT_LINES;
@@ -9845,10 +10372,10 @@ async function packSnippets(requests, opts = {}) {
9845
10372
  return { packed, dropped, totalTokens };
9846
10373
  }
9847
10374
  async function extractSnippet(req, repoRoot, contextLines = DEFAULT_CONTEXT_LINES) {
9848
- const absPath = req.filePath.startsWith("/") ? req.filePath : join21(repoRoot, req.filePath);
10375
+ const absPath = req.filePath.startsWith("/") ? req.filePath : join22(repoRoot, req.filePath);
9849
10376
  let content;
9850
10377
  try {
9851
- content = await readFile9(absPath, "utf-8");
10378
+ content = await readFile10(absPath, "utf-8");
9852
10379
  } catch {
9853
10380
  return null;
9854
10381
  }
@@ -9904,24 +10431,41 @@ async function assembleContext(request, opts) {
9904
10431
  Promise.all(request.errorHint.slice(0, maxLogs).map((e) => searchByError(e, { rootDir: repoRoot, maxMatches: 5 }))).then((res) => res.flat()),
9905
10432
  semanticEngine?.isAvailable ? semanticEngine.search(request.query, maxFiles) : Promise.resolve([])
9906
10433
  ]);
9907
- const seenFiles = /* @__PURE__ */ new Set();
9908
- const candidateFiles = [];
9909
- function addCandidate(relativePath, priority) {
9910
- if (seenFiles.has(relativePath))
9911
- return;
9912
- seenFiles.add(relativePath);
9913
- candidateFiles.push({ relativePath, priority });
9914
- }
10434
+ const queryType = classifyQuery(request.query);
10435
+ const rrfK = adaptiveK(queryType, opts.rrfConfig?.k);
10436
+ const wFts = opts.rrfConfig?.weightFts ?? 1;
10437
+ const wSem = opts.rrfConfig?.weightSemantic ?? 1;
10438
+ const lexicalCandidates = [];
9915
10439
  for (const m of pathMatches)
9916
- addCandidate(m.relativePath, 100);
10440
+ lexicalCandidates.push({ relativePath: m.relativePath, basePriority: 100 });
9917
10441
  for (const m of symbolMatches)
9918
- addCandidate(m.relativePath, 80);
9919
- for (const r of semanticResults) {
9920
- addCandidate(r.filePath, Math.round(50 + r.score * 30));
9921
- }
10442
+ lexicalCandidates.push({ relativePath: m.relativePath, basePriority: 80 });
9922
10443
  for (const m of errorMatches)
9923
- addCandidate(m.relativePath, 40);
9924
- const topFiles = candidateFiles.sort((a, b) => b.priority - a.priority).slice(0, maxFiles);
10444
+ lexicalCandidates.push({ relativePath: m.relativePath, basePriority: 40 });
10445
+ const lexDedup = /* @__PURE__ */ new Map();
10446
+ for (const c3 of lexicalCandidates) {
10447
+ const existing = lexDedup.get(c3.relativePath) ?? 0;
10448
+ lexDedup.set(c3.relativePath, Math.max(existing, c3.basePriority));
10449
+ }
10450
+ const lexRanked = Array.from(lexDedup.entries()).sort((a, b) => b[1] - a[1]).map(([path], idx) => ({ path, rank: idx + 1 }));
10451
+ const semRanked = semanticResults.sort((a, b) => b.score - a.score).map((r, idx) => ({ path: r.filePath, rank: idx + 1, score: r.score }));
10452
+ const rrfScores = /* @__PURE__ */ new Map();
10453
+ const lexRankMap = new Map(lexRanked.map((l) => [l.path, l.rank]));
10454
+ const semRankMap = new Map(semRanked.map((s) => [s.path, s.rank]));
10455
+ const allPaths = /* @__PURE__ */ new Set([...lexRankMap.keys(), ...semRankMap.keys()]);
10456
+ for (const p of allPaths) {
10457
+ const lexRank = lexRankMap.get(p);
10458
+ const semRank = semRankMap.get(p);
10459
+ let score = 0;
10460
+ if (lexRank !== void 0)
10461
+ score += wFts / (rrfK + lexRank);
10462
+ if (semRank !== void 0)
10463
+ score += wSem / (rrfK + semRank);
10464
+ rrfScores.set(p, score);
10465
+ }
10466
+ const candidateFiles = Array.from(rrfScores.entries()).sort((a, b) => b[1] - a[1]).map(([relativePath, priority]) => ({ relativePath, priority: Math.round(priority * 1e3) }));
10467
+ const seenFiles = new Set(candidateFiles.map((c3) => c3.relativePath));
10468
+ const topFiles = candidateFiles.slice(0, maxFiles);
9925
10469
  const neighborFiles = [];
9926
10470
  if (expandNeighbors && graph) {
9927
10471
  const seedPaths = topFiles.map((f) => f.relativePath);
@@ -9966,6 +10510,39 @@ async function assembleContext(request, opts) {
9966
10510
  assembledAt: (/* @__PURE__ */ new Date()).toISOString()
9967
10511
  };
9968
10512
  }
10513
+ function classifyQuery(query) {
10514
+ const trimmed = query.trim();
10515
+ if (/^["'].*["']$/.test(trimmed) || /"[^"]+"/.test(trimmed))
10516
+ return "quoted";
10517
+ if (/(?:error|exception|stack|traceback|ENOENT|EPERM|TypeError|SyntaxError)/i.test(trimmed))
10518
+ return "error";
10519
+ if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(trimmed))
10520
+ return "symbol";
10521
+ const wordCount = trimmed.split(/\s+/).length;
10522
+ if (wordCount <= 3)
10523
+ return "short";
10524
+ return "long";
10525
+ }
10526
+ function adaptiveK(queryType, overrideK) {
10527
+ if (overrideK !== void 0)
10528
+ return overrideK;
10529
+ switch (queryType) {
10530
+ case "short":
10531
+ return 30;
10532
+ // tight — top results matter more
10533
+ case "quoted":
10534
+ return 20;
10535
+ // very tight — exact match should win
10536
+ case "symbol":
10537
+ return 25;
10538
+ // tight — symbol search is precise
10539
+ case "error":
10540
+ return 40;
10541
+ // moderate — errors need breadth
10542
+ case "long":
10543
+ return 60;
10544
+ }
10545
+ }
9969
10546
  function buildSymbolSnippets(symbolMatches, maxSnippets) {
9970
10547
  const byFile = /* @__PURE__ */ new Map();
9971
10548
  for (const m of symbolMatches) {
@@ -10008,8 +10585,10 @@ __export(dist_exports, {
10008
10585
  CodeRetriever: () => CodeRetriever,
10009
10586
  GrepSearch: () => GrepSearch,
10010
10587
  IndexBackedSemanticSearchEngine: () => IndexBackedSemanticSearchEngine,
10588
+ LazySemanticSearchEngine: () => LazySemanticSearchEngine,
10011
10589
  StubSemanticSearchEngine: () => StubSemanticSearchEngine,
10012
10590
  assembleContext: () => assembleContext,
10591
+ classifyQuery: () => classifyQuery,
10013
10592
  estimatePacketTokens: () => estimatePacketTokens,
10014
10593
  estimateTokens: () => estimateTokens,
10015
10594
  expandGraph: () => expandGraph,
@@ -10017,6 +10596,7 @@ __export(dist_exports, {
10017
10596
  oneHopNeighbors: () => oneHopNeighbors,
10018
10597
  packFiles: () => packFiles,
10019
10598
  packSnippets: () => packSnippets,
10599
+ parseTagFilter: () => parseTagFilter,
10020
10600
  searchByError: () => searchByError,
10021
10601
  searchByPath: () => searchByPath,
10022
10602
  searchByQuery: () => searchByQuery,
@@ -11451,8 +12031,8 @@ Rules:
11451
12031
  async waitIfPaused() {
11452
12032
  if (!this._paused)
11453
12033
  return true;
11454
- await new Promise((resolve22) => {
11455
- this._pauseResolve = resolve22;
12034
+ await new Promise((resolve23) => {
12035
+ this._pauseResolve = resolve23;
11456
12036
  });
11457
12037
  return !this.aborted;
11458
12038
  }
@@ -11709,6 +12289,15 @@ Integrate this guidance into your current approach. Continue working on the task
11709
12289
  }
11710
12290
  }
11711
12291
  }
12292
+ if (tc.name === "explore_tools" && result.success && result.output.startsWith("UNLOCK_TOOL:")) {
12293
+ const unlockName = result.output.slice("UNLOCK_TOOL:".length).trim();
12294
+ const existingTool = this.tools.get(unlockName);
12295
+ if (existingTool) {
12296
+ result = { success: true, output: `Tool '${unlockName}' is now unlocked and available. You can use it in your next response.` };
12297
+ } else {
12298
+ result = { success: false, output: "", error: `Unknown tool '${unlockName}'. Call explore_tools() with no args to see available tools.` };
12299
+ }
12300
+ }
11712
12301
  const { toolOutputMaxChars: maxLen } = this.contextLimits();
11713
12302
  const output = result.success ? result.output.length > maxLen ? this.foldOutput(result.output, maxLen) : result.output : `Error: ${result.error || "unknown error"}
11714
12303
  ${result.output.length > maxLen ? this.foldOutput(result.output, maxLen) : result.output}`;
@@ -12020,14 +12609,14 @@ ${result.output}`;
12020
12609
  waitForSudoPassword(timeoutMs = 12e4) {
12021
12610
  if (this._sudoPassword)
12022
12611
  return Promise.resolve(this._sudoPassword);
12023
- return new Promise((resolve22) => {
12612
+ return new Promise((resolve23) => {
12024
12613
  const timer = setTimeout(() => {
12025
12614
  this._sudoResolve = null;
12026
- resolve22(null);
12615
+ resolve23(null);
12027
12616
  }, timeoutMs);
12028
12617
  this._sudoResolve = (pw) => {
12029
12618
  clearTimeout(timer);
12030
- resolve22(pw);
12619
+ resolve23(pw);
12031
12620
  };
12032
12621
  });
12033
12622
  }
@@ -12150,8 +12739,8 @@ ${marker}` : marker);
12150
12739
  return;
12151
12740
  try {
12152
12741
  const { mkdirSync: mkdirSync13, writeFileSync: writeFileSync12 } = __require("node:fs");
12153
- const { join: join36 } = __require("node:path");
12154
- const sessionDir = join36(this._workingDirectory, ".oa", "session", this._sessionId);
12742
+ const { join: join37 } = __require("node:path");
12743
+ const sessionDir = join37(this._workingDirectory, ".oa", "session", this._sessionId);
12155
12744
  mkdirSync13(sessionDir, { recursive: true });
12156
12745
  const checkpoint = {
12157
12746
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -12164,7 +12753,7 @@ ${marker}` : marker);
12164
12753
  memexEntryCount: this._memexArchive.size,
12165
12754
  fileRegistrySize: this._fileRegistry.size
12166
12755
  };
12167
- writeFileSync12(join36(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
12756
+ writeFileSync12(join37(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
12168
12757
  } catch {
12169
12758
  }
12170
12759
  }
@@ -13697,9 +14286,9 @@ var init_dist5 = __esm({
13697
14286
 
13698
14287
  // packages/cli/dist/tui/listen.js
13699
14288
  import { spawn as spawn7, execSync as execSync15 } from "node:child_process";
13700
- import { existsSync as existsSync17, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5, readdirSync as readdirSync6 } from "node:fs";
13701
- import { join as join22, dirname as dirname8 } from "node:path";
13702
- import { homedir as homedir7 } from "node:os";
14289
+ import { existsSync as existsSync18, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5, readdirSync as readdirSync6 } from "node:fs";
14290
+ import { join as join23, dirname as dirname8 } from "node:path";
14291
+ import { homedir as homedir8 } from "node:os";
13703
14292
  import { fileURLToPath as fileURLToPath5 } from "node:url";
13704
14293
  import { EventEmitter } from "node:events";
13705
14294
  import { createInterface as createInterface2 } from "node:readline";
@@ -13784,15 +14373,15 @@ function findMicCaptureCommand() {
13784
14373
  function findLiveWhisperScript() {
13785
14374
  const thisDir = dirname8(fileURLToPath5(import.meta.url));
13786
14375
  const candidates = [
13787
- join22(thisDir, "../../../../packages/execution/scripts/live-whisper.py"),
13788
- join22(thisDir, "../../../packages/execution/scripts/live-whisper.py"),
13789
- join22(thisDir, "../../execution/scripts/live-whisper.py"),
14376
+ join23(thisDir, "../../../../packages/execution/scripts/live-whisper.py"),
14377
+ join23(thisDir, "../../../packages/execution/scripts/live-whisper.py"),
14378
+ join23(thisDir, "../../execution/scripts/live-whisper.py"),
13790
14379
  // npm install layout — scripts bundled alongside dist
13791
- join22(thisDir, "../scripts/live-whisper.py"),
13792
- join22(thisDir, "../../scripts/live-whisper.py")
14380
+ join23(thisDir, "../scripts/live-whisper.py"),
14381
+ join23(thisDir, "../../scripts/live-whisper.py")
13793
14382
  ];
13794
14383
  for (const p of candidates) {
13795
- if (existsSync17(p))
14384
+ if (existsSync18(p))
13796
14385
  return p;
13797
14386
  }
13798
14387
  try {
@@ -13802,21 +14391,21 @@ function findLiveWhisperScript() {
13802
14391
  stdio: ["pipe", "pipe", "pipe"]
13803
14392
  }).trim();
13804
14393
  const candidates2 = [
13805
- join22(globalRoot, "open-agents-ai", "dist", "scripts", "live-whisper.py"),
13806
- join22(globalRoot, "open-agents-ai", "scripts", "live-whisper.py")
14394
+ join23(globalRoot, "open-agents-ai", "dist", "scripts", "live-whisper.py"),
14395
+ join23(globalRoot, "open-agents-ai", "scripts", "live-whisper.py")
13807
14396
  ];
13808
14397
  for (const p of candidates2) {
13809
- if (existsSync17(p))
14398
+ if (existsSync18(p))
13810
14399
  return p;
13811
14400
  }
13812
14401
  } catch {
13813
14402
  }
13814
- const nvmBase = join22(homedir7(), ".nvm", "versions", "node");
13815
- if (existsSync17(nvmBase)) {
14403
+ const nvmBase = join23(homedir8(), ".nvm", "versions", "node");
14404
+ if (existsSync18(nvmBase)) {
13816
14405
  try {
13817
14406
  for (const ver of readdirSync6(nvmBase)) {
13818
- const p = join22(nvmBase, ver, "lib", "node_modules", "open-agents-ai", "dist", "scripts", "live-whisper.py");
13819
- if (existsSync17(p))
14407
+ const p = join23(nvmBase, ver, "lib", "node_modules", "open-agents-ai", "dist", "scripts", "live-whisper.py");
14408
+ if (existsSync18(p))
13820
14409
  return p;
13821
14410
  }
13822
14411
  } catch {
@@ -13834,16 +14423,16 @@ function ensureTranscribeCliBackground() {
13834
14423
  timeout: 5e3,
13835
14424
  stdio: ["pipe", "pipe", "pipe"]
13836
14425
  }).trim();
13837
- if (existsSync17(join22(globalRoot, "transcribe-cli", "dist", "index.js"))) {
14426
+ if (existsSync18(join23(globalRoot, "transcribe-cli", "dist", "index.js"))) {
13838
14427
  return true;
13839
14428
  }
13840
14429
  } catch {
13841
14430
  }
13842
14431
  try {
13843
14432
  const { exec } = await import("node:child_process");
13844
- return new Promise((resolve22) => {
14433
+ return new Promise((resolve23) => {
13845
14434
  exec("npm i -g transcribe-cli", { timeout: 18e4 }, (err) => {
13846
- resolve22(!err);
14435
+ resolve23(!err);
13847
14436
  });
13848
14437
  });
13849
14438
  } catch {
@@ -13896,7 +14485,7 @@ var init_listen = __esm({
13896
14485
  return this._ready;
13897
14486
  }
13898
14487
  async start() {
13899
- return new Promise((resolve22, reject) => {
14488
+ return new Promise((resolve23, reject) => {
13900
14489
  const timeout = setTimeout(() => {
13901
14490
  reject(new Error("Whisper fallback: model load timeout (5 min). First run downloads the model."));
13902
14491
  }, 3e5);
@@ -13924,7 +14513,7 @@ var init_listen = __esm({
13924
14513
  this._ready = true;
13925
14514
  clearTimeout(timeout);
13926
14515
  this.emit("ready");
13927
- resolve22();
14516
+ resolve23();
13928
14517
  break;
13929
14518
  case "transcript":
13930
14519
  this.emit("transcript", {
@@ -14051,24 +14640,24 @@ var init_listen = __esm({
14051
14640
  timeout: 5e3,
14052
14641
  stdio: ["pipe", "pipe", "pipe"]
14053
14642
  }).trim();
14054
- const tcPath = join22(globalRoot, "transcribe-cli");
14055
- if (existsSync17(join22(tcPath, "dist", "index.js"))) {
14643
+ const tcPath = join23(globalRoot, "transcribe-cli");
14644
+ if (existsSync18(join23(tcPath, "dist", "index.js"))) {
14056
14645
  const { createRequire: createRequire4 } = await import("node:module");
14057
14646
  const req = createRequire4(import.meta.url);
14058
- return req(join22(tcPath, "dist", "index.js"));
14647
+ return req(join23(tcPath, "dist", "index.js"));
14059
14648
  }
14060
14649
  } catch {
14061
14650
  }
14062
- const nvmBase = join22(homedir7(), ".nvm", "versions", "node");
14063
- if (existsSync17(nvmBase)) {
14651
+ const nvmBase = join23(homedir8(), ".nvm", "versions", "node");
14652
+ if (existsSync18(nvmBase)) {
14064
14653
  try {
14065
14654
  const { readdirSync: readdirSync11 } = await import("node:fs");
14066
14655
  for (const ver of readdirSync11(nvmBase)) {
14067
- const tcPath = join22(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
14068
- if (existsSync17(join22(tcPath, "dist", "index.js"))) {
14656
+ const tcPath = join23(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
14657
+ if (existsSync18(join23(tcPath, "dist", "index.js"))) {
14069
14658
  const { createRequire: createRequire4 } = await import("node:module");
14070
14659
  const req = createRequire4(import.meta.url);
14071
- return req(join22(tcPath, "dist", "index.js"));
14660
+ return req(join23(tcPath, "dist", "index.js"));
14072
14661
  }
14073
14662
  }
14074
14663
  } catch {
@@ -14128,11 +14717,11 @@ var init_listen = __esm({
14128
14717
  this.liveTranscriber.on("error", (err) => {
14129
14718
  this.emit("error", err);
14130
14719
  });
14131
- await new Promise((resolve22, reject) => {
14720
+ await new Promise((resolve23, reject) => {
14132
14721
  const timeout = setTimeout(() => reject(new Error("Model load timeout (60s)")), 6e4);
14133
14722
  this.liveTranscriber.on("ready", () => {
14134
14723
  clearTimeout(timeout);
14135
- resolve22();
14724
+ resolve23();
14136
14725
  });
14137
14726
  this.liveTranscriber.on("error", (err) => {
14138
14727
  clearTimeout(timeout);
@@ -14293,10 +14882,10 @@ transcribe-cli error: ${transcribeCliError}` : "";
14293
14882
  wordTimestamps: false
14294
14883
  });
14295
14884
  if (outputDir) {
14296
- const { basename: basename13 } = await import("node:path");
14297
- const transcriptDir = join22(outputDir, ".oa", "transcripts");
14885
+ const { basename: basename14 } = await import("node:path");
14886
+ const transcriptDir = join23(outputDir, ".oa", "transcripts");
14298
14887
  mkdirSync5(transcriptDir, { recursive: true });
14299
- const outFile = join22(transcriptDir, `${basename13(filePath)}.txt`);
14888
+ const outFile = join23(transcriptDir, `${basename14(filePath)}.txt`);
14300
14889
  writeFileSync5(outFile, result.text, "utf-8");
14301
14890
  }
14302
14891
  return {
@@ -15568,7 +16157,7 @@ Approach this task thoughtfully:
15568
16157
  });
15569
16158
 
15570
16159
  // packages/prompts/dist/index.js
15571
- import { join as join23, dirname as dirname9 } from "node:path";
16160
+ import { join as join24, dirname as dirname9 } from "node:path";
15572
16161
  import { fileURLToPath as fileURLToPath6 } from "node:url";
15573
16162
  var _dir, _packageRoot;
15574
16163
  var init_dist6 = __esm({
@@ -15579,28 +16168,28 @@ var init_dist6 = __esm({
15579
16168
  init_task_templates();
15580
16169
  init_render2();
15581
16170
  _dir = dirname9(fileURLToPath6(import.meta.url));
15582
- _packageRoot = join23(_dir, "..");
16171
+ _packageRoot = join24(_dir, "..");
15583
16172
  }
15584
16173
  });
15585
16174
 
15586
16175
  // packages/cli/dist/tui/oa-directory.js
15587
- import { existsSync as existsSync18, mkdirSync as mkdirSync6, readFileSync as readFileSync13, writeFileSync as writeFileSync6, readdirSync as readdirSync7, statSync as statSync9, unlinkSync as unlinkSync3 } from "node:fs";
15588
- import { join as join24, relative as relative2, basename as basename8, extname as extname8 } from "node:path";
15589
- import { homedir as homedir8 } from "node:os";
16176
+ import { existsSync as existsSync19, mkdirSync as mkdirSync6, readFileSync as readFileSync13, writeFileSync as writeFileSync6, readdirSync as readdirSync7, statSync as statSync9, unlinkSync as unlinkSync3 } from "node:fs";
16177
+ import { join as join25, relative as relative2, basename as basename9, extname as extname8 } from "node:path";
16178
+ import { homedir as homedir9 } from "node:os";
15590
16179
  function initOaDirectory(repoRoot) {
15591
- const oaPath = join24(repoRoot, OA_DIR);
16180
+ const oaPath = join25(repoRoot, OA_DIR);
15592
16181
  for (const sub of SUBDIRS) {
15593
- mkdirSync6(join24(oaPath, sub), { recursive: true });
16182
+ mkdirSync6(join25(oaPath, sub), { recursive: true });
15594
16183
  }
15595
16184
  return oaPath;
15596
16185
  }
15597
16186
  function hasOaDirectory(repoRoot) {
15598
- return existsSync18(join24(repoRoot, OA_DIR, "index"));
16187
+ return existsSync19(join25(repoRoot, OA_DIR, "index"));
15599
16188
  }
15600
16189
  function loadProjectSettings(repoRoot) {
15601
- const settingsPath = join24(repoRoot, OA_DIR, "settings.json");
16190
+ const settingsPath = join25(repoRoot, OA_DIR, "settings.json");
15602
16191
  try {
15603
- if (existsSync18(settingsPath)) {
16192
+ if (existsSync19(settingsPath)) {
15604
16193
  return JSON.parse(readFileSync13(settingsPath, "utf-8"));
15605
16194
  }
15606
16195
  } catch {
@@ -15608,16 +16197,16 @@ function loadProjectSettings(repoRoot) {
15608
16197
  return {};
15609
16198
  }
15610
16199
  function saveProjectSettings(repoRoot, settings) {
15611
- const oaPath = join24(repoRoot, OA_DIR);
16200
+ const oaPath = join25(repoRoot, OA_DIR);
15612
16201
  mkdirSync6(oaPath, { recursive: true });
15613
16202
  const existing = loadProjectSettings(repoRoot);
15614
16203
  const merged = { ...existing, ...settings };
15615
- writeFileSync6(join24(oaPath, "settings.json"), JSON.stringify(merged, null, 2) + "\n", "utf-8");
16204
+ writeFileSync6(join25(oaPath, "settings.json"), JSON.stringify(merged, null, 2) + "\n", "utf-8");
15616
16205
  }
15617
16206
  function loadGlobalSettings() {
15618
- const settingsPath = join24(homedir8(), ".open-agents", "settings.json");
16207
+ const settingsPath = join25(homedir9(), ".open-agents", "settings.json");
15619
16208
  try {
15620
- if (existsSync18(settingsPath)) {
16209
+ if (existsSync19(settingsPath)) {
15621
16210
  return JSON.parse(readFileSync13(settingsPath, "utf-8"));
15622
16211
  }
15623
16212
  } catch {
@@ -15625,11 +16214,11 @@ function loadGlobalSettings() {
15625
16214
  return {};
15626
16215
  }
15627
16216
  function saveGlobalSettings(settings) {
15628
- const dir = join24(homedir8(), ".open-agents");
16217
+ const dir = join25(homedir9(), ".open-agents");
15629
16218
  mkdirSync6(dir, { recursive: true });
15630
16219
  const existing = loadGlobalSettings();
15631
16220
  const merged = { ...existing, ...settings };
15632
- writeFileSync6(join24(dir, "settings.json"), JSON.stringify(merged, null, 2) + "\n", "utf-8");
16221
+ writeFileSync6(join25(dir, "settings.json"), JSON.stringify(merged, null, 2) + "\n", "utf-8");
15633
16222
  }
15634
16223
  function resolveSettings(repoRoot) {
15635
16224
  const global = loadGlobalSettings();
@@ -15644,9 +16233,9 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
15644
16233
  while (dir && !visited.has(dir)) {
15645
16234
  visited.add(dir);
15646
16235
  for (const name of CONTEXT_FILES) {
15647
- const filePath = join24(dir, name);
16236
+ const filePath = join25(dir, name);
15648
16237
  const normalizedName = name.toLowerCase();
15649
- if (existsSync18(filePath) && !seen.has(filePath)) {
16238
+ if (existsSync19(filePath) && !seen.has(filePath)) {
15650
16239
  seen.add(filePath);
15651
16240
  try {
15652
16241
  let content = readFileSync13(filePath, "utf-8");
@@ -15663,8 +16252,8 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
15663
16252
  }
15664
16253
  }
15665
16254
  }
15666
- const projectMap = join24(dir, OA_DIR, "context", "project-map.md");
15667
- if (existsSync18(projectMap) && !seen.has(projectMap)) {
16255
+ const projectMap = join25(dir, OA_DIR, "context", "project-map.md");
16256
+ if (existsSync19(projectMap) && !seen.has(projectMap)) {
15668
16257
  seen.add(projectMap);
15669
16258
  try {
15670
16259
  let content = readFileSync13(projectMap, "utf-8");
@@ -15679,7 +16268,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
15679
16268
  } catch {
15680
16269
  }
15681
16270
  }
15682
- const parent = join24(dir, "..");
16271
+ const parent = join25(dir, "..");
15683
16272
  if (parent === dir)
15684
16273
  break;
15685
16274
  dir = parent;
@@ -15697,7 +16286,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
15697
16286
  return found;
15698
16287
  }
15699
16288
  function readIndexMeta(repoRoot) {
15700
- const metaPath = join24(repoRoot, OA_DIR, "index", "meta.json");
16289
+ const metaPath = join25(repoRoot, OA_DIR, "index", "meta.json");
15701
16290
  try {
15702
16291
  return JSON.parse(readFileSync13(metaPath, "utf-8"));
15703
16292
  } catch {
@@ -15706,7 +16295,7 @@ function readIndexMeta(repoRoot) {
15706
16295
  }
15707
16296
  function generateProjectMap(repoRoot) {
15708
16297
  const sections = [];
15709
- const repoName2 = basename8(repoRoot);
16298
+ const repoName2 = basename9(repoRoot);
15710
16299
  sections.push(`# Project Map: ${repoName2}
15711
16300
  `);
15712
16301
  sections.push(`> Auto-generated by open-agents. Updated: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}
@@ -15750,28 +16339,28 @@ ${tree}\`\`\`
15750
16339
  sections.push("");
15751
16340
  }
15752
16341
  const content = sections.join("\n");
15753
- const contextDir = join24(repoRoot, OA_DIR, "context");
16342
+ const contextDir = join25(repoRoot, OA_DIR, "context");
15754
16343
  mkdirSync6(contextDir, { recursive: true });
15755
- writeFileSync6(join24(contextDir, "project-map.md"), content, "utf-8");
16344
+ writeFileSync6(join25(contextDir, "project-map.md"), content, "utf-8");
15756
16345
  return content;
15757
16346
  }
15758
16347
  function saveSession(repoRoot, session) {
15759
- const historyDir = join24(repoRoot, OA_DIR, "history");
16348
+ const historyDir = join25(repoRoot, OA_DIR, "history");
15760
16349
  mkdirSync6(historyDir, { recursive: true });
15761
- writeFileSync6(join24(historyDir, `${session.id}.json`), JSON.stringify(session, null, 2), "utf-8");
16350
+ writeFileSync6(join25(historyDir, `${session.id}.json`), JSON.stringify(session, null, 2), "utf-8");
15762
16351
  }
15763
16352
  function loadRecentSessions(repoRoot, limit = 5) {
15764
- const historyDir = join24(repoRoot, OA_DIR, "history");
15765
- if (!existsSync18(historyDir))
16353
+ const historyDir = join25(repoRoot, OA_DIR, "history");
16354
+ if (!existsSync19(historyDir))
15766
16355
  return [];
15767
16356
  try {
15768
16357
  const files = readdirSync7(historyDir).filter((f) => f.endsWith(".json") && f !== "pending-task.json").map((f) => {
15769
- const stat5 = statSync9(join24(historyDir, f));
16358
+ const stat5 = statSync9(join25(historyDir, f));
15770
16359
  return { file: f, mtime: stat5.mtimeMs };
15771
16360
  }).sort((a, b) => b.mtime - a.mtime).slice(0, limit);
15772
16361
  return files.map((f) => {
15773
16362
  try {
15774
- return JSON.parse(readFileSync13(join24(historyDir, f.file), "utf-8"));
16363
+ return JSON.parse(readFileSync13(join25(historyDir, f.file), "utf-8"));
15775
16364
  } catch {
15776
16365
  return null;
15777
16366
  }
@@ -15781,14 +16370,14 @@ function loadRecentSessions(repoRoot, limit = 5) {
15781
16370
  }
15782
16371
  }
15783
16372
  function savePendingTask(repoRoot, task) {
15784
- const historyDir = join24(repoRoot, OA_DIR, "history");
16373
+ const historyDir = join25(repoRoot, OA_DIR, "history");
15785
16374
  mkdirSync6(historyDir, { recursive: true });
15786
- writeFileSync6(join24(historyDir, PENDING_TASK_FILE), JSON.stringify(task, null, 2) + "\n", "utf-8");
16375
+ writeFileSync6(join25(historyDir, PENDING_TASK_FILE), JSON.stringify(task, null, 2) + "\n", "utf-8");
15787
16376
  }
15788
16377
  function loadPendingTask(repoRoot) {
15789
- const filePath = join24(repoRoot, OA_DIR, "history", PENDING_TASK_FILE);
16378
+ const filePath = join25(repoRoot, OA_DIR, "history", PENDING_TASK_FILE);
15790
16379
  try {
15791
- if (!existsSync18(filePath))
16380
+ if (!existsSync19(filePath))
15792
16381
  return null;
15793
16382
  const data = JSON.parse(readFileSync13(filePath, "utf-8"));
15794
16383
  try {
@@ -15801,12 +16390,12 @@ function loadPendingTask(repoRoot) {
15801
16390
  }
15802
16391
  }
15803
16392
  function saveSessionContext(repoRoot, entry) {
15804
- const contextDir = join24(repoRoot, OA_DIR, "context");
16393
+ const contextDir = join25(repoRoot, OA_DIR, "context");
15805
16394
  mkdirSync6(contextDir, { recursive: true });
15806
- const filePath = join24(contextDir, CONTEXT_SAVE_FILE);
16395
+ const filePath = join25(contextDir, CONTEXT_SAVE_FILE);
15807
16396
  let ctx;
15808
16397
  try {
15809
- if (existsSync18(filePath)) {
16398
+ if (existsSync19(filePath)) {
15810
16399
  ctx = JSON.parse(readFileSync13(filePath, "utf-8"));
15811
16400
  } else {
15812
16401
  ctx = { entries: [], maxEntries: MAX_CONTEXT_ENTRIES, updatedAt: "" };
@@ -15822,9 +16411,9 @@ function saveSessionContext(repoRoot, entry) {
15822
16411
  writeFileSync6(filePath, JSON.stringify(ctx, null, 2) + "\n", "utf-8");
15823
16412
  }
15824
16413
  function loadSessionContext(repoRoot) {
15825
- const filePath = join24(repoRoot, OA_DIR, "context", CONTEXT_SAVE_FILE);
16414
+ const filePath = join25(repoRoot, OA_DIR, "context", CONTEXT_SAVE_FILE);
15826
16415
  try {
15827
- if (!existsSync18(filePath))
16416
+ if (!existsSync19(filePath))
15828
16417
  return null;
15829
16418
  return JSON.parse(readFileSync13(filePath, "utf-8"));
15830
16419
  } catch {
@@ -15873,8 +16462,8 @@ function detectManifests(repoRoot) {
15873
16462
  { file: "docker-compose.yaml", type: "Docker Compose" }
15874
16463
  ];
15875
16464
  for (const check of checks) {
15876
- const filePath = join24(repoRoot, check.file);
15877
- if (existsSync18(filePath)) {
16465
+ const filePath = join25(repoRoot, check.file);
16466
+ if (existsSync19(filePath)) {
15878
16467
  let name;
15879
16468
  if (check.nameField) {
15880
16469
  try {
@@ -15907,7 +16496,7 @@ function findKeyFiles(repoRoot) {
15907
16496
  { pattern: "CLAUDE.md", description: "Claude Code context" }
15908
16497
  ];
15909
16498
  for (const check of checks) {
15910
- if (existsSync18(join24(repoRoot, check.pattern))) {
16499
+ if (existsSync19(join25(repoRoot, check.pattern))) {
15911
16500
  keyFiles.push({ path: check.pattern, description: check.description });
15912
16501
  }
15913
16502
  }
@@ -15933,12 +16522,12 @@ function buildDirTree(root, maxDepth, prefix = "", depth = 0) {
15933
16522
  if (entry.isDirectory()) {
15934
16523
  let fileCount = 0;
15935
16524
  try {
15936
- fileCount = readdirSync7(join24(root, entry.name)).filter((f) => !f.startsWith(".")).length;
16525
+ fileCount = readdirSync7(join25(root, entry.name)).filter((f) => !f.startsWith(".")).length;
15937
16526
  } catch {
15938
16527
  }
15939
16528
  result += `${prefix}${connector}${entry.name}/ (${fileCount})
15940
16529
  `;
15941
- result += buildDirTree(join24(root, entry.name), maxDepth, childPrefix, depth + 1);
16530
+ result += buildDirTree(join25(root, entry.name), maxDepth, childPrefix, depth + 1);
15942
16531
  } else if (depth < maxDepth) {
15943
16532
  result += `${prefix}${connector}${entry.name}
15944
16533
  `;
@@ -15992,9 +16581,9 @@ var init_oa_directory = __esm({
15992
16581
  // packages/cli/dist/tui/setup.js
15993
16582
  import * as readline from "node:readline";
15994
16583
  import { execSync as execSync16, spawn as spawn8 } from "node:child_process";
15995
- import { existsSync as existsSync19, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "node:fs";
15996
- import { join as join25 } from "node:path";
15997
- import { homedir as homedir9, platform } from "node:os";
16584
+ import { existsSync as existsSync20, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "node:fs";
16585
+ import { join as join26 } from "node:path";
16586
+ import { homedir as homedir10, platform } from "node:os";
15998
16587
  function detectSystemSpecs() {
15999
16588
  let totalRamGB = 0;
16000
16589
  let availableRamGB = 0;
@@ -16077,8 +16666,8 @@ function modelSupportsToolCalling(modelName) {
16077
16666
  return false;
16078
16667
  }
16079
16668
  function ask(rl, question) {
16080
- return new Promise((resolve22) => {
16081
- rl.question(question, (answer) => resolve22(answer.trim()));
16669
+ return new Promise((resolve23) => {
16670
+ rl.question(question, (answer) => resolve23(answer.trim()));
16082
16671
  });
16083
16672
  }
16084
16673
  async function autoInstallOllama(rl) {
@@ -16145,7 +16734,7 @@ async function installOllamaMac(rl) {
16145
16734
  execSync16('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"', { stdio: "inherit", timeout: 6e5 });
16146
16735
  if (!hasCmd("brew")) {
16147
16736
  try {
16148
- const brewPrefix = existsSync19("/opt/homebrew/bin/brew") ? "/opt/homebrew" : "/usr/local";
16737
+ const brewPrefix = existsSync20("/opt/homebrew/bin/brew") ? "/opt/homebrew" : "/usr/local";
16149
16738
  process.env["PATH"] = `${brewPrefix}/bin:${process.env["PATH"]}`;
16150
16739
  } catch {
16151
16740
  }
@@ -16436,7 +17025,7 @@ async function doSetup(config, rl) {
16436
17025
  try {
16437
17026
  const child = spawn8("ollama", ["serve"], { stdio: "ignore", detached: true });
16438
17027
  child.unref();
16439
- await new Promise((resolve22) => setTimeout(resolve22, 3e3));
17028
+ await new Promise((resolve23) => setTimeout(resolve23, 3e3));
16440
17029
  try {
16441
17030
  models = await fetchOllamaModels(config.backendUrl);
16442
17031
  process.stdout.write(` ${c2.green("\u2714")} Ollama is running.
@@ -16464,7 +17053,7 @@ async function doSetup(config, rl) {
16464
17053
  try {
16465
17054
  const child = spawn8("ollama", ["serve"], { stdio: "ignore", detached: true });
16466
17055
  child.unref();
16467
- await new Promise((resolve22) => setTimeout(resolve22, 3e3));
17056
+ await new Promise((resolve23) => setTimeout(resolve23, 3e3));
16468
17057
  try {
16469
17058
  models = await fetchOllamaModels(config.backendUrl);
16470
17059
  process.stdout.write(` ${c2.green("\u2714")} Ollama is running.
@@ -16619,9 +17208,9 @@ async function doSetup(config, rl) {
16619
17208
  `PARAMETER num_predict ${numPredict}`,
16620
17209
  `PARAMETER stop "<|endoftext|>"`
16621
17210
  ].join("\n");
16622
- const modelDir2 = join25(homedir9(), ".open-agents", "models");
17211
+ const modelDir2 = join26(homedir10(), ".open-agents", "models");
16623
17212
  mkdirSync7(modelDir2, { recursive: true });
16624
- const modelfilePath = join25(modelDir2, `Modelfile.${customName}`);
17213
+ const modelfilePath = join26(modelDir2, `Modelfile.${customName}`);
16625
17214
  writeFileSync7(modelfilePath, modelfileContent + "\n", "utf8");
16626
17215
  process.stdout.write(` ${c2.dim("Creating model...")} `);
16627
17216
  execSync16(`ollama create ${customName} -f ${modelfilePath}`, {
@@ -16667,7 +17256,7 @@ async function isModelAvailable(config) {
16667
17256
  }
16668
17257
  function isFirstRun() {
16669
17258
  try {
16670
- return !existsSync19(join25(homedir9(), ".open-agents", "config.json"));
17259
+ return !existsSync20(join26(homedir10(), ".open-agents", "config.json"));
16671
17260
  } catch {
16672
17261
  return true;
16673
17262
  }
@@ -16704,7 +17293,7 @@ function detectPkgManager() {
16704
17293
  return null;
16705
17294
  }
16706
17295
  function getVenvDir() {
16707
- return join25(homedir9(), ".open-agents", "venv");
17296
+ return join26(homedir10(), ".open-agents", "venv");
16708
17297
  }
16709
17298
  function hasVenvModule() {
16710
17299
  try {
@@ -16716,8 +17305,8 @@ function hasVenvModule() {
16716
17305
  }
16717
17306
  function ensureVenv(log) {
16718
17307
  const venvDir = getVenvDir();
16719
- const venvPip = join25(venvDir, "bin", "pip");
16720
- if (existsSync19(venvPip))
17308
+ const venvPip = join26(venvDir, "bin", "pip");
17309
+ if (existsSync20(venvPip))
16721
17310
  return venvDir;
16722
17311
  log("Creating Python venv for vision deps...");
16723
17312
  if (!hasCmd("python3")) {
@@ -16729,9 +17318,9 @@ function ensureVenv(log) {
16729
17318
  return null;
16730
17319
  }
16731
17320
  try {
16732
- mkdirSync7(join25(homedir9(), ".open-agents"), { recursive: true });
17321
+ mkdirSync7(join26(homedir10(), ".open-agents"), { recursive: true });
16733
17322
  execSync16(`python3 -m venv "${venvDir}"`, { stdio: "pipe", timeout: 3e4 });
16734
- execSync16(`"${join25(venvDir, "bin", "pip")}" install --upgrade pip`, {
17323
+ execSync16(`"${join26(venvDir, "bin", "pip")}" install --upgrade pip`, {
16735
17324
  stdio: "pipe",
16736
17325
  timeout: 6e4
16737
17326
  });
@@ -16940,15 +17529,15 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
16940
17529
  }
16941
17530
  }
16942
17531
  const venvDir = getVenvDir();
16943
- const venvBin = join25(venvDir, "bin");
16944
- const venvMoondream = join25(venvBin, "moondream-station");
17532
+ const venvBin = join26(venvDir, "bin");
17533
+ const venvMoondream = join26(venvBin, "moondream-station");
16945
17534
  const venv = ensureVenv(log);
16946
- if (venv && !hasCmd("moondream-station") && !existsSync19(venvMoondream)) {
16947
- const venvPip = join25(venvBin, "pip");
17535
+ if (venv && !hasCmd("moondream-station") && !existsSync20(venvMoondream)) {
17536
+ const venvPip = join26(venvBin, "pip");
16948
17537
  log("Installing moondream-station in ~/.open-agents/venv...");
16949
17538
  try {
16950
17539
  execSync16(`"${venvPip}" install moondream-station`, { stdio: "pipe", timeout: 3e5 });
16951
- if (existsSync19(venvMoondream)) {
17540
+ if (existsSync20(venvMoondream)) {
16952
17541
  log("moondream-station installed successfully.");
16953
17542
  } else {
16954
17543
  try {
@@ -16965,8 +17554,8 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
16965
17554
  }
16966
17555
  }
16967
17556
  if (venv) {
16968
- const venvPython = join25(venvBin, "python");
16969
- const venvPip2 = join25(venvBin, "pip");
17557
+ const venvPython = join26(venvBin, "python");
17558
+ const venvPip2 = join26(venvBin, "pip");
16970
17559
  let ocrStackInstalled = false;
16971
17560
  try {
16972
17561
  execSync16(`"${venvPython}" -c "import cv2, pytesseract, numpy, PIL"`, { stdio: "pipe", timeout: 1e4 });
@@ -17026,9 +17615,9 @@ function createExpandedVariant(baseModel, specs, sizeGB) {
17026
17615
  `PARAMETER num_predict ${numPredict}`,
17027
17616
  `PARAMETER stop "<|endoftext|>"`
17028
17617
  ].join("\n");
17029
- const modelDir2 = join25(homedir9(), ".open-agents", "models");
17618
+ const modelDir2 = join26(homedir10(), ".open-agents", "models");
17030
17619
  mkdirSync7(modelDir2, { recursive: true });
17031
- const modelfilePath = join25(modelDir2, `Modelfile.${customName}`);
17620
+ const modelfilePath = join26(modelDir2, `Modelfile.${customName}`);
17032
17621
  writeFileSync7(modelfilePath, modelfileContent + "\n", "utf8");
17033
17622
  execSync16(`ollama create ${customName} -f ${modelfilePath}`, {
17034
17623
  stdio: "pipe",
@@ -17792,17 +18381,17 @@ async function handleUpdate(subcommand, ctx) {
17792
18381
  try {
17793
18382
  const { createRequire: createRequire4 } = await import("node:module");
17794
18383
  const { fileURLToPath: fileURLToPath9 } = await import("node:url");
17795
- const { dirname: dirname12, join: join36 } = await import("node:path");
17796
- const { existsSync: existsSync26 } = await import("node:fs");
18384
+ const { dirname: dirname12, join: join37 } = await import("node:path");
18385
+ const { existsSync: existsSync27 } = await import("node:fs");
17797
18386
  const req = createRequire4(import.meta.url);
17798
18387
  const thisDir = dirname12(fileURLToPath9(import.meta.url));
17799
18388
  const candidates = [
17800
- join36(thisDir, "..", "package.json"),
17801
- join36(thisDir, "..", "..", "package.json"),
17802
- join36(thisDir, "..", "..", "..", "package.json")
18389
+ join37(thisDir, "..", "package.json"),
18390
+ join37(thisDir, "..", "..", "package.json"),
18391
+ join37(thisDir, "..", "..", "..", "package.json")
17803
18392
  ];
17804
18393
  for (const pkgPath of candidates) {
17805
- if (existsSync26(pkgPath)) {
18394
+ if (existsSync27(pkgPath)) {
17806
18395
  const pkg = req(pkgPath);
17807
18396
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
17808
18397
  currentVersion = pkg.version ?? "0.0.0";
@@ -17917,10 +18506,10 @@ var init_commands = __esm({
17917
18506
  });
17918
18507
 
17919
18508
  // packages/cli/dist/tui/project-context.js
17920
- import { existsSync as existsSync20, readFileSync as readFileSync14, readdirSync as readdirSync8 } from "node:fs";
17921
- import { join as join26, basename as basename9 } from "node:path";
18509
+ import { existsSync as existsSync21, readFileSync as readFileSync14, readdirSync as readdirSync8 } from "node:fs";
18510
+ import { join as join27, basename as basename10 } from "node:path";
17922
18511
  import { execSync as execSync17 } from "node:child_process";
17923
- import { homedir as homedir10, platform as platform2, release } from "node:os";
18512
+ import { homedir as homedir11, platform as platform2, release } from "node:os";
17924
18513
  function getModelTier(modelName) {
17925
18514
  const m = modelName.toLowerCase();
17926
18515
  const sizeMatch = m.match(/\b(\d+)b\b/);
@@ -17953,8 +18542,8 @@ function loadProjectMap(repoRoot) {
17953
18542
  if (!hasOaDirectory(repoRoot)) {
17954
18543
  initOaDirectory(repoRoot);
17955
18544
  }
17956
- const mapPath = join26(repoRoot, OA_DIR, "context", "project-map.md");
17957
- if (existsSync20(mapPath)) {
18545
+ const mapPath = join27(repoRoot, OA_DIR, "context", "project-map.md");
18546
+ if (existsSync21(mapPath)) {
17958
18547
  try {
17959
18548
  const content = readFileSync14(mapPath, "utf-8");
17960
18549
  return content;
@@ -17997,33 +18586,33 @@ ${log}`);
17997
18586
  }
17998
18587
  function loadMemoryContext(repoRoot) {
17999
18588
  const sections = [];
18000
- const oaMemDir = join26(repoRoot, OA_DIR, "memory");
18589
+ const oaMemDir = join27(repoRoot, OA_DIR, "memory");
18001
18590
  const oaEntries = loadMemoryDir(oaMemDir, "project");
18002
18591
  if (oaEntries)
18003
18592
  sections.push(oaEntries);
18004
- const legacyMemDir = join26(repoRoot, ".open-agents", "memory");
18005
- if (legacyMemDir !== oaMemDir && existsSync20(legacyMemDir)) {
18593
+ const legacyMemDir = join27(repoRoot, ".open-agents", "memory");
18594
+ if (legacyMemDir !== oaMemDir && existsSync21(legacyMemDir)) {
18006
18595
  const legacyEntries = loadMemoryDir(legacyMemDir, "project/legacy");
18007
18596
  if (legacyEntries)
18008
18597
  sections.push(legacyEntries);
18009
18598
  }
18010
- const globalMemDir = join26(homedir10(), ".open-agents", "memory");
18599
+ const globalMemDir = join27(homedir11(), ".open-agents", "memory");
18011
18600
  const globalEntries = loadMemoryDir(globalMemDir, "global");
18012
18601
  if (globalEntries)
18013
18602
  sections.push(globalEntries);
18014
18603
  return sections.join("\n\n");
18015
18604
  }
18016
18605
  function loadMemoryDir(memDir, scope) {
18017
- if (!existsSync20(memDir))
18606
+ if (!existsSync21(memDir))
18018
18607
  return "";
18019
18608
  const lines = [];
18020
18609
  try {
18021
18610
  const files = readdirSync8(memDir).filter((f) => f.endsWith(".json"));
18022
18611
  for (const file of files.slice(0, 10)) {
18023
18612
  try {
18024
- const raw = readFileSync14(join26(memDir, file), "utf-8");
18613
+ const raw = readFileSync14(join27(memDir, file), "utf-8");
18025
18614
  const entries = JSON.parse(raw);
18026
- const topic = basename9(file, ".json");
18615
+ const topic = basename10(file, ".json");
18027
18616
  const keys = Object.keys(entries);
18028
18617
  if (keys.length === 0)
18029
18618
  continue;
@@ -19048,12 +19637,12 @@ var init_carousel = __esm({
19048
19637
  });
19049
19638
 
19050
19639
  // packages/cli/dist/tui/carousel-descriptors.js
19051
- import { existsSync as existsSync21, readFileSync as readFileSync15, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, readdirSync as readdirSync9 } from "node:fs";
19052
- import { join as join27, basename as basename10 } from "node:path";
19640
+ import { existsSync as existsSync22, readFileSync as readFileSync15, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, readdirSync as readdirSync9 } from "node:fs";
19641
+ import { join as join28, basename as basename11 } from "node:path";
19053
19642
  function loadToolProfile(repoRoot) {
19054
- const filePath = join27(repoRoot, OA_DIR, "context", TOOL_PROFILE_FILE);
19643
+ const filePath = join28(repoRoot, OA_DIR, "context", TOOL_PROFILE_FILE);
19055
19644
  try {
19056
- if (!existsSync21(filePath))
19645
+ if (!existsSync22(filePath))
19057
19646
  return null;
19058
19647
  return JSON.parse(readFileSync15(filePath, "utf-8"));
19059
19648
  } catch {
@@ -19061,9 +19650,9 @@ function loadToolProfile(repoRoot) {
19061
19650
  }
19062
19651
  }
19063
19652
  function saveToolProfile(repoRoot, profile) {
19064
- const contextDir = join27(repoRoot, OA_DIR, "context");
19653
+ const contextDir = join28(repoRoot, OA_DIR, "context");
19065
19654
  mkdirSync8(contextDir, { recursive: true });
19066
- writeFileSync8(join27(contextDir, TOOL_PROFILE_FILE), JSON.stringify(profile, null, 2), "utf-8");
19655
+ writeFileSync8(join28(contextDir, TOOL_PROFILE_FILE), JSON.stringify(profile, null, 2), "utf-8");
19067
19656
  }
19068
19657
  function categorizeToolCall(toolName) {
19069
19658
  for (const cat of TOOL_CATEGORIES) {
@@ -19121,9 +19710,9 @@ function weightedColor(profile) {
19121
19710
  return selectedCat.colors[Math.floor(Math.random() * selectedCat.colors.length)];
19122
19711
  }
19123
19712
  function loadCachedDescriptors(repoRoot) {
19124
- const filePath = join27(repoRoot, OA_DIR, "context", DESCRIPTOR_FILE);
19713
+ const filePath = join28(repoRoot, OA_DIR, "context", DESCRIPTOR_FILE);
19125
19714
  try {
19126
- if (!existsSync21(filePath))
19715
+ if (!existsSync22(filePath))
19127
19716
  return null;
19128
19717
  const cached = JSON.parse(readFileSync15(filePath, "utf-8"));
19129
19718
  return cached.phrases.length > 0 ? cached.phrases : null;
@@ -19132,14 +19721,14 @@ function loadCachedDescriptors(repoRoot) {
19132
19721
  }
19133
19722
  }
19134
19723
  function saveCachedDescriptors(repoRoot, phrases, sourceHash) {
19135
- const contextDir = join27(repoRoot, OA_DIR, "context");
19724
+ const contextDir = join28(repoRoot, OA_DIR, "context");
19136
19725
  mkdirSync8(contextDir, { recursive: true });
19137
19726
  const cached = {
19138
19727
  phrases,
19139
19728
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
19140
19729
  sourceHash
19141
19730
  };
19142
- writeFileSync8(join27(contextDir, DESCRIPTOR_FILE), JSON.stringify(cached, null, 2), "utf-8");
19731
+ writeFileSync8(join28(contextDir, DESCRIPTOR_FILE), JSON.stringify(cached, null, 2), "utf-8");
19143
19732
  }
19144
19733
  function generateDescriptors(repoRoot) {
19145
19734
  const profile = loadToolProfile(repoRoot);
@@ -19150,7 +19739,7 @@ function generateDescriptors(repoRoot) {
19150
19739
  extractFromSessions(repoRoot, tags);
19151
19740
  extractFromMemory(repoRoot, tags);
19152
19741
  extractFromToolProfile(profile, tags);
19153
- const repoName2 = basename10(repoRoot);
19742
+ const repoName2 = basename11(repoRoot);
19154
19743
  if (repoName2 && !tags.includes(repoName2)) {
19155
19744
  tags.push(repoName2);
19156
19745
  }
@@ -19187,9 +19776,9 @@ function generateDescriptors(repoRoot) {
19187
19776
  return phrases;
19188
19777
  }
19189
19778
  function extractFromPackageJson(repoRoot, tags) {
19190
- const pkgPath = join27(repoRoot, "package.json");
19779
+ const pkgPath = join28(repoRoot, "package.json");
19191
19780
  try {
19192
- if (!existsSync21(pkgPath))
19781
+ if (!existsSync22(pkgPath))
19193
19782
  return;
19194
19783
  const pkg = JSON.parse(readFileSync15(pkgPath, "utf-8"));
19195
19784
  if (pkg.name && typeof pkg.name === "string") {
@@ -19235,7 +19824,7 @@ function extractFromManifests(repoRoot, tags) {
19235
19824
  { file: ".github/workflows", tag: "ci/cd" }
19236
19825
  ];
19237
19826
  for (const check of manifestChecks) {
19238
- if (existsSync21(join27(repoRoot, check.file))) {
19827
+ if (existsSync22(join28(repoRoot, check.file))) {
19239
19828
  tags.push(check.tag);
19240
19829
  }
19241
19830
  }
@@ -19257,16 +19846,16 @@ function extractFromSessions(repoRoot, tags) {
19257
19846
  }
19258
19847
  }
19259
19848
  function extractFromMemory(repoRoot, tags) {
19260
- const memoryDir = join27(repoRoot, OA_DIR, "memory");
19849
+ const memoryDir = join28(repoRoot, OA_DIR, "memory");
19261
19850
  try {
19262
- if (!existsSync21(memoryDir))
19851
+ if (!existsSync22(memoryDir))
19263
19852
  return;
19264
19853
  const files = readdirSync9(memoryDir).filter((f) => f.endsWith(".json"));
19265
19854
  for (const file of files) {
19266
19855
  const topic = file.replace(/\.json$/, "").replace(/[-_]/g, " ");
19267
19856
  tags.push(topic);
19268
19857
  try {
19269
- const data = JSON.parse(readFileSync15(join27(memoryDir, file), "utf-8"));
19858
+ const data = JSON.parse(readFileSync15(join28(memoryDir, file), "utf-8"));
19270
19859
  if (data && typeof data === "object") {
19271
19860
  const keys = Object.keys(data).slice(0, 3);
19272
19861
  for (const key of keys) {
@@ -19401,25 +19990,25 @@ var init_carousel_descriptors = __esm({
19401
19990
  });
19402
19991
 
19403
19992
  // packages/cli/dist/tui/voice.js
19404
- import { existsSync as existsSync22, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9, readFileSync as readFileSync16, unlinkSync as unlinkSync4 } from "node:fs";
19405
- import { join as join28 } from "node:path";
19406
- import { homedir as homedir11, tmpdir as tmpdir6, platform as platform3 } from "node:os";
19993
+ import { existsSync as existsSync23, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9, readFileSync as readFileSync16, unlinkSync as unlinkSync4 } from "node:fs";
19994
+ import { join as join29 } from "node:path";
19995
+ import { homedir as homedir12, tmpdir as tmpdir6, platform as platform3 } from "node:os";
19407
19996
  import { execSync as execSync18, spawn as nodeSpawn } from "node:child_process";
19408
19997
  import { createRequire } from "node:module";
19409
19998
  function voiceDir() {
19410
- return join28(homedir11(), ".open-agents", "voice");
19999
+ return join29(homedir12(), ".open-agents", "voice");
19411
20000
  }
19412
20001
  function modelsDir() {
19413
- return join28(voiceDir(), "models");
20002
+ return join29(voiceDir(), "models");
19414
20003
  }
19415
20004
  function modelDir(id) {
19416
- return join28(modelsDir(), id);
20005
+ return join29(modelsDir(), id);
19417
20006
  }
19418
20007
  function modelOnnxPath(id) {
19419
- return join28(modelDir(id), "model.onnx");
20008
+ return join29(modelDir(id), "model.onnx");
19420
20009
  }
19421
20010
  function modelConfigPath(id) {
19422
- return join28(modelDir(id), "config.json");
20011
+ return join29(modelDir(id), "config.json");
19423
20012
  }
19424
20013
  function describeToolCall(toolName, args) {
19425
20014
  const path = args["path"];
@@ -19692,7 +20281,7 @@ var init_voice = __esm({
19692
20281
  const audioData = result["output"].data;
19693
20282
  if (audioData.length === 0)
19694
20283
  return;
19695
- const wavPath = join28(tmpdir6(), `oa-voice-${Date.now()}.wav`);
20284
+ const wavPath = join29(tmpdir6(), `oa-voice-${Date.now()}.wav`);
19696
20285
  this.writeWav(audioData, this.config.audio.sample_rate, wavPath);
19697
20286
  await this.playWav(wavPath);
19698
20287
  try {
@@ -19781,7 +20370,7 @@ var init_voice = __esm({
19781
20370
  const cmd = this.getPlayCommand(path);
19782
20371
  if (!cmd)
19783
20372
  return;
19784
- return new Promise((resolve22) => {
20373
+ return new Promise((resolve23) => {
19785
20374
  const child = nodeSpawn(cmd[0], cmd.slice(1), {
19786
20375
  stdio: "ignore",
19787
20376
  detached: false
@@ -19790,12 +20379,12 @@ var init_voice = __esm({
19790
20379
  child.on("close", () => {
19791
20380
  if (this.currentPlayback === child)
19792
20381
  this.currentPlayback = null;
19793
- resolve22();
20382
+ resolve23();
19794
20383
  });
19795
20384
  child.on("error", () => {
19796
20385
  if (this.currentPlayback === child)
19797
20386
  this.currentPlayback = null;
19798
- resolve22();
20387
+ resolve23();
19799
20388
  });
19800
20389
  setTimeout(() => {
19801
20390
  if (this.currentPlayback === child) {
@@ -19805,7 +20394,7 @@ var init_voice = __esm({
19805
20394
  }
19806
20395
  this.currentPlayback = null;
19807
20396
  }
19808
- resolve22();
20397
+ resolve23();
19809
20398
  }, 15e3);
19810
20399
  });
19811
20400
  }
@@ -19847,12 +20436,12 @@ var init_voice = __esm({
19847
20436
  const arch = process.arch;
19848
20437
  const isArmLinux = (arch === "arm64" || arch === "arm") && process.platform === "linux";
19849
20438
  mkdirSync9(voiceDir(), { recursive: true });
19850
- const pkgPath = join28(voiceDir(), "package.json");
20439
+ const pkgPath = join29(voiceDir(), "package.json");
19851
20440
  const expectedDeps = {
19852
20441
  "onnxruntime-node": "^1.21.0",
19853
20442
  "phonemizer": "^1.2.1"
19854
20443
  };
19855
- if (existsSync22(pkgPath)) {
20444
+ if (existsSync23(pkgPath)) {
19856
20445
  try {
19857
20446
  const existing = JSON.parse(readFileSync16(pkgPath, "utf8"));
19858
20447
  if (!existing.dependencies?.["phonemizer"]) {
@@ -19862,14 +20451,14 @@ var init_voice = __esm({
19862
20451
  } catch {
19863
20452
  }
19864
20453
  }
19865
- if (!existsSync22(pkgPath)) {
20454
+ if (!existsSync23(pkgPath)) {
19866
20455
  writeFileSync9(pkgPath, JSON.stringify({
19867
20456
  name: "open-agents-voice",
19868
20457
  private: true,
19869
20458
  dependencies: expectedDeps
19870
20459
  }, null, 2));
19871
20460
  }
19872
- const voiceRequire = createRequire(join28(voiceDir(), "index.js"));
20461
+ const voiceRequire = createRequire(join29(voiceDir(), "index.js"));
19873
20462
  try {
19874
20463
  this.ort = voiceRequire("onnxruntime-node");
19875
20464
  } catch {
@@ -19923,10 +20512,10 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
19923
20512
  const dir = modelDir(id);
19924
20513
  const onnxPath = modelOnnxPath(id);
19925
20514
  const configPath = modelConfigPath(id);
19926
- if (existsSync22(onnxPath) && existsSync22(configPath))
20515
+ if (existsSync23(onnxPath) && existsSync23(configPath))
19927
20516
  return;
19928
20517
  mkdirSync9(dir, { recursive: true });
19929
- if (!existsSync22(configPath)) {
20518
+ if (!existsSync23(configPath)) {
19930
20519
  renderInfo(`Downloading ${model.label} voice config...`);
19931
20520
  const configResp = await fetch(model.configUrl);
19932
20521
  if (!configResp.ok)
@@ -19934,7 +20523,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
19934
20523
  const configText = await configResp.text();
19935
20524
  writeFileSync9(configPath, configText);
19936
20525
  }
19937
- if (!existsSync22(onnxPath)) {
20526
+ if (!existsSync23(onnxPath)) {
19938
20527
  renderInfo(`Downloading ${model.label} voice model (this may take a minute)...`);
19939
20528
  const onnxResp = await fetch(model.onnxUrl);
19940
20529
  if (!onnxResp.ok)
@@ -19970,7 +20559,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
19970
20559
  throw new Error("ONNX runtime not loaded");
19971
20560
  const onnxPath = modelOnnxPath(this.modelId);
19972
20561
  const configPath = modelConfigPath(this.modelId);
19973
- if (!existsSync22(onnxPath) || !existsSync22(configPath)) {
20562
+ if (!existsSync23(onnxPath) || !existsSync23(configPath)) {
19974
20563
  throw new Error(`Model files not found for ${this.modelId}`);
19975
20564
  }
19976
20565
  this.config = JSON.parse(readFileSync16(configPath, "utf8"));
@@ -20474,10 +21063,10 @@ var init_stream_renderer = __esm({
20474
21063
 
20475
21064
  // packages/cli/dist/tui/edit-history.js
20476
21065
  import { appendFileSync, mkdirSync as mkdirSync10 } from "node:fs";
20477
- import { join as join29 } from "node:path";
21066
+ import { join as join30 } from "node:path";
20478
21067
  function createEditHistoryLogger(repoRoot, sessionId) {
20479
- const historyDir = join29(repoRoot, ".oa", "history");
20480
- const logPath = join29(historyDir, "edits.jsonl");
21068
+ const historyDir = join30(repoRoot, ".oa", "history");
21069
+ const logPath = join30(historyDir, "edits.jsonl");
20481
21070
  try {
20482
21071
  mkdirSync10(historyDir, { recursive: true });
20483
21072
  } catch {
@@ -20588,8 +21177,8 @@ var init_edit_history = __esm({
20588
21177
  });
20589
21178
 
20590
21179
  // packages/cli/dist/tui/dream-engine.js
20591
- import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync10, readFileSync as readFileSync17, existsSync as existsSync23, cpSync, rmSync, readdirSync as readdirSync10 } from "node:fs";
20592
- import { join as join30, basename as basename11 } from "node:path";
21180
+ import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync10, readFileSync as readFileSync17, existsSync as existsSync24, cpSync, rmSync, readdirSync as readdirSync10 } from "node:fs";
21181
+ import { join as join31, basename as basename12 } from "node:path";
20593
21182
  import { execSync as execSync19 } from "node:child_process";
20594
21183
  function adaptTool(tool) {
20595
21184
  return {
@@ -20764,12 +21353,12 @@ var init_dream_engine = __esm({
20764
21353
  const content = String(args["content"] ?? "");
20765
21354
  if (!rawPath)
20766
21355
  return { success: false, output: "", error: "path is required", durationMs: Date.now() - start };
20767
- const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join30(this.dreamsDir, basename11(rawPath)) : join30(this.dreamsDir, rawPath);
21356
+ const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join31(this.dreamsDir, basename12(rawPath)) : join31(this.dreamsDir, rawPath);
20768
21357
  if (!targetPath.startsWith(this.dreamsDir)) {
20769
21358
  return { success: false, output: "", error: "Dream mode: writes are confined to .oa/dreams/", durationMs: Date.now() - start };
20770
21359
  }
20771
21360
  try {
20772
- const dir = join30(targetPath, "..");
21361
+ const dir = join31(targetPath, "..");
20773
21362
  mkdirSync11(dir, { recursive: true });
20774
21363
  writeFileSync10(targetPath, content, "utf-8");
20775
21364
  return { success: true, output: `Wrote ${content.length} bytes to ${rawPath}`, durationMs: Date.now() - start };
@@ -20799,12 +21388,12 @@ var init_dream_engine = __esm({
20799
21388
  const rawPath = String(args["path"] ?? "");
20800
21389
  const oldStr = String(args["old_string"] ?? "");
20801
21390
  const newStr = String(args["new_string"] ?? "");
20802
- const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join30(this.dreamsDir, basename11(rawPath)) : join30(this.dreamsDir, rawPath);
21391
+ const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join31(this.dreamsDir, basename12(rawPath)) : join31(this.dreamsDir, rawPath);
20803
21392
  if (!targetPath.startsWith(this.dreamsDir)) {
20804
21393
  return { success: false, output: "", error: "Dream mode: edits are confined to .oa/dreams/", durationMs: Date.now() - start };
20805
21394
  }
20806
21395
  try {
20807
- if (!existsSync23(targetPath)) {
21396
+ if (!existsSync24(targetPath)) {
20808
21397
  return { success: false, output: "", error: `File not found: ${rawPath}`, durationMs: Date.now() - start };
20809
21398
  }
20810
21399
  let content = readFileSync17(targetPath, "utf-8");
@@ -20866,7 +21455,7 @@ var init_dream_engine = __esm({
20866
21455
  constructor(config, repoRoot) {
20867
21456
  this.config = config;
20868
21457
  this.repoRoot = repoRoot;
20869
- this.dreamsDir = join30(repoRoot, ".oa", "dreams");
21458
+ this.dreamsDir = join31(repoRoot, ".oa", "dreams");
20870
21459
  this.state = {
20871
21460
  mode: "default",
20872
21461
  active: false,
@@ -20938,7 +21527,7 @@ ${result.summary}`;
20938
21527
  if (mode !== "default" || cycle === totalCycles) {
20939
21528
  renderDreamContraction(cycle);
20940
21529
  const cycleSummary = this.buildCycleSummary(cycle, previousFindings);
20941
- const summaryPath = join30(this.dreamsDir, `cycle-${cycle}-summary.md`);
21530
+ const summaryPath = join31(this.dreamsDir, `cycle-${cycle}-summary.md`);
20942
21531
  writeFileSync10(summaryPath, cycleSummary, "utf-8");
20943
21532
  }
20944
21533
  if (mode === "lucid" && !this.abortController.signal.aborted) {
@@ -21061,7 +21650,7 @@ Dreams directory: ${this.dreamsDir}`);
21061
21650
  }
21062
21651
  /** Save workspace backup for lucid mode */
21063
21652
  saveVersionCheckpoint(cycle) {
21064
- const checkpointDir = join30(this.dreamsDir, "checkpoints", `cycle-${cycle}`);
21653
+ const checkpointDir = join31(this.dreamsDir, "checkpoints", `cycle-${cycle}`);
21065
21654
  try {
21066
21655
  mkdirSync11(checkpointDir, { recursive: true });
21067
21656
  try {
@@ -21080,10 +21669,10 @@ Dreams directory: ${this.dreamsDir}`);
21080
21669
  encoding: "utf-8",
21081
21670
  timeout: 5e3
21082
21671
  }).trim();
21083
- writeFileSync10(join30(checkpointDir, "git-status.txt"), gitStatus, "utf-8");
21084
- writeFileSync10(join30(checkpointDir, "git-diff.patch"), gitDiff, "utf-8");
21085
- writeFileSync10(join30(checkpointDir, "git-hash.txt"), gitHash, "utf-8");
21086
- writeFileSync10(join30(checkpointDir, "checkpoint.json"), JSON.stringify({
21672
+ writeFileSync10(join31(checkpointDir, "git-status.txt"), gitStatus, "utf-8");
21673
+ writeFileSync10(join31(checkpointDir, "git-diff.patch"), gitDiff, "utf-8");
21674
+ writeFileSync10(join31(checkpointDir, "git-hash.txt"), gitHash, "utf-8");
21675
+ writeFileSync10(join31(checkpointDir, "checkpoint.json"), JSON.stringify({
21087
21676
  cycle,
21088
21677
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
21089
21678
  gitHash,
@@ -21091,7 +21680,7 @@ Dreams directory: ${this.dreamsDir}`);
21091
21680
  }, null, 2), "utf-8");
21092
21681
  renderInfo(`Checkpoint saved: cycle ${cycle} (${gitHash.slice(0, 8)})`);
21093
21682
  } catch {
21094
- writeFileSync10(join30(checkpointDir, "checkpoint.json"), JSON.stringify({ cycle, timestamp: (/* @__PURE__ */ new Date()).toISOString(), mode: this.state.mode }, null, 2), "utf-8");
21683
+ writeFileSync10(join31(checkpointDir, "checkpoint.json"), JSON.stringify({ cycle, timestamp: (/* @__PURE__ */ new Date()).toISOString(), mode: this.state.mode }, null, 2), "utf-8");
21095
21684
  renderInfo(`Checkpoint saved: cycle ${cycle} (no git)`);
21096
21685
  }
21097
21686
  } catch (err) {
@@ -21149,14 +21738,14 @@ ${files.map((f) => `- [\`${f}\`](./${f})`).join("\n")}
21149
21738
  ---
21150
21739
  *Auto-generated by open-agents dream engine*
21151
21740
  `;
21152
- writeFileSync10(join30(this.dreamsDir, "PROPOSAL-INDEX.md"), index, "utf-8");
21741
+ writeFileSync10(join31(this.dreamsDir, "PROPOSAL-INDEX.md"), index, "utf-8");
21153
21742
  } catch {
21154
21743
  }
21155
21744
  }
21156
21745
  /** Save dream state for resume/inspection */
21157
21746
  saveDreamState() {
21158
21747
  try {
21159
- writeFileSync10(join30(this.dreamsDir, "dream-state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
21748
+ writeFileSync10(join31(this.dreamsDir, "dream-state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
21160
21749
  } catch {
21161
21750
  }
21162
21751
  }
@@ -22024,11 +22613,11 @@ var init_status_bar = __esm({
22024
22613
  import * as readline2 from "node:readline";
22025
22614
  import { Writable } from "node:stream";
22026
22615
  import { cwd } from "node:process";
22027
- import { resolve as resolve19, join as join31, dirname as dirname10, extname as extname9 } from "node:path";
22616
+ import { resolve as resolve20, join as join32, dirname as dirname10, extname as extname9 } from "node:path";
22028
22617
  import { createRequire as createRequire2 } from "node:module";
22029
22618
  import { fileURLToPath as fileURLToPath7 } from "node:url";
22030
22619
  import { readFileSync as readFileSync18, rmSync as rmSync2 } from "node:fs";
22031
- import { existsSync as existsSync24 } from "node:fs";
22620
+ import { existsSync as existsSync25 } from "node:fs";
22032
22621
  function formatTimeAgo(date) {
22033
22622
  const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
22034
22623
  if (seconds < 60)
@@ -22047,12 +22636,12 @@ function getVersion() {
22047
22636
  const require2 = createRequire2(import.meta.url);
22048
22637
  const thisDir = dirname10(fileURLToPath7(import.meta.url));
22049
22638
  const candidates = [
22050
- join31(thisDir, "..", "package.json"),
22051
- join31(thisDir, "..", "..", "package.json"),
22052
- join31(thisDir, "..", "..", "..", "package.json")
22639
+ join32(thisDir, "..", "package.json"),
22640
+ join32(thisDir, "..", "..", "package.json"),
22641
+ join32(thisDir, "..", "..", "..", "package.json")
22053
22642
  ];
22054
22643
  for (const pkgPath of candidates) {
22055
- if (existsSync24(pkgPath)) {
22644
+ if (existsSync25(pkgPath)) {
22056
22645
  const pkg = require2(pkgPath);
22057
22646
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
22058
22647
  return pkg.version ?? "0.0.0";
@@ -22104,6 +22693,8 @@ function buildTools(repoRoot, config, contextWindowSize) {
22104
22693
  new WebCrawlTool(repoRoot),
22105
22694
  new MemoryReadTool(repoRoot),
22106
22695
  new MemoryWriteTool(repoRoot),
22696
+ new MemorySearchTool(repoRoot),
22697
+ new ExploreToolsTool(),
22107
22698
  // AIWG SDLC tools (auto-detect if aiwg is installed)
22108
22699
  new AiwgSetupTool(repoRoot),
22109
22700
  new AiwgHealthTool(repoRoot),
@@ -22519,7 +23110,7 @@ ${entry.fullContent}`
22519
23110
  } };
22520
23111
  }
22521
23112
  async function startInteractive(config, repoPath) {
22522
- const repoRoot = resolve19(repoPath ?? cwd());
23113
+ const repoRoot = resolve20(repoPath ?? cwd());
22523
23114
  const resumeFlag = process.env.__OA_RESUMED ?? "";
22524
23115
  const isResumed = resumeFlag !== "";
22525
23116
  const hasTaskToResume = resumeFlag === "1";
@@ -22671,14 +23262,14 @@ async function startInteractive(config, repoPath) {
22671
23262
  renderInfo(msg);
22672
23263
  statusBar.endContentWrite();
22673
23264
  }
22674
- }, () => new Promise((resolve22) => {
23265
+ }, () => new Promise((resolve23) => {
22675
23266
  depSudoPromptPending = true;
22676
23267
  depSudoResolver = (pw) => {
22677
23268
  depSudoPromptPending = false;
22678
23269
  depSudoResolver = null;
22679
23270
  if (pw)
22680
23271
  sessionSudoPassword = pw;
22681
- resolve22(pw);
23272
+ resolve23(pw);
22682
23273
  };
22683
23274
  if (statusBar?.isActive) {
22684
23275
  statusBar.beginContentWrite();
@@ -23092,8 +23683,8 @@ async function startInteractive(config, repoPath) {
23092
23683
  return true;
23093
23684
  },
23094
23685
  destroyProject() {
23095
- const oaPath = join31(repoRoot, OA_DIR);
23096
- if (existsSync24(oaPath)) {
23686
+ const oaPath = join32(repoRoot, OA_DIR);
23687
+ if (existsSync25(oaPath)) {
23097
23688
  try {
23098
23689
  rmSync2(oaPath, { recursive: true, force: true });
23099
23690
  writeContent(() => renderInfo(`Removed ${OA_DIR}/ directory.`));
@@ -23325,12 +23916,12 @@ Execute this skill now. Follow the behavioral guidance above.`;
23325
23916
  }
23326
23917
  }
23327
23918
  const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
23328
- const isImage = isImagePath(cleanPath) && existsSync24(resolve19(repoRoot, cleanPath));
23329
- const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync24(resolve19(repoRoot, cleanPath));
23919
+ const isImage = isImagePath(cleanPath) && existsSync25(resolve20(repoRoot, cleanPath));
23920
+ const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync25(resolve20(repoRoot, cleanPath));
23330
23921
  if (activeTask) {
23331
23922
  if (isImage) {
23332
23923
  try {
23333
- const imgPath = resolve19(repoRoot, cleanPath);
23924
+ const imgPath = resolve20(repoRoot, cleanPath);
23334
23925
  const imgBuffer = readFileSync18(imgPath);
23335
23926
  const base64 = imgBuffer.toString("base64");
23336
23927
  const ext = extname9(cleanPath).toLowerCase();
@@ -23344,7 +23935,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
23344
23935
  } else if (isMedia) {
23345
23936
  writeContent(() => renderInfo(`Transcribing: ${cleanPath}...`));
23346
23937
  const engine = getListenEngine();
23347
- const result = await engine.transcribeFile(resolve19(repoRoot, cleanPath), repoRoot);
23938
+ const result = await engine.transcribeFile(resolve20(repoRoot, cleanPath), repoRoot);
23348
23939
  if (result) {
23349
23940
  const transcript = `[Transcription of ${cleanPath}]
23350
23941
  ${result.text}`;
@@ -23377,7 +23968,7 @@ ${result.text}`;
23377
23968
  if (isMedia && fullInput === input) {
23378
23969
  writeContent(() => renderInfo(`Transcribing: ${cleanPath}...`));
23379
23970
  const engine = getListenEngine();
23380
- const result = await engine.transcribeFile(resolve19(repoRoot, cleanPath), repoRoot);
23971
+ const result = await engine.transcribeFile(resolve20(repoRoot, cleanPath), repoRoot);
23381
23972
  if (result) {
23382
23973
  fullInput = `The user has provided an audio/video file: ${cleanPath}.
23383
23974
 
@@ -23506,7 +24097,7 @@ ${c2.dim("(Use /quit to exit)")}
23506
24097
  });
23507
24098
  }
23508
24099
  async function runWithTUI(task, config, repoPath) {
23509
- const repoRoot = resolve19(repoPath ?? cwd());
24100
+ const repoRoot = resolve20(repoPath ?? cwd());
23510
24101
  const needsSetup = isFirstRun() || !await isModelAvailable(config);
23511
24102
  if (needsSetup && config.backendType === "ollama") {
23512
24103
  const setupModel = await runSetupWizard(config);
@@ -23609,9 +24200,9 @@ var init_run = __esm({
23609
24200
  // packages/indexer/dist/codebase-indexer.js
23610
24201
  import { glob } from "glob";
23611
24202
  import ignore from "ignore";
23612
- import { readFile as readFile10, stat as stat4 } from "node:fs/promises";
24203
+ import { readFile as readFile11, stat as stat4 } from "node:fs/promises";
23613
24204
  import { createHash } from "node:crypto";
23614
- import { join as join32, relative as relative3, extname as extname10, basename as basename12 } from "node:path";
24205
+ import { join as join33, relative as relative3, extname as extname10, basename as basename13 } from "node:path";
23615
24206
  var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
23616
24207
  var init_codebase_indexer = __esm({
23617
24208
  "packages/indexer/dist/codebase-indexer.js"() {
@@ -23655,7 +24246,7 @@ var init_codebase_indexer = __esm({
23655
24246
  const ig = ignore.default();
23656
24247
  if (this.config.respectGitignore) {
23657
24248
  try {
23658
- const gitignoreContent = await readFile10(join32(this.config.rootDir, ".gitignore"), "utf-8");
24249
+ const gitignoreContent = await readFile11(join33(this.config.rootDir, ".gitignore"), "utf-8");
23659
24250
  ig.add(gitignoreContent);
23660
24251
  } catch {
23661
24252
  }
@@ -23670,12 +24261,12 @@ var init_codebase_indexer = __esm({
23670
24261
  for (const relativePath of files) {
23671
24262
  if (ig.ignores(relativePath))
23672
24263
  continue;
23673
- const fullPath = join32(this.config.rootDir, relativePath);
24264
+ const fullPath = join33(this.config.rootDir, relativePath);
23674
24265
  try {
23675
24266
  const fileStat = await stat4(fullPath);
23676
24267
  if (fileStat.size > this.config.maxFileSize)
23677
24268
  continue;
23678
- const content = await readFile10(fullPath);
24269
+ const content = await readFile11(fullPath);
23679
24270
  const hash = createHash("sha256").update(content).digest("hex");
23680
24271
  const ext = extname10(relativePath);
23681
24272
  indexed.push({
@@ -23693,7 +24284,7 @@ var init_codebase_indexer = __esm({
23693
24284
  }
23694
24285
  buildTree(files) {
23695
24286
  const root = {
23696
- name: basename12(this.config.rootDir),
24287
+ name: basename13(this.config.rootDir),
23697
24288
  path: this.config.rootDir,
23698
24289
  type: "directory",
23699
24290
  children: []
@@ -23716,7 +24307,7 @@ var init_codebase_indexer = __esm({
23716
24307
  if (!child) {
23717
24308
  child = {
23718
24309
  name: part,
23719
- path: join32(current.path, part),
24310
+ path: join33(current.path, part),
23720
24311
  type: "directory",
23721
24312
  children: []
23722
24313
  };
@@ -23772,6 +24363,13 @@ var init_embeddings = __esm({
23772
24363
  }
23773
24364
  });
23774
24365
 
24366
+ // packages/indexer/dist/ollamaEmbeddings.js
24367
+ var init_ollamaEmbeddings = __esm({
24368
+ "packages/indexer/dist/ollamaEmbeddings.js"() {
24369
+ "use strict";
24370
+ }
24371
+ });
24372
+
23775
24373
  // packages/indexer/dist/index.js
23776
24374
  var init_dist8 = __esm({
23777
24375
  "packages/indexer/dist/index.js"() {
@@ -23782,6 +24380,7 @@ var init_dist8 = __esm({
23782
24380
  init_graphBuilder();
23783
24381
  init_fileSummarizer();
23784
24382
  init_embeddings();
24383
+ init_ollamaEmbeddings();
23785
24384
  }
23786
24385
  });
23787
24386
 
@@ -23790,14 +24389,14 @@ var index_repo_exports = {};
23790
24389
  __export(index_repo_exports, {
23791
24390
  indexRepoCommand: () => indexRepoCommand
23792
24391
  });
23793
- import { resolve as resolve20 } from "node:path";
23794
- import { existsSync as existsSync25, statSync as statSync10 } from "node:fs";
24392
+ import { resolve as resolve21 } from "node:path";
24393
+ import { existsSync as existsSync26, statSync as statSync10 } from "node:fs";
23795
24394
  import { cwd as cwd2 } from "node:process";
23796
24395
  async function indexRepoCommand(opts, _config) {
23797
- const repoRoot = resolve20(opts.repoPath ?? cwd2());
24396
+ const repoRoot = resolve21(opts.repoPath ?? cwd2());
23798
24397
  printHeader("Index Repository");
23799
24398
  printInfo(`Indexing: ${repoRoot}`);
23800
- if (!existsSync25(repoRoot)) {
24399
+ if (!existsSync26(repoRoot)) {
23801
24400
  printError(`Path does not exist: ${repoRoot}`);
23802
24401
  process.exit(1);
23803
24402
  }
@@ -24043,8 +24642,8 @@ var config_exports = {};
24043
24642
  __export(config_exports, {
24044
24643
  configCommand: () => configCommand
24045
24644
  });
24046
- import { join as join33, resolve as resolve21 } from "node:path";
24047
- import { homedir as homedir12 } from "node:os";
24645
+ import { join as join34, resolve as resolve22 } from "node:path";
24646
+ import { homedir as homedir13 } from "node:os";
24048
24647
  import { cwd as cwd3 } from "node:process";
24049
24648
  function coerceForSettings(key, value) {
24050
24649
  if (INT_KEYS.has(key))
@@ -24064,7 +24663,7 @@ async function configCommand(opts, config) {
24064
24663
  return handleShow(opts, config);
24065
24664
  }
24066
24665
  function handleShow(opts, config) {
24067
- const repoRoot = resolve21(opts.repoPath ?? cwd3());
24666
+ const repoRoot = resolve22(opts.repoPath ?? cwd3());
24068
24667
  printHeader("Configuration");
24069
24668
  printSection("Active Settings (merged)");
24070
24669
  printKeyValue("backendUrl", config.backendUrl, 2);
@@ -24096,7 +24695,7 @@ function handleShow(opts, config) {
24096
24695
  }
24097
24696
  }
24098
24697
  printSection("Config File");
24099
- printInfo(`~/.open-agents/config.json (${join33(homedir12(), ".open-agents", "config.json")})`);
24698
+ printInfo(`~/.open-agents/config.json (${join34(homedir13(), ".open-agents", "config.json")})`);
24100
24699
  printSection("Priority Chain");
24101
24700
  printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
24102
24701
  printInfo(" 2. Project .oa/settings.json (--local)");
@@ -24129,13 +24728,13 @@ function handleSet(opts, _config) {
24129
24728
  process.exit(1);
24130
24729
  }
24131
24730
  if (opts.local) {
24132
- const repoRoot = resolve21(opts.repoPath ?? cwd3());
24731
+ const repoRoot = resolve22(opts.repoPath ?? cwd3());
24133
24732
  try {
24134
24733
  initOaDirectory(repoRoot);
24135
24734
  const coerced = coerceForSettings(key, value);
24136
24735
  saveProjectSettings(repoRoot, { [key]: coerced });
24137
24736
  printSuccess(`Project override set: ${key} = ${value}`);
24138
- printInfo(`Saved to ${join33(repoRoot, ".oa", "settings.json")}`);
24737
+ printInfo(`Saved to ${join34(repoRoot, ".oa", "settings.json")}`);
24139
24738
  printInfo("This override applies only when running in this workspace.");
24140
24739
  } catch (err) {
24141
24740
  printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
@@ -24287,7 +24886,7 @@ async function serveVllm(opts, config) {
24287
24886
  await runVllmServer(args, opts.verbose ?? false);
24288
24887
  }
24289
24888
  async function runVllmServer(args, verbose) {
24290
- return new Promise((resolve22, reject) => {
24889
+ return new Promise((resolve23, reject) => {
24291
24890
  const child = spawn9("python", args, {
24292
24891
  stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
24293
24892
  env: { ...process.env }
@@ -24322,10 +24921,10 @@ async function runVllmServer(args, verbose) {
24322
24921
  child.once("exit", (code, signal) => {
24323
24922
  if (signal) {
24324
24923
  printInfo(`vLLM server stopped by signal ${signal}`);
24325
- resolve22();
24924
+ resolve23();
24326
24925
  } else if (code === 0) {
24327
24926
  printSuccess("vLLM server exited cleanly");
24328
- resolve22();
24927
+ resolve23();
24329
24928
  } else {
24330
24929
  printError(`vLLM server exited with code ${code}`);
24331
24930
  reject(new Error(`vLLM exited with code ${code}`));
@@ -24354,7 +24953,7 @@ __export(eval_exports, {
24354
24953
  });
24355
24954
  import { tmpdir as tmpdir7 } from "node:os";
24356
24955
  import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync11 } from "node:fs";
24357
- import { join as join34 } from "node:path";
24956
+ import { join as join35 } from "node:path";
24358
24957
  async function evalCommand(opts, config) {
24359
24958
  const suiteName = opts.suite ?? "basic";
24360
24959
  const suite = SUITES[suiteName];
@@ -24475,9 +25074,9 @@ async function evalCommand(opts, config) {
24475
25074
  process.exit(failed > 0 ? 1 : 0);
24476
25075
  }
24477
25076
  function createTempEvalRepo() {
24478
- const dir = join34(tmpdir7(), `open-agents-eval-${Date.now()}`);
25077
+ const dir = join35(tmpdir7(), `open-agents-eval-${Date.now()}`);
24479
25078
  mkdirSync12(dir, { recursive: true });
24480
- writeFileSync11(join34(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
25079
+ writeFileSync11(join35(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
24481
25080
  return dir;
24482
25081
  }
24483
25082
  var BASIC_SUITE, FULL_SUITE, SUITES;
@@ -24537,7 +25136,7 @@ init_updater();
24537
25136
  import { parseArgs as nodeParseArgs2 } from "node:util";
24538
25137
  import { createRequire as createRequire3 } from "node:module";
24539
25138
  import { fileURLToPath as fileURLToPath8 } from "node:url";
24540
- import { dirname as dirname11, join as join35 } from "node:path";
25139
+ import { dirname as dirname11, join as join36 } from "node:path";
24541
25140
 
24542
25141
  // packages/cli/dist/cli.js
24543
25142
  import { createInterface } from "node:readline";
@@ -24644,7 +25243,7 @@ init_output();
24644
25243
  function getVersion2() {
24645
25244
  try {
24646
25245
  const require2 = createRequire3(import.meta.url);
24647
- const pkgPath = join35(dirname11(fileURLToPath8(import.meta.url)), "..", "package.json");
25246
+ const pkgPath = join36(dirname11(fileURLToPath8(import.meta.url)), "..", "package.json");
24648
25247
  const pkg = require2(pkgPath);
24649
25248
  return pkg.version;
24650
25249
  } catch {