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,1777 @@
1
+ """Shared model-switching logic for CLI and gateway /model commands.
2
+
3
+ Both the CLI (cli.py) and gateway (gateway/run.py) /model handlers
4
+ share the same core pipeline:
5
+
6
+ parse flags -> alias resolution -> provider resolution ->
7
+ credential resolution -> normalize model name ->
8
+ metadata lookup -> build result
9
+
10
+ This module ties together the foundation layers:
11
+
12
+ - ``agent.models_dev`` -- models.dev catalog, ModelInfo, ProviderInfo
13
+ - ``hermes_cli.providers`` -- canonical provider identity + overlays
14
+ - ``hermes_cli.model_normalize`` -- per-provider name formatting
15
+
16
+ Provider switching uses the ``--provider`` flag exclusively.
17
+ No colon-based ``provider:model`` syntax — colons are reserved for
18
+ OpenRouter variant suffixes (``:free``, ``:extended``, ``:fast``).
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import logging
24
+ import re
25
+ from dataclasses import dataclass
26
+ from typing import List, NamedTuple, Optional
27
+
28
+ from hermes_cli.providers import (
29
+ custom_provider_slug,
30
+ determine_api_mode,
31
+ get_label,
32
+ is_aggregator,
33
+ resolve_provider_full,
34
+ )
35
+ from hermes_cli.model_normalize import (
36
+ normalize_model_for_provider,
37
+ )
38
+ from agent.models_dev import (
39
+ ModelCapabilities,
40
+ ModelInfo,
41
+ get_model_capabilities,
42
+ get_model_info,
43
+ list_provider_models,
44
+ )
45
+
46
+ logger = logging.getLogger(__name__)
47
+
48
+
49
+ # ---------------------------------------------------------------------------
50
+ # Non-agentic model warning
51
+ # ---------------------------------------------------------------------------
52
+
53
+ _HERMES_MODEL_WARNING = (
54
+ "Nous Research Hermes 3 & 4 models are NOT agentic and are not designed "
55
+ "for use with Hermes Agent. They lack the tool-calling capabilities "
56
+ "required for agent workflows. Consider using an agentic model instead "
57
+ "(Claude, GPT, Gemini, DeepSeek, etc.)."
58
+ )
59
+
60
+ # Match only the real Nous Research Hermes 3 / Hermes 4 chat families.
61
+ # The previous substring check (`"hermes" in name.lower()`) false-positived on
62
+ # unrelated local Modelfiles like ``hermes-brain:qwen3-14b-ctx16k`` that just
63
+ # happen to carry "hermes" in their tag but are fully tool-capable.
64
+ #
65
+ # Positive examples the regex must match:
66
+ # NousResearch/Hermes-3-Llama-3.1-70B, hermes-4-405b, openrouter/hermes3:70b
67
+ # Negative examples it must NOT match:
68
+ # hermes-brain:qwen3-14b-ctx16k, qwen3:14b, claude-opus-4-6
69
+ _NOUS_HERMES_NON_AGENTIC_RE = re.compile(
70
+ r"(?:^|[/:])hermes[-_ ]?[34](?:[-_.:]|$)",
71
+ re.IGNORECASE,
72
+ )
73
+
74
+
75
+ def is_nous_hermes_non_agentic(model_name: str) -> bool:
76
+ """Return True if *model_name* is a real Nous Hermes 3/4 chat model.
77
+
78
+ Used to decide whether to surface the non-agentic warning at startup.
79
+ Callers in :mod:`cli.py` and here should go through this single helper
80
+ so the two sites don't drift.
81
+ """
82
+ if not model_name:
83
+ return False
84
+ return bool(_NOUS_HERMES_NON_AGENTIC_RE.search(model_name))
85
+
86
+
87
+ def _check_hermes_model_warning(model_name: str) -> str:
88
+ """Return a warning string if *model_name* is a Nous Hermes 3/4 chat model."""
89
+ if is_nous_hermes_non_agentic(model_name):
90
+ return _HERMES_MODEL_WARNING
91
+ return ""
92
+
93
+
94
+ # ---------------------------------------------------------------------------
95
+ # Model aliases -- short names -> (vendor, family) with NO version numbers.
96
+ # Resolved dynamically against the live models.dev catalog.
97
+ # ---------------------------------------------------------------------------
98
+
99
+ class ModelIdentity(NamedTuple):
100
+ """Vendor slug and family prefix used for catalog resolution."""
101
+ vendor: str
102
+ family: str
103
+
104
+
105
+ MODEL_ALIASES: dict[str, ModelIdentity] = {
106
+ # Anthropic
107
+ "sonnet": ModelIdentity("anthropic", "claude-sonnet"),
108
+ "opus": ModelIdentity("anthropic", "claude-opus"),
109
+ "haiku": ModelIdentity("anthropic", "claude-haiku"),
110
+ "claude": ModelIdentity("anthropic", "claude"),
111
+
112
+ # OpenAI
113
+ "gpt5": ModelIdentity("openai", "gpt-5"),
114
+ "gpt": ModelIdentity("openai", "gpt"),
115
+ "codex": ModelIdentity("openai", "codex"),
116
+ "o3": ModelIdentity("openai", "o3"),
117
+ "o4": ModelIdentity("openai", "o4"),
118
+
119
+ # Google
120
+ "gemini": ModelIdentity("google", "gemini"),
121
+
122
+ # DeepSeek
123
+ "deepseek": ModelIdentity("deepseek", "deepseek-chat"),
124
+
125
+ # X.AI
126
+ "grok": ModelIdentity("x-ai", "grok"),
127
+
128
+ # Meta
129
+ "llama": ModelIdentity("meta-llama", "llama"),
130
+
131
+ # Qwen / Alibaba
132
+ "qwen": ModelIdentity("qwen", "qwen"),
133
+
134
+ # MiniMax
135
+ "minimax": ModelIdentity("minimax", "minimax"),
136
+
137
+ # Nvidia
138
+ "nemotron": ModelIdentity("nvidia", "nemotron"),
139
+
140
+ # Moonshot / Kimi
141
+ "kimi": ModelIdentity("moonshotai", "kimi"),
142
+
143
+ # Z.AI / GLM
144
+ "glm": ModelIdentity("z-ai", "glm"),
145
+
146
+ # Step Plan (StepFun)
147
+ "step": ModelIdentity("stepfun", "step"),
148
+
149
+ # Xiaomi
150
+ "mimo": ModelIdentity("xiaomi", "mimo"),
151
+
152
+ # Arcee
153
+ "trinity": ModelIdentity("arcee-ai", "trinity"),
154
+ }
155
+
156
+
157
+ # ---------------------------------------------------------------------------
158
+ # Direct aliases — exact model+provider+base_url for endpoints that aren't
159
+ # in the models.dev catalog (e.g. Ollama Cloud, local servers).
160
+ # Checked BEFORE catalog resolution. Format:
161
+ # alias -> (model_id, provider, base_url)
162
+ # These can also be loaded from config.yaml ``model_aliases:`` section.
163
+ # ---------------------------------------------------------------------------
164
+
165
+ class DirectAlias(NamedTuple):
166
+ """Exact model mapping that bypasses catalog resolution."""
167
+ model: str
168
+ provider: str
169
+ base_url: str
170
+
171
+
172
+ # Built-in direct aliases (can be extended via config.yaml model_aliases:)
173
+ _BUILTIN_DIRECT_ALIASES: dict[str, DirectAlias] = {}
174
+
175
+ # Merged dict (builtins + user config); populated by _load_direct_aliases()
176
+ DIRECT_ALIASES: dict[str, DirectAlias] = {}
177
+
178
+
179
+ def _load_direct_aliases() -> dict[str, DirectAlias]:
180
+ """Load direct aliases from config.yaml ``model_aliases:`` section.
181
+
182
+ Config format::
183
+
184
+ model_aliases:
185
+ qwen:
186
+ model: "qwen3.5:397b"
187
+ provider: custom
188
+ base_url: "https://ollama.com/v1"
189
+ minimax:
190
+ model: "minimax-m2.7"
191
+ provider: custom
192
+ base_url: "https://ollama.com/v1"
193
+
194
+ Also reads ``model.aliases`` (set by ``hermes config set model.aliases.xxx``)
195
+ and converts simple string entries (``ds-flash: deepseek/deepseek-v4-flash``)
196
+ into DirectAlias objects. The provider is parsed from the ``provider/``
197
+ prefix in the value; if no slash, the current provider is used.
198
+ """
199
+ merged = dict(_BUILTIN_DIRECT_ALIASES)
200
+ try:
201
+ from hermes_cli.config import load_config
202
+ cfg = load_config()
203
+
204
+ # --- model_aliases (dict-based format) ---
205
+ user_aliases = cfg.get("model_aliases")
206
+ if isinstance(user_aliases, dict):
207
+ for name, entry in user_aliases.items():
208
+ if not isinstance(entry, dict):
209
+ continue
210
+ model = entry.get("model", "")
211
+ provider = entry.get("provider", "custom")
212
+ base_url = entry.get("base_url", "")
213
+ if model:
214
+ merged[name.strip().lower()] = DirectAlias(
215
+ model=model, provider=provider, base_url=base_url,
216
+ )
217
+
218
+ # --- model.aliases (string-based format, from config set) ---
219
+ model_section = cfg.get("model", {})
220
+ if isinstance(model_section, dict):
221
+ simple_aliases = model_section.get("aliases")
222
+ if isinstance(simple_aliases, dict):
223
+ current_provider = model_section.get("provider", "")
224
+ for name, value in simple_aliases.items():
225
+ if not isinstance(value, str) or not value.strip():
226
+ continue
227
+ key = name.strip().lower()
228
+ if key in merged:
229
+ continue # don't override explicit model_aliases entries
230
+ val = value.strip()
231
+ if "/" in val:
232
+ provider, model = val.split("/", 1)
233
+ else:
234
+ provider = current_provider
235
+ model = val
236
+ merged[key] = DirectAlias(
237
+ model=model.strip(),
238
+ provider=provider.strip() or current_provider,
239
+ base_url="",
240
+ )
241
+ except Exception:
242
+ pass
243
+ return merged
244
+
245
+
246
+ def _ensure_direct_aliases() -> None:
247
+ """Lazy-load direct aliases on first use.
248
+
249
+ Mutates the existing DIRECT_ALIASES dict in place rather than rebinding
250
+ the module attribute. This keeps `from hermes_cli.model_switch import
251
+ DIRECT_ALIASES` references valid in callers — rebinding would leave them
252
+ pointing at a stale empty dict.
253
+ """
254
+ if not DIRECT_ALIASES:
255
+ DIRECT_ALIASES.update(_load_direct_aliases())
256
+
257
+
258
+ # ---------------------------------------------------------------------------
259
+ # Result dataclasses
260
+ # ---------------------------------------------------------------------------
261
+
262
+ @dataclass
263
+ class ModelSwitchResult:
264
+ """Result of a model switch attempt."""
265
+
266
+ success: bool
267
+ new_model: str = ""
268
+ target_provider: str = ""
269
+ provider_changed: bool = False
270
+ api_key: str = ""
271
+ base_url: str = ""
272
+ api_mode: str = ""
273
+ error_message: str = ""
274
+ warning_message: str = ""
275
+ provider_label: str = ""
276
+ resolved_via_alias: str = ""
277
+ capabilities: Optional[ModelCapabilities] = None
278
+ model_info: Optional[ModelInfo] = None
279
+ is_global: bool = False
280
+
281
+
282
+ @dataclass
283
+ class CustomAutoResult:
284
+ """Result of switching to bare 'custom' provider with auto-detect."""
285
+
286
+ success: bool
287
+ model: str = ""
288
+ base_url: str = ""
289
+ api_key: str = ""
290
+ error_message: str = ""
291
+
292
+
293
+ # ---------------------------------------------------------------------------
294
+ # Flag parsing
295
+ # ---------------------------------------------------------------------------
296
+
297
+ def parse_model_flags(raw_args: str) -> tuple[str, str, bool]:
298
+ """Parse --provider and --global flags from /model command args.
299
+
300
+ Returns (model_input, explicit_provider, is_global).
301
+
302
+ Examples::
303
+
304
+ "sonnet" -> ("sonnet", "", False)
305
+ "sonnet --global" -> ("sonnet", "", True)
306
+ "sonnet --provider anthropic" -> ("sonnet", "anthropic", False)
307
+ "--provider my-ollama" -> ("", "my-ollama", False)
308
+ "sonnet --provider anthropic --global" -> ("sonnet", "anthropic", True)
309
+ """
310
+ is_global = False
311
+ explicit_provider = ""
312
+
313
+ # Normalize Unicode dashes (Telegram/iOS auto-converts -- to em/en dash)
314
+ # A single Unicode dash before a flag keyword becomes "--"
315
+ import re as _re
316
+ raw_args = _re.sub(r'[\u2012\u2013\u2014\u2015](provider|global)', r'--\1', raw_args)
317
+
318
+ # Extract --global
319
+ if "--global" in raw_args:
320
+ is_global = True
321
+ raw_args = raw_args.replace("--global", "").strip()
322
+
323
+ # Extract --provider <name>
324
+ parts = raw_args.split()
325
+ i = 0
326
+ filtered: list[str] = []
327
+ while i < len(parts):
328
+ if parts[i] == "--provider" and i + 1 < len(parts):
329
+ explicit_provider = parts[i + 1]
330
+ i += 2
331
+ else:
332
+ filtered.append(parts[i])
333
+ i += 1
334
+
335
+ model_input = " ".join(filtered).strip()
336
+ return (model_input, explicit_provider, is_global)
337
+
338
+
339
+ # ---------------------------------------------------------------------------
340
+ # Alias resolution
341
+ # ---------------------------------------------------------------------------
342
+
343
+ def _model_sort_key(model_id: str, prefix: str) -> tuple:
344
+ """Sort key for model version preference.
345
+
346
+ Extracts version numbers after the family prefix and returns a sort key
347
+ that prefers higher versions. Suffix tokens (``pro``, ``omni``, etc.)
348
+ are used as tiebreakers, with common quality indicators ranked.
349
+
350
+ Examples (with prefix ``"mimo"``)::
351
+
352
+ mimo-v2.5-pro → (-2.5, 0, 'pro') # highest version wins
353
+ mimo-v2.5 → (-2.5, 1, '') # no suffix = lower than pro
354
+ mimo-v2-pro → (-2.0, 0, 'pro')
355
+ mimo-v2-omni → (-2.0, 1, 'omni')
356
+ mimo-v2-flash → (-2.0, 1, 'flash')
357
+ """
358
+ # Strip the prefix (and optional "/" separator for aggregator slugs)
359
+ rest = model_id[len(prefix):]
360
+ if rest.startswith("/"):
361
+ rest = rest[1:]
362
+ rest = rest.lstrip("-").strip()
363
+
364
+ # Parse version and suffix from the remainder.
365
+ # "v2.5-pro" → version [2.5], suffix "pro"
366
+ # "-omni" → version [], suffix "omni"
367
+ # State machine: start → in_version → between → in_suffix
368
+ nums: list[float] = []
369
+ suffix_buf = ""
370
+ state = "start"
371
+ num_buf = ""
372
+
373
+ for ch in rest:
374
+ if state == "start":
375
+ if ch in "vV":
376
+ state = "in_version"
377
+ elif ch.isdigit():
378
+ state = "in_version"
379
+ num_buf += ch
380
+ elif ch in "-_.":
381
+ pass # skip separators before any content
382
+ else:
383
+ state = "in_suffix"
384
+ suffix_buf += ch
385
+ elif state == "in_version":
386
+ if ch.isdigit():
387
+ num_buf += ch
388
+ elif ch == ".":
389
+ if "." in num_buf:
390
+ # Second dot — flush current number, start new component
391
+ try:
392
+ nums.append(float(num_buf.rstrip(".")))
393
+ except ValueError:
394
+ pass
395
+ num_buf = ""
396
+ else:
397
+ num_buf += ch
398
+ elif ch in "-_.":
399
+ if num_buf:
400
+ try:
401
+ nums.append(float(num_buf.rstrip(".")))
402
+ except ValueError:
403
+ pass
404
+ num_buf = ""
405
+ state = "between"
406
+ else:
407
+ if num_buf:
408
+ try:
409
+ nums.append(float(num_buf.rstrip(".")))
410
+ except ValueError:
411
+ pass
412
+ num_buf = ""
413
+ state = "in_suffix"
414
+ suffix_buf += ch
415
+ elif state == "between":
416
+ if ch.isdigit():
417
+ state = "in_version"
418
+ num_buf = ch
419
+ elif ch in "vV":
420
+ state = "in_version"
421
+ elif ch in "-_.":
422
+ pass
423
+ else:
424
+ state = "in_suffix"
425
+ suffix_buf += ch
426
+ elif state == "in_suffix":
427
+ suffix_buf += ch
428
+
429
+ # Flush remaining buffer (strip trailing dots — "5.4." → "5.4")
430
+ if num_buf and state == "in_version":
431
+ try:
432
+ nums.append(float(num_buf.rstrip(".")))
433
+ except ValueError:
434
+ pass
435
+
436
+ suffix = suffix_buf.lower().strip("-_.")
437
+ suffix = suffix.strip()
438
+
439
+ # Negate versions so higher → sorts first
440
+ version_key = tuple(-n for n in nums)
441
+
442
+ # Suffix quality ranking: pro/max > (no suffix) > omni/flash/mini/lite
443
+ # Lower number = preferred
444
+ _SUFFIX_RANK = {"pro": 0, "max": 0, "plus": 0, "turbo": 0}
445
+ suffix_rank = _SUFFIX_RANK.get(suffix, 1)
446
+
447
+ return version_key + (suffix_rank, suffix)
448
+
449
+
450
+ def resolve_alias(
451
+ raw_input: str,
452
+ current_provider: str,
453
+ ) -> Optional[tuple[str, str, str]]:
454
+ """Resolve a short alias against the current provider's catalog.
455
+
456
+ Looks up *raw_input* in :data:`MODEL_ALIASES`, then searches the
457
+ current provider's models.dev catalog for the model whose ID starts
458
+ with ``vendor/family`` (or just ``family`` for non-aggregator
459
+ providers) and has the **highest version**.
460
+
461
+ Returns:
462
+ ``(provider, resolved_model_id, alias_name)`` if a match is
463
+ found on the current provider, or ``None`` if the alias doesn't
464
+ exist or no matching model is available.
465
+ """
466
+ key = raw_input.strip().lower()
467
+
468
+ # Check direct aliases first (exact model+provider+base_url mappings)
469
+ _ensure_direct_aliases()
470
+ direct = DIRECT_ALIASES.get(key)
471
+ if direct is not None:
472
+ return (direct.provider, direct.model, key)
473
+
474
+ # Reverse lookup: match by model ID so full names (e.g. "kimi-k2.5",
475
+ # "glm-4.7") route through direct aliases instead of falling through
476
+ # to the catalog/OpenRouter.
477
+ for alias_name, da in DIRECT_ALIASES.items():
478
+ if da.model.lower() == key:
479
+ return (da.provider, da.model, alias_name)
480
+
481
+ identity = MODEL_ALIASES.get(key)
482
+ if identity is None:
483
+ return None
484
+
485
+ vendor, family = identity
486
+
487
+ # Build catalog from models.dev, then merge in static _PROVIDER_MODELS
488
+ # entries that models.dev may be missing (e.g. newly added models not
489
+ # yet synced to the registry).
490
+ catalog = list_provider_models(current_provider)
491
+ try:
492
+ from hermes_cli.models import _PROVIDER_MODELS
493
+ static = _PROVIDER_MODELS.get(current_provider, [])
494
+ if static:
495
+ seen = {m.lower() for m in catalog}
496
+ for m in static:
497
+ if m.lower() not in seen:
498
+ catalog.append(m)
499
+ except Exception:
500
+ pass
501
+
502
+ # For aggregators, models are vendor/model-name format
503
+ aggregator = is_aggregator(current_provider)
504
+
505
+ if aggregator:
506
+ prefix = f"{vendor}/{family}".lower()
507
+ matches = [
508
+ mid for mid in catalog
509
+ if mid.lower().startswith(prefix)
510
+ ]
511
+ else:
512
+ family_lower = family.lower()
513
+ matches = [
514
+ mid for mid in catalog
515
+ if mid.lower().startswith(family_lower)
516
+ ]
517
+
518
+ if not matches:
519
+ return None
520
+
521
+ # Sort by version descending — prefer the latest/highest version
522
+ prefix_for_sort = f"{vendor}/{family}" if aggregator else family
523
+ matches.sort(key=lambda m: _model_sort_key(m, prefix_for_sort))
524
+ return (current_provider, matches[0], key)
525
+
526
+
527
+ def get_authenticated_provider_slugs(
528
+ current_provider: str = "",
529
+ user_providers: dict = None,
530
+ custom_providers: list | None = None,
531
+ ) -> list[str]:
532
+ """Return slugs of providers that have credentials.
533
+
534
+ Uses ``list_authenticated_providers()`` which is backed by the models.dev
535
+ in-memory cache (1 hr TTL) — no extra network cost.
536
+ """
537
+ try:
538
+ providers = list_authenticated_providers(
539
+ current_provider=current_provider,
540
+ user_providers=user_providers,
541
+ custom_providers=custom_providers,
542
+ max_models=0,
543
+ )
544
+ return [p["slug"] for p in providers]
545
+ except Exception:
546
+ return []
547
+
548
+
549
+ def _resolve_alias_fallback(
550
+ raw_input: str,
551
+ authenticated_providers: list[str] = (),
552
+ ) -> Optional[tuple[str, str, str]]:
553
+ """Try to resolve an alias on the user's authenticated providers.
554
+
555
+ Falls back to ``("openrouter", "nous")`` only when no authenticated
556
+ providers are supplied (backwards compat for non-interactive callers).
557
+ """
558
+ providers = authenticated_providers or ("openrouter", "nous")
559
+ for provider in providers:
560
+ result = resolve_alias(raw_input, provider)
561
+ if result is not None:
562
+ return result
563
+ return None
564
+
565
+
566
+ def resolve_display_context_length(
567
+ model: str,
568
+ provider: str,
569
+ base_url: str = "",
570
+ api_key: str = "",
571
+ model_info: Optional[ModelInfo] = None,
572
+ custom_providers: list | None = None,
573
+ config_context_length: int | None = None,
574
+ ) -> Optional[int]:
575
+ """Resolve the context length to show in /model output.
576
+
577
+ models.dev reports per-vendor context (e.g. gpt-5.5 = 1.05M on openai)
578
+ but provider-enforced limits can be lower (e.g. Codex OAuth caps the
579
+ same slug at 272k). The authoritative source is
580
+ ``agent.model_metadata.get_model_context_length`` which already knows
581
+ about Codex OAuth, Copilot, Nous, and falls back to models.dev for the
582
+ rest.
583
+
584
+ When ``custom_providers`` is provided, per-model ``context_length``
585
+ overrides from ``custom_providers[].models.<id>.context_length`` are
586
+ honored — this closes #15779 where ``/model`` switch ignored user-set
587
+ overrides.
588
+
589
+ Prefer the provider-aware value; fall back to ``model_info.context_window``
590
+ only if the resolver returns nothing.
591
+ """
592
+ try:
593
+ from agent.model_metadata import get_model_context_length
594
+ ctx = get_model_context_length(
595
+ model,
596
+ base_url=base_url or "",
597
+ api_key=api_key or "",
598
+ provider=provider or None,
599
+ custom_providers=custom_providers,
600
+ config_context_length=config_context_length,
601
+ )
602
+ if ctx:
603
+ return int(ctx)
604
+ except Exception:
605
+ pass
606
+ if model_info is not None and model_info.context_window:
607
+ return int(model_info.context_window)
608
+ return None
609
+
610
+
611
+ # ---------------------------------------------------------------------------
612
+ # Core model-switching pipeline
613
+ # ---------------------------------------------------------------------------
614
+
615
+ def switch_model(
616
+ raw_input: str,
617
+ current_provider: str,
618
+ current_model: str,
619
+ current_base_url: str = "",
620
+ current_api_key: str = "",
621
+ is_global: bool = False,
622
+ explicit_provider: str = "",
623
+ user_providers: dict = None,
624
+ custom_providers: list | None = None,
625
+ ) -> ModelSwitchResult:
626
+ """Core model-switching pipeline shared between CLI and gateway.
627
+
628
+ Resolution chain:
629
+
630
+ If --provider given:
631
+ a. Resolve provider via resolve_provider_full()
632
+ b. Resolve credentials
633
+ c. If model given, resolve alias on target provider or use as-is
634
+ d. If no model, auto-detect from endpoint
635
+
636
+ If no --provider:
637
+ a. Try alias resolution on current provider
638
+ b. If alias exists but not on current provider -> fallback
639
+ c. On aggregator, try vendor/model slug conversion
640
+ d. Aggregator catalog search
641
+ e. detect_provider_for_model() as last resort
642
+ f. Resolve credentials
643
+ g. Normalize model name for target provider
644
+
645
+ Finally:
646
+ h. Get full model metadata from models.dev
647
+ i. Build result
648
+
649
+ Args:
650
+ raw_input: The model name (after flag parsing).
651
+ current_provider: The currently active provider.
652
+ current_model: The currently active model name.
653
+ current_base_url: The currently active base URL.
654
+ current_api_key: The currently active API key.
655
+ is_global: Whether to persist the switch.
656
+ explicit_provider: From --provider flag (empty = no explicit provider).
657
+ user_providers: The ``providers:`` dict from config.yaml (for user endpoints).
658
+ custom_providers: The ``custom_providers:`` list from config.yaml.
659
+
660
+ Returns:
661
+ ModelSwitchResult with all information the caller needs.
662
+ """
663
+ from hermes_cli.models import (
664
+ copilot_model_api_mode,
665
+ detect_provider_for_model,
666
+ validate_requested_model,
667
+ opencode_model_api_mode,
668
+ )
669
+ from hermes_cli.runtime_provider import resolve_runtime_provider
670
+
671
+ resolved_alias = ""
672
+ new_model = raw_input.strip()
673
+ target_provider = current_provider
674
+
675
+ # =================================================================
676
+ # PATH A: Explicit --provider given
677
+ # =================================================================
678
+ if explicit_provider:
679
+ # Resolve the provider
680
+ pdef = resolve_provider_full(
681
+ explicit_provider,
682
+ user_providers,
683
+ custom_providers,
684
+ )
685
+ if pdef is None:
686
+ _switch_err = (
687
+ f"Unknown provider '{explicit_provider}'. "
688
+ f"Check 'hermes model' for available providers, or define it "
689
+ f"in config.yaml under 'providers:'."
690
+ )
691
+ # Check for common config issues that cause provider resolution failures
692
+ try:
693
+ from hermes_cli.config import validate_config_structure
694
+ _cfg_issues = validate_config_structure()
695
+ if _cfg_issues:
696
+ _switch_err += "\n\nRun 'hermes doctor' — config issues detected:"
697
+ for _ci in _cfg_issues[:3]:
698
+ _switch_err += f"\n • {_ci.message}"
699
+ except Exception:
700
+ pass
701
+ return ModelSwitchResult(
702
+ success=False,
703
+ is_global=is_global,
704
+ error_message=_switch_err,
705
+ )
706
+
707
+ target_provider = pdef.id
708
+
709
+ # If no model specified, try auto-detect from endpoint
710
+ if not new_model:
711
+ if pdef.base_url:
712
+ from hermes_cli.runtime_provider import _auto_detect_local_model
713
+ detected = _auto_detect_local_model(pdef.base_url)
714
+ if detected:
715
+ new_model = detected
716
+ else:
717
+ return ModelSwitchResult(
718
+ success=False,
719
+ target_provider=target_provider,
720
+ provider_label=pdef.name,
721
+ is_global=is_global,
722
+ error_message=(
723
+ f"No model detected on {pdef.name} ({pdef.base_url}). "
724
+ f"Specify the model explicitly: /model <model-name> --provider {explicit_provider}"
725
+ ),
726
+ )
727
+ else:
728
+ return ModelSwitchResult(
729
+ success=False,
730
+ target_provider=target_provider,
731
+ provider_label=pdef.name,
732
+ is_global=is_global,
733
+ error_message=(
734
+ f"Provider '{pdef.name}' has no base URL configured. "
735
+ f"Specify a model: /model <model-name> --provider {explicit_provider}"
736
+ ),
737
+ )
738
+
739
+ # Resolve alias on the TARGET provider
740
+ alias_result = resolve_alias(new_model, target_provider)
741
+ if alias_result is not None:
742
+ _, new_model, resolved_alias = alias_result
743
+
744
+ # =================================================================
745
+ # PATH B: No explicit provider — resolve from model input
746
+ # =================================================================
747
+ else:
748
+ # --- Step a: Try alias resolution on current provider ---
749
+ alias_result = resolve_alias(raw_input, current_provider)
750
+
751
+ if alias_result is not None:
752
+ target_provider, new_model, resolved_alias = alias_result
753
+ logger.debug(
754
+ "Alias '%s' resolved to %s on %s",
755
+ resolved_alias, new_model, target_provider,
756
+ )
757
+ else:
758
+ # --- Step b: Alias exists but not on current provider -> fallback ---
759
+ key = raw_input.strip().lower()
760
+ if key in MODEL_ALIASES:
761
+ authed = get_authenticated_provider_slugs(
762
+ current_provider=current_provider,
763
+ user_providers=user_providers,
764
+ custom_providers=custom_providers,
765
+ )
766
+ fallback_result = _resolve_alias_fallback(raw_input, authed)
767
+ if fallback_result is not None:
768
+ target_provider, new_model, resolved_alias = fallback_result
769
+ logger.debug(
770
+ "Alias '%s' resolved via fallback to %s on %s",
771
+ resolved_alias, new_model, target_provider,
772
+ )
773
+ else:
774
+ identity = MODEL_ALIASES[key]
775
+ return ModelSwitchResult(
776
+ success=False,
777
+ is_global=is_global,
778
+ error_message=(
779
+ f"Alias '{key}' maps to {identity.vendor}/{identity.family} "
780
+ f"but no matching model was found in any provider catalog. "
781
+ f"Try specifying the full model name."
782
+ ),
783
+ )
784
+ else:
785
+ # --- Step c: On aggregator, convert vendor:model to vendor/model ---
786
+ # Only convert when there's no slash — a slash means the name
787
+ # is already in vendor/model format and the colon is a variant
788
+ # tag (:free, :extended, :fast) that must be preserved.
789
+ colon_pos = raw_input.find(":")
790
+ if colon_pos > 0 and "/" not in raw_input and is_aggregator(current_provider):
791
+ left = raw_input[:colon_pos].strip().lower()
792
+ right = raw_input[colon_pos + 1:].strip()
793
+ if left and right:
794
+ # Colons become slashes for aggregator slugs
795
+ new_model = f"{left}/{right}"
796
+ logger.debug(
797
+ "Converted vendor:model '%s' to aggregator slug '%s'",
798
+ raw_input, new_model,
799
+ )
800
+
801
+ # --- Step d: Aggregator catalog search ---
802
+ # Track whether the live catalog of the CURRENT provider resolved the
803
+ # model — if so, step e must not second-guess and switch providers.
804
+ # Critical for flat-namespace resellers like opencode-go / opencode-zen
805
+ # whose live /v1/models returns bare IDs (e.g. "deepseek-v4-flash") that
806
+ # coincidentally match entries in native providers' static catalogs.
807
+ resolved_in_current_catalog = False
808
+ if is_aggregator(target_provider) and not resolved_alias:
809
+ catalog = list_provider_models(target_provider)
810
+ if catalog:
811
+ new_model_lower = new_model.lower()
812
+ for mid in catalog:
813
+ if mid.lower() == new_model_lower:
814
+ new_model = mid
815
+ resolved_in_current_catalog = True
816
+ break
817
+ else:
818
+ for mid in catalog:
819
+ if "/" in mid:
820
+ _, bare = mid.split("/", 1)
821
+ if bare.lower() == new_model_lower:
822
+ new_model = mid
823
+ resolved_in_current_catalog = True
824
+ break
825
+
826
+ # --- Step e: detect_provider_for_model() as last resort ---
827
+ _base = current_base_url or ""
828
+ is_custom = current_provider in {"custom", "local"} or (
829
+ "localhost" in _base or "127.0.0.1" in _base
830
+ )
831
+
832
+ if (
833
+ target_provider == current_provider
834
+ and not is_custom
835
+ and not resolved_alias
836
+ and not resolved_in_current_catalog
837
+ ):
838
+ detected = detect_provider_for_model(new_model, current_provider)
839
+ if detected:
840
+ target_provider, new_model = detected
841
+
842
+ # =================================================================
843
+ # COMMON PATH: Resolve credentials, normalize, get metadata
844
+ # =================================================================
845
+
846
+ provider_changed = target_provider != current_provider
847
+ provider_label = get_label(target_provider)
848
+ if target_provider.startswith("custom:"):
849
+ custom_pdef = resolve_provider_full(
850
+ target_provider,
851
+ user_providers,
852
+ custom_providers,
853
+ )
854
+ if custom_pdef is not None:
855
+ provider_label = custom_pdef.name
856
+
857
+ # --- Resolve credentials ---
858
+ api_key = current_api_key
859
+ base_url = current_base_url
860
+ api_mode = ""
861
+
862
+ if provider_changed or explicit_provider:
863
+ try:
864
+ runtime = resolve_runtime_provider(
865
+ requested=target_provider,
866
+ target_model=new_model,
867
+ )
868
+ api_key = runtime.get("api_key", "")
869
+ base_url = runtime.get("base_url", "")
870
+ api_mode = runtime.get("api_mode", "")
871
+ except Exception as e:
872
+ return ModelSwitchResult(
873
+ success=False,
874
+ target_provider=target_provider,
875
+ provider_label=provider_label,
876
+ is_global=is_global,
877
+ error_message=(
878
+ f"Could not resolve credentials for provider "
879
+ f"'{provider_label}': {e}"
880
+ ),
881
+ )
882
+ else:
883
+ try:
884
+ runtime = resolve_runtime_provider(
885
+ requested=current_provider,
886
+ target_model=new_model,
887
+ )
888
+ # If resolution fell through to "custom" (e.g. named custom provider like
889
+ # "ollama-launch" that resolve_runtime_provider doesn't know), keep existing
890
+ # credentials. Otherwise use the resolved values (picks up credential rotation,
891
+ # base_url adjustments for OpenCode, etc.).
892
+ api_key = runtime.get("api_key", "")
893
+ base_url = runtime.get("base_url", "")
894
+ api_mode = runtime.get("api_mode", "")
895
+ except Exception:
896
+ pass
897
+
898
+ # --- Direct alias override: use exact base_url from the alias if set ---
899
+ if resolved_alias:
900
+ _ensure_direct_aliases()
901
+ _da = DIRECT_ALIASES.get(resolved_alias)
902
+ if _da is not None and _da.base_url:
903
+ base_url = _da.base_url
904
+ api_mode = "" # clear so determine_api_mode re-detects from URL
905
+ if not api_key:
906
+ api_key = "no-key-required"
907
+
908
+ # --- Normalize model name for target provider ---
909
+ new_model = normalize_model_for_provider(new_model, target_provider)
910
+
911
+ # --- Validate ---
912
+ try:
913
+ validation = validate_requested_model(
914
+ new_model,
915
+ target_provider,
916
+ api_key=api_key,
917
+ base_url=base_url,
918
+ api_mode=api_mode or None,
919
+ )
920
+ except Exception as e:
921
+ validation = {
922
+ "accepted": False,
923
+ "persist": False,
924
+ "recognized": False,
925
+ "message": f"Could not validate `{new_model}`: {e}",
926
+ }
927
+
928
+ # Override rejection if model is in the user's saved provider config.
929
+ # API /v1/models may not list cloud/aliased models even though the server supports them.
930
+ if not validation.get("accepted"):
931
+ override = False
932
+ if user_providers:
933
+ # user_providers is a dict: {provider_slug: config_dict}
934
+ for slug, cfg in user_providers.items():
935
+ if slug == target_provider:
936
+ cfg_models = cfg.get("models", {})
937
+ # Direct membership works for dict (keys) and list (strings)
938
+ if new_model in cfg_models:
939
+ override = True
940
+ break
941
+ # Also accept if models is a list of dicts with 'name' field
942
+ if isinstance(cfg_models, list):
943
+ if any(m.get("name") == new_model for m in cfg_models if isinstance(m, dict)):
944
+ override = True
945
+ break
946
+ # Also check custom_providers list — models declared there should be accepted
947
+ # even if the remote /v1/models endpoint doesn't list them.
948
+ if not override and custom_providers and isinstance(custom_providers, list):
949
+ for entry in custom_providers:
950
+ if not isinstance(entry, dict):
951
+ continue
952
+ # Match by provider slug (custom:<name>) or by base_url
953
+ entry_name = entry.get("name", "")
954
+ entry_slug = f"custom:{entry_name}" if entry_name else ""
955
+ entry_url = entry.get("base_url", "")
956
+ if entry_slug == target_provider or entry_url == base_url:
957
+ # Check if the requested model matches the entry's model
958
+ entry_model = entry.get("model", "")
959
+ entry_models = entry.get("models", {})
960
+ if new_model == entry_model:
961
+ override = True
962
+ break
963
+ if isinstance(entry_models, dict) and new_model in entry_models:
964
+ override = True
965
+ break
966
+ if override:
967
+ validation = {"accepted": True, "persist": True, "recognized": False, "message": validation.get("message", "")}
968
+ else:
969
+ msg = validation.get("message", "Invalid model")
970
+ return ModelSwitchResult(
971
+ success=False,
972
+ new_model=new_model,
973
+ target_provider=target_provider,
974
+ provider_label=provider_label,
975
+ is_global=is_global,
976
+ error_message=msg,
977
+ )
978
+
979
+ # Apply auto-correction if validation found a closer match
980
+ if validation.get("corrected_model"):
981
+ new_model = validation["corrected_model"]
982
+
983
+ # --- Copilot api_mode override ---
984
+ if target_provider in {"copilot", "github-copilot"}:
985
+ api_mode = copilot_model_api_mode(new_model, api_key=api_key)
986
+
987
+ # --- OpenCode api_mode override ---
988
+ if target_provider in {"opencode-zen", "opencode-go", "opencode"}:
989
+ api_mode = opencode_model_api_mode(target_provider, new_model)
990
+
991
+ # --- Determine api_mode if not already set ---
992
+ if not api_mode:
993
+ api_mode = determine_api_mode(target_provider, base_url)
994
+
995
+ # OpenCode base URLs end with /v1 for OpenAI-compatible models, but the
996
+ # Anthropic SDK prepends its own /v1/messages to the base_url. Strip the
997
+ # trailing /v1 so the SDK constructs the correct path (e.g.
998
+ # https://opencode.ai/zen/go/v1/messages instead of .../v1/v1/messages).
999
+ # Mirrors the same logic in hermes_cli.runtime_provider.resolve_runtime_provider;
1000
+ # without it, /model switches into an anthropic_messages-routed OpenCode
1001
+ # model (e.g. `/model minimax-m2.7` on opencode-go, `/model claude-sonnet-4-6`
1002
+ # on opencode-zen) hit a double /v1 and returned OpenCode's website 404 page.
1003
+ if (
1004
+ api_mode == "anthropic_messages"
1005
+ and target_provider in {"opencode-zen", "opencode-go"}
1006
+ and isinstance(base_url, str)
1007
+ and base_url
1008
+ ):
1009
+ base_url = re.sub(r"/v1/?$", "", base_url)
1010
+
1011
+ # --- Get capabilities (legacy) ---
1012
+ capabilities = get_model_capabilities(target_provider, new_model)
1013
+
1014
+ # --- Get full model info from models.dev ---
1015
+ model_info = get_model_info(target_provider, new_model)
1016
+
1017
+ # --- Collect warnings ---
1018
+ warnings: list[str] = []
1019
+ if validation.get("message"):
1020
+ warnings.append(validation["message"])
1021
+ hermes_warn = _check_hermes_model_warning(new_model)
1022
+ if hermes_warn:
1023
+ warnings.append(hermes_warn)
1024
+
1025
+ # --- Build result ---
1026
+ return ModelSwitchResult(
1027
+ success=True,
1028
+ new_model=new_model,
1029
+ target_provider=target_provider,
1030
+ provider_changed=provider_changed,
1031
+ api_key=api_key,
1032
+ base_url=base_url,
1033
+ api_mode=api_mode,
1034
+ warning_message=" | ".join(warnings) if warnings else "",
1035
+ provider_label=provider_label,
1036
+ resolved_via_alias=resolved_alias,
1037
+ capabilities=capabilities,
1038
+ model_info=model_info,
1039
+ is_global=is_global,
1040
+ )
1041
+
1042
+
1043
+ # ---------------------------------------------------------------------------
1044
+ # Authenticated providers listing (for /model no-args display)
1045
+ # ---------------------------------------------------------------------------
1046
+
1047
+ def list_authenticated_providers(
1048
+ current_provider: str = "",
1049
+ current_base_url: str = "",
1050
+ user_providers: dict = None,
1051
+ custom_providers: list | None = None,
1052
+ max_models: int = 8,
1053
+ current_model: str = "",
1054
+ ) -> List[dict]:
1055
+ """Detect which providers have credentials and list their curated models.
1056
+
1057
+ Uses the curated model lists from hermes_cli/models.py (OPENROUTER_MODELS,
1058
+ _PROVIDER_MODELS) — NOT the full models.dev catalog. These are hand-picked
1059
+ agentic models that work well as agent backends.
1060
+
1061
+ Returns a list of dicts, each with:
1062
+ - slug: str — the --provider value to use
1063
+ - name: str — display name
1064
+ - is_current: bool
1065
+ - is_user_defined: bool
1066
+ - models: list[str] — curated model IDs (up to max_models)
1067
+ - total_models: int — total curated count
1068
+ - source: str — "built-in", "models.dev", "user-config"
1069
+
1070
+ Only includes providers that have API keys set or are user-defined endpoints.
1071
+ """
1072
+ import os
1073
+ from agent.models_dev import (
1074
+ PROVIDER_TO_MODELS_DEV,
1075
+ fetch_models_dev,
1076
+ get_provider_info as _mdev_pinfo,
1077
+ )
1078
+ from hermes_cli.auth import PROVIDER_REGISTRY
1079
+ from hermes_cli.models import (
1080
+ OPENROUTER_MODELS, _PROVIDER_MODELS,
1081
+ _MODELS_DEV_PREFERRED, _merge_with_models_dev, provider_model_ids,
1082
+ get_curated_nous_model_ids,
1083
+ )
1084
+
1085
+ results: List[dict] = []
1086
+ seen_slugs: set = set() # lowercase-normalized to catch case variants (#9545)
1087
+ seen_mdev_ids: set = set() # prevent duplicate entries for aliases (e.g. kimi-coding + kimi-coding-cn)
1088
+ # Effective base URLs of every built-in row we emit (normalized lower+rstrip).
1089
+ # Section 4 uses this to hide ``custom_providers`` entries that point at the
1090
+ # same endpoint as a built-in (e.g. a user-defined "my-dashscope" on
1091
+ # https://coding-intl.dashscope.aliyuncs.com/v1 collides with the built-in
1092
+ # alibaba-coding-plan row when DASHSCOPE_API_KEY is present). Fixes #16970.
1093
+ _builtin_endpoints: set = set()
1094
+
1095
+ def _norm_url(url: str) -> str:
1096
+ return str(url or "").strip().rstrip("/").lower()
1097
+
1098
+ def _record_builtin_endpoint(slug: str) -> None:
1099
+ """Record the effective base URL for a built-in provider row.
1100
+
1101
+ Prefers the live env-override (e.g. DASHSCOPE_BASE_URL) over the
1102
+ static inference_base_url so the dedup matches what a user typing
1103
+ that URL into custom_providers would actually hit."""
1104
+ try:
1105
+ from hermes_cli.auth import PROVIDER_REGISTRY as _reg
1106
+ except Exception:
1107
+ return
1108
+ pcfg = _reg.get(slug)
1109
+ if not pcfg:
1110
+ return
1111
+ url = ""
1112
+ if getattr(pcfg, "base_url_env_var", ""):
1113
+ url = os.environ.get(pcfg.base_url_env_var, "") or ""
1114
+ if not url:
1115
+ url = getattr(pcfg, "inference_base_url", "") or ""
1116
+ normed = _norm_url(url)
1117
+ if normed:
1118
+ _builtin_endpoints.add(normed)
1119
+
1120
+ def _has_fast_aws_sdk_signal() -> bool:
1121
+ """Return True when explicit AWS auth config is present.
1122
+
1123
+ This intentionally avoids botocore's full credential chain. Provider
1124
+ picker/model-switch discovery can run for non-Bedrock providers, and
1125
+ botocore may otherwise probe EC2 IMDS (169.254.169.254) on local
1126
+ machines before returning no credentials.
1127
+ """
1128
+ if os.environ.get("AWS_BEARER_TOKEN_BEDROCK", "").strip():
1129
+ return True
1130
+ if (
1131
+ os.environ.get("AWS_ACCESS_KEY_ID", "").strip()
1132
+ and os.environ.get("AWS_SECRET_ACCESS_KEY", "").strip()
1133
+ ):
1134
+ return True
1135
+ return any(
1136
+ os.environ.get(name, "").strip()
1137
+ for name in (
1138
+ "AWS_PROFILE",
1139
+ "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI",
1140
+ "AWS_CONTAINER_CREDENTIALS_FULL_URI",
1141
+ "AWS_WEB_IDENTITY_TOKEN_FILE",
1142
+ )
1143
+ )
1144
+
1145
+ def _has_aws_sdk_creds_for_listing(slug: str) -> bool:
1146
+ """Credential check for AWS SDK providers in non-runtime discovery."""
1147
+ slug_norm = str(slug or "").strip().lower()
1148
+ current_norm = str(current_provider or "").strip().lower()
1149
+ if _has_fast_aws_sdk_signal():
1150
+ return True
1151
+ if slug_norm != current_norm:
1152
+ return False
1153
+ try:
1154
+ from agent.bedrock_adapter import has_aws_credentials
1155
+ return bool(has_aws_credentials())
1156
+ except Exception:
1157
+ return False
1158
+
1159
+ data = fetch_models_dev()
1160
+
1161
+ # Build curated model lists keyed by hermes provider ID
1162
+ curated: dict[str, list[str]] = dict(_PROVIDER_MODELS)
1163
+ curated["openrouter"] = [mid for mid, _ in OPENROUTER_MODELS]
1164
+ # "nous" pulls from the remote model-catalog manifest published at
1165
+ # https://hermes-agent.nousresearch.com/docs/api/model-catalog.json so
1166
+ # newly added Portal models surface in the /model picker without
1167
+ # requiring a Hermes release. Falls back to the in-repo
1168
+ # _PROVIDER_MODELS["nous"] snapshot when the manifest is unreachable.
1169
+ curated["nous"] = get_curated_nous_model_ids()
1170
+ # Ollama Cloud uses dynamic discovery (no static curated list)
1171
+ if "ollama-cloud" not in curated:
1172
+ from hermes_cli.models import fetch_ollama_cloud_models
1173
+ curated["ollama-cloud"] = fetch_ollama_cloud_models()
1174
+ # LM Studio has no static catalog — probe its native /api/v1/models
1175
+ # endpoint live so the picker reflects whatever the user has loaded.
1176
+ # Base URL precedence: LM_BASE_URL env var > active config's base_url
1177
+ # (when current provider is lmstudio) > 127.0.0.1 default.
1178
+ # On auth rejection or unreachable server, fall back to the caller-supplied
1179
+ # current model so the picker still shows something when offline / mis-keyed.
1180
+ if "lmstudio" not in curated and (
1181
+ os.environ.get("LM_API_KEY") or os.environ.get("LM_BASE_URL") or current_provider.strip().lower() == "lmstudio"
1182
+ ):
1183
+ from hermes_cli.models import fetch_lmstudio_models
1184
+ from hermes_cli.auth import AuthError
1185
+ is_current_lmstudio = current_provider.strip().lower() == "lmstudio"
1186
+ lm_base = (
1187
+ os.environ.get("LM_BASE_URL")
1188
+ or (current_base_url if is_current_lmstudio and current_base_url else None)
1189
+ or "http://127.0.0.1:1234/v1"
1190
+ )
1191
+ try:
1192
+ live = fetch_lmstudio_models(
1193
+ api_key=os.environ.get("LM_API_KEY", ""),
1194
+ base_url=lm_base,
1195
+ timeout=1.5, # Smaller timeout for picker
1196
+ )
1197
+ except AuthError:
1198
+ live = []
1199
+ if not live and is_current_lmstudio and current_model:
1200
+ live = [current_model]
1201
+ curated["lmstudio"] = live
1202
+
1203
+ # --- 1. Check Hermes-mapped providers ---
1204
+ for hermes_id, mdev_id in PROVIDER_TO_MODELS_DEV.items():
1205
+ # Skip aliases that map to the same models.dev provider (e.g.
1206
+ # kimi-coding and kimi-coding-cn both → kimi-for-coding).
1207
+ # The first one with valid credentials wins (#10526).
1208
+ if mdev_id in seen_mdev_ids:
1209
+ continue
1210
+ pdata = data.get(mdev_id)
1211
+ if not isinstance(pdata, dict):
1212
+ continue
1213
+
1214
+ # Prefer auth.py PROVIDER_REGISTRY for env var names — it's our
1215
+ # source of truth. models.dev can have wrong mappings (e.g.
1216
+ # minimax-cn → MINIMAX_API_KEY instead of MINIMAX_CN_API_KEY).
1217
+ pconfig = PROVIDER_REGISTRY.get(hermes_id)
1218
+ # Skip non-API-key auth providers here — they are handled in
1219
+ # section 2 (HERMES_OVERLAYS) with proper auth store checking.
1220
+ if pconfig and pconfig.auth_type != "api_key":
1221
+ continue
1222
+ if pconfig and pconfig.api_key_env_vars:
1223
+ env_vars = list(pconfig.api_key_env_vars)
1224
+ else:
1225
+ env_vars = pdata.get("env", [])
1226
+ if not isinstance(env_vars, list):
1227
+ continue
1228
+
1229
+ # Check if any env var is set
1230
+ has_creds = any(os.environ.get(ev) for ev in env_vars)
1231
+ if not has_creds:
1232
+ try:
1233
+ from hermes_cli.auth import _load_auth_store
1234
+ store = _load_auth_store()
1235
+ if store and hermes_id in store.get("credential_pool", {}):
1236
+ has_creds = True
1237
+ except Exception:
1238
+ pass
1239
+ if not has_creds:
1240
+ continue
1241
+
1242
+ # Use curated list, falling back to models.dev if no curated list.
1243
+ # For preferred providers, merge models.dev entries into the curated
1244
+ # catalog so newly released models (e.g. mimo-v2.5-pro on opencode-go)
1245
+ # show up in the picker without requiring a Hermes release.
1246
+ model_ids = curated.get(hermes_id, [])
1247
+ if hermes_id in _MODELS_DEV_PREFERRED:
1248
+ model_ids = _merge_with_models_dev(hermes_id, model_ids)
1249
+ total = len(model_ids)
1250
+ top = model_ids[:max_models]
1251
+
1252
+ slug = hermes_id
1253
+ pinfo = _mdev_pinfo(mdev_id)
1254
+ display_name = pinfo.name if pinfo else mdev_id
1255
+
1256
+ results.append({
1257
+ "slug": slug,
1258
+ "name": display_name,
1259
+ "is_current": slug == current_provider or mdev_id == current_provider,
1260
+ "is_user_defined": False,
1261
+ "models": top,
1262
+ "total_models": total,
1263
+ "source": "built-in",
1264
+ })
1265
+ seen_slugs.add(slug.lower())
1266
+ seen_mdev_ids.add(mdev_id)
1267
+ _record_builtin_endpoint(slug)
1268
+
1269
+ # --- 2. Check Hermes-only providers (nous, openai-codex, copilot, opencode-go) ---
1270
+ from hermes_cli.providers import HERMES_OVERLAYS
1271
+ from hermes_cli.auth import PROVIDER_REGISTRY as _auth_registry
1272
+
1273
+ # Build reverse mapping: models.dev ID → Hermes provider ID.
1274
+ # HERMES_OVERLAYS keys may be models.dev IDs (e.g. "github-copilot")
1275
+ # while _PROVIDER_MODELS and config.yaml use Hermes IDs ("copilot").
1276
+ _mdev_to_hermes = {v: k for k, v in PROVIDER_TO_MODELS_DEV.items()}
1277
+
1278
+ for pid, overlay in HERMES_OVERLAYS.items():
1279
+ if pid.lower() in seen_slugs:
1280
+ continue
1281
+
1282
+ # Resolve Hermes slug — e.g. "github-copilot" → "copilot"
1283
+ hermes_slug = _mdev_to_hermes.get(pid, pid)
1284
+ if hermes_slug.lower() in seen_slugs:
1285
+ continue
1286
+
1287
+ # Check if credentials exist
1288
+ has_creds = False
1289
+ if overlay.auth_type == "aws_sdk":
1290
+ has_creds = _has_aws_sdk_creds_for_listing(hermes_slug)
1291
+ elif overlay.extra_env_vars:
1292
+ has_creds = any(os.environ.get(ev) for ev in overlay.extra_env_vars)
1293
+ # Also check api_key_env_vars from PROVIDER_REGISTRY for api_key auth_type
1294
+ if not has_creds and overlay.auth_type == "api_key":
1295
+ for _key in (pid, hermes_slug):
1296
+ pcfg = _auth_registry.get(_key)
1297
+ if pcfg and pcfg.api_key_env_vars:
1298
+ if any(os.environ.get(ev) for ev in pcfg.api_key_env_vars):
1299
+ has_creds = True
1300
+ break
1301
+ # Check auth store and credential pool for non-env-var credentials.
1302
+ # This applies to OAuth providers AND api_key providers that also
1303
+ # support OAuth (e.g. anthropic supports both API key and Claude Code
1304
+ # OAuth via external credential files).
1305
+ if not has_creds:
1306
+ try:
1307
+ from hermes_cli.auth import _load_auth_store
1308
+ store = _load_auth_store()
1309
+ providers_store = store.get("providers", {})
1310
+ if store and (pid in providers_store or hermes_slug in providers_store):
1311
+ has_creds = True
1312
+ except Exception as exc:
1313
+ logger.debug("Auth store check failed for %s: %s", pid, exc)
1314
+ # Fallback: check the credential pool with full auto-seeding.
1315
+ # This catches credentials that exist in external stores (e.g.
1316
+ # Codex CLI ~/.codex/auth.json) which _seed_from_singletons()
1317
+ # imports on demand but aren't in the raw auth.json yet.
1318
+ if not has_creds:
1319
+ try:
1320
+ from agent.credential_pool import load_pool
1321
+ pool = load_pool(hermes_slug)
1322
+ if pool.has_credentials():
1323
+ has_creds = True
1324
+ except Exception as exc:
1325
+ logger.debug("Credential pool check failed for %s: %s", hermes_slug, exc)
1326
+ # Fallback: check external credential files directly.
1327
+ # The credential pool gates anthropic behind
1328
+ # is_provider_explicitly_configured() to prevent auxiliary tasks
1329
+ # from silently consuming Claude Code tokens (PR #4210).
1330
+ # But the /model picker is discovery-oriented — we WANT to show
1331
+ # providers the user can switch to, even if they aren't currently
1332
+ # configured.
1333
+ if not has_creds and hermes_slug == "anthropic":
1334
+ try:
1335
+ from agent.anthropic_adapter import (
1336
+ read_claude_code_credentials,
1337
+ read_hermes_oauth_credentials,
1338
+ )
1339
+ hermes_creds = read_hermes_oauth_credentials()
1340
+ cc_creds = read_claude_code_credentials()
1341
+ if (hermes_creds and hermes_creds.get("accessToken")) or \
1342
+ (cc_creds and cc_creds.get("accessToken")):
1343
+ has_creds = True
1344
+ except Exception as exc:
1345
+ logger.debug("Anthropic external creds check failed: %s", exc)
1346
+ if not has_creds:
1347
+ continue
1348
+
1349
+ if hermes_slug in {"openai-codex", "copilot", "copilot-acp"}:
1350
+ # Use live OAuth-backed discovery so the gateway /model picker
1351
+ # matches what the user's authenticated Codex/Copilot backend
1352
+ # actually serves — including ChatGPT-Pro-only Codex slugs
1353
+ # (e.g. gpt-5.3-codex-spark) that aren't in the static curated
1354
+ # catalog. ``provider_model_ids()`` falls back to the curated
1355
+ # list when the live endpoint is unreachable, so this is safe
1356
+ # for unauthenticated and offline cases too.
1357
+ model_ids = provider_model_ids(hermes_slug)
1358
+ # For aws_sdk providers (bedrock), use live discovery so the list
1359
+ # reflects the active region (eu.*, ap.*) not the static us.* list.
1360
+ elif overlay.auth_type == "aws_sdk":
1361
+ try:
1362
+ from agent.bedrock_adapter import bedrock_model_ids_or_none
1363
+ _ids = bedrock_model_ids_or_none()
1364
+ model_ids = _ids if _ids is not None else (curated.get(hermes_slug, []) or curated.get(pid, []))
1365
+ except Exception:
1366
+ model_ids = curated.get(hermes_slug, []) or curated.get(pid, [])
1367
+ else:
1368
+ # Use curated list — look up by Hermes slug, fall back to overlay key
1369
+ model_ids = curated.get(hermes_slug, []) or curated.get(pid, [])
1370
+ # Merge with models.dev for preferred providers (same rationale as above).
1371
+ if hermes_slug in _MODELS_DEV_PREFERRED:
1372
+ model_ids = _merge_with_models_dev(hermes_slug, model_ids)
1373
+ total = len(model_ids)
1374
+ top = model_ids[:max_models]
1375
+
1376
+ results.append({
1377
+ "slug": hermes_slug,
1378
+ "name": get_label(hermes_slug),
1379
+ "is_current": hermes_slug == current_provider or pid == current_provider,
1380
+ "is_user_defined": False,
1381
+ "models": top,
1382
+ "total_models": total,
1383
+ "source": "hermes",
1384
+ })
1385
+ seen_slugs.add(pid.lower())
1386
+ seen_slugs.add(hermes_slug.lower())
1387
+ _record_builtin_endpoint(hermes_slug)
1388
+
1389
+ # --- 2b. Cross-check canonical provider list ---
1390
+ # Catches providers that are in CANONICAL_PROVIDERS but weren't found
1391
+ # in PROVIDER_TO_MODELS_DEV or HERMES_OVERLAYS (keeps /model in sync
1392
+ # with `hermes model`).
1393
+ try:
1394
+ from hermes_cli.models import CANONICAL_PROVIDERS as _canon_provs
1395
+ except ImportError:
1396
+ _canon_provs = []
1397
+
1398
+ for _cp in _canon_provs:
1399
+ if _cp.slug.lower() in seen_slugs:
1400
+ continue
1401
+
1402
+ # Check credentials via PROVIDER_REGISTRY (auth.py)
1403
+ _cp_config = _auth_registry.get(_cp.slug)
1404
+ _cp_has_creds = False
1405
+ if _cp_config and _cp_config.api_key_env_vars:
1406
+ _cp_has_creds = any(os.environ.get(ev) for ev in _cp_config.api_key_env_vars)
1407
+ # Also check auth store and credential pool
1408
+ if not _cp_has_creds:
1409
+ try:
1410
+ from hermes_cli.auth import _load_auth_store
1411
+ _cp_store = _load_auth_store()
1412
+ _cp_providers_store = _cp_store.get("providers", {})
1413
+ if _cp_store and _cp.slug in _cp_providers_store:
1414
+ _cp_has_creds = True
1415
+ except Exception:
1416
+ pass
1417
+ if not _cp_has_creds:
1418
+ try:
1419
+ from agent.credential_pool import load_pool
1420
+ _cp_pool = load_pool(_cp.slug)
1421
+ if _cp_pool.has_credentials():
1422
+ _cp_has_creds = True
1423
+ except Exception:
1424
+ pass
1425
+
1426
+ # Special case: aws_sdk auth (bedrock) — no API key env vars,
1427
+ # credentials come from the boto3 credential chain (env vars,
1428
+ # ~/.aws/credentials, instance roles, etc.)
1429
+ if not _cp_has_creds and _cp_config and getattr(_cp_config, "auth_type", "") == "aws_sdk":
1430
+ _cp_has_creds = _has_aws_sdk_creds_for_listing(_cp.slug)
1431
+
1432
+ if not _cp_has_creds:
1433
+ continue
1434
+
1435
+ # For bedrock, use live discovery so the list reflects the active
1436
+ # region (eu.*, us.*, ap.*) instead of the hardcoded us.* static list.
1437
+ if _cp_config and getattr(_cp_config, "auth_type", "") == "aws_sdk":
1438
+ try:
1439
+ from agent.bedrock_adapter import bedrock_model_ids_or_none
1440
+ _ids = bedrock_model_ids_or_none()
1441
+ _cp_model_ids = _ids if _ids is not None else curated.get(_cp.slug, [])
1442
+ except Exception:
1443
+ _cp_model_ids = curated.get(_cp.slug, [])
1444
+ else:
1445
+ _cp_model_ids = curated.get(_cp.slug, [])
1446
+ _cp_total = len(_cp_model_ids)
1447
+ _cp_top = _cp_model_ids[:max_models]
1448
+
1449
+ results.append({
1450
+ "slug": _cp.slug,
1451
+ "name": _cp.label,
1452
+ "is_current": _cp.slug == current_provider,
1453
+ "is_user_defined": False,
1454
+ "models": _cp_top,
1455
+ "total_models": _cp_total,
1456
+ "source": "canonical",
1457
+ })
1458
+ seen_slugs.add(_cp.slug.lower())
1459
+ _record_builtin_endpoint(_cp.slug)
1460
+
1461
+ # --- 3. User-defined endpoints from config ---
1462
+ # Track (name, base_url) of what section 3 emits so section 4 can skip
1463
+ # any overlapping ``custom_providers:`` entries. Callers typically pass
1464
+ # both (gateway/CLI invoke ``get_compatible_custom_providers()`` which
1465
+ # merges ``providers:`` into the list) — without this, the same endpoint
1466
+ # produces two picker rows: one bare-slug ("openrouter") from section 3
1467
+ # and one "custom:openrouter" from section 4, both labelled identically.
1468
+ _section3_emitted_pairs: set = set()
1469
+ if user_providers and isinstance(user_providers, dict):
1470
+ for ep_name, ep_cfg in user_providers.items():
1471
+ if not isinstance(ep_cfg, dict):
1472
+ continue
1473
+ # Skip if this slug was already emitted (e.g. canonical provider
1474
+ # with the same name) or will be picked up by section 4.
1475
+ if ep_name.lower() in seen_slugs:
1476
+ continue
1477
+ display_name = ep_cfg.get("name", "") or ep_name
1478
+ # ``base_url`` is Hermes's canonical write key (matches
1479
+ # custom_providers and _save_custom_provider); ``api`` / ``url``
1480
+ # remain as fallbacks for hand-edited / legacy configs.
1481
+ api_url = (
1482
+ ep_cfg.get("base_url", "")
1483
+ or ep_cfg.get("api", "")
1484
+ or ep_cfg.get("url", "")
1485
+ or ""
1486
+ )
1487
+ # ``default_model`` is the legacy key; ``model`` matches what
1488
+ # custom_providers entries use, so accept either.
1489
+ default_model = ep_cfg.get("default_model", "") or ep_cfg.get("model", "")
1490
+
1491
+ # Build models list from both default_model and full models array
1492
+ models_list = []
1493
+ if default_model:
1494
+ models_list.append(default_model)
1495
+ # Also include the full models list from config.
1496
+ # Hermes writes ``models:`` as a dict keyed by model id
1497
+ # (see hermes_cli/main.py::_save_custom_provider); older
1498
+ # configs or hand-edited files may still use a list.
1499
+ cfg_models = ep_cfg.get("models", [])
1500
+ if isinstance(cfg_models, dict):
1501
+ for m in cfg_models:
1502
+ if m and m not in models_list:
1503
+ models_list.append(m)
1504
+ elif isinstance(cfg_models, list):
1505
+ for m in cfg_models:
1506
+ if m and m not in models_list:
1507
+ models_list.append(m)
1508
+
1509
+ # Official OpenAI API rows in providers: often have base_url but no
1510
+ # explicit models: dict — avoid a misleading zero count in /model.
1511
+ if not models_list:
1512
+ url_lower = str(api_url).strip().lower()
1513
+ if "api.openai.com" in url_lower:
1514
+ fb = curated.get("openai") or []
1515
+ if fb:
1516
+ models_list = list(fb)
1517
+
1518
+ # Prefer the endpoint's live /models list when credentials are
1519
+ # available, unless the provider explicitly opts out via
1520
+ # discover_models: false (e.g. dedicated endpoints that expose
1521
+ # the entire aggregator catalog via /models).
1522
+ api_key = str(ep_cfg.get("api_key", "") or "").strip()
1523
+ if not api_key:
1524
+ key_env = str(ep_cfg.get("key_env", "") or "").strip()
1525
+ api_key = os.environ.get(key_env, "").strip() if key_env else ""
1526
+ discover = ep_cfg.get("discover_models", True)
1527
+ if isinstance(discover, str):
1528
+ discover = discover.lower() not in {"false", "no", "0"}
1529
+ if api_url and api_key and discover:
1530
+ try:
1531
+ from hermes_cli.models import fetch_api_models
1532
+ live_models = fetch_api_models(api_key, api_url)
1533
+ if live_models:
1534
+ models_list = live_models
1535
+ except Exception:
1536
+ pass
1537
+
1538
+ results.append({
1539
+ "slug": ep_name,
1540
+ "name": display_name,
1541
+ "is_current": ep_name == current_provider,
1542
+ "is_user_defined": True,
1543
+ "models": models_list,
1544
+ "total_models": len(models_list) if models_list else 0,
1545
+ "source": "user-config",
1546
+ "api_url": api_url,
1547
+ })
1548
+ seen_slugs.add(ep_name.lower())
1549
+ seen_slugs.add(custom_provider_slug(display_name).lower())
1550
+ _pair = (
1551
+ str(display_name).strip().lower(),
1552
+ str(api_url).strip().rstrip("/").lower(),
1553
+ )
1554
+ if _pair[0] and _pair[1]:
1555
+ _section3_emitted_pairs.add(_pair)
1556
+
1557
+ # --- 4. Saved custom providers from config ---
1558
+ # Each ``custom_providers`` entry represents one model under a named
1559
+ # provider. Entries sharing the same endpoint (``base_url`` + ``api_key``)
1560
+ # are grouped into a single picker row, so e.g. four Ollama entries
1561
+ # pointing at ``http://localhost:11434/v1`` with per-model display names
1562
+ # ("Ollama — GLM 5.1", "Ollama — Qwen3-coder", ...) appear as one
1563
+ # "Ollama" row with four models inside instead of four near-duplicates
1564
+ # that differ only by suffix. Entries with distinct endpoints still
1565
+ # produce separate rows.
1566
+ #
1567
+ # When the grouped endpoint matches ``current_base_url`` the group's
1568
+ # slug becomes ``current_provider`` so that selecting a model from the
1569
+ # picker flows back through the runtime provider that already holds
1570
+ # valid credentials — no re-resolution needed.
1571
+ if custom_providers and isinstance(custom_providers, list):
1572
+ from collections import OrderedDict
1573
+
1574
+ # Key by (base_url, api_key) instead of slug: names frequently
1575
+ # differ per model ("Ollama — X") while the endpoint stays the
1576
+ # same. Slug-based grouping left them as separate rows.
1577
+ groups: "OrderedDict[tuple, dict]" = OrderedDict()
1578
+ for entry in custom_providers:
1579
+ if not isinstance(entry, dict):
1580
+ continue
1581
+
1582
+ raw_name = (entry.get("name") or "").strip()
1583
+ api_url = (
1584
+ entry.get("base_url", "")
1585
+ or entry.get("url", "")
1586
+ or entry.get("api", "")
1587
+ or ""
1588
+ ).strip().rstrip("/")
1589
+ if not raw_name or not api_url:
1590
+ continue
1591
+ api_key = (entry.get("api_key") or "").strip()
1592
+
1593
+ group_key = (api_url, api_key)
1594
+ if group_key not in groups:
1595
+ # Strip per-model suffix so "Ollama — GLM 5.1" becomes
1596
+ # "Ollama" for the grouped row. Em dash is the convention
1597
+ # Hermes's own writer uses; a hyphen variant is accepted
1598
+ # for hand-edited configs.
1599
+ display_name = raw_name
1600
+ for sep in ("—", " - "):
1601
+ if sep in display_name:
1602
+ display_name = display_name.split(sep)[0].strip()
1603
+ break
1604
+ if not display_name:
1605
+ display_name = raw_name
1606
+ # If this endpoint matches the currently active one, use
1607
+ # ``current_provider`` as the slug so picker-driven switches
1608
+ # route through the live credential pipeline.
1609
+ if (
1610
+ current_base_url
1611
+ and api_url == current_base_url.strip().rstrip("/")
1612
+ ):
1613
+ # Guard against bare "custom" slug left by a prior
1614
+ # failed switch — always resolve to the canonical
1615
+ # custom:<name> form. (GH #17478)
1616
+ slug = (
1617
+ current_provider
1618
+ if current_provider and current_provider != "custom"
1619
+ else custom_provider_slug(display_name)
1620
+ )
1621
+ else:
1622
+ slug = custom_provider_slug(display_name)
1623
+ groups[group_key] = {
1624
+ "slug": slug,
1625
+ "name": display_name,
1626
+ "api_url": api_url,
1627
+ "models": [],
1628
+ }
1629
+
1630
+ # The singular ``model:`` field only holds the currently
1631
+ # active model. Hermes's own writer (main.py::_save_custom_provider)
1632
+ # stores every configured model as a dict under ``models:``;
1633
+ # downstream readers (agent/models_dev.py, gateway/run.py,
1634
+ # run_agent.py, hermes_cli/config.py) already consume that dict.
1635
+ default_model = (entry.get("model") or "").strip()
1636
+ if default_model and default_model not in groups[group_key]["models"]:
1637
+ groups[group_key]["models"].append(default_model)
1638
+
1639
+ cfg_models = entry.get("models", {})
1640
+ if isinstance(cfg_models, dict):
1641
+ for m in cfg_models:
1642
+ if m and m not in groups[group_key]["models"]:
1643
+ groups[group_key]["models"].append(m)
1644
+ elif isinstance(cfg_models, list):
1645
+ for m in cfg_models:
1646
+ if m and m not in groups[group_key]["models"]:
1647
+ groups[group_key]["models"].append(m)
1648
+
1649
+ _section4_emitted_slugs: set = set()
1650
+ for grp_key, grp in groups.items():
1651
+ api_url, api_key = grp_key
1652
+ slug = grp["slug"]
1653
+ # If the slug is already claimed by a built-in / overlay /
1654
+ # user-provider row (sections 1-3), skip this custom group
1655
+ # to avoid shadowing a real provider.
1656
+ if slug.lower() in seen_slugs and slug.lower() not in _section4_emitted_slugs:
1657
+ continue
1658
+ # If a prior section-4 group already used this slug (two custom
1659
+ # endpoints with the same cleaned name — e.g. two OpenAI-
1660
+ # compatible gateways named identically with different keys),
1661
+ # append a counter so both rows stay visible in the picker.
1662
+ if slug.lower() in _section4_emitted_slugs:
1663
+ base_slug = slug
1664
+ n = 2
1665
+ while f"{base_slug}-{n}".lower() in seen_slugs:
1666
+ n += 1
1667
+ slug = f"{base_slug}-{n}"
1668
+ grp["slug"] = slug
1669
+ # Skip if section 3 already emitted this endpoint under its
1670
+ # ``providers:`` dict key — matches on (display_name, base_url).
1671
+ # Prevents two picker rows labelled identically when callers
1672
+ # pass both ``user_providers`` and a compatibility-merged
1673
+ # ``custom_providers`` list.
1674
+ _pair_key = (
1675
+ str(grp["name"]).strip().lower(),
1676
+ str(grp["api_url"]).strip().rstrip("/").lower(),
1677
+ )
1678
+ if _pair_key[0] and _pair_key[1] and _pair_key in _section3_emitted_pairs:
1679
+ continue
1680
+ # Skip if a built-in row (sections 1/2/2b) already represents this
1681
+ # endpoint. Fixes #16970: a user-defined "my-dashscope" pointing at
1682
+ # https://coding-intl.dashscope.aliyuncs.com/v1 duplicates the
1683
+ # built-in alibaba-coding-plan row whenever DASHSCOPE_API_KEY is
1684
+ # set. The built-in row carries the curated model list, correct
1685
+ # auth wiring, and canonical slug — keep it and hide the shadow.
1686
+ _grp_url_norm = _pair_key[1]
1687
+ if _grp_url_norm and _grp_url_norm in _builtin_endpoints:
1688
+ continue
1689
+ # Live model discovery from custom provider endpoints (matches
1690
+ # Section 3 behavior for user ``providers:`` entries).
1691
+ if api_url and api_key:
1692
+ try:
1693
+ from hermes_cli.models import fetch_api_models
1694
+
1695
+ live_models = fetch_api_models(api_key, api_url)
1696
+ if live_models:
1697
+ grp["models"] = live_models
1698
+ grp["total_models"] = len(live_models)
1699
+ except Exception:
1700
+ pass
1701
+ results.append({
1702
+ "slug": slug,
1703
+ "name": grp["name"],
1704
+ "is_current": slug == current_provider,
1705
+ "is_user_defined": True,
1706
+ "models": grp["models"],
1707
+ "total_models": len(grp["models"]),
1708
+ "source": "user-config",
1709
+ "api_url": grp["api_url"],
1710
+ })
1711
+ seen_slugs.add(slug.lower())
1712
+ _section4_emitted_slugs.add(slug.lower())
1713
+
1714
+ # Sort: current provider first, then by model count descending
1715
+ results.sort(key=lambda r: (not r["is_current"], -r["total_models"]))
1716
+
1717
+ return results
1718
+
1719
+
1720
+ def list_picker_providers(
1721
+ current_provider: str = "",
1722
+ current_base_url: str = "",
1723
+ user_providers: dict = None,
1724
+ custom_providers: list | None = None,
1725
+ max_models: int = 8,
1726
+ current_model: str = "",
1727
+ ) -> List[dict]:
1728
+ """Interactive-picker variant of :func:`list_authenticated_providers`.
1729
+
1730
+ Post-processes the base list so the ``/model`` picker (Telegram/Discord
1731
+ inline keyboards) only surfaces models that are actually callable in the
1732
+ current install:
1733
+
1734
+ - OpenRouter's model list is replaced with the output of
1735
+ :func:`hermes_cli.models.fetch_openrouter_models`, which filters the
1736
+ curated ``OPENROUTER_MODELS`` snapshot against the live OpenRouter
1737
+ catalog. IDs the live catalog no longer carries drop out, so the
1738
+ picker never offers a model the user can't call.
1739
+ - Provider rows whose model list ends up empty are dropped, except
1740
+ custom endpoints (``is_user_defined=True`` with an ``api_url``) where
1741
+ the user may supply their own model set through config.
1742
+
1743
+ All other providers and metadata fields are passed through unchanged.
1744
+ The typed ``/model <name>`` path is unaffected -- only the interactive
1745
+ picker payload is narrowed.
1746
+ """
1747
+ from hermes_cli.models import fetch_openrouter_models
1748
+
1749
+ providers = list_authenticated_providers(
1750
+ current_provider=current_provider,
1751
+ current_base_url=current_base_url,
1752
+ user_providers=user_providers,
1753
+ custom_providers=custom_providers,
1754
+ max_models=max_models,
1755
+ current_model=current_model,
1756
+ )
1757
+
1758
+ filtered: List[dict] = []
1759
+ for p in providers:
1760
+ slug = str(p.get("slug", "")).lower()
1761
+ if slug == "openrouter":
1762
+ try:
1763
+ live = fetch_openrouter_models()
1764
+ live_ids = [mid for mid, _ in live]
1765
+ except Exception:
1766
+ live_ids = list(p.get("models", []))
1767
+ p = dict(p)
1768
+ p["models"] = live_ids[:max_models]
1769
+ p["total_models"] = len(live_ids)
1770
+
1771
+ has_models = bool(p.get("models"))
1772
+ is_custom_endpoint = bool(p.get("is_user_defined")) and bool(p.get("api_url"))
1773
+ if not has_models and not is_custom_endpoint:
1774
+ continue
1775
+ filtered.append(p)
1776
+
1777
+ return filtered