@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
@@ -1,93 +1,47 @@
1
- import React, { useMemo } from "react";
2
- import { Box, Text } from "ink";
3
- import { useTheme } from "../context/theme-context.js";
4
- // Memoized ChatInput to reduce re-renders and prevent flickering
1
+ import React, { useMemo } from 'react';
2
+ import { Box, Text } from 'ink';
3
+ import { useTheme } from '../context/theme-context.js';
4
+ /** A bounded draft viewport. Editing remains available while the agent works. */
5
5
  export const ChatInput = React.memo(function ChatInput({ input, cursorPosition, isProcessing, isStreaming, mode = 'code', }) {
6
6
  const { colors } = useTheme();
7
- // Mode icons and colors for prompt
8
- const modePromptIcons = {
9
- plan: '📋',
10
- code: '',
11
- ask: '',
12
- };
13
- const modePromptColors = {
14
- plan: colors.info,
15
- code: colors.primary,
16
- ask: colors.secondary,
17
- };
18
- const promptIcon = modePromptIcons[mode] || '❯';
19
- const promptColor = modePromptColors[mode] || colors.primary;
20
- // Memoize cursor calculations to avoid recomputing on every render
21
- const cursorData = useMemo(() => {
22
- const lines = input.split("\n");
23
- const isMultiline = lines.length > 1;
24
- const beforeCursor = input.slice(0, cursorPosition);
25
- // Calculate cursor position across lines
26
- let currentLineIndex = 0;
27
- let currentCharIndex = 0;
28
- let totalChars = 0;
29
- for (let i = 0; i < lines.length; i++) {
30
- const line = lines[i] ?? "";
31
- if (totalChars + line.length >= cursorPosition) {
32
- currentLineIndex = i;
33
- currentCharIndex = cursorPosition - totalChars;
34
- break;
35
- }
36
- totalChars += line.length + 1; // +1 for newline
37
- }
38
- return { lines, isMultiline, beforeCursor, currentLineIndex, currentCharIndex };
7
+ const busy = isProcessing || isStreaming;
8
+ const viewport = useMemo(() => {
9
+ const position = Math.max(0, Math.min(input.length, cursorPosition));
10
+ const lines = input.split('\n');
11
+ const before = input.slice(0, position).split('\n');
12
+ const row = before.length - 1;
13
+ const column = before[row]?.length ?? 0;
14
+ const start = Math.max(0, Math.min(row - 3, lines.length - 6));
15
+ return { lines, row, column, start, visible: lines.slice(start, start + 6) };
39
16
  }, [input, cursorPosition]);
40
- const { lines, isMultiline, beforeCursor, currentLineIndex, currentCharIndex } = cursorData;
41
- const showCursor = !isProcessing && !isStreaming;
42
- const borderColor = isProcessing || isStreaming ? colors.borderBusy : colors.borderActive;
43
- // Display placeholder when input is empty
44
- const placeholderText = mode === 'plan'
45
- ? "Describe the task you want to plan..."
46
- : mode === 'ask'
47
- ? "Ask a question..."
48
- : "Ask me anything...";
49
- const isPlaceholder = !input;
50
- if (isMultiline) {
51
- return (React.createElement(Box, { borderStyle: "round", borderColor: borderColor, paddingY: 0, marginTop: 1 }, lines.map((line, index) => {
52
- const isCurrentLine = index === currentLineIndex;
53
- const promptChar = index === 0 ? promptIcon : "│";
54
- if (isCurrentLine) {
55
- const beforeCursorInLine = line.slice(0, currentCharIndex);
56
- const cursorChar = line.slice(currentCharIndex, currentCharIndex + 1) || " ";
57
- const afterCursorInLine = line.slice(currentCharIndex + 1);
58
- return (React.createElement(Box, { key: index },
59
- React.createElement(Text, { color: promptColor },
60
- promptChar,
61
- " "),
62
- React.createElement(Text, null,
63
- beforeCursorInLine,
64
- showCursor && (React.createElement(Text, { backgroundColor: "white", color: "black" }, cursorChar)),
65
- !showCursor && cursorChar !== " " && cursorChar,
66
- afterCursorInLine)));
67
- }
68
- else {
69
- return (React.createElement(Box, { key: index },
70
- React.createElement(Text, { color: promptColor },
71
- promptChar,
72
- " "),
73
- React.createElement(Text, null, line)));
74
- }
75
- })));
76
- }
77
- // Single line input box
78
- const cursorChar = input.slice(cursorPosition, cursorPosition + 1) || " ";
79
- const afterCursorText = input.slice(cursorPosition + 1);
80
- return (React.createElement(Box, { borderStyle: "round", borderColor: borderColor, paddingX: 1, paddingY: 0, marginTop: 1 },
81
- React.createElement(Box, null,
82
- React.createElement(Text, { color: promptColor },
83
- promptIcon,
84
- " "),
85
- isPlaceholder ? (React.createElement(React.Fragment, null,
86
- React.createElement(Text, { color: colors.textMuted, dimColor: true }, placeholderText),
87
- showCursor && (React.createElement(Text, { backgroundColor: "white", color: "black" }, " ")))) : (React.createElement(Text, null,
88
- beforeCursor,
89
- showCursor && (React.createElement(Text, { backgroundColor: "white", color: "black" }, cursorChar)),
90
- !showCursor && cursorChar !== " " && cursorChar,
91
- afterCursorText)))));
17
+ const placeholder = mode === 'plan' ? 'Describe what you want to plan…'
18
+ : mode === 'ask' ? 'Ask a question…'
19
+ : busy ? 'Write a follow-up while I work…' : 'Describe a task, or type / for commands…';
20
+ return (React.createElement(Box, { flexDirection: "column", borderStyle: "round", borderColor: busy ? colors.borderBusy : colors.borderActive, paddingX: 1, marginTop: 1 },
21
+ React.createElement(Box, { justifyContent: "space-between" },
22
+ React.createElement(Text, { bold: true, color: colors.primary }, mode === 'plan' ? 'Plan' : mode === 'ask' ? 'Question' : 'Message'),
23
+ React.createElement(Text, { color: colors.textMuted },
24
+ busy ? 'Draft · working' : 'Ready',
25
+ viewport.lines.length > 1 ? ` · ${viewport.lines.length} lines` : '')),
26
+ viewport.start > 0 && React.createElement(Text, { dimColor: true },
27
+ "\u2026 ",
28
+ viewport.start,
29
+ " lines above"),
30
+ viewport.visible.map((line, index) => {
31
+ const active = viewport.start + index === viewport.row;
32
+ const char = Array.from(line.slice(viewport.column))[0] || ' ';
33
+ return (React.createElement(Box, { key: viewport.start + index },
34
+ React.createElement(Text, { color: colors.primary }, active ? '❯ ' : ' '),
35
+ !input ? (React.createElement(Text, null,
36
+ React.createElement(Text, { inverse: true }, " "),
37
+ React.createElement(Text, { dimColor: true }, placeholder))) : active ? (React.createElement(Text, null,
38
+ line.slice(0, viewport.column),
39
+ React.createElement(Text, { inverse: true }, char),
40
+ line.slice(viewport.column + char.length))) : React.createElement(Text, null, line || ' ')));
41
+ }),
42
+ viewport.start + 6 < viewport.lines.length && React.createElement(Text, { dimColor: true },
43
+ "\u2026 ",
44
+ viewport.lines.length - viewport.start - 6,
45
+ " lines below")));
92
46
  });
93
47
  //# sourceMappingURL=ChatInput.js.map
@@ -1,8 +1,10 @@
1
1
  import React from "react";
2
- import type { CodeBuddyAgent } from "../../agent/codebuddy-agent.js";
2
+ import type { CodeBuddyAgent, ChatEntry } from "../../agent/codebuddy-agent.js";
3
3
  interface ChatInterfaceProps {
4
4
  agent?: CodeBuddyAgent;
5
5
  initialMessage?: string;
6
+ /** History of a resumed session, shown before the first new turn. */
7
+ initialHistory?: ChatEntry[];
6
8
  }
7
- export default function ChatInterface({ agent, initialMessage, }: ChatInterfaceProps): React.JSX.Element;
9
+ export default function ChatInterface({ agent, initialMessage, initialHistory, }: ChatInterfaceProps): React.JSX.Element;
8
10
  export {};
@@ -12,20 +12,18 @@ import { MCPStatus } from "./McpStatus.js";
12
12
  import ConfirmationDialog from "./ConfirmationDialog.js";
13
13
  import { ConfirmationService, } from "../../utils/confirmation-service.js";
14
14
  import ApiKeyInput from "./ApiKeyInput.js";
15
- import { renderColorBanner } from "../../utils/ascii-banner.js";
16
15
  import { ThemeProvider, useTheme } from "../context/theme-context.js";
17
16
  import { getErrorMessage } from "../../types/index.js";
18
17
  import { MiniStatusBar } from "./StatusBar.js";
19
- import { KeyboardHelp, useKeyboardHelp, KeyboardHelpButton } from "./KeyboardHelp.js";
18
+ import { KeyboardHelp, useKeyboardHelp } from "./KeyboardHelp.js";
20
19
  import { ToastProvider } from "./ToastNotifications.js";
21
- import { logger } from "../../utils/logger.js";
22
20
  import { getTTSManager } from "../../input/text-to-speech.js";
23
21
  import { announceToScreenReader, useAccessibilitySettings, useKeyboardShortcuts, } from "../utils/accessibility.js";
24
22
  // Main chat component that handles input when agent is available
25
- function ChatInterfaceWithAgent({ agent, initialMessage, }) {
26
- const { colors, theme } = useTheme();
23
+ function ChatInterfaceWithAgent({ agent, initialMessage, initialHistory, }) {
24
+ const { colors } = useTheme();
27
25
  const { settings } = useAccessibilitySettings();
28
- const [chatHistory, setChatHistory] = useState([]);
26
+ const [chatHistory, setChatHistory] = useState(() => initialHistory ?? []);
29
27
  const [isProcessing, setIsProcessing] = useState(false);
30
28
  const [processingTime, setProcessingTime] = useState(0);
31
29
  const [tokenCount, setTokenCount] = useState(0);
@@ -98,7 +96,7 @@ function ChatInterfaceWithAgent({ agent, initialMessage, }) {
98
96
  return prev;
99
97
  });
100
98
  }, []);
101
- const { input, cursorPosition, showCommandSuggestions, selectedCommandIndex, showModelSelection, selectedModelIndex, showFileAutocomplete, selectedFileIndex, fileSuggestions, commandSuggestions, availableModels, autoEditEnabled, handleInputSubmit, } = useInputHandler({
99
+ const { input, cursorPosition, showCommandSuggestions, selectedCommandIndex, showModelSelection, selectedModelIndex, showFileAutocomplete, selectedFileIndex, fileSuggestions, commandSuggestions, availableModels, autoEditEnabled, queuedMessageCount, handleInputSubmit, } = useInputHandler({
102
100
  agent,
103
101
  chatHistory,
104
102
  setChatHistory,
@@ -110,39 +108,15 @@ function ChatInterfaceWithAgent({ agent, initialMessage, }) {
110
108
  processingStartTime,
111
109
  isProcessing,
112
110
  isStreaming,
113
- isConfirmationActive: !!confirmationOptions,
111
+ isConfirmationActive: !!confirmationOptions || !!pendingQuestion || keyboardHelp.isVisible,
114
112
  appendStreamingContent,
115
113
  finalizeStreamingEntry,
116
114
  updateToolCallEntry,
117
115
  });
118
116
  useEffect(() => {
119
- // Only clear console on non-Windows platforms or if not PowerShell
120
- // Windows PowerShell can have issues with console.clear() causing flickering
121
- const isWindows = process.platform === "win32";
122
- const isPowerShell = process.env.ComSpec?.toLowerCase().includes("powershell") ||
123
- process.env.PSModulePath !== undefined;
124
- if (!isWindows || !isPowerShell) {
125
- process.stdout.write('\x1b[2J\x1b[0f'); // ANSI escape code to clear screen
126
- }
127
- // Add top padding
128
- logger.info(" ");
129
- // Generate logo with MIT-licensed ascii-banner (replaces GPL cfonts)
130
- const logoOutput = renderColorBanner("CODE BUDDY", ["magenta", "cyan"]);
131
- // Add horizontal margin (2 spaces) to match Ink paddingX={2}
132
- const logoLines = logoOutput.split("\n");
133
- logoLines.forEach((line) => {
134
- if (line.trim()) {
135
- logger.info(" " + line); // Add 2 spaces for horizontal margin
136
- }
137
- else {
138
- logger.info(line); // Keep empty lines as-is
139
- }
140
- });
141
- logger.info(" "); // Spacing after logo
142
- setChatHistory([]);
143
117
  // Announce to screen readers
144
118
  if (settings.screenReader) {
145
- announceToScreenReader('Code Buddy started. Chat interface ready. Press Ctrl+H for help.', 'polite');
119
+ announceToScreenReader('Code Buddy started. Chat interface ready. Type /help for commands.', 'polite');
146
120
  }
147
121
  }, [settings.screenReader]);
148
122
  // Process initial message if provided (streaming for faster feedback)
@@ -371,6 +345,7 @@ function ChatInterfaceWithAgent({ agent, initialMessage, }) {
371
345
  announceToScreenReader(`Error occurred: ${errorMessage}`, 'assertive');
372
346
  }
373
347
  }
348
+ await agent.persistInteractiveSession();
374
349
  setIsProcessing(false);
375
350
  processingStartTime.current = 0;
376
351
  };
@@ -422,53 +397,42 @@ function ChatInterfaceWithAgent({ agent, initialMessage, }) {
422
397
  }
423
398
  };
424
399
  return (React.createElement(Box, { flexDirection: "column", paddingX: 2 },
425
- chatHistory.length === 0 && !confirmationOptions && (React.createElement(Box, { flexDirection: "column", marginBottom: 2 },
426
- React.createElement(Text, { color: colors.primary, bold: true }, "Tips for getting started:"),
427
- React.createElement(Box, { marginTop: 1, flexDirection: "column" },
428
- React.createElement(Text, { color: colors.textMuted }, "1. Ask questions, edit files, or run commands."),
429
- React.createElement(Text, { color: colors.textMuted }, "2. Be specific for the best results."),
430
- React.createElement(Text, { color: colors.textMuted }, "3. Create CODEBUDDY.md files to customize your interactions with Code Buddy."),
431
- React.createElement(Text, { color: colors.textMuted }, "4. Press Shift+Tab to toggle auto-edit mode."),
432
- React.createElement(Text, { color: colors.textMuted }, "5. /help for more information."),
433
- React.createElement(Text, { color: colors.textMuted }, "6. /theme to change the theme, /avatar to change avatars.")),
434
- React.createElement(Box, { marginTop: 1 },
435
- React.createElement(KeyboardHelpButton, null)))),
436
- React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
437
- React.createElement(Text, { color: colors.textMuted }, "Type your request in natural language. Ctrl+C to clear, 'exit' to quit.")),
400
+ chatHistory.length === 0 && !confirmationOptions && (React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
401
+ React.createElement(Text, { bold: true, color: colors.primary }, "Code Buddy"),
402
+ React.createElement(Text, { color: colors.textMuted, wrap: "truncate-middle" }, process.cwd()),
403
+ React.createElement(Text, { color: colors.textMuted }, "Ask a question or describe a change. /help commands \u00B7 /model choose a model"))),
438
404
  React.createElement(Box, { flexDirection: "column", ref: scrollRef },
439
405
  React.createElement(ChatHistory, { entries: chatHistory, isConfirmationActive: !!confirmationOptions })),
440
406
  pendingQuestion && (React.createElement(TabbedQuestion, { question: pendingQuestion.question, options: pendingQuestion.options, onAnswer: (answer) => {
441
407
  pendingQuestion.resolve(answer);
442
408
  } })),
443
409
  confirmationOptions && (React.createElement(ConfirmationDialog, { operation: confirmationOptions.operation, filename: confirmationOptions.filename, showVSCodeOpen: confirmationOptions.showVSCodeOpen, content: confirmationOptions.content, onConfirm: handleConfirmation, onReject: handleRejection })),
444
- !confirmationOptions && (React.createElement(React.Fragment, null,
410
+ !confirmationOptions && !pendingQuestion && !keyboardHelp.isVisible && (React.createElement(React.Fragment, null,
445
411
  React.createElement(StatusBlock, { isActive: isProcessing || isStreaming, processingTime: processingTime, tokenCount: tokenCount, activity: currentActivity }),
412
+ queuedMessageCount > 0 && React.createElement(Text, { color: colors.info },
413
+ queuedMessageCount,
414
+ " message(s) queued \u00B7 sent after the current reply"),
446
415
  React.createElement(ChatInput, { input: input, cursorPosition: cursorPosition, isProcessing: isProcessing, isStreaming: isStreaming, mode: agent.getMode() }),
447
- React.createElement(Box, { flexDirection: "row", marginTop: 1, justifyContent: "space-between" },
448
- React.createElement(Box, { flexDirection: "row" },
416
+ React.createElement(Text, { color: colors.textMuted, dimColor: true },
417
+ isProcessing || isStreaming ? 'Enter queue' : 'Enter send',
418
+ " \u00B7 Ctrl+J newline \u00B7 Esc cancel \u00B7 Ctrl+C quit"),
419
+ React.createElement(Box, { flexDirection: "row", flexWrap: "wrap", marginTop: 1, justifyContent: "space-between" },
420
+ React.createElement(Box, { flexDirection: "row", flexWrap: "wrap" },
449
421
  React.createElement(Box, { marginRight: 2 },
450
- React.createElement(Text, { color: colors.primary },
451
- autoEditEnabled ? "▶" : "⏸",
452
- " auto-edit:",
453
- " ",
454
- autoEditEnabled ? "on" : "off"),
422
+ React.createElement(Text, { color: colors.primary }, autoEditEnabled ? "Edits: automatic" : "Edits: ask first"),
455
423
  React.createElement(Text, { color: colors.textMuted, dimColor: true },
456
424
  " ",
457
425
  "(shift + tab)")),
458
- React.createElement(Box, { marginRight: 2 },
459
- React.createElement(Text, { color: colors.secondary },
460
- "\u25D0 ",
461
- theme.name)),
462
426
  React.createElement(MCPStatus, null)),
463
427
  React.createElement(Box, null,
464
- React.createElement(MiniStatusBar, { tokenCount: tokenCount, modelName: agent.getCurrentModel(), mode: agent.getMode(), yolo: agent.isYoloModeEnabled() }))),
428
+ React.createElement(MiniStatusBar, { tokenCount: tokenCount, modelName: agent.getCurrentModel(), providerName: agent.getClient().getProviderName(), mode: agent.getMode(), yolo: agent.isYoloModeEnabled() }))),
465
429
  React.createElement(CommandSuggestions, { suggestions: commandSuggestions, input: input, selectedIndex: selectedCommandIndex, isVisible: showCommandSuggestions }),
466
430
  React.createElement(FileAutocomplete, { input: input, visible: showFileAutocomplete, selectedIndex: selectedFileIndex, suggestions: fileSuggestions }),
467
431
  React.createElement(ModelSelection, { models: availableModels, selectedIndex: selectedModelIndex, isVisible: showModelSelection, currentModel: agent.getCurrentModel() }))),
468
432
  React.createElement(KeyboardHelp, { isVisible: keyboardHelp.isVisible, onClose: keyboardHelp.hide })));
469
433
  }
