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,1825 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ File Operations Module
4
+
5
+ Provides file manipulation capabilities (read, write, patch, search) that work
6
+ across all terminal backends (local, docker, ssh, singularity, modal, daytona, vercel_sandbox).
7
+
8
+ The key insight is that all file operations can be expressed as shell commands,
9
+ so we wrap the terminal backend's execute() interface to provide a unified file API.
10
+
11
+ Usage:
12
+ from tools.file_operations import ShellFileOperations
13
+ from tools.terminal_tool import _active_environments
14
+
15
+ # Get file operations for a terminal environment
16
+ file_ops = ShellFileOperations(terminal_env)
17
+
18
+ # Read a file
19
+ result = file_ops.read_file("/path/to/file.py")
20
+
21
+ # Write a file
22
+ result = file_ops.write_file("/path/to/new.py", "print('hello')")
23
+
24
+ # Search for content
25
+ result = file_ops.search("TODO", path=".", file_glob="*.py")
26
+ """
27
+
28
+ import os
29
+ import re
30
+ import difflib
31
+ from abc import ABC, abstractmethod
32
+ from dataclasses import dataclass, field
33
+ from typing import Optional, List, Dict, Any
34
+ from pathlib import Path
35
+ from tools.binary_extensions import BINARY_EXTENSIONS
36
+
37
+ from agent.file_safety import (
38
+ build_write_denied_paths,
39
+ build_write_denied_prefixes,
40
+ get_safe_write_root as _shared_get_safe_write_root,
41
+ is_write_denied as _shared_is_write_denied,
42
+ )
43
+
44
+
45
+ # ---------------------------------------------------------------------------
46
+ # Write-path deny list — blocks writes to sensitive system/credential files
47
+ # ---------------------------------------------------------------------------
48
+
49
+ _HOME = str(Path.home())
50
+
51
+ WRITE_DENIED_PATHS = build_write_denied_paths(_HOME)
52
+
53
+ WRITE_DENIED_PREFIXES = build_write_denied_prefixes(_HOME)
54
+
55
+
56
+ _OSC_SEQUENCE_RE = re.compile(r"\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)")
57
+ _FENCE_MARKER_RE = re.compile(r"'?\x07?__HERMES_FENCE_[A-Za-z0-9]+__\x07?'?")
58
+
59
+
60
+ def _strip_terminal_fence_leaks(text: str) -> str:
61
+ """Strip leaked terminal fence wrappers from file read output."""
62
+ if not text:
63
+ return text
64
+
65
+ cleaned_lines: List[str] = []
66
+ for line in text.splitlines(keepends=True):
67
+ had_terminal_wrapper = "__HERMES_FENCE_" in line or "\x1b]" in line
68
+ cleaned = _OSC_SEQUENCE_RE.sub("", line)
69
+ cleaned = _FENCE_MARKER_RE.sub("", cleaned)
70
+ cleaned = cleaned.replace("\x07", "")
71
+ if had_terminal_wrapper and cleaned.strip("'\r\n\t ") == "":
72
+ continue
73
+ cleaned_lines.append(cleaned)
74
+ return "".join(cleaned_lines)
75
+
76
+
77
+ def _get_safe_write_root() -> Optional[str]:
78
+ """Return the resolved HERMES_WRITE_SAFE_ROOT path, or None if unset.
79
+
80
+ When set, all write_file/patch operations are constrained to this
81
+ directory tree. Writes outside it are denied even if the target is
82
+ not on the static deny list. Opt-in hardening for gateway/messaging
83
+ deployments that should only touch a workspace checkout.
84
+ """
85
+ return _shared_get_safe_write_root()
86
+
87
+
88
+ def _is_write_denied(path: str) -> bool:
89
+ """Return True if path is on the write deny list."""
90
+ return _shared_is_write_denied(path)
91
+
92
+
93
+ # =============================================================================
94
+ # Result Data Classes
95
+ # =============================================================================
96
+
97
+ @dataclass
98
+ class ReadResult:
99
+ """Result from reading a file."""
100
+ content: str = ""
101
+ total_lines: int = 0
102
+ file_size: int = 0
103
+ truncated: bool = False
104
+ hint: Optional[str] = None
105
+ is_binary: bool = False
106
+ is_image: bool = False
107
+ base64_content: Optional[str] = None
108
+ mime_type: Optional[str] = None
109
+ dimensions: Optional[str] = None # For images: "WIDTHxHEIGHT"
110
+ error: Optional[str] = None
111
+ similar_files: List[str] = field(default_factory=list)
112
+
113
+ def to_dict(self) -> dict:
114
+ return {k: v for k, v in self.__dict__.items() if v is not None and v != []}
115
+
116
+
117
+ @dataclass
118
+ class WriteResult:
119
+ """Result from writing a file."""
120
+ bytes_written: int = 0
121
+ dirs_created: bool = False
122
+ lint: Optional[Dict[str, Any]] = None
123
+ # Semantic diagnostics from the LSP layer, when applicable. Kept in
124
+ # its own field (not folded into ``lint``) so the model and any
125
+ # downstream parsers can read syntax errors and semantic errors as
126
+ # separate signals. ``None`` when LSP is disabled, when the file
127
+ # isn't in a git workspace, or when no diagnostics were introduced
128
+ # by this edit.
129
+ lsp_diagnostics: Optional[str] = None
130
+ error: Optional[str] = None
131
+ warning: Optional[str] = None
132
+
133
+ def to_dict(self) -> dict:
134
+ return {k: v for k, v in self.__dict__.items() if v is not None}
135
+
136
+
137
+ @dataclass
138
+ class PatchResult:
139
+ """Result from patching a file."""
140
+ success: bool = False
141
+ diff: str = ""
142
+ files_modified: List[str] = field(default_factory=list)
143
+ files_created: List[str] = field(default_factory=list)
144
+ files_deleted: List[str] = field(default_factory=list)
145
+ lint: Optional[Dict[str, Any]] = None
146
+ # See :class:`WriteResult.lsp_diagnostics`.
147
+ lsp_diagnostics: Optional[str] = None
148
+ error: Optional[str] = None
149
+
150
+ def to_dict(self) -> dict:
151
+ result = {"success": self.success}
152
+ if self.diff:
153
+ result["diff"] = self.diff
154
+ if self.files_modified:
155
+ result["files_modified"] = self.files_modified
156
+ if self.files_created:
157
+ result["files_created"] = self.files_created
158
+ if self.files_deleted:
159
+ result["files_deleted"] = self.files_deleted
160
+ if self.lint:
161
+ result["lint"] = self.lint
162
+ if self.lsp_diagnostics:
163
+ result["lsp_diagnostics"] = self.lsp_diagnostics
164
+ if self.error:
165
+ result["error"] = self.error
166
+ return result
167
+
168
+
169
+ @dataclass
170
+ class SearchMatch:
171
+ """A single search match."""
172
+ path: str
173
+ line_number: int
174
+ content: str
175
+ mtime: float = 0.0 # Modification time for sorting
176
+
177
+
178
+ @dataclass
179
+ class SearchResult:
180
+ """Result from searching."""
181
+ matches: List[SearchMatch] = field(default_factory=list)
182
+ files: List[str] = field(default_factory=list)
183
+ counts: Dict[str, int] = field(default_factory=dict)
184
+ total_count: int = 0
185
+ truncated: bool = False
186
+ error: Optional[str] = None
187
+
188
+ def to_dict(self) -> dict:
189
+ result = {"total_count": self.total_count}
190
+ if self.matches:
191
+ result["matches"] = [
192
+ {"path": m.path, "line": m.line_number, "content": m.content}
193
+ for m in self.matches
194
+ ]
195
+ if self.files:
196
+ result["files"] = self.files
197
+ if self.counts:
198
+ result["counts"] = self.counts
199
+ if self.truncated:
200
+ result["truncated"] = True
201
+ if self.error:
202
+ result["error"] = self.error
203
+ return result
204
+
205
+
206
+ @dataclass
207
+ class LintResult:
208
+ """Result from linting a file."""
209
+ success: bool = True
210
+ skipped: bool = False
211
+ output: str = ""
212
+ message: str = ""
213
+
214
+ def to_dict(self) -> dict:
215
+ if self.skipped:
216
+ return {"status": "skipped", "message": self.message}
217
+ result = {"status": "ok" if self.success else "error", "output": self.output}
218
+ if self.message:
219
+ result["message"] = self.message
220
+ return result
221
+
222
+
223
+ @dataclass
224
+ class ExecuteResult:
225
+ """Result from executing a shell command."""
226
+ stdout: str = ""
227
+ exit_code: int = 0
228
+
229
+
230
+ def _parse_search_context_line(line: str) -> tuple[str, int, str] | None:
231
+ """Parse grep/rg context output in ``path-line-content`` format.
232
+
233
+ Context lines are ambiguous because filenames may legitimately contain
234
+ ``-<digits>-`` segments. Prefer the rightmost numeric separator so a path
235
+ like ``dir/file-12-name.py-8-context`` resolves to
236
+ ``dir/file-12-name.py`` line ``8`` instead of truncating at ``file``.
237
+ """
238
+ if not line or line == "--":
239
+ return None
240
+
241
+ match = None
242
+ for candidate in re.finditer(r'-(\d+)-', line):
243
+ match = candidate
244
+
245
+ if match is None:
246
+ return None
247
+
248
+ path = line[:match.start()]
249
+ if not path:
250
+ return None
251
+
252
+ return path, int(match.group(1)), line[match.end():]
253
+
254
+
255
+ # =============================================================================
256
+ # Abstract Interface
257
+ # =============================================================================
258
+
259
+ class FileOperations(ABC):
260
+ """Abstract interface for file operations across terminal backends."""
261
+
262
+ @abstractmethod
263
+ def read_file(self, path: str, offset: int = 1, limit: int = 500) -> ReadResult:
264
+ """Read a file with pagination support."""
265
+ ...
266
+
267
+ @abstractmethod
268
+ def read_file_raw(self, path: str) -> ReadResult:
269
+ """Read the complete file content as a plain string.
270
+
271
+ No pagination, no line-number prefixes, no per-line truncation.
272
+ Returns ReadResult with .content = full file text, .error set on
273
+ failure. Always reads to EOF regardless of file size.
274
+ """
275
+ ...
276
+
277
+ @abstractmethod
278
+ def write_file(self, path: str, content: str) -> WriteResult:
279
+ """Write content to a file, creating directories as needed."""
280
+ ...
281
+
282
+ @abstractmethod
283
+ def patch_replace(self, path: str, old_string: str, new_string: str,
284
+ replace_all: bool = False) -> PatchResult:
285
+ """Replace text in a file using fuzzy matching."""
286
+ ...
287
+
288
+ @abstractmethod
289
+ def patch_v4a(self, patch_content: str) -> PatchResult:
290
+ """Apply a V4A format patch."""
291
+ ...
292
+
293
+ @abstractmethod
294
+ def delete_file(self, path: str) -> WriteResult:
295
+ """Delete a file. Returns WriteResult with .error set on failure."""
296
+ ...
297
+
298
+ @abstractmethod
299
+ def move_file(self, src: str, dst: str) -> WriteResult:
300
+ """Move/rename a file from src to dst. Returns WriteResult with .error set on failure."""
301
+ ...
302
+
303
+ @abstractmethod
304
+ def search(self, pattern: str, path: str = ".", target: str = "content",
305
+ file_glob: Optional[str] = None, limit: int = 50, offset: int = 0,
306
+ output_mode: str = "content", context: int = 0) -> SearchResult:
307
+ """Search for content or files."""
308
+ ...
309
+
310
+
311
+ # =============================================================================
312
+ # Shell-based Implementation
313
+ # =============================================================================
314
+
315
+ # Image extensions (subset of binary that we can return as base64)
316
+ IMAGE_EXTENSIONS = {'.png', '.jpg', '.jpeg', '.gif', '.webp', '.bmp', '.ico'}
317
+
318
+ # Shell-based linters by file extension. Invoked via _exec() with the
319
+ # filesystem path. Cover languages where a compile/type check needs an
320
+ # external toolchain (py_compile, node, tsc, go vet, rustfmt).
321
+ LINTERS = {
322
+ '.py': 'python -m py_compile {file} 2>&1',
323
+ '.js': 'node --check {file} 2>&1',
324
+ '.ts': 'npx tsc --noEmit {file} 2>&1',
325
+ '.go': 'go vet {file} 2>&1',
326
+ '.rs': 'rustfmt --check {file} 2>&1',
327
+ }
328
+
329
+
330
+ # Patterns that indicate the linter base command exists on PATH but
331
+ # couldn't actually run — e.g. ``npx tsc`` when tsc isn't installed in
332
+ # node_modules, or rustfmt complaining there's no Cargo project. When
333
+ # any of these substrings appears in the linter output, ``_check_lint``
334
+ # returns ``skipped`` instead of ``error`` so:
335
+ #
336
+ # 1. The write isn't flagged for a tooling problem the agent can't fix.
337
+ # 2. The LSP semantic tier still runs (it gates on success/skipped).
338
+ #
339
+ # Patterns are matched case-insensitively against linter stdout.
340
+ _LINTER_UNUSABLE_PATTERNS = {
341
+ 'npx': (
342
+ # npx prints this banner when the package isn't installed locally
343
+ # AND it can't auto-install (no internet, registry off, etc.) or
344
+ # when the binary it tried to run is the wrong one.
345
+ 'this is not the tsc command you are looking for',
346
+ # npx with --no-install resolution failures
347
+ 'could not determine executable to run',
348
+ 'not found in npm registry',
349
+ ),
350
+ 'rustfmt': (
351
+ # rustfmt outside a Cargo project
352
+ 'no input filename given',
353
+ 'error: not a workspace',
354
+ ),
355
+ 'go': (
356
+ # ``go vet`` on a file outside a module / GOPATH
357
+ 'cannot find package',
358
+ 'go: cannot find main module',
359
+ ),
360
+ }
361
+
362
+
363
+ def _looks_like_linter_unusable(base_cmd: str, output: str) -> bool:
364
+ """Return True iff ``output`` from ``base_cmd`` indicates the linter
365
+ itself couldn't run (a tooling gap), as opposed to a real lint error
366
+ in the file being checked.
367
+
368
+ ``base_cmd`` is the first word of the linter command line (``npx``,
369
+ ``rustfmt``, ``go``, ...). ``output`` is the stdout/stderr captured
370
+ from running it.
371
+ """
372
+ patterns = _LINTER_UNUSABLE_PATTERNS.get(base_cmd)
373
+ if not patterns:
374
+ return False
375
+ lower = output.lower()
376
+ return any(p in lower for p in patterns)
377
+
378
+
379
+ def _lint_json_inproc(content: str) -> tuple[bool, str]:
380
+ """In-process JSON syntax check. Returns (ok, error_message)."""
381
+ import json as _json
382
+ try:
383
+ _json.loads(content)
384
+ return True, ""
385
+ except _json.JSONDecodeError as e:
386
+ return False, f"JSONDecodeError: {e.msg} (line {e.lineno}, column {e.colno})"
387
+ except Exception as e: # noqa: BLE001 — any parse failure is a lint failure
388
+ return False, f"{type(e).__name__}: {e}"
389
+
390
+
391
+ def _lint_yaml_inproc(content: str) -> tuple[bool, str]:
392
+ """In-process YAML syntax check. Returns (ok, error_message).
393
+
394
+ Skipped gracefully if PyYAML isn't installed — YAML parsing is optional.
395
+ """
396
+ try:
397
+ import yaml as _yaml
398
+ except ImportError:
399
+ # PyYAML not available — skip silently, caller treats as no linter.
400
+ return True, "__SKIP__"
401
+ try:
402
+ _yaml.safe_load(content)
403
+ return True, ""
404
+ except _yaml.YAMLError as e:
405
+ return False, f"YAMLError: {e}"
406
+ except Exception as e: # noqa: BLE001
407
+ return False, f"{type(e).__name__}: {e}"
408
+
409
+
410
+ def _lint_toml_inproc(content: str) -> tuple[bool, str]:
411
+ """In-process TOML syntax check (stdlib tomllib, Python 3.11+)."""
412
+ try:
413
+ import tomllib as _toml
414
+ except ImportError:
415
+ # Pre-3.11 fallback via tomli, if installed.
416
+ try:
417
+ import tomli as _toml # type: ignore[no-redef]
418
+ except ImportError:
419
+ return True, "__SKIP__"
420
+ try:
421
+ _toml.loads(content)
422
+ return True, ""
423
+ except Exception as e: # tomllib raises TOMLDecodeError, a ValueError subclass
424
+ return False, f"{type(e).__name__}: {e}"
425
+
426
+
427
+ def _lint_python_inproc(content: str) -> tuple[bool, str]:
428
+ """In-process Python syntax check via ast.parse.
429
+
430
+ Catches SyntaxError, IndentationError, and everything else the
431
+ ast module rejects — matching py_compile's scope but with no
432
+ subprocess overhead and no dependency on a ``python`` in PATH.
433
+ """
434
+ import ast as _ast
435
+ try:
436
+ _ast.parse(content)
437
+ return True, ""
438
+ except SyntaxError as e:
439
+ loc = f" (line {e.lineno}, column {e.offset})" if e.lineno else ""
440
+ return False, f"{type(e).__name__}: {e.msg}{loc}"
441
+ except Exception as e: # noqa: BLE001
442
+ return False, f"{type(e).__name__}: {e}"
443
+
444
+
445
+ # In-process linters by file extension. Preferred over shell linters when
446
+ # present — no subprocess overhead, microseconds per call. Each callable
447
+ # takes file content (str) and returns (ok: bool, error: str). An error
448
+ # string of ``"__SKIP__"`` signals the linter isn't available (missing
449
+ # dependency) and should be treated as "no linter".
450
+ LINTERS_INPROC = {
451
+ '.py': _lint_python_inproc,
452
+ '.json': _lint_json_inproc,
453
+ '.yaml': _lint_yaml_inproc,
454
+ '.yml': _lint_yaml_inproc,
455
+ '.toml': _lint_toml_inproc,
456
+ }
457
+
458
+ # Max limits for read operations
459
+ MAX_LINES = 2000
460
+ MAX_LINE_LENGTH = 2000
461
+ MAX_FILE_SIZE = 50 * 1024 # 50KB
462
+ DEFAULT_READ_OFFSET = 1
463
+ DEFAULT_READ_LIMIT = 500
464
+ DEFAULT_SEARCH_OFFSET = 0
465
+ DEFAULT_SEARCH_LIMIT = 50
466
+
467
+
468
+ def _coerce_int(value: Any, default: int) -> int:
469
+ """Best-effort integer coercion for tool pagination inputs."""
470
+ try:
471
+ return int(value)
472
+ except (TypeError, ValueError):
473
+ return default
474
+
475
+
476
+ def normalize_read_pagination(offset: Any = DEFAULT_READ_OFFSET,
477
+ limit: Any = DEFAULT_READ_LIMIT) -> tuple[int, int]:
478
+ """Return safe read_file pagination bounds.
479
+
480
+ Tool schemas declare minimum/maximum values, but not every caller or
481
+ provider enforces schemas before dispatch. Clamp here so invalid values
482
+ cannot leak into sed ranges like ``0,-1p``.
483
+
484
+ The upper bound on ``limit`` comes from ``tool_output.max_lines`` in
485
+ config.yaml (defaults to the module-level ``MAX_LINES`` constant).
486
+ """
487
+ from tools.tool_output_limits import get_max_lines
488
+ max_lines = get_max_lines()
489
+ normalized_offset = max(1, _coerce_int(offset, DEFAULT_READ_OFFSET))
490
+ normalized_limit = _coerce_int(limit, DEFAULT_READ_LIMIT)
491
+ normalized_limit = max(1, min(normalized_limit, max_lines))
492
+ return normalized_offset, normalized_limit
493
+
494
+
495
+ def normalize_search_pagination(offset: Any = DEFAULT_SEARCH_OFFSET,
496
+ limit: Any = DEFAULT_SEARCH_LIMIT) -> tuple[int, int]:
497
+ """Return safe search pagination bounds for shell head/tail pipelines."""
498
+ normalized_offset = max(0, _coerce_int(offset, DEFAULT_SEARCH_OFFSET))
499
+ normalized_limit = max(1, _coerce_int(limit, DEFAULT_SEARCH_LIMIT))
500
+ return normalized_offset, normalized_limit
501
+
502
+
503
+ class ShellFileOperations(FileOperations):
504
+ """
505
+ File operations implemented via shell commands.
506
+
507
+ Works with ANY terminal backend that has execute(command, cwd) method.
508
+ This includes local, docker, singularity, ssh, modal, and daytona environments.
509
+ """
510
+
511
+ def __init__(self, terminal_env, cwd: str = None):
512
+ """
513
+ Initialize file operations with a terminal environment.
514
+
515
+ Args:
516
+ terminal_env: Any object with execute(command, cwd) method.
517
+ Returns {"output": str, "returncode": int}
518
+ cwd: Optional explicit fallback cwd when the terminal env has
519
+ no cwd attribute (rare — most backends track cwd live).
520
+
521
+ Note:
522
+ Every _exec() call prefers the LIVE ``terminal_env.cwd`` over
523
+ ``self.cwd`` so ``cd`` commands run via the terminal tool are
524
+ picked up immediately. ``self.cwd`` is only used as a fallback
525
+ when the env has no cwd at all — it is NOT the authoritative
526
+ cwd, despite being settable at init time.
527
+
528
+ Historical bug (fixed): prior versions of this class used the
529
+ init-time cwd for every _exec() call, which caused relative
530
+ paths passed to patch/read/write to target the wrong directory
531
+ after the user ran ``cd`` in the terminal. Patches would
532
+ claim success and return a plausible diff but land in the
533
+ original directory, producing apparent silent failures.
534
+ """
535
+ self.env = terminal_env
536
+ # Determine cwd from various possible sources.
537
+ # IMPORTANT: do NOT fall back to os.getcwd() -- that's the HOST's local
538
+ # path which doesn't exist inside container/cloud backends (modal, docker).
539
+ # If nothing provides a cwd, use "/" as a safe universal default.
540
+ self.cwd = cwd or getattr(terminal_env, 'cwd', None) or \
541
+ getattr(getattr(terminal_env, 'config', None), 'cwd', None) or "/"
542
+
543
+ # Cache for command availability checks
544
+ self._command_cache: Dict[str, bool] = {}
545
+
546
+ def _exec(self, command: str, cwd: str = None, timeout: int = None,
547
+ stdin_data: str = None) -> ExecuteResult:
548
+ """Execute command via terminal backend.
549
+
550
+ Args:
551
+ stdin_data: If provided, piped to the process's stdin instead of
552
+ embedding in the command string. Bypasses ARG_MAX.
553
+
554
+ Cwd resolution order (critical — see class docstring):
555
+ 1. Explicit ``cwd`` arg (if provided)
556
+ 2. Live ``self.env.cwd`` (tracks ``cd`` commands run via terminal)
557
+ 3. Init-time ``self.cwd`` (fallback when env has no cwd attribute)
558
+
559
+ This ordering ensures relative paths in file operations follow the
560
+ terminal's current directory — not the directory this file_ops was
561
+ originally created in. See test_file_ops_cwd_tracking.py.
562
+ """
563
+ kwargs = {}
564
+ if timeout:
565
+ kwargs['timeout'] = timeout
566
+ if stdin_data is not None:
567
+ kwargs['stdin_data'] = stdin_data
568
+
569
+ # Resolve cwd from the live env so `cd` commands are picked up.
570
+ # Fall through to init-time self.cwd only if the env doesn't track cwd.
571
+ effective_cwd = cwd or getattr(self.env, 'cwd', None) or self.cwd
572
+ result = self.env.execute(command, cwd=effective_cwd, **kwargs)
573
+ return ExecuteResult(
574
+ stdout=result.get("output", ""),
575
+ exit_code=result.get("returncode", 0)
576
+ )
577
+
578
+ def _has_command(self, cmd: str) -> bool:
579
+ """Check if a command exists in the environment (cached)."""
580
+ if cmd not in self._command_cache:
581
+ result = self._exec(f"command -v {cmd} >/dev/null 2>&1 && echo 'yes'")
582
+ self._command_cache[cmd] = result.stdout.strip() == 'yes'
583
+ return self._command_cache[cmd]
584
+
585
+ def _is_likely_binary(self, path: str, content_sample: str = None) -> bool:
586
+ """
587
+ Check if a file is likely binary.
588
+
589
+ Uses extension check (fast) + content analysis (fallback).
590
+ """
591
+ ext = os.path.splitext(path)[1].lower()
592
+ if ext in BINARY_EXTENSIONS:
593
+ return True
594
+
595
+ # Content analysis: >30% non-printable chars = binary
596
+ if content_sample:
597
+ non_printable = sum(1 for c in content_sample[:1000]
598
+ if ord(c) < 32 and c not in '\n\r\t')
599
+ return non_printable / min(len(content_sample), 1000) > 0.30
600
+
601
+ return False
602
+
603
+ def _is_image(self, path: str) -> bool:
604
+ """Check if file is an image we can return as base64."""
605
+ ext = os.path.splitext(path)[1].lower()
606
+ return ext in IMAGE_EXTENSIONS
607
+
608
+ def _add_line_numbers(self, content: str, start_line: int = 1) -> str:
609
+ """Add line numbers to content in LINE_NUM|CONTENT format."""
610
+ from tools.tool_output_limits import get_max_line_length
611
+ max_line_length = get_max_line_length()
612
+ lines = content.split('\n')
613
+ numbered = []
614
+ for i, line in enumerate(lines, start=start_line):
615
+ # Truncate long lines
616
+ if len(line) > max_line_length:
617
+ line = line[:max_line_length] + "... [truncated]"
618
+ numbered.append(f"{i:6d}|{line}")
619
+ return '\n'.join(numbered)
620
+
621
+ def _expand_path(self, path: str) -> str:
622
+ """
623
+ Expand shell-style paths like ~ and ~user to absolute paths.
624
+
625
+ This must be done BEFORE shell escaping, since ~ doesn't expand
626
+ inside single quotes.
627
+ """
628
+ if not path:
629
+ return path
630
+
631
+ # Handle ~ and ~user
632
+ if path.startswith('~'):
633
+ # Get home directory via the terminal environment
634
+ result = self._exec("echo $HOME")
635
+ if result.exit_code == 0 and result.stdout.strip():
636
+ home = result.stdout.strip()
637
+ if path == '~':
638
+ return home
639
+ elif path.startswith('~/'):
640
+ return home + path[1:] # Replace ~ with home
641
+ # ~username format - extract and validate username before
642
+ # letting shell expand it (prevent shell injection via
643
+ # paths like "~; rm -rf /").
644
+ rest = path[1:] # strip leading ~
645
+ slash_idx = rest.find('/')
646
+ username = rest[:slash_idx] if slash_idx >= 0 else rest
647
+ if username and re.fullmatch(r'[a-zA-Z0-9._-]+', username):
648
+ # Only expand ~username (not the full path) to avoid shell
649
+ # injection via path suffixes like "~user/$(malicious)".
650
+ expand_result = self._exec(f"echo ~{username}")
651
+ if expand_result.exit_code == 0 and expand_result.stdout.strip():
652
+ user_home = expand_result.stdout.strip()
653
+ suffix = path[1 + len(username):] # e.g. "/rest/of/path"
654
+ return user_home + suffix
655
+
656
+ return path
657
+
658
+ def _escape_shell_arg(self, arg: str) -> str:
659
+ """Escape a string for safe use in shell commands."""
660
+ # Use single quotes and escape any single quotes in the string
661
+ return "'" + arg.replace("'", "'\"'\"'") + "'"
662
+
663
+ def _unified_diff(self, old_content: str, new_content: str, filename: str) -> str:
664
+ """Generate unified diff between old and new content."""
665
+ old_lines = old_content.splitlines(keepends=True)
666
+ new_lines = new_content.splitlines(keepends=True)
667
+ diff = difflib.unified_diff(
668
+ old_lines, new_lines,
669
+ fromfile=f"a/{filename}",
670
+ tofile=f"b/{filename}"
671
+ )
672
+ return ''.join(diff)
673
+
674
+ # =========================================================================
675
+ # READ Implementation
676
+ # =========================================================================
677
+
678
+ def read_file(self, path: str, offset: int = 1, limit: int = 500) -> ReadResult:
679
+ """
680
+ Read a file with pagination, binary detection, and line numbers.
681
+
682
+ Args:
683
+ path: File path (absolute or relative to cwd)
684
+ offset: Line number to start from (1-indexed, default 1)
685
+ limit: Maximum lines to return (default 500, max 2000)
686
+
687
+ Returns:
688
+ ReadResult with content, metadata, or error info
689
+ """
690
+ # Expand ~ and other shell paths
691
+ path = self._expand_path(path)
692
+
693
+ offset, limit = normalize_read_pagination(offset, limit)
694
+
695
+ # Check if file exists and get size (wc -c is POSIX, works on Linux + macOS)
696
+ stat_cmd = f"wc -c < {self._escape_shell_arg(path)} 2>/dev/null"
697
+ stat_result = self._exec(stat_cmd)
698
+
699
+ if stat_result.exit_code != 0:
700
+ # File not found - try to suggest similar files
701
+ return self._suggest_similar_files(path)
702
+
703
+ stat_output = _strip_terminal_fence_leaks(stat_result.stdout)
704
+ try:
705
+ file_size = int(stat_output.strip())
706
+ except ValueError:
707
+ file_size = 0
708
+
709
+ # Check if file is too large
710
+ if file_size > MAX_FILE_SIZE:
711
+ # Still try to read, but warn
712
+ pass
713
+
714
+ # Images are never inlined — redirect to the vision tool
715
+ if self._is_image(path):
716
+ return ReadResult(
717
+ is_image=True,
718
+ is_binary=True,
719
+ file_size=file_size,
720
+ hint=(
721
+ "Image file detected. Automatically redirected to vision_analyze tool. "
722
+ "Use vision_analyze with this file path to inspect the image contents."
723
+ ),
724
+ )
725
+
726
+ # Read a sample to check for binary content
727
+ sample_cmd = f"head -c 1000 {self._escape_shell_arg(path)} 2>/dev/null"
728
+ sample_result = self._exec(sample_cmd)
729
+ sample_output = _strip_terminal_fence_leaks(sample_result.stdout)
730
+
731
+ if self._is_likely_binary(path, sample_output):
732
+ return ReadResult(
733
+ is_binary=True,
734
+ file_size=file_size,
735
+ error="Binary file - cannot display as text. Use appropriate tools to handle this file type."
736
+ )
737
+
738
+ # Read with pagination using sed
739
+ end_line = offset + limit - 1
740
+ read_cmd = f"sed -n '{offset},{end_line}p' {self._escape_shell_arg(path)}"
741
+ read_result = self._exec(read_cmd)
742
+
743
+ if read_result.exit_code != 0:
744
+ return ReadResult(error=f"Failed to read file: {read_result.stdout}")
745
+ read_output = _strip_terminal_fence_leaks(read_result.stdout)
746
+
747
+ # Get total line count
748
+ wc_cmd = f"wc -l < {self._escape_shell_arg(path)}"
749
+ wc_result = self._exec(wc_cmd)
750
+ wc_output = _strip_terminal_fence_leaks(wc_result.stdout)
751
+ try:
752
+ total_lines = int(wc_output.strip())
753
+ except ValueError:
754
+ total_lines = 0
755
+
756
+ # Check if truncated
757
+ truncated = total_lines > end_line
758
+ hint = None
759
+ if truncated:
760
+ hint = f"Use offset={end_line + 1} to continue reading (showing {offset}-{end_line} of {total_lines} lines)"
761
+
762
+ return ReadResult(
763
+ content=self._add_line_numbers(read_output, offset),
764
+ total_lines=total_lines,
765
+ file_size=file_size,
766
+ truncated=truncated,
767
+ hint=hint
768
+ )
769
+
770
+ def _suggest_similar_files(self, path: str) -> ReadResult:
771
+ """Suggest similar files when the requested file is not found."""
772
+ dir_path = os.path.dirname(path) or "."
773
+ filename = os.path.basename(path)
774
+ basename_no_ext = os.path.splitext(filename)[0]
775
+ ext = os.path.splitext(filename)[1].lower()
776
+ lower_name = filename.lower()
777
+
778
+ # List files in the target directory
779
+ ls_cmd = f"ls -1 {self._escape_shell_arg(dir_path)} 2>/dev/null | head -50"
780
+ ls_result = self._exec(ls_cmd)
781
+
782
+ scored: list = [] # (score, filepath) — higher is better
783
+ if ls_result.exit_code == 0 and ls_result.stdout.strip():
784
+ for f in ls_result.stdout.strip().split('\n'):
785
+ if not f:
786
+ continue
787
+ lf = f.lower()
788
+ score = 0
789
+
790
+ # Exact match (shouldn't happen, but guard)
791
+ if lf == lower_name:
792
+ score = 100
793
+ # Same base name, different extension (e.g. config.yml vs config.yaml)
794
+ elif os.path.splitext(f)[0].lower() == basename_no_ext.lower():
795
+ score = 90
796
+ # Target is prefix of candidate or vice-versa
797
+ elif lf.startswith(lower_name) or lower_name.startswith(lf):
798
+ score = 70
799
+ # Substring match (candidate contains query)
800
+ elif lower_name in lf:
801
+ score = 60
802
+ # Reverse substring (query contains candidate name)
803
+ elif lf in lower_name and len(lf) > 2:
804
+ score = 40
805
+ # Same extension with some overlap
806
+ elif ext and os.path.splitext(f)[1].lower() == ext:
807
+ common = set(lower_name) & set(lf)
808
+ if len(common) >= max(len(lower_name), len(lf)) * 0.4:
809
+ score = 30
810
+
811
+ if score > 0:
812
+ scored.append((score, os.path.join(dir_path, f)))
813
+
814
+ scored.sort(key=lambda x: -x[0])
815
+ similar = [fp for _, fp in scored[:5]]
816
+
817
+ return ReadResult(
818
+ error=f"File not found: {path}",
819
+ similar_files=similar
820
+ )
821
+
822
+ def read_file_raw(self, path: str) -> ReadResult:
823
+ """Read the complete file content as a plain string.
824
+
825
+ No pagination, no line-number prefixes, no per-line truncation.
826
+ Uses cat so the full file is returned regardless of size.
827
+ """
828
+ path = self._expand_path(path)
829
+ stat_cmd = f"wc -c < {self._escape_shell_arg(path)} 2>/dev/null"
830
+ stat_result = self._exec(stat_cmd)
831
+ if stat_result.exit_code != 0:
832
+ return self._suggest_similar_files(path)
833
+ stat_output = _strip_terminal_fence_leaks(stat_result.stdout)
834
+ try:
835
+ file_size = int(stat_output.strip())
836
+ except ValueError:
837
+ file_size = 0
838
+ if self._is_image(path):
839
+ return ReadResult(is_image=True, is_binary=True, file_size=file_size)
840
+ sample_result = self._exec(f"head -c 1000 {self._escape_shell_arg(path)} 2>/dev/null")
841
+ sample_output = _strip_terminal_fence_leaks(sample_result.stdout)
842
+ if self._is_likely_binary(path, sample_output):
843
+ return ReadResult(
844
+ is_binary=True, file_size=file_size,
845
+ error="Binary file — cannot display as text."
846
+ )
847
+ cat_result = self._exec(f"cat {self._escape_shell_arg(path)}")
848
+ if cat_result.exit_code != 0:
849
+ return ReadResult(error=f"Failed to read file: {cat_result.stdout}")
850
+ return ReadResult(
851
+ content=_strip_terminal_fence_leaks(cat_result.stdout),
852
+ file_size=file_size,
853
+ )
854
+
855
+ def delete_file(self, path: str) -> WriteResult:
856
+ """Delete a file via rm."""
857
+ path = self._expand_path(path)
858
+ if _is_write_denied(path):
859
+ return WriteResult(error=f"Delete denied: {path} is a protected path")
860
+ result = self._exec(f"rm -f {self._escape_shell_arg(path)}")
861
+ if result.exit_code != 0:
862
+ return WriteResult(error=f"Failed to delete {path}: {result.stdout}")
863
+ return WriteResult()
864
+
865
+ def move_file(self, src: str, dst: str) -> WriteResult:
866
+ """Move a file via mv."""
867
+ src = self._expand_path(src)
868
+ dst = self._expand_path(dst)
869
+ for p in (src, dst):
870
+ if _is_write_denied(p):
871
+ return WriteResult(error=f"Move denied: {p} is a protected path")
872
+ result = self._exec(
873
+ f"mv {self._escape_shell_arg(src)} {self._escape_shell_arg(dst)}"
874
+ )
875
+ if result.exit_code != 0:
876
+ return WriteResult(error=f"Failed to move {src} -> {dst}: {result.stdout}")
877
+ return WriteResult()
878
+
879
+ # =========================================================================
880
+ # WRITE Implementation
881
+ # =========================================================================
882
+
883
+ def write_file(self, path: str, content: str) -> WriteResult:
884
+ """
885
+ Write content to a file, creating parent directories as needed.
886
+
887
+ Pipes content through stdin to avoid OS ARG_MAX limits on large
888
+ files. The content never appears in the shell command string —
889
+ only the file path does.
890
+
891
+ After the write, runs a post-first / pre-lazy lint check via
892
+ ``_check_lint_delta()``. If the new content is clean, the lint
893
+ call is O(one parse). If the new content has errors, the pre-write
894
+ content is linted too and only errors newly introduced by this
895
+ write are surfaced — pre-existing problems are filtered out so
896
+ the agent isn't distracted chasing them.
897
+
898
+ Args:
899
+ path: File path to write
900
+ content: Content to write
901
+
902
+ Returns:
903
+ WriteResult with bytes written, lint summary, or error.
904
+ """
905
+ # Expand ~ and other shell paths
906
+ path = self._expand_path(path)
907
+
908
+ # Block writes to sensitive paths
909
+ if _is_write_denied(path):
910
+ return WriteResult(error=f"Write denied: '{path}' is a protected system/credential file.")
911
+
912
+ # Capture pre-write content. Two consumers want it:
913
+ #
914
+ # 1. The lint-delta layer (for in-process linters like ast.parse
915
+ # and json.loads) needs the previous content to compute the
916
+ # set of NEW lint errors introduced by this write.
917
+ # 2. The LSP layer needs pre/post content to build a line-shift
918
+ # map — pre-existing diagnostics below the edit point shift
919
+ # when lines are added/removed, and the shift map remaps
920
+ # baseline diagnostics into post-edit coordinates so the
921
+ # strict (range-aware) delta key matches.
922
+ #
923
+ # The set of extensions we capture pre_content for is therefore
924
+ # the UNION of in-process lint coverage and LSP coverage. For
925
+ # extensions outside both sets (binaries, opaque formats),
926
+ # skipping the read keeps the hot path fast.
927
+ ext = os.path.splitext(path)[1].lower()
928
+ pre_content: Optional[str] = None
929
+ want_pre = ext in LINTERS_INPROC or self._lsp_handles_extension(ext)
930
+ if want_pre:
931
+ # Best-effort read; failure (file missing, permission) leaves
932
+ # pre_content as None which makes both downstream consumers
933
+ # degrade gracefully (lint reports all errors; LSP skips the
934
+ # shift map).
935
+ read_cmd = f"cat {self._escape_shell_arg(path)} 2>/dev/null"
936
+ read_result = self._exec(read_cmd)
937
+ if read_result.exit_code == 0 and read_result.stdout:
938
+ pre_content = read_result.stdout
939
+
940
+ # Snapshot LSP diagnostics for this file (best-effort) so the
941
+ # post-write LSP layer can return only diagnostics introduced
942
+ # by this specific edit. Mirrors claude-code's
943
+ # ``beforeFileEdited`` pattern but wired to the local LSP
944
+ # rather than an external IDE.
945
+ self._snapshot_lsp_baseline(path)
946
+
947
+ # Create parent directories
948
+ parent = os.path.dirname(path)
949
+ dirs_created = False
950
+
951
+ if parent:
952
+ mkdir_cmd = f"mkdir -p {self._escape_shell_arg(parent)}"
953
+ mkdir_result = self._exec(mkdir_cmd)
954
+ if mkdir_result.exit_code == 0:
955
+ dirs_created = True
956
+
957
+ # Write via stdin pipe — content bypasses shell arg parsing entirely,
958
+ # so there's no ARG_MAX limit regardless of file size.
959
+ write_cmd = f"cat > {self._escape_shell_arg(path)}"
960
+ write_result = self._exec(write_cmd, stdin_data=content)
961
+
962
+ if write_result.exit_code != 0:
963
+ return WriteResult(error=f"Failed to write file: {write_result.stdout}")
964
+
965
+ # Get bytes written (wc -c is POSIX, works on Linux + macOS)
966
+ stat_cmd = f"wc -c < {self._escape_shell_arg(path)} 2>/dev/null"
967
+ stat_result = self._exec(stat_cmd)
968
+
969
+ try:
970
+ bytes_written = int(stat_result.stdout.strip())
971
+ except ValueError:
972
+ bytes_written = len(content.encode('utf-8'))
973
+
974
+ # Post-write lint with delta refinement.
975
+ lint_result = self._check_lint_delta(path, pre_content=pre_content, post_content=content)
976
+
977
+ # Semantic diagnostics from the LSP layer — separate channel.
978
+ # Only fired when the syntax tier reported clean (no point asking
979
+ # an LSP for a file that won't even parse). Pass pre/post
980
+ # content so the LSP layer can build a line-shift map and
981
+ # remap baseline diagnostics into post-edit coordinates.
982
+ # Best-effort: ``""`` is returned for any failure path.
983
+ lsp_diagnostics: Optional[str] = None
984
+ if lint_result.success or lint_result.skipped:
985
+ block = self._maybe_lsp_diagnostics(
986
+ path, pre_content=pre_content, post_content=content
987
+ )
988
+ if block:
989
+ lsp_diagnostics = block
990
+
991
+ return WriteResult(
992
+ bytes_written=bytes_written,
993
+ dirs_created=dirs_created,
994
+ lint=lint_result.to_dict() if lint_result else None,
995
+ lsp_diagnostics=lsp_diagnostics,
996
+ )
997
+
998
+ # =========================================================================
999
+ # PATCH Implementation (Replace Mode)
1000
+ # =========================================================================
1001
+
1002
+ def patch_replace(self, path: str, old_string: str, new_string: str,
1003
+ replace_all: bool = False) -> PatchResult:
1004
+ """
1005
+ Replace text in a file using fuzzy matching.
1006
+
1007
+ Args:
1008
+ path: File path to modify
1009
+ old_string: Text to find (must be unique unless replace_all=True)
1010
+ new_string: Replacement text
1011
+ replace_all: If True, replace all occurrences
1012
+
1013
+ Returns:
1014
+ PatchResult with diff and lint results
1015
+ """
1016
+ # Expand ~ and other shell paths
1017
+ path = self._expand_path(path)
1018
+
1019
+ # Block writes to sensitive paths
1020
+ if _is_write_denied(path):
1021
+ return PatchResult(error=f"Write denied: '{path}' is a protected system/credential file.")
1022
+
1023
+ # Read current content
1024
+ read_cmd = f"cat {self._escape_shell_arg(path)} 2>/dev/null"
1025
+ read_result = self._exec(read_cmd)
1026
+
1027
+ if read_result.exit_code != 0:
1028
+ return PatchResult(error=f"Failed to read file: {path}")
1029
+
1030
+ content = read_result.stdout
1031
+
1032
+ # Import and use fuzzy matching
1033
+ from tools.fuzzy_match import fuzzy_find_and_replace
1034
+
1035
+ new_content, match_count, _strategy, error = fuzzy_find_and_replace(
1036
+ content, old_string, new_string, replace_all
1037
+ )
1038
+
1039
+ if error or match_count == 0:
1040
+ err_msg = error or f"Could not find match for old_string in {path}"
1041
+ try:
1042
+ from tools.fuzzy_match import format_no_match_hint
1043
+ err_msg += format_no_match_hint(err_msg, match_count, old_string, content)
1044
+ except Exception:
1045
+ pass
1046
+ return PatchResult(error=err_msg)
1047
+ # Write back
1048
+ write_result = self.write_file(path, new_content)
1049
+ if write_result.error:
1050
+ return PatchResult(error=f"Failed to write changes: {write_result.error}")
1051
+
1052
+ # Post-write verification — re-read the file and confirm the bytes we
1053
+ # intended to write actually landed. Catches silent persistence
1054
+ # failures (backend FS oddities, race with another task, truncated
1055
+ # pipe, etc.) that would otherwise return success-with-diff while the
1056
+ # file is unchanged on disk.
1057
+ verify_cmd = f"cat {self._escape_shell_arg(path)} 2>/dev/null"
1058
+ verify_result = self._exec(verify_cmd)
1059
+ if verify_result.exit_code != 0:
1060
+ return PatchResult(error=f"Post-write verification failed: could not re-read {path}")
1061
+ # Normalize line endings before comparing. On Windows, Python's
1062
+ # default text-mode ``open()`` translates ``\n`` → ``\r\n`` on
1063
+ # write, so the file on disk legitimately holds CRLFs while our
1064
+ # ``new_content`` string has bare LFs. Without this normalization
1065
+ # every patch on Windows returns a bogus "wrote 39, read 42"
1066
+ # false-negative even though the edit landed correctly. POSIX
1067
+ # backends don't translate, so this is a no-op there.
1068
+ _verify_stdout_normalized = verify_result.stdout.replace("\r\n", "\n").replace("\r", "\n")
1069
+ _new_content_normalized = new_content.replace("\r\n", "\n").replace("\r", "\n")
1070
+ if _verify_stdout_normalized != _new_content_normalized:
1071
+ return PatchResult(error=(
1072
+ f"Post-write verification failed for {path}: on-disk content "
1073
+ f"differs from intended write "
1074
+ f"(wrote {len(_new_content_normalized)} chars, read back "
1075
+ f"{len(_verify_stdout_normalized)} chars after normalizing line endings). "
1076
+ "The patch did not persist. Re-read the file and try again."
1077
+ ))
1078
+
1079
+ # Generate diff
1080
+ diff = self._unified_diff(content, new_content, path)
1081
+
1082
+ # Auto-lint with delta refinement: only surface errors introduced
1083
+ # by this patch, filtering out pre-existing lint failures so the
1084
+ # agent isn't distracted by problems that were already there.
1085
+ lint_result = self._check_lint_delta(path, pre_content=content, post_content=new_content)
1086
+
1087
+ return PatchResult(
1088
+ success=True,
1089
+ diff=diff,
1090
+ files_modified=[path],
1091
+ lint=lint_result.to_dict() if lint_result else None,
1092
+ # Propagate the LSP diagnostics already captured by the
1093
+ # internal ``write_file`` call. Its baseline was the
1094
+ # pre-patch content (taken at the start of write_file via
1095
+ # ``_snapshot_lsp_baseline``) so the delta is correct for
1096
+ # the patch as a whole. Keep the field separate from the
1097
+ # syntax-check ``lint`` so the agent can read both signals.
1098
+ lsp_diagnostics=write_result.lsp_diagnostics,
1099
+ )
1100
+
1101
+ def patch_v4a(self, patch_content: str) -> PatchResult:
1102
+ """
1103
+ Apply a V4A format patch.
1104
+
1105
+ V4A format:
1106
+ *** Begin Patch
1107
+ *** Update File: path/to/file.py
1108
+ @@ context hint @@
1109
+ context line
1110
+ -removed line
1111
+ +added line
1112
+ *** End Patch
1113
+
1114
+ Args:
1115
+ patch_content: V4A format patch string
1116
+
1117
+ Returns:
1118
+ PatchResult with changes made
1119
+ """
1120
+ # Import patch parser
1121
+ from tools.patch_parser import parse_v4a_patch, apply_v4a_operations
1122
+
1123
+ operations, parse_error = parse_v4a_patch(patch_content)
1124
+ if parse_error:
1125
+ return PatchResult(error=f"Failed to parse patch: {parse_error}")
1126
+
1127
+ # Apply operations
1128
+ result = apply_v4a_operations(operations, self)
1129
+ return result
1130
+
1131
+ def _check_lint(self, path: str, content: Optional[str] = None) -> LintResult:
1132
+ """
1133
+ Run syntax check on a file after editing.
1134
+
1135
+ Prefers the in-process linter for structured formats (JSON, YAML,
1136
+ TOML) when possible — those parse via the Python stdlib in
1137
+ microseconds and don't require a subprocess. Falls back to the
1138
+ shell linter table for compiled/type-checked languages
1139
+ (py_compile, node --check, tsc, go vet, rustfmt).
1140
+
1141
+ Args:
1142
+ path: File path (used to select the linter + for shell invocation).
1143
+ content: Optional file content. If provided AND an in-process
1144
+ linter matches the extension, we lint the content
1145
+ directly without re-reading the file from disk. Ignored
1146
+ for shell linters.
1147
+
1148
+ Returns:
1149
+ LintResult with status and any errors.
1150
+ """
1151
+ ext = os.path.splitext(path)[1].lower()
1152
+
1153
+ # Prefer in-process linter when available.
1154
+ inproc = LINTERS_INPROC.get(ext)
1155
+ if inproc is not None:
1156
+ # Need content — either passed in or read from disk.
1157
+ if content is None:
1158
+ read_cmd = f"cat {self._escape_shell_arg(path)} 2>/dev/null"
1159
+ read_result = self._exec(read_cmd)
1160
+ if read_result.exit_code != 0:
1161
+ return LintResult(skipped=True, message=f"Failed to read {path} for lint")
1162
+ content = read_result.stdout
1163
+ ok, err = inproc(content)
1164
+ if err == "__SKIP__":
1165
+ return LintResult(skipped=True, message=f"No linter available for {ext} (missing dependency)")
1166
+ return LintResult(success=ok, output="" if ok else err)
1167
+
1168
+ # Fall back to shell linter.
1169
+ if ext not in LINTERS:
1170
+ return LintResult(skipped=True, message=f"No linter for {ext} files")
1171
+
1172
+ linter_cmd = LINTERS[ext]
1173
+ # Extract the base command (first word)
1174
+ base_cmd = linter_cmd.split()[0]
1175
+
1176
+ if not self._has_command(base_cmd):
1177
+ return LintResult(skipped=True, message=f"{base_cmd} not available")
1178
+
1179
+ # Run linter
1180
+ cmd = linter_cmd.replace("{file}", self._escape_shell_arg(path))
1181
+ result = self._exec(cmd, timeout=30)
1182
+
1183
+ if result.exit_code != 0 and _looks_like_linter_unusable(base_cmd, result.stdout):
1184
+ # The linter command exists on PATH but couldn't actually run
1185
+ # (e.g. ``npx tsc`` when tsc isn't in node_modules; ``rustfmt
1186
+ # --check`` without a Cargo project). This is a tooling gap,
1187
+ # not a real lint failure — surface it as ``skipped`` so the
1188
+ # write doesn't get flagged AND so the LSP tier still runs.
1189
+ from tools.ansi_strip import strip_ansi
1190
+ cleaned = strip_ansi(result.stdout).strip()
1191
+ # Collapse to a single line — the npx banner is multi-line ASCII.
1192
+ first_line = next(
1193
+ (ln.strip() for ln in cleaned.splitlines() if ln.strip()),
1194
+ cleaned[:120],
1195
+ )
1196
+ return LintResult(
1197
+ skipped=True,
1198
+ message=f"{base_cmd} not usable: {first_line[:200]}",
1199
+ )
1200
+
1201
+ return LintResult(
1202
+ success=result.exit_code == 0,
1203
+ output=result.stdout.strip() if result.stdout.strip() else ""
1204
+ )
1205
+
1206
+ def _check_lint_delta(self, path: str, pre_content: Optional[str],
1207
+ post_content: Optional[str] = None) -> LintResult:
1208
+ """
1209
+ Run post-write syntax lint with pre-write baseline comparison.
1210
+
1211
+ Two-tier strategy:
1212
+
1213
+ 1. **Syntax check** (in-process or shell-based, microseconds).
1214
+ Catches the bug class that motivated this layer: corrupt
1215
+ writes, mashed quotes, truncated output. Hot path.
1216
+
1217
+ 2. **Delta refinement against pre-write content** when the
1218
+ syntax tier reports errors. Filter out errors that already
1219
+ existed pre-edit so the agent isn't distracted by inherited
1220
+ state.
1221
+
1222
+ Semantic diagnostics from the LSP layer are fetched separately
1223
+ via :meth:`_maybe_lsp_diagnostics` and surfaced in the
1224
+ ``lsp_diagnostics`` field on :class:`WriteResult` /
1225
+ :class:`PatchResult`. Keeping the two channels separate lets
1226
+ the agent (and any downstream parsers) read syntax errors and
1227
+ semantic errors as independent signals.
1228
+
1229
+ Args:
1230
+ path: File path (for linter selection).
1231
+ pre_content: File content BEFORE the write. Pass None for new
1232
+ files or when the pre-state isn't available — the
1233
+ delta refinement is skipped and all post errors
1234
+ are returned.
1235
+ post_content: File content AFTER the write. Optional; if None,
1236
+ the shell linter reads from disk (same as
1237
+ _check_lint).
1238
+
1239
+ Returns:
1240
+ LintResult. ``output`` contains either the full post-lint
1241
+ errors (no pre-state) or just the new-error lines (delta
1242
+ refinement applied).
1243
+ """
1244
+ post = self._check_lint(path, content=post_content)
1245
+
1246
+ # Hot path: clean post-write syntactically.
1247
+ if post.success or post.skipped:
1248
+ return post
1249
+
1250
+ # Post-write has syntax errors. If we have pre-content, run the
1251
+ # delta refinement to filter out pre-existing errors.
1252
+ if pre_content is None:
1253
+ return post
1254
+
1255
+ pre = self._check_lint(path, content=pre_content)
1256
+ if pre.success or pre.skipped or not pre.output:
1257
+ # Pre-write was clean (or we couldn't lint it) — post errors
1258
+ # are all new. Return the full post output.
1259
+ return post
1260
+
1261
+ # Both pre- and post-write had errors. Compute the set-difference
1262
+ # on non-empty stripped lines. Caveat: single-error parsers
1263
+ # (ast.parse, json.loads) stop at the first error and don't report
1264
+ # later ones — if the pre-existing error blocks parsing before
1265
+ # reaching the edit region, we can't prove the edit is clean. So
1266
+ # if every post error also appeared pre-edit, we report the file
1267
+ # as still broken but annotate that this edit introduced nothing
1268
+ # new on top — the agent knows it's inherited state, not fresh
1269
+ # damage, without silently dropping the error.
1270
+ pre_lines = {ln.strip() for ln in pre.output.splitlines() if ln.strip()}
1271
+ post_lines = [ln for ln in post.output.splitlines() if ln.strip() and ln.strip() not in pre_lines]
1272
+
1273
+ if not post_lines:
1274
+ # Every error in post was also in pre — this edit didn't make
1275
+ # anything obviously worse, but the file remains broken and
1276
+ # the agent should know.
1277
+ return LintResult(
1278
+ success=False,
1279
+ output=post.output,
1280
+ message="Pre-existing lint errors — this edit didn't introduce new ones but the file is still broken.",
1281
+ )
1282
+
1283
+ return LintResult(
1284
+ success=False,
1285
+ output=(
1286
+ "New lint errors introduced by this edit "
1287
+ "(pre-existing errors filtered out):\n" + "\n".join(post_lines)
1288
+ )
1289
+ )
1290
+
1291
+ def _lsp_local_only(self) -> bool:
1292
+ """Return True iff this FileOperations is wired to a local backend.
1293
+
1294
+ LSP servers run on the host process — they need access to the
1295
+ files they're linting. Remote/sandboxed backends (Docker,
1296
+ Modal, SSH, Daytona) keep files inside the sandbox where the
1297
+ host-side LSP server can't reach them, so we skip the LSP
1298
+ path for those entirely.
1299
+ """
1300
+ env = getattr(self, "env", None)
1301
+ if env is None:
1302
+ # Defensive: some tests construct ShellFileOperations via
1303
+ # ``__new__`` without going through ``__init__``, so
1304
+ # ``self.env`` may be missing. No env = no LSP path.
1305
+ return False
1306
+ try:
1307
+ from tools.environments.local import LocalEnvironment
1308
+ except Exception: # noqa: BLE001
1309
+ return False
1310
+ return isinstance(env, LocalEnvironment)
1311
+
1312
+ def _lsp_handles_extension(self, ext: str) -> bool:
1313
+ """Return True iff some registered LSP server claims this extension.
1314
+
1315
+ Used to decide whether to capture pre-write content for the
1316
+ line-shift map. Capturing is cheap (one ``cat`` on the host)
1317
+ but pointless if no LSP would ever look at the file.
1318
+
1319
+ Safe to call on remote backends — the registry is purely
1320
+ in-process metadata; we still gate the actual LSP path on
1321
+ :meth:`_lsp_local_only`.
1322
+ """
1323
+ if not ext:
1324
+ return False
1325
+ try:
1326
+ from agent.lsp.servers import SERVERS
1327
+ except Exception: # noqa: BLE001
1328
+ return False
1329
+ ext_lower = ext.lower()
1330
+ for srv in SERVERS:
1331
+ if ext_lower in srv.extensions:
1332
+ return True
1333
+ return False
1334
+
1335
+ def _snapshot_lsp_baseline(self, path: str) -> None:
1336
+ """Capture pre-edit LSP diagnostics so the post-write delta is correct.
1337
+
1338
+ Best-effort. Silent on every failure path — LSP is an
1339
+ enrichment layer and must never break a write.
1340
+
1341
+ Skipped entirely on non-local backends (Docker, Modal, SSH,
1342
+ etc.) — the server can't see files inside the sandbox.
1343
+ """
1344
+ if not self._lsp_local_only():
1345
+ return
1346
+ try:
1347
+ from agent.lsp import get_service
1348
+ svc = get_service()
1349
+ except Exception: # noqa: BLE001
1350
+ return
1351
+ if svc is None:
1352
+ return
1353
+ try:
1354
+ svc.snapshot_baseline(path)
1355
+ except Exception: # noqa: BLE001
1356
+ pass
1357
+
1358
+ def _maybe_lsp_diagnostics(
1359
+ self,
1360
+ path: str,
1361
+ *,
1362
+ pre_content: Optional[str] = None,
1363
+ post_content: Optional[str] = None,
1364
+ ) -> str:
1365
+ """Best-effort LSP semantic diagnostics for ``path``.
1366
+
1367
+ Returns a formatted ``<diagnostics>`` block, or empty string
1368
+ when LSP is unavailable / disabled / produced no errors.
1369
+
1370
+ When both ``pre_content`` and ``post_content`` are provided,
1371
+ a line-shift map is built and passed to the LSPService so
1372
+ baseline diagnostics are remapped into post-edit coordinates
1373
+ before the set-difference. Without this, edits that delete
1374
+ or insert lines surface every pre-existing diagnostic below
1375
+ the edit point as "introduced by this edit".
1376
+
1377
+ Wraps everything in a try/except so a misbehaving LSP server
1378
+ can't break a write. This intentionally swallows all errors
1379
+ — the calling tier already returned a clean syntax result, so
1380
+ ``""`` here just means "no extra info to add".
1381
+
1382
+ Skipped entirely on non-local backends (Docker, Modal, SSH,
1383
+ etc.) — same reasoning as ``_snapshot_lsp_baseline``.
1384
+ """
1385
+ if not self._lsp_local_only():
1386
+ return ""
1387
+ try:
1388
+ from agent.lsp import get_service
1389
+ except Exception: # noqa: BLE001
1390
+ return ""
1391
+ try:
1392
+ svc = get_service()
1393
+ except Exception: # noqa: BLE001
1394
+ return ""
1395
+ if svc is None or not svc.enabled_for(path):
1396
+ return ""
1397
+
1398
+ # Build a line-shift map when we have both pre and post — it
1399
+ # remaps baseline diagnostics into post-edit coordinates so
1400
+ # the strict (range-aware) delta key matches correctly.
1401
+ line_shift = None
1402
+ if pre_content is not None and post_content is not None and pre_content != post_content:
1403
+ try:
1404
+ from agent.lsp.range_shift import build_line_shift
1405
+ line_shift = build_line_shift(pre_content, post_content)
1406
+ except Exception: # noqa: BLE001
1407
+ line_shift = None
1408
+
1409
+ try:
1410
+ diagnostics = svc.get_diagnostics_sync(path, delta=True, line_shift=line_shift)
1411
+ except Exception: # noqa: BLE001
1412
+ return ""
1413
+ if not diagnostics:
1414
+ return ""
1415
+ try:
1416
+ from agent.lsp.reporter import report_for_file, truncate
1417
+ block = report_for_file(path, diagnostics)
1418
+ if not block:
1419
+ return ""
1420
+ return truncate("LSP diagnostics introduced by this edit:\n" + block)
1421
+ except Exception: # noqa: BLE001
1422
+ return ""
1423
+
1424
+ # =========================================================================
1425
+ # SEARCH Implementation
1426
+ # =========================================================================
1427
+
1428
+ def search(self, pattern: str, path: str = ".", target: str = "content",
1429
+ file_glob: Optional[str] = None, limit: int = 50, offset: int = 0,
1430
+ output_mode: str = "content", context: int = 0) -> SearchResult:
1431
+ """
1432
+ Search for content or files.
1433
+
1434
+ Args:
1435
+ pattern: Regex (for content) or glob pattern (for files)
1436
+ path: Directory/file to search (default: cwd)
1437
+ target: "content" (grep) or "files" (glob)
1438
+ file_glob: File pattern filter for content search (e.g., "*.py")
1439
+ limit: Max results (default 50)
1440
+ offset: Skip first N results
1441
+ output_mode: "content", "files_only", or "count"
1442
+ context: Lines of context around matches
1443
+
1444
+ Returns:
1445
+ SearchResult with matches or file list
1446
+ """
1447
+ offset, limit = normalize_search_pagination(offset, limit)
1448
+
1449
+ # Expand ~ and other shell paths
1450
+ path = self._expand_path(path)
1451
+
1452
+ # Validate that the path exists before searching
1453
+ check = self._exec(f"test -e {self._escape_shell_arg(path)} && echo exists || echo not_found")
1454
+ if "not_found" in check.stdout:
1455
+ # Try to suggest nearby paths
1456
+ parent = os.path.dirname(path) or "."
1457
+ basename_query = os.path.basename(path)
1458
+ hint_parts = [f"Path not found: {path}"]
1459
+ # Check if parent directory exists and list similar entries
1460
+ parent_check = self._exec(
1461
+ f"test -d {self._escape_shell_arg(parent)} && echo yes || echo no"
1462
+ )
1463
+ if "yes" in parent_check.stdout and basename_query:
1464
+ ls_result = self._exec(
1465
+ f"ls -1 {self._escape_shell_arg(parent)} 2>/dev/null | head -20"
1466
+ )
1467
+ if ls_result.exit_code == 0 and ls_result.stdout.strip():
1468
+ lower_q = basename_query.lower()
1469
+ candidates = []
1470
+ for entry in ls_result.stdout.strip().split('\n'):
1471
+ if not entry:
1472
+ continue
1473
+ le = entry.lower()
1474
+ if lower_q in le or le in lower_q or le.startswith(lower_q[:3]):
1475
+ candidates.append(os.path.join(parent, entry))
1476
+ if candidates:
1477
+ hint_parts.append(
1478
+ "Similar paths: " + ", ".join(candidates[:5])
1479
+ )
1480
+ return SearchResult(
1481
+ error=". ".join(hint_parts),
1482
+ total_count=0
1483
+ )
1484
+
1485
+ if target == "files":
1486
+ return self._search_files(pattern, path, limit, offset)
1487
+ else:
1488
+ return self._search_content(pattern, path, file_glob, limit, offset,
1489
+ output_mode, context)
1490
+
1491
+ def _search_files(self, pattern: str, path: str, limit: int, offset: int) -> SearchResult:
1492
+ """Search for files by name pattern (glob-like)."""
1493
+ # Auto-prepend **/ for recursive search if not already present
1494
+ if not pattern.startswith('**/') and '/' not in pattern:
1495
+ search_pattern = pattern
1496
+ else:
1497
+ search_pattern = pattern.split('/')[-1]
1498
+
1499
+ search_root = Path(path)
1500
+ has_hidden_path_ancestor = any(
1501
+ part not in {".", ".."} and part.startswith(".")
1502
+ for part in search_root.parts
1503
+ )
1504
+
1505
+ # Prefer ripgrep: respects .gitignore, excludes hidden dirs by
1506
+ # default, and has parallel directory traversal (~200x faster than
1507
+ # find on wide trees). Mirrors _search_content which already uses rg.
1508
+ if self._has_command('rg'):
1509
+ return self._search_files_rg(search_pattern, path, limit, offset)
1510
+
1511
+ # Fallback: find (slower, no .gitignore awareness)
1512
+ if not self._has_command('find'):
1513
+ return SearchResult(
1514
+ error="File search requires 'rg' (ripgrep) or 'find'. "
1515
+ "Install ripgrep for best results: "
1516
+ "https://github.com/BurntSushi/ripgrep#installation"
1517
+ )
1518
+
1519
+ # Exclude hidden directories (matching ripgrep's default behavior).
1520
+ hidden_exclude = "-not -path '*/.*'" if not has_hidden_path_ancestor else ""
1521
+ hidden_filter_expr = f" {hidden_exclude}" if hidden_exclude else ""
1522
+
1523
+ # Use shell pagination for standard roots. For hidden roots, gather full
1524
+ # output so we can re-apply hidden-descendant filtering while allowing
1525
+ # explicit hidden-root searches.
1526
+ pagination_expr = ""
1527
+ if not has_hidden_path_ancestor:
1528
+ pagination_expr = f" | tail -n +{offset + 1} | head -n {limit}"
1529
+
1530
+ cmd = f"find {self._escape_shell_arg(path)}{hidden_filter_expr} -type f -name {self._escape_shell_arg(search_pattern)} " \
1531
+ f"-printf '%T@ %p\\n' 2>/dev/null | sort -rn{pagination_expr}"
1532
+
1533
+ result = self._exec(cmd, timeout=60)
1534
+
1535
+ if not result.stdout.strip():
1536
+ # Try without -printf (BSD find compatibility -- macOS)
1537
+ cmd_simple = f"find {self._escape_shell_arg(path)}{hidden_filter_expr} -type f -name {self._escape_shell_arg(search_pattern)} " \
1538
+ f"2>/dev/null | sort -rn{pagination_expr}"
1539
+ result = self._exec(cmd_simple, timeout=60)
1540
+
1541
+ files = []
1542
+ for line in result.stdout.strip().split('\n'):
1543
+ if not line:
1544
+ continue
1545
+ parts = line.split(' ', 1)
1546
+ if len(parts) == 2 and parts[0].replace('.', '').isdigit():
1547
+ files.append(parts[1])
1548
+ else:
1549
+ files.append(line)
1550
+
1551
+ # For explicit hidden roots, find's path-based filtering excludes every
1552
+ # file under the hidden path. Apply descendant filtering after command
1553
+ # execution so only the explicit root ancestry is bypassed.
1554
+ if has_hidden_path_ancestor:
1555
+ normalized_root = search_root.resolve()
1556
+ filtered_files = []
1557
+ for file_path in files:
1558
+ try:
1559
+ rel_parts = Path(file_path).resolve().relative_to(normalized_root).parts
1560
+ except ValueError:
1561
+ rel_parts = Path(file_path).parts
1562
+ if any(part not in {".", ".."} and part.startswith(".") for part in rel_parts):
1563
+ continue
1564
+ filtered_files.append(file_path)
1565
+ files = filtered_files[offset:offset + limit]
1566
+ # pagination for standard roots is already applied in shell
1567
+
1568
+ return SearchResult(
1569
+ files=files,
1570
+ total_count=len(files)
1571
+ )
1572
+
1573
+ def _search_files_rg(self, pattern: str, path: str, limit: int, offset: int) -> SearchResult:
1574
+ """Search for files by name using ripgrep's --files mode.
1575
+
1576
+ rg --files respects .gitignore and excludes hidden directories by
1577
+ default, and uses parallel directory traversal for ~200x speedup
1578
+ over find on wide trees. Results are sorted by modification time
1579
+ (most recently edited first) when rg >= 13.0 supports --sortr.
1580
+ """
1581
+ # rg --files -g uses glob patterns; wrap bare names so they match
1582
+ # at any depth (equivalent to find -name).
1583
+ if '/' not in pattern and not pattern.startswith('*'):
1584
+ glob_pattern = f"*{pattern}"
1585
+ else:
1586
+ glob_pattern = pattern
1587
+
1588
+ fetch_limit = limit + offset
1589
+ # Try mtime-sorted first (rg 13+); fall back to unsorted if not supported.
1590
+ cmd_sorted = (
1591
+ f"rg --files --sortr=modified -g {self._escape_shell_arg(glob_pattern)} "
1592
+ f"{self._escape_shell_arg(path)} 2>/dev/null "
1593
+ f"| head -n {fetch_limit}"
1594
+ )
1595
+ result = self._exec(cmd_sorted, timeout=60)
1596
+ all_files = [f for f in result.stdout.strip().split('\n') if f]
1597
+
1598
+ if not all_files:
1599
+ # --sortr may have failed on older rg; retry without it.
1600
+ cmd_plain = (
1601
+ f"rg --files -g {self._escape_shell_arg(glob_pattern)} "
1602
+ f"{self._escape_shell_arg(path)} 2>/dev/null "
1603
+ f"| head -n {fetch_limit}"
1604
+ )
1605
+ result = self._exec(cmd_plain, timeout=60)
1606
+ all_files = [f for f in result.stdout.strip().split('\n') if f]
1607
+
1608
+ page = all_files[offset:offset + limit]
1609
+
1610
+ return SearchResult(
1611
+ files=page,
1612
+ total_count=len(all_files),
1613
+ truncated=len(all_files) >= fetch_limit,
1614
+ )
1615
+
1616
+ def _search_content(self, pattern: str, path: str, file_glob: Optional[str],
1617
+ limit: int, offset: int, output_mode: str, context: int) -> SearchResult:
1618
+ """Search for content inside files (grep-like)."""
1619
+ # Try ripgrep first (fast), fallback to grep (slower but works)
1620
+ if self._has_command('rg'):
1621
+ return self._search_with_rg(pattern, path, file_glob, limit, offset,
1622
+ output_mode, context)
1623
+ elif self._has_command('grep'):
1624
+ return self._search_with_grep(pattern, path, file_glob, limit, offset,
1625
+ output_mode, context)
1626
+ else:
1627
+ # Neither rg nor grep available (Windows without Git Bash, etc.)
1628
+ return SearchResult(
1629
+ error="Content search requires ripgrep (rg) or grep. "
1630
+ "Install ripgrep: https://github.com/BurntSushi/ripgrep#installation"
1631
+ )
1632
+
1633
+ def _search_with_rg(self, pattern: str, path: str, file_glob: Optional[str],
1634
+ limit: int, offset: int, output_mode: str, context: int) -> SearchResult:
1635
+ """Search using ripgrep."""
1636
+ cmd_parts = ["rg", "--line-number", "--no-heading", "--with-filename"]
1637
+
1638
+ # Add context if requested
1639
+ if context > 0:
1640
+ cmd_parts.extend(["-C", str(context)])
1641
+
1642
+ # Add file glob filter (must be quoted to prevent shell expansion)
1643
+ if file_glob:
1644
+ cmd_parts.extend(["--glob", self._escape_shell_arg(file_glob)])
1645
+
1646
+ # Output mode handling
1647
+ if output_mode == "files_only":
1648
+ cmd_parts.append("-l") # Files only
1649
+ elif output_mode == "count":
1650
+ cmd_parts.append("-c") # Count per file
1651
+
1652
+ # Add pattern and path
1653
+ cmd_parts.append(self._escape_shell_arg(pattern))
1654
+ cmd_parts.append(self._escape_shell_arg(path))
1655
+
1656
+ # Fetch extra rows so we can report the true total before slicing.
1657
+ # For context mode, rg emits separator lines ("--") between groups,
1658
+ # so we grab generously and filter in Python.
1659
+ fetch_limit = limit + offset + 200 if context > 0 else limit + offset
1660
+ cmd_parts.extend(["|", "head", "-n", str(fetch_limit)])
1661
+
1662
+ cmd = " ".join(cmd_parts)
1663
+ result = self._exec(cmd, timeout=60)
1664
+
1665
+ # rg exit codes: 0=matches found, 1=no matches, 2=error
1666
+ if result.exit_code == 2 and not result.stdout.strip():
1667
+ error_msg = result.stderr.strip() if hasattr(result, 'stderr') and result.stderr else "Search error"
1668
+ return SearchResult(error=f"Search failed: {error_msg}", total_count=0)
1669
+
1670
+ # Parse results based on output mode
1671
+ if output_mode == "files_only":
1672
+ all_files = [f for f in result.stdout.strip().split('\n') if f]
1673
+ total = len(all_files)
1674
+ page = all_files[offset:offset + limit]
1675
+ return SearchResult(files=page, total_count=total)
1676
+
1677
+ elif output_mode == "count":
1678
+ counts = {}
1679
+ for line in result.stdout.strip().split('\n'):
1680
+ if ':' in line:
1681
+ parts = line.rsplit(':', 1)
1682
+ if len(parts) == 2:
1683
+ try:
1684
+ counts[parts[0]] = int(parts[1])
1685
+ except ValueError:
1686
+ pass
1687
+ return SearchResult(counts=counts, total_count=sum(counts.values()))
1688
+
1689
+ else:
1690
+ # Parse content matches and context lines.
1691
+ # rg match lines: "file:lineno:content" (colon separator)
1692
+ # rg context lines: "file-lineno-content" (dash separator)
1693
+ # rg group seps: "--"
1694
+ # Note: on Windows, paths contain drive letters (e.g. C:\path),
1695
+ # so naive split(":") breaks. Use regex to handle both platforms.
1696
+ _match_re = re.compile(r'^([A-Za-z]:)?(.*?):(\d+):(.*)$')
1697
+ matches = []
1698
+ for line in result.stdout.strip().split('\n'):
1699
+ if not line or line == "--":
1700
+ continue
1701
+
1702
+ # Try match line first (colon-separated: file:line:content)
1703
+ m = _match_re.match(line)
1704
+ if m:
1705
+ matches.append(SearchMatch(
1706
+ path=(m.group(1) or '') + m.group(2),
1707
+ line_number=int(m.group(3)),
1708
+ content=m.group(4)[:500]
1709
+ ))
1710
+ continue
1711
+
1712
+ # Try context line (dash-separated: file-line-content)
1713
+ # Only attempt if context was requested to avoid false positives
1714
+ if context > 0:
1715
+ parsed = _parse_search_context_line(line)
1716
+ if parsed:
1717
+ matches.append(SearchMatch(
1718
+ path=parsed[0],
1719
+ line_number=parsed[1],
1720
+ content=parsed[2][:500]
1721
+ ))
1722
+
1723
+ total = len(matches)
1724
+ page = matches[offset:offset + limit]
1725
+ return SearchResult(
1726
+ matches=page,
1727
+ total_count=total,
1728
+ truncated=total > offset + limit
1729
+ )
1730
+
1731
+ def _search_with_grep(self, pattern: str, path: str, file_glob: Optional[str],
1732
+ limit: int, offset: int, output_mode: str, context: int) -> SearchResult:
1733
+ """Fallback search using grep."""
1734
+ cmd_parts = ["grep", "-rnH"] # -H forces filename even for single-file searches
1735
+
1736
+ # Exclude hidden directories (matching ripgrep's default behavior).
1737
+ # This prevents searching inside .hub/index-cache/, .git/, etc.
1738
+ cmd_parts.append("--exclude-dir='.*'")
1739
+
1740
+ # Add context if requested
1741
+ if context > 0:
1742
+ cmd_parts.extend(["-C", str(context)])
1743
+
1744
+ # Add file pattern filter (must be quoted to prevent shell expansion)
1745
+ if file_glob:
1746
+ cmd_parts.extend(["--include", self._escape_shell_arg(file_glob)])
1747
+
1748
+ # Output mode handling
1749
+ if output_mode == "files_only":
1750
+ cmd_parts.append("-l")
1751
+ elif output_mode == "count":
1752
+ cmd_parts.append("-c")
1753
+
1754
+ # Add pattern and path
1755
+ cmd_parts.append(self._escape_shell_arg(pattern))
1756
+ cmd_parts.append(self._escape_shell_arg(path))
1757
+
1758
+ # Fetch generously so we can compute total before slicing
1759
+ fetch_limit = limit + offset + (200 if context > 0 else 0)
1760
+ cmd_parts.extend(["|", "head", "-n", str(fetch_limit)])
1761
+
1762
+ cmd = " ".join(cmd_parts)
1763
+ result = self._exec(cmd, timeout=60)
1764
+
1765
+ # grep exit codes: 0=matches found, 1=no matches, 2=error
1766
+ if result.exit_code == 2 and not result.stdout.strip():
1767
+ error_msg = result.stderr.strip() if hasattr(result, 'stderr') and result.stderr else "Search error"
1768
+ return SearchResult(error=f"Search failed: {error_msg}", total_count=0)
1769
+
1770
+ if output_mode == "files_only":
1771
+ all_files = [f for f in result.stdout.strip().split('\n') if f]
1772
+ total = len(all_files)
1773
+ page = all_files[offset:offset + limit]
1774
+ return SearchResult(files=page, total_count=total)
1775
+
1776
+ elif output_mode == "count":
1777
+ counts = {}
1778
+ for line in result.stdout.strip().split('\n'):
1779
+ if ':' in line:
1780
+ parts = line.rsplit(':', 1)
1781
+ if len(parts) == 2:
1782
+ try:
1783
+ counts[parts[0]] = int(parts[1])
1784
+ except ValueError:
1785
+ pass
1786
+ return SearchResult(counts=counts, total_count=sum(counts.values()))
1787
+
1788
+ else:
1789
+ # grep match lines: "file:lineno:content" (colon)
1790
+ # grep context lines: "file-lineno-content" (dash)
1791
+ # grep group seps: "--"
1792
+ # Note: on Windows, paths contain drive letters (e.g. C:\path),
1793
+ # so naive split(":") breaks. Use regex to handle both platforms.
1794
+ _match_re = re.compile(r'^([A-Za-z]:)?(.*?):(\d+):(.*)$')
1795
+ matches = []
1796
+ for line in result.stdout.strip().split('\n'):
1797
+ if not line or line == "--":
1798
+ continue
1799
+
1800
+ m = _match_re.match(line)
1801
+ if m:
1802
+ matches.append(SearchMatch(
1803
+ path=(m.group(1) or '') + m.group(2),
1804
+ line_number=int(m.group(3)),
1805
+ content=m.group(4)[:500]
1806
+ ))
1807
+ continue
1808
+
1809
+ if context > 0:
1810
+ parsed = _parse_search_context_line(line)
1811
+ if parsed:
1812
+ matches.append(SearchMatch(
1813
+ path=parsed[0],
1814
+ line_number=parsed[1],
1815
+ content=parsed[2][:500]
1816
+ ))
1817
+
1818
+
1819
+ total = len(matches)
1820
+ page = matches[offset:offset + limit]
1821
+ return SearchResult(
1822
+ matches=page,
1823
+ total_count=total,
1824
+ truncated=total > offset + limit
1825
+ )