@orquentra/codebuddy 2.5.0 → 2.6.2

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.
Files changed (89) hide show
  1. package/CLAUDE_CODEX.md +6 -4
  2. package/README.md +8 -0
  3. package/WORKFLOW.md +5 -5
  4. package/dist/{chunk-JDZ3VK26.js → chunk-2XDPKFUW.js} +114 -823
  5. package/dist/chunk-2XDPKFUW.js.map +1 -0
  6. package/dist/{chunk-QDBDYCM2.js → chunk-5FW3PMNP.js} +2 -2
  7. package/dist/{chunk-776EQXDV.js → chunk-5KZY6OTG.js} +82 -5
  8. package/dist/chunk-5KZY6OTG.js.map +1 -0
  9. package/dist/{chunk-UFZD3JAA.js → chunk-5MQOE4J6.js} +3 -3
  10. package/dist/chunk-5UH3BEQR.js +32 -0
  11. package/dist/chunk-5UH3BEQR.js.map +1 -0
  12. package/dist/{chunk-ROQTT5ZO.js → chunk-B6CO63SQ.js} +8 -7
  13. package/dist/chunk-B6CO63SQ.js.map +1 -0
  14. package/dist/chunk-CSRD5OQA.js +79 -0
  15. package/dist/chunk-CSRD5OQA.js.map +1 -0
  16. package/dist/{chunk-PYLH4MH5.js → chunk-FJOTP632.js} +1 -1
  17. package/dist/{chunk-3XYQGFPB.js → chunk-IBLJOHJL.js} +16 -3
  18. package/dist/chunk-IBLJOHJL.js.map +1 -0
  19. package/dist/chunk-IMFUYEZA.js +1607 -0
  20. package/dist/chunk-IMFUYEZA.js.map +1 -0
  21. package/dist/{chunk-CQPCHMBS.js → chunk-J2EAZ4MA.js} +21 -8
  22. package/dist/chunk-J2EAZ4MA.js.map +1 -0
  23. package/dist/{chunk-KYK6RPAJ.js → chunk-JFDRBPYF.js} +2 -2
  24. package/dist/{chunk-JMWJ7V6Y.js → chunk-JPHJBCZB.js} +2 -2
  25. package/dist/{chunk-JMWJ7V6Y.js.map → chunk-JPHJBCZB.js.map} +1 -1
  26. package/dist/{chunk-L5AYZC3F.js → chunk-NERKZSSE.js} +7 -7
  27. package/dist/{chunk-PCE4STAY.js → chunk-OWWCDRXW.js} +5 -5
  28. package/dist/{chunk-WHZSVY2L.js → chunk-QBDJXGG5.js} +2 -2
  29. package/dist/{chunk-Z5QB367W.js → chunk-R7CD6EXS.js} +367 -1798
  30. package/dist/chunk-R7CD6EXS.js.map +1 -0
  31. package/dist/{chunk-6MKEIDX5.js → chunk-RAJJSCIP.js} +2 -2
  32. package/dist/chunk-S6VEG4S2.js +991 -0
  33. package/dist/chunk-S6VEG4S2.js.map +1 -0
  34. package/dist/{chunk-4BYGTEJT.js → chunk-XBJQKCLU.js} +2 -2
  35. package/dist/cli/index.js +14 -3
  36. package/dist/cli/index.js.map +1 -1
  37. package/dist/{cloud-GP6G3EAK.js → cloud-7WM3YLI4.js} +3 -3
  38. package/dist/{codebuddy-DM-i0Fu5.d.ts → codebuddy-B_pCaQrV.d.ts} +22 -2
  39. package/dist/{config-KFEHLV6W.js → config-DEVHUDIU.js} +3 -3
  40. package/dist/docker-autostart-KDME7TVC.js +12 -0
  41. package/dist/index.d.ts +4 -2
  42. package/dist/index.js +22 -18
  43. package/dist/langgraph/index.d.ts +1 -1
  44. package/dist/lean-command-HTQCPH76.js +15 -0
  45. package/dist/local-5MZURLCZ.js +17 -0
  46. package/dist/{main-BDVQAGAS.js → main-MTBQZGJV.js} +333 -219
  47. package/dist/main-MTBQZGJV.js.map +1 -0
  48. package/dist/{memory-4RGVLPKG.js → memory-KIC5FJVW.js} +4 -4
  49. package/dist/{operations-EQGOFCBD.js → operations-POCHY3WR.js} +8 -7
  50. package/dist/postgres-docker-QQZQ2ABK.js +16 -0
  51. package/dist/{pretool-command-MQQ2UNQM.js → pretool-command-AX6JXP25.js} +3 -3
  52. package/dist/{rerank-3P3C2UHN.js → rerank-5QZ3PNUW.js} +4 -4
  53. package/dist/runtime-CUBOOPZO.js +43 -0
  54. package/dist/runtime-CUBOOPZO.js.map +1 -0
  55. package/dist/stdio-HOV4P3DQ.js +12 -0
  56. package/dist/stdio-HOV4P3DQ.js.map +1 -0
  57. package/dist/{summaries-ZBV5IN7Y.js → summaries-SB5L2TSW.js} +6 -6
  58. package/dist/summaries-SB5L2TSW.js.map +1 -0
  59. package/dist/{zvec-MAPSJQSR.js → zvec-MSRKT7IV.js} +3 -3
  60. package/dist/zvec-MSRKT7IV.js.map +1 -0
  61. package/package.json +7 -10
  62. package/dist/chunk-3XYQGFPB.js.map +0 -1
  63. package/dist/chunk-776EQXDV.js.map +0 -1
  64. package/dist/chunk-CQPCHMBS.js.map +0 -1
  65. package/dist/chunk-JDZ3VK26.js.map +0 -1
  66. package/dist/chunk-ROQTT5ZO.js.map +0 -1
  67. package/dist/chunk-Z5QB367W.js.map +0 -1
  68. package/dist/lean-command-DA4ZNKG3.js +0 -15
  69. package/dist/local-3NGNESNB.js +0 -13
  70. package/dist/main-BDVQAGAS.js.map +0 -1
  71. /package/dist/{chunk-QDBDYCM2.js.map → chunk-5FW3PMNP.js.map} +0 -0
  72. /package/dist/{chunk-UFZD3JAA.js.map → chunk-5MQOE4J6.js.map} +0 -0
  73. /package/dist/{chunk-PYLH4MH5.js.map → chunk-FJOTP632.js.map} +0 -0
  74. /package/dist/{chunk-KYK6RPAJ.js.map → chunk-JFDRBPYF.js.map} +0 -0
  75. /package/dist/{chunk-L5AYZC3F.js.map → chunk-NERKZSSE.js.map} +0 -0
  76. /package/dist/{chunk-PCE4STAY.js.map → chunk-OWWCDRXW.js.map} +0 -0
  77. /package/dist/{chunk-WHZSVY2L.js.map → chunk-QBDJXGG5.js.map} +0 -0
  78. /package/dist/{chunk-6MKEIDX5.js.map → chunk-RAJJSCIP.js.map} +0 -0
  79. /package/dist/{chunk-4BYGTEJT.js.map → chunk-XBJQKCLU.js.map} +0 -0
  80. /package/dist/{cloud-GP6G3EAK.js.map → cloud-7WM3YLI4.js.map} +0 -0
  81. /package/dist/{config-KFEHLV6W.js.map → config-DEVHUDIU.js.map} +0 -0
  82. /package/dist/{lean-command-DA4ZNKG3.js.map → docker-autostart-KDME7TVC.js.map} +0 -0
  83. /package/dist/{local-3NGNESNB.js.map → lean-command-HTQCPH76.js.map} +0 -0
  84. /package/dist/{operations-EQGOFCBD.js.map → local-5MZURLCZ.js.map} +0 -0
  85. /package/dist/{memory-4RGVLPKG.js.map → memory-KIC5FJVW.js.map} +0 -0
  86. /package/dist/{pretool-command-MQQ2UNQM.js.map → operations-POCHY3WR.js.map} +0 -0
  87. /package/dist/{summaries-ZBV5IN7Y.js.map → postgres-docker-QQZQ2ABK.js.map} +0 -0
  88. /package/dist/{zvec-MAPSJQSR.js.map → pretool-command-AX6JXP25.js.map} +0 -0
  89. /package/dist/{rerank-3P3C2UHN.js.map → rerank-5QZ3PNUW.js.map} +0 -0
