@phuetz/code-buddy 2.0.0 → 2.2.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 (421) hide show
  1. package/README.fr.md +56 -0
  2. package/README.md +74 -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 +176 -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.d.ts +7 -0
  13. package/dist/agent/execution/tool-selection-strategy.js +32 -2
  14. package/dist/agent/facades/session-facade.d.ts +0 -6
  15. package/dist/agent/facades/session-facade.js +0 -45
  16. package/dist/agent/hermes-claw-migrate.d.ts +0 -21
  17. package/dist/agent/hermes-claw-migrate.js +9 -4
  18. package/dist/agent/hermes-protocol-gateways.js +8 -1
  19. package/dist/agent/repo-profiler.js +17 -4
  20. package/dist/agent/self-improvement/authored-tool-runtime.js +10 -2
  21. package/dist/agent/self-improvement/evolution/ast-novelty.d.ts +5 -0
  22. package/dist/agent/self-improvement/evolution/ast-novelty.js +58 -23
  23. package/dist/agent/self-improvement/evolution/code-variant-store.d.ts +3 -0
  24. package/dist/agent/self-improvement/evolution/evolution-engine.js +2 -0
  25. package/dist/agent/self-improvement/evolution/protected-paths.js +6 -0
  26. package/dist/agent/self-improvement/evolution/variant-fitness.d.ts +13 -2
  27. package/dist/agent/self-improvement/evolution/variant-fitness.js +184 -58
  28. package/dist/agent/self-improvement/evolution/worktree-scorer.d.ts +2 -0
  29. package/dist/agent/self-improvement/evolution/worktree-scorer.js +15 -0
  30. package/dist/agent/self-improvement/evolutionary-archive.d.ts +2 -1
  31. package/dist/agent/self-improvement/evolutionary-archive.js +34 -5
  32. package/dist/agent/self-improvement/proposal-store.d.ts +1 -0
  33. package/dist/agent/self-improvement/proposal-store.js +79 -17
  34. package/dist/agent/self-improvement/skill-apply-journal.d.ts +44 -0
  35. package/dist/agent/self-improvement/skill-apply-journal.js +178 -0
  36. package/dist/agent/self-improvement/skill-behavior-benchmark.d.ts +3 -0
  37. package/dist/agent/self-improvement/skill-behavior-benchmark.js +19 -0
  38. package/dist/agent/self-improvement/skill-behavior-gate.d.ts +34 -0
  39. package/dist/agent/self-improvement/skill-behavior-gate.js +96 -0
  40. package/dist/agent/self-improvement/skill-engine.d.ts +22 -0
  41. package/dist/agent/self-improvement/skill-engine.js +385 -13
  42. package/dist/agent/self-improvement/skill-gate.d.ts +2 -0
  43. package/dist/agent/self-improvement/skill-gate.js +17 -2
  44. package/dist/agent/self-improvement/skill-mutator.d.ts +6 -1
  45. package/dist/agent/self-improvement/skill-mutator.js +51 -15
  46. package/dist/agent/self-improvement/skill-types.d.ts +2 -1
  47. package/dist/agent/self-improvement/types.d.ts +11 -0
  48. package/dist/agent/tool-handler.d.ts +1 -1
  49. package/dist/agent/tool-handler.js +28 -9
  50. package/dist/auth/profile-manager.js +1 -1
  51. package/dist/channels/companion-channel-turn.d.ts +53 -4
  52. package/dist/channels/companion-channel-turn.js +218 -16
  53. package/dist/channels/slash-parity.d.ts +4 -6
  54. package/dist/channels/slash-parity.js +9 -44
  55. package/dist/cli/session-commands.d.ts +9 -0
  56. package/dist/cli/session-commands.js +45 -5
  57. package/dist/cli/session-picker.d.ts +43 -0
  58. package/dist/cli/session-picker.js +128 -0
  59. package/dist/codebuddy/a2a-call-tool-defs.d.ts +26 -0
  60. package/dist/codebuddy/a2a-call-tool-defs.js +12 -0
  61. package/dist/codebuddy/fleet-tool-defs.d.ts +2 -0
  62. package/dist/codebuddy/fleet-tool-defs.js +55 -0
  63. package/dist/codebuddy/providers/chatgpt-headers.d.ts +18 -0
  64. package/dist/codebuddy/providers/chatgpt-headers.js +37 -0
  65. package/dist/codebuddy/providers/provider-chatgpt-responses.d.ts +2 -1
  66. package/dist/codebuddy/providers/provider-chatgpt-responses.js +10 -23
  67. package/dist/codebuddy/providers/provider-openai-compat.d.ts +7 -0
  68. package/dist/codebuddy/providers/provider-openai-compat.js +29 -1
  69. package/dist/codebuddy/ragchat-tool-defs.d.ts +31 -0
  70. package/dist/codebuddy/ragchat-tool-defs.js +19 -0
  71. package/dist/codebuddy/resource-catalog-tool-defs.d.ts +28 -0
  72. package/dist/codebuddy/resource-catalog-tool-defs.js +18 -0
  73. package/dist/codebuddy/tool-definitions/agent-tools.js +2 -2
  74. package/dist/codebuddy/tool-definitions/code-exec-tools.js +5 -1
  75. package/dist/codebuddy/tool-definitions/cron-tools.js +6 -0
  76. package/dist/codebuddy/tool-definitions/self-describe-tools.js +6 -1
  77. package/dist/codebuddy/tools.d.ts +0 -6
  78. package/dist/codebuddy/tools.js +25 -3
  79. package/dist/commands/cli/daemon-commands.js +3 -1
  80. package/dist/commands/cli/evolve-command.js +21 -5
  81. package/dist/commands/cli/fleet-collaboration-commands.d.ts +2 -0
  82. package/dist/commands/cli/fleet-collaboration-commands.js +57 -0
  83. package/dist/commands/cli/fleet-commands.js +29 -0
  84. package/dist/commands/cli/fleet-mission-commands.d.ts +3 -0
  85. package/dist/commands/cli/fleet-mission-commands.js +72 -0
  86. package/dist/commands/cli/fleet-rooms-commands.d.ts +10 -0
  87. package/dist/commands/cli/fleet-rooms-commands.js +289 -0
  88. package/dist/commands/cli/tools-commands.js +2 -1
  89. package/dist/commands/cli/triage-command.d.ts +8 -0
  90. package/dist/commands/cli/triage-command.js +72 -0
  91. package/dist/commands/cli/utility-commands.js +25 -1
  92. package/dist/commands/client-dispatcher.d.ts +7 -0
  93. package/dist/commands/client-dispatcher.js +73 -21
  94. package/dist/commands/cron-cli/index.d.ts +3 -1
  95. package/dist/commands/cron-cli/index.js +25 -0
  96. package/dist/commands/device-auth.d.ts +10 -0
  97. package/dist/commands/device-auth.js +91 -0
  98. package/dist/commands/enhanced-command-handler.d.ts +9 -0
  99. package/dist/commands/enhanced-command-handler.js +28 -6
  100. package/dist/commands/handlers/agent-handlers.d.ts +1 -1
  101. package/dist/commands/handlers/agent-handlers.js +4 -4
  102. package/dist/commands/handlers/channel-handlers.js +53 -2
  103. package/dist/commands/handlers/export-handlers.d.ts +3 -2
  104. package/dist/commands/handlers/export-handlers.js +55 -28
  105. package/dist/commands/handlers/extra-handlers.js +5 -1
  106. package/dist/commands/handlers/grill-me-handler.js +26 -18
  107. package/dist/commands/handlers/memory-handlers.d.ts +6 -2
  108. package/dist/commands/handlers/memory-handlers.js +35 -15
  109. package/dist/commands/handlers/missing-handlers.d.ts +2 -2
  110. package/dist/commands/handlers/missing-handlers.js +12 -4
  111. package/dist/commands/handlers/resources-handler.d.ts +12 -0
  112. package/dist/commands/handlers/resources-handler.js +52 -0
  113. package/dist/commands/handlers/starter-handlers.d.ts +1 -1
  114. package/dist/commands/handlers/starter-handlers.js +32 -2
  115. package/dist/commands/handlers/switch-handler.d.ts +1 -1
  116. package/dist/commands/handlers/switch-handler.js +15 -0
  117. package/dist/commands/handlers/test-handlers.js +4 -86
  118. package/dist/commands/handlers/ui-handlers.js +11 -5
  119. package/dist/commands/login-chatgpt.d.ts +8 -0
  120. package/dist/commands/login-chatgpt.js +17 -0
  121. package/dist/commands/mcp-import.d.ts +11 -0
  122. package/dist/commands/mcp-import.js +67 -0
  123. package/dist/commands/mcp-invoke.d.ts +2 -0
  124. package/dist/commands/mcp-invoke.js +68 -0
  125. package/dist/commands/mcp.d.ts +13 -0
  126. package/dist/commands/mcp.js +66 -21
  127. package/dist/commands/pipeline.d.ts +7 -1
  128. package/dist/commands/pipeline.js +104 -7
  129. package/dist/commands/resources.d.ts +2 -0
  130. package/dist/commands/resources.js +64 -0
  131. package/dist/commands/skills-cli/index.js +35 -12
  132. package/dist/commands/slash/builtin-commands.js +16 -3
  133. package/dist/commands/slash/index.d.ts +3 -1
  134. package/dist/commands/slash/index.js +2 -0
  135. package/dist/commands/slash/surfaces.d.ts +53 -0
  136. package/dist/commands/slash/surfaces.js +177 -0
  137. package/dist/commands/slash/types.d.ts +17 -0
  138. package/dist/commands/try.d.ts +1 -1
  139. package/dist/commands/try.js +1 -1
  140. package/dist/companion/companion-identity.d.ts +43 -0
  141. package/dist/companion/companion-identity.js +136 -0
  142. package/dist/companion/companion-toolset.d.ts +66 -0
  143. package/dist/companion/companion-toolset.js +368 -0
  144. package/dist/companion/companion-turn.d.ts +10 -2
  145. package/dist/companion/companion-turn.js +38 -1
  146. package/dist/config/code-exec-policy.d.ts +25 -0
  147. package/dist/config/code-exec-policy.js +39 -0
  148. package/dist/config/model-tools.d.ts +9 -0
  149. package/dist/config/model-tools.js +103 -0
  150. package/dist/context/context-manager-v2.js +2 -2
  151. package/dist/context/lm-resizer-compressor.js +3 -2
  152. package/dist/context/lm-resizer-diagnostics.d.ts +9 -0
  153. package/dist/context/lm-resizer-diagnostics.js +30 -0
  154. package/dist/context/tool-output-masking.js +3 -4
  155. package/dist/curator/curator.d.ts +6 -0
  156. package/dist/curator/curator.js +53 -3
  157. package/dist/daemon/cron-agent-bridge.d.ts +6 -0
  158. package/dist/daemon/cron-agent-bridge.js +31 -4
  159. package/dist/doctor/index.d.ts +11 -2
  160. package/dist/doctor/index.js +84 -21
  161. package/dist/doctor/integrations.d.ts +197 -0
  162. package/dist/doctor/integrations.js +241 -0
  163. package/dist/doctor/triage.d.ts +108 -0
  164. package/dist/doctor/triage.js +304 -0
  165. package/dist/errors/crash-handler.js +2 -0
  166. package/dist/fleet/collaboration.d.ts +44 -0
  167. package/dist/fleet/collaboration.js +170 -0
  168. package/dist/fleet/fleet-listener.d.ts +1 -0
  169. package/dist/fleet/fleet-listener.js +87 -46
  170. package/dist/fleet/fleet-registry.d.ts +2 -0
  171. package/dist/fleet/resource-catalog.d.ts +245 -0
  172. package/dist/fleet/resource-catalog.js +211 -0
  173. package/dist/fleet/rooms/room-access.d.ts +138 -0
  174. package/dist/fleet/rooms/room-access.js +196 -0
  175. package/dist/fleet/rooms/room-client.d.ts +158 -0
  176. package/dist/fleet/rooms/room-client.js +685 -0
  177. package/dist/fleet/rooms/room-event.d.ts +139 -0
  178. package/dist/fleet/rooms/room-event.js +330 -0
  179. package/dist/fleet/rooms/room-filter.d.ts +48 -0
  180. package/dist/fleet/rooms/room-filter.js +152 -0
  181. package/dist/fleet/rooms/room-hub.d.ts +154 -0
  182. package/dist/fleet/rooms/room-hub.js +363 -0
  183. package/dist/fleet/rooms/room-identity.d.ts +26 -0
  184. package/dist/fleet/rooms/room-identity.js +82 -0
  185. package/dist/fleet/rooms/room-lock.d.ts +34 -0
  186. package/dist/fleet/rooms/room-lock.js +180 -0
  187. package/dist/fleet/rooms/room-observations.d.ts +7 -0
  188. package/dist/fleet/rooms/room-observations.js +61 -0
  189. package/dist/fleet/rooms/room-server.d.ts +28 -0
  190. package/dist/fleet/rooms/room-server.js +75 -0
  191. package/dist/fleet/rooms/room-store.d.ts +119 -0
  192. package/dist/fleet/rooms/room-store.js +448 -0
  193. package/dist/fleet/rooms/room-ws-bridge.d.ts +27 -0
  194. package/dist/fleet/rooms/room-ws-bridge.js +137 -0
  195. package/dist/fleet/sensory-mission-bridge.d.ts +42 -0
  196. package/dist/fleet/sensory-mission-bridge.js +136 -0
  197. package/dist/git/worktree-sessions.js +1 -0
  198. package/dist/harness/contract.d.ts +4 -4
  199. package/dist/harness/fleet-supervisor.d.ts +16 -0
  200. package/dist/harness/fleet-supervisor.js +64 -0
  201. package/dist/harness/index.d.ts +4 -0
  202. package/dist/harness/index.js +4 -0
  203. package/dist/harness/mission-runner.d.ts +3 -0
  204. package/dist/harness/mission-runner.js +53 -0
  205. package/dist/harness/mission-store.d.ts +93 -0
  206. package/dist/harness/mission-store.js +297 -0
  207. package/dist/harness/tool-harness.d.ts +56 -0
  208. package/dist/harness/tool-harness.js +153 -0
  209. package/dist/hooks/use-enhanced-input.js +48 -4
  210. package/dist/hooks/use-input-handler.d.ts +1 -0
  211. package/dist/hooks/use-input-handler.js +82 -22
  212. package/dist/hooks/use-input-history.js +1 -0
  213. package/dist/identity/lisa-introspection.js +5 -2
  214. package/dist/identity/operational-self-model.d.ts +2 -0
  215. package/dist/identity/operational-self-model.js +4 -0
  216. package/dist/index.js +52 -6
  217. package/dist/mcp/client.d.ts +11 -0
  218. package/dist/mcp/client.js +68 -3
  219. package/dist/mcp/config.d.ts +20 -0
  220. package/dist/mcp/config.js +121 -8
  221. package/dist/mcp/import-normalize.d.ts +12 -0
  222. package/dist/mcp/import-normalize.js +114 -0
  223. package/dist/mcp/mcp-oauth-constants.d.ts +8 -0
  224. package/dist/mcp/mcp-oauth-constants.js +9 -0
  225. package/dist/mcp/mcp-oauth-provider.d.ts +80 -0
  226. package/dist/mcp/mcp-oauth-provider.js +241 -0
  227. package/dist/mcp/mcp-oauth.d.ts +60 -1
  228. package/dist/mcp/mcp-oauth.js +241 -65
  229. package/dist/mcp/transports.d.ts +14 -5
  230. package/dist/mcp/transports.js +112 -101
  231. package/dist/mcp/types.d.ts +5 -0
  232. package/dist/media/comfyui-recipe-contract.d.ts +7 -7
  233. package/dist/memory/facts-memory.d.ts +11 -1
  234. package/dist/memory/facts-memory.js +47 -8
  235. package/dist/memory/memory-candidate-queue.d.ts +2 -2
  236. package/dist/memory/memory-candidate-queue.js +6 -6
  237. package/dist/memory/persistent-memory.d.ts +13 -8
  238. package/dist/memory/persistent-memory.js +77 -30
  239. package/dist/nodes/device-node.js +5 -9
  240. package/dist/observability/mobile-supervision-gateway-contract.js +20 -7
  241. package/dist/observability/run-event-writer.d.ts +21 -0
  242. package/dist/observability/run-event-writer.js +81 -0
  243. package/dist/observability/run-store.d.ts +5 -0
  244. package/dist/observability/run-store.js +18 -13
  245. package/dist/observability/run-trajectory.js +1 -1
  246. package/dist/optimization/prompt-cache.d.ts +19 -2
  247. package/dist/optimization/prompt-cache.js +41 -6
  248. package/dist/orchestration/orchestrator.d.ts +21 -0
  249. package/dist/orchestration/orchestrator.js +122 -15
  250. package/dist/persistence/session-content.d.ts +8 -0
  251. package/dist/persistence/session-content.js +76 -0
  252. package/dist/persistence/session-handoff.d.ts +64 -0
  253. package/dist/persistence/session-handoff.js +80 -0
  254. package/dist/persistence/session-history.d.ts +4 -0
  255. package/dist/persistence/session-history.js +38 -0
  256. package/dist/persistence/session-store.d.ts +9 -0
  257. package/dist/persistence/session-store.js +48 -20
  258. package/dist/personas/persona-manager.js +17 -1
  259. package/dist/plugins/code-explorer/CodeExplorerManager.d.ts +10 -4
  260. package/dist/plugins/code-explorer/CodeExplorerManager.js +69 -16
  261. package/dist/plugins/plugin-manager.js +10 -1
  262. package/dist/prompts/prompt-manager.js +11 -4
  263. package/dist/prompts/system-base.js +6 -2
  264. package/dist/protocols/a2a/codebuddy-executor.d.ts +11 -2
  265. package/dist/protocols/a2a/codebuddy-executor.js +9 -8
  266. package/dist/protocols/a2a/index.d.ts +1 -1
  267. package/dist/protocols/a2a/jsonrpc-v1.d.ts +41 -0
  268. package/dist/protocols/a2a/jsonrpc-v1.js +145 -0
  269. package/dist/protocols/a2a/peer-config.d.ts +20 -0
  270. package/dist/protocols/a2a/peer-config.js +55 -0
  271. package/dist/providers/codex-oauth.js +30 -6
  272. package/dist/providers/model-provider-compat.js +2 -1
  273. package/dist/sandbox/os-sandbox.d.ts +1 -1
  274. package/dist/scheduler/cron-scheduler.d.ts +15 -2
  275. package/dist/scheduler/cron-scheduler.js +35 -4
  276. package/dist/scheduler/job-notepad.d.ts +69 -0
  277. package/dist/scheduler/job-notepad.js +339 -0
  278. package/dist/security/audit-logger.d.ts +1 -1
  279. package/dist/security/compute-confinement.d.ts +4 -0
  280. package/dist/security/compute-confinement.js +89 -0
  281. package/dist/security/session-encryption.d.ts +4 -0
  282. package/dist/security/session-encryption.js +31 -0
  283. package/dist/sensory/voice-loop.d.ts +17 -0
  284. package/dist/sensory/voice-loop.js +72 -15
  285. package/dist/server/auth/device-session-context.d.ts +9 -0
  286. package/dist/server/auth/device-session-context.js +13 -0
  287. package/dist/server/auth/device-store.d.ts +89 -0
  288. package/dist/server/auth/device-store.js +261 -0
  289. package/dist/server/auth/device-token.d.ts +3 -0
  290. package/dist/server/auth/device-token.js +6 -0
  291. package/dist/server/auth/jwt.js +4 -0
  292. package/dist/server/index.d.ts +0 -10
  293. package/dist/server/index.js +28 -0
  294. package/dist/server/middleware/auth.js +3 -2
  295. package/dist/server/routes/a2a-jsonrpc.d.ts +9 -0
  296. package/dist/server/routes/a2a-jsonrpc.js +66 -0
  297. package/dist/server/routes/a2a-protocol.d.ts +12 -0
  298. package/dist/server/routes/a2a-protocol.js +1 -1
  299. package/dist/server/routes/device-auth.d.ts +4 -0
  300. package/dist/server/routes/device-auth.js +40 -0
  301. package/dist/server/types.d.ts +4 -0
  302. package/dist/server/websocket/handler.d.ts +13 -0
  303. package/dist/server/websocket/handler.js +102 -17
  304. package/dist/services/prompt-builder.d.ts +2 -0
  305. package/dist/services/prompt-builder.js +16 -6
  306. package/dist/services/runtime-settings-context.d.ts +81 -0
  307. package/dist/services/runtime-settings-context.js +79 -0
  308. package/dist/skills/executor.js +2 -0
  309. package/dist/skills/hub.js +16 -14
  310. package/dist/skills/local-inventory.d.ts +21 -0
  311. package/dist/skills/local-inventory.js +72 -0
  312. package/dist/skills/skill-loader.js +2 -2
  313. package/dist/skills/skill-usage-store.d.ts +49 -0
  314. package/dist/skills/skill-usage-store.js +121 -0
  315. package/dist/testing/ai-integration-tests.js +8 -5
  316. package/dist/themes/theme-manager.d.ts +12 -0
  317. package/dist/themes/theme-manager.js +29 -0
  318. package/dist/themes/theme-schema.d.ts +24 -24
  319. package/dist/tools/a2a-call-tool.d.ts +34 -0
  320. package/dist/tools/a2a-call-tool.js +75 -0
  321. package/dist/tools/bash/streaming-executor.d.ts +1 -0
  322. package/dist/tools/bash/streaming-executor.js +78 -90
  323. package/dist/tools/code-exec-preflight-runner.d.ts +41 -0
  324. package/dist/tools/code-exec-preflight-runner.js +254 -0
  325. package/dist/tools/code-exec-preflight.d.ts +44 -0
  326. package/dist/tools/code-exec-preflight.js +501 -0
  327. package/dist/tools/code-exec-tool.d.ts +48 -1
  328. package/dist/tools/code-exec-tool.js +191 -47
  329. package/dist/tools/comment-watcher.js +29 -12
  330. package/dist/tools/core-code-inspection.d.ts +56 -0
  331. package/dist/tools/core-code-inspection.js +86 -0
  332. package/dist/tools/create-skill-tool.d.ts +2 -3
  333. package/dist/tools/create-skill-tool.js +16 -75
  334. package/dist/tools/cronjob-tool.d.ts +1 -0
  335. package/dist/tools/cronjob-tool.js +1 -0
  336. package/dist/tools/env-doctor-tool.d.ts +2 -0
  337. package/dist/tools/env-doctor-tool.js +4 -3
  338. package/dist/tools/execute-code-rpc-invoker.d.ts +1 -1
  339. package/dist/tools/execute-code-rpc-invoker.js +35 -19
  340. package/dist/tools/execute-code-runner.d.ts +2 -0
  341. package/dist/tools/execute-code-runner.js +52 -17
  342. package/dist/tools/fleet-room-tool.d.ts +104 -0
  343. package/dist/tools/fleet-room-tool.js +124 -0
  344. package/dist/tools/integration-tool-hints.d.ts +4 -0
  345. package/dist/tools/integration-tool-hints.js +19 -0
  346. package/dist/tools/list-peers-tool.d.ts +3 -0
  347. package/dist/tools/list-peers-tool.js +11 -4
  348. package/dist/tools/media-generation-tool.d.ts +16 -1
  349. package/dist/tools/media-generation-tool.js +341 -9
  350. package/dist/tools/merge-conflict-tool.js +53 -25
  351. package/dist/tools/metadata.d.ts +1 -5
  352. package/dist/tools/metadata.js +30 -28
  353. package/dist/tools/peer-tool-invoke-tool.d.ts +61 -0
  354. package/dist/tools/peer-tool-invoke-tool.js +396 -0
  355. package/dist/tools/ragchat-tool.d.ts +39 -0
  356. package/dist/tools/ragchat-tool.js +105 -0
  357. package/dist/tools/registry/fleet-tools.d.ts +21 -3
  358. package/dist/tools/registry/fleet-tools.js +137 -4
  359. package/dist/tools/registry/index.d.ts +1 -1
  360. package/dist/tools/registry/index.js +2 -2
  361. package/dist/tools/registry/knowledge-tools.d.ts +2 -2
  362. package/dist/tools/registry/knowledge-tools.js +2 -2
  363. package/dist/tools/registry/lessons-tools.d.ts +7 -0
  364. package/dist/tools/registry/lessons-tools.js +43 -3
  365. package/dist/tools/registry/memory-tools.d.ts +1 -1
  366. package/dist/tools/registry/memory-tools.js +8 -8
  367. package/dist/tools/registry/research-tools.d.ts +1 -0
  368. package/dist/tools/registry/research-tools.js +4 -13
  369. package/dist/tools/registry/self-describe-tools.d.ts +1 -1
  370. package/dist/tools/registry/self-describe-tools.js +43 -30
  371. package/dist/tools/resource-catalog-tool.d.ts +38 -0
  372. package/dist/tools/resource-catalog-tool.js +46 -0
  373. package/dist/tools/skills-inspection-tool.js +30 -1
  374. package/dist/tools/stream-tool-output.d.ts +3 -0
  375. package/dist/tools/stream-tool-output.js +33 -0
  376. package/dist/tools/tool-call-scheduler.d.ts +10 -0
  377. package/dist/tools/tool-call-scheduler.js +58 -0
  378. package/dist/tools/tool-effect.d.ts +5 -0
  379. package/dist/tools/tool-effect.js +26 -0
  380. package/dist/tools/tool-search.d.ts +12 -11
  381. package/dist/tools/tool-search.js +67 -26
  382. package/dist/tools/types.d.ts +6 -0
  383. package/dist/ui/components/ChatHistory.d.ts +1 -1
  384. package/dist/ui/components/ChatHistory.js +2 -2
  385. package/dist/ui/components/ChatInput.d.ts +2 -1
  386. package/dist/ui/components/ChatInput.js +42 -88
  387. package/dist/ui/components/ChatInterface.d.ts +4 -2
  388. package/dist/ui/components/ChatInterface.js +27 -63
  389. package/dist/ui/components/CommandSuggestions.d.ts +0 -1
  390. package/dist/ui/components/CommandSuggestions.js +4 -6
  391. package/dist/ui/components/FileAutocomplete.js +1 -1
  392. package/dist/ui/components/KeyboardHelp.js +8 -6
  393. package/dist/ui/components/ModelSelection.js +6 -5
  394. package/dist/ui/components/StatusBar.d.ts +2 -1
  395. package/dist/ui/components/StatusBar.js +8 -7
  396. package/dist/ui/context/theme-context.js +3 -2
  397. package/dist/ui/index.d.ts +1 -1
  398. package/dist/ui/index.js +1 -1
  399. package/dist/ui/utils/markdown-renderer.js +4 -13
  400. package/dist/utils/atomic-write.d.ts +22 -0
  401. package/dist/utils/atomic-write.js +29 -0
  402. package/dist/utils/bounded-output.d.ts +16 -0
  403. package/dist/utils/bounded-output.js +63 -0
  404. package/dist/utils/config-validation/schema.d.ts +2 -2
  405. package/dist/utils/device-store-file.d.ts +4 -0
  406. package/dist/utils/device-store-file.js +40 -0
  407. package/dist/utils/export-manager.d.ts +9 -0
  408. package/dist/utils/export-manager.js +19 -0
  409. package/dist/utils/first-use-hints.d.ts +25 -0
  410. package/dist/utils/first-use-hints.js +58 -0
  411. package/dist/utils/graceful-shutdown.d.ts +8 -0
  412. package/dist/utils/graceful-shutdown.js +23 -7
  413. package/dist/utils/history-manager.js +1 -1
  414. package/dist/utils/update-notifier.js +16 -18
  415. package/dist/wizard/environment-detection.d.ts +5 -1
  416. package/dist/wizard/environment-detection.js +49 -7
  417. package/dist/wizard/onboarding.d.ts +5 -1
  418. package/dist/wizard/onboarding.js +90 -30
  419. package/dist/wizard/provider-onboarding.d.ts +2 -0
  420. package/dist/wizard/provider-onboarding.js +55 -17
  421. package/package.json +7 -3
