@orquentra/codebuddy 2.8.0 → 2.14.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/CLAUDE_CODEX.md +33 -0
- package/README.md +27 -3
- package/dist/{adapters-S4HHTWJW.js → adapters-OJRSVFV3.js} +2 -2
- package/dist/{chunk-GKNYMNFM.js → chunk-4DKYKDHI.js} +6 -1
- package/dist/chunk-4DKYKDHI.js.map +1 -0
- package/dist/{chunk-6KGYAFG7.js → chunk-7QMHIJBA.js} +30 -3
- package/dist/chunk-7QMHIJBA.js.map +1 -0
- package/dist/{chunk-6NZEZJYD.js → chunk-ESC4Y3L7.js} +3 -5
- package/dist/{chunk-6NZEZJYD.js.map → chunk-ESC4Y3L7.js.map} +1 -1
- package/dist/chunk-GQKWUHMA.js +20 -0
- package/dist/chunk-GQKWUHMA.js.map +1 -0
- package/dist/{chunk-J4T6HHI4.js → chunk-L6BRYZ6G.js} +537 -316
- package/dist/chunk-L6BRYZ6G.js.map +1 -0
- package/dist/{chunk-UK6XTS2Y.js → chunk-LRQNPYCK.js} +13 -19
- package/dist/chunk-LRQNPYCK.js.map +1 -0
- package/dist/{chunk-GXOML4UZ.js → chunk-LW75SKZR.js} +2 -2
- package/dist/{chunk-EJQVGFH2.js → chunk-UOTKHSQ5.js} +26 -9
- package/dist/chunk-UOTKHSQ5.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-ZNLSCV3J.js → chunk-XSNW6Y3X.js} +1253 -315
- package/dist/chunk-XSNW6Y3X.js.map +1 -0
- package/dist/{chunk-6DONJW3W.js → chunk-YJPCS2GP.js} +274 -69
- package/dist/chunk-YJPCS2GP.js.map +1 -0
- package/dist/{chunk-XL2HLACE.js → chunk-YN7TEIUH.js} +1 -1
- package/dist/chunk-YN7TEIUH.js.map +1 -0
- package/dist/{chunk-TLWGZVPC.js → chunk-YNSTIMCF.js} +746 -66
- package/dist/chunk-YNSTIMCF.js.map +1 -0
- package/dist/{chunk-NY2YXP3R.js → chunk-YWDH6DQ6.js} +70 -4
- package/dist/chunk-YWDH6DQ6.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/index.d.ts +6 -4
- package/dist/index.js +9 -9
- package/dist/install-EU35ERK5.js +30 -0
- package/dist/langgraph/index.d.ts +1 -1
- package/dist/lean-43ADYTBW.js +28 -0
- package/dist/{main-QUASSFP7.js → main-SFC5LV4E.js} +1333 -437
- package/dist/main-SFC5LV4E.js.map +1 -0
- package/dist/{operations-WJR7AZZF.js → operations-6Z6ZDVBP.js} +3 -3
- package/dist/{pretool-command-JTKX6G3M.js → pretool-command-B5GY5T6E.js} +3 -3
- package/dist/prompt-gate-TDTFFQW2.js +8 -0
- package/dist/{runtime-OQQ22VJF.js → runtime-W5AW32SD.js} +15 -7
- package/dist/{summaries-ML53R7EL.js → summaries-32PHOB6L.js} +3 -4
- package/dist/{zvec-XDZNZ2OL.js → zvec-24HLAFGN.js} +3 -4
- package/dist/zvec-24HLAFGN.js.map +1 -0
- package/package.json +11 -2
- package/dist/chunk-6DONJW3W.js.map +0 -1
- package/dist/chunk-6KGYAFG7.js.map +0 -1
- package/dist/chunk-EJQVGFH2.js.map +0 -1
- package/dist/chunk-GKNYMNFM.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-NY2YXP3R.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/chunk-XL2HLACE.js.map +0 -1
- package/dist/chunk-ZNLSCV3J.js.map +0 -1
- package/dist/install-BXM56QCD.js +0 -19
- package/dist/lean-command-7DFW32MA.js +0 -19
- package/dist/main-QUASSFP7.js.map +0 -1
- /package/dist/{adapters-S4HHTWJW.js.map → adapters-OJRSVFV3.js.map} +0 -0
- /package/dist/{chunk-GXOML4UZ.js.map → chunk-LW75SKZR.js.map} +0 -0
- /package/dist/{install-BXM56QCD.js.map → install-EU35ERK5.js.map} +0 -0
- /package/dist/{lean-command-7DFW32MA.js.map → lean-43ADYTBW.js.map} +0 -0
- /package/dist/{operations-WJR7AZZF.js.map → operations-6Z6ZDVBP.js.map} +0 -0
- /package/dist/{pretool-command-JTKX6G3M.js.map → pretool-command-B5GY5T6E.js.map} +0 -0
- /package/dist/{runtime-OQQ22VJF.js.map → prompt-gate-TDTFFQW2.js.map} +0 -0
- /package/dist/{summaries-ML53R7EL.js.map → runtime-W5AW32SD.js.map} +0 -0
- /package/dist/{zvec-XDZNZ2OL.js.map → summaries-32PHOB6L.js.map} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
refreshZvecIndex
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-LW75SKZR.js";
|
|
4
4
|
import {
|
|
5
5
|
PlanFileStore,
|
|
6
6
|
PlanLifecycle,
|
|
@@ -11,38 +11,41 @@ import {
|
|
|
11
11
|
configuredReranker,
|
|
12
12
|
enforceContextBudget,
|
|
13
13
|
llmMemoryOptions,
|
|
14
|
+
rankSemanticReuse,
|
|
14
15
|
readPolicyFile,
|
|
15
16
|
resolveRiskPaths
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import {
|
|
18
|
-
SessionCapsuleLedger,
|
|
19
|
-
coveringTestCandidates,
|
|
20
|
-
estimateTokens
|
|
21
|
-
} from "./chunk-GKNYMNFM.js";
|
|
17
|
+
} from "./chunk-XSNW6Y3X.js";
|
|
22
18
|
import {
|
|
23
19
|
readTraces,
|
|
24
20
|
recordTrace
|
|
25
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-YN7TEIUH.js";
|
|
22
|
+
import {
|
|
23
|
+
SessionCapsuleLedger,
|
|
24
|
+
coveringTestCandidates,
|
|
25
|
+
estimateTokens,
|
|
26
|
+
findCoveringTest
|
|
27
|
+
} from "./chunk-4DKYKDHI.js";
|
|
26
28
|
import {
|
|
27
29
|
codeBuddyConfigSchema,
|
|
28
30
|
createRuntime,
|
|
29
31
|
listFactsPage
|
|
30
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-YWDH6DQ6.js";
|
|
31
33
|
import {
|
|
32
34
|
MemoryFileStore,
|
|
33
35
|
VERSION
|
|
34
|
-
} from "./chunk-
|
|
35
|
-
import {
|
|
36
|
-
generateGraphifyGraph,
|
|
37
|
-
loadProjectArchitectureMap
|
|
38
|
-
} from "./chunk-TLWGZVPC.js";
|
|
36
|
+
} from "./chunk-7QMHIJBA.js";
|
|
39
37
|
import {
|
|
38
|
+
NON_SOURCE_PATH,
|
|
39
|
+
TEST_PATH,
|
|
40
40
|
buildArchitectureMap,
|
|
41
|
+
generateGraphifyGraph,
|
|
41
42
|
indexRepository,
|
|
42
43
|
loadFreshIndex,
|
|
44
|
+
loadProjectArchitectureMap,
|
|
43
45
|
neighbours,
|
|
44
|
-
queryMap
|
|
45
|
-
|
|
46
|
+
queryMap,
|
|
47
|
+
taskTerms
|
|
48
|
+
} from "./chunk-YNSTIMCF.js";
|
|
46
49
|
import {
|
|
47
50
|
redactPersisted
|
|
48
51
|
} from "./chunk-AL6VBTNA.js";
|
|
@@ -172,6 +175,7 @@ function checksum(content) {
|
|
|
172
175
|
|
|
173
176
|
// src/telemetry/telemetry.ts
|
|
174
177
|
import { createHash as createHash2, randomUUID } from "crypto";
|
|
178
|
+
import { existsSync } from "fs";
|
|
175
179
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
176
180
|
import { homedir } from "os";
|
|
177
181
|
import { dirname, join } from "path";
|
|
@@ -286,9 +290,24 @@ async function flushTelemetry(repositoryRoot, options = {}) {
|
|
|
286
290
|
return 0;
|
|
287
291
|
}
|
|
288
292
|
}
|
|
293
|
+
async function traceCliCommand(command, started, root = process.cwd()) {
|
|
294
|
+
if (/^\[(hook|admin)\]/.test(command.description()) || command.name() === "serve") return;
|
|
295
|
+
if (!existsSync(join(root, ".codebuddy"))) return;
|
|
296
|
+
const path = [];
|
|
297
|
+
for (let current = command; current?.parent; current = current.parent) {
|
|
298
|
+
path.unshift(current.name());
|
|
299
|
+
}
|
|
300
|
+
await recordTrace(root, {
|
|
301
|
+
kind: "cli",
|
|
302
|
+
name: path.join(".") || "use",
|
|
303
|
+
ms: Date.now() - started,
|
|
304
|
+
ok: !process.exitCode
|
|
305
|
+
});
|
|
306
|
+
await flushTelemetry(root);
|
|
307
|
+
}
|
|
289
308
|
async function installedClients(repositoryRoot) {
|
|
290
|
-
const { CLIENT_IDS } = await import("./adapters-
|
|
291
|
-
const { detectClient } = await import("./install-
|
|
309
|
+
const { CLIENT_IDS } = await import("./adapters-OJRSVFV3.js");
|
|
310
|
+
const { detectClient } = await import("./install-EU35ERK5.js");
|
|
292
311
|
const found = [];
|
|
293
312
|
for (const id of CLIENT_IDS) {
|
|
294
313
|
const status = await detectClient(id, repositoryRoot).catch(() => null);
|
|
@@ -312,7 +331,8 @@ var OMITTABLE_SECTIONS = [
|
|
|
312
331
|
"handoffs",
|
|
313
332
|
"architecture",
|
|
314
333
|
"symbols",
|
|
315
|
-
"neighbours"
|
|
334
|
+
"neighbours",
|
|
335
|
+
"reuse"
|
|
316
336
|
];
|
|
317
337
|
var SESSION_TTL_MS = 30 * 60 * 1e3;
|
|
318
338
|
async function applySessionDelivery(repositoryRoot, payload, options) {
|
|
@@ -357,10 +377,88 @@ async function applySessionDelivery(repositoryRoot, payload, options) {
|
|
|
357
377
|
}
|
|
358
378
|
}
|
|
359
379
|
|
|
380
|
+
// src/context/reuse.ts
|
|
381
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
382
|
+
import { join as join2 } from "path";
|
|
383
|
+
var REUSE_ADMISSION = { minMatched: 2, minCoverage: 0.67, limit: 3 };
|
|
384
|
+
var REUSABLE_KINDS = /* @__PURE__ */ new Set(["function", "class", "method", "const"]);
|
|
385
|
+
async function findReuse(repositoryRoot, task, manifest, map, admission = REUSE_ADMISSION, semanticRanker = rankSemanticReuse) {
|
|
386
|
+
const terms = new Set(taskTerms(task));
|
|
387
|
+
if (terms.size < admission.minMatched) return [];
|
|
388
|
+
const symbols = Object.values(manifest.entries).filter((entry) => !TEST_PATH.test(entry.path) && !NON_SOURCE_PATH.test(entry.path)).flatMap(
|
|
389
|
+
(entry) => (entry.symbolTable ?? []).filter((symbol) => symbol.exported && REUSABLE_KINDS.has(symbol.kind)).map((symbol) => ({ ...symbol, path: entry.path, words: new Set(taskTerms(symbol.name)) }))
|
|
390
|
+
);
|
|
391
|
+
const frequency = /* @__PURE__ */ new Map();
|
|
392
|
+
for (const symbol of symbols) {
|
|
393
|
+
for (const word of symbol.words) frequency.set(word, (frequency.get(word) ?? 0) + 1);
|
|
394
|
+
}
|
|
395
|
+
const idf = (word) => Math.log((symbols.length + 1) / ((frequency.get(word) ?? 0) + 1));
|
|
396
|
+
const ranked = symbols.map((symbol) => {
|
|
397
|
+
const matched = [...symbol.words].filter((word) => terms.has(word));
|
|
398
|
+
return {
|
|
399
|
+
symbol,
|
|
400
|
+
matched,
|
|
401
|
+
coverage: symbol.words.size > 0 ? matched.length / symbol.words.size : 0,
|
|
402
|
+
score: matched.reduce((sum, word) => sum + idf(word), 0)
|
|
403
|
+
};
|
|
404
|
+
}).filter(
|
|
405
|
+
(item) => item.matched.length >= admission.minMatched && item.coverage >= admission.minCoverage
|
|
406
|
+
).sort((a, b) => b.score - a.score || a.symbol.path.localeCompare(b.symbol.path));
|
|
407
|
+
let semantic = false;
|
|
408
|
+
if (!ranked.length) {
|
|
409
|
+
const candidates = await semanticRanker(repositoryRoot, task, manifest);
|
|
410
|
+
const first = candidates[0];
|
|
411
|
+
if (first && first.score >= 0.84 && first.score - (candidates[1]?.score ?? 0) >= 0.04) {
|
|
412
|
+
const symbol = symbols.find((item) => item.path === first.path && item.name === first.name);
|
|
413
|
+
if (symbol) {
|
|
414
|
+
ranked.push({ symbol, matched: [], coverage: 0, score: first.score });
|
|
415
|
+
semantic = true;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
const indexed = new Set(Object.keys(manifest.entries));
|
|
420
|
+
const seen = /* @__PURE__ */ new Set();
|
|
421
|
+
const picked = [];
|
|
422
|
+
for (const { symbol, matched, score } of ranked) {
|
|
423
|
+
const key = `${symbol.path}:${symbol.name}`;
|
|
424
|
+
if (seen.has(key)) continue;
|
|
425
|
+
seen.add(key);
|
|
426
|
+
const usage = await usageSite(repositoryRoot, symbol.path, symbol.name, map);
|
|
427
|
+
const test = findCoveringTest(symbol.path, indexed);
|
|
428
|
+
picked.push({
|
|
429
|
+
path: symbol.path,
|
|
430
|
+
name: symbol.name,
|
|
431
|
+
signature: symbol.signature,
|
|
432
|
+
startLine: symbol.startLine,
|
|
433
|
+
endLine: symbol.endLine,
|
|
434
|
+
matched,
|
|
435
|
+
score: Math.round(score * 100) / 100,
|
|
436
|
+
...semantic ? { evidence: "semantic" } : {},
|
|
437
|
+
...usage ? { usage } : {},
|
|
438
|
+
...test ? { test } : {}
|
|
439
|
+
});
|
|
440
|
+
if (picked.length === admission.limit) break;
|
|
441
|
+
}
|
|
442
|
+
return picked;
|
|
443
|
+
}
|
|
444
|
+
async function usageSite(root, path, name, map) {
|
|
445
|
+
const short = name.split(".").at(-1) ?? name;
|
|
446
|
+
const pattern = new RegExp(`\\b${short.replace(/[^\w$]/g, "")}\\b`);
|
|
447
|
+
const importers = (map?.edges ?? []).filter((edge) => edge.to === path && !TEST_PATH.test(edge.from)).map((edge) => edge.from).sort();
|
|
448
|
+
for (const importer of importers.slice(0, 20)) {
|
|
449
|
+
const source = await readFile2(join2(root, importer), "utf8").catch(() => "");
|
|
450
|
+
const lines = source.split("\n");
|
|
451
|
+
const index = lines.findIndex((line) => pattern.test(line) && !/^\s*import\b/.test(line));
|
|
452
|
+
if (index !== -1)
|
|
453
|
+
return `${importer}:${index + 1}: ${(lines[index] ?? "").trim().slice(0, 140)}`;
|
|
454
|
+
}
|
|
455
|
+
return void 0;
|
|
456
|
+
}
|
|
457
|
+
|
|
360
458
|
// src/suggest/engine.ts
|
|
361
459
|
import { constants } from "fs";
|
|
362
460
|
import { access } from "fs/promises";
|
|
363
|
-
import { extname, join as
|
|
461
|
+
import { extname, join as join3, resolve } from "path";
|
|
364
462
|
|
|
365
463
|
// src/suggest/types.ts
|
|
366
464
|
var SEVERITY_RANK = {
|
|
@@ -397,7 +495,7 @@ async function generateSuggestions(input) {
|
|
|
397
495
|
resolveRelevantPlan(planStore, namespace, input.planId),
|
|
398
496
|
memoryStore.findIncidentFactsForPaths({ namespace, paths: targetPaths }),
|
|
399
497
|
buildArchitectureMap(repositoryRoot),
|
|
400
|
-
readPolicyFile(
|
|
498
|
+
readPolicyFile(join3(repositoryRoot, ".codebuddy", "policies.yaml"))
|
|
401
499
|
]);
|
|
402
500
|
const suggestions = [];
|
|
403
501
|
for (const item of risks.items) {
|
|
@@ -477,7 +575,7 @@ async function generateSuggestions(input) {
|
|
|
477
575
|
for (const rule of policyFile.rules) {
|
|
478
576
|
const prefix = literalPrefix(rule.pattern);
|
|
479
577
|
if (!prefix) continue;
|
|
480
|
-
if (await pathExists(
|
|
578
|
+
if (await pathExists(join3(repositoryRoot, prefix))) continue;
|
|
481
579
|
suggestions.push({
|
|
482
580
|
id: `stale_policy:${rule.id}`,
|
|
483
581
|
category: "stale_policy",
|
|
@@ -521,7 +619,7 @@ function isTestableCode(path) {
|
|
|
521
619
|
}
|
|
522
620
|
async function hasSiblingTest(repositoryRoot, path) {
|
|
523
621
|
for (const candidate of coveringTestCandidates(path)) {
|
|
524
|
-
if (await pathExists(
|
|
622
|
+
if (await pathExists(join3(repositoryRoot, candidate))) return true;
|
|
525
623
|
}
|
|
526
624
|
return false;
|
|
527
625
|
}
|
|
@@ -570,6 +668,40 @@ function normalize(path) {
|
|
|
570
668
|
return path.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
571
669
|
}
|
|
572
670
|
|
|
671
|
+
// src/mcp/database-retry.ts
|
|
672
|
+
function isTransientDatabaseError(error) {
|
|
673
|
+
let current = error;
|
|
674
|
+
for (let depth = 0; depth < 4 && current && typeof current === "object"; depth++) {
|
|
675
|
+
const item = current;
|
|
676
|
+
if (typeof item.code === "string" && (/* @__PURE__ */ new Set([
|
|
677
|
+
"ECONNRESET",
|
|
678
|
+
"ECONNREFUSED",
|
|
679
|
+
"EPIPE",
|
|
680
|
+
"CONNECTION_CLOSED",
|
|
681
|
+
"CONNECTION_ENDED",
|
|
682
|
+
"08000",
|
|
683
|
+
"08001",
|
|
684
|
+
"08003",
|
|
685
|
+
"08006",
|
|
686
|
+
"57P01",
|
|
687
|
+
"57P02",
|
|
688
|
+
"57P03"
|
|
689
|
+
])).has(item.code))
|
|
690
|
+
return true;
|
|
691
|
+
current = item.cause;
|
|
692
|
+
}
|
|
693
|
+
return false;
|
|
694
|
+
}
|
|
695
|
+
async function withDatabaseRetry(operation, readOnly, delayMs = 250) {
|
|
696
|
+
try {
|
|
697
|
+
return await operation();
|
|
698
|
+
} catch (error) {
|
|
699
|
+
if (!readOnly || !isTransientDatabaseError(error)) throw error;
|
|
700
|
+
await new Promise((resolve5) => setTimeout(resolve5, delayMs));
|
|
701
|
+
return operation();
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
573
705
|
// src/mcp/tool-result.ts
|
|
574
706
|
function serializeToolResult(value, format = process.env.CODEBUDDY_RESPONSE_FORMAT ?? "both") {
|
|
575
707
|
if (format !== "text" && format !== "both") {
|
|
@@ -615,7 +747,7 @@ var recallSchema = {
|
|
|
615
747
|
budget: z.number().int().positive().optional(),
|
|
616
748
|
callerModel: z.string().min(1).max(200).optional(),
|
|
617
749
|
conflictMode: z.enum(["all", "latest", "highest_confidence"]).optional(),
|
|
618
|
-
/**
|
|
750
|
+
/** Default true: a flat list of memories (id, content, date). false = full provenance + stats. */
|
|
619
751
|
compact: z.boolean().optional()
|
|
620
752
|
};
|
|
621
753
|
var shareSchema = {
|
|
@@ -752,6 +884,30 @@ var FILE_TOOLS = Object.keys(mcpToolInputSchemas).filter(
|
|
|
752
884
|
(name) => !DATABASE_TOOLS.includes(name)
|
|
753
885
|
);
|
|
754
886
|
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.";
|
|
887
|
+
var LEAN_TOOLS = {
|
|
888
|
+
context_pack: {
|
|
889
|
+
description: "Find the files, symbols and line ranges for a coding task. Call only when the injected CodeBuddy block names no files.",
|
|
890
|
+
defaults: { tokenBudget: 800 },
|
|
891
|
+
inputSchema: {
|
|
892
|
+
task: z.string(),
|
|
893
|
+
paths: z.array(z.string()).optional(),
|
|
894
|
+
sessionId: z.string().optional(),
|
|
895
|
+
ack: z.string().optional()
|
|
896
|
+
}
|
|
897
|
+
},
|
|
898
|
+
recall: {
|
|
899
|
+
description: "Recall stored project memory (conventions, decisions, gotchas) for a question.",
|
|
900
|
+
inputSchema: { query: z.string() },
|
|
901
|
+
defaults: { sessionId: "agent" }
|
|
902
|
+
},
|
|
903
|
+
remember: {
|
|
904
|
+
description: "Store one durable project fact (convention, decision, gotcha).",
|
|
905
|
+
inputSchema: { content: z.string() },
|
|
906
|
+
// A fact is Markdown-backed and survives reindex; the full profile's
|
|
907
|
+
// default (`interaction`) is a database-only conversation record.
|
|
908
|
+
defaults: { type: "fact" }
|
|
909
|
+
}
|
|
910
|
+
};
|
|
755
911
|
var CORE_TOOLS = [
|
|
756
912
|
"context_pack",
|
|
757
913
|
"context_bootstrap",
|
|
@@ -761,9 +917,9 @@ var CORE_TOOLS = [
|
|
|
761
917
|
"health"
|
|
762
918
|
];
|
|
763
919
|
function resolveToolProfile(value = process.env.CODEBUDDY_TOOL_PROFILE) {
|
|
764
|
-
if (value === void 0 || value === "" || value === "
|
|
765
|
-
if (value === "core") return
|
|
766
|
-
throw new Error(`CODEBUDDY_TOOL_PROFILE must be "core" or "full", got "${value}"`);
|
|
920
|
+
if (value === void 0 || value === "" || value === "lean") return "lean";
|
|
921
|
+
if (value === "core" || value === "full") return value;
|
|
922
|
+
throw new Error(`CODEBUDDY_TOOL_PROFILE must be "lean", "core" or "full", got "${value}"`);
|
|
767
923
|
}
|
|
768
924
|
var PLAN_BODY_LIMIT = 8e3;
|
|
769
925
|
function serializePlan(plan) {
|
|
@@ -774,7 +930,7 @@ function serializePlan(plan) {
|
|
|
774
930
|
return { plan: { ...plan, body } };
|
|
775
931
|
}
|
|
776
932
|
function registerCodeBuddyTools(server, options, profile = "full") {
|
|
777
|
-
const exposed = (name) => profile === "full" || CORE_TOOLS.includes(name);
|
|
933
|
+
const exposed = (name) => profile === "full" || (profile === "lean" ? name in LEAN_TOOLS : CORE_TOOLS.includes(name));
|
|
778
934
|
const config = "database" in options ? options.config : options.memory.config;
|
|
779
935
|
const traceRoot = config.projectRoot ?? process.cwd();
|
|
780
936
|
const register = (name, toolConfig, callback) => {
|
|
@@ -799,7 +955,29 @@ function registerCodeBuddyTools(server, options, profile = "full") {
|
|
|
799
955
|
throw error;
|
|
800
956
|
}
|
|
801
957
|
});
|
|
802
|
-
const
|
|
958
|
+
const lean = profile === "lean" ? LEAN_TOOLS[name] : void 0;
|
|
959
|
+
const full = mcpToolInputSchemas[name];
|
|
960
|
+
const tool = lean ? server.registerTool(
|
|
961
|
+
name,
|
|
962
|
+
{
|
|
963
|
+
...toolConfig,
|
|
964
|
+
description: lean.description,
|
|
965
|
+
inputSchema: lean.inputSchema
|
|
966
|
+
},
|
|
967
|
+
// The lean schema only lists fields; the full schema enforces limits.
|
|
968
|
+
(async (input, extra) => {
|
|
969
|
+
const parsed = full.safeParse({ ...lean.defaults, ...input });
|
|
970
|
+
if (!parsed.success) {
|
|
971
|
+
return {
|
|
972
|
+
content: [
|
|
973
|
+
{ type: "text", text: `Invalid input: ${parsed.error.message}` }
|
|
974
|
+
],
|
|
975
|
+
isError: true
|
|
976
|
+
};
|
|
977
|
+
}
|
|
978
|
+
return traced(parsed.data, extra);
|
|
979
|
+
})
|
|
980
|
+
) : server.registerTool(name, toolConfig, traced);
|
|
803
981
|
if (!exposed(name)) tool.remove();
|
|
804
982
|
return tool;
|
|
805
983
|
};
|
|
@@ -815,7 +993,25 @@ function registerCodeBuddyTools(server, options, profile = "full") {
|
|
|
815
993
|
isError: true
|
|
816
994
|
};
|
|
817
995
|
}
|
|
818
|
-
|
|
996
|
+
try {
|
|
997
|
+
return json(
|
|
998
|
+
await withDatabaseRetry(
|
|
999
|
+
() => run(db),
|
|
1000
|
+
["recall", "list_facts", "list_namespaces"].includes(tool)
|
|
1001
|
+
)
|
|
1002
|
+
);
|
|
1003
|
+
} catch (error) {
|
|
1004
|
+
if (!isTransientDatabaseError(error)) throw error;
|
|
1005
|
+
return {
|
|
1006
|
+
...json({
|
|
1007
|
+
degraded: true,
|
|
1008
|
+
tool,
|
|
1009
|
+
database: { ...database.status(), available: false, state: "unavailable" },
|
|
1010
|
+
fallback: "The database connection failed during this operation. A write may have committed; verify state before repeating it. File-based context remains available."
|
|
1011
|
+
}),
|
|
1012
|
+
isError: true
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
819
1015
|
};
|
|
820
1016
|
const namespace = config.namespace;
|
|
821
1017
|
const projectRoot = config.projectRoot ?? process.cwd();
|
|
@@ -864,12 +1060,12 @@ function registerCodeBuddyTools(server, options, profile = "full") {
|
|
|
864
1060
|
"recall",
|
|
865
1061
|
{
|
|
866
1062
|
title: "Recall",
|
|
867
|
-
description: "Recall
|
|
1063
|
+
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.",
|
|
868
1064
|
inputSchema: mcpToolInputSchemas.recall.shape
|
|
869
1065
|
},
|
|
870
1066
|
async (input) => viaDatabase(
|
|
871
1067
|
"recall",
|
|
872
|
-
async (db) => withResponseTokens(await db.memory.recall(toRecallInput(input))
|
|
1068
|
+
async (db) => input.compact === false ? withResponseTokens(await db.memory.recall(toRecallInput(input))) : compactRecall(await db.memory.recall(toRecallInput(input)))
|
|
873
1069
|
)
|
|
874
1070
|
);
|
|
875
1071
|
register(
|
|
@@ -1132,24 +1328,35 @@ function registerCodeBuddyTools(server, options, profile = "full") {
|
|
|
1132
1328
|
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.",
|
|
1133
1329
|
inputSchema: mcpToolInputSchemas.context_pack.shape
|
|
1134
1330
|
},
|
|
1135
|
-
async (input) =>
|
|
1136
|
-
await
|
|
1137
|
-
projectRoot,
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
})
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1331
|
+
async (input) => {
|
|
1332
|
+
const context = await buildBeforeEditContext({
|
|
1333
|
+
repositoryRoot: projectRoot,
|
|
1334
|
+
namespace,
|
|
1335
|
+
task: input.task,
|
|
1336
|
+
semanticRanker: rankContextFacts,
|
|
1337
|
+
...await rerankerOption(),
|
|
1338
|
+
...input.evidence ? { evidence: input.evidence } : {},
|
|
1339
|
+
...input.paths !== void 0 ? { paths: input.paths } : {},
|
|
1340
|
+
...input.planId !== void 0 ? { planId: input.planId } : {},
|
|
1341
|
+
...input.useGit !== void 0 ? { useGit: input.useGit } : {},
|
|
1342
|
+
tokenBudget: input.tokenBudget ?? tokenBudget ?? 4e3
|
|
1343
|
+
});
|
|
1344
|
+
const reuse = await loadFreshIndex(projectRoot).then(
|
|
1345
|
+
async ({ manifest }) => findReuse(
|
|
1346
|
+
projectRoot,
|
|
1347
|
+
input.task,
|
|
1348
|
+
manifest,
|
|
1349
|
+
await loadProjectArchitectureMap(projectRoot, manifest)
|
|
1350
|
+
)
|
|
1351
|
+
).catch(() => []);
|
|
1352
|
+
return json(
|
|
1353
|
+
await applySessionDelivery(
|
|
1354
|
+
projectRoot,
|
|
1355
|
+
enforceContextBudget({ ...context, ...reuse.length > 0 ? { reuse } : {} }),
|
|
1356
|
+
deliveryOptions(input)
|
|
1357
|
+
)
|
|
1358
|
+
);
|
|
1359
|
+
}
|
|
1153
1360
|
);
|
|
1154
1361
|
register(
|
|
1155
1362
|
"context_after_turn",
|
|
@@ -1243,21 +1450,17 @@ function toRecallInput(input) {
|
|
|
1243
1450
|
const { compact: _compact, ...rest } = input;
|
|
1244
1451
|
return cleanOptional(rest);
|
|
1245
1452
|
}
|
|
1246
|
-
function
|
|
1247
|
-
const
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
} : {
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
content: message.content
|
|
1258
|
-
})),
|
|
1259
|
-
stats
|
|
1260
|
-
} : { ...result, stats };
|
|
1453
|
+
function compactRecall(result) {
|
|
1454
|
+
const memories = result.messages.map((message) => ({
|
|
1455
|
+
...message.fact ? { id: message.fact.id } : {},
|
|
1456
|
+
content: message.content,
|
|
1457
|
+
...message.fact?.createdAt ? { date: message.fact.createdAt.slice(0, 10) } : {}
|
|
1458
|
+
}));
|
|
1459
|
+
return memories.length > 0 ? { memories } : { memories, note: "nothing relevant" };
|
|
1460
|
+
}
|
|
1461
|
+
function withResponseTokens(result) {
|
|
1462
|
+
const stats = { ...result.stats };
|
|
1463
|
+
const value = { ...result, stats };
|
|
1261
1464
|
for (let pass = 0; pass < 2; pass++) {
|
|
1262
1465
|
const serialized = serializeToolResult(value);
|
|
1263
1466
|
stats.responseTokens = estimateTokens(serialized.content[0]?.text);
|
|
@@ -1276,7 +1479,7 @@ import pino from "pino";
|
|
|
1276
1479
|
|
|
1277
1480
|
// src/automation/project-sync.ts
|
|
1278
1481
|
import { watch as fsWatch2 } from "fs";
|
|
1279
|
-
import { join as
|
|
1482
|
+
import { join as join4, relative, resolve as resolve3, sep } from "path";
|
|
1280
1483
|
|
|
1281
1484
|
// src/indexer/watch.ts
|
|
1282
1485
|
import { watch as fsWatch } from "fs";
|
|
@@ -1457,7 +1660,7 @@ function startProjectSync(options) {
|
|
|
1457
1660
|
300
|
|
1458
1661
|
);
|
|
1459
1662
|
memoryWatcher = fsWatch2(
|
|
1460
|
-
|
|
1663
|
+
join4(repositoryRoot, ".codebuddy", "memory"),
|
|
1461
1664
|
{ recursive: true },
|
|
1462
1665
|
(_event, filename) => {
|
|
1463
1666
|
const name = filename?.replace(/\\/g, "/") ?? "";
|
|
@@ -1660,7 +1863,7 @@ async function startMcpServer(options = {}) {
|
|
|
1660
1863
|
};
|
|
1661
1864
|
let stopping;
|
|
1662
1865
|
const stop = () => {
|
|
1663
|
-
stopping
|
|
1866
|
+
if (!stopping) stopping = shutdown().finally(() => process.exit(0));
|
|
1664
1867
|
};
|
|
1665
1868
|
process.once("SIGINT", stop);
|
|
1666
1869
|
process.once("SIGTERM", stop);
|
|
@@ -1767,9 +1970,11 @@ export {
|
|
|
1767
1970
|
TELEMETRY_NOTICE,
|
|
1768
1971
|
showTelemetryNoticeOnce,
|
|
1769
1972
|
flushTelemetry,
|
|
1973
|
+
traceCliCommand,
|
|
1974
|
+
findReuse,
|
|
1770
1975
|
generateSuggestions,
|
|
1771
1976
|
mcpToolInputSchemas,
|
|
1772
1977
|
registerCodeBuddyTools,
|
|
1773
1978
|
startMcpServer
|
|
1774
1979
|
};
|
|
1775
|
-
//# sourceMappingURL=chunk-
|
|
1980
|
+
//# sourceMappingURL=chunk-YJPCS2GP.js.map
|