@orquentra/codebuddy 2.14.0 → 2.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/ARCHITECTURE.md +98 -0
  2. package/README.md +87 -6
  3. package/dist/{chunk-YNSTIMCF.js → chunk-4DTO2E4Y.js} +352 -157
  4. package/dist/chunk-4DTO2E4Y.js.map +1 -0
  5. package/dist/{chunk-CAEPHLHC.js → chunk-57642NGU.js} +2 -44
  6. package/dist/chunk-57642NGU.js.map +1 -0
  7. package/dist/chunk-6OQKL35B.js +55 -0
  8. package/dist/chunk-6OQKL35B.js.map +1 -0
  9. package/dist/{chunk-4DKYKDHI.js → chunk-7IPSDDO5.js} +5 -3
  10. package/dist/{chunk-4DKYKDHI.js.map → chunk-7IPSDDO5.js.map} +1 -1
  11. package/dist/chunk-7JPUMXFE.js +413 -0
  12. package/dist/chunk-7JPUMXFE.js.map +1 -0
  13. package/dist/{chunk-LRQNPYCK.js → chunk-AFXWCSQ4.js} +13 -7
  14. package/dist/chunk-AFXWCSQ4.js.map +1 -0
  15. package/dist/chunk-BNZDEU5K.js +368 -0
  16. package/dist/chunk-BNZDEU5K.js.map +1 -0
  17. package/dist/chunk-EMWGLKPR.js +45 -0
  18. package/dist/chunk-EMWGLKPR.js.map +1 -0
  19. package/dist/{chunk-YJPCS2GP.js → chunk-GNV4X67F.js} +59 -20
  20. package/dist/chunk-GNV4X67F.js.map +1 -0
  21. package/dist/{chunk-YWDH6DQ6.js → chunk-IM5RFEW4.js} +21 -19
  22. package/dist/{chunk-YWDH6DQ6.js.map → chunk-IM5RFEW4.js.map} +1 -1
  23. package/dist/chunk-K4XNTYV7.js +136 -0
  24. package/dist/chunk-K4XNTYV7.js.map +1 -0
  25. package/dist/{chunk-ESZXCZIN.js → chunk-MNSMW4MZ.js} +33 -5
  26. package/dist/chunk-MNSMW4MZ.js.map +1 -0
  27. package/dist/chunk-NNJSAYHY.js +372 -0
  28. package/dist/chunk-NNJSAYHY.js.map +1 -0
  29. package/dist/{chunk-XSNW6Y3X.js → chunk-OO7Q7XZF.js} +28 -24
  30. package/dist/chunk-OO7Q7XZF.js.map +1 -0
  31. package/dist/{chunk-L6BRYZ6G.js → chunk-PZ4EBFIA.js} +7 -7
  32. package/dist/{chunk-L6BRYZ6G.js.map → chunk-PZ4EBFIA.js.map} +1 -1
  33. package/dist/chunk-RGIVHKBH.js +156 -0
  34. package/dist/chunk-RGIVHKBH.js.map +1 -0
  35. package/dist/{chunk-LW75SKZR.js → chunk-RKF4HBBQ.js} +126 -18
  36. package/dist/chunk-RKF4HBBQ.js.map +1 -0
  37. package/dist/{chunk-7QMHIJBA.js → chunk-VBDM7HC5.js} +969 -968
  38. package/dist/chunk-VBDM7HC5.js.map +1 -0
  39. package/dist/chunk-VF7DKRIU.js +50 -0
  40. package/dist/chunk-VF7DKRIU.js.map +1 -0
  41. package/dist/{chunk-KNR2P2UY.js → chunk-Y4QQML24.js} +21 -6
  42. package/dist/chunk-Y4QQML24.js.map +1 -0
  43. package/dist/cli/index.js +4 -4
  44. package/dist/config-S2BDMT4B.js +15 -0
  45. package/dist/expand-TONFVT5D.js +98 -0
  46. package/dist/expand-TONFVT5D.js.map +1 -0
  47. package/dist/file-vectors-VREL75MA.js +19 -0
  48. package/dist/index-facts-MBJKBYA3.js +38 -0
  49. package/dist/index-pass-RP23G2CR.js +15 -0
  50. package/dist/index.js +24 -22
  51. package/dist/{install-EU35ERK5.js → install-MCJIJMFF.js} +11 -10
  52. package/dist/{lean-43ADYTBW.js → lean-CBHVW6JM.js} +8 -7
  53. package/dist/local-TH5XCLVJ.js +48 -0
  54. package/dist/local-llm-GZREB5DF.js +19 -0
  55. package/dist/local-llm-GZREB5DF.js.map +1 -0
  56. package/dist/{main-SFC5LV4E.js → main-QF6Z552J.js} +346 -140
  57. package/dist/main-QF6Z552J.js.map +1 -0
  58. package/dist/{memory-TGHVTBME.js → memory-LSZKSF53.js} +9 -6
  59. package/dist/{memory-TGHVTBME.js.map → memory-LSZKSF53.js.map} +1 -1
  60. package/dist/{operations-6Z6ZDVBP.js → operations-BPI633VN.js} +8 -7
  61. package/dist/operations-BPI633VN.js.map +1 -0
  62. package/dist/{rerank-IQAEWLQR.js → rerank-EPCTSEVP.js} +7 -4
  63. package/dist/{rerank-IQAEWLQR.js.map → rerank-EPCTSEVP.js.map} +1 -1
  64. package/dist/{runtime-W5AW32SD.js → runtime-W5ACTDFS.js} +9 -8
  65. package/dist/runtime-W5ACTDFS.js.map +1 -0
  66. package/dist/summaries-W2J5FCLG.js +32 -0
  67. package/dist/summaries-W2J5FCLG.js.map +1 -0
  68. package/dist/{zvec-24HLAFGN.js → zvec-LSA2IRAU.js} +13 -5
  69. package/dist/zvec-LSA2IRAU.js.map +1 -0
  70. package/package.json +3 -2
  71. package/dist/chunk-7QMHIJBA.js.map +0 -1
  72. package/dist/chunk-CAEPHLHC.js.map +0 -1
  73. package/dist/chunk-ESC4Y3L7.js +0 -204
  74. package/dist/chunk-ESC4Y3L7.js.map +0 -1
  75. package/dist/chunk-ESZXCZIN.js.map +0 -1
  76. package/dist/chunk-KNR2P2UY.js.map +0 -1
  77. package/dist/chunk-LRQNPYCK.js.map +0 -1
  78. package/dist/chunk-LW75SKZR.js.map +0 -1
  79. package/dist/chunk-SFMIMLXR.js +0 -63
  80. package/dist/chunk-SFMIMLXR.js.map +0 -1
  81. package/dist/chunk-XSNW6Y3X.js.map +0 -1
  82. package/dist/chunk-YJPCS2GP.js.map +0 -1
  83. package/dist/chunk-YNSTIMCF.js.map +0 -1
  84. package/dist/config-GEZFLXK6.js +0 -12
  85. package/dist/main-SFC5LV4E.js.map +0 -1
  86. package/dist/summaries-32PHOB6L.js +0 -20
  87. /package/dist/{config-GEZFLXK6.js.map → config-S2BDMT4B.js.map} +0 -0
  88. /package/dist/{install-EU35ERK5.js.map → file-vectors-VREL75MA.js.map} +0 -0
  89. /package/dist/{lean-43ADYTBW.js.map → index-facts-MBJKBYA3.js.map} +0 -0
  90. /package/dist/{operations-6Z6ZDVBP.js.map → index-pass-RP23G2CR.js.map} +0 -0
  91. /package/dist/{runtime-W5AW32SD.js.map → install-MCJIJMFF.js.map} +0 -0
  92. /package/dist/{summaries-32PHOB6L.js.map → lean-CBHVW6JM.js.map} +0 -0
  93. /package/dist/{zvec-24HLAFGN.js.map → local-TH5XCLVJ.js.map} +0 -0
