@phuetz/code-buddy 1.1.0 → 1.3.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 (381) hide show
  1. package/README.md +211 -163
  2. package/dist/agent/autonomous/agentic-coding-contract.d.ts +12 -12
  3. package/dist/agent/base-agent.d.ts +4 -0
  4. package/dist/agent/base-agent.js +6 -0
  5. package/dist/agent/codebuddy-agent.d.ts +1 -1
  6. package/dist/agent/codebuddy-agent.js +69 -14
  7. package/dist/agent/execution/agent-executor.js +122 -12
  8. package/dist/agent/execution/tool-dependency-graph.js +7 -0
  9. package/dist/agent/execution/tool-hooks.d.ts +6 -0
  10. package/dist/agent/execution/tool-hooks.js +13 -5
  11. package/dist/agent/execution/tool-selection-strategy.d.ts +11 -2
  12. package/dist/agent/execution/tool-selection-strategy.js +67 -10
  13. package/dist/agent/extended-thinking.d.ts +8 -0
  14. package/dist/agent/extended-thinking.js +27 -0
  15. package/dist/agent/facades/infrastructure-facade.d.ts +9 -2
  16. package/dist/agent/facades/infrastructure-facade.js +15 -6
  17. package/dist/agent/hermes-browser-backends.js +151 -11
  18. package/dist/agent/hermes-claw-migrate.d.ts +59 -0
  19. package/dist/agent/hermes-claw-migrate.js +427 -26
  20. package/dist/agent/hermes-parity-manifest.js +78 -71
  21. package/dist/agent/hermes-runtime-lifecycle.d.ts +67 -0
  22. package/dist/agent/hermes-runtime-lifecycle.js +468 -0
  23. package/dist/agent/middleware/index.d.ts +1 -0
  24. package/dist/agent/middleware/index.js +1 -0
  25. package/dist/agent/middleware/visual-validation-middleware.d.ts +17 -0
  26. package/dist/agent/middleware/visual-validation-middleware.js +67 -0
  27. package/dist/agent/model-benchmark.d.ts +77 -0
  28. package/dist/agent/model-benchmark.js +309 -0
  29. package/dist/agent/model-tier.d.ts +14 -0
  30. package/dist/agent/model-tier.js +71 -0
  31. package/dist/agent/multi-agent/agents/orchestrator-agent.js +17 -6
  32. package/dist/agent/multi-agent/multi-agent-system.js +3 -1
  33. package/dist/agent/multi-agent/session-fleet-bridge.d.ts +2 -0
  34. package/dist/agent/multi-agent/session-fleet-bridge.js +9 -1
  35. package/dist/agent/multi-agent/session-tools.js +22 -5
  36. package/dist/agent/reasoning/mcts.js +20 -6
  37. package/dist/agent/self-improvement/authored-artifact-gate.d.ts +18 -0
  38. package/dist/agent/self-improvement/authored-artifact-gate.js +42 -0
  39. package/dist/agent/self-improvement/authored-tool-runtime.d.ts +27 -0
  40. package/dist/agent/self-improvement/authored-tool-runtime.js +57 -0
  41. package/dist/agent/self-improvement/authored-tool-store.d.ts +24 -0
  42. package/dist/agent/self-improvement/authored-tool-store.js +57 -0
  43. package/dist/agent/self-improvement/llm-tool-proposer.d.ts +41 -0
  44. package/dist/agent/self-improvement/llm-tool-proposer.js +136 -0
  45. package/dist/agent/self-improvement/sandbox-scorer.d.ts +17 -0
  46. package/dist/agent/self-improvement/sandbox-scorer.js +43 -0
  47. package/dist/agent/self-improvement/self-knowledge.d.ts +8 -0
  48. package/dist/agent/self-improvement/self-knowledge.js +24 -0
  49. package/dist/agent/self-improvement/skill-benchmark.d.ts +9 -0
  50. package/dist/agent/self-improvement/skill-benchmark.js +22 -0
  51. package/dist/agent/self-improvement/skill-consolidator.d.ts +71 -0
  52. package/dist/agent/self-improvement/skill-consolidator.js +137 -0
  53. package/dist/agent/self-improvement/skill-engine.d.ts +42 -0
  54. package/dist/agent/self-improvement/skill-engine.js +87 -0
  55. package/dist/agent/self-improvement/skill-gate.d.ts +19 -0
  56. package/dist/agent/self-improvement/skill-gate.js +62 -0
  57. package/dist/agent/self-improvement/skill-mutator.d.ts +74 -0
  58. package/dist/agent/self-improvement/skill-mutator.js +223 -0
  59. package/dist/agent/self-improvement/skill-proposer.d.ts +40 -0
  60. package/dist/agent/self-improvement/skill-proposer.js +82 -0
  61. package/dist/agent/self-improvement/skill-types.d.ts +41 -0
  62. package/dist/agent/self-improvement/skill-types.js +13 -0
  63. package/dist/agent/self-improvement/tool-benchmark.d.ts +10 -0
  64. package/dist/agent/self-improvement/tool-benchmark.js +37 -0
  65. package/dist/agent/self-improvement/tool-engine.d.ts +54 -0
  66. package/dist/agent/self-improvement/tool-engine.js +101 -0
  67. package/dist/agent/self-improvement/tool-gate.d.ts +20 -0
  68. package/dist/agent/self-improvement/tool-gate.js +78 -0
  69. package/dist/agent/self-improvement/tool-proposer.d.ts +31 -0
  70. package/dist/agent/self-improvement/tool-proposer.js +34 -0
  71. package/dist/agent/self-improvement/tool-skill-mutator.d.ts +40 -0
  72. package/dist/agent/self-improvement/tool-skill-mutator.js +79 -0
  73. package/dist/agent/self-improvement/tool-types.d.ts +48 -0
  74. package/dist/agent/self-improvement/tool-types.js +9 -0
  75. package/dist/agent/self-improvement/types.d.ts +3 -1
  76. package/dist/agent/session-end-flush.d.ts +6 -1
  77. package/dist/agent/session-end-flush.js +20 -4
  78. package/dist/agent/streaming/streaming-handler.d.ts +7 -0
  79. package/dist/agent/streaming/streaming-handler.js +8 -1
  80. package/dist/agent/tool-executor.js +1 -0
  81. package/dist/agent/tool-handler.d.ts +5 -0
  82. package/dist/agent/tool-handler.js +133 -4
  83. package/dist/browser-automation/browser-operator-executor.js +15 -0
  84. package/dist/browser-automation/browser-use-runner.d.ts +96 -0
  85. package/dist/browser-automation/browser-use-runner.js +492 -0
  86. package/dist/browser-automation/camofox-runner.d.ts +107 -0
  87. package/dist/browser-automation/camofox-runner.js +287 -0
  88. package/dist/channels/dingtalk/index.js +3 -0
  89. package/dist/channels/discord/client.d.ts +9 -0
  90. package/dist/channels/discord/client.js +12 -0
  91. package/dist/channels/feishu/index.d.ts +167 -1
  92. package/dist/channels/feishu/index.js +432 -7
  93. package/dist/channels/gateway-lifecycle.d.ts +132 -0
  94. package/dist/channels/gateway-lifecycle.js +219 -0
  95. package/dist/channels/google-chat/index.d.ts +5 -1
  96. package/dist/channels/google-chat/index.js +5 -1
  97. package/dist/channels/imessage/index.d.ts +14 -0
  98. package/dist/channels/imessage/index.js +64 -17
  99. package/dist/channels/index.d.ts +4 -0
  100. package/dist/channels/index.js +4 -0
  101. package/dist/channels/irc/index.d.ts +73 -3
  102. package/dist/channels/irc/index.js +446 -11
  103. package/dist/channels/line/index.js +3 -0
  104. package/dist/channels/mattermost/index.d.ts +51 -4
  105. package/dist/channels/mattermost/index.js +303 -20
  106. package/dist/channels/nextcloud-talk/index.d.ts +89 -8
  107. package/dist/channels/nextcloud-talk/index.js +367 -16
  108. package/dist/channels/nostr/index.d.ts +121 -1
  109. package/dist/channels/nostr/index.js +396 -8
  110. package/dist/channels/ntfy/index.js +3 -0
  111. package/dist/channels/qq/index.js +3 -0
  112. package/dist/channels/slash-parity.d.ts +117 -0
  113. package/dist/channels/slash-parity.js +185 -0
  114. package/dist/channels/synology-chat/index.js +3 -0
  115. package/dist/channels/teams/index.d.ts +3 -0
  116. package/dist/channels/teams/index.js +3 -0
  117. package/dist/channels/telegram/client.d.ts +9 -0
  118. package/dist/channels/telegram/client.js +12 -0
  119. package/dist/channels/twilio-voice/index.js +3 -0
  120. package/dist/channels/webchat/index.d.ts +7 -1
  121. package/dist/channels/webchat/index.js +7 -1
  122. package/dist/channels/wecom/index.js +3 -0
  123. package/dist/channels/weixin/index.js +3 -0
  124. package/dist/channels/zalo/index.js +3 -0
  125. package/dist/cli/config-loader.js +1 -1
  126. package/dist/codebuddy/client.d.ts +30 -1
  127. package/dist/codebuddy/client.js +167 -20
  128. package/dist/codebuddy/providers/provider-chatgpt-responses.d.ts +5 -0
  129. package/dist/codebuddy/providers/provider-chatgpt-responses.js +7 -1
  130. package/dist/codebuddy/providers/provider-gemini-native.js +1 -1
  131. package/dist/codebuddy/providers/provider-openai-compat.d.ts +5 -0
  132. package/dist/codebuddy/providers/provider-openai-compat.js +82 -2
  133. package/dist/codebuddy/tool-definitions/computer-control-tools.js +32 -2
  134. package/dist/codebuddy/tool-definitions/core-tools.js +3 -3
  135. package/dist/codebuddy/tool-definitions/index.d.ts +2 -1
  136. package/dist/codebuddy/tool-definitions/index.js +2 -1
  137. package/dist/codebuddy/tool-definitions/multimodal-tools.d.ts +1 -0
  138. package/dist/codebuddy/tool-definitions/multimodal-tools.js +44 -1
  139. package/dist/codebuddy/tool-definitions/windows-tools.d.ts +2 -0
  140. package/dist/codebuddy/tool-definitions/windows-tools.js +34 -0
  141. package/dist/codebuddy/tools.d.ts +8 -1
  142. package/dist/codebuddy/tools.js +67 -24
  143. package/dist/commands/cli/hermes-commands.js +108 -0
  144. package/dist/commands/cli/improve-command.js +123 -0
  145. package/dist/commands/cli/native-engine-commands.js +102 -3
  146. package/dist/commands/cli/utility-commands.js +45 -0
  147. package/dist/commands/enhanced-command-handler.js +2 -2
  148. package/dist/commands/goal-cli.d.ts +30 -0
  149. package/dist/commands/goal-cli.js +210 -27
  150. package/dist/commands/handlers/goal-handler.d.ts +9 -2
  151. package/dist/commands/handlers/goal-handler.js +36 -9
  152. package/dist/commands/handlers/infra-handlers.js +36 -0
  153. package/dist/commands/handlers/memory-handlers.js +96 -1
  154. package/dist/commands/handlers/missing-handlers.d.ts +1 -1
  155. package/dist/commands/handlers/missing-handlers.js +26 -3
  156. package/dist/commands/headless-slash.d.ts +2 -0
  157. package/dist/commands/headless-slash.js +12 -0
  158. package/dist/commands/llm-provider-resolution.d.ts +5 -3
  159. package/dist/commands/llm-provider-resolution.js +87 -33
  160. package/dist/commands/ollama.d.ts +25 -0
  161. package/dist/commands/ollama.js +100 -0
  162. package/dist/commands/provider.d.ts +5 -0
  163. package/dist/commands/provider.js +106 -55
  164. package/dist/commands/skills-cli/index.js +123 -0
  165. package/dist/commands/slash/builtin-commands.js +1 -1
  166. package/dist/commands/spec-next.js +2 -1
  167. package/dist/commands/spec-plan.js +5 -16
  168. package/dist/commands/tunnel.d.ts +2 -0
  169. package/dist/commands/tunnel.js +48 -0
  170. package/dist/companion/percepts.js +11 -1
  171. package/dist/config/config-resolver.d.ts +2 -1
  172. package/dist/config/config-resolver.js +54 -41
  173. package/dist/config/constants.d.ts +28 -0
  174. package/dist/config/constants.js +7 -0
  175. package/dist/config/env-schema.js +756 -0
  176. package/dist/config/model-tools.js +4 -4
  177. package/dist/config/toml-config.d.ts +16 -0
  178. package/dist/config/toml-config.js +3 -0
  179. package/dist/context/bootstrap-loader.js +6 -23
  180. package/dist/context/context-manager-v2.js +1 -0
  181. package/dist/context/import-directive-parser.d.ts +4 -0
  182. package/dist/context/import-directive-parser.js +51 -6
  183. package/dist/context/instruction-excludes.d.ts +30 -1
  184. package/dist/context/instruction-excludes.js +71 -1
  185. package/dist/context/jit-context.d.ts +8 -10
  186. package/dist/context/jit-context.js +28 -106
  187. package/dist/context/project-context.d.ts +90 -0
  188. package/dist/context/project-context.js +295 -0
  189. package/dist/daemon/autonomous-daemon.d.ts +1 -1
  190. package/dist/daemon/autonomous-daemon.js +3 -3
  191. package/dist/daemon/autonomous-loop.d.ts +31 -1
  192. package/dist/daemon/autonomous-loop.js +91 -4
  193. package/dist/daemon/colab-goal.js +9 -1
  194. package/dist/daemon/cron-agent-bridge.d.ts +12 -3
  195. package/dist/daemon/cron-agent-bridge.js +25 -9
  196. package/dist/desktop/codebuddy-engine-adapter.d.ts +32 -0
  197. package/dist/desktop/codebuddy-engine-adapter.js +257 -80
  198. package/dist/desktop/engine-adapter.d.ts +14 -0
  199. package/dist/desktop-automation/automation-manager.js +16 -0
  200. package/dist/desktop-automation/omniparser-runner.d.ts +63 -0
  201. package/dist/desktop-automation/omniparser-runner.js +115 -0
  202. package/dist/desktop-automation/smart-snapshot.d.ts +11 -0
  203. package/dist/desktop-automation/smart-snapshot.js +72 -5
  204. package/dist/doctor/index.js +40 -23
  205. package/dist/events/types.d.ts +11 -0
  206. package/dist/fleet/colab-store.js +14 -2
  207. package/dist/fleet/peer-session-bridge.js +50 -12
  208. package/dist/fleet/peer-tool-bridge.js +14 -0
  209. package/dist/goals/goal-decomposer.d.ts +27 -0
  210. package/dist/goals/goal-decomposer.js +293 -0
  211. package/dist/goals/goal-judge-client.d.ts +15 -0
  212. package/dist/goals/goal-judge-client.js +45 -0
  213. package/dist/goals/goal-judge.d.ts +2 -0
  214. package/dist/goals/goal-judge.js +35 -6
  215. package/dist/goals/goal-loop.d.ts +14 -0
  216. package/dist/goals/goal-loop.js +47 -2
  217. package/dist/goals/goal-manager.d.ts +6 -0
  218. package/dist/goals/goal-manager.js +67 -14
  219. package/dist/goals/goal-state.d.ts +13 -0
  220. package/dist/goals/goal-state.js +83 -13
  221. package/dist/goals/goal-store.d.ts +3 -0
  222. package/dist/goals/goal-store.js +31 -15
  223. package/dist/harness/contract.d.ts +28 -28
  224. package/dist/hooks/user-hooks.js +17 -3
  225. package/dist/identity/identity-manager.js +3 -2
  226. package/dist/index.js +481 -26
  227. package/dist/input/text-to-speech.d.ts +2 -6
  228. package/dist/input/text-to-speech.js +2 -27
  229. package/dist/integrations/screenpipe/screenpipe-client.d.ts +10 -0
  230. package/dist/integrations/screenpipe/screenpipe-client.js +12 -2
  231. package/dist/integrations/tailscale.d.ts +13 -0
  232. package/dist/integrations/tailscale.js +87 -34
  233. package/dist/knowledge/workspace-indexer.js +53 -9
  234. package/dist/mcp/client.js +1 -0
  235. package/dist/mcp/mcp-desktop-tools.d.ts +23 -0
  236. package/dist/mcp/mcp-desktop-tools.js +158 -0
  237. package/dist/mcp/mcp-resources.js +2 -3
  238. package/dist/mcp/mcp-server.js +2 -0
  239. package/dist/memory/enhanced-memory.d.ts +10 -0
  240. package/dist/memory/enhanced-memory.js +33 -2
  241. package/dist/memory/index.d.ts +3 -1
  242. package/dist/memory/index.js +4 -1
  243. package/dist/memory/memory-auto-proposer.d.ts +23 -0
  244. package/dist/memory/memory-auto-proposer.js +308 -0
  245. package/dist/memory/memory-candidate-queue.d.ts +92 -0
  246. package/dist/memory/memory-candidate-queue.js +261 -0
  247. package/dist/memory/persistent-memory.d.ts +45 -2
  248. package/dist/memory/persistent-memory.js +236 -40
  249. package/dist/ml/bayesian-qualifier.d.ts +1 -1
  250. package/dist/ml/bayesian-qualifier.js +35 -2
  251. package/dist/openclaw/gateway-bridge.js +5 -0
  252. package/dist/plugins/marketplace.d.ts +1 -0
  253. package/dist/plugins/marketplace.js +7 -0
  254. package/dist/prompts/execution-discipline.d.ts +14 -0
  255. package/dist/prompts/execution-discipline.js +29 -0
  256. package/dist/prompts/variation-injector.js +9 -2
  257. package/dist/protocols/acp/acp-agentic-runner.d.ts +7 -6
  258. package/dist/protocols/acp/acp-agentic-runner.js +115 -18
  259. package/dist/protocols/acp/acp-session-store.d.ts +23 -0
  260. package/dist/protocols/acp/acp-session-store.js +77 -0
  261. package/dist/protocols/acp/acp-stdio-server.d.ts +7 -0
  262. package/dist/protocols/acp/acp-stdio-server.js +71 -16
  263. package/dist/providers/active-llm-registry.d.ts +37 -0
  264. package/dist/providers/active-llm-registry.js +186 -0
  265. package/dist/providers/auxiliary-provider.d.ts +25 -0
  266. package/dist/providers/auxiliary-provider.js +192 -0
  267. package/dist/providers/codex-oauth.d.ts +1 -1
  268. package/dist/providers/codex-oauth.js +27 -4
  269. package/dist/providers/index.d.ts +3 -0
  270. package/dist/providers/index.js +4 -0
  271. package/dist/providers/provider-catalog.d.ts +70 -0
  272. package/dist/providers/provider-catalog.js +738 -0
  273. package/dist/providers/provider-fallback.d.ts +35 -0
  274. package/dist/providers/provider-fallback.js +171 -0
  275. package/dist/providers/xai-oauth.d.ts +128 -0
  276. package/dist/providers/xai-oauth.js +735 -0
  277. package/dist/scheduler/cron-scheduler.d.ts +15 -3
  278. package/dist/scheduler/cron-scheduler.js +53 -7
  279. package/dist/scheduler/script-runner.d.ts +2 -0
  280. package/dist/scheduler/script-runner.js +19 -4
  281. package/dist/scheduler/watchdog-handlers.js +7 -20
  282. package/dist/search/usearch-index.js +7 -2
  283. package/dist/security/tool-policy/tool-groups.js +2 -0
  284. package/dist/sensory/dreaming.d.ts +45 -0
  285. package/dist/sensory/dreaming.js +114 -0
  286. package/dist/sensory/heartbeat-scheduler.d.ts +38 -0
  287. package/dist/sensory/heartbeat-scheduler.js +72 -0
  288. package/dist/sensory/reactions.d.ts +24 -0
  289. package/dist/sensory/reactions.js +31 -0
  290. package/dist/sensory/screen-reaction.d.ts +23 -0
  291. package/dist/sensory/screen-reaction.js +59 -0
  292. package/dist/sensory/sensory-bridge.d.ts +23 -0
  293. package/dist/sensory/sensory-bridge.js +85 -0
  294. package/dist/sensory/sensory-memory.d.ts +20 -0
  295. package/dist/sensory/sensory-memory.js +39 -0
  296. package/dist/sensory/speech-reaction.d.ts +21 -0
  297. package/dist/sensory/speech-reaction.js +83 -0
  298. package/dist/sensory/vision-reaction.d.ts +31 -0
  299. package/dist/sensory/vision-reaction.js +74 -0
  300. package/dist/server/index.js +106 -2
  301. package/dist/server/routes/mobile.d.ts +12 -4
  302. package/dist/server/routes/mobile.js +116 -1
  303. package/dist/server/tls-config.d.ts +35 -0
  304. package/dist/server/tls-config.js +142 -0
  305. package/dist/server/tunnel-manager.d.ts +20 -0
  306. package/dist/server/tunnel-manager.js +58 -0
  307. package/dist/server/websocket/fleet-bridge.js +5 -0
  308. package/dist/services/prompt-builder.d.ts +11 -0
  309. package/dist/services/prompt-builder.js +124 -17
  310. package/dist/shared/engine-types.d.ts +15 -1
  311. package/dist/sidecar/sidecar-bridge.d.ts +1 -0
  312. package/dist/sidecar/sidecar-bridge.js +21 -10
  313. package/dist/skills/parser.js +3 -0
  314. package/dist/skills/skill-importer.d.ts +58 -0
  315. package/dist/skills/skill-importer.js +261 -0
  316. package/dist/skills/skill-sources.d.ts +20 -0
  317. package/dist/skills/skill-sources.js +102 -0
  318. package/dist/skills/types.d.ts +6 -0
  319. package/dist/spec/spec-store.js +8 -1
  320. package/dist/talk-mode/providers/audioreader-tts.d.ts +1 -1
  321. package/dist/talk-mode/providers/audioreader-tts.js +8 -8
  322. package/dist/templates/project-scaffolding.js +3 -2
  323. package/dist/themes/theme-schema.d.ts +10 -10
  324. package/dist/tools/application-profiles.js +38 -0
  325. package/dist/tools/bash/bash-tool.d.ts +1 -0
  326. package/dist/tools/bash/bash-tool.js +16 -2
  327. package/dist/tools/bash/command-validator.js +3 -0
  328. package/dist/tools/bash/rtk-rewrite.d.ts +16 -0
  329. package/dist/tools/bash/rtk-rewrite.js +100 -0
  330. package/dist/tools/bash/streaming-executor.js +14 -1
  331. package/dist/tools/computer-control-tool.d.ts +16 -1
  332. package/dist/tools/computer-control-tool.js +317 -5
  333. package/dist/tools/document-generator.d.ts +14 -0
  334. package/dist/tools/document-generator.js +79 -0
  335. package/dist/tools/execute-code-rpc-invoker.d.ts +26 -2
  336. package/dist/tools/execute-code-rpc-invoker.js +46 -5
  337. package/dist/tools/metadata.js +28 -0
  338. package/dist/tools/office-macro-tool.d.ts +10 -0
  339. package/dist/tools/office-macro-tool.js +93 -0
  340. package/dist/tools/register-tool-handler.d.ts +25 -0
  341. package/dist/tools/register-tool-handler.js +100 -0
  342. package/dist/tools/registry/index.d.ts +2 -1
  343. package/dist/tools/registry/index.js +2 -1
  344. package/dist/tools/registry/memory-tools.d.ts +20 -0
  345. package/dist/tools/registry/memory-tools.js +225 -3
  346. package/dist/tools/registry/multimodal-tools.js +2 -2
  347. package/dist/tools/registry/vision-tools.d.ts +33 -0
  348. package/dist/tools/registry/vision-tools.js +308 -6
  349. package/dist/tools/registry/windows-tools.d.ts +2 -0
  350. package/dist/tools/registry/windows-tools.js +47 -0
  351. package/dist/tools/registry.d.ts +6 -0
  352. package/dist/tools/registry.js +8 -0
  353. package/dist/tools/route-peer-tool.js +14 -0
  354. package/dist/tools/screenshot-tool.js +14 -2
  355. package/dist/tools/text-to-speech-tool.d.ts +1 -1
  356. package/dist/tools/text-to-speech-tool.js +2 -12
  357. package/dist/tools/tool-selector.js +3 -59
  358. package/dist/utils/config-validation/schema.d.ts +40 -7
  359. package/dist/utils/config-validation/schema.js +130 -1
  360. package/dist/utils/cost-tracker.js +21 -1
  361. package/dist/utils/disk-guard.d.ts +180 -0
  362. package/dist/utils/disk-guard.js +404 -0
  363. package/dist/utils/init-project.d.ts +7 -0
  364. package/dist/utils/init-project.js +37 -0
  365. package/dist/utils/interactive-setup.js +35 -2
  366. package/dist/utils/model-utils.js +11 -2
  367. package/dist/utils/output-sanitizer.js +11 -0
  368. package/dist/utils/provider-detector.d.ts +8 -7
  369. package/dist/utils/provider-detector.js +19 -77
  370. package/dist/utils/settings-manager.d.ts +19 -0
  371. package/dist/utils/token-display.d.ts +3 -3
  372. package/dist/utils/token-display.js +22 -4
  373. package/dist/wizard/onboarding.d.ts +39 -0
  374. package/dist/wizard/onboarding.js +433 -21
  375. package/dist/wizard/provider-onboarding.d.ts +8 -23
  376. package/dist/wizard/provider-onboarding.js +39 -158
  377. package/package.json +4 -2
  378. package/dist/plugins/provider-onboarding.d.ts +0 -23
  379. package/dist/plugins/provider-onboarding.js +0 -116
  380. package/dist/utils/kokoro-tts.d.ts +0 -8
  381. package/dist/utils/kokoro-tts.js +0 -67
