@phuetz/code-buddy 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (381) hide show
  1. package/README.md +211 -163
  2. package/dist/agent/autonomous/agentic-coding-contract.d.ts +12 -12
  3. package/dist/agent/base-agent.d.ts +4 -0
  4. package/dist/agent/base-agent.js +6 -0
  5. package/dist/agent/codebuddy-agent.d.ts +1 -1
  6. package/dist/agent/codebuddy-agent.js +69 -14
  7. package/dist/agent/execution/agent-executor.js +122 -12
  8. package/dist/agent/execution/tool-dependency-graph.js +7 -0
  9. package/dist/agent/execution/tool-hooks.d.ts +6 -0
  10. package/dist/agent/execution/tool-hooks.js +13 -5
  11. package/dist/agent/execution/tool-selection-strategy.d.ts +11 -2
  12. package/dist/agent/execution/tool-selection-strategy.js +67 -10
  13. package/dist/agent/extended-thinking.d.ts +8 -0
  14. package/dist/agent/extended-thinking.js +27 -0
  15. package/dist/agent/facades/infrastructure-facade.d.ts +9 -2
  16. package/dist/agent/facades/infrastructure-facade.js +15 -6
  17. package/dist/agent/hermes-browser-backends.js +151 -11
  18. package/dist/agent/hermes-claw-migrate.d.ts +59 -0
  19. package/dist/agent/hermes-claw-migrate.js +427 -26
  20. package/dist/agent/hermes-parity-manifest.js +78 -71
  21. package/dist/agent/hermes-runtime-lifecycle.d.ts +67 -0
  22. package/dist/agent/hermes-runtime-lifecycle.js +468 -0
  23. package/dist/agent/middleware/index.d.ts +1 -0
  24. package/dist/agent/middleware/index.js +1 -0
  25. package/dist/agent/middleware/visual-validation-middleware.d.ts +17 -0
  26. package/dist/agent/middleware/visual-validation-middleware.js +67 -0
  27. package/dist/agent/model-benchmark.d.ts +77 -0
  28. package/dist/agent/model-benchmark.js +309 -0
  29. package/dist/agent/model-tier.d.ts +14 -0
  30. package/dist/agent/model-tier.js +71 -0
  31. package/dist/agent/multi-agent/agents/orchestrator-agent.js +17 -6
  32. package/dist/agent/multi-agent/multi-agent-system.js +3 -1
  33. package/dist/agent/multi-agent/session-fleet-bridge.d.ts +2 -0
  34. package/dist/agent/multi-agent/session-fleet-bridge.js +9 -1
  35. package/dist/agent/multi-agent/session-tools.js +22 -5
  36. package/dist/agent/reasoning/mcts.js +20 -6
  37. package/dist/agent/self-improvement/authored-artifact-gate.d.ts +18 -0
  38. package/dist/agent/self-improvement/authored-artifact-gate.js +42 -0
  39. package/dist/agent/self-improvement/authored-tool-runtime.d.ts +27 -0
  40. package/dist/agent/self-improvement/authored-tool-runtime.js +57 -0
  41. package/dist/agent/self-improvement/authored-tool-store.d.ts +24 -0
  42. package/dist/agent/self-improvement/authored-tool-store.js +57 -0
  43. package/dist/agent/self-improvement/llm-tool-proposer.d.ts +41 -0
  44. package/dist/agent/self-improvement/llm-tool-proposer.js +136 -0
  45. package/dist/agent/self-improvement/sandbox-scorer.d.ts +17 -0
  46. package/dist/agent/self-improvement/sandbox-scorer.js +43 -0
  47. package/dist/agent/self-improvement/self-knowledge.d.ts +8 -0
  48. package/dist/agent/self-improvement/self-knowledge.js +24 -0
  49. package/dist/agent/self-improvement/skill-benchmark.d.ts +9 -0
  50. package/dist/agent/self-improvement/skill-benchmark.js +22 -0
  51. package/dist/agent/self-improvement/skill-consolidator.d.ts +71 -0
  52. package/dist/agent/self-improvement/skill-consolidator.js +137 -0
  53. package/dist/agent/self-improvement/skill-engine.d.ts +42 -0
  54. package/dist/agent/self-improvement/skill-engine.js +87 -0
  55. package/dist/agent/self-improvement/skill-gate.d.ts +19 -0
  56. package/dist/agent/self-improvement/skill-gate.js +62 -0
  57. package/dist/agent/self-improvement/skill-mutator.d.ts +74 -0
  58. package/dist/agent/self-improvement/skill-mutator.js +223 -0
  59. package/dist/agent/self-improvement/skill-proposer.d.ts +40 -0
  60. package/dist/agent/self-improvement/skill-proposer.js +82 -0
  61. package/dist/agent/self-improvement/skill-types.d.ts +41 -0
  62. package/dist/agent/self-improvement/skill-types.js +13 -0
  63. package/dist/agent/self-improvement/tool-benchmark.d.ts +10 -0
  64. package/dist/agent/self-improvement/tool-benchmark.js +37 -0
  65. package/dist/agent/self-improvement/tool-engine.d.ts +54 -0
  66. package/dist/agent/self-improvement/tool-engine.js +101 -0
  67. package/dist/agent/self-improvement/tool-gate.d.ts +20 -0
  68. package/dist/agent/self-improvement/tool-gate.js +78 -0
  69. package/dist/agent/self-improvement/tool-proposer.d.ts +31 -0
  70. package/dist/agent/self-improvement/tool-proposer.js +34 -0
  71. package/dist/agent/self-improvement/tool-skill-mutator.d.ts +40 -0
  72. package/dist/agent/self-improvement/tool-skill-mutator.js +79 -0
  73. package/dist/agent/self-improvement/tool-types.d.ts +48 -0
  74. package/dist/agent/self-improvement/tool-types.js +9 -0
  75. package/dist/agent/self-improvement/types.d.ts +3 -1
  76. package/dist/agent/session-end-flush.d.ts +6 -1
  77. package/dist/agent/session-end-flush.js +20 -4
  78. package/dist/agent/streaming/streaming-handler.d.ts +7 -0
  79. package/dist/agent/streaming/streaming-handler.js +8 -1
  80. package/dist/agent/tool-executor.js +1 -0
  81. package/dist/agent/tool-handler.d.ts +5 -0
  82. package/dist/agent/tool-handler.js +133 -4
  83. package/dist/browser-automation/browser-operator-executor.js +15 -0
  84. package/dist/browser-automation/browser-use-runner.d.ts +96 -0
  85. package/dist/browser-automation/browser-use-runner.js +492 -0
  86. package/dist/browser-automation/camofox-runner.d.ts +107 -0
  87. package/dist/browser-automation/camofox-runner.js +287 -0
  88. package/dist/channels/dingtalk/index.js +3 -0
  89. package/dist/channels/discord/client.d.ts +9 -0
  90. package/dist/channels/discord/client.js +12 -0
  91. package/dist/channels/feishu/index.d.ts +167 -1
  92. package/dist/channels/feishu/index.js +432 -7
  93. package/dist/channels/gateway-lifecycle.d.ts +132 -0
  94. package/dist/channels/gateway-lifecycle.js +219 -0
  95. package/dist/channels/google-chat/index.d.ts +5 -1
  96. package/dist/channels/google-chat/index.js +5 -1
  97. package/dist/channels/imessage/index.d.ts +14 -0
  98. package/dist/channels/imessage/index.js +64 -17
  99. package/dist/channels/index.d.ts +4 -0
  100. package/dist/channels/index.js +4 -0
  101. package/dist/channels/irc/index.d.ts +73 -3
  102. package/dist/channels/irc/index.js +446 -11
  103. package/dist/channels/line/index.js +3 -0
  104. package/dist/channels/mattermost/index.d.ts +51 -4
  105. package/dist/channels/mattermost/index.js +303 -20
  106. package/dist/channels/nextcloud-talk/index.d.ts +89 -8
  107. package/dist/channels/nextcloud-talk/index.js +367 -16
  108. package/dist/channels/nostr/index.d.ts +121 -1
  109. package/dist/channels/nostr/index.js +396 -8
  110. package/dist/channels/ntfy/index.js +3 -0
  111. package/dist/channels/qq/index.js +3 -0
  112. package/dist/channels/slash-parity.d.ts +117 -0
  113. package/dist/channels/slash-parity.js +185 -0
  114. package/dist/channels/synology-chat/index.js +3 -0
  115. package/dist/channels/teams/index.d.ts +3 -0
  116. package/dist/channels/teams/index.js +3 -0
  117. package/dist/channels/telegram/client.d.ts +9 -0
  118. package/dist/channels/telegram/client.js +12 -0
  119. package/dist/channels/twilio-voice/index.js +3 -0
  120. package/dist/channels/webchat/index.d.ts +7 -1
  121. package/dist/channels/webchat/index.js +7 -1
  122. package/dist/channels/wecom/index.js +3 -0
  123. package/dist/channels/weixin/index.js +3 -0
  124. package/dist/channels/zalo/index.js +3 -0
  125. package/dist/cli/config-loader.js +1 -1
  126. package/dist/codebuddy/client.d.ts +30 -1
  127. package/dist/codebuddy/client.js +167 -20
  128. package/dist/codebuddy/providers/provider-chatgpt-responses.d.ts +5 -0
  129. package/dist/codebuddy/providers/provider-chatgpt-responses.js +7 -1
  130. package/dist/codebuddy/providers/provider-gemini-native.js +1 -1
  131. package/dist/codebuddy/providers/provider-openai-compat.d.ts +5 -0
  132. package/dist/codebuddy/providers/provider-openai-compat.js +82 -2
  133. package/dist/codebuddy/tool-definitions/computer-control-tools.js +32 -2
  134. package/dist/codebuddy/tool-definitions/core-tools.js +3 -3
  135. package/dist/codebuddy/tool-definitions/index.d.ts +2 -1
  136. package/dist/codebuddy/tool-definitions/index.js +2 -1
  137. package/dist/codebuddy/tool-definitions/multimodal-tools.d.ts +1 -0
  138. package/dist/codebuddy/tool-definitions/multimodal-tools.js +44 -1
  139. package/dist/codebuddy/tool-definitions/windows-tools.d.ts +2 -0
  140. package/dist/codebuddy/tool-definitions/windows-tools.js +34 -0
  141. package/dist/codebuddy/tools.d.ts +8 -1
  142. package/dist/codebuddy/tools.js +67 -24
  143. package/dist/commands/cli/hermes-commands.js +108 -0
  144. package/dist/commands/cli/improve-command.js +123 -0
  145. package/dist/commands/cli/native-engine-commands.js +102 -3
  146. package/dist/commands/cli/utility-commands.js +45 -0
  147. package/dist/commands/enhanced-command-handler.js +2 -2
  148. package/dist/commands/goal-cli.d.ts +30 -0
  149. package/dist/commands/goal-cli.js +210 -27
  150. package/dist/commands/handlers/goal-handler.d.ts +9 -2
  151. package/dist/commands/handlers/goal-handler.js +36 -9
  152. package/dist/commands/handlers/infra-handlers.js +36 -0
  153. package/dist/commands/handlers/memory-handlers.js +96 -1
  154. package/dist/commands/handlers/missing-handlers.d.ts +1 -1
  155. package/dist/commands/handlers/missing-handlers.js +26 -3
  156. package/dist/commands/headless-slash.d.ts +2 -0
  157. package/dist/commands/headless-slash.js +12 -0
  158. package/dist/commands/llm-provider-resolution.d.ts +5 -3
  159. package/dist/commands/llm-provider-resolution.js +87 -33
  160. package/dist/commands/ollama.d.ts +25 -0
  161. package/dist/commands/ollama.js +100 -0
  162. package/dist/commands/provider.d.ts +5 -0
  163. package/dist/commands/provider.js +106 -55
  164. package/dist/commands/skills-cli/index.js +123 -0
  165. package/dist/commands/slash/builtin-commands.js +1 -1
  166. package/dist/commands/spec-next.js +2 -1
  167. package/dist/commands/spec-plan.js +5 -16
  168. package/dist/commands/tunnel.d.ts +2 -0
  169. package/dist/commands/tunnel.js +48 -0
  170. package/dist/companion/percepts.js +11 -1
  171. package/dist/config/config-resolver.d.ts +2 -1
  172. package/dist/config/config-resolver.js +54 -41
  173. package/dist/config/constants.d.ts +28 -0
  174. package/dist/config/constants.js +7 -0
  175. package/dist/config/env-schema.js +756 -0
  176. package/dist/config/model-tools.js +4 -4
  177. package/dist/config/toml-config.d.ts +16 -0
  178. package/dist/config/toml-config.js +3 -0
  179. package/dist/context/bootstrap-loader.js +6 -23
  180. package/dist/context/context-manager-v2.js +1 -0
  181. package/dist/context/import-directive-parser.d.ts +4 -0
  182. package/dist/context/import-directive-parser.js +51 -6
  183. package/dist/context/instruction-excludes.d.ts +30 -1
  184. package/dist/context/instruction-excludes.js +71 -1
  185. package/dist/context/jit-context.d.ts +8 -10
  186. package/dist/context/jit-context.js +28 -106
  187. package/dist/context/project-context.d.ts +90 -0
  188. package/dist/context/project-context.js +295 -0
  189. package/dist/daemon/autonomous-daemon.d.ts +1 -1
  190. package/dist/daemon/autonomous-daemon.js +3 -3
  191. package/dist/daemon/autonomous-loop.d.ts +31 -1
  192. package/dist/daemon/autonomous-loop.js +91 -4
  193. package/dist/daemon/colab-goal.js +9 -1
  194. package/dist/daemon/cron-agent-bridge.d.ts +12 -3
  195. package/dist/daemon/cron-agent-bridge.js +25 -9
  196. package/dist/desktop/codebuddy-engine-adapter.d.ts +32 -0
  197. package/dist/desktop/codebuddy-engine-adapter.js +257 -80
  198. package/dist/desktop/engine-adapter.d.ts +14 -0
  199. package/dist/desktop-automation/automation-manager.js +16 -0
  200. package/dist/desktop-automation/omniparser-runner.d.ts +63 -0
  201. package/dist/desktop-automation/omniparser-runner.js +115 -0
  202. package/dist/desktop-automation/smart-snapshot.d.ts +11 -0
  203. package/dist/desktop-automation/smart-snapshot.js +72 -5
  204. package/dist/doctor/index.js +40 -23
  205. package/dist/events/types.d.ts +11 -0
  206. package/dist/fleet/colab-store.js +14 -2
  207. package/dist/fleet/peer-session-bridge.js +50 -12
  208. package/dist/fleet/peer-tool-bridge.js +14 -0
  209. package/dist/goals/goal-decomposer.d.ts +27 -0
  210. package/dist/goals/goal-decomposer.js +293 -0
  211. package/dist/goals/goal-judge-client.d.ts +15 -0
  212. package/dist/goals/goal-judge-client.js +45 -0
  213. package/dist/goals/goal-judge.d.ts +2 -0
  214. package/dist/goals/goal-judge.js +35 -6
  215. package/dist/goals/goal-loop.d.ts +14 -0
  216. package/dist/goals/goal-loop.js +47 -2
  217. package/dist/goals/goal-manager.d.ts +6 -0
  218. package/dist/goals/goal-manager.js +67 -14
  219. package/dist/goals/goal-state.d.ts +13 -0
  220. package/dist/goals/goal-state.js +83 -13
  221. package/dist/goals/goal-store.d.ts +3 -0
  222. package/dist/goals/goal-store.js +31 -15
  223. package/dist/harness/contract.d.ts +28 -28
  224. package/dist/hooks/user-hooks.js +17 -3
  225. package/dist/identity/identity-manager.js +3 -2
  226. package/dist/index.js +481 -26
  227. package/dist/input/text-to-speech.d.ts +2 -6
  228. package/dist/input/text-to-speech.js +2 -27
  229. package/dist/integrations/screenpipe/screenpipe-client.d.ts +10 -0
  230. package/dist/integrations/screenpipe/screenpipe-client.js +12 -2
  231. package/dist/integrations/tailscale.d.ts +13 -0
  232. package/dist/integrations/tailscale.js +87 -34
  233. package/dist/knowledge/workspace-indexer.js +53 -9
  234. package/dist/mcp/client.js +1 -0
  235. package/dist/mcp/mcp-desktop-tools.d.ts +23 -0
  236. package/dist/mcp/mcp-desktop-tools.js +158 -0
  237. package/dist/mcp/mcp-resources.js +2 -3
  238. package/dist/mcp/mcp-server.js +2 -0
  239. package/dist/memory/enhanced-memory.d.ts +10 -0
  240. package/dist/memory/enhanced-memory.js +33 -2
  241. package/dist/memory/index.d.ts +3 -1
  242. package/dist/memory/index.js +4 -1
  243. package/dist/memory/memory-auto-proposer.d.ts +23 -0
  244. package/dist/memory/memory-auto-proposer.js +308 -0
  245. package/dist/memory/memory-candidate-queue.d.ts +92 -0
  246. package/dist/memory/memory-candidate-queue.js +261 -0
  247. package/dist/memory/persistent-memory.d.ts +45 -2
  248. package/dist/memory/persistent-memory.js +236 -40
  249. package/dist/ml/bayesian-qualifier.d.ts +1 -1
  250. package/dist/ml/bayesian-qualifier.js +35 -2
  251. package/dist/openclaw/gateway-bridge.js +5 -0
  252. package/dist/plugins/marketplace.d.ts +1 -0
  253. package/dist/plugins/marketplace.js +7 -0
  254. package/dist/prompts/execution-discipline.d.ts +14 -0
  255. package/dist/prompts/execution-discipline.js +29 -0
  256. package/dist/prompts/variation-injector.js +9 -2
  257. package/dist/protocols/acp/acp-agentic-runner.d.ts +7 -6
  258. package/dist/protocols/acp/acp-agentic-runner.js +115 -18
  259. package/dist/protocols/acp/acp-session-store.d.ts +23 -0
  260. package/dist/protocols/acp/acp-session-store.js +77 -0
  261. package/dist/protocols/acp/acp-stdio-server.d.ts +7 -0
  262. package/dist/protocols/acp/acp-stdio-server.js +71 -16
  263. package/dist/providers/active-llm-registry.d.ts +37 -0
  264. package/dist/providers/active-llm-registry.js +186 -0
  265. package/dist/providers/auxiliary-provider.d.ts +25 -0
  266. package/dist/providers/auxiliary-provider.js +192 -0
  267. package/dist/providers/codex-oauth.d.ts +1 -1
  268. package/dist/providers/codex-oauth.js +27 -4
  269. package/dist/providers/index.d.ts +3 -0
  270. package/dist/providers/index.js +4 -0
  271. package/dist/providers/provider-catalog.d.ts +70 -0
  272. package/dist/providers/provider-catalog.js +738 -0
  273. package/dist/providers/provider-fallback.d.ts +35 -0
  274. package/dist/providers/provider-fallback.js +171 -0
  275. package/dist/providers/xai-oauth.d.ts +128 -0
  276. package/dist/providers/xai-oauth.js +735 -0
  277. package/dist/scheduler/cron-scheduler.d.ts +15 -3
  278. package/dist/scheduler/cron-scheduler.js +53 -7
  279. package/dist/scheduler/script-runner.d.ts +2 -0
  280. package/dist/scheduler/script-runner.js +19 -4
  281. package/dist/scheduler/watchdog-handlers.js +7 -20
  282. package/dist/search/usearch-index.js +7 -2
  283. package/dist/security/tool-policy/tool-groups.js +2 -0
  284. package/dist/sensory/dreaming.d.ts +45 -0
  285. package/dist/sensory/dreaming.js +114 -0
  286. package/dist/sensory/heartbeat-scheduler.d.ts +38 -0
  287. package/dist/sensory/heartbeat-scheduler.js +72 -0
  288. package/dist/sensory/reactions.d.ts +24 -0
  289. package/dist/sensory/reactions.js +31 -0
  290. package/dist/sensory/screen-reaction.d.ts +23 -0
  291. package/dist/sensory/screen-reaction.js +59 -0
  292. package/dist/sensory/sensory-bridge.d.ts +23 -0
  293. package/dist/sensory/sensory-bridge.js +85 -0
  294. package/dist/sensory/sensory-memory.d.ts +20 -0
  295. package/dist/sensory/sensory-memory.js +39 -0
  296. package/dist/sensory/speech-reaction.d.ts +21 -0
  297. package/dist/sensory/speech-reaction.js +83 -0
  298. package/dist/sensory/vision-reaction.d.ts +31 -0
  299. package/dist/sensory/vision-reaction.js +74 -0
  300. package/dist/server/index.js +106 -2
  301. package/dist/server/routes/mobile.d.ts +12 -4
  302. package/dist/server/routes/mobile.js +116 -1
  303. package/dist/server/tls-config.d.ts +35 -0
  304. package/dist/server/tls-config.js +142 -0
  305. package/dist/server/tunnel-manager.d.ts +20 -0
  306. package/dist/server/tunnel-manager.js +58 -0
  307. package/dist/server/websocket/fleet-bridge.js +5 -0
  308. package/dist/services/prompt-builder.d.ts +11 -0
  309. package/dist/services/prompt-builder.js +124 -17
  310. package/dist/shared/engine-types.d.ts +15 -1
  311. package/dist/sidecar/sidecar-bridge.d.ts +1 -0
  312. package/dist/sidecar/sidecar-bridge.js +21 -10
  313. package/dist/skills/parser.js +3 -0
  314. package/dist/skills/skill-importer.d.ts +58 -0
  315. package/dist/skills/skill-importer.js +261 -0
  316. package/dist/skills/skill-sources.d.ts +20 -0
  317. package/dist/skills/skill-sources.js +102 -0
  318. package/dist/skills/types.d.ts +6 -0
  319. package/dist/spec/spec-store.js +8 -1
  320. package/dist/talk-mode/providers/audioreader-tts.d.ts +1 -1
  321. package/dist/talk-mode/providers/audioreader-tts.js +8 -8
  322. package/dist/templates/project-scaffolding.js +3 -2
  323. package/dist/themes/theme-schema.d.ts +10 -10
  324. package/dist/tools/application-profiles.js +38 -0
  325. package/dist/tools/bash/bash-tool.d.ts +1 -0
  326. package/dist/tools/bash/bash-tool.js +16 -2
  327. package/dist/tools/bash/command-validator.js +3 -0
  328. package/dist/tools/bash/rtk-rewrite.d.ts +16 -0
  329. package/dist/tools/bash/rtk-rewrite.js +100 -0
  330. package/dist/tools/bash/streaming-executor.js +14 -1
  331. package/dist/tools/computer-control-tool.d.ts +16 -1
  332. package/dist/tools/computer-control-tool.js +317 -5
  333. package/dist/tools/document-generator.d.ts +14 -0
  334. package/dist/tools/document-generator.js +79 -0
  335. package/dist/tools/execute-code-rpc-invoker.d.ts +26 -2
  336. package/dist/tools/execute-code-rpc-invoker.js +46 -5
  337. package/dist/tools/metadata.js +28 -0
  338. package/dist/tools/office-macro-tool.d.ts +10 -0
  339. package/dist/tools/office-macro-tool.js +93 -0
  340. package/dist/tools/register-tool-handler.d.ts +25 -0
  341. package/dist/tools/register-tool-handler.js +100 -0
  342. package/dist/tools/registry/index.d.ts +2 -1
  343. package/dist/tools/registry/index.js +2 -1
  344. package/dist/tools/registry/memory-tools.d.ts +20 -0
  345. package/dist/tools/registry/memory-tools.js +225 -3
  346. package/dist/tools/registry/multimodal-tools.js +2 -2
  347. package/dist/tools/registry/vision-tools.d.ts +33 -0
  348. package/dist/tools/registry/vision-tools.js +308 -6
  349. package/dist/tools/registry/windows-tools.d.ts +2 -0
  350. package/dist/tools/registry/windows-tools.js +47 -0
  351. package/dist/tools/registry.d.ts +6 -0
  352. package/dist/tools/registry.js +8 -0
  353. package/dist/tools/route-peer-tool.js +14 -0
  354. package/dist/tools/screenshot-tool.js +14 -2
  355. package/dist/tools/text-to-speech-tool.d.ts +1 -1
  356. package/dist/tools/text-to-speech-tool.js +2 -12
  357. package/dist/tools/tool-selector.js +3 -59
  358. package/dist/utils/config-validation/schema.d.ts +40 -7
  359. package/dist/utils/config-validation/schema.js +130 -1
  360. package/dist/utils/cost-tracker.js +21 -1
  361. package/dist/utils/disk-guard.d.ts +180 -0
  362. package/dist/utils/disk-guard.js +404 -0
  363. package/dist/utils/init-project.d.ts +7 -0
  364. package/dist/utils/init-project.js +37 -0
  365. package/dist/utils/interactive-setup.js +35 -2
  366. package/dist/utils/model-utils.js +11 -2
  367. package/dist/utils/output-sanitizer.js +11 -0
  368. package/dist/utils/provider-detector.d.ts +8 -7
  369. package/dist/utils/provider-detector.js +19 -77
  370. package/dist/utils/settings-manager.d.ts +19 -0
  371. package/dist/utils/token-display.d.ts +3 -3
  372. package/dist/utils/token-display.js +22 -4
  373. package/dist/wizard/onboarding.d.ts +39 -0
  374. package/dist/wizard/onboarding.js +433 -21
  375. package/dist/wizard/provider-onboarding.d.ts +8 -23
  376. package/dist/wizard/provider-onboarding.js +39 -158
  377. package/package.json +4 -2
  378. package/dist/plugins/provider-onboarding.d.ts +0 -23
  379. package/dist/plugins/provider-onboarding.js +0 -116
  380. package/dist/utils/kokoro-tts.d.ts +0 -8
  381. package/dist/utils/kokoro-tts.js +0 -67