@@ -6,20 +6,101 @@ import {
6
6
  import {
7
7
  isCredentialPath
8
8
  } from "./chunk-AL6VBTNA.js";
9
- import {
10
- LOCAL_EMBEDDING_MODEL
11
- } from "./chunk-HPOR6YXA.js";
12
9
  import {
13
10
  readConfigFile
14
- } from "./chunk-KNR2P2UY.js";
11
+ } from "./chunk-Y4QQML24.js";
15
12
  import {
16
13
  assertNoSymlinkBetween,
17
14
  writeAtomic
18
15
  } from "./chunk-CG5B3LYG.js";
16
+ import {
17
+ LOCAL_EMBEDDING_MODEL
18
+ } from "./chunk-HPOR6YXA.js";
19
+
20
+ // src/context/file-vectors.ts
21
+ import { createHash as createHash3 } from "crypto";
22
+ import { mkdir as mkdir5, readFile as readFile10 } from "fs/promises";
23
+ import { dirname as dirname6, join as join9 } from "path";
24
+
25
+ // src/indexer/engine.ts
26
+ import { createHash } from "crypto";
27
+ import { readFile as readFile4, stat as stat2 } from "fs/promises";
28
+ import { join as join5, resolve as resolve4 } from "path";
29
+
30
+ // src/map/cache.ts
31
+ import { mkdir as mkdir2, readFile as readFile3 } from "fs/promises";
32
+ import { dirname as dirname3, extname as extname2, join as join3, resolve as resolve3 } from "path";
33
+
34
+ // src/indexer/store.ts
35
+ import { mkdir, readFile } from "fs/promises";
36
+ import { dirname, join, resolve } from "path";
37
+ import { z } from "zod";
38
+
39
+ // src/indexer/types.ts
40
+ var INDEX_MANIFEST_VERSION = 3;
41
+
42
+ // src/indexer/store.ts
43
+ var symbolSpanSchema = z.object({
44
+ name: z.string(),
45
+ kind: z.enum(["function", "method", "class", "interface", "type", "enum", "const", "heading"]),
46
+ startLine: z.number().int().nonnegative(),
47
+ endLine: z.number().int().nonnegative(),
48
+ signature: z.string(),
49
+ exported: z.boolean()
50
+ });
51
+ var entrySchema = z.object({
52
+ path: z.string(),
53
+ hash: z.string(),
54
+ size: z.number().int().nonnegative(),
55
+ mtimeMs: z.number().optional(),
56
+ ctimeMs: z.number().optional(),
57
+ language: z.string(),
58
+ lines: z.number().int().nonnegative(),
59
+ symbols: z.array(z.string()),
60
+ symbolTable: z.array(symbolSpanSchema).optional(),
61
+ summary: z.string(),
62
+ indexedAt: z.string()
63
+ });
64
+ var manifestSchema = z.object({
65
+ version: z.literal(INDEX_MANIFEST_VERSION),
66
+ generatedAt: z.string(),
67
+ entries: z.record(z.string(), entrySchema)
68
+ });
69
+ var IndexStore = class {
70
+ repositoryRoot;
71
+ cacheDirectory;
72
+ manifestPath;
73
+ constructor(repositoryRoot = process.cwd()) {
74
+ this.repositoryRoot = resolve(repositoryRoot);
75
+ this.cacheDirectory = join(this.repositoryRoot, ".codebuddy", "cache");
76
+ this.manifestPath = join(this.cacheDirectory, "index.json");
77
+ }
78
+ /** Read the manifest, or an empty one if absent/corrupt/version-mismatched. */
79
+ async read() {
80
+ try {
81
+ const raw = await readFile(this.manifestPath, "utf8");
82
+ const parsed = manifestSchema.safeParse(JSON.parse(raw));
83
+ if (!parsed.success) return emptyManifest();
84
+ return parsed.data;
85
+ } catch (error) {
86
+ if (error.code === "ENOENT") return emptyManifest();
87
+ return emptyManifest();
88
+ }
89
+ }
90
+ async write(manifest) {
91
+ await assertNoSymlinkBetween(this.repositoryRoot, dirname(this.manifestPath));
92
+ await mkdir(this.cacheDirectory, { recursive: true, mode: 448 });
93
+ await writeAtomic(this.manifestPath, `${JSON.stringify(manifest, null, 2)}
94
+ `);
95
+ }
96
+ };
97
+ function emptyManifest() {
98
+ return { version: INDEX_MANIFEST_VERSION, generatedAt: (/* @__PURE__ */ new Date(0)).toISOString(), entries: {} };
99
+ }
19
100
 
20
101
  // src/map/indexer.ts
21
- import { readdir, readFile, stat } from "fs/promises";
22
- import { dirname, extname, join, relative, resolve } from "path";
102
+ import { readdir, readFile as readFile2, stat } from "fs/promises";
103
+ import { dirname as dirname2, extname, join as join2, relative, resolve as resolve2 } from "path";
23
104
  var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py"]);
24
105
  var IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
25
106
  ".git",
