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,1639 @@
1
+ """
2
+ Checkpoint Manager — Transparent filesystem snapshots via a single shared
3
+ shadow git store.
4
+
5
+ Creates automatic snapshots of working directories before file-mutating
6
+ operations (``write_file``, ``patch``, ``terminal`` with destructive flags),
7
+ triggered once per conversation turn. Provides rollback to any previous
8
+ checkpoint.
9
+
10
+ This is NOT a tool — the LLM never sees it. It's transparent infrastructure
11
+ controlled by the ``checkpoints`` config flag or ``--checkpoints`` CLI flag.
12
+
13
+ Storage layout (single shared store, git objects deduplicated across projects)
14
+ -----------------------------------------------------------------------------
15
+
16
+ ~/.hermes/checkpoints/
17
+ store/ — single bare-ish git repo
18
+ HEAD, config, objects/ — standard git internals (shared)
19
+ refs/hermes/<hash16> — per-project branch tip
20
+ indexes/<hash16> — per-project git index
21
+ projects/<hash16>.json — {workdir, created_at, last_touch}
22
+ info/exclude — default excludes (shared)
23
+ .last_prune — auto-prune idempotency marker
24
+ legacy-<timestamp>/ — archived pre-v2 per-project shadow
25
+ repos (auto-migrated on first init)
26
+
27
+ Why a single store?
28
+ -------------------
29
+
30
+ The pre-v2 design kept a full shadow repo per working directory. Each one
31
+ re-stored most of the project's files under its own ``objects/`` tree, with
32
+ zero sharing across worktrees of the same project. A single user with a
33
+ dozen worktrees of the same repo burned ~40 MB each (~500 MB total) storing
34
+ the same blobs over and over. A single shared store lets git's content-
35
+ addressable object DB deduplicate across projects and across turns, so adding
36
+ a new worktree costs near-zero.
37
+
38
+ The shadow store uses ``GIT_DIR`` + ``GIT_WORK_TREE`` + ``GIT_INDEX_FILE``
39
+ so no git state leaks into the user's project directory.
40
+
41
+ Auto-maintenance
42
+ ----------------
43
+
44
+ Shadow state accumulates over time. ``prune_checkpoints`` deletes refs whose
45
+ recorded working directory no longer exists (orphan) or whose last touch is
46
+ older than ``retention_days`` (stale), then runs ``git gc --prune=now`` to
47
+ reclaim object storage. A size-cap pass drops the oldest checkpoints per
48
+ project until total store size is under ``max_total_size_mb``.
49
+ """
50
+
51
+ import hashlib
52
+ import json
53
+ import logging
54
+ import os
55
+ import re
56
+ import shutil
57
+ import subprocess
58
+ import time
59
+ from pathlib import Path
60
+ from calvyn_constants import get_hermes_home
61
+ from typing import Dict, List, Optional, Set, Tuple
62
+
63
+ logger = logging.getLogger(__name__)
64
+
65
+ # ---------------------------------------------------------------------------
66
+ # Constants
67
+ # ---------------------------------------------------------------------------
68
+
69
+ CHECKPOINT_BASE = get_hermes_home() / "checkpoints"
70
+
71
+ # Single shared store directory under CHECKPOINT_BASE.
72
+ _STORE_DIRNAME = "store"
73
+ _REFS_PREFIX = "refs/hermes"
74
+ _INDEXES_DIRNAME = "indexes"
75
+ _PROJECTS_DIRNAME = "projects"
76
+ _LEGACY_PREFIX = "legacy-"
77
+
78
+ DEFAULT_EXCLUDES = [
79
+ # Dependency / build output
80
+ "node_modules/",
81
+ "dist/",
82
+ "build/",
83
+ "target/",
84
+ "out/",
85
+ ".next/",
86
+ ".nuxt/",
87
+ # Caches
88
+ "__pycache__/",
89
+ "*.pyc",
90
+ "*.pyo",
91
+ ".cache/",
92
+ ".pytest_cache/",
93
+ ".mypy_cache/",
94
+ ".ruff_cache/",
95
+ "coverage/",
96
+ ".coverage",
97
+ # Virtualenvs
98
+ ".venv/",
99
+ "venv/",
100
+ "env/",
101
+ # VCS
102
+ ".git/",
103
+ ".hg/",
104
+ ".svn/",
105
+ # Worktrees (Hermes convention — don't recursively snapshot siblings)
106
+ ".worktrees/",
107
+ # Native / compiled binaries
108
+ "*.so",
109
+ "*.dylib",
110
+ "*.dll",
111
+ "*.o",
112
+ "*.a",
113
+ "*.jar",
114
+ "*.class",
115
+ "*.exe",
116
+ "*.obj",
117
+ # Media / large binaries
118
+ "*.mp4",
119
+ "*.mov",
120
+ "*.mkv",
121
+ "*.webm",
122
+ "*.zip",
123
+ "*.tar",
124
+ "*.tar.gz",
125
+ "*.tgz",
126
+ "*.7z",
127
+ "*.rar",
128
+ "*.iso",
129
+ # Secrets
130
+ ".env",
131
+ ".env.*",
132
+ ".env.local",
133
+ ".env.*.local",
134
+ # OS junk
135
+ ".DS_Store",
136
+ "Thumbs.db",
137
+ # Logs
138
+ "*.log",
139
+ ]
140
+
141
+ # Git subprocess timeout (seconds).
142
+ _GIT_TIMEOUT: int = max(10, min(60, int(os.getenv("HERMES_CHECKPOINT_TIMEOUT", "30"))))
143
+
144
+ # Max files to snapshot — skip huge directories to avoid slowdowns.
145
+ _MAX_FILES = 50_000
146
+
147
+ # Valid git commit hash pattern: 4–40 hex chars (short or full SHA-1/SHA-256).
148
+ _COMMIT_HASH_RE = re.compile(r'^[0-9a-fA-F]{4,64}$')
149
+
150
+
151
+ # ---------------------------------------------------------------------------
152
+ # Input validation helpers
153
+ # ---------------------------------------------------------------------------
154
+
155
+ def _validate_commit_hash(commit_hash: str) -> Optional[str]:
156
+ """Validate a commit hash to prevent git argument injection.
157
+
158
+ Returns an error string if invalid, None if valid.
159
+ Values starting with '-' would be interpreted as git flags
160
+ (e.g., '--patch', '-p') instead of revision specifiers.
161
+ """
162
+ if not commit_hash or not commit_hash.strip():
163
+ return "Empty commit hash"
164
+ if commit_hash.startswith("-"):
165
+ return f"Invalid commit hash (must not start with '-'): {commit_hash!r}"
166
+ if not _COMMIT_HASH_RE.match(commit_hash):
167
+ return f"Invalid commit hash (expected 4-64 hex characters): {commit_hash!r}"
168
+ return None
169
+
170
+
171
+ def _validate_file_path(file_path: str, working_dir: str) -> Optional[str]:
172
+ """Validate a file path to prevent path traversal outside the working directory.
173
+
174
+ Returns an error string if invalid, None if valid.
175
+ """
176
+ if not file_path or not file_path.strip():
177
+ return "Empty file path"
178
+ if os.path.isabs(file_path):
179
+ return f"File path must be relative, got absolute path: {file_path!r}"
180
+ abs_workdir = _normalize_path(working_dir)
181
+ resolved = (abs_workdir / file_path).resolve()
182
+ try:
183
+ resolved.relative_to(abs_workdir)
184
+ except ValueError:
185
+ return f"File path escapes the working directory via traversal: {file_path!r}"
186
+ return None
187
+
188
+
189
+ # ---------------------------------------------------------------------------
190
+ # Path / hash helpers
191
+ # ---------------------------------------------------------------------------
192
+
193
+ def _normalize_path(path_value: str) -> Path:
194
+ """Return a canonical absolute path for checkpoint operations."""
195
+ return Path(path_value).expanduser().resolve()
196
+
197
+
198
+ def _project_hash(working_dir: str) -> str:
199
+ """Deterministic per-project hash: sha256(abs_path)[:16]."""
200
+ abs_path = str(_normalize_path(working_dir))
201
+ return hashlib.sha256(abs_path.encode()).hexdigest()[:16]
202
+
203
+
204
+ def _store_path(base: Optional[Path] = None) -> Path:
205
+ """Return the single shared shadow store path."""
206
+ return (base or CHECKPOINT_BASE) / _STORE_DIRNAME
207
+
208
+
209
+ def _shadow_repo_path(working_dir: str) -> Path: # pragma: no cover — kept for BC
210
+ """Return the shared store path.
211
+
212
+ Retained for backward-compatibility with callers / tests that imported
213
+ this helper. Under v2 the shadow git storage is shared across all
214
+ projects — per-project isolation lives in refs and indexes, not in
215
+ separate repo directories.
216
+ """
217
+ return _store_path()
218
+
219
+
220
+ def _index_path(store: Path, dir_hash: str) -> Path:
221
+ return store / _INDEXES_DIRNAME / dir_hash
222
+
223
+
224
+ def _ref_name(dir_hash: str) -> str:
225
+ return f"{_REFS_PREFIX}/{dir_hash}"
226
+
227
+
228
+ def _project_meta_path(store: Path, dir_hash: str) -> Path:
229
+ return store / _PROJECTS_DIRNAME / f"{dir_hash}.json"
230
+
231
+
232
+ # ---------------------------------------------------------------------------
233
+ # Git env
234
+ # ---------------------------------------------------------------------------
235
+
236
+ def _git_env(
237
+ store: Path,
238
+ working_dir: str,
239
+ index_file: Optional[Path] = None,
240
+ ) -> dict:
241
+ """Build env dict that redirects git to the shared store.
242
+
243
+ The shared store is internal Hermes infrastructure — it must NOT inherit
244
+ the user's global or system git config. User-level settings like
245
+ ``commit.gpgsign = true``, signing hooks, or credential helpers would
246
+ either break background snapshots or, worse, spawn interactive prompts
247
+ (pinentry GUI windows) mid-session every time a file is written.
248
+
249
+ Isolation strategy:
250
+ * ``GIT_CONFIG_GLOBAL=<os.devnull>`` — ignore ``~/.gitconfig`` (git 2.32+).
251
+ * ``GIT_CONFIG_SYSTEM=<os.devnull>`` — ignore ``/etc/gitconfig`` (git 2.32+).
252
+ * ``GIT_CONFIG_NOSYSTEM=1`` — legacy belt-and-suspenders for older git.
253
+
254
+ ``index_file``, if given, forces git to use a per-project index under
255
+ ``store/indexes/<hash>`` so projects don't race on a shared index.
256
+ """
257
+ normalized_working_dir = _normalize_path(working_dir)
258
+ env = os.environ.copy()
259
+ env["GIT_DIR"] = str(store)
260
+ env["GIT_WORK_TREE"] = str(normalized_working_dir)
261
+ env.pop("GIT_NAMESPACE", None)
262
+ env.pop("GIT_ALTERNATE_OBJECT_DIRECTORIES", None)
263
+ if index_file is not None:
264
+ env["GIT_INDEX_FILE"] = str(index_file)
265
+ else:
266
+ env.pop("GIT_INDEX_FILE", None)
267
+ env["GIT_CONFIG_GLOBAL"] = os.devnull
268
+ env["GIT_CONFIG_SYSTEM"] = os.devnull
269
+ env["GIT_CONFIG_NOSYSTEM"] = "1"
270
+ return env
271
+
272
+
273
+ def _run_git(
274
+ args: List[str],
275
+ store: Path,
276
+ working_dir: str,
277
+ timeout: int = _GIT_TIMEOUT,
278
+ allowed_returncodes: Optional[Set[int]] = None,
279
+ index_file: Optional[Path] = None,
280
+ ) -> Tuple[bool, str, str]:
281
+ """Run a git command against the shared store. Returns (ok, stdout, stderr).
282
+
283
+ ``allowed_returncodes`` suppresses error logging for known/expected non-zero
284
+ exits while preserving the normal ``ok = (returncode == 0)`` contract.
285
+ Example: ``git diff --cached --quiet`` returns 1 when changes exist.
286
+ """
287
+ normalized_working_dir = _normalize_path(working_dir)
288
+ if not normalized_working_dir.exists():
289
+ msg = f"working directory not found: {normalized_working_dir}"
290
+ logger.error("Git command skipped: %s (%s)", " ".join(["git"] + list(args)), msg)
291
+ return False, "", msg
292
+ if not normalized_working_dir.is_dir():
293
+ msg = f"working directory is not a directory: {normalized_working_dir}"
294
+ logger.error("Git command skipped: %s (%s)", " ".join(["git"] + list(args)), msg)
295
+ return False, "", msg
296
+
297
+ env = _git_env(store, str(normalized_working_dir), index_file=index_file)
298
+ cmd = ["git"] + list(args)
299
+ allowed_returncodes = allowed_returncodes or set()
300
+ try:
301
+ result = subprocess.run(
302
+ cmd,
303
+ capture_output=True,
304
+ text=True,
305
+ timeout=timeout,
306
+ env=env,
307
+ cwd=str(normalized_working_dir),
308
+ )
309
+ ok = result.returncode == 0
310
+ stdout = result.stdout.strip()
311
+ stderr = result.stderr.strip()
312
+ if not ok and result.returncode not in allowed_returncodes:
313
+ logger.error(
314
+ "Git command failed: %s (rc=%d) stderr=%s",
315
+ " ".join(cmd), result.returncode, stderr,
316
+ )
317
+ return ok, stdout, stderr
318
+ except subprocess.TimeoutExpired:
319
+ msg = f"git timed out after {timeout}s: {' '.join(cmd)}"
320
+ logger.error(msg, exc_info=True)
321
+ return False, "", msg
322
+ except FileNotFoundError as exc:
323
+ missing_target = getattr(exc, "filename", None)
324
+ if missing_target == "git":
325
+ logger.error("Git executable not found: %s", " ".join(cmd), exc_info=True)
326
+ return False, "", "git not found"
327
+ msg = f"working directory not found: {normalized_working_dir}"
328
+ logger.error("Git command failed before execution: %s (%s)", " ".join(cmd), msg, exc_info=True)
329
+ return False, "", msg
330
+ except Exception as exc:
331
+ logger.error("Unexpected git error running %s: %s", " ".join(cmd), exc, exc_info=True)
332
+ return False, "", str(exc)
333
+
334
+
335
+ # ---------------------------------------------------------------------------
336
+ # Store initialisation + legacy migration
337
+ # ---------------------------------------------------------------------------
338
+
339
+ def _migrate_legacy_store(base: Path) -> Optional[Path]:
340
+ """Move pre-v2 per-project shadow repos into a ``legacy-<ts>/`` dir.
341
+
342
+ The pre-v2 layout had one shadow git repo per working directory directly
343
+ under ``CHECKPOINT_BASE``. The v2 layout wants a single ``store/`` dir.
344
+ Rather than delete the old data (users might want to recover), rename
345
+ everything except our own v2 entries into ``legacy-<timestamp>/``. The
346
+ legacy dir is subject to the same retention sweep and can be manually
347
+ cleared with ``hermes checkpoints clear-legacy``.
348
+
349
+ Returns the legacy-archive path, or None if nothing to migrate.
350
+ """
351
+ if not base.exists():
352
+ return None
353
+ store = _store_path(base)
354
+ legacy_root: Optional[Path] = None
355
+ # Reserved top-level entries managed by v2.
356
+ reserved = {_STORE_DIRNAME, _PRUNE_MARKER_NAME}
357
+ for child in list(base.iterdir()):
358
+ name = child.name
359
+ if name in reserved or name.startswith(_LEGACY_PREFIX):
360
+ continue
361
+ # Candidate: pre-v2 shadow repo (has HEAD) OR stray dir. Either way
362
+ # we archive it so v2 starts clean.
363
+ if legacy_root is None:
364
+ stamp = time.strftime("%Y%m%d-%H%M%S")
365
+ legacy_root = base / f"{_LEGACY_PREFIX}{stamp}"
366
+ try:
367
+ legacy_root.mkdir(parents=True, exist_ok=True)
368
+ except OSError as exc:
369
+ logger.warning("Could not create legacy archive dir: %s", exc)
370
+ return None
371
+ dest = legacy_root / name
372
+ try:
373
+ shutil.move(str(child), str(dest))
374
+ except OSError as exc:
375
+ logger.warning("Could not archive legacy checkpoint %s: %s", child, exc)
376
+ # If the store still hasn't been created, create it here.
377
+ _ = store
378
+ if legacy_root is not None:
379
+ logger.info(
380
+ "Migrated pre-v2 checkpoint repos to %s. "
381
+ "Clear with `hermes checkpoints clear-legacy` when safe.",
382
+ legacy_root,
383
+ )
384
+ return legacy_root
385
+
386
+
387
+ def _init_store(store: Path, working_dir: str) -> Optional[str]:
388
+ """Initialise the shared shadow store if needed. Returns error or None.
389
+
390
+ Also performs one-time migration of pre-v2 per-directory shadow repos
391
+ into ``legacy-<timestamp>/``.
392
+ """
393
+ base = store.parent
394
+ # One-time legacy migration before we create the store.
395
+ if not store.exists():
396
+ try:
397
+ base.mkdir(parents=True, exist_ok=True)
398
+ except OSError as exc:
399
+ return f"Could not create checkpoint base: {exc}"
400
+ # Only migrate if the base dir has pre-existing content that isn't
401
+ # our own v2 layout.
402
+ _migrate_legacy_store(base)
403
+
404
+ if (store / "HEAD").exists():
405
+ return None
406
+
407
+ store.mkdir(parents=True, exist_ok=True)
408
+ (store / _INDEXES_DIRNAME).mkdir(exist_ok=True)
409
+ (store / _PROJECTS_DIRNAME).mkdir(exist_ok=True)
410
+
411
+ # ``git init --bare`` rejects GIT_WORK_TREE, so we can't use _run_git
412
+ # here (which always sets GIT_DIR + GIT_WORK_TREE). Use a raw
413
+ # subprocess with just the config-isolation env vars.
414
+ init_env = os.environ.copy()
415
+ init_env["GIT_CONFIG_GLOBAL"] = os.devnull
416
+ init_env["GIT_CONFIG_SYSTEM"] = os.devnull
417
+ init_env["GIT_CONFIG_NOSYSTEM"] = "1"
418
+ # Drop any inherited GIT_* that would interfere.
419
+ for k in ("GIT_DIR", "GIT_WORK_TREE", "GIT_INDEX_FILE", "GIT_NAMESPACE",
420
+ "GIT_ALTERNATE_OBJECT_DIRECTORIES"):
421
+ init_env.pop(k, None)
422
+ try:
423
+ result = subprocess.run(
424
+ ["git", "init", "--bare", str(store)],
425
+ capture_output=True, text=True,
426
+ env=init_env, timeout=_GIT_TIMEOUT,
427
+ )
428
+ if result.returncode != 0:
429
+ return f"Shadow store init failed: {result.stderr.strip()}"
430
+ except (subprocess.TimeoutExpired, FileNotFoundError) as exc:
431
+ return f"Shadow store init failed: {exc}"
432
+
433
+ # Per-store config (isolated by env vars above, but belt-and-suspenders).
434
+ # Use the base dir as the working_dir for config commands — it always
435
+ # exists since we just created the store inside it.
436
+ cfg_wd = str(base)
437
+ _run_git(["config", "user.email", "hermes@local"], store, cfg_wd)
438
+ _run_git(["config", "user.name", "Hermes Checkpoint"], store, cfg_wd)
439
+ _run_git(["config", "commit.gpgsign", "false"], store, cfg_wd)
440
+ _run_git(["config", "tag.gpgSign", "false"], store, cfg_wd)
441
+ _run_git(["config", "gc.auto", "0"], store, cfg_wd)
442
+
443
+ info_dir = store / "info"
444
+ info_dir.mkdir(exist_ok=True)
445
+ (info_dir / "exclude").write_text(
446
+ "\n".join(DEFAULT_EXCLUDES) + "\n", encoding="utf-8"
447
+ )
448
+
449
+ logger.debug("Initialised checkpoint store at %s", store)
450
+ return None
451
+
452
+
453
+ def _register_project(store: Path, working_dir: str) -> None:
454
+ """Create or update ``projects/<hash>.json`` with workdir + timestamps."""
455
+ dir_hash = _project_hash(working_dir)
456
+ meta_path = _project_meta_path(store, dir_hash)
457
+ now = time.time()
458
+ meta: Dict = {"workdir": str(_normalize_path(working_dir)),
459
+ "created_at": now, "last_touch": now}
460
+ if meta_path.exists():
461
+ try:
462
+ existing = json.loads(meta_path.read_text(encoding="utf-8"))
463
+ if isinstance(existing, dict):
464
+ meta["created_at"] = existing.get("created_at", now)
465
+ except (OSError, ValueError):
466
+ pass
467
+ try:
468
+ meta_path.parent.mkdir(parents=True, exist_ok=True)
469
+ meta_path.write_text(json.dumps(meta), encoding="utf-8")
470
+ except OSError as exc:
471
+ logger.debug("Could not write project metadata %s: %s", meta_path, exc)
472
+
473
+
474
+ def _touch_project(store: Path, working_dir: str) -> None:
475
+ """Update last_touch for a project, preserving created_at."""
476
+ dir_hash = _project_hash(working_dir)
477
+ meta_path = _project_meta_path(store, dir_hash)
478
+ if not meta_path.exists():
479
+ _register_project(store, working_dir)
480
+ return
481
+ try:
482
+ meta = json.loads(meta_path.read_text(encoding="utf-8"))
483
+ except (OSError, ValueError):
484
+ meta = {}
485
+ if not isinstance(meta, dict):
486
+ meta = {}
487
+ meta["workdir"] = str(_normalize_path(working_dir))
488
+ meta["last_touch"] = time.time()
489
+ meta.setdefault("created_at", meta["last_touch"])
490
+ try:
491
+ meta_path.write_text(json.dumps(meta), encoding="utf-8")
492
+ except OSError as exc:
493
+ logger.debug("Could not update project metadata %s: %s", meta_path, exc)
494
+
495
+
496
+ def _list_projects(store: Path) -> List[Dict]:
497
+ """Return all registered projects under the store."""
498
+ projects_dir = store / _PROJECTS_DIRNAME
499
+ if not projects_dir.exists():
500
+ return []
501
+ out: List[Dict] = []
502
+ for meta_path in projects_dir.glob("*.json"):
503
+ dir_hash = meta_path.stem
504
+ try:
505
+ meta = json.loads(meta_path.read_text(encoding="utf-8"))
506
+ except (OSError, ValueError):
507
+ continue
508
+ if not isinstance(meta, dict):
509
+ continue
510
+ meta["_hash"] = dir_hash
511
+ out.append(meta)
512
+ return out
513
+
514
+
515
+ def _dir_file_count(path: str) -> int:
516
+ """Quick file count estimate (stops early if over _MAX_FILES)."""
517
+ count = 0
518
+ try:
519
+ for _ in Path(path).rglob("*"):
520
+ count += 1
521
+ if count > _MAX_FILES:
522
+ return count
523
+ except (PermissionError, OSError):
524
+ pass
525
+ return count
526
+
527
+
528
+ def _dir_size_bytes(path: Path) -> int:
529
+ """Best-effort recursive size in bytes. Returns 0 on error."""
530
+ total = 0
531
+ try:
532
+ for p in path.rglob("*"):
533
+ try:
534
+ if p.is_file():
535
+ total += p.stat().st_size
536
+ except OSError:
537
+ continue
538
+ except OSError:
539
+ pass
540
+ return total
541
+
542
+
543
+ # Backwards-compatibility shim — some tests import ``_init_shadow_repo`` and
544
+ # look for ``HEAD``/``info/exclude``/``HERMES_WORKDIR``. In v2 we also write
545
+ # those markers, but inside the shared store + under ``projects/<hash>.json``.
546
+ # The shim initialises the store and registers the project so the old
547
+ # surface keeps roughly the same shape.
548
+ def _init_shadow_repo(shadow_repo: Path, working_dir: str) -> Optional[str]:
549
+ """Backwards-compatible initialiser.
550
+
551
+ In v1 ``shadow_repo`` was a per-project dir; in v2 it's the shared
552
+ ``store/`` path (or a test path that we respect). We initialise the
553
+ store at ``shadow_repo``, create per-project markers, and return None
554
+ on success.
555
+ """
556
+ err = _init_store(shadow_repo, working_dir)
557
+ if err:
558
+ return err
559
+ _register_project(shadow_repo, working_dir)
560
+ # Compat marker for tests that look at HERMES_WORKDIR
561
+ # (write in addition to the JSON metadata).
562
+ try:
563
+ (shadow_repo / "HERMES_WORKDIR").write_text(
564
+ str(_normalize_path(working_dir)) + "\n", encoding="utf-8"
565
+ )
566
+ except OSError:
567
+ pass
568
+ return None
569
+
570
+
571
+ # ---------------------------------------------------------------------------
572
+ # CheckpointManager
573
+ # ---------------------------------------------------------------------------
574
+
575
+ class CheckpointManager:
576
+ """Manages automatic filesystem checkpoints.
577
+
578
+ Designed to be owned by AIAgent. Call ``new_turn()`` at the start of
579
+ each conversation turn and ``ensure_checkpoint(dir, reason)`` before
580
+ any file-mutating tool call. The manager deduplicates so at most one
581
+ snapshot is taken per directory per turn.
582
+
583
+ Parameters
584
+ ----------
585
+ enabled : bool
586
+ Master switch (from config / CLI flag).
587
+ max_snapshots : int
588
+ Keep at most this many checkpoints per directory.
589
+ max_total_size_mb : int
590
+ Hard ceiling on total store size. Oldest checkpoints per project
591
+ are dropped when the store exceeds this after a commit.
592
+ max_file_size_mb : int
593
+ Skip adding any single file larger than this to a checkpoint.
594
+ (Implemented via ``.gitignore`` excludes + a post-stage size check.)
595
+ """
596
+
597
+ def __init__(
598
+ self,
599
+ enabled: bool = False,
600
+ max_snapshots: int = 20,
601
+ max_total_size_mb: int = 500,
602
+ max_file_size_mb: int = 10,
603
+ ):
604
+ self.enabled = enabled
605
+ self.max_snapshots = max(1, int(max_snapshots))
606
+ self.max_total_size_mb = max(0, int(max_total_size_mb))
607
+ self.max_file_size_mb = max(0, int(max_file_size_mb))
608
+ self._checkpointed_dirs: Set[str] = set()
609
+ self._git_available: Optional[bool] = None # lazy probe
610
+
611
+ # ------------------------------------------------------------------
612
+ # Turn lifecycle
613
+ # ------------------------------------------------------------------
614
+
615
+ def new_turn(self) -> None:
616
+ """Reset per-turn dedup. Call at the start of each agent iteration."""
617
+ self._checkpointed_dirs.clear()
618
+
619
+ # ------------------------------------------------------------------
620
+ # Public API
621
+ # ------------------------------------------------------------------
622
+
623
+ def ensure_checkpoint(self, working_dir: str, reason: str = "auto") -> bool:
624
+ """Take a checkpoint if enabled and not already done this turn.
625
+
626
+ Returns True if a checkpoint was taken, False otherwise.
627
+ Never raises — all errors are silently logged.
628
+ """
629
+ if not self.enabled:
630
+ return False
631
+
632
+ if self._git_available is None:
633
+ self._git_available = shutil.which("git") is not None
634
+ if not self._git_available:
635
+ logger.debug("Checkpoints disabled: git not found")
636
+ if not self._git_available:
637
+ return False
638
+
639
+ abs_dir = str(_normalize_path(working_dir))
640
+
641
+ # Skip root, home, and other overly broad directories
642
+ if abs_dir in {"/", str(Path.home())}:
643
+ logger.debug("Checkpoint skipped: directory too broad (%s)", abs_dir)
644
+ return False
645
+
646
+ if abs_dir in self._checkpointed_dirs:
647
+ return False
648
+
649
+ self._checkpointed_dirs.add(abs_dir)
650
+
651
+ try:
652
+ return self._take(abs_dir, reason)
653
+ except Exception as e:
654
+ logger.debug("Checkpoint failed (non-fatal): %s", e)
655
+ return False
656
+
657
+ def list_checkpoints(self, working_dir: str) -> List[Dict]:
658
+ """List available checkpoints for a directory (most recent first)."""
659
+ abs_dir = str(_normalize_path(working_dir))
660
+ store = _store_path(CHECKPOINT_BASE)
661
+
662
+ if not (store / "HEAD").exists():
663
+ return []
664
+
665
+ ref = _ref_name(_project_hash(abs_dir))
666
+ ok, stdout, _ = _run_git(
667
+ ["log", ref, f"--format=%H|%h|%aI|%s", "-n", str(self.max_snapshots)],
668
+ store, abs_dir,
669
+ allowed_returncodes={128, 129},
670
+ )
671
+
672
+ if not ok or not stdout:
673
+ return []
674
+
675
+ results: List[Dict] = []
676
+ for line in stdout.splitlines():
677
+ parts = line.split("|", 3)
678
+ if len(parts) == 4:
679
+ entry = {
680
+ "hash": parts[0],
681
+ "short_hash": parts[1],
682
+ "timestamp": parts[2],
683
+ "reason": parts[3],
684
+ "files_changed": 0,
685
+ "insertions": 0,
686
+ "deletions": 0,
687
+ }
688
+ stat_ok, stat_out, _ = _run_git(
689
+ ["diff", "--shortstat", f"{parts[0]}~1", parts[0]],
690
+ store, abs_dir,
691
+ allowed_returncodes={128, 129},
692
+ )
693
+ if stat_ok and stat_out:
694
+ self._parse_shortstat(stat_out, entry)
695
+ results.append(entry)
696
+ return results
697
+
698
+ @staticmethod
699
+ def _parse_shortstat(stat_line: str, entry: Dict) -> None:
700
+ """Parse git --shortstat output into entry dict."""
701
+ m = re.search(r'(\d+) file', stat_line)
702
+ if m:
703
+ entry["files_changed"] = int(m.group(1))
704
+ m = re.search(r'(\d+) insertion', stat_line)
705
+ if m:
706
+ entry["insertions"] = int(m.group(1))
707
+ m = re.search(r'(\d+) deletion', stat_line)
708
+ if m:
709
+ entry["deletions"] = int(m.group(1))
710
+
711
+ def diff(self, working_dir: str, commit_hash: str) -> Dict:
712
+ """Show diff between a checkpoint and the current working tree."""
713
+ hash_err = _validate_commit_hash(commit_hash)
714
+ if hash_err:
715
+ return {"success": False, "error": hash_err}
716
+
717
+ abs_dir = str(_normalize_path(working_dir))
718
+ store = _store_path(CHECKPOINT_BASE)
719
+
720
+ if not (store / "HEAD").exists():
721
+ return {"success": False, "error": "No checkpoints exist for this directory"}
722
+
723
+ ok, _, err = _run_git(
724
+ ["cat-file", "-t", commit_hash], store, abs_dir,
725
+ )
726
+ if not ok:
727
+ return {"success": False, "error": f"Checkpoint '{commit_hash}' not found"}
728
+
729
+ dir_hash = _project_hash(abs_dir)
730
+ index_file = _index_path(store, dir_hash)
731
+
732
+ # Stage current state into the per-project index to compare.
733
+ _run_git(["add", "-A"], store, abs_dir,
734
+ timeout=_GIT_TIMEOUT * 2, index_file=index_file)
735
+
736
+ ok_stat, stat_out, _ = _run_git(
737
+ ["diff", "--stat", commit_hash, "--cached"],
738
+ store, abs_dir, index_file=index_file,
739
+ )
740
+ ok_diff, diff_out, _ = _run_git(
741
+ ["diff", commit_hash, "--cached", "--no-color"],
742
+ store, abs_dir, index_file=index_file,
743
+ )
744
+
745
+ # Reset staged tree back to the project's last checkpoint so the
746
+ # index doesn't drift out of sync with the ref.
747
+ ref = _ref_name(dir_hash)
748
+ _run_git(["read-tree", ref], store, abs_dir,
749
+ index_file=index_file,
750
+ allowed_returncodes={128})
751
+
752
+ if not ok_stat and not ok_diff:
753
+ return {"success": False, "error": "Could not generate diff"}
754
+
755
+ return {
756
+ "success": True,
757
+ "stat": stat_out if ok_stat else "",
758
+ "diff": diff_out if ok_diff else "",
759
+ }
760
+
761
+ def restore(self, working_dir: str, commit_hash: str, file_path: str = None) -> Dict:
762
+ """Restore files to a checkpoint state."""
763
+ hash_err = _validate_commit_hash(commit_hash)
764
+ if hash_err:
765
+ return {"success": False, "error": hash_err}
766
+
767
+ abs_dir = str(_normalize_path(working_dir))
768
+
769
+ if file_path:
770
+ path_err = _validate_file_path(file_path, abs_dir)
771
+ if path_err:
772
+ return {"success": False, "error": path_err}
773
+
774
+ store = _store_path(CHECKPOINT_BASE)
775
+
776
+ if not (store / "HEAD").exists():
777
+ return {"success": False, "error": "No checkpoints exist for this directory"}
778
+
779
+ ok, _, err = _run_git(
780
+ ["cat-file", "-t", commit_hash], store, abs_dir,
781
+ )
782
+ if not ok:
783
+ return {"success": False, "error": f"Checkpoint '{commit_hash}' not found",
784
+ "debug": err or None}
785
+
786
+ # Take a pre-rollback snapshot so you can undo the undo.
787
+ self._take(abs_dir, f"pre-rollback snapshot (restoring to {commit_hash[:8]})")
788
+
789
+ dir_hash = _project_hash(abs_dir)
790
+ index_file = _index_path(store, dir_hash)
791
+
792
+ restore_target = file_path if file_path else "."
793
+ ok, stdout, err = _run_git(
794
+ ["checkout", commit_hash, "--", restore_target],
795
+ store, abs_dir, timeout=_GIT_TIMEOUT * 2,
796
+ index_file=index_file,
797
+ )
798
+
799
+ if not ok:
800
+ return {"success": False, "error": f"Restore failed: {err}",
801
+ "debug": err or None}
802
+
803
+ ok2, reason_out, _ = _run_git(
804
+ ["log", "--format=%s", "-1", commit_hash], store, abs_dir,
805
+ )
806
+ reason = reason_out if ok2 else "unknown"
807
+
808
+ result = {
809
+ "success": True,
810
+ "restored_to": commit_hash[:8],
811
+ "reason": reason,
812
+ "directory": abs_dir,
813
+ }
814
+ if file_path:
815
+ result["file"] = file_path
816
+ return result
817
+
818
+ def get_working_dir_for_path(self, file_path: str) -> str:
819
+ """Resolve a file path to its working directory for checkpointing."""
820
+ path = _normalize_path(file_path)
821
+ if path.is_dir():
822
+ candidate = path
823
+ else:
824
+ candidate = path.parent
825
+
826
+ markers = {".git", "pyproject.toml", "package.json", "Cargo.toml",
827
+ "go.mod", "Makefile", "pom.xml", ".hg", "Gemfile"}
828
+ check = candidate
829
+ while check != check.parent:
830
+ if any((check / m).exists() for m in markers):
831
+ return str(check)
832
+ check = check.parent
833
+
834
+ return str(candidate)
835
+
836
+ # ------------------------------------------------------------------
837
+ # Internal
838
+ # ------------------------------------------------------------------
839
+
840
+ def _take(self, working_dir: str, reason: str) -> bool:
841
+ """Take a snapshot. Returns True on success."""
842
+ store = _store_path(CHECKPOINT_BASE)
843
+
844
+ err = _init_store(store, working_dir)
845
+ if err:
846
+ logger.debug("Checkpoint store init failed: %s", err)
847
+ return False
848
+
849
+ _touch_project(store, working_dir)
850
+
851
+ # Quick size guard — don't try to snapshot enormous directories
852
+ if _dir_file_count(working_dir) > _MAX_FILES:
853
+ logger.debug("Checkpoint skipped: >%d files in %s", _MAX_FILES, working_dir)
854
+ return False
855
+
856
+ dir_hash = _project_hash(working_dir)
857
+ index_file = _index_path(store, dir_hash)
858
+ ref = _ref_name(dir_hash)
859
+
860
+ # Seed the per-project index from the last checkpoint, if any, so the
861
+ # diff/commit machinery sees only changes since then. On first call,
862
+ # clear the index so ``git add -A`` produces a clean tree.
863
+ if index_file.exists():
864
+ # Reset index to current ref tip to avoid accumulating stale paths.
865
+ ok_ref, ref_commit, _ = _run_git(
866
+ ["rev-parse", "--verify", ref + "^{commit}"],
867
+ store, working_dir,
868
+ allowed_returncodes={128},
869
+ )
870
+ if ok_ref and ref_commit:
871
+ _run_git(
872
+ ["read-tree", ref_commit],
873
+ store, working_dir,
874
+ index_file=index_file,
875
+ allowed_returncodes={128},
876
+ )
877
+ else:
878
+ try:
879
+ index_file.unlink()
880
+ except OSError:
881
+ pass
882
+ else:
883
+ # First snapshot for this project.
884
+ index_file.parent.mkdir(parents=True, exist_ok=True)
885
+
886
+ # Stage with per-project index. Include a per-stage file-size filter
887
+ # via ``core.bigFileThreshold`` is not what we want — instead, we
888
+ # rely on the exclude file for broad patterns and post-stage prune
889
+ # any path whose size exceeds max_file_size_mb.
890
+ ok, _, err = _run_git(
891
+ ["add", "-A"], store, working_dir,
892
+ timeout=_GIT_TIMEOUT * 2, index_file=index_file,
893
+ )
894
+ if not ok:
895
+ logger.debug("Checkpoint git-add failed: %s", err)
896
+ return False
897
+
898
+ if self.max_file_size_mb > 0:
899
+ self._drop_oversize_from_index(store, working_dir, index_file)
900
+
901
+ # Compare against the current ref tip (not HEAD — HEAD points to a
902
+ # branch that doesn't exist on a bare store, so ``diff --cached``
903
+ # against HEAD would always show "new file" for every staged path).
904
+ ok_ref, ref_commit, _ = _run_git(
905
+ ["rev-parse", "--verify", ref + "^{commit}"],
906
+ store, working_dir,
907
+ allowed_returncodes={128},
908
+ )
909
+ has_ref = ok_ref and bool(ref_commit)
910
+
911
+ if has_ref:
912
+ ok_diff, _, _ = _run_git(
913
+ ["diff-index", "--cached", "--quiet", ref_commit],
914
+ store, working_dir,
915
+ allowed_returncodes={1},
916
+ index_file=index_file,
917
+ )
918
+ if ok_diff:
919
+ logger.debug("Checkpoint skipped: no changes in %s", working_dir)
920
+ return False
921
+ else:
922
+ # No ref yet — skip only if the index is empty.
923
+ ok_ls, ls_out, _ = _run_git(
924
+ ["ls-files", "--cached"],
925
+ store, working_dir,
926
+ index_file=index_file,
927
+ )
928
+ if ok_ls and not ls_out.strip():
929
+ logger.debug("Checkpoint skipped: empty tree in %s", working_dir)
930
+ return False
931
+
932
+ # Write tree from per-project index.
933
+ ok_tree, tree_sha, err = _run_git(
934
+ ["write-tree"], store, working_dir,
935
+ index_file=index_file,
936
+ )
937
+ if not ok_tree or not tree_sha:
938
+ logger.debug("Checkpoint write-tree failed: %s", err)
939
+ return False
940
+
941
+ # Build commit (parent = current ref tip, if any).
942
+ commit_args = ["commit-tree", tree_sha, "-m", reason, "--no-gpg-sign"]
943
+ if has_ref:
944
+ commit_args = ["commit-tree", tree_sha, "-p", ref_commit, "-m", reason, "--no-gpg-sign"]
945
+ ok_commit, new_sha, err = _run_git(
946
+ commit_args, store, working_dir,
947
+ index_file=index_file,
948
+ )
949
+ if not ok_commit or not new_sha:
950
+ logger.debug("Checkpoint commit-tree failed: %s", err)
951
+ return False
952
+
953
+ # Update the per-project ref.
954
+ update_args = ["update-ref", ref, new_sha]
955
+ if has_ref:
956
+ update_args = ["update-ref", ref, new_sha, ref_commit]
957
+ ok_update, _, err = _run_git(
958
+ update_args, store, working_dir,
959
+ )
960
+ if not ok_update:
961
+ logger.debug("Checkpoint update-ref failed: %s", err)
962
+ return False
963
+
964
+ logger.debug("Checkpoint taken in %s: %s (%s)", working_dir, reason, new_sha[:8])
965
+
966
+ # Real pruning — drop old commits beyond max_snapshots.
967
+ self._prune(store, working_dir, ref)
968
+
969
+ # Enforce global size cap.
970
+ self._enforce_size_cap(store)
971
+
972
+ return True
973
+
974
+ def _drop_oversize_from_index(
975
+ self, store: Path, working_dir: str, index_file: Path,
976
+ ) -> None:
977
+ """Remove any staged file larger than ``max_file_size_mb`` from the index.
978
+
979
+ Lets the agent keep snapshotting source code while refusing to
980
+ swallow generated assets (datasets, model weights, logs, videos).
981
+ """
982
+ cap = self.max_file_size_mb * 1024 * 1024
983
+ if cap <= 0:
984
+ return
985
+ ok, stdout, _ = _run_git(
986
+ ["ls-files", "--cached", "-z"],
987
+ store, working_dir, index_file=index_file,
988
+ )
989
+ if not ok or not stdout:
990
+ return
991
+ # ls-files -z output is NUL-separated. _run_git strips trailing
992
+ # whitespace but that leaves NULs alone; rebuild list.
993
+ paths = [p for p in stdout.split("\x00") if p]
994
+ abs_workdir = _normalize_path(working_dir)
995
+ oversize: List[str] = []
996
+ for rel in paths:
997
+ try:
998
+ size = (abs_workdir / rel).stat().st_size
999
+ except OSError:
1000
+ continue
1001
+ if size > cap:
1002
+ oversize.append(rel)
1003
+ if not oversize:
1004
+ return
1005
+ logger.debug(
1006
+ "Checkpoint: dropping %d oversize file(s) (>%d MB) from index",
1007
+ len(oversize), self.max_file_size_mb,
1008
+ )
1009
+ # Use --pathspec-from-file for safety with many paths.
1010
+ # Chunk into manageable batches.
1011
+ BATCH = 200
1012
+ for i in range(0, len(oversize), BATCH):
1013
+ chunk = oversize[i:i + BATCH]
1014
+ _run_git(
1015
+ ["rm", "--cached", "--quiet", "--"] + chunk,
1016
+ store, working_dir, index_file=index_file,
1017
+ allowed_returncodes={128},
1018
+ )
1019
+
1020
+ def _prune(self, store: Path, working_dir: str, ref: str) -> None:
1021
+ """Keep only the last ``max_snapshots`` commits on the per-project ref.
1022
+
1023
+ v1's ``_prune`` was documented as a no-op (``git``'s pack mechanism
1024
+ was supposed to handle it, but only the log view was limited — loose
1025
+ objects accumulated forever). v2 actually rewrites the ref to drop
1026
+ commits older than ``max_snapshots`` and then runs ``git gc`` on the
1027
+ store so unreachable objects are reclaimed.
1028
+ """
1029
+ ok, stdout, _ = _run_git(
1030
+ ["rev-list", "--count", ref], store, working_dir,
1031
+ allowed_returncodes={128},
1032
+ )
1033
+ if not ok:
1034
+ return
1035
+ try:
1036
+ count = int(stdout)
1037
+ except ValueError:
1038
+ return
1039
+ if count <= self.max_snapshots:
1040
+ return
1041
+
1042
+ # Collect commits oldest → newest, take last N.
1043
+ ok_list, list_out, _ = _run_git(
1044
+ ["rev-list", "--reverse", ref], store, working_dir,
1045
+ )
1046
+ if not ok_list or not list_out:
1047
+ return
1048
+ commits = list_out.splitlines()
1049
+ keep = commits[-self.max_snapshots:]
1050
+
1051
+ # Rebuild a linear chain off keep[0]'s tree.
1052
+ new_parent: Optional[str] = None
1053
+ for sha in keep:
1054
+ ok_tree, tree_sha, _ = _run_git(
1055
+ ["rev-parse", f"{sha}^{{tree}}"], store, working_dir,
1056
+ )
1057
+ if not ok_tree or not tree_sha:
1058
+ return
1059
+ ok_msg, msg, _ = _run_git(
1060
+ ["log", "--format=%s", "-1", sha], store, working_dir,
1061
+ )
1062
+ commit_msg = msg if ok_msg and msg else "checkpoint"
1063
+ args = ["commit-tree", tree_sha, "-m", commit_msg, "--no-gpg-sign"]
1064
+ if new_parent is not None:
1065
+ args = ["commit-tree", tree_sha, "-p", new_parent,
1066
+ "-m", commit_msg, "--no-gpg-sign"]
1067
+ ok_commit, new_sha, _ = _run_git(args, store, working_dir)
1068
+ if not ok_commit or not new_sha:
1069
+ return
1070
+ new_parent = new_sha
1071
+
1072
+ if new_parent is None:
1073
+ return
1074
+ _run_git(["update-ref", ref, new_parent], store, working_dir)
1075
+
1076
+ # Reclaim objects from the dropped commits.
1077
+ _run_git(
1078
+ ["reflog", "expire", "--expire=now", "--all"],
1079
+ store, working_dir,
1080
+ )
1081
+ _run_git(
1082
+ ["gc", "--prune=now", "--quiet"],
1083
+ store, working_dir, timeout=_GIT_TIMEOUT * 3,
1084
+ )
1085
+
1086
+ def _enforce_size_cap(self, store: Path) -> None:
1087
+ """If total store size exceeds ``max_total_size_mb``, drop oldest
1088
+ checkpoints across ALL projects until under the cap.
1089
+ """
1090
+ if self.max_total_size_mb <= 0:
1091
+ return
1092
+ cap_bytes = self.max_total_size_mb * 1024 * 1024
1093
+ size = _dir_size_bytes(store)
1094
+ if size <= cap_bytes:
1095
+ return
1096
+ logger.info(
1097
+ "Checkpoint store exceeded %d MB (actual %d MB) — pruning oldest",
1098
+ self.max_total_size_mb, size // (1024 * 1024),
1099
+ )
1100
+
1101
+ # Collect (commit_time, ref, sha) across all per-project refs.
1102
+ ok, stdout, _ = _run_git(
1103
+ ["for-each-ref", "--format=%(refname)", _REFS_PREFIX],
1104
+ store, str(store.parent),
1105
+ allowed_returncodes={128},
1106
+ )
1107
+ if not ok or not stdout:
1108
+ return
1109
+ refs = [r for r in stdout.splitlines() if r.strip()]
1110
+
1111
+ any_dropped = False
1112
+ # Round-robin-drop oldest commit per ref until under cap.
1113
+ for _ in range(20): # hard upper bound to avoid pathological loops
1114
+ size = _dir_size_bytes(store)
1115
+ if size <= cap_bytes:
1116
+ break
1117
+ for ref in refs:
1118
+ ok_count, count_out, _ = _run_git(
1119
+ ["rev-list", "--count", ref], store, str(store.parent),
1120
+ allowed_returncodes={128},
1121
+ )
1122
+ try:
1123
+ count = int(count_out) if ok_count else 0
1124
+ except ValueError:
1125
+ count = 0
1126
+ if count <= 1:
1127
+ continue # keep at least one snapshot per project
1128
+ ok_list, list_out, _ = _run_git(
1129
+ ["rev-list", "--reverse", ref], store, str(store.parent),
1130
+ )
1131
+ if not ok_list or not list_out:
1132
+ continue
1133
+ commits = list_out.splitlines()
1134
+ keep = commits[1:] # drop oldest
1135
+ new_parent: Optional[str] = None
1136
+ fail = False
1137
+ for sha in keep:
1138
+ ok_tree, tree_sha, _ = _run_git(
1139
+ ["rev-parse", f"{sha}^{{tree}}"], store, str(store.parent),
1140
+ )
1141
+ if not ok_tree or not tree_sha:
1142
+ fail = True
1143
+ break
1144
+ ok_msg, msg, _ = _run_git(
1145
+ ["log", "--format=%s", "-1", sha], store, str(store.parent),
1146
+ )
1147
+ commit_msg = msg if ok_msg and msg else "checkpoint"
1148
+ args = ["commit-tree", tree_sha, "-m", commit_msg, "--no-gpg-sign"]
1149
+ if new_parent is not None:
1150
+ args = ["commit-tree", tree_sha, "-p", new_parent,
1151
+ "-m", commit_msg, "--no-gpg-sign"]
1152
+ ok_commit, new_sha, _ = _run_git(args, store, str(store.parent))
1153
+ if not ok_commit or not new_sha:
1154
+ fail = True
1155
+ break
1156
+ new_parent = new_sha
1157
+ if fail or new_parent is None:
1158
+ continue
1159
+ _run_git(["update-ref", ref, new_parent], store, str(store.parent))
1160
+ any_dropped = True
1161
+ if not any_dropped:
1162
+ break
1163
+
1164
+ _run_git(
1165
+ ["reflog", "expire", "--expire=now", "--all"],
1166
+ store, str(store.parent),
1167
+ )
1168
+ _run_git(
1169
+ ["gc", "--prune=now", "--quiet"],
1170
+ store, str(store.parent), timeout=_GIT_TIMEOUT * 3,
1171
+ )
1172
+
1173
+
1174
+ def format_checkpoint_list(checkpoints: List[Dict], directory: str) -> str:
1175
+ """Format checkpoint list for display to user."""
1176
+ if not checkpoints:
1177
+ return f"No checkpoints found for {directory}"
1178
+
1179
+ lines = [f"📸 Checkpoints for {directory}:\n"]
1180
+ for i, cp in enumerate(checkpoints, 1):
1181
+ ts = cp["timestamp"]
1182
+ if "T" in ts:
1183
+ ts = ts.split("T")[1].split("+")[0].split("-")[0][:5]
1184
+ date = cp["timestamp"].split("T")[0]
1185
+ ts = f"{date} {ts}"
1186
+
1187
+ files = cp.get("files_changed", 0)
1188
+ ins = cp.get("insertions", 0)
1189
+ dele = cp.get("deletions", 0)
1190
+ if files:
1191
+ stat = f" ({files} file{'s' if files != 1 else ''}, +{ins}/-{dele})"
1192
+ else:
1193
+ stat = ""
1194
+
1195
+ lines.append(f" {i}. {cp['short_hash']} {ts} {cp['reason']}{stat}")
1196
+
1197
+ lines.append("\n /rollback <N> restore to checkpoint N")
1198
+ lines.append(" /rollback diff <N> preview changes since checkpoint N")
1199
+ lines.append(" /rollback <N> <file> restore a single file from checkpoint N")
1200
+ return "\n".join(lines)
1201
+
1202
+
1203
+ # ---------------------------------------------------------------------------
1204
+ # Auto-maintenance
1205
+ # ---------------------------------------------------------------------------
1206
+ #
1207
+ # v2 rewrite. The sweep now operates on per-project refs inside the shared
1208
+ # store rather than per-project shadow repos. Legacy-archive dirs
1209
+ # (``legacy-<ts>/``) are swept with the same retention policy.
1210
+
1211
+ _PRUNE_MARKER_NAME = ".last_prune"
1212
+
1213
+
1214
+ def _delete_ref(store: Path, ref: str) -> bool:
1215
+ """Delete a ref from the store. Returns True on success."""
1216
+ ok, _, _ = _run_git(
1217
+ ["update-ref", "-d", ref], store, str(store.parent),
1218
+ allowed_returncodes={128},
1219
+ )
1220
+ return ok
1221
+
1222
+
1223
+ def prune_checkpoints(
1224
+ retention_days: int = 7,
1225
+ delete_orphans: bool = True,
1226
+ checkpoint_base: Optional[Path] = None,
1227
+ max_total_size_mb: int = 0,
1228
+ ) -> Dict[str, int]:
1229
+ """Delete stale/orphan checkpoints and reclaim store space.
1230
+
1231
+ A project entry is deleted when either:
1232
+
1233
+ * ``delete_orphans=True`` and its ``workdir`` no longer exists on disk
1234
+ (the original project was deleted / moved); OR
1235
+ * its ``last_touch`` is older than ``retention_days`` days.
1236
+
1237
+ Additionally, if ``max_total_size_mb > 0`` and the store exceeds that
1238
+ after orphan/stale pruning, the oldest commit per remaining project is
1239
+ dropped until the store is under the cap.
1240
+
1241
+ Legacy-archive dirs (``legacy-*``) older than ``retention_days`` are
1242
+ also deleted.
1243
+
1244
+ Returns a dict with counts ``{"scanned", "deleted_orphan",
1245
+ "deleted_stale", "errors", "bytes_freed"}``.
1246
+
1247
+ Never raises — maintenance must never block interactive startup.
1248
+ """
1249
+ base = checkpoint_base or CHECKPOINT_BASE
1250
+ result = {
1251
+ "scanned": 0,
1252
+ "deleted_orphan": 0,
1253
+ "deleted_stale": 0,
1254
+ "errors": 0,
1255
+ "bytes_freed": 0,
1256
+ }
1257
+ if not base.exists():
1258
+ return result
1259
+
1260
+ size_before = _dir_size_bytes(base)
1261
+
1262
+ # --- Legacy pre-v2 per-project shadow repos (kept directly under base) ---
1263
+ # Pre-v2 layout: ``base/<hash>/HEAD`` etc. We treat these exactly as the
1264
+ # v1 pruner did so behaviour is unchanged for anyone still on that layout
1265
+ # or sitting on a mid-migration system.
1266
+ cutoff = 0.0
1267
+ if retention_days > 0:
1268
+ cutoff = time.time() - retention_days * 86400
1269
+
1270
+ for child in base.iterdir():
1271
+ if not child.is_dir():
1272
+ continue
1273
+ if child.name == _STORE_DIRNAME:
1274
+ continue
1275
+ if child.name.startswith(_LEGACY_PREFIX):
1276
+ # Legacy archive: prune by dir mtime using same retention rule.
1277
+ if retention_days <= 0:
1278
+ continue
1279
+ try:
1280
+ m = child.stat().st_mtime
1281
+ except OSError:
1282
+ continue
1283
+ if m >= cutoff:
1284
+ continue
1285
+ try:
1286
+ size = _dir_size_bytes(child)
1287
+ shutil.rmtree(child)
1288
+ result["bytes_freed"] += size
1289
+ result["deleted_stale"] += 1
1290
+ except OSError as exc:
1291
+ result["errors"] += 1
1292
+ logger.warning("Failed to delete legacy archive %s: %s", child, exc)
1293
+ continue
1294
+ # Only count as a pre-v2 shadow repo if it has a HEAD.
1295
+ if not (child / "HEAD").exists():
1296
+ continue
1297
+ result["scanned"] += 1
1298
+ reason: Optional[str] = None
1299
+ if delete_orphans:
1300
+ workdir: Optional[str] = None
1301
+ wd_marker = child / "HERMES_WORKDIR"
1302
+ if wd_marker.exists():
1303
+ try:
1304
+ workdir = wd_marker.read_text(encoding="utf-8").strip()
1305
+ except (OSError, UnicodeDecodeError):
1306
+ workdir = None
1307
+ if workdir is None or not Path(workdir).exists():
1308
+ reason = "orphan"
1309
+ if reason is None and retention_days > 0:
1310
+ newest = 0.0
1311
+ try:
1312
+ for p in child.rglob("*"):
1313
+ try:
1314
+ mt = p.stat().st_mtime
1315
+ newest = max(newest, mt)
1316
+ except OSError:
1317
+ continue
1318
+ except OSError:
1319
+ pass
1320
+ if newest > 0 and newest < cutoff:
1321
+ reason = "stale"
1322
+ if reason is None:
1323
+ continue
1324
+ try:
1325
+ size = _dir_size_bytes(child)
1326
+ shutil.rmtree(child)
1327
+ result["bytes_freed"] += size
1328
+ if reason == "orphan":
1329
+ result["deleted_orphan"] += 1
1330
+ else:
1331
+ result["deleted_stale"] += 1
1332
+ except OSError as exc:
1333
+ result["errors"] += 1
1334
+ logger.warning("Failed to prune checkpoint repo %s: %s", child.name, exc)
1335
+
1336
+ # --- v2 shared store: per-project ref pruning via metadata ---
1337
+ store = _store_path(base)
1338
+ if (store / "HEAD").exists():
1339
+ for meta in _list_projects(store):
1340
+ dir_hash = meta.get("_hash") or ""
1341
+ workdir = meta.get("workdir") or ""
1342
+ if not dir_hash:
1343
+ continue
1344
+ result["scanned"] += 1
1345
+ reason = None
1346
+ if delete_orphans and (not workdir or not Path(workdir).exists()):
1347
+ reason = "orphan"
1348
+ elif retention_days > 0:
1349
+ last_touch = float(meta.get("last_touch", 0) or 0)
1350
+ if last_touch > 0 and last_touch < cutoff:
1351
+ reason = "stale"
1352
+ if reason is None:
1353
+ continue
1354
+ ref = _ref_name(dir_hash)
1355
+ _delete_ref(store, ref)
1356
+ # Drop per-project index and metadata.
1357
+ try:
1358
+ idx = _index_path(store, dir_hash)
1359
+ if idx.exists():
1360
+ idx.unlink()
1361
+ except OSError:
1362
+ pass
1363
+ try:
1364
+ mp = _project_meta_path(store, dir_hash)
1365
+ if mp.exists():
1366
+ mp.unlink()
1367
+ except OSError:
1368
+ pass
1369
+ if reason == "orphan":
1370
+ result["deleted_orphan"] += 1
1371
+ else:
1372
+ result["deleted_stale"] += 1
1373
+
1374
+ # GC the store to reclaim unreachable objects from dropped refs.
1375
+ _run_git(
1376
+ ["reflog", "expire", "--expire=now", "--all"],
1377
+ store, str(base),
1378
+ )
1379
+ _run_git(
1380
+ ["gc", "--prune=now", "--quiet"],
1381
+ store, str(base), timeout=_GIT_TIMEOUT * 3,
1382
+ )
1383
+
1384
+ # Size-cap pass across remaining projects.
1385
+ if max_total_size_mb > 0:
1386
+ cap_bytes = max_total_size_mb * 1024 * 1024
1387
+ for _i in range(20):
1388
+ size = _dir_size_bytes(store)
1389
+ if size <= cap_bytes:
1390
+ break
1391
+ ok, stdout, _ = _run_git(
1392
+ ["for-each-ref", "--format=%(refname)", _REFS_PREFIX],
1393
+ store, str(base),
1394
+ allowed_returncodes={128},
1395
+ )
1396
+ refs = [r for r in stdout.splitlines() if r.strip()] if ok else []
1397
+ if not refs:
1398
+ break
1399
+ any_drop = False
1400
+ for ref in refs:
1401
+ ok_c, count_out, _ = _run_git(
1402
+ ["rev-list", "--count", ref], store, str(base),
1403
+ allowed_returncodes={128},
1404
+ )
1405
+ try:
1406
+ count = int(count_out) if ok_c else 0
1407
+ except ValueError:
1408
+ count = 0
1409
+ if count <= 1:
1410
+ continue
1411
+ ok_l, lo, _ = _run_git(
1412
+ ["rev-list", "--reverse", ref], store, str(base),
1413
+ )
1414
+ if not ok_l or not lo:
1415
+ continue
1416
+ commits = lo.splitlines()
1417
+ keep = commits[1:]
1418
+ new_parent: Optional[str] = None
1419
+ fail = False
1420
+ for sha in keep:
1421
+ ok_t, tsha, _ = _run_git(
1422
+ ["rev-parse", f"{sha}^{{tree}}"], store, str(base),
1423
+ )
1424
+ if not ok_t or not tsha:
1425
+ fail = True
1426
+ break
1427
+ ok_m, m, _ = _run_git(
1428
+ ["log", "--format=%s", "-1", sha], store, str(base),
1429
+ )
1430
+ msg = m if ok_m and m else "checkpoint"
1431
+ args = ["commit-tree", tsha, "-m", msg, "--no-gpg-sign"]
1432
+ if new_parent is not None:
1433
+ args = ["commit-tree", tsha, "-p", new_parent,
1434
+ "-m", msg, "--no-gpg-sign"]
1435
+ ok_cm, new_sha, _ = _run_git(args, store, str(base))
1436
+ if not ok_cm or not new_sha:
1437
+ fail = True
1438
+ break
1439
+ new_parent = new_sha
1440
+ if fail or new_parent is None:
1441
+ continue
1442
+ _run_git(["update-ref", ref, new_parent], store, str(base))
1443
+ any_drop = True
1444
+ if not any_drop:
1445
+ break
1446
+ _run_git(
1447
+ ["reflog", "expire", "--expire=now", "--all"],
1448
+ store, str(base),
1449
+ )
1450
+ _run_git(
1451
+ ["gc", "--prune=now", "--quiet"],
1452
+ store, str(base), timeout=_GIT_TIMEOUT * 3,
1453
+ )
1454
+
1455
+ size_after = _dir_size_bytes(base)
1456
+ delta = size_before - size_after
1457
+ result["bytes_freed"] = max(result["bytes_freed"], delta)
1458
+
1459
+ return result
1460
+
1461
+
1462
+ def maybe_auto_prune_checkpoints(
1463
+ retention_days: int = 7,
1464
+ min_interval_hours: int = 24,
1465
+ delete_orphans: bool = True,
1466
+ checkpoint_base: Optional[Path] = None,
1467
+ max_total_size_mb: int = 0,
1468
+ ) -> Dict[str, object]:
1469
+ """Idempotent wrapper around ``prune_checkpoints`` for startup hooks.
1470
+
1471
+ Writes ``CHECKPOINT_BASE/.last_prune`` on completion so subsequent
1472
+ calls within ``min_interval_hours`` short-circuit.
1473
+
1474
+ Returns ``{"skipped": bool, "result": prune_checkpoints-dict,
1475
+ "error": optional str}``.
1476
+ """
1477
+ base = checkpoint_base or CHECKPOINT_BASE
1478
+ out: Dict[str, object] = {"skipped": False}
1479
+
1480
+ try:
1481
+ if not base.exists():
1482
+ out["result"] = {
1483
+ "scanned": 0, "deleted_orphan": 0, "deleted_stale": 0,
1484
+ "errors": 0, "bytes_freed": 0,
1485
+ }
1486
+ return out
1487
+
1488
+ marker = base / _PRUNE_MARKER_NAME
1489
+ now = time.time()
1490
+ if marker.exists():
1491
+ try:
1492
+ last_ts = float(marker.read_text(encoding="utf-8").strip())
1493
+ if now - last_ts < min_interval_hours * 3600:
1494
+ out["skipped"] = True
1495
+ return out
1496
+ except (OSError, ValueError):
1497
+ pass # corrupt marker — treat as no prior run
1498
+
1499
+ result = prune_checkpoints(
1500
+ retention_days=retention_days,
1501
+ delete_orphans=delete_orphans,
1502
+ checkpoint_base=base,
1503
+ max_total_size_mb=max_total_size_mb,
1504
+ )
1505
+ out["result"] = result
1506
+
1507
+ try:
1508
+ marker.write_text(str(now), encoding="utf-8")
1509
+ except OSError as exc:
1510
+ logger.debug("Could not write checkpoint prune marker: %s", exc)
1511
+
1512
+ total = result["deleted_orphan"] + result["deleted_stale"]
1513
+ if total > 0:
1514
+ logger.info(
1515
+ "checkpoint auto-maintenance: pruned %d entry(ies) "
1516
+ "(%d orphan, %d stale), reclaimed %.1f MB",
1517
+ total,
1518
+ result["deleted_orphan"],
1519
+ result["deleted_stale"],
1520
+ result["bytes_freed"] / (1024 * 1024),
1521
+ )
1522
+ except Exception as exc:
1523
+ logger.warning("checkpoint auto-maintenance failed: %s", exc)
1524
+ out["error"] = str(exc)
1525
+
1526
+ return out
1527
+
1528
+
1529
+ # ---------------------------------------------------------------------------
1530
+ # Public helpers for `hermes checkpoints` CLI
1531
+ # ---------------------------------------------------------------------------
1532
+
1533
+ def store_status(checkpoint_base: Optional[Path] = None) -> Dict:
1534
+ """Return a summary of the shadow store.
1535
+
1536
+ ``{"base": path, "store_size_bytes": N, "legacy_size_bytes": N,
1537
+ "total_size_bytes": N, "project_count": N, "projects": [...],
1538
+ "legacy_archives": [...]}``
1539
+ """
1540
+ base = checkpoint_base or CHECKPOINT_BASE
1541
+ out: Dict = {
1542
+ "base": str(base),
1543
+ "store_size_bytes": 0,
1544
+ "legacy_size_bytes": 0,
1545
+ "total_size_bytes": 0,
1546
+ "project_count": 0,
1547
+ "projects": [],
1548
+ "legacy_archives": [],
1549
+ }
1550
+ if not base.exists():
1551
+ return out
1552
+
1553
+ store = _store_path(base)
1554
+ if store.exists():
1555
+ out["store_size_bytes"] = _dir_size_bytes(store)
1556
+ if (store / "HEAD").exists():
1557
+ for meta in _list_projects(store):
1558
+ dir_hash = meta.get("_hash") or ""
1559
+ workdir = meta.get("workdir") or ""
1560
+ ref = _ref_name(dir_hash)
1561
+ ok, count_out, _ = _run_git(
1562
+ ["rev-list", "--count", ref], store, str(base),
1563
+ allowed_returncodes={128},
1564
+ )
1565
+ try:
1566
+ commits = int(count_out) if ok else 0
1567
+ except ValueError:
1568
+ commits = 0
1569
+ out["projects"].append({
1570
+ "hash": dir_hash,
1571
+ "workdir": workdir,
1572
+ "exists": bool(workdir) and Path(workdir).exists(),
1573
+ "created_at": meta.get("created_at"),
1574
+ "last_touch": meta.get("last_touch"),
1575
+ "commits": commits,
1576
+ })
1577
+ out["project_count"] = len(out["projects"])
1578
+
1579
+ for child in base.iterdir():
1580
+ if child.is_dir() and child.name.startswith(_LEGACY_PREFIX):
1581
+ try:
1582
+ size = _dir_size_bytes(child)
1583
+ except OSError:
1584
+ size = 0
1585
+ out["legacy_size_bytes"] += size
1586
+ try:
1587
+ mt = child.stat().st_mtime
1588
+ except OSError:
1589
+ mt = 0
1590
+ out["legacy_archives"].append({
1591
+ "name": child.name,
1592
+ "size_bytes": size,
1593
+ "mtime": mt,
1594
+ })
1595
+
1596
+ out["total_size_bytes"] = _dir_size_bytes(base)
1597
+ return out
1598
+
1599
+
1600
+ def clear_all(checkpoint_base: Optional[Path] = None) -> Dict[str, int]:
1601
+ """Nuke the entire checkpoint base (store + legacy). Irreversible.
1602
+
1603
+ Returns ``{"bytes_freed": N, "deleted": bool}``.
1604
+ """
1605
+ base = checkpoint_base or CHECKPOINT_BASE
1606
+ out = {"bytes_freed": 0, "deleted": False}
1607
+ if not base.exists():
1608
+ return out
1609
+ size = _dir_size_bytes(base)
1610
+ try:
1611
+ shutil.rmtree(base)
1612
+ out["bytes_freed"] = size
1613
+ out["deleted"] = True
1614
+ except OSError as exc:
1615
+ logger.warning("Could not clear checkpoint base %s: %s", base, exc)
1616
+ return out
1617
+
1618
+
1619
+ def clear_legacy(checkpoint_base: Optional[Path] = None) -> Dict[str, int]:
1620
+ """Delete all ``legacy-*`` archive directories.
1621
+
1622
+ Returns ``{"bytes_freed": N, "deleted": count}``.
1623
+ """
1624
+ base = checkpoint_base or CHECKPOINT_BASE
1625
+ out = {"bytes_freed": 0, "deleted": 0}
1626
+ if not base.exists():
1627
+ return out
1628
+ for child in list(base.iterdir()):
1629
+ if not child.is_dir() or not child.name.startswith(_LEGACY_PREFIX):
1630
+ continue
1631
+ try:
1632
+ size = _dir_size_bytes(child)
1633
+ shutil.rmtree(child)
1634
+ out["bytes_freed"] += size
1635
+ out["deleted"] += 1
1636
+ except OSError as exc:
1637
+ logger.warning("Could not delete legacy archive %s: %s", child, exc)
1638
+ return out
1639
+