@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
@@ -190,8 +190,17 @@ export class BayesianQualifier {
190
190
  * Load the qualifier state from a JSON string
191
191
  */
192
192
  loadState(stateJson) {
193
+ const trimmed = stateJson.trim();
194
+ if (!trimmed) {
195
+ logger.debug('[BayesianQualifier] Ignoring empty persisted state');
196
+ return false;
197
+ }
193
198
  try {
194
- const state = JSON.parse(stateJson);
199
+ const parsed = JSON.parse(trimmed);
200
+ if (!isBayesianState(parsed)) {
201
+ throw new Error('invalid bayesian state shape');
202
+ }
203
+ const state = parsed;
195
204
  this.X = state.X;
196
205
  this.y = state.y;
197
206
  this.scaler.means = state.means;
@@ -202,9 +211,12 @@ export class BayesianQualifier {
202
211
  if (this.X.length > 0) {
203
212
  this.train();
204
213
  }
214
+ return true;
205
215
  }
206
216
  catch (err) {
207
- logger.error(`[BayesianQualifier] Failed to load state: ${err.message}`);
217
+ const message = err instanceof Error ? err.message : String(err);
218
+ logger.debug(`[BayesianQualifier] Ignoring invalid persisted state: ${message}`);
219
+ return false;
208
220
  }
209
221
  }
210
222
  // ============================================================================
@@ -248,4 +260,25 @@ export class BayesianQualifier {
248
260
  return x;
249
261
  }
250
262
  }
263
+ function isNumberArray(value) {
264
+ return Array.isArray(value) && value.every(item => typeof item === 'number' && Number.isFinite(item));
265
+ }
266
+ function isNumberMatrix(value) {
267
+ return Array.isArray(value) && value.every(isNumberArray);
268
+ }
269
+ function isBayesianState(value) {
270
+ if (!value || typeof value !== 'object')
271
+ return false;
272
+ const state = value;
273
+ return (isNumberMatrix(state.X) &&
274
+ isNumberArray(state.y) &&
275
+ isNumberArray(state.means) &&
276
+ isNumberArray(state.stds) &&
277
+ typeof state.lengthScale === 'number' &&
278
+ Number.isFinite(state.lengthScale) &&
279
+ typeof state.signalVariance === 'number' &&
280
+ Number.isFinite(state.signalVariance) &&
281
+ typeof state.noiseVariance === 'number' &&
282
+ Number.isFinite(state.noiseVariance));
283
+ }
251
284
  //# sourceMappingURL=bayesian-qualifier.js.map
@@ -1,5 +1,6 @@
1
1
  import { constants as fsConstants } from 'fs';
2
2
  import { access, appendFile, mkdir, readFile, writeFile } from 'fs/promises';
3
+ import { rotateIfLarge } from '../utils/disk-guard.js';
3
4
  import * as os from 'os';
4
5
  import * as path from 'path';
5
6
  import { createPublicKey, randomUUID, sign as signPayload } from 'crypto';
@@ -355,6 +356,7 @@ function responseSummary(response) {
355
356
  }
356
357
  async function appendAttachRecord(attachLogPath, record) {
357
358
  await mkdir(path.dirname(attachLogPath), { recursive: true });
359
+ rotateIfLarge(attachLogPath);
358
360
  await appendFile(attachLogPath, `${JSON.stringify(record)}\n`, 'utf8');
359
361
  }
360
362
  function sendResponseSummary(response) {
@@ -378,14 +380,17 @@ function sendResponseSummary(response) {
378
380
  }
379
381
  async function appendSendRecord(sendLogPath, record) {
380
382
  await mkdir(path.dirname(sendLogPath), { recursive: true });
383
+ rotateIfLarge(sendLogPath);
381
384
  await appendFile(sendLogPath, `${JSON.stringify(record)}\n`, 'utf8');
382
385
  }
383
386
  async function appendWebSocketProbeRecord(probeLogPath, record) {
384
387
  await mkdir(path.dirname(probeLogPath), { recursive: true });
388
+ rotateIfLarge(probeLogPath);
385
389
  await appendFile(probeLogPath, `${JSON.stringify(record)}\n`, 'utf8');
386
390
  }
387
391
  async function appendWebSocketCallRecord(callLogPath, record) {
388
392
  await mkdir(path.dirname(callLogPath), { recursive: true });
393
+ rotateIfLarge(callLogPath);
389
394
  await appendFile(callLogPath, `${JSON.stringify(record)}\n`, 'utf8');
390
395
  }
391
396
  function parseOpenClawWebSocketFrame(data) {
@@ -144,6 +144,7 @@ export declare class PluginMarketplace extends EventEmitter {
144
144
  private providers;
145
145
  private hooks;
146
146
  private updateCheckerIntervalId;
147
+ private disposed;
147
148
  constructor(config?: Partial<MarketplaceConfig>);
148
149
  /**
149
150
  * Initialize marketplace
@@ -41,6 +41,7 @@ export class PluginMarketplace extends EventEmitter {
41
41
  providers = new Map();
42
42
  hooks = new Map();
43
43
  updateCheckerIntervalId = null;
44
+ disposed = false;
44
45
  constructor(config = {}) {
45
46
  super();
46
47
  this.config = { ...DEFAULT_CONFIG, ...config };
@@ -55,6 +56,8 @@ export class PluginMarketplace extends EventEmitter {
55
56
  await fs.ensureDir(path.join(this.pluginsDir, 'installed'));
56
57
  await fs.ensureDir(path.join(this.pluginsDir, 'cache'));
57
58
  await this.loadInstalledPlugins();
59
+ if (this.disposed)
60
+ return;
58
61
  if (this.config.autoUpdate) {
59
62
  this.startUpdateChecker();
60
63
  }
@@ -273,9 +276,12 @@ export class PluginMarketplace extends EventEmitter {
273
276
  * Start update checker
274
277
  */
275
278
  startUpdateChecker() {
279
+ if (this.disposed || this.updateCheckerIntervalId)
280
+ return;
276
281
  this.updateCheckerIntervalId = setInterval(() => {
277
282
  this.checkUpdates();
278
283
  }, this.config.checkUpdatesInterval);
284
+ this.updateCheckerIntervalId.unref?.();
279
285
  }
280
286
  /**
281
287
  * Validate plugin path is within allowed directory
@@ -641,6 +647,7 @@ export class PluginMarketplace extends EventEmitter {
641
647
  * Dispose
642
648
  */
643
649
  async dispose() {
650
+ this.disposed = true;
644
651
  if (this.updateCheckerIntervalId) {
645
652
  clearInterval(this.updateCheckerIntervalId);
646
653
  this.updateCheckerIntervalId = null;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Execution-discipline guidance — the highest-leverage prompt block borrowed
3
+ * from the Hermes Agent prompt audit (2026-06-16). Hermes ships an always-on
4
+ * `TASK_COMPLETION_GUIDANCE` + `<tool_persistence>` / `<mandatory_tool_use>` /
5
+ * `<verification>` set that pushes the model to *act with tools and deliver a
6
+ * verified artifact* rather than describe one. Code Buddy previously had only a
7
+ * gated `workflow-rules` Verification Contract (off for simple/lite queries) and
8
+ * no anti-stub / tool-persistence / mandatory-tool guidance at all.
9
+ *
10
+ * Kept short (~12 lines, ~150 tokens) and model-agnostic. Gated off for
11
+ * trivial/lite queries and for models without tool-call support
12
+ * (see prompt-builder.ts gating).
13
+ */
14
+ export declare function getExecutionDisciplineBlock(): string;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Execution-discipline guidance — the highest-leverage prompt block borrowed
3
+ * from the Hermes Agent prompt audit (2026-06-16). Hermes ships an always-on
4
+ * `TASK_COMPLETION_GUIDANCE` + `<tool_persistence>` / `<mandatory_tool_use>` /
5
+ * `<verification>` set that pushes the model to *act with tools and deliver a
6
+ * verified artifact* rather than describe one. Code Buddy previously had only a
7
+ * gated `workflow-rules` Verification Contract (off for simple/lite queries) and
8
+ * no anti-stub / tool-persistence / mandatory-tool guidance at all.
9
+ *
10
+ * Kept short (~12 lines, ~150 tokens) and model-agnostic. Gated off for
11
+ * trivial/lite queries and for models without tool-call support
12
+ * (see prompt-builder.ts gating).
13
+ */
14
+ export function getExecutionDisciplineBlock() {
15
+ return [
16
+ '## Execution discipline',
17
+ 'You take ACTION with tools — you do not describe what you would do. Each response either makes',
18
+ 'progress via tool calls or delivers a verified final result.',
19
+ '- The deliverable is a working artifact backed by real tool output, not a description of one.',
20
+ ' Do not stop after writing a stub, a plan, or a single command.',
21
+ '- Keep using tools until (1) the task is complete AND (2) you have verified the result with a tool',
22
+ ' (test output, file read-back, command exit code). Never claim success you have not verified.',
23
+ '- For anything checkable — file contents, git state, arithmetic, current time, command results —',
24
+ ' ALWAYS use a tool. Never guess or fabricate tool output.',
25
+ '- Before finalizing, self-check: Correctness (every requirement met?), Grounding (claims backed by',
26
+ ' tool output?), Scope (no unintended file changes?).',
27
+ ].join('\n');
28
+ }
29
+ //# sourceMappingURL=execution-discipline.js.map
@@ -142,11 +142,18 @@ export function extractBlocks(prompt) {
142
142
  const prefix = lines.slice(0, blockStart).join('\n');
143
143
  const rawBlocks = lines.slice(blockStart, blockEnd);
144
144
  const suffix = '';
145
- // Split rawBlocks into individual bullet points
145
+ // Split rawBlocks into HEADING-ATOMIC sections: a new block begins at every
146
+ // `##`/`###` heading and absorbs ALL following lines (bullets, numbered items,
147
+ // blank lines) until the next heading. Previously this split at every bullet
148
+ // line, so the Fisher-Yates shuffle in applyVariation() interleaved foreign
149
+ // bullets (e.g. tool-parameter docs) into the middle of a `##`-headed block
150
+ // such as the Verification Contract (`## Workflow Orchestration`), corrupting
151
+ // structured guidance. Heading-atomic grouping shuffles whole sections instead
152
+ // — the anti-repetition variation is preserved, but no block is ever fragmented.
146
153
  const blocks = [];
147
154
  let current = '';
148
155
  for (const line of rawBlocks) {
149
- if ((line.startsWith('- ') || line.startsWith('* ') || line.match(/^\d+\./)) && current) {
156
+ if (/^#{2,3}\s+/.test(line.trim()) && current.trim()) {
150
157
  blocks.push(current.trim());
151
158
  current = line;
152
159
  }
@@ -5,7 +5,7 @@
5
5
  * (https://agentclientprotocol.com). Unlike the original text-only runner,
6
6
  * this drives a real agentic loop:
7
7
  *
8
- * 1. Ask the LLM (with a small read-only toolset) for the next step.
8
+ * 1. Ask the LLM (with a small toolset) for the next step.
9
9
  * 2. If it emits tool calls, EXECUTE each one and feed the result back.
10
10
  * 3. Repeat until the model stops calling tools (`end_turn`) or we hit
11
11
  * the round cap (`max_turn_requests`).
@@ -26,10 +26,11 @@
26
26
  * `session/request_permission` when that round-trip is available; a
27
27
  * rejection fails the tool call instead of leaking content.
28
28
  *
29
- * Only read-only tools are exposed (`view_file`, `list_directory`,
30
- * `search`) this runner never writes. Cancellation is honoured by
31
- * checking `signal.aborted` on every loop iteration and after every client
32
- * round-trip.
29
+ * Read-only tools are always exposed (`view_file`, `list_directory`,
30
+ * `search`). `write_file` is exposed only when the editor advertises
31
+ * `fs.writeTextFile`, and the write is routed through the editor permission
32
+ * flow. Cancellation is honoured by checking `signal.aborted` on every loop
33
+ * iteration and after every client round-trip.
33
34
  */
34
35
  import type { AcpPromptContext, AcpStopReason } from './acp-stdio-server.js';
35
36
  import type { CodeBuddyMessage, CodeBuddyResponse, CodeBuddyTool } from '../../codebuddy/client.js';
@@ -50,5 +51,5 @@ export interface AcpAgenticRunnerOptions {
50
51
  export declare function createAcpAgenticRunner(options: AcpAgenticRunnerOptions): (ctx: AcpPromptContext) => Promise<{
51
52
  stopReason: AcpStopReason;
52
53
  }>;
53
- /** Test-only: the static read-only toolset this runner exposes. */
54
+ /** Test-only: the static read-only toolset this runner always exposes. */
54
55
  export declare const ACP_READONLY_TOOLS: ReadonlyArray<CodeBuddyTool>;
@@ -5,7 +5,7 @@
5
5
  * (https://agentclientprotocol.com). Unlike the original text-only runner,
6
6
  * this drives a real agentic loop:
7
7
  *
8
- * 1. Ask the LLM (with a small read-only toolset) for the next step.
8
+ * 1. Ask the LLM (with a small toolset) for the next step.
9
9
  * 2. If it emits tool calls, EXECUTE each one and feed the result back.
10
10
  * 3. Repeat until the model stops calling tools (`end_turn`) or we hit
11
11
  * the round cap (`max_turn_requests`).
@@ -26,10 +26,11 @@
26
26
  * `session/request_permission` when that round-trip is available; a
27
27
  * rejection fails the tool call instead of leaking content.
28
28
  *
29
- * Only read-only tools are exposed (`view_file`, `list_directory`,
30
- * `search`) this runner never writes. Cancellation is honoured by
31
- * checking `signal.aborted` on every loop iteration and after every client
32
- * round-trip.
29
+ * Read-only tools are always exposed (`view_file`, `list_directory`,
30
+ * `search`). `write_file` is exposed only when the editor advertises
31
+ * `fs.writeTextFile`, and the write is routed through the editor permission
32
+ * flow. Cancellation is honoured by checking `signal.aborted` on every loop
33
+ * iteration and after every client round-trip.
33
34
  */
34
35
  import { spawn } from 'child_process';
35
36
  import { rgPath } from '@vscode/ripgrep';
@@ -42,9 +43,9 @@ const LIST_DIRECTORY_MAX_ENTRIES = 256;
42
43
  const SEARCH_TIMEOUT_MS = 30_000;
43
44
  const SEARCH_MAX_RESULTS = 200;
44
45
  const SYSTEM_PROMPT = 'You are Code Buddy, a coding assistant operating over the Agent Client Protocol ' +
45
- 'inside a code editor. You have read-only tools (view_file, list_directory, search) ' +
46
- 'to inspect the workspace. Use them when you need to look at files, then answer ' +
47
- 'concisely in Markdown. Never claim to have modified files you cannot write.';
46
+ 'inside a code editor. Use the tools provided for this turn when you need workspace context. ' +
47
+ 'If write_file is not available, never claim to have modified files. If write_file is available, ' +
48
+ 'writes are routed through the editor and require client permission. Answer concisely in Markdown.';
48
49
  const READONLY_TOOLS = [
49
50
  {
50
51
  type: 'function',
@@ -90,11 +91,26 @@ const READONLY_TOOLS = [
90
91
  },
91
92
  },
92
93
  ];
93
- /** Maps each read-only tool to its ACP tool-call `kind` (spec enum). */
94
+ const WRITE_FILE_TOOL = {
95
+ type: 'function',
96
+ function: {
97
+ name: 'write_file',
98
+ description: 'Write text content to a file through the editor client. Will overwrite existing files after permission.',
99
+ parameters: {
100
+ type: 'object',
101
+ properties: {
102
+ file_path: { type: 'string', description: 'Path to the file (absolute, or relative to the workspace).' },
103
+ content: { type: 'string', description: 'The exact string content to write into the file.' },
104
+ },
105
+ required: ['file_path', 'content'],
106
+ },
107
+ },
108
+ };
94
109
  const TOOL_KIND = {
95
110
  view_file: 'read',
96
111
  list_directory: 'read',
97
112
  search: 'search',
113
+ write_file: 'edit',
98
114
  };
99
115
  /**
100
116
  * Build an injectable ACP prompt runner that performs a bounded,
@@ -103,22 +119,63 @@ const TOOL_KIND = {
103
119
  export function createAcpAgenticRunner(options) {
104
120
  const maxRounds = options.maxRounds ?? DEFAULT_MAX_ROUNDS;
105
121
  const maxToolOutputBytes = options.maxToolOutputBytes ?? DEFAULT_MAX_TOOL_OUTPUT_BYTES;
122
+ // Cache of MCPClientManager instances per session, so we don't reconnect on every prompt
123
+ const mcpManagers = new Map();
106
124
  return async function run(ctx) {
107
125
  const userText = extractPromptText(ctx.prompt);
108
126
  if (!userText) {
109
127
  return { stopReason: 'end_turn' };
110
128
  }
129
+ let mcpManager = mcpManagers.get(ctx.sessionId);
130
+ if (!mcpManager && ctx.mcpServers) {
131
+ try {
132
+ const { MCPManager } = await import('../../mcp/client.js');
133
+ mcpManager = new MCPManager();
134
+ mcpManagers.set(ctx.sessionId, mcpManager);
135
+ const servers = Array.isArray(ctx.mcpServers)
136
+ ? ctx.mcpServers
137
+ : typeof ctx.mcpServers === 'object' && ctx.mcpServers !== null
138
+ ? Object.entries(ctx.mcpServers).map(([name, conf]) => ({ name, ...conf }))
139
+ : [];
140
+ for (const server of servers) {
141
+ try {
142
+ await mcpManager.addServer(server);
143
+ }
144
+ catch (e) {
145
+ logger.warn(`Failed to add MCP server ${server.name}`, { error: String(e) });
146
+ }
147
+ }
148
+ }
149
+ catch (e) {
150
+ logger.warn('Failed to initialize MCPManager for passthrough', { error: String(e) });
151
+ }
152
+ }
111
153
  const messages = [
112
154
  { role: 'system', content: SYSTEM_PROMPT },
113
155
  { role: 'user', content: userText },
114
156
  ];
157
+ const allTools = [...READONLY_TOOLS];
158
+ if (ctx.canRequestClient('fs/write_text_file')) {
159
+ allTools.push(WRITE_FILE_TOOL);
160
+ }
161
+ if (mcpManager) {
162
+ const mcpTools = mcpManager.getTools().map((tool) => ({
163
+ type: 'function',
164
+ function: {
165
+ name: tool.name,
166
+ description: tool.description,
167
+ parameters: tool.inputSchema,
168
+ }
169
+ }));
170
+ allTools.push(...mcpTools);
171
+ }
115
172
  let toolCallSeq = 0;
116
173
  for (let round = 0; round < maxRounds; round++) {
117
174
  if (ctx.signal.aborted)
118
175
  return { stopReason: 'cancelled' };
119
176
  let response;
120
177
  try {
121
- response = await options.chat(messages, READONLY_TOOLS);
178
+ response = await options.chat(messages, allTools);
122
179
  }
123
180
  catch (err) {
124
181
  if (ctx.signal.aborted)
@@ -164,13 +221,28 @@ export function createAcpAgenticRunner(options) {
164
221
  status: 'in_progress',
165
222
  rawInput: args,
166
223
  });
167
- const result = await executeAcpTool({
168
- name: call.function.name,
169
- args,
170
- ctx,
171
- toolCallId,
172
- maxToolOutputBytes,
173
- });
224
+ let result;
225
+ if (call.function.name.startsWith('mcp__') && mcpManager) {
226
+ try {
227
+ const mcpRes = await mcpManager.callTool(call.function.name, args);
228
+ const outputText = Array.isArray(mcpRes.content)
229
+ ? mcpRes.content.map((c) => c.text).join('\n')
230
+ : String(mcpRes);
231
+ result = { output: outputText, isError: !!mcpRes.isError };
232
+ }
233
+ catch (e) {
234
+ result = { output: String(e), isError: true };
235
+ }
236
+ }
237
+ else {
238
+ result = await executeAcpTool({
239
+ name: call.function.name,
240
+ args,
241
+ ctx,
242
+ toolCallId,
243
+ maxToolOutputBytes,
244
+ });
245
+ }
174
246
  if (ctx.signal.aborted)
175
247
  return { stopReason: 'cancelled' };
176
248
  ctx.sendUpdate({
@@ -205,6 +277,8 @@ async function executeAcpTool(input) {
205
277
  return { output: await listDirectory(args, ctx.cwd), isError: false };
206
278
  case 'search':
207
279
  return { output: await searchWorkspace(args, ctx.cwd, maxToolOutputBytes), isError: false };
280
+ case 'write_file':
281
+ return { output: await writeFileViaClientOrDisk(args, ctx, toolCallId), isError: false };
208
282
  default:
209
283
  return { output: `Unknown tool: ${name}`, isError: true };
210
284
  }
@@ -248,6 +322,29 @@ async function readFileViaClientOrDisk(args, ctx, toolCallId, maxBytes) {
248
322
  const content = await fs.readFile(resolved, 'utf-8');
249
323
  return truncate(content, maxBytes);
250
324
  }
325
+ /**
326
+ * Write a file through the editor client. There is deliberately no direct disk
327
+ * fallback: ACP writes are only allowed when the editor advertises
328
+ * `fs.writeTextFile`, and they are always gated by client permission.
329
+ */
330
+ async function writeFileViaClientOrDisk(args, ctx, toolCallId) {
331
+ const rawPath = stringArg(args, 'file_path') ?? stringArg(args, 'path');
332
+ const content = stringArg(args, 'content');
333
+ if (!rawPath)
334
+ throw new Error('write_file: missing string file_path');
335
+ if (typeof content !== 'string')
336
+ throw new Error('write_file: missing string content');
337
+ if (!ctx.canRequestClient('fs/write_text_file')) {
338
+ throw new Error('write_file is unavailable because the ACP client did not advertise fs.writeTextFile.');
339
+ }
340
+ const absolute = path.isAbsolute(rawPath) ? rawPath : path.resolve(ctx.cwd, rawPath);
341
+ const allowed = await requestPermission(ctx, toolCallId, absolute);
342
+ if (!allowed) {
343
+ throw new Error(`Permission to write ${rawPath} was denied by the editor.`);
344
+ }
345
+ await ctx.requestClient('fs/write_text_file', { sessionId: ctx.sessionId, path: absolute, content });
346
+ return `Successfully wrote to ${rawPath} via editor client`;
347
+ }
251
348
  async function requestPermission(ctx, toolCallId, target) {
252
349
  const outcome = await ctx.requestClient('session/request_permission', {
253
350
  sessionId: ctx.sessionId,
@@ -402,6 +499,6 @@ function truncate(text, maxBytes) {
402
499
  return text;
403
500
  return `${text.slice(0, maxBytes)}\n... [truncated]`;
404
501
  }
405
- /** Test-only: the static read-only toolset this runner exposes. */
502
+ /** Test-only: the static read-only toolset this runner always exposes. */
406
503
  export const ACP_READONLY_TOOLS = READONLY_TOOLS;
407
504
  //# sourceMappingURL=acp-agentic-runner.js.map
@@ -0,0 +1,23 @@
1
+ export interface AcpPersistedSession {
2
+ sessionId: string;
3
+ cwd: string;
4
+ title?: string;
5
+ history: unknown[];
6
+ mcpServers?: unknown;
7
+ updatedAt: string;
8
+ }
9
+ export interface AcpSessionStoreConfig {
10
+ storeDir?: string;
11
+ }
12
+ export declare class AcpSessionStore {
13
+ private readonly dir;
14
+ constructor(config?: AcpSessionStoreConfig);
15
+ save(session: AcpPersistedSession): Promise<void>;
16
+ load(sessionId: string): Promise<AcpPersistedSession | null>;
17
+ delete(sessionId: string): Promise<void>;
18
+ listAll(): Promise<AcpPersistedSession[]>;
19
+ private writeUnlocked;
20
+ private fileFor;
21
+ private ensureDir;
22
+ private defaultDir;
23
+ }
@@ -0,0 +1,77 @@
1
+ import * as fs from 'fs';
2
+ import * as os from 'os';
3
+ import * as path from 'path';
4
+ import { withSessionLock } from '../../persistence/session-lock.js';
5
+ import { logger } from '../../utils/logger.js';
6
+ export class AcpSessionStore {
7
+ dir;
8
+ constructor(config = {}) {
9
+ this.dir = config.storeDir ?? this.defaultDir();
10
+ this.ensureDir();
11
+ }
12
+ async save(session) {
13
+ const file = this.fileFor(session.sessionId);
14
+ await withSessionLock(file, async () => {
15
+ await this.writeUnlocked(session);
16
+ });
17
+ }
18
+ async load(sessionId) {
19
+ const file = this.fileFor(sessionId);
20
+ if (!fs.existsSync(file))
21
+ return null;
22
+ try {
23
+ const raw = await fs.promises.readFile(file, 'utf-8');
24
+ return JSON.parse(raw);
25
+ }
26
+ catch (err) {
27
+ logger.warn?.('[acp-session-store] failed to read session', {
28
+ sessionId,
29
+ error: err instanceof Error ? err.message : String(err),
30
+ });
31
+ return null;
32
+ }
33
+ }
34
+ async delete(sessionId) {
35
+ const file = this.fileFor(sessionId);
36
+ await withSessionLock(file, async () => {
37
+ if (fs.existsSync(file)) {
38
+ await fs.promises.unlink(file);
39
+ }
40
+ });
41
+ }
42
+ async listAll() {
43
+ if (!fs.existsSync(this.dir))
44
+ return [];
45
+ const files = await fs.promises.readdir(this.dir);
46
+ const sessions = [];
47
+ for (const f of files) {
48
+ if (!f.endsWith('.json'))
49
+ continue;
50
+ const sessionId = f.slice(0, -5);
51
+ const s = await this.load(sessionId);
52
+ if (s)
53
+ sessions.push(s);
54
+ }
55
+ return sessions;
56
+ }
57
+ async writeUnlocked(session) {
58
+ const file = this.fileFor(session.sessionId);
59
+ const temp = `${file}.tmp.${Date.now()}-${Math.random().toString(36).slice(2)}`;
60
+ await fs.promises.writeFile(temp, JSON.stringify(session, null, 2), 'utf-8');
61
+ await fs.promises.rename(temp, file);
62
+ }
63
+ fileFor(sessionId) {
64
+ const safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, '_');
65
+ return path.join(this.dir, `${safe}.json`);
66
+ }
67
+ ensureDir() {
68
+ if (!fs.existsSync(this.dir)) {
69
+ fs.mkdirSync(this.dir, { recursive: true });
70
+ }
71
+ }
72
+ defaultDir() {
73
+ const home = os.homedir();
74
+ return path.join(home, '.codebuddy', 'acp-sessions');
75
+ }
76
+ }
77
+ //# sourceMappingURL=acp-session-store.js.map
@@ -30,6 +30,7 @@
30
30
  * backed by client `fs/*` + `session/request_permission`, and MCP passthrough.
31
31
  */
32
32
  import type { Readable, Writable } from 'node:stream';
33
+ import { AcpSessionStore } from './acp-session-store.js';
33
34
  export declare const ACP_PROTOCOL_VERSION = 1;
34
35
  export interface AcpContentBlock {
35
36
  type: string;
@@ -53,6 +54,7 @@ export interface AcpPromptContext {
53
54
  sessionId: string;
54
55
  cwd: string;
55
56
  clientCapabilities: AcpClientCapabilities;
57
+ mcpServers?: unknown;
56
58
  canRequestClient: (method: string) => boolean;
57
59
  prompt: AcpContentBlock[];
58
60
  signal: AbortSignal;
@@ -68,6 +70,7 @@ export interface AcpAgentInfo {
68
70
  version: string;
69
71
  }
70
72
  export interface AcpStdioServerOptions {
73
+ store?: AcpSessionStore;
71
74
  promptRunner: AcpPromptRunner;
72
75
  /** Defaults to process.stdin. */
73
76
  input?: Readable;
@@ -87,6 +90,8 @@ export declare class AcpStdioServer {
87
90
  private readonly clientRequestTimeoutMs;
88
91
  private readonly sessions;
89
92
  private readonly pendingClientRequests;
93
+ private readonly store;
94
+ private storeLoaded;
90
95
  private clientCapabilities;
91
96
  private nextClientRequestId;
92
97
  private buffer;
@@ -98,6 +103,8 @@ export declare class AcpStdioServer {
98
103
  private ingest;
99
104
  private write;
100
105
  private sendUpdate;
106
+ private ensureStoreLoaded;
107
+ private persistSession;
101
108
  private requestClient;
102
109
  private handleLine;
103
110
  private dispatch;