calvyn-code 0.14.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 (1718) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +217 -0
  3. package/README.zh-CN.md +180 -0
  4. package/acp_adapter/__init__.py +1 -0
  5. package/acp_adapter/__main__.py +5 -0
  6. package/acp_adapter/auth.py +68 -0
  7. package/acp_adapter/bootstrap/__init__.py +0 -0
  8. package/acp_adapter/bootstrap/bootstrap_browser_tools.ps1 +288 -0
  9. package/acp_adapter/bootstrap/bootstrap_browser_tools.sh +399 -0
  10. package/acp_adapter/entry.py +292 -0
  11. package/acp_adapter/events.py +265 -0
  12. package/acp_adapter/permissions.py +148 -0
  13. package/acp_adapter/server.py +1713 -0
  14. package/acp_adapter/session.py +629 -0
  15. package/acp_adapter/tools.py +1180 -0
  16. package/agent/__init__.py +6 -0
  17. package/agent/__pycache__/__init__.cpython-312.pyc +0 -0
  18. package/agent/__pycache__/account_usage.cpython-312.pyc +0 -0
  19. package/agent/__pycache__/anthropic_adapter.cpython-312.pyc +0 -0
  20. package/agent/__pycache__/async_utils.cpython-312.pyc +0 -0
  21. package/agent/__pycache__/auxiliary_client.cpython-312.pyc +0 -0
  22. package/agent/__pycache__/codex_responses_adapter.cpython-312.pyc +0 -0
  23. package/agent/__pycache__/context_compressor.cpython-312.pyc +0 -0
  24. package/agent/__pycache__/context_engine.cpython-312.pyc +0 -0
  25. package/agent/__pycache__/context_references.cpython-312.pyc +0 -0
  26. package/agent/__pycache__/credential_pool.cpython-312.pyc +0 -0
  27. package/agent/__pycache__/curator.cpython-312.pyc +0 -0
  28. package/agent/__pycache__/display.cpython-312.pyc +0 -0
  29. package/agent/__pycache__/error_classifier.cpython-312.pyc +0 -0
  30. package/agent/__pycache__/file_safety.cpython-312.pyc +0 -0
  31. package/agent/__pycache__/google_code_assist.cpython-312.pyc +0 -0
  32. package/agent/__pycache__/google_oauth.cpython-312.pyc +0 -0
  33. package/agent/__pycache__/i18n.cpython-312.pyc +0 -0
  34. package/agent/__pycache__/image_gen_provider.cpython-312.pyc +0 -0
  35. package/agent/__pycache__/image_gen_registry.cpython-312.pyc +0 -0
  36. package/agent/__pycache__/insights.cpython-312.pyc +0 -0
  37. package/agent/__pycache__/lmstudio_reasoning.cpython-312.pyc +0 -0
  38. package/agent/__pycache__/manual_compression_feedback.cpython-312.pyc +0 -0
  39. package/agent/__pycache__/markdown_tables.cpython-312.pyc +0 -0
  40. package/agent/__pycache__/memory_manager.cpython-312.pyc +0 -0
  41. package/agent/__pycache__/memory_provider.cpython-312.pyc +0 -0
  42. package/agent/__pycache__/model_metadata.cpython-312.pyc +0 -0
  43. package/agent/__pycache__/models_dev.cpython-312.pyc +0 -0
  44. package/agent/__pycache__/moonshot_schema.cpython-312.pyc +0 -0
  45. package/agent/__pycache__/onboarding.cpython-312.pyc +0 -0
  46. package/agent/__pycache__/portal_tags.cpython-312.pyc +0 -0
  47. package/agent/__pycache__/prompt_builder.cpython-312.pyc +0 -0
  48. package/agent/__pycache__/prompt_caching.cpython-312.pyc +0 -0
  49. package/agent/__pycache__/redact.cpython-312.pyc +0 -0
  50. package/agent/__pycache__/retry_utils.cpython-312.pyc +0 -0
  51. package/agent/__pycache__/shell_hooks.cpython-312.pyc +0 -0
  52. package/agent/__pycache__/skill_commands.cpython-312.pyc +0 -0
  53. package/agent/__pycache__/skill_preprocessing.cpython-312.pyc +0 -0
  54. package/agent/__pycache__/skill_utils.cpython-312.pyc +0 -0
  55. package/agent/__pycache__/subdirectory_hints.cpython-312.pyc +0 -0
  56. package/agent/__pycache__/think_scrubber.cpython-312.pyc +0 -0
  57. package/agent/__pycache__/title_generator.cpython-312.pyc +0 -0
  58. package/agent/__pycache__/tool_guardrails.cpython-312.pyc +0 -0
  59. package/agent/__pycache__/tool_result_classification.cpython-312.pyc +0 -0
  60. package/agent/__pycache__/trajectory.cpython-312.pyc +0 -0
  61. package/agent/__pycache__/usage_pricing.cpython-312.pyc +0 -0
  62. package/agent/__pycache__/video_gen_provider.cpython-312.pyc +0 -0
  63. package/agent/__pycache__/video_gen_registry.cpython-312.pyc +0 -0
  64. package/agent/__pycache__/web_search_provider.cpython-312.pyc +0 -0
  65. package/agent/__pycache__/web_search_registry.cpython-312.pyc +0 -0
  66. package/agent/account_usage.py +326 -0
  67. package/agent/anthropic_adapter.py +2087 -0
  68. package/agent/async_utils.py +68 -0
  69. package/agent/auxiliary_client.py +4893 -0
  70. package/agent/bedrock_adapter.py +1276 -0
  71. package/agent/codex_responses_adapter.py +1084 -0
  72. package/agent/context_compressor.py +1583 -0
  73. package/agent/context_engine.py +211 -0
  74. package/agent/context_references.py +519 -0
  75. package/agent/copilot_acp_client.py +684 -0
  76. package/agent/credential_pool.py +1780 -0
  77. package/agent/credential_sources.py +449 -0
  78. package/agent/curator.py +1782 -0
  79. package/agent/curator_backup.py +694 -0
  80. package/agent/display.py +987 -0
  81. package/agent/error_classifier.py +1058 -0
  82. package/agent/file_safety.py +112 -0
  83. package/agent/gemini_cloudcode_adapter.py +909 -0
  84. package/agent/gemini_native_adapter.py +971 -0
  85. package/agent/gemini_schema.py +99 -0
  86. package/agent/google_code_assist.py +452 -0
  87. package/agent/google_oauth.py +1062 -0
  88. package/agent/i18n.py +258 -0
  89. package/agent/image_gen_provider.py +243 -0
  90. package/agent/image_gen_registry.py +145 -0
  91. package/agent/image_routing.py +301 -0
  92. package/agent/insights.py +931 -0
  93. package/agent/lmstudio_reasoning.py +48 -0
  94. package/agent/lsp/__init__.py +106 -0
  95. package/agent/lsp/__pycache__/__init__.cpython-312.pyc +0 -0
  96. package/agent/lsp/__pycache__/cli.cpython-312.pyc +0 -0
  97. package/agent/lsp/__pycache__/client.cpython-312.pyc +0 -0
  98. package/agent/lsp/__pycache__/eventlog.cpython-312.pyc +0 -0
  99. package/agent/lsp/__pycache__/manager.cpython-312.pyc +0 -0
  100. package/agent/lsp/__pycache__/protocol.cpython-312.pyc +0 -0
  101. package/agent/lsp/__pycache__/servers.cpython-312.pyc +0 -0
  102. package/agent/lsp/__pycache__/workspace.cpython-312.pyc +0 -0
  103. package/agent/lsp/cli.py +308 -0
  104. package/agent/lsp/client.py +930 -0
  105. package/agent/lsp/eventlog.py +213 -0
  106. package/agent/lsp/install.py +376 -0
  107. package/agent/lsp/manager.py +644 -0
  108. package/agent/lsp/protocol.py +196 -0
  109. package/agent/lsp/range_shift.py +149 -0
  110. package/agent/lsp/reporter.py +78 -0
  111. package/agent/lsp/servers.py +1040 -0
  112. package/agent/lsp/workspace.py +223 -0
  113. package/agent/manual_compression_feedback.py +49 -0
  114. package/agent/markdown_tables.py +309 -0
  115. package/agent/memory_manager.py +556 -0
  116. package/agent/memory_provider.py +279 -0
  117. package/agent/model_metadata.py +1827 -0
  118. package/agent/models_dev.py +724 -0
  119. package/agent/moonshot_schema.py +231 -0
  120. package/agent/nous_rate_guard.py +326 -0
  121. package/agent/onboarding.py +193 -0
  122. package/agent/plugin_llm.py +1046 -0
  123. package/agent/portal_tags.py +64 -0
  124. package/agent/prompt_builder.py +1457 -0
  125. package/agent/prompt_caching.py +79 -0
  126. package/agent/rate_limit_tracker.py +246 -0
  127. package/agent/redact.py +403 -0
  128. package/agent/retry_utils.py +57 -0
  129. package/agent/shell_hooks.py +837 -0
  130. package/agent/skill_commands.py +502 -0
  131. package/agent/skill_preprocessing.py +131 -0
  132. package/agent/skill_utils.py +512 -0
  133. package/agent/subdirectory_hints.py +224 -0
  134. package/agent/think_scrubber.py +386 -0
  135. package/agent/title_generator.py +171 -0
  136. package/agent/tool_guardrails.py +458 -0
  137. package/agent/tool_result_classification.py +26 -0
  138. package/agent/trajectory.py +56 -0
  139. package/agent/transports/__init__.py +68 -0
  140. package/agent/transports/__pycache__/__init__.cpython-312.pyc +0 -0
  141. package/agent/transports/__pycache__/anthropic.cpython-312.pyc +0 -0
  142. package/agent/transports/__pycache__/base.cpython-312.pyc +0 -0
  143. package/agent/transports/__pycache__/bedrock.cpython-312.pyc +0 -0
  144. package/agent/transports/__pycache__/chat_completions.cpython-312.pyc +0 -0
  145. package/agent/transports/__pycache__/codex.cpython-312.pyc +0 -0
  146. package/agent/transports/__pycache__/types.cpython-312.pyc +0 -0
  147. package/agent/transports/anthropic.py +179 -0
  148. package/agent/transports/base.py +89 -0
  149. package/agent/transports/bedrock.py +154 -0
  150. package/agent/transports/chat_completions.py +614 -0
  151. package/agent/transports/codex.py +283 -0
  152. package/agent/transports/codex_app_server.py +368 -0
  153. package/agent/transports/codex_app_server_session.py +810 -0
  154. package/agent/transports/codex_event_projector.py +312 -0
  155. package/agent/transports/hermes_tools_mcp_server.py +233 -0
  156. package/agent/transports/types.py +162 -0
  157. package/agent/usage_pricing.py +877 -0
  158. package/agent/video_gen_provider.py +300 -0
  159. package/agent/video_gen_registry.py +117 -0
  160. package/agent/web_search_provider.py +221 -0
  161. package/agent/web_search_registry.py +262 -0
  162. package/assets/banner.png +0 -0
  163. package/batch_runner.py +1303 -0
  164. package/bin/calvyn.js +67 -0
  165. package/calvyn_bootstrap.py +130 -0
  166. package/calvyn_constants.py +346 -0
  167. package/calvyn_logging.py +390 -0
  168. package/calvyn_state.py +2967 -0
  169. package/calvyn_time.py +105 -0
  170. package/cli.py +14160 -0
  171. package/cron/__init__.py +42 -0
  172. package/cron/__pycache__/__init__.cpython-312.pyc +0 -0
  173. package/cron/__pycache__/jobs.cpython-312.pyc +0 -0
  174. package/cron/__pycache__/scheduler.cpython-312.pyc +0 -0
  175. package/cron/jobs.py +1160 -0
  176. package/cron/scheduler.py +1832 -0
  177. package/gateway/__init__.py +35 -0
  178. package/gateway/__pycache__/__init__.cpython-312.pyc +0 -0
  179. package/gateway/__pycache__/channel_directory.cpython-312.pyc +0 -0
  180. package/gateway/__pycache__/config.cpython-312.pyc +0 -0
  181. package/gateway/__pycache__/delivery.cpython-312.pyc +0 -0
  182. package/gateway/__pycache__/display_config.cpython-312.pyc +0 -0
  183. package/gateway/__pycache__/hooks.cpython-312.pyc +0 -0
  184. package/gateway/__pycache__/pairing.cpython-312.pyc +0 -0
  185. package/gateway/__pycache__/platform_registry.cpython-312.pyc +0 -0
  186. package/gateway/__pycache__/restart.cpython-312.pyc +0 -0
  187. package/gateway/__pycache__/run.cpython-312.pyc +0 -0
  188. package/gateway/__pycache__/runtime_footer.cpython-312.pyc +0 -0
  189. package/gateway/__pycache__/session.cpython-312.pyc +0 -0
  190. package/gateway/__pycache__/session_context.cpython-312.pyc +0 -0
  191. package/gateway/__pycache__/shutdown_forensics.cpython-312.pyc +0 -0
  192. package/gateway/__pycache__/slash_access.cpython-312.pyc +0 -0
  193. package/gateway/__pycache__/status.cpython-312.pyc +0 -0
  194. package/gateway/__pycache__/stream_consumer.cpython-312.pyc +0 -0
  195. package/gateway/__pycache__/whatsapp_identity.cpython-312.pyc +0 -0
  196. package/gateway/assets/telegram-botfather-threads-settings.jpg +0 -0
  197. package/gateway/builtin_hooks/__init__.py +1 -0
  198. package/gateway/channel_directory.py +357 -0
  199. package/gateway/config.py +1873 -0
  200. package/gateway/delivery.py +258 -0
  201. package/gateway/display_config.py +206 -0
  202. package/gateway/hooks.py +210 -0
  203. package/gateway/mirror.py +179 -0
  204. package/gateway/pairing.py +322 -0
  205. package/gateway/platform_registry.py +260 -0
  206. package/gateway/platforms/ADDING_A_PLATFORM.md +374 -0
  207. package/gateway/platforms/__init__.py +45 -0
  208. package/gateway/platforms/__pycache__/__init__.cpython-312.pyc +0 -0
  209. package/gateway/platforms/__pycache__/base.cpython-312.pyc +0 -0
  210. package/gateway/platforms/__pycache__/helpers.cpython-312.pyc +0 -0
  211. package/gateway/platforms/__pycache__/telegram.cpython-312.pyc +0 -0
  212. package/gateway/platforms/__pycache__/telegram_network.cpython-312.pyc +0 -0
  213. package/gateway/platforms/__pycache__/yuanbao.cpython-312.pyc +0 -0
  214. package/gateway/platforms/__pycache__/yuanbao_media.cpython-312.pyc +0 -0
  215. package/gateway/platforms/__pycache__/yuanbao_proto.cpython-312.pyc +0 -0
  216. package/gateway/platforms/_http_client_limits.py +84 -0
  217. package/gateway/platforms/api_server.py +3488 -0
  218. package/gateway/platforms/base.py +3747 -0
  219. package/gateway/platforms/bluebubbles.py +937 -0
  220. package/gateway/platforms/dingtalk.py +1473 -0
  221. package/gateway/platforms/discord.py +5584 -0
  222. package/gateway/platforms/email.py +773 -0
  223. package/gateway/platforms/feishu.py +5059 -0
  224. package/gateway/platforms/feishu_comment.py +1382 -0
  225. package/gateway/platforms/feishu_comment_rules.py +430 -0
  226. package/gateway/platforms/helpers.py +279 -0
  227. package/gateway/platforms/homeassistant.py +449 -0
  228. package/gateway/platforms/matrix.py +2777 -0
  229. package/gateway/platforms/mattermost.py +852 -0
  230. package/gateway/platforms/msgraph_webhook.py +397 -0
  231. package/gateway/platforms/qqbot/__init__.py +91 -0
  232. package/gateway/platforms/qqbot/adapter.py +3072 -0
  233. package/gateway/platforms/qqbot/chunked_upload.py +602 -0
  234. package/gateway/platforms/qqbot/constants.py +74 -0
  235. package/gateway/platforms/qqbot/crypto.py +45 -0
  236. package/gateway/platforms/qqbot/keyboards.py +473 -0
  237. package/gateway/platforms/qqbot/onboard.py +220 -0
  238. package/gateway/platforms/qqbot/utils.py +71 -0
  239. package/gateway/platforms/signal.py +1518 -0
  240. package/gateway/platforms/signal_rate_limit.py +369 -0
  241. package/gateway/platforms/slack.py +3028 -0
  242. package/gateway/platforms/sms.py +377 -0
  243. package/gateway/platforms/telegram.py +4836 -0
  244. package/gateway/platforms/telegram_network.py +249 -0
  245. package/gateway/platforms/webhook.py +806 -0
  246. package/gateway/platforms/wecom.py +1610 -0
  247. package/gateway/platforms/wecom_callback.py +403 -0
  248. package/gateway/platforms/wecom_crypto.py +142 -0
  249. package/gateway/platforms/weixin.py +2170 -0
  250. package/gateway/platforms/whatsapp.py +1283 -0
  251. package/gateway/platforms/yuanbao.py +4873 -0
  252. package/gateway/platforms/yuanbao_media.py +645 -0
  253. package/gateway/platforms/yuanbao_proto.py +1209 -0
  254. package/gateway/platforms/yuanbao_sticker.py +558 -0
  255. package/gateway/restart.py +20 -0
  256. package/gateway/run.py +17074 -0
  257. package/gateway/runtime_footer.py +150 -0
  258. package/gateway/session.py +1399 -0
  259. package/gateway/session_context.py +156 -0
  260. package/gateway/shutdown_forensics.py +462 -0
  261. package/gateway/slash_access.py +229 -0
  262. package/gateway/status.py +972 -0
  263. package/gateway/sticker_cache.py +111 -0
  264. package/gateway/stream_consumer.py +1286 -0
  265. package/gateway/whatsapp_identity.py +156 -0
  266. package/hermes_cli/__init__.py +47 -0
  267. package/hermes_cli/__pycache__/__init__.cpython-312.pyc +0 -0
  268. package/hermes_cli/__pycache__/_parser.cpython-312.pyc +0 -0
  269. package/hermes_cli/__pycache__/auth.cpython-312.pyc +0 -0
  270. package/hermes_cli/__pycache__/banner.cpython-312.pyc +0 -0
  271. package/hermes_cli/__pycache__/browser_connect.cpython-312.pyc +0 -0
  272. package/hermes_cli/__pycache__/callbacks.cpython-312.pyc +0 -0
  273. package/hermes_cli/__pycache__/checkpoints.cpython-312.pyc +0 -0
  274. package/hermes_cli/__pycache__/cli_output.cpython-312.pyc +0 -0
  275. package/hermes_cli/__pycache__/codex_models.cpython-312.pyc +0 -0
  276. package/hermes_cli/__pycache__/codex_runtime_switch.cpython-312.pyc +0 -0
  277. package/hermes_cli/__pycache__/colors.cpython-312.pyc +0 -0
  278. package/hermes_cli/__pycache__/commands.cpython-312.pyc +0 -0
  279. package/hermes_cli/__pycache__/config.cpython-312.pyc +0 -0
  280. package/hermes_cli/__pycache__/copilot_auth.cpython-312.pyc +0 -0
  281. package/hermes_cli/__pycache__/curator.cpython-312.pyc +0 -0
  282. package/hermes_cli/__pycache__/curses_ui.cpython-312.pyc +0 -0
  283. package/hermes_cli/__pycache__/debug.cpython-312.pyc +0 -0
  284. package/hermes_cli/__pycache__/default_soul.cpython-312.pyc +0 -0
  285. package/hermes_cli/__pycache__/env_loader.cpython-312.pyc +0 -0
  286. package/hermes_cli/__pycache__/fallback_cmd.cpython-312.pyc +0 -0
  287. package/hermes_cli/__pycache__/gateway.cpython-312.pyc +0 -0
  288. package/hermes_cli/__pycache__/gateway_windows.cpython-312.pyc +0 -0
  289. package/hermes_cli/__pycache__/goals.cpython-312.pyc +0 -0
  290. package/hermes_cli/__pycache__/inventory.cpython-312.pyc +0 -0
  291. package/hermes_cli/__pycache__/kanban.cpython-312.pyc +0 -0
  292. package/hermes_cli/__pycache__/kanban_db.cpython-312.pyc +0 -0
  293. package/hermes_cli/__pycache__/main.cpython-312.pyc +0 -0
  294. package/hermes_cli/__pycache__/model_catalog.cpython-312.pyc +0 -0
  295. package/hermes_cli/__pycache__/model_normalize.cpython-312.pyc +0 -0
  296. package/hermes_cli/__pycache__/model_switch.cpython-312.pyc +0 -0
  297. package/hermes_cli/__pycache__/models.cpython-312.pyc +0 -0
  298. package/hermes_cli/__pycache__/nous_subscription.cpython-312.pyc +0 -0
  299. package/hermes_cli/__pycache__/pairing.cpython-312.pyc +0 -0
  300. package/hermes_cli/__pycache__/platforms.cpython-312.pyc +0 -0
  301. package/hermes_cli/__pycache__/plugins.cpython-312.pyc +0 -0
  302. package/hermes_cli/__pycache__/profiles.cpython-312.pyc +0 -0
  303. package/hermes_cli/__pycache__/providers.cpython-312.pyc +0 -0
  304. package/hermes_cli/__pycache__/pt_input_extras.cpython-312.pyc +0 -0
  305. package/hermes_cli/__pycache__/runtime_provider.cpython-312.pyc +0 -0
  306. package/hermes_cli/__pycache__/security_advisories.cpython-312.pyc +0 -0
  307. package/hermes_cli/__pycache__/setup.cpython-312.pyc +0 -0
  308. package/hermes_cli/__pycache__/skills_hub.cpython-312.pyc +0 -0
  309. package/hermes_cli/__pycache__/skin_engine.cpython-312.pyc +0 -0
  310. package/hermes_cli/__pycache__/stdio.cpython-312.pyc +0 -0
  311. package/hermes_cli/__pycache__/timeouts.cpython-312.pyc +0 -0
  312. package/hermes_cli/__pycache__/tips.cpython-312.pyc +0 -0
  313. package/hermes_cli/__pycache__/tools_config.cpython-312.pyc +0 -0
  314. package/hermes_cli/__pycache__/voice.cpython-312.pyc +0 -0
  315. package/hermes_cli/_parser.py +365 -0
  316. package/hermes_cli/_subprocess_compat.py +175 -0
  317. package/hermes_cli/auth.py +6299 -0
  318. package/hermes_cli/auth_commands.py +749 -0
  319. package/hermes_cli/azure_detect.py +300 -0
  320. package/hermes_cli/backup.py +938 -0
  321. package/hermes_cli/banner.py +703 -0
  322. package/hermes_cli/browser_connect.py +139 -0
  323. package/hermes_cli/callbacks.py +243 -0
  324. package/hermes_cli/checkpoints.py +244 -0
  325. package/hermes_cli/claw.py +810 -0
  326. package/hermes_cli/cli_output.py +78 -0
  327. package/hermes_cli/clipboard.py +495 -0
  328. package/hermes_cli/codex_models.py +198 -0
  329. package/hermes_cli/codex_runtime_plugin_migration.py +757 -0
  330. package/hermes_cli/codex_runtime_switch.py +266 -0
  331. package/hermes_cli/colors.py +38 -0
  332. package/hermes_cli/commands.py +1728 -0
  333. package/hermes_cli/completion.py +315 -0
  334. package/hermes_cli/config.py +5382 -0
  335. package/hermes_cli/copilot_auth.py +392 -0
  336. package/hermes_cli/cron.py +313 -0
  337. package/hermes_cli/curator.py +598 -0
  338. package/hermes_cli/curses_ui.py +472 -0
  339. package/hermes_cli/debug.py +747 -0
  340. package/hermes_cli/default_soul.py +11 -0
  341. package/hermes_cli/dep_ensure.py +107 -0
  342. package/hermes_cli/dingtalk_auth.py +293 -0
  343. package/hermes_cli/doctor.py +1863 -0
  344. package/hermes_cli/dump.py +326 -0
  345. package/hermes_cli/env_loader.py +175 -0
  346. package/hermes_cli/fallback_cmd.py +361 -0
  347. package/hermes_cli/gateway.py +5422 -0
  348. package/hermes_cli/gateway_windows.py +692 -0
  349. package/hermes_cli/goals.py +757 -0
  350. package/hermes_cli/hooks.py +385 -0
  351. package/hermes_cli/inventory.py +240 -0
  352. package/hermes_cli/kanban.py +2252 -0
  353. package/hermes_cli/kanban_db.py +4840 -0
  354. package/hermes_cli/kanban_diagnostics.py +776 -0
  355. package/hermes_cli/kanban_specify.py +266 -0
  356. package/hermes_cli/logs.py +391 -0
  357. package/hermes_cli/main.py +12396 -0
  358. package/hermes_cli/mcp_config.py +781 -0
  359. package/hermes_cli/memory_setup.py +465 -0
  360. package/hermes_cli/model_catalog.py +330 -0
  361. package/hermes_cli/model_normalize.py +473 -0
  362. package/hermes_cli/model_switch.py +1777 -0
  363. package/hermes_cli/models.py +3789 -0
  364. package/hermes_cli/nous_subscription.py +799 -0
  365. package/hermes_cli/oneshot.py +351 -0
  366. package/hermes_cli/pairing.py +115 -0
  367. package/hermes_cli/platforms.py +83 -0
  368. package/hermes_cli/plugins.py +1562 -0
  369. package/hermes_cli/plugins_cmd.py +1587 -0
  370. package/hermes_cli/profile_distribution.py +703 -0
  371. package/hermes_cli/profiles.py +1319 -0
  372. package/hermes_cli/providers.py +720 -0
  373. package/hermes_cli/proxy/__init__.py +20 -0
  374. package/hermes_cli/proxy/adapters/__init__.py +35 -0
  375. package/hermes_cli/proxy/adapters/base.py +94 -0
  376. package/hermes_cli/proxy/adapters/nous_portal.py +137 -0
  377. package/hermes_cli/proxy/cli.py +141 -0
  378. package/hermes_cli/proxy/server.py +265 -0
  379. package/hermes_cli/pt_input_extras.py +83 -0
  380. package/hermes_cli/pty_bridge.py +237 -0
  381. package/hermes_cli/relaunch.py +205 -0
  382. package/hermes_cli/runtime_provider.py +1428 -0
  383. package/hermes_cli/security_advisories.py +452 -0
  384. package/hermes_cli/setup.py +3559 -0
  385. package/hermes_cli/skills_config.py +177 -0
  386. package/hermes_cli/skills_hub.py +1595 -0
  387. package/hermes_cli/skin_engine.py +929 -0
  388. package/hermes_cli/slack_cli.py +160 -0
  389. package/hermes_cli/status.py +550 -0
  390. package/hermes_cli/stdio.py +252 -0
  391. package/hermes_cli/timeouts.py +82 -0
  392. package/hermes_cli/tips.py +487 -0
  393. package/hermes_cli/tools_config.py +3151 -0
  394. package/hermes_cli/uninstall.py +681 -0
  395. package/hermes_cli/vercel_auth.py +70 -0
  396. package/hermes_cli/voice.py +846 -0
  397. package/hermes_cli/web_server.py +4438 -0
  398. package/hermes_cli/webhook.py +275 -0
  399. package/locales/af.yaml +350 -0
  400. package/locales/de.yaml +350 -0
  401. package/locales/en.yaml +365 -0
  402. package/locales/es.yaml +350 -0
  403. package/locales/fr.yaml +350 -0
  404. package/locales/ga.yaml +354 -0
  405. package/locales/hu.yaml +350 -0
  406. package/locales/it.yaml +350 -0
  407. package/locales/ja.yaml +350 -0
  408. package/locales/ko.yaml +350 -0
  409. package/locales/pt.yaml +350 -0
  410. package/locales/ru.yaml +350 -0
  411. package/locales/tr.yaml +350 -0
  412. package/locales/uk.yaml +350 -0
  413. package/locales/zh-hant.yaml +350 -0
  414. package/locales/zh.yaml +350 -0
  415. package/mcp_serve.py +898 -0
  416. package/model_tools.py +899 -0
  417. package/optional-skills/DESCRIPTION.md +24 -0
  418. package/optional-skills/autonomous-ai-agents/DESCRIPTION.md +2 -0
  419. package/optional-skills/autonomous-ai-agents/blackbox/SKILL.md +144 -0
  420. package/optional-skills/autonomous-ai-agents/honcho/SKILL.md +431 -0
  421. package/optional-skills/blockchain/evm/SKILL.md +211 -0
  422. package/optional-skills/blockchain/evm/scripts/evm_client.py +1508 -0
  423. package/optional-skills/blockchain/hyperliquid/SKILL.md +211 -0
  424. package/optional-skills/blockchain/hyperliquid/scripts/hyperliquid_client.py +1660 -0
  425. package/optional-skills/blockchain/solana/SKILL.md +208 -0
  426. package/optional-skills/blockchain/solana/scripts/solana_client.py +698 -0
  427. package/optional-skills/communication/DESCRIPTION.md +1 -0
  428. package/optional-skills/communication/one-three-one-rule/SKILL.md +104 -0
  429. package/optional-skills/creative/blender-mcp/SKILL.md +117 -0
  430. package/optional-skills/creative/concept-diagrams/SKILL.md +362 -0
  431. package/optional-skills/creative/concept-diagrams/examples/apartment-floor-plan-conversion.md +244 -0
  432. package/optional-skills/creative/concept-diagrams/examples/automated-password-reset-flow.md +276 -0
  433. package/optional-skills/creative/concept-diagrams/examples/autonomous-llm-research-agent-flow.md +240 -0
  434. package/optional-skills/creative/concept-diagrams/examples/banana-journey-tree-to-smoothie.md +161 -0
  435. package/optional-skills/creative/concept-diagrams/examples/commercial-aircraft-structure.md +209 -0
  436. package/optional-skills/creative/concept-diagrams/examples/cpu-ooo-microarchitecture.md +236 -0
  437. package/optional-skills/creative/concept-diagrams/examples/electricity-grid-flow.md +182 -0
  438. package/optional-skills/creative/concept-diagrams/examples/feature-film-production-pipeline.md +172 -0
  439. package/optional-skills/creative/concept-diagrams/examples/hospital-emergency-department-flow.md +165 -0
  440. package/optional-skills/creative/concept-diagrams/examples/ml-benchmark-grouped-bar-chart.md +114 -0
  441. package/optional-skills/creative/concept-diagrams/examples/place-order-uml-sequence.md +325 -0
  442. package/optional-skills/creative/concept-diagrams/examples/smart-city-infrastructure.md +173 -0
  443. package/optional-skills/creative/concept-diagrams/examples/smartphone-layer-anatomy.md +154 -0
  444. package/optional-skills/creative/concept-diagrams/examples/sn2-reaction-mechanism.md +247 -0
  445. package/optional-skills/creative/concept-diagrams/examples/wind-turbine-structure.md +338 -0
  446. package/optional-skills/creative/concept-diagrams/references/dashboard-patterns.md +43 -0
  447. package/optional-skills/creative/concept-diagrams/references/infrastructure-patterns.md +144 -0
  448. package/optional-skills/creative/concept-diagrams/references/physical-shape-cookbook.md +42 -0
  449. package/optional-skills/creative/concept-diagrams/templates/template.html +174 -0
  450. package/optional-skills/creative/hyperframes/SKILL.md +191 -0
  451. package/optional-skills/creative/hyperframes/references/cli.md +185 -0
  452. package/optional-skills/creative/hyperframes/references/composition.md +129 -0
  453. package/optional-skills/creative/hyperframes/references/features.md +289 -0
  454. package/optional-skills/creative/hyperframes/references/gsap.md +136 -0
  455. package/optional-skills/creative/hyperframes/references/troubleshooting.md +137 -0
  456. package/optional-skills/creative/hyperframes/references/website-to-video.md +145 -0
  457. package/optional-skills/creative/hyperframes/scripts/setup.sh +135 -0
  458. package/optional-skills/creative/kanban-video-orchestrator/SKILL.md +207 -0
  459. package/optional-skills/creative/kanban-video-orchestrator/assets/brief.md.tmpl +79 -0
  460. package/optional-skills/creative/kanban-video-orchestrator/assets/setup.sh.tmpl +185 -0
  461. package/optional-skills/creative/kanban-video-orchestrator/assets/soul.md.tmpl +38 -0
  462. package/optional-skills/creative/kanban-video-orchestrator/references/examples.md +227 -0
  463. package/optional-skills/creative/kanban-video-orchestrator/references/intake.md +166 -0
  464. package/optional-skills/creative/kanban-video-orchestrator/references/kanban-setup.md +276 -0
  465. package/optional-skills/creative/kanban-video-orchestrator/references/monitoring.md +180 -0
  466. package/optional-skills/creative/kanban-video-orchestrator/references/role-archetypes.md +298 -0
  467. package/optional-skills/creative/kanban-video-orchestrator/references/tool-matrix.md +317 -0
  468. package/optional-skills/creative/kanban-video-orchestrator/scripts/bootstrap_pipeline.py +501 -0
  469. package/optional-skills/creative/kanban-video-orchestrator/scripts/monitor.py +195 -0
  470. package/optional-skills/creative/meme-generation/EXAMPLES.md +46 -0
  471. package/optional-skills/creative/meme-generation/SKILL.md +130 -0
  472. package/optional-skills/creative/meme-generation/scripts/generate_meme.py +471 -0
  473. package/optional-skills/creative/meme-generation/scripts/templates.json +97 -0
  474. package/optional-skills/devops/cli/SKILL.md +156 -0
  475. package/optional-skills/devops/cli/references/app-discovery.md +112 -0
  476. package/optional-skills/devops/cli/references/authentication.md +59 -0
  477. package/optional-skills/devops/cli/references/cli-reference.md +104 -0
  478. package/optional-skills/devops/cli/references/running-apps.md +171 -0
  479. package/optional-skills/devops/docker-management/SKILL.md +281 -0
  480. package/optional-skills/devops/pinggy-tunnel/SKILL.md +309 -0
  481. package/optional-skills/devops/watchers/SKILL.md +112 -0
  482. package/optional-skills/devops/watchers/scripts/_watermark.py +148 -0
  483. package/optional-skills/devops/watchers/scripts/watch_github.py +168 -0
  484. package/optional-skills/devops/watchers/scripts/watch_http_json.py +131 -0
  485. package/optional-skills/devops/watchers/scripts/watch_rss.py +121 -0
  486. package/optional-skills/dogfood/DESCRIPTION.md +3 -0
  487. package/optional-skills/dogfood/adversarial-ux-test/SKILL.md +191 -0
  488. package/optional-skills/email/agentmail/SKILL.md +126 -0
  489. package/optional-skills/finance/3-statement-model/SKILL.md +433 -0
  490. package/optional-skills/finance/3-statement-model/references/formatting.md +118 -0
  491. package/optional-skills/finance/3-statement-model/references/formulas.md +292 -0
  492. package/optional-skills/finance/3-statement-model/references/sec-filings.md +125 -0
  493. package/optional-skills/finance/comps-analysis/SKILL.md +662 -0
  494. package/optional-skills/finance/dcf-model/SKILL.md +1270 -0
  495. package/optional-skills/finance/dcf-model/TROUBLESHOOTING.md +40 -0
  496. package/optional-skills/finance/dcf-model/requirements.txt +7 -0
  497. package/optional-skills/finance/dcf-model/scripts/validate_dcf.py +292 -0
  498. package/optional-skills/finance/excel-author/SKILL.md +244 -0
  499. package/optional-skills/finance/excel-author/scripts/recalc.py +88 -0
  500. package/optional-skills/finance/lbo-model/SKILL.md +291 -0
  501. package/optional-skills/finance/merger-model/SKILL.md +144 -0
  502. package/optional-skills/finance/pptx-author/SKILL.md +173 -0
  503. package/optional-skills/finance/stocks/SKILL.md +95 -0
  504. package/optional-skills/finance/stocks/scripts/stocks_client.py +755 -0
  505. package/optional-skills/health/DESCRIPTION.md +1 -0
  506. package/optional-skills/health/fitness-nutrition/SKILL.md +256 -0
  507. package/optional-skills/health/fitness-nutrition/references/FORMULAS.md +100 -0
  508. package/optional-skills/health/fitness-nutrition/scripts/body_calc.py +210 -0
  509. package/optional-skills/health/fitness-nutrition/scripts/nutrition_search.py +86 -0
  510. package/optional-skills/health/neuroskill-bci/SKILL.md +459 -0
  511. package/optional-skills/health/neuroskill-bci/references/api.md +286 -0
  512. package/optional-skills/health/neuroskill-bci/references/metrics.md +220 -0
  513. package/optional-skills/health/neuroskill-bci/references/protocols.md +452 -0
  514. package/optional-skills/mcp/DESCRIPTION.md +3 -0
  515. package/optional-skills/mcp/fastmcp/SKILL.md +300 -0
  516. package/optional-skills/mcp/fastmcp/references/fastmcp-cli.md +110 -0
  517. package/optional-skills/mcp/fastmcp/scripts/scaffold_fastmcp.py +56 -0
  518. package/optional-skills/mcp/fastmcp/templates/api_wrapper.py +54 -0
  519. package/optional-skills/mcp/fastmcp/templates/database_server.py +77 -0
  520. package/optional-skills/mcp/fastmcp/templates/file_processor.py +55 -0
  521. package/optional-skills/mcp/mcporter/SKILL.md +123 -0
  522. package/optional-skills/migration/DESCRIPTION.md +2 -0
  523. package/optional-skills/migration/openclaw-migration/SKILL.md +298 -0
  524. package/optional-skills/migration/openclaw-migration/scripts/openclaw_to_hermes.py +3136 -0
  525. package/optional-skills/mlops/accelerate/SKILL.md +336 -0
  526. package/optional-skills/mlops/accelerate/references/custom-plugins.md +453 -0
  527. package/optional-skills/mlops/accelerate/references/megatron-integration.md +489 -0
  528. package/optional-skills/mlops/accelerate/references/performance.md +525 -0
  529. package/optional-skills/mlops/chroma/SKILL.md +410 -0
  530. package/optional-skills/mlops/chroma/references/integration.md +38 -0
  531. package/optional-skills/mlops/clip/SKILL.md +257 -0
  532. package/optional-skills/mlops/clip/references/applications.md +207 -0
  533. package/optional-skills/mlops/faiss/SKILL.md +225 -0
  534. package/optional-skills/mlops/faiss/references/index_types.md +280 -0
  535. package/optional-skills/mlops/flash-attention/SKILL.md +367 -0
  536. package/optional-skills/mlops/flash-attention/references/benchmarks.md +215 -0
  537. package/optional-skills/mlops/flash-attention/references/transformers-integration.md +293 -0
  538. package/optional-skills/mlops/guidance/SKILL.md +576 -0
  539. package/optional-skills/mlops/guidance/references/backends.md +554 -0
  540. package/optional-skills/mlops/guidance/references/constraints.md +674 -0
  541. package/optional-skills/mlops/guidance/references/examples.md +767 -0
  542. package/optional-skills/mlops/huggingface-tokenizers/SKILL.md +520 -0
  543. package/optional-skills/mlops/huggingface-tokenizers/references/algorithms.md +653 -0
  544. package/optional-skills/mlops/huggingface-tokenizers/references/integration.md +637 -0
  545. package/optional-skills/mlops/huggingface-tokenizers/references/pipeline.md +723 -0
  546. package/optional-skills/mlops/huggingface-tokenizers/references/training.md +565 -0
  547. package/optional-skills/mlops/inference/outlines/SKILL.md +656 -0
  548. package/optional-skills/mlops/inference/outlines/references/backends.md +615 -0
  549. package/optional-skills/mlops/inference/outlines/references/examples.md +773 -0
  550. package/optional-skills/mlops/inference/outlines/references/json_generation.md +652 -0
  551. package/optional-skills/mlops/instructor/SKILL.md +744 -0
  552. package/optional-skills/mlops/instructor/references/examples.md +107 -0
  553. package/optional-skills/mlops/instructor/references/providers.md +70 -0
  554. package/optional-skills/mlops/instructor/references/validation.md +606 -0
  555. package/optional-skills/mlops/lambda-labs/SKILL.md +549 -0
  556. package/optional-skills/mlops/lambda-labs/references/advanced-usage.md +611 -0
  557. package/optional-skills/mlops/lambda-labs/references/troubleshooting.md +530 -0
  558. package/optional-skills/mlops/llava/SKILL.md +308 -0
  559. package/optional-skills/mlops/llava/references/training.md +197 -0
  560. package/optional-skills/mlops/modal/SKILL.md +345 -0
  561. package/optional-skills/mlops/modal/references/advanced-usage.md +503 -0
  562. package/optional-skills/mlops/modal/references/troubleshooting.md +494 -0
  563. package/optional-skills/mlops/nemo-curator/SKILL.md +387 -0
  564. package/optional-skills/mlops/nemo-curator/references/deduplication.md +87 -0
  565. package/optional-skills/mlops/nemo-curator/references/filtering.md +102 -0
  566. package/optional-skills/mlops/peft/SKILL.md +435 -0
  567. package/optional-skills/mlops/peft/references/advanced-usage.md +514 -0
  568. package/optional-skills/mlops/peft/references/troubleshooting.md +480 -0
  569. package/optional-skills/mlops/pinecone/SKILL.md +362 -0
  570. package/optional-skills/mlops/pinecone/references/deployment.md +181 -0
  571. package/optional-skills/mlops/pytorch-fsdp/SKILL.md +130 -0
  572. package/optional-skills/mlops/pytorch-fsdp/references/index.md +7 -0
  573. package/optional-skills/mlops/pytorch-fsdp/references/other.md +4261 -0
  574. package/optional-skills/mlops/pytorch-lightning/SKILL.md +350 -0
  575. package/optional-skills/mlops/pytorch-lightning/references/callbacks.md +436 -0
  576. package/optional-skills/mlops/pytorch-lightning/references/distributed.md +490 -0
  577. package/optional-skills/mlops/pytorch-lightning/references/hyperparameter-tuning.md +556 -0
  578. package/optional-skills/mlops/qdrant/SKILL.md +497 -0
  579. package/optional-skills/mlops/qdrant/references/advanced-usage.md +648 -0
  580. package/optional-skills/mlops/qdrant/references/troubleshooting.md +631 -0
  581. package/optional-skills/mlops/saelens/SKILL.md +390 -0
  582. package/optional-skills/mlops/saelens/references/README.md +69 -0
  583. package/optional-skills/mlops/saelens/references/api.md +333 -0
  584. package/optional-skills/mlops/saelens/references/tutorials.md +318 -0
  585. package/optional-skills/mlops/simpo/SKILL.md +223 -0
  586. package/optional-skills/mlops/simpo/references/datasets.md +478 -0
  587. package/optional-skills/mlops/simpo/references/hyperparameters.md +452 -0
  588. package/optional-skills/mlops/simpo/references/loss-functions.md +350 -0
  589. package/optional-skills/mlops/slime/SKILL.md +468 -0
  590. package/optional-skills/mlops/slime/references/api-reference.md +392 -0
  591. package/optional-skills/mlops/slime/references/troubleshooting.md +386 -0
  592. package/optional-skills/mlops/stable-diffusion/SKILL.md +523 -0
  593. package/optional-skills/mlops/stable-diffusion/references/advanced-usage.md +716 -0
  594. package/optional-skills/mlops/stable-diffusion/references/troubleshooting.md +555 -0
  595. package/optional-skills/mlops/tensorrt-llm/SKILL.md +191 -0
  596. package/optional-skills/mlops/tensorrt-llm/references/multi-gpu.md +298 -0
  597. package/optional-skills/mlops/tensorrt-llm/references/optimization.md +242 -0
  598. package/optional-skills/mlops/tensorrt-llm/references/serving.md +470 -0
  599. package/optional-skills/mlops/torchtitan/SKILL.md +362 -0
  600. package/optional-skills/mlops/torchtitan/references/checkpoint.md +181 -0
  601. package/optional-skills/mlops/torchtitan/references/custom-models.md +258 -0
  602. package/optional-skills/mlops/torchtitan/references/float8.md +133 -0
  603. package/optional-skills/mlops/torchtitan/references/fsdp.md +126 -0
  604. package/optional-skills/mlops/training/axolotl/SKILL.md +166 -0
  605. package/optional-skills/mlops/training/axolotl/references/api.md +5548 -0
  606. package/optional-skills/mlops/training/axolotl/references/dataset-formats.md +1029 -0
  607. package/optional-skills/mlops/training/axolotl/references/index.md +15 -0
  608. package/optional-skills/mlops/training/axolotl/references/other.md +3563 -0
  609. package/optional-skills/mlops/training/trl-fine-tuning/SKILL.md +463 -0
  610. package/optional-skills/mlops/training/trl-fine-tuning/references/dpo-variants.md +227 -0
  611. package/optional-skills/mlops/training/trl-fine-tuning/references/grpo-training.md +504 -0
  612. package/optional-skills/mlops/training/trl-fine-tuning/references/online-rl.md +82 -0
  613. package/optional-skills/mlops/training/trl-fine-tuning/references/reward-modeling.md +122 -0
  614. package/optional-skills/mlops/training/trl-fine-tuning/references/sft-training.md +168 -0
  615. package/optional-skills/mlops/training/trl-fine-tuning/templates/basic_grpo_training.py +228 -0
  616. package/optional-skills/mlops/training/unsloth/SKILL.md +84 -0
  617. package/optional-skills/mlops/training/unsloth/references/index.md +7 -0
  618. package/optional-skills/mlops/training/unsloth/references/llms-full.md +16799 -0
  619. package/optional-skills/mlops/training/unsloth/references/llms-txt.md +12044 -0
  620. package/optional-skills/mlops/training/unsloth/references/llms.md +82 -0
  621. package/optional-skills/mlops/whisper/SKILL.md +321 -0
  622. package/optional-skills/mlops/whisper/references/languages.md +189 -0
  623. package/optional-skills/productivity/canvas/SKILL.md +98 -0
  624. package/optional-skills/productivity/canvas/scripts/canvas_api.py +157 -0
  625. package/optional-skills/productivity/here-now/SKILL.md +217 -0
  626. package/optional-skills/productivity/here-now/scripts/drive.sh +406 -0
  627. package/optional-skills/productivity/here-now/scripts/publish.sh +445 -0
  628. package/optional-skills/productivity/memento-flashcards/SKILL.md +324 -0
  629. package/optional-skills/productivity/memento-flashcards/scripts/memento_cards.py +353 -0
  630. package/optional-skills/productivity/memento-flashcards/scripts/youtube_quiz.py +88 -0
  631. package/optional-skills/productivity/shop-app/SKILL.md +340 -0
  632. package/optional-skills/productivity/shopify/SKILL.md +373 -0
  633. package/optional-skills/productivity/siyuan/SKILL.md +298 -0
  634. package/optional-skills/productivity/telephony/SKILL.md +418 -0
  635. package/optional-skills/productivity/telephony/scripts/telephony.py +1343 -0
  636. package/optional-skills/research/bioinformatics/SKILL.md +235 -0
  637. package/optional-skills/research/darwinian-evolver/SKILL.md +199 -0
  638. package/optional-skills/research/darwinian-evolver/scripts/parrot_openrouter.py +218 -0
  639. package/optional-skills/research/darwinian-evolver/scripts/show_snapshot.py +69 -0
  640. package/optional-skills/research/darwinian-evolver/templates/custom_problem_template.py +240 -0
  641. package/optional-skills/research/domain-intel/SKILL.md +97 -0
  642. package/optional-skills/research/domain-intel/scripts/domain_intel.py +397 -0
  643. package/optional-skills/research/drug-discovery/SKILL.md +227 -0
  644. package/optional-skills/research/drug-discovery/references/ADMET_REFERENCE.md +66 -0
  645. package/optional-skills/research/drug-discovery/scripts/chembl_target.py +53 -0
  646. package/optional-skills/research/drug-discovery/scripts/ro5_screen.py +44 -0
  647. package/optional-skills/research/duckduckgo-search/SKILL.md +238 -0
  648. package/optional-skills/research/duckduckgo-search/scripts/duckduckgo.sh +28 -0
  649. package/optional-skills/research/gitnexus-explorer/SKILL.md +214 -0
  650. package/optional-skills/research/gitnexus-explorer/scripts/proxy.mjs +92 -0
  651. package/optional-skills/research/osint-investigation/SKILL.md +277 -0
  652. package/optional-skills/research/osint-investigation/references/sources/courtlistener.md +98 -0
  653. package/optional-skills/research/osint-investigation/references/sources/gdelt.md +104 -0
  654. package/optional-skills/research/osint-investigation/references/sources/icij-offshore.md +104 -0
  655. package/optional-skills/research/osint-investigation/references/sources/nyc-acris.md +90 -0
  656. package/optional-skills/research/osint-investigation/references/sources/ofac-sdn.md +92 -0
  657. package/optional-skills/research/osint-investigation/references/sources/opencorporates.md +103 -0
  658. package/optional-skills/research/osint-investigation/references/sources/sec-edgar.md +83 -0
  659. package/optional-skills/research/osint-investigation/references/sources/senate-ld.md +89 -0
  660. package/optional-skills/research/osint-investigation/references/sources/usaspending.md +97 -0
  661. package/optional-skills/research/osint-investigation/references/sources/wayback.md +93 -0
  662. package/optional-skills/research/osint-investigation/references/sources/wikipedia.md +107 -0
  663. package/optional-skills/research/osint-investigation/scripts/_http.py +82 -0
  664. package/optional-skills/research/osint-investigation/scripts/_normalize.py +67 -0
  665. package/optional-skills/research/osint-investigation/scripts/build_findings.py +221 -0
  666. package/optional-skills/research/osint-investigation/scripts/entity_resolution.py +228 -0
  667. package/optional-skills/research/osint-investigation/scripts/fetch_courtlistener.py +149 -0
  668. package/optional-skills/research/osint-investigation/scripts/fetch_gdelt.py +162 -0
  669. package/optional-skills/research/osint-investigation/scripts/fetch_icij_offshore.py +234 -0
  670. package/optional-skills/research/osint-investigation/scripts/fetch_nyc_acris.py +203 -0
  671. package/optional-skills/research/osint-investigation/scripts/fetch_ofac_sdn.py +175 -0
  672. package/optional-skills/research/osint-investigation/scripts/fetch_opencorporates.py +192 -0
  673. package/optional-skills/research/osint-investigation/scripts/fetch_sec_edgar.py +184 -0
  674. package/optional-skills/research/osint-investigation/scripts/fetch_senate_ld.py +146 -0
  675. package/optional-skills/research/osint-investigation/scripts/fetch_usaspending.py +170 -0
  676. package/optional-skills/research/osint-investigation/scripts/fetch_wayback.py +142 -0
  677. package/optional-skills/research/osint-investigation/scripts/fetch_wikipedia.py +267 -0
  678. package/optional-skills/research/osint-investigation/scripts/timing_analysis.py +253 -0
  679. package/optional-skills/research/osint-investigation/templates/source-template.md +59 -0
  680. package/optional-skills/research/parallel-cli/SKILL.md +391 -0
  681. package/optional-skills/research/qmd/SKILL.md +441 -0
  682. package/optional-skills/research/scrapling/SKILL.md +336 -0
  683. package/optional-skills/research/searxng-search/SKILL.md +212 -0
  684. package/optional-skills/research/searxng-search/scripts/searxng.sh +22 -0
  685. package/optional-skills/security/1password/SKILL.md +163 -0
  686. package/optional-skills/security/1password/references/cli-examples.md +31 -0
  687. package/optional-skills/security/1password/references/get-started.md +21 -0
  688. package/optional-skills/security/DESCRIPTION.md +3 -0
  689. package/optional-skills/security/oss-forensics/SKILL.md +423 -0
  690. package/optional-skills/security/oss-forensics/references/evidence-types.md +89 -0
  691. package/optional-skills/security/oss-forensics/references/github-archive-guide.md +184 -0
  692. package/optional-skills/security/oss-forensics/references/investigation-templates.md +131 -0
  693. package/optional-skills/security/oss-forensics/references/recovery-techniques.md +164 -0
  694. package/optional-skills/security/oss-forensics/scripts/evidence-store.py +313 -0
  695. package/optional-skills/security/oss-forensics/templates/forensic-report.md +151 -0
  696. package/optional-skills/security/oss-forensics/templates/malicious-package-report.md +43 -0
  697. package/optional-skills/security/sherlock/SKILL.md +193 -0
  698. package/optional-skills/software-development/rest-graphql-debug/SKILL.md +514 -0
  699. package/optional-skills/web-development/DESCRIPTION.md +5 -0
  700. package/optional-skills/web-development/page-agent/SKILL.md +190 -0
  701. package/package.json +78 -0
  702. package/plugins/__init__.py +1 -0
  703. package/plugins/__pycache__/__init__.cpython-312.pyc +0 -0
  704. package/plugins/context_engine/__init__.py +219 -0
  705. package/plugins/disk-cleanup/README.md +51 -0
  706. package/plugins/disk-cleanup/__init__.py +316 -0
  707. package/plugins/disk-cleanup/disk_cleanup.py +497 -0
  708. package/plugins/disk-cleanup/plugin.yaml +7 -0
  709. package/plugins/example-dashboard/dashboard/manifest.json +14 -0
  710. package/plugins/example-dashboard/dashboard/plugin_api.py +17 -0
  711. package/plugins/google_meet/README.md +131 -0
  712. package/plugins/google_meet/SKILL.md +148 -0
  713. package/plugins/google_meet/__init__.py +103 -0
  714. package/plugins/google_meet/audio_bridge.py +244 -0
  715. package/plugins/google_meet/cli.py +479 -0
  716. package/plugins/google_meet/meet_bot.py +852 -0
  717. package/plugins/google_meet/node/__init__.py +54 -0
  718. package/plugins/google_meet/node/cli.py +125 -0
  719. package/plugins/google_meet/node/client.py +107 -0
  720. package/plugins/google_meet/node/protocol.py +124 -0
  721. package/plugins/google_meet/node/registry.py +113 -0
  722. package/plugins/google_meet/node/server.py +201 -0
  723. package/plugins/google_meet/plugin.yaml +16 -0
  724. package/plugins/google_meet/process_manager.py +324 -0
  725. package/plugins/google_meet/realtime/__init__.py +10 -0
  726. package/plugins/google_meet/realtime/openai_client.py +332 -0
  727. package/plugins/google_meet/tools.py +348 -0
  728. package/plugins/hermes-achievements/LICENSE +21 -0
  729. package/plugins/hermes-achievements/README.md +150 -0
  730. package/plugins/hermes-achievements/dashboard/dist/index.js +732 -0
  731. package/plugins/hermes-achievements/dashboard/dist/style.css +146 -0
  732. package/plugins/hermes-achievements/dashboard/manifest.json +11 -0
  733. package/plugins/hermes-achievements/dashboard/plugin_api.py +1062 -0
  734. package/plugins/hermes-achievements/docs/achievements-performance-implementation-plan.md +157 -0
  735. package/plugins/hermes-achievements/docs/achievements-performance-implementation-spec.md +219 -0
  736. package/plugins/hermes-achievements/docs/achievements-performance-spec.md +174 -0
  737. package/plugins/hermes-achievements/docs/assets/achievements-dashboard-hd.png +0 -0
  738. package/plugins/hermes-achievements/docs/assets/achievements-tier-showcase-hd.png +0 -0
  739. package/plugins/hermes-achievements/tests/test_achievement_engine.py +156 -0
  740. package/plugins/image_gen/openai/__init__.py +303 -0
  741. package/plugins/image_gen/openai/__pycache__/__init__.cpython-312.pyc +0 -0
  742. package/plugins/image_gen/openai/plugin.yaml +7 -0
  743. package/plugins/image_gen/openai-codex/__init__.py +378 -0
  744. package/plugins/image_gen/openai-codex/__pycache__/__init__.cpython-312.pyc +0 -0
  745. package/plugins/image_gen/openai-codex/plugin.yaml +5 -0
  746. package/plugins/image_gen/xai/__init__.py +316 -0
  747. package/plugins/image_gen/xai/__pycache__/__init__.cpython-312.pyc +0 -0
  748. package/plugins/image_gen/xai/plugin.yaml +7 -0
  749. package/plugins/kanban/dashboard/dist/index.js +3143 -0
  750. package/plugins/kanban/dashboard/dist/style.css +1500 -0
  751. package/plugins/kanban/dashboard/manifest.json +14 -0
  752. package/plugins/kanban/dashboard/plugin_api.py +1612 -0
  753. package/plugins/kanban/systemd/hermes-kanban-dispatcher.service +32 -0
  754. package/plugins/memory/__init__.py +408 -0
  755. package/plugins/memory/byterover/README.md +41 -0
  756. package/plugins/memory/byterover/__init__.py +384 -0
  757. package/plugins/memory/byterover/plugin.yaml +9 -0
  758. package/plugins/memory/hindsight/README.md +138 -0
  759. package/plugins/memory/hindsight/__init__.py +1758 -0
  760. package/plugins/memory/hindsight/plugin.yaml +8 -0
  761. package/plugins/memory/holographic/README.md +36 -0
  762. package/plugins/memory/holographic/__init__.py +409 -0
  763. package/plugins/memory/holographic/holographic.py +203 -0
  764. package/plugins/memory/holographic/plugin.yaml +5 -0
  765. package/plugins/memory/holographic/retrieval.py +593 -0
  766. package/plugins/memory/holographic/store.py +579 -0
  767. package/plugins/memory/honcho/README.md +328 -0
  768. package/plugins/memory/honcho/__init__.py +1329 -0
  769. package/plugins/memory/honcho/cli.py +1452 -0
  770. package/plugins/memory/honcho/client.py +784 -0
  771. package/plugins/memory/honcho/plugin.yaml +7 -0
  772. package/plugins/memory/honcho/session.py +1255 -0
  773. package/plugins/memory/mem0/README.md +38 -0
  774. package/plugins/memory/mem0/__init__.py +374 -0
  775. package/plugins/memory/mem0/plugin.yaml +5 -0
  776. package/plugins/memory/openviking/README.md +40 -0
  777. package/plugins/memory/openviking/__init__.py +945 -0
  778. package/plugins/memory/openviking/plugin.yaml +9 -0
  779. package/plugins/memory/retaindb/README.md +40 -0
  780. package/plugins/memory/retaindb/__init__.py +767 -0
  781. package/plugins/memory/retaindb/plugin.yaml +7 -0
  782. package/plugins/memory/supermemory/README.md +99 -0
  783. package/plugins/memory/supermemory/__init__.py +792 -0
  784. package/plugins/memory/supermemory/plugin.yaml +5 -0
  785. package/plugins/model-providers/README.md +70 -0
  786. package/plugins/model-providers/ai-gateway/__init__.py +43 -0
  787. package/plugins/model-providers/ai-gateway/__pycache__/__init__.cpython-312.pyc +0 -0
  788. package/plugins/model-providers/ai-gateway/plugin.yaml +5 -0
  789. package/plugins/model-providers/alibaba/__init__.py +13 -0
  790. package/plugins/model-providers/alibaba/__pycache__/__init__.cpython-312.pyc +0 -0
  791. package/plugins/model-providers/alibaba/plugin.yaml +5 -0
  792. package/plugins/model-providers/alibaba-coding-plan/__init__.py +21 -0
  793. package/plugins/model-providers/alibaba-coding-plan/__pycache__/__init__.cpython-312.pyc +0 -0
  794. package/plugins/model-providers/alibaba-coding-plan/plugin.yaml +5 -0
  795. package/plugins/model-providers/anthropic/__init__.py +52 -0
  796. package/plugins/model-providers/anthropic/__pycache__/__init__.cpython-312.pyc +0 -0
  797. package/plugins/model-providers/anthropic/plugin.yaml +5 -0
  798. package/plugins/model-providers/arcee/__init__.py +13 -0
  799. package/plugins/model-providers/arcee/__pycache__/__init__.cpython-312.pyc +0 -0
  800. package/plugins/model-providers/arcee/plugin.yaml +5 -0
  801. package/plugins/model-providers/azure-foundry/__init__.py +21 -0
  802. package/plugins/model-providers/azure-foundry/__pycache__/__init__.cpython-312.pyc +0 -0
  803. package/plugins/model-providers/azure-foundry/plugin.yaml +5 -0
  804. package/plugins/model-providers/bedrock/__init__.py +29 -0
  805. package/plugins/model-providers/bedrock/__pycache__/__init__.cpython-312.pyc +0 -0
  806. package/plugins/model-providers/bedrock/plugin.yaml +5 -0
  807. package/plugins/model-providers/copilot/__init__.py +58 -0
  808. package/plugins/model-providers/copilot/__pycache__/__init__.cpython-312.pyc +0 -0
  809. package/plugins/model-providers/copilot/plugin.yaml +5 -0
  810. package/plugins/model-providers/copilot-acp/__init__.py +34 -0
  811. package/plugins/model-providers/copilot-acp/__pycache__/__init__.cpython-312.pyc +0 -0
  812. package/plugins/model-providers/copilot-acp/plugin.yaml +5 -0
  813. package/plugins/model-providers/custom/__init__.py +68 -0
  814. package/plugins/model-providers/custom/__pycache__/__init__.cpython-312.pyc +0 -0
  815. package/plugins/model-providers/custom/plugin.yaml +5 -0
  816. package/plugins/model-providers/deepseek/__init__.py +99 -0
  817. package/plugins/model-providers/deepseek/__pycache__/__init__.cpython-312.pyc +0 -0
  818. package/plugins/model-providers/deepseek/plugin.yaml +5 -0
  819. package/plugins/model-providers/gemini/__init__.py +72 -0
  820. package/plugins/model-providers/gemini/__pycache__/__init__.cpython-312.pyc +0 -0
  821. package/plugins/model-providers/gemini/plugin.yaml +5 -0
  822. package/plugins/model-providers/gmi/__init__.py +31 -0
  823. package/plugins/model-providers/gmi/__pycache__/__init__.cpython-312.pyc +0 -0
  824. package/plugins/model-providers/gmi/plugin.yaml +5 -0
  825. package/plugins/model-providers/huggingface/__init__.py +20 -0
  826. package/plugins/model-providers/huggingface/__pycache__/__init__.cpython-312.pyc +0 -0
  827. package/plugins/model-providers/huggingface/plugin.yaml +5 -0
  828. package/plugins/model-providers/kilocode/__init__.py +14 -0
  829. package/plugins/model-providers/kilocode/__pycache__/__init__.cpython-312.pyc +0 -0
  830. package/plugins/model-providers/kilocode/plugin.yaml +5 -0
  831. package/plugins/model-providers/kimi-coding/__init__.py +71 -0
  832. package/plugins/model-providers/kimi-coding/__pycache__/__init__.cpython-312.pyc +0 -0
  833. package/plugins/model-providers/kimi-coding/plugin.yaml +5 -0
  834. package/plugins/model-providers/minimax/__init__.py +45 -0
  835. package/plugins/model-providers/minimax/__pycache__/__init__.cpython-312.pyc +0 -0
  836. package/plugins/model-providers/minimax/plugin.yaml +5 -0
  837. package/plugins/model-providers/nous/__init__.py +54 -0
  838. package/plugins/model-providers/nous/__pycache__/__init__.cpython-312.pyc +0 -0
  839. package/plugins/model-providers/nous/plugin.yaml +5 -0
  840. package/plugins/model-providers/novita/__init__.py +27 -0
  841. package/plugins/model-providers/novita/__pycache__/__init__.cpython-312.pyc +0 -0
  842. package/plugins/model-providers/novita/plugin.yaml +5 -0
  843. package/plugins/model-providers/nvidia/__init__.py +21 -0
  844. package/plugins/model-providers/nvidia/__pycache__/__init__.cpython-312.pyc +0 -0
  845. package/plugins/model-providers/nvidia/plugin.yaml +5 -0
  846. package/plugins/model-providers/ollama-cloud/__init__.py +14 -0
  847. package/plugins/model-providers/ollama-cloud/__pycache__/__init__.cpython-312.pyc +0 -0
  848. package/plugins/model-providers/ollama-cloud/plugin.yaml +5 -0
  849. package/plugins/model-providers/openai-codex/__init__.py +15 -0
  850. package/plugins/model-providers/openai-codex/__pycache__/__init__.cpython-312.pyc +0 -0
  851. package/plugins/model-providers/openai-codex/plugin.yaml +5 -0
  852. package/plugins/model-providers/opencode-zen/__init__.py +30 -0
  853. package/plugins/model-providers/opencode-zen/__pycache__/__init__.cpython-312.pyc +0 -0
  854. package/plugins/model-providers/opencode-zen/plugin.yaml +5 -0
  855. package/plugins/model-providers/openrouter/__init__.py +115 -0
  856. package/plugins/model-providers/openrouter/__pycache__/__init__.cpython-312.pyc +0 -0
  857. package/plugins/model-providers/openrouter/plugin.yaml +5 -0
  858. package/plugins/model-providers/qwen-oauth/__init__.py +82 -0
  859. package/plugins/model-providers/qwen-oauth/__pycache__/__init__.cpython-312.pyc +0 -0
  860. package/plugins/model-providers/qwen-oauth/plugin.yaml +5 -0
  861. package/plugins/model-providers/stepfun/__init__.py +14 -0
  862. package/plugins/model-providers/stepfun/__pycache__/__init__.cpython-312.pyc +0 -0
  863. package/plugins/model-providers/stepfun/plugin.yaml +5 -0
  864. package/plugins/model-providers/xai/__init__.py +15 -0
  865. package/plugins/model-providers/xai/__pycache__/__init__.cpython-312.pyc +0 -0
  866. package/plugins/model-providers/xai/plugin.yaml +5 -0
  867. package/plugins/model-providers/xiaomi/__init__.py +14 -0
  868. package/plugins/model-providers/xiaomi/__pycache__/__init__.cpython-312.pyc +0 -0
  869. package/plugins/model-providers/xiaomi/plugin.yaml +5 -0
  870. package/plugins/model-providers/zai/__init__.py +21 -0
  871. package/plugins/model-providers/zai/__pycache__/__init__.cpython-312.pyc +0 -0
  872. package/plugins/model-providers/zai/plugin.yaml +5 -0
  873. package/plugins/observability/langfuse/README.md +53 -0
  874. package/plugins/observability/langfuse/__init__.py +1004 -0
  875. package/plugins/observability/langfuse/plugin.yaml +14 -0
  876. package/plugins/platforms/google_chat/__init__.py +3 -0
  877. package/plugins/platforms/google_chat/__pycache__/__init__.cpython-312.pyc +0 -0
  878. package/plugins/platforms/google_chat/__pycache__/adapter.cpython-312.pyc +0 -0
  879. package/plugins/platforms/google_chat/adapter.py +3343 -0
  880. package/plugins/platforms/google_chat/oauth.py +639 -0
  881. package/plugins/platforms/google_chat/plugin.yaml +39 -0
  882. package/plugins/platforms/irc/__init__.py +3 -0
  883. package/plugins/platforms/irc/__pycache__/__init__.cpython-312.pyc +0 -0
  884. package/plugins/platforms/irc/__pycache__/adapter.cpython-312.pyc +0 -0
  885. package/plugins/platforms/irc/adapter.py +969 -0
  886. package/plugins/platforms/irc/plugin.yaml +54 -0
  887. package/plugins/platforms/line/__init__.py +3 -0
  888. package/plugins/platforms/line/__pycache__/__init__.cpython-312.pyc +0 -0
  889. package/plugins/platforms/line/__pycache__/adapter.cpython-312.pyc +0 -0
  890. package/plugins/platforms/line/adapter.py +1639 -0
  891. package/plugins/platforms/line/plugin.yaml +65 -0
  892. package/plugins/platforms/simplex/__init__.py +3 -0
  893. package/plugins/platforms/simplex/__pycache__/__init__.cpython-312.pyc +0 -0
  894. package/plugins/platforms/simplex/__pycache__/adapter.cpython-312.pyc +0 -0
  895. package/plugins/platforms/simplex/adapter.py +746 -0
  896. package/plugins/platforms/simplex/plugin.yaml +37 -0
  897. package/plugins/platforms/teams/__init__.py +3 -0
  898. package/plugins/platforms/teams/__pycache__/__init__.cpython-312.pyc +0 -0
  899. package/plugins/platforms/teams/__pycache__/adapter.cpython-312.pyc +0 -0
  900. package/plugins/platforms/teams/adapter.py +1188 -0
  901. package/plugins/platforms/teams/plugin.yaml +48 -0
  902. package/plugins/spotify/__init__.py +66 -0
  903. package/plugins/spotify/__pycache__/__init__.cpython-312.pyc +0 -0
  904. package/plugins/spotify/__pycache__/client.cpython-312.pyc +0 -0
  905. package/plugins/spotify/__pycache__/tools.cpython-312.pyc +0 -0
  906. package/plugins/spotify/client.py +435 -0
  907. package/plugins/spotify/plugin.yaml +13 -0
  908. package/plugins/spotify/tools.py +454 -0
  909. package/plugins/teams_pipeline/__init__.py +23 -0
  910. package/plugins/teams_pipeline/cli.py +463 -0
  911. package/plugins/teams_pipeline/meetings.py +333 -0
  912. package/plugins/teams_pipeline/models.py +350 -0
  913. package/plugins/teams_pipeline/pipeline.py +692 -0
  914. package/plugins/teams_pipeline/plugin.yaml +9 -0
  915. package/plugins/teams_pipeline/runtime.py +135 -0
  916. package/plugins/teams_pipeline/store.py +194 -0
  917. package/plugins/teams_pipeline/subscriptions.py +249 -0
  918. package/plugins/video_gen/fal/__init__.py +523 -0
  919. package/plugins/video_gen/fal/__pycache__/__init__.cpython-312.pyc +0 -0
  920. package/plugins/video_gen/fal/plugin.yaml +7 -0
  921. package/plugins/video_gen/xai/__init__.py +441 -0
  922. package/plugins/video_gen/xai/__pycache__/__init__.cpython-312.pyc +0 -0
  923. package/plugins/video_gen/xai/plugin.yaml +7 -0
  924. package/plugins/web/__init__.py +7 -0
  925. package/plugins/web/__pycache__/__init__.cpython-312.pyc +0 -0
  926. package/plugins/web/brave_free/__init__.py +14 -0
  927. package/plugins/web/brave_free/__pycache__/__init__.cpython-312.pyc +0 -0
  928. package/plugins/web/brave_free/__pycache__/provider.cpython-312.pyc +0 -0
  929. package/plugins/web/brave_free/plugin.yaml +7 -0
  930. package/plugins/web/brave_free/provider.py +137 -0
  931. package/plugins/web/ddgs/__init__.py +15 -0
  932. package/plugins/web/ddgs/__pycache__/__init__.cpython-312.pyc +0 -0
  933. package/plugins/web/ddgs/__pycache__/provider.cpython-312.pyc +0 -0
  934. package/plugins/web/ddgs/plugin.yaml +7 -0
  935. package/plugins/web/ddgs/provider.py +104 -0
  936. package/plugins/web/exa/__init__.py +15 -0
  937. package/plugins/web/exa/__pycache__/__init__.cpython-312.pyc +0 -0
  938. package/plugins/web/exa/__pycache__/provider.cpython-312.pyc +0 -0
  939. package/plugins/web/exa/plugin.yaml +7 -0
  940. package/plugins/web/exa/provider.py +212 -0
  941. package/plugins/web/firecrawl/__init__.py +28 -0
  942. package/plugins/web/firecrawl/__pycache__/__init__.cpython-312.pyc +0 -0
  943. package/plugins/web/firecrawl/__pycache__/provider.cpython-312.pyc +0 -0
  944. package/plugins/web/firecrawl/plugin.yaml +7 -0
  945. package/plugins/web/firecrawl/provider.py +773 -0
  946. package/plugins/web/parallel/__init__.py +16 -0
  947. package/plugins/web/parallel/__pycache__/__init__.cpython-312.pyc +0 -0
  948. package/plugins/web/parallel/__pycache__/provider.cpython-312.pyc +0 -0
  949. package/plugins/web/parallel/plugin.yaml +7 -0
  950. package/plugins/web/parallel/provider.py +291 -0
  951. package/plugins/web/searxng/__init__.py +15 -0
  952. package/plugins/web/searxng/__pycache__/__init__.cpython-312.pyc +0 -0
  953. package/plugins/web/searxng/__pycache__/provider.cpython-312.pyc +0 -0
  954. package/plugins/web/searxng/plugin.yaml +7 -0
  955. package/plugins/web/searxng/provider.py +140 -0
  956. package/plugins/web/tavily/__init__.py +15 -0
  957. package/plugins/web/tavily/__pycache__/__init__.cpython-312.pyc +0 -0
  958. package/plugins/web/tavily/__pycache__/provider.cpython-312.pyc +0 -0
  959. package/plugins/web/tavily/plugin.yaml +7 -0
  960. package/plugins/web/tavily/provider.py +285 -0
  961. package/providers/README.md +78 -0
  962. package/providers/__init__.py +192 -0
  963. package/providers/__pycache__/__init__.cpython-312.pyc +0 -0
  964. package/providers/__pycache__/base.cpython-312.pyc +0 -0
  965. package/providers/base.py +184 -0
  966. package/pyproject.toml +255 -0
  967. package/run_agent.py +16409 -0
  968. package/scripts/benchmark_browser_eval.py +138 -0
  969. package/scripts/build_model_catalog.py +95 -0
  970. package/scripts/build_skills_index.py +325 -0
  971. package/scripts/check-windows-footguns.py +624 -0
  972. package/scripts/contributor_audit.py +473 -0
  973. package/scripts/discord-voice-doctor.py +396 -0
  974. package/scripts/hermes-gateway +416 -0
  975. package/scripts/install.cmd +28 -0
  976. package/scripts/install.ps1 +1611 -0
  977. package/scripts/install.sh +2007 -0
  978. package/scripts/install_psutil_android.py +117 -0
  979. package/scripts/keystroke_diagnostic.py +81 -0
  980. package/scripts/kill_modal.sh +34 -0
  981. package/scripts/lib/node-bootstrap.sh +238 -0
  982. package/scripts/lint_diff.py +207 -0
  983. package/scripts/postinstall.js +150 -0
  984. package/scripts/profile-tui.py +626 -0
  985. package/scripts/release.py +1680 -0
  986. package/scripts/run_tests.sh +129 -0
  987. package/scripts/sample_and_compress.py +409 -0
  988. package/scripts/setup_open_webui.sh +349 -0
  989. package/scripts/whatsapp-bridge/allowlist.js +88 -0
  990. package/scripts/whatsapp-bridge/allowlist.test.mjs +80 -0
  991. package/scripts/whatsapp-bridge/bridge.js +729 -0
  992. package/scripts/whatsapp-bridge/package-lock.json +2141 -0
  993. package/scripts/whatsapp-bridge/package.json +19 -0
  994. package/skills/apple/DESCRIPTION.md +2 -0
  995. package/skills/apple/apple-notes/SKILL.md +90 -0
  996. package/skills/apple/apple-reminders/SKILL.md +98 -0
  997. package/skills/apple/findmy/SKILL.md +131 -0
  998. package/skills/apple/imessage/SKILL.md +102 -0
  999. package/skills/apple/macos-computer-use/SKILL.md +201 -0
  1000. package/skills/autonomous-ai-agents/DESCRIPTION.md +3 -0
  1001. package/skills/autonomous-ai-agents/claude-code/SKILL.md +745 -0
  1002. package/skills/autonomous-ai-agents/codex/SKILL.md +130 -0
  1003. package/skills/autonomous-ai-agents/hermes-agent/SKILL.md +1014 -0
  1004. package/skills/autonomous-ai-agents/opencode/SKILL.md +219 -0
  1005. package/skills/creative/DESCRIPTION.md +3 -0
  1006. package/skills/creative/architecture-diagram/SKILL.md +148 -0
  1007. package/skills/creative/architecture-diagram/templates/template.html +319 -0
  1008. package/skills/creative/ascii-art/SKILL.md +322 -0
  1009. package/skills/creative/ascii-video/README.md +290 -0
  1010. package/skills/creative/ascii-video/SKILL.md +241 -0
  1011. package/skills/creative/ascii-video/references/architecture.md +802 -0
  1012. package/skills/creative/ascii-video/references/composition.md +892 -0
  1013. package/skills/creative/ascii-video/references/effects.md +1865 -0
  1014. package/skills/creative/ascii-video/references/inputs.md +685 -0
  1015. package/skills/creative/ascii-video/references/optimization.md +688 -0
  1016. package/skills/creative/ascii-video/references/scenes.md +1011 -0
  1017. package/skills/creative/ascii-video/references/shaders.md +1385 -0
  1018. package/skills/creative/ascii-video/references/troubleshooting.md +367 -0
  1019. package/skills/creative/baoyu-comic/PORT_NOTES.md +77 -0
  1020. package/skills/creative/baoyu-comic/SKILL.md +247 -0
  1021. package/skills/creative/baoyu-comic/references/analysis-framework.md +176 -0
  1022. package/skills/creative/baoyu-comic/references/art-styles/chalk.md +101 -0
  1023. package/skills/creative/baoyu-comic/references/art-styles/ink-brush.md +97 -0
  1024. package/skills/creative/baoyu-comic/references/art-styles/ligne-claire.md +75 -0
  1025. package/skills/creative/baoyu-comic/references/art-styles/manga.md +93 -0
  1026. package/skills/creative/baoyu-comic/references/art-styles/minimalist.md +84 -0
  1027. package/skills/creative/baoyu-comic/references/art-styles/realistic.md +89 -0
  1028. package/skills/creative/baoyu-comic/references/auto-selection.md +71 -0
  1029. package/skills/creative/baoyu-comic/references/base-prompt.md +98 -0
  1030. package/skills/creative/baoyu-comic/references/character-template.md +180 -0
  1031. package/skills/creative/baoyu-comic/references/layouts/cinematic.md +23 -0
  1032. package/skills/creative/baoyu-comic/references/layouts/dense.md +23 -0
  1033. package/skills/creative/baoyu-comic/references/layouts/four-panel.md +40 -0
  1034. package/skills/creative/baoyu-comic/references/layouts/mixed.md +23 -0
  1035. package/skills/creative/baoyu-comic/references/layouts/splash.md +23 -0
  1036. package/skills/creative/baoyu-comic/references/layouts/standard.md +23 -0
  1037. package/skills/creative/baoyu-comic/references/layouts/webtoon.md +30 -0
  1038. package/skills/creative/baoyu-comic/references/ohmsha-guide.md +85 -0
  1039. package/skills/creative/baoyu-comic/references/partial-workflows.md +106 -0
  1040. package/skills/creative/baoyu-comic/references/presets/concept-story.md +121 -0
  1041. package/skills/creative/baoyu-comic/references/presets/four-panel.md +107 -0
  1042. package/skills/creative/baoyu-comic/references/presets/ohmsha.md +114 -0
  1043. package/skills/creative/baoyu-comic/references/presets/shoujo.md +116 -0
  1044. package/skills/creative/baoyu-comic/references/presets/wuxia.md +110 -0
  1045. package/skills/creative/baoyu-comic/references/storyboard-template.md +143 -0
  1046. package/skills/creative/baoyu-comic/references/tones/action.md +110 -0
  1047. package/skills/creative/baoyu-comic/references/tones/dramatic.md +95 -0
  1048. package/skills/creative/baoyu-comic/references/tones/energetic.md +105 -0
  1049. package/skills/creative/baoyu-comic/references/tones/neutral.md +63 -0
  1050. package/skills/creative/baoyu-comic/references/tones/romantic.md +100 -0
  1051. package/skills/creative/baoyu-comic/references/tones/vintage.md +104 -0
  1052. package/skills/creative/baoyu-comic/references/tones/warm.md +94 -0
  1053. package/skills/creative/baoyu-comic/references/workflow.md +401 -0
  1054. package/skills/creative/baoyu-infographic/PORT_NOTES.md +43 -0
  1055. package/skills/creative/baoyu-infographic/SKILL.md +237 -0
  1056. package/skills/creative/baoyu-infographic/references/analysis-framework.md +182 -0
  1057. package/skills/creative/baoyu-infographic/references/base-prompt.md +43 -0
  1058. package/skills/creative/baoyu-infographic/references/layouts/bento-grid.md +41 -0
  1059. package/skills/creative/baoyu-infographic/references/layouts/binary-comparison.md +48 -0
  1060. package/skills/creative/baoyu-infographic/references/layouts/bridge.md +41 -0
  1061. package/skills/creative/baoyu-infographic/references/layouts/circular-flow.md +41 -0
  1062. package/skills/creative/baoyu-infographic/references/layouts/comic-strip.md +41 -0
  1063. package/skills/creative/baoyu-infographic/references/layouts/comparison-matrix.md +41 -0
  1064. package/skills/creative/baoyu-infographic/references/layouts/dashboard.md +41 -0
  1065. package/skills/creative/baoyu-infographic/references/layouts/dense-modules.md +72 -0
  1066. package/skills/creative/baoyu-infographic/references/layouts/funnel.md +41 -0
  1067. package/skills/creative/baoyu-infographic/references/layouts/hierarchical-layers.md +48 -0
  1068. package/skills/creative/baoyu-infographic/references/layouts/hub-spoke.md +41 -0
  1069. package/skills/creative/baoyu-infographic/references/layouts/iceberg.md +41 -0
  1070. package/skills/creative/baoyu-infographic/references/layouts/isometric-map.md +41 -0
  1071. package/skills/creative/baoyu-infographic/references/layouts/jigsaw.md +41 -0
  1072. package/skills/creative/baoyu-infographic/references/layouts/linear-progression.md +48 -0
  1073. package/skills/creative/baoyu-infographic/references/layouts/periodic-table.md +41 -0
  1074. package/skills/creative/baoyu-infographic/references/layouts/story-mountain.md +41 -0
  1075. package/skills/creative/baoyu-infographic/references/layouts/structural-breakdown.md +48 -0
  1076. package/skills/creative/baoyu-infographic/references/layouts/tree-branching.md +41 -0
  1077. package/skills/creative/baoyu-infographic/references/layouts/venn-diagram.md +41 -0
  1078. package/skills/creative/baoyu-infographic/references/layouts/winding-roadmap.md +41 -0
  1079. package/skills/creative/baoyu-infographic/references/structured-content-template.md +244 -0
  1080. package/skills/creative/baoyu-infographic/references/styles/aged-academia.md +36 -0
  1081. package/skills/creative/baoyu-infographic/references/styles/bold-graphic.md +36 -0
  1082. package/skills/creative/baoyu-infographic/references/styles/chalkboard.md +61 -0
  1083. package/skills/creative/baoyu-infographic/references/styles/claymation.md +29 -0
  1084. package/skills/creative/baoyu-infographic/references/styles/corporate-memphis.md +29 -0
  1085. package/skills/creative/baoyu-infographic/references/styles/craft-handmade.md +44 -0
  1086. package/skills/creative/baoyu-infographic/references/styles/cyberpunk-neon.md +29 -0
  1087. package/skills/creative/baoyu-infographic/references/styles/hand-drawn-edu.md +63 -0
  1088. package/skills/creative/baoyu-infographic/references/styles/ikea-manual.md +29 -0
  1089. package/skills/creative/baoyu-infographic/references/styles/kawaii.md +29 -0
  1090. package/skills/creative/baoyu-infographic/references/styles/knolling.md +29 -0
  1091. package/skills/creative/baoyu-infographic/references/styles/lego-brick.md +29 -0
  1092. package/skills/creative/baoyu-infographic/references/styles/morandi-journal.md +60 -0
  1093. package/skills/creative/baoyu-infographic/references/styles/origami.md +29 -0
  1094. package/skills/creative/baoyu-infographic/references/styles/pixel-art.md +29 -0
  1095. package/skills/creative/baoyu-infographic/references/styles/pop-laboratory.md +48 -0
  1096. package/skills/creative/baoyu-infographic/references/styles/retro-pop-grid.md +47 -0
  1097. package/skills/creative/baoyu-infographic/references/styles/storybook-watercolor.md +29 -0
  1098. package/skills/creative/baoyu-infographic/references/styles/subway-map.md +29 -0
  1099. package/skills/creative/baoyu-infographic/references/styles/technical-schematic.md +36 -0
  1100. package/skills/creative/baoyu-infographic/references/styles/ui-wireframe.md +29 -0
  1101. package/skills/creative/claude-design/SKILL.md +591 -0
  1102. package/skills/creative/comfyui/SKILL.md +612 -0
  1103. package/skills/creative/comfyui/references/official-cli.md +255 -0
  1104. package/skills/creative/comfyui/references/rest-api.md +312 -0
  1105. package/skills/creative/comfyui/references/template-integrity.md +243 -0
  1106. package/skills/creative/comfyui/references/workflow-format.md +226 -0
  1107. package/skills/creative/comfyui/scripts/_common.py +835 -0
  1108. package/skills/creative/comfyui/scripts/auto_fix_deps.py +225 -0
  1109. package/skills/creative/comfyui/scripts/check_deps.py +437 -0
  1110. package/skills/creative/comfyui/scripts/comfyui_setup.sh +286 -0
  1111. package/skills/creative/comfyui/scripts/extract_schema.py +315 -0
  1112. package/skills/creative/comfyui/scripts/fetch_logs.py +158 -0
  1113. package/skills/creative/comfyui/scripts/hardware_check.py +497 -0
  1114. package/skills/creative/comfyui/scripts/health_check.py +223 -0
  1115. package/skills/creative/comfyui/scripts/run_batch.py +243 -0
  1116. package/skills/creative/comfyui/scripts/run_workflow.py +796 -0
  1117. package/skills/creative/comfyui/scripts/ws_monitor.py +267 -0
  1118. package/skills/creative/comfyui/tests/README.md +50 -0
  1119. package/skills/creative/comfyui/tests/conftest.py +64 -0
  1120. package/skills/creative/comfyui/tests/pytest.ini +5 -0
  1121. package/skills/creative/comfyui/tests/test_check_deps.py +68 -0
  1122. package/skills/creative/comfyui/tests/test_cloud_integration.py +95 -0
  1123. package/skills/creative/comfyui/tests/test_common.py +447 -0
  1124. package/skills/creative/comfyui/tests/test_extract_schema.py +185 -0
  1125. package/skills/creative/comfyui/tests/test_run_workflow.py +213 -0
  1126. package/skills/creative/comfyui/workflows/README.md +86 -0
  1127. package/skills/creative/comfyui/workflows/animatediff_video.json +64 -0
  1128. package/skills/creative/comfyui/workflows/flux_dev_txt2img.json +78 -0
  1129. package/skills/creative/comfyui/workflows/sd15_txt2img.json +49 -0
  1130. package/skills/creative/comfyui/workflows/sdxl_img2img.json +54 -0
  1131. package/skills/creative/comfyui/workflows/sdxl_inpaint.json +59 -0
  1132. package/skills/creative/comfyui/workflows/sdxl_txt2img.json +49 -0
  1133. package/skills/creative/comfyui/workflows/upscale_4x.json +27 -0
  1134. package/skills/creative/comfyui/workflows/wan_video_t2v.json +69 -0
  1135. package/skills/creative/creative-ideation/SKILL.md +152 -0
  1136. package/skills/creative/creative-ideation/references/full-prompt-library.md +110 -0
  1137. package/skills/creative/design-md/SKILL.md +199 -0
  1138. package/skills/creative/design-md/templates/starter.md +99 -0
  1139. package/skills/creative/excalidraw/SKILL.md +199 -0
  1140. package/skills/creative/excalidraw/references/colors.md +44 -0
  1141. package/skills/creative/excalidraw/references/dark-mode.md +68 -0
  1142. package/skills/creative/excalidraw/references/examples.md +141 -0
  1143. package/skills/creative/excalidraw/scripts/upload.py +133 -0
  1144. package/skills/creative/humanizer/LICENSE +21 -0
  1145. package/skills/creative/humanizer/SKILL.md +578 -0
  1146. package/skills/creative/manim-video/README.md +23 -0
  1147. package/skills/creative/manim-video/SKILL.md +269 -0
  1148. package/skills/creative/manim-video/references/animation-design-thinking.md +161 -0
  1149. package/skills/creative/manim-video/references/animations.md +282 -0
  1150. package/skills/creative/manim-video/references/camera-and-3d.md +135 -0
  1151. package/skills/creative/manim-video/references/decorations.md +202 -0
  1152. package/skills/creative/manim-video/references/equations.md +216 -0
  1153. package/skills/creative/manim-video/references/graphs-and-data.md +163 -0
  1154. package/skills/creative/manim-video/references/mobjects.md +333 -0
  1155. package/skills/creative/manim-video/references/paper-explainer.md +255 -0
  1156. package/skills/creative/manim-video/references/production-quality.md +190 -0
  1157. package/skills/creative/manim-video/references/rendering.md +185 -0
  1158. package/skills/creative/manim-video/references/scene-planning.md +118 -0
  1159. package/skills/creative/manim-video/references/troubleshooting.md +135 -0
  1160. package/skills/creative/manim-video/references/updaters-and-trackers.md +260 -0
  1161. package/skills/creative/manim-video/references/visual-design.md +124 -0
  1162. package/skills/creative/manim-video/scripts/setup.sh +14 -0
  1163. package/skills/creative/p5js/README.md +64 -0
  1164. package/skills/creative/p5js/SKILL.md +556 -0
  1165. package/skills/creative/p5js/references/animation.md +439 -0
  1166. package/skills/creative/p5js/references/color-systems.md +352 -0
  1167. package/skills/creative/p5js/references/core-api.md +410 -0
  1168. package/skills/creative/p5js/references/export-pipeline.md +566 -0
  1169. package/skills/creative/p5js/references/interaction.md +398 -0
  1170. package/skills/creative/p5js/references/shapes-and-geometry.md +300 -0
  1171. package/skills/creative/p5js/references/troubleshooting.md +532 -0
  1172. package/skills/creative/p5js/references/typography.md +302 -0
  1173. package/skills/creative/p5js/references/visual-effects.md +895 -0
  1174. package/skills/creative/p5js/references/webgl-and-3d.md +423 -0
  1175. package/skills/creative/p5js/scripts/export-frames.js +179 -0
  1176. package/skills/creative/p5js/scripts/render.sh +108 -0
  1177. package/skills/creative/p5js/scripts/serve.sh +28 -0
  1178. package/skills/creative/p5js/scripts/setup.sh +87 -0
  1179. package/skills/creative/p5js/templates/viewer.html +395 -0
  1180. package/skills/creative/pixel-art/ATTRIBUTION.md +54 -0
  1181. package/skills/creative/pixel-art/SKILL.md +218 -0
  1182. package/skills/creative/pixel-art/references/palettes.md +49 -0
  1183. package/skills/creative/pixel-art/scripts/__init__.py +0 -0
  1184. package/skills/creative/pixel-art/scripts/palettes.py +167 -0
  1185. package/skills/creative/pixel-art/scripts/pixel_art.py +162 -0
  1186. package/skills/creative/pixel-art/scripts/pixel_art_video.py +345 -0
  1187. package/skills/creative/popular-web-designs/SKILL.md +214 -0
  1188. package/skills/creative/popular-web-designs/templates/airbnb.md +259 -0
  1189. package/skills/creative/popular-web-designs/templates/airtable.md +102 -0
  1190. package/skills/creative/popular-web-designs/templates/apple.md +326 -0
  1191. package/skills/creative/popular-web-designs/templates/bmw.md +193 -0
  1192. package/skills/creative/popular-web-designs/templates/cal.md +272 -0
  1193. package/skills/creative/popular-web-designs/templates/claude.md +325 -0
  1194. package/skills/creative/popular-web-designs/templates/clay.md +317 -0
  1195. package/skills/creative/popular-web-designs/templates/clickhouse.md +294 -0
  1196. package/skills/creative/popular-web-designs/templates/cohere.md +279 -0
  1197. package/skills/creative/popular-web-designs/templates/coinbase.md +142 -0
  1198. package/skills/creative/popular-web-designs/templates/composio.md +320 -0
  1199. package/skills/creative/popular-web-designs/templates/cursor.md +322 -0
  1200. package/skills/creative/popular-web-designs/templates/elevenlabs.md +278 -0
  1201. package/skills/creative/popular-web-designs/templates/expo.md +294 -0
  1202. package/skills/creative/popular-web-designs/templates/figma.md +233 -0
  1203. package/skills/creative/popular-web-designs/templates/framer.md +259 -0
  1204. package/skills/creative/popular-web-designs/templates/hashicorp.md +291 -0
  1205. package/skills/creative/popular-web-designs/templates/ibm.md +345 -0
  1206. package/skills/creative/popular-web-designs/templates/intercom.md +159 -0
  1207. package/skills/creative/popular-web-designs/templates/kraken.md +138 -0
  1208. package/skills/creative/popular-web-designs/templates/linear.app.md +380 -0
  1209. package/skills/creative/popular-web-designs/templates/lovable.md +311 -0
  1210. package/skills/creative/popular-web-designs/templates/minimax.md +270 -0
  1211. package/skills/creative/popular-web-designs/templates/mintlify.md +339 -0
  1212. package/skills/creative/popular-web-designs/templates/miro.md +121 -0
  1213. package/skills/creative/popular-web-designs/templates/mistral.ai.md +274 -0
  1214. package/skills/creative/popular-web-designs/templates/mongodb.md +279 -0
  1215. package/skills/creative/popular-web-designs/templates/notion.md +322 -0
  1216. package/skills/creative/popular-web-designs/templates/nvidia.md +306 -0
  1217. package/skills/creative/popular-web-designs/templates/ollama.md +280 -0
  1218. package/skills/creative/popular-web-designs/templates/opencode.ai.md +294 -0
  1219. package/skills/creative/popular-web-designs/templates/pinterest.md +243 -0
  1220. package/skills/creative/popular-web-designs/templates/posthog.md +269 -0
  1221. package/skills/creative/popular-web-designs/templates/raycast.md +281 -0
  1222. package/skills/creative/popular-web-designs/templates/replicate.md +274 -0
  1223. package/skills/creative/popular-web-designs/templates/resend.md +316 -0
  1224. package/skills/creative/popular-web-designs/templates/revolut.md +198 -0
  1225. package/skills/creative/popular-web-designs/templates/runwayml.md +257 -0
  1226. package/skills/creative/popular-web-designs/templates/sanity.md +370 -0
  1227. package/skills/creative/popular-web-designs/templates/sentry.md +275 -0
  1228. package/skills/creative/popular-web-designs/templates/spacex.md +207 -0
  1229. package/skills/creative/popular-web-designs/templates/spotify.md +259 -0
  1230. package/skills/creative/popular-web-designs/templates/stripe.md +335 -0
  1231. package/skills/creative/popular-web-designs/templates/supabase.md +268 -0
  1232. package/skills/creative/popular-web-designs/templates/superhuman.md +265 -0
  1233. package/skills/creative/popular-web-designs/templates/together.ai.md +276 -0
  1234. package/skills/creative/popular-web-designs/templates/uber.md +308 -0
  1235. package/skills/creative/popular-web-designs/templates/vercel.md +323 -0
  1236. package/skills/creative/popular-web-designs/templates/voltagent.md +336 -0
  1237. package/skills/creative/popular-web-designs/templates/warp.md +266 -0
  1238. package/skills/creative/popular-web-designs/templates/webflow.md +105 -0
  1239. package/skills/creative/popular-web-designs/templates/wise.md +186 -0
  1240. package/skills/creative/popular-web-designs/templates/x.ai.md +270 -0
  1241. package/skills/creative/popular-web-designs/templates/zapier.md +341 -0
  1242. package/skills/creative/pretext/SKILL.md +220 -0
  1243. package/skills/creative/pretext/references/patterns.md +258 -0
  1244. package/skills/creative/pretext/templates/donut-orbit.html +1468 -0
  1245. package/skills/creative/pretext/templates/hello-orb-flow.html +95 -0
  1246. package/skills/creative/sketch/SKILL.md +218 -0
  1247. package/skills/creative/songwriting-and-ai-music/SKILL.md +287 -0
  1248. package/skills/creative/touchdesigner-mcp/SKILL.md +356 -0
  1249. package/skills/creative/touchdesigner-mcp/references/3d-scene.md +275 -0
  1250. package/skills/creative/touchdesigner-mcp/references/animation.md +221 -0
  1251. package/skills/creative/touchdesigner-mcp/references/audio-reactive.md +175 -0
  1252. package/skills/creative/touchdesigner-mcp/references/dat-scripting.md +352 -0
  1253. package/skills/creative/touchdesigner-mcp/references/external-data.md +322 -0
  1254. package/skills/creative/touchdesigner-mcp/references/geometry-comp.md +121 -0
  1255. package/skills/creative/touchdesigner-mcp/references/glsl.md +151 -0
  1256. package/skills/creative/touchdesigner-mcp/references/layout-compositor.md +131 -0
  1257. package/skills/creative/touchdesigner-mcp/references/mcp-tools.md +382 -0
  1258. package/skills/creative/touchdesigner-mcp/references/midi-osc.md +211 -0
  1259. package/skills/creative/touchdesigner-mcp/references/network-patterns.md +966 -0
  1260. package/skills/creative/touchdesigner-mcp/references/operator-tips.md +106 -0
  1261. package/skills/creative/touchdesigner-mcp/references/operators.md +239 -0
  1262. package/skills/creative/touchdesigner-mcp/references/panel-ui.md +281 -0
  1263. package/skills/creative/touchdesigner-mcp/references/particles.md +245 -0
  1264. package/skills/creative/touchdesigner-mcp/references/pitfalls.md +704 -0
  1265. package/skills/creative/touchdesigner-mcp/references/postfx.md +183 -0
  1266. package/skills/creative/touchdesigner-mcp/references/projection-mapping.md +211 -0
  1267. package/skills/creative/touchdesigner-mcp/references/python-api.md +463 -0
  1268. package/skills/creative/touchdesigner-mcp/references/replicator.md +198 -0
  1269. package/skills/creative/touchdesigner-mcp/references/troubleshooting.md +244 -0
  1270. package/skills/creative/touchdesigner-mcp/scripts/setup.sh +115 -0
  1271. package/skills/data-science/DESCRIPTION.md +3 -0
  1272. package/skills/data-science/jupyter-live-kernel/SKILL.md +167 -0
  1273. package/skills/devops/kanban-orchestrator/SKILL.md +189 -0
  1274. package/skills/devops/kanban-worker/SKILL.md +184 -0
  1275. package/skills/devops/webhook-subscriptions/SKILL.md +204 -0
  1276. package/skills/diagramming/DESCRIPTION.md +3 -0
  1277. package/skills/dogfood/SKILL.md +162 -0
  1278. package/skills/dogfood/references/issue-taxonomy.md +109 -0
  1279. package/skills/dogfood/templates/dogfood-report-template.md +86 -0
  1280. package/skills/domain/DESCRIPTION.md +24 -0
  1281. package/skills/email/DESCRIPTION.md +3 -0
  1282. package/skills/email/himalaya/SKILL.md +299 -0
  1283. package/skills/email/himalaya/references/configuration.md +227 -0
  1284. package/skills/email/himalaya/references/message-composition.md +199 -0
  1285. package/skills/gaming/DESCRIPTION.md +3 -0
  1286. package/skills/gaming/minecraft-modpack-server/SKILL.md +187 -0
  1287. package/skills/gaming/pokemon-player/SKILL.md +216 -0
  1288. package/skills/gifs/DESCRIPTION.md +3 -0
  1289. package/skills/github/DESCRIPTION.md +3 -0
  1290. package/skills/github/codebase-inspection/SKILL.md +116 -0
  1291. package/skills/github/github-auth/SKILL.md +247 -0
  1292. package/skills/github/github-auth/scripts/gh-env.sh +66 -0
  1293. package/skills/github/github-code-review/SKILL.md +481 -0
  1294. package/skills/github/github-code-review/references/review-output-template.md +74 -0
  1295. package/skills/github/github-issues/SKILL.md +370 -0
  1296. package/skills/github/github-issues/templates/bug-report.md +35 -0
  1297. package/skills/github/github-issues/templates/feature-request.md +31 -0
  1298. package/skills/github/github-pr-workflow/SKILL.md +367 -0
  1299. package/skills/github/github-pr-workflow/references/ci-troubleshooting.md +183 -0
  1300. package/skills/github/github-pr-workflow/references/conventional-commits.md +71 -0
  1301. package/skills/github/github-pr-workflow/templates/pr-body-bugfix.md +35 -0
  1302. package/skills/github/github-pr-workflow/templates/pr-body-feature.md +33 -0
  1303. package/skills/github/github-repo-management/SKILL.md +516 -0
  1304. package/skills/github/github-repo-management/references/github-api-cheatsheet.md +161 -0
  1305. package/skills/index-cache/anthropics_skills_skills_.json +1 -0
  1306. package/skills/index-cache/claude_marketplace_anthropics_skills.json +1 -0
  1307. package/skills/index-cache/lobehub_index.json +1 -0
  1308. package/skills/index-cache/openai_skills_skills_.json +1 -0
  1309. package/skills/inference-sh/DESCRIPTION.md +19 -0
  1310. package/skills/mcp/DESCRIPTION.md +3 -0
  1311. package/skills/mcp/native-mcp/SKILL.md +357 -0
  1312. package/skills/media/DESCRIPTION.md +3 -0
  1313. package/skills/media/gif-search/SKILL.md +91 -0
  1314. package/skills/media/heartmula/SKILL.md +171 -0
  1315. package/skills/media/songsee/SKILL.md +83 -0
  1316. package/skills/media/spotify/SKILL.md +135 -0
  1317. package/skills/media/youtube-content/SKILL.md +73 -0
  1318. package/skills/media/youtube-content/references/output-formats.md +56 -0
  1319. package/skills/media/youtube-content/scripts/fetch_transcript.py +124 -0
  1320. package/skills/mlops/DESCRIPTION.md +3 -0
  1321. package/skills/mlops/evaluation/DESCRIPTION.md +3 -0
  1322. package/skills/mlops/evaluation/lm-evaluation-harness/SKILL.md +498 -0
  1323. package/skills/mlops/evaluation/lm-evaluation-harness/references/api-evaluation.md +490 -0
  1324. package/skills/mlops/evaluation/lm-evaluation-harness/references/benchmark-guide.md +488 -0
  1325. package/skills/mlops/evaluation/lm-evaluation-harness/references/custom-tasks.md +602 -0
  1326. package/skills/mlops/evaluation/lm-evaluation-harness/references/distributed-eval.md +519 -0
  1327. package/skills/mlops/evaluation/weights-and-biases/SKILL.md +594 -0
  1328. package/skills/mlops/evaluation/weights-and-biases/references/artifacts.md +584 -0
  1329. package/skills/mlops/evaluation/weights-and-biases/references/integrations.md +700 -0
  1330. package/skills/mlops/evaluation/weights-and-biases/references/sweeps.md +847 -0
  1331. package/skills/mlops/huggingface-hub/SKILL.md +81 -0
  1332. package/skills/mlops/inference/DESCRIPTION.md +3 -0
  1333. package/skills/mlops/inference/llama-cpp/SKILL.md +249 -0
  1334. package/skills/mlops/inference/llama-cpp/references/advanced-usage.md +504 -0
  1335. package/skills/mlops/inference/llama-cpp/references/hub-discovery.md +168 -0
  1336. package/skills/mlops/inference/llama-cpp/references/optimization.md +89 -0
  1337. package/skills/mlops/inference/llama-cpp/references/quantization.md +243 -0
  1338. package/skills/mlops/inference/llama-cpp/references/server.md +150 -0
  1339. package/skills/mlops/inference/llama-cpp/references/troubleshooting.md +442 -0
  1340. package/skills/mlops/inference/obliteratus/SKILL.md +342 -0
  1341. package/skills/mlops/inference/obliteratus/references/analysis-modules.md +166 -0
  1342. package/skills/mlops/inference/obliteratus/references/methods-guide.md +141 -0
  1343. package/skills/mlops/inference/obliteratus/templates/abliteration-config.yaml +33 -0
  1344. package/skills/mlops/inference/obliteratus/templates/analysis-study.yaml +40 -0
  1345. package/skills/mlops/inference/obliteratus/templates/batch-abliteration.yaml +41 -0
  1346. package/skills/mlops/inference/vllm/SKILL.md +372 -0
  1347. package/skills/mlops/inference/vllm/references/optimization.md +226 -0
  1348. package/skills/mlops/inference/vllm/references/quantization.md +284 -0
  1349. package/skills/mlops/inference/vllm/references/server-deployment.md +255 -0
  1350. package/skills/mlops/inference/vllm/references/troubleshooting.md +447 -0
  1351. package/skills/mlops/models/DESCRIPTION.md +3 -0
  1352. package/skills/mlops/models/audiocraft/SKILL.md +568 -0
  1353. package/skills/mlops/models/audiocraft/references/advanced-usage.md +666 -0
  1354. package/skills/mlops/models/audiocraft/references/troubleshooting.md +504 -0
  1355. package/skills/mlops/models/segment-anything/SKILL.md +506 -0
  1356. package/skills/mlops/models/segment-anything/references/advanced-usage.md +589 -0
  1357. package/skills/mlops/models/segment-anything/references/troubleshooting.md +484 -0
  1358. package/skills/mlops/research/DESCRIPTION.md +3 -0
  1359. package/skills/mlops/research/dspy/SKILL.md +594 -0
  1360. package/skills/mlops/research/dspy/references/examples.md +663 -0
  1361. package/skills/mlops/research/dspy/references/modules.md +475 -0
  1362. package/skills/mlops/research/dspy/references/optimizers.md +566 -0
  1363. package/skills/mlops/training/DESCRIPTION.md +3 -0
  1364. package/skills/mlops/vector-databases/DESCRIPTION.md +3 -0
  1365. package/skills/note-taking/DESCRIPTION.md +3 -0
  1366. package/skills/note-taking/obsidian/SKILL.md +61 -0
  1367. package/skills/productivity/DESCRIPTION.md +3 -0
  1368. package/skills/productivity/airtable/SKILL.md +229 -0
  1369. package/skills/productivity/google-workspace/SKILL.md +335 -0
  1370. package/skills/productivity/google-workspace/references/gmail-search-syntax.md +63 -0
  1371. package/skills/productivity/google-workspace/scripts/_hermes_home.py +43 -0
  1372. package/skills/productivity/google-workspace/scripts/google_api.py +1221 -0
  1373. package/skills/productivity/google-workspace/scripts/gws_bridge.py +108 -0
  1374. package/skills/productivity/google-workspace/scripts/setup.py +454 -0
  1375. package/skills/productivity/linear/SKILL.md +380 -0
  1376. package/skills/productivity/linear/scripts/linear_api.py +445 -0
  1377. package/skills/productivity/maps/SKILL.md +195 -0
  1378. package/skills/productivity/maps/scripts/maps_client.py +1298 -0
  1379. package/skills/productivity/nano-pdf/SKILL.md +52 -0
  1380. package/skills/productivity/notion/SKILL.md +448 -0
  1381. package/skills/productivity/notion/references/block-types.md +112 -0
  1382. package/skills/productivity/ocr-and-documents/DESCRIPTION.md +3 -0
  1383. package/skills/productivity/ocr-and-documents/SKILL.md +172 -0
  1384. package/skills/productivity/ocr-and-documents/scripts/extract_marker.py +87 -0
  1385. package/skills/productivity/ocr-and-documents/scripts/extract_pymupdf.py +98 -0
  1386. package/skills/productivity/powerpoint/LICENSE.txt +30 -0
  1387. package/skills/productivity/powerpoint/SKILL.md +237 -0
  1388. package/skills/productivity/powerpoint/editing.md +205 -0
  1389. package/skills/productivity/powerpoint/pptxgenjs.md +420 -0
  1390. package/skills/productivity/powerpoint/scripts/__init__.py +0 -0
  1391. package/skills/productivity/powerpoint/scripts/add_slide.py +195 -0
  1392. package/skills/productivity/powerpoint/scripts/clean.py +286 -0
  1393. package/skills/productivity/powerpoint/scripts/office/helpers/__init__.py +0 -0
  1394. package/skills/productivity/powerpoint/scripts/office/helpers/merge_runs.py +199 -0
  1395. package/skills/productivity/powerpoint/scripts/office/helpers/simplify_redlines.py +197 -0
  1396. package/skills/productivity/powerpoint/scripts/office/pack.py +159 -0
  1397. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  1398. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  1399. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  1400. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  1401. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  1402. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  1403. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  1404. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  1405. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  1406. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  1407. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  1408. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  1409. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  1410. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  1411. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  1412. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  1413. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  1414. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  1415. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  1416. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  1417. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  1418. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  1419. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  1420. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  1421. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  1422. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  1423. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  1424. package/skills/productivity/powerpoint/scripts/office/schemas/ecma/fourth-edition/opc-contentTypes.xsd +42 -0
  1425. package/skills/productivity/powerpoint/scripts/office/schemas/ecma/fourth-edition/opc-coreProperties.xsd +50 -0
  1426. package/skills/productivity/powerpoint/scripts/office/schemas/ecma/fourth-edition/opc-digSig.xsd +49 -0
  1427. package/skills/productivity/powerpoint/scripts/office/schemas/ecma/fourth-edition/opc-relationships.xsd +33 -0
  1428. package/skills/productivity/powerpoint/scripts/office/schemas/mce/mc.xsd +75 -0
  1429. package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
  1430. package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
  1431. package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
  1432. package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
  1433. package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
  1434. package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  1435. package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
  1436. package/skills/productivity/teams-meeting-pipeline/SKILL.md +116 -0
  1437. package/skills/red-teaming/godmode/SKILL.md +404 -0
  1438. package/skills/red-teaming/godmode/references/jailbreak-templates.md +128 -0
  1439. package/skills/red-teaming/godmode/references/refusal-detection.md +142 -0
  1440. package/skills/red-teaming/godmode/scripts/auto_jailbreak.py +769 -0
  1441. package/skills/red-teaming/godmode/scripts/godmode_race.py +530 -0
  1442. package/skills/red-teaming/godmode/scripts/load_godmode.py +45 -0
  1443. package/skills/red-teaming/godmode/scripts/parseltongue.py +550 -0
  1444. package/skills/red-teaming/godmode/templates/prefill-subtle.json +10 -0
  1445. package/skills/red-teaming/godmode/templates/prefill.json +18 -0
  1446. package/skills/research/DESCRIPTION.md +3 -0
  1447. package/skills/research/arxiv/SKILL.md +282 -0
  1448. package/skills/research/arxiv/scripts/search_arxiv.py +114 -0
  1449. package/skills/research/blogwatcher/SKILL.md +137 -0
  1450. package/skills/research/llm-wiki/SKILL.md +507 -0
  1451. package/skills/research/polymarket/SKILL.md +77 -0
  1452. package/skills/research/polymarket/references/api-endpoints.md +220 -0
  1453. package/skills/research/polymarket/scripts/polymarket.py +284 -0
  1454. package/skills/research/research-paper-writing/SKILL.md +2377 -0
  1455. package/skills/research/research-paper-writing/references/autoreason-methodology.md +394 -0
  1456. package/skills/research/research-paper-writing/references/checklists.md +434 -0
  1457. package/skills/research/research-paper-writing/references/citation-workflow.md +564 -0
  1458. package/skills/research/research-paper-writing/references/experiment-patterns.md +728 -0
  1459. package/skills/research/research-paper-writing/references/human-evaluation.md +476 -0
  1460. package/skills/research/research-paper-writing/references/paper-types.md +481 -0
  1461. package/skills/research/research-paper-writing/references/reviewer-guidelines.md +433 -0
  1462. package/skills/research/research-paper-writing/references/sources.md +191 -0
  1463. package/skills/research/research-paper-writing/references/writing-guide.md +474 -0
  1464. package/skills/research/research-paper-writing/templates/README.md +251 -0
  1465. package/skills/research/research-paper-writing/templates/aaai2026/README.md +534 -0
  1466. package/skills/research/research-paper-writing/templates/aaai2026/aaai2026-unified-supp.tex +144 -0
  1467. package/skills/research/research-paper-writing/templates/aaai2026/aaai2026-unified-template.tex +952 -0
  1468. package/skills/research/research-paper-writing/templates/aaai2026/aaai2026.bib +111 -0
  1469. package/skills/research/research-paper-writing/templates/aaai2026/aaai2026.bst +1493 -0
  1470. package/skills/research/research-paper-writing/templates/aaai2026/aaai2026.sty +315 -0
  1471. package/skills/research/research-paper-writing/templates/acl/README.md +50 -0
  1472. package/skills/research/research-paper-writing/templates/acl/acl.sty +312 -0
  1473. package/skills/research/research-paper-writing/templates/acl/acl_latex.tex +377 -0
  1474. package/skills/research/research-paper-writing/templates/acl/acl_lualatex.tex +101 -0
  1475. package/skills/research/research-paper-writing/templates/acl/acl_natbib.bst +1940 -0
  1476. package/skills/research/research-paper-writing/templates/acl/anthology.bib.txt +26 -0
  1477. package/skills/research/research-paper-writing/templates/acl/custom.bib +70 -0
  1478. package/skills/research/research-paper-writing/templates/acl/formatting.md +326 -0
  1479. package/skills/research/research-paper-writing/templates/colm2025/README.md +3 -0
  1480. package/skills/research/research-paper-writing/templates/colm2025/colm2025_conference.bib +11 -0
  1481. package/skills/research/research-paper-writing/templates/colm2025/colm2025_conference.bst +1440 -0
  1482. package/skills/research/research-paper-writing/templates/colm2025/colm2025_conference.pdf +0 -0
  1483. package/skills/research/research-paper-writing/templates/colm2025/colm2025_conference.sty +218 -0
  1484. package/skills/research/research-paper-writing/templates/colm2025/colm2025_conference.tex +305 -0
  1485. package/skills/research/research-paper-writing/templates/colm2025/fancyhdr.sty +485 -0
  1486. package/skills/research/research-paper-writing/templates/colm2025/math_commands.tex +508 -0
  1487. package/skills/research/research-paper-writing/templates/colm2025/natbib.sty +1246 -0
  1488. package/skills/research/research-paper-writing/templates/iclr2026/fancyhdr.sty +485 -0
  1489. package/skills/research/research-paper-writing/templates/iclr2026/iclr2026_conference.bib +24 -0
  1490. package/skills/research/research-paper-writing/templates/iclr2026/iclr2026_conference.bst +1440 -0
  1491. package/skills/research/research-paper-writing/templates/iclr2026/iclr2026_conference.pdf +0 -0
  1492. package/skills/research/research-paper-writing/templates/iclr2026/iclr2026_conference.sty +246 -0
  1493. package/skills/research/research-paper-writing/templates/iclr2026/iclr2026_conference.tex +414 -0
  1494. package/skills/research/research-paper-writing/templates/iclr2026/math_commands.tex +508 -0
  1495. package/skills/research/research-paper-writing/templates/iclr2026/natbib.sty +1246 -0
  1496. package/skills/research/research-paper-writing/templates/icml2026/algorithm.sty +79 -0
  1497. package/skills/research/research-paper-writing/templates/icml2026/algorithmic.sty +201 -0
  1498. package/skills/research/research-paper-writing/templates/icml2026/example_paper.bib +75 -0
  1499. package/skills/research/research-paper-writing/templates/icml2026/example_paper.pdf +0 -0
  1500. package/skills/research/research-paper-writing/templates/icml2026/example_paper.tex +662 -0
  1501. package/skills/research/research-paper-writing/templates/icml2026/fancyhdr.sty +864 -0
  1502. package/skills/research/research-paper-writing/templates/icml2026/icml2026.bst +1443 -0
  1503. package/skills/research/research-paper-writing/templates/icml2026/icml2026.sty +767 -0
  1504. package/skills/research/research-paper-writing/templates/icml2026/icml_numpapers.pdf +0 -0
  1505. package/skills/research/research-paper-writing/templates/neurips2025/Makefile +36 -0
  1506. package/skills/research/research-paper-writing/templates/neurips2025/extra_pkgs.tex +53 -0
  1507. package/skills/research/research-paper-writing/templates/neurips2025/main.tex +38 -0
  1508. package/skills/research/research-paper-writing/templates/neurips2025/neurips.sty +382 -0
  1509. package/skills/smart-home/DESCRIPTION.md +3 -0
  1510. package/skills/smart-home/openhue/SKILL.md +109 -0
  1511. package/skills/social-media/DESCRIPTION.md +3 -0
  1512. package/skills/social-media/xurl/SKILL.md +414 -0
  1513. package/skills/software-development/debugging-hermes-tui-commands/SKILL.md +152 -0
  1514. package/skills/software-development/hermes-agent-skill-authoring/SKILL.md +165 -0
  1515. package/skills/software-development/node-inspect-debugger/SKILL.md +319 -0
  1516. package/skills/software-development/plan/SKILL.md +58 -0
  1517. package/skills/software-development/python-debugpy/SKILL.md +375 -0
  1518. package/skills/software-development/requesting-code-review/SKILL.md +280 -0
  1519. package/skills/software-development/spike/SKILL.md +197 -0
  1520. package/skills/software-development/subagent-driven-development/SKILL.md +352 -0
  1521. package/skills/software-development/subagent-driven-development/references/context-budget-discipline.md +53 -0
  1522. package/skills/software-development/subagent-driven-development/references/gates-taxonomy.md +93 -0
  1523. package/skills/software-development/systematic-debugging/SKILL.md +367 -0
  1524. package/skills/software-development/test-driven-development/SKILL.md +343 -0
  1525. package/skills/software-development/writing-plans/SKILL.md +297 -0
  1526. package/skills/yuanbao/SKILL.md +108 -0
  1527. package/tools/__init__.py +25 -0
  1528. package/tools/__pycache__/__init__.cpython-312.pyc +0 -0
  1529. package/tools/__pycache__/approval.cpython-312.pyc +0 -0
  1530. package/tools/__pycache__/binary_extensions.cpython-312.pyc +0 -0
  1531. package/tools/__pycache__/browser_camofox.cpython-312.pyc +0 -0
  1532. package/tools/__pycache__/browser_camofox_state.cpython-312.pyc +0 -0
  1533. package/tools/__pycache__/browser_cdp_tool.cpython-312.pyc +0 -0
  1534. package/tools/__pycache__/browser_dialog_tool.cpython-312.pyc +0 -0
  1535. package/tools/__pycache__/browser_supervisor.cpython-312.pyc +0 -0
  1536. package/tools/__pycache__/browser_tool.cpython-312.pyc +0 -0
  1537. package/tools/__pycache__/budget_config.cpython-312.pyc +0 -0
  1538. package/tools/__pycache__/checkpoint_manager.cpython-312.pyc +0 -0
  1539. package/tools/__pycache__/clarify_gateway.cpython-312.pyc +0 -0
  1540. package/tools/__pycache__/clarify_tool.cpython-312.pyc +0 -0
  1541. package/tools/__pycache__/code_execution_tool.cpython-312.pyc +0 -0
  1542. package/tools/__pycache__/computer_use_tool.cpython-312.pyc +0 -0
  1543. package/tools/__pycache__/cronjob_tools.cpython-312.pyc +0 -0
  1544. package/tools/__pycache__/debug_helpers.cpython-312.pyc +0 -0
  1545. package/tools/__pycache__/delegate_tool.cpython-312.pyc +0 -0
  1546. package/tools/__pycache__/discord_tool.cpython-312.pyc +0 -0
  1547. package/tools/__pycache__/feishu_doc_tool.cpython-312.pyc +0 -0
  1548. package/tools/__pycache__/feishu_drive_tool.cpython-312.pyc +0 -0
  1549. package/tools/__pycache__/file_operations.cpython-312.pyc +0 -0
  1550. package/tools/__pycache__/file_state.cpython-312.pyc +0 -0
  1551. package/tools/__pycache__/file_tools.cpython-312.pyc +0 -0
  1552. package/tools/__pycache__/homeassistant_tool.cpython-312.pyc +0 -0
  1553. package/tools/__pycache__/image_generation_tool.cpython-312.pyc +0 -0
  1554. package/tools/__pycache__/interrupt.cpython-312.pyc +0 -0
  1555. package/tools/__pycache__/kanban_tools.cpython-312.pyc +0 -0
  1556. package/tools/__pycache__/lazy_deps.cpython-312.pyc +0 -0
  1557. package/tools/__pycache__/managed_tool_gateway.cpython-312.pyc +0 -0
  1558. package/tools/__pycache__/mcp_tool.cpython-312.pyc +0 -0
  1559. package/tools/__pycache__/memory_tool.cpython-312.pyc +0 -0
  1560. package/tools/__pycache__/mixture_of_agents_tool.cpython-312.pyc +0 -0
  1561. package/tools/__pycache__/openrouter_client.cpython-312.pyc +0 -0
  1562. package/tools/__pycache__/process_registry.cpython-312.pyc +0 -0
  1563. package/tools/__pycache__/registry.cpython-312.pyc +0 -0
  1564. package/tools/__pycache__/schema_sanitizer.cpython-312.pyc +0 -0
  1565. package/tools/__pycache__/send_message_tool.cpython-312.pyc +0 -0
  1566. package/tools/__pycache__/session_search_tool.cpython-312.pyc +0 -0
  1567. package/tools/__pycache__/skill_manager_tool.cpython-312.pyc +0 -0
  1568. package/tools/__pycache__/skill_provenance.cpython-312.pyc +0 -0
  1569. package/tools/__pycache__/skill_usage.cpython-312.pyc +0 -0
  1570. package/tools/__pycache__/skills_guard.cpython-312.pyc +0 -0
  1571. package/tools/__pycache__/skills_sync.cpython-312.pyc +0 -0
  1572. package/tools/__pycache__/skills_tool.cpython-312.pyc +0 -0
  1573. package/tools/__pycache__/slash_confirm.cpython-312.pyc +0 -0
  1574. package/tools/__pycache__/terminal_tool.cpython-312.pyc +0 -0
  1575. package/tools/__pycache__/tirith_security.cpython-312.pyc +0 -0
  1576. package/tools/__pycache__/todo_tool.cpython-312.pyc +0 -0
  1577. package/tools/__pycache__/tool_backend_helpers.cpython-312.pyc +0 -0
  1578. package/tools/__pycache__/tool_result_storage.cpython-312.pyc +0 -0
  1579. package/tools/__pycache__/tts_tool.cpython-312.pyc +0 -0
  1580. package/tools/__pycache__/url_safety.cpython-312.pyc +0 -0
  1581. package/tools/__pycache__/video_generation_tool.cpython-312.pyc +0 -0
  1582. package/tools/__pycache__/vision_tools.cpython-312.pyc +0 -0
  1583. package/tools/__pycache__/voice_mode.cpython-312.pyc +0 -0
  1584. package/tools/__pycache__/web_tools.cpython-312.pyc +0 -0
  1585. package/tools/__pycache__/website_policy.cpython-312.pyc +0 -0
  1586. package/tools/__pycache__/x_search_tool.cpython-312.pyc +0 -0
  1587. package/tools/__pycache__/xai_http.cpython-312.pyc +0 -0
  1588. package/tools/__pycache__/yuanbao_tools.cpython-312.pyc +0 -0
  1589. package/tools/ansi_strip.py +44 -0
  1590. package/tools/approval.py +1392 -0
  1591. package/tools/binary_extensions.py +42 -0
  1592. package/tools/browser_camofox.py +700 -0
  1593. package/tools/browser_camofox_state.py +48 -0
  1594. package/tools/browser_cdp_tool.py +569 -0
  1595. package/tools/browser_dialog_tool.py +148 -0
  1596. package/tools/browser_providers/__init__.py +10 -0
  1597. package/tools/browser_providers/__pycache__/__init__.cpython-312.pyc +0 -0
  1598. package/tools/browser_providers/__pycache__/base.cpython-312.pyc +0 -0
  1599. package/tools/browser_providers/__pycache__/browser_use.cpython-312.pyc +0 -0
  1600. package/tools/browser_providers/__pycache__/browserbase.cpython-312.pyc +0 -0
  1601. package/tools/browser_providers/__pycache__/firecrawl.cpython-312.pyc +0 -0
  1602. package/tools/browser_providers/base.py +59 -0
  1603. package/tools/browser_providers/browser_use.py +225 -0
  1604. package/tools/browser_providers/browserbase.py +222 -0
  1605. package/tools/browser_providers/firecrawl.py +112 -0
  1606. package/tools/browser_supervisor.py +1457 -0
  1607. package/tools/browser_tool.py +3676 -0
  1608. package/tools/budget_config.py +51 -0
  1609. package/tools/checkpoint_manager.py +1639 -0
  1610. package/tools/clarify_gateway.py +278 -0
  1611. package/tools/clarify_tool.py +141 -0
  1612. package/tools/code_execution_tool.py +1782 -0
  1613. package/tools/computer_use/__init__.py +43 -0
  1614. package/tools/computer_use/__pycache__/__init__.cpython-312.pyc +0 -0
  1615. package/tools/computer_use/__pycache__/backend.cpython-312.pyc +0 -0
  1616. package/tools/computer_use/__pycache__/schema.cpython-312.pyc +0 -0
  1617. package/tools/computer_use/__pycache__/tool.cpython-312.pyc +0 -0
  1618. package/tools/computer_use/backend.py +150 -0
  1619. package/tools/computer_use/cua_backend.py +682 -0
  1620. package/tools/computer_use/schema.py +191 -0
  1621. package/tools/computer_use/tool.py +521 -0
  1622. package/tools/computer_use_tool.py +39 -0
  1623. package/tools/credential_files.py +437 -0
  1624. package/tools/cronjob_tools.py +719 -0
  1625. package/tools/debug_helpers.py +106 -0
  1626. package/tools/delegate_tool.py +2797 -0
  1627. package/tools/discord_tool.py +959 -0
  1628. package/tools/env_passthrough.py +145 -0
  1629. package/tools/environments/__init__.py +14 -0
  1630. package/tools/environments/__pycache__/__init__.cpython-312.pyc +0 -0
  1631. package/tools/environments/__pycache__/base.cpython-312.pyc +0 -0
  1632. package/tools/environments/__pycache__/docker.cpython-312.pyc +0 -0
  1633. package/tools/environments/__pycache__/file_sync.cpython-312.pyc +0 -0
  1634. package/tools/environments/__pycache__/local.cpython-312.pyc +0 -0
  1635. package/tools/environments/__pycache__/managed_modal.cpython-312.pyc +0 -0
  1636. package/tools/environments/__pycache__/modal.cpython-312.pyc +0 -0
  1637. package/tools/environments/__pycache__/modal_utils.cpython-312.pyc +0 -0
  1638. package/tools/environments/__pycache__/singularity.cpython-312.pyc +0 -0
  1639. package/tools/environments/__pycache__/ssh.cpython-312.pyc +0 -0
  1640. package/tools/environments/base.py +844 -0
  1641. package/tools/environments/daytona.py +270 -0
  1642. package/tools/environments/docker.py +656 -0
  1643. package/tools/environments/file_sync.py +400 -0
  1644. package/tools/environments/local.py +658 -0
  1645. package/tools/environments/managed_modal.py +282 -0
  1646. package/tools/environments/modal.py +479 -0
  1647. package/tools/environments/modal_utils.py +199 -0
  1648. package/tools/environments/singularity.py +263 -0
  1649. package/tools/environments/ssh.py +295 -0
  1650. package/tools/environments/vercel_sandbox.py +655 -0
  1651. package/tools/feishu_doc_tool.py +138 -0
  1652. package/tools/feishu_drive_tool.py +431 -0
  1653. package/tools/file_operations.py +1825 -0
  1654. package/tools/file_state.py +332 -0
  1655. package/tools/file_tools.py +1172 -0
  1656. package/tools/fuzzy_match.py +703 -0
  1657. package/tools/homeassistant_tool.py +513 -0
  1658. package/tools/image_generation_tool.py +1098 -0
  1659. package/tools/interrupt.py +98 -0
  1660. package/tools/kanban_tools.py +1139 -0
  1661. package/tools/lazy_deps.py +608 -0
  1662. package/tools/managed_tool_gateway.py +168 -0
  1663. package/tools/mcp_oauth.py +633 -0
  1664. package/tools/mcp_oauth_manager.py +607 -0
  1665. package/tools/mcp_tool.py +3483 -0
  1666. package/tools/memory_tool.py +584 -0
  1667. package/tools/microsoft_graph_auth.py +245 -0
  1668. package/tools/microsoft_graph_client.py +408 -0
  1669. package/tools/mixture_of_agents_tool.py +542 -0
  1670. package/tools/neutts_samples/jo.txt +1 -0
  1671. package/tools/neutts_samples/jo.wav +0 -0
  1672. package/tools/neutts_synth.py +104 -0
  1673. package/tools/openrouter_client.py +33 -0
  1674. package/tools/osv_check.py +155 -0
  1675. package/tools/patch_parser.py +592 -0
  1676. package/tools/path_security.py +43 -0
  1677. package/tools/process_registry.py +1534 -0
  1678. package/tools/registry.py +589 -0
  1679. package/tools/schema_sanitizer.py +370 -0
  1680. package/tools/send_message_tool.py +1900 -0
  1681. package/tools/session_search_tool.py +613 -0
  1682. package/tools/skill_manager_tool.py +932 -0
  1683. package/tools/skill_provenance.py +78 -0
  1684. package/tools/skill_usage.py +610 -0
  1685. package/tools/skills_guard.py +932 -0
  1686. package/tools/skills_hub.py +3263 -0
  1687. package/tools/skills_sync.py +432 -0
  1688. package/tools/skills_tool.py +1569 -0
  1689. package/tools/slash_confirm.py +167 -0
  1690. package/tools/terminal_tool.py +2376 -0
  1691. package/tools/tirith_security.py +775 -0
  1692. package/tools/todo_tool.py +277 -0
  1693. package/tools/tool_backend_helpers.py +144 -0
  1694. package/tools/tool_output_limits.py +92 -0
  1695. package/tools/tool_result_storage.py +232 -0
  1696. package/tools/transcription_tools.py +936 -0
  1697. package/tools/tts_tool.py +2285 -0
  1698. package/tools/url_safety.py +330 -0
  1699. package/tools/video_generation_tool.py +561 -0
  1700. package/tools/vision_tools.py +1422 -0
  1701. package/tools/voice_mode.py +1019 -0
  1702. package/tools/web_tools.py +1551 -0
  1703. package/tools/website_policy.py +283 -0
  1704. package/tools/x_search_tool.py +424 -0
  1705. package/tools/xai_http.py +83 -0
  1706. package/tools/yuanbao_tools.py +736 -0
  1707. package/toolset_distributions.py +364 -0
  1708. package/toolsets.py +866 -0
  1709. package/trajectory_compressor.py +1509 -0
  1710. package/tui_gateway/__init__.py +0 -0
  1711. package/tui_gateway/entry.py +251 -0
  1712. package/tui_gateway/event_publisher.py +126 -0
  1713. package/tui_gateway/render.py +49 -0
  1714. package/tui_gateway/server.py +6623 -0
  1715. package/tui_gateway/slash_worker.py +76 -0
  1716. package/tui_gateway/transport.py +219 -0
  1717. package/tui_gateway/ws.py +178 -0
  1718. package/utils.py +361 -0
