@orquentra/codebuddy 2.14.0 → 2.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +98 -0
- package/README.md +87 -6
- package/dist/{chunk-LW75SKZR.js → chunk-4BSO3HST.js} +126 -18
- package/dist/chunk-4BSO3HST.js.map +1 -0
- package/dist/{chunk-CAEPHLHC.js → chunk-57642NGU.js} +2 -44
- package/dist/chunk-57642NGU.js.map +1 -0
- package/dist/{chunk-ESZXCZIN.js → chunk-6YI2D5F5.js} +33 -5
- package/dist/chunk-6YI2D5F5.js.map +1 -0
- package/dist/{chunk-4DKYKDHI.js → chunk-7IPSDDO5.js} +5 -3
- package/dist/{chunk-4DKYKDHI.js.map → chunk-7IPSDDO5.js.map} +1 -1
- package/dist/chunk-BTTQWSDS.js +372 -0
- package/dist/chunk-BTTQWSDS.js.map +1 -0
- package/dist/{chunk-YJPCS2GP.js → chunk-D5E7SGI5.js} +57 -18
- package/dist/chunk-D5E7SGI5.js.map +1 -0
- package/dist/chunk-EMWGLKPR.js +45 -0
- package/dist/chunk-EMWGLKPR.js.map +1 -0
- package/dist/chunk-ITXE27SZ.js +358 -0
- package/dist/chunk-ITXE27SZ.js.map +1 -0
- package/dist/{chunk-LRQNPYCK.js → chunk-JJQDVGF7.js} +13 -7
- package/dist/chunk-JJQDVGF7.js.map +1 -0
- package/dist/{chunk-XSNW6Y3X.js → chunk-KQCP3ZYH.js} +28 -24
- package/dist/chunk-KQCP3ZYH.js.map +1 -0
- package/dist/{chunk-YWDH6DQ6.js → chunk-KYRM3HPP.js} +21 -19
- package/dist/{chunk-YWDH6DQ6.js.map → chunk-KYRM3HPP.js.map} +1 -1
- package/dist/{chunk-KNR2P2UY.js → chunk-M75SN4D4.js} +19 -4
- package/dist/chunk-M75SN4D4.js.map +1 -0
- package/dist/{chunk-L6BRYZ6G.js → chunk-RZ266NHE.js} +7 -7
- package/dist/chunk-U7KDM62P.js +43 -0
- package/dist/chunk-U7KDM62P.js.map +1 -0
- package/dist/chunk-UATJCD2T.js +368 -0
- package/dist/chunk-UATJCD2T.js.map +1 -0
- package/dist/{chunk-YNSTIMCF.js → chunk-UR3DF74I.js} +352 -157
- package/dist/chunk-UR3DF74I.js.map +1 -0
- package/dist/chunk-UTPC66MV.js +128 -0
- package/dist/chunk-UTPC66MV.js.map +1 -0
- package/dist/chunk-WHKXUXHE.js +156 -0
- package/dist/chunk-WHKXUXHE.js.map +1 -0
- package/dist/{chunk-7QMHIJBA.js → chunk-YMXFSHXT.js} +969 -968
- package/dist/chunk-YMXFSHXT.js.map +1 -0
- package/dist/cli/index.js +4 -4
- package/dist/config-TXQJCCVI.js +15 -0
- package/dist/expand-KWYGNCKZ.js +98 -0
- package/dist/expand-KWYGNCKZ.js.map +1 -0
- package/dist/file-vectors-MKXTSGGH.js +19 -0
- package/dist/index-facts-4MTEHKMN.js +38 -0
- package/dist/index-pass-TBDUEZCB.js +14 -0
- package/dist/index.js +24 -22
- package/dist/{install-EU35ERK5.js → install-E3JWINTN.js} +11 -10
- package/dist/{lean-43ADYTBW.js → lean-MLTAFS5L.js} +8 -7
- package/dist/local-75DJECVR.js +48 -0
- package/dist/local-llm-MECVJTVU.js +19 -0
- package/dist/local-llm-MECVJTVU.js.map +1 -0
- package/dist/{main-SFC5LV4E.js → main-RLMKQZW4.js} +332 -123
- package/dist/main-RLMKQZW4.js.map +1 -0
- package/dist/{memory-TGHVTBME.js → memory-PFFVMTCH.js} +9 -6
- package/dist/{memory-TGHVTBME.js.map → memory-PFFVMTCH.js.map} +1 -1
- package/dist/{operations-6Z6ZDVBP.js → operations-STR7S5UO.js} +8 -7
- package/dist/operations-STR7S5UO.js.map +1 -0
- package/dist/{rerank-IQAEWLQR.js → rerank-XXKWDI5Q.js} +7 -4
- package/dist/{rerank-IQAEWLQR.js.map → rerank-XXKWDI5Q.js.map} +1 -1
- package/dist/{runtime-W5AW32SD.js → runtime-SWFWGTQ4.js} +9 -8
- package/dist/runtime-SWFWGTQ4.js.map +1 -0
- package/dist/summaries-QXWFFDUZ.js +31 -0
- package/dist/summaries-QXWFFDUZ.js.map +1 -0
- package/dist/{zvec-24HLAFGN.js → zvec-F73IBWO5.js} +13 -5
- package/dist/zvec-F73IBWO5.js.map +1 -0
- package/package.json +3 -2
- package/dist/chunk-7QMHIJBA.js.map +0 -1
- package/dist/chunk-CAEPHLHC.js.map +0 -1
- package/dist/chunk-ESC4Y3L7.js +0 -204
- package/dist/chunk-ESC4Y3L7.js.map +0 -1
- package/dist/chunk-ESZXCZIN.js.map +0 -1
- package/dist/chunk-KNR2P2UY.js.map +0 -1
- package/dist/chunk-LRQNPYCK.js.map +0 -1
- package/dist/chunk-LW75SKZR.js.map +0 -1
- package/dist/chunk-SFMIMLXR.js +0 -63
- package/dist/chunk-SFMIMLXR.js.map +0 -1
- package/dist/chunk-XSNW6Y3X.js.map +0 -1
- package/dist/chunk-YJPCS2GP.js.map +0 -1
- package/dist/chunk-YNSTIMCF.js.map +0 -1
- package/dist/config-GEZFLXK6.js +0 -12
- package/dist/main-SFC5LV4E.js.map +0 -1
- package/dist/summaries-32PHOB6L.js +0 -20
- /package/dist/{chunk-L6BRYZ6G.js.map → chunk-RZ266NHE.js.map} +0 -0
- /package/dist/{config-GEZFLXK6.js.map → config-TXQJCCVI.js.map} +0 -0
- /package/dist/{install-EU35ERK5.js.map → file-vectors-MKXTSGGH.js.map} +0 -0
- /package/dist/{lean-43ADYTBW.js.map → index-facts-4MTEHKMN.js.map} +0 -0
- /package/dist/{operations-6Z6ZDVBP.js.map → index-pass-TBDUEZCB.js.map} +0 -0
- /package/dist/{runtime-W5AW32SD.js.map → install-E3JWINTN.js.map} +0 -0
- /package/dist/{summaries-32PHOB6L.js.map → lean-MLTAFS5L.js.map} +0 -0
- /package/dist/{zvec-24HLAFGN.js.map → local-75DJECVR.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-
|
|
11
|
+
} from "./chunk-M75SN4D4.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 =
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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)
|
|
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
|
-
|
|
1255
|
-
const
|
|
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-QXWFFDUZ.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 ? {
|
|
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-KWYGNCKZ.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-
|
|
1391
|
+
} : await import("./zvec-F73IBWO5.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
|
-
}
|
|
1427
|
+
}
|
|
1428
|
+
if (denseAvailable) {
|
|
1353
1429
|
const terms = taskTerms(task);
|
|
1354
1430
|
const vector = [];
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
)) {
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
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
|
-
|
|
1460
|
+
[]
|
|
1385
1461
|
);
|
|
1386
|
-
hits = semantic.hits.filter((hit) => vector.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 ${
|
|
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 =
|
|
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
|
|
1504
|
+
ranked = [...doc, ...vectors].slice(0, TASK_FILES);
|
|
1429
1505
|
explain.push(
|
|
1430
|
-
`retrieval: file vectors ordered the files (best ${
|
|
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:
|
|
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-
|
|
1595
|
+
config = await (await import("./config-TXQJCCVI.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-
|
|
1620
|
+
const { rerankCandidates } = await import("./rerank-XXKWDI5Q.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-QXWFFDUZ.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
|
-
|
|
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(
|
|
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-
|
|
2162
|
+
//# sourceMappingURL=chunk-UR3DF74I.js.map
|