470
434
  // Inner component that handles API key input or chat interface
471
- function ChatInterfaceInner({ agent, initialMessage, }) {
435
+ function ChatInterfaceInner({ agent, initialMessage, initialHistory, }) {
472
436
  const [currentAgent, setCurrentAgent] = useState(agent || null);
473
437
  const handleApiKeySet = (newAgent) => {
474
438
  setCurrentAgent(newAgent);
@@ -476,12 +440,12 @@ function ChatInterfaceInner({ agent, initialMessage, }) {
476
440
  if (!currentAgent) {
477
441
  return React.createElement(ApiKeyInput, { onApiKeySet: handleApiKeySet });
478
442
  }
479
- return (React.createElement(ChatInterfaceWithAgent, { agent: currentAgent, initialMessage: initialMessage }));
443
+ return (React.createElement(ChatInterfaceWithAgent, { agent: currentAgent, initialMessage: initialMessage, initialHistory: initialHistory }));
480
444
  }
481
445
  // Main component wrapped with ThemeProvider and ToastProvider
482
- export default function ChatInterface({ agent, initialMessage, }) {
446
+ export default function ChatInterface({ agent, initialMessage, initialHistory, }) {
483
447
  return (React.createElement(ThemeProvider, null,
484
448
  React.createElement(ToastProvider, null,
485
- React.createElement(ChatInterfaceInner, { agent: agent, initialMessage: initialMessage }))));
449
+ React.createElement(ChatInterfaceInner, { agent: agent, initialMessage: initialMessage, initialHistory: initialHistory }))));
486
450
  }
487
451
  //# sourceMappingURL=ChatInterface.js.map
@@ -10,7 +10,6 @@ interface CommandSuggestionsProps {
10
10
  selectedIndex: number;
11
11
  isVisible: boolean;
12
12
  }
13
- export declare const MAX_SUGGESTIONS = 15;
14
13
  export declare const VISIBLE_SUGGESTIONS = 10;
15
14
  export declare function filterCommandSuggestions<T extends {
16
15
  command: string;
@@ -1,7 +1,6 @@
1
1
  import React, { useMemo } from "react";
2
2
  import { Box, Text } from "ink";
3
3
  import { getSlashCommandManager } from "../../commands/slash-commands.js";
4
- export const MAX_SUGGESTIONS = 15;
5
4
  export const VISIBLE_SUGGESTIONS = 10;
6
5
  /**
7
6
  * Get argument suggestions for a command
@@ -50,7 +49,7 @@ export function filterCommandSuggestions(suggestions, input) {
50
49
  const currentArg = parts.length > 1 ? parts.slice(1).join(' ') : '';
51
50
  const argSuggestions = getArgumentSuggestions(command, currentArg);
52
51
  if (argSuggestions.length > 0) {
53
- return argSuggestions.slice(0, MAX_SUGGESTIONS);
52
+ return argSuggestions;
54
53
  }
55
54
  }
56
55
  }
@@ -72,11 +71,10 @@ export function filterCommandSuggestions(suggestions, input) {
72
71
  return -1;
73
72
  return aIndex - bIndex;
74
73
  });
75
- return sorted.slice(0, MAX_SUGGESTIONS);
74
+ return sorted;
76
75
  }
77
76
  return suggestions
78
- .filter((s) => s.command.toLowerCase().startsWith(lowerInput))
79
- .slice(0, MAX_SUGGESTIONS);
77
+ .filter((s) => s.command.toLowerCase().startsWith(lowerInput));
80
78
  }
81
79
  // Memoized individual suggestion item
82
80
  const SuggestionItem = React.memo(function SuggestionItem({ command, description, isSelected, isArgument, }) {
@@ -126,7 +124,7 @@ export const CommandSuggestions = React.memo(function CommandSuggestions({ sugge
126
124
  " more below..."))),
127
125
  React.createElement(Box, { marginTop: 1 },
128
126
  React.createElement(Text, { color: "gray", dimColor: true },
129
- "\u2191\u2193 navigate \u2022 Enter/Tab select \u2022 Esc cancel \u2022 ",
127
+ "\u2191\u2193 navigate \u2022 \u2192/Tab complete \u2022 Enter run \u2022 Esc close \u2022 ",
130
128
  totalMatches,
131
129
  "/",
132
130
  totalCommands,
@@ -211,7 +211,7 @@ export const FileAutocomplete = React.memo(function FileAutocomplete({ input, vi
211
211
  return null;
212
212
  }
213
213
  return (React.createElement(Box, { flexDirection: "column", borderStyle: "round", borderColor: colors.borderActive, marginTop: 1, paddingX: 1 },
214
- React.createElement(Text, { color: colors.textMuted, dimColor: true }, "File suggestions (Tab to select):"),
214
+ React.createElement(Text, { color: colors.textMuted, dimColor: true }, "File suggestions (\u2192/Tab complete, Enter select):"),
215
215
  suggestions.map((suggestion, index) => {
216
216
  const isSelected = index === selectedIndex;
217
217
  const icon = getFileIcon(suggestion);
@@ -19,7 +19,9 @@ const KEYBOARD_SHORTCUTS = [
19
19
  { keys: 'Tab', description: 'Autocomplete command', category: 'Navigation' },
20
20
  { keys: 'Shift+Tab', description: 'Toggle auto-edit mode', category: 'Navigation' },
21
21
  // Editing
22
- { keys: 'Ctrl+C', description: 'Clear current input / Interrupt', category: 'Editing' },
22
+ { keys: 'Ctrl+C', description: 'Quit Code Buddy', category: 'Session' },
23
+ { keys: 'Ctrl+J', description: 'Insert a new line', category: 'Editing' },
24
+ { keys: 'Enter', description: 'Send message (queue while working)', category: 'Editing' },
23
25
  { keys: 'Ctrl+U', description: 'Clear line', category: 'Editing' },
24
26
  { keys: 'Ctrl+W', description: 'Delete word', category: 'Editing' },
25
27
  { keys: 'Ctrl+K', description: 'Delete to end of line', category: 'Editing' },
@@ -31,7 +33,7 @@ const KEYBOARD_SHORTCUTS = [
31
33
  { keys: '/review', description: 'Code review', category: 'Tools' },
32
34
  { keys: '/test', description: 'Run tests', category: 'Tools' },
33
35
  // View
34
- { keys: '?', description: 'Toggle this help', category: 'View' },
36
+ { keys: '/help', description: 'Show help', category: 'View' },
35
37
  { keys: '/theme', description: 'Change theme', category: 'View' },
36
38
  { keys: '/avatar', description: 'Change avatars', category: 'View' },
37
39
  { keys: '/stats', description: 'Show statistics', category: 'View' },
@@ -70,7 +72,7 @@ export function KeyboardHelp({ isVisible, onClose, categories, }) {
70
72
  if (input === '?' || key.escape || key.return) {
71
73
  onClose();
72
74
  }
73
- });
75
+ }, { isActive: isVisible });
74
76
  if (!isVisible)
75
77
  return null;
76
78
  // Filter shortcuts by category if specified
@@ -138,9 +140,9 @@ export function KeyboardHelpButton() {
138
140
  const { colors } = useTheme();
139
141
  return (React.createElement(Box, null,
140
142
  React.createElement(Text, { dimColor: true },
141
- "Press ",
142
- React.createElement(Text, { bold: true, color: colors.accent }, "?"),
143
- " for help")));
143
+ "Type ",
144
+ React.createElement(Text, { bold: true, color: colors.accent }, "/help"),
145
+ " for commands")));
144
146
  }
145
147
  export default KeyboardHelp;
146
148
  //# sourceMappingURL=KeyboardHelp.js.map
@@ -1,4 +1,4 @@
1
- import React, { useMemo } from 'react';
1
+ import React from 'react';
2
2
  import { Box, Text } from 'ink';
3
3
  // Memoized individual model item to prevent re-renders
4
4
  const ModelItem = React.memo(function ModelItem({ model, isSelected, }) {
@@ -9,13 +9,14 @@ export const ModelSelection = React.memo(function ModelSelection({ models, selec
9
9
  // Early return for invisible state
10
10
  if (!isVisible)
11
11
  return null;
12
- // Memoize header text to prevent re-computation
13
- const headerText = useMemo(() => `Select Grok Model (current: ${currentModel}):`, [currentModel]);
12
+ const headerText = `Select model (current: ${currentModel}):`;
13
+ const start = Math.max(0, Math.min(selectedIndex - 4, models.length - 8));
14
+ const visibleModels = models.slice(start, start + 8);
14
15
  return (React.createElement(Box, { marginTop: 1, flexDirection: "column" },
15
16
  React.createElement(Box, { marginBottom: 1 },
16
17
  React.createElement(Text, { color: "cyan" }, headerText)),
17
- models.map((modelOption, index) => (React.createElement(ModelItem, { key: modelOption.model, model: modelOption.model, isSelected: index === selectedIndex }))),
18
+ visibleModels.map((modelOption, index) => (React.createElement(ModelItem, { key: modelOption.model, model: modelOption.model, isSelected: start + index === selectedIndex }))),
18
19
  React.createElement(Box, { marginTop: 1 },
19
- React.createElement(Text, { color: "gray", dimColor: true }, "\u2191\u2193 navigate \u2022 Enter/Tab select \u2022 Esc cancel"))));
20
+ React.createElement(Text, { color: "gray", dimColor: true }, "\u2191\u2193 navigate \u2022 \u2192/Enter select \u2022 \u2190/Esc cancel"))));
20
21
  });
21
22
  //# sourceMappingURL=ModelSelection.js.map
@@ -45,10 +45,11 @@ export declare function StatusBar({ tokenCount, maxTokens, cost, budget, modelNa
45
45
  /**
46
46
  * Mini Status Bar - For inline display in chat interface
47
47
  */
48
- export declare function MiniStatusBar({ tokenCount, cost, modelName, mode, yolo, }: {
48
+ export declare function MiniStatusBar({ tokenCount, cost, modelName, providerName, mode, yolo, }: {
49
49
  tokenCount: number;
50
50
  cost?: number;
51
51
  modelName?: string;
52
+ providerName?: string;
52
53
  mode?: string;
53
54
  yolo?: boolean;
54
55
  }): React.JSX.Element;
@@ -256,16 +256,17 @@ export function StatusBar({ tokenCount, maxTokens = 128000, cost = 0, budget = 1
256
256
  /**
257
257
  * Mini Status Bar - For inline display in chat interface
258
258
  */
259
- export function MiniStatusBar({ tokenCount, cost, modelName, mode = 'code', yolo = false, }) {
259
+ export function MiniStatusBar({ tokenCount, cost, modelName, providerName, mode = 'code', yolo = false, }) {
260
260
  const { colors } = useTheme();
261
- return (React.createElement(Box, null,
262
- mode && (React.createElement(Text, { color: mode === 'plan' ? colors.info : colors.primary }, mode === 'plan' ? '📋' : mode === 'ask' ? '❓' : '💻')),
263
- yolo && React.createElement(Text, { color: colors.error }, " \uD83D\uDD25"),
261
+ return (React.createElement(Box, { flexWrap: "wrap" },
262
+ mode && (React.createElement(Text, { color: mode === 'plan' ? colors.info : colors.primary }, mode)),
263
+ yolo && React.createElement(Text, { color: colors.error }, " \u00B7 YOLO"),
264
264
  React.createElement(Text, { dimColor: true }, " \u2022 "),
265
+ providerName && React.createElement(Text, { color: colors.textMuted },
266
+ providerName,
267
+ " \u00B7 "),
265
268
  modelName && (React.createElement(React.Fragment, null,
266
- React.createElement(Text, { color: colors.accent },
267
- "\u224B ",
268
- modelName),
269
+ React.createElement(Text, { bold: true, color: colors.accent }, modelName),
269
270
  React.createElement(Text, { dimColor: true }, " \u2022 "))),
270
271
  React.createElement(Text, { color: colors.info },
271
272
  "\u2191 ",
@@ -2,7 +2,7 @@
2
2
  * Theme Context for Code Buddy
3
3
  * Provides theme and avatar information to all UI components
4
4
  */
5
- import React, { createContext, useContext, useState, useCallback, useMemo } from 'react';
5
+ import React, { createContext, useContext, useState, useCallback, useMemo, useSyncExternalStore } from 'react';
6
6
  import { getThemeManager } from '../../themes/theme-manager.js';
7
7
  /**
8
8
  * Create the theme context
@@ -14,6 +14,7 @@ const ThemeContext = createContext(null);
14
14
  export function ThemeProvider({ children }) {
15
15
  const [themeManager] = useState(() => getThemeManager());
16
16
  const [refreshKey, setRefreshKey] = useState(0);
17
+ const revision = useSyncExternalStore(themeManager.subscribe, themeManager.getSnapshot, themeManager.getSnapshot);
17
18
  // Force re-render when theme changes
18
19
  const refreshTheme = useCallback(() => {
19
20
  setRefreshKey(prev => prev + 1);
@@ -77,7 +78,7 @@ export function ThemeProvider({ children }) {
77
78
  clearCustomColors,
78
79
  refreshTheme,
79
80
  }), [
80
- theme, colors, avatars, refreshKey,
81
+ theme, colors, avatars, refreshKey, revision,
81
82
  setTheme, getAvailableThemes, setAvatarPreset,
82
83
  setCustomAvatar, clearCustomAvatars, getAvatarPresets,
83
84
  setCustomColor, clearCustomColors, refreshTheme
@@ -4,7 +4,7 @@
4
4
  export { SectionHeader, StatusWithText, AccessibleProgress, KeyboardShortcut, HelpPanel, AccessibleList, DefinitionList, Announcement, AccessibleError, AccessibleSuccess, AccessibleTable, AccessibleCodeBlock, Divider, } from "./components/AccessibleOutput.js";
5
5
  export { ChatHistory } from "./components/ChatHistory.js";
6
6
  export { ChatInput } from "./components/ChatInput.js";
7
- export { MAX_SUGGESTIONS, VISIBLE_SUGGESTIONS, filterCommandSuggestions, CommandSuggestions, } from "./components/CommandSuggestions.js";
7
+ export { VISIBLE_SUGGESTIONS, filterCommandSuggestions, CommandSuggestions, } from "./components/CommandSuggestions.js";
8
8
  export { parseDiffWithLineNumbers, DiffRenderer, } from "./components/DiffRenderer.js";
9
9
  export { EnhancedChatInput, useInputHistory, } from "./components/EnhancedChatInput.js";
10
10
  export { EnhancedConfirmationDialog, type OperationType, } from "./components/EnhancedConfirmationDialog.js";
package/dist/ui/index.js CHANGED
@@ -11,7 +11,7 @@ export { ChatHistory } from "./components/ChatHistory.js";
11
11
  export { ChatInput } from "./components/ChatInput.js";
12
12
  // ChatInterface (only has default export, not re-exported by barrel)
13
13
  // To use: import ChatInterface from './ui/components/ChatInterface.js'
14
- export { MAX_SUGGESTIONS, VISIBLE_SUGGESTIONS, filterCommandSuggestions, CommandSuggestions, } from "./components/CommandSuggestions.js";
14
+ export { VISIBLE_SUGGESTIONS, filterCommandSuggestions, CommandSuggestions, } from "./components/CommandSuggestions.js";
15
15
  // ConfirmationDialog (only has default export, not re-exported by barrel)
16
16
  // To use: import ConfirmationDialog from './ui/components/ConfirmationDialog.js'
17
17
  export { parseDiffWithLineNumbers, DiffRenderer, } from "./components/DiffRenderer.js";
@@ -74,19 +74,10 @@ marked.setOptions({
74
74
  },
75
75
  // Inline code styling
76
76
  codespan: (text) => `${ANSI.cyan}${text}${ANSI.reset}`,
77
- // Heading styles by level
78
- heading: (text, level) => {
79
- const colors = [
80
- ANSI.magentaBold,
81
- ANSI.blueBold,
82
- ANSI.yellowBold,
83
- ANSI.blue,
84
- ANSI.yellow,
85
- ANSI.white,
86
- ];
87
- const color = colors[Math.min(level - 1, colors.length - 1)];
88
- return `\n${color}${'#'.repeat(level)} ${text}${ANSI.reset}\n`;
89
- },
77
+ // marked-terminal supplies styled text only here (including its prefix),
78
+ // unlike a marked renderer method, which also receives the heading level.
79
+ heading: (text) => `${ANSI.blueBold}${text}${ANSI.reset}`,
80
+ firstHeading: (text) => `${ANSI.magentaBold}${text}${ANSI.reset}`,
90
81
  // Text emphasis
91
82
  strong: (text) => `${ANSI.bold}${text}${ANSI.reset}`,
92
83
  em: (text) => `${ANSI.italic}${text}${ANSI.reset}`,
@@ -51,6 +51,28 @@ export declare function readTextAtomic(filePath: string, fallback: string, optio
51
51
  export declare function readJsonLinesAtomic<T>(filePath: string, fallback: T[], isValid: (value: unknown) => value is T): Promise<T[]>;
52
52
  /** Reset the process-local warning guard; intended for isolated tests. */
53
53
  export declare function resetAtomicReadWarningsForTests(): void;
54
+ /**
55
+ * Outcome of a strictly read-only JSON read. `missing` is normal (no file);
56
+ * `corrupt` means the file exists but is empty or not valid JSON; `unreadable`
57
+ * means the file exists but could not be read (permissions, EISDIR, ...).
58
+ */
59
+ export type ReadOnlyJsonOutcome<T> = {
60
+ status: 'ok';
61
+ value: T;
62
+ } | {
63
+ status: 'missing';
64
+ } | {
65
+ status: 'corrupt';
66
+ } | {
67
+ status: 'unreadable';
68
+ };
69
+ /**
70
+ * Strictly read-only JSON reader for diagnostics. Never restores, renames,
71
+ * chmods, creates, or writes anything — not the primary file, not `.bak`,
72
+ * not `.tmp.*`. Never consults recovery candidates. Callers that need the
73
+ * historical recovery policy must keep using `readJsonAtomicSync`.
74
+ */
75
+ export declare function readJsonAtomicSyncReadOnly<T>(filePath: string, isValid?: (value: unknown) => value is T): ReadOnlyJsonOutcome<T>;
54
76
  export interface CleanupOrphanedTemporariesOptions extends AtomicWriteOptions {
55
77
  /**
56
78
  * A temporary older than this (in ms) is considered orphaned and removed.