@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
@@ -0,0 +1,261 @@
1
+ /**
2
+ * Review-gated long-term memory candidates.
3
+ *
4
+ * Declarative memories are more dangerous than procedural lessons because they
5
+ * are injected into future prompts as "facts". The safe loop is therefore:
6
+ * infer -> enqueue with evidence -> human accepts/rejects -> write bounded
7
+ * persistent memory. Proposing a candidate never mutates CODEBUDDY_MEMORY.md.
8
+ */
9
+ import fs from 'fs';
10
+ import path from 'path';
11
+ import { scanForSecrets, redactSecrets } from '../fleet/privacy-lint.js';
12
+ import { logger } from '../utils/logger.js';
13
+ import { getMemoryManager, } from './persistent-memory.js';
14
+ export const MEMORY_CANDIDATE_SCHEMA_VERSION = 1;
15
+ const VALID_CATEGORIES = [
16
+ 'project',
17
+ 'preferences',
18
+ 'decisions',
19
+ 'patterns',
20
+ 'context',
21
+ 'custom',
22
+ ];
23
+ const registry = new Map();
24
+ export function getMemoryCandidateQueue(workDir = process.cwd()) {
25
+ const key = path.resolve(workDir);
26
+ if (!registry.has(key)) {
27
+ registry.set(key, new MemoryCandidateQueue(key));
28
+ if (registry.size > 20) {
29
+ const firstKey = registry.keys().next().value;
30
+ if (firstKey)
31
+ registry.delete(firstKey);
32
+ }
33
+ }
34
+ return registry.get(key);
35
+ }
36
+ export function resetMemoryCandidateQueues() {
37
+ registry.clear();
38
+ }
39
+ export class MemoryCandidateQueue {
40
+ workDir;
41
+ memoryManager;
42
+ filePath;
43
+ candidates = [];
44
+ loaded = false;
45
+ constructor(workDir = process.cwd(), memoryManager) {
46
+ this.workDir = workDir;
47
+ this.memoryManager = memoryManager;
48
+ this.filePath = path.join(workDir, '.codebuddy', 'memory-candidates.json');
49
+ }
50
+ propose(input) {
51
+ this.load();
52
+ const key = normalizeText(input.key);
53
+ const value = normalizeText(input.value);
54
+ const scope = normalizeScope(input.scope);
55
+ const category = normalizeCategory(input.category);
56
+ if (!key)
57
+ throw new Error('Memory candidate key is required.');
58
+ if (!value)
59
+ throw new Error('Memory candidate value is required.');
60
+ const citations = sanitizeCitations(input.citations);
61
+ const lintTarget = [
62
+ key,
63
+ value,
64
+ input.rationale ?? '',
65
+ ...citations.map((citation) => citation.snippet),
66
+ ].join('\n');
67
+ const lint = scanForSecrets(lintTarget);
68
+ if (lint.hasSecrets) {
69
+ throw new Error(`Memory candidate rejected before queueing: sensitive material detected (${lint.matches.map((m) => m.kind).join(', ')}).`);
70
+ }
71
+ const existing = this.candidates.find((candidate) => candidate.status === 'pending' &&
72
+ candidate.scope === scope &&
73
+ candidate.key.trim().toLowerCase() === key.toLowerCase() &&
74
+ candidate.value.trim().toLowerCase() === value.toLowerCase());
75
+ if (existing) {
76
+ return { candidate: existing, deduped: true };
77
+ }
78
+ const candidate = {
79
+ id: `mc-${Date.now().toString(36)}${Math.random().toString(36).slice(2, 5)}`,
80
+ key,
81
+ value,
82
+ scope,
83
+ category,
84
+ status: 'pending',
85
+ createdAt: Date.now(),
86
+ source: input.source ?? 'self_observed',
87
+ ...(typeof input.confidence === 'number' ? { confidence: clampConfidence(input.confidence) } : {}),
88
+ ...(input.rationale?.trim() ? { rationale: input.rationale.trim() } : {}),
89
+ ...(citations.length > 0 ? { citations } : {}),
90
+ };
91
+ this.candidates.push(candidate);
92
+ this.save();
93
+ return { candidate, deduped: false };
94
+ }
95
+ list(status) {
96
+ this.load();
97
+ const items = status ? this.candidates.filter((candidate) => candidate.status === status) : this.candidates;
98
+ return [...items].sort((a, b) => b.createdAt - a.createdAt);
99
+ }
100
+ get(id) {
101
+ this.load();
102
+ return this.candidates.find((candidate) => candidate.id === id) ?? null;
103
+ }
104
+ async accept(id, input) {
105
+ this.load();
106
+ const reviewedBy = input.reviewedBy?.trim();
107
+ if (!reviewedBy) {
108
+ throw new Error('Human approval (reviewedBy) is required before a memory candidate can be written.');
109
+ }
110
+ const candidate = this.candidates.find((item) => item.id === id);
111
+ if (!candidate)
112
+ throw new Error(`Memory candidate not found: ${id}`);
113
+ if (candidate.status !== 'pending') {
114
+ throw new Error(`Memory candidate ${id} is already ${candidate.status}; only pending candidates can be accepted.`);
115
+ }
116
+ const key = input.key !== undefined ? normalizeText(input.key) : candidate.key;
117
+ const value = input.value !== undefined ? normalizeText(input.value) : candidate.value;
118
+ const scope = input.scope ? normalizeScope(input.scope) : candidate.scope;
119
+ const category = input.category ? normalizeCategory(input.category) : candidate.category;
120
+ if (!key)
121
+ throw new Error('Accepted memory key cannot be empty.');
122
+ if (!value)
123
+ throw new Error('Accepted memory value cannot be empty.');
124
+ const manager = this.memoryManager ?? getMemoryManager();
125
+ await manager.initialize();
126
+ const write = await manager.remember(key, value, {
127
+ scope,
128
+ category,
129
+ tags: ['memory-candidate', candidate.id],
130
+ });
131
+ candidate.key = key;
132
+ candidate.value = value;
133
+ candidate.scope = scope;
134
+ candidate.category = category;
135
+ candidate.status = 'accepted';
136
+ candidate.reviewedAt = Date.now();
137
+ candidate.reviewedBy = reviewedBy;
138
+ candidate.write = { status: write.status, usage: write.usage };
139
+ if (input.reviewNote?.trim()) {
140
+ candidate.reviewNote = input.reviewNote.trim();
141
+ }
142
+ this.save();
143
+ return { candidate, write };
144
+ }
145
+ reject(id, input = {}) {
146
+ this.load();
147
+ const candidate = this.candidates.find((item) => item.id === id);
148
+ if (!candidate)
149
+ throw new Error(`Memory candidate not found: ${id}`);
150
+ if (candidate.status === 'accepted') {
151
+ throw new Error(`Memory candidate ${id} was already accepted and cannot be rejected.`);
152
+ }
153
+ candidate.status = 'rejected';
154
+ candidate.reviewedAt = Date.now();
155
+ if (input.reviewedBy?.trim()) {
156
+ candidate.reviewedBy = input.reviewedBy.trim();
157
+ }
158
+ if (input.reason?.trim()) {
159
+ candidate.reviewNote = input.reason.trim();
160
+ }
161
+ this.save();
162
+ return candidate;
163
+ }
164
+ getStats() {
165
+ this.load();
166
+ const byStatus = {
167
+ pending: 0,
168
+ accepted: 0,
169
+ rejected: 0,
170
+ };
171
+ for (const candidate of this.candidates) {
172
+ byStatus[candidate.status] += 1;
173
+ }
174
+ return { total: this.candidates.length, byStatus };
175
+ }
176
+ load() {
177
+ if (this.loaded)
178
+ return;
179
+ this.loaded = true;
180
+ try {
181
+ if (!fs.existsSync(this.filePath))
182
+ return;
183
+ const parsed = JSON.parse(fs.readFileSync(this.filePath, 'utf-8'));
184
+ if (Array.isArray(parsed.candidates)) {
185
+ this.candidates = parsed.candidates.filter(isValidCandidate);
186
+ }
187
+ }
188
+ catch (err) {
189
+ logger.warn('[memory-candidates] failed to load queue', {
190
+ error: err instanceof Error ? err.message : String(err),
191
+ });
192
+ }
193
+ }
194
+ save() {
195
+ try {
196
+ fs.mkdirSync(path.dirname(this.filePath), { recursive: true });
197
+ const file = {
198
+ schemaVersion: MEMORY_CANDIDATE_SCHEMA_VERSION,
199
+ candidates: this.candidates,
200
+ };
201
+ fs.writeFileSync(this.filePath, JSON.stringify(file, null, 2), 'utf-8');
202
+ }
203
+ catch (err) {
204
+ logger.warn('[memory-candidates] failed to save queue', {
205
+ error: err instanceof Error ? err.message : String(err),
206
+ });
207
+ }
208
+ }
209
+ }
210
+ function normalizeText(value) {
211
+ return (value ?? '').replace(/\s+/g, ' ').trim();
212
+ }
213
+ function normalizeScope(scope) {
214
+ return scope === 'user' ? 'user' : 'project';
215
+ }
216
+ function normalizeCategory(category) {
217
+ const normalized = category ?? 'context';
218
+ if (!VALID_CATEGORIES.includes(normalized)) {
219
+ throw new Error(`Memory category must be one of: ${VALID_CATEGORIES.join(', ')}`);
220
+ }
221
+ return normalized;
222
+ }
223
+ function clampConfidence(value) {
224
+ if (!Number.isFinite(value))
225
+ return 0;
226
+ return Math.max(0, Math.min(1, value));
227
+ }
228
+ function sanitizeCitations(citations) {
229
+ if (!Array.isArray(citations))
230
+ return [];
231
+ return citations
232
+ .map((citation) => {
233
+ const snippet = redactSecrets(normalizeText(citation.snippet)).slice(0, 280);
234
+ if (!snippet)
235
+ return null;
236
+ return {
237
+ ...(citation.sessionId ? { sessionId: citation.sessionId } : {}),
238
+ ...(typeof citation.messageId === 'number' ? { messageId: citation.messageId } : {}),
239
+ ...(typeof citation.messageIndex === 'number' ? { messageIndex: citation.messageIndex } : {}),
240
+ ...(citation.role ? { role: citation.role } : {}),
241
+ snippet,
242
+ };
243
+ })
244
+ .filter((citation) => citation !== null)
245
+ .slice(0, 3);
246
+ }
247
+ function isValidCandidate(value) {
248
+ if (!value || typeof value !== 'object')
249
+ return false;
250
+ const candidate = value;
251
+ return (typeof candidate.id === 'string' &&
252
+ typeof candidate.key === 'string' &&
253
+ typeof candidate.value === 'string' &&
254
+ (candidate.scope === 'project' || candidate.scope === 'user') &&
255
+ typeof candidate.category === 'string' &&
256
+ VALID_CATEGORIES.includes(candidate.category) &&
257
+ (candidate.status === 'pending' || candidate.status === 'accepted' || candidate.status === 'rejected') &&
258
+ typeof candidate.createdAt === 'number' &&
259
+ typeof candidate.source === 'string');
260
+ }
261
+ //# sourceMappingURL=memory-candidate-queue.js.map
@@ -15,6 +15,32 @@ export interface MemoryConfig {
15
15
  autoCapture: boolean;
16
16
  maxMemories: number;
17
17
  relevanceThreshold: number;
18
+ enforceCharLimits: boolean;
19
+ projectCharLimit: number;
20
+ userCharLimit: number;
21
+ securityScan: boolean;
22
+ rejectExactDuplicates: boolean;
23
+ }
24
+ export type MemoryScope = "project" | "user";
25
+ export interface MemoryUsage {
26
+ scope: MemoryScope;
27
+ used: number;
28
+ limit: number;
29
+ percent: number;
30
+ }
31
+ export type MemoryWriteStatus = 'stored' | 'updated' | 'duplicate' | 'replaced' | 'missing';
32
+ export interface MemoryWriteResult {
33
+ status: MemoryWriteStatus;
34
+ key: string;
35
+ scope: MemoryScope;
36
+ category?: MemoryCategory;
37
+ usage: MemoryUsage;
38
+ message: string;
39
+ }
40
+ export declare class MemoryWriteRejectedError extends Error {
41
+ readonly code: 'memory_limit_exceeded' | 'memory_security_rejected';
42
+ readonly usage?: MemoryUsage | undefined;
43
+ constructor(message: string, code: 'memory_limit_exceeded' | 'memory_security_rejected', usage?: MemoryUsage | undefined);
18
44
  }
