@orquentra/codebuddy 2.15.0 → 2.15.3
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 +12 -7
- package/README.md +2 -2
- package/dist/{chunk-YMXFSHXT.js → chunk-3L5IR6OW.js} +2 -2
- package/dist/{chunk-YMXFSHXT.js.map → chunk-3L5IR6OW.js.map} +1 -1
- package/dist/{chunk-JJQDVGF7.js → chunk-3TZNQJTH.js} +3 -3
- package/dist/{chunk-4BSO3HST.js → chunk-4LMBZWIF.js} +48 -13
- package/dist/chunk-4LMBZWIF.js.map +1 -0
- package/dist/{chunk-WHKXUXHE.js → chunk-4TKKLQLH.js} +5 -5
- package/dist/chunk-4TKKLQLH.js.map +1 -0
- package/dist/{chunk-KQCP3ZYH.js → chunk-5ZLNHYJH.js} +31 -15
- package/dist/chunk-5ZLNHYJH.js.map +1 -0
- package/dist/{chunk-U7KDM62P.js → chunk-6KSSJJZO.js} +17 -9
- package/dist/chunk-6KSSJJZO.js.map +1 -0
- package/dist/{chunk-6YI2D5F5.js → chunk-7IXPARDM.js} +3 -3
- package/dist/{chunk-UTPC66MV.js → chunk-FEFOZ2ZW.js} +23 -4
- package/dist/chunk-FEFOZ2ZW.js.map +1 -0
- package/dist/{chunk-ITXE27SZ.js → chunk-FGJ2KPPN.js} +104 -22
- package/dist/chunk-FGJ2KPPN.js.map +1 -0
- package/dist/{chunk-D5E7SGI5.js → chunk-KGDRGA2L.js} +14 -14
- package/dist/{chunk-D5E7SGI5.js.map → chunk-KGDRGA2L.js.map} +1 -1
- package/dist/{chunk-UR3DF74I.js → chunk-LZTYPJ5I.js} +36 -18
- package/dist/chunk-LZTYPJ5I.js.map +1 -0
- package/dist/{chunk-UATJCD2T.js → chunk-R5E2YGLE.js} +14 -8
- package/dist/chunk-R5E2YGLE.js.map +1 -0
- package/dist/chunk-R5JRKMEP.js +55 -0
- package/dist/chunk-R5JRKMEP.js.map +1 -0
- package/dist/{chunk-RZ266NHE.js → chunk-SPQU2422.js} +5 -5
- package/dist/{chunk-RZ266NHE.js.map → chunk-SPQU2422.js.map} +1 -1
- package/dist/{chunk-BTTQWSDS.js → chunk-SXVH74NE.js} +36 -6
- package/dist/chunk-SXVH74NE.js.map +1 -0
- package/dist/{chunk-KYRM3HPP.js → chunk-TIMS3PB7.js} +3 -3
- package/dist/{chunk-M75SN4D4.js → chunk-Y4QQML24.js} +3 -3
- package/dist/{chunk-M75SN4D4.js.map → chunk-Y4QQML24.js.map} +1 -1
- package/dist/cli/index.js +4 -4
- package/dist/{config-TXQJCCVI.js → config-32X53LWY.js} +4 -4
- package/dist/{expand-KWYGNCKZ.js → expand-VFYOWNZS.js} +5 -5
- package/dist/{file-vectors-MKXTSGGH.js → file-vectors-UBOKGYXX.js} +4 -3
- package/dist/{index-facts-4MTEHKMN.js → index-facts-ZTUANWBF.js} +7 -7
- package/dist/index-pass-S6NC25P5.js +15 -0
- package/dist/index.js +9 -8
- package/dist/{install-E3JWINTN.js → install-ZTE3H7QM.js} +8 -7
- package/dist/{lean-MLTAFS5L.js → lean-5N6BOONS.js} +5 -4
- package/dist/{local-75DJECVR.js → local-5EYLEBEP.js} +4 -2
- package/dist/{local-llm-MECVJTVU.js → local-llm-ESMVP5LE.js} +4 -4
- package/dist/{main-RLMKQZW4.js → main-B3HZCGVE.js} +61 -50
- package/dist/main-B3HZCGVE.js.map +1 -0
- package/dist/{memory-PFFVMTCH.js → memory-CI7HIGHN.js} +5 -5
- package/dist/{operations-STR7S5UO.js → operations-MW52HIQ3.js} +4 -4
- package/dist/{rerank-XXKWDI5Q.js → rerank-O4S5BC45.js} +5 -5
- package/dist/{runtime-SWFWGTQ4.js → runtime-SZAWIXEB.js} +6 -5
- package/dist/{summaries-QXWFFDUZ.js → summaries-GCHZGIIA.js} +11 -8
- package/dist/{zvec-F73IBWO5.js → zvec-V34P24WF.js} +11 -6
- package/package.json +1 -1
- package/dist/chunk-4BSO3HST.js.map +0 -1
- package/dist/chunk-BTTQWSDS.js.map +0 -1
- package/dist/chunk-ITXE27SZ.js.map +0 -1
- package/dist/chunk-KQCP3ZYH.js.map +0 -1
- package/dist/chunk-U7KDM62P.js.map +0 -1
- package/dist/chunk-UATJCD2T.js.map +0 -1
- package/dist/chunk-UR3DF74I.js.map +0 -1
- package/dist/chunk-UTPC66MV.js.map +0 -1
- package/dist/chunk-WHKXUXHE.js.map +0 -1
- package/dist/index-pass-TBDUEZCB.js +0 -14
- package/dist/main-RLMKQZW4.js.map +0 -1
- /package/dist/{chunk-JJQDVGF7.js.map → chunk-3TZNQJTH.js.map} +0 -0
- /package/dist/{chunk-6YI2D5F5.js.map → chunk-7IXPARDM.js.map} +0 -0
- /package/dist/{chunk-KYRM3HPP.js.map → chunk-TIMS3PB7.js.map} +0 -0
- /package/dist/{config-TXQJCCVI.js.map → config-32X53LWY.js.map} +0 -0
- /package/dist/{expand-KWYGNCKZ.js.map → expand-VFYOWNZS.js.map} +0 -0
- /package/dist/{file-vectors-MKXTSGGH.js.map → file-vectors-UBOKGYXX.js.map} +0 -0
- /package/dist/{index-facts-4MTEHKMN.js.map → index-facts-ZTUANWBF.js.map} +0 -0
- /package/dist/{index-pass-TBDUEZCB.js.map → index-pass-S6NC25P5.js.map} +0 -0
- /package/dist/{install-E3JWINTN.js.map → install-ZTE3H7QM.js.map} +0 -0
- /package/dist/{lean-MLTAFS5L.js.map → lean-5N6BOONS.js.map} +0 -0
- /package/dist/{local-75DJECVR.js.map → local-5EYLEBEP.js.map} +0 -0
- /package/dist/{local-llm-MECVJTVU.js.map → local-llm-ESMVP5LE.js.map} +0 -0
- /package/dist/{memory-PFFVMTCH.js.map → memory-CI7HIGHN.js.map} +0 -0
- /package/dist/{operations-STR7S5UO.js.map → operations-MW52HIQ3.js.map} +0 -0
- /package/dist/{rerank-XXKWDI5Q.js.map → rerank-O4S5BC45.js.map} +0 -0
- /package/dist/{runtime-SWFWGTQ4.js.map → runtime-SZAWIXEB.js.map} +0 -0
- /package/dist/{summaries-QXWFFDUZ.js.map → summaries-GCHZGIIA.js.map} +0 -0
- /package/dist/{zvec-F73IBWO5.js.map → zvec-V34P24WF.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/retrieval/zvec.ts"],"sourcesContent":["import { execFile, spawn } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { mkdir, readFile, rm, stat, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport { asksForChangelog } from \"../context/discovery.js\";\nimport { readConfigFile } from \"../core/config-file.js\";\nimport { writeAtomic } from \"../core/markdown-store-fs.js\";\n\n/**\n * Optional semantic candidate source backed by zvec-grep (`zg`), a local\n * code-search CLI. It only *suggests* files: hits are normalized to\n * repository-relative paths, checked against the working tree, and fused with\n * the keyword ranking by the caller. Risk, policy and incident evidence are\n * never derived from it.\n *\n * Off unless `.codebuddy/config.json` sets `zvec.enabled` (or\n * `CODEBUDDY_ZVEC=1`). It never builds an index implicitly: an unready index,\n * a missing or unsupported binary, a timeout, or unparseable output all return\n * no candidates plus a reason, and callers fall back to keyword ranking.\n *\n * Queries exclude non-source paths (docs, Markdown, evals, scripts, tests,\n * CodeBuddy's own state) unless the task asks about them: otherwise prose that\n * quotes a task, such as audits or eval prompts, outranks the code it describes.\n *\n * Benchmarked: vector-only queries beat zg's default hybrid route on code\n * tasks, so only `--vector` is used. Results are parsed from zg's agent\n * markdown (`#N matchedBy=… path:start-end`), as 0.2.x has no JSON output.\n *\n * Queries use `--mode auto`: a running `zg server` answers in ~200ms, otherwise\n * zg searches directly (~400ms). Auto mode never starts the daemon. The\n * version/readiness check (~400ms) is cached on disk for a few minutes so the\n * per-prompt hook process doesn't repeat it. A failed check (not installed,\n * index not ready, timeout) is cached too, but only for 30 s and only until the\n * workspace's `.zvec-grep/` changes, so an unready index costs one probe per\n * window instead of one per call while a fresh `zg index` is still picked up.\n *\n * Freshness: queries keep `--refresh off` so the prompt path never waits on\n * embedding. Instead `refreshZvecIndex` (run by project sync after index\n * passes, off the request path) and `codebuddy zvec index` record when the zg\n * index was last brought up to date, and hits whose file changed after that are\n * dropped rather than presented with their old meaning.\n */\n\n/** zvec-grep versions whose CLI and output format this adapter was tested against. */\nconst SUPPORTED = /^0\\.2\\.\\d+$/;\n/** zg 0.2.x rejects `--limit` above 50 in server/auto mode (\"Too big: expected number to be <=50\"). */\nexport const ZG_MAX_LIMIT = 50;\nconst DEFAULT_TIMEOUT_MS = 1_500;\nconst READY_CACHE_MS = 10 * 60_000;\n/** A failed readiness check is reused this long, so a fresh `zg index` is noticed quickly. */\nconst NOT_READY_CACHE_MS = 30_000;\n/** An incremental `zg index` runs in the background; only a runaway is killed. */\nconst REFRESH_TIMEOUT_MS = 10 * 60_000;\n/** Small, fast local model; indexes this repo in seconds. */\nexport const DEFAULT_ZVEC_MODEL = \"local/potion-code-16m-v2\";\n/**\n * Default `zvec.minScore`: a vector-only file must cover this share of the\n * task's IDF mass in its current source. zg 0.2.x prints no similarity (its\n * `--trace` score is 1/(60+rank)), so the floor is CodeBuddy's own measure. 0.3\n * is the content gate's value (`MIN_IDF_COVERAGE`), not calibrated on vector\n * hits: see docs/zvec-floor.md to calibrate it.\n */\nexport const DEFAULT_ZVEC_MIN_SCORE = 0.3;\nconst DOC_GLOBS = [\"!**/*.md\", \"!**/*.mdx\", \"!**/*.rst\", \"!**/*.adoc\", \"!docs/**\"];\n/** zg globs are case-sensitive: the usual spellings of changelogs and release notes. */\nconst CHANGELOG_GLOBS = [\n \"!**/CHANGES*\",\n \"!**/CHANGELOG*\",\n \"!**/HISTORY*\",\n \"!**/NEWS*\",\n \"!**/RELEASE*\",\n \"!**/changelog*\",\n \"!**/Changelog*\",\n \"!**/ChangeLog*\",\n];\nconst TEST_GLOBS = [\n \"!**/*.test.*\",\n \"!**/*.spec.*\",\n \"!**/__tests__/**\",\n \"!**/test/**\",\n \"!**/tests/**\",\n \"!**/test_app/**\",\n \"!**/test_apps/**\",\n \"!**/testdata/**\",\n];\nconst ALWAYS_EXCLUDED_GLOBS = [\"!evals/**\", \"!scripts/**\", \"!.codebuddy/**\", \"!**/fixtures/**\"];\n\n/** zg `-g` exclusions for a task: docs and tests stay searchable when the task names them. */\nexport function zvecExcludeGlobs(task: string): string[] {\n return [\n ...(/\\b(docs?|readme|documentation|markdown)\\b/i.test(task) ? [] : DOC_GLOBS),\n ...(/\\b(tests?|spec)\\b/i.test(task) ? [] : TEST_GLOBS),\n ...(asksForChangelog(task) ? [] : CHANGELOG_GLOBS),\n ...ALWAYS_EXCLUDED_GLOBS,\n ];\n}\n\nconst EXCLUDED_PREFIXES = [\".codebuddy/cache/\", \".zvec-grep/\", \".git/\", \"node_modules/\"];\n\nexport type ZvecStatus =\n | \"ok\"\n | \"disabled\"\n | \"not-installed\"\n | \"unsupported-version\"\n | \"index-not-ready\"\n | \"timeout\"\n | \"failed\"\n | \"no-server\"\n /** Another zg process (a background `zg index`) holds the index lock. */\n | \"busy\";\n\n/** zg provides no content hash: a valid range alone cannot prove index freshness. */\nexport type RetrievalHit = {\n path: string;\n startLine: number;\n endLine: number;\n rank: number;\n /** `anchor`: a line the task itself names (path:line, stack frame, error string). */\n source: \"zvec\" | \"anchor\";\n freshness: \"unverified\";\n};\n\nexport type ZvecCandidates = {\n status: ZvecStatus;\n /** Repo-relative paths of existing files, best first. */\n paths: string[];\n /** Every chunk hit inside `paths`, in rank order (several per file). */\n hits: RetrievalHit[];\n reason: string;\n /** Hits dropped because the file no longer exists (stale index). */\n stale: number;\n /** Hits dropped because the file changed after the zg index was refreshed. */\n changed: number;\n /** `zvec.minScore` for vector-only files; set on every `ok` result. */\n minScore?: number;\n /**\n * Source paths whose intent card (`cardsDir(root)/<path>.md`, written\n * by the card pass) matched the task in the card workspace, best first.\n * Paths only: a card's line ranges say nothing about its source file.\n */\n cardPaths?: string[];\n};\n\nexport async function zvecCandidates(\n repositoryRoot: string,\n task: string,\n options: {\n limit?: number;\n /**\n * Hard stop (epoch ms) for every zg call: each one is killed at the\n * deadline and the caller falls back to keyword ranking. A miss is not\n * cached, so a slow prompt does not turn zvec off for the next one.\n */\n deadlineAt?: number;\n /** Query only while a `zg server` is running (checked at most every 30 s). */\n requireServer?: boolean;\n } = {},\n): Promise<ZvecCandidates> {\n const root = resolve(repositoryRoot);\n const config = await zvecConfig(root);\n if (!config.enabled) return none(\"disabled\", \"zvec-grep not enabled\");\n const { deadlineAt } = options;\n const run = (args: string[], cwd = root): Promise<RunResult> => {\n const ms =\n deadlineAt === undefined\n ? config.timeoutMs\n : Math.min(config.timeoutMs, deadlineAt - Date.now());\n if (ms <= 0) return Promise.resolve({ stdout: \"\", stderr: \"\", error: deadlineError() });\n return runZg(config.binary, args, cwd, ms);\n };\n const missedDeadline = (status: ZvecStatus) =>\n deadlineAt !== undefined && status === \"timeout\" && Date.now() >= deadlineAt - 5;\n\n const cached = await readCachedReadiness(root, config.binary);\n if (cached !== \"ready\") {\n if (cached) return cached;\n const readiness = await checkReadiness(run);\n if (!(readiness && missedDeadline(readiness.status))) {\n await markReadiness(root, config.binary, readiness);\n }\n if (readiness) return readiness;\n }\n if (options.requireServer && !(await serverRunning(root, config.binary, run))) {\n return none(\"no-server\", \"no running `zg server` (this path never starts one)\");\n }\n\n // zg ranks chunks, and one file can own many of them: oversample chunks so\n // `limit` distinct files survive de-duplication.\n const limit = Math.min(20, Math.max(1, Math.floor(options.limit ?? 10)));\n const chunkLimit = Math.min(ZG_MAX_LIMIT, limit * 8);\n const globs = zvecExcludeGlobs(task);\n const query = [\n \"query\",\n \"--vector\",\n task,\n \"--mode\",\n \"auto\",\n \"--refresh\",\n \"off\",\n \"--limit\",\n String(chunkLimit),\n ...globs.flatMap((glob) => [\"-g\", glob]),\n ];\n // The card workspace is queried in parallel; it never delays or fails the code query.\n const cardQuery = queryCards(root, task, limit, (args, cwd) => run(args, cwd));\n let result = await run(query);\n // A background `zg index` (project sync) holds the lock for a moment: one retry.\n if (\n result.error &&\n isBusy(result) &&\n (deadlineAt === undefined || deadlineAt - Date.now() > 400)\n ) {\n await new Promise((resolveWait) => setTimeout(resolveWait, BUSY_RETRY_MS));\n result = await run(query);\n }\n if (result.error) {\n const failure = fromError(result.error, \"zvec-grep query\", result.stderr);\n if (!missedDeadline(failure.status) && failure.status !== \"busy\") await resetZvecCache(root);\n return failure;\n }\n\n const hits = parseHits(result.stdout).slice(0, chunkLimit);\n const cardPaths = await cardQuery;\n // With no index, zg answers with a \"run zg index\" hint instead of hits.\n if (hits.length === 0 && /\\bzg index\\b/.test(result.stdout)) {\n const notReady = none(\"index-not-ready\", NOT_READY);\n await markReadiness(root, config.binary, notReady);\n return notReady;\n }\n const indexedAt = await readIndexedAt(root);\n const paths: string[] = [];\n const candidates: RetrievalHit[] = [];\n const seen = new Set<string>();\n let stale = 0;\n let changed = 0;\n for (const hit of hits) {\n const path = toRepoRelative(root, hit.path);\n if (!path) continue;\n // Later chunks of an accepted file keep their spans; a rejected file stays rejected.\n if (seen.has(path)) {\n if (paths.includes(path)) candidates.push({ ...hit, path });\n continue;\n }\n if (paths.length >= limit) continue;\n seen.add(path);\n if (EXCLUDED_PREFIXES.some((prefix) => path.startsWith(prefix))) continue;\n try {\n const info = await stat(resolve(root, path));\n if (!info.isFile()) continue;\n // ctime too: a rename over the path keeps the old mtime.\n if (indexedAt !== null && Math.max(info.mtimeMs, info.ctimeMs) > indexedAt) {\n changed++;\n continue;\n }\n } catch {\n stale++;\n continue;\n }\n paths.push(path);\n candidates.push({ ...hit, path });\n }\n return {\n status: \"ok\",\n paths,\n hits: candidates,\n stale,\n changed,\n minScore: config.minScore,\n ...(cardPaths.length > 0 ? { cardPaths } : {}),\n reason:\n `zvec-grep vector search: ${paths.length} file(s)` +\n (globs.length > 0 ? \"; non-source paths excluded\" : \"\") +\n (stale > 0 ? `, ${stale} stale hit(s) dropped` : \"\") +\n (changed > 0 ? `, ${changed} hit(s) changed since the zg index dropped` : \"\") +\n (cardPaths.length > 0 ? `; ${cardPaths.length} intent card match(es)` : \"\") +\n (indexedAt === null\n ? \"; index age unknown, hits unverified (run `codebuddy zvec index`)\"\n : \"\"),\n };\n}\n\nexport type ZvecRefresh = { status: ZvecStatus; reason: string };\n\n/**\n * Incrementally refresh an existing zg index (no `--rebuild`, no embedding\n * flag) and record when it started, which is the freshness bound applied to\n * later hits. A stale index is exactly what this repairs, so only a missing\n * binary, an unsupported version or no index at all skip it. Never builds a\n * missing index and never starts a zg server; every failure is returned as a\n * status for the caller to log.\n */\nexport async function refreshZvecIndex(\n repositoryRoot: string,\n options: { signal?: AbortSignal } = {},\n): Promise<ZvecRefresh> {\n const root = resolve(repositoryRoot);\n const config = await zvecConfig(root);\n if (!config.enabled) return { status: \"disabled\", reason: \"zvec-grep not enabled\" };\n const readiness = await checkReadiness((args) =>\n runZg(config.binary, args, root, config.timeoutMs),\n );\n if (readiness) return { status: readiness.status, reason: readiness.reason };\n const startedAt = Date.now();\n // An explicit root also resets the workspace roots, which pre-2.15.2 card\n // passes pointed at `.codebuddy/cache/cards` (every repo file then read as deleted).\n const result = await runZg(\n config.binary,\n [\"index\", root, \"--mode\", \"auto\"],\n root,\n REFRESH_TIMEOUT_MS,\n options.signal,\n );\n if (result.error) {\n const failure = fromError(result.error, \"zvec-grep refresh\", result.stderr);\n return { status: failure.status, reason: failure.reason };\n }\n await markIndexed(root, startedAt);\n // The next query uses the refreshed index at once, not a cached \"not ready\".\n await markReadiness(root, config.binary, null);\n return { status: \"ok\", reason: \"zvec-grep index refreshed\" };\n}\n\n/** Extract bounded, validated line ranges in retrieval rank order. */\nexport function parseHits(output: string): RetrievalHit[] {\n return [...output.matchAll(/^#(\\d+) matchedBy=\\S+ (.+?):(\\d+)(?:-(\\d+))?\\s*$/gm)]\n .flatMap((match) => {\n const rank = Number(match[1]);\n const startLine = Number(match[3]);\n const endLine = Number(match[4] ?? match[3]);\n if (startLine < 1 || endLine < startLine) return [];\n return [\n {\n path: match[2] as string,\n rank,\n startLine,\n endLine,\n source: \"zvec\" as const,\n freshness: \"unverified\" as const,\n },\n ];\n })\n .sort((left, right) => left.rank - right.rank);\n}\n\n/** Forget the cached readiness check, e.g. after `zg index` or a failed query. */\nexport async function resetZvecCache(repositoryRoot: string): Promise<void> {\n await rm(readyPath(resolve(repositoryRoot)), { force: true });\n}\n\nexport type ZvecReport = {\n enabled: boolean;\n binary: string;\n version: string | null;\n supported: boolean;\n indexReady: boolean;\n server: \"running\" | \"stopped\" | \"unknown\";\n /** The intent-card workspace (`cardsDir`): built by card passes, never by status. */\n cardIndex: \"ready\" | \"stale\" | \"missing\";\n reason: string;\n};\n\n/** Everything `codebuddy zvec status` shows. Read-only; never builds an index. */\nexport async function zvecStatus(repositoryRoot: string): Promise<ZvecReport> {\n const root = resolve(repositoryRoot);\n const config = await zvecConfig(root);\n const run = (args: string[]) =>\n runZg(config.binary, args, root, Math.max(config.timeoutMs, 5_000));\n const version = await run([\"version\"]);\n const found = version.error ? null : (version.stdout.trim().split(/\\s+/).pop() ?? null);\n const supported = found !== null && SUPPORTED.test(found);\n const readiness = supported ? await checkReadiness(run) : null;\n const server = supported ? await run([\"server\", \"status\"]) : null;\n const cards = cardsDir(root);\n const cardStatus =\n supported && (await stat(join(cards, \".zvec-grep\")).catch(() => null))\n ? await runZg(\n config.binary,\n [\"status\", cards, \"--check-ready\", \"--mode\", \"auto\"],\n cards,\n 5_000,\n )\n : null;\n return {\n enabled: config.enabled,\n binary: config.binary,\n version: found,\n supported,\n indexReady: supported && readiness === null,\n cardIndex: !cardStatus\n ? \"missing\"\n : !cardStatus.error\n ? \"ready\"\n : STALE.test(cardStatus.stdout)\n ? \"stale\"\n : \"missing\",\n server:\n server === null || server.error\n ? \"unknown\"\n : /running|ready/i.test(server.stdout)\n ? \"running\"\n : \"stopped\",\n reason: version.error\n ? fromError(version.error, \"zvec-grep version check\").reason\n : !supported\n ? `zvec-grep ${found ?? \"unknown\"} is not 0.2.x`\n : (readiness?.reason ?? \"ready\"),\n };\n}\n\n/**\n * Build or incrementally refresh the zg index for this repository, streaming\n * zg's progress. Explicit by design: CodeBuddy never indexes implicitly.\n */\nexport async function buildZvecIndex(\n repositoryRoot: string,\n options: {\n model?: string;\n rebuild?: boolean /** Discard zg's progress output. */;\n quiet?: boolean;\n } = {},\n): Promise<number> {\n const root = resolve(repositoryRoot);\n const config = await zvecConfig(root);\n const args = [\n \"index\",\n root,\n \"--embedding\",\n options.model ?? DEFAULT_ZVEC_MODEL,\n \"--mode\",\n \"auto\",\n ];\n if (options.rebuild) args.push(\"--rebuild\");\n const startedAt = Date.now();\n const code = await new Promise<number>((resolveRun, reject) => {\n const child = spawn(config.binary, args, {\n cwd: root,\n stdio: options.quiet ? \"ignore\" : \"inherit\",\n });\n child.on(\"error\", reject);\n child.on(\"close\", (exit) => resolveRun(exit ?? 1));\n });\n await resetZvecCache(root);\n if (code === 0) {\n // zg's index is binary and rebuildable: keep it out of git (and so out of\n // the uncommitted-file targets) without touching the project's .gitignore.\n await writeFile(join(root, \".zvec-grep\", \".gitignore\"), \"*\\n\", { flag: \"wx\" }).catch(() => {});\n await markIndexed(root, startedAt);\n }\n return code;\n}\n\nconst NOT_READY = \"zvec-grep index missing or not ready; run `codebuddy zvec index`\";\n\n/**\n * Intent cards live in their own zg workspace, one Markdown file per source\n * file at `<path>.md`. It sits outside the repository on purpose: zg resolves\n * any folder under an indexed repo to the repo's own workspace, so an in-repo\n * card folder could never get its own index (model mismatch) and indexing it\n * re-pointed the repo index's roots. Cards are plain English, so they get an\n * English sentence model instead of the code model.\n */\nexport function cardsDir(repositoryRoot: string): string {\n const base = process.env.CODEBUDDY_CARD_CACHE ?? join(homedir(), \".cache\", \"codebuddy\", \"cards\");\n const id = createHash(\"sha256\").update(resolve(repositoryRoot)).digest(\"hex\").slice(0, 16);\n return join(base, id);\n}\n/** Where cards lived before 2.15.2; removed by the next card pass. */\nexport const LEGACY_CARDS_DIR = join(\".codebuddy\", \"cache\", \"cards\");\nexport const DEFAULT_CARD_MODEL = \"local/bge-small-en-v1.5\";\n\n/** Source paths whose card matched the task; empty when there is no card index or it fails. */\nasync function queryCards(\n root: string,\n task: string,\n limit: number,\n run: (args: string[], cwd: string) => Promise<RunResult>,\n): Promise<string[]> {\n const cards = cardsDir(root);\n if (!(await stat(join(cards, \".zvec-grep\")).catch(() => null))) return [];\n const result = await run(\n [\n \"query\",\n \"--vector\",\n task,\n \"--mode\",\n \"auto\",\n \"--refresh\",\n \"off\",\n \"--limit\",\n String(Math.min(ZG_MAX_LIMIT, limit)),\n ],\n cards,\n );\n if (result.error) return [];\n const paths: string[] = [];\n for (const hit of parseHits(result.stdout)) {\n const card = toRepoRelative(cards, hit.path);\n if (!card?.endsWith(\".md\")) continue;\n const path = card.slice(0, -3);\n if (paths.includes(path)) continue;\n if (!(await stat(resolve(root, path)).catch(() => null))?.isFile()) continue;\n paths.push(path);\n }\n return paths.slice(0, limit);\n}\n\n/**\n * Build or refresh the card workspace's zg index (background only: after a\n * card pass). No-op without cards or with zvec off; never throws.\n */\nexport async function refreshZvecCardIndex(\n repositoryRoot: string,\n options: { signal?: AbortSignal } = {},\n): Promise<ZvecRefresh> {\n const root = resolve(repositoryRoot);\n const config = await zvecConfig(root);\n if (!config.enabled) return { status: \"disabled\", reason: \"zvec-grep not enabled\" };\n const cards = cardsDir(root);\n if (!(await stat(cards).catch(() => null)))\n return { status: \"ok\", reason: \"no intent cards yet\" };\n const exists = await stat(join(cards, \".zvec-grep\")).catch(() => null);\n const result = await runZg(\n config.binary,\n [\n \"index\",\n cards,\n ...(exists ? [] : [\"--embedding\", config.cardModel]),\n \"--no-ignore\",\n \"--mode\",\n \"auto\",\n ],\n cards,\n REFRESH_TIMEOUT_MS,\n options.signal,\n );\n if (result.error) {\n const failure = fromError(result.error, \"zvec-grep card index\", result.stderr);\n return { status: failure.status, reason: failure.reason };\n }\n await writeFile(join(cards, \".zvec-grep\", \".gitignore\"), \"*\\n\", { flag: \"wx\" }).catch(() => {});\n return { status: \"ok\", reason: \"zvec-grep card index refreshed\" };\n}\n\n/**\n * Start the shared `zg server` for this project when it is enabled and ready,\n * so the prompt hook (which only queries a running server) gets vector\n * candidates within its deadline. Returns a stop function that stops the\n * server only if this call started it.\n */\nexport async function ensureZvecServer(repositoryRoot: string): Promise<{\n started: boolean;\n reason: string;\n stop: () => Promise<void>;\n}> {\n const root = resolve(repositoryRoot);\n const config = await zvecConfig(root);\n const noop = async () => {};\n if (!config.enabled) return { started: false, reason: \"zvec-grep not enabled\", stop: noop };\n const run = (args: string[]) =>\n runZg(config.binary, args, root, Math.max(config.timeoutMs, 5_000));\n const readiness = await checkReadiness(run);\n if (readiness) return { started: false, reason: readiness.reason, stop: noop };\n const status = await run([\"server\", \"status\"]);\n if (!status.error && /^Server: ready\\b/m.test(status.stdout)) {\n return { started: false, reason: \"zg server already running (reused)\", stop: noop };\n }\n const on = await run([\"server\", \"on\"]);\n // The hook's 30 s server-status cache would otherwise keep saying \"stopped\".\n await rm(serverPath(root), { force: true });\n if (on.error) {\n return {\n started: false,\n reason: fromError(on.error, \"zg server on\", on.stderr).reason,\n stop: noop,\n };\n }\n return {\n started: true,\n reason: \"zg server started\",\n // ponytail: the daemon is shared; a second `codebuddy serve` that reused it\n // loses vectors when this one exits. Refcount via ZVEC_GREP_HOME if that matters.\n stop: async () => {\n await runZg(config.binary, [\"server\", \"off\"], root, 5_000);\n await rm(serverPath(root), { force: true });\n },\n };\n}\n\n/**\n * Version + index readiness. Returns null when the index is usable, else the\n * failure. A stale index (\"needs an update\") is usable: zg serves it with\n * `--refresh off`, and hits on files changed since the last refresh are\n * dropped by mtime (`zvec-index.json`), so a few edited files never turn zvec off.\n */\nasync function checkReadiness(\n run: (args: string[]) => Promise<RunResult>,\n): Promise<ZvecCandidates | null> {\n const version = await run([\"version\"]);\n if (version.error) return fromError(version.error, \"zvec-grep version check\");\n const found = version.stdout.trim().split(/\\s+/).pop() ?? \"\";\n if (!SUPPORTED.test(found)) {\n return none(\"unsupported-version\", `zvec-grep ${found || \"unknown\"} is not 0.2.x`);\n }\n const ready = await run([\"status\", \"--check-ready\", \"--mode\", \"auto\"]);\n if (!ready.error || STALE.test(ready.stdout)) return null;\n return ready.error.code === \"ETIMEDOUT\"\n ? none(\"timeout\", \"zvec-grep status timed out\")\n : none(\"index-not-ready\", NOT_READY);\n}\n\n/** `zg status` headline for an index that exists but has pending file changes. */\nconst STALE = /Workspace index needs an update/;\n\nfunction readyPath(root: string): string {\n return join(root, \".codebuddy\", \"cache\", \"zvec-ready.json\");\n}\n\ntype CachedReadiness = {\n binary?: string;\n checkedAt?: string;\n /** Absent in caches written before failures were cached: those were always ready. */\n failure?: { status: ZvecStatus; reason: string };\n};\n\n/**\n * \"ready\", a cached failure (reason marked as cached), or null when the check\n * must run. A failure is dropped once `.zvec-grep/` changed after it was\n * recorded, i.e. someone (re)built the index outside CodeBuddy.\n */\nasync function readCachedReadiness(\n root: string,\n binary: string,\n): Promise<\"ready\" | ZvecCandidates | null> {\n let cached: CachedReadiness;\n try {\n cached = JSON.parse(await readFile(readyPath(root), \"utf8\")) as CachedReadiness;\n } catch {\n return null;\n }\n const checkedAt = Date.parse(cached.checkedAt ?? \"\");\n const age = Date.now() - checkedAt;\n if (cached.binary !== binary || !(age >= 0)) return null;\n if (!cached.failure) return age <= READY_CACHE_MS ? \"ready\" : null;\n if (age > NOT_READY_CACHE_MS) return null;\n const workspace = await stat(join(root, \".zvec-grep\")).catch(() => null);\n if (workspace && workspace.mtimeMs > checkedAt) return null;\n const { status, reason } = cached.failure;\n return none(status, `${reason}; cached check from ${Math.round(age / 1000)}s ago`);\n}\n\n/** Cache a readiness result: null = ready. */\nasync function markReadiness(\n root: string,\n binary: string,\n failure: ZvecCandidates | null,\n): Promise<void> {\n try {\n const path = readyPath(root);\n await mkdir(dirname(path), { recursive: true, mode: 0o700 });\n const record: CachedReadiness = {\n binary,\n checkedAt: new Date().toISOString(),\n ...(failure ? { failure: { status: failure.status, reason: failure.reason } } : {}),\n };\n await writeAtomic(path, `${JSON.stringify(record)}\\n`);\n } catch {\n // A read-only cache only costs a repeated readiness check.\n }\n}\n\nfunction indexedPath(root: string): string {\n return join(root, \".codebuddy\", \"cache\", \"zvec-index.json\");\n}\n\n/** When the zg index was last refreshed by CodeBuddy, or null if unknown. */\nasync function readIndexedAt(root: string): Promise<number | null> {\n try {\n const parsed = JSON.parse(await readFile(indexedPath(root), \"utf8\")) as { indexedAt?: string };\n const at = Date.parse(parsed.indexedAt ?? \"\");\n return Number.isFinite(at) ? at : null;\n } catch {\n return null;\n }\n}\n\nasync function markIndexed(root: string, at: number): Promise<void> {\n try {\n const path = indexedPath(root);\n await mkdir(dirname(path), { recursive: true, mode: 0o700 });\n await writeAtomic(path, `${JSON.stringify({ indexedAt: new Date(at).toISOString() })}\\n`);\n } catch {\n // Without the record, later hits are reported as unverified, not trusted.\n }\n}\n\nasync function zvecConfig(root: string): Promise<{\n enabled: boolean;\n binary: string;\n timeoutMs: number;\n minScore: number;\n cardModel: string;\n}> {\n let file: Awaited<ReturnType<typeof readConfigFile>> = {};\n try {\n file = await readConfigFile(root);\n } catch {\n // A broken config must not break context assembly; treat zvec as disabled.\n }\n const env = process.env.CODEBUDDY_ZVEC;\n return {\n enabled: env !== undefined ? env === \"1\" || env === \"true\" : (file.zvec?.enabled ?? false),\n binary: file.zvec?.binary ?? \"zg\",\n timeoutMs: file.zvec?.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n minScore: file.zvec?.minScore ?? DEFAULT_ZVEC_MIN_SCORE,\n cardModel: file.zvec?.cardModel ?? DEFAULT_CARD_MODEL,\n };\n}\n\ntype RunResult = {\n stdout: string;\n stderr: string;\n error: (Error & { code?: string | number | null | undefined }) | null;\n};\n\nfunction runZg(\n binary: string,\n args: string[],\n cwd: string,\n timeoutMs: number,\n signal?: AbortSignal,\n): Promise<RunResult> {\n return new Promise((resolveRun) => {\n execFile(\n binary,\n args,\n {\n cwd,\n timeout: timeoutMs,\n maxBuffer: 1024 * 1024,\n killSignal: \"SIGKILL\",\n ...(signal ? { signal } : {}),\n },\n (error, stdout, stderr) => {\n if (error && (error as { killed?: boolean }).killed) {\n resolveRun({\n stdout: \"\",\n stderr: String(stderr),\n error: Object.assign(error, { code: \"ETIMEDOUT\" }),\n });\n return;\n }\n resolveRun({ stdout: String(stdout), stderr: String(stderr), error });\n },\n );\n });\n}\n\nfunction deadlineError(): NonNullable<RunResult[\"error\"]> {\n return Object.assign(new Error(\"hook deadline reached\"), { code: \"ETIMEDOUT\" });\n}\n\nfunction serverPath(root: string): string {\n return join(root, \".codebuddy\", \"cache\", \"zvec-server.json\");\n}\n\n/** `zg server status` says ready; the answer (either way) is reused for 30 s. */\nasync function serverRunning(\n root: string,\n binary: string,\n run: (args: string[]) => Promise<RunResult>,\n): Promise<boolean> {\n try {\n const cached = JSON.parse(await readFile(serverPath(root), \"utf8\")) as {\n binary?: string;\n checkedAt?: number;\n running?: boolean;\n };\n const age = Date.now() - (cached.checkedAt ?? 0);\n if (cached.binary === binary && age >= 0 && age <= NOT_READY_CACHE_MS) {\n return cached.running === true;\n }\n } catch {\n // No record yet: ask zg.\n }\n const status = await run([\"server\", \"status\"]);\n // A deadline miss says nothing about the server: not cached.\n if (status.error?.code === \"ETIMEDOUT\") return false;\n const running = !status.error && /^Server: ready\\b/m.test(status.stdout);\n try {\n await mkdir(dirname(serverPath(root)), { recursive: true, mode: 0o700 });\n await writeAtomic(\n serverPath(root),\n `${JSON.stringify({ binary, checkedAt: Date.now(), running })}\\n`,\n );\n } catch {\n // An unwritable cache only repeats the check.\n }\n return running;\n}\n\nfunction fromError(\n error: NonNullable<RunResult[\"error\"]>,\n what: string,\n stderr = \"\",\n): ZvecCandidates {\n if (error.code === \"ENOENT\") return none(\"not-installed\", \"zvec-grep (`zg`) not found on PATH\");\n if (error.code === \"ETIMEDOUT\") return none(\"timeout\", `${what} timed out`);\n if (BUSY.test(stderr)) return none(\"busy\", `${what}: index busy (a zg index refresh is running)`);\n // zg prints `Code: ZVEC_GREP.…` or an `Error: …` line (e.g. a limit or\n // model-mismatch validation error); keep it so the explain line says why.\n const code = stderr.match(/\\bCode:\\s*(\\S+)/)?.[1];\n const message = stderr\n .match(/^(?:Error:\\s*)?(.*(?:error|mismatch|does not match|Too big).*)$/im)?.[1]\n ?.trim()\n .slice(0, 160);\n const detail = [code, message].filter(Boolean).join(\": \");\n return none(\"failed\", `${what} failed${detail ? ` (${detail})` : \"\"}`);\n}\n\n/** zg's lock error while another process (a background `zg index`) writes the index. */\nconst BUSY = /ZVEC_GREP\\.ENGINE\\.LOCK\\.BUSY/;\nconst BUSY_RETRY_MS = 150;\n\nfunction isBusy(result: RunResult): boolean {\n return BUSY.test(result.stderr);\n}\n\nfunction none(status: ZvecStatus, reason: string): ZvecCandidates {\n return { status, paths: [], hits: [], reason, stale: 0, changed: 0 };\n}\n\nfunction toRepoRelative(root: string, path: string): string | null {\n const absolute = isAbsolute(path) ? path : resolve(root, path);\n const rel = relative(root, absolute);\n if (rel === \"\" || rel === \"..\" || rel.startsWith(`..${sep}`) || isAbsolute(rel)) return null;\n return rel.split(sep).join(\"/\");\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
readConfigFile
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-Y4QQML24.js";
|
|
4
4
|
import {
|
|
5
5
|
installedLocalModel
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-SXVH74NE.js";
|
|
7
7
|
|
|
8
8
|
// src/core/global-config.ts
|
|
9
9
|
import { chmod, mkdir, readFile, writeFile } from "fs/promises";
|
|
@@ -14,12 +14,12 @@ var GLOBAL_DIR = ".codebuddy";
|
|
|
14
14
|
var GLOBAL_FILE = "global.json";
|
|
15
15
|
var globalConfigSchema = z.object({
|
|
16
16
|
hfToken: z.string().min(1).optional(),
|
|
17
|
-
/** Cloud LLM keys asked for by `codebuddy
|
|
17
|
+
/** Cloud LLM keys asked for by `codebuddy` on machines too small for the local model. */
|
|
18
18
|
groqApiKey: z.string().min(1).optional(),
|
|
19
19
|
openrouterApiKey: z.string().min(1).optional(),
|
|
20
20
|
databaseUrl: z.string().min(1).optional(),
|
|
21
21
|
// Where the codebuddy install lives on this machine. Cached so future
|
|
22
|
-
// `codebuddy
|
|
22
|
+
// `codebuddy` calls in unrelated projects can find the CLI entry
|
|
23
23
|
// without re-resolving via process.argv every time.
|
|
24
24
|
installPath: z.string().optional()
|
|
25
25
|
});
|
|
@@ -153,4 +153,4 @@ export {
|
|
|
153
153
|
resolveLlmConfig,
|
|
154
154
|
redactLlmKeys
|
|
155
155
|
};
|
|
156
|
-
//# sourceMappingURL=chunk-
|
|
156
|
+
//# sourceMappingURL=chunk-4TKKLQLH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/global-config.ts","../src/llm/config.ts"],"sourcesContent":["import { chmod, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { z } from \"zod\";\n\n/**\n * User-level configuration shared across all projects on this machine.\n * Stored at ~/.codebuddy/global.json with 0600 permissions so the HF token\n * is never world-readable. Per-project namespace is NOT stored here — that\n * is implicit in the directory the user runs `codebuddy` from.\n */\n\nexport const GLOBAL_DIR = \".codebuddy\";\nexport const GLOBAL_FILE = \"global.json\";\n\nconst globalConfigSchema = z.object({\n hfToken: z.string().min(1).optional(),\n /** Cloud LLM keys asked for by `codebuddy` on machines too small for the local model. */\n groqApiKey: z.string().min(1).optional(),\n openrouterApiKey: z.string().min(1).optional(),\n databaseUrl: z.string().min(1).optional(),\n // Where the codebuddy install lives on this machine. Cached so future\n // `codebuddy` calls in unrelated projects can find the CLI entry\n // without re-resolving via process.argv every time.\n installPath: z.string().optional(),\n});\n\nexport type GlobalConfig = z.infer<typeof globalConfigSchema>;\n\nexport function globalConfigPath(home = homedir()): string {\n return join(home, GLOBAL_DIR, GLOBAL_FILE);\n}\n\nexport async function readGlobalConfig(home = homedir()): Promise<GlobalConfig> {\n const path = globalConfigPath(home);\n try {\n const raw = await readFile(path, \"utf8\");\n return globalConfigSchema.parse(JSON.parse(raw));\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return {};\n throw error;\n }\n}\n\nexport async function writeGlobalConfig(\n next: GlobalConfig,\n home = homedir(),\n): Promise<{ path: string }> {\n const path = globalConfigPath(home);\n await mkdir(dirname(path), { recursive: true, mode: 0o700 });\n await writeFile(path, `${JSON.stringify(next, null, 2)}\\n`, { mode: 0o600 });\n await chmod(path, 0o600);\n return { path };\n}\n\nexport async function mergeGlobalConfig(\n patch: GlobalConfig,\n home = homedir(),\n): Promise<{ path: string; merged: GlobalConfig }> {\n const current = await readGlobalConfig(home);\n const merged: GlobalConfig = { ...current, ...patch };\n const { path } = await writeGlobalConfig(merged, home);\n return { path, merged };\n}\n","import { readConfigFile } from \"../core/config-file.js\";\nimport { readGlobalConfig } from \"../core/global-config.js\";\nimport { installedLocalModel, type LocalModelSize, type LocalModelSpec } from \"./local.js\";\n\n/**\n * Small-model layer: bring-your-own-key (Groq/OpenRouter) or local\n * (`provider: \"local\"`, a GGUF model from `codebuddy models add local-llm`).\n * BYOK is off unless `.codebuddy/config.json` has `llm.enabled` and the\n * environment holds a key; keys are read from the environment only, never\n * stored in config, and redacted from any error text. The local backend is on\n * whenever its model is installed and no `llm` block says otherwise.\n */\nexport type LlmProvider = \"groq\" | \"openrouter\" | \"local\";\nexport type LlmFeatures = {\n summaries: boolean;\n rerank: boolean;\n memory: boolean;\n /** Project facts extracted at index time (`llm/index-facts.ts`). */\n facts?: boolean;\n /** Prompt-time code-term expansion for weak tasks (local backend only). */\n expansion?: boolean;\n};\ntype Endpoint = { provider: LlmProvider; model: string; baseUrl: string; apiKey: string };\nexport type EnabledLlmConfig = Endpoint & {\n enabled: true;\n timeoutMs: number;\n dailyTokenBudget: number;\n features: LlmFeatures;\n /** Background work only; never on the prompt path. */\n fallback: Endpoint | null;\n /** Set for `provider: \"local\"`: the installed GGUF model. */\n local?: LocalModelSpec;\n};\nexport type LlmConfig = EnabledLlmConfig | { enabled: false; reason: string };\n\ntype HostedProvider = Exclude<LlmProvider, \"local\">;\nconst BASE_URL: Record<HostedProvider, string> = {\n groq: \"https://api.groq.com/openai/v1\",\n openrouter: \"https://openrouter.ai/api/v1\",\n};\nconst KEY_ENV: Record<HostedProvider, string> = {\n groq: \"GROQ_API_KEY\",\n openrouter: \"OPENROUTER_API_KEY\",\n};\nconst DEFAULT_MODEL: Record<HostedProvider, string> = {\n // Qwen everywhere: the cloud path for machines too small for the local\n // Qwen3. Groq shut llama-3.1-8b-instant down on 2026-08-16 and\n // qwen3.6-27b on 2026-09-14; qwen3.8-27b is its replacement (reasoning off\n // by default). OpenRouter lists no free Qwen model (2026-11), so it is paid there.\n groq: \"qwen/qwen3.8-27b\",\n openrouter: \"qwen/qwen3.8-27b\",\n};\nconst DEFAULTS = { timeoutMs: 700, dailyTokenBudget: 400_000 } as const;\n\nexport async function resolveLlmConfig(\n repositoryRoot: string,\n env: NodeJS.ProcessEnv = process.env,\n): Promise<LlmConfig> {\n if (env.CODEBUDDY_LLM === \"0\") return { enabled: false, reason: \"CODEBUDDY_LLM=0\" };\n // CODEBUDDY_LLM=1 turns it on with defaults where no config says otherwise\n // (eval copies, one-off runs); an explicit `enabled: false` still wins.\n const configured = (await readConfigFile(repositoryRoot)).llm;\n if (configured === undefined || configured.provider === \"local\") {\n if (configured?.enabled === false) return { enabled: false, reason: \"llm not enabled\" };\n const local = await installedLocalModel(configured?.size);\n if (local) return localConfig(local, configured);\n if (configured?.provider === \"local\") {\n return {\n enabled: false,\n reason: \"local model not installed (codebuddy models add local-llm)\",\n };\n }\n }\n const block = configured ?? (env.CODEBUDDY_LLM === \"1\" ? { enabled: true } : undefined);\n if (!block?.enabled) return { enabled: false, reason: \"llm not enabled\" };\n const provider: HostedProvider =\n block.provider === \"local\" || block.provider === undefined ? \"groq\" : block.provider;\n const apiKey =\n env.CODEBUDDY_LLM_API_KEY || env[KEY_ENV[provider]] || (await savedKey(provider, env));\n if (!apiKey) return { enabled: false, reason: `no API key in ${KEY_ENV[provider]}` };\n const fallbackKey =\n block.fallback &&\n (env[KEY_ENV[block.fallback.provider]] || (await savedKey(block.fallback.provider, env)));\n return {\n enabled: true,\n provider,\n model: block.model ?? DEFAULT_MODEL[provider],\n // Any OpenAI-compatible endpoint (a proxy, a test stub).\n baseUrl: env.CODEBUDDY_LLM_BASE_URL?.replace(/\\/+$/, \"\") || BASE_URL[provider],\n apiKey,\n timeoutMs: block.timeoutMs ?? DEFAULTS.timeoutMs,\n dailyTokenBudget: block.dailyTokenBudget ?? DEFAULTS.dailyTokenBudget,\n features: {\n summaries: block.features?.summaries ?? true,\n rerank: block.features?.rerank ?? true,\n memory: block.features?.memory ?? false,\n },\n fallback:\n block.fallback && fallbackKey\n ? {\n provider: block.fallback.provider,\n model: block.fallback.model,\n baseUrl: BASE_URL[block.fallback.provider],\n apiKey: fallbackKey,\n }\n : null,\n };\n}\n\n/**\n * A key `codebuddy` asked for and saved in ~/.codebuddy/global.json (0600),\n * the same place as the HF token; the environment always wins. Off with\n * `CODEBUDDY_GLOBAL_CONFIG=0` (tests), so a developer's saved key never leaks in.\n */\nasync function savedKey(\n provider: HostedProvider,\n env: NodeJS.ProcessEnv,\n): Promise<string | undefined> {\n if (env.CODEBUDDY_GLOBAL_CONFIG === \"0\") return undefined;\n const global = await readGlobalConfig().catch(\n () => ({}) as Awaited<ReturnType<typeof readGlobalConfig>>,\n );\n return provider === \"groq\" ? global.groqApiKey : global.openrouterApiKey;\n}\n\ntype LlmBlock = NonNullable<Awaited<ReturnType<typeof readConfigFile>>[\"llm\"]>;\n\n/**\n * The local backend: no key, no daily budget (no cost), no hosted fallback.\n * Cards, facts and expansion default on; rerank stays off until the harness\n * shows it beats dense order (the standing rule for rerankers).\n */\nfunction localConfig(spec: LocalModelSpec, block: LlmBlock | undefined): EnabledLlmConfig {\n return {\n enabled: true,\n provider: \"local\",\n model: spec.id,\n baseUrl: \"\",\n apiKey: \"\",\n timeoutMs: block?.timeoutMs ?? DEFAULTS.timeoutMs,\n dailyTokenBudget: Number.POSITIVE_INFINITY,\n features: {\n summaries: block?.features?.summaries ?? true,\n rerank: block?.features?.rerank ?? false,\n memory: block?.features?.memory ?? false,\n facts: block?.features?.facts ?? true,\n expansion: block?.features?.expansion ?? true,\n },\n fallback: null,\n local: spec,\n };\n}\n\nexport type { LocalModelSize };\n\n/** Replace every LLM key present in the environment with `[REDACTED]`. */\nexport function redactLlmKeys(text: string, env: NodeJS.ProcessEnv = process.env): string {\n let redacted = text;\n // (A saved key is redacted by the client, which always strips `config.apiKey`.)\n for (const name of [\"CODEBUDDY_LLM_API_KEY\", ...Object.values(KEY_ENV)]) {\n const key = env[name];\n if (key) redacted = redacted.split(key).join(\"[REDACTED]\");\n }\n return redacted;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -31,11 +31,14 @@ import {
|
|
|
31
31
|
readBoundedSource,
|
|
32
32
|
syncFileVectors,
|
|
33
33
|
taskTerms
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-LZTYPJ5I.js";
|
|
35
35
|
import {
|
|
36
36
|
extractSymbolTable,
|
|
37
37
|
supportsSymbols
|
|
38
38
|
} from "./chunk-Y7D7PUBE.js";
|
|
39
|
+
import {
|
|
40
|
+
withCardLock
|
|
41
|
+
} from "./chunk-R5JRKMEP.js";
|
|
39
42
|
import {
|
|
40
43
|
INCIDENT_SEVERITIES,
|
|
41
44
|
MemoryFileStore,
|
|
@@ -43,7 +46,7 @@ import {
|
|
|
43
46
|
isEligibleMemory,
|
|
44
47
|
lexicalTerms,
|
|
45
48
|
termOverlap
|
|
46
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-3L5IR6OW.js";
|
|
47
50
|
import {
|
|
48
51
|
generateEntityId
|
|
49
52
|
} from "./chunk-EMWGLKPR.js";
|
|
@@ -62,7 +65,7 @@ import {
|
|
|
62
65
|
loadPlanPolicy,
|
|
63
66
|
loadRuntimeConfig,
|
|
64
67
|
readConfigFile
|
|
65
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-Y4QQML24.js";
|
|
66
69
|
import {
|
|
67
70
|
assertNoSymlinkBetween,
|
|
68
71
|
composeMarkdown,
|
|
@@ -2191,8 +2194,11 @@ ${lines.slice(Math.max(0, symbol.startLine - 4), symbol.endLine).join("\n")}`.sl
|
|
|
2191
2194
|
async function syncReuseVectors(root, budgetMs) {
|
|
2192
2195
|
if (budgetMs <= 0 || process.env.CODEBUDDY_SEMANTIC === "0") return null;
|
|
2193
2196
|
try {
|
|
2194
|
-
const
|
|
2195
|
-
|
|
2197
|
+
const locked = await withCardLock(root, async () => {
|
|
2198
|
+
const { manifest } = await loadFreshIndex(root);
|
|
2199
|
+
return refreshReuseVectors(root, manifest, Date.now() + budgetMs);
|
|
2200
|
+
});
|
|
2201
|
+
return locked.ok ? locked.value : { embedded: 0, pending: 0, lockedBy: locked.holder };
|
|
2196
2202
|
} catch {
|
|
2197
2203
|
return null;
|
|
2198
2204
|
}
|
|
@@ -3850,7 +3856,7 @@ async function openHookSemantics(repositoryRoot) {
|
|
|
3850
3856
|
const connect = async () => {
|
|
3851
3857
|
const config = await loadRuntimeConfig(repositoryRoot, { requireDatabase: false });
|
|
3852
3858
|
if (!config.postgresUrl) return null;
|
|
3853
|
-
const { createRuntime } = await import("./operations-
|
|
3859
|
+
const { createRuntime } = await import("./operations-MW52HIQ3.js");
|
|
3854
3860
|
const opening = createRuntime(config, {
|
|
3855
3861
|
repositoryRoot,
|
|
3856
3862
|
startWorker: false,
|
|
@@ -4180,7 +4186,7 @@ async function runStageHook(input) {
|
|
|
4180
4186
|
}
|
|
4181
4187
|
async function llmMemoryOptions(repositoryRoot) {
|
|
4182
4188
|
try {
|
|
4183
|
-
return await (await import("./memory-
|
|
4189
|
+
return await (await import("./memory-CI7HIGHN.js")).llmCaptureOptions(repositoryRoot);
|
|
4184
4190
|
} catch {
|
|
4185
4191
|
return {};
|
|
4186
4192
|
}
|
|
@@ -4275,7 +4281,7 @@ async function runSyncHook(repositoryRoot, options = {}) {
|
|
|
4275
4281
|
await writeFile(dirty, "").catch(() => void 0);
|
|
4276
4282
|
return null;
|
|
4277
4283
|
}
|
|
4278
|
-
const { createRuntime } = await import("./operations-
|
|
4284
|
+
const { createRuntime } = await import("./operations-MW52HIQ3.js");
|
|
4279
4285
|
const runtime = await createRuntime(config, { repositoryRoot }).catch(async (error) => {
|
|
4280
4286
|
await rm5(lock, { recursive: true, force: true });
|
|
4281
4287
|
throw error;
|
|
@@ -4316,13 +4322,14 @@ async function runSyncHook(repositoryRoot, options = {}) {
|
|
|
4316
4322
|
const vectorStarted = Date.now();
|
|
4317
4323
|
const vectors = await syncFileVectors(repositoryRoot, SYNC_BUDGET_MS);
|
|
4318
4324
|
await syncReuseVectors(repositoryRoot, SYNC_BUDGET_MS - (Date.now() - vectorStarted));
|
|
4319
|
-
if (vectors) {
|
|
4325
|
+
if (vectors && vectors.lockedBy === void 0) {
|
|
4326
|
+
const { lockedBy: _, ...counts } = vectors;
|
|
4320
4327
|
await recordTrace(repositoryRoot, {
|
|
4321
4328
|
kind: "sync",
|
|
4322
4329
|
name: "file-vectors",
|
|
4323
4330
|
ms: Date.now() - started,
|
|
4324
4331
|
ok: true,
|
|
4325
|
-
detail:
|
|
4332
|
+
detail: counts
|
|
4326
4333
|
});
|
|
4327
4334
|
}
|
|
4328
4335
|
}
|
|
@@ -4578,14 +4585,23 @@ async function renderContextBlock(bootstrap, beforeEdit, ledger, sessionId, anno
|
|
|
4578
4585
|
});
|
|
4579
4586
|
}
|
|
4580
4587
|
const ranked = Boolean(beforeEdit?.task);
|
|
4581
|
-
const
|
|
4588
|
+
const codeSearch = beforeEdit?.pathSource === "task" && beforeEdit.targetPaths.length > 0;
|
|
4589
|
+
const strong = (fact) => fact.reason.includes("matches a target path") || fact.reason.includes("task term") && fact.reason.includes("semantic");
|
|
4590
|
+
const facts = (ranked ? beforeEdit?.facts ?? [] : bootstrap.facts).filter(
|
|
4591
|
+
(fact, index) => !codeSearch || index === 0 || strong(fact)
|
|
4592
|
+
);
|
|
4582
4593
|
for (const fact of facts) {
|
|
4583
4594
|
capsules.push({
|
|
4584
4595
|
priority: ranked ? 2 : 6,
|
|
4585
4596
|
capsule: { key: `fact:${fact.id}`, text: bound(`fact: ${fact.summary}`) }
|
|
4586
4597
|
});
|
|
4587
4598
|
}
|
|
4588
|
-
|
|
4599
|
+
const targets = new Set(beforeEdit?.targetPaths ?? []);
|
|
4600
|
+
const handoffs = ranked ? bootstrap.handoffs.filter(
|
|
4601
|
+
(handoff) => handoff.files.some((file2) => targets.has(file2)) || // An investigation handoff edits nothing; it names the file instead.
|
|
4602
|
+
[...targets].some((path) => handoff.summary.includes(path))
|
|
4603
|
+
).slice(0, 1) : bootstrap.handoffs;
|
|
4604
|
+
for (const handoff of handoffs) {
|
|
4589
4605
|
const drift = [
|
|
4590
4606
|
handoff.changedSince.length > 0 ? `${handoff.changedSince.length} file(s) changed since` : "",
|
|
4591
4607
|
handoff.missing.length > 0 ? `${handoff.missing.length} missing` : ""
|
|
@@ -4627,9 +4643,9 @@ async function renderContextBlock(bootstrap, beforeEdit, ledger, sessionId, anno
|
|
|
4627
4643
|
)
|
|
4628
4644
|
}
|
|
4629
4645
|
});
|
|
4630
|
-
const
|
|
4646
|
+
const targets2 = new Set(beforeEdit.targetPaths);
|
|
4631
4647
|
const risks = beforeEdit.risks.items.filter(
|
|
4632
|
-
(item) =>
|
|
4648
|
+
(item) => targets2.has(item.path) && item.score >= RISK_LINE_MIN_SCORE
|
|
4633
4649
|
);
|
|
4634
4650
|
if (risks.length > 0) {
|
|
4635
4651
|
capsules.push({
|
|
@@ -4733,4 +4749,4 @@ export {
|
|
|
4733
4749
|
readCaptureTurn,
|
|
4734
4750
|
renderContextBlock
|
|
4735
4751
|
};
|
|
4736
|
-
//# sourceMappingURL=chunk-
|
|
4752
|
+
//# sourceMappingURL=chunk-5ZLNHYJH.js.map
|