@@ -35,13 +116,13 @@ var IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
35
116
  "__pycache__"
36
117
  ]);
37
118
  async function buildArchitectureMap(repositoryRoot = process.cwd()) {
38
- const root = resolve(repositoryRoot);
119
+ const root = resolve2(repositoryRoot);
39
120
  const files = await listSourceFiles(root);
40
121
  const fileSet = new Set(files.map((file) => normalize(relative(root, file))));
41
122
  const modules = [];
42
123
  const edges = [];
43
124
  for (const absolutePath of files) {
44
- const source = await readFile(absolutePath, "utf8");
125
+ const source = await readFile2(absolutePath, "utf8");
45
126
  const from = normalize(relative(root, absolutePath));
46
127
  const resolvedImports = moduleImports(root, from, source, fileSet);
47
128
  edges.push(...resolvedImports.map(({ to, kind }) => ({ from, to, kind })));
@@ -59,7 +140,7 @@ async function buildArchitectureMap(repositoryRoot = process.cwd()) {
59
140
  };
60
141
  }
61
142
  async function updateArchitectureMap(repositoryRoot, sourcePaths, previous, changedPaths) {
62
- const root = resolve(repositoryRoot);
143
+ const root = resolve2(repositoryRoot);
63
144
  const normalizedPaths = sourcePaths.map(normalize).sort();
64
145
  const fileSet = new Set(normalizedPaths);
65
146
  const changed = new Set(changedPaths.map(normalize));
@@ -73,7 +154,7 @@ async function updateArchitectureMap(repositoryRoot, sourcePaths, previous, chan
73
154
  const edges = [...retainedEdges];
74
155
  for (const path of normalizedPaths) {
75
156
  if (!changed.has(path)) continue;
76
- const source = await readFile(join(root, path), "utf8");
157
+ const source = await readFile2(join2(root, path), "utf8");
77
158
  const resolvedImports = moduleImports(root, path, source, fileSet);
78
159
  edges.push(...resolvedImports.map(({ to, kind }) => ({ from: path, to, kind })));
79
160
  modules.push({
@@ -125,7 +206,7 @@ async function listSourceFiles(root) {
125
206
  async function walk(directory, files) {
126
207
  const entries = await readdir(directory, { withFileTypes: true });
127
208
  for (const entry of entries) {
128
- const absolute = join(directory, entry.name);
209
+ const absolute = join2(directory, entry.name);
129
210
  if (entry.isDirectory()) {
130
211
  if (IGNORED_DIRECTORIES.has(entry.name)) continue;
131
212
  await walk(absolute, files);
@@ -199,7 +280,7 @@ function extractImports(source) {
199
280
  }
200
281
  function resolveImport(root, from, specifier, fileSet) {
201
282
  if (!specifier.startsWith(".")) return null;
202
- const base = normalize(relative(root, resolve(root, dirname(from), specifier)));
283
+ const base = normalize(relative(root, resolve2(root, dirname2(from), specifier)));
203
284
  const stem = base.replace(/\.(js|jsx|mjs|cjs)$/, "");
204
285
  const bases = stem === base ? [base] : [base, stem];
205
286
  const candidates = bases.flatMap((b) => [
@@ -221,82 +302,6 @@ function normalize(path) {
221
302
  return path.replace(/\\/g, "/").replace(/^\.\//, "");
222
303
  }
223
304
 
224
- // src/indexer/engine.ts
225
- import { createHash } from "crypto";
226
- import { readFile as readFile4, stat as stat2 } from "fs/promises";
227
- import { join as join5, resolve as resolve4 } from "path";
228
-
229
- // src/map/cache.ts
230
- import { mkdir as mkdir2, readFile as readFile3 } from "fs/promises";
231
- import { dirname as dirname3, extname as extname2, join as join3, resolve as resolve3 } from "path";
232
-
233
- // src/indexer/store.ts
234
- import { mkdir, readFile as readFile2 } from "fs/promises";
235
- import { dirname as dirname2, join as join2, resolve as resolve2 } from "path";
236
- import { z } from "zod";
237
-
238
- // src/indexer/types.ts
239
- var INDEX_MANIFEST_VERSION = 3;
240
-
241
- // src/indexer/store.ts
242
- var symbolSpanSchema = z.object({
243
- name: z.string(),
244
- kind: z.enum(["function", "method", "class", "interface", "type", "enum", "const", "heading"]),
245
- startLine: z.number().int().nonnegative(),
246
- endLine: z.number().int().nonnegative(),
247
- signature: z.string(),
248
- exported: z.boolean()
249
- });
250
- var entrySchema = z.object({
251
- path: z.string(),
252
- hash: z.string(),
253
- size: z.number().int().nonnegative(),
254
- mtimeMs: z.number().optional(),
255
- ctimeMs: z.number().optional(),
256
- language: z.string(),
257
- lines: z.number().int().nonnegative(),
258
- symbols: z.array(z.string()),
259
- symbolTable: z.array(symbolSpanSchema).optional(),
260
- summary: z.string(),
261
- indexedAt: z.string()
262
- });
263
- var manifestSchema = z.object({
264
- version: z.literal(INDEX_MANIFEST_VERSION),
265
- generatedAt: z.string(),
266
- entries: z.record(z.string(), entrySchema)
267
- });
268
- var IndexStore = class {
269
- repositoryRoot;
270
- cacheDirectory;
271
- manifestPath;
272
- constructor(repositoryRoot = process.cwd()) {
273
- this.repositoryRoot = resolve2(repositoryRoot);
274
- this.cacheDirectory = join2(this.repositoryRoot, ".codebuddy", "cache");
275
- this.manifestPath = join2(this.cacheDirectory, "index.json");
276
- }
277
- /** Read the manifest, or an empty one if absent/corrupt/version-mismatched. */
278
- async read() {
279
- try {
280
- const raw = await readFile2(this.manifestPath, "utf8");
281
- const parsed = manifestSchema.safeParse(JSON.parse(raw));
282
- if (!parsed.success) return emptyManifest();
283
- return parsed.data;
284
- } catch (error) {
285
- if (error.code === "ENOENT") return emptyManifest();
286
- return emptyManifest();
287
- }
288
- }
289
- async write(manifest) {
290
- await assertNoSymlinkBetween(this.repositoryRoot, dirname2(this.manifestPath));
291
- await mkdir(this.cacheDirectory, { recursive: true, mode: 448 });
292
- await writeAtomic(this.manifestPath, `${JSON.stringify(manifest, null, 2)}
293
- `);
294
- }
295
- };
296
- function emptyManifest() {
297
- return { version: INDEX_MANIFEST_VERSION, generatedAt: (/* @__PURE__ */ new Date(0)).toISOString(), entries: {} };
298
- }
299
-
300
305
  // src/map/cache.ts
301
306
  var CACHE_VERSION = 1;
302
307
  var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py"]);
@@ -671,6 +676,10 @@ function sortEntries(entries) {
671
676
  );
672
677
  }
673
678
 
679
+ // src/context/discovery.ts
680
+ import { readFile as readFile9, realpath, stat as stat4 } from "fs/promises";
681
+ import { isAbsolute as isAbsolute3, join as join8, relative as relative6 } from "path";
682
+
674
683
  // src/integrations/graphify.ts
675
684
  import { execFile } from "child_process";
676
685
  import { mkdir as mkdir3, mkdtemp, readFile as readFile6, rm, stat as stat3, utimes } from "fs/promises";
@@ -867,14 +876,6 @@ function arrayLength(value) {
867
876
  return Array.isArray(value) ? value.length : 0;
868
877
  }
869
878
 
870
- // src/context/file-vectors.ts
871
- import { mkdir as mkdir5, readFile as readFile10 } from "fs/promises";
872
- import { dirname as dirname6, join as join9 } from "path";
873
-
874
- // src/context/discovery.ts
875
- import { readFile as readFile9, realpath, stat as stat4 } from "fs/promises";
876
- import { isAbsolute as isAbsolute3, join as join8, relative as relative6 } from "path";
877
-
878
879
  // src/map/graphify.ts
879
880
  import { readFile as readFile7 } from "fs/promises";
880
881
  import { isAbsolute, relative as relative4, resolve as resolve6 } from "path";
@@ -1090,7 +1091,8 @@ var B = 0.75;
1090
1091
  var MIN_TERMS = 2;
1091
1092
  var MIN_SHARE = 0.5;
1092
1093
  var MIN_IDF_COVERAGE = 0.3;
1093
- async function rankContent(repositoryRoot, manifest, terms, wantsTests, wantsDocs = false, wantsChangelog = false) {
1094
+ var CARD_WEIGHT = 0.5;
1095
+ async function rankContent(repositoryRoot, manifest, terms, wantsTests, wantsDocs = false, wantsChangelog = false, cards = /* @__PURE__ */ new Map()) {
1094
1096
  const none = { matches: [], idf: /* @__PURE__ */ new Map() };
1095
1097
  if (terms.length === 0) return none;
1096
1098
  const paths = Object.keys(manifest.entries).filter(
@@ -1134,29 +1136,38 @@ async function rankContent(repositoryRoot, manifest, terms, wantsTests, wantsDoc
1134
1136
  }
1135
1137
  const documents = Object.entries(files);
1136
1138
  if (documents.length === 0) return none;
1139
+ const cardWords = new Map(
1140
+ documents.flatMap(([path]) => {
1141
+ const text = cards.get(path);
1142
+ return text ? [[path, new Set(splitWords(text))]] : [];
1143
+ })
1144
+ );
1145
+ const has = (path, file, term) => (file.counts[term] ?? 0) > 0 || cardWords.get(path)?.has(term) === true;
1137
1146
  const averageLength = documents.reduce((sum, [, file]) => sum + file.length, 0) / documents.length;
1138
1147
  const idf = new Map(
1139
1148
  terms.map((term) => {
1140
- const df = documents.filter(([, file]) => (file.counts[term] ?? 0) > 0).length;
1149
+ const df = documents.filter(([path, file]) => has(path, file, term)).length;
1141
1150
  return [term, Math.log(1 + (documents.length - df + 0.5) / (df + 0.5))];
1142
1151
  })
1143
1152
  );
1144
1153
  const totalIdf = [...idf.values()].reduce((sum, value) => sum + value, 0);
1145
1154
  const scored = documents.map(([path, file]) => {
1146
1155
  const fileName = new Set(splitWords(path.slice(path.lastIndexOf("/") + 1)));
1156
+ const card = cardWords.get(path);
1147
1157
  let score = 0;
1148
1158
  let covered = 0;
1149
1159
  for (const term of terms) {
1150
- const tf = file.counts[term] ?? 0;
1160
+ const inSource = file.counts[term] ?? 0;
1161
+ const tf = inSource || (card?.has(term) ? CARD_WEIGHT : 0);
1151
1162
  if (tf === 0) continue;
1152
- covered += idf.get(term) ?? 0;
1163
+ covered += (idf.get(term) ?? 0) * (inSource > 0 ? 1 : CARD_WEIGHT);
1153
1164
  const saturation = tf * (K1 + 1) / (tf + K1 * (1 - B + B * file.length / averageLength));
1154
1165
  score += (idf.get(term) ?? 0) * saturation * (fileName.has(term) ? 1.5 : 1);
1155
1166
  }
1156
1167
  const named = terms.filter((term) => fileName.has(term));
1157
1168
  const matched = Math.max(
1158
1169
  named.length,
1159
- ...file.passages.map(
1170
+ ...[...file.passages, ...card ? [[...card]] : []].map(
1160
1171
  (words) => (/* @__PURE__ */ new Set([...named, ...terms.filter((term) => words.includes(term))])).size
1161
1172
  )
1162
1173
  );
@@ -1218,8 +1229,10 @@ async function discoverTaskPaths(repositoryRoot, task, manifest, mapSource, opti
1218
1229
  task,
1219
1230
  new Set(Object.keys(manifest.entries))
1220
1231
  );
1221
- if (anchors.length === 0)
1222
- return rankTaskFiles(repositoryRoot, task, manifest, mapSource, options);
1232
+ if (anchors.length === 0) {
1233
+ const ranked2 = await rankTaskFiles(repositoryRoot, task, manifest, mapSource, options);
1234
+ return await withExpansion(repositoryRoot, task, ranked2, manifest, mapSource, options) ?? ranked2;
1235
+ }
1223
1236
  const anchored = anchors.map((anchor) => anchor.path);
1224
1237
  const hits = anchors.flatMap(
1225
1238
  (anchor) => anchor.line === null ? [] : [
@@ -1236,7 +1249,9 @@ async function discoverTaskPaths(repositoryRoot, task, manifest, mapSource, opti
1236
1249
  const explain = `retrieval: anchors (${anchors.map(
1237
1250
  (anchor) => `${anchor.kind} ${anchor.path}${anchor.line === null ? "" : `:${anchor.line}`}`
1238
1251
  ).join(", ")})`;
1239
- if (anchored.length >= TASK_FILES) return { paths: anchored, hits, explain: [explain] };
1252
+ if (anchored.length >= TASK_FILES) {
1253
+ return { paths: anchored, hits, explain: [explain], confidence: "high" };
1254
+ }
1240
1255
  const ranked = await rankTaskFiles(repositoryRoot, task, manifest, mapSource, options);
1241
1256
  return {
1242
1257
  ...ranked.symbols ? { symbols: ranked.symbols } : {},
@@ -1245,26 +1260,72 @@ async function discoverTaskPaths(repositoryRoot, task, manifest, mapSource, opti
1245
1260
  TASK_FILES
1246
1261
  ),
1247
1262
  hits: [...hits, ...ranked.hits.filter((hit) => !anchored.includes(hit.path))],
1248
- explain: [explain, ...ranked.explain]
1263
+ explain: [explain, ...ranked.explain],
1264
+ confidence: "high"
1249
1265
  };
1250
1266
  }
1251
1267
  async function withLlmSummaries(repositoryRoot, manifest) {
1252
1268
  const entries = Object.values(manifest.entries);
1253
1269
  try {
1254
- const { resolveLlmConfig } = await import("./config-GEZFLXK6.js");
1255
- const config = await resolveLlmConfig(repositoryRoot);
1256
- if (!config.enabled || !config.features.summaries) return entries;
1257
- const { loadLlmSummaries } = await import("./summaries-32PHOB6L.js");
1270
+ if ((await readConfigFile(repositoryRoot)).llm?.enabled === false) return entries;
1271
+ const { loadLlmSummaries, cardWords } = await import("./summaries-W2J5FCLG.js");
1258
1272
  const summaries = await loadLlmSummaries(repositoryRoot, manifest);
1259
1273
  if (summaries.size === 0) return entries;
1260
1274
  return entries.map((entry) => {
1261
1275
  const summary = summaries.get(entry.path);
1262
- return summary ? { ...entry, llmText: `${summary.summary} ${Object.values(summary.symbols).join(" ")}` } : entry;
1276
+ return summary ? {
1277
+ ...entry,
1278
+ llmText: `${summary.summary} ${Object.values(summary.symbols).join(" ")}`,
1279
+ ...summary.symptoms ? { cardWords: cardWords(summary) } : {}
1280
+ } : entry;
1263
1281
  });
1264
1282
  } catch {
1265
1283
  return entries;
1266
1284
  }
1267
1285
  }
1286
+ var EXPANSION_MS = { hook: 300, pack: 800 };
1287
+ async function withExpansion(repositoryRoot, task, ranked, manifest, mapSource, options) {
1288
+ if (ranked.paths.length > 0 && ranked.confidence !== "low") return null;
1289
+ if (identifierTokens(task).some((token) => CODE_IDENTIFIER.test(token))) return null;
1290
+ const deadlineAt = options.expansionDeadlineAt ?? Date.now() + EXPANSION_MS.pack;
1291
+ const { expandTask } = await import("./expand-TONFVT5D.js");
1292
+ const expansion = await expandTask(repositoryRoot, task, deadlineAt - Date.now());
1293
+ if (!expansion) return null;
1294
+ const expanded = await rankTaskFiles(
1295
+ repositoryRoot,
1296
+ `${task} ${expansion.terms.join(" ")}`,
1297
+ manifest,
1298
+ mapSource,
1299
+ options
1300
+ );
1301
+ const note = `expansion: task expanded with ${expansion.terms.length} code term(s) (${expansion.terms.join(", ")}; ${expansion.cached ? "cached" : "local model"})`;
1302
+ if (expanded.paths.length === 0)
1303
+ return { ...ranked, explain: [...ranked.explain, `${note}; still no match`] };
1304
+ return { ...expanded, explain: [...ranked.explain, note, ...expanded.explain] };
1305
+ }
1306
+ var AGREEMENT = { topK: 5, chunkFloor: 0.8, cardFloor: 0.75 };
1307
+ function agreementVotes(path, signals, config = AGREEMENT) {
1308
+ const names = [];
1309
+ let scored = 0;
1310
+ if (signals.zg.slice(0, config.topK).includes(path)) names.push("zg");
1311
+ const within = (ranking, floor) => (ranking ?? []).slice(0, config.topK).some((match) => match.path === path && match.score >= floor);
1312
+ if (within(signals.chunks, config.chunkFloor)) {
1313
+ names.push("chunk");
1314
+ scored++;
1315
+ }
1316
+ if (within(signals.cards, config.cardFloor)) {
1317
+ names.push("card");
1318
+ scored++;
1319
+ }
1320
+ if (signals.term) {
1321
+ names.push("terms");
1322
+ scored++;
1323
+ }
1324
+ return { votes: names.length, scored, names };
1325
+ }
1326
+ function agrees(vote) {
1327
+ return vote.votes >= 2 && vote.scored >= 1;
1328
+ }
1268
1329
  async function rankTaskFiles(repositoryRoot, task, manifest, mapSource, options) {
1269
1330
  const wantsChangelog = asksForChangelog(task);
1270
1331
  const entries = (await withLlmSummaries(repositoryRoot, manifest)).filter(
@@ -1298,6 +1359,7 @@ async function rankTaskFiles(repositoryRoot, task, manifest, mapSource, options)
1298
1359
  return {
1299
1360
  paths: expansion2.paths.slice(0, TASK_FILES),
1300
1361
  hits: [],
1362
+ confidence: "high",
1301
1363
  explain: [
1302
1364
  `retrieval: exact-symbol routing (${identifiers.slice(0, 5).join(", ")})`,
1303
1365
  ...expansion2.explain ? [expansion2.explain] : []
@@ -1314,7 +1376,8 @@ async function rankTaskFiles(repositoryRoot, task, manifest, mapSource, options)
1314
1376
  taskTerms(task),
1315
1377
  wantsTests,
1316
1378
  DOCS_TASK.test(task),
1317
- wantsChangelog
1379
+ wantsChangelog,
1380
+ new Map(entries.flatMap((entry) => entry.cardWords ? [[entry.path, entry.cardWords]] : []))
1318
1381
  );
1319
1382
  const keyword = content.length > 0 ? fuseRankings([summaryKeyword, content.map((match) => match.path)]) : summaryKeyword;
1320
1383
  const weakKeyword = scored.length - keyword.length;
@@ -1325,7 +1388,7 @@ async function rankTaskFiles(repositoryRoot, task, manifest, mapSource, options)
1325
1388
  reason: "semantic retrieval off",
1326
1389
  stale: 0,
1327
1390
  changed: 0
1328
- } : await import("./zvec-24HLAFGN.js").then(
1391
+ } : await import("./zvec-LSA2IRAU.js").then(
1329
1392
  ({ zvecCandidates }) => zvecCandidates(
1330
1393
  repositoryRoot,
1331
1394
  task,
@@ -1347,51 +1410,64 @@ async function rankTaskFiles(repositoryRoot, task, manifest, mapSource, options)
1347
1410
  let ranked = keyword;
1348
1411
  let hits = [];
1349
1412
  const explain = [];
1413
+ const agreement = await agreementConfig(repositoryRoot);
1414
+ const cardsOn = entries.some((entry) => entry.cardWords);
1415
+ const dense = options.semantic === false && options.vectorDeadlineAt === void 0 ? null : await raceDeadline(
1416
+ rankFileVectors(repositoryRoot, manifest, task, options.embed),
1417
+ options.semantic === false ? options.vectorDeadlineAt : void 0
1418
+ );
1419
+ const chunks = dense?.chunks ?? null;
1420
+ const cards = cardsOn ? dense?.cards ?? null : null;
1421
+ const usable = (path) => (wantsTests || !TEST_PATH.test(path)) && (wantsChangelog || !CHANGELOG_PATH.test(path));
1422
+ const zg = fuseRankings([semantic.paths, semantic.cardPaths ?? []]).filter(usable);
1423
+ const votes = /* @__PURE__ */ new Map();
1424
+ const denseAvailable = zg.length > 0 || chunks !== null || cards !== null;
1350
1425
  if (semantic.status !== "disabled" && semantic.paths.length === 0) {
1351
1426
  explain.push(`retrieval: keyword ranking only (${semantic.reason})`);
1352
- } else if (semantic.status !== "disabled") {
1427
+ }
1428
+ if (denseAvailable) {
1353
1429
  const terms = taskTerms(task);
1354
1430
  const vector = [];
1355
- const partial = [];
1356
- let uncorroborated = 0;
1357
- let belowFloor = 0;
1358
- const minScore = semantic.minScore ?? 0;
1359
- for (const path of semantic.paths) {
1360
- if (!wantsTests && TEST_PATH.test(path)) continue;
1361
- if (!wantsChangelog && CHANGELOG_PATH.test(path)) continue;
1362
- if (keyword.includes(path)) vector.push(path);
1363
- else if (await hasMatchedPassageEvidence(
1364
- repositoryRoot,
1365
- path,
1366
- semantic.hits,
1367
- terms,
1368
- manifest.entries[path]?.symbolTable ?? []
1369
- )) {
1370
- const source = await readBoundedSource(repositoryRoot, path) ?? "";
1371
- if (idfCoverage(`${path} ${source}`, terms, idf) < minScore) {
1372
- belowFloor++;
1373
- continue;
1374
- }
1375
- if (countTerms(source, terms) >= EVIDENCE_FLOOR.vectorTerms) vector.push(path);
1376
- else partial.push(path);
1377
- if (!evidence.has(path)) evidence.set(path, 0);
1378
- } else uncorroborated++;
1431
+ let rejected = 0;
1432
+ const top = (ranking) => (ranking ?? []).slice(0, agreement.topK).map((match) => match.path);
1433
+ const candidates = [
1434
+ .../* @__PURE__ */ new Set([
1435
+ ...semantic.paths,
1436
+ ...zg.slice(0, agreement.topK),
1437
+ ...top(chunks),
1438
+ ...top(cards)
1439
+ ])
1440
+ ].filter(usable);
1441
+ for (const path of candidates) {
1442
+ const termVote = await termEvidence(repositoryRoot, path, semantic, terms, idf, manifest);
1443
+ const vote = agreementVotes(path, { zg, chunks, cards, term: termVote }, agreement);
1444
+ votes.set(path, vote);
1445
+ if (keyword.includes(path)) {
1446
+ vector.push(path);
1447
+ continue;
1448
+ }
1449
+ if (!countsAsSource(path, task) || !agrees(vote)) {
1450
+ rejected++;
1451
+ continue;
1452
+ }
1453
+ vector.push(path);
1454
+ if (!evidence.has(path)) evidence.set(path, 0);
1379
1455
  }
1380
1456
  ranked = rankEvidenceCandidates(
1381
1457
  scored.map((entry) => entry.path),
1382
1458
  keyword,
1383
1459
  vector,
1384
- partial
1460
+ []
1385
1461
  );
1386
- hits = semantic.hits.filter((hit) => vector.includes(hit.path) || partial.includes(hit.path));
1462
+ hits = semantic.hits.filter((hit) => vector.includes(hit.path));
1463
+ const sources = [
1464
+ ...zg.length > 0 ? [semantic.reason] : [],
1465
+ ...chunks ? ["file vectors"] : [],
1466
+ ...cards ? ["intent-card vectors"] : []
1467
+ ];
1387
1468
  explain.push(
1388
- `retrieval: keyword ranking fused with ${semantic.reason}` + (uncorroborated > 0 ? `; ${uncorroborated} uncorroborated vector file(s) dropped` : "")
1469
+ `retrieval: keyword ranking fused with ${sources.join(", ")}; agreement rule (2 of zg/chunk/card/terms in top ${agreement.topK})` + (rejected > 0 ? `; ${rejected} dense candidate(s) without agreement dropped` : "")
1389
1470
  );
1390
- if (belowFloor > 0) {
1391
- explain.push(
1392
- `abstention: ${belowFloor} vector-only file(s) below zvec.minScore ${minScore} (task IDF coverage of current source) dropped`
1393
- );
1394
- }
1395
1471
  }
1396
1472
  let symbols;
1397
1473
  const reranked = await llmRerank({
@@ -1413,21 +1489,21 @@ async function rankTaskFiles(repositoryRoot, task, manifest, mapSource, options)
1413
1489
  const wantsDocs = DOCS_TASK.test(task);
1414
1490
  if (!ranked.some((path) => countsAsSource(path, task))) {
1415
1491
  explain.push(
1416
- "abstention: no source file reached the evidence floor (" + (ranked.length > 0 ? "only docs/config did" : `best keyword score ${scored[0]?.score ?? 0} < ${EVIDENCE_FLOOR.keywordScore}`) + (commands.length > 0 ? "); only the named CLI command returned" : "); no task targets returned")
1492
+ "abstention: no source file reached the evidence floor or the agreement rule (" + (ranked.length > 0 ? "only docs/config did" : `best keyword score ${scored[0]?.score ?? 0} < ${EVIDENCE_FLOOR.keywordScore}`) + (commands.length > 0 ? "); only the named CLI command returned" : "); no task targets returned")
1417
1493
  );
1418
- return { paths: commands, hits: [], explain };
1494
+ return { paths: commands, hits: [], explain, confidence: commands.length > 0 ? "high" : "low" };
1419
1495
  }
1420
1496
  if (weakKeyword > 0) {
1421
1497
  explain.push(
1422
1498
  `abstention: ${weakKeyword} weak keyword candidate(s) below the evidence floor (score < ${EVIDENCE_FLOOR.keywordScore}) dropped`
1423
1499
  );
1424
1500
  }
1425
- const vectors = options.semantic === false || reranked ? null : await rankFilesByVector(repositoryRoot, manifest, task);
1501
+ const vectors = reranked || !chunks ? null : cards ? fuseRankings([chunks, cards].map((ranking) => ranking.map((match) => match.path))) : chunks.map((match) => match.path);
1426
1502
  if (vectors && vectors.length > 0) {
1427
1503
  const doc = wantsDocs ? ranked.filter((path) => DOC_PATH.test(path)).slice(0, 1) : [];
1428
- ranked = [...doc, ...vectors.map((match) => match.path)].slice(0, TASK_FILES);
1504
+ ranked = [...doc, ...vectors].slice(0, TASK_FILES);
1429
1505
  explain.push(
1430
- `retrieval: file vectors ordered the files (best ${vectors[0]?.score.toFixed(2)})`
1506
+ `retrieval: ${cards ? "file and card" : "file"} vectors ordered the files (best chunk ${chunks?.[0]?.score.toFixed(2)})`
1431
1507
  );
1432
1508
  }
1433
1509
  const expansion = expandAlongImports(ranked, await mapSource, evidence, task);
@@ -1441,18 +1517,82 @@ async function rankTaskFiles(repositoryRoot, task, manifest, mapSource, options)
1441
1517
  `abstention: ${paths.length - TASK_FILES} lower-ranked candidate(s) beyond the top ${TASK_FILES} dropped`
1442
1518
  );
1443
1519
  }
1520
+ const returned = paths.slice(0, TASK_FILES);
1521
+ const confidence = confidenceOf(returned, {
1522
+ keyword,
1523
+ strongKeyword: scored.filter((entry) => entry.score >= 2 * EVIDENCE_FLOOR.keywordScore).map((entry) => entry.path),
1524
+ commands,
1525
+ votes,
1526
+ denseAvailable
1527
+ });
1528
+ if (confidence === "low") {
1529
+ explain.push(
1530
+ "abstention: low confidence (no returned file had two agreeing signals); no task targets returned"
1531
+ );
1532
+ return { paths: [], hits: [], explain, confidence };
1533
+ }
1444
1534
  return {
1445
- paths: paths.slice(0, TASK_FILES),
1535
+ paths: returned,
1446
1536
  hits,
1447
1537
  explain,
1538
+ confidence,
1448
1539
  ...symbols && Object.keys(symbols).length > 0 ? { symbols } : {}
1449
1540
  };
1450
1541
  }
1542
+ function confidenceOf(paths, input) {
1543
+ if (paths.some((path) => input.commands.includes(path))) return "high";
1544
+ if (!input.denseAvailable) return "medium";
1545
+ let best = 0;
1546
+ for (const path of paths) {
1547
+ const dense = input.votes.get(path)?.votes ?? 0;
1548
+ const lexical = input.strongKeyword.includes(path) ? 2 : input.keyword.includes(path) ? 1 : 0;
1549
+ best = Math.max(best, dense + lexical);
1550
+ }
1551
+ return best >= 3 ? "high" : best >= 2 ? "medium" : "low";
1552
+ }
1553
+ async function termEvidence(repositoryRoot, path, semantic, terms, idf, manifest) {
1554
+ if (!await hasMatchedPassageEvidence(
1555
+ repositoryRoot,
1556
+ path,
1557
+ semantic.hits,
1558
+ terms,
1559
+ manifest.entries[path]?.symbolTable ?? []
1560
+ )) {
1561
+ return false;
1562
+ }
1563
+ const source = await readBoundedSource(repositoryRoot, path) ?? "";
1564
+ return idfCoverage(`${path} ${source}`, terms, idf) >= (semantic.minScore ?? DEFAULT_MIN_SCORE);
1565
+ }
1566
+ var DEFAULT_MIN_SCORE = 0.3;
1567
+ async function agreementConfig(repositoryRoot) {
1568
+ try {
1569
+ const configured = (await readConfigFile(repositoryRoot)).discovery?.agreement ?? {};
1570
+ return {
1571
+ topK: configured.topK ?? AGREEMENT.topK,
1572
+ chunkFloor: configured.chunkFloor ?? AGREEMENT.chunkFloor,
1573
+ cardFloor: configured.cardFloor ?? AGREEMENT.cardFloor
1574
+ };
1575
+ } catch {
1576
+ return AGREEMENT;
1577
+ }
1578
+ }
1579
+ async function raceDeadline(promise, deadlineAt) {
1580
+ if (deadlineAt === void 0) return promise;
1581
+ const ms = deadlineAt - Date.now();
1582
+ if (ms <= 0) return null;
1583
+ let timer;
1584
+ return Promise.race([
1585
+ promise,
1586
+ new Promise((resolve8) => {
1587
+ timer = setTimeout(() => resolve8(null), ms);
1588
+ })
1589
+ ]).finally(() => clearTimeout(timer));
1590
+ }
1451
1591
  var MIN_RERANK_MS = 200;
1452
1592
  async function llmRerank(input) {
1453
1593
  let config;
1454
1594
  try {
1455
- config = await (await import("./config-GEZFLXK6.js")).resolveLlmConfig(input.repositoryRoot);
1595
+ config = await (await import("./config-S2BDMT4B.js")).resolveLlmConfig(input.repositoryRoot);
1456
1596
  } catch {
1457
1597
  return null;
1458
1598
  }
@@ -1477,7 +1617,7 @@ async function llmRerank(input) {
1477
1617
  input.deadlineAt === void 0 ? config.timeoutMs : input.deadlineAt - Date.now()
1478
1618
  );
1479
1619
  if (deadlineMs < MIN_RERANK_MS) return skipped("no time left in the hook budget");
1480
- const { rerankCandidates } = await import("./rerank-IQAEWLQR.js");
1620
+ const { rerankCandidates } = await import("./rerank-EPCTSEVP.js");
1481
1621
  const result = await rerankCandidates(
1482
1622
  input.repositoryRoot,
1483
1623
  config,
@@ -1839,7 +1979,9 @@ async function refreshFileVectors(repositoryRoot, manifest, deadlineAt, embed =
1839
1979
  if (cached && cached.hash === manifest.entries[path]?.hash) files[path] = cached;
1840
1980
  else todo.push(path);
1841
1981
  }
1982
+ const cards = await currentCardTexts(repositoryRoot, manifest);
1842
1983
  let embedded = 0;
1984
+ let embeddedCards = 0;
1843
1985
  let lastSave = Date.now();
1844
1986
  for (const path of todo) {
1845
1987
  if (Date.now() >= deadlineAt) break;
@@ -1859,13 +2001,52 @@ async function refreshFileVectors(repositoryRoot, manifest, deadlineAt, embed =
1859
2001
  lastSave = Date.now();
1860
2002
  }
1861
2003
  }
2004
+ const stale = Object.keys(files).filter((path) => {
2005
+ const text = cards.get(path);
2006
+ return text !== void 0 && files[path]?.cardHash !== textHash(text);
2007
+ });
2008
+ for (let start = 0; start < stale.length && Date.now() < deadlineAt; start += BATCH) {
2009
+ const batch = stale.slice(start, start + BATCH);
2010
+ const vectors = await embed(batch.map((path) => cards.get(path)));
2011
+ batch.forEach((path, index) => {
2012
+ const file = files[path];
2013
+ const vector = vectors[index];
2014
+ if (!file || !vector) return;
2015
+ files[path] = {
2016
+ ...file,
2017
+ card: encode(vector),
2018
+ cardHash: textHash(cards.get(path))
2019
+ };
2020
+ embeddedCards += 1;
2021
+ });
2022
+ }
2023
+ for (const [path, file] of Object.entries(files)) {
2024
+ if (file.card && !cards.has(path)) files[path] = { hash: file.hash, vectors: file.vectors };
2025
+ }
1862
2026
  await saveStore(repositoryRoot, { version: 1, model: MODEL, files });
1863
2027
  return {
1864
2028
  embedded,
1865
2029
  files: Object.keys(files).length,
1866
- pending: eligible.length - Object.keys(files).length
2030
+ pending: eligible.length - Object.keys(files).length,
2031
+ ...embeddedCards > 0 ? { cards: embeddedCards } : {}
1867
2032
  };
1868
2033
  }
2034
+ async function currentCardTexts(repositoryRoot, manifest) {
2035
+ try {
2036
+ const { cardText, loadLlmSummaries } = await import("./summaries-W2J5FCLG.js");
2037
+ const texts = /* @__PURE__ */ new Map();
2038
+ for (const [path, card] of await loadLlmSummaries(repositoryRoot, manifest)) {
2039
+ if (card.symptoms) texts.set(path, `${path}
2040
+ ${cardText(card)}`);
2041
+ }
2042
+ return texts;
2043
+ } catch {
2044
+ return /* @__PURE__ */ new Map();
2045
+ }
2046
+ }
2047
+ function textHash(text) {
2048
+ return createHash3("sha256").update(text).digest("hex").slice(0, 16);
2049
+ }
1869
2050
  async function syncFileVectors(repositoryRoot, budgetMs) {
1870
2051
  const started = Date.now();
1871
2052
  try {
@@ -1876,6 +2057,9 @@ async function syncFileVectors(repositoryRoot, budgetMs) {
1876
2057
  }
1877
2058
  }
1878
2059
  async function rankFilesByVector(repositoryRoot, manifest, task, embed = localEmbed) {
2060
+ return (await rankFileVectors(repositoryRoot, manifest, task, embed))?.chunks ?? null;
2061
+ }
2062
+ async function rankFileVectors(repositoryRoot, manifest, task, embed = localEmbed) {
1879
2063
  if (process.env.CODEBUDDY_SEMANTIC === "0") return null;
1880
2064
  const store = await loadStore(repositoryRoot);
1881
2065
  const current = eligiblePaths(manifest).filter(
@@ -1890,10 +2074,16 @@ async function rankFilesByVector(repositoryRoot, manifest, task, embed = localEm
1890
2074
  } catch {
1891
2075
  return null;
1892
2076
  }
1893
- return current.map((path) => ({
2077
+ const order = (left, right) => right.score - left.score || left.path.localeCompare(right.path);
2078
+ const chunks = current.map((path) => ({
1894
2079
  path,
1895
2080
  score: Math.max(...(store.files[path]?.vectors ?? []).map((v) => dot(decode(v), query)))
1896
- })).sort((left, right) => right.score - left.score || left.path.localeCompare(right.path));
2081
+ })).sort(order);
2082
+ const cards = current.flatMap((path) => {
2083
+ const card = store.files[path]?.card;
2084
+ return card ? [{ path, score: dot(decode(card), query) }] : [];
2085
+ }).sort(order);
2086
+ return { chunks, cards: cards.length > 0 ? cards : null };
1897
2087
  }
1898
2088
  function eligiblePaths(manifest) {
1899
2089
  return Object.keys(manifest.entries).filter(
@@ -1951,11 +2141,16 @@ export {
1951
2141
  setupGraphify,
1952
2142
  generateGraphifyGraph,
1953
2143
  loadGraphifyMap,
2144
+ refreshFileVectors,
1954
2145
  syncFileVectors,
2146
+ rankFilesByVector,
2147
+ rankFileVectors,
1955
2148
  TASK_PATH_LIMIT,
1956
2149
  readBoundedSource,
1957
2150
  discoverTaskPaths,
2151
+ EXPANSION_MS,
1958
2152
  TEST_PATH,
2153
+ CHANGELOG_PATH,
1959
2154
  asksForChangelog,
1960
2155
  NON_SOURCE_PATH,
1961
2156
  taskTerms,
@@ -1964,4 +2159,4 @@ export {
1964
2159
  namedSegments,
1965
2160
  loadProjectArchitectureMap
1966
2161
  };
1967
- //# sourceMappingURL=chunk-YNSTIMCF.js.map
2162
+ //# sourceMappingURL=chunk-4DTO2E4Y.js.map