@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
@@ -12,10 +12,72 @@
12
12
  *
13
13
  * Exit codes: 0 = goal done, 1 = paused (budget/judge) or error.
14
14
  */
15
- import { Command } from 'commander';
15
+ import { Command, InvalidArgumentError } from 'commander';
16
+ import path from 'path';
17
+ import { resolveGoalJudgeClient } from '../goals/goal-judge-client.js';
16
18
  import { maybeContinueGoalAfterTurn } from '../goals/goal-loop.js';
17
- import { getGoalManager } from '../goals/goal-manager.js';
19
+ import { getGoalManager, resolveGoalsConfig } from '../goals/goal-manager.js';
18
20
  import { resolveCommandProvider } from './llm-provider-resolution.js';
21
+ const TOOL_RESULT_SNIPPET_CHARS = 1600;
22
+ export const LOCAL_GOAL_ACTOR_SYSTEM_PROMPT = 'You are Code Buddy running in headless goal mode on a local model. ' +
23
+ 'Work only toward the user standing goal. Use available tools when they are necessary, ' +
24
+ 'then report concrete progress or the final result. For simple answer-only goals, ' +
25
+ 'output exactly the requested answer and no extra text. Do not greet the user, add markdown, ' +
26
+ 'or explain unless the goal asks for it.';
27
+ export function buildLocalGoalActorSystemPrompt(workingDirectory = process.cwd()) {
28
+ return `${LOCAL_GOAL_ACTOR_SYSTEM_PROMPT}
29
+
30
+ Workspace:
31
+ - Current project directory: ${workingDirectory}
32
+ - Use paths relative to the current project directory whenever possible.
33
+ - Do not invent container paths such as /workspace or root paths such as /src unless a tool result proves they exist.`;
34
+ }
35
+ export function shouldUseLocalGoalActorPrompt(provider) {
36
+ const label = provider.providerLabel?.toLowerCase() ?? '';
37
+ const baseURL = provider.baseURL?.toLowerCase() ?? '';
38
+ return provider.apiKey === 'ollama' || label.includes('ollama') || baseURL.includes(':11434');
39
+ }
40
+ export function resolveLocalGoalActorSystemPrompt(provider, workingDirectory = process.cwd()) {
41
+ return shouldUseLocalGoalActorPrompt(provider)
42
+ ? buildLocalGoalActorSystemPrompt(workingDirectory)
43
+ : undefined;
44
+ }
45
+ function truncateGoalTurnPart(text) {
46
+ if (text.length <= TOOL_RESULT_SNIPPET_CHARS)
47
+ return text;
48
+ return `${text.slice(0, TOOL_RESULT_SNIPPET_CHARS)}... [truncated]`;
49
+ }
50
+ function buildGoalTurnSummary(entries) {
51
+ const parts = [];
52
+ let hasToolResult = false;
53
+ for (const entry of entries) {
54
+ if (entry.type === 'assistant' && entry.content.trim()) {
55
+ parts.push(entry.content.trim());
56
+ continue;
57
+ }
58
+ if (entry.type !== 'tool_result')
59
+ continue;
60
+ hasToolResult = true;
61
+ const toolOutput = (entry.toolResult?.success ? entry.toolResult.output : entry.toolResult?.error) ??
62
+ entry.content;
63
+ const trimmedOutput = String(toolOutput ?? '').trim();
64
+ if (!trimmedOutput)
65
+ continue;
66
+ const toolName = entry.toolCall?.function?.name ?? 'tool';
67
+ const status = entry.toolResult ? (entry.toolResult.success ? 'success' : 'error') : 'result';
68
+ parts.push(`[tool:${toolName} ${status}]\n${truncateGoalTurnPart(trimmedOutput)}`);
69
+ }
70
+ const summary = parts.join('\n\n');
71
+ if (summary && !hasToolResult) {
72
+ return `[tool evidence: none]\n\n${summary}`;
73
+ }
74
+ return summary;
75
+ }
76
+ function buildGoalRunSummary(turnSummaries) {
77
+ return turnSummaries
78
+ .map((summary, index) => `[Goal turn ${index + 1}]\n${summary}`)
79
+ .join('\n\n');
80
+ }
19
81
  /**
20
82
  * Drive the goal loop headlessly on an in-process agent. Sets the goal,
21
83
  * runs the first turn with the goal text (mirroring the interactive
@@ -24,25 +86,32 @@ import { resolveCommandProvider } from './llm-provider-resolution.js';
24
86
  */