@@ -1,40 +1,53 @@
1
+ import {
2
+ runPreToolHookCommand
3
+ } from "./chunk-QBDJXGG5.js";
1
4
  import {
2
5
  loadLlmSummaries,
3
6
  summarizeRepository
4
- } from "./chunk-PCE4STAY.js";
7
+ } from "./chunk-OWWCDRXW.js";
5
8
  import {
6
9
  chatJson,
7
10
  coolingDown,
8
11
  usageToday
9
- } from "./chunk-UFZD3JAA.js";
12
+ } from "./chunk-5MQOE4J6.js";
13
+ import {
14
+ isDockerDaemonRunning,
15
+ tryStartDockerDesktop,
16
+ waitForDockerDaemon
17
+ } from "./chunk-5UH3BEQR.js";
18
+ import {
19
+ postgresDown,
20
+ postgresStatus,
21
+ postgresUp
22
+ } from "./chunk-CSRD5OQA.js";
10
23
  import {
11
24
  renderLeanBlock,
12
25
  runLeanHookCommand
13
- } from "./chunk-ROQTT5ZO.js";
14
- import {
15
- runPreToolHookCommand
16
- } from "./chunk-WHZSVY2L.js";
26
+ } from "./chunk-B6CO63SQ.js";
17
27
  import {
18
28
  failSoft,
19
29
  readHookInput,
20
30
  writeStdout
21
- } from "./chunk-PYLH4MH5.js";
31
+ } from "./chunk-FJOTP632.js";
32
+ import {
33
+ generateSuggestions,
34
+ migrateMemoryToFiles,
35
+ registerCodeBuddyTools,
36
+ startMcpServer,
37
+ watchRepository
38
+ } from "./chunk-IMFUYEZA.js";
22
39
  import {
23
40
  PlanFileStore,
24
41
  PlanLifecycle,
25
42
  ReviewStore,
26
- VERSION,
27
43
  WorklogStore,
28
44
  approveReviewItem,
29
45
  assessRisk,
30
46
  buildBeforeEditContext,
31
47
  buildBootstrapContext,
32
- generateSuggestions,
33
- migrateMemoryToFiles,
34
48
  openHookSemantics,
35
49
  parseTraceLines,
36
50
  readTraces,
37
- registerCodeBuddyTools,
38
51
  renderContextBlock,
39
52
  resolveRiskPaths,
40
53
  runCaptureHook,
@@ -42,15 +55,14 @@ import {
42
55
  runResetHook,
43
56
  runStageHook,
44
57
  runSyncHook,
45
- startMcpServer,
46
- tracePath,
47
- watchRepository
48
- } from "./chunk-Z5QB367W.js";
58
+ tracePath
59
+ } from "./chunk-R7CD6EXS.js";
49
60
  import "./chunk-IHQM2ZDV.js";
50
61
  import {
51
62
  SessionCapsuleLedger,
52
- estimateTokens
53
- } from "./chunk-CQPCHMBS.js";
63
+ estimateTokens,
64
+ hookRoot
65
+ } from "./chunk-J2EAZ4MA.js";
54
66
  import {
55
67
  buildArchitectureMap,
56
68
  generateGraphifyGraph,
@@ -60,13 +72,12 @@ import {
60
72
  neighbours,
61
73
  queryMap,
62
74
  setupGraphify
63
- } from "./chunk-L5AYZC3F.js";
75
+ } from "./chunk-NERKZSSE.js";
64
76
  import {
65
77
  extractSymbolTable,
66
78
  supportsSymbols
67
79
  } from "./chunk-PQK3GKZH.js";
68
80
  import {
69
- MemoryFileStore,
70
81
  bootstrapDatabase,
71
82
  buildProviderFromConfig,
72
83
  createDatabaseClient,
@@ -77,39 +88,46 @@ import {
77
88
  pingDatabase,
78
89
  runDoctor,
79
90
  runMigrations
80
- } from "./chunk-JDZ3VK26.js";
91
+ } from "./chunk-2XDPKFUW.js";
92
+ import {
93
+ MemoryFileStore,
94
+ VERSION
95
+ } from "./chunk-S6VEG4S2.js";
81
96
  import {
82
97
  redactPersisted
83
98
  } from "./chunk-GDJH7XJC.js";
84
99
  import {
85
100
  computeFactHash,
86
101
  generateEntityId
87
- } from "./chunk-4BYGTEJT.js";
88
- import "./chunk-KYK6RPAJ.js";
102
+ } from "./chunk-XBJQKCLU.js";
103
+ import "./chunk-JFDRBPYF.js";
89
104
  import {
105
+ localRuntimeInstalled,
90
106
  modelCacheDir
91
- } from "./chunk-3XYQGFPB.js";
107
+ } from "./chunk-IBLJOHJL.js";
92
108
  import {
93
109
  DEFAULT_CLOUD_EMBEDDING_MODELS,
94
110
  DEFAULT_RERANK_MODELS,
95
111
  LOCAL_EMBEDDING_MODEL,
96
112
  getModelDefinition
97
- } from "./chunk-JMWJ7V6Y.js";
113
+ } from "./chunk-JPHJBCZB.js";
98
114
  import {
99
115
  DEFAULT_ZVEC_MODEL,
100
116
  buildZvecIndex,
101
117
  zvecStatus
102
- } from "./chunk-QDBDYCM2.js";
118
+ } from "./chunk-5FW3PMNP.js";
103
119
  import {
104
120
  resolveLlmConfig
105
- } from "./chunk-6MKEIDX5.js";
121
+ } from "./chunk-RAJJSCIP.js";
106
122
  import {
107
123
  PLAN_POLICIES,
108
124
  configPath,
125
+ defaultNamespaceForCwd,
109
126
  initConfigFile,
110
127
  initProjectScaffold,
111
128
  loadPlanPolicy,
112
129
  loadRuntimeConfig,
130
+ migrateLegacyNamespace,
113
131
  readConfigFile,
114
132
  redactSecrets,
115
133
  resolveNamespaceFrom,
@@ -119,7 +137,7 @@ import {
119
137
  setZvecEnabled,
120
138
  writeAtomic,
121
139
  writeConfigFile
122
- } from "./chunk-776EQXDV.js";
140
+ } from "./chunk-5KZY6OTG.js";
123
141
  import "./chunk-PZ5AY32C.js";
124
142
 
125
143
  // src/cli/main.ts
@@ -338,7 +356,7 @@ function runTestCommand(command, source, repositoryRoot, timeoutMs) {
338
356
  if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
339
357
  throw new Error("--timeout must be a positive number of milliseconds.");
340
358
  }
