@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
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Skill consolidator — merges a CLUSTER of overlapping authored skills into one
3
+ * "umbrella" skill (Hermes's idea) but with OUR distinctive safety net: the merge
4
+ * is accepted only if the umbrella still passes the firewall AND COVERS EVERY
5
+ * scenario the absorbed siblings covered. A merge that drops coverage is rejected
6
+ * (Hermes consolidates by LLM judgment alone; we gate it empirically).
7
+ *
8
+ * Operates only on authored-* skills; pinned siblings are skipped (kept intact);
9
+ * absorbed siblings are ARCHIVED (recoverable), never deleted; each is recorded in
10
+ * the evolutionary archive with `absorbedInto` for audit.
11
+ *
12
+ * @module agent/self-improvement/skill-consolidator
13
+ */
14
+ import { coversScenario } from './skill-gate.js';
15
+ import { safetyGateSkill, toAuthoredSkillName } from './skill-mutator.js';
16
+ /** Build a cluster from installed authored skills that map to a known scenario. */
17
+ export function buildClusterFromInstalled(mutator, scenarios) {
18
+ const installed = new Set(mutator.listAuthored());
19
+ const siblings = [];
20
+ for (const scenario of scenarios) {
21
+ const name = toAuthoredSkillName(scenario.id);
22
+ if (installed.has(name))
23
+ siblings.push({ name, scenario });
24
+ }
25
+ return { siblings };
26
+ }
27
+ export async function consolidateCluster(cluster, proposer, mutator, archive, options) {
28
+ const skippedPinned = cluster.siblings.filter((s) => mutator.isPinned(s.name)).map((s) => s.name);
29
+ const mergeable = cluster.siblings.filter((s) => !mutator.isPinned(s.name));
30
+ if (mergeable.length < 2) {
31
+ return { accepted: false, absorbed: [], skippedPinned, rejectionReason: 'cluster-too-small', reasons: ['need ≥2 non-pinned authored skills to consolidate'] };
32
+ }
33
+ const proposal = await proposer.propose({ siblings: mergeable });
34
+ if (!proposal || !proposal.content.trim()) {
35
+ return { accepted: false, absorbed: [], skippedPinned, rejectionReason: 'no-proposal', reasons: ['no umbrella proposal'] };
36
+ }
37
+ // Gate 1 — the umbrella content must be safe.
38
+ const gate = safetyGateSkill(proposal.content);
39
+ if (!gate.ok) {
40
+ return { accepted: false, absorbed: [], skippedPinned, rejectionReason: 'firewall', reasons: gate.reasons };
41
+ }
42
+ // Gate 2 (the distinctive one) — the umbrella must still cover EVERY merged
43
+ // sibling's scenario. A consolidation that loses coverage is rejected.
44
+ const lost = mergeable.filter((s) => !coversScenario(proposal.content, s.scenario)).map((s) => s.scenario.id);
45
+ if (lost.length > 0) {
46
+ return { accepted: false, absorbed: [], skippedPinned, rejectionReason: 'coverage-loss', reasons: [`umbrella drops coverage for: ${lost.join(', ')}`] };
47
+ }
48
+ const umbrellaName = toAuthoredSkillName(proposal.name);
49
+ if (!options.keepOnAccept) {
50
+ return { accepted: true, umbrellaName, absorbed: [], skippedPinned, reasons: ['accepted (propose-only): umbrella safe + covers all merged scenarios, not installed'] };
51
+ }
52
+ // Install the umbrella, archive the merged siblings (recoverable), audit each.
53
+ mutator.create({ name: umbrellaName, description: `Umbrella skill consolidating ${mergeable.length} authored skills`, content: proposal.content });
54
+ const absorbed = [];
55
+ for (const s of mergeable) {
56
+ if (s.name === umbrellaName)
57
+ continue; // never archive the umbrella itself
58
+ if (mutator.archive(s.name)) {
59
+ absorbed.push(s.name);
60
+ archive.append({
61
+ proposalId: `consolidate:${umbrellaName}`,
62
+ kind: 'skill',
63
+ targetScenarioId: s.scenario.id,
64
+ delta: 0,
65
+ scoreAfter: 1,
66
+ appliedRef: umbrellaName,
67
+ absorbedInto: umbrellaName,
68
+ });
69
+ }
70
+ }
71
+ return { accepted: true, umbrellaName, absorbed, skippedPinned, reasons: [`consolidated ${absorbed.length} skill(s) into ${umbrellaName}`] };
72
+ }
73
+ // ── proposers ────────────────────────────────────────────────────────────────
74
+ /** Deterministic umbrella proposer (fixture for tests). */
75
+ export class StaticUmbrellaProposer {
76
+ umbrella;
77
+ constructor(umbrella) {
78
+ this.umbrella = umbrella;
79
+ }
80
+ async propose() {
81
+ return this.umbrella;
82
+ }
83
+ }
84
+ export class LlmUmbrellaProposer {
85
+ clientPromise;
86
+ constructor(options = {}) {
87
+ this.clientPromise = options.client !== undefined ? Promise.resolve(options.client) : null;
88
+ }
89
+ getClient() {
90
+ if (!this.clientPromise) {
91
+ this.clientPromise = (async () => {
92
+ try {
93
+ const { detectProviderFromEnv } = await import('../../utils/provider-detector.js');
94
+ const { CodeBuddyClient } = await import('../../codebuddy/client.js');
95
+ const detected = detectProviderFromEnv();
96
+ if (!detected)
97
+ return null;
98
+ return new CodeBuddyClient(detected.apiKey, detected.defaultModel, detected.baseURL);
99
+ }
100
+ catch {
101
+ return null;
102
+ }
103
+ })();
104
+ }
105
+ return this.clientPromise;
106
+ }
107
+ async propose(cluster) {
108
+ const client = await this.getClient();
109
+ if (!client)
110
+ return null;
111
+ const terms = cluster.siblings.flatMap((s) => s.scenario.expectIncludes);
112
+ const topics = cluster.siblings.map((s) => `- ${s.scenario.query}`).join('\n');
113
+ const prompt = [
114
+ 'Merge these related guidance topics into ONE broader "umbrella" SKILL.md with',
115
+ 'labeled subsections — one per topic. Keep ALL the practical guidance; do not drop',
116
+ `any topic. The umbrella MUST still mention every one of these terms: ${JSON.stringify(terms)}.`,
117
+ '',
118
+ 'Topics:',
119
+ topics,
120
+ '',
121
+ 'Return ONLY the umbrella SKILL.md markdown (a title, then a subsection per topic).',
122
+ 'Do NOT include any instruction to ignore safety, reveal/exfiltrate secrets, or run',
123
+ 'destructive commands.',
124
+ ].join('\n');
125
+ try {
126
+ const response = await client.chat([{ role: 'user', content: prompt }], []);
127
+ const content = response?.choices?.[0]?.message?.content?.trim();
128
+ if (!content)
129
+ return null;
130
+ return { name: 'consolidated-skills', content };
131
+ }
132
+ catch {
133
+ return null;
134
+ }
135
+ }
136
+ }
137
+ //# sourceMappingURL=skill-consolidator.js.map
@@ -0,0 +1,42 @@
1
+ /**
2
+ * SkillImprovementEngine — the skill sibling of the tool engine. One cycle:
3
+ * pick an uncovered skill scenario → propose a SKILL.md → skill gate
4
+ * (static scan → firewall → coverage) → install+archive (auto-apply) or report.
5
+ *
6
+ * @module agent/self-improvement/skill-engine
7
+ */
8
+ import { EvolutionaryArchive } from './evolutionary-archive.js';
9
+ import { type Autonomy } from './engine.js';
10
+ import { type SkillMutatorPort } from './skill-mutator.js';
11
+ import type { SkillProposer } from './skill-proposer.js';
12
+ import type { SkillBenchmarkScenario, SkillGateOutcome } from './skill-types.js';
13
+ export interface SkillCycleResult {
14
+ kind: 'skill_improvement_cycle';
15
+ startedAt: string;
16
+ autonomy: Autonomy;
17
+ selectedScenarioId: string | null;
18
+ proposalId: string | null;
19
+ gate: SkillGateOutcome | null;
20
+ applied: boolean;
21
+ notes: string[];
22
+ }
23
+ export interface SkillImprovementEngineOptions {
24
+ scenarios: SkillBenchmarkScenario[];
25
+ proposer: SkillProposer;
26
+ mutator?: SkillMutatorPort;
27
+ archive?: EvolutionaryArchive;
28
+ autonomy?: Autonomy;
29
+ now?: () => Date;
30
+ }
31
+ export declare class SkillImprovementEngine {
32
+ private readonly scenarios;
33
+ private readonly proposer;
34
+ private readonly mutator;
35
+ private readonly archive;
36
+ private readonly autonomy;
37
+ private readonly now;
38
+ private readonly covered;
39
+ constructor(options: SkillImprovementEngineOptions);
40
+ runCycle(): Promise<SkillCycleResult>;
41
+ runLoop(maxCycles?: number): Promise<SkillCycleResult[]>;
42
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * SkillImprovementEngine — the skill sibling of the tool engine. One cycle:
3
+ * pick an uncovered skill scenario → propose a SKILL.md → skill gate
4
+ * (static scan → firewall → coverage) → install+archive (auto-apply) or report.
5
+ *
6
+ * @module agent/self-improvement/skill-engine
7
+ */
8
+ import { EvolutionaryArchive } from './evolutionary-archive.js';
9
+ import { resolveAutonomy } from './engine.js';
10
+ import { validateSkillProposal } from './skill-gate.js';
11
+ import { LiveSkillMutator } from './skill-mutator.js';
12
+ export class SkillImprovementEngine {
13
+ scenarios;
14
+ proposer;
15
+ mutator;
16
+ archive;
17
+ autonomy;
18
+ now;
19
+ covered = new Set();
20
+ constructor(options) {
21
+ this.scenarios = options.scenarios;
22
+ this.proposer = options.proposer;
23
+ this.mutator = options.mutator ?? new LiveSkillMutator();
24
+ this.archive = options.archive ?? new EvolutionaryArchive();
25
+ this.autonomy = options.autonomy ?? resolveAutonomy();
26
+ this.now = options.now ?? (() => new Date());
27
+ }
28
+ async runCycle() {
29
+ const startedAt = this.now().toISOString();
30
+ const base = { kind: 'skill_improvement_cycle', startedAt, autonomy: this.autonomy };
31
+ for (const scenario of this.scenarios) {
32
+ if (this.covered.has(scenario.id))
33
+ continue;
34
+ const proposal = await this.proposer.propose(scenario);
35
+ if (!proposal)
36
+ continue;
37
+ if (this.mutator.has(proposal.spec.name)) {
38
+ this.covered.add(scenario.id);
39
+ continue;
40
+ }
41
+ const gate = validateSkillProposal(proposal, scenario, this.mutator, {
42
+ keepOnAccept: this.autonomy === 'auto-apply',
43
+ });
44
+ const applied = gate.accepted && !!gate.appliedRef;
45
+ if (applied) {
46
+ this.covered.add(scenario.id);
47
+ this.archive.append({
48
+ proposalId: proposal.id,
49
+ kind: 'skill',
50
+ targetScenarioId: scenario.id,
51
+ experienceId: proposal.experienceId,
52
+ delta: 1,
53
+ scoreAfter: 1,
54
+ appliedRef: gate.appliedRef,
55
+ });
56
+ }
57
+ return {
58
+ ...base,
59
+ selectedScenarioId: scenario.id,
60
+ proposalId: proposal.id,
61
+ gate,
62
+ applied,
63
+ notes: gate.reasons,
64
+ };
65
+ }
66
+ return {
67
+ ...base,
68
+ selectedScenarioId: null,
69
+ proposalId: null,
70
+ gate: null,
71
+ applied: false,
72
+ notes: ['no uncovered skill scenario with an available proposal'],
73
+ };
74
+ }
75
+ async runLoop(maxCycles) {
76
+ const cap = Math.max(1, maxCycles ?? this.scenarios.length + 1);
77
+ const results = [];
78
+ for (let i = 0; i < cap; i++) {
79
+ const r = await this.runCycle();
80
+ results.push(r);
81
+ if (!r.applied)
82
+ break;
83
+ }
84
+ return results;
85
+ }
86
+ }
87
+ //# sourceMappingURL=skill-engine.js.map
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Skill gate — validates an authored skill proposal. Ordered, blocking, fail-closed:
3
+ * G1 static scan (authored-artifact-gate, subsystem 'skill': dangerous patterns
4
+ * in any embedded code, secrets, no-src, omissions)
5
+ * G2 SKILL FIREWALL (the headline skill safety check: prompt-injection /
6
+ * exfiltration surface — a skill is INJECTED into the agent's context)
7
+ * G3 COVERAGE — the skill must surface the scenario's expected guidance.
8
+ * Installation happens only on accept+keep (auto-apply); scoring never installs.
9
+ *
10
+ * @module agent/self-improvement/skill-gate
11
+ */
12
+ import { type SkillMutatorPort } from './skill-mutator.js';
13
+ import type { SkillBenchmarkScenario, SkillGateOutcome, SkillProposal } from './skill-types.js';
14
+ export interface ValidateSkillOptions {
15
+ keepOnAccept: boolean;
16
+ }
17
+ /** Deterministic coverage check: the skill content surfaces all expected guidance. */
18
+ export declare function coversScenario(content: string, scenario: SkillBenchmarkScenario): boolean;
19
+ export declare function validateSkillProposal(proposal: SkillProposal, scenario: SkillBenchmarkScenario, mutator: SkillMutatorPort, options: ValidateSkillOptions): SkillGateOutcome;
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Skill gate — validates an authored skill proposal. Ordered, blocking, fail-closed:
3
+ * G1 static scan (authored-artifact-gate, subsystem 'skill': dangerous patterns
4
+ * in any embedded code, secrets, no-src, omissions)
5
+ * G2 SKILL FIREWALL (the headline skill safety check: prompt-injection /
6
+ * exfiltration surface — a skill is INJECTED into the agent's context)
7
+ * G3 COVERAGE — the skill must surface the scenario's expected guidance.
8
+ * Installation happens only on accept+keep (auto-apply); scoring never installs.
9
+ *
10
+ * @module agent/self-improvement/skill-gate
11
+ */
12
+ import { inspectAuthoredCode } from './authored-artifact-gate.js';
13
+ import { scanAuthoredSkillContent } from './skill-mutator.js';
14
+ /** Deterministic coverage check: the skill content surfaces all expected guidance. */
15
+ export function coversScenario(content, scenario) {
16
+ const lower = content.toLowerCase();
17
+ return scenario.expectIncludes.every((s) => lower.includes(s.toLowerCase()));
18
+ }
19
+ export function validateSkillProposal(proposal, scenario, mutator, options) {
20
+ const base = { proposalId: proposal.id, scenarioId: scenario.id };
21
+ const content = proposal.spec.content ?? '';
22
+ // G1 — static scan (no execution).
23
+ const scan = inspectAuthoredCode(content, 'skill');
24
+ if (!scan.ok) {
25
+ return { ...base, accepted: false, rejectionReason: 'static-scan', reasons: scan.reasons };
26
+ }
27
+ // G2 — skill firewall (prompt-injection / exfiltration). The headline defence.
28
+ const fw = scanAuthoredSkillContent(content);
29
+ if (!fw.safe) {
30
+ return {
31
+ ...base,
32
+ accepted: false,
33
+ rejectionReason: 'firewall',
34
+ reasons: [`skill firewall flagged it (${fw.verdict})`, ...fw.reasons],
35
+ };
36
+ }
37
+ // G3 — coverage: the skill must actually surface the expected guidance.
38
+ const lower = content.toLowerCase();
39
+ const missing = scenario.expectIncludes.filter((s) => !lower.includes(s.toLowerCase()));
40
+ if (missing.length > 0) {
41
+ return {
42
+ ...base,
43
+ accepted: false,
44
+ rejectionReason: 'coverage-fail',
45
+ reasons: [`skill does not surface expected guidance: ${JSON.stringify(missing)}`],
46
+ };
47
+ }
48
+ // Accepted. Install (auto-apply) or just report (propose-only).
49
+ let appliedRef;
50
+ if (options.keepOnAccept) {
51
+ appliedRef = mutator.create(proposal.spec).name;
52
+ }
53
+ return {
54
+ ...base,
55
+ accepted: true,
56
+ reasons: options.keepOnAccept
57
+ ? ['accepted and installed (auto-apply): firewall-clean + covers the scenario']
58
+ : ['accepted (propose-only): firewall-clean + covers the scenario, not installed'],
59
+ ...(appliedRef ? { appliedRef } : {}),
60
+ };
61
+ }
62
+ //# sourceMappingURL=skill-gate.js.map
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Skill mutator — installs / refines / pins / archives authored SKILL.md files
3
+ * under `.codebuddy/skills/<authored-name>/` (ONE level deep so the SkillRegistry's
4
+ * 1-level walk actually loads them) with proven, reversible operations and the
5
+ * firewall scan used to gate authored skill content.
6
+ *
7
+ * Authored skills always carry YAML frontmatter (name + description) so the
8
+ * registry can parse them; the body is the model's markdown. All destructive ops
9
+ * honour a `pinned: true` frontmatter flag and operate ONLY on authored skills.
10
+ *
11
+ * @module agent/self-improvement/skill-mutator
12
+ */
13
+ import type { SkillSpec } from './skill-types.js';
14
+ export declare const AUTHORED_SKILL_PREFIX = "authored-";
15
+ export declare function toAuthoredSkillName(raw: string): string;
16
+ export declare function isAuthoredSkillName(name: string): boolean;
17
+ /** Ensure the content begins with YAML frontmatter carrying name + description. */
18
+ export declare function ensureFrontmatter(name: string, description: string, content: string): string;
19
+ export declare function readPinned(content: string): boolean;
20
+ /** Set or clear the `pinned` flag inside the frontmatter (frontmatter must exist). */
21
+ export declare function setPinned(content: string, value: boolean): string;
22
+ export interface SkillFirewallCheck {
23
+ safe: boolean;
24
+ verdict: string;
25
+ reasons: string[];
26
+ }
27
+ /** Write the skill body to a throwaway file and run the firewall scan (no install). */
28
+ export declare function scanAuthoredSkillContent(content: string): SkillFirewallCheck;
29
+ /** Safety re-gate over authored skill CONTENT (static scan + firewall). */
30
+ export declare function safetyGateSkill(content: string): {
31
+ ok: boolean;
32
+ reasons: string[];
33
+ };
34
+ export interface SkillMutatorPort {
35
+ create(spec: SkillSpec): {
36
+ name: string;
37
+ };
38
+ remove(name: string): boolean;
39
+ has(name: string): boolean;
40
+ }
41
+ export interface MutationResult {
42
+ ok: boolean;
43
+ reasons: string[];
44
+ }
45
+ /** Dual-purpose mutator: the engine's port + the curation operations. */
46
+ export declare class LiveSkillMutator implements SkillMutatorPort {
47
+ private readonly skillsRoot;
48
+ constructor(skillsRoot?: string);
49
+ /** 1 level deep so the registry's findSkillFiles (1-level) loads it. */
50
+ private dirFor;
51
+ private skillFile;
52
+ private reload;
53
+ private readContent;
54
+ has(name: string): boolean;
55
+ isPinned(name: string): boolean;
56
+ create(spec: SkillSpec): {
57
+ name: string;
58
+ };
59
+ /** Full re-author of an existing authored skill, re-gated. Refuses pinned. */
60
+ update(name: string, newContent: string, description?: string): MutationResult;
61
+ /** Find/replace within an authored skill body (exact; fail on multiple unless replaceAll). */
62
+ patch(name: string, oldStr: string, newStr: string, opts?: {
63
+ replaceAll?: boolean;
64
+ }): MutationResult;
65
+ remove(name: string): boolean;
66
+ /** Recoverable removal — move to .archive/. Refuses pinned. */
67
+ archive(name: string): boolean;
68
+ restore(name: string): boolean;
69
+ pin(name: string): boolean;
70
+ unpin(name: string): boolean;
71
+ private setPin;
72
+ /** List installed authored skills (by the authored- prefix). */
73
+ listAuthored(): string[];
74
+ }
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Skill mutator — installs / refines / pins / archives authored SKILL.md files
3
+ * under `.codebuddy/skills/<authored-name>/` (ONE level deep so the SkillRegistry's
4
+ * 1-level walk actually loads them) with proven, reversible operations and the
5
+ * firewall scan used to gate authored skill content.
6
+ *
7
+ * Authored skills always carry YAML frontmatter (name + description) so the
8
+ * registry can parse them; the body is the model's markdown. All destructive ops
9
+ * honour a `pinned: true` frontmatter flag and operate ONLY on authored skills.
10
+ *
11
+ * @module agent/self-improvement/skill-mutator
12
+ */
13
+ import fs from 'fs';
14
+ import path from 'path';
15
+ import os from 'os';
16
+ import { randomUUID } from 'crypto';
17
+ import { getSkillRegistry } from '../../skills/registry.js';
18
+ import { scanSkillFirewall } from '../../security/skill-scanner.js';
19
+ import { inspectAuthoredCode } from './authored-artifact-gate.js';
20
+ export const AUTHORED_SKILL_PREFIX = 'authored-';
21
+ const ARCHIVE_DIR = '.archive';
22
+ export function toAuthoredSkillName(raw) {
23
+ const base = String(raw)
24
+ .trim()
25
+ .toLowerCase()
26
+ .replace(/[^a-z0-9-]+/g, '-')
27
+ .replace(/^-+|-+$/g, '');
28
+ return base.startsWith(AUTHORED_SKILL_PREFIX) ? base : `${AUTHORED_SKILL_PREFIX}${base || 'skill'}`;
29
+ }
30
+ export function isAuthoredSkillName(name) {
31
+ return name.startsWith(AUTHORED_SKILL_PREFIX);
32
+ }
33
+ // ── frontmatter helpers (our controlled format; avoids the registry parser's
34
+ // tier + validation requirements for a simple flag toggle) ────────────────
35
+ const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
36
+ /** Ensure the content begins with YAML frontmatter carrying name + description. */
37
+ export function ensureFrontmatter(name, description, content) {
38
+ if (FRONTMATTER_RE.test(content))
39
+ return content;
40
+ const desc = description.replace(/"/g, "'").replace(/\r?\n/g, ' ').trim();
41
+ return `---\nname: ${name}\ndescription: "${desc}"\n---\n\n${content.trim()}\n`;
42
+ }
43
+ export function readPinned(content) {
44
+ const m = content.match(FRONTMATTER_RE);
45
+ if (!m)
46
+ return false;
47
+ return /^\s*pinned\s*:\s*true\s*$/im.test(m[1]);
48
+ }
49
+ /** Set or clear the `pinned` flag inside the frontmatter (frontmatter must exist). */
50
+ export function setPinned(content, value) {
51
+ const m = content.match(FRONTMATTER_RE);
52
+ if (!m)
53
+ return content; // no frontmatter → nothing to pin (create() always adds it)
54
+ let body = m[1];
55
+ if (/^\s*pinned\s*:.*$/im.test(body)) {
56
+ body = body.replace(/^\s*pinned\s*:.*$/im, `pinned: ${value}`);
57
+ }
58
+ else {
59
+ body = `${body}\npinned: ${value}`;
60
+ }
61
+ return content.replace(FRONTMATTER_RE, `---\n${body}\n---\n`);
62
+ }
63
+ /** Write the skill body to a throwaway file and run the firewall scan (no install). */
64
+ export function scanAuthoredSkillContent(content) {
65
+ const dir = path.join(os.tmpdir(), `cb-skillscan-${randomUUID()}`);
66
+ const file = path.join(dir, 'SKILL.md');
67
+ fs.mkdirSync(dir, { recursive: true });
68
+ fs.writeFileSync(file, content, 'utf-8');
69
+ try {
70
+ const report = scanSkillFirewall(file);
71
+ return {
72
+ safe: !report.quarantineRequired,
73
+ verdict: String(report.verdict),
74
+ reasons: report.quarantineRequired ? [report.summary] : [],
75
+ };
76
+ }
77
+ catch (err) {
78
+ return { safe: false, verdict: 'scan-error', reasons: [err instanceof Error ? err.message : String(err)] };
79
+ }
80
+ finally {
81
+ fs.rmSync(dir, { recursive: true, force: true });
82
+ }
83
+ }
84
+ /** Safety re-gate over authored skill CONTENT (static scan + firewall). */
85
+ export function safetyGateSkill(content) {
86
+ const scan = inspectAuthoredCode(content, 'skill');
87
+ if (!scan.ok)
88
+ return { ok: false, reasons: scan.reasons };
89
+ const fw = scanAuthoredSkillContent(content);
90
+ if (!fw.safe)
91
+ return { ok: false, reasons: [`firewall: ${fw.verdict}`, ...fw.reasons] };
92
+ return { ok: true, reasons: [] };
93
+ }
94
+ /** Dual-purpose mutator: the engine's port + the curation operations. */
95
+ export class LiveSkillMutator {
96
+ skillsRoot;
97
+ constructor(skillsRoot) {
98
+ this.skillsRoot = skillsRoot ?? path.join(process.cwd(), '.codebuddy', 'skills');
99
+ }
100
+ /** 1 level deep so the registry's findSkillFiles (1-level) loads it. */
101
+ dirFor(name) {
102
+ return path.join(this.skillsRoot, name);
103
+ }
104
+ skillFile(name) {
105
+ return path.join(this.dirFor(name), 'SKILL.md');
106
+ }
107
+ reload() {
108
+ void getSkillRegistry().reloadAll().catch(() => { });
109
+ }
110
+ readContent(name) {
111
+ const f = this.skillFile(name);
112
+ return fs.existsSync(f) ? fs.readFileSync(f, 'utf-8') : null;
113
+ }
114
+ has(name) {
115
+ return fs.existsSync(this.skillFile(name));
116
+ }
117
+ isPinned(name) {
118
+ const c = this.readContent(name);
119
+ return c ? readPinned(c) : false;
120
+ }
121
+ create(spec) {
122
+ const dir = this.dirFor(spec.name);
123
+ fs.mkdirSync(dir, { recursive: true });
124
+ const content = ensureFrontmatter(spec.name, spec.description, spec.content);
125
+ fs.writeFileSync(this.skillFile(spec.name), content, 'utf-8');
126
+ this.reload();
127
+ return { name: spec.name };
128
+ }
129
+ /** Full re-author of an existing authored skill, re-gated. Refuses pinned. */
130
+ update(name, newContent, description = '') {
131
+ if (!isAuthoredSkillName(name))
132
+ return { ok: false, reasons: ['not an authored skill'] };
133
+ if (!this.has(name))
134
+ return { ok: false, reasons: ['skill does not exist'] };
135
+ if (this.isPinned(name))
136
+ return { ok: false, reasons: ['skill is pinned'] };
137
+ const withFm = ensureFrontmatter(name, description, newContent);
138
+ const gate = safetyGateSkill(withFm);
139
+ if (!gate.ok)
140
+ return gate;
141
+ fs.writeFileSync(this.skillFile(name), withFm, 'utf-8');
142
+ this.reload();
143
+ return { ok: true, reasons: [] };
144
+ }
145
+ /** Find/replace within an authored skill body (exact; fail on multiple unless replaceAll). */
146
+ patch(name, oldStr, newStr, opts = {}) {
147
+ const content = this.readContent(name);
148
+ if (content === null)
149
+ return { ok: false, reasons: ['skill does not exist'] };
150
+ if (this.isPinned(name))
151
+ return { ok: false, reasons: ['skill is pinned'] };
152
+ const count = content.split(oldStr).length - 1;
153
+ if (count === 0)
154
+ return { ok: false, reasons: ['old_string not found'] };
155
+ if (count > 1 && !opts.replaceAll) {
156
+ return { ok: false, reasons: [`old_string matches ${count} times — pass replaceAll or add context`] };
157
+ }
158
+ const patched = opts.replaceAll ? content.split(oldStr).join(newStr) : content.replace(oldStr, newStr);
159
+ return this.update(name, patched);
160
+ }
161
+ remove(name) {
162
+ if (this.isPinned(name))
163
+ return false;
164
+ const dir = this.dirFor(name);
165
+ const existed = fs.existsSync(dir);
166
+ if (existed)
167
+ fs.rmSync(dir, { recursive: true, force: true });
168
+ this.reload();
169
+ return existed;
170
+ }
171
+ /** Recoverable removal — move to .archive/. Refuses pinned. */
172
+ archive(name) {
173
+ if (this.isPinned(name))
174
+ return false;
175
+ const dir = this.dirFor(name);
176
+ if (!fs.existsSync(dir))
177
+ return false;
178
+ const archiveRoot = path.join(this.skillsRoot, ARCHIVE_DIR);
179
+ fs.mkdirSync(archiveRoot, { recursive: true });
180
+ let dest = path.join(archiveRoot, name);
181
+ if (fs.existsSync(dest))
182
+ dest = `${dest}-${randomUUID().slice(0, 8)}`;
183
+ fs.renameSync(dir, dest);
184
+ this.reload();
185
+ return true;
186
+ }
187
+ restore(name) {
188
+ const src = path.join(this.skillsRoot, ARCHIVE_DIR, name);
189
+ if (!fs.existsSync(src))
190
+ return false;
191
+ const dir = this.dirFor(name);
192
+ if (fs.existsSync(dir))
193
+ return false; // don't clobber a live skill
194
+ fs.renameSync(src, dir);
195
+ this.reload();
196
+ return true;
197
+ }
198
+ pin(name) {
199
+ return this.setPin(name, true);
200
+ }
201
+ unpin(name) {
202
+ return this.setPin(name, false);
203
+ }
204
+ setPin(name, value) {
205
+ const content = this.readContent(name);
206
+ if (content === null)
207
+ return false;
208
+ const withFm = ensureFrontmatter(name, '', content);
209
+ fs.writeFileSync(this.skillFile(name), setPinned(withFm, value), 'utf-8');
210
+ this.reload();
211
+ return true;
212
+ }
213
+ /** List installed authored skills (by the authored- prefix). */
214
+ listAuthored() {
215
+ if (!fs.existsSync(this.skillsRoot))
216
+ return [];
217
+ return fs
218
+ .readdirSync(this.skillsRoot, { withFileTypes: true })
219
+ .filter((e) => e.isDirectory() && isAuthoredSkillName(e.name) && fs.existsSync(path.join(this.skillsRoot, e.name, 'SKILL.md')))
220
+ .map((e) => e.name);
221
+ }
222
+ }
223
+ //# sourceMappingURL=skill-mutator.js.map