19
45
  /**
20
46
  * Persistent Memory Manager - Inspired by Claude's CLAUDE.md memory system
@@ -50,10 +76,25 @@ export declare class PersistentMemoryManager extends EventEmitter {
50
76
  * Remember something (store in memory)
51
77
  */
52
78
  remember(key: string, value: string, options?: {
53
- scope?: "project" | "user";
79
+ scope?: MemoryScope;
54
80
  category?: MemoryCategory;
55
81
  tags?: string[];
56
- }): Promise<void>;
82
+ }): Promise<MemoryWriteResult>;
83
+ replace(key: string, value: string, options?: {
84
+ scope?: MemoryScope;
85
+ category?: MemoryCategory;
86
+ tags?: string[];
87
+ }): Promise<MemoryWriteResult>;
88
+ private setMemoryDirect;
89
+ private assertMemoryWriteSafe;
90
+ private assertScopeWithinLimit;
91
+ private getMemoryLimit;
92
+ private renderScopeEntries;
93
+ getMemoryUsage(scope: MemoryScope): MemoryUsage;
94
+ getMemoryUsages(): {
95
+ project: MemoryUsage;
96
+ user: MemoryUsage;
97
+ };
57
98
  /**
58
99
  * Recall something from memory
59
100
  */
@@ -82,6 +123,8 @@ export declare class PersistentMemoryManager extends EventEmitter {
82
123
  * Get context string for system prompt
83
124
  */
84
125
  getContextForPrompt(): string;
126
+ getHermesSnapshotForPrompt(): string;
127
+ private renderHermesMemorySection;
85
128
  /**
86
129
  * Auto-capture important information from conversation
87
130
  */
@@ -33,7 +33,39 @@ const DEFAULT_CONFIG = {
33
33
  autoCapture: true,
34
34
  maxMemories: 100,
35
35
  relevanceThreshold: 0.5,
36
+ enforceCharLimits: process.env.CODEBUDDY_MEMORY_ENFORCE_LIMITS !== 'false',
37
+ projectCharLimit: parsePositiveInt(process.env.CODEBUDDY_MEMORY_PROJECT_CHAR_LIMIT, 2200),
38
+ userCharLimit: parsePositiveInt(process.env.CODEBUDDY_MEMORY_USER_CHAR_LIMIT, 1375),
39
+ securityScan: process.env.CODEBUDDY_MEMORY_SECURITY_SCAN !== 'false',
40
+ rejectExactDuplicates: process.env.CODEBUDDY_MEMORY_REJECT_DUPLICATES !== 'false',
36
41
  };
42
+ export class MemoryWriteRejectedError extends Error {
43
+ code;
44
+ usage;
45
+ constructor(message, code, usage) {
46
+ super(message);
47
+ this.code = code;
48
+ this.usage = usage;
49
+ this.name = 'MemoryWriteRejectedError';
50
+ }
51
+ }
52
+ function parsePositiveInt(value, fallback) {
53
+ if (!value)
54
+ return fallback;
55
+ const parsed = Number.parseInt(value, 10);
56
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
57
+ }
58
+ function cloneMemoryMap(memories) {
59
+ return new Map(Array.from(memories.entries()).map(([key, memory]) => [
60
+ key,
61
+ {
62
+ ...memory,
63
+ createdAt: new Date(memory.createdAt),
64
+ updatedAt: new Date(memory.updatedAt),
65
+ tags: memory.tags ? [...memory.tags] : undefined,
66
+ },
67
+ ]));
68
+ }
37
69
  const MEMORY_TEMPLATE = `# Code Buddy Memory
38
70
 
39
71
  This file stores persistent memory for the Code Buddy agent.
@@ -147,6 +179,7 @@ export class PersistentMemoryManager extends EventEmitter {
147
179
  "User Preferences": "preferences",
148
180
  "Decisions": "decisions",
149
181
  "Patterns": "patterns",
182
+ "Context": "context",
150
183
  "Custom": "custom",
151
184
  };
152
185
  let currentCategory = "custom";
@@ -212,13 +245,29 @@ export class PersistentMemoryManager extends EventEmitter {
212
245
  async remember(key, value, options = {}) {
213
246
  const { scope = "project", category = "context", tags } = options;
214
247
  const memories = scope === "project" ? this.projectMemories : this.userMemories;
248
+ const normalizedKey = key.trim();
249
+ const normalizedValue = value.trim();
250
+ this.assertMemoryWriteSafe(normalizedKey, normalizedValue);
251
+ const existing = memories.get(normalizedKey);
252
+ if (this.config.rejectExactDuplicates && existing?.value === normalizedValue) {
253
+ return {
254
+ status: 'duplicate',
255
+ key: normalizedKey,
256
+ scope,
257
+ category: existing.category,
258
+ usage: this.getMemoryUsage(scope),
259
+ message: `No duplicate added for "${normalizedKey}".`,
260
+ };
261
+ }
262
+ const previousMemories = cloneMemoryMap(memories);
263
+ const status = existing ? 'updated' : 'stored';
215
264
  try {
216
265
  const { FactsMemoryService } = await import('./facts-memory.js');
217
266
  const service = new FactsMemoryService();
218
267
  if (await service.isAvailable()) {
219
268
  const newFact = {
220
269
  category: mapMemoryCategoryToFactCategory(category),
221
- text: `${key}: ${value}`,
270
+ text: `${normalizedKey}: ${normalizedValue}`,
222
271
  source: tags?.join(', ') || 'manual',
223
272
  updatedAt: new Date()
224
273
  };
@@ -252,35 +301,166 @@ export class PersistentMemoryManager extends EventEmitter {
252
301
  }
253
302
  else {
254
303
  // Fallback to default direct write
255
- const existing = memories.get(key);
256
- const memory = {
257
- key,
258
- value,
259
- category,
260
- createdAt: existing?.createdAt || new Date(),
261
- updatedAt: new Date(),
262
- accessCount: existing?.accessCount || 0,
263
- tags,
264
- };
265
- memories.set(key, memory);
304
+ this.setMemoryDirect(memories, normalizedKey, normalizedValue, category, tags);
266
305
  }
267
306
  }
268
307
  catch (err) {
269
- logger.warn(`[FactsMemory] Failed to reconcile remember, falling back to default behavior: ${err.message}`);
270
- const existing = memories.get(key);
271
- const memory = {
272
- key,
273
- value,
308
+ const message = err instanceof Error ? err.message : String(err);
309
+ logger.warn(`[FactsMemory] Failed to reconcile remember, falling back to default behavior: ${message}`);
310
+ memories.clear();
311
+ for (const [memoryKey, memory] of previousMemories) {
312
+ memories.set(memoryKey, memory);
313
+ }
314
+ this.setMemoryDirect(memories, normalizedKey, normalizedValue, category, tags);
315
+ }
316
+ try {
317
+ this.assertScopeWithinLimit(scope);
318
+ }
319
+ catch (err) {
320
+ memories.clear();
321
+ for (const [memoryKey, memory] of previousMemories) {
322
+ memories.set(memoryKey, memory);
323
+ }
324
+ throw err;
325
+ }
326
+ await this.saveMemories(scope);
327
+ this.emit("memory:remembered", { key: normalizedKey, scope, category });
328
+ return {
329
+ status,
330
+ key: normalizedKey,
331
+ scope,
332
+ category,
333
+ usage: this.getMemoryUsage(scope),
334
+ message: status === 'updated'
335
+ ? `Updated "${normalizedKey}" in ${scope} memory.`
336
+ : `Stored "${normalizedKey}" in ${scope} memory.`,
337
+ };
338
+ }
339
+ async replace(key, value, options = {}) {
340
+ const { scope = 'project', category, tags } = options;
341
+ const memories = scope === 'project' ? this.projectMemories : this.userMemories;
342
+ const normalizedKey = key.trim();
343
+ const normalizedValue = value.trim();
344
+ const existing = memories.get(normalizedKey);
345
+ if (!existing) {
346
+ return {
347
+ status: 'missing',
348
+ key: normalizedKey,
349
+ scope,
274
350
  category,
275
- createdAt: existing?.createdAt || new Date(),
276
- updatedAt: new Date(),
277
- accessCount: existing?.accessCount || 0,
278
- tags,
351
+ usage: this.getMemoryUsage(scope),
352
+ message: `No memory found for key "${normalizedKey}" in ${scope} scope.`,
279
353
  };
280
- memories.set(key, memory);
354
+ }
355
+ this.assertMemoryWriteSafe(normalizedKey, normalizedValue);
356
+ const previousMemories = cloneMemoryMap(memories);
357
+ memories.set(normalizedKey, {
358
+ ...existing,
359
+ value: normalizedValue,
360
+ category: category ?? existing.category,
361
+ updatedAt: new Date(),
362
+ tags: tags ?? existing.tags,
363
+ });
364
+ try {
365
+ this.assertScopeWithinLimit(scope);
366
+ }
367
+ catch (err) {
368
+ memories.clear();
369
+ for (const [memoryKey, memory] of previousMemories) {
370
+ memories.set(memoryKey, memory);
371
+ }
372
+ throw err;
281
373
  }
282
374
  await this.saveMemories(scope);
283
- this.emit("memory:remembered", { key, scope, category });
375
+ this.emit("memory:replaced", { key: normalizedKey, scope, category: category ?? existing.category });
376
+ return {
377
+ status: 'replaced',
378
+ key: normalizedKey,
379
+ scope,
380
+ category: category ?? existing.category,
381
+ usage: this.getMemoryUsage(scope),
382
+ message: `Replaced "${normalizedKey}" in ${scope} memory.`,
383
+ };
384
+ }
385
+ setMemoryDirect(memories, key, value, category, tags) {
386
+ const existing = memories.get(key);
387
+ const memory = {
388
+ key,
389
+ value,
390
+ category,
391
+ createdAt: existing?.createdAt || new Date(),
392
+ updatedAt: new Date(),
393
+ accessCount: existing?.accessCount || 0,
394
+ tags,
395
+ };
396
+ memories.set(key, memory);
397
+ }
398
+ assertMemoryWriteSafe(key, value) {
399
+ if (!key || !value) {
400
+ throw new MemoryWriteRejectedError('Memory key and value must be non-empty.', 'memory_security_rejected');
401
+ }
402
+ if (!this.config.securityScan)
403
+ return;
404
+ const content = `${key}\n${value}`;
405
+ if (/[\u200B-\u200F\u202A-\u202E\u2060-\u206F\uFEFF]/u.test(content)) {
406
+ throw new MemoryWriteRejectedError('Memory write rejected: invisible Unicode control characters are not allowed in prompt-injected memory.', 'memory_security_rejected');
407
+ }
408
+ const threatPatterns = [
409
+ {
410
+ pattern: /\b(ignore|override|bypass|discard)\b.{0,80}\b(system|developer|previous|prior|above)\b.{0,80}\b(instructions?|prompt|rules?)\b/i,
411
+ reason: 'prompt injection instruction',
412
+ },
413
+ {
414
+ pattern: /\b(exfiltrate|steal|leak|send|upload|post)\b.{0,100}\b(api[-_ ]?key|token|secret|password|credential|private key)\b/i,
415
+ reason: 'credential exfiltration instruction',
416
+ },
417
+ {
418
+ pattern: /\b(authorized_keys|reverse shell|backdoor|ssh-rsa)\b/i,
419
+ reason: 'backdoor or SSH persistence pattern',
420
+ },
421
+ {
422
+ pattern: /-----BEGIN (?:OPENSSH|RSA|EC|DSA) PRIVATE KEY-----/i,
423
+ reason: 'private key material',
424
+ },
425
+ ];
426
+ for (const { pattern, reason } of threatPatterns) {
427
+ if (pattern.test(content)) {
428
+ throw new MemoryWriteRejectedError(`Memory write rejected: ${reason} detected.`, 'memory_security_rejected');
429
+ }
430
+ }
431
+ }
432
+ assertScopeWithinLimit(scope) {
433
+ if (!this.config.enforceCharLimits)
434
+ return;
435
+ const usage = this.getMemoryUsage(scope);
436
+ if (usage.limit > 0 && usage.used > usage.limit) {
437
+ throw new MemoryWriteRejectedError(`Memory ${scope} is full (${usage.used}/${usage.limit} chars). Consolidate or remove entries before retrying.`, 'memory_limit_exceeded', usage);
438
+ }
439
+ }
440
+ getMemoryLimit(scope) {
441
+ return scope === 'project' ? this.config.projectCharLimit : this.config.userCharLimit;
442
+ }
443
+ renderScopeEntries(memories) {
444
+ return Array.from(memories.values())
445
+ .map((memory) => `${memory.key}: ${memory.value}`)
446
+ .join('\n§\n');
447
+ }
448
+ getMemoryUsage(scope) {
449
+ const memories = scope === 'project' ? this.projectMemories : this.userMemories;
450
+ const used = this.renderScopeEntries(memories).length;
451
+ const limit = this.getMemoryLimit(scope);
452
+ return {
453
+ scope,
454
+ used,
455
+ limit,
456
+ percent: limit > 0 ? Math.min(100, Math.round((used / limit) * 100)) : 0,
457
+ };
458
+ }
459
+ getMemoryUsages() {
460
+ return {
461
+ project: this.getMemoryUsage('project'),
462
+ user: this.getMemoryUsage('user'),
463
+ };
284
464
  }
285
465
  /**
286
466
  * Recall something from memory
@@ -463,21 +643,34 @@ export class PersistentMemoryManager extends EventEmitter {
463
643
  * Get context string for system prompt
464
644
  */
465
645
  getContextForPrompt() {
466
- const relevant = [
467
- ...this.getByCategory("project", "project"),
468
- ...this.getByCategory("preferences", "user"),
469
- ...this.getByCategory("decisions"),
470
- ...this.getByCategory("patterns"),
471
- ].slice(0, 20);
472
- if (relevant.length === 0) {
646
+ const snapshot = this.getHermesSnapshotForPrompt();
647
+ if (!snapshot)
473
648
  return "";
649
+ return `--- PERSISTENT MEMORY ---\n${snapshot}\n--- END MEMORY ---\n`;
650
+ }
651
+ getHermesSnapshotForPrompt() {
652
+ const sections = [];
653
+ const projectEntries = this.renderScopeEntries(this.projectMemories);
654
+ const userEntries = this.renderScopeEntries(this.userMemories);
655
+ if (projectEntries) {
656
+ const usage = this.getMemoryUsage('project');
657
+ sections.push(this.renderHermesMemorySection('MEMORY (project notes)', usage, projectEntries));
474
658
  }
475
- let context = "\n--- PERSISTENT MEMORY ---\n";
476
- for (const memory of relevant) {
477
- context += `• ${memory.key}: ${memory.value}\n`;
659
+ if (userEntries) {
660
+ const usage = this.getMemoryUsage('user');
661
+ sections.push(this.renderHermesMemorySection('USER (profile and preferences)', usage, userEntries));
478
662
  }
479
- context += "--- END MEMORY ---\n";
480
- return context;
663
+ return sections.join('\n\n');
664
+ }
665
+ renderHermesMemorySection(title, usage, entries) {
666
+ const width = 46;
667
+ const bar = '═'.repeat(width);
668
+ return [
669
+ bar,
670
+ `${title} [${usage.percent}% - ${usage.used}/${usage.limit} chars]`,
671
+ bar,
672
+ entries,
673
+ ].join('\n');
481
674
  }
482
675
  /**
483
676
  * Auto-capture important information from conversation
@@ -527,7 +720,8 @@ export class PersistentMemoryManager extends EventEmitter {
527
720
  await this.saveMemories("project");
528
721
  }
529
722
  catch (err) {
530
- logger.warn(`[FactsMemory] Failed to autoCapture facts, falling back to pattern matching: ${err.message}`);
723
+ const message = err instanceof Error ? err.message : String(err);
724
+ logger.warn(`[FactsMemory] Failed to autoCapture facts, falling back to pattern matching: ${message}`);
531
725
  // Fallback: Detect project context
532
726
  const projectPatterns = [
533
727
  /this (?:is|project) (?:a|an) ([^.]+)/i,
@@ -605,8 +799,10 @@ export class PersistentMemoryManager extends EventEmitter {
605
799
  */
606
800
  formatMemories(scope) {
607
801
  let output = `\n🧠 Persistent Memory\n${"═".repeat(50)}\n\n`;
608
- const formatScope = (name, memories) => {
802
+ const formatScope = (name, memories, memoryScope) => {
803
+ const usage = this.getMemoryUsage(memoryScope);
609
804
  output += `📁 ${name}\n`;
805
+ output += ` Capacity: ${usage.used}/${usage.limit} chars (${usage.percent}%)\n`;
610
806
  if (memories.size === 0) {
611
807
  output += ` (empty)\n`;
612
808
  }
@@ -619,13 +815,13 @@ export class PersistentMemoryManager extends EventEmitter {
619
815
  output += `\n`;
620
816
  };
621
817
  if (!scope || scope === "project") {
622
- formatScope("Project Memory", this.projectMemories);
818
+ formatScope("Project Memory", this.projectMemories, 'project');
623
819
  }
624
820
  if (!scope || scope === "user") {
625
- formatScope("User Memory", this.userMemories);
821
+ formatScope("User Memory", this.userMemories, 'user');
626
822
  }
627
823
  output += `${"═".repeat(50)}\n`;
628
- output += `💡 Commands: /remember <key> <value>, /recall <key>, /forget <key>\n`;
824
+ output += `💡 Commands: /remember <key> <value>, /memory replace <key> <value>, /recall <key>, /forget <key>\n`;
629
825
  return output;
630
826
  }
631
827
  getStats() {
@@ -56,7 +56,7 @@ export declare class BayesianQualifier {
56
56
  /**
57
57
  * Load the qualifier state from a JSON string
58
58
  */
59
- loadState(stateJson: string): void;
59
+ loadState(stateJson: string): boolean;
60
60
  private rbfKernel;
61
61
  /**
62
62
  * Solve L * x = b for lower triangular matrix L