341
- return new Promise((resolve14) => {
359
+ return new Promise((resolve13) => {
342
360
  const startedAt = Date.now();
343
361
  const child = spawn(command, {
344
362
  cwd: repositoryRoot,
@@ -363,7 +381,7 @@ ${output.slice(-MAX_TEST_OUTPUT_CHARS)}`;
363
381
  }, timeoutMs);
364
382
  child.on("close", (exitCode, signal) => {
365
383
  clearTimeout(timer);
366
- resolve14({
384
+ resolve13({
367
385
  status: timedOut ? "timed_out" : exitCode === 0 ? "passed" : "failed",
368
386
  command,
369
387
  source,
@@ -375,7 +393,7 @@ ${output.slice(-MAX_TEST_OUTPUT_CHARS)}`;
375
393
  });
376
394
  child.on("error", (error) => {
377
395
  clearTimeout(timer);
378
- resolve14({
396
+ resolve13({
379
397
  status: "failed",
380
398
  command,
381
399
  source,
@@ -633,14 +651,17 @@ function resolveCliEntrypoint() {
633
651
  }
634
652
  function buildEntry(options) {
635
653
  const env = {
636
- CODEBUDDY_NAMESPACE: options.namespace
654
+ CODEBUDDY_NAMESPACE: options.namespace,
655
+ CODEBUDDY_PROJECT_ROOT: resolve2(options.projectRoot ?? process.cwd())
637
656
  };
638
- if (options.projectRoot) env.CODEBUDDY_PROJECT_ROOT = options.projectRoot;
639
657
  if (options.hfToken) env.HF_TOKEN = options.hfToken;
640
658
  if (options.groqApiKey) env.GROQ_API_KEY = options.groqApiKey;
641
659
  if (options.databaseUrl) env.DATABASE_URL = options.databaseUrl;
642
660
  return {
643
- command: "node",
661
+ // Absolute: Claude Desktop is a GUI app and does not inherit the shell's
662
+ // PATH (nvm, Homebrew), so a bare "node" may not resolve or may be another
663
+ // version. Re-run `codebuddy claude install` after switching Node.
664
+ command: process.execPath,
644
665
  args: [resolveCliEntrypoint(), "serve"],
645
666
  env
646
667
  };
@@ -1034,6 +1055,8 @@ function hook(command, payload) {
1034
1055
  child = spawn("codebuddy", ["hooks", command], {
1035
1056
  cwd: payload.cwd,
1036
1057
  stdio: ["pipe", "pipe", "ignore"],
1058
+ // npm installs a codebuddy.cmd shim on Windows, which spawn only runs through a shell.
1059
+ shell: process.platform === "win32",
1037
1060
  });
1038
1061
  } catch {
1039
1062
  done("");
@@ -2938,7 +2961,13 @@ data: ${data}
2938
2961
  `);
2939
2962
  };
2940
2963
  watchFile(path, { interval: options.pollMs ?? 1e3 }, () => void onChange());
2964
+ let boundPort = 0;
2941
2965
  const server = createServer(async (request, response) => {
2966
+ const host = request.headers.host ?? "";
2967
+ if (host !== `127.0.0.1:${boundPort}` && host !== `localhost:${boundPort}`) {
2968
+ response.writeHead(403, { "content-type": "text/plain" }).end("Forbidden host");
2969
+ return;
2970
+ }
2942
2971
  const url = new URL(request.url ?? "/", "http://localhost");
2943
2972
  if (request.method !== "GET") {
2944
2973
  response.writeHead(405).end();
@@ -2978,18 +3007,19 @@ data: ${data}
2978
3007
  response.writeHead(404, { "content-type": "text/plain" }).end("Not found");
2979
3008
  });
2980
3009
  const port = await listen(server, options.port ?? 4777);
3010
+ boundPort = port;
2981
3011
  const heartbeat = setInterval(() => {
2982
3012
  for (const client of clients) client.write(": ping\n\n");
2983
3013
  }, 25e3);
2984
3014
  heartbeat.unref();
2985
3015
  return {
2986
3016
  url: `http://127.0.0.1:${port}/`,
2987
- close: () => new Promise((resolve14) => {
3017
+ close: () => new Promise((resolve13) => {
2988
3018
  clearInterval(heartbeat);
2989
3019
  unwatchFile(path);
2990
3020
  for (const client of clients) client.end();
2991
3021
  server.closeAllConnections();
2992
- server.close(() => resolve14());
3022
+ server.close(() => resolve13());
2993
3023
  })
2994
3024
  };
2995
3025
  }
@@ -2997,11 +3027,11 @@ async function listen(server, port) {
2997
3027
  for (let attempt = 0; attempt < 10; attempt += 1) {
2998
3028
  const candidate = port === 0 ? 0 : port + attempt;
2999
3029
  try {
3000
- await new Promise((resolve14, reject) => {
3030
+ await new Promise((resolve13, reject) => {
3001
3031
  server.once("error", reject);
3002
3032
  server.listen(candidate, "127.0.0.1", () => {
3003
3033
  server.off("error", reject);
3004
- resolve14();
3034
+ resolve13();
3005
3035
  });
3006
3036
  });
3007
3037
  return server.address().port;
@@ -3039,8 +3069,8 @@ function registerDashboardCommand(program, runSafely2) {
3039
3069
  );
3040
3070
  console.log(pc4.dim(" Ctrl+C to stop."));
3041
3071
  if (opts.open) openBrowser(dashboard.url);
3042
- await new Promise((resolve14) => {
3043
- const stop = () => void dashboard.close().then(resolve14);
3072
+ await new Promise((resolve13) => {
3073
+ const stop = () => void dashboard.close().then(resolve13);
3044
3074
  process.once("SIGINT", stop);
3045
3075
  process.once("SIGTERM", stop);
3046
3076
  });
@@ -3146,7 +3176,7 @@ function registerGitHubCommands(program, runSafely2) {
3146
3176
  }
3147
3177
 
3148
3178
  // src/cli/commands/hooks.ts
3149
- import { spawn as spawn3 } from "child_process";
3179
+ import { execFile as execFile2, spawn as spawn3 } from "child_process";
3150
3180
  import { relative as relative2 } from "path";
3151
3181
  import pc7 from "picocolors";
3152
3182
  function registerHooksCommands(program, runSafely2) {
@@ -3168,7 +3198,8 @@ function registerHooksCommands(program, runSafely2) {
3168
3198
  `${changed ? pc7.green("installed") : pc7.dim("unchanged")} CodeBuddy hooks in ${where}`
3169
3199
  );
3170
3200
  await reconcileRules(client, "hooks");
3171
- syncInBackground(process.cwd());
3201
+ warnIfHookCommandStale();
3202
+ syncInBackground(process.cwd(), true);
3172
3203
  console.log(
3173
3204
  pc7.dim(
3174
3205
  ` prompt\u2192recall \xB7 edit\u2192stage \xB7 turn end\u2192capture \xB7 compaction\u2192reset. Restart ${CLIENT_ADAPTERS[client].name} to activate.`
@@ -3226,18 +3257,18 @@ function registerHooksCommands(program, runSafely2) {
3226
3257
  `codebuddy: captured from ${changedFiles.length} changed file(s) \u2014 ${result.saved.length} saved, ${result.queuedForReview.length} queued
3227
3258
  `
3228
3259
  );
3229
- if (result.saved.length > 0) syncInBackground(input.cwd ?? process.cwd());
3260
+ if (result.saved.length > 0) syncInBackground(hookRoot(input.cwd));
3230
3261
  }
3231
3262
  });
3232
3263
  });
3233
3264
  hooks.command("sync").description(
3234
3265
  "[hook] Reindex Markdown memory into PostgreSQL and embed it locally (runs detached after capture)."
3235
- ).action(async () => {
3266
+ ).option("--respace", "Also re-embed vectors made by another embedding model.").action(async (opts) => {
3236
3267
  await failSoft(async () => {
3237
- const result = await runSyncHook(process.cwd());
3268
+ const result = await runSyncHook(process.cwd(), opts.respace ? { respace: true } : {});
3238
3269
  process.stderr.write(
3239
3270
  result ? `codebuddy: synced ${result.reindex.facts.imported} new / ${result.reindex.facts.updated} updated fact(s)${result.reindex.reembedding ? `, ${result.reindex.reembedding} re-embedding` : ""}${result.drained ? "" : " (embeddings still pending)"}
3240
- ` : "codebuddy: no PostgreSQL configured; nothing to sync\n"
3271
+ ` : "codebuddy: nothing to sync (no PostgreSQL configured, or another sync is running)\n"
3241
3272
  );
3242
3273
  });
3243
3274
  });
@@ -3271,15 +3302,42 @@ async function reconcileRules(client, mode) {
3271
3302
  );
3272
3303
  }
3273
3304
  }
3274
- function syncInBackground(cwd) {
3305
+ function warnIfHookCommandStale() {
3306
+ execFile2(
3307
+ "codebuddy",
3308
+ ["--version"],
3309
+ { timeout: 1e4, shell: process.platform === "win32" },
3310
+ (error, stdout) => {
3311
+ const found = stdout.trim();
3312
+ if (error || !found) {
3313
+ console.log(
3314
+ pc7.yellow(
3315
+ " ! `codebuddy` is not on PATH, so the hooks cannot run. Install it globally: npm i -g @orquentra/codebuddy"
3316
+ )
3317
+ );
3318
+ } else if (found !== VERSION) {
3319
+ console.log(
3320
+ pc7.yellow(
3321
+ ` ! The hooks will run codebuddy ${found} from PATH, not ${VERSION}. Update it: npm i -g @orquentra/codebuddy@${VERSION}`
3322
+ )
3323
+ );
3324
+ }
3325
+ }
3326
+ );
3327
+ }
3328
+ function syncInBackground(cwd, respace = false) {
3275
3329
  const entry = process.argv[1];
3276
3330
  if (!entry) return;
3277
3331
  try {
3278
- spawn3(process.execPath, [...process.execArgv, entry, "hooks", "sync"], {
3279
- cwd,
3280
- detached: true,
3281
- stdio: "ignore"
3282
- }).unref();
3332
+ spawn3(
3333
+ process.execPath,
3334
+ [...process.execArgv, entry, "hooks", "sync", ...respace ? ["--respace"] : []],
3335
+ {
3336
+ cwd,
3337
+ detached: true,
3338
+ stdio: "ignore"
3339
+ }
3340
+ ).unref();
3283
3341
  } catch {
3284
3342
  }
3285
3343
  }
@@ -3446,81 +3504,6 @@ function printResult(result, compact = false) {
3446
3504
  // src/cli/commands/init-wizard.ts
3447
3505
  import { writeFile as writeFile2 } from "fs/promises";
3448
3506
  import { confirm, isCancel, log, note, password, spinner, text } from "@clack/prompts";
3449
-
3450
- // src/cli/commands/postgres-docker.ts
3451
- import { spawn as spawn4 } from "child_process";
3452
- import { existsSync as existsSync3 } from "fs";
3453
- import { dirname as dirname11, resolve as resolve12 } from "path";
3454
- import { fileURLToPath as fileURLToPath2 } from "url";
3455
- function resolveBundledComposeFile() {
3456
- const here = dirname11(fileURLToPath2(import.meta.url));
3457
- const candidates = [
3458
- // installed package: dist/cli/commands/ -> root
3459
- resolve12(here, "..", "..", "..", "docker-compose.yml"),
3460
- // source layout: src/cli/commands/ -> root
3461
- resolve12(here, "..", "..", "..", "..", "docker-compose.yml"),
3462
- resolve12(here, "..", "..", "docker-compose.yml"),
3463
- resolve12(process.cwd(), "docker-compose.yml")
3464
- ];
3465
- for (const candidate of candidates) {
3466
- if (existsSync3(candidate)) return candidate;
3467
- }
3468
- throw new Error(`Could not locate docker-compose.yml. Looked in:
3469
- ${candidates.join("\n ")}`);
3470
- }
3471
- async function runDockerCompose(args, options = {}) {
3472
- const spawnImpl = options.spawnImpl ?? spawn4;
3473
- const composeFile = resolveBundledComposeFile();
3474
- const attempts = [
3475
- { kind: "v2", bin: "docker", args: ["compose", "-f", composeFile, ...args] },
3476
- { kind: "v1", bin: "docker-compose", args: ["-f", composeFile, ...args] }
3477
- ];
3478
- let lastSpawnError = null;
3479
- for (const attempt of attempts) {
3480
- try {
3481
- return await spawnOnce(spawnImpl, attempt);
3482
- } catch (error) {
3483
- const err = error;
3484
- if (err.code !== "ENOENT") throw err;
3485
- lastSpawnError = err;
3486
- }
3487
- }
3488
- throw new Error(
3489
- `Could not find docker. Install Docker Desktop (or docker-compose v1) and ensure it is on your PATH. (${lastSpawnError?.message ?? "spawn ENOENT"})`
3490
- );
3491
- }
3492
- function spawnOnce(spawnImpl, attempt) {
3493
- return new Promise((resolvePromise, rejectPromise) => {
3494
- const child = spawnImpl(attempt.bin, attempt.args, {
3495
- stdio: ["ignore", "pipe", "pipe"]
3496
- });
3497
- let stdout = "";
3498
- let stderr = "";
3499
- child.stdout?.on("data", (chunk) => {
3500
- stdout += String(chunk);
3501
- });
3502
- child.stderr?.on("data", (chunk) => {
3503
- stderr += String(chunk);
3504
- });
3505
- child.on("error", (error) => {
3506
- rejectPromise(error);
3507
- });
3508
- child.on("close", (code) => {
3509
- resolvePromise({ code: code ?? 0, stdout, stderr });
3510
- });
3511
- });
3512
- }
3513
- async function postgresUp(options) {
3514
- return runDockerCompose(["up", "-d"], options ?? {});
3515
- }
3516
- async function postgresDown(options) {
3517
- return runDockerCompose(["down"], options ?? {});
3518
- }
3519
- async function postgresStatus(options) {
3520
- return runDockerCompose(["ps"], options ?? {});
3521
- }
3522
-
3523
- // src/cli/commands/init-wizard.ts
3524
3507
  function bail() {
3525
3508
  log.warn("Aborted. No config was written.");
3526
3509
  process.exit(1);
@@ -3540,6 +3523,7 @@ async function pingOnce(databaseUrl) {
3540
3523
  }
3541
3524
  }
3542
3525
  async function runInitWizard() {
3526
+ const projectRoot = process.cwd();
3543
3527
  const sigintHandler = () => bail();
3544
3528
  process.on("SIGINT", sigintHandler);
3545
3529
  try {
@@ -3562,7 +3546,7 @@ async function runInitWizard() {
3562
3546
  const namespace = unwrap(
3563
3547
  await text({
3564
3548
  message: "Default namespace",
3565
- initialValue: process.env.CODEBUDDY_NAMESPACE ?? "default",
3549
+ initialValue: process.env.CODEBUDDY_NAMESPACE ?? defaultNamespaceForCwd(projectRoot),
3566
3550
  validate: (value) => value && /^[a-zA-Z0-9_.:-]+$/.test(value) ? void 0 : "Letters, digits, _ . : - only."
3567
3551
  })
3568
3552
  );
@@ -3585,7 +3569,7 @@ async function runInitWizard() {
3585
3569
  if (result.code === 0) {
3586
3570
  dockerSpinner.stop("Postgres container started.");
3587
3571
  for (let attempt = 0; attempt < 10 && !connected; attempt++) {
3588
- await new Promise((resolve14) => setTimeout(resolve14, 500));
3572
+ await new Promise((resolve13) => setTimeout(resolve13, 500));
3589
3573
  connected = await pingOnce(databaseUrl);
3590
3574
  }
3591
3575
  if (!connected) {
@@ -3638,6 +3622,7 @@ async function runInitWizard() {
3638
3622
  try {
3639
3623
  const install = await installClaudeEntry({
3640
3624
  namespace,
3625
+ projectRoot,
3641
3626
  hfToken,
3642
3627
  databaseUrl
3643
3628
  });
@@ -3773,7 +3758,7 @@ function registerMapCommands(program, runSafely2) {
3773
3758
  }
3774
3759
 
3775
3760
  // src/cli/commands/memory-review.ts
3776
- import { spawn as spawn5 } from "child_process";
3761
+ import { spawn as spawn4 } from "child_process";
3777
3762
  import { relative as relative3 } from "path";
3778
3763
  import pc12 from "picocolors";
3779
3764
  function registerMemoryCommands(program, runSafely2) {
@@ -3869,22 +3854,22 @@ function truncate(value, max) {
3869
3854
  function openEditor(path) {
3870
3855
  const editor = process.env.EDITOR ?? process.env.VISUAL ?? "vi";
3871
3856
  return new Promise((resolvePromise, reject) => {
3872
- const child = spawn5(editor, [path], { stdio: "inherit" });
3857
+ const child = spawn4(editor, [path], { stdio: "inherit" });
3873
3858
  child.on("error", reject);
3874
3859
  child.on("close", () => resolvePromise());
3875
3860
  });
3876
3861
  }
3877
3862
 
3878
3863
  // src/cli/commands/models.ts
3879
- import { existsSync as existsSync4 } from "fs";
3864
+ import { existsSync as existsSync3 } from "fs";
3880
3865
  import { join as join15 } from "path";
3881
3866
  import { spinner as spinner2 } from "@clack/prompts";
3882
3867
  import pc13 from "picocolors";
3883
3868
 
3884
3869
  // evals/fact-relevance.json
3885
3870
  var fact_relevance_default = {
3886
- version: 1,
3887
- note: "Task prompts vs durable project facts. Queries are paraphrased so most share few or no words with their fact; every unlisted (query, fact) pair is irrelevant.",
3871
+ version: 2,
3872
+ note: "Task prompts vs durable project facts. Queries are paraphrased so most share few or no words with their fact; every unlisted (query, fact) pair is irrelevant. Hard negatives share a subsystem with a relevant fact but do not answer its task. Queries alternate dev/test by position (even index = dev): floors are chosen on dev and reported on test.",
3888
3873
  facts: {
3889
3874
  cookie: "OAuth callback breaks unless the session cookie is SameSite=Lax; Strict drops it on the cross-site redirect.",
3890
3875
  pool: "Postgres connections go through one bounded pool of 10; never open ad-hoc clients in request handlers.",
@@ -3905,43 +3890,174 @@ var fact_relevance_default = {
3905
3890
  avatar: "Profile images are resized to 256px and stored as WebP in the media bucket.",
3906
3891
  flags: "Feature flags are read once at boot; changing one requires a restart of the worker.",
3907
3892
  pagination: "List endpoints use cursor pagination with an opaque base64url cursor of createdAt and id.",
3908
- i18n: "UI strings live in locales/en.json; never hard-code user-facing text in components."
3893
+ i18n: "UI strings live in locales/en.json; never hard-code user-facing text in components.",
3894
+ cookieDomain: "Session cookies are scoped to the app subdomain; never set them on the apex domain.",
3895
+ poolMetrics: "Database pool metrics are exported to Prometheus under the codebuddy_pool_ prefix.",
3896
+ releaseNotes: "Release notes are drafted from merged pull request titles by the changelog script.",
3897
+ hookInstall: "Hooks are written to .claude/settings.json and merged idempotently with the user's own hooks.",
3898
+ migrationNaming: "Migration files are numbered by drizzle-kit; never rename or edit a migration that has been applied.",
3899
+ testsParallel: "Vitest runs test files in parallel, so every test must use its own temporary directory.",
3900
+ logsStderr: "Server logs go to stderr through pino; never log full request bodies.",
3901
+ retry5xx: "The HTTP client retries 5xx responses twice with jittered backoff.",
3902
+ dateFormat: "Dates in the UI are formatted with the user's locale through Intl.DateTimeFormat.",
3903
+ flagNames: "Feature flag names use kebab-case and are declared in flags.yaml."
3909
3904
  },
3910
3905
  queries: [
3911
3906
  {
3912
3907
  q: "users get bounced back to sign-in forever after the identity provider returns",
3913
3908
  relevant: ["cookie"]
3914
3909
  },
3915
- { q: "handlers are exhausting connections to the database under load", relevant: ["pool"] },
3916
- { q: "cut a new version and push the package to the registry", relevant: ["release"] },
3917
- { q: "the injected block sometimes never shows up in the chat", relevant: ["hook"] },
3918
- { q: "fresh database setup fails on the embedding column", relevant: ["migration"] },
3919
- { q: "an API key ended up in a saved note", relevant: ["redaction"] },
3920
- { q: "context is sent again after I switch tasks and come back", relevant: ["ledger"] },
3921
- { q: "semantic code search crashes and the agent gets no files", relevant: ["zvec"] },
3922
- { q: "why do the db tests not run on my machine", relevant: ["tests"] },
3923
- { q: "module not found when importing a sibling ts file at runtime", relevant: ["esm"] },
3924
- { q: "Claude Desktop says Unexpected token in the server response", relevant: ["stdout"] },
3925
- { q: "the summarizer quietly stopped calling Groq in the afternoon", relevant: ["budget"] },
3926
- { q: "my uncommitted changes vanished after another session ran", relevant: ["worktree"] },
3910
+ {
3911
+ q: "handlers are exhausting connections to the database under load",
3912
+ relevant: ["pool"]
3913
+ },
3914
+ {
3915
+ q: "cut a new version and push the package to the registry",
3916
+ relevant: ["release"]
3917
+ },
3918
+ {
3919
+ q: "the injected block sometimes never shows up in the chat",
3920
+ relevant: ["hook"]
3921
+ },
3922
+ {
3923
+ q: "fresh database setup fails on the embedding column",
3924
+ relevant: ["migration"]
3925
+ },
3926
+ {
3927
+ q: "an API key ended up in a saved note",
3928
+ relevant: ["redaction"]
3929
+ },
3930
+ {
3931
+ q: "context is sent again after I switch tasks and come back",
3932
+ relevant: ["ledger"]
3933
+ },
3934
+ {
3935
+ q: "semantic code search crashes and the agent gets no files",
3936
+ relevant: ["zvec"]
3937
+ },
3938
+ {
3939
+ q: "why do the db tests not run on my machine",
3940
+ relevant: ["tests"]
3941
+ },
3942
+ {
3943
+ q: "module not found when importing a sibling ts file at runtime",
3944
+ relevant: ["esm"]
3945
+ },
3946
+ {
3947
+ q: "Claude Desktop says Unexpected token in the server response",
3948
+ relevant: ["stdout"]
3949
+ },
3950
+ {
3951
+ q: "the summarizer quietly stopped calling Groq in the afternoon",
3952
+ relevant: ["budget"]
3953
+ },
3954
+ {
3955
+ q: "my uncommitted changes vanished after another session ran",
3956
+ relevant: ["worktree"]
3957
+ },
3927
3958
  {
3928
3959
  q: "clients see too many requests errors during the import job",
3929
3960
  relevant: ["rateLimit"]
3930
3961
  },
3931
- { q: "meeting times show up one hour off for users in Berlin", relevant: ["timezone"] },
3932
- { q: "uploaded profile pictures look blurry", relevant: ["avatar"] },
3933
- { q: "I toggled the new checkout switch but nothing changed", relevant: ["flags"] },
3934
- { q: "infinite scroll repeats items on the second page", relevant: ["pagination"] },
3935
- { q: "translate the onboarding screen to German", relevant: ["i18n"] },
3936
- { q: "format the code before I commit", relevant: ["biome"] },
3937
- { q: "make the sidebar collapsible", relevant: [] },
3938
- { q: "add dark mode to the dashboard", relevant: [] },
3939
- { q: "write a haiku about the project", relevant: [] },
3940
- { q: "rename the button label on the settings page", relevant: [] }
3962
+ {
3963
+ q: "meeting times show up one hour off for users in Berlin",
3964
+ relevant: ["timezone"]
3965
+ },
3966
+ {
3967
+ q: "uploaded profile pictures look blurry",
3968
+ relevant: ["avatar"]
3969
+ },
3970
+ {
3971
+ q: "I toggled the new checkout switch but nothing changed",
3972
+ relevant: ["flags"]
3973
+ },
3974
+ {
3975
+ q: "infinite scroll repeats items on the second page",
3976
+ relevant: ["pagination"]
3977
+ },
3978
+ {
3979
+ q: "translate the onboarding screen to German",
3980
+ relevant: ["i18n"]
3981
+ },
3982
+ {
3983
+ q: "format the code before I commit",
3984
+ relevant: ["biome"]
3985
+ },
3986
+ {
3987
+ q: "make the sidebar collapsible",
3988
+ relevant: []
3989
+ },
3990
+ {
3991
+ q: "add dark mode to the dashboard",
3992
+ relevant: []
3993
+ },
3994
+ {
3995
+ q: "write a haiku about the project",
3996
+ relevant: []
3997
+ },
3998
+ {
3999
+ q: "rename the button label on the settings page",
4000
+ relevant: []
4001
+ },
4002
+ {
4003
+ q: "where do I declare a new feature flag",
4004
+ relevant: ["flagNames"]
4005
+ },
4006
+ {
4007
+ q: "show dates in the user's own language and order",
4008
+ relevant: ["dateFormat"]
4009
+ },
4010
+ {
4011
+ q: "can I tidy up the name of the 0004 migration file",
4012
+ relevant: ["migrationNaming"]
4013
+ },
4014
+ {
4015
+ q: "tests interfere with each other when the whole suite runs",
4016
+ relevant: ["testsParallel"]
4017
+ },
4018
+ {
4019
+ q: "where can I see how busy the connection pool is",
4020
+ relevant: ["poolMetrics"]
4021
+ },
4022
+ {
4023
+ q: "how is the text for the changelog produced",
4024
+ relevant: ["releaseNotes"]
4025
+ },
4026
+ {
4027
+ q: "the login cookie shows up on example.com instead of app.example.com",
4028
+ relevant: ["cookieDomain"]
4029
+ },
4030
+ {
4031
+ q: "is it fine to print the incoming payload for debugging",
4032
+ relevant: ["logsStderr"]
4033
+ },
4034
+ {
4035
+ q: "our hook setup appears twice in the Claude settings file",
4036
+ relevant: ["hookInstall"]
4037
+ },
4038
+ {
4039
+ q: "flaky upstream 502s should not fail the request on the first try",
4040
+ relevant: ["retry5xx"]
4041
+ },
4042
+ {
4043
+ q: "rewrite the marketing copy on the landing page",
4044
+ relevant: []
4045
+ },
4046
+ {
4047
+ q: "upgrade React to the next major version",
4048
+ relevant: []
4049
+ },
4050
+ {
4051
+ q: "add a CSV export button to the reports table",
4052
+ relevant: []
4053
+ }
3941
4054
  ]
3942
4055
  };
3943
4056
 
3944
4057
  // src/providers/calibration.ts
4058
+ function splitOf(index) {
4059
+ return index % 2 === 0 ? "dev" : "test";
4060
+ }
3945
4061
  async function calibrateEmbedder(embed) {
3946
4062
  const data = fact_relevance_default;
3947
4063
  const factIds = Object.keys(data.facts);
@@ -3950,47 +4066,59 @@ async function calibrateEmbedder(embed) {
3950
4066
  const dot = (a, b) => a.reduce((sum, value, index) => sum + value * (b[index] ?? 0), 0);
3951
4067
  const scores = queryVectors.map((query) => factVectors.map((fact) => dot(query, fact)));
3952
4068
  const relevant = (qi, fi) => data.queries[qi]?.relevant.includes(factIds[fi] ?? "") ?? false;
4069
+ const answerable = (qi) => (data.queries[qi]?.relevant.length ?? 0) > 0;
4070
+ const rows = (split) => scores.flatMap((row2, qi) => splitOf(qi) === split ? [{ row: row2, qi }] : []);
3953
4071
  const positives = [];
3954
4072
  const negatives = [];
3955
- for (const [qi, row2] of scores.entries()) {
3956
- for (const [fi, score] of row2.entries()) (relevant(qi, fi) ? positives : negatives).push(score);
3957
- }
3958
- const auc = positives.reduce((wins, p) => wins + negatives.filter((n) => p > n).length, 0) / (positives.length * negatives.length);
3959
4073
  let hits = 0;
3960
4074
  let reciprocal = 0;
3961
- let answerable = 0;
3962
- for (const [qi, row2] of scores.entries()) {
3963
- if (!data.queries[qi]?.relevant.length) continue;
3964
- answerable += 1;
4075
+ let answered = 0;
4076
+ for (const { row: row2, qi } of rows("test")) {
4077
+ for (const [fi, score] of row2.entries()) (relevant(qi, fi) ? positives : negatives).push(score);
4078
+ if (!answerable(qi)) continue;
4079
+ answered += 1;
3965
4080
  const order = row2.map((score, fi) => ({ score, fi })).sort((a, b) => b.score - a.score);
3966
4081
  const rank = order.findIndex(({ fi }) => relevant(qi, fi)) + 1;
3967
4082
  if (rank === 1) hits += 1;
3968
4083
  reciprocal += 1 / rank;
3969
4084
  }
3970
- const at = (floor) => {
4085
+ const auc = positives.reduce((wins, p) => wins + negatives.filter((n) => p > n).length, 0) / (positives.length * negatives.length);
4086
+ const at = (floor, split = "test") => {
3971
4087
  let tp = 0;
3972
4088
  let fp = 0;
4089
+ let relevantPairs = 0;
3973
4090
  let abstained = 0;
3974
4091
  let unrelated = 0;
3975
- for (const [qi, row2] of scores.entries()) {
4092
+ for (const { row: row2, qi } of rows(split)) {
4093
+ relevantPairs += data.queries[qi]?.relevant.length ?? 0;
3976
4094
  const admitted = row2.flatMap((score, fi) => score >= floor ? [fi] : []);
3977
4095
  for (const fi of admitted) {
3978
4096
  if (relevant(qi, fi)) tp += 1;
3979
4097
  else fp += 1;
3980
4098
  }
3981
- if (!data.queries[qi]?.relevant.length) {
4099
+ if (!answerable(qi)) {
3982
4100
  unrelated += 1;
3983
4101
  if (admitted.length === 0) abstained += 1;
3984
4102
  }
3985
4103
  }
3986
4104
  const precision = tp + fp === 0 ? 1 : tp / (tp + fp);
3987
- const recall = tp / positives.length;
4105
+ const recall = relevantPairs === 0 ? 0 : tp / relevantPairs;
3988
4106
  const f05 = precision + recall === 0 ? 0 : 1.25 * precision * recall / (0.25 * precision + recall);
3989
- return { floor, precision, recall, f05, abstain: abstained / unrelated };
4107
+ return { floor, precision, recall, f05, abstain: unrelated === 0 ? 1 : abstained / unrelated };
3990
4108
  };
3991
- const sweep = Array.from({ length: 96 }, (_, i) => at(Math.round((0.05 + i * 0.01) * 100) / 100));
4109
+ const sweep = Array.from(
4110
+ { length: 96 },
4111
+ (_, i) => at(Math.round((0.05 + i * 0.01) * 100) / 100, "dev")
4112
+ );
3992
4113
  const best = sweep.reduce((left, right) => right.f05 > left.f05 ? right : left);
3993
- return { auc, recallAt1: hits / answerable, mrr: reciprocal / answerable, best, at };
4114
+ return {
4115
+ auc,
4116
+ recallAt1: answered === 0 ? 0 : hits / answered,
4117
+ mrr: answered === 0 ? 0 : reciprocal / answered,
4118
+ best,
4119
+ test: at(best.floor, "test"),
4120
+ at
4121
+ };
3994
4122
  }
3995
4123
 
3996
4124
  // src/cli/commands/models.ts
@@ -4008,7 +4136,7 @@ async function withSpinner(label, work, done) {
4008
4136
  progress.stop(done(value));
4009
4137
  return value;
4010
4138
  } catch (error) {
4011
- progress.stop(pc13.red(`\u2717 ${label}`), 1);
4139
+ progress.error(pc13.red(`\u2717 ${label}`));
4012
4140
  throw error;
4013
4141
  }
4014
4142
  }
@@ -4017,7 +4145,7 @@ function keyPresent(provider, apiKey) {
4017
4145
  }
4018
4146
  function localModelDownloaded(id, revision) {
4019
4147
  const dir = join15(modelCacheDir(), id, ...revision ? [revision] : []);
4020
- return existsSync4(join15(dir, "onnx", "model_quantized.onnx"));
4148
+ return existsSync3(join15(dir, "onnx", "model_quantized.onnx"));
4021
4149
  }
4022
4150
  async function vectorCounts(postgresUrl, namespace, space) {
4023
4151
  const client = createDatabaseClient({ postgresUrl, maxConnections: 1, connectTimeoutSeconds: 3 });
@@ -4049,7 +4177,12 @@ async function printStatus() {
4049
4177
  const next = [];
4050
4178
  console.log(pc13.bold("Embeddings"));
4051
4179
  console.log(row("provider", `${provider.type} ${pc13.dim(model)}`));
4052
- if (provider.type === "local") {
4180
+ if (provider.type === "local" && !localRuntimeInstalled()) {
4181
+ console.log(
4182
+ row("runtime", warn("@huggingface/transformers is not installed: dense recall is off"))
4183
+ );
4184
+ next.push("npm i -g @huggingface/transformers");
4185
+ } else if (provider.type === "local") {
4053
4186
  const ready = localModelDownloaded(LOCAL_EMBEDDING_MODEL.id, LOCAL_EMBEDDING_MODEL.revision);
4054
4187
  console.log(
4055
4188
  row(
@@ -4185,7 +4318,7 @@ Examples:
4185
4318
  );
4186
4319
  }
4187
4320
  if (!missingKey) {
4188
- syncInBackground(process.cwd());
4321
+ syncInBackground(process.cwd(), true);
4189
4322
  console.log(
4190
4323
  pc13.dim(" Re-embedding existing memory in the background (codebuddy hooks sync).")
4191
4324
  );
@@ -4225,7 +4358,7 @@ before keeping one on. A reranker never admits a fact, it only orders them.`
4225
4358
  });
4226
4359
  models.command("pull").description("Download the local models now instead of on first use.").action(async () => {
4227
4360
  await runSafely2(async () => {
4228
- const { LocalModelProvider, rerankLocally } = await import("./local-3NGNESNB.js");
4361
+ const { LocalModelProvider, rerankLocally } = await import("./local-5MZURLCZ.js");
4229
4362
  const file = await readConfigFile();
4230
4363
  let started = Date.now();
4231
4364
  await withSpinner(
@@ -4261,13 +4394,13 @@ before keeping one on. A reranker never admits a fact, it only orders them.`
4261
4394
  console.log(
4262
4395
  row(
4263
4396
  "ranking",
4264
- `AUC ${result.auc.toFixed(3)} \xB7 right fact first ${pct(result.recallAt1)}`
4397
+ `AUC ${result.auc.toFixed(3)} \xB7 right fact first ${pct(result.recallAt1)} ${pc13.dim("(held-out tasks)")}`
4265
4398
  )
4266
4399
  );
4267
4400
  console.log(
4268
4401
  row(
4269
4402
  "floor",
4270
- `${result.best.floor}: precision ${pct(result.best.precision)}, recall ${pct(result.best.recall)}, silent on ${pct(result.best.abstain)} of unrelated tasks`
4403
+ `${result.best.floor}: precision ${pct(result.test.precision)}, recall ${pct(result.test.recall)}, silent on ${pct(result.test.abstain)} of unrelated tasks ${pc13.dim("(chosen on dev, measured on test)")}`
4271
4404
  )
4272
4405
  );
4273
4406
  if (opts.dryRun) return;
@@ -4282,7 +4415,7 @@ before keeping one on. A reranker never admits a fact, it only orders them.`
4282
4415
  }
4283
4416
 
4284
4417
  // src/cli/commands/plan.ts
4285
- import { spawn as spawn6 } from "child_process";
4418
+ import { spawn as spawn5 } from "child_process";
4286
4419
  import { relative as relative4 } from "path";
4287
4420
  import pc14 from "picocolors";
4288
4421
  function makeLifecycle(cwd = process.cwd()) {
@@ -4344,15 +4477,15 @@ function renderPlan(plan) {
4344
4477
  }
4345
4478
  function openEditor2(path) {
4346
4479
  const editor = process.env.EDITOR ?? process.env.VISUAL ?? "vi";
4347
- return new Promise((resolve14, reject) => {
4348
- const child = spawn6(editor, [path], { stdio: "inherit" });
4480
+ return new Promise((resolve13, reject) => {
4481
+ const child = spawn5(editor, [path], { stdio: "inherit" });
4349
4482
  child.on("error", reject);
4350
- child.on("close", () => resolve14());
4483
+ child.on("close", () => resolve13());
4351
4484
  });
4352
4485
  }
4353
4486
  function runGit(args) {
4354
- return new Promise((resolve14, reject) => {
4355
- const child = spawn6("git", args, { stdio: ["ignore", "pipe", "pipe"] });
4487
+ return new Promise((resolve13, reject) => {
4488
+ const child = spawn5("git", args, { stdio: ["ignore", "pipe", "pipe"] });
4356
4489
  let stdout = "";
4357
4490
  let stderr = "";
4358
4491
  child.stdout.on("data", (c) => {
@@ -4362,7 +4495,7 @@ function runGit(args) {
4362
4495
  stderr += String(c);
4363
4496
  });
4364
4497
  child.on("error", reject);
4365
- child.on("close", (code) => resolve14({ code: code ?? 0, stdout, stderr }));
4498
+ child.on("close", (code) => resolve13({ code: code ?? 0, stdout, stderr }));
4366
4499
  });
4367
4500
  }
4368
4501
  function registerPlanCommands(program, runSafely2) {
@@ -4677,7 +4810,7 @@ function severityBadge2(severity) {
4677
4810
 
4678
4811
  // src/cli/commands/symbols.ts
4679
4812
  import { readFile as readFile13 } from "fs/promises";
4680
- import { resolve as resolve13 } from "path";
4813
+ import { resolve as resolve12 } from "path";
4681
4814
  import pc18 from "picocolors";
4682
4815
  function registerSymbolsCommand(program, runSafely2) {
4683
4816
  program.command("symbols").argument("<path>", "Repo-relative or absolute path to a code file.").option("--json", "Print machine-readable JSON.").description("List a file's top-level symbols (functions, classes, types, exports).").action(async (path, opts) => {
@@ -4686,7 +4819,7 @@ function registerSymbolsCommand(program, runSafely2) {
4686
4819
  console.log(pc18.dim(`no symbol extraction for ${path} (unsupported language)`));
4687
4820
  return;
4688
4821
  }
4689
- const content = await readFile13(resolve13(path), "utf8");
4822
+ const content = await readFile13(resolve12(path), "utf8");
4690
4823
  const table = extractSymbolTable(content);
4691
4824
  if (opts.json) {
4692
4825
  console.log(JSON.stringify({ path, symbols: table }, null, 2));
@@ -4716,7 +4849,7 @@ import pc19 from "picocolors";
4716
4849
  // src/core/global-config.ts
4717
4850
  import { chmod, mkdir as mkdir8, readFile as readFile14, writeFile as writeFile3 } from "fs/promises";
4718
4851
  import { homedir as homedir3 } from "os";
4719
- import { dirname as dirname12, join as join16 } from "path";
4852
+ import { dirname as dirname11, join as join16 } from "path";
4720
4853
  import { z as z2 } from "zod";
4721
4854
  var GLOBAL_DIR = ".codebuddy";
4722
4855
  var GLOBAL_FILE = "global.json";
@@ -4743,7 +4876,7 @@ async function readGlobalConfig(home = homedir3()) {
4743
4876
  }
4744
4877
  async function writeGlobalConfig(next, home = homedir3()) {
4745
4878
  const path = globalConfigPath(home);
4746
- await mkdir8(dirname12(path), { recursive: true, mode: 448 });
4879
+ await mkdir8(dirname11(path), { recursive: true, mode: 448 });
4747
4880
  await writeFile3(path, `${JSON.stringify(next, null, 2)}
4748
4881
  `, { mode: 384 });
4749
4882
  await chmod(path, 384);
@@ -4756,32 +4889,6 @@ async function mergeGlobalConfig(patch, home = homedir3()) {
4756
4889
  return { path, merged };
4757
4890
  }
4758
4891
 
4759
- // src/cli/commands/docker-autostart.ts
4760
- import { spawn as spawn7 } from "child_process";
4761
- async function isDockerDaemonRunning() {
4762
- return new Promise((resolve14) => {
4763
- const child = spawn7("docker", ["info"], { stdio: "ignore" });
4764
- child.on("error", () => resolve14(false));
4765
- child.on("close", (code) => resolve14(code === 0));
4766
- });
4767
- }
4768
- async function tryStartDockerDesktop() {
4769
- if (process.platform !== "darwin") return { started: false };
4770
- return new Promise((resolve14) => {
4771
- const child = spawn7("open", ["-ga", "Docker"], { stdio: "ignore" });
4772
- child.on("error", () => resolve14({ started: false }));
4773
- child.on("close", (code) => resolve14({ started: code === 0 }));
4774
- });
4775
- }
4776
- async function waitForDockerDaemon(timeoutMs = 6e4) {
4777
- const deadline = Date.now() + timeoutMs;
4778
- while (Date.now() < deadline) {
4779
- if (await isDockerDaemonRunning()) return true;
4780
- await new Promise((resolve14) => setTimeout(resolve14, 1e3));
4781
- }
4782
- return false;
4783
- }
4784
-
4785
4892
  // src/cli/commands/use-command.ts
4786
4893
  function bail2() {
4787
4894
  log2.warn("Aborted.");
@@ -4812,6 +4919,7 @@ async function runUseCommand(options = {}) {
4812
4919
  const folderName = basename2(process.cwd());
4813
4920
  const namespace = sanitizeNamespace(options.namespace ?? folderName);
4814
4921
  await initProjectScaffold();
4922
+ if (options.namespace === void 0) await migrateLegacyNamespace();
4815
4923
  const graphifyEnabled = options.graphify ?? unwrap2(
4816
4924
  await confirm2({
4817
4925
  message: "Set up Graphify for richer architecture context?",
@@ -4915,7 +5023,7 @@ Namespace: ${pc19.bold(namespace)}`,
4915
5023
  if (result.code === 0) {
4916
5024
  composeSpinner.stop("Postgres container started.");
4917
5025
  for (let attempt = 0; attempt < 12 && !connected; attempt++) {
4918
- await new Promise((resolve14) => setTimeout(resolve14, 500));
5026
+ await new Promise((resolve13) => setTimeout(resolve13, 500));
4919
5027
  connected = await pingOnce2(databaseUrl);
4920
5028
  }
4921
5029
  if (!connected) {
@@ -5326,7 +5434,7 @@ function createCli() {
5326
5434
  console.log(`Claude Desktop config: ${result.path}`);
5327
5435
  for (const entry of result.entries) {
5328
5436
  console.log(
5329
- ` ${entry.key} namespace=${entry.namespace ?? "?"} db=${entry.databaseUrl ?? "?"}`
5437
+ ` ${entry.key} namespace=${entry.namespace ?? "?"} db=${entry.databaseUrl ? String(redactSecrets(entry.databaseUrl)) : "?"}`
5330
5438
  );
5331
5439
  }
5332
5440
  });
@@ -5371,7 +5479,7 @@ function createCli() {
5371
5479
  console.log(`Codex config: ${result.path}`);
5372
5480
  for (const entry of result.entries) {
5373
5481
  console.log(
5374
- ` ${entry.key} namespace=${entry.namespace ?? "?"} db=${entry.databaseUrl ?? "?"}`
5482
+ ` ${entry.key} namespace=${entry.namespace ?? "?"} db=${entry.databaseUrl ? String(redactSecrets(entry.databaseUrl)) : "?"}`
5375
5483
  );
5376
5484
  }
5377
5485
  });
@@ -5557,6 +5665,9 @@ function printDoctor(report) {
5557
5665
  console.log(
5558
5666
  ` runtime=${report.namespace.runtime ?? "unset"} default=${report.namespace.expectedDefault}`
5559
5667
  );
5668
+ if (report.namespace.migrated) {
5669
+ console.log(` migrated legacy namespace "default" to "${report.namespace.migrated}"`);
5670
+ }
5560
5671
  if (report.namespace.warning) console.log(` ${report.namespace.warning}`);
5561
5672
  console.log(
5562
5673
  `vectors: ${report.vectors.count} index=${report.vectors.index ?? "missing"} tuning=${report.vectors.needsTuning ? "recommended" : "not-needed"}`
@@ -5586,9 +5697,12 @@ function printDbDoctor(report) {
5586
5697
  if (report.pgvector.error) console.log(` ${report.pgvector.error}`);
5587
5698
  console.log(`namespace: ${report.namespace.ok ? ok2 : warn2}`);
5588
5699
  console.log(` runtime=${report.namespace.runtime ?? "unset"}`);
5700
+ if (report.namespace.migrated) {
5701
+ console.log(` migrated legacy namespace "default" to "${report.namespace.migrated}"`);
5702
+ }
5589
5703
  if (report.namespace.warning) console.log(` ${report.namespace.warning}`);
5590
5704
  }
5591
5705
  export {
5592
5706
  createCli
5593
5707
  };
5594
- //# sourceMappingURL=main-BDVQAGAS.js.map
5708
+ //# sourceMappingURL=main-MTBQZGJV.js.map