@orquentra/codebuddy 2.6.2 → 2.8.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/README.md +10 -0
- package/dist/adapters-S4HHTWJW.js +24 -0
- package/dist/{chunk-IBLJOHJL.js → chunk-3QGW53GD.js} +2 -2
- package/dist/{chunk-IMFUYEZA.js → chunk-6DONJW3W.js} +232 -64
- package/dist/chunk-6DONJW3W.js.map +1 -0
- package/dist/{chunk-JFDRBPYF.js → chunk-6JCKMIQY.js} +2 -2
- package/dist/{chunk-S6VEG4S2.js → chunk-6KGYAFG7.js} +28 -5
- package/dist/chunk-6KGYAFG7.js.map +1 -0
- package/dist/{chunk-OWWCDRXW.js → chunk-6NZEZJYD.js} +9 -7
- package/dist/chunk-6NZEZJYD.js.map +1 -0
- package/dist/{chunk-GDJH7XJC.js → chunk-AL6VBTNA.js} +77 -3
- package/dist/chunk-AL6VBTNA.js.map +1 -0
- package/dist/{chunk-XBJQKCLU.js → chunk-CAEPHLHC.js} +13 -9
- package/dist/chunk-CAEPHLHC.js.map +1 -0
- package/dist/chunk-CG5B3LYG.js +66 -0
- package/dist/chunk-CG5B3LYG.js.map +1 -0
- package/dist/{chunk-IHQM2ZDV.js → chunk-DFV2SK6C.js} +1 -1
- package/dist/{chunk-IHQM2ZDV.js.map → chunk-DFV2SK6C.js.map} +1 -1
- package/dist/{chunk-QBDJXGG5.js → chunk-EJQVGFH2.js} +93 -22
- package/dist/chunk-EJQVGFH2.js.map +1 -0
- package/dist/{chunk-5MQOE4J6.js → chunk-ESZXCZIN.js} +3 -3
- package/dist/{chunk-J2EAZ4MA.js → chunk-GKNYMNFM.js} +22 -25
- package/dist/chunk-GKNYMNFM.js.map +1 -0
- package/dist/{chunk-5FW3PMNP.js → chunk-GXOML4UZ.js} +76 -11
- package/dist/chunk-GXOML4UZ.js.map +1 -0
- package/dist/{chunk-JPHJBCZB.js → chunk-HPOR6YXA.js} +3 -2
- package/dist/chunk-HPOR6YXA.js.map +1 -0
- package/dist/chunk-ITQO632W.js +673 -0
- package/dist/chunk-ITQO632W.js.map +1 -0
- package/dist/chunk-J4T6HHI4.js +1444 -0
- package/dist/chunk-J4T6HHI4.js.map +1 -0
- package/dist/{chunk-5KZY6OTG.js → chunk-KNR2P2UY.js} +33 -83
- package/dist/chunk-KNR2P2UY.js.map +1 -0
- package/dist/{chunk-2XDPKFUW.js → chunk-NY2YXP3R.js} +46 -20
- package/dist/chunk-NY2YXP3R.js.map +1 -0
- package/dist/{chunk-RAJJSCIP.js → chunk-SFMIMLXR.js} +2 -2
- package/dist/chunk-TGFTKWOR.js +16 -0
- package/dist/chunk-TGFTKWOR.js.map +1 -0
- package/dist/{chunk-NERKZSSE.js → chunk-TLWGZVPC.js} +395 -686
- package/dist/chunk-TLWGZVPC.js.map +1 -0
- package/dist/{chunk-B6CO63SQ.js → chunk-UK6XTS2Y.js} +24 -10
- package/dist/chunk-UK6XTS2Y.js.map +1 -0
- package/dist/chunk-W7GAXL6C.js +104 -0
- package/dist/chunk-W7GAXL6C.js.map +1 -0
- package/dist/chunk-XL2HLACE.js +55 -0
- package/dist/chunk-XL2HLACE.js.map +1 -0
- package/dist/chunk-Y7D7PUBE.js +321 -0
- package/dist/chunk-Y7D7PUBE.js.map +1 -0
- package/dist/{chunk-R7CD6EXS.js → chunk-ZNLSCV3J.js} +578 -381
- package/dist/chunk-ZNLSCV3J.js.map +1 -0
- package/dist/cli/index.js +5 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/{cloud-7WM3YLI4.js → cloud-LXZUR3U2.js} +3 -3
- package/dist/{codebuddy-B_pCaQrV.d.ts → codebuddy-DO7ZhoWn.d.ts} +15 -1
- package/dist/config-GEZFLXK6.js +12 -0
- package/dist/index.d.ts +46 -3
- package/dist/index.js +23 -19
- package/dist/install-BXM56QCD.js +19 -0
- package/dist/langgraph/index.d.ts +1 -1
- package/dist/lean-command-7DFW32MA.js +19 -0
- package/dist/{local-5MZURLCZ.js → local-ST4WMRCG.js} +3 -3
- package/dist/{main-MTBQZGJV.js → main-QUASSFP7.js} +987 -1741
- package/dist/main-QUASSFP7.js.map +1 -0
- package/dist/{memory-KIC5FJVW.js → memory-TGHVTBME.js} +9 -8
- package/dist/memory-TGHVTBME.js.map +1 -0
- package/dist/operations-WJR7AZZF.js +26 -0
- package/dist/pretool-command-JTKX6G3M.js +13 -0
- package/dist/{rerank-5QZ3PNUW.js → rerank-IQAEWLQR.js} +6 -5
- package/dist/rerank-IQAEWLQR.js.map +1 -0
- package/dist/{runtime-CUBOOPZO.js → runtime-OQQ22VJF.js} +15 -11
- package/dist/summaries-ML53R7EL.js +21 -0
- package/dist/summaries-ML53R7EL.js.map +1 -0
- package/dist/{zvec-MSRKT7IV.js → zvec-XDZNZ2OL.js} +11 -3
- package/dist/zvec-XDZNZ2OL.js.map +1 -0
- package/package.json +1 -1
- package/src/db/migrations/0006_fact_idempotency_key.sql +2 -0
- package/src/db/migrations/meta/0006_snapshot.json +1258 -0
- package/src/db/migrations/meta/_journal.json +7 -0
- package/dist/chunk-2XDPKFUW.js.map +0 -1
- package/dist/chunk-5FW3PMNP.js.map +0 -1
- package/dist/chunk-5KZY6OTG.js.map +0 -1
- package/dist/chunk-B6CO63SQ.js.map +0 -1
- package/dist/chunk-GDJH7XJC.js.map +0 -1
- package/dist/chunk-IMFUYEZA.js.map +0 -1
- package/dist/chunk-J2EAZ4MA.js.map +0 -1
- package/dist/chunk-JPHJBCZB.js.map +0 -1
- package/dist/chunk-NERKZSSE.js.map +0 -1
- package/dist/chunk-OWWCDRXW.js.map +0 -1
- package/dist/chunk-PQK3GKZH.js +0 -98
- package/dist/chunk-PQK3GKZH.js.map +0 -1
- package/dist/chunk-QBDJXGG5.js.map +0 -1
- package/dist/chunk-R7CD6EXS.js.map +0 -1
- package/dist/chunk-S6VEG4S2.js.map +0 -1
- package/dist/chunk-XBJQKCLU.js.map +0 -1
- package/dist/config-DEVHUDIU.js +0 -11
- package/dist/lean-command-HTQCPH76.js +0 -15
- package/dist/main-MTBQZGJV.js.map +0 -1
- package/dist/memory-KIC5FJVW.js.map +0 -1
- package/dist/operations-POCHY3WR.js +0 -25
- package/dist/pretool-command-AX6JXP25.js +0 -10
- package/dist/rerank-5QZ3PNUW.js.map +0 -1
- package/dist/summaries-SB5L2TSW.js +0 -18
- /package/dist/{cloud-7WM3YLI4.js.map → adapters-S4HHTWJW.js.map} +0 -0
- /package/dist/{chunk-IBLJOHJL.js.map → chunk-3QGW53GD.js.map} +0 -0
- /package/dist/{chunk-JFDRBPYF.js.map → chunk-6JCKMIQY.js.map} +0 -0
- /package/dist/{chunk-5MQOE4J6.js.map → chunk-ESZXCZIN.js.map} +0 -0
- /package/dist/{chunk-RAJJSCIP.js.map → chunk-SFMIMLXR.js.map} +0 -0
- /package/dist/{config-DEVHUDIU.js.map → cloud-LXZUR3U2.js.map} +0 -0
- /package/dist/{lean-command-HTQCPH76.js.map → config-GEZFLXK6.js.map} +0 -0
- /package/dist/{local-5MZURLCZ.js.map → install-BXM56QCD.js.map} +0 -0
- /package/dist/{operations-POCHY3WR.js.map → lean-command-7DFW32MA.js.map} +0 -0
- /package/dist/{pretool-command-AX6JXP25.js.map → local-ST4WMRCG.js.map} +0 -0
- /package/dist/{runtime-CUBOOPZO.js.map → operations-WJR7AZZF.js.map} +0 -0
- /package/dist/{summaries-SB5L2TSW.js.map → pretool-command-JTKX6G3M.js.map} +0 -0
- /package/dist/{zvec-MSRKT7IV.js.map → runtime-OQQ22VJF.js.map} +0 -0
package/README.md
CHANGED
|
@@ -52,6 +52,15 @@ This opens a live local page showing:
|
|
|
52
52
|
|
|
53
53
|
It updates as you work, and the traces never leave your machine.
|
|
54
54
|
|
|
55
|
+
## Telemetry
|
|
56
|
+
|
|
57
|
+
CodeBuddy sends anonymous usage counts (tool names, timings, success, version,
|
|
58
|
+
OS, agent client) so we can see which features are used. Prompts, code, file
|
|
59
|
+
paths and repository names are never sent, and nothing is sent until a notice
|
|
60
|
+
has been shown once in your terminal. Opt out with `codebuddy telemetry disable`,
|
|
61
|
+
`CODEBUDDY_TELEMETRY=0` or `DO_NOT_TRACK=1`; CI never sends. Details:
|
|
62
|
+
[docs/telemetry.md](https://github.com/Orquentra-Inc/CodeBuddy/blob/main/docs/telemetry.md).
|
|
63
|
+
|
|
55
64
|
## Try it without a database
|
|
56
65
|
|
|
57
66
|
```bash
|
|
@@ -66,6 +75,7 @@ needs more detail. Inspect missing or truncated evidence before editing.
|
|
|
66
75
|
## Documentation
|
|
67
76
|
|
|
68
77
|
- [Full guide and examples](https://github.com/Orquentra-Inc/CodeBuddy/blob/348bb7c/README.md)
|
|
78
|
+
- [Telemetry and the admin panel](https://github.com/Orquentra-Inc/CodeBuddy/blob/main/docs/telemetry.md)
|
|
69
79
|
- [Token budgets](https://github.com/Orquentra-Inc/CodeBuddy/blob/main/docs/token-budgets.md)
|
|
70
80
|
- [Optional LLM setup](https://github.com/Orquentra-Inc/CodeBuddy/blob/main/docs/llm-byok.md)
|
|
71
81
|
- [Source and issues](https://github.com/Orquentra-Inc/CodeBuddy)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AUTOMATION_MODES,
|
|
3
|
+
CLIENT_ADAPTERS,
|
|
4
|
+
CLIENT_IDS,
|
|
5
|
+
LIFECYCLE_EVENTS,
|
|
6
|
+
MODE_LABELS,
|
|
7
|
+
parseClient,
|
|
8
|
+
parseMode,
|
|
9
|
+
sharedRulesReaders,
|
|
10
|
+
supportedModes
|
|
11
|
+
} from "./chunk-W7GAXL6C.js";
|
|
12
|
+
import "./chunk-PZ5AY32C.js";
|
|
13
|
+
export {
|
|
14
|
+
AUTOMATION_MODES,
|
|
15
|
+
CLIENT_ADAPTERS,
|
|
16
|
+
CLIENT_IDS,
|
|
17
|
+
LIFECYCLE_EVENTS,
|
|
18
|
+
MODE_LABELS,
|
|
19
|
+
parseClient,
|
|
20
|
+
parseMode,
|
|
21
|
+
sharedRulesReaders,
|
|
22
|
+
supportedModes
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=adapters-S4HHTWJW.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
LOCAL_EMBEDDING_MODEL
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-HPOR6YXA.js";
|
|
4
4
|
|
|
5
5
|
// src/providers/local.ts
|
|
6
6
|
import { homedir } from "os";
|
|
@@ -101,4 +101,4 @@ export {
|
|
|
101
101
|
LocalModelProvider,
|
|
102
102
|
rerankLocally
|
|
103
103
|
};
|
|
104
|
-
//# sourceMappingURL=chunk-
|
|
104
|
+
//# sourceMappingURL=chunk-3QGW53GD.js.map
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
refreshZvecIndex
|
|
3
|
+
} from "./chunk-GXOML4UZ.js";
|
|
1
4
|
import {
|
|
2
5
|
PlanFileStore,
|
|
3
6
|
PlanLifecycle,
|
|
@@ -9,43 +12,46 @@ import {
|
|
|
9
12
|
enforceContextBudget,
|
|
10
13
|
llmMemoryOptions,
|
|
11
14
|
readPolicyFile,
|
|
12
|
-
recordTrace,
|
|
13
15
|
resolveRiskPaths
|
|
14
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-ZNLSCV3J.js";
|
|
15
17
|
import {
|
|
16
18
|
SessionCapsuleLedger,
|
|
19
|
+
coveringTestCandidates,
|
|
17
20
|
estimateTokens
|
|
18
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-GKNYMNFM.js";
|
|
19
22
|
import {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
loadArchitectureMap,
|
|
24
|
-
loadFreshIndex,
|
|
25
|
-
neighbours,
|
|
26
|
-
queryMap
|
|
27
|
-
} from "./chunk-NERKZSSE.js";
|
|
23
|
+
readTraces,
|
|
24
|
+
recordTrace
|
|
25
|
+
} from "./chunk-XL2HLACE.js";
|
|
28
26
|
import {
|
|
29
27
|
codeBuddyConfigSchema,
|
|
30
28
|
createRuntime,
|
|
31
29
|
listFactsPage
|
|
32
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-NY2YXP3R.js";
|
|
33
31
|
import {
|
|
34
32
|
MemoryFileStore,
|
|
35
33
|
VERSION
|
|
36
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-6KGYAFG7.js";
|
|
37
35
|
import {
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
generateGraphifyGraph,
|
|
37
|
+
loadProjectArchitectureMap
|
|
38
|
+
} from "./chunk-TLWGZVPC.js";
|
|
40
39
|
import {
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
buildArchitectureMap,
|
|
41
|
+
indexRepository,
|
|
42
|
+
loadFreshIndex,
|
|
43
|
+
neighbours,
|
|
44
|
+
queryMap
|
|
45
|
+
} from "./chunk-ITQO632W.js";
|
|
46
|
+
import {
|
|
47
|
+
redactPersisted
|
|
48
|
+
} from "./chunk-AL6VBTNA.js";
|
|
43
49
|
import {
|
|
44
50
|
configPath,
|
|
45
51
|
loadPlanPolicy,
|
|
46
52
|
loadRuntimeConfig,
|
|
47
53
|
redactSecrets
|
|
48
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-KNR2P2UY.js";
|
|
49
55
|
|
|
50
56
|
// src/core/migrate-to-files.ts
|
|
51
57
|
import { createHash } from "crypto";
|
|
@@ -164,11 +170,138 @@ function checksum(content) {
|
|
|
164
170
|
return createHash("sha256").update(content).digest("hex");
|
|
165
171
|
}
|
|
166
172
|
|
|
173
|
+
// src/telemetry/telemetry.ts
|
|
174
|
+
import { createHash as createHash2, randomUUID } from "crypto";
|
|
175
|
+
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
176
|
+
import { homedir } from "os";
|
|
177
|
+
import { dirname, join } from "path";
|
|
178
|
+
var TELEMETRY_URL = "https://tanmay-hp-linux-server.tail41864f.ts.net/v1/events";
|
|
179
|
+
var FLUSH_INTERVAL_MS = 10 * 6e4;
|
|
180
|
+
var MAX_EVENTS = 500;
|
|
181
|
+
var SEND_TIMEOUT_MS = 3e3;
|
|
182
|
+
var NAME = /^[A-Za-z][A-Za-z0-9_:.-]{0,63}$/;
|
|
183
|
+
function telemetryStatePath(home = homedir()) {
|
|
184
|
+
return join(home, ".codebuddy", "telemetry.json");
|
|
185
|
+
}
|
|
186
|
+
async function readTelemetryState(home = homedir()) {
|
|
187
|
+
try {
|
|
188
|
+
const state = JSON.parse(await readFile(telemetryStatePath(home), "utf8"));
|
|
189
|
+
if (typeof state.installId === "string" && state.installId) return state;
|
|
190
|
+
} catch {
|
|
191
|
+
}
|
|
192
|
+
return writeTelemetryState({ installId: randomUUID() }, home);
|
|
193
|
+
}
|
|
194
|
+
async function writeTelemetryState(state, home = homedir()) {
|
|
195
|
+
const path = telemetryStatePath(home);
|
|
196
|
+
await mkdir(dirname(path), { recursive: true, mode: 448 });
|
|
197
|
+
await writeFile(path, `${JSON.stringify(state, null, 2)}
|
|
198
|
+
`, { mode: 384 });
|
|
199
|
+
return state;
|
|
200
|
+
}
|
|
201
|
+
function telemetryBlocked(state, env = process.env) {
|
|
202
|
+
if (env.CODEBUDDY_TELEMETRY === "0") return "CODEBUDDY_TELEMETRY=0";
|
|
203
|
+
if (env.DO_NOT_TRACK === "1" || env.DO_NOT_TRACK === "true") return "DO_NOT_TRACK";
|
|
204
|
+
if (env.CI) return "CI";
|
|
205
|
+
if (state.disabled) return "disabled with `codebuddy telemetry disable`";
|
|
206
|
+
if (!telemetryUrl(env)) return "no collector configured";
|
|
207
|
+
if (!state.noticeAt) return "first-run notice not shown yet";
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
function telemetryUrl(env = process.env) {
|
|
211
|
+
return env.CODEBUDDY_TELEMETRY_URL ?? TELEMETRY_URL;
|
|
212
|
+
}
|
|
213
|
+
var TELEMETRY_NOTICE = `CodeBuddy collects anonymous usage data (which tools run, how long they take,
|
|
214
|
+
success/failure, version, OS, agent client) to improve the product.
|
|
215
|
+
Prompts, code, file paths and repository names are never sent.
|
|
216
|
+
Opt out any time: \`codebuddy telemetry disable\` or CODEBUDDY_TELEMETRY=0.
|
|
217
|
+
Details: https://github.com/Orquentra-Inc/CodeBuddy/blob/main/docs/telemetry.md`;
|
|
218
|
+
async function showTelemetryNoticeOnce(write = (text) => process.stderr.write(text), options = {}) {
|
|
219
|
+
const env = options.env ?? process.env;
|
|
220
|
+
if (!(options.tty ?? process.stderr.isTTY)) return;
|
|
221
|
+
try {
|
|
222
|
+
const state = await readTelemetryState(options.home);
|
|
223
|
+
if (state.noticeAt || state.disabled || env.CODEBUDDY_TELEMETRY === "0" || env.CI) return;
|
|
224
|
+
if (!telemetryUrl(env)) return;
|
|
225
|
+
write(`
|
|
226
|
+
${TELEMETRY_NOTICE}
|
|
227
|
+
|
|
228
|
+
`);
|
|
229
|
+
await writeTelemetryState({ ...state, noticeAt: (/* @__PURE__ */ new Date()).toISOString() }, options.home);
|
|
230
|
+
} catch {
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
function anonymize(installId, value) {
|
|
234
|
+
return createHash2("sha256").update(`${installId}\0${value}`).digest("hex").slice(0, 16);
|
|
235
|
+
}
|
|
236
|
+
function toTelemetryEvents(installId, traces) {
|
|
237
|
+
return traces.map((trace) => ({
|
|
238
|
+
ts: trace.ts,
|
|
239
|
+
kind: NAME.test(trace.kind) ? trace.kind : "other",
|
|
240
|
+
name: NAME.test(trace.name) ? trace.name : "other",
|
|
241
|
+
ms: Math.max(0, Math.round(trace.ms) || 0),
|
|
242
|
+
ok: trace.ok === true,
|
|
243
|
+
...typeof trace.tokensIn === "number" ? { tokensIn: trace.tokensIn } : {},
|
|
244
|
+
...typeof trace.tokensOut === "number" ? { tokensOut: trace.tokensOut } : {},
|
|
245
|
+
...trace.session ? { session: anonymize(installId, trace.session) } : {}
|
|
246
|
+
}));
|
|
247
|
+
}
|
|
248
|
+
async function flushTelemetry(repositoryRoot, options = {}) {
|
|
249
|
+
const env = options.env ?? process.env;
|
|
250
|
+
const now = options.now ?? Date.now();
|
|
251
|
+
try {
|
|
252
|
+
const state = await readTelemetryState(options.home);
|
|
253
|
+
if (telemetryBlocked(state, env)) return 0;
|
|
254
|
+
const cursorPath = join(repositoryRoot, ".codebuddy", "cache", "telemetry.json");
|
|
255
|
+
const cursor = await readFile(cursorPath, "utf8").then((raw) => JSON.parse(raw)).catch(() => ({}));
|
|
256
|
+
if (cursor.flushedAt && now - cursor.flushedAt < FLUSH_INTERVAL_MS) return 0;
|
|
257
|
+
const save = (next) => mkdir(dirname(cursorPath), { recursive: true }).then(
|
|
258
|
+
() => writeFile(cursorPath, JSON.stringify(next))
|
|
259
|
+
);
|
|
260
|
+
await save({ ...cursor, flushedAt: now });
|
|
261
|
+
const pending = (await readTraces(repositoryRoot, 1e4)).filter((trace) => !cursor.sentTs || trace.ts > cursor.sentTs).slice(-MAX_EVENTS);
|
|
262
|
+
const last = pending.at(-1);
|
|
263
|
+
if (!last) return 0;
|
|
264
|
+
const batch = {
|
|
265
|
+
installId: state.installId,
|
|
266
|
+
project: anonymize(state.installId, repositoryRoot),
|
|
267
|
+
version: VERSION,
|
|
268
|
+
platform: process.platform,
|
|
269
|
+
arch: process.arch,
|
|
270
|
+
node: process.versions.node.split(".")[0] ?? "",
|
|
271
|
+
clients: await (options.clients ?? (() => installedClients(repositoryRoot)))().catch(
|
|
272
|
+
() => []
|
|
273
|
+
),
|
|
274
|
+
events: toTelemetryEvents(state.installId, pending)
|
|
275
|
+
};
|
|
276
|
+
const response = await (options.fetchImpl ?? fetch)(telemetryUrl(env), {
|
|
277
|
+
method: "POST",
|
|
278
|
+
headers: { "content-type": "application/json" },
|
|
279
|
+
body: JSON.stringify(batch),
|
|
280
|
+
signal: AbortSignal.timeout(SEND_TIMEOUT_MS)
|
|
281
|
+
});
|
|
282
|
+
if (!response.ok) return 0;
|
|
283
|
+
await save({ sentTs: last.ts, flushedAt: now });
|
|
284
|
+
return batch.events.length;
|
|
285
|
+
} catch {
|
|
286
|
+
return 0;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
async function installedClients(repositoryRoot) {
|
|
290
|
+
const { CLIENT_IDS } = await import("./adapters-S4HHTWJW.js");
|
|
291
|
+
const { detectClient } = await import("./install-BXM56QCD.js");
|
|
292
|
+
const found = [];
|
|
293
|
+
for (const id of CLIENT_IDS) {
|
|
294
|
+
const status = await detectClient(id, repositoryRoot).catch(() => null);
|
|
295
|
+
if (status && (status.hooks || status.mcp)) found.push(id);
|
|
296
|
+
}
|
|
297
|
+
return found;
|
|
298
|
+
}
|
|
299
|
+
|
|
167
300
|
// src/mcp/tools/index.ts
|
|
168
301
|
import { z } from "zod";
|
|
169
302
|
|
|
170
303
|
// src/context/delivery.ts
|
|
171
|
-
import { createHash as
|
|
304
|
+
import { createHash as createHash3 } from "crypto";
|
|
172
305
|
var DELIVERY_VERSION = 1;
|
|
173
306
|
var OMITTABLE_SECTIONS = [
|
|
174
307
|
"plan",
|
|
@@ -187,7 +320,7 @@ async function applySessionDelivery(repositoryRoot, payload, options) {
|
|
|
187
320
|
if (!options.sessionId) return output;
|
|
188
321
|
const sections = OMITTABLE_SECTIONS.filter((key) => output[key] !== void 0).map((key) => ({
|
|
189
322
|
key: `mcp:${key}`,
|
|
190
|
-
hash:
|
|
323
|
+
hash: createHash3("sha256").update(JSON.stringify(output[key])).digest("hex")
|
|
191
324
|
}));
|
|
192
325
|
try {
|
|
193
326
|
await new SessionCapsuleLedger(repositoryRoot).exchange(options.sessionId, sections, {
|
|
@@ -214,7 +347,7 @@ async function applySessionDelivery(repositoryRoot, payload, options) {
|
|
|
214
347
|
output = enforceContextBudget(output);
|
|
215
348
|
return OMITTABLE_SECTIONS.filter((key) => output[key] !== void 0).map((key) => ({
|
|
216
349
|
key: `mcp:${key}`,
|
|
217
|
-
hash:
|
|
350
|
+
hash: createHash3("sha256").update(JSON.stringify(output[key])).digest("hex")
|
|
218
351
|
}));
|
|
219
352
|
}
|
|
220
353
|
});
|
|
@@ -227,7 +360,7 @@ async function applySessionDelivery(repositoryRoot, payload, options) {
|
|
|
227
360
|
// src/suggest/engine.ts
|
|
228
361
|
import { constants } from "fs";
|
|
229
362
|
import { access } from "fs/promises";
|
|
230
|
-
import { extname, join, resolve } from "path";
|
|
363
|
+
import { extname, join as join2, resolve } from "path";
|
|
231
364
|
|
|
232
365
|
// src/suggest/types.ts
|
|
233
366
|
var SEVERITY_RANK = {
|
|
@@ -241,7 +374,7 @@ var SEVERITY_RANK = {
|
|
|
241
374
|
var RISK_SUGGEST_THRESHOLD = 50;
|
|
242
375
|
var BLAST_RADIUS_MEDIUM = 5;
|
|
243
376
|
var BLAST_RADIUS_HIGH = 10;
|
|
244
|
-
var CODE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
377
|
+
var CODE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py"]);
|
|
245
378
|
async function generateSuggestions(input) {
|
|
246
379
|
const repositoryRoot = resolve(input.repositoryRoot ?? process.cwd());
|
|
247
380
|
const namespace = input.namespace;
|
|
@@ -264,7 +397,7 @@ async function generateSuggestions(input) {
|
|
|
264
397
|
resolveRelevantPlan(planStore, namespace, input.planId),
|
|
265
398
|
memoryStore.findIncidentFactsForPaths({ namespace, paths: targetPaths }),
|
|
266
399
|
buildArchitectureMap(repositoryRoot),
|
|
267
|
-
readPolicyFile(
|
|
400
|
+
readPolicyFile(join2(repositoryRoot, ".codebuddy", "policies.yaml"))
|
|
268
401
|
]);
|
|
269
402
|
const suggestions = [];
|
|
270
403
|
for (const item of risks.items) {
|
|
@@ -338,13 +471,13 @@ async function generateSuggestions(input) {
|
|
|
338
471
|
title: `No test found for ${path}`,
|
|
339
472
|
detail: "Consider adding a test alongside this change.",
|
|
340
473
|
path,
|
|
341
|
-
evidence: [{ kind: "no_test", detail: "no
|
|
474
|
+
evidence: [{ kind: "no_test", detail: "no conventional test file found" }]
|
|
342
475
|
});
|
|
343
476
|
}
|
|
344
477
|
for (const rule of policyFile.rules) {
|
|
345
478
|
const prefix = literalPrefix(rule.pattern);
|
|
346
479
|
if (!prefix) continue;
|
|
347
|
-
if (await pathExists(
|
|
480
|
+
if (await pathExists(join2(repositoryRoot, prefix))) continue;
|
|
348
481
|
suggestions.push({
|
|
349
482
|
id: `stale_policy:${rule.id}`,
|
|
350
483
|
category: "stale_policy",
|
|
@@ -381,21 +514,14 @@ function isTestableCode(path) {
|
|
|
381
514
|
if (/\.(test|spec)\.[cm]?[jt]sx?$/.test(path)) return false;
|
|
382
515
|
if (path.endsWith(".d.ts")) return false;
|
|
383
516
|
if (path.includes("__tests__/")) return false;
|
|
517
|
+
if (/(^|\/)(test_[^/]*|[^/]*_test|conftest|__init__)\.py$|(^|\/)tests?\/.*\.py$/.test(path)) {
|
|
518
|
+
return false;
|
|
519
|
+
}
|
|
384
520
|
return CODE_EXTENSIONS.has(extname(path).toLowerCase());
|
|
385
521
|
}
|
|
386
522
|
async function hasSiblingTest(repositoryRoot, path) {
|
|
387
|
-
const
|
|
388
|
-
|
|
389
|
-
const dir = base.includes("/") ? base.slice(0, base.lastIndexOf("/")) : "";
|
|
390
|
-
const name = base.includes("/") ? base.slice(base.lastIndexOf("/") + 1) : base;
|
|
391
|
-
const candidates = [
|
|
392
|
-
`${base}.test${ext}`,
|
|
393
|
-
`${base}.spec${ext}`,
|
|
394
|
-
`${dir ? `${dir}/` : ""}__tests__/${name}${ext}`,
|
|
395
|
-
`${dir ? `${dir}/` : ""}__tests__/${name}.test${ext}`
|
|
396
|
-
];
|
|
397
|
-
for (const candidate of candidates) {
|
|
398
|
-
if (await pathExists(join(repositoryRoot, candidate))) return true;
|
|
523
|
+
for (const candidate of coveringTestCandidates(path)) {
|
|
524
|
+
if (await pathExists(join2(repositoryRoot, candidate))) return true;
|
|
399
525
|
}
|
|
400
526
|
return false;
|
|
401
527
|
}
|
|
@@ -466,26 +592,31 @@ var INPUT_LIMITS = {
|
|
|
466
592
|
arrayItems: 100,
|
|
467
593
|
pathChars: 1024,
|
|
468
594
|
taskChars: 2e3,
|
|
469
|
-
agentIdChars: 200
|
|
595
|
+
agentIdChars: 200,
|
|
596
|
+
/** Entity ids and list cursors are short; a megabyte one is never valid. */
|
|
597
|
+
idChars: 512
|
|
470
598
|
};
|
|
471
599
|
var deliverySchema = {
|
|
472
600
|
sessionId: z.string().min(1).max(200).optional(),
|
|
473
601
|
ack: z.string().regex(/^dlv_[a-z0-9]+$/).optional(),
|
|
474
602
|
full: z.boolean().optional()
|
|
475
603
|
};
|
|
604
|
+
var pgText = (max) => z.string().min(1).max(max).refine((value) => !value.includes("\0"), "must not contain NUL bytes");
|
|
476
605
|
var rememberSchema = {
|
|
477
|
-
sessionId:
|
|
478
|
-
content:
|
|
606
|
+
sessionId: pgText(200).optional(),
|
|
607
|
+
content: pgText(INPUT_LIMITS.contentChars),
|
|
479
608
|
type: z.enum(["interaction", "fact", "summary"]).optional(),
|
|
480
|
-
idempotencyKey:
|
|
481
|
-
agentId:
|
|
609
|
+
idempotencyKey: pgText(200).optional(),
|
|
610
|
+
agentId: pgText(INPUT_LIMITS.agentIdChars).optional()
|
|
482
611
|
};
|
|
483
612
|
var recallSchema = {
|
|
484
|
-
sessionId:
|
|
485
|
-
query:
|
|
613
|
+
sessionId: pgText(200),
|
|
614
|
+
query: pgText(INPUT_LIMITS.taskChars),
|
|
486
615
|
budget: z.number().int().positive().optional(),
|
|
487
616
|
callerModel: z.string().min(1).max(200).optional(),
|
|
488
|
-
conflictMode: z.enum(["all", "latest", "highest_confidence"]).optional()
|
|
617
|
+
conflictMode: z.enum(["all", "latest", "highest_confidence"]).optional(),
|
|
618
|
+
/** Return only system, message id + content and core stats (no provenance). */
|
|
619
|
+
compact: z.boolean().optional()
|
|
489
620
|
};
|
|
490
621
|
var shareSchema = {
|
|
491
622
|
from: z.string().min(1).max(INPUT_LIMITS.agentIdChars).optional(),
|
|
@@ -521,15 +652,17 @@ var planPatchSchema = {
|
|
|
521
652
|
};
|
|
522
653
|
var mcpToolInputSchemas = {
|
|
523
654
|
remember: z.object(rememberSchema),
|
|
524
|
-
remember_batch: z.object({
|
|
655
|
+
remember_batch: z.object({
|
|
656
|
+
items: z.array(z.object(rememberSchema)).min(1).max(INPUT_LIMITS.batchItems)
|
|
657
|
+
}),
|
|
525
658
|
recall: z.object(recallSchema),
|
|
526
659
|
list_facts: z.object({
|
|
527
|
-
subject: z.string().optional(),
|
|
660
|
+
subject: z.string().max(INPUT_LIMITS.titleChars).optional(),
|
|
528
661
|
limit: z.number().int().positive().max(100).default(50),
|
|
529
|
-
cursor: z.string().optional()
|
|
662
|
+
cursor: z.string().max(INPUT_LIMITS.idChars).optional()
|
|
530
663
|
}),
|
|
531
664
|
list_namespaces: z.object({}),
|
|
532
|
-
forget: z.object({ id: z.string().min(1) }),
|
|
665
|
+
forget: z.object({ id: z.string().min(1).max(INPUT_LIMITS.idChars) }),
|
|
533
666
|
share: z.object(shareSchema),
|
|
534
667
|
unshare: z.object(unshareSchema),
|
|
535
668
|
plan_current: z.object({}),
|
|
@@ -731,10 +864,13 @@ function registerCodeBuddyTools(server, options, profile = "full") {
|
|
|
731
864
|
"recall",
|
|
732
865
|
{
|
|
733
866
|
title: "Recall",
|
|
734
|
-
description: "Recall prompt-ready CodeBuddy context.",
|
|
867
|
+
description: "Recall prompt-ready CodeBuddy context. `budget` bounds message content (stats.tokensUsed); stats.responseTokens counts the whole JSON text returned (provenance and stats included) and stats.transportTokens the full tool result, which also repeats it as structuredContent. Pass compact=true for only message id + content.",
|
|
735
868
|
inputSchema: mcpToolInputSchemas.recall.shape
|
|
736
869
|
},
|
|
737
|
-
async (input) => viaDatabase(
|
|
870
|
+
async (input) => viaDatabase(
|
|
871
|
+
"recall",
|
|
872
|
+
async (db) => withResponseTokens(await db.memory.recall(toRecallInput(input)), input.compact === true)
|
|
873
|
+
)
|
|
738
874
|
);
|
|
739
875
|
register(
|
|
740
876
|
"list_facts",
|
|
@@ -939,12 +1075,10 @@ function registerCodeBuddyTools(server, options, profile = "full") {
|
|
|
939
1075
|
async (input) => json(neighbours(await cachedMap(), input.module, input.direction))
|
|
940
1076
|
);
|
|
941
1077
|
const tokenBudget = config.tokenBudget;
|
|
942
|
-
const cachedMap = async () =>
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
return buildArchitectureMap(projectRoot);
|
|
947
|
-
};
|
|
1078
|
+
const cachedMap = async () => loadProjectArchitectureMap(
|
|
1079
|
+
projectRoot,
|
|
1080
|
+
loadFreshIndex(projectRoot).then(({ manifest }) => manifest)
|
|
1081
|
+
);
|
|
948
1082
|
register(
|
|
949
1083
|
"context_bootstrap",
|
|
950
1084
|
{
|
|
@@ -1106,7 +1240,30 @@ function toRememberInput(input) {
|
|
|
1106
1240
|
return cleanOptional(input);
|
|
1107
1241
|
}
|
|
1108
1242
|
function toRecallInput(input) {
|
|
1109
|
-
|
|
1243
|
+
const { compact: _compact, ...rest } = input;
|
|
1244
|
+
return cleanOptional(rest);
|
|
1245
|
+
}
|
|
1246
|
+
function withResponseTokens(result, compact) {
|
|
1247
|
+
const stats = compact ? {
|
|
1248
|
+
tokensUsed: result.stats.tokensUsed,
|
|
1249
|
+
itemsIncluded: result.stats.itemsIncluded,
|
|
1250
|
+
itemsSkipped: result.stats.itemsSkipped,
|
|
1251
|
+
...result.stats.budgetStatus ? { budgetStatus: result.stats.budgetStatus } : {}
|
|
1252
|
+
} : { ...result.stats };
|
|
1253
|
+
const value = compact ? {
|
|
1254
|
+
system: result.system,
|
|
1255
|
+
messages: result.messages.map((message) => ({
|
|
1256
|
+
...message.fact ? { id: message.fact.id } : {},
|
|
1257
|
+
content: message.content
|
|
1258
|
+
})),
|
|
1259
|
+
stats
|
|
1260
|
+
} : { ...result, stats };
|
|
1261
|
+
for (let pass = 0; pass < 2; pass++) {
|
|
1262
|
+
const serialized = serializeToolResult(value);
|
|
1263
|
+
stats.responseTokens = estimateTokens(serialized.content[0]?.text);
|
|
1264
|
+
stats.transportTokens = estimateTokens(serialized);
|
|
1265
|
+
}
|
|
1266
|
+
return value;
|
|
1110
1267
|
}
|
|
1111
1268
|
function cleanOptional(input) {
|
|
1112
1269
|
return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== void 0));
|
|
@@ -1119,7 +1276,7 @@ import pino from "pino";
|
|
|
1119
1276
|
|
|
1120
1277
|
// src/automation/project-sync.ts
|
|
1121
1278
|
import { watch as fsWatch2 } from "fs";
|
|
1122
|
-
import { join as
|
|
1279
|
+
import { join as join3, relative, resolve as resolve3, sep } from "path";
|
|
1123
1280
|
|
|
1124
1281
|
// src/indexer/watch.ts
|
|
1125
1282
|
import { watch as fsWatch } from "fs";
|
|
@@ -1300,7 +1457,7 @@ function startProjectSync(options) {
|
|
|
1300
1457
|
300
|
|
1301
1458
|
);
|
|
1302
1459
|
memoryWatcher = fsWatch2(
|
|
1303
|
-
|
|
1460
|
+
join3(repositoryRoot, ".codebuddy", "memory"),
|
|
1304
1461
|
{ recursive: true },
|
|
1305
1462
|
(_event, filename) => {
|
|
1306
1463
|
const name = filename?.replace(/\\/g, "/") ?? "";
|
|
@@ -1334,7 +1491,7 @@ function startProjectSync(options) {
|
|
|
1334
1491
|
|
|
1335
1492
|
// src/core/project-root.ts
|
|
1336
1493
|
import { realpath, stat } from "fs/promises";
|
|
1337
|
-
import { homedir } from "os";
|
|
1494
|
+
import { homedir as homedir2 } from "os";
|
|
1338
1495
|
import { isAbsolute, parse, resolve as resolve4 } from "path";
|
|
1339
1496
|
async function resolveInitializedProjectRoot(configuredRoot, cwd = process.cwd()) {
|
|
1340
1497
|
if (configuredRoot !== void 0 && !isAbsolute(configuredRoot)) {
|
|
@@ -1342,7 +1499,7 @@ async function resolveInitializedProjectRoot(configuredRoot, cwd = process.cwd()
|
|
|
1342
1499
|
}
|
|
1343
1500
|
const selected = resolve4(configuredRoot ?? cwd);
|
|
1344
1501
|
const root = await realpath(selected);
|
|
1345
|
-
if (root === parse(root).root || root === await realpath(
|
|
1502
|
+
if (root === parse(root).root || root === await realpath(homedir2())) {
|
|
1346
1503
|
throw new Error(
|
|
1347
1504
|
"Select an initialized project folder, not the filesystem root or home folder."
|
|
1348
1505
|
);
|
|
@@ -1492,8 +1649,11 @@ async function startMcpServer(options = {}) {
|
|
|
1492
1649
|
});
|
|
1493
1650
|
const server = new McpServer({ name: "codebuddy", version: VERSION });
|
|
1494
1651
|
registerCodeBuddyTools(server, { config, database }, toolProfile);
|
|
1652
|
+
const telemetry = setInterval(() => void flushTelemetry(projectRoot), 6e4);
|
|
1653
|
+
telemetry.unref();
|
|
1495
1654
|
const shutdown = async () => {
|
|
1496
1655
|
logger.info("codebuddy MCP server shutting down");
|
|
1656
|
+
clearInterval(telemetry);
|
|
1497
1657
|
await server.close();
|
|
1498
1658
|
await sync.close();
|
|
1499
1659
|
await database.close();
|
|
@@ -1599,9 +1759,17 @@ function isConnectionRefused(error) {
|
|
|
1599
1759
|
export {
|
|
1600
1760
|
migrateMemoryToFiles,
|
|
1601
1761
|
watchRepository,
|
|
1762
|
+
telemetryStatePath,
|
|
1763
|
+
readTelemetryState,
|
|
1764
|
+
writeTelemetryState,
|
|
1765
|
+
telemetryBlocked,
|
|
1766
|
+
telemetryUrl,
|
|
1767
|
+
TELEMETRY_NOTICE,
|
|
1768
|
+
showTelemetryNoticeOnce,
|
|
1769
|
+
flushTelemetry,
|
|
1602
1770
|
generateSuggestions,
|
|
1603
1771
|
mcpToolInputSchemas,
|
|
1604
1772
|
registerCodeBuddyTools,
|
|
1605
1773
|
startMcpServer
|
|
1606
1774
|
};
|
|
1607
|
-
//# sourceMappingURL=chunk-
|
|
1775
|
+
//# sourceMappingURL=chunk-6DONJW3W.js.map
|