@@ -27,17 +27,37 @@ function formatTimeAgo(date, now = new Date()) {
27
27
  const yr = Math.floor(day / 365);
28
28
  return `${yr} year${yr === 1 ? "" : "s"} ago`;
29
29
  }
30
+ /**
31
+ * Report a remember operation honestly: the persistent write is the primary
32
+ * result; fact reconciliation and the semantic index are secondary and their
33
+ * failures are shown without hiding (or overstating) the saved memory.
34
+ */
35
+ async function describeRememberOutcome(write, requestedKey, scope, storeSemantic) {
36
+ const lines = [`āœ… Remembered: "${write?.key ?? requestedKey}" in persistent ${scope} memory.`];
37
+ if (write?.reconciliation?.status === "failed") {
38
+ lines.push(`āš ļø Fact reconciliation failed (${write.reconciliation.reason ?? "unknown error"}); the memory was saved directly and existing memories were kept unchanged.`);
39
+ }
40
+ try {
41
+ await storeSemantic();
42
+ lines.push("Semantic index updated.");
43
+ }
44
+ catch (error) {
45
+ lines.push(`āš ļø Semantic index not updated: ${getErrorMessage(error)}`);
46
+ }
47
+ return lines.join("\n");
48
+ }
30
49
  function clip(text, max = 180) {
31
50
  return text.length > max ? text.slice(0, max - 1) + "…" : text;
32
51
  }
