@phuetz/code-buddy 2.0.0 → 2.1.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 (403) hide show
  1. package/README.fr.md +56 -0
  2. package/README.md +73 -16
  3. package/codebuddy-runtime.json +5 -5
  4. package/dist/agent/codebuddy-agent.d.ts +18 -0
  5. package/dist/agent/codebuddy-agent.js +45 -8
  6. package/dist/agent/execution/agent-executor.d.ts +0 -9
  7. package/dist/agent/execution/agent-executor.js +165 -12
  8. package/dist/agent/execution/context-pipeline.d.ts +9 -0
  9. package/dist/agent/execution/context-pipeline.js +64 -2
  10. package/dist/agent/execution/tool-loop-guard.d.ts +76 -0
  11. package/dist/agent/execution/tool-loop-guard.js +165 -0
  12. package/dist/agent/execution/tool-selection-strategy.js +19 -2
  13. package/dist/agent/facades/session-facade.d.ts +0 -6
  14. package/dist/agent/facades/session-facade.js +0 -45
  15. package/dist/agent/hermes-claw-migrate.d.ts +0 -21
  16. package/dist/agent/hermes-claw-migrate.js +9 -4
  17. package/dist/agent/hermes-protocol-gateways.js +8 -1
  18. package/dist/agent/repo-profiler.js +17 -4
  19. package/dist/agent/self-improvement/authored-tool-runtime.js +10 -2
  20. package/dist/agent/self-improvement/evolution/ast-novelty.d.ts +5 -0
  21. package/dist/agent/self-improvement/evolution/ast-novelty.js +58 -23
  22. package/dist/agent/self-improvement/evolution/code-variant-store.d.ts +3 -0
  23. package/dist/agent/self-improvement/evolution/evolution-engine.js +2 -0
  24. package/dist/agent/self-improvement/evolution/protected-paths.js +6 -0
  25. package/dist/agent/self-improvement/evolution/variant-fitness.d.ts +13 -2
  26. package/dist/agent/self-improvement/evolution/variant-fitness.js +184 -58
  27. package/dist/agent/self-improvement/evolution/worktree-scorer.d.ts +2 -0
  28. package/dist/agent/self-improvement/evolution/worktree-scorer.js +15 -0
  29. package/dist/agent/self-improvement/evolutionary-archive.d.ts +2 -1
  30. package/dist/agent/self-improvement/evolutionary-archive.js +34 -5
  31. package/dist/agent/self-improvement/proposal-store.d.ts +1 -0
  32. package/dist/agent/self-improvement/proposal-store.js +79 -17
  33. package/dist/agent/self-improvement/skill-apply-journal.d.ts +44 -0
  34. package/dist/agent/self-improvement/skill-apply-journal.js +178 -0
  35. package/dist/agent/self-improvement/skill-behavior-benchmark.d.ts +3 -0
  36. package/dist/agent/self-improvement/skill-behavior-benchmark.js +19 -0
  37. package/dist/agent/self-improvement/skill-behavior-gate.d.ts +34 -0
  38. package/dist/agent/self-improvement/skill-behavior-gate.js +96 -0
  39. package/dist/agent/self-improvement/skill-engine.d.ts +22 -0
  40. package/dist/agent/self-improvement/skill-engine.js +385 -13
  41. package/dist/agent/self-improvement/skill-gate.d.ts +2 -0
  42. package/dist/agent/self-improvement/skill-gate.js +17 -2
  43. package/dist/agent/self-improvement/skill-mutator.d.ts +6 -1
  44. package/dist/agent/self-improvement/skill-mutator.js +51 -15
  45. package/dist/agent/self-improvement/skill-types.d.ts +2 -1
  46. package/dist/agent/self-improvement/types.d.ts +11 -0
  47. package/dist/agent/tool-handler.d.ts +1 -1
  48. package/dist/agent/tool-handler.js +28 -9
  49. package/dist/auth/profile-manager.js +1 -1
  50. package/dist/channels/companion-channel-turn.d.ts +53 -4
  51. package/dist/channels/companion-channel-turn.js +218 -16
  52. package/dist/channels/slash-parity.d.ts +4 -6
  53. package/dist/channels/slash-parity.js +9 -44
  54. package/dist/cli/session-commands.d.ts +9 -0
  55. package/dist/cli/session-commands.js +45 -5
  56. package/dist/cli/session-picker.d.ts +43 -0
  57. package/dist/cli/session-picker.js +128 -0
  58. package/dist/codebuddy/a2a-call-tool-defs.d.ts +26 -0
  59. package/dist/codebuddy/a2a-call-tool-defs.js +12 -0
  60. package/dist/codebuddy/fleet-tool-defs.d.ts +1 -0
  61. package/dist/codebuddy/fleet-tool-defs.js +24 -0
  62. package/dist/codebuddy/providers/chatgpt-headers.d.ts +18 -0
  63. package/dist/codebuddy/providers/chatgpt-headers.js +37 -0
  64. package/dist/codebuddy/providers/provider-chatgpt-responses.d.ts +2 -1
  65. package/dist/codebuddy/providers/provider-chatgpt-responses.js +10 -23
  66. package/dist/codebuddy/providers/provider-openai-compat.js +1 -1
  67. package/dist/codebuddy/ragchat-tool-defs.d.ts +31 -0
  68. package/dist/codebuddy/ragchat-tool-defs.js +19 -0
  69. package/dist/codebuddy/resource-catalog-tool-defs.d.ts +28 -0
  70. package/dist/codebuddy/resource-catalog-tool-defs.js +18 -0
  71. package/dist/codebuddy/tool-definitions/agent-tools.js +2 -2
  72. package/dist/codebuddy/tool-definitions/code-exec-tools.js +5 -1
  73. package/dist/codebuddy/tool-definitions/cron-tools.js +6 -0
  74. package/dist/codebuddy/tool-definitions/self-describe-tools.js +6 -1
  75. package/dist/codebuddy/tools.d.ts +0 -6
  76. package/dist/codebuddy/tools.js +25 -3
  77. package/dist/commands/cli/daemon-commands.js +3 -1
  78. package/dist/commands/cli/evolve-command.js +21 -5
  79. package/dist/commands/cli/fleet-collaboration-commands.d.ts +2 -0
  80. package/dist/commands/cli/fleet-collaboration-commands.js +57 -0
  81. package/dist/commands/cli/fleet-commands.js +29 -0
  82. package/dist/commands/cli/fleet-mission-commands.d.ts +3 -0
  83. package/dist/commands/cli/fleet-mission-commands.js +72 -0
  84. package/dist/commands/cli/fleet-rooms-commands.d.ts +10 -0
  85. package/dist/commands/cli/fleet-rooms-commands.js +289 -0
  86. package/dist/commands/cli/tools-commands.js +2 -1
  87. package/dist/commands/cli/triage-command.d.ts +8 -0
  88. package/dist/commands/cli/triage-command.js +72 -0
  89. package/dist/commands/cli/utility-commands.js +25 -1
  90. package/dist/commands/client-dispatcher.d.ts +7 -0
  91. package/dist/commands/client-dispatcher.js +73 -21
  92. package/dist/commands/cron-cli/index.d.ts +3 -1
  93. package/dist/commands/cron-cli/index.js +25 -0
  94. package/dist/commands/device-auth.d.ts +10 -0
  95. package/dist/commands/device-auth.js +91 -0
  96. package/dist/commands/enhanced-command-handler.d.ts +9 -0
  97. package/dist/commands/enhanced-command-handler.js +28 -6
  98. package/dist/commands/handlers/agent-handlers.d.ts +1 -1
  99. package/dist/commands/handlers/agent-handlers.js +4 -4
  100. package/dist/commands/handlers/channel-handlers.js +53 -2
  101. package/dist/commands/handlers/export-handlers.d.ts +3 -2
  102. package/dist/commands/handlers/export-handlers.js +55 -28
  103. package/dist/commands/handlers/extra-handlers.js +5 -1
  104. package/dist/commands/handlers/grill-me-handler.js +26 -18
  105. package/dist/commands/handlers/memory-handlers.d.ts +6 -2
  106. package/dist/commands/handlers/memory-handlers.js +35 -15
  107. package/dist/commands/handlers/missing-handlers.d.ts +2 -2
  108. package/dist/commands/handlers/missing-handlers.js +4 -4
  109. package/dist/commands/handlers/resources-handler.d.ts +12 -0
  110. package/dist/commands/handlers/resources-handler.js +52 -0
  111. package/dist/commands/handlers/starter-handlers.d.ts +1 -1
  112. package/dist/commands/handlers/starter-handlers.js +32 -2
  113. package/dist/commands/handlers/switch-handler.d.ts +1 -1
  114. package/dist/commands/handlers/switch-handler.js +15 -0
  115. package/dist/commands/handlers/test-handlers.js +4 -86
  116. package/dist/commands/handlers/ui-handlers.js +11 -5
  117. package/dist/commands/login-chatgpt.d.ts +8 -0
  118. package/dist/commands/login-chatgpt.js +17 -0
  119. package/dist/commands/mcp-import.d.ts +11 -0
  120. package/dist/commands/mcp-import.js +67 -0
  121. package/dist/commands/mcp-invoke.d.ts +2 -0
  122. package/dist/commands/mcp-invoke.js +68 -0
  123. package/dist/commands/mcp.js +4 -0
  124. package/dist/commands/pipeline.d.ts +7 -1
  125. package/dist/commands/pipeline.js +104 -7
  126. package/dist/commands/resources.d.ts +2 -0
  127. package/dist/commands/resources.js +64 -0
  128. package/dist/commands/skills-cli/index.js +35 -12
  129. package/dist/commands/slash/builtin-commands.js +16 -3
  130. package/dist/commands/slash/index.d.ts +3 -1
  131. package/dist/commands/slash/index.js +2 -0
  132. package/dist/commands/slash/surfaces.d.ts +53 -0
  133. package/dist/commands/slash/surfaces.js +177 -0
  134. package/dist/commands/slash/types.d.ts +17 -0
  135. package/dist/commands/try.d.ts +1 -1
  136. package/dist/commands/try.js +1 -1
  137. package/dist/companion/companion-identity.d.ts +43 -0
  138. package/dist/companion/companion-identity.js +136 -0
  139. package/dist/companion/companion-toolset.d.ts +66 -0
  140. package/dist/companion/companion-toolset.js +368 -0
  141. package/dist/companion/companion-turn.d.ts +10 -2
  142. package/dist/companion/companion-turn.js +38 -1
  143. package/dist/config/code-exec-policy.d.ts +25 -0
  144. package/dist/config/code-exec-policy.js +39 -0
  145. package/dist/config/model-tools.d.ts +9 -0
  146. package/dist/config/model-tools.js +4 -0
  147. package/dist/context/context-manager-v2.js +2 -2
  148. package/dist/context/lm-resizer-compressor.js +3 -2
  149. package/dist/context/lm-resizer-diagnostics.d.ts +9 -0
  150. package/dist/context/lm-resizer-diagnostics.js +30 -0
  151. package/dist/context/tool-output-masking.js +3 -4
  152. package/dist/curator/curator.d.ts +6 -0
  153. package/dist/curator/curator.js +53 -3
  154. package/dist/daemon/cron-agent-bridge.d.ts +6 -0
  155. package/dist/daemon/cron-agent-bridge.js +31 -4
  156. package/dist/doctor/index.d.ts +11 -2
  157. package/dist/doctor/index.js +84 -21
  158. package/dist/doctor/integrations.d.ts +179 -0
  159. package/dist/doctor/integrations.js +227 -0
  160. package/dist/doctor/triage.d.ts +108 -0
  161. package/dist/doctor/triage.js +304 -0
  162. package/dist/fleet/collaboration.d.ts +44 -0
  163. package/dist/fleet/collaboration.js +170 -0
  164. package/dist/fleet/fleet-listener.d.ts +1 -0
  165. package/dist/fleet/fleet-listener.js +87 -46
  166. package/dist/fleet/fleet-registry.d.ts +2 -0
  167. package/dist/fleet/resource-catalog.d.ts +245 -0
  168. package/dist/fleet/resource-catalog.js +211 -0
  169. package/dist/fleet/rooms/room-access.d.ts +138 -0
  170. package/dist/fleet/rooms/room-access.js +196 -0
  171. package/dist/fleet/rooms/room-client.d.ts +158 -0
  172. package/dist/fleet/rooms/room-client.js +685 -0
  173. package/dist/fleet/rooms/room-event.d.ts +139 -0
  174. package/dist/fleet/rooms/room-event.js +330 -0
  175. package/dist/fleet/rooms/room-filter.d.ts +48 -0
  176. package/dist/fleet/rooms/room-filter.js +152 -0
  177. package/dist/fleet/rooms/room-hub.d.ts +154 -0
  178. package/dist/fleet/rooms/room-hub.js +363 -0
  179. package/dist/fleet/rooms/room-identity.d.ts +26 -0
  180. package/dist/fleet/rooms/room-identity.js +82 -0
  181. package/dist/fleet/rooms/room-lock.d.ts +34 -0
  182. package/dist/fleet/rooms/room-lock.js +180 -0
  183. package/dist/fleet/rooms/room-observations.d.ts +7 -0
  184. package/dist/fleet/rooms/room-observations.js +61 -0
  185. package/dist/fleet/rooms/room-server.d.ts +28 -0
  186. package/dist/fleet/rooms/room-server.js +75 -0
  187. package/dist/fleet/rooms/room-store.d.ts +119 -0
  188. package/dist/fleet/rooms/room-store.js +448 -0
  189. package/dist/fleet/rooms/room-ws-bridge.d.ts +27 -0
  190. package/dist/fleet/rooms/room-ws-bridge.js +137 -0
  191. package/dist/fleet/sensory-mission-bridge.d.ts +42 -0
  192. package/dist/fleet/sensory-mission-bridge.js +136 -0
  193. package/dist/git/worktree-sessions.js +1 -0
  194. package/dist/harness/contract.d.ts +4 -4
  195. package/dist/harness/fleet-supervisor.d.ts +16 -0
  196. package/dist/harness/fleet-supervisor.js +64 -0
  197. package/dist/harness/index.d.ts +4 -0
  198. package/dist/harness/index.js +4 -0
  199. package/dist/harness/mission-runner.d.ts +3 -0
  200. package/dist/harness/mission-runner.js +53 -0
  201. package/dist/harness/mission-store.d.ts +93 -0
  202. package/dist/harness/mission-store.js +297 -0
  203. package/dist/harness/tool-harness.d.ts +56 -0
  204. package/dist/harness/tool-harness.js +153 -0
  205. package/dist/hooks/use-enhanced-input.js +48 -4
  206. package/dist/hooks/use-input-handler.d.ts +1 -0
  207. package/dist/hooks/use-input-handler.js +82 -22
  208. package/dist/hooks/use-input-history.js +1 -0
  209. package/dist/identity/lisa-introspection.js +5 -2
  210. package/dist/identity/operational-self-model.d.ts +2 -0
  211. package/dist/identity/operational-self-model.js +4 -0
  212. package/dist/index.js +52 -6
  213. package/dist/mcp/client.js +6 -0
  214. package/dist/mcp/config.d.ts +20 -0
  215. package/dist/mcp/config.js +121 -8
  216. package/dist/mcp/import-normalize.d.ts +12 -0
  217. package/dist/mcp/import-normalize.js +114 -0
  218. package/dist/mcp/transports.d.ts +10 -5
  219. package/dist/mcp/transports.js +61 -99
  220. package/dist/mcp/types.d.ts +5 -0
  221. package/dist/media/comfyui-recipe-contract.d.ts +7 -7
  222. package/dist/memory/facts-memory.d.ts +11 -1
  223. package/dist/memory/facts-memory.js +47 -8
  224. package/dist/memory/memory-candidate-queue.d.ts +2 -2
  225. package/dist/memory/memory-candidate-queue.js +6 -6
  226. package/dist/memory/persistent-memory.d.ts +13 -8
  227. package/dist/memory/persistent-memory.js +77 -30
  228. package/dist/nodes/device-node.js +5 -9
  229. package/dist/observability/mobile-supervision-gateway-contract.js +20 -7
  230. package/dist/observability/run-event-writer.d.ts +21 -0
  231. package/dist/observability/run-event-writer.js +81 -0
  232. package/dist/observability/run-store.d.ts +5 -0
  233. package/dist/observability/run-store.js +18 -13
  234. package/dist/observability/run-trajectory.js +1 -1
  235. package/dist/optimization/prompt-cache.d.ts +19 -2
  236. package/dist/optimization/prompt-cache.js +41 -6
  237. package/dist/orchestration/orchestrator.d.ts +21 -0
  238. package/dist/orchestration/orchestrator.js +122 -15
  239. package/dist/persistence/session-content.d.ts +8 -0
  240. package/dist/persistence/session-content.js +76 -0
  241. package/dist/persistence/session-handoff.d.ts +64 -0
  242. package/dist/persistence/session-handoff.js +80 -0
  243. package/dist/persistence/session-history.d.ts +4 -0
  244. package/dist/persistence/session-history.js +38 -0
  245. package/dist/persistence/session-store.d.ts +9 -0
  246. package/dist/persistence/session-store.js +48 -20
  247. package/dist/personas/persona-manager.js +17 -1
  248. package/dist/plugins/code-explorer/CodeExplorerManager.d.ts +10 -4
  249. package/dist/plugins/code-explorer/CodeExplorerManager.js +69 -16
  250. package/dist/plugins/plugin-manager.js +10 -1
  251. package/dist/prompts/prompt-manager.js +11 -4
  252. package/dist/prompts/system-base.js +6 -2
  253. package/dist/protocols/a2a/codebuddy-executor.d.ts +11 -2
  254. package/dist/protocols/a2a/codebuddy-executor.js +9 -8
  255. package/dist/protocols/a2a/index.d.ts +1 -1
  256. package/dist/protocols/a2a/jsonrpc-v1.d.ts +41 -0
  257. package/dist/protocols/a2a/jsonrpc-v1.js +145 -0
  258. package/dist/protocols/a2a/peer-config.d.ts +20 -0
  259. package/dist/protocols/a2a/peer-config.js +55 -0
  260. package/dist/providers/codex-oauth.js +30 -6
  261. package/dist/providers/model-provider-compat.js +2 -1
  262. package/dist/sandbox/os-sandbox.d.ts +1 -1
  263. package/dist/scheduler/cron-scheduler.d.ts +15 -2
  264. package/dist/scheduler/cron-scheduler.js +35 -4
  265. package/dist/scheduler/job-notepad.d.ts +69 -0
  266. package/dist/scheduler/job-notepad.js +339 -0
  267. package/dist/security/audit-logger.d.ts +1 -1
  268. package/dist/security/compute-confinement.d.ts +4 -0
  269. package/dist/security/compute-confinement.js +89 -0
  270. package/dist/security/session-encryption.d.ts +4 -0
  271. package/dist/security/session-encryption.js +31 -0
  272. package/dist/sensory/voice-loop.d.ts +17 -0
  273. package/dist/sensory/voice-loop.js +72 -15
  274. package/dist/server/auth/device-session-context.d.ts +9 -0
  275. package/dist/server/auth/device-session-context.js +13 -0
  276. package/dist/server/auth/device-store.d.ts +89 -0
  277. package/dist/server/auth/device-store.js +261 -0
  278. package/dist/server/auth/device-token.d.ts +3 -0
  279. package/dist/server/auth/device-token.js +6 -0
  280. package/dist/server/auth/jwt.js +4 -0
  281. package/dist/server/index.d.ts +0 -10
  282. package/dist/server/index.js +28 -0
  283. package/dist/server/middleware/auth.js +3 -2
  284. package/dist/server/routes/a2a-jsonrpc.d.ts +9 -0
  285. package/dist/server/routes/a2a-jsonrpc.js +66 -0
  286. package/dist/server/routes/a2a-protocol.d.ts +12 -0
  287. package/dist/server/routes/a2a-protocol.js +1 -1
  288. package/dist/server/routes/device-auth.d.ts +4 -0
  289. package/dist/server/routes/device-auth.js +40 -0
  290. package/dist/server/types.d.ts +4 -0
  291. package/dist/server/websocket/handler.d.ts +13 -0
  292. package/dist/server/websocket/handler.js +102 -17
  293. package/dist/services/prompt-builder.d.ts +2 -0
  294. package/dist/services/prompt-builder.js +13 -5
  295. package/dist/services/runtime-settings-context.d.ts +73 -0
  296. package/dist/services/runtime-settings-context.js +69 -0
  297. package/dist/skills/executor.js +2 -0
  298. package/dist/skills/hub.js +16 -14
  299. package/dist/skills/local-inventory.d.ts +21 -0
  300. package/dist/skills/local-inventory.js +72 -0
  301. package/dist/skills/skill-loader.js +2 -2
  302. package/dist/skills/skill-usage-store.d.ts +49 -0
  303. package/dist/skills/skill-usage-store.js +121 -0
  304. package/dist/testing/ai-integration-tests.js +8 -5
  305. package/dist/themes/theme-manager.d.ts +12 -0
  306. package/dist/themes/theme-manager.js +29 -0
  307. package/dist/themes/theme-schema.d.ts +24 -24
  308. package/dist/tools/a2a-call-tool.d.ts +34 -0
  309. package/dist/tools/a2a-call-tool.js +75 -0
  310. package/dist/tools/bash/streaming-executor.d.ts +1 -0
  311. package/dist/tools/bash/streaming-executor.js +78 -90
  312. package/dist/tools/code-exec-preflight-runner.d.ts +41 -0
  313. package/dist/tools/code-exec-preflight-runner.js +254 -0
  314. package/dist/tools/code-exec-preflight.d.ts +44 -0
  315. package/dist/tools/code-exec-preflight.js +501 -0
  316. package/dist/tools/code-exec-tool.d.ts +48 -1
  317. package/dist/tools/code-exec-tool.js +191 -47
  318. package/dist/tools/comment-watcher.js +29 -12
  319. package/dist/tools/core-code-inspection.d.ts +56 -0
  320. package/dist/tools/core-code-inspection.js +86 -0
  321. package/dist/tools/create-skill-tool.d.ts +2 -3
  322. package/dist/tools/create-skill-tool.js +16 -75
  323. package/dist/tools/cronjob-tool.d.ts +1 -0
  324. package/dist/tools/cronjob-tool.js +1 -0
  325. package/dist/tools/env-doctor-tool.d.ts +2 -0
  326. package/dist/tools/env-doctor-tool.js +4 -3
  327. package/dist/tools/execute-code-rpc-invoker.d.ts +1 -1
  328. package/dist/tools/execute-code-rpc-invoker.js +35 -19
  329. package/dist/tools/execute-code-runner.d.ts +2 -0
  330. package/dist/tools/execute-code-runner.js +52 -17
  331. package/dist/tools/fleet-room-tool.d.ts +104 -0
  332. package/dist/tools/fleet-room-tool.js +124 -0
  333. package/dist/tools/integration-tool-hints.d.ts +4 -0
  334. package/dist/tools/integration-tool-hints.js +19 -0
  335. package/dist/tools/list-peers-tool.d.ts +3 -0
  336. package/dist/tools/list-peers-tool.js +11 -4
  337. package/dist/tools/media-generation-tool.d.ts +16 -1
  338. package/dist/tools/media-generation-tool.js +341 -9
  339. package/dist/tools/merge-conflict-tool.js +53 -25
  340. package/dist/tools/metadata.d.ts +1 -5
  341. package/dist/tools/metadata.js +21 -28
  342. package/dist/tools/ragchat-tool.d.ts +39 -0
  343. package/dist/tools/ragchat-tool.js +105 -0
  344. package/dist/tools/registry/fleet-tools.d.ts +9 -0
  345. package/dist/tools/registry/fleet-tools.js +22 -1
  346. package/dist/tools/registry/knowledge-tools.d.ts +2 -2
  347. package/dist/tools/registry/knowledge-tools.js +2 -2
  348. package/dist/tools/registry/lessons-tools.d.ts +7 -0
  349. package/dist/tools/registry/lessons-tools.js +43 -3
  350. package/dist/tools/registry/memory-tools.d.ts +1 -1
  351. package/dist/tools/registry/memory-tools.js +8 -8
  352. package/dist/tools/registry/research-tools.d.ts +1 -0
  353. package/dist/tools/registry/research-tools.js +4 -13
  354. package/dist/tools/registry/self-describe-tools.d.ts +1 -1
  355. package/dist/tools/registry/self-describe-tools.js +43 -30
  356. package/dist/tools/resource-catalog-tool.d.ts +38 -0
  357. package/dist/tools/resource-catalog-tool.js +46 -0
  358. package/dist/tools/skills-inspection-tool.js +30 -1
  359. package/dist/tools/stream-tool-output.d.ts +3 -0
  360. package/dist/tools/stream-tool-output.js +33 -0
  361. package/dist/tools/tool-call-scheduler.d.ts +10 -0
  362. package/dist/tools/tool-call-scheduler.js +58 -0
  363. package/dist/tools/tool-effect.d.ts +5 -0
  364. package/dist/tools/tool-effect.js +26 -0
  365. package/dist/tools/tool-search.d.ts +12 -11
  366. package/dist/tools/tool-search.js +67 -26
  367. package/dist/tools/types.d.ts +6 -0
  368. package/dist/ui/components/ChatHistory.d.ts +1 -1
  369. package/dist/ui/components/ChatHistory.js +2 -2
  370. package/dist/ui/components/ChatInput.d.ts +2 -1
  371. package/dist/ui/components/ChatInput.js +42 -88
  372. package/dist/ui/components/ChatInterface.d.ts +4 -2
  373. package/dist/ui/components/ChatInterface.js +27 -63
  374. package/dist/ui/components/CommandSuggestions.d.ts +0 -1
  375. package/dist/ui/components/CommandSuggestions.js +4 -6
  376. package/dist/ui/components/FileAutocomplete.js +1 -1
  377. package/dist/ui/components/KeyboardHelp.js +8 -6
  378. package/dist/ui/components/ModelSelection.js +6 -5
  379. package/dist/ui/components/StatusBar.d.ts +2 -1
  380. package/dist/ui/components/StatusBar.js +8 -7
  381. package/dist/ui/context/theme-context.js +3 -2
  382. package/dist/ui/index.d.ts +1 -1
  383. package/dist/ui/index.js +1 -1
  384. package/dist/ui/utils/markdown-renderer.js +4 -13
  385. package/dist/utils/atomic-write.d.ts +22 -0
  386. package/dist/utils/atomic-write.js +29 -0
  387. package/dist/utils/bounded-output.d.ts +16 -0
  388. package/dist/utils/bounded-output.js +63 -0
  389. package/dist/utils/device-store-file.d.ts +4 -0
  390. package/dist/utils/device-store-file.js +40 -0
  391. package/dist/utils/export-manager.d.ts +9 -0
  392. package/dist/utils/export-manager.js +19 -0
  393. package/dist/utils/first-use-hints.d.ts +25 -0
  394. package/dist/utils/first-use-hints.js +58 -0
  395. package/dist/utils/history-manager.js +1 -1
  396. package/dist/utils/update-notifier.js +16 -18
  397. package/dist/wizard/environment-detection.d.ts +5 -1
  398. package/dist/wizard/environment-detection.js +49 -7
  399. package/dist/wizard/onboarding.d.ts +5 -1
  400. package/dist/wizard/onboarding.js +90 -30
  401. package/dist/wizard/provider-onboarding.d.ts +2 -0
  402. package/dist/wizard/provider-onboarding.js +55 -17
  403. package/package.json +7 -3
