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,1713 @@
1
+ """ACP agent server — exposes Hermes Agent via the Agent Client Protocol."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import base64
7
+ import contextvars
8
+ import json
9
+ import logging
10
+ import os
11
+ from collections import defaultdict, deque
12
+ from concurrent.futures import ThreadPoolExecutor
13
+ from pathlib import Path
14
+ from typing import Any, Deque, Optional
15
+ from urllib.parse import unquote, urlparse
16
+
17
+ import acp
18
+ from acp.schema import (
19
+ AgentCapabilities,
20
+ AgentMessageChunk,
21
+ AuthenticateResponse,
22
+ AvailableCommand,
23
+ AvailableCommandsUpdate,
24
+ BlobResourceContents,
25
+ ClientCapabilities,
26
+ EmbeddedResourceContentBlock,
27
+ ForkSessionResponse,
28
+ ImageContentBlock,
29
+ AudioContentBlock,
30
+ Implementation,
31
+ InitializeResponse,
32
+ ListSessionsResponse,
33
+ LoadSessionResponse,
34
+ McpServerHttp,
35
+ McpServerSse,
36
+ McpServerStdio,
37
+ ModelInfo,
38
+ NewSessionResponse,
39
+ PromptCapabilities,
40
+ PromptResponse,
41
+ ResumeSessionResponse,
42
+ SetSessionConfigOptionResponse,
43
+ SetSessionModelResponse,
44
+ SetSessionModeResponse,
45
+ ResourceContentBlock,
46
+ SessionCapabilities,
47
+ SessionForkCapabilities,
48
+ SessionListCapabilities,
49
+ SessionModelState,
50
+ SessionResumeCapabilities,
51
+ SessionInfo,
52
+ TextContentBlock,
53
+ TextResourceContents,
54
+ UnstructuredCommandInput,
55
+ Usage,
56
+ UsageUpdate,
57
+ UserMessageChunk,
58
+ )
59
+
60
+ from acp_adapter.auth import TERMINAL_SETUP_AUTH_METHOD_ID, build_auth_methods, detect_provider
61
+ from acp_adapter.events import (
62
+ _build_plan_update_from_todo_result,
63
+ make_message_cb,
64
+ make_step_cb,
65
+ make_thinking_cb,
66
+ make_tool_progress_cb,
67
+ )
68
+ from acp_adapter.permissions import make_approval_callback
69
+ from acp_adapter.session import SessionManager, SessionState, _expand_acp_enabled_toolsets
70
+ from acp_adapter.tools import build_tool_complete, build_tool_start
71
+
72
+ logger = logging.getLogger(__name__)
73
+
74
+ try:
75
+ from hermes_cli import __version__ as HERMES_VERSION
76
+ except Exception:
77
+ HERMES_VERSION = "0.0.0"
78
+
79
+ # Thread pool for running AIAgent (synchronous) in parallel.
80
+ _executor = ThreadPoolExecutor(max_workers=4, thread_name_prefix="acp-agent")
81
+
82
+ # Server-side page size for list_sessions. The ACP ListSessionsRequest schema
83
+ # does not expose a client-side limit, so this is a fixed cap that clients
84
+ # paginate against using `cursor` / `next_cursor`.
85
+ _LIST_SESSIONS_PAGE_SIZE = 50
86
+ _MAX_ACP_RESOURCE_BYTES = 512 * 1024
87
+ _TEXT_RESOURCE_MIME_PREFIXES = ("text/",)
88
+ _TEXT_RESOURCE_MIME_TYPES = {
89
+ "application/json",
90
+ "application/javascript",
91
+ "application/typescript",
92
+ "application/xml",
93
+ "application/x-yaml",
94
+ "application/yaml",
95
+ "application/toml",
96
+ "application/sql",
97
+ }
98
+
99
+
100
+ def _resource_display_name(uri: str, name: str | None = None, title: str | None = None) -> str:
101
+ """Human-readable attachment name for prompt context."""
102
+ raw_name = (name or "").strip()
103
+ raw_title = (title or "").strip()
104
+ if raw_title and raw_name and raw_title != raw_name:
105
+ return f"{raw_title} ({raw_name})"
106
+ if raw_title:
107
+ return raw_title
108
+ if raw_name:
109
+ return raw_name
110
+ parsed = urlparse(uri)
111
+ candidate = parsed.path if parsed.scheme else uri
112
+ return Path(unquote(candidate)).name or uri or "resource"
113
+
114
+
115
+ def _is_text_resource(mime_type: str | None) -> bool:
116
+ mime = (mime_type or "").split(";", 1)[0].strip().lower()
117
+ if not mime:
118
+ return False
119
+ return mime.startswith(_TEXT_RESOURCE_MIME_PREFIXES) or mime in _TEXT_RESOURCE_MIME_TYPES
120
+
121
+
122
+ def _is_image_resource(mime_type: str | None) -> bool:
123
+ mime = (mime_type or "").split(";", 1)[0].strip().lower()
124
+ return mime.startswith("image/")
125
+
126
+
127
+ def _guess_image_mime_from_path(path: Path) -> str | None:
128
+ suffix = path.suffix.lower()
129
+ return {
130
+ ".png": "image/png",
131
+ ".jpg": "image/jpeg",
132
+ ".jpeg": "image/jpeg",
133
+ ".gif": "image/gif",
134
+ ".webp": "image/webp",
135
+ ".bmp": "image/bmp",
136
+ ".svg": "image/svg+xml",
137
+ }.get(suffix)
138
+
139
+
140
+ def _image_data_url(data: bytes, mime_type: str) -> str:
141
+ return f"data:{mime_type};base64,{base64.b64encode(data).decode('ascii')}"
142
+
143
+
144
+ def _path_from_file_uri(uri: str) -> Path | None:
145
+ """Convert local file URIs/paths from ACP clients into a readable Path.
146
+
147
+ Zed may send POSIX file URIs from Linux/WSL workspaces or Windows-ish paths
148
+ when launched through wsl.exe. Translate the common Windows drive form to
149
+ /mnt/<drive>/... so Hermes running in WSL can read it.
150
+ """
151
+ raw = (uri or "").strip()
152
+ if not raw:
153
+ return None
154
+
155
+ parsed = urlparse(raw)
156
+ if parsed.scheme and parsed.scheme != "file":
157
+ return None
158
+
159
+ if parsed.scheme == "file":
160
+ if parsed.netloc and parsed.netloc not in {"", "localhost"}:
161
+ return None
162
+ path_text = unquote(parsed.path or "")
163
+ else:
164
+ path_text = unquote(raw)
165
+
166
+ # file:///C:/Users/... or C:\Users\...
167
+ if len(path_text) >= 3 and path_text[0] == "/" and path_text[2] == ":" and path_text[1].isalpha():
168
+ drive = path_text[1].lower()
169
+ rest = path_text[3:].lstrip("/\\").replace("\\", "/")
170
+ return Path("/mnt") / drive / rest
171
+ if len(path_text) >= 2 and path_text[1] == ":" and path_text[0].isalpha():
172
+ drive = path_text[0].lower()
173
+ rest = path_text[2:].lstrip("/\\").replace("\\", "/")
174
+ return Path("/mnt") / drive / rest
175
+
176
+ return Path(path_text)
177
+
178
+
179
+ def _decode_text_bytes(data: bytes, mime_type: str | None) -> str | None:
180
+ """Decode resource bytes if they are probably text; return None for binary."""
181
+ if b"\x00" in data and not _is_text_resource(mime_type):
182
+ return None
183
+ for encoding in ("utf-8-sig", "utf-8", "latin-1"):
184
+ try:
185
+ return data.decode(encoding)
186
+ except UnicodeDecodeError:
187
+ continue
188
+ return data.decode("utf-8", errors="replace")
189
+
190
+
191
+ def _format_resource_text(
192
+ *,
193
+ uri: str,
194
+ body: str,
195
+ name: str | None = None,
196
+ title: str | None = None,
197
+ note: str | None = None,
198
+ ) -> str:
199
+ display = _resource_display_name(uri, name=name, title=title)
200
+ header = f"[Attached file: {display}]"
201
+ if note:
202
+ header += f" ({note})"
203
+ return f"{header}\nURI: {uri}\n\n{body}"
204
+
205
+
206
+ def _resource_link_to_parts(block: ResourceContentBlock) -> list[dict[str, Any]]:
207
+ """Convert an ACP resource_link block to OpenAI content parts.
208
+
209
+ Returns a list of {"type": "text", ...} and/or {"type": "image_url", ...}
210
+ parts. Image resources produce an image_url part with a small text header
211
+ so the model knows which attachment it is. Non-image resources return a
212
+ single text part with the inlined file body (or a binary-omit note).
213
+ """
214
+ uri = str(getattr(block, "uri", "") or "").strip()
215
+ if not uri:
216
+ return []
217
+
218
+ name = str(getattr(block, "name", "") or "").strip() or None
219
+ title = str(getattr(block, "title", "") or "").strip() or None
220
+ mime_type = str(getattr(block, "mime_type", "") or "").strip() or None
221
+ path = _path_from_file_uri(uri)
222
+
223
+ if path is None:
224
+ return [{
225
+ "type": "text",
226
+ "text": _format_resource_text(
227
+ uri=uri,
228
+ name=name,
229
+ title=title,
230
+ body="[Resource link only; Hermes cannot read non-file ACP resource URIs directly.]",
231
+ ),
232
+ }]
233
+
234
+ # Image files: emit a short text header + image_url data URL so vision
235
+ # models can see the attachment instead of a "binary omitted" note.
236
+ image_mime = mime_type if _is_image_resource(mime_type) else _guess_image_mime_from_path(path)
237
+ if image_mime and _is_image_resource(image_mime):
238
+ try:
239
+ size = path.stat().st_size
240
+ if size > _MAX_ACP_RESOURCE_BYTES:
241
+ return [{
242
+ "type": "text",
243
+ "text": _format_resource_text(
244
+ uri=uri,
245
+ name=name,
246
+ title=title,
247
+ body=f"[Image too large to inline: {size} bytes, cap={_MAX_ACP_RESOURCE_BYTES}]",
248
+ ),
249
+ }]
250
+ with path.open("rb") as fh:
251
+ data = fh.read()
252
+ except OSError as exc:
253
+ logger.warning("ACP image resource read failed: %s", uri, exc_info=True)
254
+ return [{
255
+ "type": "text",
256
+ "text": _format_resource_text(
257
+ uri=uri,
258
+ name=name,
259
+ title=title,
260
+ body=f"[Could not read attached image: {exc}]",
261
+ ),
262
+ }]
263
+ display = _resource_display_name(uri, name=name, title=title)
264
+ return [
265
+ {"type": "text", "text": f"[Attached image: {display}]\nURI: {uri}"},
266
+ {"type": "image_url", "image_url": {"url": _image_data_url(data, image_mime)}},
267
+ ]
268
+
269
+ try:
270
+ size = path.stat().st_size
271
+ read_size = min(size, _MAX_ACP_RESOURCE_BYTES)
272
+ with path.open("rb") as fh:
273
+ data = fh.read(read_size)
274
+ text = _decode_text_bytes(data, mime_type)
275
+ if text is None:
276
+ return [{
277
+ "type": "text",
278
+ "text": _format_resource_text(
279
+ uri=uri,
280
+ name=name,
281
+ title=title,
282
+ body=f"[Binary file omitted: {size} bytes, mime={mime_type or 'unknown'}]",
283
+ ),
284
+ }]
285
+ note = None
286
+ if size > _MAX_ACP_RESOURCE_BYTES:
287
+ note = f"truncated to {_MAX_ACP_RESOURCE_BYTES} of {size} bytes"
288
+ return [{
289
+ "type": "text",
290
+ "text": _format_resource_text(uri=uri, name=name, title=title, body=text, note=note),
291
+ }]
292
+ except OSError as exc:
293
+ logger.warning("ACP resource read failed: %s", uri, exc_info=True)
294
+ return [{
295
+ "type": "text",
296
+ "text": _format_resource_text(
297
+ uri=uri,
298
+ name=name,
299
+ title=title,
300
+ body=f"[Could not read attached file: {exc}]",
301
+ ),
302
+ }]
303
+
304
+
305
+ def _embedded_resource_to_parts(block: EmbeddedResourceContentBlock) -> list[dict[str, Any]]:
306
+ resource = getattr(block, "resource", None)
307
+ if resource is None:
308
+ return []
309
+
310
+ uri = str(getattr(resource, "uri", "") or "").strip()
311
+ mime_type = str(getattr(resource, "mime_type", "") or "").strip() or None
312
+
313
+ if isinstance(resource, TextResourceContents):
314
+ return [{"type": "text", "text": _format_resource_text(uri=uri, body=resource.text)}]
315
+
316
+ if isinstance(resource, BlobResourceContents):
317
+ blob = resource.blob or ""
318
+ try:
319
+ data = base64.b64decode(blob, validate=True)
320
+ except Exception:
321
+ data = blob.encode("utf-8", errors="replace")
322
+
323
+ # Image blobs go through as image_url so vision models can see them.
324
+ if _is_image_resource(mime_type):
325
+ if len(data) > _MAX_ACP_RESOURCE_BYTES:
326
+ return [{
327
+ "type": "text",
328
+ "text": _format_resource_text(
329
+ uri=uri,
330
+ body=f"[Embedded image too large to inline: {len(data)} bytes, cap={_MAX_ACP_RESOURCE_BYTES}]",
331
+ ),
332
+ }]
333
+ display = _resource_display_name(uri)
334
+ return [
335
+ {"type": "text", "text": f"[Attached image: {display}]" + (f"\nURI: {uri}" if uri else "")},
336
+ {"type": "image_url", "image_url": {"url": _image_data_url(data, mime_type or "image/png")}},
337
+ ]
338
+
339
+ text = _decode_text_bytes(data[:_MAX_ACP_RESOURCE_BYTES], mime_type)
340
+ if text is None:
341
+ body = f"[Binary embedded file omitted: {len(data)} bytes, mime={mime_type or 'unknown'}]"
342
+ else:
343
+ body = text
344
+ if len(data) > _MAX_ACP_RESOURCE_BYTES:
345
+ body += f"\n\n[Truncated to {_MAX_ACP_RESOURCE_BYTES} of {len(data)} bytes]"
346
+ return [{"type": "text", "text": _format_resource_text(uri=uri, body=body)}]
347
+
348
+ text = getattr(resource, "text", None)
349
+ if text:
350
+ return [{"type": "text", "text": _format_resource_text(uri=uri, body=str(text))}]
351
+ return []
352
+
353
+
354
+ def _extract_text(
355
+ prompt: list[
356
+ TextContentBlock
357
+ | ImageContentBlock
358
+ | AudioContentBlock
359
+ | ResourceContentBlock
360
+ | EmbeddedResourceContentBlock
361
+ ],
362
+ ) -> str:
363
+ """Extract plain text from ACP content blocks for display/commands."""
364
+ parts: list[str] = []
365
+ for block in prompt:
366
+ if isinstance(block, TextContentBlock):
367
+ parts.append(block.text)
368
+ elif hasattr(block, "text"):
369
+ parts.append(str(block.text))
370
+ return "\n".join(parts)
371
+
372
+
373
+ def _image_block_to_openai_part(block: ImageContentBlock) -> dict[str, Any] | None:
374
+ """Convert an ACP image content block to OpenAI-style multimodal content."""
375
+ data = str(getattr(block, "data", "") or "").strip()
376
+ uri = str(getattr(block, "uri", "") or "").strip()
377
+ mime_type = str(getattr(block, "mime_type", "") or "image/png").strip() or "image/png"
378
+
379
+ if data:
380
+ url = data if data.startswith("data:") else f"data:{mime_type};base64,{data}"
381
+ elif uri:
382
+ url = uri
383
+ else:
384
+ return None
385
+
386
+ return {"type": "image_url", "image_url": {"url": url}}
387
+
388
+
389
+ def _content_blocks_to_openai_user_content(
390
+ prompt: list[
391
+ TextContentBlock
392
+ | ImageContentBlock
393
+ | AudioContentBlock
394
+ | ResourceContentBlock
395
+ | EmbeddedResourceContentBlock
396
+ ],
397
+ ) -> str | list[dict[str, Any]]:
398
+ """Convert ACP prompt blocks into a Hermes/OpenAI-compatible user content payload."""
399
+ parts: list[dict[str, Any]] = []
400
+ text_parts: list[str] = []
401
+
402
+ for block in prompt:
403
+ if isinstance(block, TextContentBlock):
404
+ if block.text:
405
+ parts.append({"type": "text", "text": block.text})
406
+ text_parts.append(block.text)
407
+ continue
408
+ if isinstance(block, ImageContentBlock):
409
+ image_part = _image_block_to_openai_part(block)
410
+ if image_part is not None:
411
+ parts.append(image_part)
412
+ continue
413
+ if isinstance(block, ResourceContentBlock):
414
+ resource_parts = _resource_link_to_parts(block)
415
+ for part in resource_parts:
416
+ parts.append(part)
417
+ if part.get("type") == "text":
418
+ text_parts.append(part["text"])
419
+ continue
420
+ if isinstance(block, EmbeddedResourceContentBlock):
421
+ resource_parts = _embedded_resource_to_parts(block)
422
+ for part in resource_parts:
423
+ parts.append(part)
424
+ if part.get("type") == "text":
425
+ text_parts.append(part["text"])
426
+ continue
427
+
428
+ if not parts:
429
+ return _extract_text(prompt)
430
+
431
+ # Keep pure text prompts as strings so slash-command handling and text-only
432
+ # providers keep the exact legacy path. Switch to structured content only
433
+ # when an actual non-text block is present.
434
+ if all(part.get("type") == "text" for part in parts):
435
+ return "\n".join(text_parts)
436
+
437
+ return parts
438
+
439
+
440
+ class HermesACPAgent(acp.Agent):
441
+ """ACP Agent implementation wrapping Hermes AIAgent."""
442
+
443
+ _SLASH_COMMANDS = {
444
+ "help": "Show available commands",
445
+ "model": "Show or change current model",
446
+ "tools": "List available tools",
447
+ "context": "Show conversation context info",
448
+ "reset": "Clear conversation history",
449
+ "compact": "Compress conversation context",
450
+ "steer": "Inject guidance into the currently running agent turn",
451
+ "queue": "Queue a prompt to run after the current turn finishes",
452
+ "version": "Show Hermes version",
453
+ }
454
+
455
+ _ADVERTISED_COMMANDS = (
456
+ {
457
+ "name": "help",
458
+ "description": "List available commands",
459
+ },
460
+ {
461
+ "name": "model",
462
+ "description": "Show current model and provider, or switch models",
463
+ "input_hint": "model name to switch to",
464
+ },
465
+ {
466
+ "name": "tools",
467
+ "description": "List available tools with descriptions",
468
+ },
469
+ {
470
+ "name": "context",
471
+ "description": "Show conversation message counts by role",
472
+ },
473
+ {
474
+ "name": "reset",
475
+ "description": "Clear conversation history",
476
+ },
477
+ {
478
+ "name": "compact",
479
+ "description": "Compress conversation context",
480
+ },
481
+ {
482
+ "name": "steer",
483
+ "description": "Inject guidance into the currently running agent turn",
484
+ "input_hint": "guidance for the active turn",
485
+ },
486
+ {
487
+ "name": "queue",
488
+ "description": "Queue a prompt to run after the current turn finishes",
489
+ "input_hint": "prompt to run next",
490
+ },
491
+ {
492
+ "name": "version",
493
+ "description": "Show Hermes version",
494
+ },
495
+ )
496
+
497
+ def __init__(self, session_manager: SessionManager | None = None):
498
+ super().__init__()
499
+ self.session_manager = session_manager or SessionManager()
500
+ self._conn: Optional[acp.Client] = None
501
+
502
+ # ---- Connection lifecycle -----------------------------------------------
503
+
504
+ def on_connect(self, conn: acp.Client) -> None:
505
+ """Store the client connection for sending session updates."""
506
+ self._conn = conn
507
+ logger.info("ACP client connected")
508
+
509
+ @staticmethod
510
+ def _encode_model_choice(provider: str | None, model: str | None) -> str:
511
+ """Encode a model selection so ACP clients can keep provider context."""
512
+ raw_model = str(model or "").strip()
513
+ if not raw_model:
514
+ return ""
515
+ raw_provider = str(provider or "").strip().lower()
516
+ if not raw_provider:
517
+ return raw_model
518
+ return f"{raw_provider}:{raw_model}"
519
+
520
+ def _build_model_state(self, state: SessionState) -> SessionModelState | None:
521
+ """Return the ACP model selector payload for editors like Zed."""
522
+ model = str(state.model or getattr(state.agent, "model", "") or "").strip()
523
+ provider = getattr(state.agent, "provider", None) or detect_provider() or "openrouter"
524
+
525
+ try:
526
+ from hermes_cli.models import curated_models_for_provider, normalize_provider, provider_label
527
+
528
+ normalized_provider = normalize_provider(provider)
529
+ provider_name = provider_label(normalized_provider)
530
+ available_models: list[ModelInfo] = []
531
+ seen_ids: set[str] = set()
532
+
533
+ for model_id, description in curated_models_for_provider(normalized_provider):
534
+ rendered_model = str(model_id or "").strip()
535
+ if not rendered_model:
536
+ continue
537
+ choice_id = self._encode_model_choice(normalized_provider, rendered_model)
538
+ if choice_id in seen_ids:
539
+ continue
540
+ desc_parts = [f"Provider: {provider_name}"]
541
+ if description:
542
+ desc_parts.append(str(description).strip())
543
+ if rendered_model == model:
544
+ desc_parts.append("current")
545
+ available_models.append(
546
+ ModelInfo(
547
+ model_id=choice_id,
548
+ name=rendered_model,
549
+ description=" • ".join(part for part in desc_parts if part),
550
+ )
551
+ )
552
+ seen_ids.add(choice_id)
553
+
554
+ current_model_id = self._encode_model_choice(normalized_provider, model)
555
+ if current_model_id and current_model_id not in seen_ids:
556
+ available_models.insert(
557
+ 0,
558
+ ModelInfo(
559
+ model_id=current_model_id,
560
+ name=model,
561
+ description=f"Provider: {provider_name} • current",
562
+ ),
563
+ )
564
+
565
+ if available_models:
566
+ return SessionModelState(
567
+ available_models=available_models,
568
+ current_model_id=current_model_id or available_models[0].model_id,
569
+ )
570
+ except Exception:
571
+ logger.debug("Could not build ACP model state", exc_info=True)
572
+
573
+ if not model:
574
+ return None
575
+
576
+ fallback_choice = self._encode_model_choice(provider, model)
577
+ return SessionModelState(
578
+ available_models=[ModelInfo(model_id=fallback_choice, name=model)],
579
+ current_model_id=fallback_choice,
580
+ )
581
+
582
+ @staticmethod
583
+ def _resolve_model_selection(raw_model: str, current_provider: str) -> tuple[str, str]:
584
+ """Resolve ``provider:model`` input into the provider and normalized model id."""
585
+ target_provider = current_provider
586
+ new_model = raw_model.strip()
587
+
588
+ try:
589
+ from hermes_cli.models import detect_provider_for_model, parse_model_input
590
+
591
+ target_provider, new_model = parse_model_input(new_model, current_provider)
592
+ if target_provider == current_provider:
593
+ detected = detect_provider_for_model(new_model, current_provider)
594
+ if detected:
595
+ target_provider, new_model = detected
596
+ except Exception:
597
+ logger.debug("Provider detection failed, using model as-is", exc_info=True)
598
+
599
+ return target_provider, new_model
600
+
601
+ @staticmethod
602
+ def _build_usage_update(state: SessionState) -> UsageUpdate | None:
603
+ """Build ACP native context-usage data for clients like Zed.
604
+
605
+ Zed's circular context indicator is driven by ACP ``usage_update``
606
+ session updates: ``size`` is the model context window and ``used`` is
607
+ the current request pressure. Hermes estimates ``used`` from the same
608
+ buckets it sends to providers: system prompt, conversation history, and
609
+ tool schemas.
610
+ """
611
+ agent = state.agent
612
+ compressor = getattr(agent, "context_compressor", None)
613
+ size = int(getattr(compressor, "context_length", 0) or 0)
614
+ if size <= 0:
615
+ return None
616
+
617
+ try:
618
+ from agent.model_metadata import estimate_request_tokens_rough
619
+
620
+ used = estimate_request_tokens_rough(
621
+ state.history,
622
+ system_prompt=getattr(agent, "_cached_system_prompt", "") or "",
623
+ tools=getattr(agent, "tools", None) or None,
624
+ )
625
+ except Exception:
626
+ logger.debug("Could not estimate ACP native context usage", exc_info=True)
627
+ used = int(getattr(compressor, "last_prompt_tokens", 0) or 0)
628
+
629
+ return UsageUpdate(
630
+ session_update="usage_update",
631
+ size=max(size, 0),
632
+ used=max(used, 0),
633
+ )
634
+
635
+ async def _send_usage_update(self, state: SessionState) -> None:
636
+ """Send ACP native context usage to the connected client."""
637
+ if not self._conn:
638
+ return
639
+ update = self._build_usage_update(state)
640
+ if update is None:
641
+ return
642
+ try:
643
+ await self._conn.session_update(
644
+ session_id=state.session_id,
645
+ update=update,
646
+ )
647
+ except Exception:
648
+ logger.warning(
649
+ "Failed to send ACP usage update for session %s",
650
+ state.session_id,
651
+ exc_info=True,
652
+ )
653
+
654
+ def _schedule_usage_update(self, state: SessionState) -> None:
655
+ """Schedule native context indicator refresh after ACP responses."""
656
+ if not self._conn:
657
+ return
658
+ loop = asyncio.get_running_loop()
659
+ loop.call_soon(asyncio.create_task, self._send_usage_update(state))
660
+
661
+ async def _register_session_mcp_servers(
662
+ self,
663
+ state: SessionState,
664
+ mcp_servers: list[McpServerStdio | McpServerHttp | McpServerSse] | None,
665
+ ) -> None:
666
+ """Register ACP-provided MCP servers and refresh the agent tool surface."""
667
+ if not mcp_servers:
668
+ return
669
+
670
+ try:
671
+ from tools.mcp_tool import register_mcp_servers
672
+
673
+ config_map: dict[str, dict] = {}
674
+ for server in mcp_servers:
675
+ name = server.name
676
+ if isinstance(server, McpServerStdio):
677
+ config = {
678
+ "command": server.command,
679
+ "args": list(server.args),
680
+ "env": {item.name: item.value for item in server.env},
681
+ }
682
+ else:
683
+ config = {
684
+ "url": server.url,
685
+ "headers": {item.name: item.value for item in server.headers},
686
+ }
687
+ config_map[name] = config
688
+
689
+ await asyncio.to_thread(register_mcp_servers, config_map)
690
+ except Exception:
691
+ logger.warning(
692
+ "Session %s: failed to register ACP MCP servers",
693
+ state.session_id,
694
+ exc_info=True,
695
+ )
696
+ return
697
+
698
+ try:
699
+ from model_tools import get_tool_definitions
700
+
701
+ enabled_toolsets = _expand_acp_enabled_toolsets(
702
+ getattr(state.agent, "enabled_toolsets", None) or ["hermes-acp"],
703
+ mcp_server_names=[server.name for server in mcp_servers],
704
+ )
705
+ state.agent.enabled_toolsets = enabled_toolsets
706
+ disabled_toolsets = getattr(state.agent, "disabled_toolsets", None)
707
+ state.agent.tools = get_tool_definitions(
708
+ enabled_toolsets=enabled_toolsets,
709
+ disabled_toolsets=disabled_toolsets,
710
+ quiet_mode=True,
711
+ )
712
+ state.agent.valid_tool_names = {
713
+ tool["function"]["name"] for tool in state.agent.tools or []
714
+ }
715
+ invalidate = getattr(state.agent, "_invalidate_system_prompt", None)
716
+ if callable(invalidate):
717
+ invalidate()
718
+ logger.info(
719
+ "Session %s: refreshed tool surface after ACP MCP registration (%d tools)",
720
+ state.session_id,
721
+ len(state.agent.tools or []),
722
+ )
723
+ except Exception:
724
+ logger.warning(
725
+ "Session %s: failed to refresh tool surface after ACP MCP registration",
726
+ state.session_id,
727
+ exc_info=True,
728
+ )
729
+
730
+ # ---- ACP lifecycle ------------------------------------------------------
731
+
732
+ async def initialize(
733
+ self,
734
+ protocol_version: int | None = None,
735
+ client_capabilities: ClientCapabilities | None = None,
736
+ client_info: Implementation | None = None,
737
+ **kwargs: Any,
738
+ ) -> InitializeResponse:
739
+ resolved_protocol_version = (
740
+ protocol_version if isinstance(protocol_version, int) else acp.PROTOCOL_VERSION
741
+ )
742
+ auth_methods = build_auth_methods()
743
+
744
+ client_name = client_info.name if client_info else "unknown"
745
+ logger.info(
746
+ "Initialize from %s (protocol v%s)",
747
+ client_name,
748
+ resolved_protocol_version,
749
+ )
750
+
751
+ return InitializeResponse(
752
+ protocol_version=acp.PROTOCOL_VERSION,
753
+ agent_info=Implementation(name="hermes-agent", version=HERMES_VERSION),
754
+ agent_capabilities=AgentCapabilities(
755
+ load_session=True,
756
+ prompt_capabilities=PromptCapabilities(image=True),
757
+ session_capabilities=SessionCapabilities(
758
+ fork=SessionForkCapabilities(),
759
+ list=SessionListCapabilities(),
760
+ resume=SessionResumeCapabilities(),
761
+ ),
762
+ ),
763
+ auth_methods=auth_methods,
764
+ )
765
+
766
+ async def authenticate(self, method_id: str, **kwargs: Any) -> AuthenticateResponse | None:
767
+ # Only accept authenticate() calls whose method_id matches the
768
+ # provider we advertised in initialize(). Without this check,
769
+ # authenticate() would acknowledge any method_id as long as the
770
+ # server has provider credentials configured — harmless under
771
+ # Hermes' threat model (ACP is stdio-only, local-trust), but poor
772
+ # API hygiene and confusing if ACP ever grows multi-method auth.
773
+ if not isinstance(method_id, str):
774
+ return None
775
+ normalized_method = method_id.strip().lower()
776
+ provider = detect_provider()
777
+
778
+ if normalized_method == TERMINAL_SETUP_AUTH_METHOD_ID:
779
+ # Terminal auth launches Hermes setup/model selection out-of-band.
780
+ # Only report success once that flow has produced usable runtime
781
+ # credentials for the normal ACP session.
782
+ return AuthenticateResponse() if provider else None
783
+
784
+ if not provider or normalized_method != provider:
785
+ return None
786
+ return AuthenticateResponse()
787
+
788
+ # ---- Session management -------------------------------------------------
789
+
790
+ @staticmethod
791
+ def _history_message_text(message: dict[str, Any]) -> str:
792
+ """Extract displayable text from a persisted OpenAI-style message."""
793
+ content = message.get("content")
794
+ if isinstance(content, str):
795
+ return content.strip()
796
+ if isinstance(content, list):
797
+ parts: list[str] = []
798
+ for item in content:
799
+ if isinstance(item, dict):
800
+ text = item.get("text")
801
+ if isinstance(text, str):
802
+ parts.append(text)
803
+ elif item.get("type") == "text" and isinstance(item.get("content"), str):
804
+ parts.append(item["content"])
805
+ elif isinstance(item, str):
806
+ parts.append(item)
807
+ return "\n".join(part.strip() for part in parts if part and part.strip()).strip()
808
+ return ""
809
+
810
+ @staticmethod
811
+ def _history_message_update(
812
+ *,
813
+ role: str,
814
+ text: str,
815
+ ) -> UserMessageChunk | AgentMessageChunk | None:
816
+ """Build an ACP history replay update for a user/assistant message."""
817
+ block = TextContentBlock(type="text", text=text)
818
+ if role == "user":
819
+ return UserMessageChunk(
820
+ session_update="user_message_chunk",
821
+ content=block,
822
+ )
823
+ if role == "assistant":
824
+ return AgentMessageChunk(
825
+ session_update="agent_message_chunk",
826
+ content=block,
827
+ )
828
+ return None
829
+
830
+ @staticmethod
831
+ def _history_tool_call_name_args(tool_call: dict[str, Any]) -> tuple[str, dict[str, Any]]:
832
+ """Extract function name/arguments from an OpenAI-style tool_call."""
833
+ function = tool_call.get("function") if isinstance(tool_call.get("function"), dict) else {}
834
+ name = str(function.get("name") or tool_call.get("name") or "unknown_tool")
835
+ raw_args = function.get("arguments") or tool_call.get("arguments") or tool_call.get("args") or {}
836
+ if isinstance(raw_args, str):
837
+ try:
838
+ parsed = json.loads(raw_args)
839
+ except Exception:
840
+ parsed = {"raw": raw_args}
841
+ raw_args = parsed
842
+ if not isinstance(raw_args, dict):
843
+ raw_args = {}
844
+ return name, raw_args
845
+
846
+ @staticmethod
847
+ def _history_tool_call_id(tool_call: dict[str, Any]) -> str:
848
+ """Return the stable provider tool call id for ACP history replay."""
849
+ return str(
850
+ tool_call.get("id")
851
+ or tool_call.get("call_id")
852
+ or tool_call.get("tool_call_id")
853
+ or ""
854
+ ).strip()
855
+
856
+ async def _replay_session_history(self, state: SessionState) -> None:
857
+ """Send persisted user/assistant history to clients during session/load.
858
+
859
+ Zed's ACP history UI calls ``session/load`` after the user picks an item
860
+ from the Agents sidebar. The agent must then replay the full conversation
861
+ as user/assistant chunks plus reconstructed tool-call start/completion
862
+ notifications; merely restoring server-side state makes Hermes remember
863
+ context, but leaves the editor looking like a clean thread.
864
+ """
865
+ if not self._conn or not state.history:
866
+ return
867
+
868
+ active_tool_calls: dict[str, tuple[str, dict[str, Any]]] = {}
869
+
870
+ async def _send(update: Any) -> bool:
871
+ try:
872
+ await self._conn.session_update(session_id=state.session_id, update=update)
873
+ return True
874
+ except Exception:
875
+ logger.warning(
876
+ "Failed to replay ACP history for session %s",
877
+ state.session_id,
878
+ exc_info=True,
879
+ )
880
+ return False
881
+
882
+ for message in state.history:
883
+ role = str(message.get("role") or "")
884
+
885
+ if role in {"user", "assistant"}:
886
+ text = self._history_message_text(message)
887
+ if text:
888
+ update = self._history_message_update(role=role, text=text)
889
+ if update is not None and not await _send(update):
890
+ return
891
+
892
+ if role == "assistant" and isinstance(message.get("tool_calls"), list):
893
+ for tool_call in message["tool_calls"]:
894
+ if not isinstance(tool_call, dict):
895
+ continue
896
+ tool_call_id = self._history_tool_call_id(tool_call)
897
+ if not tool_call_id:
898
+ continue
899
+ tool_name, args = self._history_tool_call_name_args(tool_call)
900
+ active_tool_calls[tool_call_id] = (tool_name, args)
901
+ if not await _send(build_tool_start(tool_call_id, tool_name, args)):
902
+ return
903
+ continue
904
+
905
+ if role == "tool":
906
+ tool_call_id = str(message.get("tool_call_id") or "").strip()
907
+ tool_name = str(message.get("tool_name") or "").strip()
908
+ function_args: dict[str, Any] | None = None
909
+ if tool_call_id in active_tool_calls:
910
+ tool_name, function_args = active_tool_calls.pop(tool_call_id)
911
+ if not tool_call_id or not tool_name:
912
+ continue
913
+ result = message.get("content")
914
+ result_text = result if isinstance(result, str) else None
915
+ if not await _send(
916
+ build_tool_complete(
917
+ tool_call_id,
918
+ tool_name,
919
+ result=result_text,
920
+ function_args=function_args,
921
+ )
922
+ ):
923
+ return
924
+ if tool_name == "todo":
925
+ plan_update = _build_plan_update_from_todo_result(result_text)
926
+ if plan_update is not None and not await _send(plan_update):
927
+ return
928
+
929
+ async def new_session(
930
+ self,
931
+ cwd: str,
932
+ mcp_servers: list | None = None,
933
+ **kwargs: Any,
934
+ ) -> NewSessionResponse:
935
+ state = self.session_manager.create_session(cwd=cwd)
936
+ await self._register_session_mcp_servers(state, mcp_servers)
937
+ logger.info("New session %s (cwd=%s)", state.session_id, cwd)
938
+ self._schedule_available_commands_update(state.session_id)
939
+ self._schedule_usage_update(state)
940
+ return NewSessionResponse(
941
+ session_id=state.session_id,
942
+ models=self._build_model_state(state),
943
+ )
944
+
945
+ def _schedule_history_replay(self, state: SessionState) -> None:
946
+ """Replay persisted history after session/load or session/resume returns.
947
+
948
+ Zed only attaches streamed transcript/tool updates once the load/resume
949
+ response has completed. Sending replay notifications while the request is
950
+ still in-flight can make the server look correct in logs while the editor
951
+ drops or fails to attach the tool-call history.
952
+ """
953
+ loop = asyncio.get_running_loop()
954
+ replay_coro = self._replay_session_history(state)
955
+ loop.call_soon(asyncio.create_task, replay_coro)
956
+
957
+ async def load_session(
958
+ self,
959
+ cwd: str,
960
+ session_id: str,
961
+ mcp_servers: list | None = None,
962
+ **kwargs: Any,
963
+ ) -> LoadSessionResponse | None:
964
+ state = self.session_manager.update_cwd(session_id, cwd)
965
+ if state is None:
966
+ logger.warning("load_session: session %s not found", session_id)
967
+ return None
968
+ await self._register_session_mcp_servers(state, mcp_servers)
969
+ logger.info("Loaded session %s", session_id)
970
+ self._schedule_history_replay(state)
971
+ self._schedule_available_commands_update(session_id)
972
+ self._schedule_usage_update(state)
973
+ return LoadSessionResponse(models=self._build_model_state(state))
974
+
975
+ async def resume_session(
976
+ self,
977
+ cwd: str,
978
+ session_id: str,
979
+ mcp_servers: list | None = None,
980
+ **kwargs: Any,
981
+ ) -> ResumeSessionResponse:
982
+ state = self.session_manager.update_cwd(session_id, cwd)
983
+ if state is None:
984
+ logger.warning("resume_session: session %s not found, creating new", session_id)
985
+ state = self.session_manager.create_session(cwd=cwd)
986
+ await self._register_session_mcp_servers(state, mcp_servers)
987
+ logger.info("Resumed session %s", state.session_id)
988
+ self._schedule_history_replay(state)
989
+ self._schedule_available_commands_update(state.session_id)
990
+ self._schedule_usage_update(state)
991
+ return ResumeSessionResponse(models=self._build_model_state(state))
992
+
993
+ async def cancel(self, session_id: str, **kwargs: Any) -> None:
994
+ state = self.session_manager.get_session(session_id)
995
+ if state and state.cancel_event:
996
+ with state.runtime_lock:
997
+ if state.is_running and state.current_prompt_text:
998
+ state.interrupted_prompt_text = state.current_prompt_text
999
+ state.cancel_event.set()
1000
+ try:
1001
+ if getattr(state, "agent", None) and hasattr(state.agent, "interrupt"):
1002
+ state.agent.interrupt()
1003
+ except Exception:
1004
+ logger.debug("Failed to interrupt ACP session %s", session_id, exc_info=True)
1005
+ logger.info("Cancelled session %s", session_id)
1006
+
1007
+ async def fork_session(
1008
+ self,
1009
+ cwd: str,
1010
+ session_id: str,
1011
+ mcp_servers: list | None = None,
1012
+ **kwargs: Any,
1013
+ ) -> ForkSessionResponse:
1014
+ state = self.session_manager.fork_session(session_id, cwd=cwd)
1015
+ new_id = state.session_id if state else ""
1016
+ if state is not None:
1017
+ await self._register_session_mcp_servers(state, mcp_servers)
1018
+ logger.info("Forked session %s -> %s", session_id, new_id)
1019
+ if new_id:
1020
+ self._schedule_available_commands_update(new_id)
1021
+ return ForkSessionResponse(session_id=new_id)
1022
+
1023
+ async def list_sessions(
1024
+ self,
1025
+ cursor: str | None = None,
1026
+ cwd: str | None = None,
1027
+ **kwargs: Any,
1028
+ ) -> ListSessionsResponse:
1029
+ """List ACP sessions with optional ``cwd`` filtering and cursor pagination.
1030
+
1031
+ ``cwd`` is passed through to ``SessionManager.list_sessions`` which already
1032
+ normalizes and filters by working directory. ``cursor`` is a ``session_id``
1033
+ previously returned as ``next_cursor``; results resume after that entry.
1034
+ Server-side page size is capped at ``_LIST_SESSIONS_PAGE_SIZE``; when more
1035
+ results remain, ``next_cursor`` is set to the last returned ``session_id``.
1036
+ """
1037
+ infos = self.session_manager.list_sessions(cwd=cwd)
1038
+
1039
+ if cursor:
1040
+ for idx, s in enumerate(infos):
1041
+ if s["session_id"] == cursor:
1042
+ infos = infos[idx + 1:]
1043
+ break
1044
+ else:
1045
+ # Unknown cursor -> empty page (do not fall back to full list).
1046
+ infos = []
1047
+
1048
+ has_more = len(infos) > _LIST_SESSIONS_PAGE_SIZE
1049
+ infos = infos[:_LIST_SESSIONS_PAGE_SIZE]
1050
+
1051
+ sessions = []
1052
+ for s in infos:
1053
+ updated_at = s.get("updated_at")
1054
+ if updated_at is not None and not isinstance(updated_at, str):
1055
+ updated_at = str(updated_at)
1056
+ sessions.append(
1057
+ SessionInfo(
1058
+ session_id=s["session_id"],
1059
+ cwd=s["cwd"],
1060
+ title=s.get("title"),
1061
+ updated_at=updated_at,
1062
+ )
1063
+ )
1064
+
1065
+ next_cursor = sessions[-1].session_id if has_more and sessions else None
1066
+ return ListSessionsResponse(sessions=sessions, next_cursor=next_cursor)
1067
+
1068
+ # ---- Prompt (core) ------------------------------------------------------
1069
+
1070
+ async def prompt(
1071
+ self,
1072
+ prompt: list[
1073
+ TextContentBlock
1074
+ | ImageContentBlock
1075
+ | AudioContentBlock
1076
+ | ResourceContentBlock
1077
+ | EmbeddedResourceContentBlock
1078
+ ],
1079
+ session_id: str,
1080
+ **kwargs: Any,
1081
+ ) -> PromptResponse:
1082
+ """Run Hermes on the user's prompt and stream events back to the editor."""
1083
+ state = self.session_manager.get_session(session_id)
1084
+ if state is None:
1085
+ logger.error("prompt: session %s not found", session_id)
1086
+ return PromptResponse(stop_reason="refusal")
1087
+
1088
+ user_text = _extract_text(prompt).strip()
1089
+ user_content = _content_blocks_to_openai_user_content(prompt)
1090
+ text_only_prompt = all(isinstance(block, TextContentBlock) for block in prompt)
1091
+ has_content = bool(user_text) or (
1092
+ isinstance(user_content, list) and bool(user_content)
1093
+ )
1094
+ if not has_content:
1095
+ return PromptResponse(stop_reason="end_turn")
1096
+
1097
+ # /steer on an idle session has no in-flight tool call to inject into.
1098
+ # Rewrite it so the payload runs as a normal user prompt, matching the
1099
+ # gateway's behavior (gateway/run.py ~L4898). Two sub-cases:
1100
+ # 1. Zed-interrupt salvage — a prior prompt was cancelled by the
1101
+ # client right before /steer arrived; replay it with the steer
1102
+ # text attached as explicit correction/guidance so the user's
1103
+ # in-flight work isn't lost.
1104
+ # 2. Plain idle — no prior work to salvage; just run the steer
1105
+ # payload as a regular prompt. Without this, _cmd_steer would
1106
+ # silently append to state.queued_prompts and respond with
1107
+ # "No active turn — queued for the next turn", which looks like
1108
+ # /queue even though the user never typed /queue.
1109
+ if text_only_prompt and isinstance(user_content, str) and user_text.startswith("/steer"):
1110
+ steer_text = user_text.split(maxsplit=1)[1].strip() if len(user_text.split(maxsplit=1)) > 1 else ""
1111
+ interrupted_prompt = ""
1112
+ rewrite_idle = False
1113
+ with state.runtime_lock:
1114
+ if not state.is_running and steer_text:
1115
+ if state.interrupted_prompt_text:
1116
+ interrupted_prompt = state.interrupted_prompt_text
1117
+ state.interrupted_prompt_text = ""
1118
+ else:
1119
+ rewrite_idle = True
1120
+ if interrupted_prompt:
1121
+ user_text = (
1122
+ f"{interrupted_prompt}\n\n"
1123
+ f"User correction/guidance after interrupt: {steer_text}"
1124
+ )
1125
+ user_content = user_text
1126
+ elif rewrite_idle:
1127
+ user_text = steer_text
1128
+ user_content = steer_text
1129
+
1130
+ # Intercept slash commands — handle locally without calling the LLM.
1131
+ # Slash commands are text-only; if the client included images/resources,
1132
+ # send the whole multimodal prompt to the agent instead of treating it as
1133
+ # an ACP command.
1134
+ if text_only_prompt and isinstance(user_content, str) and user_text.startswith("/"):
1135
+ response_text = self._handle_slash_command(user_text, state)
1136
+ if response_text is not None:
1137
+ if self._conn:
1138
+ update = acp.update_agent_message_text(response_text)
1139
+ await self._conn.session_update(session_id, update)
1140
+ await self._send_usage_update(state)
1141
+ return PromptResponse(stop_reason="end_turn")
1142
+
1143
+ # If Zed sends another regular prompt while the same ACP session is
1144
+ # still running, queue it instead of racing two AIAgent loops against
1145
+ # the same state.history. /steer and /queue are handled above and can
1146
+ # land immediately.
1147
+ with state.runtime_lock:
1148
+ if state.is_running:
1149
+ queued_text = user_text or "[Image attachment]"
1150
+ state.queued_prompts.append(queued_text)
1151
+ depth = len(state.queued_prompts)
1152
+ if self._conn:
1153
+ update = acp.update_agent_message_text(
1154
+ f"Queued for the next turn. ({depth} queued)"
1155
+ )
1156
+ await self._conn.session_update(session_id, update)
1157
+ return PromptResponse(stop_reason="end_turn")
1158
+ state.is_running = True
1159
+ state.current_prompt_text = user_text or "[Image attachment]"
1160
+
1161
+ logger.info("Prompt on session %s: %s", session_id, user_text[:100])
1162
+
1163
+ conn = self._conn
1164
+ loop = asyncio.get_running_loop()
1165
+
1166
+ if state.cancel_event:
1167
+ state.cancel_event.clear()
1168
+
1169
+ tool_call_ids: dict[str, Deque[str]] = defaultdict(deque)
1170
+ tool_call_meta: dict[str, dict[str, Any]] = {}
1171
+ previous_approval_cb = None
1172
+
1173
+ streamed_message = False
1174
+
1175
+ if conn:
1176
+ tool_progress_cb = make_tool_progress_cb(conn, session_id, loop, tool_call_ids, tool_call_meta)
1177
+ reasoning_cb = make_thinking_cb(conn, session_id, loop)
1178
+ step_cb = make_step_cb(conn, session_id, loop, tool_call_ids, tool_call_meta)
1179
+ message_cb = make_message_cb(conn, session_id, loop)
1180
+
1181
+ def stream_delta_cb(text: str) -> None:
1182
+ nonlocal streamed_message
1183
+ if text:
1184
+ streamed_message = True
1185
+ message_cb(text)
1186
+
1187
+ approval_cb = make_approval_callback(conn.request_permission, loop, session_id)
1188
+ else:
1189
+ tool_progress_cb = None
1190
+ reasoning_cb = None
1191
+ step_cb = None
1192
+ stream_delta_cb = None
1193
+ approval_cb = None
1194
+
1195
+ agent = state.agent
1196
+ agent.tool_progress_callback = tool_progress_cb
1197
+ # ACP thought panes should not receive Hermes' local kawaii waiting/status
1198
+ # updates. Route provider/model reasoning deltas instead; if the provider
1199
+ # emits no reasoning, Zed should not get a fake "thinking" accordion.
1200
+ agent.thinking_callback = None
1201
+ agent.reasoning_callback = reasoning_cb
1202
+ agent.step_callback = step_cb
1203
+ agent.stream_delta_callback = stream_delta_cb
1204
+
1205
+ # Approval callback is per-thread (thread-local, GHSA-qg5c-hvr5-hjgr).
1206
+ # Set it INSIDE _run_agent so the TLS write happens in the executor
1207
+ # thread — setting it here would write to the event-loop thread's TLS,
1208
+ # not the executor's. Also set HERMES_INTERACTIVE so approval.py
1209
+ # takes the CLI-interactive path (which calls the registered
1210
+ # callback via prompt_dangerous_approval) instead of the
1211
+ # non-interactive auto-approve branch (GHSA-96vc-wcxf-jjff).
1212
+ # ACP's conn.request_permission maps cleanly to the interactive
1213
+ # callback shape — not the gateway-queue HERMES_EXEC_ASK path,
1214
+ # which requires a notify_cb registered in _gateway_notify_cbs.
1215
+ previous_approval_cb = None
1216
+ previous_interactive = None
1217
+
1218
+ def _run_agent() -> dict:
1219
+ nonlocal previous_approval_cb, previous_interactive
1220
+ # Bind HERMES_SESSION_KEY for this session so per-session caches
1221
+ # (e.g. the interactive sudo password cache in tools.terminal_tool)
1222
+ # scope to the ACP session rather than leaking across sessions
1223
+ # that land on the same reused executor thread. This call runs
1224
+ # inside a contextvars.copy_context() below, so the ContextVar
1225
+ # write is isolated from other concurrent ACP sessions.
1226
+ try:
1227
+ from gateway.session_context import (
1228
+ clear_session_vars,
1229
+ set_session_vars,
1230
+ )
1231
+ session_tokens = set_session_vars(session_key=session_id)
1232
+ except Exception:
1233
+ session_tokens = None
1234
+ clear_session_vars = None # type: ignore[assignment]
1235
+ logger.debug("Could not set ACP session context", exc_info=True)
1236
+ if approval_cb:
1237
+ try:
1238
+ from tools import terminal_tool as _terminal_tool
1239
+ previous_approval_cb = _terminal_tool._get_approval_callback()
1240
+ _terminal_tool.set_approval_callback(approval_cb)
1241
+ except Exception:
1242
+ logger.debug("Could not set ACP approval callback", exc_info=True)
1243
+ # Signal to tools.approval that we have an interactive callback
1244
+ # and the non-interactive auto-approve path must not fire.
1245
+ previous_interactive = os.environ.get("HERMES_INTERACTIVE")
1246
+ os.environ["HERMES_INTERACTIVE"] = "1"
1247
+ try:
1248
+ result = agent.run_conversation(
1249
+ user_message=user_content,
1250
+ conversation_history=state.history,
1251
+ task_id=session_id,
1252
+ persist_user_message=user_text or "[Image attachment]",
1253
+ )
1254
+ return result
1255
+ except Exception as e:
1256
+ logger.exception("Agent error in session %s", session_id)
1257
+ return {"final_response": f"Error: {e}", "messages": state.history}
1258
+ finally:
1259
+ # Restore HERMES_INTERACTIVE.
1260
+ if previous_interactive is None:
1261
+ os.environ.pop("HERMES_INTERACTIVE", None)
1262
+ else:
1263
+ os.environ["HERMES_INTERACTIVE"] = previous_interactive
1264
+ if approval_cb:
1265
+ try:
1266
+ from tools import terminal_tool as _terminal_tool
1267
+ _terminal_tool.set_approval_callback(previous_approval_cb)
1268
+ except Exception:
1269
+ logger.debug("Could not restore approval callback", exc_info=True)
1270
+ if session_tokens is not None and clear_session_vars is not None:
1271
+ try:
1272
+ clear_session_vars(session_tokens)
1273
+ except Exception:
1274
+ logger.debug("Could not clear ACP session context", exc_info=True)
1275
+
1276
+ try:
1277
+ # Wrap the executor call in a fresh copy of the current context so
1278
+ # concurrent ACP sessions on the shared ThreadPoolExecutor don't
1279
+ # stomp on each other's ContextVar writes (HERMES_SESSION_KEY in
1280
+ # particular — used by the interactive sudo password cache scope).
1281
+ ctx = contextvars.copy_context()
1282
+ result = await loop.run_in_executor(_executor, ctx.run, _run_agent)
1283
+ except Exception:
1284
+ logger.exception("Executor error for session %s", session_id)
1285
+ with state.runtime_lock:
1286
+ state.is_running = False
1287
+ state.current_prompt_text = ""
1288
+ return PromptResponse(stop_reason="end_turn")
1289
+
1290
+ if result.get("messages"):
1291
+ state.history = result["messages"]
1292
+ # Persist updated history so sessions survive process restarts.
1293
+ self.session_manager.save_session(session_id)
1294
+
1295
+ final_response = result.get("final_response", "")
1296
+ if final_response:
1297
+ try:
1298
+ from agent.title_generator import maybe_auto_title
1299
+
1300
+ maybe_auto_title(
1301
+ self.session_manager._get_db(),
1302
+ session_id,
1303
+ user_text,
1304
+ final_response,
1305
+ state.history,
1306
+ )
1307
+ except Exception:
1308
+ logger.debug("Failed to auto-title ACP session %s", session_id, exc_info=True)
1309
+ if final_response and conn and not streamed_message:
1310
+ update = acp.update_agent_message_text(final_response)
1311
+ await conn.session_update(session_id, update)
1312
+
1313
+ # Mark this turn idle before draining queued work so recursive prompt()
1314
+ # calls can acquire the session. Queued turns are intentionally run as
1315
+ # normal follow-up user prompts, preserving role alternation and history.
1316
+ with state.runtime_lock:
1317
+ state.is_running = False
1318
+ state.current_prompt_text = ""
1319
+
1320
+ while True:
1321
+ with state.runtime_lock:
1322
+ if not state.queued_prompts:
1323
+ break
1324
+ next_prompt = state.queued_prompts.pop(0)
1325
+ if conn:
1326
+ await conn.session_update(
1327
+ session_id,
1328
+ acp.update_user_message_text(next_prompt),
1329
+ )
1330
+ await self.prompt(
1331
+ prompt=[TextContentBlock(type="text", text=next_prompt)],
1332
+ session_id=session_id,
1333
+ )
1334
+
1335
+ usage = None
1336
+ if any(result.get(key) is not None for key in ("prompt_tokens", "completion_tokens", "total_tokens")):
1337
+ usage = Usage(
1338
+ input_tokens=result.get("prompt_tokens", 0),
1339
+ output_tokens=result.get("completion_tokens", 0),
1340
+ total_tokens=result.get("total_tokens", 0),
1341
+ thought_tokens=result.get("reasoning_tokens"),
1342
+ cached_read_tokens=result.get("cache_read_tokens"),
1343
+ )
1344
+
1345
+ await self._send_usage_update(state)
1346
+
1347
+ stop_reason = "cancelled" if state.cancel_event and state.cancel_event.is_set() else "end_turn"
1348
+ return PromptResponse(stop_reason=stop_reason, usage=usage)
1349
+
1350
+ # ---- Slash commands (headless) -------------------------------------------
1351
+
1352
+ @classmethod
1353
+ def _available_commands(cls) -> list[AvailableCommand]:
1354
+ commands: list[AvailableCommand] = []
1355
+ for spec in cls._ADVERTISED_COMMANDS:
1356
+ input_hint = spec.get("input_hint")
1357
+ commands.append(
1358
+ AvailableCommand(
1359
+ name=spec["name"],
1360
+ description=spec["description"],
1361
+ input=UnstructuredCommandInput(hint=input_hint)
1362
+ if input_hint
1363
+ else None,
1364
+ )
1365
+ )
1366
+ return commands
1367
+
1368
+ async def _send_available_commands_update(self, session_id: str) -> None:
1369
+ """Advertise supported slash commands to the connected ACP client."""
1370
+ if not self._conn:
1371
+ return
1372
+
1373
+ try:
1374
+ await self._conn.session_update(
1375
+ session_id=session_id,
1376
+ update=AvailableCommandsUpdate(
1377
+ session_update="available_commands_update",
1378
+ available_commands=self._available_commands(),
1379
+ ),
1380
+ )
1381
+ except Exception:
1382
+ logger.warning(
1383
+ "Failed to advertise ACP slash commands for session %s",
1384
+ session_id,
1385
+ exc_info=True,
1386
+ )
1387
+
1388
+ def _schedule_available_commands_update(self, session_id: str) -> None:
1389
+ """Send the command advertisement after the session response is queued."""
1390
+ if not self._conn:
1391
+ return
1392
+ loop = asyncio.get_running_loop()
1393
+ loop.call_soon(
1394
+ asyncio.create_task, self._send_available_commands_update(session_id)
1395
+ )
1396
+
1397
+ def _handle_slash_command(self, text: str, state: SessionState) -> str | None:
1398
+ """Dispatch a slash command and return the response text.
1399
+
1400
+ Returns ``None`` for unrecognized commands so they fall through
1401
+ to the LLM (the user may have typed ``/something`` as prose).
1402
+ """
1403
+ parts = text.split(maxsplit=1)
1404
+ cmd = parts[0].lstrip("/").lower()
1405
+ args = parts[1].strip() if len(parts) > 1 else ""
1406
+
1407
+ handler = {
1408
+ "help": self._cmd_help,
1409
+ "model": self._cmd_model,
1410
+ "tools": self._cmd_tools,
1411
+ "context": self._cmd_context,
1412
+ "reset": self._cmd_reset,
1413
+ "compact": self._cmd_compact,
1414
+ "steer": self._cmd_steer,
1415
+ "queue": self._cmd_queue,
1416
+ "version": self._cmd_version,
1417
+ }.get(cmd)
1418
+
1419
+ if handler is None:
1420
+ return None # not a known command — let the LLM handle it
1421
+
1422
+ try:
1423
+ return handler(args, state)
1424
+ except Exception as e:
1425
+ logger.error("Slash command /%s error: %s", cmd, e, exc_info=True)
1426
+ return f"Error executing /{cmd}: {e}"
1427
+
1428
+ def _cmd_help(self, args: str, state: SessionState) -> str:
1429
+ lines = ["Available commands:", ""]
1430
+ for cmd, desc in self._SLASH_COMMANDS.items():
1431
+ lines.append(f" /{cmd:10s} {desc}")
1432
+ lines.append("")
1433
+ lines.append("Unrecognized /commands are sent to the model as normal messages.")
1434
+ return "\n".join(lines)
1435
+
1436
+ def _cmd_model(self, args: str, state: SessionState) -> str:
1437
+ if not args:
1438
+ model = state.model or getattr(state.agent, "model", "unknown")
1439
+ provider = getattr(state.agent, "provider", None) or "auto"
1440
+ return f"Current model: {model}\nProvider: {provider}"
1441
+
1442
+ current_provider = getattr(state.agent, "provider", None) or "openrouter"
1443
+ target_provider, new_model = self._resolve_model_selection(args, current_provider)
1444
+
1445
+ state.model = new_model
1446
+ state.agent = self.session_manager._make_agent(
1447
+ session_id=state.session_id,
1448
+ cwd=state.cwd,
1449
+ model=new_model,
1450
+ requested_provider=target_provider,
1451
+ )
1452
+ self.session_manager.save_session(state.session_id)
1453
+ provider_label = getattr(state.agent, "provider", None) or target_provider or current_provider
1454
+ logger.info("Session %s: model switched to %s", state.session_id, new_model)
1455
+ return f"Model switched to: {new_model}\nProvider: {provider_label}"
1456
+
1457
+ def _cmd_tools(self, args: str, state: SessionState) -> str:
1458
+ try:
1459
+ from model_tools import get_tool_definitions
1460
+ toolsets = _expand_acp_enabled_toolsets(
1461
+ getattr(state.agent, "enabled_toolsets", None) or ["hermes-acp"]
1462
+ )
1463
+ tools = get_tool_definitions(enabled_toolsets=toolsets, quiet_mode=True)
1464
+ if not tools:
1465
+ return "No tools available."
1466
+ lines = [f"Available tools ({len(tools)}):"]
1467
+ for t in tools:
1468
+ name = t.get("function", {}).get("name", "?")
1469
+ desc = t.get("function", {}).get("description", "")
1470
+ # Truncate long descriptions
1471
+ if len(desc) > 80:
1472
+ desc = desc[:77] + "..."
1473
+ lines.append(f" {name}: {desc}")
1474
+ return "\n".join(lines)
1475
+ except Exception as e:
1476
+ return f"Could not list tools: {e}"
1477
+
1478
+ def _cmd_context(self, args: str, state: SessionState) -> str:
1479
+ """Show ACP session context pressure and compression guidance."""
1480
+ n_messages = len(state.history)
1481
+
1482
+ # Count by role.
1483
+ roles: dict[str, int] = {}
1484
+ for msg in state.history:
1485
+ role = msg.get("role", "unknown")
1486
+ roles[role] = roles.get(role, 0) + 1
1487
+
1488
+ agent = state.agent
1489
+ model = state.model or getattr(agent, "model", "")
1490
+ provider = getattr(agent, "provider", None) or "auto"
1491
+ compressor = getattr(agent, "context_compressor", None)
1492
+ context_length = int(getattr(compressor, "context_length", 0) or 0)
1493
+ threshold_tokens = int(getattr(compressor, "threshold_tokens", 0) or 0)
1494
+
1495
+ try:
1496
+ from agent.model_metadata import estimate_request_tokens_rough
1497
+
1498
+ system_prompt = getattr(agent, "_cached_system_prompt", "") or ""
1499
+ tools = getattr(agent, "tools", None) or None
1500
+ approx_tokens = estimate_request_tokens_rough(
1501
+ state.history,
1502
+ system_prompt=system_prompt,
1503
+ tools=tools,
1504
+ )
1505
+ except Exception:
1506
+ logger.debug("Could not estimate ACP context usage", exc_info=True)
1507
+ approx_tokens = 0
1508
+
1509
+ if threshold_tokens <= 0 and context_length > 0:
1510
+ threshold_tokens = int(context_length * 0.80)
1511
+
1512
+ lines = [
1513
+ f"Conversation: {n_messages} messages"
1514
+ if n_messages
1515
+ else "Conversation is empty (no messages yet).",
1516
+ f" user: {roles.get('user', 0)}, assistant: {roles.get('assistant', 0)}, "
1517
+ f"tool: {roles.get('tool', 0)}, system: {roles.get('system', 0)}",
1518
+ ]
1519
+ if model:
1520
+ lines.append(f"Model: {model}")
1521
+ lines.append(f"Provider: {provider}")
1522
+
1523
+ if approx_tokens > 0:
1524
+ if context_length > 0:
1525
+ usage_pct = (approx_tokens / context_length) * 100
1526
+ lines.append(
1527
+ f"Context usage: ~{approx_tokens:,} / {context_length:,} tokens ({usage_pct:.1f}%)"
1528
+ )
1529
+ else:
1530
+ lines.append(f"Context usage: ~{approx_tokens:,} tokens")
1531
+
1532
+ if threshold_tokens > 0:
1533
+ if approx_tokens > 0:
1534
+ threshold_pct = (threshold_tokens / context_length) * 100 if context_length > 0 else 0
1535
+ remaining = max(threshold_tokens - approx_tokens, 0)
1536
+ if approx_tokens >= threshold_tokens:
1537
+ lines.append(
1538
+ f"Compression: due now (threshold ~{threshold_tokens:,}"
1539
+ + (f", {threshold_pct:.0f}%" if threshold_pct else "")
1540
+ + "). Run /compact."
1541
+ )
1542
+ else:
1543
+ lines.append(
1544
+ f"Compression: ~{remaining:,} tokens until threshold "
1545
+ f"(~{threshold_tokens:,}"
1546
+ + (f", {threshold_pct:.0f}%" if threshold_pct else "")
1547
+ + ")."
1548
+ )
1549
+ else:
1550
+ lines.append(f"Compression threshold: ~{threshold_tokens:,} tokens")
1551
+
1552
+ if getattr(agent, "compression_enabled", True) is False:
1553
+ lines.append("Compression is disabled for this agent.")
1554
+ else:
1555
+ lines.append("Tip: run /compact to compress manually before the threshold.")
1556
+
1557
+ return "\n".join(lines)
1558
+
1559
+ def _cmd_reset(self, args: str, state: SessionState) -> str:
1560
+ state.history.clear()
1561
+ self.session_manager.save_session(state.session_id)
1562
+ return "Conversation history cleared."
1563
+
1564
+ def _cmd_compact(self, args: str, state: SessionState) -> str:
1565
+ if not state.history:
1566
+ return "Nothing to compress — conversation is empty."
1567
+ try:
1568
+ agent = state.agent
1569
+ if not getattr(agent, "compression_enabled", True):
1570
+ return "Context compression is disabled for this agent."
1571
+ if not hasattr(agent, "_compress_context"):
1572
+ return "Context compression not available for this agent."
1573
+
1574
+ from agent.model_metadata import estimate_request_tokens_rough
1575
+
1576
+ original_count = len(state.history)
1577
+ # Include system prompt + tool schemas so the figure reflects real
1578
+ # request pressure, not a transcript-only underestimate (#6217).
1579
+ _sys_prompt = getattr(agent, "_cached_system_prompt", "") or ""
1580
+ _tools = getattr(agent, "tools", None) or None
1581
+ approx_tokens = estimate_request_tokens_rough(
1582
+ state.history, system_prompt=_sys_prompt, tools=_tools
1583
+ )
1584
+ original_session_db = getattr(agent, "_session_db", None)
1585
+
1586
+ try:
1587
+ # ACP sessions must keep a stable session id, so avoid the
1588
+ # SQLite session-splitting side effect inside _compress_context.
1589
+ agent._session_db = None
1590
+ compressed, _ = agent._compress_context(
1591
+ state.history,
1592
+ getattr(agent, "_cached_system_prompt", "") or "",
1593
+ approx_tokens=approx_tokens,
1594
+ task_id=state.session_id,
1595
+ )
1596
+ finally:
1597
+ agent._session_db = original_session_db
1598
+
1599
+ state.history = compressed
1600
+ self.session_manager.save_session(state.session_id)
1601
+
1602
+ new_count = len(state.history)
1603
+ _sys_prompt_after = getattr(agent, "_cached_system_prompt", "") or _sys_prompt
1604
+ _tools_after = getattr(agent, "tools", None) or _tools
1605
+ new_tokens = estimate_request_tokens_rough(
1606
+ state.history,
1607
+ system_prompt=_sys_prompt_after,
1608
+ tools=_tools_after,
1609
+ )
1610
+ return (
1611
+ f"Context compressed: {original_count} -> {new_count} messages\n"
1612
+ f"~{approx_tokens:,} -> ~{new_tokens:,} tokens"
1613
+ )
1614
+ except Exception as e:
1615
+ return f"Compression failed: {e}"
1616
+
1617
+ def _cmd_steer(self, args: str, state: SessionState) -> str:
1618
+ steer_text = args.strip()
1619
+ if not steer_text:
1620
+ return "Usage: /steer <guidance>"
1621
+
1622
+ if state.is_running and hasattr(state.agent, "steer"):
1623
+ try:
1624
+ if state.agent.steer(steer_text):
1625
+ preview = steer_text[:80] + ("..." if len(steer_text) > 80 else "")
1626
+ return f"⏩ Steer queued for the active turn: {preview}"
1627
+ except Exception as exc:
1628
+ logger.warning("ACP steer failed for session %s: %s", state.session_id, exc)
1629
+ return f"⚠️ Steer failed: {exc}"
1630
+
1631
+ with state.runtime_lock:
1632
+ state.queued_prompts.append(steer_text)
1633
+ depth = len(state.queued_prompts)
1634
+ return f"No active turn — queued for the next turn. ({depth} queued)"
1635
+
1636
+ def _cmd_queue(self, args: str, state: SessionState) -> str:
1637
+ queued_text = args.strip()
1638
+ if not queued_text:
1639
+ return "Usage: /queue <prompt>"
1640
+ with state.runtime_lock:
1641
+ state.queued_prompts.append(queued_text)
1642
+ depth = len(state.queued_prompts)
1643
+ return f"Queued for the next turn. ({depth} queued)"
1644
+
1645
+ def _cmd_version(self, args: str, state: SessionState) -> str:
1646
+ return f"Hermes Agent v{HERMES_VERSION}"
1647
+
1648
+ # ---- Model switching (ACP protocol method) -------------------------------
1649
+
1650
+ async def set_session_model(
1651
+ self, model_id: str, session_id: str, **kwargs: Any
1652
+ ) -> SetSessionModelResponse | None:
1653
+ """Switch the model for a session (called by ACP protocol)."""
1654
+ state = self.session_manager.get_session(session_id)
1655
+ if state:
1656
+ current_provider = getattr(state.agent, "provider", None)
1657
+ requested_provider, resolved_model = self._resolve_model_selection(
1658
+ model_id,
1659
+ current_provider or "openrouter",
1660
+ )
1661
+ state.model = resolved_model
1662
+ provider_changed = bool(current_provider and requested_provider != current_provider)
1663
+ current_base_url = None if provider_changed else getattr(state.agent, "base_url", None)
1664
+ current_api_mode = None if provider_changed else getattr(state.agent, "api_mode", None)
1665
+ state.agent = self.session_manager._make_agent(
1666
+ session_id=session_id,
1667
+ cwd=state.cwd,
1668
+ model=resolved_model,
1669
+ requested_provider=requested_provider,
1670
+ base_url=current_base_url,
1671
+ api_mode=current_api_mode,
1672
+ )
1673
+ self.session_manager.save_session(session_id)
1674
+ logger.info(
1675
+ "Session %s: model switched to %s via provider %s",
1676
+ session_id,
1677
+ resolved_model,
1678
+ requested_provider,
1679
+ )
1680
+ return SetSessionModelResponse()
1681
+ logger.warning("Session %s: model switch requested for missing session", session_id)
1682
+ return None
1683
+
1684
+ async def set_session_mode(
1685
+ self, mode_id: str, session_id: str, **kwargs: Any
1686
+ ) -> SetSessionModeResponse | None:
1687
+ """Persist the editor-requested mode so ACP clients do not fail on mode switches."""
1688
+ state = self.session_manager.get_session(session_id)
1689
+ if state is None:
1690
+ logger.warning("Session %s: mode switch requested for missing session", session_id)
1691
+ return None
1692
+ setattr(state, "mode", mode_id)
1693
+ self.session_manager.save_session(session_id)
1694
+ logger.info("Session %s: mode switched to %s", session_id, mode_id)
1695
+ return SetSessionModeResponse()
1696
+
1697
+ async def set_config_option(
1698
+ self, config_id: str, session_id: str, value: str, **kwargs: Any
1699
+ ) -> SetSessionConfigOptionResponse | None:
1700
+ """Accept ACP config option updates even when Hermes has no typed ACP config surface yet."""
1701
+ state = self.session_manager.get_session(session_id)
1702
+ if state is None:
1703
+ logger.warning("Session %s: config update requested for missing session", session_id)
1704
+ return None
1705
+
1706
+ options = getattr(state, "config_options", None)
1707
+ if not isinstance(options, dict):
1708
+ options = {}
1709
+ options[str(config_id)] = value
1710
+ setattr(state, "config_options", options)
1711
+ self.session_manager.save_session(session_id)
1712
+ logger.info("Session %s: config option %s updated", session_id, config_id)
1713
+ return SetSessionConfigOptionResponse(config_options=[])