@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
@@ -0,0 +1,368 @@
1
+ /**
2
+ * Companion Toolset definition, authorization and execution gates.
3
+ *
4
+ * Defines which tools Lisa can use based on the interlocutor's identity tier:
5
+ * - 'owner': image_generate, image_edit, remind, web_search, weather, stock_quote,
6
+ * understand_video, camera_analyze, recall.
7
+ * - 'present': same tools WITHOUT remind and WITHOUT camera (camera_analyze).
8
+ * - 'guest': NO tools (fail-closed, byte-identical to historical turn).
9
+ *
10
+ * Hard security invariants:
11
+ * - NEVER bash, shell_exec, file writing (create_file, edit, patch), MCP, fleet tools.
12
+ * - Circuit-breaker: CODEBUDDY_COMPANION_TOOLS_ENABLED (default: false -> 0 tools).
13
+ * - Surcharge: CODEBUDDY_COMPANION_TOOLS (csv list, filtered against hard constraints).
14
+ *
15
+ * @module companion/companion-toolset
16
+ */
17
+ import path from 'path';
18
+ import { logger } from '../utils/logger.js';
19
+ import { FormalToolRegistry } from '../tools/registry/tool-registry.js';
20
+ export const OWNER_COMPANION_TOOLS = Object.freeze([
21
+ 'image_generate',
22
+ 'image_edit',
23
+ 'remind',
24
+ 'web_search',
25
+ 'weather',
26
+ 'stock_quote',
27
+ 'understand_video',
28
+ 'camera_analyze',
29
+ 'recall',
30
+ ]);
31
+ export const PRESENT_COMPANION_TOOLS = Object.freeze([
32
+ 'image_generate',
33
+ 'image_edit',
34
+ 'web_search',
35
+ 'weather',
36
+ 'stock_quote',
37
+ 'understand_video',
38
+ 'recall',
39
+ ]);
40
+ export const GUEST_COMPANION_TOOLS = Object.freeze([]);
41
+ /** Strictly forbidden tool patterns that can NEVER be exposed to companion */
42
+ export const COMPANION_FORBIDDEN_PATTERNS = Object.freeze([
43
+ // bash* family (bash, bash_exec, etc.)
44
+ /^bash/i,
45
+ 'terminal',
46
+ 'interactive_shell',
47
+ // shell* family (shell_exec, shell_git, shell_process, shell_docker, shell_k8s, etc.)
48
+ /^shell/i,
49
+ // *_exec family and code execution (code_exec, shell_exec, execute_code, etc.)
50
+ /(?:^|_)exec(?:$|_)/i,
51
+ /^execute_/i,
52
+ 'js_repl',
53
+ // write_* family & file writing
54
+ /^write_/i,
55
+ /^file_write/i,
56
+ 'create_file',
57
+ // patch family
58
+ 'patch',
59
+ /^apply_patch/i,
60
+ // str_replace* family (str_replace, str_replace_editor, etc.)
61
+ /^str_replace/i,
62
+ // multi_edit and edit_* family (file editing; does NOT match image_edit)
63
+ 'multi_edit',
64
+ /^multi_edit/i,
65
+ /^edit_/i,
66
+ /^file_edit/i,
67
+ // delete_* family
68
+ /^delete_/i,
69
+ // system / infra / process / code execution / app server
70
+ 'docker',
71
+ 'kubernetes',
72
+ 'process',
73
+ /^process/i,
74
+ 'git',
75
+ /^git_/i,
76
+ 'resolve_conflicts',
77
+ 'app_server',
78
+ 'computer_control',
79
+ 'office_macro_execute',
80
+ 'codebase_replace',
81
+ 'scaffold_app',
82
+ 'tool_search',
83
+ 'extension_forge',
84
+ 'scan_vulnerabilities',
85
+ 'env_doctor',
86
+ 'resource_catalog',
87
+ 'port_check',
88
+ 'lint_project',
89
+ 'test_runner',
90
+ 'format_project',
91
+ 'build_project',
92
+ // A2A / MCP / orchestration / registration
93
+ /^a2a_/i,
94
+ /^mcp_/i,
95
+ /^fleet_/i,
96
+ /^peer_/i,
97
+ /^delegate_/i,
98
+ /^register_tool/i,
99
+ 'register_tool',
100
+ ]);
101
+ /**
102
+ * Check if a tool is strictly forbidden for the companion.
103
+ */
104
+ export function isForbiddenCompanionTool(toolName) {
105
+ const norm = toolName.trim().toLowerCase();
106
+ for (const pattern of COMPANION_FORBIDDEN_PATTERNS) {
107
+ if (typeof pattern === 'string') {
108
+ if (norm === pattern.toLowerCase())
109
+ return true;
110
+ }
111
+ else if (pattern instanceof RegExp) {
112
+ if (pattern.test(norm))
113
+ return true;
114
+ }
115
+ }
116
+ return false;
117
+ }
118
+ /**
119
+ * Check if companion tools are enabled via circuit-breaker.
120
+ * Default is FALSE (OFF).
121
+ */
122
+ export function isCompanionToolsEnabled(env = process.env) {
123
+ const raw = (env.CODEBUDDY_COMPANION_TOOLS_ENABLED ?? '').trim().toLowerCase();
124
+ return raw === 'true' || raw === '1' || raw === 'yes' || raw === 'on';
125
+ }
126
+ /**
127
+ * Resolve allowed tool names for a given identity and environment.
128
+ */
129
+ export function getCompanionToolNames(identity, env = process.env) {
130
+ // 1. Circuit breaker OFF -> zero tools
131
+ if (!isCompanionToolsEnabled(env)) {
132
+ return [];
133
+ }
134
+ // 2. Guest role -> zero tools (fail-closed)
135
+ if (identity.role === 'guest') {
136
+ return [];
137
+ }
138
+ // 3. Baseline per role
139
+ const baseline = identity.role === 'owner' ? OWNER_COMPANION_TOOLS : PRESENT_COMPANION_TOOLS;
140
+ // 4. Surcharge via CODEBUDDY_COMPANION_TOOLS (CSV)
141
+ // Hard invariant: CSV can ONLY INTERSECT the role's baseline tools, NEVER extend it.
142
+ let allowed;
143
+ const configured = (env.CODEBUDDY_COMPANION_TOOLS ?? '').trim();
144
+ if (configured) {
145
+ const requested = new Set(configured
146
+ .split(',')
147
+ .map((s) => s.trim().toLowerCase())
148
+ .filter(Boolean));
149
+ // Strict intersection with role baseline (order preserved from baseline)
150
+ allowed = baseline.filter((tool) => {
151
+ const match = requested.has(tool.toLowerCase());
152
+ if (!match)
153
+ return false;
154
+ if (isForbiddenCompanionTool(tool)) {
155
+ logger.warn(`[companion-toolset] Surcharge tool "${tool}" rejected: strictly forbidden`);
156
+ return false;
157
+ }
158
+ return true;
159
+ });
160
+ }
161
+ else {
162
+ allowed = [...baseline];
163
+ }
164
+ // Final sanity filter: eliminate any forbidden tool that could have leaked
165
+ return allowed.filter((tool) => !isForbiddenCompanionTool(tool));
166
+ }
167
+ /**
168
+ * Human-friendly waiting phrase when a slow tool starts executing.
169
+ */
170
+ export function getCompanionToolWaitingWord(toolName) {
171
+ switch (toolName) {
172
+ case 'image_generate':
173
+ return 'Je dessine…';
174
+ case 'image_edit':
175
+ return 'Je modifie l’image…';
176
+ case 'camera_analyze':
177
+ case 'camera_snapshot':
178
+ return 'Je regarde…';
179
+ case 'web_search':
180
+ return 'Je cherche sur le web…';
181
+ case 'weather':
182
+ return 'Je regarde la météo…';
183
+ case 'stock_quote':
184
+ return 'Je vérifie les cours de bourse…';
185
+ case 'understand_video':
186
+ return 'J’analyse la vidéo…';
187
+ case 'remind':
188
+ return 'Je note ton rappel…';
189
+ case 'recall':
190
+ return 'Je vérifie dans mes souvenirs…';
191
+ default:
192
+ return null;
193
+ }
194
+ }
195
+ /**
196
+ * Get OpenAI-compatible function tool definitions for allowed companion tools.
197
+ */
198
+ export async function getCompanionToolDefinitions(identity, options = {}) {
199
+ const env = options.env ?? process.env;
200
+ const toolNames = getCompanionToolNames(identity, env);
201
+ if (toolNames.length === 0)
202
+ return [];
203
+ const registry = options.registry ?? FormalToolRegistry.getInstance();
204
+ if (registry.getNames().length === 0) {
205
+ const { registerBuiltinTools } = await import('../tools/registry/index.js');
206
+ registerBuiltinTools(registry);
207
+ }
208
+ const definitions = [];
209
+ for (const name of toolNames) {
210
+ const registered = registry.get(name);
211
+ if (!registered) {
212
+ continue;
213
+ }
214
+ const schema = registered.tool.getSchema();
215
+ definitions.push({
216
+ type: 'function',
217
+ function: {
218
+ name: schema.name,
219
+ description: schema.description,
220
+ parameters: {
221
+ type: 'object',
222
+ properties: schema.parameters?.properties ?? {},
223
+ required: schema.parameters?.required ?? [],
224
+ ...(schema.parameters?.additionalProperties !== undefined
225
+ ? { additionalProperties: schema.parameters.additionalProperties }
226
+ : {}),
227
+ },
228
+ },
229
+ });
230
+ }
231
+ return definitions;
232
+ }
233
+ /**
234
+ * Safely execute a companion tool call.
235
+ */
236
+ export async function executeCompanionTool(toolName, args, context) {
237
+ const env = context.env ?? process.env;
238
+ // 1. Hard invariant: forbidden tool
239
+ if (isForbiddenCompanionTool(toolName)) {
240
+ const err = `Tool "${toolName}" is strictly forbidden in companion mode.`;
241
+ logger.warn(`[companion-toolset] ${err}`);
242
+ return { success: false, error: err };
243
+ }
244
+ // 2. Authorization check against identity role
245
+ const allowedNames = getCompanionToolNames(context.identity, env);
246
+ if (!allowedNames.includes(toolName)) {
247
+ const err = `Tool "${toolName}" is not permitted for companion identity role "${context.identity.role}".`;
248
+ logger.warn(`[companion-toolset] ${err}`);
249
+ return { success: false, error: err };
250
+ }
251
+ // 3. Confirmation gate:
252
+ // Destructive tools are blocked by isForbiddenCompanionTool.
253
+ // For permitted companion read/generation tools, validate against policy engine kill-switch
254
+ // and honor any explicit confirmationService passed in context.
255
+ if (context.confirmationService) {
256
+ const confirmationRes = await context.confirmationService.requestConfirmation({
257
+ operation: `companion:${toolName}`,
258
+ filename: toolName,
259
+ toolName,
260
+ toolArgs: args,
261
+ showVSCodeOpen: false,
262
+ content: `Companion tool: ${toolName}\nArguments:\n${JSON.stringify(args, null, 2)}`,
263
+ }, 'tool');
264
+ if (!confirmationRes.confirmed) {
265
+ return {
266
+ success: false,
267
+ error: confirmationRes.feedback ?? `Execution of "${toolName}" was rejected by confirmation policy.`,
268
+ };
269
+ }
270
+ }
271
+ else {
272
+ const { PolicyEngine } = await import('../security/policy-engine.js');
273
+ if (PolicyEngine.getInstance().isKilled()) {
274
+ return {
275
+ success: false,
276
+ error: `Security kill-switch active: ${PolicyEngine.getInstance().getKillReason()}`,
277
+ };
278
+ }
279
+ }
280
+ // 4. Retrieve tool from registry
281
+ const registry = context.registry ?? FormalToolRegistry.getInstance();
282
+ if (registry.getNames().length === 0) {
283
+ const { registerBuiltinTools } = await import('../tools/registry/index.js');
284
+ registerBuiltinTools(registry);
285
+ }
286
+ const registered = registry.get(toolName);
287
+ if (!registered) {
288
+ return {
289
+ success: false,
290
+ error: `Companion tool "${toolName}" is not registered in the tool registry.`,
291
+ };
292
+ }
293
+ // 5. Execute
294
+ try {
295
+ return await registered.tool.execute(args, {
296
+ cwd: context.cwd ?? process.cwd(),
297
+ abortSignal: context.signal,
298
+ });
299
+ }
300
+ catch (execError) {
301
+ const msg = execError instanceof Error ? execError.message : String(execError);
302
+ logger.warn(`[companion-toolset] Error executing tool "${toolName}": ${msg}`);
303
+ return {
304
+ success: false,
305
+ error: `Tool execution error: ${msg}`,
306
+ };
307
+ }
308
+ }
309
+ /**
310
+ * Extract image path from tool execution result if one was created/returned.
311
+ */
312
+ export function extractImagePathFromToolResult(result, cwd = process.cwd()) {
313
+ if (!result || !result.success)
314
+ return undefined;
315
+ const isImagePath = (val) => {
316
+ if (typeof val !== 'string' || !val.trim())
317
+ return false;
318
+ const clean = val.trim();
319
+ return /\.(png|jpe?g|webp)$/i.test(clean);
320
+ };
321
+ const toAbs = (filePath) => {
322
+ return path.isAbsolute(filePath) ? filePath : path.resolve(cwd, filePath);
323
+ };
324
+ const data = result.data;
325
+ if (data && typeof data === 'object') {
326
+ if (isImagePath(data.mediaPath))
327
+ return toAbs(data.mediaPath);
328
+ if (isImagePath(data.imagePath))
329
+ return toAbs(data.imagePath);
330
+ if (isImagePath(data.outputPath))
331
+ return toAbs(data.outputPath);
332
+ if (isImagePath(data.path))
333
+ return toAbs(data.path);
334
+ if (isImagePath(data.image))
335
+ return toAbs(data.image);
336
+ if (Array.isArray(data.images) && isImagePath(data.images[0]?.path)) {
337
+ return toAbs(data.images[0].path);
338
+ }
339
+ }
340
+ // Fallback: check output string if JSON
341
+ if (typeof result.output === 'string') {
342
+ try {
343
+ const parsed = JSON.parse(result.output);
344
+ if (parsed && typeof parsed === 'object') {
345
+ if (isImagePath(parsed.mediaPath))
346
+ return toAbs(parsed.mediaPath);
347
+ if (isImagePath(parsed.imagePath))
348
+ return toAbs(parsed.imagePath);
349
+ if (isImagePath(parsed.outputPath))
350
+ return toAbs(parsed.outputPath);
351
+ if (isImagePath(parsed.path))
352
+ return toAbs(parsed.path);
353
+ if (isImagePath(parsed.image))
354
+ return toAbs(parsed.image);
355
+ }
356
+ }
357
+ catch {
358
+ // not JSON
359
+ }
360
+ // Search for an absolute POSIX or Windows image path in human-readable output.
361
+ const match = result.output.match(/(?:^|[\s"'`])((?:[a-z]:[\\/]|\/)[^\s"'`]+\.(?:png|jpe?g|webp))/i);
362
+ if (match && match[1]) {
363
+ return match[1];
364
+ }
365
+ }
366
+ return undefined;
367
+ }
368
+ //# sourceMappingURL=companion-toolset.js.map
@@ -31,6 +31,7 @@ import type { CompanionSelfieServeResult, CompanionSelfieSurface, TryServeCompan
31
31
  /** A companion surface. `voice` keeps its own loop; it is listed for symmetry. */
32
32
  export type CompanionSurface = CompanionSelfieSurface;
33
33
  export type { CompanionHistoryTurn } from './companion-history.js';
34
+ import { type CompanionIdentity } from './companion-identity.js';
34
35
  export interface CompanionTurnResult {
35
36
  text: string;
36
37
  kind: 'selfie' | 'text';
@@ -40,6 +41,8 @@ export interface CompanionTurnResult {
40
41
  };
41
42
  imagePath?: string;
42
43
  model?: string;
44
+ historySuffix?: string;
45
+ executedTools?: import('../channels/companion-channel-turn.js').CompanionExecutedTool[];
43
46
  /** Present only when the user shared photos in this turn. */
44
47
  photos?: {
45
48
  /** Where the image went. `local` means the bytes never left the machine. */
@@ -60,6 +63,11 @@ export interface RunCompanionTurnOptions {
60
63
  history?: CompanionHistoryTurn[];
61
64
  env?: NodeJS.ProcessEnv;
62
65
  signal?: AbortSignal;
66
+ /** Explicit identity of the user, or resolved from surface and IDs */
67
+ identity?: CompanionIdentity;
68
+ userId?: string;
69
+ chatId?: string;
70
+ onWaitingWord?: (word: string) => Promise<void> | void;
63
71
  /**
64
72
  * Photos the user shared with this message. Absent (the default) the turn is
65
73
  * byte-identical to a text-only turn: no photo module is even imported.
@@ -70,11 +78,11 @@ export interface RunCompanionTurnOptions {
70
78
  /** Injectables — production resolves each of these itself. */
71
79
  resolveProvider?: (env: NodeJS.ProcessEnv) => CompanionTurnProvider | null;
72
80
  serveSelfie?: (text: string, options: TryServeCompanionSelfieOptions) => Promise<CompanionSelfieServeResult | null>;
73
- chat?: (messages: CodeBuddyMessage[], tools: [], opts: {
81
+ chat?: (messages: CodeBuddyMessage[], tools: unknown[], opts: {
74
82
  model: string;
75
83
  maxTokens?: number;
76
84
  signal?: AbortSignal;
77
- tool_choice: 'none';
85
+ tool_choice?: unknown;
78
86
  }) => Promise<CodeBuddyResponse>;
79
87
  /** Photo seams — production uses the real pipeline and the real album. */
80
88
  preparePhotos?: typeof prepareCompanionPhotos;
@@ -32,6 +32,7 @@ import { attachPhotoParts, looksLikeVisionRefusal, prepareCompanionPhotos, } fro
32
32
  import { rememberSharedPhotos } from './shared-photo-memory.js';
33
33
  import { applyLimitsContract } from './reply-augment.js';
34
34
  import { guardRelationshipReply } from '../conversation/relationship-safety.js';
35
+ import { resolveCompanionIdentity } from './companion-identity.js';
35
36
  /** Fallback when no provider is configured — spoken, never a silent empty reply. */
36
37
  const NO_PROVIDER_MESSAGE = 'unreachable: no configured provider for the companion turn';
37
38
  export { historyHasRecentSelfie } from './companion-history.js';
@@ -132,6 +133,13 @@ export async function runCompanionTurn(message, options) {
132
133
  const messagesFor = (batch, base) => batch && batch.mode === 'cloud' && batch.photos.length > 0
133
134
  ? attachPhotoParts(base, batch.photos)
134
135
  : base;
136
+ const identity = options.identity ??
137
+ resolveCompanionIdentity({
138
+ channel: options.surface === 'mobile' ? 'pwa' : options.surface,
139
+ userId: options.userId,
140
+ chatId: options.chatId,
141
+ env,
142
+ });
135
143
  try {
136
144
  let batch = prepared;
137
145
  let generated = await runCompanionChannelTurn({
@@ -139,6 +147,10 @@ export async function runCompanionTurn(message, options) {
139
147
  baseUrl: provider.baseUrl,
140
148
  model: provider.model,
141
149
  messages: messagesFor(batch, prompt.messages),
150
+ identity,
151
+ surface: options.surface,
152
+ env,
153
+ ...(options.onWaitingWord ? { onWaitingWord: options.onWaitingWord } : {}),
142
154
  ...(options.signal ? { signal: options.signal } : {}),
143
155
  ...(options.chat ? { chat: options.chat } : {}),
144
156
  });
@@ -168,6 +180,10 @@ export async function runCompanionTurn(message, options) {
168
180
  baseUrl: provider.baseUrl,
169
181
  model: provider.model,
170
182
  messages: localPrompt.messages,
183
+ identity,
184
+ surface: options.surface,
185
+ env,
186
+ ...(options.onWaitingWord ? { onWaitingWord: options.onWaitingWord } : {}),
171
187
  ...(options.signal ? { signal: options.signal } : {}),
172
188
  ...(options.chat ? { chat: options.chat } : {}),
173
189
  });
@@ -184,10 +200,31 @@ export async function runCompanionTurn(message, options) {
184
200
  }
185
201
  const guarded = guardRelationshipReply(text);
186
202
  const limited = applyLimitsContract(guarded.response, { heard: message, env });
203
+ const firstMedia = generated.media?.[0];
204
+ let generatedImage;
205
+ if (firstMedia?.imagePath && (options.includeImageBytes === true || options.surface === 'mobile')) {
206
+ try {
207
+ const fsMod = await import('fs/promises');
208
+ const pathMod = await import('path');
209
+ const ext = pathMod.extname(firstMedia.imagePath).slice(1).toLowerCase();
210
+ const mimeType = ext === 'jpg' || ext === 'jpeg' ? 'image/jpeg' : `image/${ext || 'png'}`;
211
+ const data = (await fsMod.readFile(firstMedia.imagePath)).toString('base64');
212
+ generatedImage = { mimeType, data };
213
+ }
214
+ catch (readErr) {
215
+ logger.warn('[companion-turn] Failed to read generated media bytes', {
216
+ error: readErr instanceof Error ? readErr.message : String(readErr),
217
+ });
218
+ }
219
+ }
187
220
  return {
188
221
  text: prependUserFacingFailoverNotice(limited.text, 'companion-turn'),
189
- kind: 'text',
222
+ kind: firstMedia ? 'selfie' : 'text',
223
+ ...(firstMedia?.imagePath ? { imagePath: firstMedia.imagePath } : {}),
224
+ ...(generatedImage ? { image: generatedImage } : {}),
190
225
  model: generated.model,
226
+ ...(generated.historySuffix ? { historySuffix: generated.historySuffix } : {}),
227
+ ...(generated.executedTools ? { executedTools: generated.executedTools } : {}),
191
228
  ...(photoSummary ? { photos: photoSummary } : {}),
192
229
  };
193
230
  }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Programmatic tool calling (`code_exec`) policy per model (comparatif plan P5).
3
+ *
4
+ * - `offer` (default, unchanged behaviour): `code_exec` is selected by relevance
5
+ * or when the user explicitly asks for programmatic tool calling.
6
+ * - `prefer`: `code_exec` is always offered and the model gets a short hint to
7
+ * batch multi-step reads/computations into one program.
8
+ * - `off`: `code_exec` is never offered, even on explicit request; the model is
9
+ * told why through the runtime settings snapshot.
10
+ *
11
+ * Promotion rule: NO model ships with `prefer`. A `prefer` entry in
12
+ * `model-tools.ts` must carry `codeExecEvidence` (a Buddy recette report proving
13
+ * ADV01–ADV09 on that model). Other projects' "preferred" lists are not evidence.
14
+ * `CODEBUDDY_CODE_EXEC_POLICY` is an explicit operator override for trials.
15
+ */
16
+ export type CodeExecPolicy = 'off' | 'offer' | 'prefer';
17
+ export interface ResolvedCodeExecPolicy {
18
+ policy: CodeExecPolicy;
19
+ source: 'env' | 'model' | 'default';
20
+ evidence?: string;
21
+ }
22
+ export declare function isCodeExecPolicy(value: unknown): value is CodeExecPolicy;
23
+ export declare function resolveCodeExecPolicy(model: string | undefined): ResolvedCodeExecPolicy;
24
+ export declare const CODE_EXEC_PREFER_HINT = "Programmatic tool calling is preferred for this model: when a task needs several reads, searches or computations whose results feed each other, run them in ONE code_exec program (tools.call) instead of many separate tool rounds. Keep single-step tasks as direct tool calls.";
25
+ export declare const CODE_EXEC_OFF_NOTICE = "Programmatic tool calling (code_exec) is disabled by the model policy for this model. If the user asks for code_exec or tools.call, say that it is disabled for this model and use direct tool calls instead.";
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Programmatic tool calling (`code_exec`) policy per model (comparatif plan P5).
3
+ *
4
+ * - `offer` (default, unchanged behaviour): `code_exec` is selected by relevance
5
+ * or when the user explicitly asks for programmatic tool calling.
6
+ * - `prefer`: `code_exec` is always offered and the model gets a short hint to
7
+ * batch multi-step reads/computations into one program.
8
+ * - `off`: `code_exec` is never offered, even on explicit request; the model is
9
+ * told why through the runtime settings snapshot.
10
+ *
11
+ * Promotion rule: NO model ships with `prefer`. A `prefer` entry in
12
+ * `model-tools.ts` must carry `codeExecEvidence` (a Buddy recette report proving
13
+ * ADV01–ADV09 on that model). Other projects' "preferred" lists are not evidence.
14
+ * `CODEBUDDY_CODE_EXEC_POLICY` is an explicit operator override for trials.
15
+ */
16
+ import { getModelToolConfig } from './model-tools.js';
17
+ const POLICIES = new Set(['off', 'offer', 'prefer']);
18
+ export function isCodeExecPolicy(value) {
19
+ return typeof value === 'string' && POLICIES.has(value);
20
+ }
21
+ export function resolveCodeExecPolicy(model) {
22
+ const override = process.env.CODEBUDDY_CODE_EXEC_POLICY?.trim().toLowerCase();
23
+ if (isCodeExecPolicy(override))
24
+ return { policy: override, source: 'env' };
25
+ if (model) {
26
+ const config = getModelToolConfig(model);
27
+ if (isCodeExecPolicy(config.codeExec)) {
28
+ return {
29
+ policy: config.codeExec,
30
+ source: 'model',
31
+ ...(config.codeExecEvidence ? { evidence: config.codeExecEvidence } : {}),
32
+ };
33
+ }
34
+ }
35
+ return { policy: 'offer', source: 'default' };
36
+ }
37
+ export const CODE_EXEC_PREFER_HINT = 'Programmatic tool calling is preferred for this model: when a task needs several reads, searches or computations whose results feed each other, run them in ONE code_exec program (tools.call) instead of many separate tool rounds. Keep single-step tasks as direct tool calls.';
38
+ export const CODE_EXEC_OFF_NOTICE = 'Programmatic tool calling (code_exec) is disabled by the model policy for this model. If the user asks for code_exec or tools.call, say that it is disabled for this model and use direct tool calls instead.';
39
+ //# sourceMappingURL=code-exec-policy.js.map
@@ -54,6 +54,13 @@ export interface ModelToolConfig {
54
54
  * full instruction set.
55
55
  */
56
56
  promptProfile?: 'lite' | 'standard' | 'rich';
57
+ /**
58
+ * Programmatic tool calling policy (P5, `src/config/code-exec-policy.ts`).
59
+ * Absent = `offer` (historical behaviour). `prefer` requires `codeExecEvidence`.
60
+ */
61
+ codeExec?: 'off' | 'offer' | 'prefer';
62
+ /** Path of the Buddy recette report (ADV01–ADV09) that justifies `codeExec: 'prefer'`. */
63
+ codeExecEvidence?: string;
57
64
  }
58
65
  /**
59
66
  * Nom « nu » d'un modèle : sans préfixe fournisseur (`moonshotai/kimi-k3` → `kimi-k3`) ni tag
@@ -81,6 +88,8 @@ export declare function resetRuntimeModelContextCache(): void;
81
88
  * décrits ici sans les dupliquer dans `SUPPORTED_MODELS`.
82
89
  */
83
90
  export declare function findModelToolConfig(modelName: string, customConfigs?: ModelToolConfig[]): ModelToolConfig | null;
91
+ /** Read-only view of the built-in table (consistency tests, e.g. P5 `codeExecEvidence`). */
92
+ export declare function listDefaultModelToolConfigs(): readonly Readonly<ModelToolConfig>[];
84
93
  export declare function getModelToolConfig(modelName: string, customConfigs?: ModelToolConfig[]): ModelToolConfig;
85
94
  /** Test seam — clear the strengths memo. */
86
95
  export declare function resetModelStrengthsCache(): void;
@@ -1169,6 +1169,10 @@ export function resetRuntimeModelContextCache() {
1169
1169
  export function findModelToolConfig(modelName, customConfigs) {
1170
1170
  return findConfigMatch(modelName, [...(customConfigs || []), ...DEFAULT_MODEL_CONFIGS])?.config ?? null;
1171
1171
  }
1172
+ /** Read-only view of the built-in table (consistency tests, e.g. P5 `codeExecEvidence`). */
1173
+ export function listDefaultModelToolConfigs() {
1174
+ return DEFAULT_MODEL_CONFIGS.map((config) => Object.freeze({ ...config }));
1175
+ }
1172
1176
  export function getModelToolConfig(modelName, customConfigs) {
1173
1177
  // Use cache for default config lookups (hot path)
1174
1178
  if (!customConfigs && _configCache.has(modelName)) {
@@ -12,6 +12,7 @@
12
12
  * - Content-type-aware Compression
13
13
  * - Key Information Preservation
14
14
  */
15
+ import { truncateOutput } from '../utils/bounded-output.js';
15
16
  import { createHash } from 'node:crypto';
16
17
  import * as fs from 'fs';
17
18
  import * as path from 'path';
@@ -703,8 +704,7 @@ export class ContextManagerV2 {
703
704
  if (msg.content.length > MAX_TOOL_RESULT_LENGTH) {
704
705
  return {
705
706
  ...msg,
706
- content: msg.content.substring(0, MAX_TOOL_RESULT_LENGTH) +
707
- '\n... [truncated for context limits]',
707
+ content: truncateOutput(msg.content, MAX_TOOL_RESULT_LENGTH),
708
708
  };
709
709
  }
710
710
  }
@@ -44,8 +44,9 @@ function stringArray(value) {
44
44
  /** Resolve lm-resizer: explicit env -> stable install -> PATH -> mutable DEV build. */
45
45
  export function resolveLmResizerBin() {
46
46
  const env = process.env.CODEBUDDY_LM_RESIZER_BIN;
47
- if (env && existsSync(env))
48
- return env;
47
+ // An explicit choice must not silently fall through to an older binary.
48
+ if (env?.trim())
49
+ return env.trim();
49
50
  const stable = join(homedir(), '.local', 'bin', 'lm-resizer');
50
51
  if (existsSync(stable))
51
52
  return stable;
@@ -0,0 +1,9 @@
1
+ /** Read-only host probe. Availability alone does not establish protocol support. */
2
+ export declare function diagnoseLmResizer(): Promise<{
3
+ binary: string;
4
+ enabled: boolean;
5
+ available: boolean;
6
+ toolOutputSupported: boolean;
7
+ version: string;
8
+ warning: string;
9
+ }>;
@@ -0,0 +1,30 @@
1
+ import { execFile } from 'child_process';
2
+ import { promisify } from 'util';
3
+ import { isLmResizerEnabled, resolveLmResizerBin } from './lm-resizer-compressor.js';
4
+ const run = promisify(execFile);
5
+ /** Read-only host probe. Availability alone does not establish protocol support. */
6
+ export async function diagnoseLmResizer() {
7
+ const binary = resolveLmResizerBin();
8
+ const result = { binary, enabled: isLmResizerEnabled(), available: false, toolOutputSupported: false, version: 'unknown', warning: '' };
9
+ const options = { timeout: 3000, maxBuffer: 64 * 1024, windowsHide: true };
10
+ try {
11
+ await run(binary, ['--help'], options);
12
+ result.available = true;
13
+ try {
14
+ result.version = (await run(binary, ['--version'], options)).stdout.trim();
15
+ }
16
+ catch { /* Older CLI has no version flag. */ }
17
+ try {
18
+ const probe = await run(binary, ['tool-output', '--help'], options);
19
+ result.toolOutputSupported = /tool-output/.test(probe.stdout);
20
+ }
21
+ catch { /* Old protocol: retain raw observations. */ }
22
+ if (!result.toolOutputSupported)
23
+ result.warning = 'This binary lacks the tool-output protocol. Buddy keeps raw observations; install a compatible release to enable observation compression.';
24
+ }
25
+ catch {
26
+ result.warning = 'LM Resizer is unavailable on the host. Buddy keeps raw observations.';
27
+ }
28
+ return result;
29
+ }
30
+ //# sourceMappingURL=lm-resizer-diagnostics.js.map