@@ -1595,6 +1595,8 @@ export async function registerAIMessageHandler(manager) {
1595
1595
  let successfulLisaSelfieToolResult = false;
1596
1596
  let shouldPersistChannelSession = Boolean(agent);
1597
1597
  let telegramWidget;
1598
+ let companionMediaResult;
1599
+ let companionHistorySuffix;
1598
1600
  if (prefetchedDirectResponse) {
1599
1601
  response = prefetchedDirectResponse;
1600
1602
  if (agent && !agent.recordTrustedExternalConversationTurn(agentInput, response)) {
@@ -1632,16 +1634,34 @@ export async function registerAIMessageHandler(manager) {
1632
1634
  sharedPhotos: companionPhotos?.photos.length ?? 0,
1633
1635
  });
1634
1636
  try {
1637
+ let companionIdentity;
1638
+ if (channel.type === 'telegram') {
1639
+ const { resolveCompanionIdentity } = await import('../../companion/companion-identity.js');
1640
+ const telegramChannel = channel;
1641
+ companionIdentity = resolveCompanionIdentity({
1642
+ channel: 'telegram',
1643
+ chatId: message.channel.id,
1644
+ senderId: message.sender?.id,
1645
+ senderUsername: message.sender?.username,
1646
+ allowedUsers: telegramChannel.config?.allowedUsers ?? [],
1647
+ env: process.env,
1648
+ });
1649
+ }
1635
1650
  const generated = await runCompanionChannelTurn({
1636
1651
  apiKey: effectiveRuntime.apiKey,
1637
1652
  baseUrl: effectiveRuntime.baseUrl,
1638
1653
  model: effectiveRuntime.model,
1639
1654
  messages: companionMessages,
1640
1655
  signal: turn.signal,
1656
+ ...(companionIdentity ? { identity: companionIdentity } : {}),
1657
+ surface: channel.type,
1658
+ env: process.env,
1641
1659
  });
1642
1660
  turn.throwIfAborted();
1643
1661
  response = generated.text;
1644
1662
  hasGeneratedResponse = response.trim() !== '';
1663
+ companionMediaResult = generated.media;
1664
+ companionHistorySuffix = generated.historySuffix;
1645
1665
  if (hasSharedPhotos && companionPhotos) {
1646
1666
  // The album write is deliberately after the reply: a full disk must
1647
1667
  // cost the memory, never the reaction.
@@ -1860,7 +1880,35 @@ export async function registerAIMessageHandler(manager) {
1860
1880
  turn.throwIfAborted();
1861
1881
  turn.phase('delivery');
1862
1882
  deliveryState = 'started';
1863
- if (channel.type === 'telegram' && response.trim() && telegramWidget) {
1883
+ if (channel.type === 'telegram' && response.trim() && companionMediaResult && companionMediaResult.length > 0) {
1884
+ const media = companionMediaResult[0];
1885
+ if (media) {
1886
+ const pathMod = await import('path');
1887
+ const ext = pathMod.extname(media.imagePath).slice(1) || 'png';
1888
+ const result = await channel.send({
1889
+ channelId: message.channel.id,
1890
+ content: response,
1891
+ replyTo: message.id,
1892
+ attachments: [
1893
+ {
1894
+ type: 'image',
1895
+ filePath: media.imagePath,
1896
+ fileName: pathMod.basename(media.imagePath),
1897
+ mimeType: ext === 'jpg' || ext === 'jpeg' ? 'image/jpeg' : `image/${ext}`,
1898
+ },
1899
+ ],
1900
+ });
1901
+ delivered = result?.success === true;
1902
+ deliveredChunks = delivered ? 1 : 0;
1903
+ if (delivered)
1904
+ deliveredAssistantContent = response;
1905
+ if (delivered)
1906
+ deliveryMode = 'telegram-photo';
1907
+ else
1908
+ deliveryMode = 'failed';
1909
+ }
1910
+ }
1911
+ else if (channel.type === 'telegram' && response.trim() && telegramWidget) {
1864
1912
  const result = await channel.send({
1865
1913
  channelId: message.channel.id,
1866
1914
  content: response,
@@ -2070,7 +2118,10 @@ export async function registerAIMessageHandler(manager) {
2070
2118
  turn.throwIfAborted();
2071
2119
  turn.phase('persistence');
2072
2120
  if (useCompanionProfile && response.trim()) {
2073
- rememberCompanionChannelTurn(sessionKey, message.content, response);
2121
+ const recordedResponse = companionHistorySuffix
2122
+ ? `${response}${companionHistorySuffix}`
2123
+ : response;
2124
+ rememberCompanionChannelTurn(sessionKey, message.content, recordedResponse);
2074
2125
  }
2075
2126
  if (shouldPersistChannelSession && agent)
2076
2127
  await persistChannelSession(agent, sessionKey);
@@ -3,12 +3,13 @@
3
3
  *
4
4
  * Handlers for exporting sessions, conversations, and tool results
5
5
  */
6
+ import type { ChatEntry } from '../../agent/types.js';
6
7
  import { CommandHandlerResult } from './branch-handlers.js';
7
8
  /**
8
9
  * Handle /export command
9
- * Export current or specified session to file
10
+ * Export the current conversation, or a saved session with session:<id>
10
11
  */
11
- export declare function handleExport(args: string[]): Promise<CommandHandlerResult>;
12
+ export declare function handleExport(args: string[], conversationHistory?: ChatEntry[], currentModel?: string): Promise<CommandHandlerResult>;
12
13
  /**
13
14
  * Handle /export-list command
14
15
  * List all exported files
@@ -3,54 +3,81 @@
3
3
  *
4
4
  * Handlers for exporting sessions, conversations, and tool results
5
5
  */
6
+ import { initializeDatabase } from '../../database/database-manager.js';
6
7
  import { getExportManager } from '../../utils/export-manager.js';
7
- import { getSessionRepository } from '../../database/repositories/session-repository.js';
8
+ function reply(content) {
9
+ return { handled: true, entry: { type: 'assistant', content, timestamp: new Date() } };
10
+ }
11
+ /** Map the visible transcript to export messages; UI-only entries are skipped. */
12
+ function chatEntriesToMessages(history) {
13
+ const messages = [];
14
+ for (const entry of history) {
15
+ if (entry.type === 'user' || entry.type === 'assistant') {
16
+ messages.push({ role: entry.type, content: entry.content, timestamp: entry.timestamp });
17
+ }
18
+ else if (entry.type === 'tool_result') {
19
+ messages.push({
20
+ role: 'tool',
21
+ content: entry.content,
22
+ timestamp: entry.timestamp,
23
+ toolName: entry.toolCall?.function?.name ?? 'tool',
24
+ toolCallId: entry.toolCall?.id,
25
+ });
26
+ }
27
+ }
28
+ return messages;
29
+ }
8
30
  /**
9
31
  * Handle /export command
10
- * Export current or specified session to file
32
+ * Export the current conversation, or a saved session with session:<id>
11
33
  */
12
- export async function handleExport(args) {
34
+ export async function handleExport(args, conversationHistory = [], currentModel) {
13
35
  const exportManager = getExportManager();
14
- const sessionRepo = getSessionRepository();
15
36
  // Parse arguments
16
37
  const format = args.find(a => ['json', 'markdown', 'html', 'text'].includes(a)) || 'markdown';
17
38
  const sessionIdArg = args.find(a => a.startsWith('session:'))?.split(':')[1];
18
39
  const includeSecrets = args.includes('--include-secrets');
19
40
  const noToolCalls = args.includes('--no-tools');
20
41
  const noMetadata = args.includes('--no-metadata');
21
- // Get session to export
22
- let sessionId;
42
+ const options = {
43
+ redactSecrets: !includeSecrets,
44
+ includeToolCalls: !noToolCalls,
45
+ includeMetadata: !noMetadata,
46
+ };
47
+ let result;
23
48
  if (sessionIdArg) {
24
- sessionId = sessionIdArg;
49
+ // Saved sessions live in the SQLite session database, which the
50
+ // interactive CLI does not open at startup.
51
+ try {
52
+ await initializeDatabase();
53
+ }
54
+ catch (error) {
55
+ return reply(`Failed to export session ${sessionIdArg}: session database unavailable (${error instanceof Error ? error.message : String(error)}).`);
56
+ }
57
+ result = await exportManager.exportSession(sessionIdArg, format, options);
25
58
  }
26
59
  else {
27
- // Get most recent session
28
- const sessions = sessionRepo.findSessions({ limit: 1 });
29
- const mostRecent = sessions[0];
30
- if (!mostRecent) {
31
- return {
32
- handled: true,
33
- entry: {
34
- type: 'assistant',
35
- content: 'No sessions found to export.',
36
- timestamp: new Date(),
37
- },
38
- };
60
+ // The current session is the conversation on screen, not the most recent
61
+ // database row (which may belong to another project).
62
+ const messages = chatEntriesToMessages(conversationHistory);
63
+ if (messages.length === 0) {
64
+ return reply('Nothing to export yet: the current conversation is empty.\n\nSend a message first, or export a saved session with /export <format> session:<id>.');
39
65
  }
40
- sessionId = mostRecent.id;
66
+ result = await exportManager.exportConversationData({
67
+ title: 'Code Buddy conversation',
68
+ model: currentModel,
69
+ startTime: messages[0]?.timestamp,
70
+ endTime: messages[messages.length - 1]?.timestamp,
71
+ messages,
72
+ metadata: { projectPath: process.cwd(), messageCount: messages.length },
73
+ }, format, options);
41
74
  }
42
- // Export session
43
- const result = await exportManager.exportSession(sessionId, format, {
44
- redactSecrets: !includeSecrets,
45
- includeToolCalls: !noToolCalls,
46
- includeMetadata: !noMetadata,
47
- });
48
75
  if (result.success && result.filePath) {
49
76
  return {
50
77
  handled: true,
51
78
  entry: {
52
79
  type: 'assistant',
53
- content: `Session exported successfully!
80
+ content: `${sessionIdArg ? `Session ${sessionIdArg}` : 'Current conversation'} exported successfully!
54
81
 
55
82
  **Format:** ${format}
56
83
  **File:** ${result.filePath}
@@ -68,7 +95,7 @@ cat "${result.filePath}"
68
95
  handled: true,
69
96
  entry: {
70
97
  type: 'assistant',
71
- content: `Failed to export session: ${result.error}`,
98
+ content: `Failed to export ${sessionIdArg ? `session ${sessionIdArg}` : 'the current conversation'}: ${result.error}`,
72
99
  timestamp: new Date(),
73
100
  },
74
101
  };
@@ -311,7 +311,10 @@ export async function handleSearch(args) {
311
311
  try {
312
312
  const cwd = process.cwd();
313
313
  let output = '';
314
- const rgResult = runCommand('rg', ['--line-number', '--no-heading', '--color=never', '--max-count=20', '--', query], { cwd, timeoutMs: 10000 });
314
+ // Explicit `.` path: without one, ripgrep searches stdin whenever stdin is
315
+ // not a TTY (every non-interactive spawn), so real matches were reported as
316
+ // "No matches" (status 1).
317
+ const rgResult = runCommand('rg', ['--line-number', '--no-heading', '--color=never', '--max-count=20', '--', query, '.'], { cwd, timeoutMs: 10000 });
315
318
  if (rgResult.success) {
316
319
  output = rgResult.output;
317
320
  }
@@ -586,6 +589,7 @@ function createProgressBar(percent, width) {
586
589
  function runCommand(command, args, { cwd, timeoutMs, env }) {
587
590
  const result = spawnSync(command, args, {
588
591
  cwd,
592
+ stdio: ['ignore', 'pipe', 'pipe'],
589
593
  encoding: 'utf-8',
590
594
  maxBuffer: 5 * 1024 * 1024,
591
595
  timeout: timeoutMs,
@@ -1,32 +1,40 @@
1
+ // Written as the user's own request about their own work. The previous wording
2
+ // (role orders addressed to the assistant: "Mène un interrogatoire", "Exige",
3
+ // "Ne flatte pas l'auteur", "ce qui ment") made qwen3:4b answer the injection
4
+ // refusal sentence in the real CLI (recette 2026-09-14), without any tool call.
1
5
  function buildPrompt(target, yolo) {
2
6
  const scope = target
3
- ? `Sujet ciblé par l'utilisateur : ${target}`
4
- : 'Sujet par défaut : le travail récent du dépôt.';
7
+ ? `Sujet ciblé : ${target}`
8
+ : 'Sujet par défaut : mon travail récent dans ce dépôt.';
9
+ // The recent work includes uncommitted changes, and HEAD~1 does not exist in
10
+ // a single-commit repository: inspect the working tree first.
11
+ const gitInspection = 'git status --short, git diff (modifications non indexées), git diff --cached (modifications indexées) et git log -5 --oneline ; git diff HEAD~1 seulement si le dépôt compte au moins deux commits';
5
12
  const baseInstructions = target
6
- ? `Examine d'abord ce sujet précis avec les outils disponibles : ${target}. Utilise aussi le contexte git pertinent si nécessaire, notamment git log -5, git diff HEAD~1 et les fichiers modifiés.`
7
- : 'Examine d\'abord le travail récent avec les outils disponibles : git log -5, git diff HEAD~1 et la liste des fichiers modifiés.';
13
+ ? `Examine d'abord ce sujet avec les outils disponibles : ${target}. Utilise aussi le contexte git utile et la liste des fichiers modifiés : ${gitInspection}.`
14
+ : `Examine d'abord mon travail récent et la liste des fichiers modifiés avec les outils disponibles : ${gitInspection}.`;
8
15
  if (yolo) {
9
- return `${scope}
16
+ return `J'ai lancé /grill-me --yolo : je veux une revue technique de mon propre travail en mode ROAST intégral.
17
+
18
+ ${scope}
10
19
 
11
20
  ${baseInstructions}
12
21
 
13
- Tu es en mode ROAST intégral pour /grill-me --yolo.
14
- Interroge techniquement l'auteur sans aucune complaisance : brutal, sarcastique, aucune politesse, aucun coussin diplomatique.
15
- Chaque pique DOIT rester techniquement exacte, vérifiable et actionnable : cite les fichiers, diffs, noms, tests ou choix qui justifient l'attaque.
16
- Grille l'auteur sur les choix discutables, la dette introduite, les tests manquants, les cas limites ignorés, la sécurité, les abstractions inutiles et les noms mensongers.
17
- Exige des réponses concrètes, pas des excuses : pour chaque accusation, demande quelle preuve, quel test ou quel correctif va fermer le sujet.
18
- Si une critique n'est pas étayée par le dépôt ou le diff, ne la formule pas.`;
22
+ Ensuite, sois brutal et sarcastique avec moi, sans politesse ni précautions diplomatiques.
23
+ Chaque critique doit rester techniquement exacte, vérifiable et actionnable : cite les fichiers, diffs, noms, tests ou choix qui la justifient.
24
+ Vise mes choix discutables, la dette introduite, les tests manquants, les cas limites ignorés, la sécurité, les abstractions inutiles et les noms trompeurs.
25
+ Pour chaque critique, demande-moi quelle preuve, quel test ou quel correctif fermera le sujet.
26
+ N'invente rien : une critique que le dépôt ou le diff ne prouve pas ne doit pas être formulée.`;
19
27
  }
20
- return `${scope}
28
+ return `J'ai lancé /grill-me : je veux une revue technique exigeante de mon propre travail.
29
+
30
+ ${scope}
21
31
 
22
32
  ${baseInstructions}
23
33
 
24
- Mène un interrogatoire technique ferme mais constructif.
25
- Après examen, pose 5 à 7 questions dures et précises sur les choix discutables, la dette introduite, les tests manquants, les cas limites ignorés, la sécurité et les noms mensongers.
26
- Les questions doivent viser des lignes, fichiers, comportements ou décisions observables, pas des généralités.
27
- Exige des réponses et des preuves concrètes, pas des excuses.
28
- Ajoute ensuite 3 risques classés par sévérité, avec pour chacun l'impact, la probabilité et l'action minimale pour le réduire.
29
- Ne flatte pas l'auteur : aide-le à voir ce qui casse, ce qui ment et ce qui manque.`;
34
+ Ensuite, pose-moi 5 à 7 questions difficiles et précises sur mes choix discutables, la dette introduite, les tests manquants, les cas limites ignorés, la sécurité et les noms trompeurs.
35
+ Chaque question doit viser des lignes, fichiers, comportements ou décisions observables, pas des généralités, et me demander une preuve concrète.
36
+ Termine par 3 risques classés par sévérité, avec pour chacun l'impact, la probabilité et l'action minimale pour le réduire.
37
+ Reste franc et constructif, sans compliments inutiles : aide-moi à voir ce qui casse, ce qui est inexact et ce qui manque.`;
30
38
  }
31
39
  export async function handleGrillMe(args) {
32
40
  const remainingArgs = args.filter(arg => arg !== '--yolo');
@@ -1,4 +1,8 @@
1
1
  import { ChatEntry } from "../../agent/codebuddy-agent.js";
2
+ export interface MemoryCommandContext {
3
+ cwd?: string;
4
+ botId?: string;
5
+ }
2
6
  export interface CommandHandlerResult {
3
7
  handled: boolean;
4
8
  entry?: ChatEntry;
@@ -9,11 +13,11 @@ export interface CommandHandlerResult {
9
13
  /**
10
14
  * Memory - Manage persistent memory using PersistentMemoryManager (Markdown) and EnhancedMemory (SQLite/Vector)
11
15
  */
12
- export declare function handleMemory(args: string[]): Promise<CommandHandlerResult>;
16
+ export declare function handleMemory(args: string[], context?: MemoryCommandContext): Promise<CommandHandlerResult>;
13
17
  /**
14
18
  * Remember - Quick memory store using PersistentMemoryManager and EnhancedMemory
15
19
  */
16
- export declare function handleRemember(args: string[]): Promise<CommandHandlerResult>;
20
+ export declare function handleRemember(args: string[], context?: MemoryCommandContext): Promise<CommandHandlerResult>;
17
21
  /**
18
22
  * Scan Todos - Find AI-directed comments
19
23
  */
@@ -27,17 +27,37 @@ 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
+ /**
31
+ * Report a remember operation honestly: the persistent write is the primary
32
+ * result; fact reconciliation and the semantic index are secondary and their
33
+ * failures are shown without hiding (or overstating) the saved memory.
34
+ */
35
+ async function describeRememberOutcome(write, requestedKey, scope, storeSemantic) {
36
+ const lines = [`✅ Remembered: "${write?.key ?? requestedKey}" in persistent ${scope} memory.`];
37
+ if (write?.reconciliation?.status === "failed") {
38
+ lines.push(`⚠️ Fact reconciliation failed (${write.reconciliation.reason ?? "unknown error"}); the memory was saved directly and existing memories were kept unchanged.`);
39
+ }
40
+ try {
41
+ await storeSemantic();
42
+ lines.push("Semantic index updated.");
43
+ }
44
+ catch (error) {
45
+ lines.push(`⚠️ Semantic index not updated: ${getErrorMessage(error)}`);
46
+ }
47
+ return lines.join("\n");
48
+ }
30
49
  function clip(text, max = 180) {
31
50
  return text.length > max ? text.slice(0, max - 1) + "…" : text;
32
51
  }
33
52
  /**
34
53
  * Memory - Manage persistent memory using PersistentMemoryManager (Markdown) and EnhancedMemory (SQLite/Vector)
35
54
  */
36
- export async function handleMemory(args) {
55
+ export async function handleMemory(args, context) {
37
56
  const enhancedMemory = getEnhancedMemory();
38
- const persistentMemory = getMemoryManager();
57
+ const persistentMemory = getMemoryManager(undefined, context?.botId, context?.cwd);
39
58
  const action = args[0]?.toLowerCase() || 'list';
40
59
  try {
60
+ await persistentMemory.initialize();
41
61
  let content;
42
62
  switch (action) {
43
63
  case "recall":
@@ -151,14 +171,13 @@ export async function handleMemory(args) {
151
171
  : "project";
152
172
  const value = args.slice(2).join(" ");
153
173
  // Store in both for redundancy and better retrieval
154
- await persistentMemory.remember(key, value, { scope, category: "custom" });
155
- await enhancedMemory.store({
174
+ const write = await persistentMemory.remember(key, value, { scope, category: "custom" });
175
+ content = await describeRememberOutcome(write, key, scope, () => enhancedMemory.store({
156
176
  type: 'fact',
157
177
  content: `${key}: ${value}`,
158
178
  tags: [key, scope],
159
179
  importance: 0.8
160
- });
161
- content = `✅ Remembered: "${key}" in persistent ${scope} memory and semantic index.`;
180
+ }));
162
181
  }
163
182
  else {
164
183
  content = `Usage: /memory remember <key> <content> [project|user]`;
@@ -231,7 +250,7 @@ export async function handleMemory(args) {
231
250
  : undefined;
232
251
  const rawLimit = parseInt(args[status ? 2 : 1] ?? "20", 10);
233
252
  const limit = Math.min(50, Math.max(1, Number.isFinite(rawLimit) ? rawLimit : 20));
234
- const candidates = getMemoryCandidateQueue(process.cwd()).list(status).slice(0, limit);
253
+ const candidates = getMemoryCandidateQueue(context?.cwd ?? process.cwd(), context?.botId).list(status).slice(0, limit);
235
254
  if (candidates.length === 0) {
236
255
  content = status ? `No ${status} memory candidates.` : "No memory candidates yet.";
237
256
  }
@@ -268,7 +287,7 @@ export async function handleMemory(args) {
268
287
  }
269
288
  const reviewedBy = args.slice(2).join(" ").trim() || "user";
270
289
  const { getMemoryCandidateQueue } = await import("../../memory/memory-candidate-queue.js");
271
- const { candidate, write } = await getMemoryCandidateQueue(process.cwd()).accept(id, { reviewedBy });
290
+ const { candidate, write } = await getMemoryCandidateQueue(context?.cwd ?? process.cwd(), context?.botId).accept(id, { reviewedBy });
272
291
  content = `✅ Accepted ${candidate.id} into ${candidate.scope} memory as "${candidate.key}".\n` +
273
292
  `Write status: ${write.status}. Capacity: ${write.usage.used}/${write.usage.limit} chars (${write.usage.percent}%).`;
274
293
  break;
@@ -282,7 +301,7 @@ export async function handleMemory(args) {
282
301
  }
283
302
  const reason = args.slice(2).join(" ").trim();
284
303
  const { getMemoryCandidateQueue } = await import("../../memory/memory-candidate-queue.js");
285
- const candidate = getMemoryCandidateQueue(process.cwd()).reject(id, {
304
+ const candidate = getMemoryCandidateQueue(context?.cwd ?? process.cwd(), context?.botId).reject(id, {
286
305
  reviewedBy: "user",
287
306
  ...(reason ? { reason } : {}),
288
307
  });
@@ -319,7 +338,7 @@ export async function handleMemory(args) {
319
338
  /**
320
339
  * Remember - Quick memory store using PersistentMemoryManager and EnhancedMemory
321
340
  */
322
- export async function handleRemember(args) {
341
+ export async function handleRemember(args, context) {
323
342
  if (args.length < 2) {
324
343
  return {
325
344
  handled: true,
@@ -346,20 +365,21 @@ export async function handleRemember(args) {
346
365
  : "project";
347
366
  const value = args.slice(1).join(" ");
348
367
  try {
349
- const persistentMemory = getMemoryManager();
368
+ const persistentMemory = getMemoryManager(undefined, context?.botId, context?.cwd);
350
369
  const enhancedMemory = getEnhancedMemory();
351
- await persistentMemory.remember(key, value, { scope, category: "custom" });
352
- await enhancedMemory.store({
370
+ await persistentMemory.initialize();
371
+ const write = await persistentMemory.remember(key, value, { scope, category: "custom" });
372
+ const content = await describeRememberOutcome(write, key, scope, () => enhancedMemory.store({
353
373
  type: 'fact',
354
374
  content: `${key}: ${value}`,
355
375
  tags: [key, scope],
356
376
  importance: 0.8
357
- });
377
+ }));
358
378
  return {
359
379
  handled: true,
360
380
  entry: {
361
381
  type: "assistant",
362
- content: `✅ Remembered: "${key}" in persistent ${scope} memory and semantic index.`,
382
+ content,
363
383
  timestamp: new Date(),
364
384
  },
365
385
  };
@@ -14,7 +14,7 @@
14
14
  * - __RESTORE_CHECKPOINT__ - /restore
15
15
  */
16
16
  import type { CommandHandlerResult } from './branch-handlers.js';
17
- export declare function handleChangeModel(args: string[]): Promise<CommandHandlerResult>;
17
+ export declare function handleChangeModel(args: string[], activeModel?: string): Promise<CommandHandlerResult>;
18
18
  export declare function handleChangeMode(args: string[]): Promise<CommandHandlerResult>;
19
19
  export declare function handleClearChat(): CommandHandlerResult;
20
20
  export declare function handleColab(args: string[]): Promise<CommandHandlerResult>;
@@ -24,5 +24,5 @@ export declare function handleListCheckpoints(_args: string[]): Promise<CommandH
24
24
  export declare function handleRestoreCheckpoint(args: string[]): Promise<CommandHandlerResult>;
25
25
  export declare function handleInitGrok(args?: string[]): Promise<CommandHandlerResult>;
26
26
  export declare function handleReinitGrok(): Promise<CommandHandlerResult>;
27
- export declare function handleStatus(): Promise<CommandHandlerResult>;
27
+ export declare function handleStatus(activeModel?: string): Promise<CommandHandlerResult>;
28
28
  export declare function handleNew(args: string[]): Promise<CommandHandlerResult>;
@@ -17,14 +17,14 @@ import { handleColabCommand } from './colab-handler.js';
17
17
  // ============================================================================
18
18
  // /model - Change Model
19
19
  // ============================================================================
20
- export async function handleChangeModel(args) {
20
+ export async function handleChangeModel(args, activeModel) {
21
21
  const { getSupportedModels, getModelInfo, suggestModel } = await import('../../utils/model-utils.js');
22
22
  const { getSettingsManager } = await import('../../utils/settings-manager.js');
23
23
  const modelName = args[0];
24
24
  const settingsManager = getSettingsManager();
25
25
  // If no model specified, show current model and list available models
26
26
  if (!modelName || modelName === 'list') {
27
- const currentModel = process.env.GROK_MODEL || 'grok-beta';
27
+ const currentModel = activeModel ?? settingsManager.getCurrentModel();
28
28
  const supportedModels = getSupportedModels();
29
29
  // Group models by provider
30
30
  const modelsByProvider = {};
@@ -803,13 +803,13 @@ function formatStatusTimeAgo(date, now = new Date()) {
803
803
  const day = Math.floor(hr / 24);
804
804
  return `${day}d ago`;
805
805
  }
806
- export async function handleStatus() {
806
+ export async function handleStatus(activeModel) {
807
807
  const lines = [];
808
808
  lines.push('Status Dashboard');
809
809
  lines.push('='.repeat(50));
810
810
  lines.push('');
811
811
  // Current model
812
- const currentModel = process.env.GROK_MODEL || 'grok-beta';
812
+ const currentModel = activeModel ?? (await import('../../utils/settings-manager.js')).getSettingsManager().getCurrentModel();
813
813
  lines.push(` Model: ${currentModel}`);
814
814
  // Agent mode
815
815
  try {
@@ -0,0 +1,12 @@
1
+ /**
2
+ * /resources — read-only view of the explicit resource catalog (P8).
3
+ *
4
+ * Reads ~/.codebuddy/resources/catalog.json through ResourceCatalog.list():
5
+ * no probe, no network, no write, no dispatch. Shows endpoint REFERENCES
6
+ * (environment variable names), never resolved URLs or fingerprints.
7
+ */
8
+ import type { CommandHandlerResult } from './branch-handlers.js';
9
+ import { ResourceCatalog, type PublicResourceStatus } from '../../fleet/resource-catalog.js';
10
+ export declare const RESOURCES_EMPTY_HINT: string;
11
+ export declare function formatResourcesTable(resources: PublicResourceStatus[], now?: number): string;
12
+ export declare function handleResources(catalog?: ResourceCatalog, now?: () => number): Promise<CommandHandlerResult>;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * /resources — read-only view of the explicit resource catalog (P8).
3
+ *
4
+ * Reads ~/.codebuddy/resources/catalog.json through ResourceCatalog.list():
5
+ * no probe, no network, no write, no dispatch. Shows endpoint REFERENCES
6
+ * (environment variable names), never resolved URLs or fingerprints.
7
+ */
8
+ import fs from 'node:fs';
9
+ import { publicResourceStatus, ResourceCatalog } from '../../fleet/resource-catalog.js';
10
+ export const RESOURCES_EMPTY_HINT = 'No resource catalog yet. Declare one with `buddy resources add <file.json>` (fields: `buddy resources schema`), '
11
+ + 'then refresh its health explicitly with `buddy resources probe <id>`.';
12
+ function textResult(content) {
13
+ return { handled: true, entry: { type: 'assistant', content, timestamp: new Date() } };
14
+ }
15
+ function age(from, now) {
16
+ if (from === null)
17
+ return 'never';
18
+ const minutes = Math.max(0, Math.round((now - from) / 60_000));
19
+ if (minutes < 1)
20
+ return 'just now';
21
+ if (minutes < 120)
22
+ return `${minutes} min ago`;
23
+ return `${Math.round(minutes / 60)} h ago`;
24
+ }
25
+ export function formatResourcesTable(resources, now = Date.now()) {
26
+ const lines = [`Resources (${resources.length}) — read-only, no probe`, ''];
27
+ for (const entry of resources) {
28
+ const r = entry.resource;
29
+ const use = r.permissions.use ? 'use' : 'no-use';
30
+ const probe = r.permissions.probe ? 'probe' : 'no-probe';
31
+ lines.push(` ${r.id} [${r.kind}] on ${r.hostId}`);
32
+ lines.push(` state: ${entry.state} (${entry.reason}), checked ${age(entry.checkedAt, now)}`);
33
+ lines.push(` capabilities: ${r.declaredCapabilities.join(', ')} · endpoint ref: ${r.endpointRef} · ${use}, ${probe}`);
34
+ }
35
+ lines.push('', 'Health is not proof of usage and load is unknown. Refresh with `buddy resources probe <id>`.');
36
+ return lines.join('\n');
37
+ }
38
+ export async function handleResources(catalog = new ResourceCatalog(), now = Date.now) {
39
+ let resources;
40
+ try {
41
+ resources = (await catalog.list()).map(publicResourceStatus);
42
+ }
43
+ catch (error) {
44
+ const code = error instanceof Error ? error.message : 'INVALID_CATALOG';
45
+ return textResult(`Resource catalog unreadable (${code}). Nothing was changed; inspect ${catalog.filename}.`);
46
+ }
47
+ if (resources.length === 0) {
48
+ return textResult(fs.existsSync(catalog.filename) ? `The resource catalog is empty. ${RESOURCES_EMPTY_HINT.replace(/^No resource catalog yet\. /, '')}` : RESOURCES_EMPTY_HINT);
49
+ }
50
+ return textResult(formatResourcesTable(resources, now()));
51
+ }
52
+ //# sourceMappingURL=resources-handler.js.map
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Starter Pack Slash Command Handler
3
3
  *
4
- * /starter - List all starter packs grouped by language
4
+ * /starter, /starter list - List all starter packs grouped by language
5
5
  * /starter <name> - Activate a specific starter pack (name or alias)
6
6
  * /starter search <q> - Search starters by keyword
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Starter Pack Slash Command Handler
3
3
  *
4
- * /starter - List all starter packs grouped by language
4
+ * /starter, /starter list - List all starter packs grouped by language
5
5
  * /starter <name> - Activate a specific starter pack (name or alias)
6
6
  * /starter search <q> - Search starters by keyword
7
7
  */
@@ -25,7 +25,16 @@ const LANGUAGE_FAMILIES = {
25
25
  function formatStarterList() {
26
26
  const starters = getStarterPacks();
27
27
  if (starters.length === 0) {
28
- return 'No starter packs found. Ensure bundled skills are loaded.';
28
+ // No starter pack ships with the package today: say where packs are found
29
+ // instead of implying a loading failure.
30
+ return [
31
+ 'No starter packs are installed.',
32
+ '',
33
+ 'Starter packs are SKILL.md skills tagged "starter", discovered in:',
34
+ ' .codebuddy/skills/ (this project)',
35
+ ' ~/.codebuddy/skills/ (user)',
36
+ ' the bundled skills directory shipped with Code Buddy',
37
+ ].join('\n');
29
38
  }
30
39
  const lines = [
31
40
  `Starter Packs (${starters.length} available)`,
@@ -82,6 +91,27 @@ export async function handleStarter(args) {
82
91
  };
83
92
  }
84
93
  const action = first.toLowerCase();
94
+ // /starter list — documented alias of the bare command
95
+ if (action === 'list' && args.length === 1) {
96
+ return {
97
+ handled: true,
98
+ entry: {
99
+ type: 'assistant',
100
+ content: formatStarterList(),
101
+ timestamp: new Date(),
102
+ },
103
+ };
104
+ }
105
+ if (action === 'search' && args.length === 1) {
106
+ return {
107
+ handled: true,
108
+ entry: {
109
+ type: 'assistant',
110
+ content: 'Usage: /starter search <query>',
111
+ timestamp: new Date(),
112
+ },
113
+ };
114
+ }
85
115
  // /starter search <query>
86
116
  if (action === 'search' && args.length > 1) {
87
117
  const query = args.slice(1).join(' ');