@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
@@ -113,6 +113,17 @@ export interface ArchiveEntry {
113
113
  reviewedBy: string;
114
114
  /** Origin of non-lesson archive entries, for example the project CHANGELOG or delegation logs. */
115
115
  provenance?: 'changelog' | 'delegation-log' | string;
116
+ evidence?: {
117
+ artifactSha256: string;
118
+ benchmarkSha256: string;
119
+ wins: number;
120
+ losses: number;
121
+ cases: {
122
+ id: string;
123
+ before: boolean;
124
+ after: boolean;
125
+ }[];
126
+ };
116
127
  }
117
128
  export interface SelfImprovementCycleResult {
118
129
  schemaVersion: typeof SELF_IMPROVEMENT_SCHEMA_VERSION;
@@ -243,7 +243,7 @@ export declare class ToolHandler {
243
243
  private executeStreamingBash;
244
244
  /**
245
245
  * Execute a tool with streaming output.
246
- * Currently only supports bash. Falls back to executeTool for other tools.
246
+ * Supports process output, code_exec yields and progress-producing tools.
247
247
  * Yields string deltas for real-time output.
248
248
  */
249
249
  executeToolStreaming(toolCall: CodeBuddyToolCall, executionExtra?: Record<string, unknown>): AsyncGenerator<string, ToolResult, undefined>;
@@ -15,6 +15,7 @@
15
15
  * All tools are registered as ITool adapters in the FormalToolRegistry.
16
16
  * Tool instances are lazy-loaded on first access for optimal startup time.
17
17
  */
18
+ import { streamToolOutput } from '../tools/stream-tool-output.js';
18
19
  import { TextEditorTool, MorphEditorTool, ImageTool, BashTool, } from "../tools/index.js";
19
20
  import { isBareChangeDirectory } from "../tools/bash/bash-tool.js";
20
21
  import { getFormalToolRegistry } from "../tools/registry/index.js";
@@ -1034,14 +1035,22 @@ export class ToolHandler {
1034
1035
  ...(abortSignal ? { abortSignal } : {}),
1035
1036
  ...(Object.keys(contextExtra).length > 0 ? { extra: contextExtra } : {}),
1036
1037
  };
1038
+ const toolCatalog = toolName === 'code_exec' || toolName === 'tool_search' ? [
1039
+ ...this.registry.getSchemas().map(tool => ({
1040
+ ...tool, keywords: this.registry.get(tool.name)?.metadata.keywords,
1041
+ })),
1042
+ ...getMCPManager().getTools().map(tool => ({ name: tool.name, description: tool.description, parameters: tool.inputSchema })),
1043
+ ...this.deps.marketplace.getTools().map(name => {
1044
+ const definition = this.deps.marketplace.getToolDefinition(name);
1045
+ return { name: `plugin__${name}`, description: definition?.description ?? '', parameters: definition?.parameters };
1046
+ }),
1047
+ ].filter(tool => isToolNameAllowed(tool.name) && isToolVisibleForSurface(tool.name)) : [];
1048
+ if (toolName === 'tool_search') {
1049
+ context = { ...context, extra: { ...context.extra, toolSearchCatalog: toolCatalog } };
1050
+ }
1037
1051
  if (toolName === 'code_exec') {
1038
- const availableTools = Array.from(new Set([
1039
- ...this.registry.getNames(),
1040
- ...getMCPManager().getTools().map((tool) => tool.name),
1041
- ...this.deps.marketplace.getTools(),
1042
- ]))
1043
- .filter((name) => name !== 'code_exec' && name !== 'exec' && isToolNameAllowed(name))
1044
- .sort();
1052
+ const availableTools = [...new Set(toolCatalog.map(tool => tool.name))]
1053
+ .filter(name => name !== 'code_exec' && name !== 'exec').sort();
1045
1054
  // HTTP uses one host agent and swaps logical conversations under a
1046
1055
  // mutex. Its SessionStore ID therefore cannot isolate code_exec state;
1047
1056
  // the opaque recovery scope is the authoritative logical session.
@@ -1055,7 +1064,11 @@ export class ToolHandler {
1055
1064
  agentId: stateAgentId,
1056
1065
  cwd: context.cwd,
1057
1066
  availableTools,
1058
- executor: async (nestedToolName, nestedArgs) => {
1067
+ abortSignal,
1068
+ onOutput: typeof executionExtra?.codeExecOnOutput === 'function' ? executionExtra.codeExecOnOutput : undefined,
1069
+ toolMetadata: toolCatalog.map(tool => ({ name: tool.name, description: tool.description })),
1070
+ parallelTools: availableTools.filter(name => this.registry.get(name)?.metadata.fleetSafe === true && this.registry.get(name)?.metadata.effect === 'read'),
1071
+ executor: async (nestedToolName, nestedArgs, nestedSignal) => {
1059
1072
  // Defense in depth: code_exec is omitted from the child bridge and
1060
1073
  // rejected again here so tools.call('code_exec', ...) cannot recurse.
1061
1074
  if (nestedToolName === 'code_exec' || nestedToolName === 'exec') {
@@ -1083,6 +1096,7 @@ export class ToolHandler {
1083
1096
  },
1084
1097
  }, {
1085
1098
  ...(executionExtra ?? {}),
1099
+ abortSignal: nestedSignal ?? abortSignal,
1086
1100
  recoverySessionId,
1087
1101
  });
1088
1102
  },
@@ -1385,7 +1399,7 @@ export class ToolHandler {
1385
1399
  }
1386
1400
  /**
1387
1401
  * Execute a tool with streaming output.
1388
- * Currently only supports bash. Falls back to executeTool for other tools.
1402
+ * Supports process output, code_exec yields and progress-producing tools.
1389
1403
  * Yields string deltas for real-time output.
1390
1404
  */
1391
1405
  async *executeToolStreaming(toolCall, executionExtra) {
@@ -1401,6 +1415,11 @@ export class ToolHandler {
1401
1415
  if (toolName === 'bash') {
1402
1416
  return yield* this.executeStreamingBash(toolCall, executionExtra, startTime);
1403
1417
  }
1418
+ if (toolName === 'code_exec') {
1419
+ return yield* streamToolOutput((abortSignal, codeExecOnOutput) => this.executeTool(toolCall, {
1420
+ ...(executionExtra ?? {}), abortSignal, codeExecOnOutput,
1421
+ }), abortSignalFromExecutionExtra(executionExtra));
1422
+ }
1404
1423
  // Reason: stream MCTS progress events in real-time
1405
1424
  if (toolName === 'reason') {
1406
1425
  try {
@@ -22,7 +22,7 @@ export const DEFAULT_AUTH_PROFILE_MANAGER_CONFIG = {
22
22
  cooldownMs: 60_000, // 1 minute
23
23
  billingCooldownMs: 18_000_000, // 5 hours
24
24
  maxCooldownMs: 86_400_000, // 24 hours
25
- persistPath: path.join(os.homedir(), '.codebuddy', 'auth-profiles.json'),
25
+ get persistPath() { return path.join(os.homedir(), '.codebuddy', 'auth-profiles.json'); },
26
26
  };
27
27
  // ============================================================================
28
28
  // Auth Profile Manager
@@ -1,12 +1,32 @@
1
1
  /**
2
- * Companion channel generation: a single no-tools chat() call.
2
+ * Companion channel generation: single chat() call when without tools,
3
+ * or bounded tool loop (<= 3 rounds) when the speaker is identified.
3
4
  *
4
5
  * Failover seam: this goes through CodeBuddyClient.chat so
5
6
  * feat/provider-fallback-2026-09-06 (`CODEBUDDY_PROVIDER_FALLBACK`) takes
6
7
  * over when that lane is merged. Do not reimplement a fallback chain here.
8
+ *
9
+ * @module channels/companion-channel-turn
7
10
  */
8
- import { type CodeBuddyMessage, type CodeBuddyResponse } from '../codebuddy/client.js';
11
+ import { type CodeBuddyMessage, type CodeBuddyResponse, type CodeBuddyTool } from '../codebuddy/client.js';
12
+ import type { CompanionIdentity } from '../companion/companion-identity.js';
13
+ import { type CompanionToolExecutionContext } from '../companion/companion-toolset.js';
14
+ import type { ToolResult } from '../types/index.js';
15
+ import type { FormalToolRegistry } from '../tools/registry/tool-registry.js';
16
+ import type { ConfirmationService } from '../utils/confirmation-service.js';
9
17
  export declare const COMPANION_CHANNEL_FAILOVER_SEAM = "CodeBuddyClient.chat";
18
+ export declare const MAX_COMPANION_TOOL_ROUNDS = 3;
19
+ export interface CompanionChannelMedia {
20
+ type: 'image';
21
+ imagePath: string;
22
+ caption?: string;
23
+ }
24
+ export interface CompanionExecutedTool {
25
+ name: string;
26
+ success: boolean;
27
+ output?: string;
28
+ imagePath?: string;
29
+ }
10
30
  export interface CompanionChannelTurnInput {
11
31
  apiKey: string;
12
32
  baseUrl: string;
@@ -15,16 +35,45 @@ export interface CompanionChannelTurnInput {
15
35
  signal?: AbortSignal;
16
36
  maxTokens?: number;
17
37
  /** Injectable chat for tests. Production uses CodeBuddyClient. */
18
- chat?: (messages: CodeBuddyMessage[], tools: [], opts: {
38
+ chat?: (messages: CodeBuddyMessage[], tools: CodeBuddyTool[], opts: {
19
39
  model: string;
20
40
  maxTokens?: number;
21
41
  signal?: AbortSignal;
22
- tool_choice: 'none';
42
+ tool_choice: 'none' | 'auto' | 'required';
23
43
  }) => Promise<CodeBuddyResponse>;
44
+ /** Authenticated identity of the interlocutor */
45
+ identity?: CompanionIdentity;
46
+ /** Surface: 'telegram' | 'mobile' | 'pwa' | 'voice' | 'channel' */
47
+ surface?: string;
48
+ /** Environment override */
49
+ env?: NodeJS.ProcessEnv;
50
+ /** Callback fired immediately when a long-running tool starts */
51
+ onWaitingWord?: (word: string) => Promise<void> | void;
52
+ /** Optional media delivery callback */
53
+ deliverMedia?: (media: CompanionChannelMedia) => Promise<void>;
54
+ /** Optional custom tool executor (injectable for tests) */
55
+ executeTool?: (toolName: string, args: Record<string, unknown>, context: CompanionToolExecutionContext) => Promise<ToolResult>;
56
+ /** Optional tool registry */
57
+ registry?: FormalToolRegistry;
58
+ /** Optional confirmation service */
59
+ confirmationService?: ConfirmationService;
60
+ /** Timeout in milliseconds (defaults to CODEBUDDY_CHANNEL_TURN_TIMEOUT_MS or 120_000) */
61
+ timeoutMs?: number;
62
+ /** Working directory */
63
+ cwd?: string;
24
64
  }
25
65
  export interface CompanionChannelTurnResult {
26
66
  text: string;
27
67
  model: string;
28
68
  promptTokens?: number;
69
+ media?: CompanionChannelMedia[];
70
+ executedTools?: CompanionExecutedTool[];
71
+ historySuffix?: string;
29
72
  }
73
+ /**
74
+ * Executes a companion turn.
75
+ * If interlocutor is guest or tools circuit-breaker is OFF, runs the historical
76
+ * single chat(messages, [], tool_choice: 'none') call.
77
+ * If authorized, runs up to 3 tool turns and delivers media automatically.
78
+ */
30
79
  export declare function runCompanionChannelTurn(input: CompanionChannelTurnInput): Promise<CompanionChannelTurnResult>;
@@ -1,38 +1,240 @@
1
1
  /**
2
- * Companion channel generation: a single no-tools chat() call.
2
+ * Companion channel generation: single chat() call when without tools,
3
+ * or bounded tool loop (<= 3 rounds) when the speaker is identified.
3
4
  *
4
5
  * Failover seam: this goes through CodeBuddyClient.chat so
5
6
  * feat/provider-fallback-2026-09-06 (`CODEBUDDY_PROVIDER_FALLBACK`) takes
6
7
  * over when that lane is merged. Do not reimplement a fallback chain here.
8
+ *
9
+ * @module channels/companion-channel-turn
7
10
  */
8
11
  import { CodeBuddyClient } from '../codebuddy/client.js';
9
12
  import { logger } from '../utils/logger.js';
13
+ import { isCompanionToolsEnabled, getCompanionToolDefinitions, getCompanionToolWaitingWord, executeCompanionTool, extractImagePathFromToolResult, } from '../companion/companion-toolset.js';
10
14
  export const COMPANION_CHANNEL_FAILOVER_SEAM = 'CodeBuddyClient.chat';
15
+ export const MAX_COMPANION_TOOL_ROUNDS = 3;
16
+ /**
17
+ * Executes a companion turn.
18
+ * If interlocutor is guest or tools circuit-breaker is OFF, runs the historical
19
+ * single chat(messages, [], tool_choice: 'none') call.
20
+ * If authorized, runs up to 3 tool turns and delivers media automatically.
21
+ */
11
22
  export async function runCompanionChannelTurn(input) {
23
+ const env = input.env ?? process.env;
24
+ const identity = input.identity;
25
+ const toolsEnabled = isCompanionToolsEnabled(env) && Boolean(identity && identity.role !== 'guest');
12
26
  const chat = input.chat ??
13
27
  (async (messages, tools, opts) => {
14
28
  const client = new CodeBuddyClient(input.apiKey, input.model, input.baseUrl);
15
29
  return client.chat(messages, tools, opts);
16
30
  });
17
- const response = await chat(input.messages, [], {
18
- model: input.model,
19
- maxTokens: input.maxTokens ?? 512,
20
- ...(input.signal ? { signal: input.signal } : {}),
21
- tool_choice: 'none',
22
- });
23
- const text = response.choices[0]?.message?.content?.trim() ?? '';
24
- if (!text) {
25
- logger.warn('Companion channel turn returned empty content', {
31
+ // Resolve tool definitions if tools are allowed
32
+ let toolDefs = [];
33
+ if (toolsEnabled && identity) {
34
+ try {
35
+ toolDefs = await getCompanionToolDefinitions(identity, {
36
+ env,
37
+ registry: input.registry,
38
+ });
39
+ }
40
+ catch (err) {
41
+ logger.warn('[companion-channel-turn] Failed to resolve companion tool definitions', {
42
+ error: err instanceof Error ? err.message : String(err),
43
+ });
44
+ toolDefs = [];
45
+ }
46
+ }
47
+ // 1. FAST / HISTORICAL PATH: No tools allowed or no tools registered
48
+ if (!toolsEnabled || toolDefs.length === 0) {
49
+ const response = await chat(input.messages, [], {
26
50
  model: input.model,
27
- seam: COMPANION_CHANNEL_FAILOVER_SEAM,
51
+ maxTokens: input.maxTokens ?? 512,
52
+ ...(input.signal ? { signal: input.signal } : {}),
53
+ tool_choice: 'none',
28
54
  });
55
+ const text = response.choices[0]?.message?.content?.trim() ?? '';
56
+ if (!text) {
57
+ logger.warn('Companion channel turn returned empty content', {
58
+ model: input.model,
59
+ seam: COMPANION_CHANNEL_FAILOVER_SEAM,
60
+ });
61
+ }
62
+ return {
63
+ text,
64
+ model: response.model ?? input.model,
65
+ ...(response.usage?.prompt_tokens !== undefined
66
+ ? { promptTokens: response.usage.prompt_tokens }
67
+ : {}),
68
+ };
69
+ }
70
+ // 2. TOOL-ENABLED BOUNDED LOOP (<= 3 rounds)
71
+ const defaultTimeout = env.CODEBUDDY_CHANNEL_TURN_TIMEOUT_MS
72
+ ? parseInt(env.CODEBUDDY_CHANNEL_TURN_TIMEOUT_MS, 10)
73
+ : 120_000;
74
+ const effectiveTimeout = input.timeoutMs ?? defaultTimeout;
75
+ // Signal management: propagate caller abort or timeout
76
+ let combinedSignal = input.signal;
77
+ let timeoutId;
78
+ if (!combinedSignal && effectiveTimeout > 0) {
79
+ const controller = new AbortController();
80
+ timeoutId = setTimeout(() => controller.abort(), effectiveTimeout);
81
+ combinedSignal = controller.signal;
82
+ }
83
+ const activeMessages = [...input.messages];
84
+ const mediaProduced = [];
85
+ const executedTools = [];
86
+ const historyNotes = [];
87
+ let finalText = '';
88
+ let finalModel = input.model;
89
+ let totalPromptTokens;
90
+ try {
91
+ for (let round = 0; round < MAX_COMPANION_TOOL_ROUNDS; round += 1) {
92
+ const response = await chat(activeMessages, toolDefs, {
93
+ model: input.model,
94
+ maxTokens: input.maxTokens ?? 512,
95
+ ...(combinedSignal ? { signal: combinedSignal } : {}),
96
+ tool_choice: 'auto',
97
+ });
98
+ finalModel = response.model ?? finalModel;
99
+ if (response.usage?.prompt_tokens !== undefined) {
100
+ totalPromptTokens = (totalPromptTokens ?? 0) + response.usage.prompt_tokens;
101
+ }
102
+ const assistantMsg = response.choices[0]?.message;
103
+ if (!assistantMsg) {
104
+ break;
105
+ }
106
+ const content = assistantMsg.content?.trim() ?? '';
107
+ const toolCalls = assistantMsg.tool_calls;
108
+ // If no tool calls, this is the final conversational reply
109
+ if (!toolCalls || toolCalls.length === 0) {
110
+ finalText = content;
111
+ break;
112
+ }
113
+ // Add assistant response with tool_calls to conversation history
114
+ activeMessages.push(assistantMsg);
115
+ // Execute each tool call
116
+ for (const toolCall of toolCalls) {
117
+ const toolName = toolCall.function.name;
118
+ let args = {};
119
+ try {
120
+ args = JSON.parse(toolCall.function.arguments || '{}');
121
+ }
122
+ catch {
123
+ args = {};
124
+ }
125
+ // Notify waiting word immediately before running long tools
126
+ const waitingWord = getCompanionToolWaitingWord(toolName);
127
+ if (waitingWord && input.onWaitingWord) {
128
+ try {
129
+ await input.onWaitingWord(waitingWord);
130
+ }
131
+ catch (waitErr) {
132
+ logger.debug('[companion-channel-turn] onWaitingWord error', { error: String(waitErr) });
133
+ }
134
+ }
135
+ // Execute tool safely
136
+ const execFn = input.executeTool ?? executeCompanionTool;
137
+ let toolRes;
138
+ try {
139
+ toolRes = await execFn(toolName, args, {
140
+ identity: identity,
141
+ env,
142
+ cwd: input.cwd,
143
+ signal: combinedSignal,
144
+ registry: input.registry,
145
+ confirmationService: input.confirmationService,
146
+ });
147
+ }
148
+ catch (toolErr) {
149
+ toolRes = {
150
+ success: false,
151
+ error: toolErr instanceof Error ? toolErr.message : String(toolErr),
152
+ };
153
+ }
154
+ // Check if an image was produced
155
+ const imagePath = extractImagePathFromToolResult(toolRes, input.cwd);
156
+ if (imagePath) {
157
+ mediaProduced.push({ type: 'image', imagePath });
158
+ historyNotes.push(`[Image générée : ${imagePath}]`);
159
+ }
160
+ // Record reminder in history notes
161
+ if (toolName === 'remind' && toolRes.success) {
162
+ const label = typeof args.label === 'string' ? args.label.trim() : 'rappel';
163
+ const time = typeof args.time === 'string' ? args.time.trim() : '';
164
+ historyNotes.push(`[Rappel créé : ${label}${time ? ` à ${time}` : ''}]`);
165
+ }
166
+ executedTools.push({
167
+ name: toolName,
168
+ success: toolRes.success,
169
+ output: toolRes.output ?? toolRes.error,
170
+ ...(imagePath ? { imagePath } : {}),
171
+ });
172
+ // Add tool response message for LLM
173
+ activeMessages.push({
174
+ role: 'tool',
175
+ tool_call_id: toolCall.id,
176
+ content: toolRes.success
177
+ ? (toolRes.output ?? 'Succès')
178
+ : `Erreur outil ${toolName} : ${toolRes.error ?? 'inconnue'}`,
179
+ });
180
+ }
181
+ }
182
+ }
183
+ finally {
184
+ if (timeoutId) {
185
+ clearTimeout(timeoutId);
186
+ }
187
+ }
188
+ // Fallback text if model left content blank after tool calls
189
+ if (!finalText && executedTools.length > 0) {
190
+ const hasImage = mediaProduced.length > 0;
191
+ if (hasImage) {
192
+ finalText = 'Voilà, j’ai créé l’image pour toi !';
193
+ }
194
+ else {
195
+ finalText = 'C’est fait !';
196
+ }
197
+ }
198
+ // Deliver media (Telegram / PWA / Voice)
199
+ if (mediaProduced.length > 0) {
200
+ const surface = (input.surface ?? '').toLowerCase();
201
+ for (const media of mediaProduced) {
202
+ media.caption = finalText;
203
+ if (input.deliverMedia) {
204
+ try {
205
+ await input.deliverMedia(media);
206
+ }
207
+ catch (delivErr) {
208
+ logger.warn('[companion-channel-turn] deliverMedia failed', {
209
+ error: delivErr instanceof Error ? delivErr.message : String(delivErr),
210
+ });
211
+ }
212
+ }
213
+ else if (surface === 'voice') {
214
+ // Voice surface: alert owner on Telegram with the photo and announce it
215
+ try {
216
+ const { sendTelegramAlert } = await import('../sensory/alert.js');
217
+ await sendTelegramAlert(finalText, media.imagePath);
218
+ if (!/téléphone|telegram|envoie/i.test(finalText)) {
219
+ finalText = `${finalText} Je te l'envoie sur ton téléphone.`.trim();
220
+ }
221
+ }
222
+ catch (voiceSendErr) {
223
+ logger.warn('[companion-channel-turn] Voice media telegram delivery skipped', {
224
+ error: voiceSendErr instanceof Error ? voiceSendErr.message : String(voiceSendErr),
225
+ });
226
+ }
227
+ }
228
+ }
29
229
  }
230
+ const historySuffix = historyNotes.length > 0 ? `\n${historyNotes.join('\n')}` : undefined;
30
231
  return {
31
- text,
32
- model: response.model ?? input.model,
33
- ...(response.usage?.prompt_tokens !== undefined
34
- ? { promptTokens: response.usage.prompt_tokens }
35
- : {}),
232
+ text: finalText,
233
+ model: finalModel,
234
+ ...(totalPromptTokens !== undefined ? { promptTokens: totalPromptTokens } : {}),
235
+ ...(mediaProduced.length > 0 ? { media: mediaProduced } : {}),
236
+ ...(executedTools.length > 0 ? { executedTools } : {}),
237
+ ...(historySuffix ? { historySuffix } : {}),
36
238
  };
37
239
  }
38
240
  //# sourceMappingURL=companion-channel-turn.js.map
@@ -70,12 +70,10 @@ export interface SlashParityManifest {
70
70
  platforms: PlatformSlashParityReport[];
71
71
  }
72
72
  /**
73
- * The canonical set of slash commands expected on each platform.
74
- *
75
- * These represent the Code Buddy bot commands that users should be
76
- * able to invoke from each messaging platform. The manifest is
77
- * intentionally conservative — platforms may support additional
78
- * commands beyond what is listed here.
73
+ * The canonical set of slash commands expected on each platform, derived from
74
+ * the single surface declaration `CHANNEL_SLASH_SURFACES`
75
+ * (src/commands/slash/surfaces.ts) shared with the CLI catalog, Cowork and the
76
+ * slash wiki. Platforms may support additional commands beyond this list.
79
77
  */
80
78
  export declare const EXPECTED_SLASH_COMMANDS: Record<string, SlashCommandSpec[]>;
81
79
  /**
@@ -6,55 +6,20 @@
6
6
  * Returns a machine-readable readiness report for each platform.
7
7
  */
8
8
  import { getChannelManager } from './core.js';
9
+ import { CHANNEL_SLASH_SURFACES } from '../commands/slash/surfaces.js';
9
10
  // ============================================================================
10
11
  // Expected Commands Manifest
11
12
  // ============================================================================
12
13
  /**
13
- * The canonical set of slash commands expected on each platform.
14
- *
15
- * These represent the Code Buddy bot commands that users should be
16
- * able to invoke from each messaging platform. The manifest is
17
- * intentionally conservative — platforms may support additional
18
- * commands beyond what is listed here.
14
+ * The canonical set of slash commands expected on each platform, derived from
15
+ * the single surface declaration `CHANNEL_SLASH_SURFACES`
16
+ * (src/commands/slash/surfaces.ts) shared with the CLI catalog, Cowork and the
17
+ * slash wiki. Platforms may support additional commands beyond this list.
19
18
  */
20
- export const EXPECTED_SLASH_COMMANDS = {
21
- discord: [
22
- { name: 'ask', description: 'Ask Code Buddy a question' },
23
- { name: 'status', description: 'Show bot and channel status' },
24
- { name: 'clear', description: 'Clear conversation history' },
25
- { name: 'help', description: 'Show available commands' },
26
- { name: 'model', description: 'Switch or show current model' },
27
- { name: 'think', description: 'Set reasoning depth', required: false },
28
- { name: 'compact', description: 'Compact conversation context', required: false },
29
- { name: 'repo', description: 'Show repository info', required: false },
30
- ],
31
- telegram: [
32
- { name: 'ask', description: 'Ask Code Buddy a question' },
33
- { name: 'status', description: 'Show bot and channel status' },
34
- { name: 'clear', description: 'Clear conversation history' },
35
- { name: 'help', description: 'Show available commands' },
36
- { name: 'model', description: 'Switch or show current model' },
37
- { name: 'yolo', description: 'Toggle YOLO mode', required: false },
38
- { name: 'repo', description: 'Show repository info', required: false },
39
- { name: 'branch', description: 'Show branch info', required: false },
40
- ],
41
- slack: [
42
- { name: 'ask', description: 'Ask Code Buddy a question' },
43
- { name: 'status', description: 'Show bot and channel status' },
44
- { name: 'clear', description: 'Clear conversation history' },
45
- { name: 'help', description: 'Show available commands' },
46
- { name: 'model', description: 'Switch or show current model' },
47
- { name: 'compact', description: 'Compact conversation context', required: false },
48
- { name: 'think', description: 'Set reasoning depth', required: false },
49
- ],
50
- matrix: [
51
- { name: 'ask', description: 'Ask Code Buddy a question' },
52
- { name: 'status', description: 'Show bot and channel status' },
53
- { name: 'clear', description: 'Clear conversation history' },
54
- { name: 'help', description: 'Show available commands' },
55
- { name: 'model', description: 'Switch or show current model', required: false },
56
- ],
57
- };
19
+ export const EXPECTED_SLASH_COMMANDS = Object.fromEntries(Object.entries(CHANNEL_SLASH_SURFACES).map(([platform, specs]) => [
20
+ platform,
21
+ specs.map(({ name, description, required }) => ({ name, description, ...(required === false ? { required } : {}) })),
22
+ ]));
58
23
  /**
59
24
  * Check if a channel adapter implements SlashCommandProvider.
60
25
  */
@@ -16,6 +16,15 @@ export declare function resumeLastSession(): Promise<void>;
16
16
  * Resume a specific session by ID (--resume flag)
17
17
  */
18
18
  export declare function resumeSessionById(sessionId: string): Promise<void>;
19
+ /**
20
+ * Offer recent sessions without requiring an ID (P6). Non-interactive stdio:
21
+ * print the list and set exit code 1 (never waits for input). Returns the
22
+ * chosen session id, or null.
23
+ */
24
+ export declare function pickRecentSession(limit?: number, streams?: {
25
+ input: NodeJS.ReadStream;
26
+ output: NodeJS.WriteStream;
27
+ }): Promise<string | null>;
19
28
  /**
20
29
  * List recent sessions
21
30
  */
@@ -97,10 +97,19 @@ export function registerSessionCommands(program) {
97
97
  });
98
98
  session
99
99
  .command('resume')
100
- .description('Resume a saved session by ID or partial ID')
101
- .argument('<sessionId>', 'session ID or unique prefix')
102
- .action(async (sessionId) => {
103
- await resumeSessionById(sessionId);
100
+ .description('Resume a saved session by ID or partial ID; without an ID, pick among recent sessions')
101
+ .argument('[sessionId]', 'session ID or unique prefix (omit to pick interactively)')
102
+ .option('--limit <count>', 'recent sessions offered by the picker', parsePositiveInteger, 20)
103
+ .action(async (sessionId, options) => {
104
+ if (sessionId) {
105
+ await resumeSessionById(sessionId);
106
+ return;
107
+ }
108
+ const picked = await pickRecentSession(options.limit);
109
+ if (!picked)
110
+ return;
111
+ await resumeSessionById(picked);
112
+ console.log(`Continue it in the terminal with: buddy --resume ${picked.slice(0, 8)}`);
104
113
  });
105
114
  session
106
115
  .command('last')
@@ -142,7 +151,38 @@ export async function resumeSessionById(sessionId) {
142
151
  }
143
152
  await sessionStore.resumeSession(session.id);
144
153
  console.log(`Resuming session: ${session.name} (${session.id.slice(0, 8)})`);
145
- console.log(` ${session.messages.length} messages, last accessed: ${session.lastAccessedAt.toLocaleString()}\n`);
154
+ console.log(` ${session.messages.length} messages, last accessed: ${session.lastAccessedAt.toLocaleString()}`);
155
+ const { buildSessionRecap, formatSessionRecap } = await import('./session-picker.js');
156
+ console.log(`${formatSessionRecap(buildSessionRecap(session)).join('\n')}\n`);
157
+ }
158
+ /**
159
+ * Offer recent sessions without requiring an ID (P6). Non-interactive stdio:
160
+ * print the list and set exit code 1 (never waits for input). Returns the
161
+ * chosen session id, or null.
162
+ */
163
+ export async function pickRecentSession(limit = 20, streams = { input: process.stdin, output: process.stdout }) {
164
+ const { getSessionStore } = await import('../persistence/session-store.js');
165
+ const sessions = await getSessionStore().getRecentSessions(limit);
166
+ if (sessions.length === 0) {
167
+ console.log('No sessions found.');
168
+ process.exitCode = 1;
169
+ return null;
170
+ }
171
+ if (!streams.input.isTTY || !streams.output.isTTY) {
172
+ console.log(`Recent sessions (${sessions.length}):\n`);
173
+ sessions.forEach((session) => printSessionSummary(session));
174
+ console.log('\nNo interactive terminal: pass an ID, e.g. `buddy session resume <id>` or `buddy --resume <id>`.');
175
+ process.exitCode = 1;
176
+ return null;
177
+ }
178
+ const { pickSession } = await import('./session-picker.js');
179
+ const picked = await pickSession(sessions, streams);
180
+ if (!picked) {
181
+ console.log('Cancelled.');
182
+ process.exitCode = 1;
183
+ return null;
184
+ }
185
+ return picked.id;
146
186
  }
147
187
  /**
148
188
  * List recent sessions