@orquentra/codebuddy 2.9.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/CLAUDE_CODEX.md +33 -0
- package/README.md +114 -9
- package/dist/{adapters-S4HHTWJW.js → adapters-OJRSVFV3.js} +2 -2
- package/dist/{chunk-GXOML4UZ.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-GKNYMNFM.js → chunk-7IPSDDO5.js} +10 -3
- package/dist/chunk-7IPSDDO5.js.map +1 -0
- package/dist/chunk-BTTQWSDS.js +372 -0
- package/dist/chunk-BTTQWSDS.js.map +1 -0
- package/dist/{chunk-2WH2Q4TA.js → chunk-D5E7SGI5.js} +304 -77
- 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-GQKWUHMA.js +20 -0
- package/dist/chunk-GQKWUHMA.js.map +1 -0
- package/dist/chunk-ITXE27SZ.js +358 -0
- package/dist/chunk-ITXE27SZ.js.map +1 -0
- package/dist/{chunk-UK6XTS2Y.js → chunk-JJQDVGF7.js} +23 -23
- package/dist/chunk-JJQDVGF7.js.map +1 -0
- package/dist/{chunk-F4BJ3DXW.js → chunk-KQCP3ZYH.js} +1273 -331
- package/dist/chunk-KQCP3ZYH.js.map +1 -0
- package/dist/{chunk-QN76UJP7.js → chunk-KYRM3HPP.js} +89 -21
- package/dist/chunk-KYRM3HPP.js.map +1 -0
- package/dist/{chunk-KNR2P2UY.js → chunk-M75SN4D4.js} +19 -4
- package/dist/chunk-M75SN4D4.js.map +1 -0
- package/dist/{chunk-J4T6HHI4.js → chunk-RZ266NHE.js} +538 -317
- package/dist/chunk-RZ266NHE.js.map +1 -0
- 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-ENKDFLOO.js → chunk-UOTKHSQ5.js} +25 -8
- package/dist/chunk-UOTKHSQ5.js.map +1 -0
- package/dist/{chunk-TLWGZVPC.js → chunk-UR3DF74I.js} +1007 -132
- 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-W7GAXL6C.js → chunk-V7PT6ER5.js} +6 -5
- package/dist/chunk-V7PT6ER5.js.map +1 -0
- package/dist/chunk-WHKXUXHE.js +156 -0
- package/dist/chunk-WHKXUXHE.js.map +1 -0
- package/dist/{chunk-SRA4MDVG.js → chunk-YMXFSHXT.js} +978 -950
- package/dist/chunk-YMXFSHXT.js.map +1 -0
- package/dist/cli/index.js +23 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/{codebuddy-DO7ZhoWn.d.ts → codebuddy-CHqMptZB.d.ts} +35 -0
- 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.d.ts +6 -4
- package/dist/index.js +25 -23
- package/dist/install-E3JWINTN.js +31 -0
- package/dist/langgraph/index.d.ts +1 -1
- package/dist/lean-MLTAFS5L.js +29 -0
- package/dist/local-75DJECVR.js +48 -0
- package/dist/local-llm-MECVJTVU.js +19 -0
- package/dist/{main-YJKSYFPT.js → main-RLMKQZW4.js} +999 -328
- 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-OG4ISWIM.js → operations-STR7S5UO.js} +8 -7
- package/dist/operations-STR7S5UO.js.map +1 -0
- package/dist/{pretool-command-PRFOIHMW.js → pretool-command-B5GY5T6E.js} +2 -2
- package/dist/pretool-command-B5GY5T6E.js.map +1 -0
- package/dist/prompt-gate-TDTFFQW2.js +8 -0
- package/dist/prompt-gate-TDTFFQW2.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-GCSEIAVD.js → runtime-SWFWGTQ4.js} +18 -9
- 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-XDZNZ2OL.js → zvec-F73IBWO5.js} +13 -6
- package/dist/zvec-F73IBWO5.js.map +1 -0
- package/package.json +13 -3
- package/dist/chunk-2WH2Q4TA.js.map +0 -1
- package/dist/chunk-6NZEZJYD.js +0 -206
- package/dist/chunk-6NZEZJYD.js.map +0 -1
- package/dist/chunk-CAEPHLHC.js.map +0 -1
- package/dist/chunk-ENKDFLOO.js.map +0 -1
- package/dist/chunk-ESZXCZIN.js.map +0 -1
- package/dist/chunk-F4BJ3DXW.js.map +0 -1
- package/dist/chunk-GKNYMNFM.js.map +0 -1
- package/dist/chunk-GXOML4UZ.js.map +0 -1
- package/dist/chunk-ITQO632W.js +0 -673
- package/dist/chunk-ITQO632W.js.map +0 -1
- package/dist/chunk-J4T6HHI4.js.map +0 -1
- package/dist/chunk-KNR2P2UY.js.map +0 -1
- package/dist/chunk-QN76UJP7.js.map +0 -1
- package/dist/chunk-SFMIMLXR.js +0 -63
- package/dist/chunk-SFMIMLXR.js.map +0 -1
- package/dist/chunk-SRA4MDVG.js.map +0 -1
- package/dist/chunk-TLWGZVPC.js.map +0 -1
- package/dist/chunk-UK6XTS2Y.js.map +0 -1
- package/dist/chunk-W7GAXL6C.js.map +0 -1
- package/dist/config-GEZFLXK6.js +0 -12
- package/dist/install-BXM56QCD.js +0 -19
- package/dist/lean-command-7DFW32MA.js +0 -19
- package/dist/main-YJKSYFPT.js.map +0 -1
- package/dist/summaries-ML53R7EL.js +0 -21
- /package/dist/{adapters-S4HHTWJW.js.map → adapters-OJRSVFV3.js.map} +0 -0
- /package/dist/{config-GEZFLXK6.js.map → config-TXQJCCVI.js.map} +0 -0
- /package/dist/{install-BXM56QCD.js.map → file-vectors-MKXTSGGH.js.map} +0 -0
- /package/dist/{lean-command-7DFW32MA.js.map → index-facts-4MTEHKMN.js.map} +0 -0
- /package/dist/{operations-OG4ISWIM.js.map → index-pass-TBDUEZCB.js.map} +0 -0
- /package/dist/{pretool-command-PRFOIHMW.js.map → install-E3JWINTN.js.map} +0 -0
- /package/dist/{runtime-GCSEIAVD.js.map → lean-MLTAFS5L.js.map} +0 -0
- /package/dist/{summaries-ML53R7EL.js.map → local-75DJECVR.js.map} +0 -0
- /package/dist/{zvec-XDZNZ2OL.js.map → local-llm-MECVJTVU.js.map} +0 -0
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
refreshZvecIndex
|
|
3
|
-
} from "./chunk-GXOML4UZ.js";
|
|
4
1
|
import {
|
|
5
2
|
PlanFileStore,
|
|
6
3
|
PlanLifecycle,
|
|
@@ -11,38 +8,45 @@ import {
|
|
|
11
8
|
configuredReranker,
|
|
12
9
|
enforceContextBudget,
|
|
13
10
|
llmMemoryOptions,
|
|
11
|
+
rankSemanticReuse,
|
|
14
12
|
readPolicyFile,
|
|
15
13
|
resolveRiskPaths
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import {
|
|
18
|
-
SessionCapsuleLedger,
|
|
19
|
-
coveringTestCandidates,
|
|
20
|
-
estimateTokens
|
|
21
|
-
} from "./chunk-GKNYMNFM.js";
|
|
14
|
+
} from "./chunk-KQCP3ZYH.js";
|
|
22
15
|
import {
|
|
23
16
|
readTraces,
|
|
24
17
|
recordTrace
|
|
25
18
|
} from "./chunk-YN7TEIUH.js";
|
|
26
19
|
import {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
MemoryFileStore,
|
|
33
|
-
VERSION
|
|
34
|
-
} from "./chunk-SRA4MDVG.js";
|
|
20
|
+
SessionCapsuleLedger,
|
|
21
|
+
coveringTestCandidates,
|
|
22
|
+
estimateTokens,
|
|
23
|
+
findCoveringTest
|
|
24
|
+
} from "./chunk-7IPSDDO5.js";
|
|
35
25
|
import {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
} from "./chunk-
|
|
26
|
+
ensureZvecServer,
|
|
27
|
+
refreshZvecIndex
|
|
28
|
+
} from "./chunk-4BSO3HST.js";
|
|
39
29
|
import {
|
|
30
|
+
NON_SOURCE_PATH,
|
|
31
|
+
TEST_PATH,
|
|
40
32
|
buildArchitectureMap,
|
|
33
|
+
generateGraphifyGraph,
|
|
41
34
|
indexRepository,
|
|
42
35
|
loadFreshIndex,
|
|
36
|
+
loadProjectArchitectureMap,
|
|
43
37
|
neighbours,
|
|
44
|
-
queryMap
|
|
45
|
-
|
|
38
|
+
queryMap,
|
|
39
|
+
taskTerms
|
|
40
|
+
} from "./chunk-UR3DF74I.js";
|
|
41
|
+
import {
|
|
42
|
+
codeBuddyConfigSchema,
|
|
43
|
+
createRuntime,
|
|
44
|
+
listFactsPage
|
|
45
|
+
} from "./chunk-KYRM3HPP.js";
|
|
46
|
+
import {
|
|
47
|
+
MemoryFileStore,
|
|
48
|
+
VERSION
|
|
49
|
+
} from "./chunk-YMXFSHXT.js";
|
|
46
50
|
import {
|
|
47
51
|
redactPersisted
|
|
48
52
|
} from "./chunk-AL6VBTNA.js";
|
|
@@ -51,7 +55,10 @@ import {
|
|
|
51
55
|
loadPlanPolicy,
|
|
52
56
|
loadRuntimeConfig,
|
|
53
57
|
redactSecrets
|
|
54
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-M75SN4D4.js";
|
|
59
|
+
import {
|
|
60
|
+
markForeground
|
|
61
|
+
} from "./chunk-BTTQWSDS.js";
|
|
55
62
|
|
|
56
63
|
// src/core/migrate-to-files.ts
|
|
57
64
|
import { createHash } from "crypto";
|
|
@@ -303,8 +310,8 @@ async function traceCliCommand(command, started, root = process.cwd()) {
|
|
|
303
310
|
await flushTelemetry(root);
|
|
304
311
|
}
|
|
305
312
|
async function installedClients(repositoryRoot) {
|
|
306
|
-
const { CLIENT_IDS } = await import("./adapters-
|
|
307
|
-
const { detectClient } = await import("./install-
|
|
313
|
+
const { CLIENT_IDS } = await import("./adapters-OJRSVFV3.js");
|
|
314
|
+
const { detectClient } = await import("./install-E3JWINTN.js");
|
|
308
315
|
const found = [];
|
|
309
316
|
for (const id of CLIENT_IDS) {
|
|
310
317
|
const status = await detectClient(id, repositoryRoot).catch(() => null);
|
|
@@ -328,7 +335,8 @@ var OMITTABLE_SECTIONS = [
|
|
|
328
335
|
"handoffs",
|
|
329
336
|
"architecture",
|
|
330
337
|
"symbols",
|
|
331
|
-
"neighbours"
|
|
338
|
+
"neighbours",
|
|
339
|
+
"reuse"
|
|
332
340
|
];
|
|
333
341
|
var SESSION_TTL_MS = 30 * 60 * 1e3;
|
|
334
342
|
async function applySessionDelivery(repositoryRoot, payload, options) {
|
|
@@ -373,10 +381,88 @@ async function applySessionDelivery(repositoryRoot, payload, options) {
|
|
|
373
381
|
}
|
|
374
382
|
}
|
|
375
383
|
|
|
384
|
+
// src/context/reuse.ts
|
|
385
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
386
|
+
import { join as join2 } from "path";
|
|
387
|
+
var REUSE_ADMISSION = { minMatched: 2, minCoverage: 0.67, limit: 3 };
|
|
388
|
+
var REUSABLE_KINDS = /* @__PURE__ */ new Set(["function", "class", "method", "const"]);
|
|
389
|
+
async function findReuse(repositoryRoot, task, manifest, map, admission = REUSE_ADMISSION, semanticRanker = rankSemanticReuse) {
|
|
390
|
+
const terms = new Set(taskTerms(task));
|
|
391
|
+
if (terms.size < admission.minMatched) return [];
|
|
392
|
+
const symbols = Object.values(manifest.entries).filter((entry) => !TEST_PATH.test(entry.path) && !NON_SOURCE_PATH.test(entry.path)).flatMap(
|
|
393
|
+
(entry) => (entry.symbolTable ?? []).filter((symbol) => symbol.exported && REUSABLE_KINDS.has(symbol.kind)).map((symbol) => ({ ...symbol, path: entry.path, words: new Set(taskTerms(symbol.name)) }))
|
|
394
|
+
);
|
|
395
|
+
const frequency = /* @__PURE__ */ new Map();
|
|
396
|
+
for (const symbol of symbols) {
|
|
397
|
+
for (const word of symbol.words) frequency.set(word, (frequency.get(word) ?? 0) + 1);
|
|
398
|
+
}
|
|
399
|
+
const idf = (word) => Math.log((symbols.length + 1) / ((frequency.get(word) ?? 0) + 1));
|
|
400
|
+
const ranked = symbols.map((symbol) => {
|
|
401
|
+
const matched = [...symbol.words].filter((word) => terms.has(word));
|
|
402
|
+
return {
|
|
403
|
+
symbol,
|
|
404
|
+
matched,
|
|
405
|
+
coverage: symbol.words.size > 0 ? matched.length / symbol.words.size : 0,
|
|
406
|
+
score: matched.reduce((sum, word) => sum + idf(word), 0)
|
|
407
|
+
};
|
|
408
|
+
}).filter(
|
|
409
|
+
(item) => item.matched.length >= admission.minMatched && item.coverage >= admission.minCoverage
|
|
410
|
+
).sort((a, b) => b.score - a.score || a.symbol.path.localeCompare(b.symbol.path));
|
|
411
|
+
let semantic = false;
|
|
412
|
+
if (!ranked.length) {
|
|
413
|
+
const candidates = await semanticRanker(repositoryRoot, task, manifest);
|
|
414
|
+
const first = candidates[0];
|
|
415
|
+
if (first && first.score >= 0.84 && first.score - (candidates[1]?.score ?? 0) >= 0.04) {
|
|
416
|
+
const symbol = symbols.find((item) => item.path === first.path && item.name === first.name);
|
|
417
|
+
if (symbol) {
|
|
418
|
+
ranked.push({ symbol, matched: [], coverage: 0, score: first.score });
|
|
419
|
+
semantic = true;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
const indexed = new Set(Object.keys(manifest.entries));
|
|
424
|
+
const seen = /* @__PURE__ */ new Set();
|
|
425
|
+
const picked = [];
|
|
426
|
+
for (const { symbol, matched, score } of ranked) {
|
|
427
|
+
const key = `${symbol.path}:${symbol.name}`;
|
|
428
|
+
if (seen.has(key)) continue;
|
|
429
|
+
seen.add(key);
|
|
430
|
+
const usage = await usageSite(repositoryRoot, symbol.path, symbol.name, map);
|
|
431
|
+
const test = findCoveringTest(symbol.path, indexed);
|
|
432
|
+
picked.push({
|
|
433
|
+
path: symbol.path,
|
|
434
|
+
name: symbol.name,
|
|
435
|
+
signature: symbol.signature,
|
|
436
|
+
startLine: symbol.startLine,
|
|
437
|
+
endLine: symbol.endLine,
|
|
438
|
+
matched,
|
|
439
|
+
score: Math.round(score * 100) / 100,
|
|
440
|
+
...semantic ? { evidence: "semantic" } : {},
|
|
441
|
+
...usage ? { usage } : {},
|
|
442
|
+
...test ? { test } : {}
|
|
443
|
+
});
|
|
444
|
+
if (picked.length === admission.limit) break;
|
|
445
|
+
}
|
|
446
|
+
return picked;
|
|
447
|
+
}
|
|
448
|
+
async function usageSite(root, path, name, map) {
|
|
449
|
+
const short = name.split(".").at(-1) ?? name;
|
|
450
|
+
const pattern = new RegExp(`\\b${short.replace(/[^\w$]/g, "")}\\b`);
|
|
451
|
+
const importers = (map?.edges ?? []).filter((edge) => edge.to === path && !TEST_PATH.test(edge.from)).map((edge) => edge.from).sort();
|
|
452
|
+
for (const importer of importers.slice(0, 20)) {
|
|
453
|
+
const source = await readFile2(join2(root, importer), "utf8").catch(() => "");
|
|
454
|
+
const lines = source.split("\n");
|
|
455
|
+
const index = lines.findIndex((line) => pattern.test(line) && !/^\s*import\b/.test(line));
|
|
456
|
+
if (index !== -1)
|
|
457
|
+
return `${importer}:${index + 1}: ${(lines[index] ?? "").trim().slice(0, 140)}`;
|
|
458
|
+
}
|
|
459
|
+
return void 0;
|
|
460
|
+
}
|
|
461
|
+
|
|
376
462
|
// src/suggest/engine.ts
|
|
377
463
|
import { constants } from "fs";
|
|
378
464
|
import { access } from "fs/promises";
|
|
379
|
-
import { extname, join as
|
|
465
|
+
import { extname, join as join3, resolve } from "path";
|
|
380
466
|
|
|
381
467
|
// src/suggest/types.ts
|
|
382
468
|
var SEVERITY_RANK = {
|
|
@@ -413,7 +499,7 @@ async function generateSuggestions(input) {
|
|
|
413
499
|
resolveRelevantPlan(planStore, namespace, input.planId),
|
|
414
500
|
memoryStore.findIncidentFactsForPaths({ namespace, paths: targetPaths }),
|
|
415
501
|
buildArchitectureMap(repositoryRoot),
|
|
416
|
-
readPolicyFile(
|
|
502
|
+
readPolicyFile(join3(repositoryRoot, ".codebuddy", "policies.yaml"))
|
|
417
503
|
]);
|
|
418
504
|
const suggestions = [];
|
|
419
505
|
for (const item of risks.items) {
|
|
@@ -493,7 +579,7 @@ async function generateSuggestions(input) {
|
|
|
493
579
|
for (const rule of policyFile.rules) {
|
|
494
580
|
const prefix = literalPrefix(rule.pattern);
|
|
495
581
|
if (!prefix) continue;
|
|
496
|
-
if (await pathExists(
|
|
582
|
+
if (await pathExists(join3(repositoryRoot, prefix))) continue;
|
|
497
583
|
suggestions.push({
|
|
498
584
|
id: `stale_policy:${rule.id}`,
|
|
499
585
|
category: "stale_policy",
|
|
@@ -537,7 +623,7 @@ function isTestableCode(path) {
|
|
|
537
623
|
}
|
|
538
624
|
async function hasSiblingTest(repositoryRoot, path) {
|
|
539
625
|
for (const candidate of coveringTestCandidates(path)) {
|
|
540
|
-
if (await pathExists(
|
|
626
|
+
if (await pathExists(join3(repositoryRoot, candidate))) return true;
|
|
541
627
|
}
|
|
542
628
|
return false;
|
|
543
629
|
}
|
|
@@ -586,6 +672,40 @@ function normalize(path) {
|
|
|
586
672
|
return path.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
587
673
|
}
|
|
588
674
|
|
|
675
|
+
// src/mcp/database-retry.ts
|
|
676
|
+
function isTransientDatabaseError(error) {
|
|
677
|
+
let current = error;
|
|
678
|
+
for (let depth = 0; depth < 4 && current && typeof current === "object"; depth++) {
|
|
679
|
+
const item = current;
|
|
680
|
+
if (typeof item.code === "string" && (/* @__PURE__ */ new Set([
|
|
681
|
+
"ECONNRESET",
|
|
682
|
+
"ECONNREFUSED",
|
|
683
|
+
"EPIPE",
|
|
684
|
+
"CONNECTION_CLOSED",
|
|
685
|
+
"CONNECTION_ENDED",
|
|
686
|
+
"08000",
|
|
687
|
+
"08001",
|
|
688
|
+
"08003",
|
|
689
|
+
"08006",
|
|
690
|
+
"57P01",
|
|
691
|
+
"57P02",
|
|
692
|
+
"57P03"
|
|
693
|
+
])).has(item.code))
|
|
694
|
+
return true;
|
|
695
|
+
current = item.cause;
|
|
696
|
+
}
|
|
697
|
+
return false;
|
|
698
|
+
}
|
|
699
|
+
async function withDatabaseRetry(operation, readOnly, delayMs = 250) {
|
|
700
|
+
try {
|
|
701
|
+
return await operation();
|
|
702
|
+
} catch (error) {
|
|
703
|
+
if (!readOnly || !isTransientDatabaseError(error)) throw error;
|
|
704
|
+
await new Promise((resolve5) => setTimeout(resolve5, delayMs));
|
|
705
|
+
return operation();
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
589
709
|
// src/mcp/tool-result.ts
|
|
590
710
|
function serializeToolResult(value, format = process.env.CODEBUDDY_RESPONSE_FORMAT ?? "both") {
|
|
591
711
|
if (format !== "text" && format !== "both") {
|
|
@@ -631,7 +751,7 @@ var recallSchema = {
|
|
|
631
751
|
budget: z.number().int().positive().optional(),
|
|
632
752
|
callerModel: z.string().min(1).max(200).optional(),
|
|
633
753
|
conflictMode: z.enum(["all", "latest", "highest_confidence"]).optional(),
|
|
634
|
-
/**
|
|
754
|
+
/** Default true: a flat list of memories (id, content, date). false = full provenance + stats. */
|
|
635
755
|
compact: z.boolean().optional()
|
|
636
756
|
};
|
|
637
757
|
var shareSchema = {
|
|
@@ -768,6 +888,30 @@ var FILE_TOOLS = Object.keys(mcpToolInputSchemas).filter(
|
|
|
768
888
|
(name) => !DATABASE_TOOLS.includes(name)
|
|
769
889
|
);
|
|
770
890
|
var DEGRADED_FALLBACK = "PostgreSQL is unavailable, so this call did nothing. File-based tools still work; read the repository directly and say recall is unavailable instead of guessing. Run `codebuddy db doctor` to diagnose; the next call after retryInMs reconnects.";
|
|
891
|
+
var LEAN_TOOLS = {
|
|
892
|
+
context_pack: {
|
|
893
|
+
description: "Find the files, symbols and line ranges for a coding task. Call only when the injected CodeBuddy block names no files.",
|
|
894
|
+
defaults: { tokenBudget: 800 },
|
|
895
|
+
inputSchema: {
|
|
896
|
+
task: z.string(),
|
|
897
|
+
paths: z.array(z.string()).optional(),
|
|
898
|
+
sessionId: z.string().optional(),
|
|
899
|
+
ack: z.string().optional()
|
|
900
|
+
}
|
|
901
|
+
},
|
|
902
|
+
recall: {
|
|
903
|
+
description: "Recall stored project memory (conventions, decisions, gotchas) for a question.",
|
|
904
|
+
inputSchema: { query: z.string() },
|
|
905
|
+
defaults: { sessionId: "agent" }
|
|
906
|
+
},
|
|
907
|
+
remember: {
|
|
908
|
+
description: "Store one durable project fact (convention, decision, gotcha).",
|
|
909
|
+
inputSchema: { content: z.string() },
|
|
910
|
+
// A fact is Markdown-backed and survives reindex; the full profile's
|
|
911
|
+
// default (`interaction`) is a database-only conversation record.
|
|
912
|
+
defaults: { type: "fact" }
|
|
913
|
+
}
|
|
914
|
+
};
|
|
771
915
|
var CORE_TOOLS = [
|
|
772
916
|
"context_pack",
|
|
773
917
|
"context_bootstrap",
|
|
@@ -777,9 +921,9 @@ var CORE_TOOLS = [
|
|
|
777
921
|
"health"
|
|
778
922
|
];
|
|
779
923
|
function resolveToolProfile(value = process.env.CODEBUDDY_TOOL_PROFILE) {
|
|
780
|
-
if (value === void 0 || value === "" || value === "
|
|
781
|
-
if (value === "core") return
|
|
782
|
-
throw new Error(`CODEBUDDY_TOOL_PROFILE must be "core" or "full", got "${value}"`);
|
|
924
|
+
if (value === void 0 || value === "" || value === "lean") return "lean";
|
|
925
|
+
if (value === "core" || value === "full") return value;
|
|
926
|
+
throw new Error(`CODEBUDDY_TOOL_PROFILE must be "lean", "core" or "full", got "${value}"`);
|
|
783
927
|
}
|
|
784
928
|
var PLAN_BODY_LIMIT = 8e3;
|
|
785
929
|
function serializePlan(plan) {
|
|
@@ -790,12 +934,13 @@ function serializePlan(plan) {
|
|
|
790
934
|
return { plan: { ...plan, body } };
|
|
791
935
|
}
|
|
792
936
|
function registerCodeBuddyTools(server, options, profile = "full") {
|
|
793
|
-
const exposed = (name) => profile === "full" || CORE_TOOLS.includes(name);
|
|
937
|
+
const exposed = (name) => profile === "full" || (profile === "lean" ? name in LEAN_TOOLS : CORE_TOOLS.includes(name));
|
|
794
938
|
const config = "database" in options ? options.config : options.memory.config;
|
|
795
939
|
const traceRoot = config.projectRoot ?? process.cwd();
|
|
796
940
|
const register = (name, toolConfig, callback) => {
|
|
797
941
|
const traced = (async (...args) => {
|
|
798
942
|
const started = Date.now();
|
|
943
|
+
void markForeground(traceRoot);
|
|
799
944
|
const input = args.length > 1 ? args[0] : void 0;
|
|
800
945
|
const trace = (ok, output) => void recordTrace(traceRoot, {
|
|
801
946
|
kind: "tool",
|
|
@@ -815,7 +960,29 @@ function registerCodeBuddyTools(server, options, profile = "full") {
|
|
|
815
960
|
throw error;
|
|
816
961
|
}
|
|
817
962
|
});
|
|
818
|
-
const
|
|
963
|
+
const lean = profile === "lean" ? LEAN_TOOLS[name] : void 0;
|
|
964
|
+
const full = mcpToolInputSchemas[name];
|
|
965
|
+
const tool = lean ? server.registerTool(
|
|
966
|
+
name,
|
|
967
|
+
{
|
|
968
|
+
...toolConfig,
|
|
969
|
+
description: lean.description,
|
|
970
|
+
inputSchema: lean.inputSchema
|
|
971
|
+
},
|
|
972
|
+
// The lean schema only lists fields; the full schema enforces limits.
|
|
973
|
+
(async (input, extra) => {
|
|
974
|
+
const parsed = full.safeParse({ ...lean.defaults, ...input });
|
|
975
|
+
if (!parsed.success) {
|
|
976
|
+
return {
|
|
977
|
+
content: [
|
|
978
|
+
{ type: "text", text: `Invalid input: ${parsed.error.message}` }
|
|
979
|
+
],
|
|
980
|
+
isError: true
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
return traced(parsed.data, extra);
|
|
984
|
+
})
|
|
985
|
+
) : server.registerTool(name, toolConfig, traced);
|
|
819
986
|
if (!exposed(name)) tool.remove();
|
|
820
987
|
return tool;
|
|
821
988
|
};
|
|
@@ -831,7 +998,25 @@ function registerCodeBuddyTools(server, options, profile = "full") {
|
|
|
831
998
|
isError: true
|
|
832
999
|
};
|
|
833
1000
|
}
|
|
834
|
-
|
|
1001
|
+
try {
|
|
1002
|
+
return json(
|
|
1003
|
+
await withDatabaseRetry(
|
|
1004
|
+
() => run(db),
|
|
1005
|
+
["recall", "list_facts", "list_namespaces"].includes(tool)
|
|
1006
|
+
)
|
|
1007
|
+
);
|
|
1008
|
+
} catch (error) {
|
|
1009
|
+
if (!isTransientDatabaseError(error)) throw error;
|
|
1010
|
+
return {
|
|
1011
|
+
...json({
|
|
1012
|
+
degraded: true,
|
|
1013
|
+
tool,
|
|
1014
|
+
database: { ...database.status(), available: false, state: "unavailable" },
|
|
1015
|
+
fallback: "The database connection failed during this operation. A write may have committed; verify state before repeating it. File-based context remains available."
|
|
1016
|
+
}),
|
|
1017
|
+
isError: true
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
835
1020
|
};
|
|
836
1021
|
const namespace = config.namespace;
|
|
837
1022
|
const projectRoot = config.projectRoot ?? process.cwd();
|
|
@@ -880,12 +1065,12 @@ function registerCodeBuddyTools(server, options, profile = "full") {
|
|
|
880
1065
|
"recall",
|
|
881
1066
|
{
|
|
882
1067
|
title: "Recall",
|
|
883
|
-
description: "Recall
|
|
1068
|
+
description: "Recall project memory for a query. Returns a flat list of memories (id, content, date), or an empty list when nothing is relevant. Pass compact=false for full provenance and token stats.",
|
|
884
1069
|
inputSchema: mcpToolInputSchemas.recall.shape
|
|
885
1070
|
},
|
|
886
1071
|
async (input) => viaDatabase(
|
|
887
1072
|
"recall",
|
|
888
|
-
async (db) => withResponseTokens(await db.memory.recall(toRecallInput(input))
|
|
1073
|
+
async (db) => input.compact === false ? withResponseTokens(await db.memory.recall(toRecallInput(input))) : compactRecall(await db.memory.recall(toRecallInput(input)))
|
|
889
1074
|
)
|
|
890
1075
|
);
|
|
891
1076
|
register(
|
|
@@ -1148,24 +1333,35 @@ function registerCodeBuddyTools(server, options, profile = "full") {
|
|
|
1148
1333
|
description: "Build the smallest useful context pack for a coding task. Automatically finds relevant files from the local index when paths are omitted, then includes only bounded symbols, policies, risks, incidents, architecture neighbours, and relevant team facts within the requested token budget. Use this once at the start of a task instead of manually chaining context, risk, map, and memory tools. Request evidence=source with exact paths when short excerpts omit needed behavior; source excerpts remain bounded by the token budget. Optional sessionId enables session-aware delivery: pass the previous response's delivery.deliveryId as ack and unchanged sections are omitted (listed in delivery.unchanged); pass full=true to get everything again.",
|
|
1149
1334
|
inputSchema: mcpToolInputSchemas.context_pack.shape
|
|
1150
1335
|
},
|
|
1151
|
-
async (input) =>
|
|
1152
|
-
await
|
|
1153
|
-
projectRoot,
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
})
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1336
|
+
async (input) => {
|
|
1337
|
+
const context = await buildBeforeEditContext({
|
|
1338
|
+
repositoryRoot: projectRoot,
|
|
1339
|
+
namespace,
|
|
1340
|
+
task: input.task,
|
|
1341
|
+
semanticRanker: rankContextFacts,
|
|
1342
|
+
...await rerankerOption(),
|
|
1343
|
+
...input.evidence ? { evidence: input.evidence } : {},
|
|
1344
|
+
...input.paths !== void 0 ? { paths: input.paths } : {},
|
|
1345
|
+
...input.planId !== void 0 ? { planId: input.planId } : {},
|
|
1346
|
+
...input.useGit !== void 0 ? { useGit: input.useGit } : {},
|
|
1347
|
+
tokenBudget: input.tokenBudget ?? tokenBudget ?? 4e3
|
|
1348
|
+
});
|
|
1349
|
+
const reuse = await loadFreshIndex(projectRoot).then(
|
|
1350
|
+
async ({ manifest }) => findReuse(
|
|
1351
|
+
projectRoot,
|
|
1352
|
+
input.task,
|
|
1353
|
+
manifest,
|
|
1354
|
+
await loadProjectArchitectureMap(projectRoot, manifest)
|
|
1355
|
+
)
|
|
1356
|
+
).catch(() => []);
|
|
1357
|
+
return json(
|
|
1358
|
+
await applySessionDelivery(
|
|
1359
|
+
projectRoot,
|
|
1360
|
+
enforceContextBudget({ ...context, ...reuse.length > 0 ? { reuse } : {} }),
|
|
1361
|
+
deliveryOptions(input)
|
|
1362
|
+
)
|
|
1363
|
+
);
|
|
1364
|
+
}
|
|
1169
1365
|
);
|
|
1170
1366
|
register(
|
|
1171
1367
|
"context_after_turn",
|
|
@@ -1259,21 +1455,17 @@ function toRecallInput(input) {
|
|
|
1259
1455
|
const { compact: _compact, ...rest } = input;
|
|
1260
1456
|
return cleanOptional(rest);
|
|
1261
1457
|
}
|
|
1262
|
-
function
|
|
1263
|
-
const
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
} : {
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
content: message.content
|
|
1274
|
-
})),
|
|
1275
|
-
stats
|
|
1276
|
-
} : { ...result, stats };
|
|
1458
|
+
function compactRecall(result) {
|
|
1459
|
+
const memories = result.messages.map((message) => ({
|
|
1460
|
+
...message.fact ? { id: message.fact.id } : {},
|
|
1461
|
+
content: message.content,
|
|
1462
|
+
...message.fact?.createdAt ? { date: message.fact.createdAt.slice(0, 10) } : {}
|
|
1463
|
+
}));
|
|
1464
|
+
return memories.length > 0 ? { memories } : { memories, note: "nothing relevant" };
|
|
1465
|
+
}
|
|
1466
|
+
function withResponseTokens(result) {
|
|
1467
|
+
const stats = { ...result.stats };
|
|
1468
|
+
const value = { ...result, stats };
|
|
1277
1469
|
for (let pass = 0; pass < 2; pass++) {
|
|
1278
1470
|
const serialized = serializeToolResult(value);
|
|
1279
1471
|
stats.responseTokens = estimateTokens(serialized.content[0]?.text);
|
|
@@ -1292,7 +1484,7 @@ import pino from "pino";
|
|
|
1292
1484
|
|
|
1293
1485
|
// src/automation/project-sync.ts
|
|
1294
1486
|
import { watch as fsWatch2 } from "fs";
|
|
1295
|
-
import { join as
|
|
1487
|
+
import { join as join4, relative, resolve as resolve3, sep } from "path";
|
|
1296
1488
|
|
|
1297
1489
|
// src/indexer/watch.ts
|
|
1298
1490
|
import { watch as fsWatch } from "fs";
|
|
@@ -1396,6 +1588,8 @@ function startProjectSync(options) {
|
|
|
1396
1588
|
let closing = false;
|
|
1397
1589
|
let memoryWatcher = null;
|
|
1398
1590
|
let memoryRefresh = null;
|
|
1591
|
+
let stopZvecServer = async () => {
|
|
1592
|
+
};
|
|
1399
1593
|
const backgroundRefresh = (task) => {
|
|
1400
1594
|
let current = null;
|
|
1401
1595
|
let pending = false;
|
|
@@ -1431,9 +1625,36 @@ function startProjectSync(options) {
|
|
|
1431
1625
|
);
|
|
1432
1626
|
if (result.status !== "disabled") logger.info(`[sync] ${result.reason}`);
|
|
1433
1627
|
});
|
|
1628
|
+
const modelPass = backgroundRefresh(async () => {
|
|
1629
|
+
const { runIndexModelPass } = await import("./index-pass-TBDUEZCB.js");
|
|
1630
|
+
const result = await runIndexModelPass(repositoryRoot, { signal: controller.signal }).catch(
|
|
1631
|
+
(error) => {
|
|
1632
|
+
logger.error(`[sync] index model pass failed: ${error.message}`);
|
|
1633
|
+
return null;
|
|
1634
|
+
}
|
|
1635
|
+
);
|
|
1636
|
+
if (result?.cards && (result.cards.summarized > 0 || result.cards.remaining > 0)) {
|
|
1637
|
+
logger.info(
|
|
1638
|
+
`[sync] intent cards: ${result.cards.summarized} written, ${result.cards.remaining} left (${result.cards.stoppedBy})`
|
|
1639
|
+
);
|
|
1640
|
+
}
|
|
1641
|
+
if (result?.facts && result.facts.written + result.facts.removed > 0) {
|
|
1642
|
+
logger.info(
|
|
1643
|
+
`[sync] index facts: ${result.facts.written} written, ${result.facts.removed} replaced`
|
|
1644
|
+
);
|
|
1645
|
+
await options.onMemoryChange?.();
|
|
1646
|
+
}
|
|
1647
|
+
});
|
|
1434
1648
|
const ready = (async () => {
|
|
1435
1649
|
await indexRepository({ repositoryRoot });
|
|
1650
|
+
void ensureZvecServer(repositoryRoot).then((server) => {
|
|
1651
|
+
stopZvecServer = server.stop;
|
|
1652
|
+
if (server.reason !== "zvec-grep not enabled") logger.info(`[sync] ${server.reason}`);
|
|
1653
|
+
if (closing) void server.stop();
|
|
1654
|
+
}).catch(() => {
|
|
1655
|
+
});
|
|
1436
1656
|
zvecRefresh.schedule();
|
|
1657
|
+
modelPass.schedule();
|
|
1437
1658
|
watchMemory();
|
|
1438
1659
|
if (options.graphify?.enabled) {
|
|
1439
1660
|
await refreshGraph().catch(
|
|
@@ -1451,6 +1672,7 @@ function startProjectSync(options) {
|
|
|
1451
1672
|
onIndex: (result) => {
|
|
1452
1673
|
if (result.added + result.changed + result.removed === 0) return;
|
|
1453
1674
|
zvecRefresh.schedule();
|
|
1675
|
+
modelPass.schedule();
|
|
1454
1676
|
if (options.graphify?.enabled) graphRefresh.schedule();
|
|
1455
1677
|
},
|
|
1456
1678
|
onError: (error) => logger.error(`[sync] repository watch failed: ${error.message}`)
|
|
@@ -1473,7 +1695,7 @@ function startProjectSync(options) {
|
|
|
1473
1695
|
300
|
|
1474
1696
|
);
|
|
1475
1697
|
memoryWatcher = fsWatch2(
|
|
1476
|
-
|
|
1698
|
+
join4(repositoryRoot, ".codebuddy", "memory"),
|
|
1477
1699
|
{ recursive: true },
|
|
1478
1700
|
(_event, filename) => {
|
|
1479
1701
|
const name = filename?.replace(/\\/g, "/") ?? "";
|
|
@@ -1500,7 +1722,11 @@ function startProjectSync(options) {
|
|
|
1500
1722
|
memoryRefresh?.stop();
|
|
1501
1723
|
memoryWatcher?.close();
|
|
1502
1724
|
await watcher?.catch(() => void 0);
|
|
1503
|
-
await Promise.all([graphRefresh.settled(), zvecRefresh.settled()]);
|
|
1725
|
+
await Promise.all([graphRefresh.settled(), zvecRefresh.settled(), modelPass.settled()]);
|
|
1726
|
+
await stopZvecServer().catch(() => {
|
|
1727
|
+
});
|
|
1728
|
+
await import("./local-75DJECVR.js").then(({ unloadLocalModel }) => unloadLocalModel()).catch(() => {
|
|
1729
|
+
});
|
|
1504
1730
|
}
|
|
1505
1731
|
};
|
|
1506
1732
|
}
|
|
@@ -1676,7 +1902,7 @@ async function startMcpServer(options = {}) {
|
|
|
1676
1902
|
};
|
|
1677
1903
|
let stopping;
|
|
1678
1904
|
const stop = () => {
|
|
1679
|
-
stopping
|
|
1905
|
+
if (!stopping) stopping = shutdown().finally(() => process.exit(0));
|
|
1680
1906
|
};
|
|
1681
1907
|
process.once("SIGINT", stop);
|
|
1682
1908
|
process.once("SIGTERM", stop);
|
|
@@ -1784,9 +2010,10 @@ export {
|
|
|
1784
2010
|
showTelemetryNoticeOnce,
|
|
1785
2011
|
flushTelemetry,
|
|
1786
2012
|
traceCliCommand,
|
|
2013
|
+
findReuse,
|
|
1787
2014
|
generateSuggestions,
|
|
1788
2015
|
mcpToolInputSchemas,
|
|
1789
2016
|
registerCodeBuddyTools,
|
|
1790
2017
|
startMcpServer
|
|
1791
2018
|
};
|
|
1792
|
-
//# sourceMappingURL=chunk-
|
|
2019
|
+
//# sourceMappingURL=chunk-D5E7SGI5.js.map
|