33
52
  /**
34
53
  * Memory - Manage persistent memory using PersistentMemoryManager (Markdown) and EnhancedMemory (SQLite/Vector)
35
54
  */
36
- export async function handleMemory(args) {
55
+ export async function handleMemory(args, context) {
37
56
  const enhancedMemory = getEnhancedMemory();
38
- const persistentMemory = getMemoryManager();
57
+ const persistentMemory = getMemoryManager(undefined, context?.botId, context?.cwd);
39
58
  const action = args[0]?.toLowerCase() || 'list';
40
59
  try {
60
+ await persistentMemory.initialize();
41
61
  let content;
42
62
  switch (action) {
43
63
  case "recall":
@@ -151,14 +171,13 @@ export async function handleMemory(args) {
151
171
  : "project";
152
172
  const value = args.slice(2).join(" ");
153
173
  // Store in both for redundancy and better retrieval
154
- await persistentMemory.remember(key, value, { scope, category: "custom" });
155
- await enhancedMemory.store({
174
+ const write = await persistentMemory.remember(key, value, { scope, category: "custom" });
175
+ content = await describeRememberOutcome(write, key, scope, () => enhancedMemory.store({
156
176
  type: 'fact',
157
177
  content: `${key}: ${value}`,
158
178
  tags: [key, scope],
159
179
  importance: 0.8
160
- });
161
- content = `āœ… Remembered: "${key}" in persistent ${scope} memory and semantic index.`;
180
+ }));
162
181
  }
163
182
  else {
164
183
  content = `Usage: /memory remember <key> <content> [project|user]`;
@@ -231,7 +250,7 @@ export async function handleMemory(args) {
231
250
  : undefined;
232
251
  const rawLimit = parseInt(args[status ? 2 : 1] ?? "20", 10);
233
252
  const limit = Math.min(50, Math.max(1, Number.isFinite(rawLimit) ? rawLimit : 20));
234
- const candidates = getMemoryCandidateQueue(process.cwd()).list(status).slice(0, limit);
253
+ const candidates = getMemoryCandidateQueue(context?.cwd ?? process.cwd(), context?.botId).list(status).slice(0, limit);
235
254
  if (candidates.length === 0) {
236
255
  content = status ? `No ${status} memory candidates.` : "No memory candidates yet.";
237
256
  }
@@ -268,7 +287,7 @@ export async function handleMemory(args) {
268
287
  }
269
288
  const reviewedBy = args.slice(2).join(" ").trim() || "user";
270
289
  const { getMemoryCandidateQueue } = await import("../../memory/memory-candidate-queue.js");
271
- const { candidate, write } = await getMemoryCandidateQueue(process.cwd()).accept(id, { reviewedBy });
290
+ const { candidate, write } = await getMemoryCandidateQueue(context?.cwd ?? process.cwd(), context?.botId).accept(id, { reviewedBy });
272
291
  content = `āœ… Accepted ${candidate.id} into ${candidate.scope} memory as "${candidate.key}".\n` +
273
292
  `Write status: ${write.status}. Capacity: ${write.usage.used}/${write.usage.limit} chars (${write.usage.percent}%).`;
274
293
  break;
@@ -282,7 +301,7 @@ export async function handleMemory(args) {
282
301
  }
283
302
  const reason = args.slice(2).join(" ").trim();
284
303
  const { getMemoryCandidateQueue } = await import("../../memory/memory-candidate-queue.js");
285
- const candidate = getMemoryCandidateQueue(process.cwd()).reject(id, {
304
+ const candidate = getMemoryCandidateQueue(context?.cwd ?? process.cwd(), context?.botId).reject(id, {
286
305
  reviewedBy: "user",
287
306
  ...(reason ? { reason } : {}),
288
307
  });
@@ -319,7 +338,7 @@ export async function handleMemory(args) {
319
338
  /**
320
339
  * Remember - Quick memory store using PersistentMemoryManager and EnhancedMemory
321
340
  */
322
- export async function handleRemember(args) {
341
+ export async function handleRemember(args, context) {
323
342
  if (args.length < 2) {
324
343
  return {
325
344
  handled: true,
@@ -346,20 +365,21 @@ export async function handleRemember(args) {
346
365
  : "project";
347
366
  const value = args.slice(1).join(" ");
348
367
  try {
349
- const persistentMemory = getMemoryManager();
368
+ const persistentMemory = getMemoryManager(undefined, context?.botId, context?.cwd);
350
369
  const enhancedMemory = getEnhancedMemory();
351
- await persistentMemory.remember(key, value, { scope, category: "custom" });
352
- await enhancedMemory.store({
370
+ await persistentMemory.initialize();
371
+ const write = await persistentMemory.remember(key, value, { scope, category: "custom" });
372
+ const content = await describeRememberOutcome(write, key, scope, () => enhancedMemory.store({
353
373
  type: 'fact',
354
374
  content: `${key}: ${value}`,
355
375
  tags: [key, scope],
356
376
  importance: 0.8
357
- });
377
+ }));
358
378
  return {
359
379
  handled: true,
360
380
  entry: {
361
381
  type: "assistant",
362
- content: `āœ… Remembered: "${key}" in persistent ${scope} memory and semantic index.`,
382
+ content,
363
383
  timestamp: new Date(),
364
384
  },
365
385
  };
@@ -14,7 +14,7 @@
14
14
  * - __RESTORE_CHECKPOINT__ - /restore
15
15
  */
16
16
  import type { CommandHandlerResult } from './branch-handlers.js';
17
- export declare function handleChangeModel(args: string[]): Promise<CommandHandlerResult>;
17
+ export declare function handleChangeModel(args: string[], activeModel?: string): Promise<CommandHandlerResult>;
18
18
  export declare function handleChangeMode(args: string[]): Promise<CommandHandlerResult>;
19
19
  export declare function handleClearChat(): CommandHandlerResult;
20
20
  export declare function handleColab(args: string[]): Promise<CommandHandlerResult>;
@@ -24,5 +24,5 @@ export declare function handleListCheckpoints(_args: string[]): Promise<CommandH
24
24
  export declare function handleRestoreCheckpoint(args: string[]): Promise<CommandHandlerResult>;
25
25
  export declare function handleInitGrok(args?: string[]): Promise<CommandHandlerResult>;
26
26
  export declare function handleReinitGrok(): Promise<CommandHandlerResult>;
27
- export declare function handleStatus(): Promise<CommandHandlerResult>;
27
+ export declare function handleStatus(activeModel?: string): Promise<CommandHandlerResult>;
28
28
  export declare function handleNew(args: string[]): Promise<CommandHandlerResult>;
@@ -17,14 +17,14 @@ import { handleColabCommand } from './colab-handler.js';
17
17
  // ============================================================================
18
18
  // /model - Change Model
19
19
  // ============================================================================
20
- export async function handleChangeModel(args) {
20
+ export async function handleChangeModel(args, activeModel) {
21
21
  const { getSupportedModels, getModelInfo, suggestModel } = await import('../../utils/model-utils.js');
22
22
  const { getSettingsManager } = await import('../../utils/settings-manager.js');
23
23
  const modelName = args[0];
24
24
  const settingsManager = getSettingsManager();
25
25
  // If no model specified, show current model and list available models
26
26
  if (!modelName || modelName === 'list') {
27
- const currentModel = process.env.GROK_MODEL || 'grok-beta';
27
+ const currentModel = activeModel ?? settingsManager.getCurrentModel();
28
28
  const supportedModels = getSupportedModels();
29
29
  // Group models by provider
30
30
  const modelsByProvider = {};
@@ -803,14 +803,22 @@ function formatStatusTimeAgo(date, now = new Date()) {
803
803
  const day = Math.floor(hr / 24);
804
804
  return `${day}d ago`;
805
805
  }
806
- export async function handleStatus() {
806
+ export async function handleStatus(activeModel) {
807
807
  const lines = [];
808
808
  lines.push('Status Dashboard');
809
809
  lines.push('='.repeat(50));
810
810
  lines.push('');
811
811
  // Current model
812
- const currentModel = process.env.GROK_MODEL || 'grok-beta';
812
+ const currentModel = activeModel ?? (await import('../../utils/settings-manager.js')).getSettingsManager().getCurrentModel();
813
813
  lines.push(` Model: ${currentModel}`);
814
+ try {
815
+ const { getThemeManager } = await import('../../themes/theme-manager.js');
816
+ const theme = getThemeManager().getCurrentTheme();
817
+ lines.push(` Theme: ${theme.name} (${theme.id})`);
818
+ }
819
+ catch (_err) {
820
+ lines.push(' Theme: unknown');
821
+ }
814
822
  // Agent mode
815
823
  try {
816
824
  const { getOperatingModeManager } = await import('../../agent/operating-modes.js');
@@ -0,0 +1,12 @@
1
+ /**
2
+ * /resources — read-only view of the explicit resource catalog (P8).
3
+ *
4
+ * Reads ~/.codebuddy/resources/catalog.json through ResourceCatalog.list():
5
+ * no probe, no network, no write, no dispatch. Shows endpoint REFERENCES
6
+ * (environment variable names), never resolved URLs or fingerprints.
7
+ */
8
+ import type { CommandHandlerResult } from './branch-handlers.js';
9
+ import { ResourceCatalog, type PublicResourceStatus } from '../../fleet/resource-catalog.js';
10
+ export declare const RESOURCES_EMPTY_HINT: string;
11
+ export declare function formatResourcesTable(resources: PublicResourceStatus[], now?: number): string;
12
+ export declare function handleResources(catalog?: ResourceCatalog, now?: () => number): Promise<CommandHandlerResult>;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * /resources — read-only view of the explicit resource catalog (P8).
3
+ *
4
+ * Reads ~/.codebuddy/resources/catalog.json through ResourceCatalog.list():
5
+ * no probe, no network, no write, no dispatch. Shows endpoint REFERENCES
6
+ * (environment variable names), never resolved URLs or fingerprints.
7
+ */
8
+ import fs from 'node:fs';
9
+ import { publicResourceStatus, ResourceCatalog } from '../../fleet/resource-catalog.js';
10
+ export const RESOURCES_EMPTY_HINT = 'No resource catalog yet. Declare one with `buddy resources add <file.json>` (fields: `buddy resources schema`), '
11
+ + 'then refresh its health explicitly with `buddy resources probe <id>`.';
12
+ function textResult(content) {
13
+ return { handled: true, entry: { type: 'assistant', content, timestamp: new Date() } };
14
+ }
15
+ function age(from, now) {
16
+ if (from === null)
17
+ return 'never';
18
+ const minutes = Math.max(0, Math.round((now - from) / 60_000));
19
+ if (minutes < 1)
20
+ return 'just now';
21
+ if (minutes < 120)
22
+ return `${minutes} min ago`;
23
+ return `${Math.round(minutes / 60)} h ago`;
24
+ }
25
+ export function formatResourcesTable(resources, now = Date.now()) {
26
+ const lines = [`Resources (${resources.length}) — read-only, no probe`, ''];
27
+ for (const entry of resources) {
28
+ const r = entry.resource;
29
+ const use = r.permissions.use ? 'use' : 'no-use';
30
+ const probe = r.permissions.probe ? 'probe' : 'no-probe';
31
+ lines.push(` ${r.id} [${r.kind}] on ${r.hostId}`);
32
+ lines.push(` state: ${entry.state} (${entry.reason}), checked ${age(entry.checkedAt, now)}`);
33
+ lines.push(` capabilities: ${r.declaredCapabilities.join(', ')} Ā· endpoint ref: ${r.endpointRef} Ā· ${use}, ${probe}`);
34
+ }
35
+ lines.push('', 'Health is not proof of usage and load is unknown. Refresh with `buddy resources probe <id>`.');
36
+ return lines.join('\n');
37
+ }
38
+ export async function handleResources(catalog = new ResourceCatalog(), now = Date.now) {
39
+ let resources;
40
+ try {
41
+ resources = (await catalog.list()).map(publicResourceStatus);
42
+ }
43
+ catch (error) {
44
+ const code = error instanceof Error ? error.message : 'INVALID_CATALOG';
45
+ return textResult(`Resource catalog unreadable (${code}). Nothing was changed; inspect ${catalog.filename}.`);
46
+ }
47
+ if (resources.length === 0) {
48
+ return textResult(fs.existsSync(catalog.filename) ? `The resource catalog is empty. ${RESOURCES_EMPTY_HINT.replace(/^No resource catalog yet\. /, '')}` : RESOURCES_EMPTY_HINT);
49
+ }
50
+ return textResult(formatResourcesTable(resources, now()));
51
+ }
52
+ //# sourceMappingURL=resources-handler.js.map
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Starter Pack Slash Command Handler
3
3
  *
4
- * /starter - List all starter packs grouped by language
4
+ * /starter, /starter list - List all starter packs grouped by language
5
5
  * /starter <name> - Activate a specific starter pack (name or alias)
6
6
  * /starter search <q> - Search starters by keyword
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Starter Pack Slash Command Handler
3
3
  *
4
- * /starter - List all starter packs grouped by language
4
+ * /starter, /starter list - List all starter packs grouped by language
5
5
  * /starter <name> - Activate a specific starter pack (name or alias)
6
6
  * /starter search <q> - Search starters by keyword
7
7
  */
@@ -25,7 +25,16 @@ const LANGUAGE_FAMILIES = {
25
25
  function formatStarterList() {
26
26
  const starters = getStarterPacks();
27
27
  if (starters.length === 0) {
28
- return 'No starter packs found. Ensure bundled skills are loaded.';
28
+ // No starter pack ships with the package today: say where packs are found
29
+ // instead of implying a loading failure.
30
+ return [
31
+ 'No starter packs are installed.',
32
+ '',
33
+ 'Starter packs are SKILL.md skills tagged "starter", discovered in:',
34
+ ' .codebuddy/skills/ (this project)',
35
+ ' ~/.codebuddy/skills/ (user)',
36
+ ' the bundled skills directory shipped with Code Buddy',
37
+ ].join('\n');
29
38
  }
30
39
  const lines = [
31
40
  `Starter Packs (${starters.length} available)`,
@@ -82,6 +91,27 @@ export async function handleStarter(args) {
82
91
  };
83
92
  }
84
93
  const action = first.toLowerCase();
94
+ // /starter list — documented alias of the bare command
95
+ if (action === 'list' && args.length === 1) {
96
+ return {
97
+ handled: true,
98
+ entry: {
99
+ type: 'assistant',
100
+ content: formatStarterList(),
101
+ timestamp: new Date(),
102
+ },
103
+ };
104
+ }
105
+ if (action === 'search' && args.length === 1) {
106
+ return {
107
+ handled: true,
108
+ entry: {
109
+ type: 'assistant',
110
+ content: 'Usage: /starter search <query>',
111
+ timestamp: new Date(),
112
+ },
113
+ };
114
+ }
85
115
  // /starter search <query>
86
116
  if (action === 'search' && args.length > 1) {
87
117
  const query = args.slice(1).join(' ');
@@ -9,7 +9,7 @@
9
9
  import type { CommandHandlerResult } from './branch-handlers.js';
10
10
  /**
11
11
  * Provider for model routing state.
12
- * Set from enhanced-command-handler when the agent is available.
12
+ * Set by the conversation-loop dispatcher from the live agent.
13
13
  */
14
14
  export interface SwitchModelProvider {
15
15
  /** Get list of available model names */
@@ -23,6 +23,21 @@ export function setSwitchModelProvider(provider) {
23
23
  * /switch auto — Return to auto-routing / default
24
24
  */
25
25
  export async function handleSwitch(args) {
26
+ try {
27
+ return await runSwitch(args);
28
+ }
29
+ catch (error) {
30
+ return {
31
+ handled: true,
32
+ entry: {
33
+ type: 'assistant',
34
+ content: `Model switch failed: ${error instanceof Error ? error.message : String(error)}`,
35
+ timestamp: new Date(),
36
+ },
37
+ };
38
+ }
39
+ }
40
+ async function runSwitch(args) {
26
41
  const modelName = args[0]?.trim();
27
42
  // No provider set — try to get models from config
28
43
  if (!providerRef) {
@@ -1,6 +1,5 @@
1
1
  import { CodeBuddyClient } from "../../codebuddy/client.js";
2
2
  import { AITestRunner, createAITestRunner } from "../../testing/ai-integration-tests.js";
3
- import stringWidth from "string-width";
4
3
  /**
5
4
  * Generate Tests - Create test scaffolds
6
5
  */
@@ -47,7 +46,7 @@ export async function handleAITest(args, codebuddyClient) {
47
46
  const option = args[0]?.toLowerCase();
48
47
  // Check for API key
49
48
  const apiKey = process.env.GROK_API_KEY;
50
- if (!apiKey) {
49
+ if (!codebuddyClient && !apiKey) {
51
50
  return {
52
51
  handled: true,
53
52
  entry: {
@@ -66,9 +65,8 @@ Set your API key to run integration tests.`,
66
65
  // Fallback: create client from environment variables
67
66
  const model = process.env.GROK_MODEL || process.env.OPENAI_MODEL;
68
67
  const baseURL = process.env.GROK_BASE_URL || process.env.OPENAI_BASE_URL;
69
- client = new CodeBuddyClient(apiKey, model, baseURL);
68
+ client = new CodeBuddyClient(apiKey ?? '', model, baseURL);
70
69
  }
71
- const currentModel = client.getCurrentModel();
72
70
  const currentBaseURL = client.getBaseURL();
73
71
  // Detect local models (LM Studio, Ollama) and increase timeout
74
72
  const isLocalModel = currentBaseURL.includes(':1234') ||
@@ -86,87 +84,11 @@ Set your API key to run integration tests.`,
86
84
  testTools: option !== 'stream',
87
85
  testStreaming: option !== 'tools',
88
86
  };
89
- // Fun test names and emojis
90
- const testEmojis = {
91
- 'Basic Completion': '🧠',
92
- 'Simple Math': 'šŸ”¢',
93
- 'JSON Output': 'šŸ“‹',
94
- 'Code Generation': 'šŸ’»',
95
- 'Context Understanding': '🧩',
96
- 'Streaming Response': '🌊',
97
- 'Tool Calling': 'šŸ”§',
98
- 'Error Handling': 'šŸ›”ļø',
99
- 'Long Context': 'šŸ“š',
100
- };
101
- const spinnerFrames = ['ā ‹', 'ā ™', 'ā ¹', 'ā ø', 'ā ¼', 'ā “', 'ā ¦', 'ā §', 'ā ‡', 'ā '];
102
- let spinnerIndex = 0;
103
- let currentTest = '';
104
- const completedTests = [];
105
- let spinnerInterval = null;
106
- // Create client and run tests
87
+ // Ink owns the terminal. Render the final report through the conversation
88
+ // instead of writing cursor-control sequences over the active UI.
107
89
  try {
108
90
  const runner = createAITestRunner(client, testOptions);
109
- // Helper to pad string to width accounting for emoji visual width
110
- const padEnd = (str, targetWidth) => {
111
- const currentWidth = stringWidth(str);
112
- if (currentWidth >= targetWidth)
113
- return str;
114
- return str + ' '.repeat(targetWidth - currentWidth);
115
- };
116
- const W = 60; // box width
117
- // Build progress display with proper emoji width handling
118
- const buildProgressDisplay = () => {
119
- const lines = [];
120
- lines.push('ā”Œ' + '─'.repeat(W - 2) + '┐');
121
- lines.push('│' + padEnd(' 🧪 AI INTEGRATION TESTS IN PROGRESS', W - 2) + '│');
122
- lines.push('ā”œ' + '─'.repeat(W - 2) + '┤');
123
- lines.push('│' + padEnd(` Model: ${currentModel}`, W - 2) + '│');
124
- lines.push('ā”œ' + '─'.repeat(W - 2) + '┤');
125
- // Show completed tests
126
- for (const test of completedTests) {
127
- lines.push('│' + padEnd(` ${test}`, W - 2) + '│');
128
- }
129
- // Show current test with spinner
130
- if (currentTest) {
131
- const emoji = testEmojis[currentTest] || 'šŸ”¬';
132
- const spinner = spinnerFrames[spinnerIndex % spinnerFrames.length];
133
- lines.push('│' + padEnd(` ${spinner} ${emoji} ${currentTest}...`, W - 2) + '│');
134
- }
135
- lines.push('ā””' + '─'.repeat(W - 2) + 'ā”˜');
136
- return lines.join('\n');
137
- };
138
- // Track progress
139
- runner.on('test:start', ({ name }) => {
140
- currentTest = name;
141
- });
142
- runner.on('test:complete', (result) => {
143
- const emoji = testEmojis[result.name] || 'šŸ”¬';
144
- const status = result.passed ? 'āœ…' : 'āŒ';
145
- const duration = result.duration ? `${(result.duration / 1000).toFixed(1)}s` : '';
146
- completedTests.push(`${status} ${emoji} ${result.name} ${duration}`);
147
- currentTest = '';
148
- });
149
- runner.on('test:skipped', ({ name }) => {
150
- const emoji = testEmojis[name] || 'šŸ”¬';
151
- completedTests.push(`ā­ļø ${emoji} ${name} (skipped)`);
152
- });
153
- // Start spinner animation (write to stderr to not interfere with output)
154
- spinnerInterval = setInterval(() => {
155
- spinnerIndex++;
156
- // Clear and redraw progress (using ANSI escape codes)
157
- const progress = buildProgressDisplay();
158
- process.stderr.write(`\x1b[${completedTests.length + 7}A\x1b[0J${progress}\n`);
159
- }, 100);
160
- // Show initial progress
161
- process.stderr.write('\n' + buildProgressDisplay() + '\n');
162
91
  const suite = await runner.runAll();
163
- // Stop spinner
164
- if (spinnerInterval) {
165
- clearInterval(spinnerInterval);
166
- }
167
- // Clear progress display
168
- const clearLines = completedTests.length + 8;
169
- process.stderr.write(`\x1b[${clearLines}A\x1b[0J`);
170
92
  // Format final results
171
93
  const resultContent = AITestRunner.formatResults(suite);
172
94
  return {
@@ -179,10 +101,6 @@ Set your API key to run integration tests.`,
179
101
  };
180
102
  }
181
103
  catch (error) {
182
- // Stop spinner on error
183
- if (spinnerInterval) {
184
- clearInterval(spinnerInterval);
185
- }
186
104
  return {
187
105
  handled: true,
188
106
  entry: {
@@ -4,17 +4,17 @@ import { getThemeManager } from "../../themes/theme-manager.js";
4
4
  */
5
5
  export function handleTheme(args) {
6
6
  const themeManager = getThemeManager();
7
- const action = args[0]?.toLowerCase();
7
+ const action = (args[0]?.toLowerCase() === "set" ? args[1] : args[0])?.toLowerCase();
8
8
  let content;
9
- if (!action || action === "list") {
9
+ if (!action || action === "list" || action === "status" || action === "current") {
10
10
  const themes = themeManager.getAvailableThemes();
11
11
  const currentTheme = themeManager.getCurrentTheme();
12
- content = `šŸŽØ Available Themes\n${"═".repeat(40)}\n\n`;
12
+ content = `šŸŽØ Current theme: ${currentTheme.name} (${currentTheme.id})\nAvailable Themes\n${"═".repeat(40)}\n\n`;
13
13
  for (const theme of themes) {
14
14
  const isCurrent = theme.id === currentTheme.id;
15
15
  const marker = isCurrent ? "ā–¶" : " ";
16
16
  const builtinMarker = theme.isBuiltin ? "" : " (custom)";
17
- content += `${marker} ${theme.name}${builtinMarker}\n`;
17
+ content += `${marker} ${theme.name} (${theme.id})${builtinMarker}\n`;
18
18
  content += ` ${theme.description}\n\n`;
19
19
  }
20
20
  content += `\nšŸ’” Usage: /theme <name>\n`;
@@ -28,7 +28,13 @@ export function handleTheme(args) {
28
28
  content = `šŸŽØ Theme Changed!\n\n`;
29
29
  content += `Now using: ${theme.name}\n`;
30
30
  content += `${theme.description}\n\n`;
31
- content += `šŸ’” The theme will be applied to new messages.`;
31
+ content += `The theme is active immediately.`;
32
+ if (themeManager.getPreferenceSaveStatus() === false) {
33
+ content += `\nCould not save the preference; this change may be lost after restarting Buddy.`;
34
+ }
35
+ if (themeManager.getOverrideKeys().colors.length > 0) {
36
+ content += `\nCustom color overrides are still applied.`;
37
+ }
32
38
  }
33
39
  else {
34
40
  const themes = themeManager.getAvailableThemes();
@@ -0,0 +1,8 @@
1
+ import { type ChatGptAuth } from '../providers/codex-oauth.js';
2
+ interface LoginOutput {
3
+ stdout: (message: string) => unknown;
4
+ warn: (message: string) => unknown;
5
+ }
6
+ /** Keep the callback alive so a failed browser launch can be completed manually. */
7
+ export declare function loginChatGptWithBrowser(output: LoginOutput): Promise<ChatGptAuth>;
8
+ export {};
@@ -0,0 +1,17 @@
1
+ import open from 'open';
2
+ import { loginInteractive } from '../providers/codex-oauth.js';
3
+ /** Keep the callback alive so a failed browser launch can be completed manually. */
4
+ export function loginChatGptWithBrowser(output) {
5
+ return loginInteractive(async (url) => {
6
+ output.stdout('If the browser does not open, copy this entire URL into your browser:');
7
+ output.stdout(url);
8
+ output.stdout('Keep this terminal open until sign-in completes.\n');
9
+ try {
10
+ await open(url);
11
+ }
12
+ catch {
13
+ output.warn('Could not open the browser automatically. Open the URL above manually; login is still waiting.');
14
+ }
15
+ });
16
+ }
17
+ //# sourceMappingURL=login-chatgpt.js.map
@@ -0,0 +1,11 @@
1
+ import type { Command } from 'commander';
2
+ export declare function importMCPFile(filename: string, source: 'hermes' | 'openclaw', options?: {
3
+ dryRun?: boolean;
4
+ output?: string;
5
+ }): {
6
+ written: boolean;
7
+ servers: import("../mcp/types.js").MCPServerConfig[];
8
+ warnings: string[];
9
+ rejected: string[];
10
+ };
11
+ export declare function registerMCPImportCommand(command: Command): void;
@@ -0,0 +1,67 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { parse } from 'yaml';
4
+ import { normalizeMCPImports } from '../mcp/import-normalize.js';
5
+ import { writeJsonAtomicSync } from '../utils/atomic-write.js';
6
+ const object = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
7
+ export function importMCPFile(filename, source, options = {}) {
8
+ const stat = fs.statSync(filename);
9
+ if (!stat.isFile() || stat.size > 1024 * 1024)
10
+ throw new Error('MCP import file must be at most 1 MiB');
11
+ let input;
12
+ try {
13
+ input = parse(fs.readFileSync(filename, 'utf8'), { uniqueKeys: true });
14
+ }
15
+ catch {
16
+ throw new Error('Invalid MCP import JSON/YAML');
17
+ }
18
+ if (!object(input))
19
+ throw new Error('MCP import requires an object');
20
+ const map = input.mcpServers ?? input.mcp_servers ?? (object(input.mcp) ? input.mcp.servers : undefined) ?? input;
21
+ const normalized = normalizeMCPImports(map, source);
22
+ if (options.dryRun || normalized.servers.length === 0)
23
+ return { ...normalized, written: false };
24
+ const output = options.output ?? path.join(process.cwd(), '.codebuddy', 'mcp.json');
25
+ let existing = {};
26
+ if (fs.existsSync(output)) {
27
+ const target = fs.lstatSync(output);
28
+ if (!target.isFile() || target.isSymbolicLink() || target.size > 1024 * 1024)
29
+ throw new Error('Invalid existing MCP target');
30
+ try {
31
+ const parsed = JSON.parse(fs.readFileSync(output, 'utf8'));
32
+ if (!object(parsed) || (parsed.mcpServers !== undefined && !object(parsed.mcpServers)))
33
+ throw new Error();
34
+ existing = parsed;
35
+ }
36
+ catch {
37
+ throw new Error('Existing MCP configuration is invalid; not replaced');
38
+ }
39
+ }
40
+ const servers = object(existing.mcpServers) ? existing.mcpServers : {};
41
+ for (const server of normalized.servers) {
42
+ if (Object.hasOwn(servers, server.name))
43
+ normalized.warnings.push(`${server.name}: existing configuration preserved`);
44
+ else
45
+ servers[server.name] = server;
46
+ }
47
+ fs.mkdirSync(path.dirname(output), { recursive: true, mode: 0o700 });
48
+ writeJsonAtomicSync(output, { ...existing, mcpServers: servers }, { mode: 0o600 });
49
+ return { ...normalized, written: true };
50
+ }
51
+ export function registerMCPImportCommand(command) {
52
+ command.command('import <file>').requiredOption('--from <source>', 'hermes or openclaw')
53
+ .option('--dry-run', 'Show sanitized mapping without writing or connecting')
54
+ .option('--output <file>', 'Target MCP JSON file (default project .codebuddy/mcp.json)')
55
+ .description('Import MCP declarations; credentials become environment references and existing entries are preserved')
56
+ .action((file, options) => {
57
+ if (options.from !== 'hermes' && options.from !== 'openclaw')
58
+ command.error('Source must be hermes or openclaw');
59
+ try {
60
+ process.stdout.write(JSON.stringify(importMCPFile(file, options.from, options), null, 2) + '\n');
61
+ }
62
+ catch {
63
+ command.error('MCP import failed; check input/target configuration. No credentials are printed.');
64
+ }
65
+ });
66
+ }
67
+ //# sourceMappingURL=mcp-import.js.map
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerMCPInvocationCommands(command: Command): void;