@@ -0,0 +1,1782 @@
1
+ """Curator — background skill maintenance orchestrator.
2
+
3
+ The curator is an auxiliary-model task that periodically reviews agent-created
4
+ skills and maintains the collection. It runs inactivity-triggered (no cron
5
+ daemon): when the agent is idle and the last curator run was longer than
6
+ ``interval_hours`` ago, ``maybe_run_curator()`` spawns a forked AIAgent to do
7
+ the review.
8
+
9
+ Responsibilities:
10
+ - Auto-transition lifecycle states based on derived skill activity timestamps
11
+ - Spawn a background review agent that can pin / archive / consolidate /
12
+ patch agent-created skills via skill_manage
13
+ - Persist curator state (last_run_at, paused, etc.) in .curator_state
14
+
15
+ Strict invariants:
16
+ - Only touches agent-created skills (see tools/skill_usage.is_agent_created)
17
+ - Never auto-deletes — only archives. Archive is recoverable.
18
+ - Pinned skills bypass all auto-transitions
19
+ - Uses the auxiliary client; never touches the main session's prompt cache
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import json
25
+ import logging
26
+ import os
27
+ import re
28
+ import tempfile
29
+ import threading
30
+ from datetime import datetime, timedelta, timezone
31
+ from pathlib import Path
32
+ from typing import Any, Callable, Dict, List, NamedTuple, Optional, Set
33
+
34
+ from calvyn_constants import get_hermes_home
35
+ from tools import skill_usage
36
+
37
+ logger = logging.getLogger(__name__)
38
+
39
+
40
+ def _strip_aux_credential(value: Any) -> Optional[str]:
41
+ if value is None:
42
+ return None
43
+ text = str(value).strip()
44
+ return text or None
45
+
46
+
47
+ class _ReviewRuntimeBinding(NamedTuple):
48
+ """Provider/model for the curator review fork plus optional per-slot overrides."""
49
+
50
+ provider: str
51
+ model: str
52
+ explicit_api_key: Optional[str]
53
+ explicit_base_url: Optional[str]
54
+
55
+
56
+ DEFAULT_INTERVAL_HOURS = 24 * 7 # 7 days
57
+ DEFAULT_MIN_IDLE_HOURS = 2
58
+ DEFAULT_STALE_AFTER_DAYS = 30
59
+ DEFAULT_ARCHIVE_AFTER_DAYS = 90
60
+
61
+
62
+ # ---------------------------------------------------------------------------
63
+ # .curator_state — persistent scheduler + status
64
+ # ---------------------------------------------------------------------------
65
+
66
+ def _state_file() -> Path:
67
+ return get_hermes_home() / "skills" / ".curator_state"
68
+
69
+
70
+ def _default_state() -> Dict[str, Any]:
71
+ return {
72
+ "last_run_at": None,
73
+ "last_run_duration_seconds": None,
74
+ "last_run_summary": None,
75
+ "last_run_summary_shown_at": None,
76
+ "last_report_path": None,
77
+ "paused": False,
78
+ "run_count": 0,
79
+ }
80
+
81
+
82
+ def load_state() -> Dict[str, Any]:
83
+ path = _state_file()
84
+ if not path.exists():
85
+ return _default_state()
86
+ try:
87
+ data = json.loads(path.read_text(encoding="utf-8"))
88
+ if isinstance(data, dict):
89
+ base = _default_state()
90
+ base.update({k: v for k, v in data.items() if k in base or k.startswith("_")})
91
+ return base
92
+ except (OSError, json.JSONDecodeError) as e:
93
+ logger.debug("Failed to read curator state: %s", e)
94
+ return _default_state()
95
+
96
+
97
+ def save_state(data: Dict[str, Any]) -> None:
98
+ path = _state_file()
99
+ try:
100
+ path.parent.mkdir(parents=True, exist_ok=True)
101
+ fd, tmp = tempfile.mkstemp(dir=str(path.parent), prefix=".curator_state_", suffix=".tmp")
102
+ try:
103
+ with os.fdopen(fd, "w", encoding="utf-8") as f:
104
+ json.dump(data, f, indent=2, sort_keys=True, ensure_ascii=False)
105
+ f.flush()
106
+ os.fsync(f.fileno())
107
+ os.replace(tmp, path)
108
+ except BaseException:
109
+ try:
110
+ os.unlink(tmp)
111
+ except OSError:
112
+ pass
113
+ raise
114
+ except Exception as e:
115
+ logger.debug("Failed to save curator state: %s", e, exc_info=True)
116
+
117
+
118
+ def set_paused(paused: bool) -> None:
119
+ state = load_state()
120
+ state["paused"] = bool(paused)
121
+ save_state(state)
122
+
123
+
124
+ def is_paused() -> bool:
125
+ return bool(load_state().get("paused"))
126
+
127
+
128
+ # ---------------------------------------------------------------------------
129
+ # Config access
130
+ # ---------------------------------------------------------------------------
131
+
132
+ def _load_config() -> Dict[str, Any]:
133
+ """Read curator.* config from ~/.hermes/config.yaml. Tolerates missing file."""
134
+ try:
135
+ from hermes_cli.config import load_config
136
+ cfg = load_config()
137
+ except Exception as e:
138
+ logger.debug("Failed to load config for curator: %s", e)
139
+ return {}
140
+ if not isinstance(cfg, dict):
141
+ return {}
142
+ cur = cfg.get("curator") or {}
143
+ if not isinstance(cur, dict):
144
+ return {}
145
+ return cur
146
+
147
+
148
+ def is_enabled() -> bool:
149
+ """Default ON when no config says otherwise."""
150
+ cfg = _load_config()
151
+ return bool(cfg.get("enabled", True))
152
+
153
+
154
+ def get_interval_hours() -> int:
155
+ cfg = _load_config()
156
+ try:
157
+ return int(cfg.get("interval_hours", DEFAULT_INTERVAL_HOURS))
158
+ except (TypeError, ValueError):
159
+ return DEFAULT_INTERVAL_HOURS
160
+
161
+
162
+ def get_min_idle_hours() -> float:
163
+ cfg = _load_config()
164
+ try:
165
+ return float(cfg.get("min_idle_hours", DEFAULT_MIN_IDLE_HOURS))
166
+ except (TypeError, ValueError):
167
+ return DEFAULT_MIN_IDLE_HOURS
168
+
169
+
170
+ def get_stale_after_days() -> int:
171
+ cfg = _load_config()
172
+ try:
173
+ return int(cfg.get("stale_after_days", DEFAULT_STALE_AFTER_DAYS))
174
+ except (TypeError, ValueError):
175
+ return DEFAULT_STALE_AFTER_DAYS
176
+
177
+
178
+ def get_archive_after_days() -> int:
179
+ cfg = _load_config()
180
+ try:
181
+ return int(cfg.get("archive_after_days", DEFAULT_ARCHIVE_AFTER_DAYS))
182
+ except (TypeError, ValueError):
183
+ return DEFAULT_ARCHIVE_AFTER_DAYS
184
+
185
+
186
+ # ---------------------------------------------------------------------------
187
+ # Idle / interval check
188
+ # ---------------------------------------------------------------------------
189
+
190
+ def _parse_iso(ts: Optional[str]) -> Optional[datetime]:
191
+ if not ts:
192
+ return None
193
+ try:
194
+ return datetime.fromisoformat(ts)
195
+ except (TypeError, ValueError):
196
+ return None
197
+
198
+
199
+ def should_run_now(now: Optional[datetime] = None) -> bool:
200
+ """Return True if the curator should run immediately.
201
+
202
+ Gates:
203
+ - curator.enabled == True
204
+ - not paused
205
+ - last_run_at present AND older than interval_hours
206
+
207
+ First-run behavior: when there is no ``last_run_at`` (fresh install, or
208
+ install that predates the curator), we DO NOT run immediately. The
209
+ curator is designed to run after at least ``interval_hours`` (7 days by
210
+ default) of skill activity, not on the first background tick after
211
+ ``hermes update``. On first observation we seed ``last_run_at`` to "now"
212
+ and defer the first real pass by one full interval. Users who want to
213
+ run it sooner can always invoke ``hermes curator run`` (with or without
214
+ ``--dry-run``) explicitly — that path bypasses this gate.
215
+
216
+ The idle check (min_idle_hours) is applied at the call site where we know
217
+ whether an agent is actively running — here we only enforce the static
218
+ gates.
219
+ """
220
+ if not is_enabled():
221
+ return False
222
+ if is_paused():
223
+ return False
224
+
225
+ state = load_state()
226
+ last = _parse_iso(state.get("last_run_at"))
227
+ if last is None:
228
+ # Never run before. Seed state so we wait a full interval before the
229
+ # first real pass. Report-only; do not auto-mutate the library the
230
+ # very first time a gateway ticks after an update.
231
+ if now is None:
232
+ now = datetime.now(timezone.utc)
233
+ try:
234
+ state["last_run_at"] = now.isoformat()
235
+ state["last_run_summary"] = (
236
+ "deferred first run — curator seeded, will run after one "
237
+ "interval; use `hermes curator run --dry-run` to preview now"
238
+ )
239
+ save_state(state)
240
+ except Exception as e: # pragma: no cover — best-effort persistence
241
+ logger.debug("Failed to seed curator last_run_at: %s", e)
242
+ return False
243
+
244
+ if now is None:
245
+ now = datetime.now(timezone.utc)
246
+ if last.tzinfo is None:
247
+ last = last.replace(tzinfo=timezone.utc)
248
+ interval = timedelta(hours=get_interval_hours())
249
+ return (now - last) >= interval
250
+
251
+
252
+ # ---------------------------------------------------------------------------
253
+ # Automatic state transitions (pure function, no LLM)
254
+ # ---------------------------------------------------------------------------
255
+
256
+ def apply_automatic_transitions(now: Optional[datetime] = None) -> Dict[str, int]:
257
+ """Walk every agent-created skill and move active/stale/archived based on
258
+ the latest real activity timestamp. Pinned skills are never touched.
259
+ Returns a counter dict describing what changed."""
260
+ from tools import skill_usage as _u
261
+
262
+ if now is None:
263
+ now = datetime.now(timezone.utc)
264
+ stale_cutoff = now - timedelta(days=get_stale_after_days())
265
+ archive_cutoff = now - timedelta(days=get_archive_after_days())
266
+
267
+ counts = {"marked_stale": 0, "archived": 0, "reactivated": 0, "checked": 0}
268
+
269
+ for row in _u.agent_created_report():
270
+ counts["checked"] += 1
271
+ name = row["name"]
272
+ if row.get("pinned"):
273
+ continue
274
+
275
+ last_activity = _parse_iso(row.get("last_activity_at"))
276
+ # If never active, treat created_at as the anchor so new skills don't
277
+ # immediately archive themselves.
278
+ anchor = last_activity or _parse_iso(row.get("created_at")) or now
279
+ if anchor.tzinfo is None:
280
+ anchor = anchor.replace(tzinfo=timezone.utc)
281
+
282
+ current = row.get("state", _u.STATE_ACTIVE)
283
+
284
+ if anchor <= archive_cutoff and current != _u.STATE_ARCHIVED:
285
+ ok, _msg = _u.archive_skill(name)
286
+ if ok:
287
+ counts["archived"] += 1
288
+ elif anchor <= stale_cutoff and current == _u.STATE_ACTIVE:
289
+ _u.set_state(name, _u.STATE_STALE)
290
+ counts["marked_stale"] += 1
291
+ elif anchor > stale_cutoff and current == _u.STATE_STALE:
292
+ # Skill got used again after being marked stale — reactivate.
293
+ _u.set_state(name, _u.STATE_ACTIVE)
294
+ counts["reactivated"] += 1
295
+
296
+ return counts
297
+
298
+
299
+ # ---------------------------------------------------------------------------
300
+ # Review prompt for the forked agent
301
+ # ---------------------------------------------------------------------------
302
+
303
+ CURATOR_DRY_RUN_BANNER = (
304
+ "═══════════════════════════════════════════════════════════════\n"
305
+ "DRY-RUN — REPORT ONLY. DO NOT MUTATE THE SKILL LIBRARY.\n"
306
+ "═══════════════════════════════════════════════════════════════\n"
307
+ "\n"
308
+ "This is a PREVIEW pass. Follow every instruction below EXCEPT:\n"
309
+ "\n"
310
+ " • DO NOT call skill_manage with action=patch, create, delete, "
311
+ "write_file, or remove_file.\n"
312
+ " • DO NOT call terminal to mv skill directories into .archive/.\n"
313
+ " • DO NOT call terminal to mv, cp, rm, or rewrite any file under "
314
+ "~/.hermes/skills/.\n"
315
+ " • skills_list and skill_view are FINE — read as much as you need.\n"
316
+ "\n"
317
+ "Your output IS the deliverable. Produce the exact same "
318
+ "human-readable summary and structured YAML block you would "
319
+ "produce on a live run — but describe the actions you WOULD take, "
320
+ "not actions you took. A downstream reviewer will read the report "
321
+ "and decide whether to approve a live run with "
322
+ "`hermes curator run` (no flag).\n"
323
+ "\n"
324
+ "If you accidentally take a mutating action, say so explicitly in "
325
+ "the summary so the reviewer can revert it.\n"
326
+ "═══════════════════════════════════════════════════════════════"
327
+ )
328
+
329
+
330
+ CURATOR_REVIEW_PROMPT = (
331
+ "You are running as Hermes' background skill CURATOR. This is an "
332
+ "UMBRELLA-BUILDING consolidation pass, not a passive audit and not a "
333
+ "duplicate-finder.\n\n"
334
+ "The goal of the skill collection is a LIBRARY OF CLASS-LEVEL "
335
+ "INSTRUCTIONS AND EXPERIENTIAL KNOWLEDGE. A collection of hundreds of "
336
+ "narrow skills where each one captures one session's specific bug is "
337
+ "a FAILURE of the library — not a feature. An agent searching skills "
338
+ "matches on descriptions, not on exact names; one broad umbrella "
339
+ "skill with labeled subsections beats five narrow siblings for "
340
+ "discoverability, not the other way around.\n\n"
341
+ "The right target shape is CLASS-LEVEL skills with rich SKILL.md "
342
+ "bodies + `references/`, `templates/`, and `scripts/` subfiles for "
343
+ "session-specific detail — not one-session-one-skill micro-entries.\n\n"
344
+ "Hard rules — do not violate:\n"
345
+ "1. DO NOT touch bundled or hub-installed skills. The candidate list "
346
+ "below is already filtered to agent-created skills only.\n"
347
+ "2. DO NOT delete any skill. Archiving (moving the skill's directory "
348
+ "into ~/.hermes/skills/.archive/) is the maximum destructive action. "
349
+ "Archives are recoverable; deletion is not.\n"
350
+ "3. DO NOT touch skills shown as pinned=yes. Skip them entirely.\n"
351
+ "4. DO NOT use usage counters as a reason to skip consolidation. The "
352
+ "counters are new and often mostly zero. Judge overlap on CONTENT, "
353
+ "not on use_count. 'use=0' is not evidence a skill is valuable; it's "
354
+ "absence of evidence either way.\n"
355
+ "5. DO NOT reject consolidation on the grounds that 'each skill has "
356
+ "a distinct trigger'. Pairwise distinctness is the wrong bar. The "
357
+ "right bar is: 'would a human maintainer write this as N separate "
358
+ "skills, or as one skill with N labeled subsections?' When the "
359
+ "answer is the latter, merge.\n\n"
360
+ "How to work — not optional:\n"
361
+ "1. Scan the full candidate list. Identify PREFIX CLUSTERS (skills "
362
+ "sharing a first word or domain keyword). Examples you are likely "
363
+ "to find: hermes-config-*, hermes-dashboard-*, gateway-*, codex-*, "
364
+ "ollama-*, anthropic-*, gemini-*, mcp-*, salvage-*, pr-*, "
365
+ "competitor-*, python-*, security-*, etc. Expect 10-25 clusters.\n"
366
+ "2. For each cluster with 2+ members, do NOT ask 'are these pairs "
367
+ "overlapping?' — ask 'what is the UMBRELLA CLASS these skills all "
368
+ "serve? Would a maintainer name that class and write one skill for "
369
+ "it?' If yes, pick (or create) the umbrella and absorb the siblings "
370
+ "into it.\n"
371
+ "3. Three ways to consolidate — use the right one per cluster:\n"
372
+ " a. MERGE INTO EXISTING UMBRELLA — one skill in the cluster is "
373
+ "already broad enough to be the umbrella (example: `pr-triage-"
374
+ "salvage` for the PR review cluster). Patch it to add a labeled "
375
+ "section for each sibling's unique insight, then archive the "
376
+ "siblings.\n"
377
+ " b. CREATE A NEW UMBRELLA SKILL.md — no existing member is broad "
378
+ "enough. Use skill_manage action=create to write a new class-level "
379
+ "skill whose SKILL.md covers the shared workflow and has short "
380
+ "labeled subsections. Archive the now-absorbed narrow siblings.\n"
381
+ " c. DEMOTE TO REFERENCES/TEMPLATES/SCRIPTS — a sibling has "
382
+ "narrow-but-valuable session-specific content. Move it into the "
383
+ "umbrella's appropriate support directory:\n"
384
+ " • `references/<topic>.md` for session-specific detail OR "
385
+ "condensed knowledge banks (quoted research, API docs excerpts, "
386
+ "domain notes, provider quirks, reproduction recipes)\n"
387
+ " • `templates/<name>.<ext>` for starter files meant to be "
388
+ "copied and modified\n"
389
+ " • `scripts/<name>.<ext>` for statically re-runnable actions "
390
+ "(verification scripts, fixture generators, probes)\n"
391
+ " Then archive the old sibling. Use `terminal` with `mkdir -p "
392
+ "~/.hermes/skills/<umbrella>/references/ && mv ... <umbrella>/"
393
+ "references/<topic>.md` (or templates/ / scripts/).\n"
394
+ "4. Also flag skills whose NAME is too narrow (contains a PR number, "
395
+ "a feature codename, a specific error string, an 'audit' / "
396
+ "'diagnosis' / 'salvage' session artifact). These almost always "
397
+ "belong as a subsection or support file under a class-level umbrella.\n"
398
+ "5. Iterate. After one consolidation round, scan the remaining set "
399
+ "and look for the NEXT umbrella opportunity. Don't stop after 3 "
400
+ "merges.\n\n"
401
+ "Your toolset:\n"
402
+ " - skills_list, skill_view — read the current landscape\n"
403
+ " - skill_manage action=patch — add sections to the umbrella\n"
404
+ " - skill_manage action=create — create a new umbrella SKILL.md\n"
405
+ " - skill_manage action=write_file — add a references/, templates/, "
406
+ "or scripts/ file under an existing skill (the skill must already "
407
+ "exist)\n"
408
+ " - skill_manage action=delete — archive a skill. MUST pass "
409
+ "`absorbed_into=<umbrella>` when you've merged its content into another "
410
+ "skill, or `absorbed_into=\"\"` when you're truly pruning with no "
411
+ "forwarding target. This drives cron-job skill-reference migration — "
412
+ "guessing from your YAML summary after the fact is fragile.\n"
413
+ " - terminal — mv a sibling into the archive "
414
+ "OR move its content into a support subfile\n\n"
415
+ "'keep' is a legitimate decision ONLY when the skill is already a "
416
+ "class-level umbrella and none of the proposed merges would improve "
417
+ "discoverability. 'This is narrow but distinct from its siblings' "
418
+ "is NOT a reason to keep — it's a reason to move it under an "
419
+ "umbrella as a subsection or support file.\n\n"
420
+ "Expected output: real umbrella-ification. Process every obvious "
421
+ "cluster. If you end the pass with fewer than 10 archives, you "
422
+ "stopped too early — go back and look at the clusters you left "
423
+ "alone.\n\n"
424
+ "When done, write a human summary AND a structured machine-readable "
425
+ "block so downstream tooling can distinguish consolidation from "
426
+ "pruning. Format EXACTLY:\n\n"
427
+ "## Structured summary (required)\n"
428
+ "```yaml\n"
429
+ "consolidations:\n"
430
+ " - from: <old-skill-name>\n"
431
+ " into: <umbrella-skill-name>\n"
432
+ " reason: <one short sentence — why merged, not just 'similar'>\n"
433
+ "prunings:\n"
434
+ " - name: <skill-name>\n"
435
+ " reason: <one short sentence — why archived with no merge target>\n"
436
+ "```\n\n"
437
+ "Every skill you moved to .archive/ MUST appear in exactly one of the "
438
+ "two lists. If you consolidated X into umbrella Y (patched Y, wrote "
439
+ "a references file to Y, or created Y with X's content absorbed), X "
440
+ "goes under `consolidations` with `into: Y`. If you archived X with "
441
+ "no absorption — truly stale, irrelevant, or obsolete — X goes under "
442
+ "`prunings`. Leave a list empty (`consolidations: []`) if none. Do "
443
+ "not omit the block. The block comes AFTER your human-readable "
444
+ "summary of clusters processed, patches made, and decisions left alone."
445
+ )
446
+
447
+
448
+ # ---------------------------------------------------------------------------
449
+ # Per-run reports — {YYYYMMDD-HHMMSS}/run.json + REPORT.md under logs/curator/
450
+ # ---------------------------------------------------------------------------
451
+
452
+ def _reports_root() -> Path:
453
+ """Directory where curator run reports are written.
454
+
455
+ Lives under the profile-aware logs dir (``~/.hermes/logs/curator/``)
456
+ alongside ``agent.log`` and ``gateway.log`` so it's found by anyone
457
+ looking for operational telemetry, not mixed in with the user's
458
+ authored skill data in ``~/.hermes/skills/``.
459
+
460
+ ``ensure_hermes_home()`` pre-creates this dir on every CLI launch and
461
+ the v22→v23 migration backfills it for existing profiles, but we
462
+ still mkdir here as a belt-and-suspenders so the curator works even
463
+ from an odd entry path (e.g. gateway-only install, bare library use)
464
+ that bypasses both.
465
+ """
466
+ root = get_hermes_home() / "logs" / "curator"
467
+ try:
468
+ root.mkdir(parents=True, exist_ok=True)
469
+ except OSError as e:
470
+ logger.debug("Curator reports dir create failed: %s", e)
471
+ return root
472
+
473
+
474
+ def _needle_in_path_component(needle: str, path: str) -> bool:
475
+ """Check if *needle* is a complete filename stem or directory name in *path*.
476
+
477
+ Unlike simple substring matching, this avoids false positives where short
478
+ skill names are embedded in longer filenames (e.g. "api" matching
479
+ "references/api-design.md"). Hyphens and underscores are normalised so
480
+ "open-webui-setup" matches "open_webui_setup.md".
481
+ """
482
+ norm_needle = needle.replace("-", "_")
483
+ for part in path.replace("\\", "/").split("/"):
484
+ if not part:
485
+ continue
486
+ stem = part.rsplit(".", 1)[0] if "." in part else part
487
+ if stem.replace("-", "_") == norm_needle:
488
+ return True
489
+ return False
490
+
491
+
492
+ def _classify_removed_skills(
493
+ removed: List[str],
494
+ added: List[str],
495
+ after_names: Set[str],
496
+ tool_calls: List[Dict[str, Any]],
497
+ ) -> Dict[str, List[Dict[str, Any]]]:
498
+ """Split ``removed`` into consolidated vs pruned.
499
+
500
+ A removed skill is "consolidated" when the curator absorbed its content
501
+ into another skill (an umbrella) during this run — the content still
502
+ lives, just under a different name. A removed skill is "pruned" when the
503
+ curator archived it for staleness/irrelevance without preserving its
504
+ content elsewhere.
505
+
506
+ Heuristic: scan this run's ``skill_manage`` tool calls and look for
507
+ ``write_file``/``patch``/``create``/``edit`` actions whose target skill
508
+ (the ``name`` argument) is NOT the removed skill and whose
509
+ ``file_path`` / ``file_content`` / ``content`` arguments reference the
510
+ removed skill's name. That's the textbook "absorbed into umbrella"
511
+ signal. Ties are broken by first-match (earliest tool call wins).
512
+
513
+ Returns ``{"consolidated": [{"name", "into", "evidence"}, ...],
514
+ "pruned": [{"name"}, ...]}``.
515
+ """
516
+ consolidated: List[Dict[str, Any]] = []
517
+ pruned: List[Dict[str, Any]] = []
518
+
519
+ # Pre-parse tool calls: we only care about skill_manage.
520
+ parsed_calls: List[Dict[str, Any]] = []
521
+ for tc in tool_calls or []:
522
+ if not isinstance(tc, dict):
523
+ continue
524
+ if tc.get("name") != "skill_manage":
525
+ continue
526
+ raw = tc.get("arguments") or ""
527
+ # Arguments can be a JSON string (standard) or a dict (defensive).
528
+ args: Dict[str, Any] = {}
529
+ if isinstance(raw, dict):
530
+ args = raw
531
+ elif isinstance(raw, str):
532
+ try:
533
+ args = json.loads(raw)
534
+ except Exception:
535
+ # Truncated or malformed — fall back to substring match on
536
+ # the raw string so we still catch the common case.
537
+ args = {"_raw": raw}
538
+ if not isinstance(args, dict):
539
+ continue
540
+ parsed_calls.append(args)
541
+
542
+ # Build a set of "destination" skill names: anything still present after
543
+ # the run plus anything newly added this run. A removed skill being
544
+ # referenced from one of these is the consolidation signal.
545
+ destinations = set(after_names) | set(added or [])
546
+
547
+ for name in removed:
548
+ if not name:
549
+ continue
550
+ into: Optional[str] = None
551
+ evidence: Optional[str] = None
552
+
553
+ # Normalise name variants we'll search for in path/content strings.
554
+ needles = {name, name.replace("-", "_"), name.replace("_", "-")}
555
+
556
+ for args in parsed_calls:
557
+ target = args.get("name")
558
+ if not isinstance(target, str) or not target:
559
+ continue
560
+ # A call that operates on the removed skill itself isn't
561
+ # consolidation evidence.
562
+ if target == name:
563
+ continue
564
+ # The target must be a surviving or newly-created skill —
565
+ # otherwise we're pointing to a skill that doesn't exist.
566
+ if target not in destinations:
567
+ continue
568
+
569
+ # Look for the removed skill's name in file_path / content / raw.
570
+ # Matching strategy differs by field type:
571
+ # file_path — needle must be a complete path component
572
+ # (filename stem or directory name), so "api" does NOT
573
+ # falsely match "references/api-design.md".
574
+ # content fields — word-boundary regex so "test" does NOT
575
+ # falsely match "latest" or "testing".
576
+ haystacks: List[tuple[str, str]] = []
577
+ for key in ("file_path", "file_content", "content", "new_string", "_raw"):
578
+ v = args.get(key)
579
+ if isinstance(v, str):
580
+ haystacks.append((key, v))
581
+ hit = False
582
+ for key, hay in haystacks:
583
+ for needle in needles:
584
+ if not needle:
585
+ continue
586
+ if key == "file_path":
587
+ matched = _needle_in_path_component(needle, hay)
588
+ else:
589
+ matched = bool(
590
+ re.search(rf'\b{re.escape(needle)}\b', hay)
591
+ )
592
+ if matched:
593
+ hit = True
594
+ evidence = (
595
+ f"skill_manage action={args.get('action', '?')} "
596
+ f"on '{target}' referenced '{name}' "
597
+ f"in {hay[:80]}"
598
+ )
599
+ break
600
+ if hit:
601
+ break
602
+ if hit:
603
+ into = target
604
+ break
605
+
606
+ if into:
607
+ consolidated.append({"name": name, "into": into, "evidence": evidence})
608
+ else:
609
+ pruned.append({"name": name})
610
+
611
+ return {"consolidated": consolidated, "pruned": pruned}
612
+
613
+
614
+ def _parse_structured_summary(
615
+ llm_final: str,
616
+ ) -> Dict[str, List[Dict[str, str]]]:
617
+ """Extract the structured YAML block from the curator's final response.
618
+
619
+ The curator prompt requires a fenced ```yaml block under
620
+ ``## Structured summary (required)`` with ``consolidations:`` and
621
+ ``prunings:`` lists. This parses it tolerantly:
622
+
623
+ - Missing block → returns empty lists (we'll fall back to heuristic).
624
+ - Malformed YAML → returns empty lists and we rely on heuristic.
625
+ - Partial block (e.g. only consolidations) → returns what we could parse.
626
+
627
+ Returns ``{"consolidations": [{"from", "into", "reason"}, ...],
628
+ "prunings": [{"name", "reason"}, ...]}``.
629
+ """
630
+ empty = {"consolidations": [], "prunings": []}
631
+ if not llm_final or not isinstance(llm_final, str):
632
+ return empty
633
+
634
+ # Find the YAML fenced block. We look for ```yaml ... ``` specifically
635
+ # rather than any fenced block so we don't accidentally pick up a code
636
+ # sample the model quoted elsewhere.
637
+ import re
638
+ match = re.search(
639
+ r"```ya?ml\s*\n(.*?)\n```",
640
+ llm_final,
641
+ re.DOTALL | re.IGNORECASE,
642
+ )
643
+ if not match:
644
+ return empty
645
+
646
+ body = match.group(1)
647
+
648
+ # Prefer PyYAML when available — every hermes install already has it
649
+ # (config.yaml loader). Fall back to a hand parser for paranoia.
650
+ try:
651
+ import yaml # type: ignore
652
+ data = yaml.safe_load(body)
653
+ except Exception:
654
+ return empty
655
+
656
+ if not isinstance(data, dict):
657
+ return empty
658
+
659
+ out: Dict[str, List[Dict[str, str]]] = {"consolidations": [], "prunings": []}
660
+ cons_raw = data.get("consolidations") or []
661
+ prun_raw = data.get("prunings") or []
662
+
663
+ if isinstance(cons_raw, list):
664
+ for entry in cons_raw:
665
+ if not isinstance(entry, dict):
666
+ continue
667
+ frm = entry.get("from")
668
+ into = entry.get("into")
669
+ if not (isinstance(frm, str) and frm.strip()
670
+ and isinstance(into, str) and into.strip()):
671
+ continue
672
+ reason = entry.get("reason")
673
+ out["consolidations"].append({
674
+ "from": frm.strip(),
675
+ "into": into.strip(),
676
+ "reason": (reason or "").strip() if isinstance(reason, str) else "",
677
+ })
678
+
679
+ if isinstance(prun_raw, list):
680
+ for entry in prun_raw:
681
+ if not isinstance(entry, dict):
682
+ continue
683
+ name = entry.get("name")
684
+ if not (isinstance(name, str) and name.strip()):
685
+ continue
686
+ reason = entry.get("reason")
687
+ out["prunings"].append({
688
+ "name": name.strip(),
689
+ "reason": (reason or "").strip() if isinstance(reason, str) else "",
690
+ })
691
+
692
+ return out
693
+
694
+
695
+ def _extract_absorbed_into_declarations(
696
+ tool_calls: List[Dict[str, Any]],
697
+ ) -> Dict[str, Dict[str, Any]]:
698
+ """Walk this run's tool calls and extract model-declared absorption targets.
699
+
700
+ The curator prompt requires every ``skill_manage(action='delete')`` call
701
+ to pass ``absorbed_into=<umbrella>`` when consolidating, or
702
+ ``absorbed_into=""`` when truly pruning. This is the single authoritative
703
+ signal for classification — the model's own declaration at the moment of
704
+ deletion, which beats both post-hoc YAML summary parsing and substring
705
+ heuristics on other tool calls.
706
+
707
+ Returns ``{skill_name: {"into": "<umbrella>" | "", "declared": True}}``.
708
+ Entries with ``into == ""`` are explicit prunings.
709
+ Skills without a ``skill_manage(delete)`` call, or with one that omitted
710
+ ``absorbed_into``, are not in the returned dict — caller falls back to
711
+ the existing heuristic/YAML logic for those (backward compat with older
712
+ curator runs and any callers that don't populate the arg).
713
+ """
714
+ out: Dict[str, Dict[str, Any]] = {}
715
+ for tc in tool_calls or []:
716
+ if not isinstance(tc, dict):
717
+ continue
718
+ if tc.get("name") != "skill_manage":
719
+ continue
720
+ raw = tc.get("arguments") or ""
721
+ args: Dict[str, Any] = {}
722
+ if isinstance(raw, dict):
723
+ args = raw
724
+ elif isinstance(raw, str):
725
+ try:
726
+ args = json.loads(raw)
727
+ except Exception:
728
+ continue
729
+ if not isinstance(args, dict):
730
+ continue
731
+ if args.get("action") != "delete":
732
+ continue
733
+ name = args.get("name")
734
+ if not isinstance(name, str) or not name.strip():
735
+ continue
736
+ # absorbed_into must be present (even empty string is meaningful);
737
+ # missing key means the model didn't declare intent.
738
+ if "absorbed_into" not in args:
739
+ continue
740
+ target = args.get("absorbed_into")
741
+ if target is None:
742
+ continue
743
+ if not isinstance(target, str):
744
+ continue
745
+ out[name.strip()] = {"into": target.strip(), "declared": True}
746
+ return out
747
+
748
+
749
+ def _reconcile_classification(
750
+ removed: List[str],
751
+ heuristic: Dict[str, List[Dict[str, Any]]],
752
+ model_block: Dict[str, List[Dict[str, str]]],
753
+ destinations: Set[str],
754
+ absorbed_declarations: Optional[Dict[str, Dict[str, Any]]] = None,
755
+ ) -> Dict[str, List[Dict[str, Any]]]:
756
+ """Merge heuristic (tool-call evidence) with the model's structured block.
757
+
758
+ Rules (evaluated in order; first match wins):
759
+ - **Model-declared `absorbed_into` at delete time is authoritative.** Any
760
+ entry in ``absorbed_declarations`` beats every other signal. This is
761
+ the model telling us directly, at the moment of deletion, what it did.
762
+ ``into != ""`` and target exists → consolidated. ``into == ""`` →
763
+ pruned. ``into != ""`` but target doesn't exist → hallucination; fall
764
+ through to the usual signals.
765
+ - Model-declared consolidation wins when its ``into`` target exists
766
+ in ``destinations`` (survived or newly-created). This gives the
767
+ model authority over intent + rationale.
768
+ - Model-declared consolidation whose ``into`` target does NOT exist is
769
+ downgraded: the model hallucinated an umbrella. We prefer the
770
+ heuristic's finding for that skill, or fall back to pruned.
771
+ - Heuristic-only finding (model didn't mention it, tool calls confirm)
772
+ is preserved as a consolidation, marked ``source="tool-call audit"``.
773
+ - Model-declared pruning is accepted unless the heuristic has
774
+ tool-call evidence that contradicts it (rare — the heuristic would
775
+ have flagged consolidation). In that case we log both.
776
+
777
+ Every removed skill is placed in exactly one bucket.
778
+ """
779
+ heur_cons = {e["name"]: e for e in heuristic.get("consolidated", [])}
780
+ heur_pruned = {e["name"] for e in heuristic.get("pruned", [])}
781
+
782
+ model_cons = {e["from"]: e for e in model_block.get("consolidations", [])}
783
+ model_pruned = {e["name"]: e for e in model_block.get("prunings", [])}
784
+
785
+ declared = absorbed_declarations or {}
786
+
787
+ consolidated: List[Dict[str, Any]] = []
788
+ pruned: List[Dict[str, Any]] = []
789
+
790
+ for name in removed:
791
+ mc = model_cons.get(name)
792
+ mp = model_pruned.get(name)
793
+ hc = heur_cons.get(name)
794
+ dec = declared.get(name)
795
+
796
+ # Authoritative: model declared `absorbed_into` at the delete call.
797
+ if dec is not None:
798
+ into_claim = dec.get("into", "")
799
+ if into_claim and into_claim in destinations:
800
+ entry: Dict[str, Any] = {
801
+ "name": name,
802
+ "into": into_claim,
803
+ "source": "absorbed_into (model-declared at delete)",
804
+ "reason": (mc.get("reason") or "") if mc else "",
805
+ }
806
+ if hc and hc.get("evidence"):
807
+ entry["evidence"] = hc["evidence"]
808
+ consolidated.append(entry)
809
+ continue
810
+ if into_claim == "":
811
+ # Explicit prune declaration
812
+ pruned.append({
813
+ "name": name,
814
+ "source": "absorbed_into=\"\" (model-declared prune)",
815
+ "reason": (mp.get("reason") or "") if mp else "",
816
+ })
817
+ continue
818
+ # into_claim is non-empty but target doesn't exist: the model
819
+ # named a nonexistent umbrella at delete time. The tool already
820
+ # rejects this at the skill_manage layer, so we shouldn't see it
821
+ # in practice — but if it slips through (e.g. the umbrella was
822
+ # deleted LATER in the same run), fall through to the usual
823
+ # signals rather than trusting a broken reference.
824
+
825
+ # Model says consolidated — trust it if the destination is real.
826
+ if mc and mc.get("into") in destinations:
827
+ entry: Dict[str, Any] = {
828
+ "name": name,
829
+ "into": mc["into"],
830
+ "source": "model" + ("+audit" if hc else ""),
831
+ "reason": mc.get("reason") or "",
832
+ }
833
+ if hc and hc.get("evidence"):
834
+ entry["evidence"] = hc["evidence"]
835
+ consolidated.append(entry)
836
+ continue
837
+
838
+ # Model says consolidated but the umbrella doesn't exist —
839
+ # hallucination. Fall back to heuristic or prune.
840
+ if mc and mc.get("into") not in destinations:
841
+ if hc:
842
+ consolidated.append({
843
+ "name": name,
844
+ "into": hc["into"],
845
+ "source": "tool-call audit (model named missing umbrella)",
846
+ "reason": "",
847
+ "evidence": hc.get("evidence", ""),
848
+ "model_claimed_into": mc["into"],
849
+ })
850
+ else:
851
+ pruned.append({
852
+ "name": name,
853
+ "source": "fallback (model named missing umbrella, no tool-call evidence)",
854
+ "reason": "",
855
+ })
856
+ continue
857
+
858
+ # Heuristic found consolidation the model didn't mention.
859
+ if hc:
860
+ consolidated.append({
861
+ "name": name,
862
+ "into": hc["into"],
863
+ "source": "tool-call audit (model omitted from structured block)",
864
+ "reason": "",
865
+ "evidence": hc.get("evidence", ""),
866
+ })
867
+ continue
868
+
869
+ # Model says pruned (or no mention + no heuristic evidence).
870
+ reason = mp.get("reason", "") if mp else ""
871
+ pruned.append({
872
+ "name": name,
873
+ "source": "model" if mp else "no-evidence fallback",
874
+ "reason": reason,
875
+ })
876
+
877
+ return {"consolidated": consolidated, "pruned": pruned}
878
+
879
+
880
+ def _build_rename_summary(
881
+ *,
882
+ before_names: Set[str],
883
+ after_report: List[Dict[str, Any]],
884
+ tool_calls: List[Dict[str, Any]],
885
+ model_final: str,
886
+ ) -> str:
887
+ """Format the user-visible rename map for a curator run.
888
+
889
+ Renders the "where did my skills go?" lines that get appended to the
890
+ `final_summary` string fed to gateway/CLI receivers. Empty string when
891
+ nothing was archived this run — most ticks are no-op and shouldn't add
892
+ extra log noise.
893
+
894
+ Format::
895
+
896
+ archived 4 skill(s):
897
+ • pdf-extraction → document-tools
898
+ • docx-extraction → document-tools
899
+ • flaky-thing — pruned (stale)
900
+ • old-utility → spreadsheet-ops
901
+ full report: hermes curator status
902
+ keep an umbrella stable: hermes curator pin document-tools
903
+
904
+ Cap is 10 entries so a 50-skill consolidation doesn't blow up
905
+ agent.log; the full list is always in REPORT.md. The pin hint only
906
+ appears when at least one consolidation produced an umbrella worth
907
+ pinning (pruned-only runs skip it).
908
+ """
909
+ after_by_name = {r.get("name"): r for r in after_report if isinstance(r, dict)}
910
+ after_names = set(after_by_name.keys())
911
+ removed = sorted(before_names - after_names)
912
+ added = sorted(after_names - before_names)
913
+ if not removed:
914
+ return ""
915
+
916
+ heuristic = _classify_removed_skills(
917
+ removed=removed,
918
+ added=added,
919
+ after_names=after_names,
920
+ tool_calls=tool_calls,
921
+ )
922
+ model_block = _parse_structured_summary(model_final)
923
+ destinations = set(after_names) | set(added)
924
+ absorbed_declarations = _extract_absorbed_into_declarations(tool_calls)
925
+ classification = _reconcile_classification(
926
+ removed=removed,
927
+ heuristic=heuristic,
928
+ model_block=model_block,
929
+ destinations=destinations,
930
+ absorbed_declarations=absorbed_declarations,
931
+ )
932
+ consolidated = classification["consolidated"]
933
+ pruned = classification["pruned"]
934
+
935
+ SHOW = 10
936
+ lines: List[str] = []
937
+ total = len(consolidated) + len(pruned)
938
+ lines.append(f"archived {total} skill(s):")
939
+ shown = 0
940
+ for entry in consolidated:
941
+ if shown >= SHOW:
942
+ break
943
+ name = entry.get("name", "?")
944
+ into = entry.get("into", "?")
945
+ lines.append(f" • {name} → {into}")
946
+ shown += 1
947
+ for entry in pruned:
948
+ if shown >= SHOW:
949
+ break
950
+ name = entry.get("name", "?") if isinstance(entry, dict) else str(entry)
951
+ lines.append(f" • {name} — pruned (stale)")
952
+ shown += 1
953
+ if total > SHOW:
954
+ lines.append(f" … and {total - SHOW} more")
955
+ lines.append("full report: hermes curator status")
956
+ # Pin hint — only surface it when there's actually a destination skill
957
+ # worth pinning. The umbrella skills that absorbed content are the natural
958
+ # candidates: pinning one tells future curator runs to leave it alone.
959
+ # Pruned-only runs don't get this hint (nothing surviving to pin).
960
+ if consolidated:
961
+ umbrellas = sorted({e.get("into") for e in consolidated if e.get("into")})
962
+ if umbrellas:
963
+ example = umbrellas[0]
964
+ lines.append(
965
+ f"keep an umbrella stable: hermes curator pin {example}"
966
+ )
967
+ return "\n".join(lines)
968
+
969
+
970
+ def _write_run_report(
971
+ *,
972
+ started_at: datetime,
973
+ elapsed_seconds: float,
974
+ auto_counts: Dict[str, int],
975
+ auto_summary: str,
976
+ before_report: List[Dict[str, Any]],
977
+ before_names: Set[str],
978
+ after_report: List[Dict[str, Any]],
979
+ llm_meta: Dict[str, Any],
980
+ ) -> Optional[Path]:
981
+ """Write run.json + REPORT.md under logs/curator/{YYYYMMDD-HHMMSS}/.
982
+
983
+ Returns the report directory path on success, None if the write
984
+ couldn't happen (caller logs and continues — reporting is best-effort).
985
+ """
986
+ root = _reports_root()
987
+ try:
988
+ root.mkdir(parents=True, exist_ok=True)
989
+ except Exception as e:
990
+ logger.debug("Curator report dir create failed: %s", e)
991
+ return None
992
+
993
+ stamp = started_at.strftime("%Y%m%d-%H%M%S")
994
+ run_dir = root / stamp
995
+ # If we crash-reran within the same second, append a disambiguator
996
+ suffix = 1
997
+ while run_dir.exists():
998
+ suffix += 1
999
+ run_dir = root / f"{stamp}-{suffix}"
1000
+ try:
1001
+ run_dir.mkdir(parents=True, exist_ok=False)
1002
+ except Exception as e:
1003
+ logger.debug("Curator run dir create failed: %s", e)
1004
+ return None
1005
+
1006
+ # Diff before/after
1007
+ after_by_name = {r.get("name"): r for r in after_report if isinstance(r, dict)}
1008
+ after_names = set(after_by_name.keys())
1009
+ removed = sorted(before_names - after_names) # archived during this run
1010
+ added = sorted(after_names - before_names) # new skills this run
1011
+ before_by_name = {r.get("name"): r for r in before_report if isinstance(r, dict)}
1012
+
1013
+ # State transitions between the two snapshots (e.g. active -> stale)
1014
+ transitions: List[Dict[str, str]] = []
1015
+ for name in sorted(after_names & before_names):
1016
+ s_before = (before_by_name.get(name) or {}).get("state")
1017
+ s_after = (after_by_name.get(name) or {}).get("state")
1018
+ if s_before and s_after and s_before != s_after:
1019
+ transitions.append({"name": name, "from": s_before, "to": s_after})
1020
+
1021
+ # Classify LLM tool calls
1022
+ tc_counts: Dict[str, int] = {}
1023
+ for tc in llm_meta.get("tool_calls", []) or []:
1024
+ name = tc.get("name", "unknown")
1025
+ tc_counts[name] = tc_counts.get(name, 0) + 1
1026
+
1027
+ # Split "removed" into consolidated (absorbed into umbrella) vs pruned
1028
+ # (archived for staleness, content not preserved elsewhere). The old
1029
+ # "Skills archived" section lumped both together, which misled users
1030
+ # into thinking consolidated skills had been pruned.
1031
+ #
1032
+ # Classification strategy:
1033
+ # 1. Parse the curator's structured YAML block from its final response.
1034
+ # The curator is now prompted to emit consolidations/prunings lists
1035
+ # with short rationale. The model has intent visibility the tool
1036
+ # calls don't.
1037
+ # 2. Run the tool-call heuristic as a ground-truth audit.
1038
+ # 3. Reconcile: model gets authority over intent + rationale, heuristic
1039
+ # catches hallucination (umbrella doesn't exist) and omission
1040
+ # (model forgot to list an actual consolidation).
1041
+ heuristic = _classify_removed_skills(
1042
+ removed=removed,
1043
+ added=added,
1044
+ after_names=after_names,
1045
+ tool_calls=llm_meta.get("tool_calls", []) or [],
1046
+ )
1047
+ model_block = _parse_structured_summary(llm_meta.get("final", "") or "")
1048
+ destinations = set(after_names) | set(added or [])
1049
+ # Authoritative signal: extract per-delete `absorbed_into` declarations
1050
+ # from this run's tool calls. These beat both the YAML summary block and
1051
+ # the substring heuristic — the model is telling us directly, at the
1052
+ # moment of deletion, whether each archived skill was consolidated
1053
+ # (into=<umbrella>) or pruned (into="").
1054
+ absorbed_declarations = _extract_absorbed_into_declarations(
1055
+ llm_meta.get("tool_calls", []) or []
1056
+ )
1057
+ classification = _reconcile_classification(
1058
+ removed=removed,
1059
+ heuristic=heuristic,
1060
+ model_block=model_block,
1061
+ destinations=destinations,
1062
+ absorbed_declarations=absorbed_declarations,
1063
+ )
1064
+ consolidated = classification["consolidated"]
1065
+ pruned = classification["pruned"]
1066
+
1067
+ # Rewrite cron job skill references. When the curator consolidates
1068
+ # skill X into umbrella Y, any cron job that lists X fails to load
1069
+ # it at run time — the scheduler skips it and the job runs without
1070
+ # the instructions it was scheduled to follow. Rewriting the
1071
+ # references in-place keeps scheduled jobs working across
1072
+ # consolidation passes. Best-effort: never let a cron-module issue
1073
+ # break the curator.
1074
+ cron_rewrites: Dict[str, Any] = {"rewrites": [], "jobs_updated": 0, "jobs_scanned": 0}
1075
+ try:
1076
+ consolidated_map = {
1077
+ e["name"]: e["into"]
1078
+ for e in consolidated
1079
+ if isinstance(e, dict) and e.get("name") and e.get("into")
1080
+ }
1081
+ pruned_names = [
1082
+ e["name"] for e in pruned
1083
+ if isinstance(e, dict) and e.get("name")
1084
+ ]
1085
+ if consolidated_map or pruned_names:
1086
+ from cron.jobs import rewrite_skill_refs as _rewrite_cron_refs
1087
+ cron_rewrites = _rewrite_cron_refs(
1088
+ consolidated=consolidated_map,
1089
+ pruned=pruned_names,
1090
+ )
1091
+ except Exception as e:
1092
+ logger.debug("Curator cron skill rewrite failed: %s", e, exc_info=True)
1093
+ cron_rewrites = {
1094
+ "rewrites": [],
1095
+ "jobs_updated": 0,
1096
+ "jobs_scanned": 0,
1097
+ "error": str(e),
1098
+ }
1099
+
1100
+ payload = {
1101
+ "started_at": started_at.isoformat(),
1102
+ "duration_seconds": round(elapsed_seconds, 2),
1103
+ "model": llm_meta.get("model", ""),
1104
+ "provider": llm_meta.get("provider", ""),
1105
+ "auto_transitions": auto_counts,
1106
+ "counts": {
1107
+ "before": len(before_names),
1108
+ "after": len(after_names),
1109
+ "delta": len(after_names) - len(before_names),
1110
+ "archived_this_run": len(removed),
1111
+ "added_this_run": len(added),
1112
+ "consolidated_this_run": len(consolidated),
1113
+ "pruned_this_run": len(pruned),
1114
+ "state_transitions": len(transitions),
1115
+ "cron_jobs_rewritten": int(cron_rewrites.get("jobs_updated", 0)),
1116
+ "tool_calls_total": sum(tc_counts.values()),
1117
+ },
1118
+ "tool_call_counts": tc_counts,
1119
+ "archived": removed,
1120
+ "consolidated": consolidated,
1121
+ "pruned": pruned,
1122
+ "pruned_names": [p["name"] for p in pruned],
1123
+ "added": added,
1124
+ "state_transitions": transitions,
1125
+ "cron_rewrites": cron_rewrites,
1126
+ "llm_final": llm_meta.get("final", ""),
1127
+ "llm_summary": llm_meta.get("summary", ""),
1128
+ "llm_error": llm_meta.get("error"),
1129
+ "tool_calls": llm_meta.get("tool_calls", []),
1130
+ }
1131
+
1132
+ # run.json — machine-readable, full fidelity
1133
+ try:
1134
+ (run_dir / "run.json").write_text(
1135
+ json.dumps(payload, indent=2, ensure_ascii=False) + "\n",
1136
+ encoding="utf-8",
1137
+ )
1138
+ except Exception as e:
1139
+ logger.debug("Curator run.json write failed: %s", e)
1140
+
1141
+ # REPORT.md — human-readable
1142
+ try:
1143
+ md = _render_report_markdown(payload)
1144
+ (run_dir / "REPORT.md").write_text(md, encoding="utf-8")
1145
+ except Exception as e:
1146
+ logger.debug("Curator REPORT.md write failed: %s", e)
1147
+
1148
+ # cron_rewrites.json — only when at least one job was touched, to
1149
+ # keep run dirs uncluttered for the common no-op case.
1150
+ try:
1151
+ if int(cron_rewrites.get("jobs_updated", 0)) > 0:
1152
+ (run_dir / "cron_rewrites.json").write_text(
1153
+ json.dumps(cron_rewrites, indent=2, ensure_ascii=False) + "\n",
1154
+ encoding="utf-8",
1155
+ )
1156
+ except Exception as e:
1157
+ logger.debug("Curator cron_rewrites.json write failed: %s", e)
1158
+
1159
+ return run_dir
1160
+
1161
+
1162
+ def _render_report_markdown(p: Dict[str, Any]) -> str:
1163
+ """Render the human-readable report."""
1164
+ lines: List[str] = []
1165
+ started = p.get("started_at", "")
1166
+ duration = p.get("duration_seconds", 0) or 0
1167
+ mins, secs = divmod(int(duration), 60)
1168
+ dur_label = f"{mins}m {secs}s" if mins else f"{secs}s"
1169
+
1170
+ lines.append(f"# Curator run — {started}\n")
1171
+ model = p.get("model") or "(not resolved)"
1172
+ prov = p.get("provider") or "(not resolved)"
1173
+ counts = p.get("counts") or {}
1174
+ lines.append(
1175
+ f"Model: `{model}` via `{prov}` · Duration: {dur_label} · "
1176
+ f"Agent-created skills: {counts.get('before', 0)} → {counts.get('after', 0)} "
1177
+ f"({counts.get('delta', 0):+d})\n"
1178
+ )
1179
+
1180
+ error = p.get("llm_error")
1181
+ if error:
1182
+ lines.append(f"> ⚠ LLM pass error: `{error}`\n")
1183
+
1184
+ # Auto-transitions (pure, no LLM)
1185
+ auto = p.get("auto_transitions") or {}
1186
+ lines.append("## Auto-transitions (pure, no LLM)\n")
1187
+ lines.append(f"- checked: {auto.get('checked', 0)}")
1188
+ lines.append(f"- marked stale: {auto.get('marked_stale', 0)}")
1189
+ lines.append(f"- archived (no LLM, pure time-based staleness): {auto.get('archived', 0)}")
1190
+ lines.append(f"- reactivated: {auto.get('reactivated', 0)}")
1191
+ lines.append("")
1192
+
1193
+ # LLM pass numbers
1194
+ tc_counts = p.get("tool_call_counts") or {}
1195
+ lines.append("## LLM consolidation pass\n")
1196
+ lines.append(f"- tool calls: **{counts.get('tool_calls_total', 0)}** "
1197
+ f"(by name: {', '.join(f'{k}={v}' for k, v in sorted(tc_counts.items())) or 'none'})")
1198
+ lines.append(f"- consolidated into umbrellas: **{counts.get('consolidated_this_run', 0)}**")
1199
+ lines.append(f"- pruned (archived for staleness): **{counts.get('pruned_this_run', 0)}**")
1200
+ lines.append(f"- new skills this run: **{counts.get('added_this_run', 0)}**")
1201
+ lines.append(f"- state transitions (active ↔ stale ↔ archived): "
1202
+ f"**{counts.get('state_transitions', 0)}**")
1203
+ lines.append("")
1204
+
1205
+ # Consolidated list — content absorbed into an umbrella. The directory
1206
+ # on disk still lives under ~/.hermes/skills/.archive/ (every removal is
1207
+ # recoverable by design), but the "live" content for these skills
1208
+ # continues to exist inside the destination umbrella.
1209
+ consolidated = p.get("consolidated") or []
1210
+ if consolidated:
1211
+ lines.append(f"### Consolidated into umbrella skills ({len(consolidated)})\n")
1212
+ lines.append(
1213
+ "_These skills were **absorbed into another skill** during this run — "
1214
+ "their content still lives, just under a different name. "
1215
+ "The original directory was moved to `~/.hermes/skills/.archive/` for "
1216
+ "safety and can be restored via `hermes curator restore <name>` if the "
1217
+ "consolidation was wrong._\n"
1218
+ )
1219
+ SHOW = 50
1220
+ for entry in consolidated[:SHOW]:
1221
+ name = entry.get("name", "?")
1222
+ into = entry.get("into", "?")
1223
+ reason = (entry.get("reason") or "").strip()
1224
+ source = entry.get("source", "")
1225
+ line = f"- `{name}` → merged into `{into}`"
1226
+ if reason:
1227
+ line += f" — {reason}"
1228
+ if source and source.startswith("tool-call audit"):
1229
+ # The model didn't enumerate this one — surface that to the
1230
+ # user so they know why the row has no rationale.
1231
+ line += f" _(detected via {source})_"
1232
+ lines.append(line)
1233
+ if entry.get("model_claimed_into"):
1234
+ lines.append(
1235
+ f" ⚠ The curator's summary named `{entry['model_claimed_into']}` "
1236
+ "as the umbrella but that skill doesn't exist post-run; "
1237
+ "showing the tool-call audit's finding instead."
1238
+ )
1239
+ if len(consolidated) > SHOW:
1240
+ lines.append(f"- … and {len(consolidated) - SHOW} more (see `run.json`)")
1241
+ lines.append("")
1242
+
1243
+ # Pruned list — archived without consolidation. These are the
1244
+ # "stale skill pruned" cases the UI should mark clearly.
1245
+ pruned = p.get("pruned") or []
1246
+ if pruned:
1247
+ lines.append(f"### Pruned — archived for staleness ({len(pruned)})\n")
1248
+ lines.append(
1249
+ "_These skills were archived without being merged into an umbrella "
1250
+ "(e.g. stale, unused, or judged irrelevant). "
1251
+ "Directories live under `~/.hermes/skills/.archive/`. "
1252
+ "Restore any via `hermes curator restore <name>`._\n"
1253
+ )
1254
+ SHOW = 50
1255
+ for entry in pruned[:SHOW]:
1256
+ # Entries are dicts with {name, source, reason} when written via
1257
+ # the reconciler, or bare strings when an older format slipped
1258
+ # through. Handle both.
1259
+ if isinstance(entry, dict):
1260
+ name = entry.get("name", "?")
1261
+ reason = (entry.get("reason") or "").strip()
1262
+ line = f"- `{name}`"
1263
+ if reason:
1264
+ line += f" — {reason}"
1265
+ lines.append(line)
1266
+ else:
1267
+ lines.append(f"- `{entry}`")
1268
+ if len(pruned) > SHOW:
1269
+ lines.append(f"- … and {len(pruned) - SHOW} more (see `run.json`)")
1270
+ lines.append("")
1271
+
1272
+ # Added list
1273
+ added = p.get("added") or []
1274
+ if added:
1275
+ lines.append(f"### New skills this run ({len(added)})\n")
1276
+ lines.append("_Usually these are new class-level umbrellas created via `skill_manage action=create`._\n")
1277
+ for n in added:
1278
+ lines.append(f"- `{n}`")
1279
+ lines.append("")
1280
+
1281
+ # State transitions
1282
+ trans = p.get("state_transitions") or []
1283
+ if trans:
1284
+ lines.append(f"### State transitions ({len(trans)})\n")
1285
+ for t in trans:
1286
+ lines.append(f"- `{t.get('name')}`: {t.get('from')} → {t.get('to')}")
1287
+ lines.append("")
1288
+
1289
+ # Cron job rewrites — show which scheduled jobs had their skill
1290
+ # references updated so users can audit that the auto-rewrite did
1291
+ # the right thing. Only present when at least one job changed.
1292
+ cron_rw = p.get("cron_rewrites") or {}
1293
+ cron_rewrites_list = cron_rw.get("rewrites") or []
1294
+ if cron_rewrites_list:
1295
+ lines.append(f"### Cron job skill references rewritten ({len(cron_rewrites_list)})\n")
1296
+ lines.append(
1297
+ "_Cron jobs that referenced a consolidated or pruned skill were "
1298
+ "updated in-place so they keep loading the right instructions "
1299
+ "on their next run. See `cron_rewrites.json` for the full record._\n"
1300
+ )
1301
+ SHOW = 25
1302
+ for entry in cron_rewrites_list[:SHOW]:
1303
+ job_name = entry.get("job_name") or entry.get("job_id") or "?"
1304
+ before = entry.get("before") or []
1305
+ after = entry.get("after") or []
1306
+ mapped = entry.get("mapped") or {}
1307
+ dropped = entry.get("dropped") or []
1308
+ lines.append(
1309
+ f"- `{job_name}`: `{', '.join(before)}` → `{', '.join(after) or '(none)'}`"
1310
+ )
1311
+ for old, new in mapped.items():
1312
+ lines.append(f" - `{old}` → `{new}` (consolidated)")
1313
+ for name in dropped:
1314
+ lines.append(f" - `{name}` dropped (pruned)")
1315
+ if len(cron_rewrites_list) > SHOW:
1316
+ lines.append(
1317
+ f"- … and {len(cron_rewrites_list) - SHOW} more "
1318
+ "(see `cron_rewrites.json`)"
1319
+ )
1320
+ lines.append("")
1321
+
1322
+ # Full LLM final response
1323
+ final = (p.get("llm_final") or "").strip()
1324
+ if final:
1325
+ lines.append("## LLM final summary\n")
1326
+ lines.append(final)
1327
+ lines.append("")
1328
+ elif not error:
1329
+ llm_sum = p.get("llm_summary") or ""
1330
+ if llm_sum:
1331
+ lines.append("## LLM summary\n")
1332
+ lines.append(llm_sum)
1333
+ lines.append("")
1334
+
1335
+ # Recovery footer
1336
+ lines.append("## Recovery\n")
1337
+ lines.append("- Restore an archived skill: `hermes curator restore <name>`")
1338
+ lines.append("- All archives live under `~/.hermes/skills/.archive/` and are recoverable by `mv`")
1339
+ lines.append("- See `run.json` in this directory for the full machine-readable record.")
1340
+ lines.append("")
1341
+
1342
+ return "\n".join(lines)
1343
+
1344
+
1345
+ # ---------------------------------------------------------------------------
1346
+ # Orchestrator — spawn a forked AIAgent for the LLM review pass
1347
+ # ---------------------------------------------------------------------------
1348
+
1349
+ def _render_candidate_list() -> str:
1350
+ """Human/agent-readable list of agent-created skills with usage stats."""
1351
+ rows = skill_usage.agent_created_report()
1352
+ if not rows:
1353
+ return "No agent-created skills to review."
1354
+ lines = [f"Agent-created skills ({len(rows)}):\n"]
1355
+ for r in rows:
1356
+ lines.append(
1357
+ f"- {r['name']} "
1358
+ f"state={r['state']} "
1359
+ f"pinned={'yes' if r.get('pinned') else 'no'} "
1360
+ f"activity={r.get('activity_count', 0)} "
1361
+ f"use={r.get('use_count', 0)} "
1362
+ f"view={r.get('view_count', 0)} "
1363
+ f"patches={r.get('patch_count', 0)} "
1364
+ f"last_activity={r.get('last_activity_at') or 'never'}"
1365
+ )
1366
+ return "\n".join(lines)
1367
+
1368
+
1369
+ def run_curator_review(
1370
+ on_summary: Optional[Callable[[str], None]] = None,
1371
+ synchronous: bool = False,
1372
+ dry_run: bool = False,
1373
+ ) -> Dict[str, Any]:
1374
+ """Execute a single curator review pass.
1375
+
1376
+ Steps:
1377
+ 1. Apply automatic state transitions (pure, no LLM).
1378
+ 2. If there are agent-created skills, spawn a forked AIAgent that runs
1379
+ the LLM review prompt against the current candidate list.
1380
+ 3. Update .curator_state with last_run_at and a one-line summary.
1381
+ 4. Invoke *on_summary* with a user-visible description.
1382
+
1383
+ If *synchronous* is True, the LLM review runs in the calling thread; the
1384
+ default is to spawn a daemon thread so the caller returns immediately.
1385
+
1386
+ If *dry_run* is True, the automatic stale/archive transitions are SKIPPED
1387
+ and the LLM review pass is instructed to produce a report only — no
1388
+ skill_manage mutations, no terminal archive moves. The REPORT.md still
1389
+ gets written and ``state.last_report_path`` still records it so users
1390
+ can read what the curator WOULD have done.
1391
+ """
1392
+ start = datetime.now(timezone.utc)
1393
+ if dry_run:
1394
+ # Count candidates without mutating state.
1395
+ try:
1396
+ report = skill_usage.agent_created_report()
1397
+ counts = {
1398
+ "checked": len(report),
1399
+ "marked_stale": 0,
1400
+ "archived": 0,
1401
+ "reactivated": 0,
1402
+ }
1403
+ except Exception:
1404
+ counts = {"checked": 0, "marked_stale": 0, "archived": 0, "reactivated": 0}
1405
+ else:
1406
+ # Pre-mutation snapshot — best-effort, never blocks the run. A
1407
+ # failed snapshot logs at debug and continues (the alternative is
1408
+ # that a transient disk issue silently disables curator forever,
1409
+ # which is worse). Users who want to require snapshots can disable
1410
+ # curator entirely until they can fix disk space.
1411
+ try:
1412
+ from agent import curator_backup
1413
+ snap = curator_backup.snapshot_skills(reason="pre-curator-run")
1414
+ if snap is not None and on_summary:
1415
+ try:
1416
+ on_summary(f"curator: snapshot created ({snap.name})")
1417
+ except Exception:
1418
+ pass
1419
+ except Exception as e:
1420
+ logger.debug("Curator pre-run snapshot failed: %s", e, exc_info=True)
1421
+ counts = apply_automatic_transitions(now=start)
1422
+
1423
+ auto_summary_parts = []
1424
+ if counts["marked_stale"]:
1425
+ auto_summary_parts.append(f"{counts['marked_stale']} marked stale")
1426
+ if counts["archived"]:
1427
+ auto_summary_parts.append(f"{counts['archived']} archived")
1428
+ if counts["reactivated"]:
1429
+ auto_summary_parts.append(f"{counts['reactivated']} reactivated")
1430
+ auto_summary = ", ".join(auto_summary_parts) if auto_summary_parts else "no changes"
1431
+
1432
+ # Persist state before the LLM pass so a crash mid-review still records
1433
+ # the run and doesn't immediately re-trigger. In dry-run we do NOT bump
1434
+ # last_run_at or run_count — a preview shouldn't push the next scheduled
1435
+ # real pass out. We still record a summary so `hermes curator status`
1436
+ # shows that a preview ran.
1437
+ state = load_state()
1438
+ if not dry_run:
1439
+ state["last_run_at"] = start.isoformat()
1440
+ state["run_count"] = int(state.get("run_count", 0)) + 1
1441
+ prefix = "dry-run auto: " if dry_run else "auto: "
1442
+ state["last_run_summary"] = f"{prefix}{auto_summary}"
1443
+ save_state(state)
1444
+
1445
+ def _llm_pass():
1446
+ nonlocal auto_summary
1447
+ # Snapshot skill state BEFORE the LLM pass so the report can diff.
1448
+ try:
1449
+ before_report = skill_usage.agent_created_report()
1450
+ except Exception:
1451
+ before_report = []
1452
+ before_names = {r.get("name") for r in before_report if isinstance(r, dict)}
1453
+
1454
+ llm_meta: Dict[str, Any] = {}
1455
+ try:
1456
+ candidate_list = _render_candidate_list()
1457
+ if "No agent-created skills" in candidate_list:
1458
+ final_summary = f"{prefix}{auto_summary}; llm: skipped (no candidates)"
1459
+ llm_meta = {
1460
+ "final": "",
1461
+ "summary": "skipped (no candidates)",
1462
+ "model": "",
1463
+ "provider": "",
1464
+ "tool_calls": [],
1465
+ "error": None,
1466
+ }
1467
+ else:
1468
+ if dry_run:
1469
+ prompt = (
1470
+ f"{CURATOR_DRY_RUN_BANNER}\n\n"
1471
+ f"{CURATOR_REVIEW_PROMPT}\n\n"
1472
+ f"{candidate_list}"
1473
+ )
1474
+ else:
1475
+ prompt = f"{CURATOR_REVIEW_PROMPT}\n\n{candidate_list}"
1476
+ llm_meta = _run_llm_review(prompt)
1477
+ final_summary = (
1478
+ f"{prefix}{auto_summary}; llm: {llm_meta.get('summary', 'no change')}"
1479
+ )
1480
+ except Exception as e:
1481
+ logger.debug("Curator LLM pass failed: %s", e, exc_info=True)
1482
+ final_summary = f"{prefix}{auto_summary}; llm: error ({e})"
1483
+ llm_meta = {
1484
+ "final": "",
1485
+ "summary": f"error ({e})",
1486
+ "model": "",
1487
+ "provider": "",
1488
+ "tool_calls": [],
1489
+ "error": str(e),
1490
+ }
1491
+
1492
+ # Append the rename map (`old-name → umbrella`) to the user-visible
1493
+ # summary so people don't have to dig into REPORT.md to find out where
1494
+ # their skills went. Best-effort: classification is pure but never
1495
+ # block the run on a formatting issue.
1496
+ try:
1497
+ rename_lines = _build_rename_summary(
1498
+ before_names=before_names,
1499
+ after_report=skill_usage.agent_created_report(),
1500
+ tool_calls=llm_meta.get("tool_calls", []) or [],
1501
+ model_final=llm_meta.get("final", "") or "",
1502
+ )
1503
+ if rename_lines:
1504
+ final_summary = f"{final_summary}\n{rename_lines}"
1505
+ except Exception as e:
1506
+ logger.debug("Curator rename summary build failed: %s", e, exc_info=True)
1507
+
1508
+ elapsed = (datetime.now(timezone.utc) - start).total_seconds()
1509
+ state2 = load_state()
1510
+ state2["last_run_duration_seconds"] = elapsed
1511
+ state2["last_run_summary"] = final_summary
1512
+
1513
+ # Write the per-run report. Runs in a best-effort try so a
1514
+ # reporting bug never breaks the curator itself. Report path is
1515
+ # recorded in state so `hermes curator status` can point at it.
1516
+ try:
1517
+ after_report = skill_usage.agent_created_report()
1518
+ except Exception:
1519
+ after_report = []
1520
+ try:
1521
+ report_path = _write_run_report(
1522
+ started_at=start,
1523
+ elapsed_seconds=elapsed,
1524
+ auto_counts=counts,
1525
+ auto_summary=auto_summary,
1526
+ before_report=before_report,
1527
+ before_names=before_names,
1528
+ after_report=after_report,
1529
+ llm_meta=llm_meta,
1530
+ )
1531
+ if report_path is not None:
1532
+ state2["last_report_path"] = str(report_path)
1533
+ except Exception as e:
1534
+ logger.debug("Curator report write failed: %s", e, exc_info=True)
1535
+
1536
+ save_state(state2)
1537
+
1538
+ if on_summary:
1539
+ try:
1540
+ on_summary(f"curator: {final_summary}")
1541
+ except Exception:
1542
+ pass
1543
+
1544
+ if synchronous:
1545
+ _llm_pass()
1546
+ else:
1547
+ t = threading.Thread(target=_llm_pass, daemon=True, name="curator-review")
1548
+ t.start()
1549
+
1550
+ return {
1551
+ "started_at": start.isoformat(),
1552
+ "auto_transitions": counts,
1553
+ "summary_so_far": auto_summary,
1554
+ }
1555
+
1556
+
1557
+ def _resolve_review_runtime(cfg: Dict[str, Any]) -> _ReviewRuntimeBinding:
1558
+ """Resolve provider/model and per-slot credentials for the curator review fork.
1559
+
1560
+ Same precedence as `_resolve_review_model()`. Non-empty ``api_key`` /
1561
+ ``base_url`` from the active slot are returned as explicit overrides so
1562
+ ``resolve_runtime_provider`` does not silently reuse the main chat
1563
+ credential chain for a routed auxiliary model.
1564
+ """
1565
+ _main = cfg.get("model", {}) if isinstance(cfg.get("model"), dict) else {}
1566
+ _main_provider = _main.get("provider") or "auto"
1567
+ _main_model = _main.get("default") or _main.get("model") or ""
1568
+
1569
+ # 1. Canonical aux task slot
1570
+ _aux = cfg.get("auxiliary", {}) if isinstance(cfg.get("auxiliary"), dict) else {}
1571
+ _cur_task = _aux.get("curator", {}) if isinstance(_aux.get("curator"), dict) else {}
1572
+ _task_provider = (_cur_task.get("provider") or "").strip() or None
1573
+ _task_model = (_cur_task.get("model") or "").strip() or None
1574
+ if _task_provider and _task_provider != "auto" and _task_model:
1575
+ return _ReviewRuntimeBinding(
1576
+ _task_provider,
1577
+ _task_model,
1578
+ _strip_aux_credential(_cur_task.get("api_key")),
1579
+ _strip_aux_credential(_cur_task.get("base_url")),
1580
+ )
1581
+
1582
+ # 2. Legacy curator.auxiliary.{provider,model} (deprecated, pre-unification)
1583
+ _cur = cfg.get("curator", {}) if isinstance(cfg.get("curator"), dict) else {}
1584
+ _legacy = _cur.get("auxiliary", {}) if isinstance(_cur.get("auxiliary"), dict) else {}
1585
+ _legacy_provider = _legacy.get("provider") or None
1586
+ _legacy_model = _legacy.get("model") or None
1587
+ if _legacy_provider and _legacy_model:
1588
+ logger.info(
1589
+ "curator: using deprecated curator.auxiliary.{provider,model} "
1590
+ "config — please migrate to auxiliary.curator.{provider,model}"
1591
+ )
1592
+ return _ReviewRuntimeBinding(
1593
+ str(_legacy_provider),
1594
+ str(_legacy_model),
1595
+ _strip_aux_credential(_legacy.get("api_key")),
1596
+ _strip_aux_credential(_legacy.get("base_url")),
1597
+ )
1598
+
1599
+ # 3. Fall through to the main chat model
1600
+ return _ReviewRuntimeBinding(_main_provider, _main_model, None, None)
1601
+
1602
+
1603
+ def _resolve_review_model(cfg: Dict[str, Any]) -> tuple[str, str]:
1604
+ """Pick (provider, model) for the curator review fork.
1605
+
1606
+ Curator is a regular auxiliary task slot — ``auxiliary.curator.{provider,model}``
1607
+ — so it participates in the canonical aux-model plumbing (``hermes model`` →
1608
+ auxiliary picker, the dashboard Models tab, ``auxiliary.curator.{timeout,
1609
+ base_url,api_key,extra_body}``). ``provider: "auto"`` with an empty model
1610
+ means "use the main chat model" — same default as every other aux task.
1611
+
1612
+ Legacy fallback: users who configured ``curator.auxiliary.{provider,model}``
1613
+ under the previous one-off schema still work. Precedence:
1614
+ 1. ``auxiliary.curator.{provider,model}`` when both are set non-auto
1615
+ 2. Legacy ``curator.auxiliary.{provider,model}`` when both are set
1616
+ 3. Main ``model.{provider,default/model}`` pair
1617
+ """
1618
+ b = _resolve_review_runtime(cfg)
1619
+ return b.provider, b.model
1620
+
1621
+
1622
+ def _run_llm_review(prompt: str) -> Dict[str, Any]:
1623
+ """Spawn an AIAgent fork to run the curator review prompt.
1624
+
1625
+ Returns a dict with:
1626
+ - final: full (untruncated) final response from the reviewer
1627
+ - summary: short summary suitable for state file (240-char cap)
1628
+ - model, provider: what the fork actually ran on
1629
+ - tool_calls: list of {name, arguments} for every tool call made during
1630
+ the pass (arguments may be truncated for readability)
1631
+ - error: set if the pass failed mid-run; final/summary may still be empty
1632
+
1633
+ Never raises; callers get a structured failure instead.
1634
+ """
1635
+ import contextlib
1636
+ result_meta: Dict[str, Any] = {
1637
+ "final": "",
1638
+ "summary": "",
1639
+ "model": "",
1640
+ "provider": "",
1641
+ "tool_calls": [],
1642
+ "error": None,
1643
+ }
1644
+ try:
1645
+ from run_agent import AIAgent
1646
+ except Exception as e:
1647
+ result_meta["error"] = f"AIAgent import failed: {e}"
1648
+ result_meta["summary"] = result_meta["error"]
1649
+ return result_meta
1650
+
1651
+ # Resolve provider + model the same way the CLI does, so the curator
1652
+ # fork inherits the user's active main config rather than falling
1653
+ # through to an empty provider/model pair (which sends HTTP 400
1654
+ # "No models provided"). AIAgent() without explicit provider/model
1655
+ # arguments hits an auto-resolution path that fails for OAuth-only
1656
+ # providers and for pool-backed credentials.
1657
+ #
1658
+ # `_resolve_review_runtime()` honors `auxiliary.curator.{provider,model,...}`
1659
+ # (canonical aux-task slot, wired through `hermes model` → auxiliary
1660
+ # picker and the dashboard Models tab), with a legacy fallback to
1661
+ # `curator.auxiliary.{provider,model,...}`. See docs/user-guide/features/curator.md.
1662
+ _api_key = None
1663
+ _base_url = None
1664
+ _api_mode = None
1665
+ _resolved_provider = None
1666
+ _model_name = ""
1667
+ try:
1668
+ from hermes_cli.config import load_config
1669
+ from hermes_cli.runtime_provider import resolve_runtime_provider
1670
+ _cfg = load_config()
1671
+ _binding = _resolve_review_runtime(_cfg)
1672
+ _provider, _model_name = _binding.provider, _binding.model
1673
+ _rp = resolve_runtime_provider(
1674
+ requested=_provider,
1675
+ target_model=_model_name,
1676
+ explicit_api_key=_binding.explicit_api_key,
1677
+ explicit_base_url=_binding.explicit_base_url,
1678
+ )
1679
+ _api_key = _rp.get("api_key")
1680
+ _base_url = _rp.get("base_url")
1681
+ _api_mode = _rp.get("api_mode")
1682
+ _resolved_provider = _rp.get("provider") or _provider
1683
+ except Exception as e:
1684
+ logger.debug("Curator provider resolution failed: %s", e, exc_info=True)
1685
+
1686
+ result_meta["model"] = _model_name
1687
+ result_meta["provider"] = _resolved_provider or ""
1688
+
1689
+ review_agent = None
1690
+ try:
1691
+ review_agent = AIAgent(
1692
+ model=_model_name,
1693
+ provider=_resolved_provider,
1694
+ api_key=_api_key,
1695
+ base_url=_base_url,
1696
+ api_mode=_api_mode,
1697
+ # Umbrella-building over a large skill collection is worth a
1698
+ # high iteration ceiling — the pass typically takes 50-100
1699
+ # API calls against hundreds of candidate skills. The
1700
+ # single-session review path caps itself at a much smaller
1701
+ # number because it's not doing a curation sweep.
1702
+ max_iterations=9999,
1703
+ quiet_mode=True,
1704
+ platform="curator",
1705
+ skip_context_files=True,
1706
+ skip_memory=True,
1707
+ )
1708
+ # Disable recursive nudges — the curator must never spawn its own review.
1709
+ review_agent._memory_nudge_interval = 0
1710
+ review_agent._skill_nudge_interval = 0
1711
+
1712
+ # Redirect the forked agent's stdout/stderr to /dev/null while it
1713
+ # runs so its tool-call chatter doesn't pollute the foreground
1714
+ # terminal. The background-thread runner also hides it; this
1715
+ # belt-and-suspenders path matters when a caller invokes
1716
+ # run_curator_review(synchronous=True) from the CLI.
1717
+ with open(os.devnull, "w", encoding="utf-8") as _devnull, \
1718
+ contextlib.redirect_stdout(_devnull), \
1719
+ contextlib.redirect_stderr(_devnull):
1720
+ conv_result = review_agent.run_conversation(user_message=prompt)
1721
+
1722
+ final = ""
1723
+ if isinstance(conv_result, dict):
1724
+ final = str(conv_result.get("final_response") or "").strip()
1725
+ result_meta["final"] = final
1726
+ result_meta["summary"] = (final[:240] + "…") if len(final) > 240 else (final or "no change")
1727
+
1728
+ # Collect tool calls for the report. Walk the forked agent's
1729
+ # session messages and extract every tool_call made during the
1730
+ # pass. Truncate argument payloads so a giant skill_manage create
1731
+ # doesn't blow up the report.
1732
+ _calls: List[Dict[str, Any]] = []
1733
+ for msg in getattr(review_agent, "_session_messages", []) or []:
1734
+ if not isinstance(msg, dict):
1735
+ continue
1736
+ tcs = msg.get("tool_calls") or []
1737
+ for tc in tcs:
1738
+ if not isinstance(tc, dict):
1739
+ continue
1740
+ fn = tc.get("function") or {}
1741
+ name = fn.get("name") or ""
1742
+ args_raw = fn.get("arguments") or ""
1743
+ if isinstance(args_raw, str) and len(args_raw) > 400:
1744
+ args_raw = args_raw[:400] + "…"
1745
+ _calls.append({"name": name, "arguments": args_raw})
1746
+ result_meta["tool_calls"] = _calls
1747
+ except Exception as e:
1748
+ result_meta["error"] = f"error: {e}"
1749
+ result_meta["summary"] = result_meta["error"]
1750
+ finally:
1751
+ if review_agent is not None:
1752
+ try:
1753
+ review_agent.close()
1754
+ except Exception:
1755
+ pass
1756
+ return result_meta
1757
+
1758
+
1759
+ # ---------------------------------------------------------------------------
1760
+ # Public entrypoint for the session-start hook
1761
+ # ---------------------------------------------------------------------------
1762
+
1763
+ def maybe_run_curator(
1764
+ *,
1765
+ idle_for_seconds: Optional[float] = None,
1766
+ on_summary: Optional[Callable[[str], None]] = None,
1767
+ ) -> Optional[Dict[str, Any]]:
1768
+ """Best-effort: run a curator pass if all gates pass. Returns the result
1769
+ dict if a pass was started, else None. Never raises."""
1770
+ try:
1771
+ if not should_run_now():
1772
+ return None
1773
+ # Idle gating: only enforce when the caller provided a measurement.
1774
+ if idle_for_seconds is not None:
1775
+ min_idle_s = get_min_idle_hours() * 3600.0
1776
+ if idle_for_seconds < min_idle_s:
1777
+ return None
1778
+ return run_curator_review(on_summary=on_summary)
1779
+ except Exception as e:
1780
+ logger.debug("maybe_run_curator failed: %s", e, exc_info=True)
1781
+ return None
1782
+