@@ -405,13 +405,13 @@ const DEFAULT_MODEL_CONFIGS = [
405
405
  patchFormat: 'full_file',
406
406
  promptProfile: 'lite',
407
407
  },
408
- // Gemma 4 (Ollama, e2b/e4b) — local lightweight model. Same lite
409
- // profile as qwen/llama: minimal SP, no tool_calls advertised,
410
- // chat-only base prompt to avoid JSON hallucination on small models.
408
+ // Gemma 4 (Ollama, e2b/e4b) — local model with tool support. Keep the
409
+ // lite prompt/tool profile, but do not gate off tool calls: real `buddy goal`
410
+ // smoke with gemma4:12b only succeeds when the selected tools are preserved.
411
411
  {
412
412
  model: 'gemma4*',
413
413
  supportsReasoning: false,
414
- supportsToolCalls: false,
414
+ supportsToolCalls: true,
415
415
  supportsVision: false,
416
416
  contextWindow: 8192,
417
417
  maxOutputTokens: 2048,
@@ -122,6 +122,20 @@ export interface ModelPairsConfig {
122
122
  /** Model used for code edits and execution (the "doer") */
123
123
  editor?: string;
124
124
  }
125
+ /** Active-LLM registry: auto-failover across the user's live logins + "together". */
126
+ export interface LlmFailoverConfig {
127
+ /** Master gate. OFF by default — single-provider behavior is unchanged. */
128
+ enabled?: boolean;
129
+ /** Fallback ordering: 'resilience' (capable/subscription first, local last),
130
+ * 'free-first' (cheapest first), or 'manual' (explicit `manualOrder`). */
131
+ order?: 'resilience' | 'free-first' | 'manual';
132
+ /** Provider ids in preferred order when `order: 'manual'`. */
133
+ manualOrder?: string[];
134
+ /** Restrict the active set to local runtimes (privacy). */
135
+ local_only?: boolean;
136
+ /** Default strategy for `/llm ensemble` (Phase 2). */
137
+ together_strategy?: 'ensemble' | 'consensus' | 'fastest' | 'cascade';
138
+ }
125
139
  /**
126
140
  * External integrations configuration
127
141
  */
@@ -497,6 +511,8 @@ export interface CodeBuddyConfig {
497
511
  integrations: IntegrationsConfig;
498
512
  /** Model pairs for architect/editor split */
499
513
  model_pairs?: ModelPairsConfig;
514
+ /** Active-LLM registry: auto-failover across live logins + "together" */
515
+ llm?: LlmFailoverConfig;
500
516
  /** Agent defaults (model preferences) — Native Engine v2026.3.14 */
501
517
  agent_defaults?: AgentDefaultsConfig;
502
518
  /** Advisor tool settings (second opinion model) — V4.1 */
@@ -540,6 +540,9 @@ class ConfigManager {
540
540
  if (partial.model_pairs) {
541
541
  this.config.model_pairs = { ...this.config.model_pairs, ...partial.model_pairs };
542
542
  }
543
+ if (partial.llm) {
544
+ this.config.llm = { ...this.config.llm, ...partial.llm };
545
+ }
543
546
  }
544
547
  /**
545
548
  * Get current config
@@ -15,10 +15,12 @@ import { logger } from '../utils/logger.js';
15
15
  // ============================================================================
16
16
  // Defaults
17
17
  // ============================================================================
18
+ // AGENTS.md is intentionally NOT here — instruction files (AGENTS/CODEBUDDY/
19
+ // CONTEXT/INSTRUCTIONS) are owned by the unified project-context loader
20
+ // (src/context/project-context.ts). This loader covers soul/identity files.
18
21
  const DEFAULT_BOOTSTRAP_FILES = [
19
22
  'BOOT.md',
20
23
  'BOOTSTRAP.md',
21
- 'AGENTS.md',
22
24
  'SOUL.md',
23
25
  // TOOLS.md excluded: tool descriptions are already sent as function definitions
24
26
  'IDENTITY.md',
@@ -80,28 +82,9 @@ export class BootstrapLoader {
80
82
  sources.push(content.source);
81
83
  totalChars += text.length;
82
84
  }
83
- // 2. Hierarchical instruction files (Codex CLI pattern)
84
- if (totalChars < this.config.maxChars) {
85
- const hierarchicalResult = await this.loadHierarchical(cwd);
86
- for (const entry of hierarchicalResult) {
87
- if (totalChars >= this.config.maxChars) {
88
- truncated = true;
89
- break;
90
- }
91
- if (sources.includes(entry.source))
92
- continue;
93
- const remaining = this.config.maxChars - totalChars;
94
- let text = entry.text;
95
- if (text.length > remaining) {
96
- text = text.slice(0, remaining) + '\n\n... (truncated)';
97
- truncated = true;
98
- }
99
- const relSource = path.relative(cwd, entry.source) || entry.source;
100
- sections.push(`## ${entry.fileName} (${relSource})\n\n${text}`);
101
- sources.push(entry.source);
102
- totalChars += text.length;
103
- }
104
- }
85
+ // (Instruction-file hierarchy AGENTS/CODEBUDDY/CONTEXT/INSTRUCTIONS is
86
+ // now handled by the unified project-context loader, injected before this
87
+ // block in prompt-builder. `loadHierarchical` below is retained but unused.)
105
88
  // 3. Auto-generated project knowledge (from /docs generate --with-llm)
106
89
  if (totalChars < this.config.maxChars) {
107
90
  const knowledgePath = path.join(cwd, '.codebuddy', 'PROJECT_KNOWLEDGE.md');
@@ -699,6 +699,7 @@ export class ContextManagerV2 {
699
699
  * Clean up resources
700
700
  */
701
701
  dispose() {
702
+ this.stopPeriodicSnapshot();
702
703
  this.tokenCounter.dispose();
703
704
  this.summaries = [];
704
705
  this.triggeredWarnings.clear();
@@ -27,6 +27,10 @@ export interface ImportResolveOptions {
27
27
  depth?: number;
28
28
  /** Set of already-visited absolute paths (cycle detection) */
29
29
  visited?: Set<string>;
30
+ /** Max recursion depth for nested imports (default 5) */
31
+ maxDepth?: number;
32
+ /** Max total content size after imports, in chars (default 50000) */
33
+ maxBytes?: number;
30
34
  }
31
35
  /**
32
36
  * Resolve all @import directives in the given content.
@@ -43,14 +43,23 @@ const IMPORT_DIRECTIVE_REGEX = /^@(~\/|\/\/|[^\s@].+?)$/gm;
43
43
  * @returns Content with all imports resolved inline
44
44
  */
45
45
  export function resolveImportDirectives(content, options) {
46
- const { baseDir, projectRoot = process.cwd(), homeDir = process.env.HOME || process.env.USERPROFILE || '', depth = 0, visited = new Set(), } = options;
47
- if (depth >= MAX_IMPORT_DEPTH) {
48
- logger.debug(`Import directive: max depth ${MAX_IMPORT_DEPTH} reached, skipping further imports`);
46
+ const { baseDir, projectRoot = process.cwd(), homeDir = process.env.HOME || process.env.USERPROFILE || '', depth = 0, visited = new Set(), maxDepth = MAX_IMPORT_DEPTH, maxBytes = MAX_IMPORT_CONTENT, } = options;
47
+ if (depth >= maxDepth) {
48
+ logger.debug(`Import directive: max depth ${maxDepth} reached, skipping further imports`);
49
49
  return content;
50
50
  }
51
51
  let result = content;
52
52
  let totalSize = content.length;
53
- result = result.replace(IMPORT_DIRECTIVE_REGEX, (fullMatch, importPath) => {
53
+ // Mask code regions so an @path directive that sits inside a fenced block or
54
+ // inline code span is left as literal content, not resolved as an import.
55
+ // Matches Claude Code / Gemini CLI semantics (a code example that mentions
56
+ // `@./foo.md` must not trigger a file read).
57
+ const codeRegions = findCodeRegions(content);
58
+ result = result.replace(IMPORT_DIRECTIVE_REGEX, (fullMatch, importPath, offset) => {
59
+ // Leave directives inside code spans/fences untouched.
60
+ if (isInsideRegion(offset, codeRegions)) {
61
+ return fullMatch;
62
+ }
54
63
  // Resolve the import path
55
64
  const resolvedPath = resolveImportPath(importPath.trim(), baseDir, projectRoot, homeDir);
56
65
  if (!resolvedPath) {
@@ -71,9 +80,9 @@ export function resolveImportDirectives(content, options) {
71
80
  try {
72
81
  let importedContent = fs.readFileSync(absolutePath, 'utf-8');
73
82
  // Size guard
74
- if (totalSize + importedContent.length > MAX_IMPORT_CONTENT) {
83
+ if (totalSize + importedContent.length > maxBytes) {
75
84
  logger.debug(`Import directive: size limit reached, truncating "${importPath}"`);
76
- const remaining = MAX_IMPORT_CONTENT - totalSize;
85
+ const remaining = maxBytes - totalSize;
77
86
  if (remaining <= 0) {
78
87
  return `<!-- import truncated: ${importPath} -->`;
79
88
  }
@@ -88,6 +97,8 @@ export function resolveImportDirectives(content, options) {
88
97
  homeDir,
89
98
  depth: depth + 1,
90
99
  visited: newVisited,
100
+ maxDepth,
101
+ maxBytes,
91
102
  });
92
103
  totalSize += resolved.length;
93
104
  logger.debug(`Import directive: resolved "${importPath}" (${resolved.length} chars)`);
@@ -129,4 +140,38 @@ function resolveImportPath(importPath, baseDir, projectRoot, homeDir) {
129
140
  return null;
130
141
  }
131
142
  }
143
+ // ============================================================================
144
+ // Code-region masking (so @imports inside code are inert)
145
+ // ============================================================================
146
+ /**
147
+ * Find all code spans/fences in the content as [start, end) ranges.
148
+ *
149
+ * Covers backtick code — inline `` `…` `` and fenced ```` ```…``` ```` (one or
150
+ * more backticks, closed by the same count) — plus `~~~` fenced blocks. An
151
+ * @import directive whose `@` falls inside any of these ranges is treated as
152
+ * literal text. Mirrors the gemini-cli memory import processor.
153
+ */
154
+ function findCodeRegions(content) {
155
+ const regions = [];
156
+ // Backtick inline + fenced: one or more backticks, lazily to the same run.
157
+ const backtick = /(`+)([\s\S]*?)\1/g;
158
+ let m;
159
+ while ((m = backtick.exec(content)) !== null) {
160
+ regions.push([m.index, m.index + m[0].length]);
161
+ }
162
+ // Tilde fenced blocks: a line of >=3 tildes, content, closing tilde line.
163
+ const tilde = /^[^\S\n]*(~{3,})[^\n]*\n[\s\S]*?\n[^\S\n]*\1[^\S\n]*$/gm;
164
+ while ((m = tilde.exec(content)) !== null) {
165
+ regions.push([m.index, m.index + m[0].length]);
166
+ }
167
+ return regions;
168
+ }
169
+ /** True if `offset` lies within any [start, end) code region. */
170
+ function isInsideRegion(offset, regions) {
171
+ for (const [start, end] of regions) {
172
+ if (offset >= start && offset < end)
173
+ return true;
174
+ }
175
+ return false;
176
+ }
132
177
  //# sourceMappingURL=import-directive-parser.js.map
@@ -7,9 +7,38 @@
7
7
  * Advanced enterprise architecture for claudeMdExcludes setting.
8
8
  */
9
9
  /**
10
- * Clear the excludes cache (for testing).
10
+ * Clear the excludes cache (for testing / config reload).
11
11
  */
12
12
  export declare function clearExcludesCache(): void;
13
+ /**
14
+ * Clear the context-config cache (for testing / `/context reload`).
15
+ */
16
+ export declare function clearContextConfigCache(): void;
17
+ /**
18
+ * Accepted project-instruction filenames, in precedence order. `AGENTS.md` is
19
+ * the cross-CLI primary (read by Codex/Cursor/Copilot/Claude Code); the rest
20
+ * are read for interop. All present names compose within a directory.
21
+ */
22
+ export declare const DEFAULT_CONTEXT_FILE_NAMES: readonly string[];
23
+ export interface ResolvedContextConfig {
24
+ /** Accepted instruction filenames, in precedence order. */
25
+ fileNames: string[];
26
+ /** Total byte budget for the startup hierarchy (Codex project_doc_max_bytes parity). */
27
+ maxBytes: number;
28
+ /** Per-touch incremental byte budget for JIT discovery. */
29
+ jitMaxBytes: number;
30
+ /** Byte budget passed to the @import resolver. */
31
+ importMaxBytes: number;
32
+ /** Max recursion depth for @import. */
33
+ importMaxDepth: number;
34
+ }
35
+ /**
36
+ * Load the `context` block from `.codebuddy/settings.json`, merged over
37
+ * defaults. Cached by settings path (cleared via `clearContextConfigCache()`).
38
+ * A missing `context` key returns the defaults, so existing projects are
39
+ * unaffected.
40
+ */
41
+ export declare function loadContextConfig(projectRoot?: string): ResolvedContextConfig;
13
42
  /**
14
43
  * Load exclude patterns from settings.json.
15
44
  * Returns an array of glob patterns (e.g., ["packages/legacy/**"]).
@@ -15,13 +15,83 @@ import { logger } from '../utils/logger.js';
15
15
  // ============================================================================
16
16
  let _excludePatterns = null;
17
17
  let _excludeCachePath = null;
18
+ let _contextConfig = null;
19
+ let _contextConfigCachePath = null;
18
20
  /**
19
- * Clear the excludes cache (for testing).
21
+ * Clear the excludes cache (for testing / config reload).
20
22
  */
21
23
  export function clearExcludesCache() {
22
24
  _excludePatterns = null;
23
25
  _excludeCachePath = null;
24
26
  }
27
+ /**
28
+ * Clear the context-config cache (for testing / `/context reload`).
29
+ */
30
+ export function clearContextConfigCache() {
31
+ _contextConfig = null;
32
+ _contextConfigCachePath = null;
33
+ }
34
+ // ============================================================================
35
+ // Context-file configuration (single source of truth for accepted filenames)
36
+ // ============================================================================
37
+ /**
38
+ * Accepted project-instruction filenames, in precedence order. `AGENTS.md` is
39
+ * the cross-CLI primary (read by Codex/Cursor/Copilot/Claude Code); the rest
40
+ * are read for interop. All present names compose within a directory.
41
+ */
42
+ export const DEFAULT_CONTEXT_FILE_NAMES = [
43
+ 'AGENTS.md',
44
+ 'CODEBUDDY.md',
45
+ 'CLAUDE.md',
46
+ 'GEMINI.md',
47
+ 'CONTEXT.md',
48
+ 'INSTRUCTIONS.md',
49
+ ];
50
+ const DEFAULT_CONTEXT_CONFIG = {
51
+ fileNames: [...DEFAULT_CONTEXT_FILE_NAMES],
52
+ maxBytes: 32_768,
53
+ jitMaxBytes: 4_096,
54
+ importMaxBytes: 50_000,
55
+ importMaxDepth: 5,
56
+ };
57
+ /**
58
+ * Load the `context` block from `.codebuddy/settings.json`, merged over
59
+ * defaults. Cached by settings path (cleared via `clearContextConfigCache()`).
60
+ * A missing `context` key returns the defaults, so existing projects are
61
+ * unaffected.
62
+ */
63
+ export function loadContextConfig(projectRoot = process.cwd()) {
64
+ const settingsPath = path.join(projectRoot, '.codebuddy', 'settings.json');
65
+ if (_contextConfig && _contextConfigCachePath === settingsPath) {
66
+ return _contextConfig;
67
+ }
68
+ const cfg = { ...DEFAULT_CONTEXT_CONFIG, fileNames: [...DEFAULT_CONTEXT_FILE_NAMES] };
69
+ if (fs.existsSync(settingsPath)) {
70
+ try {
71
+ const raw = fs.readFileSync(settingsPath, 'utf-8');
72
+ const ctx = JSON.parse(raw)?.context;
73
+ if (ctx && typeof ctx === 'object') {
74
+ if (Array.isArray(ctx.fileNames) && ctx.fileNames.every((n) => typeof n === 'string') && ctx.fileNames.length > 0) {
75
+ cfg.fileNames = ctx.fileNames;
76
+ }
77
+ if (Number.isFinite(ctx.maxBytes) && ctx.maxBytes > 0)
78
+ cfg.maxBytes = ctx.maxBytes;
79
+ if (Number.isFinite(ctx.jitMaxBytes) && ctx.jitMaxBytes > 0)
80
+ cfg.jitMaxBytes = ctx.jitMaxBytes;
81
+ if (Number.isFinite(ctx.importMaxBytes) && ctx.importMaxBytes > 0)
82
+ cfg.importMaxBytes = ctx.importMaxBytes;
83
+ if (Number.isFinite(ctx.importMaxDepth) && ctx.importMaxDepth > 0)
84
+ cfg.importMaxDepth = ctx.importMaxDepth;
85
+ }
86
+ }
87
+ catch (err) {
88
+ logger.debug(`Failed to load context config: ${err}`);
89
+ }
90
+ }
91
+ _contextConfig = cfg;
92
+ _contextConfigCachePath = settingsPath;
93
+ return cfg;
94
+ }
25
95
  // ============================================================================
26
96
  // Loader
27
97
  // ============================================================================
@@ -1,24 +1,22 @@
1
1
  /**
2
2
  * JIT (Just-In-Time) Context Discovery
3
3
  *
4
- * Dynamically loads .codebuddy/ context files when tools access
5
- * subdirectories. Context grows organically as the agent explores,
6
- * rather than loading everything at startup.
4
+ * When a tool accesses a path, this loads the instruction files in that
5
+ * subtree that weren't already injected at startup (delegated to the unified
6
+ * `project-context` loader, sharing its dedup registry), plus two JIT-only
7
+ * concerns: auto-discovered doc pages (DOC_DIR_MAP) and path-scoped rules.
7
8
  *
8
- * Inspired by Gemini CLI's jit-context.ts
9
+ * Inspired by Gemini CLI's jit-context.
9
10
  */
10
11
  export declare const JIT_CONTEXT_PREFIX = "\n\n--- Discovered Context ---\n";
11
12
  export declare const JIT_CONTEXT_SUFFIX = "\n--- End Context ---";
12
13
  /**
13
- * Clear loaded paths cache (for testing).
14
+ * Clear caches (for testing / `/context reload`). Resets both the doc dedup set
15
+ * and the active context registry so the next pass re-scans from scratch.
14
16
  */
15
17
  export declare function clearJitCache(): void;
16
18
  /**
17
- * Discover and load context files for a given accessed path.
18
- *
19
- * Walks upward from the accessed file's directory to the project root,
20
- * checking for context files at each level. Only loads files that
21
- * haven't been loaded before in this session.
19
+ * Discover and load JIT context for a given accessed path.
22
20
  *
23
21
  * @param accessedPath - The file/directory path being accessed by a tool
24
22
  * @param projectRoot - The project root directory (stop walking here)
@@ -1,28 +1,18 @@
1
1
  /**
2
2
  * JIT (Just-In-Time) Context Discovery
3
3
  *
4
- * Dynamically loads .codebuddy/ context files when tools access
5
- * subdirectories. Context grows organically as the agent explores,
6
- * rather than loading everything at startup.
4
+ * When a tool accesses a path, this loads the instruction files in that
5
+ * subtree that weren't already injected at startup (delegated to the unified
6
+ * `project-context` loader, sharing its dedup registry), plus two JIT-only
7
+ * concerns: auto-discovered doc pages (DOC_DIR_MAP) and path-scoped rules.
7
8
  *
8
- * Inspired by Gemini CLI's jit-context.ts
9
+ * Inspired by Gemini CLI's jit-context.
9
10
  */
10
11
  import * as fs from 'fs';
11
12
  import * as path from 'path';
12
13
  import { logger } from '../utils/logger.js';
13
14
  import { discoverRulesForPath } from './rules-loader.js';
14
- import { shouldExcludeInstructionFile } from './instruction-excludes.js';
15
- import { resolveImportDirectives } from './import-directive-parser.js';
16
- /** Context file names to discover */
17
- const CONTEXT_FILES = [
18
- 'CODEBUDDY.md',
19
- 'CONTEXT.md',
20
- 'INSTRUCTIONS.md',
21
- 'AGENTS.md',
22
- 'README.md',
23
- ];
24
- /** Directories that may contain context files */
25
- const CONTEXT_DIRS = ['.codebuddy', '.claude'];
15
+ import { resolveJitContext, getActiveContextRegistry } from './project-context.js';
26
16
  /**
27
17
  * Map of source directory prefixes → relevant doc page slugs.
28
18
  * When a tool accesses a path under a key, the matching doc is auto-discovered.
@@ -45,26 +35,22 @@ const DOC_DIR_MAP = {
45
35
  'src/checkpoints': ['architecture'],
46
36
  'tests': ['testing'],
47
37
  };
48
- /** Set of already-loaded paths (avoid re-loading) */
38
+ /** Set of already-loaded doc paths (instruction files dedup via the registry). */
49
39
  const loadedPaths = new Set();
50
40
  /** Maximum context size per discovery (chars) */
51
41
  const MAX_JIT_CONTEXT_CHARS = 4000;
52
- /** Maximum directory depth to traverse upward */
53
- const MAX_UPWARD_DEPTH = 10;
54
42
  export const JIT_CONTEXT_PREFIX = '\n\n--- Discovered Context ---\n';
55
43
  export const JIT_CONTEXT_SUFFIX = '\n--- End Context ---';
56
44
  /**
57
- * Clear loaded paths cache (for testing).
45
+ * Clear caches (for testing / `/context reload`). Resets both the doc dedup set
46
+ * and the active context registry so the next pass re-scans from scratch.
58
47
  */
59
48
  export function clearJitCache() {
60
49
  loadedPaths.clear();
50
+ getActiveContextRegistry().clear();
61
51
  }
62
52
  /**
63
- * Discover and load context files for a given accessed path.
64
- *
65
- * Walks upward from the accessed file's directory to the project root,
66
- * checking for context files at each level. Only loads files that
67
- * haven't been loaded before in this session.
53
+ * Discover and load JIT context for a given accessed path.
68
54
  *
69
55
  * @param accessedPath - The file/directory path being accessed by a tool
70
56
  * @param projectRoot - The project root directory (stop walking here)
@@ -74,84 +60,18 @@ export function discoverJitContext(accessedPath, projectRoot = process.cwd()) {
74
60
  try {
75
61
  const normalizedRoot = path.resolve(projectRoot);
76
62
  const normalizedPath = path.resolve(accessedPath);
77
- // Start from the accessed file's directory
78
- let currentDir = fs.existsSync(normalizedPath) && fs.statSync(normalizedPath).isDirectory()
79
- ? normalizedPath
80
- : path.dirname(normalizedPath);
81
63
  const discoveredContent = [];
82
- let depth = 0;
83
- while (depth < MAX_UPWARD_DEPTH) {
84
- // Check if we've gone above the project root
85
- if (!currentDir.startsWith(normalizedRoot) && currentDir !== normalizedRoot) {
86
- break;
87
- }
88
- // Look for context files in this directory
89
- for (const contextFile of CONTEXT_FILES) {
90
- const filePath = path.join(currentDir, contextFile);
91
- if (!loadedPaths.has(filePath) && fs.existsSync(filePath)) {
92
- // CC10: Check instruction excludes
93
- if (shouldExcludeInstructionFile(filePath, normalizedRoot)) {
94
- logger.debug(`JIT context: excluded ${path.relative(normalizedRoot, filePath)}`);
95
- loadedPaths.add(filePath); // Mark as "seen" to avoid re-checking
96
- continue;
97
- }
98
- try {
99
- let content = fs.readFileSync(filePath, 'utf-8');
100
- if (content.trim()) {
101
- // CC9: Resolve @import directives
102
- content = resolveImportDirectives(content, {
103
- baseDir: path.dirname(filePath),
104
- projectRoot: normalizedRoot,
105
- });
106
- const relativePath = path.relative(normalizedRoot, filePath).replace(/\\/g, '/');
107
- discoveredContent.push(`[${relativePath}]\n${content.trim()}`);
108
- loadedPaths.add(filePath);
109
- logger.debug(`JIT context: loaded ${relativePath}`);
110
- }
111
- }
112
- catch { /* read error — skip */ }
113
- }
114
- }
115
- // Also check .codebuddy/ and .claude/ subdirectories
116
- for (const contextDir of CONTEXT_DIRS) {
117
- const dirPath = path.join(currentDir, contextDir);
118
- if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
119
- for (const contextFile of CONTEXT_FILES) {
120
- const filePath = path.join(dirPath, contextFile);
121
- if (!loadedPaths.has(filePath) && fs.existsSync(filePath)) {
122
- // CC10: Check instruction excludes
123
- if (shouldExcludeInstructionFile(filePath, normalizedRoot)) {
124
- logger.debug(`JIT context: excluded ${path.relative(normalizedRoot, filePath)}`);
125
- loadedPaths.add(filePath);
126
- continue;
127
- }
128
- try {
129
- let content = fs.readFileSync(filePath, 'utf-8');
130
- if (content.trim()) {
131
- // CC9: Resolve @import directives
132
- content = resolveImportDirectives(content, {
133
- baseDir: path.dirname(filePath),
134
- projectRoot: normalizedRoot,
135
- });
136
- const relativePath = path.relative(normalizedRoot, filePath).replace(/\\/g, '/');
137
- discoveredContent.push(`[${relativePath}]\n${content.trim()}`);
138
- loadedPaths.add(filePath);
139
- logger.debug(`JIT context: loaded ${relativePath}`);
140
- }
141
- }
142
- catch { /* read error — skip */ }
143
- }
144
- }
145
- }
146
- }
147
- // Move up
148
- const parent = path.dirname(currentDir);
149
- if (parent === currentDir)
150
- break; // reached filesystem root
151
- currentDir = parent;
152
- depth++;
64
+ // 1. Instruction files in the accessed subtree, via the unified loader.
65
+ // The shared active registry skips anything already injected at startup,
66
+ // so the same AGENTS.md/CODEBUDDY.md is never duplicated.
67
+ const ctx = resolveJitContext(accessedPath, {
68
+ projectRoot: normalizedRoot,
69
+ registry: getActiveContextRegistry(),
70
+ });
71
+ if (ctx.text) {
72
+ discoveredContent.push(ctx.text);
153
73
  }
154
- // Auto-discover relevant doc pages based on accessed path
74
+ // 2. Auto-discover relevant doc pages based on the accessed path.
155
75
  const relativePath = path.relative(normalizedRoot, normalizedPath).replace(/\\/g, '/');
156
76
  for (const [prefix, slugPatterns] of Object.entries(DOC_DIR_MAP)) {
157
77
  if (!relativePath.startsWith(prefix))
@@ -160,16 +80,16 @@ export function discoverJitContext(accessedPath, projectRoot = process.cwd()) {
160
80
  if (!fs.existsSync(docsDir))
161
81
  break;
162
82
  try {
163
- const docFiles = fs.readdirSync(docsDir).filter(f => f.endsWith('.md'));
83
+ const docFiles = fs.readdirSync(docsDir).filter((f) => f.endsWith('.md'));
164
84
  for (const pattern of slugPatterns) {
165
- const match = docFiles.find(f => f.includes(pattern));
85
+ const match = docFiles.find((f) => f.includes(pattern));
166
86
  if (!match)
167
87
  continue;
168
88
  const docPath = path.join(docsDir, match);
169
89
  if (loadedPaths.has(docPath))
170
90
  continue;
171
91
  const content = fs.readFileSync(docPath, 'utf-8');
172
- // Only inject the first 2 sections (title + first H2) to stay compact
92
+ // Only inject the first 2 sections (title + first H2) to stay compact.
173
93
  const sections = content.split(/(?=^## )/m);
174
94
  const compact = sections.slice(0, 2).join('').trim();
175
95
  if (compact) {
@@ -181,10 +101,12 @@ export function discoverJitContext(accessedPath, projectRoot = process.cwd()) {
181
101
  break; // One doc per prefix
182
102
  }
183
103
  }
184
- catch { /* docs dir not readable */ }
104
+ catch {
105
+ /* docs dir not readable */
106
+ }
185
107
  break; // One prefix match
186
108
  }
187
- // Discover path-scoped rules matching this access
109
+ // 3. Path-scoped rules matching this access.
188
110
  const rulesContext = discoverRulesForPath(accessedPath, projectRoot);
189
111
  if (rulesContext) {
190
112
  discoveredContent.push(rulesContext);