25
87
  export async function runGoalLoop(agent, goalText, options = {}) {
26
88
  const manager = getGoalManager();
27
- const state = manager.set(goalText, options.maxTurns ? { maxTurns: options.maxTurns } : {});
89
+ const state = manager.set(goalText, options.maxTurns !== undefined ? { maxTurns: options.maxTurns } : {});
28
90
  const emit = options.onMessage ?? (() => { });
91
+ const judgeClient = options.judgeClient ?? agent.getClient();
29
92
  emit(`⊙ Goal set (${state.maxTurns}-turn budget): ${state.goal}`);
30
93
  let prompt = state.goal;
94
+ const turnSummaries = [];
31
95
  // Hard backstop on top of the manager's own budget/auto-pause guards.
32
96
  const maxIterations = state.maxTurns + 1;
33
97
  for (let i = 0; i < maxIterations; i++) {
34
98
  const entries = await agent.processUserMessage(prompt);
35
- const lastResponse = entries
36
- .filter(entry => entry.type === 'assistant' && entry.content)
37
- .map(entry => entry.content)
38
- .join('\n');
99
+ const lastResponse = buildGoalTurnSummary(entries);
100
+ if (lastResponse.trim()) {
101
+ turnSummaries.push(lastResponse);
102
+ }
39
103
  const outcome = await maybeContinueGoalAfterTurn({
40
- client: agent.getClient(),
41
- lastResponse,
104
+ client: judgeClient,
105
+ lastResponse: lastResponse.trim() ? buildGoalRunSummary(turnSummaries) : lastResponse,
42
106
  interrupted: false,
43
107
  });
44
108
  if (outcome?.message)
45
109
  emit(outcome.message);
110
+ if (!outcome && !lastResponse.trim() && manager.isActive()) {
111
+ manager.pause('empty response (nothing to evaluate)');
112
+ emit('⏸ Goal paused — the agent produced no judgeable response.');
113
+ break;
114
+ }
46
115
  if (!outcome?.continuationPrompt)
47
116
  break;
48
117
  prompt = outcome.continuationPrompt;
@@ -54,37 +123,151 @@ export async function runGoalLoop(agent, goalText, options = {}) {
54
123
  ...(final?.lastReason ? { lastReason: final.lastReason } : {}),
55
124
  };
56
125
  }
126
+ async function createStandaloneJudgeClient(judgeModel, agentProvider, currentClient) {
127
+ const resolved = await resolveGoalJudgeClient(currentClient, judgeModel, agentProvider);
128
+ return resolved === currentClient ? undefined : resolved;
129
+ }
130
+ export async function runGoalCommandWithAgent(agent, goal, options) {
131
+ try {
132
+ const createJudgeClient = options.createJudgeClient ?? createStandaloneJudgeClient;
133
+ const runLoop = options.runLoop ?? runGoalLoop;
134
+ const judgeClient = await createJudgeClient(options.judgeModel, options.provider, agent.getClient());
135
+ await agent.systemPromptReady;
136
+ if (shouldUseLocalGoalActorPrompt(options.provider)) {
137
+ agent.setSystemPrompt?.(buildLocalGoalActorSystemPrompt(options.workingDirectory));
138
+ }
139
+ return await runLoop(agent, goal, {
140
+ ...(options.maxTurns !== undefined ? { maxTurns: options.maxTurns } : {}),
141
+ ...(judgeClient ? { judgeClient } : {}),
142
+ ...(options.onMessage ? { onMessage: options.onMessage } : {}),
143
+ });
144
+ }
145
+ finally {
146
+ await Promise.resolve(agent.dispose?.());
147
+ }
148
+ }
149
+ export function resolveGoalCliJudgeModel(explicitJudgeModel) {
150
+ const explicit = explicitJudgeModel?.trim();
151
+ if (explicit)
152
+ return explicit;
153
+ const configured = resolveGoalsConfig().judgeModel.trim();
154
+ return configured || undefined;
155
+ }
156
+ export function resolveGoalCliMaxToolRounds(commandValue, command) {
157
+ const commandSource = command?.getOptionValueSource?.('maxToolRounds');
158
+ if (commandSource && commandSource !== 'default') {
159
+ return commandValue ?? 50;
160
+ }
161
+ const parentSource = command?.parent?.getOptionValueSource?.('maxToolRounds');
162
+ const parentValue = command?.optsWithGlobals?.()?.maxToolRounds;
163
+ if (parentSource && parentSource !== 'default' && parentValue !== undefined) {
164
+ return parsePositiveIntegerOption(String(parentValue), '--max-tool-rounds');
165
+ }
166
+ return commandValue ?? 50;
167
+ }
168
+ export function resolveGoalCliWorkingDirectory(command) {
169
+ const value = command?.optsWithGlobals?.()?.directory;
170
+ if (typeof value !== 'string')
171
+ return undefined;
172
+ const directory = value.trim();
173
+ if (!directory)
174
+ return undefined;
175
+ return path.resolve(process.cwd(), directory);
176
+ }
177
+ export function applyGoalCliWorkingDirectory(command) {
178
+ const directory = resolveGoalCliWorkingDirectory(command);
179
+ if (directory) {
180
+ process.chdir(directory);
181
+ }
182
+ return process.cwd();
183
+ }
184
+ async function loadGoalCliEnv(directory) {
185
+ const dotenv = await import('dotenv');
186
+ dotenv.config({ path: path.join(directory, '.env') });
187
+ }
188
+ async function prepareGoalCliWorkspace(command) {
189
+ const launchDirectory = process.cwd();
190
+ await loadGoalCliEnv(launchDirectory);
191
+ const cwd = applyGoalCliWorkingDirectory(command);
192
+ if (cwd !== launchDirectory) {
193
+ await loadGoalCliEnv(cwd);
194
+ }
195
+ const opts = command?.optsWithGlobals?.();
196
+ const { initializeWorkspaceIsolation } = await import('../workspace/workspace-isolation.js');
197
+ initializeWorkspaceIsolation({
198
+ allowOutside: opts?.allowOutside,
199
+ directory: cwd,
200
+ additionalPaths: opts?.addDir,
201
+ });
202
+ return cwd;
203
+ }
204
+ export function parsePositiveIntegerOption(value, optionName) {
205
+ const trimmed = value.trim();
206
+ const n = Number(trimmed);
207
+ if (!/^[1-9]\d*$/.test(trimmed) || !Number.isSafeInteger(n)) {
208
+ throw new InvalidArgumentError(`${optionName} must be a positive integer`);
209
+ }
210
+ return n;
211
+ }
212
+ export function validateGoalCommandNumericOptions(argv) {
213
+ for (let i = 2; i < argv.length; i++) {
214
+ const arg = argv[i];
215
+ if (arg === undefined)
216
+ continue;
217
+ if (arg === '--')
218
+ break;
219
+ if (arg === '--max-turns' || arg === '--max-tool-rounds') {
220
+ const value = argv[i + 1];
221
+ if (value === undefined)
222
+ continue;
223
+ parsePositiveIntegerOption(value, arg);
224
+ i++;
225
+ continue;
226
+ }
227
+ const eqIndex = arg?.indexOf('=') ?? -1;
228
+ if (eqIndex <= 0)
229
+ continue;
230
+ const optionName = arg.slice(0, eqIndex);
231
+ if (optionName === '--max-turns' || optionName === '--max-tool-rounds') {
232
+ parsePositiveIntegerOption(arg.slice(eqIndex + 1), optionName);
233
+ }
234
+ }
235
+ }
57
236
  export function createGoalCommand() {
58
237
  const cmd = new Command('goal')
59
238
  .description('Run the agent toward a standing goal until a judge model confirms it is done (Ralph loop)')
60
239
  .argument('<goal>', 'The goal to pursue')
61
- .option('--max-turns <n>', 'Turn budget (default 20, or goals.maxTurns from settings)')
240
+ .option('--max-turns <n>', 'Turn budget (default 20, or goals.maxTurns from settings)', value => parsePositiveIntegerOption(value, '--max-turns'))
62
241
  .option('--judge-model <model>', 'Model for the goal judge (default: session model)')
63
242
  .option('-m, --model <model>', 'Override the agent model for this run')
64
- .option('--max-tool-rounds <n>', 'Max tool rounds per turn', '50')
243
+ .option('--max-tool-rounds <n>', 'Max tool rounds per turn', value => parsePositiveIntegerOption(value, '--max-tool-rounds'), 50)
65
244
  .action(async (goal, options, command) => {
66
- const modelOverride = options.model ?? command?.optsWithGlobals?.()?.model;
67
- const resolved = resolveCommandProvider({ explicitModel: modelOverride });
68
- if (!resolved) {
69
- console.error('Error: No provider available — set an API key, run `buddy onboard`, or point CODEBUDDY_PROVIDER=ollama at a local Ollama.');
70
- process.exit(1);
71
- }
72
- if (options.judgeModel) {
73
- process.env.CODEBUDDY_GOAL_JUDGE_MODEL = options.judgeModel;
74
- }
75
- process.env.CODEBUDDY_DISABLE_MCP = process.env.CODEBUDDY_DISABLE_MCP ?? 'true';
76
- process.env.CODEBUDDY_HEADLESS = 'true';
77
245
  try {
246
+ const cwd = await prepareGoalCliWorkspace(command);
247
+ const modelOverride = options.model ?? command?.optsWithGlobals?.()?.model;
248
+ const resolved = resolveCommandProvider({ explicitModel: modelOverride });
249
+ if (!resolved) {
250
+ console.error('Error: No provider available — set an API key, run `buddy onboard`, or point CODEBUDDY_PROVIDER=ollama at a local Ollama.');
251
+ process.exit(1);
252
+ }
253
+ if (options.judgeModel) {
254
+ process.env.CODEBUDDY_GOAL_JUDGE_MODEL = options.judgeModel;
255
+ }
256
+ const judgeModel = resolveGoalCliJudgeModel(options.judgeModel);
257
+ const maxToolRounds = resolveGoalCliMaxToolRounds(options.maxToolRounds, command);
258
+ process.env.CODEBUDDY_DISABLE_MCP = process.env.CODEBUDDY_DISABLE_MCP ?? 'true';
259
+ process.env.CODEBUDDY_HEADLESS = 'true';
78
260
  const { CodeBuddyAgent } = await import('../agent/codebuddy-agent.js');
79
261
  const { ConfirmationService } = await import('../utils/confirmation-service.js');
80
262
  ConfirmationService.getInstance().setSessionFlag('allOperations', true);
81
- const agent = new CodeBuddyAgent(resolved.apiKey, resolved.baseURL, resolved.model, parseInt(options.maxToolRounds, 10));
82
- await agent.systemPromptReady;
83
- const result = await runGoalLoop(agent, goal, {
84
- ...(options.maxTurns ? { maxTurns: parseInt(options.maxTurns, 10) } : {}),
263
+ const agent = new CodeBuddyAgent(resolved.apiKey, resolved.baseURL, resolved.model, maxToolRounds, true, undefined, cwd, undefined, resolveLocalGoalActorSystemPrompt(resolved, cwd));
264
+ const result = await runGoalCommandWithAgent(agent, goal, {
265
+ provider: resolved,
266
+ judgeModel,
267
+ workingDirectory: cwd,
268
+ ...(options.maxTurns !== undefined ? { maxTurns: options.maxTurns } : {}),
85
269
  onMessage: text => console.log(`\n${text}`),
86
270
  });
87
- agent.dispose?.();
88
271
  process.exit(result.status === 'done' ? 0 : 1);
89
272
  }
90
273
  catch (err) {
@@ -1,4 +1,11 @@
1
+ import type { CodeBuddyClient } from '../../codebuddy/client.js';
2
+ import { type GoalPlan } from '../../goals/goal-decomposer.js';
1
3
  import { CommandHandlerResult } from './branch-handlers.js';
4
+ export interface GoalHandlerOptions {
5
+ sessionKey?: string;
6
+ client?: CodeBuddyClient | null;
7
+ planner?: (goal: string, client: CodeBuddyClient) => Promise<GoalPlan | null>;
8
+ }
2
9
  /**
3
10
  * /goal — standing goal with judge + auto-continue loop (the Ralph loop,
4
11
  * ported from Hermes Agent).
@@ -10,7 +17,7 @@ import { CommandHandlerResult } from './branch-handlers.js';
10
17
  * /goal resume restart the loop (resets the turn budget)
11
18
  * /goal clear discard the goal (aliases: stop, done)
12
19
  */
13
- export declare function handleGoal(args: string[]): Promise<CommandHandlerResult>;
20
+ export declare function handleGoal(args: string[], options?: GoalHandlerOptions): Promise<CommandHandlerResult>;
14
21
  /**
15
22
  * /subgoal — extra acceptance criteria added mid-loop.
16
23
  *
@@ -24,4 +31,4 @@ export declare function handleGoal(args: string[]): Promise<CommandHandlerResult
24
31
  * them) and the continuation prompt (agent sees them) on the next turn
25
32
  * boundary — no special kick needed.
26
33
  */
27
- export declare function handleSubgoal(args: string[]): Promise<CommandHandlerResult>;
34
+ export declare function handleSubgoal(args: string[], options?: GoalHandlerOptions): Promise<CommandHandlerResult>;
@@ -1,3 +1,4 @@
1
+ import { decomposeGoal, formatGoalPlan, shouldAutoDecomposeGoal, } from '../../goals/goal-decomposer.js';
1
2
  import { getGoalManager } from '../../goals/goal-manager.js';
2
3
  /**
3
4
  * /goal — standing goal with judge + auto-continue loop (the Ralph loop,
@@ -10,10 +11,10 @@ import { getGoalManager } from '../../goals/goal-manager.js';
10
11
  * /goal resume restart the loop (resets the turn budget)
11
12
  * /goal clear discard the goal (aliases: stop, done)
12
13
  */
13
- export async function handleGoal(args) {
14
+ export async function handleGoal(args, options = {}) {
14
15
  const arg = args.join(' ').trim();
15
16
  const lower = arg.toLowerCase();
16
- const mgr = getGoalManager();
17
+ const mgr = getGoalManager(options.sessionKey);
17
18
  if (!arg || lower === 'status') {
18
19
  return textResult(mgr.statusLine());
19
20
  }
@@ -35,13 +36,37 @@ export async function handleGoal(args) {
35
36
  return textResult(had ? '✓ Goal cleared.' : 'No active goal.');
36
37
  }
37
38
  // Otherwise treat the arg as the goal text.
39
+ let plan = null;
40
+ let planAttempted = false;
41
+ let planError = '';
42
+ if (options.client && shouldAutoDecomposeGoal(arg)) {
43
+ planAttempted = true;
44
+ try {
45
+ plan = await (options.planner ?? decomposeGoal)(arg, options.client);
46
+ }
47
+ catch (error) {
48
+ planError = error instanceof Error ? error.message : String(error);
49
+ }
50
+ }
38
51
  let state;
39
52
  try {
40
- state = mgr.set(arg);
53
+ state = mgr.set(arg, {
54
+ ...(plan ? { goalPlan: plan } : {}),
55
+ ...(planAttempted ? { goalPlanAttempted: true } : {}),
56
+ });
57
+ if (planAttempted && !plan && planError) {
58
+ mgr.markGoalPlanAttempted(planError);
59
+ state = mgr.state ?? state;
60
+ }
41
61
  }
42
62
  catch (error) {
43
63
  return textResult(`Invalid goal: ${error instanceof Error ? error.message : String(error)}`);
44
64
  }
65
+ const planBlock = state.goalPlan
66
+ ? `\n\nHermes-style task graph attached:\n${formatGoalPlan(state.goalPlan)}`
67
+ : planError
68
+ ? `\n\nGoal planning was skipped after an LLM planner error: ${planError}`
69
+ : '';
45
70
  return {
46
71
  handled: true,
47
72
  entry: {
@@ -51,7 +76,8 @@ export async function handleGoal(args) {
51
76
  'keeps working until it is, you pause/clear it, or the budget is ' +
52
77
  'exhausted. Use /goal status, /goal pause, /goal resume, /goal clear. ' +
53
78
  'Tip: for unattended runs, enable auto-approval (/yolo or auto-edit) so ' +
54
- 'the loop is not blocked on confirmations.',
79
+ 'the loop is not blocked on confirmations.' +
80
+ planBlock,
55
81
  timestamp: new Date(),
56
82
  },
57
83
  // Kick the loop off immediately — the dispatcher feeds the goal text as
@@ -73,9 +99,9 @@ export async function handleGoal(args) {
73
99
  * them) and the continuation prompt (agent sees them) on the next turn
74
100
  * boundary — no special kick needed.
75
101
  */
76
- export async function handleSubgoal(args) {
102
+ export async function handleSubgoal(args, options = {}) {
77
103
  const arg = args.join(' ').trim();
78
- const mgr = getGoalManager();
104
+ const mgr = getGoalManager(options.sessionKey);
79
105
  if (!mgr.hasGoal()) {
80
106
  return textResult('No active goal. Set one with /goal <text>.');
81
107
  }
@@ -88,9 +114,10 @@ export async function handleSubgoal(args) {
88
114
  if (!rest) {
89
115
  return textResult('Usage: /subgoal remove <n>');
90
116
  }
91
- const idx = Number(rest.split(/\s+/)[0]);
92
- if (!Number.isInteger(idx)) {
93
- return textResult('/subgoal remove: <n> must be an integer (1-based index).');
117
+ const indexToken = rest.split(/\s+/)[0] ?? '';
118
+ const idx = Number(indexToken);
119
+ if (!/^[1-9]\d*$/.test(indexToken) || !Number.isSafeInteger(idx)) {
120
+ return textResult('/subgoal remove: <n> must be a positive integer (1-based index).');
94
121
  }
95
122
  try {
96
123
  const removed = mgr.removeSubgoal(idx);
@@ -6,6 +6,7 @@
6
6
  * and the current TurboQuant routing statistics.
7
7
  */
8
8
  import { logger } from '../../utils/logger.js';
9
+ import { fetchOllamaStatus } from '../ollama.js';
9
10
  async function checkEndpoint(name, url, timeoutMs = 4000) {
10
11
  const start = Date.now();
11
12
  try {
@@ -49,6 +50,35 @@ function formatRoutingStats(stats) {
49
50
  }
50
51
  return lines.join('\n');
51
52
  }
53
+ function formatOllamaSummary(status) {
54
+ const lines = [
55
+ ` Reachable: ${status.reachable ? 'YES' : 'NO'}`,
56
+ ` Version: ${status.version ?? '(unknown)'}`,
57
+ ` Models: ${status.models.length > 0 ? status.models.join(', ') : '(none)'}`,
58
+ ];
59
+ if (status.error) {
60
+ lines.push(` Error: ${status.error}`);
61
+ }
62
+ lines.push(` Gemma 4 ready: ${isGemma4Ready(status.version, status.models) ? 'YES' : 'NO'}`);
63
+ return lines.join('\n');
64
+ }
65
+ function isGemma4Ready(version, models) {
66
+ if (!version)
67
+ return false;
68
+ const [majorRaw, minorRaw, patchRaw] = version.split('.');
69
+ const major = Number.parseInt(majorRaw ?? '', 10);
70
+ const minor = Number.parseInt(minorRaw ?? '', 10);
71
+ const patch = Number.parseInt(patchRaw ?? '', 10);
72
+ if (!Number.isFinite(major) || !Number.isFinite(minor) || !Number.isFinite(patch))
73
+ return false;
74
+ if (major > 0)
75
+ return true;
76
+ if (minor > 24)
77
+ return true;
78
+ if (minor === 24 && patch >= 1)
79
+ return true;
80
+ return models.some((model) => model.toLowerCase().includes('gemma4'));
81
+ }
52
82
  // ---------------------------------------------------------------------------
53
83
  // Main handler
54
84
  // ---------------------------------------------------------------------------
@@ -102,6 +132,9 @@ async function handleInfraDashboard() {
102
132
  lines.push(formatStatus(s));
103
133
  }
104
134
  lines.push('');
135
+ lines.push('Ollama Summary:');
136
+ lines.push(formatOllamaSummary(await fetchOllamaStatus(ollamaUrl)));
137
+ lines.push('');
105
138
  // Routing stats from TurboQuant plugin
106
139
  try {
107
140
  const { getTurboQuantStats } = await import('../../plugins/bundled/turboquant-plugin.js');
@@ -159,6 +192,9 @@ async function handleInfraHealth() {
159
192
  for (const s of statuses) {
160
193
  lines.push(formatStatus(s));
161
194
  }
195
+ lines.push('');
196
+ lines.push('Ollama Summary:');
197
+ lines.push(formatOllamaSummary(await fetchOllamaStatus(ollamaUrl)));
162
198
  return { handled: true, response: lines.join('\n') };
163
199
  }
164
200
  //# sourceMappingURL=infra-handlers.js.map
@@ -27,6 +27,9 @@ function formatTimeAgo(date, now = new Date()) {
27
27
  const yr = Math.floor(day / 365);
28
28
  return `${yr} year${yr === 1 ? "" : "s"} ago`;
29
29
  }
30
+ function clip(text, max = 180) {
31
+ return text.length > max ? text.slice(0, max - 1) + "…" : text;
32
+ }
30
33
  /**
31
34
  * Memory - Manage persistent memory using PersistentMemoryManager (Markdown) and EnhancedMemory (SQLite/Vector)
32
35
  */
@@ -103,10 +106,10 @@ export async function handleMemory(args) {
103
106
  content = `Usage: /memory remember <key> <content> [project|user]`;
104
107
  break;
105
108
  }
106
- const value = args.slice(2).join(" ");
107
109
  const scope = (args[args.length - 1] === "user" || args[args.length - 1] === "project")
108
110
  ? args.pop()
109
111
  : "project";
112
+ const value = args.slice(2).join(" ");
110
113
  // Store in both for redundancy and better retrieval
111
114
  await persistentMemory.remember(key, value, { scope, category: "custom" });
112
115
  await enhancedMemory.store({
@@ -121,6 +124,30 @@ export async function handleMemory(args) {
121
124
  content = `Usage: /memory remember <key> <content> [project|user]`;
122
125
  }
123
126
  break;
127
+ case "replace":
128
+ case "update":
129
+ if (args.length >= 3) {
130
+ const key = args[1];
131
+ if (key === undefined) {
132
+ content = `Usage: /memory replace <key> <content> [project|user]`;
133
+ break;
134
+ }
135
+ const scope = (args[args.length - 1] === "user" || args[args.length - 1] === "project")
136
+ ? args.pop()
137
+ : "project";
138
+ const value = args.slice(2).join(" ");
139
+ const result = await persistentMemory.replace(key, value, { scope });
140
+ if (result.status === 'missing') {
141
+ content = result.message;
142
+ }
143
+ else {
144
+ content = `✅ ${result.message}\nCapacity: ${result.usage.used}/${result.usage.limit} chars (${result.usage.percent}%).`;
145
+ }
146
+ }
147
+ else {
148
+ content = `Usage: /memory replace <key> <content> [project|user]`;
149
+ }
150
+ break;
124
151
  case "context":
125
152
  const enhancedContext = await enhancedMemory.buildContext({
126
153
  includeProject: true,
@@ -154,6 +181,74 @@ export async function handleMemory(args) {
154
181
  }
155
182
  break;
156
183
  }
184
+ case "candidates":
185
+ case "candidate":
186
+ case "pending": {
187
+ const { getMemoryCandidateQueue } = await import("../../memory/memory-candidate-queue.js");
188
+ const statusArg = args[1];
189
+ const status = statusArg === "pending" || statusArg === "accepted" || statusArg === "rejected"
190
+ ? statusArg
191
+ : undefined;
192
+ const rawLimit = parseInt(args[status ? 2 : 1] ?? "20", 10);
193
+ const limit = Math.min(50, Math.max(1, Number.isFinite(rawLimit) ? rawLimit : 20));
194
+ const candidates = getMemoryCandidateQueue(process.cwd()).list(status).slice(0, limit);
195
+ if (candidates.length === 0) {
196
+ content = status ? `No ${status} memory candidates.` : "No memory candidates yet.";
197
+ }
198
+ else {
199
+ const lines = [`🧠 Memory candidates (${candidates.length}${status ? ` ${status}` : ""})`, "═".repeat(50)];
200
+ for (const candidate of candidates) {
201
+ const created = formatTimeAgo(new Date(candidate.createdAt));
202
+ const confidence = typeof candidate.confidence === "number"
203
+ ? ` | confidence ${(candidate.confidence * 100).toFixed(0)}%`
204
+ : "";
205
+ lines.push(`[${candidate.status}] ${candidate.id} | ${candidate.scope}/${candidate.category}${confidence} | ${created}`);
206
+ lines.push(` ${candidate.key}: ${clip(candidate.value)}`);
207
+ const citation = candidate.citations?.[0];
208
+ if (citation) {
209
+ const label = citation.sessionId
210
+ ? `${citation.sessionId}${citation.messageId ? `#${citation.messageId}` : citation.messageIndex ? `#${citation.messageIndex}` : ""}`
211
+ : citation.messageIndex ? `message ${citation.messageIndex}` : "evidence";
212
+ lines.push(` citation: ${label}${citation.role ? ` (${citation.role})` : ""} — ${clip(citation.snippet, 140)}`);
213
+ }
214
+ lines.push("");
215
+ }
216
+ lines.push("Approve: /memory accept <id> [reviewer]");
217
+ lines.push("Reject: /memory reject <id> [reason]");
218
+ content = lines.join("\n").trimEnd();
219
+ }
220
+ break;
221
+ }
222
+ case "accept":
223
+ case "approve": {
224
+ const id = args[1];
225
+ if (!id) {
226
+ content = `Usage: /memory accept <candidate-id> [reviewer]`;
227
+ break;
228
+ }
229
+ const reviewedBy = args.slice(2).join(" ").trim() || "user";
230
+ const { getMemoryCandidateQueue } = await import("../../memory/memory-candidate-queue.js");
231
+ const { candidate, write } = await getMemoryCandidateQueue(process.cwd()).accept(id, { reviewedBy });
232
+ content = `✅ Accepted ${candidate.id} into ${candidate.scope} memory as "${candidate.key}".\n` +
233
+ `Write status: ${write.status}. Capacity: ${write.usage.used}/${write.usage.limit} chars (${write.usage.percent}%).`;
234
+ break;
235
+ }
236
+ case "reject":
237
+ case "discard": {
238
+ const id = args[1];
239
+ if (!id) {
240
+ content = `Usage: /memory reject <candidate-id> [reason]`;
241
+ break;
242
+ }
243
+ const reason = args.slice(2).join(" ").trim();
244
+ const { getMemoryCandidateQueue } = await import("../../memory/memory-candidate-queue.js");
245
+ const candidate = getMemoryCandidateQueue(process.cwd()).reject(id, {
246
+ reviewedBy: "user",
247
+ ...(reason ? { reason } : {}),
248
+ });
249
+ content = `🗑️ Rejected memory candidate ${candidate.id}.`;
250
+ break;
251
+ }
157
252
  case "status":
158
253
  case "list":
159
254
  default:
@@ -22,7 +22,7 @@ export declare function handleDiffCheckpoints(args: string[]): Promise<CommandHa
22
22
  export declare function handleFeatures(): CommandHandlerResult;
23
23
  export declare function handleListCheckpoints(_args: string[]): Promise<CommandHandlerResult>;
24
24
  export declare function handleRestoreCheckpoint(args: string[]): Promise<CommandHandlerResult>;
25
- export declare function handleInitGrok(): Promise<CommandHandlerResult>;
25
+ export declare function handleInitGrok(args?: string[]): Promise<CommandHandlerResult>;
26
26
  export declare function handleReinitGrok(): Promise<CommandHandlerResult>;
27
27
  export declare function handleStatus(): Promise<CommandHandlerResult>;
28
28
  export declare function handleNew(args: string[]): Promise<CommandHandlerResult>;
@@ -660,17 +660,40 @@ Use /checkpoints to see available checkpoints.`,
660
660
  // ============================================================================
661
661
  // /init - Initialize Code Buddy Project
662
662
  // ============================================================================
663
- export async function handleInitGrok() {
663
+ export async function handleInitGrok(args = []) {
664
664
  try {
665
- const { initCodeBuddyProject, formatInitResult } = await import('../../utils/init-project.js');
665
+ const fast = args.some((a) => a === '--fast' || a === '-f');
666
+ const { initCodeBuddyProject, formatInitResult, buildInitPrompt } = await import('../../utils/init-project.js');
667
+ // Deterministic scaffolding first (.codebuddy plumbing + template files,
668
+ // skip-if-exists). This always runs, so the config + a baseline AGENTS.md exist.
666
669
  const initResult = await initCodeBuddyProject();
670
+ if (fast) {
671
+ // --fast: deterministic template only (the legacy behavior).
672
+ return {
673
+ handled: true,
674
+ entry: { type: 'assistant', content: formatInitResult(initResult), timestamp: new Date() },
675
+ };
676
+ }
677
+ // Default: hand off to the agent to read the code and write a tailored
678
+ // AGENTS.md, grounded on the RepoProfiler's verified facts.
679
+ let contextPack = '';
680
+ try {
681
+ const { getRepoProfiler } = await import('../../agent/repo-profiler.js');
682
+ const profile = await getRepoProfiler().getProfile();
683
+ contextPack = profile.contextPack ?? '';
684
+ }
685
+ catch {
686
+ /* profiler optional — the prompt still works without the facts block */
687
+ }
667
688
  return {
668
689
  handled: true,
669
690
  entry: {
670
691
  type: 'assistant',
671
- content: formatInitResult(initResult),
692
+ content: `${formatInitResult(initResult)}\n\nNow analyzing the repository to write a tailored \`AGENTS.md\`… (run \`/init --fast\` for the deterministic template only)`,
672
693
  timestamp: new Date(),
673
694
  },
695
+ passToAI: true,
696
+ prompt: buildInitPrompt(contextPack),
674
697
  };
675
698
  }
676
699
  catch (error) {
@@ -33,6 +33,8 @@ export interface HeadlessSlashContext {
33
33
  conversationHistory?: ChatEntry[];
34
34
  /** LLM client, for tokens that call the model directly (ai-test, btw). */
35
35
  client?: CodeBuddyClient;
36
+ /** Optional goal-state key for non-TUI surfaces with their own session ids. */
37
+ goalSessionKey?: string;
36
38
  }
37
39
  /** Result of running a special token outside the TUI. */
38
40
  export interface HeadlessSlashResult {