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.
- package/LICENSE +21 -0
- package/README.md +217 -0
- package/README.zh-CN.md +180 -0
- package/acp_adapter/__init__.py +1 -0
- package/acp_adapter/__main__.py +5 -0
- package/acp_adapter/auth.py +68 -0
- package/acp_adapter/bootstrap/__init__.py +0 -0
- package/acp_adapter/bootstrap/bootstrap_browser_tools.ps1 +288 -0
- package/acp_adapter/bootstrap/bootstrap_browser_tools.sh +399 -0
- package/acp_adapter/entry.py +292 -0
- package/acp_adapter/events.py +265 -0
- package/acp_adapter/permissions.py +148 -0
- package/acp_adapter/server.py +1713 -0
- package/acp_adapter/session.py +629 -0
- package/acp_adapter/tools.py +1180 -0
- package/agent/__init__.py +6 -0
- package/agent/__pycache__/__init__.cpython-312.pyc +0 -0
- package/agent/__pycache__/account_usage.cpython-312.pyc +0 -0
- package/agent/__pycache__/anthropic_adapter.cpython-312.pyc +0 -0
- package/agent/__pycache__/async_utils.cpython-312.pyc +0 -0
- package/agent/__pycache__/auxiliary_client.cpython-312.pyc +0 -0
- package/agent/__pycache__/codex_responses_adapter.cpython-312.pyc +0 -0
- package/agent/__pycache__/context_compressor.cpython-312.pyc +0 -0
- package/agent/__pycache__/context_engine.cpython-312.pyc +0 -0
- package/agent/__pycache__/context_references.cpython-312.pyc +0 -0
- package/agent/__pycache__/credential_pool.cpython-312.pyc +0 -0
- package/agent/__pycache__/curator.cpython-312.pyc +0 -0
- package/agent/__pycache__/display.cpython-312.pyc +0 -0
- package/agent/__pycache__/error_classifier.cpython-312.pyc +0 -0
- package/agent/__pycache__/file_safety.cpython-312.pyc +0 -0
- package/agent/__pycache__/google_code_assist.cpython-312.pyc +0 -0
- package/agent/__pycache__/google_oauth.cpython-312.pyc +0 -0
- package/agent/__pycache__/i18n.cpython-312.pyc +0 -0
- package/agent/__pycache__/image_gen_provider.cpython-312.pyc +0 -0
- package/agent/__pycache__/image_gen_registry.cpython-312.pyc +0 -0
- package/agent/__pycache__/insights.cpython-312.pyc +0 -0
- package/agent/__pycache__/lmstudio_reasoning.cpython-312.pyc +0 -0
- package/agent/__pycache__/manual_compression_feedback.cpython-312.pyc +0 -0
- package/agent/__pycache__/markdown_tables.cpython-312.pyc +0 -0
- package/agent/__pycache__/memory_manager.cpython-312.pyc +0 -0
- package/agent/__pycache__/memory_provider.cpython-312.pyc +0 -0
- package/agent/__pycache__/model_metadata.cpython-312.pyc +0 -0
- package/agent/__pycache__/models_dev.cpython-312.pyc +0 -0
- package/agent/__pycache__/moonshot_schema.cpython-312.pyc +0 -0
- package/agent/__pycache__/onboarding.cpython-312.pyc +0 -0
- package/agent/__pycache__/portal_tags.cpython-312.pyc +0 -0
- package/agent/__pycache__/prompt_builder.cpython-312.pyc +0 -0
- package/agent/__pycache__/prompt_caching.cpython-312.pyc +0 -0
- package/agent/__pycache__/redact.cpython-312.pyc +0 -0
- package/agent/__pycache__/retry_utils.cpython-312.pyc +0 -0
- package/agent/__pycache__/shell_hooks.cpython-312.pyc +0 -0
- package/agent/__pycache__/skill_commands.cpython-312.pyc +0 -0
- package/agent/__pycache__/skill_preprocessing.cpython-312.pyc +0 -0
- package/agent/__pycache__/skill_utils.cpython-312.pyc +0 -0
- package/agent/__pycache__/subdirectory_hints.cpython-312.pyc +0 -0
- package/agent/__pycache__/think_scrubber.cpython-312.pyc +0 -0
- package/agent/__pycache__/title_generator.cpython-312.pyc +0 -0
- package/agent/__pycache__/tool_guardrails.cpython-312.pyc +0 -0
- package/agent/__pycache__/tool_result_classification.cpython-312.pyc +0 -0
- package/agent/__pycache__/trajectory.cpython-312.pyc +0 -0
- package/agent/__pycache__/usage_pricing.cpython-312.pyc +0 -0
- package/agent/__pycache__/video_gen_provider.cpython-312.pyc +0 -0
- package/agent/__pycache__/video_gen_registry.cpython-312.pyc +0 -0
- package/agent/__pycache__/web_search_provider.cpython-312.pyc +0 -0
- package/agent/__pycache__/web_search_registry.cpython-312.pyc +0 -0
- package/agent/account_usage.py +326 -0
- package/agent/anthropic_adapter.py +2087 -0
- package/agent/async_utils.py +68 -0
- package/agent/auxiliary_client.py +4893 -0
- package/agent/bedrock_adapter.py +1276 -0
- package/agent/codex_responses_adapter.py +1084 -0
- package/agent/context_compressor.py +1583 -0
- package/agent/context_engine.py +211 -0
- package/agent/context_references.py +519 -0
- package/agent/copilot_acp_client.py +684 -0
- package/agent/credential_pool.py +1780 -0
- package/agent/credential_sources.py +449 -0
- package/agent/curator.py +1782 -0
- package/agent/curator_backup.py +694 -0
- package/agent/display.py +987 -0
- package/agent/error_classifier.py +1058 -0
- package/agent/file_safety.py +112 -0
- package/agent/gemini_cloudcode_adapter.py +909 -0
- package/agent/gemini_native_adapter.py +971 -0
- package/agent/gemini_schema.py +99 -0
- package/agent/google_code_assist.py +452 -0
- package/agent/google_oauth.py +1062 -0
- package/agent/i18n.py +258 -0
- package/agent/image_gen_provider.py +243 -0
- package/agent/image_gen_registry.py +145 -0
- package/agent/image_routing.py +301 -0
- package/agent/insights.py +931 -0
- package/agent/lmstudio_reasoning.py +48 -0
- package/agent/lsp/__init__.py +106 -0
- package/agent/lsp/__pycache__/__init__.cpython-312.pyc +0 -0
- package/agent/lsp/__pycache__/cli.cpython-312.pyc +0 -0
- package/agent/lsp/__pycache__/client.cpython-312.pyc +0 -0
- package/agent/lsp/__pycache__/eventlog.cpython-312.pyc +0 -0
- package/agent/lsp/__pycache__/manager.cpython-312.pyc +0 -0
- package/agent/lsp/__pycache__/protocol.cpython-312.pyc +0 -0
- package/agent/lsp/__pycache__/servers.cpython-312.pyc +0 -0
- package/agent/lsp/__pycache__/workspace.cpython-312.pyc +0 -0
- package/agent/lsp/cli.py +308 -0
- package/agent/lsp/client.py +930 -0
- package/agent/lsp/eventlog.py +213 -0
- package/agent/lsp/install.py +376 -0
- package/agent/lsp/manager.py +644 -0
- package/agent/lsp/protocol.py +196 -0
- package/agent/lsp/range_shift.py +149 -0
- package/agent/lsp/reporter.py +78 -0
- package/agent/lsp/servers.py +1040 -0
- package/agent/lsp/workspace.py +223 -0
- package/agent/manual_compression_feedback.py +49 -0
- package/agent/markdown_tables.py +309 -0
- package/agent/memory_manager.py +556 -0
- package/agent/memory_provider.py +279 -0
- package/agent/model_metadata.py +1827 -0
- package/agent/models_dev.py +724 -0
- package/agent/moonshot_schema.py +231 -0
- package/agent/nous_rate_guard.py +326 -0
- package/agent/onboarding.py +193 -0
- package/agent/plugin_llm.py +1046 -0
- package/agent/portal_tags.py +64 -0
- package/agent/prompt_builder.py +1457 -0
- package/agent/prompt_caching.py +79 -0
- package/agent/rate_limit_tracker.py +246 -0
- package/agent/redact.py +403 -0
- package/agent/retry_utils.py +57 -0
- package/agent/shell_hooks.py +837 -0
- package/agent/skill_commands.py +502 -0
- package/agent/skill_preprocessing.py +131 -0
- package/agent/skill_utils.py +512 -0
- package/agent/subdirectory_hints.py +224 -0
- package/agent/think_scrubber.py +386 -0
- package/agent/title_generator.py +171 -0
- package/agent/tool_guardrails.py +458 -0
- package/agent/tool_result_classification.py +26 -0
- package/agent/trajectory.py +56 -0
- package/agent/transports/__init__.py +68 -0
- package/agent/transports/__pycache__/__init__.cpython-312.pyc +0 -0
- package/agent/transports/__pycache__/anthropic.cpython-312.pyc +0 -0
- package/agent/transports/__pycache__/base.cpython-312.pyc +0 -0
- package/agent/transports/__pycache__/bedrock.cpython-312.pyc +0 -0
- package/agent/transports/__pycache__/chat_completions.cpython-312.pyc +0 -0
- package/agent/transports/__pycache__/codex.cpython-312.pyc +0 -0
- package/agent/transports/__pycache__/types.cpython-312.pyc +0 -0
- package/agent/transports/anthropic.py +179 -0
- package/agent/transports/base.py +89 -0
- package/agent/transports/bedrock.py +154 -0
- package/agent/transports/chat_completions.py +614 -0
- package/agent/transports/codex.py +283 -0
- package/agent/transports/codex_app_server.py +368 -0
- package/agent/transports/codex_app_server_session.py +810 -0
- package/agent/transports/codex_event_projector.py +312 -0
- package/agent/transports/hermes_tools_mcp_server.py +233 -0
- package/agent/transports/types.py +162 -0
- package/agent/usage_pricing.py +877 -0
- package/agent/video_gen_provider.py +300 -0
- package/agent/video_gen_registry.py +117 -0
- package/agent/web_search_provider.py +221 -0
- package/agent/web_search_registry.py +262 -0
- package/assets/banner.png +0 -0
- package/batch_runner.py +1303 -0
- package/bin/calvyn.js +67 -0
- package/calvyn_bootstrap.py +130 -0
- package/calvyn_constants.py +346 -0
- package/calvyn_logging.py +390 -0
- package/calvyn_state.py +2967 -0
- package/calvyn_time.py +105 -0
- package/cli.py +14160 -0
- package/cron/__init__.py +42 -0
- package/cron/__pycache__/__init__.cpython-312.pyc +0 -0
- package/cron/__pycache__/jobs.cpython-312.pyc +0 -0
- package/cron/__pycache__/scheduler.cpython-312.pyc +0 -0
- package/cron/jobs.py +1160 -0
- package/cron/scheduler.py +1832 -0
- package/gateway/__init__.py +35 -0
- package/gateway/__pycache__/__init__.cpython-312.pyc +0 -0
- package/gateway/__pycache__/channel_directory.cpython-312.pyc +0 -0
- package/gateway/__pycache__/config.cpython-312.pyc +0 -0
- package/gateway/__pycache__/delivery.cpython-312.pyc +0 -0
- package/gateway/__pycache__/display_config.cpython-312.pyc +0 -0
- package/gateway/__pycache__/hooks.cpython-312.pyc +0 -0
- package/gateway/__pycache__/pairing.cpython-312.pyc +0 -0
- package/gateway/__pycache__/platform_registry.cpython-312.pyc +0 -0
- package/gateway/__pycache__/restart.cpython-312.pyc +0 -0
- package/gateway/__pycache__/run.cpython-312.pyc +0 -0
- package/gateway/__pycache__/runtime_footer.cpython-312.pyc +0 -0
- package/gateway/__pycache__/session.cpython-312.pyc +0 -0
- package/gateway/__pycache__/session_context.cpython-312.pyc +0 -0
- package/gateway/__pycache__/shutdown_forensics.cpython-312.pyc +0 -0
- package/gateway/__pycache__/slash_access.cpython-312.pyc +0 -0
- package/gateway/__pycache__/status.cpython-312.pyc +0 -0
- package/gateway/__pycache__/stream_consumer.cpython-312.pyc +0 -0
- package/gateway/__pycache__/whatsapp_identity.cpython-312.pyc +0 -0
- package/gateway/assets/telegram-botfather-threads-settings.jpg +0 -0
- package/gateway/builtin_hooks/__init__.py +1 -0
- package/gateway/channel_directory.py +357 -0
- package/gateway/config.py +1873 -0
- package/gateway/delivery.py +258 -0
- package/gateway/display_config.py +206 -0
- package/gateway/hooks.py +210 -0
- package/gateway/mirror.py +179 -0
- package/gateway/pairing.py +322 -0
- package/gateway/platform_registry.py +260 -0
- package/gateway/platforms/ADDING_A_PLATFORM.md +374 -0
- package/gateway/platforms/__init__.py +45 -0
- package/gateway/platforms/__pycache__/__init__.cpython-312.pyc +0 -0
- package/gateway/platforms/__pycache__/base.cpython-312.pyc +0 -0
- package/gateway/platforms/__pycache__/helpers.cpython-312.pyc +0 -0
- package/gateway/platforms/__pycache__/telegram.cpython-312.pyc +0 -0
- package/gateway/platforms/__pycache__/telegram_network.cpython-312.pyc +0 -0
- package/gateway/platforms/__pycache__/yuanbao.cpython-312.pyc +0 -0
- package/gateway/platforms/__pycache__/yuanbao_media.cpython-312.pyc +0 -0
- package/gateway/platforms/__pycache__/yuanbao_proto.cpython-312.pyc +0 -0
- package/gateway/platforms/_http_client_limits.py +84 -0
- package/gateway/platforms/api_server.py +3488 -0
- package/gateway/platforms/base.py +3747 -0
- package/gateway/platforms/bluebubbles.py +937 -0
- package/gateway/platforms/dingtalk.py +1473 -0
- package/gateway/platforms/discord.py +5584 -0
- package/gateway/platforms/email.py +773 -0
- package/gateway/platforms/feishu.py +5059 -0
- package/gateway/platforms/feishu_comment.py +1382 -0
- package/gateway/platforms/feishu_comment_rules.py +430 -0
- package/gateway/platforms/helpers.py +279 -0
- package/gateway/platforms/homeassistant.py +449 -0
- package/gateway/platforms/matrix.py +2777 -0
- package/gateway/platforms/mattermost.py +852 -0
- package/gateway/platforms/msgraph_webhook.py +397 -0
- package/gateway/platforms/qqbot/__init__.py +91 -0
- package/gateway/platforms/qqbot/adapter.py +3072 -0
- package/gateway/platforms/qqbot/chunked_upload.py +602 -0
- package/gateway/platforms/qqbot/constants.py +74 -0
- package/gateway/platforms/qqbot/crypto.py +45 -0
- package/gateway/platforms/qqbot/keyboards.py +473 -0
- package/gateway/platforms/qqbot/onboard.py +220 -0
- package/gateway/platforms/qqbot/utils.py +71 -0
- package/gateway/platforms/signal.py +1518 -0
- package/gateway/platforms/signal_rate_limit.py +369 -0
- package/gateway/platforms/slack.py +3028 -0
- package/gateway/platforms/sms.py +377 -0
- package/gateway/platforms/telegram.py +4836 -0
- package/gateway/platforms/telegram_network.py +249 -0
- package/gateway/platforms/webhook.py +806 -0
- package/gateway/platforms/wecom.py +1610 -0
- package/gateway/platforms/wecom_callback.py +403 -0
- package/gateway/platforms/wecom_crypto.py +142 -0
- package/gateway/platforms/weixin.py +2170 -0
- package/gateway/platforms/whatsapp.py +1283 -0
- package/gateway/platforms/yuanbao.py +4873 -0
- package/gateway/platforms/yuanbao_media.py +645 -0
- package/gateway/platforms/yuanbao_proto.py +1209 -0
- package/gateway/platforms/yuanbao_sticker.py +558 -0
- package/gateway/restart.py +20 -0
- package/gateway/run.py +17074 -0
- package/gateway/runtime_footer.py +150 -0
- package/gateway/session.py +1399 -0
- package/gateway/session_context.py +156 -0
- package/gateway/shutdown_forensics.py +462 -0
- package/gateway/slash_access.py +229 -0
- package/gateway/status.py +972 -0
- package/gateway/sticker_cache.py +111 -0
- package/gateway/stream_consumer.py +1286 -0
- package/gateway/whatsapp_identity.py +156 -0
- package/hermes_cli/__init__.py +47 -0
- package/hermes_cli/__pycache__/__init__.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/_parser.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/auth.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/banner.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/browser_connect.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/callbacks.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/checkpoints.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/cli_output.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/codex_models.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/codex_runtime_switch.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/colors.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/commands.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/config.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/copilot_auth.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/curator.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/curses_ui.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/debug.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/default_soul.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/env_loader.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/fallback_cmd.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/gateway.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/gateway_windows.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/goals.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/inventory.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/kanban.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/kanban_db.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/main.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/model_catalog.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/model_normalize.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/model_switch.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/models.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/nous_subscription.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/pairing.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/platforms.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/plugins.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/profiles.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/providers.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/pt_input_extras.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/runtime_provider.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/security_advisories.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/setup.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/skills_hub.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/skin_engine.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/stdio.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/timeouts.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/tips.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/tools_config.cpython-312.pyc +0 -0
- package/hermes_cli/__pycache__/voice.cpython-312.pyc +0 -0
- package/hermes_cli/_parser.py +365 -0
- package/hermes_cli/_subprocess_compat.py +175 -0
- package/hermes_cli/auth.py +6299 -0
- package/hermes_cli/auth_commands.py +749 -0
- package/hermes_cli/azure_detect.py +300 -0
- package/hermes_cli/backup.py +938 -0
- package/hermes_cli/banner.py +703 -0
- package/hermes_cli/browser_connect.py +139 -0
- package/hermes_cli/callbacks.py +243 -0
- package/hermes_cli/checkpoints.py +244 -0
- package/hermes_cli/claw.py +810 -0
- package/hermes_cli/cli_output.py +78 -0
- package/hermes_cli/clipboard.py +495 -0
- package/hermes_cli/codex_models.py +198 -0
- package/hermes_cli/codex_runtime_plugin_migration.py +757 -0
- package/hermes_cli/codex_runtime_switch.py +266 -0
- package/hermes_cli/colors.py +38 -0
- package/hermes_cli/commands.py +1728 -0
- package/hermes_cli/completion.py +315 -0
- package/hermes_cli/config.py +5382 -0
- package/hermes_cli/copilot_auth.py +392 -0
- package/hermes_cli/cron.py +313 -0
- package/hermes_cli/curator.py +598 -0
- package/hermes_cli/curses_ui.py +472 -0
- package/hermes_cli/debug.py +747 -0
- package/hermes_cli/default_soul.py +11 -0
- package/hermes_cli/dep_ensure.py +107 -0
- package/hermes_cli/dingtalk_auth.py +293 -0
- package/hermes_cli/doctor.py +1863 -0
- package/hermes_cli/dump.py +326 -0
- package/hermes_cli/env_loader.py +175 -0
- package/hermes_cli/fallback_cmd.py +361 -0
- package/hermes_cli/gateway.py +5422 -0
- package/hermes_cli/gateway_windows.py +692 -0
- package/hermes_cli/goals.py +757 -0
- package/hermes_cli/hooks.py +385 -0
- package/hermes_cli/inventory.py +240 -0
- package/hermes_cli/kanban.py +2252 -0
- package/hermes_cli/kanban_db.py +4840 -0
- package/hermes_cli/kanban_diagnostics.py +776 -0
- package/hermes_cli/kanban_specify.py +266 -0
- package/hermes_cli/logs.py +391 -0
- package/hermes_cli/main.py +12396 -0
- package/hermes_cli/mcp_config.py +781 -0
- package/hermes_cli/memory_setup.py +465 -0
- package/hermes_cli/model_catalog.py +330 -0
- package/hermes_cli/model_normalize.py +473 -0
- package/hermes_cli/model_switch.py +1777 -0
- package/hermes_cli/models.py +3789 -0
- package/hermes_cli/nous_subscription.py +799 -0
- package/hermes_cli/oneshot.py +351 -0
- package/hermes_cli/pairing.py +115 -0
- package/hermes_cli/platforms.py +83 -0
- package/hermes_cli/plugins.py +1562 -0
- package/hermes_cli/plugins_cmd.py +1587 -0
- package/hermes_cli/profile_distribution.py +703 -0
- package/hermes_cli/profiles.py +1319 -0
- package/hermes_cli/providers.py +720 -0
- package/hermes_cli/proxy/__init__.py +20 -0
- package/hermes_cli/proxy/adapters/__init__.py +35 -0
- package/hermes_cli/proxy/adapters/base.py +94 -0
- package/hermes_cli/proxy/adapters/nous_portal.py +137 -0
- package/hermes_cli/proxy/cli.py +141 -0
- package/hermes_cli/proxy/server.py +265 -0
- package/hermes_cli/pt_input_extras.py +83 -0
- package/hermes_cli/pty_bridge.py +237 -0
- package/hermes_cli/relaunch.py +205 -0
- package/hermes_cli/runtime_provider.py +1428 -0
- package/hermes_cli/security_advisories.py +452 -0
- package/hermes_cli/setup.py +3559 -0
- package/hermes_cli/skills_config.py +177 -0
- package/hermes_cli/skills_hub.py +1595 -0
- package/hermes_cli/skin_engine.py +929 -0
- package/hermes_cli/slack_cli.py +160 -0
- package/hermes_cli/status.py +550 -0
- package/hermes_cli/stdio.py +252 -0
- package/hermes_cli/timeouts.py +82 -0
- package/hermes_cli/tips.py +487 -0
- package/hermes_cli/tools_config.py +3151 -0
- package/hermes_cli/uninstall.py +681 -0
- package/hermes_cli/vercel_auth.py +70 -0
- package/hermes_cli/voice.py +846 -0
- package/hermes_cli/web_server.py +4438 -0
- package/hermes_cli/webhook.py +275 -0
- package/locales/af.yaml +350 -0
- package/locales/de.yaml +350 -0
- package/locales/en.yaml +365 -0
- package/locales/es.yaml +350 -0
- package/locales/fr.yaml +350 -0
- package/locales/ga.yaml +354 -0
- package/locales/hu.yaml +350 -0
- package/locales/it.yaml +350 -0
- package/locales/ja.yaml +350 -0
- package/locales/ko.yaml +350 -0
- package/locales/pt.yaml +350 -0
- package/locales/ru.yaml +350 -0
- package/locales/tr.yaml +350 -0
- package/locales/uk.yaml +350 -0
- package/locales/zh-hant.yaml +350 -0
- package/locales/zh.yaml +350 -0
- package/mcp_serve.py +898 -0
- package/model_tools.py +899 -0
- package/optional-skills/DESCRIPTION.md +24 -0
- package/optional-skills/autonomous-ai-agents/DESCRIPTION.md +2 -0
- package/optional-skills/autonomous-ai-agents/blackbox/SKILL.md +144 -0
- package/optional-skills/autonomous-ai-agents/honcho/SKILL.md +431 -0
- package/optional-skills/blockchain/evm/SKILL.md +211 -0
- package/optional-skills/blockchain/evm/scripts/evm_client.py +1508 -0
- package/optional-skills/blockchain/hyperliquid/SKILL.md +211 -0
- package/optional-skills/blockchain/hyperliquid/scripts/hyperliquid_client.py +1660 -0
- package/optional-skills/blockchain/solana/SKILL.md +208 -0
- package/optional-skills/blockchain/solana/scripts/solana_client.py +698 -0
- package/optional-skills/communication/DESCRIPTION.md +1 -0
- package/optional-skills/communication/one-three-one-rule/SKILL.md +104 -0
- package/optional-skills/creative/blender-mcp/SKILL.md +117 -0
- package/optional-skills/creative/concept-diagrams/SKILL.md +362 -0
- package/optional-skills/creative/concept-diagrams/examples/apartment-floor-plan-conversion.md +244 -0
- package/optional-skills/creative/concept-diagrams/examples/automated-password-reset-flow.md +276 -0
- package/optional-skills/creative/concept-diagrams/examples/autonomous-llm-research-agent-flow.md +240 -0
- package/optional-skills/creative/concept-diagrams/examples/banana-journey-tree-to-smoothie.md +161 -0
- package/optional-skills/creative/concept-diagrams/examples/commercial-aircraft-structure.md +209 -0
- package/optional-skills/creative/concept-diagrams/examples/cpu-ooo-microarchitecture.md +236 -0
- package/optional-skills/creative/concept-diagrams/examples/electricity-grid-flow.md +182 -0
- package/optional-skills/creative/concept-diagrams/examples/feature-film-production-pipeline.md +172 -0
- package/optional-skills/creative/concept-diagrams/examples/hospital-emergency-department-flow.md +165 -0
- package/optional-skills/creative/concept-diagrams/examples/ml-benchmark-grouped-bar-chart.md +114 -0
- package/optional-skills/creative/concept-diagrams/examples/place-order-uml-sequence.md +325 -0
- package/optional-skills/creative/concept-diagrams/examples/smart-city-infrastructure.md +173 -0
- package/optional-skills/creative/concept-diagrams/examples/smartphone-layer-anatomy.md +154 -0
- package/optional-skills/creative/concept-diagrams/examples/sn2-reaction-mechanism.md +247 -0
- package/optional-skills/creative/concept-diagrams/examples/wind-turbine-structure.md +338 -0
- package/optional-skills/creative/concept-diagrams/references/dashboard-patterns.md +43 -0
- package/optional-skills/creative/concept-diagrams/references/infrastructure-patterns.md +144 -0
- package/optional-skills/creative/concept-diagrams/references/physical-shape-cookbook.md +42 -0
- package/optional-skills/creative/concept-diagrams/templates/template.html +174 -0
- package/optional-skills/creative/hyperframes/SKILL.md +191 -0
- package/optional-skills/creative/hyperframes/references/cli.md +185 -0
- package/optional-skills/creative/hyperframes/references/composition.md +129 -0
- package/optional-skills/creative/hyperframes/references/features.md +289 -0
- package/optional-skills/creative/hyperframes/references/gsap.md +136 -0
- package/optional-skills/creative/hyperframes/references/troubleshooting.md +137 -0
- package/optional-skills/creative/hyperframes/references/website-to-video.md +145 -0
- package/optional-skills/creative/hyperframes/scripts/setup.sh +135 -0
- package/optional-skills/creative/kanban-video-orchestrator/SKILL.md +207 -0
- package/optional-skills/creative/kanban-video-orchestrator/assets/brief.md.tmpl +79 -0
- package/optional-skills/creative/kanban-video-orchestrator/assets/setup.sh.tmpl +185 -0
- package/optional-skills/creative/kanban-video-orchestrator/assets/soul.md.tmpl +38 -0
- package/optional-skills/creative/kanban-video-orchestrator/references/examples.md +227 -0
- package/optional-skills/creative/kanban-video-orchestrator/references/intake.md +166 -0
- package/optional-skills/creative/kanban-video-orchestrator/references/kanban-setup.md +276 -0
- package/optional-skills/creative/kanban-video-orchestrator/references/monitoring.md +180 -0
- package/optional-skills/creative/kanban-video-orchestrator/references/role-archetypes.md +298 -0
- package/optional-skills/creative/kanban-video-orchestrator/references/tool-matrix.md +317 -0
- package/optional-skills/creative/kanban-video-orchestrator/scripts/bootstrap_pipeline.py +501 -0
- package/optional-skills/creative/kanban-video-orchestrator/scripts/monitor.py +195 -0
- package/optional-skills/creative/meme-generation/EXAMPLES.md +46 -0
- package/optional-skills/creative/meme-generation/SKILL.md +130 -0
- package/optional-skills/creative/meme-generation/scripts/generate_meme.py +471 -0
- package/optional-skills/creative/meme-generation/scripts/templates.json +97 -0
- package/optional-skills/devops/cli/SKILL.md +156 -0
- package/optional-skills/devops/cli/references/app-discovery.md +112 -0
- package/optional-skills/devops/cli/references/authentication.md +59 -0
- package/optional-skills/devops/cli/references/cli-reference.md +104 -0
- package/optional-skills/devops/cli/references/running-apps.md +171 -0
- package/optional-skills/devops/docker-management/SKILL.md +281 -0
- package/optional-skills/devops/pinggy-tunnel/SKILL.md +309 -0
- package/optional-skills/devops/watchers/SKILL.md +112 -0
- package/optional-skills/devops/watchers/scripts/_watermark.py +148 -0
- package/optional-skills/devops/watchers/scripts/watch_github.py +168 -0
- package/optional-skills/devops/watchers/scripts/watch_http_json.py +131 -0
- package/optional-skills/devops/watchers/scripts/watch_rss.py +121 -0
- package/optional-skills/dogfood/DESCRIPTION.md +3 -0
- package/optional-skills/dogfood/adversarial-ux-test/SKILL.md +191 -0
- package/optional-skills/email/agentmail/SKILL.md +126 -0
- package/optional-skills/finance/3-statement-model/SKILL.md +433 -0
- package/optional-skills/finance/3-statement-model/references/formatting.md +118 -0
- package/optional-skills/finance/3-statement-model/references/formulas.md +292 -0
- package/optional-skills/finance/3-statement-model/references/sec-filings.md +125 -0
- package/optional-skills/finance/comps-analysis/SKILL.md +662 -0
- package/optional-skills/finance/dcf-model/SKILL.md +1270 -0
- package/optional-skills/finance/dcf-model/TROUBLESHOOTING.md +40 -0
- package/optional-skills/finance/dcf-model/requirements.txt +7 -0
- package/optional-skills/finance/dcf-model/scripts/validate_dcf.py +292 -0
- package/optional-skills/finance/excel-author/SKILL.md +244 -0
- package/optional-skills/finance/excel-author/scripts/recalc.py +88 -0
- package/optional-skills/finance/lbo-model/SKILL.md +291 -0
- package/optional-skills/finance/merger-model/SKILL.md +144 -0
- package/optional-skills/finance/pptx-author/SKILL.md +173 -0
- package/optional-skills/finance/stocks/SKILL.md +95 -0
- package/optional-skills/finance/stocks/scripts/stocks_client.py +755 -0
- package/optional-skills/health/DESCRIPTION.md +1 -0
- package/optional-skills/health/fitness-nutrition/SKILL.md +256 -0
- package/optional-skills/health/fitness-nutrition/references/FORMULAS.md +100 -0
- package/optional-skills/health/fitness-nutrition/scripts/body_calc.py +210 -0
- package/optional-skills/health/fitness-nutrition/scripts/nutrition_search.py +86 -0
- package/optional-skills/health/neuroskill-bci/SKILL.md +459 -0
- package/optional-skills/health/neuroskill-bci/references/api.md +286 -0
- package/optional-skills/health/neuroskill-bci/references/metrics.md +220 -0
- package/optional-skills/health/neuroskill-bci/references/protocols.md +452 -0
- package/optional-skills/mcp/DESCRIPTION.md +3 -0
- package/optional-skills/mcp/fastmcp/SKILL.md +300 -0
- package/optional-skills/mcp/fastmcp/references/fastmcp-cli.md +110 -0
- package/optional-skills/mcp/fastmcp/scripts/scaffold_fastmcp.py +56 -0
- package/optional-skills/mcp/fastmcp/templates/api_wrapper.py +54 -0
- package/optional-skills/mcp/fastmcp/templates/database_server.py +77 -0
- package/optional-skills/mcp/fastmcp/templates/file_processor.py +55 -0
- package/optional-skills/mcp/mcporter/SKILL.md +123 -0
- package/optional-skills/migration/DESCRIPTION.md +2 -0
- package/optional-skills/migration/openclaw-migration/SKILL.md +298 -0
- package/optional-skills/migration/openclaw-migration/scripts/openclaw_to_hermes.py +3136 -0
- package/optional-skills/mlops/accelerate/SKILL.md +336 -0
- package/optional-skills/mlops/accelerate/references/custom-plugins.md +453 -0
- package/optional-skills/mlops/accelerate/references/megatron-integration.md +489 -0
- package/optional-skills/mlops/accelerate/references/performance.md +525 -0
- package/optional-skills/mlops/chroma/SKILL.md +410 -0
- package/optional-skills/mlops/chroma/references/integration.md +38 -0
- package/optional-skills/mlops/clip/SKILL.md +257 -0
- package/optional-skills/mlops/clip/references/applications.md +207 -0
- package/optional-skills/mlops/faiss/SKILL.md +225 -0
- package/optional-skills/mlops/faiss/references/index_types.md +280 -0
- package/optional-skills/mlops/flash-attention/SKILL.md +367 -0
- package/optional-skills/mlops/flash-attention/references/benchmarks.md +215 -0
- package/optional-skills/mlops/flash-attention/references/transformers-integration.md +293 -0
- package/optional-skills/mlops/guidance/SKILL.md +576 -0
- package/optional-skills/mlops/guidance/references/backends.md +554 -0
- package/optional-skills/mlops/guidance/references/constraints.md +674 -0
- package/optional-skills/mlops/guidance/references/examples.md +767 -0
- package/optional-skills/mlops/huggingface-tokenizers/SKILL.md +520 -0
- package/optional-skills/mlops/huggingface-tokenizers/references/algorithms.md +653 -0
- package/optional-skills/mlops/huggingface-tokenizers/references/integration.md +637 -0
- package/optional-skills/mlops/huggingface-tokenizers/references/pipeline.md +723 -0
- package/optional-skills/mlops/huggingface-tokenizers/references/training.md +565 -0
- package/optional-skills/mlops/inference/outlines/SKILL.md +656 -0
- package/optional-skills/mlops/inference/outlines/references/backends.md +615 -0
- package/optional-skills/mlops/inference/outlines/references/examples.md +773 -0
- package/optional-skills/mlops/inference/outlines/references/json_generation.md +652 -0
- package/optional-skills/mlops/instructor/SKILL.md +744 -0
- package/optional-skills/mlops/instructor/references/examples.md +107 -0
- package/optional-skills/mlops/instructor/references/providers.md +70 -0
- package/optional-skills/mlops/instructor/references/validation.md +606 -0
- package/optional-skills/mlops/lambda-labs/SKILL.md +549 -0
- package/optional-skills/mlops/lambda-labs/references/advanced-usage.md +611 -0
- package/optional-skills/mlops/lambda-labs/references/troubleshooting.md +530 -0
- package/optional-skills/mlops/llava/SKILL.md +308 -0
- package/optional-skills/mlops/llava/references/training.md +197 -0
- package/optional-skills/mlops/modal/SKILL.md +345 -0
- package/optional-skills/mlops/modal/references/advanced-usage.md +503 -0
- package/optional-skills/mlops/modal/references/troubleshooting.md +494 -0
- package/optional-skills/mlops/nemo-curator/SKILL.md +387 -0
- package/optional-skills/mlops/nemo-curator/references/deduplication.md +87 -0
- package/optional-skills/mlops/nemo-curator/references/filtering.md +102 -0
- package/optional-skills/mlops/peft/SKILL.md +435 -0
- package/optional-skills/mlops/peft/references/advanced-usage.md +514 -0
- package/optional-skills/mlops/peft/references/troubleshooting.md +480 -0
- package/optional-skills/mlops/pinecone/SKILL.md +362 -0
- package/optional-skills/mlops/pinecone/references/deployment.md +181 -0
- package/optional-skills/mlops/pytorch-fsdp/SKILL.md +130 -0
- package/optional-skills/mlops/pytorch-fsdp/references/index.md +7 -0
- package/optional-skills/mlops/pytorch-fsdp/references/other.md +4261 -0
- package/optional-skills/mlops/pytorch-lightning/SKILL.md +350 -0
- package/optional-skills/mlops/pytorch-lightning/references/callbacks.md +436 -0
- package/optional-skills/mlops/pytorch-lightning/references/distributed.md +490 -0
- package/optional-skills/mlops/pytorch-lightning/references/hyperparameter-tuning.md +556 -0
- package/optional-skills/mlops/qdrant/SKILL.md +497 -0
- package/optional-skills/mlops/qdrant/references/advanced-usage.md +648 -0
- package/optional-skills/mlops/qdrant/references/troubleshooting.md +631 -0
- package/optional-skills/mlops/saelens/SKILL.md +390 -0
- package/optional-skills/mlops/saelens/references/README.md +69 -0
- package/optional-skills/mlops/saelens/references/api.md +333 -0
- package/optional-skills/mlops/saelens/references/tutorials.md +318 -0
- package/optional-skills/mlops/simpo/SKILL.md +223 -0
- package/optional-skills/mlops/simpo/references/datasets.md +478 -0
- package/optional-skills/mlops/simpo/references/hyperparameters.md +452 -0
- package/optional-skills/mlops/simpo/references/loss-functions.md +350 -0
- package/optional-skills/mlops/slime/SKILL.md +468 -0
- package/optional-skills/mlops/slime/references/api-reference.md +392 -0
- package/optional-skills/mlops/slime/references/troubleshooting.md +386 -0
- package/optional-skills/mlops/stable-diffusion/SKILL.md +523 -0
- package/optional-skills/mlops/stable-diffusion/references/advanced-usage.md +716 -0
- package/optional-skills/mlops/stable-diffusion/references/troubleshooting.md +555 -0
- package/optional-skills/mlops/tensorrt-llm/SKILL.md +191 -0
- package/optional-skills/mlops/tensorrt-llm/references/multi-gpu.md +298 -0
- package/optional-skills/mlops/tensorrt-llm/references/optimization.md +242 -0
- package/optional-skills/mlops/tensorrt-llm/references/serving.md +470 -0
- package/optional-skills/mlops/torchtitan/SKILL.md +362 -0
- package/optional-skills/mlops/torchtitan/references/checkpoint.md +181 -0
- package/optional-skills/mlops/torchtitan/references/custom-models.md +258 -0
- package/optional-skills/mlops/torchtitan/references/float8.md +133 -0
- package/optional-skills/mlops/torchtitan/references/fsdp.md +126 -0
- package/optional-skills/mlops/training/axolotl/SKILL.md +166 -0
- package/optional-skills/mlops/training/axolotl/references/api.md +5548 -0
- package/optional-skills/mlops/training/axolotl/references/dataset-formats.md +1029 -0
- package/optional-skills/mlops/training/axolotl/references/index.md +15 -0
- package/optional-skills/mlops/training/axolotl/references/other.md +3563 -0
- package/optional-skills/mlops/training/trl-fine-tuning/SKILL.md +463 -0
- package/optional-skills/mlops/training/trl-fine-tuning/references/dpo-variants.md +227 -0
- package/optional-skills/mlops/training/trl-fine-tuning/references/grpo-training.md +504 -0
- package/optional-skills/mlops/training/trl-fine-tuning/references/online-rl.md +82 -0
- package/optional-skills/mlops/training/trl-fine-tuning/references/reward-modeling.md +122 -0
- package/optional-skills/mlops/training/trl-fine-tuning/references/sft-training.md +168 -0
- package/optional-skills/mlops/training/trl-fine-tuning/templates/basic_grpo_training.py +228 -0
- package/optional-skills/mlops/training/unsloth/SKILL.md +84 -0
- package/optional-skills/mlops/training/unsloth/references/index.md +7 -0
- package/optional-skills/mlops/training/unsloth/references/llms-full.md +16799 -0
- package/optional-skills/mlops/training/unsloth/references/llms-txt.md +12044 -0
- package/optional-skills/mlops/training/unsloth/references/llms.md +82 -0
- package/optional-skills/mlops/whisper/SKILL.md +321 -0
- package/optional-skills/mlops/whisper/references/languages.md +189 -0
- package/optional-skills/productivity/canvas/SKILL.md +98 -0
- package/optional-skills/productivity/canvas/scripts/canvas_api.py +157 -0
- package/optional-skills/productivity/here-now/SKILL.md +217 -0
- package/optional-skills/productivity/here-now/scripts/drive.sh +406 -0
- package/optional-skills/productivity/here-now/scripts/publish.sh +445 -0
- package/optional-skills/productivity/memento-flashcards/SKILL.md +324 -0
- package/optional-skills/productivity/memento-flashcards/scripts/memento_cards.py +353 -0
- package/optional-skills/productivity/memento-flashcards/scripts/youtube_quiz.py +88 -0
- package/optional-skills/productivity/shop-app/SKILL.md +340 -0
- package/optional-skills/productivity/shopify/SKILL.md +373 -0
- package/optional-skills/productivity/siyuan/SKILL.md +298 -0
- package/optional-skills/productivity/telephony/SKILL.md +418 -0
- package/optional-skills/productivity/telephony/scripts/telephony.py +1343 -0
- package/optional-skills/research/bioinformatics/SKILL.md +235 -0
- package/optional-skills/research/darwinian-evolver/SKILL.md +199 -0
- package/optional-skills/research/darwinian-evolver/scripts/parrot_openrouter.py +218 -0
- package/optional-skills/research/darwinian-evolver/scripts/show_snapshot.py +69 -0
- package/optional-skills/research/darwinian-evolver/templates/custom_problem_template.py +240 -0
- package/optional-skills/research/domain-intel/SKILL.md +97 -0
- package/optional-skills/research/domain-intel/scripts/domain_intel.py +397 -0
- package/optional-skills/research/drug-discovery/SKILL.md +227 -0
- package/optional-skills/research/drug-discovery/references/ADMET_REFERENCE.md +66 -0
- package/optional-skills/research/drug-discovery/scripts/chembl_target.py +53 -0
- package/optional-skills/research/drug-discovery/scripts/ro5_screen.py +44 -0
- package/optional-skills/research/duckduckgo-search/SKILL.md +238 -0
- package/optional-skills/research/duckduckgo-search/scripts/duckduckgo.sh +28 -0
- package/optional-skills/research/gitnexus-explorer/SKILL.md +214 -0
- package/optional-skills/research/gitnexus-explorer/scripts/proxy.mjs +92 -0
- package/optional-skills/research/osint-investigation/SKILL.md +277 -0
- package/optional-skills/research/osint-investigation/references/sources/courtlistener.md +98 -0
- package/optional-skills/research/osint-investigation/references/sources/gdelt.md +104 -0
- package/optional-skills/research/osint-investigation/references/sources/icij-offshore.md +104 -0
- package/optional-skills/research/osint-investigation/references/sources/nyc-acris.md +90 -0
- package/optional-skills/research/osint-investigation/references/sources/ofac-sdn.md +92 -0
- package/optional-skills/research/osint-investigation/references/sources/opencorporates.md +103 -0
- package/optional-skills/research/osint-investigation/references/sources/sec-edgar.md +83 -0
- package/optional-skills/research/osint-investigation/references/sources/senate-ld.md +89 -0
- package/optional-skills/research/osint-investigation/references/sources/usaspending.md +97 -0
- package/optional-skills/research/osint-investigation/references/sources/wayback.md +93 -0
- package/optional-skills/research/osint-investigation/references/sources/wikipedia.md +107 -0
- package/optional-skills/research/osint-investigation/scripts/_http.py +82 -0
- package/optional-skills/research/osint-investigation/scripts/_normalize.py +67 -0
- package/optional-skills/research/osint-investigation/scripts/build_findings.py +221 -0
- package/optional-skills/research/osint-investigation/scripts/entity_resolution.py +228 -0
- package/optional-skills/research/osint-investigation/scripts/fetch_courtlistener.py +149 -0
- package/optional-skills/research/osint-investigation/scripts/fetch_gdelt.py +162 -0
- package/optional-skills/research/osint-investigation/scripts/fetch_icij_offshore.py +234 -0
- package/optional-skills/research/osint-investigation/scripts/fetch_nyc_acris.py +203 -0
- package/optional-skills/research/osint-investigation/scripts/fetch_ofac_sdn.py +175 -0
- package/optional-skills/research/osint-investigation/scripts/fetch_opencorporates.py +192 -0
- package/optional-skills/research/osint-investigation/scripts/fetch_sec_edgar.py +184 -0
- package/optional-skills/research/osint-investigation/scripts/fetch_senate_ld.py +146 -0
- package/optional-skills/research/osint-investigation/scripts/fetch_usaspending.py +170 -0
- package/optional-skills/research/osint-investigation/scripts/fetch_wayback.py +142 -0
- package/optional-skills/research/osint-investigation/scripts/fetch_wikipedia.py +267 -0
- package/optional-skills/research/osint-investigation/scripts/timing_analysis.py +253 -0
- package/optional-skills/research/osint-investigation/templates/source-template.md +59 -0
- package/optional-skills/research/parallel-cli/SKILL.md +391 -0
- package/optional-skills/research/qmd/SKILL.md +441 -0
- package/optional-skills/research/scrapling/SKILL.md +336 -0
- package/optional-skills/research/searxng-search/SKILL.md +212 -0
- package/optional-skills/research/searxng-search/scripts/searxng.sh +22 -0
- package/optional-skills/security/1password/SKILL.md +163 -0
- package/optional-skills/security/1password/references/cli-examples.md +31 -0
- package/optional-skills/security/1password/references/get-started.md +21 -0
- package/optional-skills/security/DESCRIPTION.md +3 -0
- package/optional-skills/security/oss-forensics/SKILL.md +423 -0
- package/optional-skills/security/oss-forensics/references/evidence-types.md +89 -0
- package/optional-skills/security/oss-forensics/references/github-archive-guide.md +184 -0
- package/optional-skills/security/oss-forensics/references/investigation-templates.md +131 -0
- package/optional-skills/security/oss-forensics/references/recovery-techniques.md +164 -0
- package/optional-skills/security/oss-forensics/scripts/evidence-store.py +313 -0
- package/optional-skills/security/oss-forensics/templates/forensic-report.md +151 -0
- package/optional-skills/security/oss-forensics/templates/malicious-package-report.md +43 -0
- package/optional-skills/security/sherlock/SKILL.md +193 -0
- package/optional-skills/software-development/rest-graphql-debug/SKILL.md +514 -0
- package/optional-skills/web-development/DESCRIPTION.md +5 -0
- package/optional-skills/web-development/page-agent/SKILL.md +190 -0
- package/package.json +78 -0
- package/plugins/__init__.py +1 -0
- package/plugins/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/context_engine/__init__.py +219 -0
- package/plugins/disk-cleanup/README.md +51 -0
- package/plugins/disk-cleanup/__init__.py +316 -0
- package/plugins/disk-cleanup/disk_cleanup.py +497 -0
- package/plugins/disk-cleanup/plugin.yaml +7 -0
- package/plugins/example-dashboard/dashboard/manifest.json +14 -0
- package/plugins/example-dashboard/dashboard/plugin_api.py +17 -0
- package/plugins/google_meet/README.md +131 -0
- package/plugins/google_meet/SKILL.md +148 -0
- package/plugins/google_meet/__init__.py +103 -0
- package/plugins/google_meet/audio_bridge.py +244 -0
- package/plugins/google_meet/cli.py +479 -0
- package/plugins/google_meet/meet_bot.py +852 -0
- package/plugins/google_meet/node/__init__.py +54 -0
- package/plugins/google_meet/node/cli.py +125 -0
- package/plugins/google_meet/node/client.py +107 -0
- package/plugins/google_meet/node/protocol.py +124 -0
- package/plugins/google_meet/node/registry.py +113 -0
- package/plugins/google_meet/node/server.py +201 -0
- package/plugins/google_meet/plugin.yaml +16 -0
- package/plugins/google_meet/process_manager.py +324 -0
- package/plugins/google_meet/realtime/__init__.py +10 -0
- package/plugins/google_meet/realtime/openai_client.py +332 -0
- package/plugins/google_meet/tools.py +348 -0
- package/plugins/hermes-achievements/LICENSE +21 -0
- package/plugins/hermes-achievements/README.md +150 -0
- package/plugins/hermes-achievements/dashboard/dist/index.js +732 -0
- package/plugins/hermes-achievements/dashboard/dist/style.css +146 -0
- package/plugins/hermes-achievements/dashboard/manifest.json +11 -0
- package/plugins/hermes-achievements/dashboard/plugin_api.py +1062 -0
- package/plugins/hermes-achievements/docs/achievements-performance-implementation-plan.md +157 -0
- package/plugins/hermes-achievements/docs/achievements-performance-implementation-spec.md +219 -0
- package/plugins/hermes-achievements/docs/achievements-performance-spec.md +174 -0
- package/plugins/hermes-achievements/docs/assets/achievements-dashboard-hd.png +0 -0
- package/plugins/hermes-achievements/docs/assets/achievements-tier-showcase-hd.png +0 -0
- package/plugins/hermes-achievements/tests/test_achievement_engine.py +156 -0
- package/plugins/image_gen/openai/__init__.py +303 -0
- package/plugins/image_gen/openai/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/image_gen/openai/plugin.yaml +7 -0
- package/plugins/image_gen/openai-codex/__init__.py +378 -0
- package/plugins/image_gen/openai-codex/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/image_gen/openai-codex/plugin.yaml +5 -0
- package/plugins/image_gen/xai/__init__.py +316 -0
- package/plugins/image_gen/xai/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/image_gen/xai/plugin.yaml +7 -0
- package/plugins/kanban/dashboard/dist/index.js +3143 -0
- package/plugins/kanban/dashboard/dist/style.css +1500 -0
- package/plugins/kanban/dashboard/manifest.json +14 -0
- package/plugins/kanban/dashboard/plugin_api.py +1612 -0
- package/plugins/kanban/systemd/hermes-kanban-dispatcher.service +32 -0
- package/plugins/memory/__init__.py +408 -0
- package/plugins/memory/byterover/README.md +41 -0
- package/plugins/memory/byterover/__init__.py +384 -0
- package/plugins/memory/byterover/plugin.yaml +9 -0
- package/plugins/memory/hindsight/README.md +138 -0
- package/plugins/memory/hindsight/__init__.py +1758 -0
- package/plugins/memory/hindsight/plugin.yaml +8 -0
- package/plugins/memory/holographic/README.md +36 -0
- package/plugins/memory/holographic/__init__.py +409 -0
- package/plugins/memory/holographic/holographic.py +203 -0
- package/plugins/memory/holographic/plugin.yaml +5 -0
- package/plugins/memory/holographic/retrieval.py +593 -0
- package/plugins/memory/holographic/store.py +579 -0
- package/plugins/memory/honcho/README.md +328 -0
- package/plugins/memory/honcho/__init__.py +1329 -0
- package/plugins/memory/honcho/cli.py +1452 -0
- package/plugins/memory/honcho/client.py +784 -0
- package/plugins/memory/honcho/plugin.yaml +7 -0
- package/plugins/memory/honcho/session.py +1255 -0
- package/plugins/memory/mem0/README.md +38 -0
- package/plugins/memory/mem0/__init__.py +374 -0
- package/plugins/memory/mem0/plugin.yaml +5 -0
- package/plugins/memory/openviking/README.md +40 -0
- package/plugins/memory/openviking/__init__.py +945 -0
- package/plugins/memory/openviking/plugin.yaml +9 -0
- package/plugins/memory/retaindb/README.md +40 -0
- package/plugins/memory/retaindb/__init__.py +767 -0
- package/plugins/memory/retaindb/plugin.yaml +7 -0
- package/plugins/memory/supermemory/README.md +99 -0
- package/plugins/memory/supermemory/__init__.py +792 -0
- package/plugins/memory/supermemory/plugin.yaml +5 -0
- package/plugins/model-providers/README.md +70 -0
- package/plugins/model-providers/ai-gateway/__init__.py +43 -0
- package/plugins/model-providers/ai-gateway/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/ai-gateway/plugin.yaml +5 -0
- package/plugins/model-providers/alibaba/__init__.py +13 -0
- package/plugins/model-providers/alibaba/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/alibaba/plugin.yaml +5 -0
- package/plugins/model-providers/alibaba-coding-plan/__init__.py +21 -0
- package/plugins/model-providers/alibaba-coding-plan/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/alibaba-coding-plan/plugin.yaml +5 -0
- package/plugins/model-providers/anthropic/__init__.py +52 -0
- package/plugins/model-providers/anthropic/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/anthropic/plugin.yaml +5 -0
- package/plugins/model-providers/arcee/__init__.py +13 -0
- package/plugins/model-providers/arcee/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/arcee/plugin.yaml +5 -0
- package/plugins/model-providers/azure-foundry/__init__.py +21 -0
- package/plugins/model-providers/azure-foundry/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/azure-foundry/plugin.yaml +5 -0
- package/plugins/model-providers/bedrock/__init__.py +29 -0
- package/plugins/model-providers/bedrock/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/bedrock/plugin.yaml +5 -0
- package/plugins/model-providers/copilot/__init__.py +58 -0
- package/plugins/model-providers/copilot/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/copilot/plugin.yaml +5 -0
- package/plugins/model-providers/copilot-acp/__init__.py +34 -0
- package/plugins/model-providers/copilot-acp/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/copilot-acp/plugin.yaml +5 -0
- package/plugins/model-providers/custom/__init__.py +68 -0
- package/plugins/model-providers/custom/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/custom/plugin.yaml +5 -0
- package/plugins/model-providers/deepseek/__init__.py +99 -0
- package/plugins/model-providers/deepseek/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/deepseek/plugin.yaml +5 -0
- package/plugins/model-providers/gemini/__init__.py +72 -0
- package/plugins/model-providers/gemini/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/gemini/plugin.yaml +5 -0
- package/plugins/model-providers/gmi/__init__.py +31 -0
- package/plugins/model-providers/gmi/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/gmi/plugin.yaml +5 -0
- package/plugins/model-providers/huggingface/__init__.py +20 -0
- package/plugins/model-providers/huggingface/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/huggingface/plugin.yaml +5 -0
- package/plugins/model-providers/kilocode/__init__.py +14 -0
- package/plugins/model-providers/kilocode/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/kilocode/plugin.yaml +5 -0
- package/plugins/model-providers/kimi-coding/__init__.py +71 -0
- package/plugins/model-providers/kimi-coding/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/kimi-coding/plugin.yaml +5 -0
- package/plugins/model-providers/minimax/__init__.py +45 -0
- package/plugins/model-providers/minimax/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/minimax/plugin.yaml +5 -0
- package/plugins/model-providers/nous/__init__.py +54 -0
- package/plugins/model-providers/nous/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/nous/plugin.yaml +5 -0
- package/plugins/model-providers/novita/__init__.py +27 -0
- package/plugins/model-providers/novita/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/novita/plugin.yaml +5 -0
- package/plugins/model-providers/nvidia/__init__.py +21 -0
- package/plugins/model-providers/nvidia/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/nvidia/plugin.yaml +5 -0
- package/plugins/model-providers/ollama-cloud/__init__.py +14 -0
- package/plugins/model-providers/ollama-cloud/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/ollama-cloud/plugin.yaml +5 -0
- package/plugins/model-providers/openai-codex/__init__.py +15 -0
- package/plugins/model-providers/openai-codex/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/openai-codex/plugin.yaml +5 -0
- package/plugins/model-providers/opencode-zen/__init__.py +30 -0
- package/plugins/model-providers/opencode-zen/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/opencode-zen/plugin.yaml +5 -0
- package/plugins/model-providers/openrouter/__init__.py +115 -0
- package/plugins/model-providers/openrouter/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/openrouter/plugin.yaml +5 -0
- package/plugins/model-providers/qwen-oauth/__init__.py +82 -0
- package/plugins/model-providers/qwen-oauth/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/qwen-oauth/plugin.yaml +5 -0
- package/plugins/model-providers/stepfun/__init__.py +14 -0
- package/plugins/model-providers/stepfun/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/stepfun/plugin.yaml +5 -0
- package/plugins/model-providers/xai/__init__.py +15 -0
- package/plugins/model-providers/xai/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/xai/plugin.yaml +5 -0
- package/plugins/model-providers/xiaomi/__init__.py +14 -0
- package/plugins/model-providers/xiaomi/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/xiaomi/plugin.yaml +5 -0
- package/plugins/model-providers/zai/__init__.py +21 -0
- package/plugins/model-providers/zai/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/model-providers/zai/plugin.yaml +5 -0
- package/plugins/observability/langfuse/README.md +53 -0
- package/plugins/observability/langfuse/__init__.py +1004 -0
- package/plugins/observability/langfuse/plugin.yaml +14 -0
- package/plugins/platforms/google_chat/__init__.py +3 -0
- package/plugins/platforms/google_chat/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/platforms/google_chat/__pycache__/adapter.cpython-312.pyc +0 -0
- package/plugins/platforms/google_chat/adapter.py +3343 -0
- package/plugins/platforms/google_chat/oauth.py +639 -0
- package/plugins/platforms/google_chat/plugin.yaml +39 -0
- package/plugins/platforms/irc/__init__.py +3 -0
- package/plugins/platforms/irc/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/platforms/irc/__pycache__/adapter.cpython-312.pyc +0 -0
- package/plugins/platforms/irc/adapter.py +969 -0
- package/plugins/platforms/irc/plugin.yaml +54 -0
- package/plugins/platforms/line/__init__.py +3 -0
- package/plugins/platforms/line/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/platforms/line/__pycache__/adapter.cpython-312.pyc +0 -0
- package/plugins/platforms/line/adapter.py +1639 -0
- package/plugins/platforms/line/plugin.yaml +65 -0
- package/plugins/platforms/simplex/__init__.py +3 -0
- package/plugins/platforms/simplex/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/platforms/simplex/__pycache__/adapter.cpython-312.pyc +0 -0
- package/plugins/platforms/simplex/adapter.py +746 -0
- package/plugins/platforms/simplex/plugin.yaml +37 -0
- package/plugins/platforms/teams/__init__.py +3 -0
- package/plugins/platforms/teams/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/platforms/teams/__pycache__/adapter.cpython-312.pyc +0 -0
- package/plugins/platforms/teams/adapter.py +1188 -0
- package/plugins/platforms/teams/plugin.yaml +48 -0
- package/plugins/spotify/__init__.py +66 -0
- package/plugins/spotify/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/spotify/__pycache__/client.cpython-312.pyc +0 -0
- package/plugins/spotify/__pycache__/tools.cpython-312.pyc +0 -0
- package/plugins/spotify/client.py +435 -0
- package/plugins/spotify/plugin.yaml +13 -0
- package/plugins/spotify/tools.py +454 -0
- package/plugins/teams_pipeline/__init__.py +23 -0
- package/plugins/teams_pipeline/cli.py +463 -0
- package/plugins/teams_pipeline/meetings.py +333 -0
- package/plugins/teams_pipeline/models.py +350 -0
- package/plugins/teams_pipeline/pipeline.py +692 -0
- package/plugins/teams_pipeline/plugin.yaml +9 -0
- package/plugins/teams_pipeline/runtime.py +135 -0
- package/plugins/teams_pipeline/store.py +194 -0
- package/plugins/teams_pipeline/subscriptions.py +249 -0
- package/plugins/video_gen/fal/__init__.py +523 -0
- package/plugins/video_gen/fal/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/video_gen/fal/plugin.yaml +7 -0
- package/plugins/video_gen/xai/__init__.py +441 -0
- package/plugins/video_gen/xai/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/video_gen/xai/plugin.yaml +7 -0
- package/plugins/web/__init__.py +7 -0
- package/plugins/web/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/web/brave_free/__init__.py +14 -0
- package/plugins/web/brave_free/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/web/brave_free/__pycache__/provider.cpython-312.pyc +0 -0
- package/plugins/web/brave_free/plugin.yaml +7 -0
- package/plugins/web/brave_free/provider.py +137 -0
- package/plugins/web/ddgs/__init__.py +15 -0
- package/plugins/web/ddgs/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/web/ddgs/__pycache__/provider.cpython-312.pyc +0 -0
- package/plugins/web/ddgs/plugin.yaml +7 -0
- package/plugins/web/ddgs/provider.py +104 -0
- package/plugins/web/exa/__init__.py +15 -0
- package/plugins/web/exa/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/web/exa/__pycache__/provider.cpython-312.pyc +0 -0
- package/plugins/web/exa/plugin.yaml +7 -0
- package/plugins/web/exa/provider.py +212 -0
- package/plugins/web/firecrawl/__init__.py +28 -0
- package/plugins/web/firecrawl/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/web/firecrawl/__pycache__/provider.cpython-312.pyc +0 -0
- package/plugins/web/firecrawl/plugin.yaml +7 -0
- package/plugins/web/firecrawl/provider.py +773 -0
- package/plugins/web/parallel/__init__.py +16 -0
- package/plugins/web/parallel/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/web/parallel/__pycache__/provider.cpython-312.pyc +0 -0
- package/plugins/web/parallel/plugin.yaml +7 -0
- package/plugins/web/parallel/provider.py +291 -0
- package/plugins/web/searxng/__init__.py +15 -0
- package/plugins/web/searxng/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/web/searxng/__pycache__/provider.cpython-312.pyc +0 -0
- package/plugins/web/searxng/plugin.yaml +7 -0
- package/plugins/web/searxng/provider.py +140 -0
- package/plugins/web/tavily/__init__.py +15 -0
- package/plugins/web/tavily/__pycache__/__init__.cpython-312.pyc +0 -0
- package/plugins/web/tavily/__pycache__/provider.cpython-312.pyc +0 -0
- package/plugins/web/tavily/plugin.yaml +7 -0
- package/plugins/web/tavily/provider.py +285 -0
- package/providers/README.md +78 -0
- package/providers/__init__.py +192 -0
- package/providers/__pycache__/__init__.cpython-312.pyc +0 -0
- package/providers/__pycache__/base.cpython-312.pyc +0 -0
- package/providers/base.py +184 -0
- package/pyproject.toml +255 -0
- package/run_agent.py +16409 -0
- package/scripts/benchmark_browser_eval.py +138 -0
- package/scripts/build_model_catalog.py +95 -0
- package/scripts/build_skills_index.py +325 -0
- package/scripts/check-windows-footguns.py +624 -0
- package/scripts/contributor_audit.py +473 -0
- package/scripts/discord-voice-doctor.py +396 -0
- package/scripts/hermes-gateway +416 -0
- package/scripts/install.cmd +28 -0
- package/scripts/install.ps1 +1611 -0
- package/scripts/install.sh +2007 -0
- package/scripts/install_psutil_android.py +117 -0
- package/scripts/keystroke_diagnostic.py +81 -0
- package/scripts/kill_modal.sh +34 -0
- package/scripts/lib/node-bootstrap.sh +238 -0
- package/scripts/lint_diff.py +207 -0
- package/scripts/postinstall.js +150 -0
- package/scripts/profile-tui.py +626 -0
- package/scripts/release.py +1680 -0
- package/scripts/run_tests.sh +129 -0
- package/scripts/sample_and_compress.py +409 -0
- package/scripts/setup_open_webui.sh +349 -0
- package/scripts/whatsapp-bridge/allowlist.js +88 -0
- package/scripts/whatsapp-bridge/allowlist.test.mjs +80 -0
- package/scripts/whatsapp-bridge/bridge.js +729 -0
- package/scripts/whatsapp-bridge/package-lock.json +2141 -0
- package/scripts/whatsapp-bridge/package.json +19 -0
- package/skills/apple/DESCRIPTION.md +2 -0
- package/skills/apple/apple-notes/SKILL.md +90 -0
- package/skills/apple/apple-reminders/SKILL.md +98 -0
- package/skills/apple/findmy/SKILL.md +131 -0
- package/skills/apple/imessage/SKILL.md +102 -0
- package/skills/apple/macos-computer-use/SKILL.md +201 -0
- package/skills/autonomous-ai-agents/DESCRIPTION.md +3 -0
- package/skills/autonomous-ai-agents/claude-code/SKILL.md +745 -0
- package/skills/autonomous-ai-agents/codex/SKILL.md +130 -0
- package/skills/autonomous-ai-agents/hermes-agent/SKILL.md +1014 -0
- package/skills/autonomous-ai-agents/opencode/SKILL.md +219 -0
- package/skills/creative/DESCRIPTION.md +3 -0
- package/skills/creative/architecture-diagram/SKILL.md +148 -0
- package/skills/creative/architecture-diagram/templates/template.html +319 -0
- package/skills/creative/ascii-art/SKILL.md +322 -0
- package/skills/creative/ascii-video/README.md +290 -0
- package/skills/creative/ascii-video/SKILL.md +241 -0
- package/skills/creative/ascii-video/references/architecture.md +802 -0
- package/skills/creative/ascii-video/references/composition.md +892 -0
- package/skills/creative/ascii-video/references/effects.md +1865 -0
- package/skills/creative/ascii-video/references/inputs.md +685 -0
- package/skills/creative/ascii-video/references/optimization.md +688 -0
- package/skills/creative/ascii-video/references/scenes.md +1011 -0
- package/skills/creative/ascii-video/references/shaders.md +1385 -0
- package/skills/creative/ascii-video/references/troubleshooting.md +367 -0
- package/skills/creative/baoyu-comic/PORT_NOTES.md +77 -0
- package/skills/creative/baoyu-comic/SKILL.md +247 -0
- package/skills/creative/baoyu-comic/references/analysis-framework.md +176 -0
- package/skills/creative/baoyu-comic/references/art-styles/chalk.md +101 -0
- package/skills/creative/baoyu-comic/references/art-styles/ink-brush.md +97 -0
- package/skills/creative/baoyu-comic/references/art-styles/ligne-claire.md +75 -0
- package/skills/creative/baoyu-comic/references/art-styles/manga.md +93 -0
- package/skills/creative/baoyu-comic/references/art-styles/minimalist.md +84 -0
- package/skills/creative/baoyu-comic/references/art-styles/realistic.md +89 -0
- package/skills/creative/baoyu-comic/references/auto-selection.md +71 -0
- package/skills/creative/baoyu-comic/references/base-prompt.md +98 -0
- package/skills/creative/baoyu-comic/references/character-template.md +180 -0
- package/skills/creative/baoyu-comic/references/layouts/cinematic.md +23 -0
- package/skills/creative/baoyu-comic/references/layouts/dense.md +23 -0
- package/skills/creative/baoyu-comic/references/layouts/four-panel.md +40 -0
- package/skills/creative/baoyu-comic/references/layouts/mixed.md +23 -0
- package/skills/creative/baoyu-comic/references/layouts/splash.md +23 -0
- package/skills/creative/baoyu-comic/references/layouts/standard.md +23 -0
- package/skills/creative/baoyu-comic/references/layouts/webtoon.md +30 -0
- package/skills/creative/baoyu-comic/references/ohmsha-guide.md +85 -0
- package/skills/creative/baoyu-comic/references/partial-workflows.md +106 -0
- package/skills/creative/baoyu-comic/references/presets/concept-story.md +121 -0
- package/skills/creative/baoyu-comic/references/presets/four-panel.md +107 -0
- package/skills/creative/baoyu-comic/references/presets/ohmsha.md +114 -0
- package/skills/creative/baoyu-comic/references/presets/shoujo.md +116 -0
- package/skills/creative/baoyu-comic/references/presets/wuxia.md +110 -0
- package/skills/creative/baoyu-comic/references/storyboard-template.md +143 -0
- package/skills/creative/baoyu-comic/references/tones/action.md +110 -0
- package/skills/creative/baoyu-comic/references/tones/dramatic.md +95 -0
- package/skills/creative/baoyu-comic/references/tones/energetic.md +105 -0
- package/skills/creative/baoyu-comic/references/tones/neutral.md +63 -0
- package/skills/creative/baoyu-comic/references/tones/romantic.md +100 -0
- package/skills/creative/baoyu-comic/references/tones/vintage.md +104 -0
- package/skills/creative/baoyu-comic/references/tones/warm.md +94 -0
- package/skills/creative/baoyu-comic/references/workflow.md +401 -0
- package/skills/creative/baoyu-infographic/PORT_NOTES.md +43 -0
- package/skills/creative/baoyu-infographic/SKILL.md +237 -0
- package/skills/creative/baoyu-infographic/references/analysis-framework.md +182 -0
- package/skills/creative/baoyu-infographic/references/base-prompt.md +43 -0
- package/skills/creative/baoyu-infographic/references/layouts/bento-grid.md +41 -0
- package/skills/creative/baoyu-infographic/references/layouts/binary-comparison.md +48 -0
- package/skills/creative/baoyu-infographic/references/layouts/bridge.md +41 -0
- package/skills/creative/baoyu-infographic/references/layouts/circular-flow.md +41 -0
- package/skills/creative/baoyu-infographic/references/layouts/comic-strip.md +41 -0
- package/skills/creative/baoyu-infographic/references/layouts/comparison-matrix.md +41 -0
- package/skills/creative/baoyu-infographic/references/layouts/dashboard.md +41 -0
- package/skills/creative/baoyu-infographic/references/layouts/dense-modules.md +72 -0
- package/skills/creative/baoyu-infographic/references/layouts/funnel.md +41 -0
- package/skills/creative/baoyu-infographic/references/layouts/hierarchical-layers.md +48 -0
- package/skills/creative/baoyu-infographic/references/layouts/hub-spoke.md +41 -0
- package/skills/creative/baoyu-infographic/references/layouts/iceberg.md +41 -0
- package/skills/creative/baoyu-infographic/references/layouts/isometric-map.md +41 -0
- package/skills/creative/baoyu-infographic/references/layouts/jigsaw.md +41 -0
- package/skills/creative/baoyu-infographic/references/layouts/linear-progression.md +48 -0
- package/skills/creative/baoyu-infographic/references/layouts/periodic-table.md +41 -0
- package/skills/creative/baoyu-infographic/references/layouts/story-mountain.md +41 -0
- package/skills/creative/baoyu-infographic/references/layouts/structural-breakdown.md +48 -0
- package/skills/creative/baoyu-infographic/references/layouts/tree-branching.md +41 -0
- package/skills/creative/baoyu-infographic/references/layouts/venn-diagram.md +41 -0
- package/skills/creative/baoyu-infographic/references/layouts/winding-roadmap.md +41 -0
- package/skills/creative/baoyu-infographic/references/structured-content-template.md +244 -0
- package/skills/creative/baoyu-infographic/references/styles/aged-academia.md +36 -0
- package/skills/creative/baoyu-infographic/references/styles/bold-graphic.md +36 -0
- package/skills/creative/baoyu-infographic/references/styles/chalkboard.md +61 -0
- package/skills/creative/baoyu-infographic/references/styles/claymation.md +29 -0
- package/skills/creative/baoyu-infographic/references/styles/corporate-memphis.md +29 -0
- package/skills/creative/baoyu-infographic/references/styles/craft-handmade.md +44 -0
- package/skills/creative/baoyu-infographic/references/styles/cyberpunk-neon.md +29 -0
- package/skills/creative/baoyu-infographic/references/styles/hand-drawn-edu.md +63 -0
- package/skills/creative/baoyu-infographic/references/styles/ikea-manual.md +29 -0
- package/skills/creative/baoyu-infographic/references/styles/kawaii.md +29 -0
- package/skills/creative/baoyu-infographic/references/styles/knolling.md +29 -0
- package/skills/creative/baoyu-infographic/references/styles/lego-brick.md +29 -0
- package/skills/creative/baoyu-infographic/references/styles/morandi-journal.md +60 -0
- package/skills/creative/baoyu-infographic/references/styles/origami.md +29 -0
- package/skills/creative/baoyu-infographic/references/styles/pixel-art.md +29 -0
- package/skills/creative/baoyu-infographic/references/styles/pop-laboratory.md +48 -0
- package/skills/creative/baoyu-infographic/references/styles/retro-pop-grid.md +47 -0
- package/skills/creative/baoyu-infographic/references/styles/storybook-watercolor.md +29 -0
- package/skills/creative/baoyu-infographic/references/styles/subway-map.md +29 -0
- package/skills/creative/baoyu-infographic/references/styles/technical-schematic.md +36 -0
- package/skills/creative/baoyu-infographic/references/styles/ui-wireframe.md +29 -0
- package/skills/creative/claude-design/SKILL.md +591 -0
- package/skills/creative/comfyui/SKILL.md +612 -0
- package/skills/creative/comfyui/references/official-cli.md +255 -0
- package/skills/creative/comfyui/references/rest-api.md +312 -0
- package/skills/creative/comfyui/references/template-integrity.md +243 -0
- package/skills/creative/comfyui/references/workflow-format.md +226 -0
- package/skills/creative/comfyui/scripts/_common.py +835 -0
- package/skills/creative/comfyui/scripts/auto_fix_deps.py +225 -0
- package/skills/creative/comfyui/scripts/check_deps.py +437 -0
- package/skills/creative/comfyui/scripts/comfyui_setup.sh +286 -0
- package/skills/creative/comfyui/scripts/extract_schema.py +315 -0
- package/skills/creative/comfyui/scripts/fetch_logs.py +158 -0
- package/skills/creative/comfyui/scripts/hardware_check.py +497 -0
- package/skills/creative/comfyui/scripts/health_check.py +223 -0
- package/skills/creative/comfyui/scripts/run_batch.py +243 -0
- package/skills/creative/comfyui/scripts/run_workflow.py +796 -0
- package/skills/creative/comfyui/scripts/ws_monitor.py +267 -0
- package/skills/creative/comfyui/tests/README.md +50 -0
- package/skills/creative/comfyui/tests/conftest.py +64 -0
- package/skills/creative/comfyui/tests/pytest.ini +5 -0
- package/skills/creative/comfyui/tests/test_check_deps.py +68 -0
- package/skills/creative/comfyui/tests/test_cloud_integration.py +95 -0
- package/skills/creative/comfyui/tests/test_common.py +447 -0
- package/skills/creative/comfyui/tests/test_extract_schema.py +185 -0
- package/skills/creative/comfyui/tests/test_run_workflow.py +213 -0
- package/skills/creative/comfyui/workflows/README.md +86 -0
- package/skills/creative/comfyui/workflows/animatediff_video.json +64 -0
- package/skills/creative/comfyui/workflows/flux_dev_txt2img.json +78 -0
- package/skills/creative/comfyui/workflows/sd15_txt2img.json +49 -0
- package/skills/creative/comfyui/workflows/sdxl_img2img.json +54 -0
- package/skills/creative/comfyui/workflows/sdxl_inpaint.json +59 -0
- package/skills/creative/comfyui/workflows/sdxl_txt2img.json +49 -0
- package/skills/creative/comfyui/workflows/upscale_4x.json +27 -0
- package/skills/creative/comfyui/workflows/wan_video_t2v.json +69 -0
- package/skills/creative/creative-ideation/SKILL.md +152 -0
- package/skills/creative/creative-ideation/references/full-prompt-library.md +110 -0
- package/skills/creative/design-md/SKILL.md +199 -0
- package/skills/creative/design-md/templates/starter.md +99 -0
- package/skills/creative/excalidraw/SKILL.md +199 -0
- package/skills/creative/excalidraw/references/colors.md +44 -0
- package/skills/creative/excalidraw/references/dark-mode.md +68 -0
- package/skills/creative/excalidraw/references/examples.md +141 -0
- package/skills/creative/excalidraw/scripts/upload.py +133 -0
- package/skills/creative/humanizer/LICENSE +21 -0
- package/skills/creative/humanizer/SKILL.md +578 -0
- package/skills/creative/manim-video/README.md +23 -0
- package/skills/creative/manim-video/SKILL.md +269 -0
- package/skills/creative/manim-video/references/animation-design-thinking.md +161 -0
- package/skills/creative/manim-video/references/animations.md +282 -0
- package/skills/creative/manim-video/references/camera-and-3d.md +135 -0
- package/skills/creative/manim-video/references/decorations.md +202 -0
- package/skills/creative/manim-video/references/equations.md +216 -0
- package/skills/creative/manim-video/references/graphs-and-data.md +163 -0
- package/skills/creative/manim-video/references/mobjects.md +333 -0
- package/skills/creative/manim-video/references/paper-explainer.md +255 -0
- package/skills/creative/manim-video/references/production-quality.md +190 -0
- package/skills/creative/manim-video/references/rendering.md +185 -0
- package/skills/creative/manim-video/references/scene-planning.md +118 -0
- package/skills/creative/manim-video/references/troubleshooting.md +135 -0
- package/skills/creative/manim-video/references/updaters-and-trackers.md +260 -0
- package/skills/creative/manim-video/references/visual-design.md +124 -0
- package/skills/creative/manim-video/scripts/setup.sh +14 -0
- package/skills/creative/p5js/README.md +64 -0
- package/skills/creative/p5js/SKILL.md +556 -0
- package/skills/creative/p5js/references/animation.md +439 -0
- package/skills/creative/p5js/references/color-systems.md +352 -0
- package/skills/creative/p5js/references/core-api.md +410 -0
- package/skills/creative/p5js/references/export-pipeline.md +566 -0
- package/skills/creative/p5js/references/interaction.md +398 -0
- package/skills/creative/p5js/references/shapes-and-geometry.md +300 -0
- package/skills/creative/p5js/references/troubleshooting.md +532 -0
- package/skills/creative/p5js/references/typography.md +302 -0
- package/skills/creative/p5js/references/visual-effects.md +895 -0
- package/skills/creative/p5js/references/webgl-and-3d.md +423 -0
- package/skills/creative/p5js/scripts/export-frames.js +179 -0
- package/skills/creative/p5js/scripts/render.sh +108 -0
- package/skills/creative/p5js/scripts/serve.sh +28 -0
- package/skills/creative/p5js/scripts/setup.sh +87 -0
- package/skills/creative/p5js/templates/viewer.html +395 -0
- package/skills/creative/pixel-art/ATTRIBUTION.md +54 -0
- package/skills/creative/pixel-art/SKILL.md +218 -0
- package/skills/creative/pixel-art/references/palettes.md +49 -0
- package/skills/creative/pixel-art/scripts/__init__.py +0 -0
- package/skills/creative/pixel-art/scripts/palettes.py +167 -0
- package/skills/creative/pixel-art/scripts/pixel_art.py +162 -0
- package/skills/creative/pixel-art/scripts/pixel_art_video.py +345 -0
- package/skills/creative/popular-web-designs/SKILL.md +214 -0
- package/skills/creative/popular-web-designs/templates/airbnb.md +259 -0
- package/skills/creative/popular-web-designs/templates/airtable.md +102 -0
- package/skills/creative/popular-web-designs/templates/apple.md +326 -0
- package/skills/creative/popular-web-designs/templates/bmw.md +193 -0
- package/skills/creative/popular-web-designs/templates/cal.md +272 -0
- package/skills/creative/popular-web-designs/templates/claude.md +325 -0
- package/skills/creative/popular-web-designs/templates/clay.md +317 -0
- package/skills/creative/popular-web-designs/templates/clickhouse.md +294 -0
- package/skills/creative/popular-web-designs/templates/cohere.md +279 -0
- package/skills/creative/popular-web-designs/templates/coinbase.md +142 -0
- package/skills/creative/popular-web-designs/templates/composio.md +320 -0
- package/skills/creative/popular-web-designs/templates/cursor.md +322 -0
- package/skills/creative/popular-web-designs/templates/elevenlabs.md +278 -0
- package/skills/creative/popular-web-designs/templates/expo.md +294 -0
- package/skills/creative/popular-web-designs/templates/figma.md +233 -0
- package/skills/creative/popular-web-designs/templates/framer.md +259 -0
- package/skills/creative/popular-web-designs/templates/hashicorp.md +291 -0
- package/skills/creative/popular-web-designs/templates/ibm.md +345 -0
- package/skills/creative/popular-web-designs/templates/intercom.md +159 -0
- package/skills/creative/popular-web-designs/templates/kraken.md +138 -0
- package/skills/creative/popular-web-designs/templates/linear.app.md +380 -0
- package/skills/creative/popular-web-designs/templates/lovable.md +311 -0
- package/skills/creative/popular-web-designs/templates/minimax.md +270 -0
- package/skills/creative/popular-web-designs/templates/mintlify.md +339 -0
- package/skills/creative/popular-web-designs/templates/miro.md +121 -0
- package/skills/creative/popular-web-designs/templates/mistral.ai.md +274 -0
- package/skills/creative/popular-web-designs/templates/mongodb.md +279 -0
- package/skills/creative/popular-web-designs/templates/notion.md +322 -0
- package/skills/creative/popular-web-designs/templates/nvidia.md +306 -0
- package/skills/creative/popular-web-designs/templates/ollama.md +280 -0
- package/skills/creative/popular-web-designs/templates/opencode.ai.md +294 -0
- package/skills/creative/popular-web-designs/templates/pinterest.md +243 -0
- package/skills/creative/popular-web-designs/templates/posthog.md +269 -0
- package/skills/creative/popular-web-designs/templates/raycast.md +281 -0
- package/skills/creative/popular-web-designs/templates/replicate.md +274 -0
- package/skills/creative/popular-web-designs/templates/resend.md +316 -0
- package/skills/creative/popular-web-designs/templates/revolut.md +198 -0
- package/skills/creative/popular-web-designs/templates/runwayml.md +257 -0
- package/skills/creative/popular-web-designs/templates/sanity.md +370 -0
- package/skills/creative/popular-web-designs/templates/sentry.md +275 -0
- package/skills/creative/popular-web-designs/templates/spacex.md +207 -0
- package/skills/creative/popular-web-designs/templates/spotify.md +259 -0
- package/skills/creative/popular-web-designs/templates/stripe.md +335 -0
- package/skills/creative/popular-web-designs/templates/supabase.md +268 -0
- package/skills/creative/popular-web-designs/templates/superhuman.md +265 -0
- package/skills/creative/popular-web-designs/templates/together.ai.md +276 -0
- package/skills/creative/popular-web-designs/templates/uber.md +308 -0
- package/skills/creative/popular-web-designs/templates/vercel.md +323 -0
- package/skills/creative/popular-web-designs/templates/voltagent.md +336 -0
- package/skills/creative/popular-web-designs/templates/warp.md +266 -0
- package/skills/creative/popular-web-designs/templates/webflow.md +105 -0
- package/skills/creative/popular-web-designs/templates/wise.md +186 -0
- package/skills/creative/popular-web-designs/templates/x.ai.md +270 -0
- package/skills/creative/popular-web-designs/templates/zapier.md +341 -0
- package/skills/creative/pretext/SKILL.md +220 -0
- package/skills/creative/pretext/references/patterns.md +258 -0
- package/skills/creative/pretext/templates/donut-orbit.html +1468 -0
- package/skills/creative/pretext/templates/hello-orb-flow.html +95 -0
- package/skills/creative/sketch/SKILL.md +218 -0
- package/skills/creative/songwriting-and-ai-music/SKILL.md +287 -0
- package/skills/creative/touchdesigner-mcp/SKILL.md +356 -0
- package/skills/creative/touchdesigner-mcp/references/3d-scene.md +275 -0
- package/skills/creative/touchdesigner-mcp/references/animation.md +221 -0
- package/skills/creative/touchdesigner-mcp/references/audio-reactive.md +175 -0
- package/skills/creative/touchdesigner-mcp/references/dat-scripting.md +352 -0
- package/skills/creative/touchdesigner-mcp/references/external-data.md +322 -0
- package/skills/creative/touchdesigner-mcp/references/geometry-comp.md +121 -0
- package/skills/creative/touchdesigner-mcp/references/glsl.md +151 -0
- package/skills/creative/touchdesigner-mcp/references/layout-compositor.md +131 -0
- package/skills/creative/touchdesigner-mcp/references/mcp-tools.md +382 -0
- package/skills/creative/touchdesigner-mcp/references/midi-osc.md +211 -0
- package/skills/creative/touchdesigner-mcp/references/network-patterns.md +966 -0
- package/skills/creative/touchdesigner-mcp/references/operator-tips.md +106 -0
- package/skills/creative/touchdesigner-mcp/references/operators.md +239 -0
- package/skills/creative/touchdesigner-mcp/references/panel-ui.md +281 -0
- package/skills/creative/touchdesigner-mcp/references/particles.md +245 -0
- package/skills/creative/touchdesigner-mcp/references/pitfalls.md +704 -0
- package/skills/creative/touchdesigner-mcp/references/postfx.md +183 -0
- package/skills/creative/touchdesigner-mcp/references/projection-mapping.md +211 -0
- package/skills/creative/touchdesigner-mcp/references/python-api.md +463 -0
- package/skills/creative/touchdesigner-mcp/references/replicator.md +198 -0
- package/skills/creative/touchdesigner-mcp/references/troubleshooting.md +244 -0
- package/skills/creative/touchdesigner-mcp/scripts/setup.sh +115 -0
- package/skills/data-science/DESCRIPTION.md +3 -0
- package/skills/data-science/jupyter-live-kernel/SKILL.md +167 -0
- package/skills/devops/kanban-orchestrator/SKILL.md +189 -0
- package/skills/devops/kanban-worker/SKILL.md +184 -0
- package/skills/devops/webhook-subscriptions/SKILL.md +204 -0
- package/skills/diagramming/DESCRIPTION.md +3 -0
- package/skills/dogfood/SKILL.md +162 -0
- package/skills/dogfood/references/issue-taxonomy.md +109 -0
- package/skills/dogfood/templates/dogfood-report-template.md +86 -0
- package/skills/domain/DESCRIPTION.md +24 -0
- package/skills/email/DESCRIPTION.md +3 -0
- package/skills/email/himalaya/SKILL.md +299 -0
- package/skills/email/himalaya/references/configuration.md +227 -0
- package/skills/email/himalaya/references/message-composition.md +199 -0
- package/skills/gaming/DESCRIPTION.md +3 -0
- package/skills/gaming/minecraft-modpack-server/SKILL.md +187 -0
- package/skills/gaming/pokemon-player/SKILL.md +216 -0
- package/skills/gifs/DESCRIPTION.md +3 -0
- package/skills/github/DESCRIPTION.md +3 -0
- package/skills/github/codebase-inspection/SKILL.md +116 -0
- package/skills/github/github-auth/SKILL.md +247 -0
- package/skills/github/github-auth/scripts/gh-env.sh +66 -0
- package/skills/github/github-code-review/SKILL.md +481 -0
- package/skills/github/github-code-review/references/review-output-template.md +74 -0
- package/skills/github/github-issues/SKILL.md +370 -0
- package/skills/github/github-issues/templates/bug-report.md +35 -0
- package/skills/github/github-issues/templates/feature-request.md +31 -0
- package/skills/github/github-pr-workflow/SKILL.md +367 -0
- package/skills/github/github-pr-workflow/references/ci-troubleshooting.md +183 -0
- package/skills/github/github-pr-workflow/references/conventional-commits.md +71 -0
- package/skills/github/github-pr-workflow/templates/pr-body-bugfix.md +35 -0
- package/skills/github/github-pr-workflow/templates/pr-body-feature.md +33 -0
- package/skills/github/github-repo-management/SKILL.md +516 -0
- package/skills/github/github-repo-management/references/github-api-cheatsheet.md +161 -0
- package/skills/index-cache/anthropics_skills_skills_.json +1 -0
- package/skills/index-cache/claude_marketplace_anthropics_skills.json +1 -0
- package/skills/index-cache/lobehub_index.json +1 -0
- package/skills/index-cache/openai_skills_skills_.json +1 -0
- package/skills/inference-sh/DESCRIPTION.md +19 -0
- package/skills/mcp/DESCRIPTION.md +3 -0
- package/skills/mcp/native-mcp/SKILL.md +357 -0
- package/skills/media/DESCRIPTION.md +3 -0
- package/skills/media/gif-search/SKILL.md +91 -0
- package/skills/media/heartmula/SKILL.md +171 -0
- package/skills/media/songsee/SKILL.md +83 -0
- package/skills/media/spotify/SKILL.md +135 -0
- package/skills/media/youtube-content/SKILL.md +73 -0
- package/skills/media/youtube-content/references/output-formats.md +56 -0
- package/skills/media/youtube-content/scripts/fetch_transcript.py +124 -0
- package/skills/mlops/DESCRIPTION.md +3 -0
- package/skills/mlops/evaluation/DESCRIPTION.md +3 -0
- package/skills/mlops/evaluation/lm-evaluation-harness/SKILL.md +498 -0
- package/skills/mlops/evaluation/lm-evaluation-harness/references/api-evaluation.md +490 -0
- package/skills/mlops/evaluation/lm-evaluation-harness/references/benchmark-guide.md +488 -0
- package/skills/mlops/evaluation/lm-evaluation-harness/references/custom-tasks.md +602 -0
- package/skills/mlops/evaluation/lm-evaluation-harness/references/distributed-eval.md +519 -0
- package/skills/mlops/evaluation/weights-and-biases/SKILL.md +594 -0
- package/skills/mlops/evaluation/weights-and-biases/references/artifacts.md +584 -0
- package/skills/mlops/evaluation/weights-and-biases/references/integrations.md +700 -0
- package/skills/mlops/evaluation/weights-and-biases/references/sweeps.md +847 -0
- package/skills/mlops/huggingface-hub/SKILL.md +81 -0
- package/skills/mlops/inference/DESCRIPTION.md +3 -0
- package/skills/mlops/inference/llama-cpp/SKILL.md +249 -0
- package/skills/mlops/inference/llama-cpp/references/advanced-usage.md +504 -0
- package/skills/mlops/inference/llama-cpp/references/hub-discovery.md +168 -0
- package/skills/mlops/inference/llama-cpp/references/optimization.md +89 -0
- package/skills/mlops/inference/llama-cpp/references/quantization.md +243 -0
- package/skills/mlops/inference/llama-cpp/references/server.md +150 -0
- package/skills/mlops/inference/llama-cpp/references/troubleshooting.md +442 -0
- package/skills/mlops/inference/obliteratus/SKILL.md +342 -0
- package/skills/mlops/inference/obliteratus/references/analysis-modules.md +166 -0
- package/skills/mlops/inference/obliteratus/references/methods-guide.md +141 -0
- package/skills/mlops/inference/obliteratus/templates/abliteration-config.yaml +33 -0
- package/skills/mlops/inference/obliteratus/templates/analysis-study.yaml +40 -0
- package/skills/mlops/inference/obliteratus/templates/batch-abliteration.yaml +41 -0
- package/skills/mlops/inference/vllm/SKILL.md +372 -0
- package/skills/mlops/inference/vllm/references/optimization.md +226 -0
- package/skills/mlops/inference/vllm/references/quantization.md +284 -0
- package/skills/mlops/inference/vllm/references/server-deployment.md +255 -0
- package/skills/mlops/inference/vllm/references/troubleshooting.md +447 -0
- package/skills/mlops/models/DESCRIPTION.md +3 -0
- package/skills/mlops/models/audiocraft/SKILL.md +568 -0
- package/skills/mlops/models/audiocraft/references/advanced-usage.md +666 -0
- package/skills/mlops/models/audiocraft/references/troubleshooting.md +504 -0
- package/skills/mlops/models/segment-anything/SKILL.md +506 -0
- package/skills/mlops/models/segment-anything/references/advanced-usage.md +589 -0
- package/skills/mlops/models/segment-anything/references/troubleshooting.md +484 -0
- package/skills/mlops/research/DESCRIPTION.md +3 -0
- package/skills/mlops/research/dspy/SKILL.md +594 -0
- package/skills/mlops/research/dspy/references/examples.md +663 -0
- package/skills/mlops/research/dspy/references/modules.md +475 -0
- package/skills/mlops/research/dspy/references/optimizers.md +566 -0
- package/skills/mlops/training/DESCRIPTION.md +3 -0
- package/skills/mlops/vector-databases/DESCRIPTION.md +3 -0
- package/skills/note-taking/DESCRIPTION.md +3 -0
- package/skills/note-taking/obsidian/SKILL.md +61 -0
- package/skills/productivity/DESCRIPTION.md +3 -0
- package/skills/productivity/airtable/SKILL.md +229 -0
- package/skills/productivity/google-workspace/SKILL.md +335 -0
- package/skills/productivity/google-workspace/references/gmail-search-syntax.md +63 -0
- package/skills/productivity/google-workspace/scripts/_hermes_home.py +43 -0
- package/skills/productivity/google-workspace/scripts/google_api.py +1221 -0
- package/skills/productivity/google-workspace/scripts/gws_bridge.py +108 -0
- package/skills/productivity/google-workspace/scripts/setup.py +454 -0
- package/skills/productivity/linear/SKILL.md +380 -0
- package/skills/productivity/linear/scripts/linear_api.py +445 -0
- package/skills/productivity/maps/SKILL.md +195 -0
- package/skills/productivity/maps/scripts/maps_client.py +1298 -0
- package/skills/productivity/nano-pdf/SKILL.md +52 -0
- package/skills/productivity/notion/SKILL.md +448 -0
- package/skills/productivity/notion/references/block-types.md +112 -0
- package/skills/productivity/ocr-and-documents/DESCRIPTION.md +3 -0
- package/skills/productivity/ocr-and-documents/SKILL.md +172 -0
- package/skills/productivity/ocr-and-documents/scripts/extract_marker.py +87 -0
- package/skills/productivity/ocr-and-documents/scripts/extract_pymupdf.py +98 -0
- package/skills/productivity/powerpoint/LICENSE.txt +30 -0
- package/skills/productivity/powerpoint/SKILL.md +237 -0
- package/skills/productivity/powerpoint/editing.md +205 -0
- package/skills/productivity/powerpoint/pptxgenjs.md +420 -0
- package/skills/productivity/powerpoint/scripts/__init__.py +0 -0
- package/skills/productivity/powerpoint/scripts/add_slide.py +195 -0
- package/skills/productivity/powerpoint/scripts/clean.py +286 -0
- package/skills/productivity/powerpoint/scripts/office/helpers/__init__.py +0 -0
- package/skills/productivity/powerpoint/scripts/office/helpers/merge_runs.py +199 -0
- package/skills/productivity/powerpoint/scripts/office/helpers/simplify_redlines.py +197 -0
- package/skills/productivity/powerpoint/scripts/office/pack.py +159 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ecma/fourth-edition/opc-contentTypes.xsd +42 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ecma/fourth-edition/opc-coreProperties.xsd +50 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ecma/fourth-edition/opc-digSig.xsd +49 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/ecma/fourth-edition/opc-relationships.xsd +33 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/mce/mc.xsd +75 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/skills/productivity/teams-meeting-pipeline/SKILL.md +116 -0
- package/skills/red-teaming/godmode/SKILL.md +404 -0
- package/skills/red-teaming/godmode/references/jailbreak-templates.md +128 -0
- package/skills/red-teaming/godmode/references/refusal-detection.md +142 -0
- package/skills/red-teaming/godmode/scripts/auto_jailbreak.py +769 -0
- package/skills/red-teaming/godmode/scripts/godmode_race.py +530 -0
- package/skills/red-teaming/godmode/scripts/load_godmode.py +45 -0
- package/skills/red-teaming/godmode/scripts/parseltongue.py +550 -0
- package/skills/red-teaming/godmode/templates/prefill-subtle.json +10 -0
- package/skills/red-teaming/godmode/templates/prefill.json +18 -0
- package/skills/research/DESCRIPTION.md +3 -0
- package/skills/research/arxiv/SKILL.md +282 -0
- package/skills/research/arxiv/scripts/search_arxiv.py +114 -0
- package/skills/research/blogwatcher/SKILL.md +137 -0
- package/skills/research/llm-wiki/SKILL.md +507 -0
- package/skills/research/polymarket/SKILL.md +77 -0
- package/skills/research/polymarket/references/api-endpoints.md +220 -0
- package/skills/research/polymarket/scripts/polymarket.py +284 -0
- package/skills/research/research-paper-writing/SKILL.md +2377 -0
- package/skills/research/research-paper-writing/references/autoreason-methodology.md +394 -0
- package/skills/research/research-paper-writing/references/checklists.md +434 -0
- package/skills/research/research-paper-writing/references/citation-workflow.md +564 -0
- package/skills/research/research-paper-writing/references/experiment-patterns.md +728 -0
- package/skills/research/research-paper-writing/references/human-evaluation.md +476 -0
- package/skills/research/research-paper-writing/references/paper-types.md +481 -0
- package/skills/research/research-paper-writing/references/reviewer-guidelines.md +433 -0
- package/skills/research/research-paper-writing/references/sources.md +191 -0
- package/skills/research/research-paper-writing/references/writing-guide.md +474 -0
- package/skills/research/research-paper-writing/templates/README.md +251 -0
- package/skills/research/research-paper-writing/templates/aaai2026/README.md +534 -0
- package/skills/research/research-paper-writing/templates/aaai2026/aaai2026-unified-supp.tex +144 -0
- package/skills/research/research-paper-writing/templates/aaai2026/aaai2026-unified-template.tex +952 -0
- package/skills/research/research-paper-writing/templates/aaai2026/aaai2026.bib +111 -0
- package/skills/research/research-paper-writing/templates/aaai2026/aaai2026.bst +1493 -0
- package/skills/research/research-paper-writing/templates/aaai2026/aaai2026.sty +315 -0
- package/skills/research/research-paper-writing/templates/acl/README.md +50 -0
- package/skills/research/research-paper-writing/templates/acl/acl.sty +312 -0
- package/skills/research/research-paper-writing/templates/acl/acl_latex.tex +377 -0
- package/skills/research/research-paper-writing/templates/acl/acl_lualatex.tex +101 -0
- package/skills/research/research-paper-writing/templates/acl/acl_natbib.bst +1940 -0
- package/skills/research/research-paper-writing/templates/acl/anthology.bib.txt +26 -0
- package/skills/research/research-paper-writing/templates/acl/custom.bib +70 -0
- package/skills/research/research-paper-writing/templates/acl/formatting.md +326 -0
- package/skills/research/research-paper-writing/templates/colm2025/README.md +3 -0
- package/skills/research/research-paper-writing/templates/colm2025/colm2025_conference.bib +11 -0
- package/skills/research/research-paper-writing/templates/colm2025/colm2025_conference.bst +1440 -0
- package/skills/research/research-paper-writing/templates/colm2025/colm2025_conference.pdf +0 -0
- package/skills/research/research-paper-writing/templates/colm2025/colm2025_conference.sty +218 -0
- package/skills/research/research-paper-writing/templates/colm2025/colm2025_conference.tex +305 -0
- package/skills/research/research-paper-writing/templates/colm2025/fancyhdr.sty +485 -0
- package/skills/research/research-paper-writing/templates/colm2025/math_commands.tex +508 -0
- package/skills/research/research-paper-writing/templates/colm2025/natbib.sty +1246 -0
- package/skills/research/research-paper-writing/templates/iclr2026/fancyhdr.sty +485 -0
- package/skills/research/research-paper-writing/templates/iclr2026/iclr2026_conference.bib +24 -0
- package/skills/research/research-paper-writing/templates/iclr2026/iclr2026_conference.bst +1440 -0
- package/skills/research/research-paper-writing/templates/iclr2026/iclr2026_conference.pdf +0 -0
- package/skills/research/research-paper-writing/templates/iclr2026/iclr2026_conference.sty +246 -0
- package/skills/research/research-paper-writing/templates/iclr2026/iclr2026_conference.tex +414 -0
- package/skills/research/research-paper-writing/templates/iclr2026/math_commands.tex +508 -0
- package/skills/research/research-paper-writing/templates/iclr2026/natbib.sty +1246 -0
- package/skills/research/research-paper-writing/templates/icml2026/algorithm.sty +79 -0
- package/skills/research/research-paper-writing/templates/icml2026/algorithmic.sty +201 -0
- package/skills/research/research-paper-writing/templates/icml2026/example_paper.bib +75 -0
- package/skills/research/research-paper-writing/templates/icml2026/example_paper.pdf +0 -0
- package/skills/research/research-paper-writing/templates/icml2026/example_paper.tex +662 -0
- package/skills/research/research-paper-writing/templates/icml2026/fancyhdr.sty +864 -0
- package/skills/research/research-paper-writing/templates/icml2026/icml2026.bst +1443 -0
- package/skills/research/research-paper-writing/templates/icml2026/icml2026.sty +767 -0
- package/skills/research/research-paper-writing/templates/icml2026/icml_numpapers.pdf +0 -0
- package/skills/research/research-paper-writing/templates/neurips2025/Makefile +36 -0
- package/skills/research/research-paper-writing/templates/neurips2025/extra_pkgs.tex +53 -0
- package/skills/research/research-paper-writing/templates/neurips2025/main.tex +38 -0
- package/skills/research/research-paper-writing/templates/neurips2025/neurips.sty +382 -0
- package/skills/smart-home/DESCRIPTION.md +3 -0
- package/skills/smart-home/openhue/SKILL.md +109 -0
- package/skills/social-media/DESCRIPTION.md +3 -0
- package/skills/social-media/xurl/SKILL.md +414 -0
- package/skills/software-development/debugging-hermes-tui-commands/SKILL.md +152 -0
- package/skills/software-development/hermes-agent-skill-authoring/SKILL.md +165 -0
- package/skills/software-development/node-inspect-debugger/SKILL.md +319 -0
- package/skills/software-development/plan/SKILL.md +58 -0
- package/skills/software-development/python-debugpy/SKILL.md +375 -0
- package/skills/software-development/requesting-code-review/SKILL.md +280 -0
- package/skills/software-development/spike/SKILL.md +197 -0
- package/skills/software-development/subagent-driven-development/SKILL.md +352 -0
- package/skills/software-development/subagent-driven-development/references/context-budget-discipline.md +53 -0
- package/skills/software-development/subagent-driven-development/references/gates-taxonomy.md +93 -0
- package/skills/software-development/systematic-debugging/SKILL.md +367 -0
- package/skills/software-development/test-driven-development/SKILL.md +343 -0
- package/skills/software-development/writing-plans/SKILL.md +297 -0
- package/skills/yuanbao/SKILL.md +108 -0
- package/tools/__init__.py +25 -0
- package/tools/__pycache__/__init__.cpython-312.pyc +0 -0
- package/tools/__pycache__/approval.cpython-312.pyc +0 -0
- package/tools/__pycache__/binary_extensions.cpython-312.pyc +0 -0
- package/tools/__pycache__/browser_camofox.cpython-312.pyc +0 -0
- package/tools/__pycache__/browser_camofox_state.cpython-312.pyc +0 -0
- package/tools/__pycache__/browser_cdp_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/browser_dialog_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/browser_supervisor.cpython-312.pyc +0 -0
- package/tools/__pycache__/browser_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/budget_config.cpython-312.pyc +0 -0
- package/tools/__pycache__/checkpoint_manager.cpython-312.pyc +0 -0
- package/tools/__pycache__/clarify_gateway.cpython-312.pyc +0 -0
- package/tools/__pycache__/clarify_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/code_execution_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/computer_use_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/cronjob_tools.cpython-312.pyc +0 -0
- package/tools/__pycache__/debug_helpers.cpython-312.pyc +0 -0
- package/tools/__pycache__/delegate_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/discord_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/feishu_doc_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/feishu_drive_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/file_operations.cpython-312.pyc +0 -0
- package/tools/__pycache__/file_state.cpython-312.pyc +0 -0
- package/tools/__pycache__/file_tools.cpython-312.pyc +0 -0
- package/tools/__pycache__/homeassistant_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/image_generation_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/interrupt.cpython-312.pyc +0 -0
- package/tools/__pycache__/kanban_tools.cpython-312.pyc +0 -0
- package/tools/__pycache__/lazy_deps.cpython-312.pyc +0 -0
- package/tools/__pycache__/managed_tool_gateway.cpython-312.pyc +0 -0
- package/tools/__pycache__/mcp_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/memory_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/mixture_of_agents_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/openrouter_client.cpython-312.pyc +0 -0
- package/tools/__pycache__/process_registry.cpython-312.pyc +0 -0
- package/tools/__pycache__/registry.cpython-312.pyc +0 -0
- package/tools/__pycache__/schema_sanitizer.cpython-312.pyc +0 -0
- package/tools/__pycache__/send_message_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/session_search_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/skill_manager_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/skill_provenance.cpython-312.pyc +0 -0
- package/tools/__pycache__/skill_usage.cpython-312.pyc +0 -0
- package/tools/__pycache__/skills_guard.cpython-312.pyc +0 -0
- package/tools/__pycache__/skills_sync.cpython-312.pyc +0 -0
- package/tools/__pycache__/skills_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/slash_confirm.cpython-312.pyc +0 -0
- package/tools/__pycache__/terminal_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/tirith_security.cpython-312.pyc +0 -0
- package/tools/__pycache__/todo_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/tool_backend_helpers.cpython-312.pyc +0 -0
- package/tools/__pycache__/tool_result_storage.cpython-312.pyc +0 -0
- package/tools/__pycache__/tts_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/url_safety.cpython-312.pyc +0 -0
- package/tools/__pycache__/video_generation_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/vision_tools.cpython-312.pyc +0 -0
- package/tools/__pycache__/voice_mode.cpython-312.pyc +0 -0
- package/tools/__pycache__/web_tools.cpython-312.pyc +0 -0
- package/tools/__pycache__/website_policy.cpython-312.pyc +0 -0
- package/tools/__pycache__/x_search_tool.cpython-312.pyc +0 -0
- package/tools/__pycache__/xai_http.cpython-312.pyc +0 -0
- package/tools/__pycache__/yuanbao_tools.cpython-312.pyc +0 -0
- package/tools/ansi_strip.py +44 -0
- package/tools/approval.py +1392 -0
- package/tools/binary_extensions.py +42 -0
- package/tools/browser_camofox.py +700 -0
- package/tools/browser_camofox_state.py +48 -0
- package/tools/browser_cdp_tool.py +569 -0
- package/tools/browser_dialog_tool.py +148 -0
- package/tools/browser_providers/__init__.py +10 -0
- package/tools/browser_providers/__pycache__/__init__.cpython-312.pyc +0 -0
- package/tools/browser_providers/__pycache__/base.cpython-312.pyc +0 -0
- package/tools/browser_providers/__pycache__/browser_use.cpython-312.pyc +0 -0
- package/tools/browser_providers/__pycache__/browserbase.cpython-312.pyc +0 -0
- package/tools/browser_providers/__pycache__/firecrawl.cpython-312.pyc +0 -0
- package/tools/browser_providers/base.py +59 -0
- package/tools/browser_providers/browser_use.py +225 -0
- package/tools/browser_providers/browserbase.py +222 -0
- package/tools/browser_providers/firecrawl.py +112 -0
- package/tools/browser_supervisor.py +1457 -0
- package/tools/browser_tool.py +3676 -0
- package/tools/budget_config.py +51 -0
- package/tools/checkpoint_manager.py +1639 -0
- package/tools/clarify_gateway.py +278 -0
- package/tools/clarify_tool.py +141 -0
- package/tools/code_execution_tool.py +1782 -0
- package/tools/computer_use/__init__.py +43 -0
- package/tools/computer_use/__pycache__/__init__.cpython-312.pyc +0 -0
- package/tools/computer_use/__pycache__/backend.cpython-312.pyc +0 -0
- package/tools/computer_use/__pycache__/schema.cpython-312.pyc +0 -0
- package/tools/computer_use/__pycache__/tool.cpython-312.pyc +0 -0
- package/tools/computer_use/backend.py +150 -0
- package/tools/computer_use/cua_backend.py +682 -0
- package/tools/computer_use/schema.py +191 -0
- package/tools/computer_use/tool.py +521 -0
- package/tools/computer_use_tool.py +39 -0
- package/tools/credential_files.py +437 -0
- package/tools/cronjob_tools.py +719 -0
- package/tools/debug_helpers.py +106 -0
- package/tools/delegate_tool.py +2797 -0
- package/tools/discord_tool.py +959 -0
- package/tools/env_passthrough.py +145 -0
- package/tools/environments/__init__.py +14 -0
- package/tools/environments/__pycache__/__init__.cpython-312.pyc +0 -0
- package/tools/environments/__pycache__/base.cpython-312.pyc +0 -0
- package/tools/environments/__pycache__/docker.cpython-312.pyc +0 -0
- package/tools/environments/__pycache__/file_sync.cpython-312.pyc +0 -0
- package/tools/environments/__pycache__/local.cpython-312.pyc +0 -0
- package/tools/environments/__pycache__/managed_modal.cpython-312.pyc +0 -0
- package/tools/environments/__pycache__/modal.cpython-312.pyc +0 -0
- package/tools/environments/__pycache__/modal_utils.cpython-312.pyc +0 -0
- package/tools/environments/__pycache__/singularity.cpython-312.pyc +0 -0
- package/tools/environments/__pycache__/ssh.cpython-312.pyc +0 -0
- package/tools/environments/base.py +844 -0
- package/tools/environments/daytona.py +270 -0
- package/tools/environments/docker.py +656 -0
- package/tools/environments/file_sync.py +400 -0
- package/tools/environments/local.py +658 -0
- package/tools/environments/managed_modal.py +282 -0
- package/tools/environments/modal.py +479 -0
- package/tools/environments/modal_utils.py +199 -0
- package/tools/environments/singularity.py +263 -0
- package/tools/environments/ssh.py +295 -0
- package/tools/environments/vercel_sandbox.py +655 -0
- package/tools/feishu_doc_tool.py +138 -0
- package/tools/feishu_drive_tool.py +431 -0
- package/tools/file_operations.py +1825 -0
- package/tools/file_state.py +332 -0
- package/tools/file_tools.py +1172 -0
- package/tools/fuzzy_match.py +703 -0
- package/tools/homeassistant_tool.py +513 -0
- package/tools/image_generation_tool.py +1098 -0
- package/tools/interrupt.py +98 -0
- package/tools/kanban_tools.py +1139 -0
- package/tools/lazy_deps.py +608 -0
- package/tools/managed_tool_gateway.py +168 -0
- package/tools/mcp_oauth.py +633 -0
- package/tools/mcp_oauth_manager.py +607 -0
- package/tools/mcp_tool.py +3483 -0
- package/tools/memory_tool.py +584 -0
- package/tools/microsoft_graph_auth.py +245 -0
- package/tools/microsoft_graph_client.py +408 -0
- package/tools/mixture_of_agents_tool.py +542 -0
- package/tools/neutts_samples/jo.txt +1 -0
- package/tools/neutts_samples/jo.wav +0 -0
- package/tools/neutts_synth.py +104 -0
- package/tools/openrouter_client.py +33 -0
- package/tools/osv_check.py +155 -0
- package/tools/patch_parser.py +592 -0
- package/tools/path_security.py +43 -0
- package/tools/process_registry.py +1534 -0
- package/tools/registry.py +589 -0
- package/tools/schema_sanitizer.py +370 -0
- package/tools/send_message_tool.py +1900 -0
- package/tools/session_search_tool.py +613 -0
- package/tools/skill_manager_tool.py +932 -0
- package/tools/skill_provenance.py +78 -0
- package/tools/skill_usage.py +610 -0
- package/tools/skills_guard.py +932 -0
- package/tools/skills_hub.py +3263 -0
- package/tools/skills_sync.py +432 -0
- package/tools/skills_tool.py +1569 -0
- package/tools/slash_confirm.py +167 -0
- package/tools/terminal_tool.py +2376 -0
- package/tools/tirith_security.py +775 -0
- package/tools/todo_tool.py +277 -0
- package/tools/tool_backend_helpers.py +144 -0
- package/tools/tool_output_limits.py +92 -0
- package/tools/tool_result_storage.py +232 -0
- package/tools/transcription_tools.py +936 -0
- package/tools/tts_tool.py +2285 -0
- package/tools/url_safety.py +330 -0
- package/tools/video_generation_tool.py +561 -0
- package/tools/vision_tools.py +1422 -0
- package/tools/voice_mode.py +1019 -0
- package/tools/web_tools.py +1551 -0
- package/tools/website_policy.py +283 -0
- package/tools/x_search_tool.py +424 -0
- package/tools/xai_http.py +83 -0
- package/tools/yuanbao_tools.py +736 -0
- package/toolset_distributions.py +364 -0
- package/toolsets.py +866 -0
- package/trajectory_compressor.py +1509 -0
- package/tui_gateway/__init__.py +0 -0
- package/tui_gateway/entry.py +251 -0
- package/tui_gateway/event_publisher.py +126 -0
- package/tui_gateway/render.py +49 -0
- package/tui_gateway/server.py +6623 -0
- package/tui_gateway/slash_worker.py +76 -0
- package/tui_gateway/transport.py +219 -0
- package/tui_gateway/ws.py +178 -0
- package/utils.py +361 -0
|
@@ -0,0 +1,1863 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Doctor command for hermes CLI.
|
|
3
|
+
|
|
4
|
+
Diagnoses issues with Hermes Agent setup.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
import subprocess
|
|
10
|
+
import shutil
|
|
11
|
+
import importlib.util
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
from hermes_cli.config import get_project_root, get_hermes_home, get_env_path
|
|
15
|
+
from hermes_cli.env_loader import load_hermes_dotenv
|
|
16
|
+
from calvyn_constants import display_hermes_home
|
|
17
|
+
|
|
18
|
+
PROJECT_ROOT = get_project_root()
|
|
19
|
+
HERMES_HOME = get_hermes_home()
|
|
20
|
+
_DHH = display_hermes_home() # user-facing display path (e.g. ~/.hermes or ~/.hermes/profiles/coder)
|
|
21
|
+
|
|
22
|
+
# Load environment variables from ~/.hermes/.env so API key checks work
|
|
23
|
+
_env_path = get_env_path()
|
|
24
|
+
load_hermes_dotenv(hermes_home=_env_path.parent, project_env=PROJECT_ROOT / ".env")
|
|
25
|
+
|
|
26
|
+
from hermes_cli.colors import Colors, color
|
|
27
|
+
from hermes_cli.models import _HERMES_USER_AGENT
|
|
28
|
+
from hermes_cli.vercel_auth import describe_vercel_auth
|
|
29
|
+
from calvyn_constants import OPENROUTER_MODELS_URL
|
|
30
|
+
from utils import base_url_host_matches
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
_PROVIDER_ENV_HINTS = (
|
|
34
|
+
"OPENROUTER_API_KEY",
|
|
35
|
+
"OPENAI_API_KEY",
|
|
36
|
+
"ANTHROPIC_API_KEY",
|
|
37
|
+
"ANTHROPIC_TOKEN",
|
|
38
|
+
"OPENAI_BASE_URL",
|
|
39
|
+
"NOUS_API_KEY",
|
|
40
|
+
"GLM_API_KEY",
|
|
41
|
+
"ZAI_API_KEY",
|
|
42
|
+
"Z_AI_API_KEY",
|
|
43
|
+
"KIMI_API_KEY",
|
|
44
|
+
"KIMI_CN_API_KEY",
|
|
45
|
+
"GMI_API_KEY",
|
|
46
|
+
"MINIMAX_API_KEY",
|
|
47
|
+
"MINIMAX_CN_API_KEY",
|
|
48
|
+
"KILOCODE_API_KEY",
|
|
49
|
+
"DEEPSEEK_API_KEY",
|
|
50
|
+
"DASHSCOPE_API_KEY",
|
|
51
|
+
"HF_TOKEN",
|
|
52
|
+
"AI_GATEWAY_API_KEY",
|
|
53
|
+
"OPENCODE_ZEN_API_KEY",
|
|
54
|
+
"OPENCODE_GO_API_KEY",
|
|
55
|
+
"XIAOMI_API_KEY",
|
|
56
|
+
"TOKENHUB_API_KEY",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
from calvyn_constants import is_termux as _is_termux
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _python_install_cmd() -> str:
|
|
64
|
+
return "python -m pip install" if _is_termux() else "uv pip install"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _system_package_install_cmd(pkg: str) -> str:
|
|
68
|
+
if _is_termux():
|
|
69
|
+
return f"pkg install {pkg}"
|
|
70
|
+
if sys.platform == "darwin":
|
|
71
|
+
return f"brew install {pkg}"
|
|
72
|
+
return f"sudo apt install {pkg}"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _safe_which(cmd: str) -> str | None:
|
|
76
|
+
"""shutil.which wrapper resilient to platform monkeypatching in tests."""
|
|
77
|
+
try:
|
|
78
|
+
return shutil.which(cmd)
|
|
79
|
+
except Exception:
|
|
80
|
+
return None
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _termux_browser_setup_steps(node_installed: bool) -> list[str]:
|
|
84
|
+
steps: list[str] = []
|
|
85
|
+
step = 1
|
|
86
|
+
if not node_installed:
|
|
87
|
+
steps.append(f"{step}) pkg install nodejs")
|
|
88
|
+
step += 1
|
|
89
|
+
steps.append(f"{step}) npm install -g agent-browser")
|
|
90
|
+
steps.append(f"{step + 1}) agent-browser install")
|
|
91
|
+
return steps
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _termux_install_all_fallback_notes() -> list[str]:
|
|
95
|
+
return [
|
|
96
|
+
"Termux install profile: use .[termux-all] for broad compatibility (installer default on Termux).",
|
|
97
|
+
"Matrix E2EE extra is excluded on Termux (python-olm currently fails to build).",
|
|
98
|
+
"Local faster-whisper extra is excluded on Termux (ctranslate2/av build path unavailable).",
|
|
99
|
+
"STT fallback: use Groq Whisper (set GROQ_API_KEY) or OpenAI Whisper (set VOICE_TOOLS_OPENAI_KEY).",
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _has_provider_env_config(content: str) -> bool:
|
|
104
|
+
"""Return True when ~/.hermes/.env contains provider auth/base URL settings."""
|
|
105
|
+
return any(key in content for key in _PROVIDER_ENV_HINTS)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _honcho_is_configured_for_doctor() -> bool:
|
|
109
|
+
"""Return True when Honcho is configured, even if this process has no active session."""
|
|
110
|
+
try:
|
|
111
|
+
from plugins.memory.honcho.client import HonchoClientConfig
|
|
112
|
+
|
|
113
|
+
cfg = HonchoClientConfig.from_global_config()
|
|
114
|
+
return bool(cfg.enabled and (cfg.api_key or cfg.base_url))
|
|
115
|
+
except Exception:
|
|
116
|
+
return False
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _is_kanban_worker_env_gate(item: dict) -> bool:
|
|
120
|
+
"""Return True when Kanban is unavailable only because this is not a worker process."""
|
|
121
|
+
if item.get("name") != "kanban":
|
|
122
|
+
return False
|
|
123
|
+
if os.environ.get("HERMES_KANBAN_TASK"):
|
|
124
|
+
return False
|
|
125
|
+
|
|
126
|
+
tools = item.get("tools") or []
|
|
127
|
+
return bool(tools) and all(str(tool).startswith("kanban_") for tool in tools)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _doctor_tool_availability_detail(toolset: str) -> str:
|
|
131
|
+
"""Optional explanatory suffix for toolsets whose doctor status needs context."""
|
|
132
|
+
if toolset == "kanban" and not os.environ.get("HERMES_KANBAN_TASK"):
|
|
133
|
+
return "(runtime-gated; loaded only for dispatcher-spawned workers)"
|
|
134
|
+
return ""
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _apply_doctor_tool_availability_overrides(available: list[str], unavailable: list[dict]) -> tuple[list[str], list[dict]]:
|
|
138
|
+
"""Adjust runtime-gated tool availability for doctor diagnostics."""
|
|
139
|
+
updated_available = list(available)
|
|
140
|
+
updated_unavailable = []
|
|
141
|
+
for item in unavailable:
|
|
142
|
+
name = item.get("name")
|
|
143
|
+
if _is_kanban_worker_env_gate(item):
|
|
144
|
+
if "kanban" not in updated_available:
|
|
145
|
+
updated_available.append("kanban")
|
|
146
|
+
continue
|
|
147
|
+
if name == "honcho" and _honcho_is_configured_for_doctor():
|
|
148
|
+
if "honcho" not in updated_available:
|
|
149
|
+
updated_available.append("honcho")
|
|
150
|
+
continue
|
|
151
|
+
updated_unavailable.append(item)
|
|
152
|
+
return updated_available, updated_unavailable
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _has_healthy_oauth_fallback_for_apikey_provider(provider_label: str) -> bool:
|
|
156
|
+
"""Return True when a direct API-key probe failure is non-blocking.
|
|
157
|
+
|
|
158
|
+
Some provider families support both a direct API-key path and a separate
|
|
159
|
+
OAuth runtime path. When the OAuth path is already healthy, doctor should
|
|
160
|
+
still show a failed API-key connectivity row, but it should not promote
|
|
161
|
+
that direct-key problem into the final blocking summary.
|
|
162
|
+
"""
|
|
163
|
+
try:
|
|
164
|
+
from hermes_cli.auth import (
|
|
165
|
+
get_gemini_oauth_auth_status,
|
|
166
|
+
get_minimax_oauth_auth_status,
|
|
167
|
+
)
|
|
168
|
+
except Exception:
|
|
169
|
+
return False
|
|
170
|
+
|
|
171
|
+
normalized = (provider_label or "").strip().lower()
|
|
172
|
+
if normalized in {"google / gemini", "gemini"}:
|
|
173
|
+
return bool((get_gemini_oauth_auth_status() or {}).get("logged_in"))
|
|
174
|
+
if normalized == "minimax":
|
|
175
|
+
return bool((get_minimax_oauth_auth_status() or {}).get("logged_in"))
|
|
176
|
+
return False
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def check_ok(text: str, detail: str = ""):
|
|
180
|
+
print(f" {color('✓', Colors.GREEN)} {text}" + (f" {color(detail, Colors.DIM)}" if detail else ""))
|
|
181
|
+
|
|
182
|
+
def check_warn(text: str, detail: str = ""):
|
|
183
|
+
print(f" {color('⚠', Colors.YELLOW)} {text}" + (f" {color(detail, Colors.DIM)}" if detail else ""))
|
|
184
|
+
|
|
185
|
+
def check_fail(text: str, detail: str = ""):
|
|
186
|
+
print(f" {color('✗', Colors.RED)} {text}" + (f" {color(detail, Colors.DIM)}" if detail else ""))
|
|
187
|
+
|
|
188
|
+
def check_info(text: str):
|
|
189
|
+
print(f" {color('→', Colors.CYAN)} {text}")
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _check_gateway_service_linger(issues: list[str]) -> None:
|
|
193
|
+
"""Warn when a systemd user gateway service will stop after logout."""
|
|
194
|
+
try:
|
|
195
|
+
from hermes_cli.gateway import (
|
|
196
|
+
get_systemd_linger_status,
|
|
197
|
+
get_systemd_unit_path,
|
|
198
|
+
is_linux,
|
|
199
|
+
)
|
|
200
|
+
except Exception as e:
|
|
201
|
+
check_warn("Gateway service linger", f"(could not import gateway helpers: {e})")
|
|
202
|
+
return
|
|
203
|
+
|
|
204
|
+
if not is_linux():
|
|
205
|
+
return
|
|
206
|
+
|
|
207
|
+
unit_path = get_systemd_unit_path()
|
|
208
|
+
if not unit_path.exists():
|
|
209
|
+
return
|
|
210
|
+
|
|
211
|
+
print()
|
|
212
|
+
print(color("◆ Gateway Service", Colors.CYAN, Colors.BOLD))
|
|
213
|
+
|
|
214
|
+
linger_enabled, linger_detail = get_systemd_linger_status()
|
|
215
|
+
if linger_enabled is True:
|
|
216
|
+
check_ok("Systemd linger enabled", "(gateway service survives logout)")
|
|
217
|
+
elif linger_enabled is False:
|
|
218
|
+
check_warn("Systemd linger disabled", "(gateway may stop after logout)")
|
|
219
|
+
check_info("Run: sudo loginctl enable-linger $USER")
|
|
220
|
+
issues.append("Enable linger for the gateway user service: sudo loginctl enable-linger $USER")
|
|
221
|
+
else:
|
|
222
|
+
check_warn("Could not verify systemd linger", f"({linger_detail})")
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
_APIKEY_PROVIDERS_CACHE: list | None = None
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def _build_apikey_providers_list() -> list:
|
|
229
|
+
"""Build the API-key provider health-check list once and cache it.
|
|
230
|
+
|
|
231
|
+
Tuple format: (name, env_vars, default_url, base_env, supports_models_endpoint)
|
|
232
|
+
Base list augmented with any ProviderProfile with auth_type="api_key" not
|
|
233
|
+
already present — adding plugins/model-providers/<name>/ is sufficient to get into doctor.
|
|
234
|
+
"""
|
|
235
|
+
_static = [
|
|
236
|
+
("Z.AI / GLM", ("GLM_API_KEY", "ZAI_API_KEY", "Z_AI_API_KEY"), "https://api.z.ai/api/paas/v4/models", "GLM_BASE_URL", True),
|
|
237
|
+
("Kimi / Moonshot", ("KIMI_API_KEY",), "https://api.moonshot.ai/v1/models", "KIMI_BASE_URL", True),
|
|
238
|
+
("StepFun Step Plan", ("STEPFUN_API_KEY",), "https://api.stepfun.ai/step_plan/v1/models", "STEPFUN_BASE_URL", True),
|
|
239
|
+
("Kimi / Moonshot (China)", ("KIMI_CN_API_KEY",), "https://api.moonshot.cn/v1/models", None, True),
|
|
240
|
+
("Arcee AI", ("ARCEEAI_API_KEY",), "https://api.arcee.ai/api/v1/models", "ARCEE_BASE_URL", True),
|
|
241
|
+
("GMI Cloud", ("GMI_API_KEY",), "https://api.gmi-serving.com/v1/models", "GMI_BASE_URL", True),
|
|
242
|
+
("DeepSeek", ("DEEPSEEK_API_KEY",), "https://api.deepseek.com/v1/models", "DEEPSEEK_BASE_URL", True),
|
|
243
|
+
("Hugging Face", ("HF_TOKEN",), "https://router.huggingface.co/v1/models", "HF_BASE_URL", True),
|
|
244
|
+
("NVIDIA NIM", ("NVIDIA_API_KEY",), "https://integrate.api.nvidia.com/v1/models", "NVIDIA_BASE_URL", True),
|
|
245
|
+
("Alibaba/DashScope", ("DASHSCOPE_API_KEY",), "https://dashscope-intl.aliyuncs.com/compatible-mode/v1/models", "DASHSCOPE_BASE_URL", True),
|
|
246
|
+
# MiniMax global: /v1 endpoint supports /models.
|
|
247
|
+
("MiniMax", ("MINIMAX_API_KEY",), "https://api.minimax.io/v1/models", "MINIMAX_BASE_URL", True),
|
|
248
|
+
# MiniMax CN: /v1 endpoint does NOT support /models (returns 404).
|
|
249
|
+
("MiniMax (China)", ("MINIMAX_CN_API_KEY",), "https://api.minimaxi.com/v1/models", "MINIMAX_CN_BASE_URL", False),
|
|
250
|
+
("Vercel AI Gateway", ("AI_GATEWAY_API_KEY",), "https://ai-gateway.vercel.sh/v1/models", "AI_GATEWAY_BASE_URL", True),
|
|
251
|
+
("Kilo Code", ("KILOCODE_API_KEY",), "https://api.kilo.ai/api/gateway/models", "KILOCODE_BASE_URL", True),
|
|
252
|
+
("OpenCode Zen", ("OPENCODE_ZEN_API_KEY",), "https://opencode.ai/zen/v1/models", "OPENCODE_ZEN_BASE_URL", True),
|
|
253
|
+
# OpenCode Go has no shared /models endpoint; skip the health check.
|
|
254
|
+
("OpenCode Go", ("OPENCODE_GO_API_KEY",), None, "OPENCODE_GO_BASE_URL", False),
|
|
255
|
+
]
|
|
256
|
+
_known_names = {t[0] for t in _static}
|
|
257
|
+
# Also index by profile canonical name so profiles without display_name
|
|
258
|
+
# don't create duplicate entries for providers already in the static list.
|
|
259
|
+
_known_canonical: set[str] = set()
|
|
260
|
+
_name_to_canonical = {
|
|
261
|
+
"Z.AI / GLM": "zai", "Kimi / Moonshot": "kimi-coding",
|
|
262
|
+
"StepFun Step Plan": "stepfun", "Kimi / Moonshot (China)": "kimi-coding-cn",
|
|
263
|
+
"Arcee AI": "arcee", "GMI Cloud": "gmi", "DeepSeek": "deepseek",
|
|
264
|
+
"Hugging Face": "huggingface", "NVIDIA NIM": "nvidia",
|
|
265
|
+
"Alibaba/DashScope": "alibaba", "MiniMax": "minimax",
|
|
266
|
+
"MiniMax (China)": "minimax-cn", "Vercel AI Gateway": "ai-gateway",
|
|
267
|
+
"Kilo Code": "kilocode", "OpenCode Zen": "opencode-zen",
|
|
268
|
+
"OpenCode Go": "opencode-go",
|
|
269
|
+
}
|
|
270
|
+
for _label, _canonical in _name_to_canonical.items():
|
|
271
|
+
_known_canonical.add(_canonical)
|
|
272
|
+
# Providers that already have a dedicated health check above the generic
|
|
273
|
+
# API-key loop (with custom headers/auth). Skip their pluggable profiles
|
|
274
|
+
# here so the generic Bearer-auth loop doesn't run a duplicate, broken
|
|
275
|
+
# check (e.g. Anthropic native API requires x-api-key, not Bearer).
|
|
276
|
+
_dedicated_canonical = {"anthropic", "openrouter", "bedrock"}
|
|
277
|
+
_known_canonical.update(_dedicated_canonical)
|
|
278
|
+
try:
|
|
279
|
+
from providers import list_providers
|
|
280
|
+
from providers.base import ProviderProfile as _PP
|
|
281
|
+
try:
|
|
282
|
+
from hermes_cli.providers import normalize_provider as _normalize_provider
|
|
283
|
+
except Exception: # pragma: no cover - normalization is best-effort
|
|
284
|
+
def _normalize_provider(_name: str) -> str:
|
|
285
|
+
return (_name or "").strip().lower()
|
|
286
|
+
for _pp in list_providers():
|
|
287
|
+
if not isinstance(_pp, _PP) or _pp.auth_type != "api_key" or not _pp.env_vars:
|
|
288
|
+
continue
|
|
289
|
+
_label = _pp.display_name or _pp.name
|
|
290
|
+
if _label in _known_names or _pp.name in _known_canonical:
|
|
291
|
+
continue
|
|
292
|
+
_candidates = {_normalize_provider(_pp.name)}
|
|
293
|
+
for _alias in (_pp.aliases or ()):
|
|
294
|
+
_candidates.add(_normalize_provider(_alias))
|
|
295
|
+
if _candidates & _dedicated_canonical:
|
|
296
|
+
continue
|
|
297
|
+
# Separate API-key vars from base-URL override vars — the health-check
|
|
298
|
+
# loop sends the first found value as Authorization: Bearer, so a URL
|
|
299
|
+
# string must never be picked.
|
|
300
|
+
_key_vars = tuple(
|
|
301
|
+
v for v in _pp.env_vars
|
|
302
|
+
if not v.endswith("_BASE_URL") and not v.endswith("_URL")
|
|
303
|
+
)
|
|
304
|
+
_base_var = next(
|
|
305
|
+
(v for v in _pp.env_vars if v.endswith("_BASE_URL") or v.endswith("_URL")),
|
|
306
|
+
None,
|
|
307
|
+
)
|
|
308
|
+
if not _key_vars:
|
|
309
|
+
continue
|
|
310
|
+
_models_url = (
|
|
311
|
+
(_pp.models_url or (_pp.base_url.rstrip("/") + "/models"))
|
|
312
|
+
if _pp.base_url else None
|
|
313
|
+
)
|
|
314
|
+
_hc = getattr(_pp, "supports_health_check", True)
|
|
315
|
+
_static.append((_label, _key_vars, _models_url, _base_var, _hc))
|
|
316
|
+
except Exception:
|
|
317
|
+
pass
|
|
318
|
+
return _static
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def run_doctor(args):
|
|
322
|
+
"""Run diagnostic checks."""
|
|
323
|
+
should_fix = getattr(args, 'fix', False)
|
|
324
|
+
ack_target = getattr(args, 'ack', None)
|
|
325
|
+
|
|
326
|
+
# Doctor runs from the interactive CLI, so CLI-gated tool availability
|
|
327
|
+
# checks (like cronjob management) should see the same context as `hermes`.
|
|
328
|
+
os.environ.setdefault("HERMES_INTERACTIVE", "1")
|
|
329
|
+
|
|
330
|
+
# Handle `hermes doctor --ack <id>` as a fast path. Persist the ack and
|
|
331
|
+
# return without running the rest of the diagnostics — the user has
|
|
332
|
+
# already seen the advisory and just wants to silence it.
|
|
333
|
+
if ack_target:
|
|
334
|
+
from hermes_cli.security_advisories import (
|
|
335
|
+
ADVISORIES,
|
|
336
|
+
ack_advisory,
|
|
337
|
+
)
|
|
338
|
+
valid_ids = {a.id for a in ADVISORIES}
|
|
339
|
+
if ack_target not in valid_ids:
|
|
340
|
+
print(color(
|
|
341
|
+
f"Unknown advisory ID: {ack_target!r}. Known IDs: "
|
|
342
|
+
f"{', '.join(sorted(valid_ids)) or '(none)'}",
|
|
343
|
+
Colors.RED,
|
|
344
|
+
))
|
|
345
|
+
sys.exit(2)
|
|
346
|
+
if ack_advisory(ack_target):
|
|
347
|
+
print(color(
|
|
348
|
+
f" ✓ Acknowledged advisory {ack_target}. "
|
|
349
|
+
f"It will no longer trigger startup banners.",
|
|
350
|
+
Colors.GREEN,
|
|
351
|
+
))
|
|
352
|
+
else:
|
|
353
|
+
print(color(
|
|
354
|
+
f" ✗ Failed to persist ack for {ack_target}. "
|
|
355
|
+
f"Check ~/.hermes/config.yaml is writable.",
|
|
356
|
+
Colors.RED,
|
|
357
|
+
))
|
|
358
|
+
sys.exit(1)
|
|
359
|
+
return
|
|
360
|
+
|
|
361
|
+
issues = []
|
|
362
|
+
manual_issues = [] # issues that can't be auto-fixed
|
|
363
|
+
fixed_count = 0
|
|
364
|
+
|
|
365
|
+
print()
|
|
366
|
+
print(color("┌─────────────────────────────────────────────────────────┐", Colors.CYAN))
|
|
367
|
+
print(color("│ 🩺 Hermes Doctor │", Colors.CYAN))
|
|
368
|
+
print(color("└─────────────────────────────────────────────────────────┘", Colors.CYAN))
|
|
369
|
+
|
|
370
|
+
# =========================================================================
|
|
371
|
+
# Check: Security advisories (RUNS FIRST — these are the most urgent)
|
|
372
|
+
# =========================================================================
|
|
373
|
+
print()
|
|
374
|
+
print(color("◆ Security Advisories", Colors.CYAN, Colors.BOLD))
|
|
375
|
+
try:
|
|
376
|
+
from hermes_cli.security_advisories import (
|
|
377
|
+
detect_compromised,
|
|
378
|
+
filter_unacked,
|
|
379
|
+
full_remediation_text,
|
|
380
|
+
get_acked_ids,
|
|
381
|
+
)
|
|
382
|
+
all_hits = detect_compromised()
|
|
383
|
+
fresh_hits = filter_unacked(all_hits)
|
|
384
|
+
if fresh_hits:
|
|
385
|
+
for hit in fresh_hits:
|
|
386
|
+
check_fail(
|
|
387
|
+
f"{hit.advisory.title}",
|
|
388
|
+
f"({hit.package}=={hit.installed_version})",
|
|
389
|
+
)
|
|
390
|
+
# Print the full remediation block, indented under the
|
|
391
|
+
# check_fail header so it reads as a single section.
|
|
392
|
+
for line in full_remediation_text(hit):
|
|
393
|
+
if line:
|
|
394
|
+
print(f" {color(line, Colors.YELLOW)}")
|
|
395
|
+
else:
|
|
396
|
+
print()
|
|
397
|
+
# Funnel into the action list so the summary block surfaces it
|
|
398
|
+
# for users who scroll past the section.
|
|
399
|
+
manual_issues.append(
|
|
400
|
+
f"Resolve security advisory {hit.advisory.id}: "
|
|
401
|
+
f"uninstall {hit.package}=={hit.installed_version} and "
|
|
402
|
+
f"rotate credentials, then run "
|
|
403
|
+
f"`hermes doctor --ack {hit.advisory.id}`."
|
|
404
|
+
)
|
|
405
|
+
# Acked-but-still-installed: show as informational so the user
|
|
406
|
+
# knows the package is still on disk after the ack.
|
|
407
|
+
acked_ids = get_acked_ids()
|
|
408
|
+
for h in all_hits:
|
|
409
|
+
if h.advisory.id in acked_ids:
|
|
410
|
+
check_warn(
|
|
411
|
+
f"{h.package}=={h.installed_version} still installed "
|
|
412
|
+
f"(advisory {h.advisory.id} acknowledged)",
|
|
413
|
+
)
|
|
414
|
+
else:
|
|
415
|
+
check_ok("No active security advisories")
|
|
416
|
+
except Exception as e:
|
|
417
|
+
# Never let a bug in the advisory check block the rest of doctor.
|
|
418
|
+
check_warn(f"Security advisory check failed: {e}")
|
|
419
|
+
|
|
420
|
+
# =========================================================================
|
|
421
|
+
# Check: Python version
|
|
422
|
+
# =========================================================================
|
|
423
|
+
print()
|
|
424
|
+
print(color("◆ Python Environment", Colors.CYAN, Colors.BOLD))
|
|
425
|
+
|
|
426
|
+
py_version = sys.version_info
|
|
427
|
+
if py_version >= (3, 11):
|
|
428
|
+
check_ok(f"Python {py_version.major}.{py_version.minor}.{py_version.micro}")
|
|
429
|
+
elif py_version >= (3, 10):
|
|
430
|
+
check_ok(f"Python {py_version.major}.{py_version.minor}.{py_version.micro}")
|
|
431
|
+
check_warn("Python 3.11+ recommended for RL Training tools (tinker requires >= 3.11)")
|
|
432
|
+
elif py_version >= (3, 8):
|
|
433
|
+
check_warn(f"Python {py_version.major}.{py_version.minor}.{py_version.micro}", "(3.10+ recommended)")
|
|
434
|
+
else:
|
|
435
|
+
check_fail(f"Python {py_version.major}.{py_version.minor}.{py_version.micro}", "(3.10+ required)")
|
|
436
|
+
issues.append("Upgrade Python to 3.10+")
|
|
437
|
+
|
|
438
|
+
# Check if in virtual environment
|
|
439
|
+
in_venv = sys.prefix != sys.base_prefix
|
|
440
|
+
if in_venv:
|
|
441
|
+
check_ok("Virtual environment active")
|
|
442
|
+
else:
|
|
443
|
+
check_warn("Not in virtual environment", "(recommended)")
|
|
444
|
+
|
|
445
|
+
# =========================================================================
|
|
446
|
+
# Check: Required packages
|
|
447
|
+
# =========================================================================
|
|
448
|
+
print()
|
|
449
|
+
print(color("◆ Required Packages", Colors.CYAN, Colors.BOLD))
|
|
450
|
+
|
|
451
|
+
required_packages = [
|
|
452
|
+
("openai", "OpenAI SDK"),
|
|
453
|
+
("rich", "Rich (terminal UI)"),
|
|
454
|
+
("dotenv", "python-dotenv"),
|
|
455
|
+
("yaml", "PyYAML"),
|
|
456
|
+
("httpx", "HTTPX"),
|
|
457
|
+
]
|
|
458
|
+
|
|
459
|
+
optional_packages = [
|
|
460
|
+
("croniter", "Croniter (cron expressions)"),
|
|
461
|
+
("telegram", "python-telegram-bot"),
|
|
462
|
+
("discord", "discord.py"),
|
|
463
|
+
]
|
|
464
|
+
|
|
465
|
+
for module, name in required_packages:
|
|
466
|
+
try:
|
|
467
|
+
__import__(module)
|
|
468
|
+
check_ok(name)
|
|
469
|
+
except ImportError:
|
|
470
|
+
check_fail(name, "(missing)")
|
|
471
|
+
issues.append(f"Install {name}: {_python_install_cmd()} {module}")
|
|
472
|
+
|
|
473
|
+
for module, name in optional_packages:
|
|
474
|
+
try:
|
|
475
|
+
__import__(module)
|
|
476
|
+
check_ok(name, "(optional)")
|
|
477
|
+
except ImportError:
|
|
478
|
+
check_warn(name, "(optional, not installed)")
|
|
479
|
+
|
|
480
|
+
# =========================================================================
|
|
481
|
+
# Check: Configuration files
|
|
482
|
+
# =========================================================================
|
|
483
|
+
print()
|
|
484
|
+
print(color("◆ Configuration Files", Colors.CYAN, Colors.BOLD))
|
|
485
|
+
|
|
486
|
+
# Check ~/.hermes/.env (primary location for user config)
|
|
487
|
+
env_path = HERMES_HOME / '.env'
|
|
488
|
+
if env_path.exists():
|
|
489
|
+
check_ok(f"{_DHH}/.env file exists")
|
|
490
|
+
|
|
491
|
+
# Check for common issues. Pin encoding to UTF-8 because .env files are
|
|
492
|
+
# written as UTF-8 everywhere in the codebase, while Path.read_text()
|
|
493
|
+
# defaults to the system locale — which crashes on non-UTF-8 Windows
|
|
494
|
+
# locales (e.g. GBK) as soon as the file contains any non-ASCII byte.
|
|
495
|
+
content = env_path.read_text(encoding="utf-8")
|
|
496
|
+
if _has_provider_env_config(content):
|
|
497
|
+
check_ok("API key or custom endpoint configured")
|
|
498
|
+
else:
|
|
499
|
+
check_warn(f"No API key found in {_DHH}/.env")
|
|
500
|
+
issues.append("Run 'hermes setup' to configure API keys")
|
|
501
|
+
else:
|
|
502
|
+
# Also check project root as fallback
|
|
503
|
+
fallback_env = PROJECT_ROOT / '.env'
|
|
504
|
+
if fallback_env.exists():
|
|
505
|
+
check_ok(".env file exists (in project directory)")
|
|
506
|
+
else:
|
|
507
|
+
check_fail(f"{_DHH}/.env file missing")
|
|
508
|
+
if should_fix:
|
|
509
|
+
env_path.parent.mkdir(parents=True, exist_ok=True)
|
|
510
|
+
env_path.touch()
|
|
511
|
+
check_ok(f"Created empty {_DHH}/.env")
|
|
512
|
+
check_info("Run 'hermes setup' to configure API keys")
|
|
513
|
+
fixed_count += 1
|
|
514
|
+
else:
|
|
515
|
+
check_info("Run 'hermes setup' to create one")
|
|
516
|
+
issues.append("Run 'hermes setup' to create .env")
|
|
517
|
+
|
|
518
|
+
# Check ~/.hermes/config.yaml (primary) or project cli-config.yaml (fallback)
|
|
519
|
+
config_path = HERMES_HOME / 'config.yaml'
|
|
520
|
+
if config_path.exists():
|
|
521
|
+
check_ok(f"{_DHH}/config.yaml exists")
|
|
522
|
+
|
|
523
|
+
# Validate model.provider and model.default values
|
|
524
|
+
try:
|
|
525
|
+
import yaml as _yaml
|
|
526
|
+
cfg = _yaml.safe_load(config_path.read_text(encoding="utf-8")) or {}
|
|
527
|
+
model_section = cfg.get("model") or {}
|
|
528
|
+
provider_raw = (model_section.get("provider") or "").strip()
|
|
529
|
+
provider = provider_raw.lower()
|
|
530
|
+
default_model = (model_section.get("default") or model_section.get("model") or "").strip()
|
|
531
|
+
|
|
532
|
+
known_providers: set = set()
|
|
533
|
+
try:
|
|
534
|
+
from hermes_cli.auth import (
|
|
535
|
+
PROVIDER_REGISTRY,
|
|
536
|
+
resolve_provider as _resolve_auth_provider,
|
|
537
|
+
)
|
|
538
|
+
known_providers = set(PROVIDER_REGISTRY.keys()) | {"openrouter", "custom", "auto"}
|
|
539
|
+
except Exception:
|
|
540
|
+
_resolve_auth_provider = None
|
|
541
|
+
pass
|
|
542
|
+
try:
|
|
543
|
+
from hermes_cli.config import get_compatible_custom_providers as _compatible_custom_providers
|
|
544
|
+
from hermes_cli.providers import (
|
|
545
|
+
normalize_provider as _normalize_catalog_provider,
|
|
546
|
+
resolve_provider_full as _resolve_provider_full,
|
|
547
|
+
)
|
|
548
|
+
except Exception:
|
|
549
|
+
_compatible_custom_providers = None
|
|
550
|
+
_normalize_catalog_provider = None
|
|
551
|
+
_resolve_provider_full = None
|
|
552
|
+
|
|
553
|
+
custom_providers = []
|
|
554
|
+
if _compatible_custom_providers is not None:
|
|
555
|
+
try:
|
|
556
|
+
custom_providers = _compatible_custom_providers(cfg)
|
|
557
|
+
except Exception:
|
|
558
|
+
custom_providers = []
|
|
559
|
+
|
|
560
|
+
user_providers = cfg.get("providers")
|
|
561
|
+
if isinstance(user_providers, dict):
|
|
562
|
+
known_providers.update(str(name).strip().lower() for name in user_providers if str(name).strip())
|
|
563
|
+
for entry in custom_providers:
|
|
564
|
+
if not isinstance(entry, dict):
|
|
565
|
+
continue
|
|
566
|
+
name = str(entry.get("name") or "").strip()
|
|
567
|
+
if name:
|
|
568
|
+
known_providers.add("custom:" + name.lower().replace(" ", "-"))
|
|
569
|
+
|
|
570
|
+
valid_provider_ids = set(known_providers)
|
|
571
|
+
provider_ids_to_accept = {provider} if provider else set()
|
|
572
|
+
if _normalize_catalog_provider is not None:
|
|
573
|
+
for known_provider in known_providers:
|
|
574
|
+
try:
|
|
575
|
+
valid_provider_ids.add(_normalize_catalog_provider(known_provider))
|
|
576
|
+
except Exception:
|
|
577
|
+
continue
|
|
578
|
+
|
|
579
|
+
runtime_provider = provider
|
|
580
|
+
if (
|
|
581
|
+
provider
|
|
582
|
+
and _resolve_auth_provider is not None
|
|
583
|
+
and provider not in {"auto", "custom"}
|
|
584
|
+
):
|
|
585
|
+
try:
|
|
586
|
+
runtime_provider = _resolve_auth_provider(provider)
|
|
587
|
+
provider_ids_to_accept.add(runtime_provider)
|
|
588
|
+
except Exception:
|
|
589
|
+
runtime_provider = provider
|
|
590
|
+
|
|
591
|
+
catalog_provider = provider
|
|
592
|
+
if (
|
|
593
|
+
provider
|
|
594
|
+
and _resolve_provider_full is not None
|
|
595
|
+
and provider not in {"auto", "custom"}
|
|
596
|
+
):
|
|
597
|
+
provider_def = _resolve_provider_full(provider, user_providers, custom_providers)
|
|
598
|
+
catalog_provider = provider_def.id if provider_def is not None else None
|
|
599
|
+
if catalog_provider is not None:
|
|
600
|
+
provider_ids_to_accept.add(catalog_provider)
|
|
601
|
+
|
|
602
|
+
if provider and provider != "auto":
|
|
603
|
+
if catalog_provider is None or (
|
|
604
|
+
known_providers
|
|
605
|
+
and not (provider_ids_to_accept & valid_provider_ids)
|
|
606
|
+
):
|
|
607
|
+
known_list = ", ".join(sorted(known_providers)) if known_providers else "(unavailable)"
|
|
608
|
+
check_fail(
|
|
609
|
+
f"model.provider '{provider_raw}' is not a recognised provider",
|
|
610
|
+
f"(known: {known_list})",
|
|
611
|
+
)
|
|
612
|
+
issues.append(
|
|
613
|
+
f"model.provider '{provider_raw}' is unknown. "
|
|
614
|
+
f"Valid providers: {known_list}. "
|
|
615
|
+
f"Fix: run 'hermes config set model.provider <valid_provider>'"
|
|
616
|
+
)
|
|
617
|
+
|
|
618
|
+
# Warn if model is set to a provider-prefixed name on a provider that doesn't use them
|
|
619
|
+
provider_for_policy = runtime_provider or catalog_provider
|
|
620
|
+
providers_accepting_vendor_slugs = {
|
|
621
|
+
"openrouter",
|
|
622
|
+
"custom",
|
|
623
|
+
"auto",
|
|
624
|
+
"ai-gateway",
|
|
625
|
+
"kilocode",
|
|
626
|
+
"opencode-zen",
|
|
627
|
+
"huggingface",
|
|
628
|
+
"lmstudio",
|
|
629
|
+
"nous",
|
|
630
|
+
}
|
|
631
|
+
if (
|
|
632
|
+
default_model
|
|
633
|
+
and "/" in default_model
|
|
634
|
+
and provider_for_policy
|
|
635
|
+
and provider_for_policy not in providers_accepting_vendor_slugs
|
|
636
|
+
):
|
|
637
|
+
check_warn(
|
|
638
|
+
f"model.default '{default_model}' uses a vendor/model slug but provider is '{provider_raw}'",
|
|
639
|
+
"(vendor-prefixed slugs belong to aggregators like openrouter)",
|
|
640
|
+
)
|
|
641
|
+
issues.append(
|
|
642
|
+
f"model.default '{default_model}' is vendor-prefixed but model.provider is '{provider_raw}'. "
|
|
643
|
+
"Either set model.provider to 'openrouter', or drop the vendor prefix."
|
|
644
|
+
)
|
|
645
|
+
|
|
646
|
+
# Check credentials for the configured provider.
|
|
647
|
+
# Limit to API-key providers in PROVIDER_REGISTRY — other provider
|
|
648
|
+
# types (OAuth, SDK, openrouter/anthropic/custom/auto) have their
|
|
649
|
+
# own env-var checks elsewhere in doctor, and get_auth_status()
|
|
650
|
+
# returns a bare {logged_in: False} for anything it doesn't
|
|
651
|
+
# explicitly dispatch, which would produce false positives.
|
|
652
|
+
if runtime_provider and runtime_provider not in {"auto", "custom", "openrouter"}:
|
|
653
|
+
try:
|
|
654
|
+
from hermes_cli.auth import PROVIDER_REGISTRY, get_auth_status
|
|
655
|
+
pconfig = PROVIDER_REGISTRY.get(runtime_provider)
|
|
656
|
+
if pconfig and getattr(pconfig, "auth_type", "") == "api_key":
|
|
657
|
+
status = get_auth_status(runtime_provider) or {}
|
|
658
|
+
configured = bool(
|
|
659
|
+
status.get("configured")
|
|
660
|
+
or status.get("logged_in")
|
|
661
|
+
or status.get("api_key")
|
|
662
|
+
)
|
|
663
|
+
if not configured:
|
|
664
|
+
check_fail(
|
|
665
|
+
f"model.provider '{runtime_provider}' is set but no API key is configured",
|
|
666
|
+
"(check ~/.hermes/.env or run 'hermes setup')",
|
|
667
|
+
)
|
|
668
|
+
issues.append(
|
|
669
|
+
f"No credentials found for provider '{runtime_provider}'. "
|
|
670
|
+
f"Run 'hermes setup' or set the provider's API key in {_DHH}/.env, "
|
|
671
|
+
f"or switch providers with 'hermes config set model.provider <name>'"
|
|
672
|
+
)
|
|
673
|
+
except Exception:
|
|
674
|
+
pass
|
|
675
|
+
|
|
676
|
+
except Exception as e:
|
|
677
|
+
check_warn("Could not validate model/provider config", f"({e})")
|
|
678
|
+
else:
|
|
679
|
+
fallback_config = PROJECT_ROOT / 'cli-config.yaml'
|
|
680
|
+
if fallback_config.exists():
|
|
681
|
+
check_ok("cli-config.yaml exists (in project directory)")
|
|
682
|
+
else:
|
|
683
|
+
if should_fix:
|
|
684
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
685
|
+
example_config = PROJECT_ROOT / 'cli-config.yaml.example'
|
|
686
|
+
if example_config.exists():
|
|
687
|
+
shutil.copy2(str(example_config), str(config_path))
|
|
688
|
+
check_ok(f"Created {_DHH}/config.yaml from cli-config.yaml.example")
|
|
689
|
+
else:
|
|
690
|
+
from hermes_cli.config import DEFAULT_CONFIG, save_config
|
|
691
|
+
save_config(DEFAULT_CONFIG)
|
|
692
|
+
check_ok(f"Created {_DHH}/config.yaml from defaults")
|
|
693
|
+
fixed_count += 1
|
|
694
|
+
else:
|
|
695
|
+
check_warn("config.yaml not found", "(using defaults)")
|
|
696
|
+
|
|
697
|
+
# Check config version and stale keys
|
|
698
|
+
config_path = HERMES_HOME / 'config.yaml'
|
|
699
|
+
if config_path.exists():
|
|
700
|
+
try:
|
|
701
|
+
from hermes_cli.config import check_config_version, migrate_config
|
|
702
|
+
current_ver, latest_ver = check_config_version()
|
|
703
|
+
if current_ver < latest_ver:
|
|
704
|
+
check_warn(
|
|
705
|
+
f"Config version outdated (v{current_ver} → v{latest_ver})",
|
|
706
|
+
"(new settings available)"
|
|
707
|
+
)
|
|
708
|
+
if should_fix:
|
|
709
|
+
try:
|
|
710
|
+
migrate_config(interactive=False, quiet=False)
|
|
711
|
+
check_ok("Config migrated to latest version")
|
|
712
|
+
fixed_count += 1
|
|
713
|
+
except Exception as mig_err:
|
|
714
|
+
check_warn(f"Auto-migration failed: {mig_err}")
|
|
715
|
+
issues.append("Run 'hermes setup' to migrate config")
|
|
716
|
+
else:
|
|
717
|
+
issues.append("Run 'hermes doctor --fix' or 'hermes setup' to migrate config")
|
|
718
|
+
else:
|
|
719
|
+
check_ok(f"Config version up to date (v{current_ver})")
|
|
720
|
+
except Exception:
|
|
721
|
+
pass
|
|
722
|
+
|
|
723
|
+
# Detect stale root-level model keys (known bug source — PR #4329)
|
|
724
|
+
try:
|
|
725
|
+
import yaml
|
|
726
|
+
with open(config_path, encoding="utf-8") as f:
|
|
727
|
+
raw_config = yaml.safe_load(f) or {}
|
|
728
|
+
stale_root_keys = [k for k in ("provider", "base_url") if k in raw_config and isinstance(raw_config[k], str)]
|
|
729
|
+
if stale_root_keys:
|
|
730
|
+
check_warn(
|
|
731
|
+
f"Stale root-level config keys: {', '.join(stale_root_keys)}",
|
|
732
|
+
"(should be under 'model:' section)"
|
|
733
|
+
)
|
|
734
|
+
if should_fix:
|
|
735
|
+
model_section = raw_config.setdefault("model", {})
|
|
736
|
+
for k in stale_root_keys:
|
|
737
|
+
if not model_section.get(k):
|
|
738
|
+
model_section[k] = raw_config.pop(k)
|
|
739
|
+
else:
|
|
740
|
+
raw_config.pop(k)
|
|
741
|
+
from utils import atomic_yaml_write
|
|
742
|
+
atomic_yaml_write(config_path, raw_config)
|
|
743
|
+
check_ok("Migrated stale root-level keys into model section")
|
|
744
|
+
fixed_count += 1
|
|
745
|
+
else:
|
|
746
|
+
issues.append("Stale root-level provider/base_url in config.yaml — run 'hermes doctor --fix'")
|
|
747
|
+
except Exception:
|
|
748
|
+
pass
|
|
749
|
+
|
|
750
|
+
# Validate config structure (catches malformed custom_providers, etc.)
|
|
751
|
+
try:
|
|
752
|
+
from hermes_cli.config import validate_config_structure
|
|
753
|
+
config_issues = validate_config_structure()
|
|
754
|
+
if config_issues:
|
|
755
|
+
print()
|
|
756
|
+
print(color("◆ Config Structure", Colors.CYAN, Colors.BOLD))
|
|
757
|
+
for ci in config_issues:
|
|
758
|
+
if ci.severity == "error":
|
|
759
|
+
check_fail(ci.message)
|
|
760
|
+
else:
|
|
761
|
+
check_warn(ci.message)
|
|
762
|
+
# Show the hint indented
|
|
763
|
+
for hint_line in ci.hint.splitlines():
|
|
764
|
+
check_info(hint_line)
|
|
765
|
+
issues.append(ci.message)
|
|
766
|
+
except Exception:
|
|
767
|
+
pass
|
|
768
|
+
|
|
769
|
+
# =========================================================================
|
|
770
|
+
# Check: Auth providers
|
|
771
|
+
# =========================================================================
|
|
772
|
+
print()
|
|
773
|
+
print(color("◆ Auth Providers", Colors.CYAN, Colors.BOLD))
|
|
774
|
+
|
|
775
|
+
try:
|
|
776
|
+
from hermes_cli.auth import (
|
|
777
|
+
get_nous_auth_status,
|
|
778
|
+
get_codex_auth_status,
|
|
779
|
+
get_gemini_oauth_auth_status,
|
|
780
|
+
get_minimax_oauth_auth_status,
|
|
781
|
+
)
|
|
782
|
+
|
|
783
|
+
nous_status = get_nous_auth_status()
|
|
784
|
+
if nous_status.get("logged_in"):
|
|
785
|
+
check_ok("Nous Portal auth", "(logged in)")
|
|
786
|
+
else:
|
|
787
|
+
check_warn("Nous Portal auth", "(not logged in)")
|
|
788
|
+
|
|
789
|
+
codex_status = get_codex_auth_status()
|
|
790
|
+
if codex_status.get("logged_in"):
|
|
791
|
+
check_ok("OpenAI Codex auth", "(logged in)")
|
|
792
|
+
else:
|
|
793
|
+
check_warn("OpenAI Codex auth", "(not logged in)")
|
|
794
|
+
if codex_status.get("error"):
|
|
795
|
+
check_info(codex_status["error"])
|
|
796
|
+
|
|
797
|
+
gemini_status = get_gemini_oauth_auth_status()
|
|
798
|
+
if gemini_status.get("logged_in"):
|
|
799
|
+
email = gemini_status.get("email") or ""
|
|
800
|
+
project = gemini_status.get("project_id") or ""
|
|
801
|
+
pieces = []
|
|
802
|
+
if email:
|
|
803
|
+
pieces.append(email)
|
|
804
|
+
if project:
|
|
805
|
+
pieces.append(f"project={project}")
|
|
806
|
+
suffix = f" ({', '.join(pieces)})" if pieces else ""
|
|
807
|
+
check_ok("Google Gemini OAuth", f"(logged in{suffix})")
|
|
808
|
+
else:
|
|
809
|
+
check_warn("Google Gemini OAuth", "(not logged in)")
|
|
810
|
+
|
|
811
|
+
minimax_status = get_minimax_oauth_auth_status()
|
|
812
|
+
if minimax_status.get("logged_in"):
|
|
813
|
+
region = minimax_status.get("region", "global")
|
|
814
|
+
check_ok("MiniMax OAuth", f"(logged in, region={region})")
|
|
815
|
+
else:
|
|
816
|
+
check_warn("MiniMax OAuth", "(not logged in)")
|
|
817
|
+
except Exception as e:
|
|
818
|
+
check_warn("Auth provider status", f"(could not check: {e})")
|
|
819
|
+
|
|
820
|
+
if _safe_which("codex"):
|
|
821
|
+
check_ok("codex CLI")
|
|
822
|
+
else:
|
|
823
|
+
# Native OAuth uses Hermes' own device-code flow — the Codex CLI is
|
|
824
|
+
# only needed if you want to import existing tokens from
|
|
825
|
+
# ~/.codex/auth.json. Downgrade to info so users running
|
|
826
|
+
# `hermes auth openai-codex` aren't told they're missing something.
|
|
827
|
+
check_info(
|
|
828
|
+
"codex CLI not installed "
|
|
829
|
+
"(optional — only required to import tokens from an existing Codex CLI login)"
|
|
830
|
+
)
|
|
831
|
+
|
|
832
|
+
# =========================================================================
|
|
833
|
+
# Check: Directory structure
|
|
834
|
+
# =========================================================================
|
|
835
|
+
print()
|
|
836
|
+
print(color("◆ Directory Structure", Colors.CYAN, Colors.BOLD))
|
|
837
|
+
|
|
838
|
+
hermes_home = HERMES_HOME
|
|
839
|
+
if hermes_home.exists():
|
|
840
|
+
check_ok(f"{_DHH} directory exists")
|
|
841
|
+
elif should_fix:
|
|
842
|
+
hermes_home.mkdir(parents=True, exist_ok=True)
|
|
843
|
+
check_ok(f"Created {_DHH} directory")
|
|
844
|
+
fixed_count += 1
|
|
845
|
+
else:
|
|
846
|
+
check_warn(f"{_DHH} not found", "(will be created on first use)")
|
|
847
|
+
|
|
848
|
+
# Check expected subdirectories
|
|
849
|
+
expected_subdirs = ["cron", "sessions", "logs", "skills", "memories"]
|
|
850
|
+
for subdir_name in expected_subdirs:
|
|
851
|
+
subdir_path = hermes_home / subdir_name
|
|
852
|
+
if subdir_path.exists():
|
|
853
|
+
check_ok(f"{_DHH}/{subdir_name}/ exists")
|
|
854
|
+
elif should_fix:
|
|
855
|
+
subdir_path.mkdir(parents=True, exist_ok=True)
|
|
856
|
+
check_ok(f"Created {_DHH}/{subdir_name}/")
|
|
857
|
+
fixed_count += 1
|
|
858
|
+
else:
|
|
859
|
+
check_warn(f"{_DHH}/{subdir_name}/ not found", "(will be created on first use)")
|
|
860
|
+
|
|
861
|
+
# Check for SOUL.md persona file
|
|
862
|
+
soul_path = hermes_home / "SOUL.md"
|
|
863
|
+
if soul_path.exists():
|
|
864
|
+
content = soul_path.read_text(encoding="utf-8").strip()
|
|
865
|
+
# Check if it's just the template comments (no real content)
|
|
866
|
+
lines = [l for l in content.splitlines() if l.strip() and not l.strip().startswith(("<!--", "-->", "#"))]
|
|
867
|
+
if lines:
|
|
868
|
+
check_ok(f"{_DHH}/SOUL.md exists (persona configured)")
|
|
869
|
+
else:
|
|
870
|
+
check_info(f"{_DHH}/SOUL.md exists but is empty — edit it to customize personality")
|
|
871
|
+
else:
|
|
872
|
+
check_warn(f"{_DHH}/SOUL.md not found", "(create it to give Hermes a custom personality)")
|
|
873
|
+
if should_fix:
|
|
874
|
+
soul_path.parent.mkdir(parents=True, exist_ok=True)
|
|
875
|
+
soul_path.write_text(
|
|
876
|
+
"# Hermes Agent Persona\n\n"
|
|
877
|
+
"<!-- Edit this file to customize how Hermes communicates. -->\n\n"
|
|
878
|
+
"You are Hermes, a helpful AI assistant.\n",
|
|
879
|
+
encoding="utf-8",
|
|
880
|
+
)
|
|
881
|
+
check_ok(f"Created {_DHH}/SOUL.md with basic template")
|
|
882
|
+
fixed_count += 1
|
|
883
|
+
|
|
884
|
+
# Check memory directory
|
|
885
|
+
memories_dir = hermes_home / "memories"
|
|
886
|
+
if memories_dir.exists():
|
|
887
|
+
check_ok(f"{_DHH}/memories/ directory exists")
|
|
888
|
+
memory_file = memories_dir / "MEMORY.md"
|
|
889
|
+
user_file = memories_dir / "USER.md"
|
|
890
|
+
if memory_file.exists():
|
|
891
|
+
size = len(memory_file.read_text(encoding="utf-8").strip())
|
|
892
|
+
check_ok(f"MEMORY.md exists ({size} chars)")
|
|
893
|
+
else:
|
|
894
|
+
check_info("MEMORY.md not created yet (will be created when the agent first writes a memory)")
|
|
895
|
+
if user_file.exists():
|
|
896
|
+
size = len(user_file.read_text(encoding="utf-8").strip())
|
|
897
|
+
check_ok(f"USER.md exists ({size} chars)")
|
|
898
|
+
else:
|
|
899
|
+
check_info("USER.md not created yet (will be created when the agent first writes a memory)")
|
|
900
|
+
else:
|
|
901
|
+
check_warn(f"{_DHH}/memories/ not found", "(will be created on first use)")
|
|
902
|
+
if should_fix:
|
|
903
|
+
memories_dir.mkdir(parents=True, exist_ok=True)
|
|
904
|
+
check_ok(f"Created {_DHH}/memories/")
|
|
905
|
+
fixed_count += 1
|
|
906
|
+
|
|
907
|
+
# Check SQLite session store
|
|
908
|
+
state_db_path = hermes_home / "state.db"
|
|
909
|
+
if state_db_path.exists():
|
|
910
|
+
try:
|
|
911
|
+
import sqlite3
|
|
912
|
+
conn = sqlite3.connect(str(state_db_path))
|
|
913
|
+
cursor = conn.execute("SELECT COUNT(*) FROM sessions")
|
|
914
|
+
count = cursor.fetchone()[0]
|
|
915
|
+
conn.close()
|
|
916
|
+
check_ok(f"{_DHH}/state.db exists ({count} sessions)")
|
|
917
|
+
except Exception as e:
|
|
918
|
+
check_warn(f"{_DHH}/state.db exists but has issues: {e}")
|
|
919
|
+
else:
|
|
920
|
+
check_info(f"{_DHH}/state.db not created yet (will be created on first session)")
|
|
921
|
+
|
|
922
|
+
# Check WAL file size (unbounded growth indicates missed checkpoints)
|
|
923
|
+
wal_path = hermes_home / "state.db-wal"
|
|
924
|
+
if wal_path.exists():
|
|
925
|
+
try:
|
|
926
|
+
wal_size = wal_path.stat().st_size
|
|
927
|
+
if wal_size > 50 * 1024 * 1024: # 50 MB
|
|
928
|
+
check_warn(
|
|
929
|
+
f"WAL file is large ({wal_size // (1024*1024)} MB)",
|
|
930
|
+
"(may indicate missed checkpoints)"
|
|
931
|
+
)
|
|
932
|
+
if should_fix:
|
|
933
|
+
import sqlite3
|
|
934
|
+
conn = sqlite3.connect(str(state_db_path))
|
|
935
|
+
conn.execute("PRAGMA wal_checkpoint(PASSIVE)")
|
|
936
|
+
conn.close()
|
|
937
|
+
new_size = wal_path.stat().st_size if wal_path.exists() else 0
|
|
938
|
+
check_ok(f"WAL checkpoint performed ({wal_size // 1024}K → {new_size // 1024}K)")
|
|
939
|
+
fixed_count += 1
|
|
940
|
+
else:
|
|
941
|
+
issues.append("Large WAL file — run 'hermes doctor --fix' to checkpoint")
|
|
942
|
+
elif wal_size > 10 * 1024 * 1024: # 10 MB
|
|
943
|
+
check_info(f"WAL file is {wal_size // (1024*1024)} MB (normal for active sessions)")
|
|
944
|
+
except Exception:
|
|
945
|
+
pass
|
|
946
|
+
|
|
947
|
+
_check_gateway_service_linger(issues)
|
|
948
|
+
|
|
949
|
+
# =========================================================================
|
|
950
|
+
# Check: Command installation (hermes bin symlink)
|
|
951
|
+
# =========================================================================
|
|
952
|
+
if sys.platform != "win32":
|
|
953
|
+
print()
|
|
954
|
+
print(color("◆ Command Installation", Colors.CYAN, Colors.BOLD))
|
|
955
|
+
|
|
956
|
+
# Determine the venv entry point location
|
|
957
|
+
_venv_bin = None
|
|
958
|
+
for _venv_name in ("venv", ".venv"):
|
|
959
|
+
_candidate = PROJECT_ROOT / _venv_name / "bin" / "hermes"
|
|
960
|
+
if _candidate.exists():
|
|
961
|
+
_venv_bin = _candidate
|
|
962
|
+
break
|
|
963
|
+
|
|
964
|
+
# Determine the expected command link directory (mirrors install.sh logic)
|
|
965
|
+
_prefix = os.environ.get("PREFIX", "")
|
|
966
|
+
_is_termux_env = bool(os.environ.get("TERMUX_VERSION")) or "com.termux/files/usr" in _prefix
|
|
967
|
+
if _is_termux_env and _prefix:
|
|
968
|
+
_cmd_link_dir = Path(_prefix) / "bin"
|
|
969
|
+
_cmd_link_display = "$PREFIX/bin"
|
|
970
|
+
else:
|
|
971
|
+
_cmd_link_dir = Path.home() / ".local" / "bin"
|
|
972
|
+
_cmd_link_display = "~/.local/bin"
|
|
973
|
+
_cmd_link = _cmd_link_dir / "hermes"
|
|
974
|
+
|
|
975
|
+
if _venv_bin is None:
|
|
976
|
+
check_warn(
|
|
977
|
+
"Venv entry point not found",
|
|
978
|
+
"(hermes not in venv/bin/ or .venv/bin/ — reinstall with pip install -e '.[all]')"
|
|
979
|
+
)
|
|
980
|
+
manual_issues.append(
|
|
981
|
+
f"Reinstall entry point: cd {PROJECT_ROOT} && source venv/bin/activate && pip install -e '.[all]'"
|
|
982
|
+
)
|
|
983
|
+
else:
|
|
984
|
+
check_ok(f"Venv entry point exists ({_venv_bin.relative_to(PROJECT_ROOT)})")
|
|
985
|
+
|
|
986
|
+
# Check the symlink at the command link location
|
|
987
|
+
if _cmd_link.is_symlink():
|
|
988
|
+
_target = _cmd_link.resolve()
|
|
989
|
+
_expected = _venv_bin.resolve()
|
|
990
|
+
if _target == _expected:
|
|
991
|
+
check_ok(f"{_cmd_link_display}/hermes → correct target")
|
|
992
|
+
else:
|
|
993
|
+
check_warn(
|
|
994
|
+
f"{_cmd_link_display}/hermes points to wrong target",
|
|
995
|
+
f"(→ {_target}, expected → {_expected})"
|
|
996
|
+
)
|
|
997
|
+
if should_fix:
|
|
998
|
+
_cmd_link.unlink()
|
|
999
|
+
_cmd_link.symlink_to(_venv_bin)
|
|
1000
|
+
check_ok(f"Fixed symlink: {_cmd_link_display}/hermes → {_venv_bin}")
|
|
1001
|
+
fixed_count += 1
|
|
1002
|
+
else:
|
|
1003
|
+
issues.append(f"Broken symlink at {_cmd_link_display}/hermes — run 'hermes doctor --fix'")
|
|
1004
|
+
elif _cmd_link.exists():
|
|
1005
|
+
# It's a regular file, not a symlink — possibly a wrapper script
|
|
1006
|
+
check_ok(f"{_cmd_link_display}/hermes exists (non-symlink)")
|
|
1007
|
+
else:
|
|
1008
|
+
check_fail(
|
|
1009
|
+
f"{_cmd_link_display}/hermes not found",
|
|
1010
|
+
"(hermes command may not work outside the venv)"
|
|
1011
|
+
)
|
|
1012
|
+
if should_fix:
|
|
1013
|
+
_cmd_link_dir.mkdir(parents=True, exist_ok=True)
|
|
1014
|
+
_cmd_link.symlink_to(_venv_bin)
|
|
1015
|
+
check_ok(f"Created symlink: {_cmd_link_display}/hermes → {_venv_bin}")
|
|
1016
|
+
fixed_count += 1
|
|
1017
|
+
|
|
1018
|
+
# Check if the link dir is on PATH
|
|
1019
|
+
_path_dirs = os.environ.get("PATH", "").split(os.pathsep)
|
|
1020
|
+
if str(_cmd_link_dir) not in _path_dirs:
|
|
1021
|
+
check_warn(
|
|
1022
|
+
f"{_cmd_link_display} is not on your PATH",
|
|
1023
|
+
"(add it to your shell config: export PATH=\"$HOME/.local/bin:$PATH\")"
|
|
1024
|
+
)
|
|
1025
|
+
manual_issues.append(f"Add {_cmd_link_display} to your PATH")
|
|
1026
|
+
else:
|
|
1027
|
+
issues.append(f"Missing {_cmd_link_display}/hermes symlink — run 'hermes doctor --fix'")
|
|
1028
|
+
|
|
1029
|
+
# =========================================================================
|
|
1030
|
+
# Check: External tools
|
|
1031
|
+
# =========================================================================
|
|
1032
|
+
print()
|
|
1033
|
+
print(color("◆ External Tools", Colors.CYAN, Colors.BOLD))
|
|
1034
|
+
|
|
1035
|
+
# Git
|
|
1036
|
+
if _safe_which("git"):
|
|
1037
|
+
check_ok("git")
|
|
1038
|
+
else:
|
|
1039
|
+
check_warn("git not found", "(optional)")
|
|
1040
|
+
|
|
1041
|
+
# ripgrep (optional, for faster file search)
|
|
1042
|
+
if _safe_which("rg"):
|
|
1043
|
+
check_ok("ripgrep (rg)", "(faster file search)")
|
|
1044
|
+
else:
|
|
1045
|
+
check_warn("ripgrep (rg) not found", "(file search uses grep fallback)")
|
|
1046
|
+
check_info(f"Install for faster search: {_system_package_install_cmd('ripgrep')}")
|
|
1047
|
+
|
|
1048
|
+
# Docker (optional)
|
|
1049
|
+
terminal_env = os.getenv("TERMINAL_ENV", "local")
|
|
1050
|
+
if terminal_env == "docker":
|
|
1051
|
+
if _safe_which("docker"):
|
|
1052
|
+
# Check if docker daemon is running
|
|
1053
|
+
try:
|
|
1054
|
+
result = subprocess.run(["docker", "info"], capture_output=True, timeout=10)
|
|
1055
|
+
except subprocess.TimeoutExpired:
|
|
1056
|
+
result = None
|
|
1057
|
+
if result is not None and result.returncode == 0:
|
|
1058
|
+
check_ok("docker", "(daemon running)")
|
|
1059
|
+
else:
|
|
1060
|
+
check_fail("docker daemon not running")
|
|
1061
|
+
issues.append("Start Docker daemon")
|
|
1062
|
+
else:
|
|
1063
|
+
check_fail("docker not found", "(required for TERMINAL_ENV=docker)")
|
|
1064
|
+
issues.append("Install Docker or change TERMINAL_ENV")
|
|
1065
|
+
elif _safe_which("docker"):
|
|
1066
|
+
check_ok("docker", "(optional)")
|
|
1067
|
+
elif _is_termux():
|
|
1068
|
+
check_info("Docker backend is not available inside Termux (expected on Android)")
|
|
1069
|
+
else:
|
|
1070
|
+
check_warn("docker not found", "(optional)")
|
|
1071
|
+
|
|
1072
|
+
# SSH (if using ssh backend)
|
|
1073
|
+
if terminal_env == "ssh":
|
|
1074
|
+
ssh_host = os.getenv("TERMINAL_SSH_HOST")
|
|
1075
|
+
if ssh_host:
|
|
1076
|
+
# Try to connect
|
|
1077
|
+
try:
|
|
1078
|
+
result = subprocess.run(
|
|
1079
|
+
["ssh", "-o", "ConnectTimeout=5", "-o", "BatchMode=yes", ssh_host, "echo ok"],
|
|
1080
|
+
capture_output=True,
|
|
1081
|
+
text=True,
|
|
1082
|
+
timeout=15
|
|
1083
|
+
)
|
|
1084
|
+
except subprocess.TimeoutExpired:
|
|
1085
|
+
result = None
|
|
1086
|
+
if result is not None and result.returncode == 0:
|
|
1087
|
+
check_ok(f"SSH connection to {ssh_host}")
|
|
1088
|
+
else:
|
|
1089
|
+
check_fail(f"SSH connection to {ssh_host}")
|
|
1090
|
+
issues.append(f"Check SSH configuration for {ssh_host}")
|
|
1091
|
+
else:
|
|
1092
|
+
check_fail("TERMINAL_SSH_HOST not set", "(required for TERMINAL_ENV=ssh)")
|
|
1093
|
+
issues.append("Set TERMINAL_SSH_HOST in .env")
|
|
1094
|
+
|
|
1095
|
+
# Daytona (if using daytona backend)
|
|
1096
|
+
if terminal_env == "daytona":
|
|
1097
|
+
daytona_key = os.getenv("DAYTONA_API_KEY")
|
|
1098
|
+
if daytona_key:
|
|
1099
|
+
check_ok("Daytona API key", "(configured)")
|
|
1100
|
+
else:
|
|
1101
|
+
check_fail("DAYTONA_API_KEY not set", "(required for TERMINAL_ENV=daytona)")
|
|
1102
|
+
issues.append("Set DAYTONA_API_KEY environment variable")
|
|
1103
|
+
try:
|
|
1104
|
+
from daytona import Daytona # noqa: F401 — SDK presence check
|
|
1105
|
+
check_ok("daytona SDK", "(installed)")
|
|
1106
|
+
except ImportError:
|
|
1107
|
+
check_fail("daytona SDK not installed", "(pip install daytona)")
|
|
1108
|
+
issues.append("Install daytona SDK: pip install daytona")
|
|
1109
|
+
|
|
1110
|
+
# Vercel Sandbox (if using vercel_sandbox backend)
|
|
1111
|
+
if terminal_env == "vercel_sandbox":
|
|
1112
|
+
runtime = os.getenv("TERMINAL_VERCEL_RUNTIME", "node24").strip() or "node24"
|
|
1113
|
+
from tools.terminal_tool import _SUPPORTED_VERCEL_RUNTIMES
|
|
1114
|
+
if runtime in _SUPPORTED_VERCEL_RUNTIMES:
|
|
1115
|
+
check_ok("Vercel runtime", f"({runtime})")
|
|
1116
|
+
else:
|
|
1117
|
+
supported = ", ".join(_SUPPORTED_VERCEL_RUNTIMES)
|
|
1118
|
+
check_fail("Vercel runtime unsupported", f"({runtime}; use {supported})")
|
|
1119
|
+
issues.append(f"Set TERMINAL_VERCEL_RUNTIME to one of: {supported}")
|
|
1120
|
+
|
|
1121
|
+
disk = os.getenv("TERMINAL_CONTAINER_DISK", "51200").strip()
|
|
1122
|
+
if disk in {"", "0", "51200"}:
|
|
1123
|
+
check_ok("Vercel disk setting", "(uses platform default)")
|
|
1124
|
+
else:
|
|
1125
|
+
check_fail("Vercel custom disk unsupported", "(reset terminal.container_disk to 51200)")
|
|
1126
|
+
issues.append("Vercel Sandbox does not support custom container_disk; use the shared default 51200")
|
|
1127
|
+
|
|
1128
|
+
if importlib.util.find_spec("vercel") is not None:
|
|
1129
|
+
check_ok("vercel SDK", "(installed)")
|
|
1130
|
+
else:
|
|
1131
|
+
check_fail("vercel SDK not installed", "(pip install 'hermes-agent[vercel]')")
|
|
1132
|
+
issues.append("Install the Vercel optional dependency: pip install 'hermes-agent[vercel]'")
|
|
1133
|
+
|
|
1134
|
+
auth_status = describe_vercel_auth()
|
|
1135
|
+
if auth_status.ok:
|
|
1136
|
+
check_ok("Vercel auth", f"({auth_status.label})")
|
|
1137
|
+
elif auth_status.label.startswith("partial"):
|
|
1138
|
+
check_fail("Vercel auth incomplete", f"({auth_status.label})")
|
|
1139
|
+
issues.append("Set VERCEL_TOKEN, VERCEL_PROJECT_ID, and VERCEL_TEAM_ID together")
|
|
1140
|
+
else:
|
|
1141
|
+
check_fail("Vercel auth not configured", f"({auth_status.label})")
|
|
1142
|
+
issues.append(
|
|
1143
|
+
"Configure Vercel Sandbox auth with VERCEL_TOKEN, VERCEL_PROJECT_ID, and VERCEL_TEAM_ID"
|
|
1144
|
+
)
|
|
1145
|
+
for line in auth_status.detail_lines:
|
|
1146
|
+
check_info(f"Vercel auth {line}")
|
|
1147
|
+
|
|
1148
|
+
persistent = os.getenv("TERMINAL_CONTAINER_PERSISTENT", "true").lower() in {"1", "true", "yes", "on"}
|
|
1149
|
+
if persistent:
|
|
1150
|
+
check_info("Vercel persistence: snapshot filesystem only; live processes do not survive sandbox recreation")
|
|
1151
|
+
else:
|
|
1152
|
+
check_info("Vercel persistence: ephemeral filesystem")
|
|
1153
|
+
|
|
1154
|
+
# Node.js + agent-browser (for browser automation tools)
|
|
1155
|
+
if _safe_which("node"):
|
|
1156
|
+
check_ok("Node.js")
|
|
1157
|
+
# Check if agent-browser is installed
|
|
1158
|
+
agent_browser_path = PROJECT_ROOT / "node_modules" / "agent-browser"
|
|
1159
|
+
agent_browser_ok = False
|
|
1160
|
+
if agent_browser_path.exists():
|
|
1161
|
+
check_ok("agent-browser (Node.js)", "(browser automation)")
|
|
1162
|
+
agent_browser_ok = True
|
|
1163
|
+
elif shutil.which("agent-browser"):
|
|
1164
|
+
check_ok("agent-browser", "(browser automation)")
|
|
1165
|
+
agent_browser_ok = True
|
|
1166
|
+
elif _is_termux():
|
|
1167
|
+
check_info("agent-browser is not installed (expected in the tested Termux path)")
|
|
1168
|
+
check_info("Install it manually later with: npm install -g agent-browser && agent-browser install")
|
|
1169
|
+
check_info("Termux browser setup:")
|
|
1170
|
+
for step in _termux_browser_setup_steps(node_installed=True):
|
|
1171
|
+
check_info(step)
|
|
1172
|
+
else:
|
|
1173
|
+
check_warn("agent-browser not installed", "(run: npm install)")
|
|
1174
|
+
|
|
1175
|
+
# Chromium presence — the browser tools silently fail to register when
|
|
1176
|
+
# agent-browser is found but no Playwright-managed Chromium is on disk
|
|
1177
|
+
# (tools/browser_tool.py::check_browser_requirements filters them out
|
|
1178
|
+
# before the agent ever sees them). Reuse the exact predicate it uses
|
|
1179
|
+
# so the two checks cannot diverge. Skip on Termux (not a tested
|
|
1180
|
+
# path).
|
|
1181
|
+
if agent_browser_ok and not _is_termux():
|
|
1182
|
+
try:
|
|
1183
|
+
# Lazy import: browser_tool is a ~150KB module we don't want
|
|
1184
|
+
# to eagerly load in every `hermes doctor` invocation.
|
|
1185
|
+
from tools.browser_tool import (
|
|
1186
|
+
_chromium_installed,
|
|
1187
|
+
_is_camofox_mode,
|
|
1188
|
+
_get_cloud_provider,
|
|
1189
|
+
_get_cdp_override,
|
|
1190
|
+
_using_lightpanda_engine,
|
|
1191
|
+
)
|
|
1192
|
+
except Exception:
|
|
1193
|
+
# If browser_tool can't even import, that's a separate bug
|
|
1194
|
+
# surfaced elsewhere; don't crash doctor.
|
|
1195
|
+
pass
|
|
1196
|
+
else:
|
|
1197
|
+
# Only warn about Chromium if the installed engine actually
|
|
1198
|
+
# requires it: Camofox, CDP override, a cloud provider, or
|
|
1199
|
+
# Lightpanda all bypass the local Chromium requirement.
|
|
1200
|
+
skip_chromium_check = (
|
|
1201
|
+
_is_camofox_mode()
|
|
1202
|
+
or bool(_get_cdp_override())
|
|
1203
|
+
or _get_cloud_provider() is not None
|
|
1204
|
+
or _using_lightpanda_engine()
|
|
1205
|
+
)
|
|
1206
|
+
if not skip_chromium_check:
|
|
1207
|
+
if _chromium_installed():
|
|
1208
|
+
check_ok("Playwright Chromium", "(browser engine)")
|
|
1209
|
+
else:
|
|
1210
|
+
check_warn(
|
|
1211
|
+
"Playwright Chromium not installed",
|
|
1212
|
+
"(browser_* tools will be hidden from the agent)",
|
|
1213
|
+
)
|
|
1214
|
+
if sys.platform == "win32":
|
|
1215
|
+
check_info(
|
|
1216
|
+
f"Install with: cd {PROJECT_ROOT} && "
|
|
1217
|
+
"npx playwright install chromium"
|
|
1218
|
+
)
|
|
1219
|
+
else:
|
|
1220
|
+
check_info(
|
|
1221
|
+
f"Install with: cd {PROJECT_ROOT} && "
|
|
1222
|
+
"npx playwright install --with-deps chromium"
|
|
1223
|
+
)
|
|
1224
|
+
elif _is_termux():
|
|
1225
|
+
check_info("Node.js not found (browser tools are optional in the tested Termux path)")
|
|
1226
|
+
check_info("Install Node.js on Termux with: pkg install nodejs")
|
|
1227
|
+
check_info("Termux browser setup:")
|
|
1228
|
+
for step in _termux_browser_setup_steps(node_installed=False):
|
|
1229
|
+
check_info(step)
|
|
1230
|
+
else:
|
|
1231
|
+
check_warn("Node.js not found", "(optional, needed for browser tools)")
|
|
1232
|
+
|
|
1233
|
+
# npm audit for all Node.js packages
|
|
1234
|
+
_npm_bin = _safe_which("npm")
|
|
1235
|
+
if _npm_bin:
|
|
1236
|
+
npm_dirs = [
|
|
1237
|
+
(PROJECT_ROOT, "Browser tools (agent-browser)"),
|
|
1238
|
+
(PROJECT_ROOT / "scripts" / "whatsapp-bridge", "WhatsApp bridge"),
|
|
1239
|
+
]
|
|
1240
|
+
for npm_dir, label in npm_dirs:
|
|
1241
|
+
if not (npm_dir / "node_modules").exists():
|
|
1242
|
+
continue
|
|
1243
|
+
try:
|
|
1244
|
+
# Use resolved absolute path so Windows can execute
|
|
1245
|
+
# npm.cmd (CreateProcessW can't run bare .cmd names).
|
|
1246
|
+
audit_result = subprocess.run(
|
|
1247
|
+
[_npm_bin, "audit", "--json"],
|
|
1248
|
+
cwd=str(npm_dir),
|
|
1249
|
+
capture_output=True, text=True, timeout=30,
|
|
1250
|
+
)
|
|
1251
|
+
import json as _json
|
|
1252
|
+
audit_data = _json.loads(audit_result.stdout) if audit_result.stdout.strip() else {}
|
|
1253
|
+
vuln_count = audit_data.get("metadata", {}).get("vulnerabilities", {})
|
|
1254
|
+
critical = vuln_count.get("critical", 0)
|
|
1255
|
+
high = vuln_count.get("high", 0)
|
|
1256
|
+
moderate = vuln_count.get("moderate", 0)
|
|
1257
|
+
total = critical + high + moderate
|
|
1258
|
+
if total == 0:
|
|
1259
|
+
check_ok(f"{label} deps", "(no known vulnerabilities)")
|
|
1260
|
+
elif critical > 0 or high > 0:
|
|
1261
|
+
check_warn(
|
|
1262
|
+
f"{label} deps",
|
|
1263
|
+
f"({critical} critical, {high} high, {moderate} moderate — run: cd {npm_dir} && npm audit fix)"
|
|
1264
|
+
)
|
|
1265
|
+
issues.append(
|
|
1266
|
+
f"{label} has {total} npm "
|
|
1267
|
+
f"{'vulnerability' if total == 1 else 'vulnerabilities'}"
|
|
1268
|
+
)
|
|
1269
|
+
else:
|
|
1270
|
+
check_ok(
|
|
1271
|
+
f"{label} deps",
|
|
1272
|
+
f"({moderate} moderate "
|
|
1273
|
+
f"{'vulnerability' if moderate == 1 else 'vulnerabilities'})",
|
|
1274
|
+
)
|
|
1275
|
+
except Exception:
|
|
1276
|
+
pass
|
|
1277
|
+
|
|
1278
|
+
if _is_termux():
|
|
1279
|
+
check_info("Termux compatibility fallbacks:")
|
|
1280
|
+
for note in _termux_install_all_fallback_notes():
|
|
1281
|
+
check_info(note)
|
|
1282
|
+
|
|
1283
|
+
# =========================================================================
|
|
1284
|
+
# Check: API connectivity
|
|
1285
|
+
# =========================================================================
|
|
1286
|
+
print()
|
|
1287
|
+
print(color("◆ API Connectivity", Colors.CYAN, Colors.BOLD))
|
|
1288
|
+
|
|
1289
|
+
# Refactor: every connectivity probe below is HTTP-bound and fully
|
|
1290
|
+
# independent. Running them in series spent ~5s wall on a typical
|
|
1291
|
+
# workstation (2s of that was boto3's IMDS lookup for AWS credentials,
|
|
1292
|
+
# which times out unless you're actually on EC2). Threading them with
|
|
1293
|
+
# a small executor pool collapses the section to roughly the slowest
|
|
1294
|
+
# single probe — about 2s — without changing the output format.
|
|
1295
|
+
#
|
|
1296
|
+
# Each ``_probe_*`` helper is a pure function: takes its inputs,
|
|
1297
|
+
# makes one HTTP/SDK call, returns a ``_ConnectivityResult`` carrying
|
|
1298
|
+
# the line(s) to print and any issue strings to append. No globals,
|
|
1299
|
+
# no shared mutable state, no printing inside the workers.
|
|
1300
|
+
import concurrent.futures as _futures
|
|
1301
|
+
from collections import namedtuple as _namedtuple
|
|
1302
|
+
|
|
1303
|
+
_ConnectivityResult = _namedtuple(
|
|
1304
|
+
"_ConnectivityResult", ["label", "lines", "issues"]
|
|
1305
|
+
)
|
|
1306
|
+
_probes: list = [] # list of (label, callable) submitted in display order
|
|
1307
|
+
|
|
1308
|
+
def _probe_openrouter() -> _ConnectivityResult:
|
|
1309
|
+
key = os.getenv("OPENROUTER_API_KEY")
|
|
1310
|
+
if not key:
|
|
1311
|
+
return _ConnectivityResult(
|
|
1312
|
+
"OpenRouter API",
|
|
1313
|
+
[(color("⚠", Colors.YELLOW), "OpenRouter API",
|
|
1314
|
+
color("(not configured)", Colors.DIM))],
|
|
1315
|
+
[],
|
|
1316
|
+
)
|
|
1317
|
+
try:
|
|
1318
|
+
import httpx
|
|
1319
|
+
r = httpx.get(
|
|
1320
|
+
OPENROUTER_MODELS_URL,
|
|
1321
|
+
headers={"Authorization": f"Bearer {key}"},
|
|
1322
|
+
timeout=10,
|
|
1323
|
+
)
|
|
1324
|
+
if r.status_code == 200:
|
|
1325
|
+
return _ConnectivityResult(
|
|
1326
|
+
"OpenRouter API",
|
|
1327
|
+
[(color("✓", Colors.GREEN), "OpenRouter API", "")],
|
|
1328
|
+
[],
|
|
1329
|
+
)
|
|
1330
|
+
if r.status_code == 401:
|
|
1331
|
+
return _ConnectivityResult(
|
|
1332
|
+
"OpenRouter API",
|
|
1333
|
+
[(color("✗", Colors.RED), "OpenRouter API",
|
|
1334
|
+
color("(invalid API key)", Colors.DIM))],
|
|
1335
|
+
["Check OPENROUTER_API_KEY in .env"],
|
|
1336
|
+
)
|
|
1337
|
+
if r.status_code == 402:
|
|
1338
|
+
return _ConnectivityResult(
|
|
1339
|
+
"OpenRouter API",
|
|
1340
|
+
[(color("✗", Colors.RED), "OpenRouter API",
|
|
1341
|
+
color("(out of credits — payment required)", Colors.DIM))],
|
|
1342
|
+
["OpenRouter account has insufficient credits. "
|
|
1343
|
+
"Fix: run 'hermes config set model.provider <provider>' "
|
|
1344
|
+
"to switch providers, or fund your OpenRouter account "
|
|
1345
|
+
"at https://openrouter.ai/settings/credits"],
|
|
1346
|
+
)
|
|
1347
|
+
if r.status_code == 429:
|
|
1348
|
+
return _ConnectivityResult(
|
|
1349
|
+
"OpenRouter API",
|
|
1350
|
+
[(color("✗", Colors.RED), "OpenRouter API",
|
|
1351
|
+
color("(rate limited)", Colors.DIM))],
|
|
1352
|
+
["OpenRouter rate limit hit — consider switching to "
|
|
1353
|
+
"a different provider or waiting"],
|
|
1354
|
+
)
|
|
1355
|
+
return _ConnectivityResult(
|
|
1356
|
+
"OpenRouter API",
|
|
1357
|
+
[(color("✗", Colors.RED), "OpenRouter API",
|
|
1358
|
+
color(f"(HTTP {r.status_code})", Colors.DIM))],
|
|
1359
|
+
[],
|
|
1360
|
+
)
|
|
1361
|
+
except Exception as e:
|
|
1362
|
+
return _ConnectivityResult(
|
|
1363
|
+
"OpenRouter API",
|
|
1364
|
+
[(color("✗", Colors.RED), "OpenRouter API",
|
|
1365
|
+
color(f"({e})", Colors.DIM))],
|
|
1366
|
+
["Check network connectivity"],
|
|
1367
|
+
)
|
|
1368
|
+
|
|
1369
|
+
def _probe_anthropic() -> _ConnectivityResult:
|
|
1370
|
+
from hermes_cli.auth import get_anthropic_key
|
|
1371
|
+
key = get_anthropic_key()
|
|
1372
|
+
if not key:
|
|
1373
|
+
return _ConnectivityResult("Anthropic API", [], [])
|
|
1374
|
+
try:
|
|
1375
|
+
import httpx
|
|
1376
|
+
from agent.anthropic_adapter import (
|
|
1377
|
+
_is_oauth_token,
|
|
1378
|
+
_COMMON_BETAS,
|
|
1379
|
+
_OAUTH_ONLY_BETAS,
|
|
1380
|
+
_CONTEXT_1M_BETA,
|
|
1381
|
+
)
|
|
1382
|
+
headers = {"anthropic-version": "2023-06-01"}
|
|
1383
|
+
is_oauth = _is_oauth_token(key)
|
|
1384
|
+
if is_oauth:
|
|
1385
|
+
headers["Authorization"] = f"Bearer {key}"
|
|
1386
|
+
headers["anthropic-beta"] = ",".join(_COMMON_BETAS + _OAUTH_ONLY_BETAS)
|
|
1387
|
+
else:
|
|
1388
|
+
headers["x-api-key"] = key
|
|
1389
|
+
r = httpx.get(
|
|
1390
|
+
"https://api.anthropic.com/v1/models",
|
|
1391
|
+
headers=headers, timeout=10,
|
|
1392
|
+
)
|
|
1393
|
+
# Reactive recovery: OAuth subscriptions without 1M context reject the
|
|
1394
|
+
# request with 400 "long context beta is not yet available for this
|
|
1395
|
+
# subscription". Retry once with that beta stripped so the doctor
|
|
1396
|
+
# check doesn't falsely report Anthropic as unreachable.
|
|
1397
|
+
if (
|
|
1398
|
+
is_oauth
|
|
1399
|
+
and r.status_code == 400
|
|
1400
|
+
and "long context beta" in r.text.lower()
|
|
1401
|
+
and "not yet available" in r.text.lower()
|
|
1402
|
+
):
|
|
1403
|
+
headers["anthropic-beta"] = ",".join(
|
|
1404
|
+
[b for b in _COMMON_BETAS if b != _CONTEXT_1M_BETA]
|
|
1405
|
+
+ list(_OAUTH_ONLY_BETAS)
|
|
1406
|
+
)
|
|
1407
|
+
r = httpx.get(
|
|
1408
|
+
"https://api.anthropic.com/v1/models",
|
|
1409
|
+
headers=headers, timeout=10,
|
|
1410
|
+
)
|
|
1411
|
+
if r.status_code == 200:
|
|
1412
|
+
return _ConnectivityResult(
|
|
1413
|
+
"Anthropic API",
|
|
1414
|
+
[(color("✓", Colors.GREEN), "Anthropic API", "")],
|
|
1415
|
+
[],
|
|
1416
|
+
)
|
|
1417
|
+
if r.status_code == 401:
|
|
1418
|
+
return _ConnectivityResult(
|
|
1419
|
+
"Anthropic API",
|
|
1420
|
+
[(color("✗", Colors.RED), "Anthropic API",
|
|
1421
|
+
color("(invalid API key)", Colors.DIM))],
|
|
1422
|
+
[],
|
|
1423
|
+
)
|
|
1424
|
+
return _ConnectivityResult(
|
|
1425
|
+
"Anthropic API",
|
|
1426
|
+
[(color("⚠", Colors.YELLOW), "Anthropic API",
|
|
1427
|
+
color("(couldn't verify)", Colors.DIM))],
|
|
1428
|
+
[],
|
|
1429
|
+
)
|
|
1430
|
+
except Exception as e:
|
|
1431
|
+
return _ConnectivityResult(
|
|
1432
|
+
"Anthropic API",
|
|
1433
|
+
[(color("⚠", Colors.YELLOW), "Anthropic API",
|
|
1434
|
+
color(f"({e})", Colors.DIM))],
|
|
1435
|
+
[],
|
|
1436
|
+
)
|
|
1437
|
+
|
|
1438
|
+
def _probe_apikey_provider(pname, env_vars, default_url, base_env,
|
|
1439
|
+
supports_health_check) -> _ConnectivityResult:
|
|
1440
|
+
key = ""
|
|
1441
|
+
for ev in env_vars:
|
|
1442
|
+
key = os.getenv(ev, "")
|
|
1443
|
+
if key:
|
|
1444
|
+
break
|
|
1445
|
+
if not key:
|
|
1446
|
+
return _ConnectivityResult(pname, [], [])
|
|
1447
|
+
label = pname.ljust(20)
|
|
1448
|
+
if not supports_health_check:
|
|
1449
|
+
return _ConnectivityResult(
|
|
1450
|
+
pname,
|
|
1451
|
+
[(color("✓", Colors.GREEN), label,
|
|
1452
|
+
color("(key configured)", Colors.DIM))],
|
|
1453
|
+
[],
|
|
1454
|
+
)
|
|
1455
|
+
try:
|
|
1456
|
+
import httpx
|
|
1457
|
+
base = os.getenv(base_env, "") if base_env else ""
|
|
1458
|
+
# Auto-detect Kimi Code keys (sk-kimi-) → api.kimi.com/coding/v1
|
|
1459
|
+
# (OpenAI-compat surface, which exposes /models for health check).
|
|
1460
|
+
if not base and key.startswith("sk-kimi-"):
|
|
1461
|
+
base = "https://api.kimi.com/coding/v1"
|
|
1462
|
+
# Anthropic-compat endpoints (/anthropic, api.kimi.com/coding
|
|
1463
|
+
# with no /v1) don't support /models. Rewrite to OpenAI-compat
|
|
1464
|
+
# /v1 surface for health checks.
|
|
1465
|
+
if base and base.rstrip("/").endswith("/anthropic"):
|
|
1466
|
+
from agent.auxiliary_client import _to_openai_base_url
|
|
1467
|
+
base = _to_openai_base_url(base)
|
|
1468
|
+
if base_url_host_matches(base, "api.kimi.com") and base.rstrip("/").endswith("/coding"):
|
|
1469
|
+
base = base.rstrip("/") + "/v1"
|
|
1470
|
+
url = (base.rstrip("/") + "/models") if base else default_url
|
|
1471
|
+
headers = {
|
|
1472
|
+
"Authorization": f"Bearer {key}",
|
|
1473
|
+
"User-Agent": _HERMES_USER_AGENT,
|
|
1474
|
+
}
|
|
1475
|
+
if base_url_host_matches(base, "api.kimi.com"):
|
|
1476
|
+
headers["User-Agent"] = "claude-code/0.1.0"
|
|
1477
|
+
r = httpx.get(url, headers=headers, timeout=10)
|
|
1478
|
+
if (
|
|
1479
|
+
pname == "Alibaba/DashScope"
|
|
1480
|
+
and not base
|
|
1481
|
+
and r.status_code == 401
|
|
1482
|
+
):
|
|
1483
|
+
r = httpx.get(
|
|
1484
|
+
"https://dashscope.aliyuncs.com/compatible-mode/v1/models",
|
|
1485
|
+
headers=headers, timeout=10,
|
|
1486
|
+
)
|
|
1487
|
+
if r.status_code == 200:
|
|
1488
|
+
return _ConnectivityResult(
|
|
1489
|
+
pname,
|
|
1490
|
+
[(color("✓", Colors.GREEN), label, "")],
|
|
1491
|
+
[],
|
|
1492
|
+
)
|
|
1493
|
+
if r.status_code == 401:
|
|
1494
|
+
return _ConnectivityResult(
|
|
1495
|
+
pname,
|
|
1496
|
+
[(color("✗", Colors.RED), label,
|
|
1497
|
+
color("(invalid API key)", Colors.DIM))],
|
|
1498
|
+
[f"Check {env_vars[0]} in .env"],
|
|
1499
|
+
)
|
|
1500
|
+
return _ConnectivityResult(
|
|
1501
|
+
pname,
|
|
1502
|
+
[(color("⚠", Colors.YELLOW), label,
|
|
1503
|
+
color(f"(HTTP {r.status_code})", Colors.DIM))],
|
|
1504
|
+
[],
|
|
1505
|
+
)
|
|
1506
|
+
except Exception as e:
|
|
1507
|
+
return _ConnectivityResult(
|
|
1508
|
+
pname,
|
|
1509
|
+
[(color("⚠", Colors.YELLOW), label,
|
|
1510
|
+
color(f"({e})", Colors.DIM))],
|
|
1511
|
+
[],
|
|
1512
|
+
)
|
|
1513
|
+
|
|
1514
|
+
def _probe_bedrock() -> _ConnectivityResult:
|
|
1515
|
+
try:
|
|
1516
|
+
from agent.bedrock_adapter import (
|
|
1517
|
+
has_aws_credentials,
|
|
1518
|
+
resolve_aws_auth_env_var,
|
|
1519
|
+
resolve_bedrock_region,
|
|
1520
|
+
)
|
|
1521
|
+
except ImportError:
|
|
1522
|
+
return _ConnectivityResult("AWS Bedrock", [], [])
|
|
1523
|
+
if not has_aws_credentials():
|
|
1524
|
+
return _ConnectivityResult("AWS Bedrock", [], [])
|
|
1525
|
+
auth_var = resolve_aws_auth_env_var()
|
|
1526
|
+
region = resolve_bedrock_region()
|
|
1527
|
+
label = "AWS Bedrock".ljust(20)
|
|
1528
|
+
try:
|
|
1529
|
+
import boto3
|
|
1530
|
+
from botocore.config import Config as _BotoConfig
|
|
1531
|
+
# Trim retries on the actual Bedrock API call so a transient
|
|
1532
|
+
# failure doesn't pad the doctor run by 30+ seconds.
|
|
1533
|
+
cfg = _BotoConfig(
|
|
1534
|
+
connect_timeout=5,
|
|
1535
|
+
read_timeout=10,
|
|
1536
|
+
retries={"max_attempts": 1},
|
|
1537
|
+
)
|
|
1538
|
+
client = boto3.client("bedrock", region_name=region, config=cfg)
|
|
1539
|
+
resp = client.list_foundation_models()
|
|
1540
|
+
n = len(resp.get("modelSummaries", []))
|
|
1541
|
+
return _ConnectivityResult(
|
|
1542
|
+
"AWS Bedrock",
|
|
1543
|
+
[(color("✓", Colors.GREEN), label,
|
|
1544
|
+
color(f"({auth_var}, {region}, {n} models)", Colors.DIM))],
|
|
1545
|
+
[],
|
|
1546
|
+
)
|
|
1547
|
+
except ImportError:
|
|
1548
|
+
return _ConnectivityResult(
|
|
1549
|
+
"AWS Bedrock",
|
|
1550
|
+
[(color("⚠", Colors.YELLOW), label,
|
|
1551
|
+
color(f"(boto3 not installed — {sys.executable} -m pip install boto3)",
|
|
1552
|
+
Colors.DIM))],
|
|
1553
|
+
[f"Install boto3 for Bedrock: {sys.executable} -m pip install boto3"],
|
|
1554
|
+
)
|
|
1555
|
+
except Exception as e:
|
|
1556
|
+
err_name = type(e).__name__
|
|
1557
|
+
return _ConnectivityResult(
|
|
1558
|
+
"AWS Bedrock",
|
|
1559
|
+
[(color("⚠", Colors.YELLOW), label,
|
|
1560
|
+
color(f"({err_name}: {e})", Colors.DIM))],
|
|
1561
|
+
[f"AWS Bedrock: {err_name} — check IAM permissions for "
|
|
1562
|
+
f"bedrock:ListFoundationModels"],
|
|
1563
|
+
)
|
|
1564
|
+
|
|
1565
|
+
# Build the probe submission list in display order
|
|
1566
|
+
_probes.append(("OpenRouter API", _probe_openrouter))
|
|
1567
|
+
_probes.append(("Anthropic API", _probe_anthropic))
|
|
1568
|
+
|
|
1569
|
+
global _APIKEY_PROVIDERS_CACHE
|
|
1570
|
+
if _APIKEY_PROVIDERS_CACHE is None:
|
|
1571
|
+
_APIKEY_PROVIDERS_CACHE = _build_apikey_providers_list()
|
|
1572
|
+
for _entry in _APIKEY_PROVIDERS_CACHE:
|
|
1573
|
+
_pname, _env_vars, _default_url, _base_env, _supports = _entry
|
|
1574
|
+
# Capture loop vars by binding default args — without this, all closures
|
|
1575
|
+
# would share the final iteration's values and every probe would hit
|
|
1576
|
+
# the last provider's URL.
|
|
1577
|
+
_probes.append((_pname, lambda p=_pname, e=_env_vars, u=_default_url,
|
|
1578
|
+
b=_base_env, s=_supports:
|
|
1579
|
+
_probe_apikey_provider(p, e, u, b, s)))
|
|
1580
|
+
|
|
1581
|
+
_probes.append(("AWS Bedrock", _probe_bedrock))
|
|
1582
|
+
|
|
1583
|
+
# Print a single status line so users see something happening, then
|
|
1584
|
+
# fan out. ``\r`` clears it once the first real result line lands.
|
|
1585
|
+
print(f" {color(f'Running {len(_probes)} connectivity checks in parallel…', Colors.DIM)}",
|
|
1586
|
+
end="", flush=True)
|
|
1587
|
+
|
|
1588
|
+
# Disable boto3's EC2 instance-metadata-service probe for the duration
|
|
1589
|
+
# of the parallel block. boto's default credential chain tries
|
|
1590
|
+
# 169.254.169.254 with a multi-second timeout when we're not on EC2,
|
|
1591
|
+
# which dominated the section's wall time before this fix
|
|
1592
|
+
# (~2s on a developer laptop, even with the rest parallelized).
|
|
1593
|
+
# Set on the parent thread before submitting work so the env-var
|
|
1594
|
+
# mutation never races with another worker. has_aws_credentials() in
|
|
1595
|
+
# the bedrock probe already gates on real env-var creds, so IMDS is
|
|
1596
|
+
# never the legitimate source for `hermes doctor`.
|
|
1597
|
+
_imds_prev = os.environ.get("AWS_EC2_METADATA_DISABLED")
|
|
1598
|
+
os.environ["AWS_EC2_METADATA_DISABLED"] = "true"
|
|
1599
|
+
try:
|
|
1600
|
+
# 8 workers is plenty — each probe is a single HTTP call plus a TLS
|
|
1601
|
+
# handshake. More than that wastes thread-startup cost and risks
|
|
1602
|
+
# noisy output if anything ever printed from inside a worker.
|
|
1603
|
+
with _futures.ThreadPoolExecutor(max_workers=8,
|
|
1604
|
+
thread_name_prefix="doctor-probe") as _ex:
|
|
1605
|
+
_futures_in_order = [_ex.submit(_fn) for _, _fn in _probes]
|
|
1606
|
+
_results = [_f.result() for _f in _futures_in_order]
|
|
1607
|
+
finally:
|
|
1608
|
+
if _imds_prev is None:
|
|
1609
|
+
os.environ.pop("AWS_EC2_METADATA_DISABLED", None)
|
|
1610
|
+
else:
|
|
1611
|
+
os.environ["AWS_EC2_METADATA_DISABLED"] = _imds_prev
|
|
1612
|
+
|
|
1613
|
+
# Clear the "Running …" line and print all results in submission order.
|
|
1614
|
+
print("\r" + " " * 70 + "\r", end="")
|
|
1615
|
+
for _r in _results:
|
|
1616
|
+
for _glyph, _label, _detail in _r.lines:
|
|
1617
|
+
if _detail:
|
|
1618
|
+
print(f" {_glyph} {_label} {_detail}")
|
|
1619
|
+
else:
|
|
1620
|
+
print(f" {_glyph} {_label}")
|
|
1621
|
+
_issues_to_add = list(_r.issues)
|
|
1622
|
+
if _issues_to_add and _has_healthy_oauth_fallback_for_apikey_provider(_r.label):
|
|
1623
|
+
_issues_to_add = []
|
|
1624
|
+
for _issue in _issues_to_add:
|
|
1625
|
+
issues.append(_issue)
|
|
1626
|
+
|
|
1627
|
+
# =========================================================================
|
|
1628
|
+
# Check: Tool Availability
|
|
1629
|
+
# =========================================================================
|
|
1630
|
+
print()
|
|
1631
|
+
print(color("◆ Tool Availability", Colors.CYAN, Colors.BOLD))
|
|
1632
|
+
|
|
1633
|
+
try:
|
|
1634
|
+
# Add project root to path for imports
|
|
1635
|
+
sys.path.insert(0, str(PROJECT_ROOT))
|
|
1636
|
+
from model_tools import check_tool_availability, TOOLSET_REQUIREMENTS
|
|
1637
|
+
|
|
1638
|
+
available, unavailable = check_tool_availability()
|
|
1639
|
+
available, unavailable = _apply_doctor_tool_availability_overrides(available, unavailable)
|
|
1640
|
+
|
|
1641
|
+
for tid in available:
|
|
1642
|
+
info = TOOLSET_REQUIREMENTS.get(tid, {})
|
|
1643
|
+
check_ok(info.get("name", tid), _doctor_tool_availability_detail(tid))
|
|
1644
|
+
|
|
1645
|
+
for item in unavailable:
|
|
1646
|
+
env_vars = item.get("missing_vars") or item.get("env_vars") or []
|
|
1647
|
+
if env_vars:
|
|
1648
|
+
vars_str = ", ".join(env_vars)
|
|
1649
|
+
check_warn(item["name"], f"(missing {vars_str})")
|
|
1650
|
+
else:
|
|
1651
|
+
check_warn(item["name"], "(system dependency not met)")
|
|
1652
|
+
|
|
1653
|
+
# Count disabled tools with API key requirements
|
|
1654
|
+
api_disabled = [u for u in unavailable if (u.get("missing_vars") or u.get("env_vars"))]
|
|
1655
|
+
if api_disabled:
|
|
1656
|
+
issues.append("Run 'hermes setup' to configure missing API keys for full tool access")
|
|
1657
|
+
except Exception as e:
|
|
1658
|
+
check_warn("Could not check tool availability", f"({e})")
|
|
1659
|
+
|
|
1660
|
+
# =========================================================================
|
|
1661
|
+
# Check: Skills Hub
|
|
1662
|
+
# =========================================================================
|
|
1663
|
+
print()
|
|
1664
|
+
print(color("◆ Skills Hub", Colors.CYAN, Colors.BOLD))
|
|
1665
|
+
|
|
1666
|
+
hub_dir = HERMES_HOME / "skills" / ".hub"
|
|
1667
|
+
if hub_dir.exists():
|
|
1668
|
+
check_ok("Skills Hub directory exists")
|
|
1669
|
+
lock_file = hub_dir / "lock.json"
|
|
1670
|
+
if lock_file.exists():
|
|
1671
|
+
try:
|
|
1672
|
+
import json
|
|
1673
|
+
lock_data = json.loads(lock_file.read_text())
|
|
1674
|
+
count = len(lock_data.get("installed", {}))
|
|
1675
|
+
check_ok(f"Lock file OK ({count} hub-installed skill(s))")
|
|
1676
|
+
except Exception:
|
|
1677
|
+
check_warn("Lock file", "(corrupted or unreadable)")
|
|
1678
|
+
quarantine = hub_dir / "quarantine"
|
|
1679
|
+
q_count = sum(1 for d in quarantine.iterdir() if d.is_dir()) if quarantine.exists() else 0
|
|
1680
|
+
if q_count > 0:
|
|
1681
|
+
check_warn(f"{q_count} skill(s) in quarantine", "(pending review)")
|
|
1682
|
+
else:
|
|
1683
|
+
check_warn("Skills Hub directory not initialized", "(run: hermes skills list)")
|
|
1684
|
+
|
|
1685
|
+
from hermes_cli.config import get_env_value
|
|
1686
|
+
|
|
1687
|
+
def _gh_authenticated() -> bool:
|
|
1688
|
+
"""Check if gh CLI is authenticated via token file or device flow."""
|
|
1689
|
+
try:
|
|
1690
|
+
result = subprocess.run(
|
|
1691
|
+
["gh", "auth", "status", "--json", "authenticated"],
|
|
1692
|
+
capture_output=True, timeout=10,
|
|
1693
|
+
)
|
|
1694
|
+
return result.returncode == 0
|
|
1695
|
+
except (FileNotFoundError, subprocess.TimeoutExpired):
|
|
1696
|
+
return False
|
|
1697
|
+
|
|
1698
|
+
github_token = get_env_value("GITHUB_TOKEN") or get_env_value("GH_TOKEN")
|
|
1699
|
+
if github_token:
|
|
1700
|
+
check_ok("GitHub token configured (authenticated API access)")
|
|
1701
|
+
elif _gh_authenticated():
|
|
1702
|
+
check_ok("GitHub authenticated via gh CLI", "(full API access — no GITHUB_TOKEN needed)")
|
|
1703
|
+
else:
|
|
1704
|
+
check_warn("No GITHUB_TOKEN", f"(60 req/hr rate limit — set in {_DHH}/.env for better rates)")
|
|
1705
|
+
|
|
1706
|
+
# =========================================================================
|
|
1707
|
+
# Memory Provider (only check the active provider, if any)
|
|
1708
|
+
# =========================================================================
|
|
1709
|
+
print()
|
|
1710
|
+
print(color("◆ Memory Provider", Colors.CYAN, Colors.BOLD))
|
|
1711
|
+
|
|
1712
|
+
_active_memory_provider = ""
|
|
1713
|
+
try:
|
|
1714
|
+
import yaml as _yaml
|
|
1715
|
+
_mem_cfg_path = HERMES_HOME / "config.yaml"
|
|
1716
|
+
if _mem_cfg_path.exists():
|
|
1717
|
+
with open(_mem_cfg_path, encoding="utf-8") as _f:
|
|
1718
|
+
_raw_cfg = _yaml.safe_load(_f) or {}
|
|
1719
|
+
_active_memory_provider = (_raw_cfg.get("memory") or {}).get("provider", "")
|
|
1720
|
+
except Exception:
|
|
1721
|
+
pass
|
|
1722
|
+
|
|
1723
|
+
if not _active_memory_provider:
|
|
1724
|
+
check_ok("Built-in memory active", "(no external provider configured — this is fine)")
|
|
1725
|
+
elif _active_memory_provider == "honcho":
|
|
1726
|
+
try:
|
|
1727
|
+
from plugins.memory.honcho.client import HonchoClientConfig, resolve_config_path
|
|
1728
|
+
hcfg = HonchoClientConfig.from_global_config()
|
|
1729
|
+
_honcho_cfg_path = resolve_config_path()
|
|
1730
|
+
|
|
1731
|
+
if not _honcho_cfg_path.exists():
|
|
1732
|
+
check_warn("Honcho config not found", "run: hermes memory setup")
|
|
1733
|
+
elif not hcfg.enabled:
|
|
1734
|
+
check_info(f"Honcho disabled (set enabled: true in {_honcho_cfg_path} to activate)")
|
|
1735
|
+
elif not (hcfg.api_key or hcfg.base_url):
|
|
1736
|
+
check_fail("Honcho API key or base URL not set", "run: hermes memory setup")
|
|
1737
|
+
issues.append("No Honcho API key — run 'hermes memory setup'")
|
|
1738
|
+
else:
|
|
1739
|
+
from plugins.memory.honcho.client import get_honcho_client, reset_honcho_client
|
|
1740
|
+
reset_honcho_client()
|
|
1741
|
+
try:
|
|
1742
|
+
get_honcho_client(hcfg)
|
|
1743
|
+
check_ok(
|
|
1744
|
+
"Honcho connected",
|
|
1745
|
+
f"workspace={hcfg.workspace_id} mode={hcfg.recall_mode} freq={hcfg.write_frequency}",
|
|
1746
|
+
)
|
|
1747
|
+
except Exception as _e:
|
|
1748
|
+
check_fail("Honcho connection failed", str(_e))
|
|
1749
|
+
issues.append(f"Honcho unreachable: {_e}")
|
|
1750
|
+
except ImportError:
|
|
1751
|
+
check_fail("honcho-ai not installed", "pip install honcho-ai")
|
|
1752
|
+
issues.append("Honcho is set as memory provider but honcho-ai is not installed")
|
|
1753
|
+
except Exception as _e:
|
|
1754
|
+
check_warn("Honcho check failed", str(_e))
|
|
1755
|
+
elif _active_memory_provider == "mem0":
|
|
1756
|
+
try:
|
|
1757
|
+
from plugins.memory.mem0 import _load_config as _load_mem0_config
|
|
1758
|
+
mem0_cfg = _load_mem0_config()
|
|
1759
|
+
mem0_key = mem0_cfg.get("api_key", "")
|
|
1760
|
+
if mem0_key:
|
|
1761
|
+
check_ok("Mem0 API key configured")
|
|
1762
|
+
check_info(f"user_id={mem0_cfg.get('user_id', '?')} agent_id={mem0_cfg.get('agent_id', '?')}")
|
|
1763
|
+
else:
|
|
1764
|
+
check_fail("Mem0 API key not set", "(set MEM0_API_KEY in .env or run hermes memory setup)")
|
|
1765
|
+
issues.append("Mem0 is set as memory provider but API key is missing")
|
|
1766
|
+
except ImportError:
|
|
1767
|
+
check_fail("Mem0 plugin not loadable", "pip install mem0ai")
|
|
1768
|
+
issues.append("Mem0 is set as memory provider but mem0ai is not installed")
|
|
1769
|
+
except Exception as _e:
|
|
1770
|
+
check_warn("Mem0 check failed", str(_e))
|
|
1771
|
+
else:
|
|
1772
|
+
# Generic check for other memory providers (openviking, hindsight, etc.)
|
|
1773
|
+
try:
|
|
1774
|
+
from plugins.memory import load_memory_provider
|
|
1775
|
+
_provider = load_memory_provider(_active_memory_provider)
|
|
1776
|
+
if _provider and _provider.is_available():
|
|
1777
|
+
check_ok(f"{_active_memory_provider} provider active")
|
|
1778
|
+
elif _provider:
|
|
1779
|
+
check_warn(f"{_active_memory_provider} configured but not available", "run: hermes memory status")
|
|
1780
|
+
else:
|
|
1781
|
+
check_warn(f"{_active_memory_provider} plugin not found", "run: hermes memory setup")
|
|
1782
|
+
except Exception as _e:
|
|
1783
|
+
check_warn(f"{_active_memory_provider} check failed", str(_e))
|
|
1784
|
+
|
|
1785
|
+
# =========================================================================
|
|
1786
|
+
# Profiles
|
|
1787
|
+
# =========================================================================
|
|
1788
|
+
try:
|
|
1789
|
+
from hermes_cli.profiles import list_profiles, _get_wrapper_dir, profile_exists
|
|
1790
|
+
import re as _re
|
|
1791
|
+
|
|
1792
|
+
named_profiles = [p for p in list_profiles() if not p.is_default]
|
|
1793
|
+
if named_profiles:
|
|
1794
|
+
print()
|
|
1795
|
+
print(color("◆ Profiles", Colors.CYAN, Colors.BOLD))
|
|
1796
|
+
check_ok(f"{len(named_profiles)} profile(s) found")
|
|
1797
|
+
wrapper_dir = _get_wrapper_dir()
|
|
1798
|
+
for p in named_profiles:
|
|
1799
|
+
parts = []
|
|
1800
|
+
if p.gateway_running:
|
|
1801
|
+
parts.append("gateway running")
|
|
1802
|
+
if p.model:
|
|
1803
|
+
parts.append(p.model[:30])
|
|
1804
|
+
if not (p.path / "config.yaml").exists():
|
|
1805
|
+
parts.append("⚠ missing config")
|
|
1806
|
+
if not (p.path / ".env").exists():
|
|
1807
|
+
parts.append("no .env")
|
|
1808
|
+
wrapper = wrapper_dir / p.name
|
|
1809
|
+
if not wrapper.exists():
|
|
1810
|
+
parts.append("no alias")
|
|
1811
|
+
status = ", ".join(parts) if parts else "configured"
|
|
1812
|
+
check_ok(f" {p.name}: {status}")
|
|
1813
|
+
|
|
1814
|
+
# Check for orphan wrappers
|
|
1815
|
+
if wrapper_dir.is_dir():
|
|
1816
|
+
for wrapper in wrapper_dir.iterdir():
|
|
1817
|
+
if not wrapper.is_file():
|
|
1818
|
+
continue
|
|
1819
|
+
try:
|
|
1820
|
+
content = wrapper.read_text()
|
|
1821
|
+
if "hermes -p" in content:
|
|
1822
|
+
_m = _re.search(r"hermes -p (\S+)", content)
|
|
1823
|
+
if _m and not profile_exists(_m.group(1)):
|
|
1824
|
+
check_warn(f"Orphan alias: {wrapper.name} → profile '{_m.group(1)}' no longer exists")
|
|
1825
|
+
except Exception:
|
|
1826
|
+
pass
|
|
1827
|
+
except ImportError:
|
|
1828
|
+
pass
|
|
1829
|
+
except Exception:
|
|
1830
|
+
pass
|
|
1831
|
+
|
|
1832
|
+
# =========================================================================
|
|
1833
|
+
# Summary
|
|
1834
|
+
# =========================================================================
|
|
1835
|
+
print()
|
|
1836
|
+
remaining_issues = issues + manual_issues
|
|
1837
|
+
if should_fix and fixed_count > 0:
|
|
1838
|
+
print(color("─" * 60, Colors.GREEN))
|
|
1839
|
+
print(color(f" Fixed {fixed_count} issue(s).", Colors.GREEN, Colors.BOLD), end="")
|
|
1840
|
+
if remaining_issues:
|
|
1841
|
+
print(color(f" {len(remaining_issues)} issue(s) require manual intervention.", Colors.YELLOW, Colors.BOLD))
|
|
1842
|
+
else:
|
|
1843
|
+
print()
|
|
1844
|
+
print()
|
|
1845
|
+
if remaining_issues:
|
|
1846
|
+
for i, issue in enumerate(remaining_issues, 1):
|
|
1847
|
+
print(f" {i}. {issue}")
|
|
1848
|
+
print()
|
|
1849
|
+
elif remaining_issues:
|
|
1850
|
+
print(color("─" * 60, Colors.YELLOW))
|
|
1851
|
+
print(color(f" Found {len(remaining_issues)} issue(s) to address:", Colors.YELLOW, Colors.BOLD))
|
|
1852
|
+
print()
|
|
1853
|
+
for i, issue in enumerate(remaining_issues, 1):
|
|
1854
|
+
print(f" {i}. {issue}")
|
|
1855
|
+
print()
|
|
1856
|
+
if not should_fix:
|
|
1857
|
+
print(color(" Tip: run 'hermes doctor --fix' to auto-fix what's possible.", Colors.DIM))
|
|
1858
|
+
else:
|
|
1859
|
+
print(color("─" * 60, Colors.GREEN))
|
|
1860
|
+
print(color(" All checks passed! 🎉", Colors.GREEN, Colors.BOLD))
|
|
1861
|
+
|
|
1862
|
+
print()
|
|
1863
|
+
|