orion-super-agent-dev 0.1.28 → 0.1.30

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.
@@ -1442,6 +1442,8 @@ ${JSON.stringify(t2, null, 2)}`);
1442
1442
  });
1443
1443
 
1444
1444
  // ../packages/orion-client-core/src/indexProcessWorker.ts
1445
+ var import_fs4 = require("fs");
1446
+ var path6 = __toESM(require("path"));
1445
1447
  var v8 = __toESM(require("v8"));
1446
1448
 
1447
1449
  // ../packages/orion-client-core/src/nodeFileSource.ts
@@ -1725,26 +1727,26 @@ function tokenizeSearchText(text) {
1725
1727
  function tokenizeContentText(text) {
1726
1728
  return [...iterateTokens(text)];
1727
1729
  }
1728
- function pathSegments(path5) {
1729
- return path5.replace(/\\/g, "/").split("/").filter(Boolean);
1730
+ function pathSegments(path7) {
1731
+ return path7.replace(/\\/g, "/").split("/").filter(Boolean);
1730
1732
  }
1731
- function basenameOf(path5) {
1732
- const parts2 = pathSegments(path5);
1733
- return parts2.at(-1) ?? path5;
1733
+ function basenameOf(path7) {
1734
+ const parts2 = pathSegments(path7);
1735
+ return parts2.at(-1) ?? path7;
1734
1736
  }
1735
1737
  function stripExtension(name2) {
1736
1738
  const dot = name2.lastIndexOf(".");
1737
1739
  return dot > 0 ? name2.slice(0, dot) : name2;
1738
1740
  }
1739
- function acronymForPath(path5) {
1740
- return pathSegments(path5).map((segment) => stripExtension(segment).match(/[A-Za-z0-9]/)?.[0] ?? "").join("").toLowerCase();
1741
+ function acronymForPath(path7) {
1742
+ return pathSegments(path7).map((segment) => stripExtension(segment).match(/[A-Za-z0-9]/)?.[0] ?? "").join("").toLowerCase();
1741
1743
  }
1742
- function isConfigPath(path5) {
1743
- const lower = path5.toLowerCase();
1744
+ function isConfigPath(path7) {
1745
+ const lower = path7.toLowerCase();
1744
1746
  return lower.endsWith(".json") || lower.endsWith(".yaml") || lower.endsWith(".yml") || lower.endsWith(".toml") || lower.endsWith(".sql") || lower.endsWith("dockerfile");
1745
1747
  }
1746
- function isMarkdownPath(path5) {
1747
- const lower = path5.toLowerCase();
1748
+ function isMarkdownPath(path7) {
1749
+ const lower = path7.toLowerCase();
1748
1750
  return lower.endsWith(".md") || lower.endsWith(".markdown");
1749
1751
  }
1750
1752
  function attentionRanker(attention) {
@@ -1876,8 +1878,8 @@ function cleanPreview(text) {
1876
1878
  const collapsed = text.replace(/\s+/g, " ").trim();
1877
1879
  return collapsed.length > MAX_PREVIEW_CHARS ? collapsed.slice(0, MAX_PREVIEW_CHARS).trimEnd() + "..." : collapsed;
1878
1880
  }
1879
- function chunkId(path5, startLine, kind, title) {
1880
- return `${path5}:${startLine}:${kind}:${title}`;
1881
+ function chunkId(path7, startLine, kind, title) {
1882
+ return `${path7}:${startLine}:${kind}:${title}`;
1881
1883
  }
1882
1884
  function firstCommentTokens(lines) {
1883
1885
  const picked = [];
@@ -1889,7 +1891,7 @@ function firstCommentTokens(lines) {
1889
1891
  }
1890
1892
  return tokenizeSearchText(picked.join(" "));
1891
1893
  }
1892
- function makeChunk(path5, lines, startLine, endLine, kind, title) {
1894
+ function makeChunk(path7, lines, startLine, endLine, kind, title) {
1893
1895
  const safeStart = Math.max(1, startLine);
1894
1896
  const safeEnd = Math.max(safeStart, Math.min(lines.length, endLine));
1895
1897
  const slice = lines.slice(safeStart - 1, safeEnd);
@@ -1899,12 +1901,12 @@ function makeChunk(path5, lines, startLine, endLine, kind, title) {
1899
1901
  const commentTokens = firstCommentTokens(slice);
1900
1902
  if (tokens.length === 0 && titleTokens.length === 0) return null;
1901
1903
  return {
1902
- id: chunkId(path5, safeStart, kind, title || path5),
1903
- path: path5,
1904
+ id: chunkId(path7, safeStart, kind, title || path7),
1905
+ path: path7,
1904
1906
  startLine: safeStart,
1905
1907
  endLine: safeEnd,
1906
1908
  kind,
1907
- title: title || path5,
1909
+ title: title || path7,
1908
1910
  preview: cleanPreview(text),
1909
1911
  tokens,
1910
1912
  titleTokens,
@@ -1918,7 +1920,7 @@ function frontmatterValue(block, field) {
1918
1920
  }
1919
1921
  return "";
1920
1922
  }
1921
- function frontmatterChunk(path5, lines) {
1923
+ function frontmatterChunk(path7, lines) {
1922
1924
  if ((lines[0] ?? "").trim() !== "---") return null;
1923
1925
  let close = -1;
1924
1926
  for (let i2 = 1; i2 < Math.min(lines.length, 60); i2++) {
@@ -1931,9 +1933,9 @@ function frontmatterChunk(path5, lines) {
1931
1933
  const block = lines.slice(1, close).map((line) => line.replace(/\r$/, ""));
1932
1934
  const facets = ["type", "title", "name", "description", "tags"].map((field) => frontmatterValue(block, field)).filter((value) => value.length > 0);
1933
1935
  if (facets.length === 0) return null;
1934
- return makeChunk(path5, lines, 1, close + 1, "frontmatter", facets.join(" \u2014 "));
1936
+ return makeChunk(path7, lines, 1, close + 1, "frontmatter", facets.join(" \u2014 "));
1935
1937
  }
1936
- function buildChunksForFile(path5, content, symbols, fileSummary) {
1938
+ function buildChunksForFile(path7, content, symbols, fileSummary) {
1937
1939
  const lines = content.split("\n");
1938
1940
  const chunks = [];
1939
1941
  const sorted = [...symbols].sort((a, b) => a.line - b.line);
@@ -1941,8 +1943,8 @@ function buildChunksForFile(path5, content, symbols, fileSummary) {
1941
1943
  const headerEnd = sorted[0].line - 1;
1942
1944
  for (let start2 = 1; start2 <= headerEnd; start2 += WINDOW_LINES - WINDOW_OVERLAP) {
1943
1945
  const end = Math.min(headerEnd, start2 + WINDOW_LINES - 1);
1944
- const title = start2 === 1 && fileSummary ? fileSummary : `${path5}:${start2}-${end}`;
1945
- const chunk = makeChunk(path5, lines, start2, end, "window", title);
1946
+ const title = start2 === 1 && fileSummary ? fileSummary : `${path7}:${start2}-${end}`;
1947
+ const chunk = makeChunk(path7, lines, start2, end, "window", title);
1946
1948
  if (chunk) chunks.push(chunk);
1947
1949
  if (end >= headerEnd) break;
1948
1950
  }
@@ -1952,25 +1954,25 @@ function buildChunksForFile(path5, content, symbols, fileSummary) {
1952
1954
  const next = sorted[i2 + 1];
1953
1955
  const end = next ? Math.max(sym.line, next.line - 1) : lines.length;
1954
1956
  const kind = ["function", "method", "class"].includes(sym.kind) ? sym.kind : "module";
1955
- const chunk = makeChunk(path5, lines, sym.line, end, kind, sym.signature || sym.name);
1957
+ const chunk = makeChunk(path7, lines, sym.line, end, kind, sym.signature || sym.name);
1956
1958
  if (chunk) chunks.push(chunk);
1957
1959
  }
1958
- if (isMarkdownPath(path5)) {
1959
- const fmChunk = frontmatterChunk(path5, lines);
1960
+ if (isMarkdownPath(path7)) {
1961
+ const fmChunk = frontmatterChunk(path7, lines);
1960
1962
  if (fmChunk) chunks.push(fmChunk);
1961
1963
  const headingLines = lines.map((line, i2) => ({ line, i: i2 + 1 })).filter((x) => /^#{1,6}\s+/.test(x.line));
1962
1964
  for (let i2 = 0; i2 < headingLines.length; i2++) {
1963
1965
  const h = headingLines[i2];
1964
1966
  const end = headingLines[i2 + 1] ? headingLines[i2 + 1].i - 1 : lines.length;
1965
- const chunk = makeChunk(path5, lines, h.i, end, "markdown_section", h.line.replace(/^#+\s*/, ""));
1967
+ const chunk = makeChunk(path7, lines, h.i, end, "markdown_section", h.line.replace(/^#+\s*/, ""));
1966
1968
  if (chunk) chunks.push(chunk);
1967
1969
  }
1968
1970
  }
1969
- if (chunks.length === 0 || isConfigPath(path5)) {
1971
+ if (chunks.length === 0 || isConfigPath(path7)) {
1970
1972
  for (let start2 = 1; start2 <= lines.length; start2 += WINDOW_LINES - WINDOW_OVERLAP) {
1971
1973
  const end = Math.min(lines.length, start2 + WINDOW_LINES - 1);
1972
- const title = start2 === 1 && fileSummary ? fileSummary : `${path5}:${start2}-${end}`;
1973
- const chunk = makeChunk(path5, lines, start2, end, isConfigPath(path5) ? "config" : "window", title);
1974
+ const title = start2 === 1 && fileSummary ? fileSummary : `${path7}:${start2}-${end}`;
1975
+ const chunk = makeChunk(path7, lines, start2, end, isConfigPath(path7) ? "config" : "window", title);
1974
1976
  if (chunk) chunks.push(chunk);
1975
1977
  if (end >= lines.length) break;
1976
1978
  }
@@ -2006,17 +2008,17 @@ var ContentChunkIndex = class _ContentChunkIndex {
2006
2008
  this.clear();
2007
2009
  for (const chunk of chunks) this.insert(chunk);
2008
2010
  }
2009
- replacePath(path5, chunks) {
2011
+ replacePath(path7, chunks) {
2010
2012
  this.membershipMemo.clear();
2011
- this.removePath(path5);
2013
+ this.removePath(path7);
2012
2014
  for (const chunk of chunks) this.insert(chunk);
2013
2015
  }
2014
- removePath(path5) {
2016
+ removePath(path7) {
2015
2017
  this.membershipMemo.clear();
2016
- const ids = this.chunksByPath.get(path5);
2018
+ const ids = this.chunksByPath.get(path7);
2017
2019
  if (!ids) return;
2018
2020
  for (const id of ids) this.removeChunk(id);
2019
- this.chunksByPath.delete(path5);
2021
+ this.chunksByPath.delete(path7);
2020
2022
  }
2021
2023
  size() {
2022
2024
  return this.chunks.size;
@@ -2126,8 +2128,8 @@ var ContentChunkIndex = class _ContentChunkIndex {
2126
2128
  }
2127
2129
  return hits.sort((a, b) => b.score - a.score || a.path.localeCompare(b.path) || a.startLine - b.startLine).slice(0, options.limit ?? 20);
2128
2130
  }
2129
- bestChunksForPath(path5, limit = 3) {
2130
- return [...this.chunksByPath.get(path5) ?? []].map((id) => this.chunks.get(id)).filter((c) => Boolean(c)).sort((a, b) => a.startLine - b.startLine).slice(0, limit).map((c) => this.toIndexedChunk(c));
2131
+ bestChunksForPath(path7, limit = 3) {
2132
+ return [...this.chunksByPath.get(path7) ?? []].map((id) => this.chunks.get(id)).filter((c) => Boolean(c)).sort((a, b) => a.startLine - b.startLine).slice(0, limit).map((c) => this.toIndexedChunk(c));
2131
2133
  }
2132
2134
  /** Reconstruct the IndexedChunk shape (token multiset from interned term
2133
2135
  * frequencies — order-insensitive by contract) for the handful of chunks
@@ -2230,8 +2232,8 @@ function computeRelatedPaths(touched, dependentsOf, limit = 16) {
2230
2232
  const touchedSet = new Set(touched.map((p) => p.trim()).filter((p) => p.length > 0));
2231
2233
  const related = [];
2232
2234
  const seen = /* @__PURE__ */ new Set();
2233
- for (const path5 of touchedSet) {
2234
- for (const dep of dependentsOf(path5)) {
2235
+ for (const path7 of touchedSet) {
2236
+ for (const dep of dependentsOf(path7)) {
2235
2237
  const d = dep.trim();
2236
2238
  if (!d || touchedSet.has(d) || seen.has(d)) continue;
2237
2239
  seen.add(d);
@@ -2242,31 +2244,31 @@ function computeRelatedPaths(touched, dependentsOf, limit = 16) {
2242
2244
  return related;
2243
2245
  }
2244
2246
  function indexDependents(index, perSymbolLimit = 20) {
2245
- return (path5) => {
2247
+ return (path7) => {
2246
2248
  const out2 = [];
2247
2249
  const seen = /* @__PURE__ */ new Set();
2248
2250
  const add = (edges) => {
2249
2251
  for (const edge of edges) {
2250
2252
  const src = edge.source_path;
2251
- if (src && src !== path5 && !seen.has(src)) {
2253
+ if (src && src !== path7 && !seen.has(src)) {
2252
2254
  seen.add(src);
2253
2255
  out2.push(src);
2254
2256
  }
2255
2257
  }
2256
2258
  };
2257
- for (const symbol of index.byPath.get(path5) ?? []) {
2259
+ for (const symbol of index.byPath.get(path7) ?? []) {
2258
2260
  add(index.findCallers(symbol.name, { limit: perSymbolLimit }));
2259
2261
  }
2260
- const moduleName = path5.split("/").pop()?.replace(/\.[^.]+$/, "") ?? "";
2262
+ const moduleName = path7.split("/").pop()?.replace(/\.[^.]+$/, "") ?? "";
2261
2263
  if (moduleName) add(index.findImporters(moduleName, { limit: perSymbolLimit }));
2262
2264
  return out2;
2263
2265
  };
2264
2266
  }
2265
2267
 
2266
2268
  // ../packages/orion-client-core/src/pathIndex.ts
2267
- function isConfigOrDocPath(path5) {
2268
- if (isConfigPath(path5) || isMarkdownPath(path5)) return true;
2269
- const lower = path5.toLowerCase();
2269
+ function isConfigOrDocPath(path7) {
2270
+ if (isConfigPath(path7) || isMarkdownPath(path7)) return true;
2271
+ const lower = path7.toLowerCase();
2270
2272
  return lower.endsWith(".sh") || lower.endsWith(".bash") || lower.includes("/.github/") || lower.includes("/.gitlab/");
2271
2273
  }
2272
2274
  var PathIndex = class {
@@ -2276,29 +2278,29 @@ var PathIndex = class {
2276
2278
  }
2277
2279
  replace(paths, meta) {
2278
2280
  this.clear();
2279
- for (const path5 of paths) this.upsert(path5, meta.get(path5));
2281
+ for (const path7 of paths) this.upsert(path7, meta.get(path7));
2280
2282
  }
2281
- upsert(path5, meta) {
2282
- const basename = basenameOf(path5);
2283
+ upsert(path7, meta) {
2284
+ const basename = basenameOf(path7);
2283
2285
  const basenameStem = stripExtension(basename);
2284
- const segments = pathSegments(path5);
2286
+ const segments = pathSegments(path7);
2285
2287
  const tokens = /* @__PURE__ */ new Set();
2286
- for (const value of [path5, basename, basenameStem, ...segments]) {
2288
+ for (const value of [path7, basename, basenameStem, ...segments]) {
2287
2289
  for (const token of tokenizeIdentifier(value)) tokens.add(token);
2288
2290
  }
2289
- this.entries.set(path5, {
2290
- path: path5,
2291
- lowerPath: path5.toLowerCase(),
2291
+ this.entries.set(path7, {
2292
+ path: path7,
2293
+ lowerPath: path7.toLowerCase(),
2292
2294
  basename: basename.toLowerCase(),
2293
2295
  basenameStem: basenameStem.toLowerCase(),
2294
2296
  segments: segments.map((s) => s.toLowerCase()),
2295
2297
  tokens,
2296
- acronym: acronymForPath(path5),
2298
+ acronym: acronymForPath(path7),
2297
2299
  meta
2298
2300
  });
2299
2301
  }
2300
- remove(path5) {
2301
- this.entries.delete(path5);
2302
+ remove(path7) {
2303
+ this.entries.delete(path7);
2302
2304
  }
2303
2305
  size() {
2304
2306
  return this.entries.size;
@@ -2646,27 +2648,27 @@ var KNOWN_EDGE_KINDS = /* @__PURE__ */ new Set([
2646
2648
  "implements",
2647
2649
  "references"
2648
2650
  ]);
2649
- function isTestPath(path5) {
2650
- const p = "/" + path5.toLowerCase();
2651
+ function isTestPath(path7) {
2652
+ const p = "/" + path7.toLowerCase();
2651
2653
  if (TEST_SUBSTRINGS.some((s) => p.includes(s))) return true;
2652
- const base = path5.toLowerCase().split("/").pop() ?? "";
2654
+ const base = path7.toLowerCase().split("/").pop() ?? "";
2653
2655
  return base.startsWith("test_") || base.endsWith("_test.go");
2654
2656
  }
2655
- function isGeneratedPath(path5) {
2656
- const lower = path5.toLowerCase();
2657
+ function isGeneratedPath(path7) {
2658
+ const lower = path7.toLowerCase();
2657
2659
  const p = "/" + lower;
2658
2660
  return GENERATED_SUBSTRINGS.some((s) => p.includes(s)) || GENERATED_SUFFIXES.some((s) => lower.endsWith(s));
2659
2661
  }
2660
- function pathStems(path5) {
2661
- const parts2 = path5.replace(/\\/g, "/").split("/").filter(Boolean);
2662
+ function pathStems(path7) {
2663
+ const parts2 = path7.replace(/\\/g, "/").split("/").filter(Boolean);
2662
2664
  if (parts2.length === 0) return [];
2663
2665
  const last = parts2[parts2.length - 1];
2664
2666
  const dot = last.lastIndexOf(".");
2665
2667
  if (dot > 0) parts2[parts2.length - 1] = last.slice(0, dot);
2666
2668
  return parts2.map((p) => p.toLowerCase()).filter(Boolean);
2667
2669
  }
2668
- function dirnamePath(path5) {
2669
- const parts2 = path5.replace(/\\/g, "/").split("/");
2670
+ function dirnamePath(path7) {
2671
+ const parts2 = path7.replace(/\\/g, "/").split("/");
2670
2672
  parts2.pop();
2671
2673
  return parts2.join("/");
2672
2674
  }
@@ -2680,11 +2682,11 @@ function joinRelPath(base, spec) {
2680
2682
  }
2681
2683
  return out2.join("/");
2682
2684
  }
2683
- function withoutKnownExtension(path5) {
2684
- return path5.replace(/\.(tsx?|jsx?|mjs|cjs|py|go|rs|java|kt|kts|scala|rb)$/i, "");
2685
+ function withoutKnownExtension(path7) {
2686
+ return path7.replace(/\.(tsx?|jsx?|mjs|cjs|py|go|rs|java|kt|kts|scala|rb)$/i, "");
2685
2687
  }
2686
- function normalizeTracePath(path5) {
2687
- return path5.trim().replace(/\\/g, "/").replace(/^file:\/\//, "").replace(/^\/+/, "").replace(/[:#]L?\d+(?::\d+)?$/, "").replace(/^['"`]|['"`]$/g, "");
2688
+ function normalizeTracePath(path7) {
2689
+ return path7.trim().replace(/\\/g, "/").replace(/^file:\/\//, "").replace(/^\/+/, "").replace(/[:#]L?\d+(?::\d+)?$/, "").replace(/^['"`]|['"`]$/g, "");
2688
2690
  }
2689
2691
  function looksPathLike(value) {
2690
2692
  return /[\\/]/.test(value) || /\.[A-Za-z0-9]+(?::\d+)?$/.test(value);
@@ -2721,21 +2723,16 @@ function clampInt(value, fallback, low, high) {
2721
2723
  if (!Number.isFinite(n)) return fallback;
2722
2724
  return Math.max(low, Math.min(high, Math.trunc(n)));
2723
2725
  }
2724
- function scopeFilter(path5, scope) {
2726
+ function scopeFilter(path7, scope) {
2725
2727
  const s = String(scope ?? "").trim().replace(/\\/g, "/").replace(/^\/+|\/+$/g, "");
2726
2728
  if (!s || s === ".") return true;
2727
- return path5 === s || path5.startsWith(s + "/");
2729
+ return path7 === s || path7.startsWith(s + "/");
2728
2730
  }
2729
2731
  function detailLimit(detail, brief, normal, deep) {
2730
2732
  if (detail === "brief") return brief;
2731
2733
  if (detail === "deep") return deep;
2732
2734
  return normal;
2733
2735
  }
2734
- var DEFAULT_RETRIEVAL_MODE = "default";
2735
- function normalizeRetrievalMode(value, fallback = DEFAULT_RETRIEVAL_MODE) {
2736
- if (value === "default" || value === "enhanced") return value;
2737
- return fallback;
2738
- }
2739
2736
  var CONTENT_PROBE_DEADLINE_MS = 600;
2740
2737
  async function boundedAll(promises2, deadlineMs) {
2741
2738
  if (promises2.length === 0) return [];
@@ -2825,9 +2822,9 @@ function fuseHits(hitLists, topK) {
2825
2822
  for (const hits of hitLists) {
2826
2823
  const votedThisList = /* @__PURE__ */ new Set();
2827
2824
  hits.forEach((hit, i2) => {
2828
- const path5 = String(hit.path ?? "");
2825
+ const path7 = String(hit.path ?? "");
2829
2826
  const type = String(hit.result_type ?? "match");
2830
- const key = path5 || `${type}:${i2}`;
2827
+ const key = path7 || `${type}:${i2}`;
2831
2828
  if (votedThisList.has(key)) return;
2832
2829
  votedThisList.add(key);
2833
2830
  scores.set(key, (scores.get(key) ?? 0) + 1 / (60 + i2 + 1));
@@ -2985,8 +2982,8 @@ var WorkspaceIndexStore = class {
2985
2982
  this.setMeta(file, snapshot.file_meta[file]);
2986
2983
  }
2987
2984
  this.pathIndex.replace(this.files, this.fileMeta);
2988
- for (const [path5, summary] of Object.entries(snapshot.file_summaries)) {
2989
- if (summary) this.fileSummaries.set(path5, String(summary));
2985
+ for (const [path7, summary] of Object.entries(snapshot.file_summaries)) {
2986
+ if (summary) this.fileSummaries.set(path7, String(summary));
2990
2987
  }
2991
2988
  for (const sym of snapshot.symbols) this.insertSymbol(sym);
2992
2989
  for (const edge of snapshot.edges) this.insertEdge(edge);
@@ -3117,19 +3114,19 @@ var WorkspaceIndexStore = class {
3117
3114
  this.totalFiles = Math.max(this.totalFiles, this.processedFiles);
3118
3115
  }
3119
3116
  }
3120
- removeFile(path5) {
3117
+ removeFile(path7) {
3121
3118
  this.noteMutation();
3122
3119
  const refreshTargets = /* @__PURE__ */ new Set();
3123
- for (const sym of this.byPath.get(path5) ?? []) {
3120
+ for (const sym of this.byPath.get(path7) ?? []) {
3124
3121
  const name2 = sym.name.toLowerCase();
3125
3122
  if (name2) refreshTargets.add(name2);
3126
3123
  }
3127
- for (const stem of this.pathStemsByFile.get(path5) ?? []) {
3124
+ for (const stem of this.pathStemsByFile.get(path7) ?? []) {
3128
3125
  if (stem) refreshTargets.add(stem);
3129
3126
  }
3130
- this.removePath(path5);
3131
- this.files.delete(path5);
3132
- this.removePathStems(path5);
3127
+ this.removePath(path7);
3128
+ this.files.delete(path7);
3129
+ this.removePathStems(path7);
3133
3130
  for (const target of refreshTargets) this.refreshEdgeResolutionForTarget(target);
3134
3131
  this.indexedAt = Date.now() / 1e3;
3135
3132
  if (this.buildState === "empty") this.buildState = "partial";
@@ -3228,11 +3225,11 @@ var WorkspaceIndexStore = class {
3228
3225
  const now = Date.now() / 1e3;
3229
3226
  return filtered.map((s) => [s, this.scoreSymbol(s, needle, needleTokens, options.attention, now)]).sort((a, b) => b[1] - a[1] || a[0].path.localeCompare(b[0].path) || a[0].line - b[0].line).slice(0, options.limit ?? 50);
3230
3227
  }
3231
- listSymbols(path5) {
3232
- return [...this.byPath.get(path5) ?? []].sort((a, b) => a.line - b.line);
3228
+ listSymbols(path7) {
3229
+ return [...this.byPath.get(path7) ?? []].sort((a, b) => a.line - b.line);
3233
3230
  }
3234
- enclosingSymbol(path5, line) {
3235
- const syms = this.listSymbols(path5);
3231
+ enclosingSymbol(path7, line) {
3232
+ const syms = this.listSymbols(path7);
3236
3233
  let candidate = null;
3237
3234
  let nextStart = null;
3238
3235
  for (const sym of syms) {
@@ -3394,14 +3391,13 @@ var WorkspaceIndexStore = class {
3394
3391
  const missRank = options.attention?.length ?? 0;
3395
3392
  return [...candidates].map((p) => [p, sets.filter((s) => s.has(p)).length]).sort((a, b) => b[1] - a[1] || (attentionRank.get(a[0]) ?? missRank) - (attentionRank.get(b[0]) ?? missRank) || a[0].localeCompare(b[0])).slice(0, options.topK ?? 30);
3396
3393
  }
3397
- async searchCodebase(input, options = {}) {
3394
+ async searchCodebase(input) {
3398
3395
  const query = String(input.query ?? "").trim();
3399
3396
  if (!query) throw new Error("`query` is required");
3400
3397
  const scope = String(input.scope ?? "").trim() || void 0;
3401
3398
  const detail = ["brief", "normal", "deep"].includes(String(input.detail)) ? String(input.detail) : "normal";
3402
3399
  const intent = String(input.intent ?? "auto");
3403
3400
  const maxResults = clampInt(input.max_results, 8, 1, 25);
3404
- const retrievalMode = normalizeRetrievalMode(options.retrievalMode);
3405
3401
  const status = this.status();
3406
3402
  if (!status.ready) {
3407
3403
  return [
@@ -3416,8 +3412,8 @@ var WorkspaceIndexStore = class {
3416
3412
  const perSource = Math.max(maxResults, 12);
3417
3413
  const termSets = await this.termFileSets(queryTerms(query));
3418
3414
  const symbols = this.symbolHitsForQuery(query, perSource, attention, scope);
3419
- const files = retrievalMode === "enhanced" ? this.rankedFileHits(query, perSource, attention, scope, termSets) : this.basicFileHitsForQuery(query, perSource, attention, scope, termSets);
3420
- const content = await this.contentHitsForQuery(query, perSource, attention, scope, retrievalMode, termSets);
3415
+ const files = this.fileHitsForQuery(query, perSource, attention, scope, termSets);
3416
+ const content = await this.contentHitsForQuery(query, perSource, attention, scope, termSets);
3421
3417
  const seeds = this.graphExpansionSeeds(symbols, files);
3422
3418
  const graph = seeds.length > 0 ? this.graphHitsForQuery(seeds, perSource, scope, queryTerms(query), termSets) : [];
3423
3419
  const merged = fuseHits([symbols, files, content, graph], maxResults);
@@ -3430,7 +3426,7 @@ var WorkspaceIndexStore = class {
3430
3426
  `- query: ${query}`,
3431
3427
  `- intent: ${intent}`,
3432
3428
  `- scope: ${scope ?? "."}`,
3433
- `- retrieval_mode: ${retrievalMode}`,
3429
+ "- retrieval_level: normal",
3434
3430
  "",
3435
3431
  "Top Files"
3436
3432
  ];
@@ -3460,21 +3456,19 @@ var WorkspaceIndexStore = class {
3460
3456
  let cardRank = 0;
3461
3457
  for (const [p, cardReasons] of topPaths.slice(0, maxResults)) {
3462
3458
  cardRank += 1;
3463
- lines.push(...this.renderFileCard(p, cardRank, cardReasons, detail, retrievalMode, relatedByPath.get(p)));
3464
- }
3465
- if (retrievalMode === "enhanced") {
3466
- const chunkLimit = detailLimit(detail, 3, 6, 10);
3467
- const chunkHits = content.filter((hit) => hit.result_type === "chunk").slice(0, chunkLimit);
3468
- if (chunkHits.length > 0) {
3469
- lines.push("", "Top Matches");
3470
- for (const hit of chunkHits) {
3471
- const reasons = Array.isArray(hit.reasons) ? hit.reasons.map(String).join(", ") : "chunk";
3472
- lines.push(
3473
- `- ${hit.path}:${hit.line}-${hit.end_line} [${hit.kind}] ${hit.name} (score=${hit.score}; ${reasons})`
3474
- );
3475
- if (hit.preview) lines.push(` Preview: ${hit.preview}`);
3476
- lines.push(` Next read: read_file path=${hit.path} start_line=${hit.line} end_line=${hit.end_line} context=dependencies`);
3477
- }
3459
+ lines.push(...this.renderFileCard(p, cardRank, cardReasons, detail, relatedByPath.get(p)));
3460
+ }
3461
+ const chunkLimit = detailLimit(detail, 3, 6, 10);
3462
+ const chunkHits = content.filter((hit) => hit.result_type === "chunk").slice(0, chunkLimit);
3463
+ if (chunkHits.length > 0) {
3464
+ lines.push("", "Top Matches");
3465
+ for (const hit of chunkHits) {
3466
+ const reasons = Array.isArray(hit.reasons) ? hit.reasons.map(String).join(", ") : "chunk";
3467
+ lines.push(
3468
+ `- ${hit.path}:${hit.line}-${hit.end_line} [${hit.kind}] ${hit.name} (score=${hit.score}; ${reasons})`
3469
+ );
3470
+ if (hit.preview) lines.push(` Preview: ${hit.preview}`);
3471
+ lines.push(` Next read: read_file path=${hit.path} start_line=${hit.line} end_line=${hit.end_line} context=dependencies`);
3478
3472
  }
3479
3473
  }
3480
3474
  const symbolLimit = detailLimit(detail, 3, 6, 10);
@@ -3515,12 +3509,11 @@ var WorkspaceIndexStore = class {
3515
3509
  );
3516
3510
  return lines.join("\n");
3517
3511
  }
3518
- async traceCodebase(input, options = {}) {
3512
+ async traceCodebase(input) {
3519
3513
  const target = String(input.target ?? "").trim();
3520
3514
  if (!target) throw new Error("`target` is required");
3521
3515
  const parsedTarget = parseTraceTarget(target, input.path);
3522
3516
  const targetName = parsedTarget.name.trim() || target;
3523
- const retrievalMode = normalizeRetrievalMode(options.retrievalMode);
3524
3517
  const relation = ["auto", "impact", "callers", "importers", "references", "hierarchy", "dependencies"].includes(String(input.relation)) ? String(input.relation) : "auto";
3525
3518
  const scope = String(input.scope ?? "").trim() || void 0;
3526
3519
  const depth = clampInt(input.depth, 2, 1, 6);
@@ -3535,7 +3528,7 @@ var WorkspaceIndexStore = class {
3535
3528
  `Use grep for "${targetName}" until enough files are indexed.`
3536
3529
  ].join("\n");
3537
3530
  }
3538
- const targets = this.resolveTraceTargets(targetName, scope, 5, parsedTarget.pathHint, retrievalMode);
3531
+ const targets = this.resolveTraceTargets(targetName, scope, 5, parsedTarget.pathHint);
3539
3532
  const selected = targets[0] ?? { name: targetName, path: "", line: 1, kind: "unknown", score: 0 };
3540
3533
  const selectedName = String(selected.name || targetName).split(".").pop() ?? targetName;
3541
3534
  const selectedPath = String(selected.path || "");
@@ -3611,7 +3604,7 @@ var WorkspaceIndexStore = class {
3611
3604
  }
3612
3605
  }
3613
3606
  if (structuralHitCount === 0) {
3614
- lines.push("", ...await this.formatTraceFallback(selectedName, selectedPath, scope, detailLimit("normal", 3, 6, 10), retrievalMode));
3607
+ lines.push("", ...await this.formatTraceFallback(selectedName, selectedPath, scope, detailLimit("normal", 3, 6, 10)));
3615
3608
  }
3616
3609
  const suggested = dedupe(
3617
3610
  [
@@ -3638,13 +3631,12 @@ var WorkspaceIndexStore = class {
3638
3631
  }
3639
3632
  return lines.join("\n");
3640
3633
  }
3641
- async readContextHeader(path5, startLine, mode, options = {}) {
3634
+ async readContextHeader(path7, startLine, mode) {
3642
3635
  if (mode === "none" || !this.status().ready) return "";
3643
- const retrievalMode = normalizeRetrievalMode(options.retrievalMode);
3644
- const summary = this.fileSummaryFor(path5);
3645
- const syms = this.listSymbols(path5);
3646
- const imports = [...this.edgesOutByPath.get(path5) ?? []].filter((e) => e.kind === "imports" && e.target).map((e) => e.target);
3647
- const enclosing = this.enclosingSymbol(path5, startLine);
3636
+ const summary = this.fileSummaryFor(path7);
3637
+ const syms = this.listSymbols(path7);
3638
+ const imports = [...this.edgesOutByPath.get(path7) ?? []].filter((e) => e.kind === "imports" && e.target).map((e) => e.target);
3639
+ const enclosing = this.enclosingSymbol(path7, startLine);
3648
3640
  let parentClass = null;
3649
3641
  if (enclosing && (enclosing[0].kind === "function" || enclosing[0].kind === "method")) {
3650
3642
  for (const sym of syms) {
@@ -3654,7 +3646,7 @@ var WorkspaceIndexStore = class {
3654
3646
  }
3655
3647
  if (!summary && !parentClass && !enclosing && imports.length === 0 && syms.length === 0) return "";
3656
3648
  const lines = ["--- codebase context ---"];
3657
- if (summary) lines.push(`file: ${path5} - ${summary}`);
3649
+ if (summary) lines.push(`file: ${path7} - ${summary}`);
3658
3650
  if (parentClass) lines.push(`class: ${parentClass.path}:${parentClass.line} [${parentClass.kind}] ${parentClass.signature || parentClass.name}`);
3659
3651
  if (enclosing) {
3660
3652
  const [sym, end] = enclosing;
@@ -3675,13 +3667,13 @@ var WorkspaceIndexStore = class {
3675
3667
  }
3676
3668
  }
3677
3669
  if (["dependencies", "full", "auto"].includes(mode)) {
3678
- const related = await this.relatedContextForPath(path5, mode === "full" ? 8 : 4);
3670
+ const related = await this.relatedContextForPath(path7, mode === "full" ? 8 : 4);
3679
3671
  if (related.dependencies.length > 0) lines.push(`depends on: ${related.dependencies.join(", ")}`);
3680
3672
  if (related.dependents.length > 0) lines.push(`used by: ${related.dependents.join(", ")}`);
3681
3673
  if (related.tests.length > 0) lines.push(`related tests: ${related.tests.join(", ")}`);
3682
3674
  }
3683
- if (retrievalMode === "enhanced" && mode === "full" && this.chunkIndex.size() > 0) {
3684
- const chunks = this.chunkIndex.bestChunksForPath(path5, 4);
3675
+ if (mode === "full" && this.chunkIndex.size() > 0) {
3676
+ const chunks = this.chunkIndex.bestChunksForPath(path7, 4);
3685
3677
  if (chunks.length > 0) {
3686
3678
  lines.push(`chunks: ${chunks.map((c) => `${c.title}@${c.startLine}-${c.endLine}`).join(", ")}`);
3687
3679
  }
@@ -3707,34 +3699,28 @@ var WorkspaceIndexStore = class {
3707
3699
  }
3708
3700
  return hits;
3709
3701
  }
3710
- rankedFileHits(query, limit, attention, scope, termSets) {
3711
- return this.fileHitsForQuery(query, limit, attention, scope, true, termSets);
3712
- }
3713
- basicFileHitsForQuery(query, limit, attention, scope, termSets) {
3714
- return this.fileHitsForQuery(query, limit, attention, scope, false, termSets);
3715
- }
3716
- fileHitsForQuery(query, limit, attention, scope, includePathIndex, termSets) {
3702
+ fileHitsForQuery(query, limit, attention, scope, termSets) {
3717
3703
  const terms = queryTerms(query);
3718
3704
  const queryLc = query.toLowerCase().trim();
3719
3705
  const hits = [];
3720
- const pathHits = includePathIndex ? new Map(
3706
+ const pathHits = new Map(
3721
3707
  this.pathIndex.search(query, { limit: Math.max(limit * 4, 50), scope, attention, includeDocs: true }).map((hit) => [hit.path, hit])
3722
- ) : /* @__PURE__ */ new Map();
3708
+ );
3723
3709
  if (/[*?[\]]/.test(query)) {
3724
- for (const path5 of this.findFiles(query, limit * 2)) {
3725
- if (scopeFilter(path5, scope)) hits.push([100, path5, ["glob"]]);
3710
+ for (const path7 of this.findFiles(query, limit * 2)) {
3711
+ if (scopeFilter(path7, scope)) hits.push([100, path7, ["glob"]]);
3726
3712
  }
3727
3713
  if (hits.length > 0) {
3728
- return hits.sort((a, b) => b[0] - a[0] || a[1].localeCompare(b[1])).slice(0, limit).map(([score, path5, reasons]) => ({ result_type: "file", path: path5, score, reasons }));
3714
+ return hits.sort((a, b) => b[0] - a[0] || a[1].localeCompare(b[1])).slice(0, limit).map(([score, path7, reasons]) => ({ result_type: "file", path: path7, score, reasons }));
3729
3715
  }
3730
3716
  }
3731
- for (const path5 of this.files) {
3732
- if (!scopeFilter(path5, scope)) continue;
3717
+ for (const path7 of this.files) {
3718
+ if (!scopeFilter(path7, scope)) continue;
3733
3719
  let score = 0;
3734
3720
  const reasons = [];
3735
- const pathLc = path5.toLowerCase();
3736
- const summaryLc = (this.fileSummaries.get(path5) ?? "").toLowerCase();
3737
- const pathHit = pathHits.get(path5);
3721
+ const pathLc = path7.toLowerCase();
3722
+ const summaryLc = (this.fileSummaries.get(path7) ?? "").toLowerCase();
3723
+ const pathHit = pathHits.get(path7);
3738
3724
  if (pathHit) {
3739
3725
  score += pathHit.score;
3740
3726
  reasons.push(...pathHit.reasons);
@@ -3752,24 +3738,24 @@ var WorkspaceIndexStore = class {
3752
3738
  score += 8;
3753
3739
  if (!reasons.includes("summary")) reasons.push("summary");
3754
3740
  }
3755
- if (termSets.get(term)?.has(path5)) {
3741
+ if (termSets.get(term)?.has(path7)) {
3756
3742
  score += 5;
3757
3743
  if (!reasons.includes("content")) reasons.push("content");
3758
3744
  }
3759
3745
  }
3760
- if (attention?.includes(path5)) {
3761
- score += attention.indexOf(path5) === 0 ? 20 : 10;
3746
+ if (attention?.includes(path7)) {
3747
+ score += attention.indexOf(path7) === 0 ? 20 : 10;
3762
3748
  reasons.push("open/recent");
3763
3749
  }
3764
- const meta = this.fileMeta.get(path5);
3750
+ const meta = this.fileMeta.get(path7);
3765
3751
  if (meta?.is_generated) score -= 50;
3766
3752
  if (meta?.is_test) score -= 12;
3767
- if (score > 0) hits.push([score, path5, reasons]);
3753
+ if (score > 0) hits.push([score, path7, reasons]);
3768
3754
  }
3769
- return hits.sort((a, b) => b[0] - a[0] || a[1].localeCompare(b[1])).slice(0, limit).map(([score, path5, reasons]) => ({ result_type: "file", path: path5, score, reasons }));
3755
+ return hits.sort((a, b) => b[0] - a[0] || a[1].localeCompare(b[1])).slice(0, limit).map(([score, path7, reasons]) => ({ result_type: "file", path: path7, score, reasons }));
3770
3756
  }
3771
- async contentHitsForQuery(query, limit, attention, scope, retrievalMode, termSets) {
3772
- if (retrievalMode === "enhanced" && this.chunkIndex.size() > 0) {
3757
+ async contentHitsForQuery(query, limit, attention, scope, termSets) {
3758
+ if (this.chunkIndex.size() > 0) {
3773
3759
  return this.chunkIndex.search(query, { limit, scope, attention, meta: this.fileMeta }).map((hit) => ({
3774
3760
  result_type: "chunk",
3775
3761
  path: hit.path,
@@ -3786,21 +3772,21 @@ var WorkspaceIndexStore = class {
3786
3772
  if (terms.length === 0) return [];
3787
3773
  const hits = await this.findFilesMentioning(terms, { topK: limit * 3, attention, termSets });
3788
3774
  const out2 = [];
3789
- for (const [path5, count] of hits) {
3790
- if (!scopeFilter(path5, scope)) continue;
3791
- out2.push({ result_type: "content", path: path5, hits: count });
3775
+ for (const [path7, count] of hits) {
3776
+ if (!scopeFilter(path7, scope)) continue;
3777
+ out2.push({ result_type: "content", path: path7, hits: count });
3792
3778
  if (out2.length >= limit) break;
3793
3779
  }
3794
3780
  return out2;
3795
3781
  }
3796
- resolveTraceTargets(target, scope, limit, pathHint, retrievalMode) {
3797
- const scopedFiles = pathHint ? this.matchFilesForPathHint(pathHint, scope, limit * 4, retrievalMode) : [];
3782
+ resolveTraceTargets(target, scope, limit, pathHint) {
3783
+ const scopedFiles = pathHint ? this.matchFilesForPathHint(pathHint, scope, limit * 4) : [];
3798
3784
  if (scopedFiles.length > 0) {
3799
3785
  const needle = target.toLowerCase().trim();
3800
3786
  const needleTokens = tokenizeName(target);
3801
3787
  const symbolHits = [];
3802
- for (const path5 of scopedFiles) {
3803
- for (const sym of this.listSymbols(path5)) {
3788
+ for (const path7 of scopedFiles) {
3789
+ for (const sym of this.listSymbols(path7)) {
3804
3790
  const name2 = sym.name.toLowerCase();
3805
3791
  const tokens = this.tokensByName.get(name2) ?? tokenizeName(sym.name);
3806
3792
  let overlap = 0;
@@ -3827,15 +3813,13 @@ var WorkspaceIndexStore = class {
3827
3813
  }
3828
3814
  const candidates = this.symbolHitsForQuery(target, limit, void 0, scope);
3829
3815
  if (candidates.length > 0) return candidates;
3830
- return this.matchFilesForPathHint(target, scope, limit, retrievalMode).map((p) => ({ path: p, name: (p.split("/").pop() ?? p).split(".")[0], line: 1, kind: "file", score: 0 }));
3816
+ return this.matchFilesForPathHint(target, scope, limit).map((p) => ({ path: p, name: (p.split("/").pop() ?? p).split(".")[0], line: 1, kind: "file", score: 0 }));
3831
3817
  }
3832
- matchFilesForPathHint(pathHint, scope, limit, retrievalMode) {
3818
+ matchFilesForPathHint(pathHint, scope, limit) {
3833
3819
  const hint = normalizeTracePath(pathHint).toLowerCase();
3834
3820
  if (!hint) return [];
3835
- if (retrievalMode === "enhanced") {
3836
- const pathHits = this.pathIndex.search(hint, { scope, limit: limit * 2 });
3837
- if (pathHits.length > 0) return pathHits.slice(0, limit).map((h) => h.path);
3838
- }
3821
+ const pathHits = this.pathIndex.search(hint, { scope, limit: limit * 2 });
3822
+ if (pathHits.length > 0) return pathHits.slice(0, limit).map((h) => h.path);
3839
3823
  return [...this.files].filter((p) => scopeFilter(p, scope)).map((p) => {
3840
3824
  const lc = p.toLowerCase();
3841
3825
  let score = 0;
@@ -3846,30 +3830,28 @@ var WorkspaceIndexStore = class {
3846
3830
  return [p, score];
3847
3831
  }).filter(([, score]) => score > 0).sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, limit).map(([p]) => p);
3848
3832
  }
3849
- async formatTraceFallback(target, selectedPath, scope, limit, retrievalMode) {
3850
- if (retrievalMode === "enhanced") {
3851
- const chunkHits = this.chunkIndex.search(target, { limit, scope, meta: this.fileMeta }).filter((hit) => hit.path !== selectedPath);
3852
- if (chunkHits.length > 0) {
3853
- return [
3854
- "Trace Coverage",
3855
- "- no structural edges were indexed for this target/relation",
3856
- "- fallback: showing ranked chunk evidence from the same client index",
3857
- "",
3858
- "Possible Indexed Mentions",
3859
- ...chunkHits.map(
3860
- (hit) => `- ${hit.path}:${hit.startLine}-${hit.endLine} ${hit.title} (score=${hit.score}; ${hit.reasons.join(", ")})
3833
+ async formatTraceFallback(target, selectedPath, scope, limit) {
3834
+ const chunkHits = this.chunkIndex.search(target, { limit, scope, meta: this.fileMeta }).filter((hit) => hit.path !== selectedPath);
3835
+ if (chunkHits.length > 0) {
3836
+ return [
3837
+ "Trace Coverage",
3838
+ "- no structural edges were indexed for this target/relation",
3839
+ "- fallback: showing ranked chunk evidence from the same client index",
3840
+ "",
3841
+ "Possible Indexed Mentions",
3842
+ ...chunkHits.map(
3843
+ (hit) => `- ${hit.path}:${hit.startLine}-${hit.endLine} ${hit.title} (score=${hit.score}; ${hit.reasons.join(", ")})
3861
3844
  Preview: ${hit.preview}
3862
3845
  Exact read if needed: read_file path=${hit.path} start_line=${hit.startLine} end_line=${hit.endLine} context=dependencies`
3863
- )
3864
- ];
3865
- }
3846
+ )
3847
+ ];
3866
3848
  }
3867
3849
  const terms = queryTerms(target);
3868
3850
  const exact = target.toLowerCase().trim();
3869
3851
  if (exact && !terms.includes(exact)) terms.unshift(exact);
3870
3852
  const compact = exact.replace(/[^a-z0-9]/g, "");
3871
3853
  if (compact && !terms.includes(compact)) terms.push(compact);
3872
- const mentions = (await this.findFilesMentioning(terms, { topK: limit * 4 })).filter(([path5]) => path5 !== selectedPath && scopeFilter(path5, scope)).slice(0, limit);
3854
+ const mentions = (await this.findFilesMentioning(terms, { topK: limit * 4 })).filter(([path7]) => path7 !== selectedPath && scopeFilter(path7, scope)).slice(0, limit);
3873
3855
  const lines = [
3874
3856
  "Trace Coverage",
3875
3857
  "- no structural edges were indexed for this target/relation",
@@ -3881,22 +3863,22 @@ var WorkspaceIndexStore = class {
3881
3863
  lines.push("- none indexed; use grep for exact byte-level search");
3882
3864
  return lines;
3883
3865
  }
3884
- for (const [path5, count] of mentions) {
3885
- const syms = this.listSymbols(path5).slice(0, 3);
3886
- const outgoing = (this.edgesOutByPath.get(path5) ?? []).filter((e) => e.target === exact || terms.includes(e.target) || e.source_name.toLowerCase().includes(exact)).slice(0, 3);
3866
+ for (const [path7, count] of mentions) {
3867
+ const syms = this.listSymbols(path7).slice(0, 3);
3868
+ const outgoing = (this.edgesOutByPath.get(path7) ?? []).filter((e) => e.target === exact || terms.includes(e.target) || e.source_name.toLowerCase().includes(exact)).slice(0, 3);
3887
3869
  const details = [`content_hits=${count}`];
3888
3870
  if (syms.length > 0) details.push(`symbols=${syms.map((s) => `${s.name}@${s.line}`).join(",")}`);
3889
3871
  if (outgoing.length > 0) details.push(`edges=${outgoing.map((e) => `${e.kind}:${e.target}@${e.line}`).join(",")}`);
3890
3872
  const firstLine = syms[0]?.line ?? 1;
3891
- lines.push(`- ${path5} (${details.join("; ")})`);
3892
- lines.push(` Exact read if needed: read_file path=${path5} start_line=${firstLine} context=dependencies`);
3873
+ lines.push(`- ${path7} (${details.join("; ")})`);
3874
+ lines.push(` Exact read if needed: read_file path=${path7} start_line=${firstLine} context=dependencies`);
3893
3875
  }
3894
3876
  return lines;
3895
3877
  }
3896
- async relatedContextForPath(path5, limit) {
3897
- const imports = (this.edgesOutByPath.get(path5) ?? []).filter((e) => e.kind === "imports" && e.target).map((e) => e.target);
3898
- const dependencies = (this.edgesOutByPath.get(path5) ?? []).filter((e) => e.kind !== "imports" && e.target).map((e) => `${e.kind}:${e.target}`);
3899
- const syms = this.listSymbols(path5);
3878
+ async relatedContextForPath(path7, limit) {
3879
+ const imports = (this.edgesOutByPath.get(path7) ?? []).filter((e) => e.kind === "imports" && e.target).map((e) => e.target);
3880
+ const dependencies = (this.edgesOutByPath.get(path7) ?? []).filter((e) => e.kind !== "imports" && e.target).map((e) => `${e.kind}:${e.target}`);
3881
+ const syms = this.listSymbols(path7);
3900
3882
  const dependentEdges = [];
3901
3883
  for (const sym of syms.slice(0, 8)) {
3902
3884
  dependentEdges.push(...this.findCallers(sym.name, { limit }));
@@ -3904,17 +3886,17 @@ var WorkspaceIndexStore = class {
3904
3886
  dependentEdges.push(...this.findImporters(sym.name, { limit }));
3905
3887
  }
3906
3888
  const dependentPaths = dedupe(dependentEdges, edgeKey, limit * 2).map((e) => e.source_path);
3907
- for (const token of pathStems(path5)) {
3889
+ for (const token of pathStems(path7)) {
3908
3890
  dependentPaths.push(...this.findImporters(token, { limit }).map((e) => e.source_path));
3909
3891
  }
3910
3892
  const symbolNames = new Set(syms.slice(0, 8).map((s) => s.name.toLowerCase()));
3911
- const stems = new Set(pathStems(path5));
3893
+ const stems = new Set(pathStems(path7));
3912
3894
  const symbolSets = new Map(
3913
3895
  [...symbolNames].map((n) => [n, this.chunkIndex.filesWithTerm(n)])
3914
3896
  );
3915
3897
  const tests = [];
3916
3898
  for (const [candidate, c] of this.testFileCandidatesFor()) {
3917
- if (candidate === path5) continue;
3899
+ if (candidate === path7) continue;
3918
3900
  if ([...stems].some((t) => c.includes(t)) || [...symbolNames].some((n) => c.includes(n)) || [...symbolNames].some((n) => symbolSets.get(n)?.has(candidate) ?? false)) {
3919
3901
  tests.push(candidate);
3920
3902
  }
@@ -3923,7 +3905,7 @@ var WorkspaceIndexStore = class {
3923
3905
  imports: dedupe(imports, (p) => p, limit),
3924
3906
  dependencies: dedupe(dependencies, (p) => p, limit),
3925
3907
  // Self-references (recursion, same-file calls) are not dependents.
3926
- dependents: dedupe(dependentPaths.filter((p) => p !== path5), (p) => p, limit),
3908
+ dependents: dedupe(dependentPaths.filter((p) => p !== path7), (p) => p, limit),
3927
3909
  tests: dedupe(tests, (p) => p, limit)
3928
3910
  };
3929
3911
  }
@@ -4001,13 +3983,13 @@ var WorkspaceIndexStore = class {
4001
3983
  reasons: [c.reason]
4002
3984
  }));
4003
3985
  }
4004
- renderFileCard(path5, rank, reasons, detail, retrievalMode, related) {
3986
+ renderFileCard(path7, rank, reasons, detail, related) {
4005
3987
  const maxRelated = detailLimit(detail, 2, 4, 7);
4006
- const lines = [`${rank}. ${path5}`];
3988
+ const lines = [`${rank}. ${path7}`];
4007
3989
  if (reasons.length > 0) lines.push(` Why: ${dedupe(reasons, (r) => r, 6).join(", ")}`);
4008
- const summary = this.fileSummaryFor(path5);
3990
+ const summary = this.fileSummaryFor(path7);
4009
3991
  if (summary) lines.push(` Summary: ${summary}`);
4010
- const syms = this.listSymbols(path5);
3992
+ const syms = this.listSymbols(path7);
4011
3993
  if (syms.length > 0) {
4012
3994
  const shown = syms.slice(0, maxRelated).map((s) => `${s.signature || s.name}@${s.line}`);
4013
3995
  const tail = syms.length > shown.length ? ` (+${syms.length - shown.length} more)` : "";
@@ -4017,7 +3999,7 @@ var WorkspaceIndexStore = class {
4017
3999
  const dependencies = related.dependencies.slice(0, maxRelated);
4018
4000
  const dependents = related.dependents.slice(0, maxRelated);
4019
4001
  const relatedTests = related.tests.slice(0, maxRelated);
4020
- const chunks = retrievalMode === "enhanced" ? this.chunkIndex.bestChunksForPath(path5, detail === "deep" ? 3 : 2) : [];
4002
+ const chunks = this.chunkIndex.bestChunksForPath(path7, detail === "deep" ? 3 : 2);
4021
4003
  if (chunks.length > 0) {
4022
4004
  lines.push(` Chunks: ${chunks.map((c) => `${c.title}@${c.startLine}-${c.endLine}`).join(", ")}`);
4023
4005
  }
@@ -4025,7 +4007,7 @@ var WorkspaceIndexStore = class {
4025
4007
  if (dependencies.length > 0) lines.push(` Uses: ${dependencies.join(", ")}`);
4026
4008
  if (dependents.length > 0) lines.push(` Used by: ${dependents.join(", ")}`);
4027
4009
  if (relatedTests.length > 0) lines.push(` Related tests: ${relatedTests.join(", ")}`);
4028
- lines.push(syms.length > 0 ? ` Exact read if needed: read_file path=${path5} start_line=${syms[0].line} context=dependencies` : ` Exact read if needed: read_file path=${path5} context=dependencies`);
4010
+ lines.push(syms.length > 0 ? ` Exact read if needed: read_file path=${path7} start_line=${syms[0].line} context=dependencies` : ` Exact read if needed: read_file path=${path7} context=dependencies`);
4029
4011
  return lines;
4030
4012
  }
4031
4013
  formatEdges(title, edges, limit) {
@@ -4043,10 +4025,10 @@ var WorkspaceIndexStore = class {
4043
4025
  const s = this.status();
4044
4026
  return `ready=${s.ready} state=${s.state} progress=${s.progress_percent}% files=${s.file_count} symbols=${s.symbol_count} edges=${s.edge_count} resolved_edges=${s.resolved_edge_count} chunks=${this.chunkIndex.size()}`;
4045
4027
  }
4046
- fileSummaryFor(path5) {
4047
- const summary = (this.fileSummaries.get(path5) ?? "").trim();
4028
+ fileSummaryFor(path7) {
4029
+ const summary = (this.fileSummaries.get(path7) ?? "").trim();
4048
4030
  if (summary) return summary;
4049
- const syms = this.listSymbols(path5);
4031
+ const syms = this.listSymbols(path7);
4050
4032
  if (syms.length === 0) return "";
4051
4033
  const names = syms.map((s) => s.name).filter((n) => !n.startsWith("_"));
4052
4034
  const shown = (names.length > 0 ? names : syms.map((s) => s.name)).slice(0, 5);
@@ -4234,20 +4216,20 @@ var WorkspaceIndexStore = class {
4234
4216
  }
4235
4217
  return null;
4236
4218
  }
4237
- removePath(path5) {
4238
- this.removePathStems(path5);
4239
- this.pathIndex.remove(path5);
4240
- this.chunkIndex.removePath(path5);
4241
- const prev = this.byPath.get(path5) ?? [];
4242
- this.byPath.delete(path5);
4243
- this.removeEdgesFromPath(path5);
4244
- this.fileMeta.delete(path5);
4245
- this.fileSummaries.delete(path5);
4219
+ removePath(path7) {
4220
+ this.removePathStems(path7);
4221
+ this.pathIndex.remove(path7);
4222
+ this.chunkIndex.removePath(path7);
4223
+ const prev = this.byPath.get(path7) ?? [];
4224
+ this.byPath.delete(path7);
4225
+ this.removeEdgesFromPath(path7);
4226
+ this.fileMeta.delete(path7);
4227
+ this.fileSummaries.delete(path7);
4246
4228
  for (const sym of prev) {
4247
4229
  const key = sym.name.toLowerCase();
4248
4230
  const bucket = this.byName.get(key);
4249
4231
  if (!bucket) continue;
4250
- const next = bucket.filter((s) => s.path !== path5);
4232
+ const next = bucket.filter((s) => s.path !== path7);
4251
4233
  if (next.length > 0) {
4252
4234
  this.byName.set(key, next);
4253
4235
  } else {
@@ -4266,9 +4248,9 @@ var WorkspaceIndexStore = class {
4266
4248
  }
4267
4249
  this.totalSymbols = Math.max(0, this.totalSymbols - prev.length);
4268
4250
  }
4269
- removeEdgesFromPath(path5) {
4270
- const outgoing = this.edgesOutByPath.get(path5) ?? [];
4271
- this.edgesOutByPath.delete(path5);
4251
+ removeEdgesFromPath(path7) {
4252
+ const outgoing = this.edgesOutByPath.get(path7) ?? [];
4253
+ this.edgesOutByPath.delete(path7);
4272
4254
  if (outgoing.length === 0) return;
4273
4255
  const dropsByTarget = /* @__PURE__ */ new Map();
4274
4256
  for (const edge of outgoing) {
@@ -4285,48 +4267,48 @@ var WorkspaceIndexStore = class {
4285
4267
  this.totalEdges = Math.max(0, this.totalEdges - outgoing.length);
4286
4268
  this.totalResolvedEdges = Math.max(0, this.totalResolvedEdges - outgoing.filter((e) => (e.confidence || "AMBIGUOUS") !== "AMBIGUOUS").length);
4287
4269
  }
4288
- setMeta(path5, override) {
4289
- this.fileMeta.set(path5, {
4270
+ setMeta(path7, override) {
4271
+ this.fileMeta.set(path7, {
4290
4272
  mtime: override?.mtime ?? 0,
4291
4273
  size: override?.size ?? 0,
4292
- is_test: Boolean(override?.is_test) || isTestPath(path5),
4293
- is_generated: Boolean(override?.is_generated) || isGeneratedPath(path5)
4274
+ is_test: Boolean(override?.is_test) || isTestPath(path7),
4275
+ is_generated: Boolean(override?.is_generated) || isGeneratedPath(path7)
4294
4276
  });
4295
4277
  }
4296
4278
  suggestPaths(query, limit = 5) {
4297
4279
  return this.pathIndex.search(query, { limit, includeDocs: true }).map((hit) => hit.path);
4298
4280
  }
4299
- readRangeSuggestions(path5, limit = 5) {
4300
- return this.chunkIndex.bestChunksForPath(path5, limit).map((chunk) => ({
4281
+ readRangeSuggestions(path7, limit = 5) {
4282
+ return this.chunkIndex.bestChunksForPath(path7, limit).map((chunk) => ({
4301
4283
  startLine: chunk.startLine,
4302
4284
  endLine: chunk.endLine,
4303
4285
  title: chunk.title
4304
4286
  }));
4305
4287
  }
4306
- indexPathStems(path5) {
4307
- const stems = pathStems(path5);
4308
- this.pathStemsByFile.set(path5, stems);
4288
+ indexPathStems(path7) {
4289
+ const stems = pathStems(path7);
4290
+ this.pathStemsByFile.set(path7, stems);
4309
4291
  const final = stems.at(-1);
4310
4292
  if (final) {
4311
4293
  if (!this.filesByFinalStem.has(final)) this.filesByFinalStem.set(final, /* @__PURE__ */ new Set());
4312
- this.filesByFinalStem.get(final).add(path5);
4294
+ this.filesByFinalStem.get(final).add(path7);
4313
4295
  }
4314
4296
  }
4315
- removePathStems(path5) {
4316
- const stems = this.pathStemsByFile.get(path5);
4317
- this.pathStemsByFile.delete(path5);
4297
+ removePathStems(path7) {
4298
+ const stems = this.pathStemsByFile.get(path7);
4299
+ this.pathStemsByFile.delete(path7);
4318
4300
  const final = stems?.at(-1);
4319
4301
  if (!final) return;
4320
4302
  const bucket = this.filesByFinalStem.get(final);
4321
4303
  if (!bucket) return;
4322
- bucket.delete(path5);
4304
+ bucket.delete(path7);
4323
4305
  if (bucket.size === 0) this.filesByFinalStem.delete(final);
4324
4306
  }
4325
- stemsForPath(path5) {
4326
- const existing = this.pathStemsByFile.get(path5);
4307
+ stemsForPath(path7) {
4308
+ const existing = this.pathStemsByFile.get(path7);
4327
4309
  if (existing) return existing;
4328
- this.indexPathStems(path5);
4329
- return this.pathStemsByFile.get(path5) ?? [];
4310
+ this.indexPathStems(path7);
4311
+ return this.pathStemsByFile.get(path7) ?? [];
4330
4312
  }
4331
4313
  resolvesInFile(sourcePath, targetName) {
4332
4314
  if (!targetName) return true;
@@ -4810,7 +4792,7 @@ function moduleNameFromSourceLiteral(literal) {
4810
4792
  function moduleSpecFromSourceLiteral(literal) {
4811
4793
  return literal.replace(/^['"]|['"]$/g, "");
4812
4794
  }
4813
- function extractFromMatches(matches, path5, allLines) {
4795
+ function extractFromMatches(matches, path7, allLines) {
4814
4796
  const symbols = [];
4815
4797
  const edges = [];
4816
4798
  for (const m of matches) {
@@ -4823,7 +4805,7 @@ function extractFromMatches(matches, path5, allLines) {
4823
4805
  const name2 = byName["symbol.function.name"]?.[0]?.text;
4824
4806
  if (name2) {
4825
4807
  symbols.push({
4826
- path: path5,
4808
+ path: path7,
4827
4809
  name: name2,
4828
4810
  kind: "function",
4829
4811
  line: lineOf(def),
@@ -4836,7 +4818,7 @@ function extractFromMatches(matches, path5, allLines) {
4836
4818
  const name2 = byName["symbol.method.name"]?.[0]?.text;
4837
4819
  if (name2) {
4838
4820
  symbols.push({
4839
- path: path5,
4821
+ path: path7,
4840
4822
  name: name2,
4841
4823
  kind: "method",
4842
4824
  line: lineOf(def),
@@ -4849,7 +4831,7 @@ function extractFromMatches(matches, path5, allLines) {
4849
4831
  const name2 = byName["symbol.class.name"]?.[0]?.text;
4850
4832
  if (name2) {
4851
4833
  symbols.push({
4852
- path: path5,
4834
+ path: path7,
4853
4835
  name: name2,
4854
4836
  kind: "class",
4855
4837
  line: lineOf(def),
@@ -4858,7 +4840,7 @@ function extractFromMatches(matches, path5, allLines) {
4858
4840
  for (const parent of byName["edge.extends.parent"] ?? []) {
4859
4841
  edges.push({
4860
4842
  kind: "extends",
4861
- source_path: path5,
4843
+ source_path: path7,
4862
4844
  source_name: name2,
4863
4845
  target: parent.text.toLowerCase(),
4864
4846
  line: lineOf(parent)
@@ -4871,7 +4853,7 @@ function extractFromMatches(matches, path5, allLines) {
4871
4853
  const name2 = byName["symbol.interface.name"]?.[0]?.text;
4872
4854
  if (name2) {
4873
4855
  symbols.push({
4874
- path: path5,
4856
+ path: path7,
4875
4857
  name: name2,
4876
4858
  kind: "interface",
4877
4859
  line: lineOf(def),
@@ -4884,7 +4866,7 @@ function extractFromMatches(matches, path5, allLines) {
4884
4866
  const name2 = byName["symbol.type.name"]?.[0]?.text;
4885
4867
  if (name2) {
4886
4868
  symbols.push({
4887
- path: path5,
4869
+ path: path7,
4888
4870
  name: name2,
4889
4871
  kind: "type",
4890
4872
  line: lineOf(def),
@@ -4897,7 +4879,7 @@ function extractFromMatches(matches, path5, allLines) {
4897
4879
  const name2 = byName["symbol.enum.name"]?.[0]?.text;
4898
4880
  if (name2) {
4899
4881
  symbols.push({
4900
- path: path5,
4882
+ path: path7,
4901
4883
  name: name2,
4902
4884
  kind: "enum",
4903
4885
  line: lineOf(def),
@@ -4910,7 +4892,7 @@ function extractFromMatches(matches, path5, allLines) {
4910
4892
  const last = dotted.split(".").pop() ?? dotted;
4911
4893
  edges.push({
4912
4894
  kind: "imports",
4913
- source_path: path5,
4895
+ source_path: path7,
4914
4896
  source_name: "",
4915
4897
  target: last.toLowerCase(),
4916
4898
  line: lineOf(targetNode)
@@ -4921,7 +4903,7 @@ function extractFromMatches(matches, path5, allLines) {
4921
4903
  if (modName) {
4922
4904
  edges.push({
4923
4905
  kind: "imports",
4924
- source_path: path5,
4906
+ source_path: path7,
4925
4907
  source_name: "",
4926
4908
  target: modName.toLowerCase(),
4927
4909
  line: lineOf(sourceLit),
@@ -4933,7 +4915,7 @@ function extractFromMatches(matches, path5, allLines) {
4933
4915
  const sourceName = enclosingSymbolName(callTarget);
4934
4916
  edges.push({
4935
4917
  kind: "calls",
4936
- source_path: path5,
4918
+ source_path: path7,
4937
4919
  source_name: sourceName,
4938
4920
  target: callTarget.text.toLowerCase(),
4939
4921
  line: lineOf(callTarget)
@@ -4945,7 +4927,7 @@ function extractFromMatches(matches, path5, allLines) {
4945
4927
  if (childName) {
4946
4928
  edges.push({
4947
4929
  kind: "extends",
4948
- source_path: path5,
4930
+ source_path: path7,
4949
4931
  source_name: childName,
4950
4932
  target: parent.text.toLowerCase(),
4951
4933
  line: lineOf(parent)
@@ -4957,7 +4939,7 @@ function extractFromMatches(matches, path5, allLines) {
4957
4939
  if (childName) {
4958
4940
  edges.push({
4959
4941
  kind: "implements",
4960
- source_path: path5,
4942
+ source_path: path7,
4961
4943
  source_name: childName,
4962
4944
  target: parent.text.toLowerCase(),
4963
4945
  line: lineOf(parent)
@@ -4967,7 +4949,7 @@ function extractFromMatches(matches, path5, allLines) {
4967
4949
  }
4968
4950
  return { symbols, edges };
4969
4951
  }
4970
- function extractWithTreeSitter(handle4, lang, path5, content) {
4952
+ function extractWithTreeSitter(handle4, lang, path7, content) {
4971
4953
  const querySource = queryFor(lang);
4972
4954
  if (!querySource) return null;
4973
4955
  const tree = handle4.parse(lang, content);
@@ -4977,7 +4959,7 @@ function extractWithTreeSitter(handle4, lang, path5, content) {
4977
4959
  if (!query) return null;
4978
4960
  const matches = query.matches(tree.rootNode);
4979
4961
  const allLines = content.split("\n");
4980
- return extractFromMatches(matches, path5, allLines);
4962
+ return extractFromMatches(matches, path7, allLines);
4981
4963
  } finally {
4982
4964
  try {
4983
4965
  tree.delete();
@@ -5176,10 +5158,10 @@ function langFromExt(ext) {
5176
5158
  return null;
5177
5159
  }
5178
5160
  }
5179
- function languageForPath(path5) {
5180
- const dot = path5.lastIndexOf(".");
5161
+ function languageForPath(path7) {
5162
+ const dot = path7.lastIndexOf(".");
5181
5163
  if (dot < 0) return null;
5182
- return langFromExt(path5.slice(dot));
5164
+ return langFromExt(path7.slice(dot));
5183
5165
  }
5184
5166
  async function tryLoad(grammarDir) {
5185
5167
  if (handle2) return handle2;
@@ -5278,9 +5260,9 @@ async function ensureGrammar(h, lang) {
5278
5260
 
5279
5261
  // ../packages/orion-client-core/src/summaries.ts
5280
5262
  var SUMMARY_MAX_CHARS = 200;
5281
- function familyFor(path5) {
5282
- const dot = path5.lastIndexOf(".");
5283
- const ext = dot >= 0 ? path5.slice(dot).toLowerCase() : "";
5263
+ function familyFor(path7) {
5264
+ const dot = path7.lastIndexOf(".");
5265
+ const ext = dot >= 0 ? path7.slice(dot).toLowerCase() : "";
5284
5266
  switch (ext) {
5285
5267
  case ".py":
5286
5268
  return "python";
@@ -5333,10 +5315,10 @@ function clean(text) {
5333
5315
  function stripDocstringQuotes(raw) {
5334
5316
  return raw.trim().replace(/^[rbRBuUfF]*("""|'''|"|')/, "").replace(/("""|'''|"|')$/, "");
5335
5317
  }
5336
- function extractFileSummary(path5, content, opts) {
5318
+ function extractFileSummary(path7, content, opts) {
5337
5319
  if (!opts.shipDocstrings) return "";
5338
5320
  const lines = content.split("\n");
5339
- const raw = familyFor(path5) === "python" ? pythonModuleDocstring(lines) : leadingCommentBlock(lines, familyFor(path5));
5321
+ const raw = familyFor(path7) === "python" ? pythonModuleDocstring(lines) : leadingCommentBlock(lines, familyFor(path7));
5340
5322
  return clean(raw);
5341
5323
  }
5342
5324
  function pythonModuleDocstring(lines) {
@@ -5391,10 +5373,10 @@ function leadingCommentBlock(lines, fam) {
5391
5373
  }
5392
5374
  return collected.filter((l) => l && !isLicenseNoise(l)).join(" ");
5393
5375
  }
5394
- function extractSymbolSummaries(path5, content, symbols, opts) {
5376
+ function extractSymbolSummaries(path7, content, symbols, opts) {
5395
5377
  const out2 = /* @__PURE__ */ new Map();
5396
5378
  if (!opts.shipDocstrings || symbols.length === 0) return out2;
5397
- const fam = familyFor(path5);
5379
+ const fam = familyFor(path7);
5398
5380
  const lines = content.split("\n");
5399
5381
  for (const s of symbols) {
5400
5382
  const raw = fam === "python" ? pythonSymbolDocstring(lines, s.line) : precedingCommentSummary(lines, s.line, fam);
@@ -6190,9 +6172,9 @@ var SWIFT_RULES = [
6190
6172
  { match: /^\s*extension\s+(\w+)/, kind: "type", nameGroup: 1 },
6191
6173
  { match: /^\s*(?:(?:public|private|internal|fileprivate|open|static|class|final|override|mutating)\s+)*func\s+(\w+)/, kind: "function", nameGroup: 1 }
6192
6174
  ];
6193
- function languageFor(path5) {
6194
- const dot = path5.lastIndexOf(".");
6195
- const ext = dot >= 0 ? path5.slice(dot).toLowerCase() : "";
6175
+ function languageFor(path7) {
6176
+ const dot = path7.lastIndexOf(".");
6177
+ const ext = dot >= 0 ? path7.slice(dot).toLowerCase() : "";
6196
6178
  switch (ext) {
6197
6179
  case ".py":
6198
6180
  return { family: "python", rules: PYTHON_RULES };
@@ -6328,8 +6310,8 @@ function isProbablyGeneratedPath(p) {
6328
6310
  const lc = p.toLowerCase();
6329
6311
  return lc.includes("/generated/") || lc.includes("/__generated__/") || lc.includes("/build/") || lc.includes("/dist/") || lc.endsWith(".min.js") || lc.endsWith(".bundle.js");
6330
6312
  }
6331
- function extractSymbols(path5, content) {
6332
- const { rules } = languageFor(path5);
6313
+ function extractSymbols(path7, content) {
6314
+ const { rules } = languageFor(path7);
6333
6315
  if (rules.length === 0) return [];
6334
6316
  const out2 = [];
6335
6317
  const lines = content.split("\n");
@@ -6346,7 +6328,7 @@ function extractSymbols(path5, content) {
6346
6328
  if (!name2) continue;
6347
6329
  const sig = trimmed.length > 160 ? trimmed.slice(0, 160) + "\u2026" : trimmed;
6348
6330
  out2.push({
6349
- path: path5,
6331
+ path: path7,
6350
6332
  name: name2,
6351
6333
  kind: rule.kind,
6352
6334
  line: i2 + 1,
@@ -6368,7 +6350,7 @@ function pathBasename(s) {
6368
6350
  function jsModuleTarget(spec) {
6369
6351
  return pathBasename(spec).replace(/\.(d\.)?ts$/, "").replace(/\.js$/, "");
6370
6352
  }
6371
- function extractEdgesPython(path5, lines) {
6353
+ function extractEdgesPython(path7, lines) {
6372
6354
  const edges = [];
6373
6355
  const scope = [];
6374
6356
  const indentOf = (s) => {
@@ -6397,7 +6379,7 @@ function extractEdgesPython(path5, lines) {
6397
6379
  if (name2 && name2 !== "object") {
6398
6380
  edges.push({
6399
6381
  kind: "extends",
6400
- source_path: path5,
6382
+ source_path: path7,
6401
6383
  source_name: child,
6402
6384
  target: name2.toLowerCase(),
6403
6385
  line: i2 + 1
@@ -6418,7 +6400,7 @@ function extractEdgesPython(path5, lines) {
6418
6400
  if (tgt) {
6419
6401
  edges.push({
6420
6402
  kind: "imports",
6421
- source_path: path5,
6403
+ source_path: path7,
6422
6404
  source_name: "",
6423
6405
  target: tgt.toLowerCase(),
6424
6406
  line: i2 + 1
@@ -6434,7 +6416,7 @@ function extractEdgesPython(path5, lines) {
6434
6416
  if (tgt && tgt !== "*") {
6435
6417
  edges.push({
6436
6418
  kind: "imports",
6437
- source_path: path5,
6419
+ source_path: path7,
6438
6420
  source_name: "",
6439
6421
  target: tgt.toLowerCase(),
6440
6422
  line: i2 + 1
@@ -6452,7 +6434,7 @@ function extractEdgesPython(path5, lines) {
6452
6434
  if (CALL_NOISE.has(target)) continue;
6453
6435
  edges.push({
6454
6436
  kind: "calls",
6455
- source_path: path5,
6437
+ source_path: path7,
6456
6438
  source_name: source,
6457
6439
  target: target.toLowerCase(),
6458
6440
  line: i2 + 1
@@ -6462,7 +6444,7 @@ function extractEdgesPython(path5, lines) {
6462
6444
  }
6463
6445
  return edges;
6464
6446
  }
6465
- function extractEdgesJsTs(path5, lines) {
6447
+ function extractEdgesJsTs(path7, lines) {
6466
6448
  const edges = [];
6467
6449
  const scope = [];
6468
6450
  let braceDepth = 0;
@@ -6481,7 +6463,7 @@ function extractEdgesJsTs(path5, lines) {
6481
6463
  if (tgt) {
6482
6464
  edges.push({
6483
6465
  kind: "imports",
6484
- source_path: path5,
6466
+ source_path: path7,
6485
6467
  source_name: "",
6486
6468
  target: tgt.toLowerCase(),
6487
6469
  line: i2 + 1,
@@ -6497,7 +6479,7 @@ function extractEdgesJsTs(path5, lines) {
6497
6479
  if (cleaned) {
6498
6480
  edges.push({
6499
6481
  kind: "imports",
6500
- source_path: path5,
6482
+ source_path: path7,
6501
6483
  source_name: "",
6502
6484
  target: cleaned.toLowerCase(),
6503
6485
  line: i2 + 1,
@@ -6515,7 +6497,7 @@ function extractEdgesJsTs(path5, lines) {
6515
6497
  if (parent) {
6516
6498
  edges.push({
6517
6499
  kind: "extends",
6518
- source_path: path5,
6500
+ source_path: path7,
6519
6501
  source_name: child,
6520
6502
  target: parent.toLowerCase(),
6521
6503
  line: i2 + 1
@@ -6527,7 +6509,7 @@ function extractEdgesJsTs(path5, lines) {
6527
6509
  if (cleaned) {
6528
6510
  edges.push({
6529
6511
  kind: "implements",
6530
- source_path: path5,
6512
+ source_path: path7,
6531
6513
  source_name: child,
6532
6514
  target: cleaned.toLowerCase(),
6533
6515
  line: i2 + 1
@@ -6550,7 +6532,7 @@ function extractEdgesJsTs(path5, lines) {
6550
6532
  if (CALL_NOISE.has(target)) continue;
6551
6533
  edges.push({
6552
6534
  kind: "calls",
6553
- source_path: path5,
6535
+ source_path: path7,
6554
6536
  source_name: source,
6555
6537
  target: target.toLowerCase(),
6556
6538
  line: i2 + 1
@@ -6564,7 +6546,7 @@ function extractEdgesJsTs(path5, lines) {
6564
6546
  }
6565
6547
  return edges;
6566
6548
  }
6567
- function extractEdgesGo(path5, lines) {
6549
+ function extractEdgesGo(path7, lines) {
6568
6550
  const edges = [];
6569
6551
  let inImportBlock = false;
6570
6552
  for (let i2 = 0; i2 < lines.length; i2++) {
@@ -6583,7 +6565,7 @@ function extractEdgesGo(path5, lines) {
6583
6565
  const tgt = lastWord(m[1].replace(/\//g, "."));
6584
6566
  edges.push({
6585
6567
  kind: "imports",
6586
- source_path: path5,
6568
+ source_path: path7,
6587
6569
  source_name: "",
6588
6570
  target: tgt.toLowerCase(),
6589
6571
  line: i2 + 1
@@ -6596,7 +6578,7 @@ function extractEdgesGo(path5, lines) {
6596
6578
  const tgt = lastWord(im[1].replace(/\//g, "."));
6597
6579
  edges.push({
6598
6580
  kind: "imports",
6599
- source_path: path5,
6581
+ source_path: path7,
6600
6582
  source_name: "",
6601
6583
  target: tgt.toLowerCase(),
6602
6584
  line: i2 + 1
@@ -6605,7 +6587,7 @@ function extractEdgesGo(path5, lines) {
6605
6587
  }
6606
6588
  return edges;
6607
6589
  }
6608
- function extractEdgesRust(path5, lines) {
6590
+ function extractEdgesRust(path7, lines) {
6609
6591
  const edges = [];
6610
6592
  for (let i2 = 0; i2 < lines.length; i2++) {
6611
6593
  const line = lines[i2];
@@ -6616,7 +6598,7 @@ function extractEdgesRust(path5, lines) {
6616
6598
  if (tgt) {
6617
6599
  edges.push({
6618
6600
  kind: "imports",
6619
- source_path: path5,
6601
+ source_path: path7,
6620
6602
  source_name: "",
6621
6603
  target: tgt.toLowerCase(),
6622
6604
  line: i2 + 1
@@ -6629,7 +6611,7 @@ function extractEdgesRust(path5, lines) {
6629
6611
  if (cleaned && cleaned !== "*" && cleaned !== "self") {
6630
6612
  edges.push({
6631
6613
  kind: "imports",
6632
- source_path: path5,
6614
+ source_path: path7,
6633
6615
  source_name: "",
6634
6616
  target: cleaned.toLowerCase(),
6635
6617
  line: i2 + 1
@@ -6642,7 +6624,7 @@ function extractEdgesRust(path5, lines) {
6642
6624
  if (implMatch) {
6643
6625
  edges.push({
6644
6626
  kind: "implements",
6645
- source_path: path5,
6627
+ source_path: path7,
6646
6628
  source_name: implMatch[2],
6647
6629
  target: implMatch[1].toLowerCase(),
6648
6630
  line: i2 + 1
@@ -6651,7 +6633,7 @@ function extractEdgesRust(path5, lines) {
6651
6633
  }
6652
6634
  return edges;
6653
6635
  }
6654
- function extractEdgesJava(path5, lines) {
6636
+ function extractEdgesJava(path7, lines) {
6655
6637
  const edges = [];
6656
6638
  for (let i2 = 0; i2 < lines.length; i2++) {
6657
6639
  const line = lines[i2];
@@ -6660,7 +6642,7 @@ function extractEdgesJava(path5, lines) {
6660
6642
  const tgt = lastWord(importMatch[1]);
6661
6643
  edges.push({
6662
6644
  kind: "imports",
6663
- source_path: path5,
6645
+ source_path: path7,
6664
6646
  source_name: "",
6665
6647
  target: tgt.toLowerCase(),
6666
6648
  line: i2 + 1
@@ -6672,7 +6654,7 @@ function extractEdgesJava(path5, lines) {
6672
6654
  if (classMatch[2]) {
6673
6655
  edges.push({
6674
6656
  kind: "extends",
6675
- source_path: path5,
6657
+ source_path: path7,
6676
6658
  source_name: child,
6677
6659
  target: classMatch[2].toLowerCase(),
6678
6660
  line: i2 + 1
@@ -6684,7 +6666,7 @@ function extractEdgesJava(path5, lines) {
6684
6666
  if (cleaned) {
6685
6667
  edges.push({
6686
6668
  kind: "implements",
6687
- source_path: path5,
6669
+ source_path: path7,
6688
6670
  source_name: child,
6689
6671
  target: cleaned.toLowerCase(),
6690
6672
  line: i2 + 1
@@ -6696,7 +6678,7 @@ function extractEdgesJava(path5, lines) {
6696
6678
  }
6697
6679
  return edges;
6698
6680
  }
6699
- function extractEdgesRuby(path5, lines) {
6681
+ function extractEdgesRuby(path7, lines) {
6700
6682
  const edges = [];
6701
6683
  for (let i2 = 0; i2 < lines.length; i2++) {
6702
6684
  const line = lines[i2];
@@ -6705,7 +6687,7 @@ function extractEdgesRuby(path5, lines) {
6705
6687
  const tgt = pathBasename(requireMatch[1]).replace(/\.rb$/, "");
6706
6688
  edges.push({
6707
6689
  kind: "imports",
6708
- source_path: path5,
6690
+ source_path: path7,
6709
6691
  source_name: "",
6710
6692
  target: tgt.toLowerCase(),
6711
6693
  line: i2 + 1
@@ -6715,7 +6697,7 @@ function extractEdgesRuby(path5, lines) {
6715
6697
  if (classMatch) {
6716
6698
  edges.push({
6717
6699
  kind: "extends",
6718
- source_path: path5,
6700
+ source_path: path7,
6719
6701
  source_name: classMatch[1],
6720
6702
  target: classMatch[2].toLowerCase(),
6721
6703
  line: i2 + 1
@@ -6743,7 +6725,7 @@ function declRegexFor(keywords) {
6743
6725
  }
6744
6726
  return re;
6745
6727
  }
6746
- function extractEdgesColonInherit(path5, lines, opts) {
6728
+ function extractEdgesColonInherit(path7, lines, opts) {
6747
6729
  const edges = [];
6748
6730
  const declRe = declRegexFor(opts.declKeywords);
6749
6731
  for (let i2 = 0; i2 < lines.length; i2++) {
@@ -6754,7 +6736,7 @@ function extractEdgesColonInherit(path5, lines, opts) {
6754
6736
  if (target) {
6755
6737
  edges.push({
6756
6738
  kind: "imports",
6757
- source_path: path5,
6739
+ source_path: path7,
6758
6740
  source_name: "",
6759
6741
  target: target.toLowerCase(),
6760
6742
  line: i2 + 1
@@ -6775,7 +6757,7 @@ function extractEdgesColonInherit(path5, lines, opts) {
6775
6757
  if (/^\w+$/.test(name2) && name2 !== child) {
6776
6758
  edges.push({
6777
6759
  kind: "extends",
6778
- source_path: path5,
6760
+ source_path: path7,
6779
6761
  source_name: child,
6780
6762
  target: name2.toLowerCase(),
6781
6763
  line: i2 + 1
@@ -6786,7 +6768,7 @@ function extractEdgesColonInherit(path5, lines, opts) {
6786
6768
  }
6787
6769
  return edges;
6788
6770
  }
6789
- function extractEdgesPhp(path5, lines) {
6771
+ function extractEdgesPhp(path7, lines) {
6790
6772
  const edges = [];
6791
6773
  for (let i2 = 0; i2 < lines.length; i2++) {
6792
6774
  const line = lines[i2];
@@ -6794,7 +6776,7 @@ function extractEdgesPhp(path5, lines) {
6794
6776
  if (use) {
6795
6777
  edges.push({
6796
6778
  kind: "imports",
6797
- source_path: path5,
6779
+ source_path: path7,
6798
6780
  source_name: "",
6799
6781
  target: lastWord(use[1].replace(/\\/g, ".")).toLowerCase(),
6800
6782
  line: i2 + 1
@@ -6804,7 +6786,7 @@ function extractEdgesPhp(path5, lines) {
6804
6786
  if (req) {
6805
6787
  edges.push({
6806
6788
  kind: "imports",
6807
- source_path: path5,
6789
+ source_path: path7,
6808
6790
  source_name: "",
6809
6791
  target: pathBasename(req[1]).toLowerCase(),
6810
6792
  line: i2 + 1
@@ -6816,7 +6798,7 @@ function extractEdgesPhp(path5, lines) {
6816
6798
  if (decl[2]) {
6817
6799
  edges.push({
6818
6800
  kind: "extends",
6819
- source_path: path5,
6801
+ source_path: path7,
6820
6802
  source_name: child,
6821
6803
  target: lastWord(decl[2].replace(/\\/g, ".")).toLowerCase(),
6822
6804
  line: i2 + 1
@@ -6828,7 +6810,7 @@ function extractEdgesPhp(path5, lines) {
6828
6810
  if (name2) {
6829
6811
  edges.push({
6830
6812
  kind: "implements",
6831
- source_path: path5,
6813
+ source_path: path7,
6832
6814
  source_name: child,
6833
6815
  target: name2.toLowerCase(),
6834
6816
  line: i2 + 1
@@ -6840,24 +6822,24 @@ function extractEdgesPhp(path5, lines) {
6840
6822
  }
6841
6823
  return edges;
6842
6824
  }
6843
- function extractEdges(path5, content) {
6844
- const { family } = languageFor(path5);
6825
+ function extractEdges(path7, content) {
6826
+ const { family } = languageFor(path7);
6845
6827
  const lines = content.split("\n");
6846
6828
  switch (family) {
6847
6829
  case "python":
6848
- return extractEdgesPython(path5, lines);
6830
+ return extractEdgesPython(path7, lines);
6849
6831
  case "jsts":
6850
- return extractEdgesJsTs(path5, lines);
6832
+ return extractEdgesJsTs(path7, lines);
6851
6833
  case "go":
6852
- return extractEdgesGo(path5, lines);
6834
+ return extractEdgesGo(path7, lines);
6853
6835
  case "rust":
6854
- return extractEdgesRust(path5, lines);
6836
+ return extractEdgesRust(path7, lines);
6855
6837
  case "java":
6856
- return extractEdgesJava(path5, lines);
6838
+ return extractEdgesJava(path7, lines);
6857
6839
  case "ruby":
6858
- return extractEdgesRuby(path5, lines);
6840
+ return extractEdgesRuby(path7, lines);
6859
6841
  case "cfamily":
6860
- return extractEdgesColonInherit(path5, lines, {
6842
+ return extractEdgesColonInherit(path7, lines, {
6861
6843
  importRe: /^\s*#\s*include\s+"([^"]+)"/,
6862
6844
  importTarget: pathBasename,
6863
6845
  // C++ `enum class Foo : int` names a storage type, not a base — excluded (see declKeywords).
@@ -6865,21 +6847,21 @@ function extractEdges(path5, content) {
6865
6847
  baseNoise: /\b(?:public|private|protected|virtual)\b/g
6866
6848
  });
6867
6849
  case "csharp":
6868
- return extractEdgesColonInherit(path5, lines, {
6850
+ return extractEdgesColonInherit(path7, lines, {
6869
6851
  importRe: /^\s*(?:global\s+)?using\s+(?:static\s+)?([\w.]+)\s*;/,
6870
6852
  importTarget: lastWord,
6871
6853
  // `enum Color : byte` is a storage type, not a base — excluded (see declKeywords).
6872
6854
  declKeywords: ["class", "struct", "interface"]
6873
6855
  });
6874
6856
  case "swift":
6875
- return extractEdgesColonInherit(path5, lines, {
6857
+ return extractEdgesColonInherit(path7, lines, {
6876
6858
  importRe: /^\s*import\s+([\w.]+)/,
6877
6859
  importTarget: lastWord,
6878
6860
  // Swift DOES carry real conformance on an enum, and its query emits those edges.
6879
6861
  declKeywords: ["class", "struct", "enum", "protocol"]
6880
6862
  });
6881
6863
  case "php":
6882
- return extractEdgesPhp(path5, lines);
6864
+ return extractEdgesPhp(path7, lines);
6883
6865
  default:
6884
6866
  return [];
6885
6867
  }
@@ -7116,16 +7098,16 @@ var WorkspaceIndexer = class {
7116
7098
  this.cachedRemovals.delete(r.relPath);
7117
7099
  this.cachedUpdates.set(r.relPath, r);
7118
7100
  }
7119
- rememberRemoval(path5) {
7101
+ rememberRemoval(path7) {
7120
7102
  if (!this.building) return;
7121
- this.cachedUpdates.delete(path5);
7122
- this.cachedRemovals.add(path5);
7103
+ this.cachedUpdates.delete(path7);
7104
+ this.cachedRemovals.add(path7);
7123
7105
  }
7124
- shouldSkipStaleBuildResult(path5) {
7125
- if (this.cachedUpdates.has(path5)) return true;
7106
+ shouldSkipStaleBuildResult(path7) {
7107
+ if (this.cachedUpdates.has(path7)) return true;
7126
7108
  for (const removed of this.cachedRemovals) {
7127
7109
  const prefix = removed.endsWith("/") ? removed : removed + "/";
7128
- if (path5 === removed || path5.startsWith(prefix)) return true;
7110
+ if (path7 === removed || path7.startsWith(prefix)) return true;
7129
7111
  }
7130
7112
  return false;
7131
7113
  }
@@ -7831,18 +7813,18 @@ var WorkspaceIndexer = class {
7831
7813
  chunks: buildChunksForFile(file.relPath, text, file.symbols, file.fileSummary)
7832
7814
  };
7833
7815
  }
7834
- async tryTreeSitter(path5, content, sizeBytes) {
7816
+ async tryTreeSitter(path7, content, sizeBytes) {
7835
7817
  const enabled = this.indexConfig.useTreeSitter();
7836
7818
  const maxBytes = this.indexConfig.treeSitterMaxFileBytes();
7837
7819
  if (!shouldExtractWithTreeSitter(sizeBytes, { enabled, maxBytes })) {
7838
7820
  return null;
7839
7821
  }
7840
- const lang = languageForPath(path5);
7822
+ const lang = languageForPath(path7);
7841
7823
  if (!lang) return null;
7842
7824
  const pool = this.getWorkerPool();
7843
7825
  if (pool) {
7844
7826
  try {
7845
- return await pool.extract(lang, path5, content);
7827
+ return await pool.extract(lang, path7, content);
7846
7828
  } catch (e) {
7847
7829
  console.warn("orion: tree-sitter worker failed, falling back inline", e);
7848
7830
  }
@@ -7852,7 +7834,7 @@ var WorkspaceIndexer = class {
7852
7834
  if (!handle4) return null;
7853
7835
  const ready = await ensureGrammar(handle4, lang);
7854
7836
  if (!ready) return null;
7855
- return extractWithTreeSitter(handle4, lang, path5, content);
7837
+ return extractWithTreeSitter(handle4, lang, path7, content);
7856
7838
  } catch (e) {
7857
7839
  console.warn("orion: tree-sitter extraction failed, using regex fallback", e);
7858
7840
  return null;
@@ -7927,9 +7909,9 @@ function changedLineRanges(before, after) {
7927
7909
  }
7928
7910
  return ranges;
7929
7911
  }
7930
- function changedSymbolNames(path5, before, after) {
7931
- const postSyms = extractSymbols(path5, after);
7932
- const preSyms = extractSymbols(path5, before);
7912
+ function changedSymbolNames(path7, before, after) {
7913
+ const postSyms = extractSymbols(path7, after);
7914
+ const preSyms = extractSymbols(path7, before);
7933
7915
  const ranges = changedLineRanges(before, after);
7934
7916
  const inChangedRange = (line) => ranges.some(([s, e]) => s <= line && line <= e);
7935
7917
  const names = /* @__PURE__ */ new Set();
@@ -7942,22 +7924,22 @@ function changedSymbolNames(path5, before, after) {
7942
7924
  }
7943
7925
  return names;
7944
7926
  }
7945
- function moduleStem(path5) {
7946
- const base = path5.split("/").pop() ?? "";
7927
+ function moduleStem(path7) {
7928
+ const base = path7.split("/").pop() ?? "";
7947
7929
  const dot = base.lastIndexOf(".");
7948
7930
  return dot > 0 ? base.slice(0, dot) : base;
7949
7931
  }
7950
- function buildDependencyAdvisory(path5, before, after, graph, options = {}) {
7951
- if (!path5 || after === null) return null;
7932
+ function buildDependencyAdvisory(path7, before, after, graph, options = {}) {
7933
+ if (!path7 || after === null) return null;
7952
7934
  if (!graph.status().ready) return null;
7953
7935
  const maxFiles = Math.max(1, options.maxFiles ?? DEPENDENCY_ADVISORY_MAX_FILES);
7954
7936
  const maxSymbols = Math.max(1, options.maxSymbols ?? DEPENDENCY_ADVISORY_MAX_SYMBOLS);
7955
7937
  const isNew = before === null;
7956
7938
  let changed;
7957
7939
  if (isNew) {
7958
- changed = new Set(extractSymbols(path5, after).map((s) => s.name).filter(Boolean));
7940
+ changed = new Set(extractSymbols(path7, after).map((s) => s.name).filter(Boolean));
7959
7941
  } else {
7960
- changed = changedSymbolNames(path5, before, after);
7942
+ changed = changedSymbolNames(path7, before, after);
7961
7943
  if (changed.size === 0) return null;
7962
7944
  }
7963
7945
  const affected = /* @__PURE__ */ new Map();
@@ -7972,7 +7954,7 @@ function buildDependencyAdvisory(path5, before, after, graph, options = {}) {
7972
7954
  return names.has(name2.toLowerCase());
7973
7955
  };
7974
7956
  const add = (sourcePath, name2) => {
7975
- if (!sourcePath || sourcePath === path5) return;
7957
+ if (!sourcePath || sourcePath === path7) return;
7976
7958
  if (definesLocally(sourcePath, name2)) return;
7977
7959
  let names = affected.get(sourcePath);
7978
7960
  if (!names) affected.set(sourcePath, names = /* @__PURE__ */ new Set());
@@ -7986,7 +7968,7 @@ function buildDependencyAdvisory(path5, before, after, graph, options = {}) {
7986
7968
  add(edge.source_path, name2);
7987
7969
  }
7988
7970
  }
7989
- const stem = moduleStem(path5);
7971
+ const stem = moduleStem(path7);
7990
7972
  if (stem) {
7991
7973
  for (const edge of graph.findImporters(stem, { strictReachable: true })) {
7992
7974
  add(edge.source_path, stem);
@@ -7999,15 +7981,702 @@ function buildDependencyAdvisory(path5, before, after, graph, options = {}) {
7999
7981
  const symbolNames = [...changed].sort();
8000
7982
  let symStr = symbolNames.slice(0, maxSymbols).join(", ");
8001
7983
  if (symbolNames.length > maxSymbols) symStr += ", \u2026";
8002
- const lead = isNew ? `${files.length} existing file(s) already import or reference ${path5}` : `${files.length} other file(s) import or use what you changed in ${path5} (${symStr})`;
7984
+ const lead = isNew ? `${files.length} existing file(s) already import or reference ${path7}` : `${files.length} other file(s) import or use what you changed in ${path7} (${symStr})`;
8003
7985
  let note = `${lead}. Affected (best-effort, by name \u2014 verify before relying): ${shown.join(", ")}`;
8004
7986
  if (extra > 0) {
8005
- note += `. +${extra} more \u2014 use trace_codebase on ${path5} for the full set`;
7987
+ note += `. +${extra} more \u2014 use trace_codebase on ${path7} for the full set`;
8006
7988
  }
8007
7989
  note += ".";
8008
7990
  return { files, note };
8009
7991
  }
8010
7992
 
7993
+ // ../packages/orion-client-core/src/vectorStore.ts
7994
+ var path5 = __toESM(require("path"));
7995
+ var import_crypto2 = require("crypto");
7996
+ var import_fs3 = require("fs");
7997
+ var VECTOR_STORE_VERSION = 1;
7998
+ var VECTOR_CHECKPOINT_ROWS = 1024;
7999
+ var VECTOR_SCAN_BLOCK_ROWS = 1024;
8000
+ var VECTOR_LOCK_STALE_MS = 15 * 6e4;
8001
+ var VECTOR_LAYER_BUSY_PREFIX = "vector layer busy:";
8002
+ var BYTES_PER_FLOAT = 4;
8003
+ var VectorLayerBusyError = class extends Error {
8004
+ constructor(lockPath, holderPid) {
8005
+ super(`${VECTOR_LAYER_BUSY_PREFIX} another Orion process (pid ${holderPid}) is embedding this workspace`);
8006
+ this.lockPath = lockPath;
8007
+ this.holderPid = holderPid;
8008
+ this.name = "VectorLayerBusyError";
8009
+ }
8010
+ };
8011
+ function processAlive(pid) {
8012
+ try {
8013
+ process.kill(pid, 0);
8014
+ return true;
8015
+ } catch (error) {
8016
+ return error.code === "EPERM";
8017
+ }
8018
+ }
8019
+ var realFs2 = {
8020
+ readText: (p) => import_fs3.promises.readFile(p, "utf8"),
8021
+ writeTextAtomic: (p, content) => atomicWriteFile(p, content),
8022
+ writeBytesAtomic: (p, bytes) => atomicWriteFile(p, Buffer.from(bytes)),
8023
+ appendBytes: (p, bytes) => import_fs3.promises.appendFile(p, bytes),
8024
+ readBytesAt: async (p, offset, length) => {
8025
+ const handle4 = await import_fs3.promises.open(p, "r");
8026
+ try {
8027
+ const buffer = new Uint8Array(length);
8028
+ let read = 0;
8029
+ while (read < length) {
8030
+ const { bytesRead } = await handle4.read(buffer, read, length - read, offset + read);
8031
+ if (bytesRead === 0) break;
8032
+ read += bytesRead;
8033
+ }
8034
+ return read === length ? buffer : buffer.subarray(0, read);
8035
+ } finally {
8036
+ await handle4.close();
8037
+ }
8038
+ },
8039
+ fileSize: async (p) => {
8040
+ try {
8041
+ return (await import_fs3.promises.stat(p)).size;
8042
+ } catch {
8043
+ return null;
8044
+ }
8045
+ },
8046
+ truncate: (p, size) => import_fs3.promises.truncate(p, size),
8047
+ rename: (from, to) => import_fs3.promises.rename(from, to),
8048
+ mkdir: async (p) => {
8049
+ await import_fs3.promises.mkdir(p, { recursive: true });
8050
+ },
8051
+ rm: (p) => import_fs3.promises.rm(p, { force: true }),
8052
+ createExclusive: async (p, content) => {
8053
+ try {
8054
+ await import_fs3.promises.writeFile(p, content, { flag: "wx" });
8055
+ return true;
8056
+ } catch (error) {
8057
+ if (error.code === "EEXIST") return false;
8058
+ throw error;
8059
+ }
8060
+ }
8061
+ };
8062
+ function vectorContentHash(text) {
8063
+ return (0, import_crypto2.createHash)("sha256").update(text, "utf8").digest("hex").slice(0, 32);
8064
+ }
8065
+ function vectorModelSlug(model) {
8066
+ const slug = model.toLowerCase().replace(/[^a-z0-9.]+/g, "-").replace(/^-+|-+$/g, "");
8067
+ return slug || "model";
8068
+ }
8069
+ function encodeManifest(root, model, manifest) {
8070
+ const rows = manifest.rows.map((r) => [r.hash, r.path, r.startLine, r.endLine, r.sig]);
8071
+ return JSON.stringify({ v: VECTOR_STORE_VERSION, root, model, dims: manifest.dims, rows });
8072
+ }
8073
+ function decodeManifest(raw, expected) {
8074
+ let parsed;
8075
+ try {
8076
+ parsed = JSON.parse(raw);
8077
+ } catch {
8078
+ return null;
8079
+ }
8080
+ if (!parsed || typeof parsed !== "object") return null;
8081
+ const m = parsed;
8082
+ if (m.v !== VECTOR_STORE_VERSION || m.root !== expected.root || m.model !== expected.model) return null;
8083
+ const dims = m.dims;
8084
+ if (typeof dims !== "number" || !Number.isInteger(dims) || dims <= 0) return null;
8085
+ if (!Array.isArray(m.rows)) return null;
8086
+ const rows = [];
8087
+ for (const entry of m.rows) {
8088
+ if (!Array.isArray(entry) || entry.length !== 5) return null;
8089
+ const [hash, p, startLine, endLine, sig] = entry;
8090
+ if (typeof hash !== "string" || typeof p !== "string" || typeof sig !== "string") return null;
8091
+ if (typeof startLine !== "number" || typeof endLine !== "number") return null;
8092
+ rows.push({ hash, path: p, startLine, endLine, sig });
8093
+ }
8094
+ return { dims, rows };
8095
+ }
8096
+ var VectorStore = class {
8097
+ root;
8098
+ model;
8099
+ fsOps;
8100
+ log;
8101
+ now;
8102
+ pidAlive;
8103
+ dir;
8104
+ slug;
8105
+ dimsValue = 0;
8106
+ rowsValue = [];
8107
+ /** Rows the manifest on disk describes; rows past this are appended but uncommitted. */
8108
+ committedRows = 0;
8109
+ loaded = false;
8110
+ lockHeld = false;
8111
+ constructor(options) {
8112
+ this.root = options.root;
8113
+ this.model = options.model;
8114
+ this.fsOps = options.fsOps ?? realFs2;
8115
+ this.log = options.log ?? (() => void 0);
8116
+ this.now = options.now ?? Date.now;
8117
+ this.pidAlive = options.pidAlive ?? processAlive;
8118
+ this.dir = path5.join(options.baseDir ?? defaultIndexCacheBaseDir(), indexCacheFingerprint(options.root));
8119
+ this.slug = vectorModelSlug(options.model);
8120
+ }
8121
+ binPath() {
8122
+ return path5.join(this.dir, `vectors.${this.slug}.bin`);
8123
+ }
8124
+ manifestPath() {
8125
+ return path5.join(this.dir, `vectors.${this.slug}.json`);
8126
+ }
8127
+ lockPath() {
8128
+ return path5.join(this.dir, `vectors.${this.slug}.lock`);
8129
+ }
8130
+ /** Take the layer's writer lock: create the lock file exclusively; break a
8131
+ * stale one (dead holder, or older than VECTOR_LOCK_STALE_MS) once and retry;
8132
+ * throw VectorLayerBusyError for a live holder. */
8133
+ async acquireLock() {
8134
+ await this.fsOps.mkdir(this.dir);
8135
+ const record = { pid: process.pid, startedAt: this.now() };
8136
+ for (let attempt = 0; attempt < 2; attempt++) {
8137
+ if (await this.fsOps.createExclusive(this.lockPath(), JSON.stringify(record))) {
8138
+ this.lockHeld = true;
8139
+ return;
8140
+ }
8141
+ const holder = await this.readLock();
8142
+ const stale = holder === null || holder.pid === process.pid || !this.pidAlive(holder.pid) || this.now() - holder.startedAt > VECTOR_LOCK_STALE_MS;
8143
+ if (!stale) throw new VectorLayerBusyError(this.lockPath(), holder.pid);
8144
+ this.log(`orion: vector layer for ${this.model} \u2014 breaking a stale lock (pid ${holder?.pid ?? "?"})`);
8145
+ await this.fsOps.rm(this.lockPath());
8146
+ }
8147
+ throw new VectorLayerBusyError(this.lockPath(), 0);
8148
+ }
8149
+ async readLock() {
8150
+ try {
8151
+ const parsed = JSON.parse(await this.fsOps.readText(this.lockPath()));
8152
+ if (typeof parsed.pid !== "number" || typeof parsed.startedAt !== "number") return null;
8153
+ return { pid: parsed.pid, startedAt: parsed.startedAt };
8154
+ } catch {
8155
+ return null;
8156
+ }
8157
+ }
8158
+ /** Release the writer lock. Safe to call more than once, and without `load()`. */
8159
+ async close() {
8160
+ if (!this.lockHeld) return;
8161
+ this.lockHeld = false;
8162
+ await this.fsOps.rm(this.lockPath());
8163
+ }
8164
+ dims() {
8165
+ return this.dimsValue;
8166
+ }
8167
+ size() {
8168
+ return this.rowsValue.length;
8169
+ }
8170
+ rows() {
8171
+ return this.rowsValue;
8172
+ }
8173
+ /** Take the lock, then read the manifest and reconcile it with the .bin: an
8174
+ * absent layer starts empty; a rejected manifest or a .bin shorter than its
8175
+ * manifest discards the layer (a wrong vector is structurally impossible —
8176
+ * the worst case is re-embedding once); a .bin longer than its manifest is a
8177
+ * crashed append and its tail is truncated. */
8178
+ async load() {
8179
+ await this.acquireLock();
8180
+ try {
8181
+ await this.reconcile();
8182
+ } catch (error) {
8183
+ await this.close();
8184
+ throw error;
8185
+ }
8186
+ }
8187
+ /** The manifest ↔ .bin reconcile `load()` runs under the lock. */
8188
+ async reconcile() {
8189
+ this.loaded = true;
8190
+ this.rowsValue = [];
8191
+ this.dimsValue = 0;
8192
+ this.committedRows = 0;
8193
+ let raw;
8194
+ try {
8195
+ raw = await this.fsOps.readText(this.manifestPath());
8196
+ } catch {
8197
+ return;
8198
+ }
8199
+ const manifest = decodeManifest(raw, { root: this.root, model: this.model });
8200
+ if (!manifest) {
8201
+ this.log(`orion: vector layer for ${this.model} rejected (version/identity/shape) \u2014 re-embedding`);
8202
+ await this.discard();
8203
+ return;
8204
+ }
8205
+ const binSize = await this.fsOps.fileSize(this.binPath());
8206
+ const committedBytes = manifest.rows.length * manifest.dims * BYTES_PER_FLOAT;
8207
+ if (binSize === null || binSize < committedBytes) {
8208
+ this.log(`orion: vector file for ${this.model} is shorter than its manifest \u2014 re-embedding`);
8209
+ await this.discard();
8210
+ return;
8211
+ }
8212
+ if (binSize > committedBytes) {
8213
+ await this.fsOps.truncate(this.binPath(), committedBytes);
8214
+ this.log(`orion: vector layer for ${this.model} dropped an uncommitted tail (${binSize - committedBytes} bytes)`);
8215
+ }
8216
+ this.dimsValue = manifest.dims;
8217
+ this.rowsValue = manifest.rows;
8218
+ this.committedRows = manifest.rows.length;
8219
+ }
8220
+ async discard() {
8221
+ await this.fsOps.rm(this.binPath());
8222
+ await this.fsOps.rm(this.manifestPath());
8223
+ this.rowsValue = [];
8224
+ this.dimsValue = 0;
8225
+ this.committedRows = 0;
8226
+ }
8227
+ /** Append rows with their vectors (same length, every vector `dims` wide —
8228
+ * the first append of an empty layer fixes `dims`). Rows land in the .bin at
8229
+ * once; the manifest checkpoints every VECTOR_CHECKPOINT_ROWS rows and on
8230
+ * `flush()`, so a run's progress survives a crash in bounded pieces. */
8231
+ async append(rows, vectors) {
8232
+ this.assertLoaded();
8233
+ if (rows.length !== vectors.length) throw new Error("vector store: rows and vectors differ in length");
8234
+ if (rows.length === 0) return;
8235
+ const dims = vectors[0].length;
8236
+ if (dims === 0) throw new Error("vector store: an empty vector");
8237
+ if (this.dimsValue === 0) {
8238
+ this.dimsValue = dims;
8239
+ await this.fsOps.mkdir(this.dir);
8240
+ await this.fsOps.writeBytesAtomic(this.binPath(), new Uint8Array(0));
8241
+ } else if (dims !== this.dimsValue) {
8242
+ throw new Error(`vector store: width ${dims} does not match the layer's ${this.dimsValue}`);
8243
+ }
8244
+ const block = new Float32Array(rows.length * dims);
8245
+ for (let i2 = 0; i2 < vectors.length; i2++) {
8246
+ if (vectors[i2].length !== dims) throw new Error("vector store: vectors of differing width");
8247
+ block.set(vectors[i2], i2 * dims);
8248
+ }
8249
+ await this.fsOps.appendBytes(this.binPath(), new Uint8Array(block.buffer, block.byteOffset, block.byteLength));
8250
+ for (const row of rows) this.rowsValue.push(row);
8251
+ if (this.rowsValue.length - this.committedRows >= VECTOR_CHECKPOINT_ROWS) await this.flush();
8252
+ }
8253
+ /** Commit every appended row to the manifest (a no-op when nothing is pending). */
8254
+ async flush() {
8255
+ this.assertLoaded();
8256
+ if (this.rowsValue.length === this.committedRows) return;
8257
+ await this.fsOps.mkdir(this.dir);
8258
+ await this.fsOps.writeTextAtomic(
8259
+ this.manifestPath(),
8260
+ encodeManifest(this.root, this.model, { dims: this.dimsValue, rows: this.rowsValue })
8261
+ );
8262
+ this.committedRows = this.rowsValue.length;
8263
+ }
8264
+ /** Stream every row's vector, in row order, through a reusable block buffer:
8265
+ * `visit` must not retain `vector` past the call. `include` skips rows
8266
+ * without reading them into the visit (dead rows still cost the block read). */
8267
+ async scan(visit, include) {
8268
+ this.assertLoaded();
8269
+ const total = this.rowsValue.length;
8270
+ if (total === 0) return;
8271
+ const dims = this.dimsValue;
8272
+ const rowBytes = dims * BYTES_PER_FLOAT;
8273
+ for (let start2 = 0; start2 < total; start2 += VECTOR_SCAN_BLOCK_ROWS) {
8274
+ const count = Math.min(VECTOR_SCAN_BLOCK_ROWS, total - start2);
8275
+ const bytes = await this.fsOps.readBytesAt(this.binPath(), start2 * rowBytes, count * rowBytes);
8276
+ if (bytes.length < count * rowBytes) {
8277
+ throw new Error("vector store: the vector file is shorter than its manifest");
8278
+ }
8279
+ const floats = new Float32Array(bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + count * rowBytes));
8280
+ for (let i2 = 0; i2 < count; i2++) {
8281
+ const rowIndex = start2 + i2;
8282
+ if (include && !include(rowIndex)) continue;
8283
+ visit(rowIndex, floats.subarray(i2 * dims, (i2 + 1) * dims));
8284
+ }
8285
+ }
8286
+ }
8287
+ /** Rewrite the layer with only the rows `keep` selects — the dead-row sweep
8288
+ * after a reconcile. Streams the old .bin block by block into a sibling file
8289
+ * and renames it over, then commits the surviving rows' manifest. */
8290
+ async compact(keep) {
8291
+ this.assertLoaded();
8292
+ const total = this.rowsValue.length;
8293
+ const survivors = [];
8294
+ if (total === 0) return { kept: 0, dropped: 0 };
8295
+ const dims = this.dimsValue;
8296
+ const rowBytes = dims * BYTES_PER_FLOAT;
8297
+ const tmp = `${this.binPath()}.compact`;
8298
+ await this.fsOps.writeBytesAtomic(tmp, new Uint8Array(0));
8299
+ for (let start2 = 0; start2 < total; start2 += VECTOR_SCAN_BLOCK_ROWS) {
8300
+ const count = Math.min(VECTOR_SCAN_BLOCK_ROWS, total - start2);
8301
+ const bytes = await this.fsOps.readBytesAt(this.binPath(), start2 * rowBytes, count * rowBytes);
8302
+ const keptBytes = [];
8303
+ for (let i2 = 0; i2 < count; i2++) {
8304
+ const rowIndex = start2 + i2;
8305
+ const row = this.rowsValue[rowIndex];
8306
+ if (!keep(row, rowIndex)) continue;
8307
+ survivors.push(row);
8308
+ keptBytes.push(bytes.subarray(i2 * rowBytes, (i2 + 1) * rowBytes));
8309
+ }
8310
+ if (keptBytes.length > 0) {
8311
+ const merged = new Uint8Array(keptBytes.length * rowBytes);
8312
+ keptBytes.forEach((chunk, i2) => merged.set(chunk, i2 * rowBytes));
8313
+ await this.fsOps.appendBytes(tmp, merged);
8314
+ }
8315
+ }
8316
+ await this.fsOps.rename(tmp, this.binPath());
8317
+ const dropped = total - survivors.length;
8318
+ this.rowsValue = survivors;
8319
+ this.committedRows = -1;
8320
+ await this.fsOps.writeTextAtomic(
8321
+ this.manifestPath(),
8322
+ encodeManifest(this.root, this.model, { dims, rows: survivors })
8323
+ );
8324
+ this.committedRows = survivors.length;
8325
+ return { kept: survivors.length, dropped };
8326
+ }
8327
+ assertLoaded() {
8328
+ if (!this.loaded) throw new Error("vector store: load() first");
8329
+ }
8330
+ };
8331
+
8332
+ // ../packages/orion-client-core/src/enhancedRetrieval.ts
8333
+ var ENHANCED_TEST_DIRS = /* @__PURE__ */ new Set(["test", "tests", "testing"]);
8334
+ var ENHANCED_CHUNK_SOURCE_CHARS = 1e4;
8335
+ var ENHANCED_EMBED_BATCH_SIZE = 16;
8336
+ var ENHANCED_EMBED_MAX_RETRIES = 2;
8337
+ var ENHANCED_PAYLOAD_BUDGET_BYTES = 8 * 1024 * 1024;
8338
+ var COMPACT_MIN_DEAD_ROWS = 1e3;
8339
+ var COMPACT_DEAD_RATIO = 0.25;
8340
+ var CODE_CHUNK_KINDS = /* @__PURE__ */ new Set(["function", "method", "class", "module", "window"]);
8341
+ var CLASS_LIKE_SYMBOL_KINDS = /* @__PURE__ */ new Set(["class", "interface", "struct", "trait", "enum"]);
8342
+ function retrievalChunkType(kind) {
8343
+ if (kind === "function" || kind === "method") return "function";
8344
+ if (kind === "class") return "class";
8345
+ return "file";
8346
+ }
8347
+ function isTestDirectoryPath(relPath) {
8348
+ const parts2 = relPath.replace(/\\/g, "/").split("/");
8349
+ return parts2.slice(0, -1).some((part) => ENHANCED_TEST_DIRS.has(part.toLowerCase()));
8350
+ }
8351
+ function chunkSource(lines, startLine, endLine) {
8352
+ return lines.slice(Math.max(0, startLine - 1), Math.max(0, endLine)).join("\n");
8353
+ }
8354
+ function embeddingText(relPath, type, source) {
8355
+ return `File Path: ${relPath}
8356
+ File Type: ${type}
8357
+
8358
+ ${source.slice(0, ENHANCED_CHUNK_SOURCE_CHARS)}`;
8359
+ }
8360
+ function fileSignature(stat) {
8361
+ return `${stat.size}:${stat.mtimeMs}`;
8362
+ }
8363
+ function chunkIdentity(chunk, symbols) {
8364
+ let name2 = chunk.title;
8365
+ let parent = null;
8366
+ if (chunk.kind === "function" || chunk.kind === "method" || chunk.kind === "class") {
8367
+ const own = symbols.find((s) => s.line === chunk.startLine);
8368
+ if (own) name2 = own.name;
8369
+ if (chunk.kind === "method") {
8370
+ for (const s of symbols) {
8371
+ if (s.line >= chunk.startLine) break;
8372
+ if (CLASS_LIKE_SYMBOL_KINDS.has(s.kind)) parent = s.name;
8373
+ }
8374
+ }
8375
+ }
8376
+ return { name: name2, parent };
8377
+ }
8378
+ function normalizeInPlace(vector) {
8379
+ let sum = 0;
8380
+ for (let i2 = 0; i2 < vector.length; i2++) sum += vector[i2] * vector[i2];
8381
+ const norm = Math.sqrt(sum);
8382
+ if (norm > 0) for (let i2 = 0; i2 < vector.length; i2++) vector[i2] /= norm;
8383
+ return vector;
8384
+ }
8385
+ function cosineAgainstNormalized(query, row) {
8386
+ let dot = 0;
8387
+ let sum = 0;
8388
+ for (let i2 = 0; i2 < query.length; i2++) {
8389
+ dot += query[i2] * row[i2];
8390
+ sum += row[i2] * row[i2];
8391
+ }
8392
+ const norm = Math.sqrt(sum);
8393
+ return norm > 0 ? dot / norm : 0;
8394
+ }
8395
+ var TopK = class {
8396
+ constructor(k) {
8397
+ this.k = k;
8398
+ }
8399
+ rows = [];
8400
+ scores = [];
8401
+ offer(rowIndex, score) {
8402
+ if (this.k <= 0) return;
8403
+ const full = this.rows.length >= this.k;
8404
+ if (full && score <= this.scores[this.scores.length - 1]) return;
8405
+ let lo = 0;
8406
+ let hi = this.scores.length;
8407
+ while (lo < hi) {
8408
+ const mid = lo + hi >> 1;
8409
+ if (this.scores[mid] >= score) lo = mid + 1;
8410
+ else hi = mid;
8411
+ }
8412
+ this.rows.splice(lo, 0, rowIndex);
8413
+ this.scores.splice(lo, 0, score);
8414
+ if (full) {
8415
+ this.rows.pop();
8416
+ this.scores.pop();
8417
+ }
8418
+ }
8419
+ entries() {
8420
+ return this.rows.map((rowIndex, i2) => ({ rowIndex, score: this.scores[i2] }));
8421
+ }
8422
+ };
8423
+ var inFlight = /* @__PURE__ */ new Map();
8424
+ async function serialized(key, run2) {
8425
+ const prior = inFlight.get(key) ?? Promise.resolve();
8426
+ const next = prior.catch(() => void 0).then(run2);
8427
+ inFlight.set(key, next);
8428
+ try {
8429
+ return await next;
8430
+ } finally {
8431
+ if (inFlight.get(key) === next) inFlight.delete(key);
8432
+ }
8433
+ }
8434
+ var defaultSleep = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
8435
+ async function enhancedRetrieve(request, deps) {
8436
+ return await serialized(`${deps.baseDir ?? ""}\0${deps.root}`, () => runEnhancedRetrieve(request, deps));
8437
+ }
8438
+ async function runEnhancedRetrieve(request, deps) {
8439
+ const now = deps.now ?? Date.now;
8440
+ const started = now();
8441
+ const log = deps.log ?? (() => void 0);
8442
+ const sleep = deps.sleep ?? defaultSleep;
8443
+ const batchSize = Math.max(1, deps.batchSize ?? ENHANCED_EMBED_BATCH_SIZE);
8444
+ const maxRetries = Math.max(1, deps.maxRetries ?? ENHANCED_EMBED_MAX_RETRIES);
8445
+ const payloadBudget = deps.payloadBudgetBytes ?? ENHANCED_PAYLOAD_BUDGET_BYTES;
8446
+ const scope = normalizeScope(request.scope);
8447
+ const inventory = [];
8448
+ for (const chunk of deps.chunks()) {
8449
+ if (!CODE_CHUNK_KINDS.has(chunk.kind)) continue;
8450
+ if (isTestDirectoryPath(chunk.path)) continue;
8451
+ if (scope && !inScope(chunk.path, scope)) continue;
8452
+ inventory.push({ chunk, type: retrievalChunkType(chunk.kind), rowIndex: -1 });
8453
+ }
8454
+ const byPath = /* @__PURE__ */ new Map();
8455
+ for (const entry of inventory) {
8456
+ const list = byPath.get(entry.chunk.path);
8457
+ if (list) list.push(entry);
8458
+ else byPath.set(entry.chunk.path, [entry]);
8459
+ }
8460
+ const queryResponse = await deps.embeddings.embed({
8461
+ texts: [request.queryText],
8462
+ inputType: "query",
8463
+ sessionId: request.sessionId
8464
+ });
8465
+ const model = queryResponse.model;
8466
+ const provider = queryResponse.provider;
8467
+ const query = normalizeInPlace(Float32Array.from(queryResponse.vectors[0] ?? []));
8468
+ const stats = {
8469
+ files_considered: byPath.size,
8470
+ chunks_considered: inventory.length,
8471
+ chunks_embedded: 0,
8472
+ cache_hits: 0,
8473
+ failed_chunks: 0,
8474
+ files_sent: 0,
8475
+ files_truncated: 0,
8476
+ elapsed_ms: 0
8477
+ };
8478
+ const store2 = new VectorStore({ root: deps.root, model, baseDir: deps.baseDir, fsOps: deps.fsOps, log });
8479
+ await store2.load();
8480
+ try {
8481
+ const rowByHash = /* @__PURE__ */ new Map();
8482
+ const rowBySpan = /* @__PURE__ */ new Map();
8483
+ store2.rows().forEach((row, i2) => {
8484
+ rowByHash.set(row.hash, i2);
8485
+ rowBySpan.set(spanKey(row.path, row.sig, row.startLine, row.endLine), i2);
8486
+ });
8487
+ const signatures = /* @__PURE__ */ new Map();
8488
+ const embedBatch = async (batch) => {
8489
+ let vectors = null;
8490
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
8491
+ try {
8492
+ const response = await deps.embeddings.embed({
8493
+ texts: batch.map((m) => m.text),
8494
+ inputType: "passage",
8495
+ model,
8496
+ sessionId: request.sessionId
8497
+ });
8498
+ if (response.vectors.length !== batch.length) {
8499
+ throw new Error(`embedding batch answered ${response.vectors.length} vectors for ${batch.length} texts`);
8500
+ }
8501
+ vectors = response.vectors;
8502
+ break;
8503
+ } catch (error) {
8504
+ const message = error instanceof Error ? error.message : String(error);
8505
+ if (attempt < maxRetries - 1) {
8506
+ const waitMs = 2 ** attempt * 1e3;
8507
+ log(`orion: embedding batch failed (attempt ${attempt + 1}), retrying in ${waitMs / 1e3}s: ${message}`);
8508
+ await sleep(waitMs);
8509
+ } else {
8510
+ log(`orion: embedding batch failed after ${maxRetries} attempts: ${message}`);
8511
+ }
8512
+ }
8513
+ }
8514
+ deps.onProgress?.();
8515
+ if (!vectors) {
8516
+ stats.failed_chunks += batch.length;
8517
+ return;
8518
+ }
8519
+ const rows = [];
8520
+ const rowVectors = [];
8521
+ for (let i2 = 0; i2 < batch.length; i2++) {
8522
+ const miss = batch[i2];
8523
+ const known = rowByHash.get(miss.hash);
8524
+ if (known !== void 0) {
8525
+ miss.entry.rowIndex = known;
8526
+ continue;
8527
+ }
8528
+ const rowIndex = store2.size() + rows.length;
8529
+ rowByHash.set(miss.hash, rowIndex);
8530
+ miss.entry.rowIndex = rowIndex;
8531
+ rows.push({
8532
+ hash: miss.hash,
8533
+ path: miss.entry.chunk.path,
8534
+ startLine: miss.entry.chunk.startLine,
8535
+ endLine: miss.entry.chunk.endLine,
8536
+ sig: signatures.get(miss.entry.chunk.path) ?? ""
8537
+ });
8538
+ rowVectors.push(Float32Array.from(vectors[i2]));
8539
+ }
8540
+ if (rows.length > 0) await store2.append(rows, rowVectors);
8541
+ stats.chunks_embedded += batch.length;
8542
+ };
8543
+ let pending = [];
8544
+ const embedPending = async () => {
8545
+ if (pending.length === 0) return;
8546
+ const batch = pending;
8547
+ pending = [];
8548
+ await embedBatch(batch);
8549
+ };
8550
+ for (const [relPath, entries] of byPath) {
8551
+ const stat = await deps.stat(relPath);
8552
+ if (!stat) continue;
8553
+ const sig = fileSignature(stat);
8554
+ signatures.set(relPath, sig);
8555
+ const trusted = entries.every((entry) => {
8556
+ const row = rowBySpan.get(spanKey(relPath, sig, entry.chunk.startLine, entry.chunk.endLine));
8557
+ if (row === void 0) return false;
8558
+ entry.rowIndex = row;
8559
+ return true;
8560
+ });
8561
+ if (trusted) {
8562
+ stats.cache_hits += entries.length;
8563
+ continue;
8564
+ }
8565
+ const text = await deps.readFile(relPath);
8566
+ if (text === null) continue;
8567
+ const lines = text.split("\n");
8568
+ for (const entry of entries) {
8569
+ const rendered = embeddingText(relPath, entry.type, chunkSource(lines, entry.chunk.startLine, entry.chunk.endLine));
8570
+ const hash = vectorContentHash(rendered);
8571
+ const row = rowByHash.get(hash);
8572
+ if (row !== void 0) {
8573
+ entry.rowIndex = row;
8574
+ stats.cache_hits += 1;
8575
+ continue;
8576
+ }
8577
+ pending.push({ entry, text: rendered, hash });
8578
+ if (pending.length >= batchSize) await embedPending();
8579
+ }
8580
+ }
8581
+ await embedPending();
8582
+ await store2.flush();
8583
+ const liveRows = /* @__PURE__ */ new Map();
8584
+ for (const entry of inventory) {
8585
+ if (entry.rowIndex < 0) continue;
8586
+ const list = liveRows.get(entry.rowIndex);
8587
+ if (list) list.push(entry);
8588
+ else liveRows.set(entry.rowIndex, [entry]);
8589
+ }
8590
+ const top = new TopK(Math.max(0, Math.min(request.topK, liveRows.size)));
8591
+ if (query.length === store2.dims() && liveRows.size > 0) {
8592
+ await store2.scan(
8593
+ (rowIndex, vector) => top.offer(rowIndex, cosineAgainstNormalized(query, vector)),
8594
+ (rowIndex) => liveRows.has(rowIndex)
8595
+ );
8596
+ } else if (liveRows.size > 0) {
8597
+ log(`orion: query vector width ${query.length} does not match the layer's ${store2.dims()} \u2014 no ranking`);
8598
+ }
8599
+ const hits = [];
8600
+ for (const { rowIndex, score } of top.entries()) {
8601
+ for (const entry of liveRows.get(rowIndex) ?? []) {
8602
+ hits.push({ ...describeChunk(entry, deps.symbolsFor(entry.chunk.path)), score });
8603
+ }
8604
+ }
8605
+ hits.splice(request.topK);
8606
+ const candidateFiles = [];
8607
+ const seen = /* @__PURE__ */ new Set();
8608
+ for (const hit of hits) {
8609
+ if (seen.has(hit.path)) continue;
8610
+ seen.add(hit.path);
8611
+ candidateFiles.push(hit.path);
8612
+ }
8613
+ const files = [];
8614
+ const fileChunks = {};
8615
+ let sentBytes = 0;
8616
+ let sentChars = 0;
8617
+ for (const relPath of candidateFiles) {
8618
+ const symbols = deps.symbolsFor(relPath);
8619
+ fileChunks[relPath] = (byPath.get(relPath) ?? []).map((entry) => describeChunk(entry, symbols));
8620
+ const content = await deps.readFile(relPath);
8621
+ if (content === null) {
8622
+ stats.files_truncated += 1;
8623
+ continue;
8624
+ }
8625
+ const bytes = Buffer.byteLength(content, "utf8");
8626
+ const overBudget = files.length > 0 && sentBytes + bytes > payloadBudget;
8627
+ if (overBudget && sentChars >= request.rerankSourceChars) {
8628
+ stats.files_truncated += 1;
8629
+ continue;
8630
+ }
8631
+ files.push({ path: relPath, content });
8632
+ sentBytes += bytes;
8633
+ sentChars += content.length;
8634
+ }
8635
+ stats.files_sent = files.length;
8636
+ const dead = store2.size() - liveRows.size;
8637
+ if (dead >= COMPACT_MIN_DEAD_ROWS && dead >= store2.size() * COMPACT_DEAD_RATIO) {
8638
+ const swept = await store2.compact((_row, rowIndex) => liveRows.has(rowIndex));
8639
+ log(`orion: vector layer for ${model} compacted \u2014 kept ${swept.kept}, dropped ${swept.dropped}`);
8640
+ }
8641
+ stats.elapsed_ms = Math.max(0, now() - started);
8642
+ return {
8643
+ version: 1,
8644
+ provider,
8645
+ model,
8646
+ dims: store2.dims() || query.length,
8647
+ query_text: request.queryText,
8648
+ hits,
8649
+ candidate_files: candidateFiles,
8650
+ files,
8651
+ file_chunks: fileChunks,
8652
+ stats
8653
+ };
8654
+ } finally {
8655
+ await store2.close();
8656
+ }
8657
+ }
8658
+ function describeChunk(entry, symbols) {
8659
+ const { name: name2, parent } = chunkIdentity(entry.chunk, symbols);
8660
+ return {
8661
+ path: entry.chunk.path,
8662
+ type: entry.type,
8663
+ name: name2,
8664
+ parent,
8665
+ start_line: entry.chunk.startLine,
8666
+ end_line: entry.chunk.endLine
8667
+ };
8668
+ }
8669
+ function spanKey(relPath, sig, startLine, endLine) {
8670
+ return `${relPath}\0${sig}\0${startLine}-${endLine}`;
8671
+ }
8672
+ function normalizeScope(scope) {
8673
+ const trimmed = (scope ?? "").trim().replace(/\\/g, "/").replace(/^\.\/+/, "").replace(/\/+$/, "");
8674
+ return trimmed === "." ? "" : trimmed;
8675
+ }
8676
+ function inScope(relPath, scope) {
8677
+ return relPath === scope || relPath.startsWith(`${scope}/`);
8678
+ }
8679
+
8011
8680
  // ../packages/orion-client-core/src/shims/fileSource.ts
8012
8681
  function emptyIndexStatusDetail() {
8013
8682
  return {
@@ -8047,6 +8716,31 @@ var WorkerWorkspaceIndexer = class extends WorkspaceIndexer {
8047
8716
  return adaptiveIndexHeapBudgetBytes();
8048
8717
  }
8049
8718
  };
8719
+ var hostNextId = 1;
8720
+ var hostPending = /* @__PURE__ */ new Map();
8721
+ function callHost(method, params) {
8722
+ const id = hostNextId++;
8723
+ return new Promise((resolve5, reject) => {
8724
+ if (typeof process.send !== "function") {
8725
+ reject(new Error("embeddings are unavailable: no IPC channel to the host"));
8726
+ return;
8727
+ }
8728
+ hostPending.set(id, { resolve: resolve5, reject });
8729
+ const msg = { hostRequest: id, method, params };
8730
+ process.send(msg, (error) => {
8731
+ if (!error) return;
8732
+ hostPending.delete(id);
8733
+ reject(error);
8734
+ });
8735
+ });
8736
+ }
8737
+ function settleHostResponse(msg) {
8738
+ const pending = hostPending.get(msg.hostResponse);
8739
+ if (!pending) return;
8740
+ hostPending.delete(msg.hostResponse);
8741
+ if (msg.ok) pending.resolve(msg.result);
8742
+ else pending.reject(new Error(msg.error));
8743
+ }
8050
8744
  var config = {
8051
8745
  root: null,
8052
8746
  grammarDir: null,
@@ -8170,8 +8864,52 @@ var READ_METHODS = /* @__PURE__ */ new Set([
8170
8864
  "readContextHeader",
8171
8865
  "searchCodebase",
8172
8866
  "traceCodebase",
8867
+ "enhancedRetrieve",
8173
8868
  "dependencyAdvisory"
8174
8869
  ]);
8870
+ async function runEnhancedRetrieve2(input) {
8871
+ const root = config.root;
8872
+ if (!root) return null;
8873
+ const absolute = (rel) => path6.join(root, rel);
8874
+ return await enhancedRetrieve(
8875
+ {
8876
+ queryText: String(input.query_text ?? ""),
8877
+ topK: Number(input.top_k ?? 0),
8878
+ rerankSourceChars: Number(input.rerank_source_chars ?? 0),
8879
+ scope: input.scope,
8880
+ sessionId: input.sessionId
8881
+ },
8882
+ {
8883
+ root,
8884
+ chunks: () => store.chunkIndex.collect(),
8885
+ symbolsFor: (rel) => store.listSymbols(rel),
8886
+ readFile: async (rel) => {
8887
+ try {
8888
+ return await import_fs4.promises.readFile(absolute(rel), "utf8");
8889
+ } catch {
8890
+ return null;
8891
+ }
8892
+ },
8893
+ stat: async (rel) => {
8894
+ try {
8895
+ const s = await import_fs4.promises.stat(absolute(rel));
8896
+ return { size: s.size, mtimeMs: s.mtimeMs };
8897
+ } catch {
8898
+ return null;
8899
+ }
8900
+ },
8901
+ embeddings: {
8902
+ embed: (request) => callHost("embed", request)
8903
+ },
8904
+ ...config.cacheBaseDir ? { baseDir: config.cacheBaseDir } : {},
8905
+ log: (message) => console.log(message),
8906
+ onProgress: () => {
8907
+ lastActivityAt = Date.now();
8908
+ send({ event: "progress", kind: "heartbeat" });
8909
+ }
8910
+ }
8911
+ );
8912
+ }
8175
8913
  var WAKE_READ_WARM_WAIT_MS = 15e3;
8176
8914
  async function handle3(method, params) {
8177
8915
  if (READ_METHODS.has(method)) {
@@ -8201,19 +8939,14 @@ async function handle3(method, params) {
8201
8939
  return store.readContextHeader(
8202
8940
  String(params.path ?? ""),
8203
8941
  Number(params.line ?? 1),
8204
- String(params.mode ?? "full"),
8205
- params.options ?? {}
8942
+ String(params.mode ?? "full")
8206
8943
  );
8207
8944
  case "searchCodebase":
8208
- return store.searchCodebase(
8209
- params.input ?? {},
8210
- params.options ?? {}
8211
- );
8945
+ return store.searchCodebase(params.input ?? {});
8212
8946
  case "traceCodebase":
8213
- return store.traceCodebase(
8214
- params.input ?? {},
8215
- params.options ?? {}
8216
- );
8947
+ return store.traceCodebase(params.input ?? {});
8948
+ case "enhancedRetrieve":
8949
+ return await runEnhancedRetrieve2(params.input ?? {});
8217
8950
  case "dependencyAdvisory":
8218
8951
  return buildDependencyAdvisory(
8219
8952
  String(params.path ?? ""),
@@ -8231,6 +8964,10 @@ async function handle3(method, params) {
8231
8964
  }
8232
8965
  }
8233
8966
  process.on("message", (msg) => {
8967
+ if (msg && typeof msg === "object" && "hostResponse" in msg) {
8968
+ settleHostResponse(msg);
8969
+ return;
8970
+ }
8234
8971
  if (!msg || typeof msg.id !== "number" || typeof msg.method !== "string") return;
8235
8972
  activeRequests += 1;
8236
8973
  lastActivityAt = Date.now();