@orquentra/codebuddy 0.0.0-stage → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +269 -0
- package/CLAUDE_CODEX.md +433 -0
- package/LICENSE +21 -0
- package/README.md +55 -2
- package/WORKFLOW.md +152 -0
- package/dist/chunk-3ZELDCR3.js +204 -0
- package/dist/chunk-3ZELDCR3.js.map +1 -0
- package/dist/chunk-5OWZVZSO.js +476 -0
- package/dist/chunk-5OWZVZSO.js.map +1 -0
- package/dist/chunk-DSN5CEHO.js +175 -0
- package/dist/chunk-DSN5CEHO.js.map +1 -0
- package/dist/chunk-GDJH7XJC.js +119 -0
- package/dist/chunk-GDJH7XJC.js.map +1 -0
- package/dist/chunk-IBMJYIEP.js +1578 -0
- package/dist/chunk-IBMJYIEP.js.map +1 -0
- package/dist/chunk-IE2OUO54.js +199 -0
- package/dist/chunk-IE2OUO54.js.map +1 -0
- package/dist/chunk-IHQM2ZDV.js +19 -0
- package/dist/chunk-IHQM2ZDV.js.map +1 -0
- package/dist/chunk-ITGRANYW.js +63 -0
- package/dist/chunk-ITGRANYW.js.map +1 -0
- package/dist/chunk-K63EOA4B.js +416 -0
- package/dist/chunk-K63EOA4B.js.map +1 -0
- package/dist/chunk-OLFCOR4U.js +8580 -0
- package/dist/chunk-OLFCOR4U.js.map +1 -0
- package/dist/chunk-PQK3GKZH.js +98 -0
- package/dist/chunk-PQK3GKZH.js.map +1 -0
- package/dist/chunk-PYLH4MH5.js +34 -0
- package/dist/chunk-PYLH4MH5.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/chunk-PZ5AY32C.js.map +1 -0
- package/dist/chunk-TI5TQD6D.js +324 -0
- package/dist/chunk-TI5TQD6D.js.map +1 -0
- package/dist/chunk-WHZSVY2L.js +144 -0
- package/dist/chunk-WHZSVY2L.js.map +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +15 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/codebuddy-D2xJ6hFk.d.ts +841 -0
- package/dist/config-S2TULOMK.js +11 -0
- package/dist/config-S2TULOMK.js.map +1 -0
- package/dist/index.d.ts +2527 -0
- package/dist/index.js +116 -0
- package/dist/index.js.map +1 -0
- package/dist/langgraph/index.d.ts +53 -0
- package/dist/langgraph/index.js +143 -0
- package/dist/langgraph/index.js.map +1 -0
- package/dist/lean-command-D6TZJEFX.js +13 -0
- package/dist/lean-command-D6TZJEFX.js.map +1 -0
- package/dist/main-BFDVQHKO.js +4575 -0
- package/dist/main-BFDVQHKO.js.map +1 -0
- package/dist/memory-NIBFAMY4.js +57 -0
- package/dist/memory-NIBFAMY4.js.map +1 -0
- package/dist/pretool-command-MQQ2UNQM.js +10 -0
- package/dist/pretool-command-MQQ2UNQM.js.map +1 -0
- package/dist/rerank-Q7MIFNKA.js +60 -0
- package/dist/rerank-Q7MIFNKA.js.map +1 -0
- package/dist/summaries-TSE44KUQ.js +18 -0
- package/dist/summaries-TSE44KUQ.js.map +1 -0
- package/dist/zvec-F27AR357.js +23 -0
- package/dist/zvec-F27AR357.js.map +1 -0
- package/docker-compose.yml +20 -0
- package/examples/claude-code/README.md +67 -0
- package/examples/claude-desktop/README.md +54 -0
- package/examples/claude-desktop/claude_desktop_config.json +13 -0
- package/examples/langgraph-agent/README.md +32 -0
- package/examples/langgraph-agent/index.ts +71 -0
- package/examples/multi-agent-handoff/README.md +35 -0
- package/examples/multi-agent-handoff/index.ts +68 -0
- package/package.json +108 -4
- package/src/db/migrations/0000_cultured_satana.sql +144 -0
- package/src/db/migrations/0001_embedding_lease.sql +3 -0
- package/src/db/migrations/0002_embedding_lease_token.sql +1 -0
- package/src/db/migrations/0003_embedding_space.sql +9 -0
- package/src/db/migrations/0004_markdown_reconcile.sql +5 -0
- package/src/db/migrations/0005_fact_propositions.sql +1 -0
- package/src/db/migrations/meta/0000_snapshot.json +1169 -0
- package/src/db/migrations/meta/0002_snapshot.json +1181 -0
- package/src/db/migrations/meta/0003_snapshot.json +1214 -0
- package/src/db/migrations/meta/0004_snapshot.json +1225 -0
- package/src/db/migrations/meta/0005_snapshot.json +1231 -0
- package/src/db/migrations/meta/_journal.json +48 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import {
|
|
2
|
+
memoryCandidateSchema
|
|
3
|
+
} from "./chunk-IHQM2ZDV.js";
|
|
4
|
+
import {
|
|
5
|
+
chatJson
|
|
6
|
+
} from "./chunk-IE2OUO54.js";
|
|
7
|
+
import {
|
|
8
|
+
redactSensitive
|
|
9
|
+
} from "./chunk-GDJH7XJC.js";
|
|
10
|
+
import {
|
|
11
|
+
resolveLlmConfig
|
|
12
|
+
} from "./chunk-ITGRANYW.js";
|
|
13
|
+
import "./chunk-K63EOA4B.js";
|
|
14
|
+
import "./chunk-PZ5AY32C.js";
|
|
15
|
+
|
|
16
|
+
// src/llm/memory.ts
|
|
17
|
+
import { z } from "zod";
|
|
18
|
+
var TIMEOUT_MS = 2e4;
|
|
19
|
+
var schema = z.object({ candidates: z.array(memoryCandidateSchema).max(10) });
|
|
20
|
+
var SYSTEM = [
|
|
21
|
+
"You turn the summary of one coding turn into durable project memory.",
|
|
22
|
+
'Answer with JSON only: {"candidates":[{"class":"fact|decision|incident|note|ignored","content":"...","subject":"...","predicate":"...","object":"...","confidence":0.0,"paths":["..."],"severity":null}]}.',
|
|
23
|
+
"Keep only what will still be true and useful in a later session: decisions, confirmed bugs and their causes, project facts.",
|
|
24
|
+
"Use only paths named in the input. Confidence below 0.7 for anything uncertain. Chatter is class ignored.",
|
|
25
|
+
"Never include secrets."
|
|
26
|
+
].join(" ");
|
|
27
|
+
function createLlmMemoryExtractor(root, config) {
|
|
28
|
+
return {
|
|
29
|
+
async extract(input) {
|
|
30
|
+
const result = await chatJson(config, {
|
|
31
|
+
system: SYSTEM,
|
|
32
|
+
user: JSON.stringify({
|
|
33
|
+
summary: redactSensitive(input.summary),
|
|
34
|
+
changedFiles: (input.changedFiles ?? []).map(redactSensitive),
|
|
35
|
+
verification: (input.verification ?? []).map(redactSensitive)
|
|
36
|
+
}),
|
|
37
|
+
schema,
|
|
38
|
+
maxTokens: 800,
|
|
39
|
+
deadlineMs: TIMEOUT_MS,
|
|
40
|
+
purpose: "background",
|
|
41
|
+
repositoryRoot: root
|
|
42
|
+
});
|
|
43
|
+
if (!result.ok) throw new Error(`llm memory extraction: ${result.reason}`);
|
|
44
|
+
return result.value.candidates;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async function llmCaptureOptions(root, env = process.env) {
|
|
49
|
+
const config = await resolveLlmConfig(root, env);
|
|
50
|
+
if (!config.enabled || !config.features.memory) return {};
|
|
51
|
+
return { extractor: createLlmMemoryExtractor(root, config), retries: 0 };
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
createLlmMemoryExtractor,
|
|
55
|
+
llmCaptureOptions
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=memory-NIBFAMY4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/llm/memory.ts"],"sourcesContent":["import { z } from \"zod\";\nimport type { MemoryExtractor } from \"../memory-extract/llm.js\";\nimport { redactSensitive } from \"../memory-extract/sensitive.js\";\nimport { type ExtractionInput, memoryCandidateSchema } from \"../memory-extract/types.js\";\nimport { chatJson } from \"./client.js\";\nimport { type EnabledLlmConfig, resolveLlmConfig } from \"./config.js\";\n\n/**\n * Optional BYOK memory extraction through the existing `MemoryExtractor`\n * seam. Output must match `memoryCandidateSchema` and then passes the same\n * gate as deterministic candidates (sensitive scan, confidence, review);\n * any failure falls back to deterministic extraction.\n */\nconst TIMEOUT_MS = 20_000;\nconst schema = z.object({ candidates: z.array(memoryCandidateSchema).max(10) });\n\nconst SYSTEM = [\n \"You turn the summary of one coding turn into durable project memory.\",\n 'Answer with JSON only: {\"candidates\":[{\"class\":\"fact|decision|incident|note|ignored\",\"content\":\"...\",\"subject\":\"...\",\"predicate\":\"...\",\"object\":\"...\",\"confidence\":0.0,\"paths\":[\"...\"],\"severity\":null}]}.',\n \"Keep only what will still be true and useful in a later session: decisions, confirmed bugs and their causes, project facts.\",\n \"Use only paths named in the input. Confidence below 0.7 for anything uncertain. Chatter is class ignored.\",\n \"Never include secrets.\",\n].join(\" \");\n\nexport function createLlmMemoryExtractor(root: string, config: EnabledLlmConfig): MemoryExtractor {\n return {\n async extract(input: ExtractionInput) {\n const result = await chatJson(config, {\n system: SYSTEM,\n user: JSON.stringify({\n summary: redactSensitive(input.summary),\n changedFiles: (input.changedFiles ?? []).map(redactSensitive),\n verification: (input.verification ?? []).map(redactSensitive),\n }),\n schema,\n maxTokens: 800,\n deadlineMs: TIMEOUT_MS,\n purpose: \"background\",\n repositoryRoot: root,\n });\n if (!result.ok) throw new Error(`llm memory extraction: ${result.reason}`);\n return result.value.candidates;\n },\n };\n}\n\n/** Extra `captureAfterTurn` options when the memory feature is on: one attempt, then deterministic. */\nexport async function llmCaptureOptions(\n root: string,\n env: NodeJS.ProcessEnv = process.env,\n): Promise<{ extractor?: MemoryExtractor; retries?: number }> {\n const config = await resolveLlmConfig(root, env);\n if (!config.enabled || !config.features.memory) return {};\n return { extractor: createLlmMemoryExtractor(root, config), retries: 0 };\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAAA,SAAS,SAAS;AAalB,IAAM,aAAa;AACnB,IAAM,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,EAAE,IAAI,EAAE,EAAE,CAAC;AAE9E,IAAM,SAAS;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,GAAG;AAEH,SAAS,yBAAyB,MAAc,QAA2C;AAChG,SAAO;AAAA,IACL,MAAM,QAAQ,OAAwB;AACpC,YAAM,SAAS,MAAM,SAAS,QAAQ;AAAA,QACpC,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU;AAAA,UACnB,SAAS,gBAAgB,MAAM,OAAO;AAAA,UACtC,eAAe,MAAM,gBAAgB,CAAC,GAAG,IAAI,eAAe;AAAA,UAC5D,eAAe,MAAM,gBAAgB,CAAC,GAAG,IAAI,eAAe;AAAA,QAC9D,CAAC;AAAA,QACD;AAAA,QACA,WAAW;AAAA,QACX,YAAY;AAAA,QACZ,SAAS;AAAA,QACT,gBAAgB;AAAA,MAClB,CAAC;AACD,UAAI,CAAC,OAAO,GAAI,OAAM,IAAI,MAAM,0BAA0B,OAAO,MAAM,EAAE;AACzE,aAAO,OAAO,MAAM;AAAA,IACtB;AAAA,EACF;AACF;AAGA,eAAsB,kBACpB,MACA,MAAyB,QAAQ,KAC2B;AAC5D,QAAM,SAAS,MAAM,iBAAiB,MAAM,GAAG;AAC/C,MAAI,CAAC,OAAO,WAAW,CAAC,OAAO,SAAS,OAAQ,QAAO,CAAC;AACxD,SAAO,EAAE,WAAW,yBAAyB,MAAM,MAAM,GAAG,SAAS,EAAE;AACzE;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {
|
|
2
|
+
chatJson
|
|
3
|
+
} from "./chunk-IE2OUO54.js";
|
|
4
|
+
import {
|
|
5
|
+
redactSensitive
|
|
6
|
+
} from "./chunk-GDJH7XJC.js";
|
|
7
|
+
import "./chunk-ITGRANYW.js";
|
|
8
|
+
import "./chunk-K63EOA4B.js";
|
|
9
|
+
import "./chunk-PZ5AY32C.js";
|
|
10
|
+
|
|
11
|
+
// src/llm/rerank.ts
|
|
12
|
+
import { createHash } from "crypto";
|
|
13
|
+
import { z } from "zod";
|
|
14
|
+
var RERANK_PROMPT_VERSION = 1;
|
|
15
|
+
var LIMITS = { candidates: 15, picks: 3, signatures: 5, reason: 80, maxTokens: 300 };
|
|
16
|
+
var schema = z.object({
|
|
17
|
+
files: z.array(
|
|
18
|
+
z.object({
|
|
19
|
+
path: z.string(),
|
|
20
|
+
symbols: z.array(z.string()).default([]),
|
|
21
|
+
reason: z.string().default("")
|
|
22
|
+
})
|
|
23
|
+
).default([]),
|
|
24
|
+
abstain: z.boolean().default(false)
|
|
25
|
+
});
|
|
26
|
+
var SYSTEM = [
|
|
27
|
+
"You pick the source files a coding agent must open for a task.",
|
|
28
|
+
'Answer with JSON only: {"files":[{"path":"...","symbols":["..."],"reason":"..."}],"abstain":false}.',
|
|
29
|
+
`Choose at most ${LIMITS.picks} files, best first, only from the candidates given;`,
|
|
30
|
+
"name the functions or classes to look at when you can (from the listed signatures);",
|
|
31
|
+
"reason: a few words. If no candidate fits the task, answer with an empty files list and abstain true."
|
|
32
|
+
].join(" ");
|
|
33
|
+
async function rerankCandidates(root, config, task, candidates, deadlineMs) {
|
|
34
|
+
const sent = candidates.slice(0, LIMITS.candidates).map((candidate) => ({
|
|
35
|
+
path: candidate.path,
|
|
36
|
+
summary: redactSensitive(candidate.summary),
|
|
37
|
+
signatures: candidate.signatures.slice(0, LIMITS.signatures).map(redactSensitive)
|
|
38
|
+
}));
|
|
39
|
+
const user = JSON.stringify({ task: redactSensitive(task), candidates: sent });
|
|
40
|
+
const result = await chatJson(config, {
|
|
41
|
+
system: SYSTEM,
|
|
42
|
+
user,
|
|
43
|
+
schema,
|
|
44
|
+
maxTokens: LIMITS.maxTokens,
|
|
45
|
+
deadlineMs,
|
|
46
|
+
purpose: "prompt",
|
|
47
|
+
repositoryRoot: root,
|
|
48
|
+
cacheKey: createHash("sha256").update(`rerank:${RERANK_PROMPT_VERSION}:${user}`).digest("hex")
|
|
49
|
+
});
|
|
50
|
+
if (!result.ok) return result;
|
|
51
|
+
const allowed = new Set(sent.map((candidate) => candidate.path));
|
|
52
|
+
const seen = /* @__PURE__ */ new Set();
|
|
53
|
+
const files = result.value.files.filter((file) => allowed.has(file.path) && !seen.has(file.path) && seen.add(file.path)).slice(0, LIMITS.picks).map((file) => ({ ...file, reason: file.reason.slice(0, LIMITS.reason) }));
|
|
54
|
+
return { ...result, value: { files, abstain: result.value.abstain && files.length === 0 } };
|
|
55
|
+
}
|
|
56
|
+
export {
|
|
57
|
+
RERANK_PROMPT_VERSION,
|
|
58
|
+
rerankCandidates
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=rerank-Q7MIFNKA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/llm/rerank.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { z } from \"zod\";\nimport { redactSensitive } from \"../memory-extract/sensitive.js\";\nimport { chatJson, type LlmResult } from \"./client.js\";\nimport type { EnabledLlmConfig } from \"./config.js\";\n\n/**\n * Prompt-time rerank: the model sees the task and up to 15 candidate files\n * (path, one-line summary, a few signatures, never bodies) and picks at most\n * three, or abstains. The caller validates every pick against the candidates,\n * the symbol table and the evidence rules; this module only asks.\n */\nexport const RERANK_PROMPT_VERSION = 1;\nconst LIMITS = { candidates: 15, picks: 3, signatures: 5, reason: 80, maxTokens: 300 } as const;\n\nexport type RerankCandidate = { path: string; summary: string; signatures: string[] };\nexport type RerankPick = { path: string; symbols: string[]; reason: string };\n\nconst schema = z.object({\n files: z\n .array(\n z.object({\n path: z.string(),\n symbols: z.array(z.string()).default([]),\n reason: z.string().default(\"\"),\n }),\n )\n .default([]),\n abstain: z.boolean().default(false),\n});\n\nconst SYSTEM = [\n \"You pick the source files a coding agent must open for a task.\",\n 'Answer with JSON only: {\"files\":[{\"path\":\"...\",\"symbols\":[\"...\"],\"reason\":\"...\"}],\"abstain\":false}.',\n `Choose at most ${LIMITS.picks} files, best first, only from the candidates given;`,\n \"name the functions or classes to look at when you can (from the listed signatures);\",\n \"reason: a few words. If no candidate fits the task, answer with an empty files list and abstain true.\",\n].join(\" \");\n\nexport async function rerankCandidates(\n root: string,\n config: EnabledLlmConfig,\n task: string,\n candidates: RerankCandidate[],\n deadlineMs: number,\n): Promise<LlmResult<{ files: RerankPick[]; abstain: boolean }>> {\n const sent = candidates.slice(0, LIMITS.candidates).map((candidate) => ({\n path: candidate.path,\n summary: redactSensitive(candidate.summary),\n signatures: candidate.signatures.slice(0, LIMITS.signatures).map(redactSensitive),\n }));\n const user = JSON.stringify({ task: redactSensitive(task), candidates: sent });\n const result = await chatJson(config, {\n system: SYSTEM,\n user,\n schema,\n maxTokens: LIMITS.maxTokens,\n deadlineMs,\n purpose: \"prompt\",\n repositoryRoot: root,\n cacheKey: createHash(\"sha256\").update(`rerank:${RERANK_PROMPT_VERSION}:${user}`).digest(\"hex\"),\n });\n if (!result.ok) return result;\n const allowed = new Set(sent.map((candidate) => candidate.path));\n const seen = new Set<string>();\n const files = result.value.files\n .filter((file) => allowed.has(file.path) && !seen.has(file.path) && seen.add(file.path))\n .slice(0, LIMITS.picks)\n .map((file) => ({ ...file, reason: file.reason.slice(0, LIMITS.reason) }));\n return { ...result, value: { files, abstain: result.value.abstain && files.length === 0 } };\n}\n"],"mappings":";;;;;;;;;;;AAAA,SAAS,kBAAkB;AAC3B,SAAS,SAAS;AAWX,IAAM,wBAAwB;AACrC,IAAM,SAAS,EAAE,YAAY,IAAI,OAAO,GAAG,YAAY,GAAG,QAAQ,IAAI,WAAW,IAAI;AAKrF,IAAM,SAAS,EAAE,OAAO;AAAA,EACtB,OAAO,EACJ;AAAA,IACC,EAAE,OAAO;AAAA,MACP,MAAM,EAAE,OAAO;AAAA,MACf,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,MACvC,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE;AAAA,IAC/B,CAAC;AAAA,EACH,EACC,QAAQ,CAAC,CAAC;AAAA,EACb,SAAS,EAAE,QAAQ,EAAE,QAAQ,KAAK;AACpC,CAAC;AAED,IAAM,SAAS;AAAA,EACb;AAAA,EACA;AAAA,EACA,kBAAkB,OAAO,KAAK;AAAA,EAC9B;AAAA,EACA;AACF,EAAE,KAAK,GAAG;AAEV,eAAsB,iBACpB,MACA,QACA,MACA,YACA,YAC+D;AAC/D,QAAM,OAAO,WAAW,MAAM,GAAG,OAAO,UAAU,EAAE,IAAI,CAAC,eAAe;AAAA,IACtE,MAAM,UAAU;AAAA,IAChB,SAAS,gBAAgB,UAAU,OAAO;AAAA,IAC1C,YAAY,UAAU,WAAW,MAAM,GAAG,OAAO,UAAU,EAAE,IAAI,eAAe;AAAA,EAClF,EAAE;AACF,QAAM,OAAO,KAAK,UAAU,EAAE,MAAM,gBAAgB,IAAI,GAAG,YAAY,KAAK,CAAC;AAC7E,QAAM,SAAS,MAAM,SAAS,QAAQ;AAAA,IACpC,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA,WAAW,OAAO;AAAA,IAClB;AAAA,IACA,SAAS;AAAA,IACT,gBAAgB;AAAA,IAChB,UAAU,WAAW,QAAQ,EAAE,OAAO,UAAU,qBAAqB,IAAI,IAAI,EAAE,EAAE,OAAO,KAAK;AAAA,EAC/F,CAAC;AACD,MAAI,CAAC,OAAO,GAAI,QAAO;AACvB,QAAM,UAAU,IAAI,IAAI,KAAK,IAAI,CAAC,cAAc,UAAU,IAAI,CAAC;AAC/D,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,QAAQ,OAAO,MAAM,MACxB,OAAO,CAAC,SAAS,QAAQ,IAAI,KAAK,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,IAAI,CAAC,EACtF,MAAM,GAAG,OAAO,KAAK,EACrB,IAAI,CAAC,UAAU,EAAE,GAAG,MAAM,QAAQ,KAAK,OAAO,MAAM,GAAG,OAAO,MAAM,EAAE,EAAE;AAC3E,SAAO,EAAE,GAAG,QAAQ,OAAO,EAAE,OAAO,SAAS,OAAO,MAAM,WAAW,MAAM,WAAW,EAAE,EAAE;AAC5F;","names":[]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SUMMARY_PROMPT_VERSION,
|
|
3
|
+
loadLlmSummaries,
|
|
4
|
+
summarizeRepository
|
|
5
|
+
} from "./chunk-3ZELDCR3.js";
|
|
6
|
+
import "./chunk-IBMJYIEP.js";
|
|
7
|
+
import "./chunk-PQK3GKZH.js";
|
|
8
|
+
import "./chunk-IE2OUO54.js";
|
|
9
|
+
import "./chunk-GDJH7XJC.js";
|
|
10
|
+
import "./chunk-ITGRANYW.js";
|
|
11
|
+
import "./chunk-K63EOA4B.js";
|
|
12
|
+
import "./chunk-PZ5AY32C.js";
|
|
13
|
+
export {
|
|
14
|
+
SUMMARY_PROMPT_VERSION,
|
|
15
|
+
loadLlmSummaries,
|
|
16
|
+
summarizeRepository
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=summaries-TSE44KUQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_ZVEC_MODEL,
|
|
3
|
+
buildZvecIndex,
|
|
4
|
+
parseHits,
|
|
5
|
+
refreshZvecIndex,
|
|
6
|
+
resetZvecCache,
|
|
7
|
+
zvecCandidates,
|
|
8
|
+
zvecExcludeGlobs,
|
|
9
|
+
zvecStatus
|
|
10
|
+
} from "./chunk-TI5TQD6D.js";
|
|
11
|
+
import "./chunk-K63EOA4B.js";
|
|
12
|
+
import "./chunk-PZ5AY32C.js";
|
|
13
|
+
export {
|
|
14
|
+
DEFAULT_ZVEC_MODEL,
|
|
15
|
+
buildZvecIndex,
|
|
16
|
+
parseHits,
|
|
17
|
+
refreshZvecIndex,
|
|
18
|
+
resetZvecCache,
|
|
19
|
+
zvecCandidates,
|
|
20
|
+
zvecExcludeGlobs,
|
|
21
|
+
zvecStatus
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=zvec-F27AR357.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
services:
|
|
2
|
+
postgres:
|
|
3
|
+
image: pgvector/pgvector:pg16
|
|
4
|
+
container_name: codebuddy-postgres
|
|
5
|
+
environment:
|
|
6
|
+
POSTGRES_USER: codebuddy
|
|
7
|
+
POSTGRES_PASSWORD: codebuddy
|
|
8
|
+
POSTGRES_DB: codebuddy
|
|
9
|
+
ports:
|
|
10
|
+
- "5432:5432"
|
|
11
|
+
volumes:
|
|
12
|
+
- codebuddy-postgres-data:/var/lib/postgresql/data
|
|
13
|
+
healthcheck:
|
|
14
|
+
test: ["CMD-SHELL", "pg_isready -U codebuddy -d codebuddy"]
|
|
15
|
+
interval: 5s
|
|
16
|
+
timeout: 5s
|
|
17
|
+
retries: 10
|
|
18
|
+
|
|
19
|
+
volumes:
|
|
20
|
+
codebuddy-postgres-data:
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Claude Code MCP Example
|
|
2
|
+
|
|
3
|
+
Use CodeBuddy as a Claude Code memory server through MCP stdio.
|
|
4
|
+
|
|
5
|
+
## Local Package Development
|
|
6
|
+
|
|
7
|
+
From this repository:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install
|
|
11
|
+
npm run build
|
|
12
|
+
docker compose up -d
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Set your environment:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
export DATABASE_URL=postgres://codebuddy:codebuddy@localhost:5432/codebuddy
|
|
19
|
+
export HF_TOKEN=hf_your_token
|
|
20
|
+
export CODEBUDDY_NAMESPACE=claude-code
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Run a quick health check:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
node dist/cli/index.js doctor --skip-model-check
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Project MCP Config
|
|
30
|
+
|
|
31
|
+
Add a `.mcp.json` file to the project where you use Claude Code:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"mcpServers": {
|
|
36
|
+
"codebuddy": {
|
|
37
|
+
"command": "node",
|
|
38
|
+
"args": ["/absolute/path/to/codebuddy/dist/cli/index.js", "serve"],
|
|
39
|
+
"env": {
|
|
40
|
+
"DATABASE_URL": "postgres://codebuddy:codebuddy@localhost:5432/codebuddy",
|
|
41
|
+
"HF_TOKEN": "hf_your_token",
|
|
42
|
+
"CODEBUDDY_NAMESPACE": "claude-code"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
For an installed package, use:
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"mcpServers": {
|
|
54
|
+
"codebuddy": {
|
|
55
|
+
"command": "codebuddy",
|
|
56
|
+
"args": ["serve"],
|
|
57
|
+
"env": {
|
|
58
|
+
"DATABASE_URL": "postgres://codebuddy:codebuddy@localhost:5432/codebuddy",
|
|
59
|
+
"HF_TOKEN": "hf_your_token",
|
|
60
|
+
"CODEBUDDY_NAMESPACE": "claude-code"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Restart Claude Code after adding or changing MCP config. The available tools are `remember`, `remember_batch`, `recall`, `list_facts`, `list_namespaces`, `forget`, and `share`.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Claude Desktop MCP Example
|
|
2
|
+
|
|
3
|
+
This example runs CodeBuddy as an MCP stdio server for Claude Desktop.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
docker compose up -d
|
|
9
|
+
export DATABASE_URL=postgres://codebuddy:codebuddy@localhost:5432/codebuddy
|
|
10
|
+
export HF_TOKEN=hf_your_token
|
|
11
|
+
npm run build
|
|
12
|
+
node dist/cli/index.js init
|
|
13
|
+
node dist/cli/index.js doctor --skip-model-check
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Claude Desktop Config
|
|
17
|
+
|
|
18
|
+
Copy `claude_desktop_config.json` into your Claude Desktop MCP configuration location and replace `hf_replace_me` with your Hugging Face token.
|
|
19
|
+
|
|
20
|
+
The server command is:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx codebuddy serve
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
For local development from this repository, use:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"mcpServers": {
|
|
31
|
+
"codebuddy": {
|
|
32
|
+
"command": "node",
|
|
33
|
+
"args": ["/absolute/path/to/codebuddy/dist/cli/index.js", "serve"],
|
|
34
|
+
"env": {
|
|
35
|
+
"DATABASE_URL": "postgres://codebuddy:codebuddy@localhost:5432/codebuddy",
|
|
36
|
+
"HF_TOKEN": "hf_your_token",
|
|
37
|
+
"CODEBUDDY_NAMESPACE": "claude-desktop"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Available Tools
|
|
45
|
+
|
|
46
|
+
- `remember`
|
|
47
|
+
- `remember_batch`
|
|
48
|
+
- `recall`
|
|
49
|
+
- `list_facts`
|
|
50
|
+
- `list_namespaces`
|
|
51
|
+
- `forget`
|
|
52
|
+
- `share`
|
|
53
|
+
|
|
54
|
+
v0.1 intentionally ships MCP tools only over stdio. Resources, prompts, and HTTP transport are deferred.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mcpServers": {
|
|
3
|
+
"codebuddy": {
|
|
4
|
+
"command": "npx",
|
|
5
|
+
"args": ["codebuddy", "serve"],
|
|
6
|
+
"env": {
|
|
7
|
+
"DATABASE_URL": "postgres://codebuddy:codebuddy@localhost:5432/codebuddy",
|
|
8
|
+
"HF_TOKEN": "hf_replace_me",
|
|
9
|
+
"CODEBUDDY_NAMESPACE": "claude-desktop"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# LangGraph Agent Example
|
|
2
|
+
|
|
3
|
+
This example shows CodeBuddy inside a LangGraph flow with recall before the agent step and remember after the agent step.
|
|
4
|
+
|
|
5
|
+
It demonstrates:
|
|
6
|
+
|
|
7
|
+
- `CodeBuddyNode` in `recall` mode
|
|
8
|
+
- `CodeBuddyNode` in `remember` mode
|
|
9
|
+
- `CodeBuddyCheckpointer`
|
|
10
|
+
- expected state fields: `messages`, `memory`, `sessionId`, `agentId`
|
|
11
|
+
- `cacheTtlSeconds: 30`
|
|
12
|
+
|
|
13
|
+
## Run
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
docker compose up -d
|
|
17
|
+
export DATABASE_URL=postgres://codebuddy:codebuddy@localhost:5432/codebuddy
|
|
18
|
+
export HF_TOKEN=hf_your_token
|
|
19
|
+
npm install
|
|
20
|
+
npm run build
|
|
21
|
+
npm install @langchain/langgraph @langchain/core
|
|
22
|
+
npx tsx examples/langgraph-agent/index.ts
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The example imports from the public package surface:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { createRuntime } from "codebuddy";
|
|
29
|
+
import { CodeBuddyCheckpointer, CodeBuddyNode } from "codebuddy/langgraph";
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
If Hugging Face is cold or rate-limited, the embedding worker may need time to prepare vectors. Recall still falls back to recent context while embeddings are pending.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { type BaseMessage, HumanMessage } from "@langchain/core/messages";
|
|
2
|
+
import { Annotation, StateGraph } from "@langchain/langgraph";
|
|
3
|
+
import type { PlannedContext } from "codebuddy";
|
|
4
|
+
import { createRuntime } from "codebuddy";
|
|
5
|
+
import { CodeBuddyCheckpointer, CodeBuddyNode } from "codebuddy/langgraph";
|
|
6
|
+
|
|
7
|
+
const postgresUrl = process.env.DATABASE_URL;
|
|
8
|
+
if (!postgresUrl) {
|
|
9
|
+
throw new Error("DATABASE_URL is required.");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const runtime = await createRuntime({
|
|
13
|
+
postgresUrl,
|
|
14
|
+
provider: { type: "huggingface", apiKey: process.env.HF_TOKEN },
|
|
15
|
+
namespace: "langgraph-agent",
|
|
16
|
+
tokenBudget: 4000,
|
|
17
|
+
});
|
|
18
|
+
const { memory } = runtime;
|
|
19
|
+
|
|
20
|
+
const State = Annotation.Root({
|
|
21
|
+
messages: Annotation<BaseMessage[]>({
|
|
22
|
+
reducer: (left, right) => left.concat(right),
|
|
23
|
+
default: () => [],
|
|
24
|
+
}),
|
|
25
|
+
memory: Annotation<PlannedContext | undefined>({
|
|
26
|
+
reducer: (_, right) => right,
|
|
27
|
+
default: () => undefined,
|
|
28
|
+
}),
|
|
29
|
+
sessionId: Annotation<string>({
|
|
30
|
+
reducer: (_, right) => right,
|
|
31
|
+
}),
|
|
32
|
+
agentId: Annotation<string | undefined>({
|
|
33
|
+
reducer: (_, right) => right,
|
|
34
|
+
default: () => undefined,
|
|
35
|
+
}),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
async function agentNode(state: typeof State.State) {
|
|
39
|
+
const facts = state.memory?.messages.map((message) => message.content).join("\n") ?? "";
|
|
40
|
+
return {
|
|
41
|
+
messages: [
|
|
42
|
+
new HumanMessage(
|
|
43
|
+
facts
|
|
44
|
+
? `Agent saw recalled memory:\n${facts}`
|
|
45
|
+
: "Agent had no recalled memory for this turn.",
|
|
46
|
+
),
|
|
47
|
+
],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const graph = new StateGraph(State)
|
|
52
|
+
.addNode("recall", new CodeBuddyNode({ memory, mode: "recall", cacheTtlSeconds: 30 }))
|
|
53
|
+
.addNode("agent", agentNode)
|
|
54
|
+
.addNode("remember", new CodeBuddyNode({ memory, mode: "remember" }))
|
|
55
|
+
.addEdge("__start__", "recall")
|
|
56
|
+
.addEdge("recall", "agent")
|
|
57
|
+
.addEdge("agent", "remember")
|
|
58
|
+
.addEdge("remember", "__end__")
|
|
59
|
+
.compile({ checkpointer: new CodeBuddyCheckpointer({ namespace: "langgraph-agent" }) });
|
|
60
|
+
|
|
61
|
+
const result = await graph.invoke(
|
|
62
|
+
{
|
|
63
|
+
messages: [new HumanMessage("What do we know about deployment?")],
|
|
64
|
+
sessionId: "sess_langgraph_example",
|
|
65
|
+
agentId: "agent-langgraph",
|
|
66
|
+
},
|
|
67
|
+
{ configurable: { thread_id: "thread_langgraph_example" } },
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
console.log(result.messages.at(-1)?.content);
|
|
71
|
+
await runtime.close();
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Multi-Agent Handoff Example
|
|
2
|
+
|
|
3
|
+
This example shows two namespaces sharing memory.
|
|
4
|
+
|
|
5
|
+
Flow:
|
|
6
|
+
|
|
7
|
+
1. `research-agent` writes a fact with `agentId` and `idempotencyKey`.
|
|
8
|
+
2. `research-agent` shares that fact to `ops-agent` in `reference` mode.
|
|
9
|
+
3. `ops-agent` recalls deployment context from its own namespace.
|
|
10
|
+
4. `research-agent` also creates a `snapshot` share to show the second share mode.
|
|
11
|
+
|
|
12
|
+
## Run
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
docker compose up -d
|
|
16
|
+
export DATABASE_URL=postgres://codebuddy:codebuddy@localhost:5432/codebuddy
|
|
17
|
+
export HF_TOKEN=hf_your_token
|
|
18
|
+
npm run build
|
|
19
|
+
npx tsx examples/multi-agent-handoff/index.ts
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Behaviors To Notice
|
|
23
|
+
|
|
24
|
+
- namespaces isolate memory until a share is created
|
|
25
|
+
- `reference` shares point to the live source fact
|
|
26
|
+
- `snapshot` shares copy the fact for the target namespace
|
|
27
|
+
- repeating the example returns `deduplicated: true` for the same `idempotencyKey`
|
|
28
|
+
- `agentId` gives inspect and audit views a stable writer attribution
|
|
29
|
+
|
|
30
|
+
Inspect after running:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
node dist/cli/index.js inspect research-agent
|
|
34
|
+
node dist/cli/index.js inspect ops-agent
|
|
35
|
+
```
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { createRuntime } from "codebuddy";
|
|
2
|
+
|
|
3
|
+
const postgresUrl = process.env.DATABASE_URL;
|
|
4
|
+
if (!postgresUrl) {
|
|
5
|
+
throw new Error("DATABASE_URL is required.");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const base = {
|
|
9
|
+
postgresUrl,
|
|
10
|
+
provider: { type: "huggingface" as const, apiKey: process.env.HF_TOKEN },
|
|
11
|
+
tokenBudget: 4000,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const research = await createRuntime({
|
|
15
|
+
...base,
|
|
16
|
+
namespace: "research-agent",
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const ops = await createRuntime({
|
|
20
|
+
...base,
|
|
21
|
+
namespace: "ops-agent",
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const remembered = await research.memory.remember({
|
|
26
|
+
sessionId: "sess_handoff_example",
|
|
27
|
+
content: "The deployment target is eu-west-1 and requires layer-cached Docker builds.",
|
|
28
|
+
type: "fact",
|
|
29
|
+
idempotencyKey: "handoff:deployment-target:v1",
|
|
30
|
+
agentId: "agent-research",
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
console.log("remembered", remembered);
|
|
34
|
+
|
|
35
|
+
const referenceShare = await research.memory.share({
|
|
36
|
+
from: "research-agent",
|
|
37
|
+
to: "ops-agent",
|
|
38
|
+
factIds: [remembered.id],
|
|
39
|
+
mode: "reference",
|
|
40
|
+
agentId: "agent-research",
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
console.log("reference share", referenceShare);
|
|
44
|
+
|
|
45
|
+
const opsRecall = await ops.memory.recall({
|
|
46
|
+
sessionId: "sess_handoff_example",
|
|
47
|
+
query: "What deployment target should ops use?",
|
|
48
|
+
callerModel: "meta-llama/Llama-3.2-3B-Instruct",
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
console.log("ops recalled messages");
|
|
52
|
+
for (const message of opsRecall.messages) {
|
|
53
|
+
console.log("-", message.content);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const snapshotShare = await research.memory.share({
|
|
57
|
+
from: "research-agent",
|
|
58
|
+
to: "ops-agent",
|
|
59
|
+
factIds: [remembered.id],
|
|
60
|
+
mode: "snapshot",
|
|
61
|
+
agentId: "agent-research",
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
console.log("snapshot share", snapshotShare);
|
|
65
|
+
} finally {
|
|
66
|
+
await research.close();
|
|
67
|
+
await ops.close();
|
|
68
|
+
}
|