@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
@@ -1,7 +1,7 @@
1
1
  import { EventEmitter } from 'events';
2
2
  export interface TTSConfig {
3
3
  enabled: boolean;
4
- provider: 'edge-tts' | 'espeak' | 'say' | 'piper' | 'audioreader' | 'kokoro';
4
+ provider: 'edge-tts' | 'espeak' | 'say' | 'piper' | 'audioreader';
5
5
  voice?: string;
6
6
  rate?: string;
7
7
  volume?: string;
@@ -62,13 +62,9 @@ export declare class TextToSpeechManager extends EventEmitter {
62
62
  */
63
63
  private speakWithPiper;
64
64
  /**
65
- * Speak with AudioReader (Kokoro-82M via local API)
65
+ * Speak with AudioReader via local API
66
66
  */
67
67
  private speakWithAudioReader;
68
- /**
69
- * Speak with local Kokoro TTS model (quantized ONNX hexgrad/Kokoro-82M)
70
- */
71
- private speakWithKokoro;
72
68
  /**
73
69
  * Play audio file using available player
74
70
  */
@@ -80,9 +80,6 @@ export class TextToSpeechManager extends EventEmitter {
80
80
  * Check if TTS is available
81
81
  */
82
82
  async isAvailable() {
83
- if (this.config.provider === 'kokoro') {
84
- return { available: true };
85
- }
86
83
  // AudioReader uses HTTP API, not a CLI binary
87
84
  if (this.config.provider === 'audioreader') {
88
85
  try {
@@ -166,9 +163,6 @@ export class TextToSpeechManager extends EventEmitter {
166
163
  case 'audioreader':
167
164
  await this.speakWithAudioReader(text);
168
165
  break;
169
- case 'kokoro':
170
- await this.speakWithKokoro(text);
171
- break;
172
166
  default:
173
167
  await this.speakWithEdgeTTS(text, language);
174
168
  }
@@ -303,7 +297,7 @@ export class TextToSpeechManager extends EventEmitter {
303
297
  });
304
298
  }
305
299
  /**
306
- * Speak with AudioReader (Kokoro-82M via local API)
300
+ * Speak with AudioReader via local API
307
301
  */
308
302
  async speakWithAudioReader(text) {
309
303
  const voice = this.config.voice || 'ff_siwis';
@@ -311,7 +305,7 @@ export class TextToSpeechManager extends EventEmitter {
311
305
  method: 'POST',
312
306
  headers: { 'Content-Type': 'application/json' },
313
307
  body: JSON.stringify({
314
- model: 'kokoro',
308
+ model: 'audioreader',
315
309
  input: text,
316
310
  voice,
317
311
  speed: 1.0,
@@ -334,25 +328,6 @@ export class TextToSpeechManager extends EventEmitter {
334
328
  catch { /* ignore */ }
335
329
  }
336
330
  }
337
- /**
338
- * Speak with local Kokoro TTS model (quantized ONNX hexgrad/Kokoro-82M)
339
- */
340
- async speakWithKokoro(text) {
341
- const { kokoroTtsService } = await import('../utils/kokoro-tts.js');
342
- const voice = this.config.voice || 'af_bella';
343
- const buffer = await kokoroTtsService.generateSpeech(text, voice);
344
- const audioFile = path.join(this.tempDir, `tts_${Date.now()}.wav`);
345
- fs.writeFileSync(audioFile, buffer);
346
- try {
347
- await this.playAudio(audioFile);
348
- }
349
- finally {
350
- try {
351
- fs.unlinkSync(audioFile);
352
- }
353
- catch { /* ignore */ }
354
- }
355
- }
356
331
  /**
357
332
  * Play audio file using available player
358
333
  */
@@ -7,6 +7,11 @@
7
7
  * say / hear?" from screen+audio history — local-first, no cloud. Base URL is
8
8
  * configurable via `SCREENPIPE_URL` (default http://localhost:3030).
9
9
  *
10
+ * Recent screenpipe builds require a Bearer token on the local API. Pass it via
11
+ * `apiKey` (or `SCREENPIPE_API_KEY`) and it is attached as `Authorization:
12
+ * Bearer <key>` to every request. When unset, requests are sent unauthenticated
13
+ * exactly as before, so local no-auth instances keep working.
14
+ *
10
15
  * `fetchImpl` is injectable for tests.
11
16
  */
12
17
  export type ScreenpipeContentType = 'all' | 'ocr' | 'audio' | 'ui';
@@ -37,6 +42,7 @@ export interface ScreenpipeSearchResult {
37
42
  type FetchLike = (url: string, init?: {
38
43
  method?: string;
39
44
  signal?: AbortSignal;
45
+ headers?: Record<string, string>;
40
46
  }) => Promise<{
41
47
  ok: boolean;
42
48
  status: number;
@@ -45,10 +51,14 @@ type FetchLike = (url: string, init?: {
45
51
  export declare class ScreenpipeClient {
46
52
  readonly baseUrl: string;
47
53
  private readonly doFetch;
54
+ private readonly apiKey?;
48
55
  constructor(opts?: {
49
56
  baseUrl?: string;
50
57
  fetchImpl?: FetchLike;
58
+ apiKey?: string;
51
59
  });
60
+ /** Build request headers, attaching Bearer auth when an API key is configured. */
61
+ private buildHeaders;
52
62
  /** True if a screenpipe server answers on the health endpoint. */
53
63
  health(timeoutMs?: number): Promise<boolean>;
54
64
  /** Search captured screen/audio content. */
@@ -1,14 +1,23 @@
1
1
  export class ScreenpipeClient {
2
2
  baseUrl;
3
3
  doFetch;
4
+ apiKey;
4
5
  constructor(opts = {}) {
5
6
  this.baseUrl = (opts.baseUrl || process.env['SCREENPIPE_URL'] || 'http://localhost:3030').replace(/\/$/, '');
6
7
  this.doFetch = opts.fetchImpl ?? globalThis.fetch;
8
+ const apiKey = opts.apiKey ?? process.env['SCREENPIPE_API_KEY'];
9
+ if (apiKey)
10
+ this.apiKey = apiKey;
11
+ }
12
+ /** Build request headers, attaching Bearer auth when an API key is configured. */
13
+ buildHeaders() {
14
+ return this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : undefined;
7
15
  }
8
16
  /** True if a screenpipe server answers on the health endpoint. */
9
17
  async health(timeoutMs = 2500) {
10
18
  try {
11
- const res = await this.withTimeout((signal) => this.doFetch(`${this.baseUrl}/health`, { signal }), timeoutMs);
19
+ const headers = this.buildHeaders();
20
+ const res = await this.withTimeout((signal) => this.doFetch(`${this.baseUrl}/health`, { signal, ...(headers ? { headers } : {}) }), timeoutMs);
12
21
  return res.ok;
13
22
  }
14
23
  catch {
@@ -33,7 +42,8 @@ export class ScreenpipeClient {
33
42
  if (opts.endTime)
34
43
  params.set('end_time', opts.endTime);
35
44
  const url = `${this.baseUrl}/search?${params.toString()}`;
36
- const res = await this.withTimeout((signal) => this.doFetch(url, { signal }), timeoutMs);
45
+ const headers = this.buildHeaders();
46
+ const res = await this.withTimeout((signal) => this.doFetch(url, { signal, ...(headers ? { headers } : {}) }), timeoutMs);
37
47
  if (!res.ok) {
38
48
  throw new Error(`screenpipe /search returned ${res.status}`);
39
49
  }
@@ -32,6 +32,12 @@ export interface TailscaleStatus {
32
32
  /** Tailscale version */
33
33
  version: string;
34
34
  }
35
+ export interface TailnetOllamaPeer {
36
+ hostname: string;
37
+ ip: string;
38
+ baseURL: string;
39
+ models: string[];
40
+ }
35
41
  export declare class TailscaleManager {
36
42
  private static instance;
37
43
  private config;
@@ -47,6 +53,11 @@ export declare class TailscaleManager {
47
53
  * Get live Tailscale status from the CLI.
48
54
  */
49
55
  getStatus(): Promise<TailscaleStatus>;
56
+ /**
57
+ * Discover Ollama peers on the tailnet and return their OpenAI-compatible
58
+ * endpoints with the models they expose.
59
+ */
60
+ discoverOllamaPeers(): Promise<TailnetOllamaPeer[]>;
50
61
  /**
51
62
  * Start Tailscale Serve (tailnet-only HTTPS).
52
63
  */
@@ -81,4 +92,6 @@ export declare class TailscaleManager {
81
92
  generateAuthHeaders(): Record<string, string>;
82
93
  getConfig(): TailscaleConfig | null;
83
94
  setConfig(config: Partial<TailscaleConfig>): void;
95
+ private readStatusPayload;
96
+ private listOllamaModels;
84
97
  }
@@ -47,8 +47,8 @@ export class TailscaleManager {
47
47
  * Get live Tailscale status from the CLI.
48
48
  */
49
49
  async getStatus() {
50
- const installed = await this.isInstalled();
51
- if (!installed) {
50
+ const payload = await this.readStatusPayload();
51
+ if (!payload) {
52
52
  return {
53
53
  installed: false,
54
54
  running: false,
@@ -60,41 +60,51 @@ export class TailscaleManager {
60
60
  version: '',
61
61
  };
62
62
  }
63
+ const status = {
64
+ installed: true,
65
+ running: !!payload.BackendState && payload.BackendState === 'Running',
66
+ hostname: payload.Self?.HostName || '',
67
+ tailnetName: payload.MagicDNSSuffix || payload.CurrentTailnet?.Name || '',
68
+ ip: payload.TailscaleIPs?.[0] || payload.Self?.TailscaleIPs?.[0] || '',
69
+ serving: this.serving,
70
+ serveUrl: this.getServeUrl(),
71
+ version: '',
72
+ };
73
+ // Get version separately (status --json doesn't always include it)
63
74
  try {
64
- const { stdout } = await execFileAsync('tailscale', ['status', '--json'], { timeout: EXEC_TIMEOUT });
65
- const data = JSON.parse(stdout);
66
- const status = {
67
- installed: true,
68
- running: !!data.BackendState && data.BackendState === 'Running',
69
- hostname: data.Self?.HostName || '',
70
- tailnetName: data.MagicDNSSuffix || data.CurrentTailnet?.Name || '',
71
- ip: data.TailscaleIPs?.[0] || data.Self?.TailscaleIPs?.[0] || '',
72
- serving: this.serving,
73
- serveUrl: this.getServeUrl(),
74
- version: '',
75
- };
76
- // Get version separately (status --json doesn't always include it)
77
- try {
78
- const { stdout: ver } = await execFileAsync('tailscale', ['version'], { timeout: EXEC_TIMEOUT });
79
- status.version = ver.trim().split('\n')[0] ?? '';
80
- }
81
- catch { /* non-critical */ }
82
- this.cachedStatus = status;
83
- return status;
75
+ const { stdout: ver } = await execFileAsync('tailscale', ['version'], { timeout: EXEC_TIMEOUT });
76
+ status.version = ver.trim().split('\n')[0] ?? '';
84
77
  }
85
- catch (err) {
86
- logger.debug(`Tailscale status failed: ${err instanceof Error ? err.message : String(err)}`);
87
- return {
88
- installed: true,
89
- running: false,
90
- hostname: '',
91
- tailnetName: '',
92
- ip: '',
93
- serving: this.serving,
94
- serveUrl: null,
95
- version: '',
96
- };
78
+ catch { /* non-critical */ }
79
+ this.cachedStatus = status;
80
+ return status;
81
+ }
82
+ /**
83
+ * Discover Ollama peers on the tailnet and return their OpenAI-compatible
84
+ * endpoints with the models they expose.
85
+ */
86
+ async discoverOllamaPeers() {
87
+ const payload = await this.readStatusPayload();
88
+ if (!payload)
89
+ return [];
90
+ const peers = payload.Peer ?? {};
91
+ const discovered = [];
92
+ for (const info of Object.values(peers)) {
93
+ if (!info?.Online)
94
+ continue;
95
+ const ip = info.TailscaleIPs?.[0]?.trim();
96
+ if (!ip)
97
+ continue;
98
+ const hostname = (info.HostName ?? info.DNSName ?? '').trim();
99
+ if (!hostname)
100
+ continue;
101
+ const baseURL = `http://${ip}:11434/v1`;
102
+ const models = await this.listOllamaModels(baseURL);
103
+ if (!models.length)
104
+ continue;
105
+ discovered.push({ hostname, ip, baseURL, models });
97
106
  }
107
+ return discovered;
98
108
  }
99
109
  /**
100
110
  * Start Tailscale Serve (tailnet-only HTTPS).
@@ -250,5 +260,48 @@ export class TailscaleManager {
250
260
  };
251
261
  }
252
262
  }
263
+ async readStatusPayload() {
264
+ const installed = await this.isInstalled();
265
+ if (!installed)
266
+ return null;
267
+ try {
268
+ const { stdout } = await execFileAsync('tailscale', ['status', '--json'], { timeout: EXEC_TIMEOUT });
269
+ return JSON.parse(stdout);
270
+ }
271
+ catch (err) {
272
+ logger.debug(`Tailscale status failed: ${err instanceof Error ? err.message : String(err)}`);
273
+ return null;
274
+ }
275
+ }
276
+ async listOllamaModels(baseURL) {
277
+ const probeUrls = [`${baseURL}/models`, `${baseURL.replace(/\/v1$/, '')}/api/tags`];
278
+ for (const url of probeUrls) {
279
+ try {
280
+ const response = await fetch(url, { signal: AbortSignal.timeout(8_000) });
281
+ if (!response.ok)
282
+ continue;
283
+ const json = await response.json();
284
+ const ids = (json.data ?? json.models ?? [])
285
+ .map((item) => {
286
+ const record = item;
287
+ const id = typeof record.id === 'string'
288
+ ? record.id.trim()
289
+ : typeof record.model === 'string'
290
+ ? record.model.trim()
291
+ : typeof record.name === 'string'
292
+ ? record.name.trim()
293
+ : '';
294
+ return id || null;
295
+ })
296
+ .filter((value) => Boolean(value));
297
+ if (ids.length > 0)
298
+ return ids;
299
+ }
300
+ catch {
301
+ // try next probe
302
+ }
303
+ }
304
+ return [];
305
+ }
253
306
  }
254
307
  //# sourceMappingURL=tailscale.js.map
@@ -52,6 +52,9 @@ class BruteForceIndex {
52
52
  this.vectors = new Map(data);
53
53
  }
54
54
  }
55
+ remove(id) {
56
+ this.vectors.delete(id);
57
+ }
55
58
  }
56
59
  const DEFAULT_CONFIG = {
57
60
  workspaceRoot: process.cwd(),
@@ -132,17 +135,57 @@ export class WorkspaceIndexer extends EventEmitter {
132
135
  ignore: this.config.ignorePatterns,
133
136
  absolute: false,
134
137
  });
138
+ const mtimeCachePath = path.join(path.dirname(this.config.indexPath), 'mtimes.json');
139
+ let mtimeCache = {};
140
+ try {
141
+ if (fs.existsSync(mtimeCachePath)) {
142
+ mtimeCache = JSON.parse(await fs.readFile(mtimeCachePath, 'utf-8'));
143
+ }
144
+ }
145
+ catch (e) {
146
+ logger.warn('Failed to load mtime cache, starting fresh.');
147
+ }
148
+ const newMtimeCache = {};
149
+ const filesToIndex = [];
150
+ const currentFiles = new Set(files);
151
+ for (const file of files) {
152
+ const fullPath = path.join(this.config.workspaceRoot, file);
153
+ try {
154
+ const stats = await fs.promises.stat(fullPath);
155
+ newMtimeCache[file] = stats.mtimeMs;
156
+ if (mtimeCache[file] !== stats.mtimeMs) {
157
+ filesToIndex.push(file);
158
+ }
159
+ }
160
+ catch (err) {
161
+ // Can't stat, skip
162
+ }
163
+ }
164
+ const filesToRemove = new Set();
165
+ for (const file of filesToIndex) {
166
+ filesToRemove.add(file);
167
+ }
168
+ for (const entry of this.entries.values()) {
169
+ if (!currentFiles.has(entry.filePath)) {
170
+ filesToRemove.add(entry.filePath);
171
+ }
172
+ }
173
+ if (filesToRemove.size > 0) {
174
+ for (const [id, entry] of this.entries.entries()) {
175
+ if (filesToRemove.has(entry.filePath)) {
176
+ this.entries.delete(id);
177
+ if (this.vectorIndex instanceof BruteForceIndex) {
178
+ this.vectorIndex.remove(id);
179
+ }
180
+ else if (this.vectorIndex && this.vectorIndex.remove) {
181
+ this.vectorIndex.remove(String(id));
182
+ }
183
+ }
184
+ }
185
+ }
135
186
  let processedFiles = 0;
136
187
  let totalChunks = 0;
137
- // TODO: In a real implementation, we should diff mtimes to only index changed files.
138
- // For this PoC, we rebuild the index.
139
- this.entries.clear();
140
- this.nextId = 0;
141
- if (this.vectorIndex.clear)
142
- this.vectorIndex.clear();
143
- else if (this.vectorIndex instanceof BruteForceIndex)
144
- this.vectorIndex = new BruteForceIndex(384);
145
- for (const file of files) {
188
+ for (const file of filesToIndex) {
146
189
  const fullPath = path.join(this.config.workspaceRoot, file);
147
190
  try {
148
191
  const content = await fs.readFile(fullPath, 'utf-8');
@@ -178,6 +221,7 @@ export class WorkspaceIndexer extends EventEmitter {
178
221
  // Skip unreadable files
179
222
  }
180
223
  }
224
+ await fs.writeFile(mtimeCachePath, JSON.stringify(newMtimeCache, null, 2));
181
225
  await this.saveIndexMetadata();
182
226
  logger.info(`Workspace indexing complete: ${processedFiles} files, ${totalChunks} chunks.`);
183
227
  this.emit('indexing:complete', { files: processedFiles, chunks: totalChunks });
@@ -96,6 +96,7 @@ export class MCPManager extends EventEmitter {
96
96
  this.handleServerError(serverName, error);
97
97
  }
98
98
  }, 30000);
99
+ interval.unref?.();
99
100
  this.healthCheckIntervals.set(serverName, interval);
100
101
  }
101
102
  stopHealthCheck(serverName) {
@@ -0,0 +1,23 @@
1
+ /**
2
+ * MCP Desktop Tools — expose Code Buddy's desktop-automation over the MCP server.
3
+ *
4
+ * This is the cross-platform equivalent of mediar-ai's Terminator MCP agent, but
5
+ * backed by Code Buddy's own already-validated automation stack (nut-js input +
6
+ * AT-SPI/accessibility snapshots + screenshots), so it works on Linux/macOS/Windows
7
+ * without porting a Windows-only framework.
8
+ *
9
+ * Safety model (mirrors the peer.tool / execute_code RPC opt-in pattern):
10
+ * - Read-only tools are ALWAYS exposed: `desktop_screenshot`, `desktop_snapshot`.
11
+ * - Control tools that actuate the real desktop (`desktop_click`, `desktop_type`,
12
+ * `desktop_move_mouse`, `desktop_key`) are GATED behind
13
+ * CODEBUDDY_MCP_DESKTOP_CONTROL=1 (fail-closed: not registered when unset).
14
+ */
15
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
16
+ /** Control tools actuate the real desktop — opt-in only. */
17
+ export declare function desktopControlEnabled(): boolean;
18
+ /** Reset the lazily-created manager (tests). */
19
+ export declare function resetDesktopMcpTools(): void;
20
+ /**
21
+ * Register desktop-automation tools with the MCP server.
22
+ */
23
+ export declare function registerDesktopTools(server: McpServer): void;
@@ -0,0 +1,158 @@
1
+ /**
2
+ * MCP Desktop Tools — expose Code Buddy's desktop-automation over the MCP server.
3
+ *
4
+ * This is the cross-platform equivalent of mediar-ai's Terminator MCP agent, but
5
+ * backed by Code Buddy's own already-validated automation stack (nut-js input +
6
+ * AT-SPI/accessibility snapshots + screenshots), so it works on Linux/macOS/Windows
7
+ * without porting a Windows-only framework.
8
+ *
9
+ * Safety model (mirrors the peer.tool / execute_code RPC opt-in pattern):
10
+ * - Read-only tools are ALWAYS exposed: `desktop_screenshot`, `desktop_snapshot`.
11
+ * - Control tools that actuate the real desktop (`desktop_click`, `desktop_type`,
12
+ * `desktop_move_mouse`, `desktop_key`) are GATED behind
13
+ * CODEBUDDY_MCP_DESKTOP_CONTROL=1 (fail-closed: not registered when unset).
14
+ */
15
+ import { z } from 'zod';
16
+ import { logger } from '../utils/logger.js';
17
+ /** Control tools actuate the real desktop — opt-in only. */
18
+ export function desktopControlEnabled() {
19
+ const v = process.env['CODEBUDDY_MCP_DESKTOP_CONTROL'];
20
+ return v === '1' || v === 'true';
21
+ }
22
+ // Lazily initialize a single automation manager (native provider → mock fallback).
23
+ let managerPromise = null;
24
+ async function getManager() {
25
+ if (!managerPromise) {
26
+ managerPromise = (async () => {
27
+ const { getDesktopAutomation } = await import('../desktop-automation/index.js');
28
+ const mgr = getDesktopAutomation({ provider: 'native', fallbackProviders: ['nutjs', 'mock'] });
29
+ await mgr.initialize();
30
+ return mgr;
31
+ })().catch((err) => {
32
+ managerPromise = null; // allow retry on next call
33
+ throw err;
34
+ });
35
+ }
36
+ return managerPromise;
37
+ }
38
+ /** Reset the lazily-created manager (tests). */
39
+ export function resetDesktopMcpTools() {
40
+ managerPromise = null;
41
+ }
42
+ function ok(text) {
43
+ return { content: [{ type: 'text', text }] };
44
+ }
45
+ function fail(text) {
46
+ return { content: [{ type: 'text', text }], isError: true };
47
+ }
48
+ /**
49
+ * Register desktop-automation tools with the MCP server.
50
+ */
51
+ export function registerDesktopTools(server) {
52
+ // ---- Read-only: screenshot ------------------------------------------------
53
+ server.tool('desktop_screenshot', 'Capture a screenshot of the desktop (fullscreen by default, or a region). Returns the saved PNG path and dimensions. Read-only.', {
54
+ region: z
55
+ .object({ x: z.number(), y: z.number(), width: z.number(), height: z.number() })
56
+ .optional()
57
+ .describe('Optional region {x,y,width,height}; omit for fullscreen'),
58
+ output_path: z.string().optional().describe('Optional output PNG path'),
59
+ }, async (args) => {
60
+ try {
61
+ const { ScreenshotTool } = await import('../tools/screenshot-tool.js');
62
+ const tool = new ScreenshotTool();
63
+ const result = args.region
64
+ ? await tool.captureRegion(args.region.x, args.region.y, args.region.width, args.region.height)
65
+ : await tool.capture({ fullscreen: true, ...(args.output_path ? { outputPath: args.output_path } : {}) });
66
+ if (!result.success)
67
+ return fail(`Screenshot failed: ${result.error ?? 'unknown error'}`);
68
+ return ok(result.output ?? JSON.stringify(result.data ?? {}, null, 2));
69
+ }
70
+ catch (err) {
71
+ return fail(`Screenshot error: ${err instanceof Error ? err.message : String(err)}`);
72
+ }
73
+ });
74
+ // ---- Read-only: accessibility snapshot -----------------------------------
75
+ server.tool('desktop_snapshot', 'Enumerate on-screen UI elements (accessibility tree) with numeric refs, roles, labels, and click coordinates. Read-only. Use the returned coordinates with desktop_click.', {
76
+ interactive_only: z.boolean().optional().describe('Only return interactive elements (buttons, inputs, links)'),
77
+ max_elements: z.number().optional().describe('Cap the number of elements returned (default 60, max 200)'),
78
+ window: z.string().optional().describe('Window title to scope to (default: whole desktop / focused window)'),
79
+ }, async (args) => {
80
+ try {
81
+ const { getSmartSnapshotManager } = await import('../desktop-automation/smart-snapshot.js');
82
+ const snap = await getSmartSnapshotManager().takeSnapshot({
83
+ ...(args.interactive_only ? { interactiveOnly: true } : {}),
84
+ ...(args.window ? { window: args.window } : {}),
85
+ });
86
+ const cap = Math.max(1, Math.min(200, args.max_elements ?? 60));
87
+ const shown = snap.elements.slice(0, cap);
88
+ const lines = shown.map((el) => `[${el.ref}] ${el.role} ${JSON.stringify(el.name)}${el.interactive ? ' (interactive)' : ''} @ ${Math.round(el.center.x)},${Math.round(el.center.y)} [${el.bounds.width}x${el.bounds.height}]`);
89
+ const header = `${snap.elements.length} element(s) on "${snap.source}" (${snap.screenSize.width}x${snap.screenSize.height}); showing ${shown.length}:`;
90
+ return ok(`${header}\n${lines.join('\n')}`);
91
+ }
92
+ catch (err) {
93
+ return fail(`Snapshot error: ${err instanceof Error ? err.message : String(err)}`);
94
+ }
95
+ });
96
+ // ---- Control tools (opt-in, actuate the real desktop) --------------------
97
+ if (!desktopControlEnabled()) {
98
+ logger.debug('MCP desktop control tools disabled. Set CODEBUDDY_MCP_DESKTOP_CONTROL=1 to expose desktop_click/type/move_mouse/key.');
99
+ return;
100
+ }
101
+ server.tool('desktop_click', 'Click the mouse at screen coordinates. Requires CODEBUDDY_MCP_DESKTOP_CONTROL=1. Actuates the real desktop.', {
102
+ x: z.number().describe('X coordinate'),
103
+ y: z.number().describe('Y coordinate'),
104
+ button: z.enum(['left', 'right', 'middle']).optional().describe('Mouse button (default left)'),
105
+ double: z.boolean().optional().describe('Double-click when true'),
106
+ }, async (args) => {
107
+ try {
108
+ const mgr = await getManager();
109
+ await mgr.click(args.x, args.y, {
110
+ ...(args.button ? { button: args.button } : {}),
111
+ ...(args.double ? { clicks: 2 } : {}),
112
+ });
113
+ return ok(`Clicked ${args.button ?? 'left'}${args.double ? ' (double)' : ''} at ${args.x},${args.y}.`);
114
+ }
115
+ catch (err) {
116
+ return fail(`Click error: ${err instanceof Error ? err.message : String(err)}`);
117
+ }
118
+ });
119
+ server.tool('desktop_move_mouse', 'Move the mouse cursor to screen coordinates. Requires CODEBUDDY_MCP_DESKTOP_CONTROL=1.', { x: z.number().describe('X coordinate'), y: z.number().describe('Y coordinate') }, async (args) => {
120
+ try {
121
+ const mgr = await getManager();
122
+ await mgr.moveMouse(args.x, args.y);
123
+ return ok(`Moved mouse to ${args.x},${args.y}.`);
124
+ }
125
+ catch (err) {
126
+ return fail(`Move error: ${err instanceof Error ? err.message : String(err)}`);
127
+ }
128
+ });
129
+ server.tool('desktop_type', 'Type text at the current focus. Requires CODEBUDDY_MCP_DESKTOP_CONTROL=1. Actuates the real keyboard.', { text: z.string().describe('Text to type') }, async (args) => {
130
+ try {
131
+ const mgr = await getManager();
132
+ await mgr.type(args.text);
133
+ return ok(`Typed ${args.text.length} character(s).`);
134
+ }
135
+ catch (err) {
136
+ return fail(`Type error: ${err instanceof Error ? err.message : String(err)}`);
137
+ }
138
+ });
139
+ server.tool('desktop_key', 'Press a key (optionally with modifiers), e.g. "enter", "escape", "tab", "f5". Requires CODEBUDDY_MCP_DESKTOP_CONTROL=1.', {
140
+ key: z.string().describe('Key name, e.g. enter, escape, tab, a, f5'),
141
+ modifiers: z
142
+ .array(z.enum(['ctrl', 'alt', 'shift', 'meta', 'cmd', 'win']))
143
+ .optional()
144
+ .describe('Modifier keys to hold'),
145
+ }, async (args) => {
146
+ try {
147
+ const mgr = await getManager();
148
+ await mgr.keyPress(args.key, args.modifiers && args.modifiers.length > 0
149
+ ? { modifiers: args.modifiers }
150
+ : undefined);
151
+ return ok(`Pressed ${args.modifiers?.length ? args.modifiers.join('+') + '+' : ''}${args.key}.`);
152
+ }
153
+ catch (err) {
154
+ return fail(`Key error: ${err instanceof Error ? err.message : String(err)}`);
155
+ }
156
+ });
157
+ }
158
+ //# sourceMappingURL=mcp-desktop-tools.js.map
@@ -17,9 +17,8 @@ export function registerResources(server) {
17
17
  mimeType: 'text/markdown',
18
18
  }, async () => {
19
19
  try {
20
- const { loadContext, formatContextForPrompt } = await import('../context/context-files.js');
21
- const context = await loadContext(process.cwd());
22
- let text = formatContextForPrompt(context);
20
+ const { resolveProjectContext } = await import('../context/project-context.js');
21
+ let text = resolveProjectContext({ cwd: process.cwd() }).text;
23
22
  // Append git status
24
23
  try {
25
24
  const { execSync } = await import('child_process');
@@ -38,6 +38,7 @@ import * as fs from 'fs';
38
38
  import { registerAgentTools } from './mcp-agent-tools.js';
39
39
  import { registerMemoryTools } from './mcp-memory-tools.js';
40
40
  import { registerSessionTools } from './mcp-session-tools.js';
41
+ import { registerDesktopTools } from './mcp-desktop-tools.js';
41
42
  import { registerResources } from './mcp-resources.js';
42
43
  import { registerPrompts } from './mcp-prompts.js';
43
44
  // Read version from package.json (avoid import.meta.url for ts-jest compat)
@@ -123,6 +124,7 @@ export class CodeBuddyMCPServer {
123
124
  registerAgentTools(this.mcpServer, getAgent);
124
125
  registerMemoryTools(this.mcpServer);
125
126
  registerSessionTools(this.mcpServer, getAgent);
127
+ registerDesktopTools(this.mcpServer);
126
128
  registerResources(this.mcpServer);
127
129
  registerPrompts(this.mcpServer);
128
130
  }
@@ -99,6 +99,7 @@ export interface MemorySearchOptions {
99
99
  minImportance?: number;
100
100
  limit?: number;
101
101
  includeExpired?: boolean;
102
+ explorationFactor?: number;
102
103
  }
103
104
  export interface MemoryConfig {
104
105
  enabled: boolean;
@@ -128,6 +129,7 @@ export declare class EnhancedMemory extends EventEmitter {
128
129
  private dbRepository;
129
130
  private embeddingProvider;
130
131
  private bayesianQualifier;
132
+ private disposed;
131
133
  constructor(config?: Partial<MemoryConfig>);
132
134
  /**
133
135
  * Initialize memory system
@@ -278,6 +280,14 @@ export declare class EnhancedMemory extends EventEmitter {
278
280
  score: number;
279
281
  uncertainty: number;
280
282
  };
283
+ /**
284
+ * Active Learning: Retrieve memories with the highest uncertainty (BALD score)
285
+ * so the system can solicit user feedback and improve its relevance model.
286
+ */
287
+ getActiveLearningTargets(limit?: number, query?: string): Promise<{
288
+ memory: MemoryEntry;
289
+ baldScore: number;
290
+ }[]>;
281
291
  }
282
292
  export declare function getEnhancedMemory(config?: Partial<MemoryConfig>): EnhancedMemory;
283
293
  export declare function resetEnhancedMemory(): void;