@@ -25,15 +25,13 @@ import path from 'path';
25
25
  import { getSkillsHub } from '../skills/hub.js';
26
26
  const HOME_CANDIDATES = ['.openclaw', '.clawdbot', '.moltbot'];
27
27
  const CONFIG_NAMES = ['clawdbot.json', 'moltbot.json', 'openclaw.json', 'config.json'];
28
- const SKILL_DIR_CANDIDATES = ['skills', 'agent/skills', '.skills', 'skill'];
28
+ // `plugin-skills` is the OpenClaw 2026.6.x location; each entry there is usually
29
+ // a *symlink* into the installed openclaw npm package (verified against a real
30
+ // install). `discoverSkillDirs` therefore follows symlinks via `statSync`.
31
+ const SKILL_DIR_CANDIDATES = ['skills', 'plugin-skills', 'agent/skills', '.skills', 'skill'];
29
32
  const COMMAND_DIR_CANDIDATES = ['commands', 'slash-commands', 'agent/commands', '.commands'];
30
33
  // Categories that `--preset user-data` keeps as imports (user content only).
31
34
  const USER_DATA_IMPORTS = new Set(['persona', 'memory', 'user', 'agents', 'skills', 'commands']);
32
- /**
33
- * Archive categories whose slice can embed credentials. Their review files are
34
- * chmod 0600 like `secrets.json` (best-effort; no-op where chmod is unsupported).
35
- */
36
- const SENSITIVE_ARCHIVE_CATEGORIES = new Set(['hooks', 'webhooks', 'portal', 'secrets', 'custom_providers']);
37
35
  /**
38
36
  * Dev-only invariant: every config key is claimed by at most one archive spec.
39
37
  * Two specs sharing a key would archive the same slice into two files. Throws
@@ -193,7 +191,160 @@ export function mapClawAgentBehavior(cfg) {
193
191
  }
194
192
  return out;
195
193
  }
196
- /** Discover OpenClaw skill directories: each subdir containing a `SKILL.md`. */
194
+ /**
195
+ * Map OpenClaw cron config to a list of CronJob-compatible entries.
196
+ *
197
+ * OpenClaw stores cron jobs as an array of `{ schedule, task, label? }` objects
198
+ * or — in 2026.6.x — under `scheduler.jobs`. Only entries with both a valid
199
+ * 5-field cron expression and a non-empty task string are mapped. Everything
200
+ * else is silently dropped (will remain in the archived raw slice if one
201
+ * exists).
202
+ */
203
+ export function mapClawCronJobs(cfg) {
204
+ const out = [];
205
+ const candidates = [
206
+ cfg.cronJobs, cfg.cron, cfg.cronjobs,
207
+ nestedValue(cfg, 'scheduler.jobs'),
208
+ ];
209
+ for (const raw of candidates) {
210
+ if (!Array.isArray(raw))
211
+ continue;
212
+ for (const item of raw) {
213
+ if (!item || typeof item !== 'object')
214
+ continue;
215
+ const rec = item;
216
+ const schedule = typeof rec.schedule === 'string' ? rec.schedule.trim() : undefined;
217
+ const task = typeof rec.task === 'string' ? rec.task.trim() : undefined;
218
+ if (!schedule || !task)
219
+ continue;
220
+ // Basic 5-field cron validation: must have exactly 5 space-separated fields.
221
+ if (schedule.split(/\s+/).length !== 5)
222
+ continue;
223
+ const name = typeof rec.label === 'string' && rec.label.trim()
224
+ ? rec.label.trim()
225
+ : typeof rec.name === 'string' && rec.name.trim()
226
+ ? rec.name.trim()
227
+ : `claw-cron-${out.length}`;
228
+ out.push({ name, schedule, task });
229
+ }
230
+ if (out.length > 0)
231
+ break; // first populated candidate wins
232
+ }
233
+ return out;
234
+ }
235
+ /**
236
+ * Map OpenClaw command allowlist into a flat string array of allowed command
237
+ * basenames / patterns, consumable by Code Buddy's command validator.
238
+ *
239
+ * OpenClaw stores these as a flat string array under `commandAllowlist`,
240
+ * `allowlist`, or `allowedCommands`. Items that look like credentials or paths
241
+ * outside of simple command names are filtered out.
242
+ */
243
+ export function mapClawCommandAllowlist(cfg) {
244
+ const candidates = [cfg.commandAllowlist, cfg.allowlist, cfg.allowedCommands];
245
+ for (const raw of candidates) {
246
+ if (!Array.isArray(raw))
247
+ continue;
248
+ const out = [];
249
+ for (const item of raw) {
250
+ if (typeof item !== 'string')
251
+ continue;
252
+ const trimmed = item.trim();
253
+ // Skip empty, absolute paths, and anything resembling a secret.
254
+ if (!trimmed)
255
+ continue;
256
+ if (trimmed.startsWith('/') || trimmed.startsWith('~'))
257
+ continue;
258
+ if (/(token|secret|key|password)/i.test(trimmed))
259
+ continue;
260
+ out.push(trimmed);
261
+ }
262
+ if (out.length > 0)
263
+ return out;
264
+ }
265
+ return [];
266
+ }
267
+ // Known memory provider names that Code Buddy supports.
268
+ const KNOWN_MEMORY_PROVIDERS = new Set(['local', 'honcho', 'mem0', 'redis', 'sqlite', 'json', 'markdown']);
269
+ /**
270
+ * Map OpenClaw memory backend config to a Code Buddy memory provider name.
271
+ *
272
+ * Only well-known provider names are accepted; unknown strings are left
273
+ * unmapped (will stay in the archive). Credentials (API keys, URLs) in the
274
+ * memory backend config are never imported.
275
+ */
276
+ export function mapClawMemoryBackend(cfg) {
277
+ const raw = firstDefined(cfg, [
278
+ 'memoryBackend', 'memory_backend', 'memory.provider', 'memory.backend',
279
+ ]);
280
+ // Could be a string name or an object { provider: "...", ... }.
281
+ let name;
282
+ if (typeof raw === 'string') {
283
+ name = raw.trim().toLowerCase();
284
+ }
285
+ else if (raw && typeof raw === 'object' && !Array.isArray(raw)) {
286
+ const rec = raw;
287
+ const p = rec.provider ?? rec.backend ?? rec.type;
288
+ if (typeof p === 'string')
289
+ name = p.trim().toLowerCase();
290
+ }
291
+ if (name && KNOWN_MEMORY_PROVIDERS.has(name))
292
+ return name;
293
+ return undefined;
294
+ }
295
+ /**
296
+ * Map OpenClaw exec timeout to a numeric millisecond value for Code Buddy's
297
+ * `execTimeout` setting.
298
+ *
299
+ * OpenClaw stores this as seconds (integer) or milliseconds (large integer).
300
+ * Values ≤ 0 are ignored. Values that look like seconds (≤ 3600) are
301
+ * multiplied by 1000. Clamped to a maximum of 3600000 ms (1 hour).
302
+ */
303
+ export function mapClawExecTimeout(cfg) {
304
+ const raw = firstDefined(cfg, [
305
+ 'execTimeout', 'exec_timeout', 'timeout',
306
+ 'agents.defaults.execTimeout', 'agent.execTimeout',
307
+ ]);
308
+ if (typeof raw !== 'number' || raw <= 0 || !Number.isFinite(raw))
309
+ return undefined;
310
+ // Heuristic: values ≤ 3600 are likely seconds; larger ones milliseconds.
311
+ const ms = raw <= 3600 ? Math.round(raw * 1000) : Math.round(raw);
312
+ return Math.min(ms, 3_600_000);
313
+ }
314
+ /**
315
+ * Map OpenClaw vision settings to Code Buddy's vision config keys.
316
+ *
317
+ * Only the `enabled` boolean and `model` string are imported. Provider
318
+ * credentials, endpoint URLs, and other complex fields are left archived.
319
+ */
320
+ export function mapClawVisionSettings(cfg) {
321
+ const out = {};
322
+ const block = firstDefined(cfg, ['vision', 'visionSettings']);
323
+ if (block && typeof block === 'object' && !Array.isArray(block)) {
324
+ const rec = block;
325
+ if (typeof rec.enabled === 'boolean')
326
+ out.visionEnabled = rec.enabled;
327
+ if (typeof rec.model === 'string' && rec.model.trim()) {
328
+ // Only import model names, not URLs or credentials.
329
+ const model = rec.model.trim();
330
+ if (!model.startsWith('http') && !/(token|secret|key)/i.test(model)) {
331
+ out.visionModel = model;
332
+ }
333
+ }
334
+ }
335
+ return out;
336
+ }
337
+ /**
338
+ * Discover OpenClaw skill directories: each subdir containing a `SKILL.md`.
339
+ *
340
+ * Entries may be plain dirs (legacy `skills/<name>/SKILL.md`) or **symlinks** to
341
+ * a skill dir inside the installed openclaw npm package (2026.6.x
342
+ * `plugin-skills/<name>` → `.../dist/extensions/.../<name>`). A Dirent for a
343
+ * symlink reports `isDirectory() === false`, so we resolve the link with
344
+ * `statSync` (in a try/catch, to survive a dangling link when openclaw has been
345
+ * uninstalled) and accept any entry that resolves to a directory holding a
346
+ * readable `SKILL.md`.
347
+ */
197
348
  function discoverSkillDirs(home) {
198
349
  const found = [];
199
350
  const seen = new Set();
@@ -202,7 +353,17 @@ function discoverSkillDirs(home) {
202
353
  if (!fs.existsSync(root) || !fs.statSync(root).isDirectory())
203
354
  continue;
204
355
  for (const entry of fs.readdirSync(root, { withFileTypes: true })) {
205
- if (!entry.isDirectory())
356
+ // Resolve symlinks (plugin-skills entries are links into the npm package).
357
+ let isDir = entry.isDirectory();
358
+ if (!isDir && entry.isSymbolicLink()) {
359
+ try {
360
+ isDir = fs.statSync(path.join(root, entry.name)).isDirectory();
361
+ }
362
+ catch {
363
+ continue; // dangling symlink (openclaw uninstalled) — skip.
364
+ }
365
+ }
366
+ if (!isDir)
206
367
  continue;
207
368
  const skillFile = path.join(root, entry.name, 'SKILL.md');
208
369
  const safeName = entry.name.replace(/[^a-zA-Z0-9_-]/g, '-');
@@ -214,6 +375,46 @@ function discoverSkillDirs(home) {
214
375
  }
215
376
  return found;
216
377
  }
378
+ /**
379
+ * Resolve the base directories that may hold OpenClaw identity / memory markdown
380
+ * files. OpenClaw 2026.6.x stores SOUL/USER/AGENTS/… under the configured
381
+ * **workspace** dir (`agents.defaults.workspace`, real value
382
+ * `~/.openclaw/workspace`), not at the home root used by legacy clawdbot/moltbot
383
+ * installs. Both are searched (home root first for back-compat, then the
384
+ * configured workspace, then the conventional `home/workspace` fallback);
385
+ * callers dedup per category so an entry is emitted once. Only directories under
386
+ * (or equal to) `home` are accepted — an absolute `workspace` pointing outside
387
+ * the OpenClaw home is ignored to avoid reading arbitrary user paths.
388
+ */
389
+ function identityBaseDirs(home, cfg) {
390
+ const dirs = [home];
391
+ const configured = firstStringPath(cfg, [
392
+ 'agents.defaults.workspace', 'agent.workspace', 'workspace',
393
+ ]);
394
+ const candidates = [configured, path.join(home, 'workspace')];
395
+ for (const cand of candidates) {
396
+ if (!cand)
397
+ continue;
398
+ const resolved = path.resolve(home, cand);
399
+ // Only trust workspace dirs inside the OpenClaw home (the real layout). An
400
+ // out-of-tree absolute path is left to the archive/manual path, never read.
401
+ const rel = path.relative(home, resolved);
402
+ const insideHome = resolved === home || (!rel.startsWith('..') && !path.isAbsolute(rel));
403
+ if (insideHome && !dirs.includes(resolved) && fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {
404
+ dirs.push(resolved);
405
+ }
406
+ }
407
+ return dirs;
408
+ }
409
+ /** First existing path for `name` across the identity base dirs (or null). */
410
+ function findIdentityFile(bases, name) {
411
+ for (const base of bases) {
412
+ const full = path.join(base, name);
413
+ if (fs.existsSync(full) && fs.statSync(full).isFile())
414
+ return full;
415
+ }
416
+ return null;
417
+ }
217
418
  /** Discover OpenClaw custom slash command files consumable by Code Buddy. */
218
419
  function discoverCommandFiles(home) {
219
420
  const found = [];
@@ -249,6 +450,25 @@ function detectSecretSourceNames(config) {
249
450
  names.push(key);
250
451
  }
251
452
  }
453
+ // Known nested credential locations in the OpenClaw 2026.6.x layout. Verified
454
+ // against a real install: the gateway auth token and per-provider apiKeys live
455
+ // in nested objects, not at the top level. We surface their dotted *names*
456
+ // only — the values are already carried (0600) in the gateway / custom_providers
457
+ // archive slices; nothing here ever exposes a value.
458
+ const gatewayToken = nestedValue(config, 'gateway.auth.token');
459
+ if (typeof gatewayToken === 'string' && gatewayToken.trim())
460
+ names.push('gateway.auth.token');
461
+ const providers = nestedValue(config, 'models.providers');
462
+ if (providers && typeof providers === 'object' && !Array.isArray(providers)) {
463
+ for (const [provName, prov] of Object.entries(providers)) {
464
+ if (prov && typeof prov === 'object' && !Array.isArray(prov)) {
465
+ const apiKey = prov.apiKey;
466
+ if (typeof apiKey === 'string' && apiKey.trim()) {
467
+ names.push(`models.providers.${provName}.apiKey`);
468
+ }
469
+ }
470
+ }
471
+ }
252
472
  return Array.from(new Set(names));
253
473
  }
254
474
  /** Resolve the action for a directly-importable category given the preset. */
@@ -277,6 +497,9 @@ export function buildClawMigrationPlan(opts = {}) {
277
497
  target,
278
498
  codebuddyDir,
279
499
  };
500
+ // Identity/memory markdown files live either at the home root (legacy
501
+ // clawdbot/moltbot) or under the configured workspace dir (OpenClaw 2026.6.x).
502
+ const identityBases = identityBaseDirs(home, config?.raw ?? {});
280
503
  // --- Directly imported identity files (consumed by bootstrap loader / prompt builder) ---
281
504
  const identityFiles = [
282
505
  { category: 'persona', file: 'SOUL.md', dest: path.join(target, 'SOUL.md') },
@@ -284,15 +507,16 @@ export function buildClawMigrationPlan(opts = {}) {
284
507
  { category: 'agents', file: 'AGENTS.md', dest: path.join(target, 'AGENTS.md') },
285
508
  ];
286
509
  for (const { category, file, dest } of identityFiles) {
287
- const src = path.join(home, file);
288
- if (fs.existsSync(src)) {
510
+ const src = findIdentityFile(identityBases, file);
511
+ if (src) {
512
+ const fromWorkspace = path.dirname(src) !== home;
289
513
  entries.push({
290
514
  category,
291
515
  label: file,
292
516
  action: importOrPresetArchive(category, ctx),
293
517
  source: src,
294
518
  destination: dest,
295
- detail: `OpenClaw ${file} -> workspace ${file} (loaded as identity/bootstrap context).`,
519
+ detail: `OpenClaw ${file}${fromWorkspace ? ' (workspace)' : ''} -> workspace ${file} (loaded as identity/bootstrap context).`,
296
520
  });
297
521
  }
298
522
  else {
@@ -301,9 +525,9 @@ export function buildClawMigrationPlan(opts = {}) {
301
525
  }
302
526
  // --- MEMORY.md -> project memory file ---
303
527
  {
304
- const src = path.join(home, 'MEMORY.md');
528
+ const src = findIdentityFile(identityBases, 'MEMORY.md');
305
529
  const dest = path.join(codebuddyDir, 'CODEBUDDY_MEMORY.md');
306
- if (fs.existsSync(src)) {
530
+ if (src) {
307
531
  entries.push({
308
532
  category: 'memory',
309
533
  label: 'MEMORY.md',
@@ -417,6 +641,98 @@ export function buildClawMigrationPlan(opts = {}) {
417
641
  entries.push({ category: 'agent_settings', label: 'agent behavior defaults', action: 'skip', source: null, destination: null, detail: 'No mappable agent behavior defaults in config.' });
418
642
  }
419
643
  }
644
+ // --- Promoted categories: cron, command_allowlist, memory_backend, exec_timeout, vision ---
645
+ // These were previously archived-for-review but now have confirmed Code Buddy
646
+ // consumers. Each gets a dedicated mapper that conservatively translates
647
+ // well-understood fields; unmapped / complex fields stay in the archive.
648
+ // cron -> CronScheduler jobs written to settings.json:cronJobs
649
+ {
650
+ const jobs = mapClawCronJobs(cfg);
651
+ if (jobs.length > 0) {
652
+ entries.push({
653
+ category: 'cron',
654
+ label: `cron jobs (${jobs.length})`,
655
+ action: importOrPresetArchive('cron', ctx),
656
+ source: 'config:cronJobs',
657
+ destination: settingsKeyDest(ctx, 'cronJobs'),
658
+ detail: `Mapped ${jobs.length} cron job(s): ${jobs.map((j) => j.name).join(', ')}.`,
659
+ });
660
+ }
661
+ else {
662
+ entries.push({ category: 'cron', label: 'cron jobs', action: 'skip', source: null, destination: null, detail: 'No mappable cron jobs in config.' });
663
+ }
664
+ }
665
+ // command_allowlist -> settings.json:commandAllowlist
666
+ {
667
+ const allowlist = mapClawCommandAllowlist(cfg);
668
+ if (allowlist.length > 0) {
669
+ entries.push({
670
+ category: 'command_allowlist',
671
+ label: `command allowlist (${allowlist.length})`,
672
+ action: importOrPresetArchive('command_allowlist', ctx),
673
+ source: 'config:commandAllowlist',
674
+ destination: settingsKeyDest(ctx, 'commandAllowlist'),
675
+ detail: `Imported: ${allowlist.join(', ')}.`,
676
+ });
677
+ }
678
+ else {
679
+ entries.push({ category: 'command_allowlist', label: 'command allowlist', action: 'skip', source: null, destination: null, detail: 'No mappable command allowlist in config.' });
680
+ }
681
+ }
682
+ // memory_backend -> settings.json:memoryProvider
683
+ {
684
+ const provider = mapClawMemoryBackend(cfg);
685
+ if (provider) {
686
+ entries.push({
687
+ category: 'memory_backend',
688
+ label: `memory backend (${provider})`,
689
+ action: importOrPresetArchive('memory_backend', ctx),
690
+ source: 'config:memoryBackend',
691
+ destination: settingsKeyDest(ctx, 'memoryProvider'),
692
+ detail: `Mapped memory provider: "${provider}".`,
693
+ });
694
+ }
695
+ else {
696
+ entries.push({ category: 'memory_backend', label: 'memory backend', action: 'skip', source: null, destination: null, detail: 'No mappable memory backend in config.' });
697
+ }
698
+ }
699
+ // exec_timeout -> settings.json:execTimeout
700
+ {
701
+ const timeout = mapClawExecTimeout(cfg);
702
+ if (timeout !== undefined) {
703
+ entries.push({
704
+ category: 'exec_timeout',
705
+ label: `exec timeout (${timeout}ms)`,
706
+ action: importOrPresetArchive('exec_timeout', ctx),
707
+ source: 'config:execTimeout',
708
+ destination: settingsKeyDest(ctx, 'execTimeout'),
709
+ detail: `Exec timeout: ${timeout}ms.`,
710
+ });
711
+ }
712
+ else {
713
+ entries.push({ category: 'exec_timeout', label: 'exec timeout', action: 'skip', source: null, destination: null, detail: 'No mappable exec timeout in config.' });
714
+ }
715
+ }
716
+ // vision -> settings.json:visionEnabled + visionModel
717
+ {
718
+ const vision = mapClawVisionSettings(cfg);
719
+ const mappedKeys = Object.keys(vision);
720
+ if (mappedKeys.length > 0) {
721
+ entries.push({
722
+ category: 'vision',
723
+ label: `vision config (${mappedKeys.join(', ')})`,
724
+ action: importOrPresetArchive('vision', ctx),
725
+ source: 'config:vision',
726
+ destination: settingsKeyDest(ctx, mappedKeys.join('+')),
727
+ detail: `Imported: ${mappedKeys
728
+ .map((k) => `${k}=${JSON.stringify(vision[k])}`)
729
+ .join(', ')}.`,
730
+ });
731
+ }
732
+ else {
733
+ entries.push({ category: 'vision', label: 'vision config', action: 'skip', source: null, destination: null, detail: 'No mappable vision settings in config.' });
734
+ }
735
+ }
420
736
  // --- Archived-for-review categories (no confirmed live consumer / safety) ---
421
737
  //
422
738
  // Each category is archived (never imported) because Code Buddy has no
@@ -436,25 +752,20 @@ export function buildClawMigrationPlan(opts = {}) {
436
752
  { category: 'tts', keys: ['tts', 'textToSpeech', 'voice'], label: 'TTS / voice config' },
437
753
  { category: 'browser', keys: ['browser', 'browserSettings', 'browserBackend'], label: 'browser automation settings' },
438
754
  { category: 'tool_settings', keys: ['tools', 'toolSettings', 'tool_settings'], label: 'tool settings' },
439
- { category: 'command_allowlist', keys: ['commandAllowlist', 'allowlist', 'allowedCommands'], label: 'command allowlist' },
440
755
  { category: 'gateway', keys: ['gateway', 'gatewayConfig'], label: 'gateway config' },
441
- { category: 'cron', keys: ['cron', 'cronJobs', 'cronjobs'], label: 'cron jobs' },
442
756
  { category: 'plugins', keys: ['plugins'], label: 'plugins' },
443
757
  // `hooks` and `webhooks` are split so each lands in its own archive slice;
444
758
  // both can carry shell commands / credentials, so both archive (never run).
445
759
  { category: 'hooks', keys: ['hooks', 'lifecycleHooks'], label: 'lifecycle hooks', sensitive: true },
446
760
  { category: 'webhooks', keys: ['webhooks', 'webhookEndpoints'], label: 'webhook endpoints', sensitive: true },
447
- { category: 'memory_backend', keys: ['memoryBackend', 'memory_backend'], label: 'memory backend' },
448
761
  { category: 'agent_defaults', keys: ['agent', 'agentDefaults', 'multiAgent'], label: 'agent defaults / multi-agent' },
449
762
  { category: 'session_policies', keys: ['session', 'sessionReset', 'sessionPolicies'], label: 'session reset policies' },
450
763
  { category: 'approval_rules', keys: ['approval', 'approvalRules'], label: 'approval rules' },
451
- { category: 'exec_timeout', keys: ['execTimeout', 'exec_timeout', 'timeout'], label: 'exec timeout' },
452
764
  // --- Expanded category set (toward upstream `hermes claw migrate` parity) ---
453
765
  { category: 'toolsets', keys: ['toolsets', 'toolSets', 'toolset'], label: 'toolsets' },
454
766
  { category: 'profiles', keys: ['profiles', 'agentProfiles'], label: 'agent profiles' },
455
767
  { category: 'bundles', keys: ['bundles', 'skillBundles'], label: 'bundles' },
456
768
  { category: 'pairing', keys: ['pairing', 'pairedDevices', 'devices'], label: 'device pairing / allowlist' },
457
- { category: 'vision', keys: ['vision', 'visionSettings'], label: 'vision config' },
458
769
  { category: 'image_video', keys: ['image', 'video', 'media'], label: 'image / video generation config' },
459
770
  { category: 'runtimes', keys: ['runtimes', 'backends', 'runtime'], label: 'runtime backends (Docker/SSH/Modal/Daytona)' },
460
771
  { category: 'portal', keys: ['portal', 'nousPortal', 'toolGateway'], label: 'Nous Portal Tool Gateway config', sensitive: true },
@@ -515,8 +826,25 @@ function backupSource(home, codebuddyDir) {
515
826
  const stamp = new Date().toISOString().replace(/[:.]/g, '-');
516
827
  const backupRoot = path.join(codebuddyDir, 'openclaw-migration', 'backup', stamp);
517
828
  ensureDir(backupRoot);
829
+ // The backup aggregates the WHOLE source tree — including ~/.openclaw/identity
830
+ // device credentials and openclaw.json (gateway token / provider apiKey). Lock
831
+ // the backup root to owner-only (0700) BEFORE copying so the secrets never sit
832
+ // under a world-traversable 0755 directory, even briefly.
833
+ try {
834
+ fs.chmodSync(backupRoot, 0o700);
835
+ }
836
+ catch {
837
+ /* best-effort on platforms without chmod */
838
+ }
518
839
  // Shallow recursive copy of the source tree (fs.cpSync available on Node >= 16.7).
519
840
  fs.cpSync(home, path.join(backupRoot, path.basename(home)), { recursive: true });
841
+ // cpSync preserves source perms; harden the copied home wrapper dir too.
842
+ try {
843
+ fs.chmodSync(path.join(backupRoot, path.basename(home)), 0o700);
844
+ }
845
+ catch {
846
+ /* best-effort */
847
+ }
520
848
  return backupRoot;
521
849
  }
522
850
  function applyEntry(entry, opts, ctx) {
@@ -638,20 +966,93 @@ function applyEntry(entry, opts, ctx) {
638
966
  entry.applied = true;
639
967
  return;
640
968
  }
969
+ case 'cron': {
970
+ const jobs = mapClawCronJobs(ctx.config?.raw ?? {});
971
+ if (jobs.length === 0)
972
+ return;
973
+ mergeSettings(ctx, (settings) => {
974
+ const existing = settings.cronJobs ?? [];
975
+ const mapped = jobs.map((j) => ({
976
+ name: j.name,
977
+ type: 'cron',
978
+ schedule: { cron: j.schedule },
979
+ task: { type: 'message', message: j.task },
980
+ enabled: true,
981
+ }));
982
+ settings.cronJobs = overwrite ? mapped : [...existing, ...mapped];
983
+ });
984
+ entry.applied = true;
985
+ return;
986
+ }
987
+ case 'command_allowlist': {
988
+ const allowlist = mapClawCommandAllowlist(ctx.config?.raw ?? {});
989
+ if (allowlist.length === 0)
990
+ return;
991
+ mergeSettings(ctx, (settings) => {
992
+ const existing = settings.commandAllowlist ?? [];
993
+ settings.commandAllowlist = overwrite
994
+ ? allowlist
995
+ : Array.from(new Set([...existing, ...allowlist]));
996
+ });
997
+ entry.applied = true;
998
+ return;
999
+ }
1000
+ case 'memory_backend': {
1001
+ const provider = mapClawMemoryBackend(ctx.config?.raw ?? {});
1002
+ if (!provider)
1003
+ return;
1004
+ mergeSettings(ctx, (settings) => {
1005
+ if (overwrite || settings.memoryProvider === undefined) {
1006
+ settings.memoryProvider = provider;
1007
+ }
1008
+ });
1009
+ entry.applied = true;
1010
+ return;
1011
+ }
1012
+ case 'exec_timeout': {
1013
+ const timeout = mapClawExecTimeout(ctx.config?.raw ?? {});
1014
+ if (timeout === undefined)
1015
+ return;
1016
+ mergeSettings(ctx, (settings) => {
1017
+ if (overwrite || settings.execTimeout === undefined) {
1018
+ settings.execTimeout = timeout;
1019
+ }
1020
+ });
1021
+ entry.applied = true;
1022
+ return;
1023
+ }
1024
+ case 'vision': {
1025
+ const vision = mapClawVisionSettings(ctx.config?.raw ?? {});
1026
+ if (Object.keys(vision).length === 0)
1027
+ return;
1028
+ mergeSettings(ctx, (settings) => {
1029
+ const set = (key, value) => {
1030
+ if (value !== undefined && (overwrite || settings[key] === undefined))
1031
+ settings[key] = value;
1032
+ };
1033
+ set('visionEnabled', vision.visionEnabled);
1034
+ set('visionModel', vision.visionModel);
1035
+ });
1036
+ entry.applied = true;
1037
+ return;
1038
+ }
641
1039
  default: {
642
1040
  // Archive categories -> write the raw config slice to the review dir.
643
1041
  if (entry.action !== 'archive' || !entry.destination || !entry.source)
644
1042
  return;
645
1043
  ensureDir(path.dirname(entry.destination));
646
1044
  const slice = sliceForArchive(entry, ctx);
647
- fs.writeFileSync(entry.destination, JSON.stringify(slice, null, 2), 'utf-8');
648
- if (SENSITIVE_ARCHIVE_CATEGORIES.has(entry.category)) {
649
- try {
650
- fs.chmodSync(entry.destination, 0o600);
651
- }
652
- catch {
653
- /* best-effort on platforms without chmod */
654
- }
1045
+ // Archive slices are credential-review artifacts. Write owner-only (0600)
1046
+ // for EVERY category (not just a hand-maintained sensitive set) so a
1047
+ // mis-tagged or newly-added credential-bearing category can never be left
1048
+ // world-readable. Create at 0600 to close the write-then-chmod window,
1049
+ // then re-harden defensively.
1050
+ fs.writeFileSync(entry.destination, JSON.stringify(slice, null, 2), { encoding: 'utf-8', mode: 0o600 });
1051
+ try {
1052
+ fs.chmodSync(entry.destination, 0o600);
1053
+ }
1054
+ catch {
1055
+ /* best-effort on platforms without chmod */
655
1056
  }
656
1057
  entry.applied = true;
657
1058
  }