novacode-cli 1.2.0__py3-none-any.whl
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.
- novacode_cli/__init__.py +29 -0
- novacode_cli/__main__.py +6 -0
- novacode_cli/_lazy_heavy.py +99 -0
- novacode_cli/_version.py +3 -0
- novacode_cli/agent_stream.py +178 -0
- novacode_cli/agents/agent_file.py +250 -0
- novacode_cli/agents/agent_mailbox.py +120 -0
- novacode_cli/agents/approval_decisions.py +146 -0
- novacode_cli/agents/arg_repair.py +196 -0
- novacode_cli/agents/async_agents/__init__.py +6 -0
- novacode_cli/agents/async_agents/_config.py +213 -0
- novacode_cli/agents/async_agents/_mcp_tools.py +192 -0
- novacode_cli/agents/async_agents/_specialist.py +84 -0
- novacode_cli/agents/async_agents/_test_commands.py +89 -0
- novacode_cli/agents/async_agents/_tools.py +432 -0
- novacode_cli/agents/async_agents/general_purpose.py +42 -0
- novacode_cli/agents/async_agents/langgraph.json +9 -0
- novacode_cli/agents/async_agents/research.py +22 -0
- novacode_cli/agents/async_context.py +303 -0
- novacode_cli/agents/async_on_demand.py +52 -0
- novacode_cli/agents/async_task_errors.py +75 -0
- novacode_cli/agents/async_workspace.py +27 -0
- novacode_cli/agents/attribution.py +165 -0
- novacode_cli/agents/browser_mode.py +119 -0
- novacode_cli/agents/btw_agent.py +71 -0
- novacode_cli/agents/caveman.py +352 -0
- novacode_cli/agents/caveman_support.py +370 -0
- novacode_cli/agents/code_mode.py +774 -0
- novacode_cli/agents/code_runtime.py +160 -0
- novacode_cli/agents/context_compaction.py +1339 -0
- novacode_cli/agents/core_agent.py +2710 -0
- novacode_cli/agents/default_subagents/__init__.py +24 -0
- novacode_cli/agents/default_subagents/async_subagents.py +296 -0
- novacode_cli/agents/default_subagents/builtin/browser-automation-agent.md +110 -0
- novacode_cli/agents/default_subagents/builtin/bug-fix-agent.md +22 -0
- novacode_cli/agents/default_subagents/builtin/bug-investigation-agent.md +42 -0
- novacode_cli/agents/default_subagents/builtin/code-explorer.md +37 -0
- novacode_cli/agents/default_subagents/builtin/code-review-agent.md +33 -0
- novacode_cli/agents/default_subagents/builtin/dependency-audit-agent.md +34 -0
- novacode_cli/agents/default_subagents/builtin/documentation-update-agent.md +46 -0
- novacode_cli/agents/default_subagents/builtin/performance-audit-agent.md +41 -0
- novacode_cli/agents/default_subagents/builtin/plan-scout-agent.md +64 -0
- novacode_cli/agents/default_subagents/builtin/refactoring-agent.md +35 -0
- novacode_cli/agents/default_subagents/builtin/refactoring-specialist-agent.md +175 -0
- novacode_cli/agents/default_subagents/builtin/security-audit-agent.md +96 -0
- novacode_cli/agents/default_subagents/builtin/test-generation-agent.md +33 -0
- novacode_cli/agents/default_subagents/builtin/test-runner-agent.md +55 -0
- novacode_cli/agents/default_subagents/prompt.py +88 -0
- novacode_cli/agents/default_subagents/subagents.py +138 -0
- novacode_cli/agents/dream_agent.py +93 -0
- novacode_cli/agents/edit_diagnostics.py +362 -0
- novacode_cli/agents/edit_fallback.py +62 -0
- novacode_cli/agents/handoff.py +166 -0
- novacode_cli/agents/invocation.py +152 -0
- novacode_cli/agents/model_budget.py +42 -0
- novacode_cli/agents/model_retry.py +113 -0
- novacode_cli/agents/model_router.py +420 -0
- novacode_cli/agents/openai_decisions.py +186 -0
- novacode_cli/agents/plan_agent/__init__.py +12 -0
- novacode_cli/agents/plan_agent/plan_agent.py +357 -0
- novacode_cli/agents/plan_agent/plan_mode_middleware.py +64 -0
- novacode_cli/agents/plan_execution.py +237 -0
- novacode_cli/agents/ponytail.py +66 -0
- novacode_cli/agents/prime.py +274 -0
- novacode_cli/agents/provider_caching.py +99 -0
- novacode_cli/agents/server_launcher.py +904 -0
- novacode_cli/agents/strict_tools.py +384 -0
- novacode_cli/agents/task_discipline.py +294 -0
- novacode_cli/agents/tool_call_repair.py +290 -0
- novacode_cli/agents/tool_offload.py +291 -0
- novacode_cli/agents/tool_search.py +806 -0
- novacode_cli/agents/tool_search_variants.py +106 -0
- novacode_cli/agents/tool_verdicts.py +1194 -0
- novacode_cli/agents/user_async_agents.py +312 -0
- novacode_cli/artifacts/__init__.py +10 -0
- novacode_cli/artifacts/registry.py +278 -0
- novacode_cli/artifacts/server.py +426 -0
- novacode_cli/assets/Nova.png +0 -0
- novacode_cli/assets/nova-avatar.png +0 -0
- novacode_cli/audio/__init__.py +301 -0
- novacode_cli/audio/capture.py +137 -0
- novacode_cli/audio/downloads.py +273 -0
- novacode_cli/audio/pipeline.py +391 -0
- novacode_cli/audio/playback.py +87 -0
- novacode_cli/audio/providers.py +208 -0
- novacode_cli/audio/speakable.py +78 -0
- novacode_cli/audio/stt.py +132 -0
- novacode_cli/audio/stt_deepgram.py +69 -0
- novacode_cli/audio/stt_elevenlabs.py +89 -0
- novacode_cli/audio/stt_parakeet.py +94 -0
- novacode_cli/audio/stt_whistle.py +61 -0
- novacode_cli/audio/summarize.py +92 -0
- novacode_cli/audio/tts.py +85 -0
- novacode_cli/audio/tts_kokoro.py +73 -0
- novacode_cli/audio/tts_orpheus.py +180 -0
- novacode_cli/audio/tts_pocket.py +131 -0
- novacode_cli/audio/tts_sano.py +69 -0
- novacode_cli/audio/vad.py +145 -0
- novacode_cli/backends/__init__.py +17 -0
- novacode_cli/backends/filesystem.py +894 -0
- novacode_cli/backends/native_search.py +92 -0
- novacode_cli/bootstrap/__init__.py +9 -0
- novacode_cli/bootstrap/env_snapshot.py +240 -0
- novacode_cli/bootstrap/steering.py +464 -0
- novacode_cli/bootstrap/vision_router.py +604 -0
- novacode_cli/brand.py +362 -0
- novacode_cli/cli_args.py +718 -0
- novacode_cli/commands/__init__.py +237 -0
- novacode_cli/commands/agents_commands.py +231 -0
- novacode_cli/commands/auth_handler.py +40 -0
- novacode_cli/commands/browser_use_handler.py +75 -0
- novacode_cli/commands/cache_handler.py +32 -0
- novacode_cli/commands/chat_handler.py +1357 -0
- novacode_cli/commands/ci_fix.py +171 -0
- novacode_cli/commands/claude_plan.py +331 -0
- novacode_cli/commands/codex_plan.py +195 -0
- novacode_cli/commands/commands.py +1113 -0
- novacode_cli/commands/create_handler.py +124 -0
- novacode_cli/commands/create_server.py +1887 -0
- novacode_cli/commands/cron_handler.py +119 -0
- novacode_cli/commands/dream_handler.py +203 -0
- novacode_cli/commands/effort_handler.py +65 -0
- novacode_cli/commands/evolution_handler.py +214 -0
- novacode_cli/commands/file_commands.py +381 -0
- novacode_cli/commands/handoff_handler.py +68 -0
- novacode_cli/commands/hooks_handler.py +269 -0
- novacode_cli/commands/init_handler.py +146 -0
- novacode_cli/commands/learning_handler.py +160 -0
- novacode_cli/commands/lite_mode_handler.py +76 -0
- novacode_cli/commands/log_commands.py +363 -0
- novacode_cli/commands/mcp_handler.py +29 -0
- novacode_cli/commands/model_handler.py +29 -0
- novacode_cli/commands/notifications_handler.py +158 -0
- novacode_cli/commands/onboard_handler.py +121 -0
- novacode_cli/commands/plan_handler.py +440 -0
- novacode_cli/commands/planner_usage.py +250 -0
- novacode_cli/commands/plugin_install_handler.py +38 -0
- novacode_cli/commands/plugins_handler.py +35 -0
- novacode_cli/commands/prime_handler.py +455 -0
- novacode_cli/commands/prompt_handler.py +149 -0
- novacode_cli/commands/provider_usage.py +160 -0
- novacode_cli/commands/ralph_events.py +106 -0
- novacode_cli/commands/ralph_handler.py +1293 -0
- novacode_cli/commands/refine_handler.py +213 -0
- novacode_cli/commands/research_handler.py +202 -0
- novacode_cli/commands/rootapp_remote.py +83 -0
- novacode_cli/commands/router_handler.py +36 -0
- novacode_cli/commands/server_commands.py +249 -0
- novacode_cli/commands/session_commands.py +203 -0
- novacode_cli/commands/share_handler.py +450 -0
- novacode_cli/commands/side_commands.py +366 -0
- novacode_cli/commands/skill_invoke.py +420 -0
- novacode_cli/commands/skills_commands.py +48 -0
- novacode_cli/commands/trace_handler.py +322 -0
- novacode_cli/commands/trello_handler.py +226 -0
- novacode_cli/commands/trello_remote.py +177 -0
- novacode_cli/commands/trello_server.py +1214 -0
- novacode_cli/commands/vision_handler.py +127 -0
- novacode_cli/commands/voice_handler.py +447 -0
- novacode_cli/commands/webhook_handler.py +134 -0
- novacode_cli/commands/wiki_commands.py +227 -0
- novacode_cli/compaction.py +753 -0
- novacode_cli/computation_cache.py +159 -0
- novacode_cli/computer/__init__.py +1 -0
- novacode_cli/computer/persistent.py +234 -0
- novacode_cli/computer/preview.py +253 -0
- novacode_cli/computer/runtime.py +474 -0
- novacode_cli/computer/windows_console.py +152 -0
- novacode_cli/computer/windows_qemu.py +211 -0
- novacode_cli/config/browser_mode.py +159 -0
- novacode_cli/config/catalog_models.py +95 -0
- novacode_cli/config/config.py +1388 -0
- novacode_cli/config/credentials.py +540 -0
- novacode_cli/config/google_oauth_auth.py +281 -0
- novacode_cli/config/model_capabilities.py +343 -0
- novacode_cli/config/model_catalog.py +275 -0
- novacode_cli/config/model_create.py +1325 -0
- novacode_cli/config/model_manager.py +695 -0
- novacode_cli/config/nova_config.py +1283 -0
- novacode_cli/config/openai_chatgpt_auth.py +384 -0
- novacode_cli/config/opencode_gateway.py +25 -0
- novacode_cli/config/plan_mode.py +188 -0
- novacode_cli/config/provider_auth.py +438 -0
- novacode_cli/config/provider_catalog.json +5127 -0
- novacode_cli/config/provider_registry.py +38 -0
- novacode_cli/config/provider_transports.py +258 -0
- novacode_cli/config/role_models.py +175 -0
- novacode_cli/context/__init__.py +50 -0
- novacode_cli/context/_analysis.py +799 -0
- novacode_cli/context/_budget.py +116 -0
- novacode_cli/context/_conversation.py +73 -0
- novacode_cli/context/_dynamic.py +264 -0
- novacode_cli/context/_model_config.py +380 -0
- novacode_cli/context/_models_dev.py +99 -0
- novacode_cli/context/archives.py +248 -0
- novacode_cli/context/estimates.py +65 -0
- novacode_cli/context/history.py +17 -0
- novacode_cli/context/knowledge_cache.py +292 -0
- novacode_cli/context/manager.py +101 -0
- novacode_cli/context/observations.py +65 -0
- novacode_cli/context/pressure.py +168 -0
- novacode_cli/context/provider_accounting.py +109 -0
- novacode_cli/context/snapshot.py +493 -0
- novacode_cli/context/strategies.py +279 -0
- novacode_cli/context/task_progress.py +122 -0
- novacode_cli/core/__init__.py +0 -0
- novacode_cli/core/agent_loop.py +1821 -0
- novacode_cli/core/autonomous_loop.py +277 -0
- novacode_cli/core/code_approvals.py +57 -0
- novacode_cli/core/input_preparation.py +276 -0
- novacode_cli/core/reasoning.py +67 -0
- novacode_cli/core/streaming.py +326 -0
- novacode_cli/core/subagent_tasks.py +696 -0
- novacode_cli/core/subagent_tracking.py +235 -0
- novacode_cli/core/tool_results.py +116 -0
- novacode_cli/core/verification_loop.py +272 -0
- novacode_cli/council.py +595 -0
- novacode_cli/council_consensus.py +115 -0
- novacode_cli/council_decision.py +157 -0
- novacode_cli/council_planner.py +1421 -0
- novacode_cli/council_settings.py +208 -0
- novacode_cli/council_web_settings.py +41 -0
- novacode_cli/council_workspace.py +56 -0
- novacode_cli/cowork/__init__.py +10 -0
- novacode_cli/cowork/broker_middleware.py +162 -0
- novacode_cli/cowork/launcher.py +102 -0
- novacode_cli/cowork/policy.py +284 -0
- novacode_cli/cowork/ui.py +826 -0
- novacode_cli/daemons/__init__.py +1 -0
- novacode_cli/daemons/registry.py +342 -0
- novacode_cli/desktop_notifications.py +302 -0
- novacode_cli/doctor.py +251 -0
- novacode_cli/embeddings.py +109 -0
- novacode_cli/entrypoint.py +56 -0
- novacode_cli/errors/__init__.py +19 -0
- novacode_cli/errors/handlers.py +648 -0
- novacode_cli/errors/provider_errors.py +249 -0
- novacode_cli/errors/taxonomy.py +80 -0
- novacode_cli/events.py +179 -0
- novacode_cli/file_ops.py +714 -0
- novacode_cli/git_safety.py +281 -0
- novacode_cli/handoff.py +383 -0
- novacode_cli/headless/__init__.py +18 -0
- novacode_cli/headless/input.py +58 -0
- novacode_cli/headless/output.py +224 -0
- novacode_cli/headless/pipe.py +532 -0
- novacode_cli/headless/runner.py +461 -0
- novacode_cli/hermes/__init__.py +39 -0
- novacode_cli/hermes/activation.py +297 -0
- novacode_cli/hermes/config.py +129 -0
- novacode_cli/hermes/curator.py +199 -0
- novacode_cli/hermes/evolution.py +374 -0
- novacode_cli/hermes/ledger.py +364 -0
- novacode_cli/hermes/memory_tiers.py +969 -0
- novacode_cli/hermes/middleware.py +678 -0
- novacode_cli/hermes/overview.py +174 -0
- novacode_cli/hermes/prompt_evolution.py +503 -0
- novacode_cli/hermes/refine_loop.py +643 -0
- novacode_cli/hermes/refinement_log.py +190 -0
- novacode_cli/hermes/review.py +674 -0
- novacode_cli/hermes/skill_debate.py +135 -0
- novacode_cli/hermes/skill_discovery.py +450 -0
- novacode_cli/hermes/skill_manager.py +335 -0
- novacode_cli/hermes/skill_proposals.py +43 -0
- novacode_cli/hermes/test_gaming.py +119 -0
- novacode_cli/hermes/tracker.py +435 -0
- novacode_cli/hermes/tuner.py +206 -0
- novacode_cli/hermes/verification_memory.py +134 -0
- novacode_cli/hermes/verifier.py +277 -0
- novacode_cli/hitl/__init__.py +22 -0
- novacode_cli/hitl/interrupts.py +493 -0
- novacode_cli/hooks.py +359 -0
- novacode_cli/image_utils.py +517 -0
- novacode_cli/init/__init__.py +7 -0
- novacode_cli/init/events.py +43 -0
- novacode_cli/input_utils.py +526 -0
- novacode_cli/install_commands.py +87 -0
- novacode_cli/integrations/__init__.py +82 -0
- novacode_cli/integrations/daytona.py +122 -0
- novacode_cli/integrations/docker.py +309 -0
- novacode_cli/integrations/host_path.py +111 -0
- novacode_cli/integrations/langsmith.py +151 -0
- novacode_cli/integrations/modal.py +134 -0
- novacode_cli/integrations/runloop.py +130 -0
- novacode_cli/integrations/sandbox_factory.py +1388 -0
- novacode_cli/integrations/sandbox_registry.py +312 -0
- novacode_cli/integrations/workdir_backend.py +589 -0
- novacode_cli/main.py +2078 -0
- novacode_cli/mcp/__init__.py +73 -0
- novacode_cli/mcp/auth.py +189 -0
- novacode_cli/mcp/client.py +571 -0
- novacode_cli/mcp/code_mode.py +5 -0
- novacode_cli/mcp/code_runtime.py +5 -0
- novacode_cli/mcp/commands.py +902 -0
- novacode_cli/mcp/config.py +406 -0
- novacode_cli/mcp/generic.py +128 -0
- novacode_cli/mcp/middleware.py +993 -0
- novacode_cli/mcp/presets.py +367 -0
- novacode_cli/memory/__init__.py +1 -0
- novacode_cli/memory/agent_memory.py +1312 -0
- novacode_cli/memory/builtin_lessons.py +60 -0
- novacode_cli/memory/dream_gates.py +192 -0
- novacode_cli/memory/limits.py +59 -0
- novacode_cli/memory/parsed_cache.py +106 -0
- novacode_cli/memory/recall_stats.py +97 -0
- novacode_cli/memory/semantic.py +116 -0
- novacode_cli/memory/store.py +335 -0
- novacode_cli/memory/wiki.py +274 -0
- novacode_cli/migrate.py +185 -0
- novacode_cli/onboarding.py +649 -0
- novacode_cli/onboarding_check.py +119 -0
- novacode_cli/path_approval.py +297 -0
- novacode_cli/plan_archive.py +148 -0
- novacode_cli/plugins/__init__.py +121 -0
- novacode_cli/plugins/claude_plugins.py +538 -0
- novacode_cli/plugins/cli.py +168 -0
- novacode_cli/plugins/components.py +413 -0
- novacode_cli/plugins/hooks.py +356 -0
- novacode_cli/plugins/loader.py +317 -0
- novacode_cli/plugins/marketplaces.py +199 -0
- novacode_cli/plugins/storage.py +70 -0
- novacode_cli/prime.py +759 -0
- novacode_cli/prime_factory/__init__.py +15 -0
- novacode_cli/prime_factory/container.py +198 -0
- novacode_cli/prime_factory/controller.py +565 -0
- novacode_cli/prime_factory/knowledge.py +261 -0
- novacode_cli/prime_factory/publication.py +218 -0
- novacode_cli/prime_factory/recovery.py +50 -0
- novacode_cli/prime_factory/research.py +370 -0
- novacode_cli/prime_factory/runner.py +608 -0
- novacode_cli/prime_factory/runtime.py +261 -0
- novacode_cli/prime_factory/state.py +201 -0
- novacode_cli/prime_factory/store.py +128 -0
- novacode_cli/prime_factory/worker.py +129 -0
- novacode_cli/prime_factory/workflow.py +899 -0
- novacode_cli/prime_factory/workspace.py +317 -0
- novacode_cli/prime_memory.py +290 -0
- novacode_cli/process_manager.py +585 -0
- novacode_cli/project_onboard.py +537 -0
- novacode_cli/prompts/System_Prompt_Nova.jinja +23 -0
- novacode_cli/prompts/__init__.py +168 -0
- novacode_cli/prompts/agent_definitions.jinja +11 -0
- novacode_cli/prompts/agent_generation.jinja +125 -0
- novacode_cli/prompts/async_agents/general_purpose.jinja +22 -0
- novacode_cli/prompts/claude_plan_mode.jinja +12 -0
- novacode_cli/prompts/coding_workflow.jinja +18 -0
- novacode_cli/prompts/computer_use.jinja +17 -0
- novacode_cli/prompts/core_agent_system.jinja +81 -0
- novacode_cli/prompts/delegation.jinja +15 -0
- novacode_cli/prompts/desktop_power.jinja +4 -0
- novacode_cli/prompts/file_paths.jinja +15 -0
- novacode_cli/prompts/file_tracker.jinja +23 -0
- novacode_cli/prompts/init_agents_md.jinja +56 -0
- novacode_cli/prompts/init_exploration.jinja +174 -0
- novacode_cli/prompts/init_semantic_orchestrate.jinja +37 -0
- novacode_cli/prompts/instruction_scope.jinja +5 -0
- novacode_cli/prompts/learnings_extraction.jinja +45 -0
- novacode_cli/prompts/longterm_memory.jinja +54 -0
- novacode_cli/prompts/mcp.jinja +84 -0
- novacode_cli/prompts/memory_consolidation.jinja +40 -0
- novacode_cli/prompts/nova_evolution.jinja +73 -0
- novacode_cli/prompts/nova_review.jinja +158 -0
- novacode_cli/prompts/nova_skill_debate.jinja +36 -0
- novacode_cli/prompts/nova_standing_instructions.jinja +26 -0
- novacode_cli/prompts/nova_verify.jinja +100 -0
- novacode_cli/prompts/onboard_dashboard.jinja +378 -0
- novacode_cli/prompts/plan_agent.jinja +87 -0
- novacode_cli/prompts/plan_scouts.jinja +5 -0
- novacode_cli/prompts/plan_storage.jinja +8 -0
- novacode_cli/prompts/planning.jinja +82 -0
- novacode_cli/prompts/ponytail/LICENSE +21 -0
- novacode_cli/prompts/ponytail/UPSTREAM.json +15 -0
- novacode_cli/prompts/ponytail/hooks/ponytail-config.js +175 -0
- novacode_cli/prompts/ponytail/hooks/ponytail-instructions.js +98 -0
- novacode_cli/prompts/ponytail/skills/ponytail/SKILL.md +52 -0
- novacode_cli/prompts/ponytail/skills/ponytail-audit/SKILL.md +103 -0
- novacode_cli/prompts/ponytail/skills/ponytail-debt/SKILL.md +44 -0
- novacode_cli/prompts/ponytail/skills/ponytail-gain/SKILL.md +52 -0
- novacode_cli/prompts/ponytail/skills/ponytail-help/SKILL.md +76 -0
- novacode_cli/prompts/ponytail/skills/ponytail-review/SKILL.md +101 -0
- novacode_cli/prompts/prompt_evolution.jinja +27 -0
- novacode_cli/prompts/ralph_iteration.jinja +75 -0
- novacode_cli/prompts/refine_gate.jinja +31 -0
- novacode_cli/prompts/refine_plan.jinja +64 -0
- novacode_cli/prompts/refine_review.jinja +34 -0
- novacode_cli/prompts/research_delivery.jinja +9 -0
- novacode_cli/prompts/research_swarm.jinja +130 -0
- novacode_cli/prompts/response_style.jinja +5 -0
- novacode_cli/prompts/session_summarization.jinja +86 -0
- novacode_cli/prompts/skill_creation.jinja +85 -0
- novacode_cli/prompts/subagents/fact_checker.jinja +48 -0
- novacode_cli/prompts/subagents/financial_analyst.jinja +50 -0
- novacode_cli/prompts/subagents/literature_reviewer.jinja +52 -0
- novacode_cli/prompts/subagents/market_analyst.jinja +48 -0
- novacode_cli/prompts/subagents/research_synthesizer.jinja +57 -0
- novacode_cli/prompts/subagents/technical_researcher.jinja +56 -0
- novacode_cli/prompts/subagents/web_researcher.jinja +46 -0
- novacode_cli/prompts/summarization.jinja +107 -0
- novacode_cli/prompts/summarization_answers.jinja +23 -0
- novacode_cli/prompts/summarization_questions.jinja +32 -0
- novacode_cli/prompts/vision_caption.jinja +21 -0
- novacode_cli/prompts/voice_summary.jinja +65 -0
- novacode_cli/prompts/wiki_file.jinja +57 -0
- novacode_cli/prompts/wiki_ingest.jinja +87 -0
- novacode_cli/recovery.py +383 -0
- novacode_cli/remote/__init__.py +45 -0
- novacode_cli/remote/approvals.py +282 -0
- novacode_cli/remote/async_task_clients.py +97 -0
- novacode_cli/remote/async_task_watcher.py +240 -0
- novacode_cli/remote/bridge.py +905 -0
- novacode_cli/remote/command_menu.py +26 -0
- novacode_cli/remote/command_ui.py +243 -0
- novacode_cli/remote/config.py +199 -0
- novacode_cli/remote/discord_bridge.py +530 -0
- novacode_cli/remote/discord_format.py +31 -0
- novacode_cli/remote/discord_threads.py +225 -0
- novacode_cli/remote/images.py +97 -0
- novacode_cli/remote/processor.py +601 -0
- novacode_cli/remote/rootapp_bot/bot.cjs +16 -0
- novacode_cli/remote/rootapp_bot/package-lock.json +2683 -0
- novacode_cli/remote/rootapp_bot/package.json +18 -0
- novacode_cli/remote/rootapp_bot/transport.cjs +80 -0
- novacode_cli/remote/rootapp_bridge.py +370 -0
- novacode_cli/remote/rootapp_setup.py +89 -0
- novacode_cli/remote/routing.py +103 -0
- novacode_cli/remote/scheduler.py +302 -0
- novacode_cli/remote/session.py +164 -0
- novacode_cli/remote/status.py +411 -0
- novacode_cli/remote/streaming.py +188 -0
- novacode_cli/remote/telegram_bridge.py +1118 -0
- novacode_cli/remote/telegram_format.py +215 -0
- novacode_cli/remote/telegram_hub.py +256 -0
- novacode_cli/remote/voice_notes.py +120 -0
- novacode_cli/remote/webhook_adapters.py +167 -0
- novacode_cli/remote/webhook_server.py +154 -0
- novacode_cli/rewind.py +150 -0
- novacode_cli/rooms/__init__.py +1 -0
- novacode_cli/rooms/bridge.py +86 -0
- novacode_cli/rooms/cli.py +231 -0
- novacode_cli/rooms/nova.py +227 -0
- novacode_cli/rooms/runtime.py +299 -0
- novacode_cli/rooms/store.py +538 -0
- novacode_cli/rooms/workspace.py +94 -0
- novacode_cli/security/__init__.py +29 -0
- novacode_cli/security/approval_context.py +45 -0
- novacode_cli/security/delegated_approval.py +68 -0
- novacode_cli/security/local_http.py +85 -0
- novacode_cli/security/middleware.py +87 -0
- novacode_cli/security/paths.py +35 -0
- novacode_cli/security/policy.py +535 -0
- novacode_cli/security/policy_writer.py +90 -0
- novacode_cli/security/prompt_injection.py +203 -0
- novacode_cli/security/remember.py +81 -0
- novacode_cli/security/rule_synthesis.py +116 -0
- novacode_cli/security/secret_files.py +61 -0
- novacode_cli/security/session_allow.py +114 -0
- novacode_cli/security/unicode_security.py +516 -0
- novacode_cli/security/validator.py +173 -0
- novacode_cli/server/__init__.py +9 -0
- novacode_cli/server/app.py +632 -0
- novacode_cli/server/event_adapter.py +189 -0
- novacode_cli/server/session_manager.py +90 -0
- novacode_cli/server_main.py +64 -0
- novacode_cli/server_runner/dev_server.py +530 -0
- novacode_cli/server_runner/test_runner.py +470 -0
- novacode_cli/session/__init__.py +1 -0
- novacode_cli/session/adapters/__init__.py +240 -0
- novacode_cli/session/adapters/claude_code.py +102 -0
- novacode_cli/session/adapters/codex.py +77 -0
- novacode_cli/session/adapters/harness_native.py +75 -0
- novacode_cli/session/checkpoint_coordinator.py +448 -0
- novacode_cli/session/context_restore.py +25 -0
- novacode_cli/session/history_export.py +228 -0
- novacode_cli/session/history_tree.py +174 -0
- novacode_cli/session/imported_context.py +267 -0
- novacode_cli/session/runtime_identity.py +32 -0
- novacode_cli/session/session_persistence.py +1168 -0
- novacode_cli/session/session_prompt_builder.py +279 -0
- novacode_cli/session/session_restore.py +351 -0
- novacode_cli/session/session_summarization.py +20 -0
- novacode_cli/session/transcript_journal.py +153 -0
- novacode_cli/sessions/__init__.py +11 -0
- novacode_cli/sessions/gateway.py +84 -0
- novacode_cli/sessions/launch.py +51 -0
- novacode_cli/sessions/lease.py +213 -0
- novacode_cli/sessions/messaging.py +255 -0
- novacode_cli/sessions/protocol.py +216 -0
- novacode_cli/sessions/resume.py +31 -0
- novacode_cli/sessions/supervisor.py +498 -0
- novacode_cli/sessions/tasks.py +73 -0
- novacode_cli/sessions/tui_messaging.py +413 -0
- novacode_cli/sessions/worker.py +652 -0
- novacode_cli/sessions/worktree.py +262 -0
- novacode_cli/shell/__init__.py +27 -0
- novacode_cli/shell/jobs.py +475 -0
- novacode_cli/shell/middleware.py +1568 -0
- novacode_cli/shell/os_sandbox.py +205 -0
- novacode_cli/shell/output.py +181 -0
- novacode_cli/shell/patterns.py +275 -0
- novacode_cli/shell/processes.py +87 -0
- novacode_cli/shell/utils.py +236 -0
- novacode_cli/skills/__init__.py +26 -0
- novacode_cli/skills/builtin/handoff/SKILL.md +15 -0
- novacode_cli/skills/curation_middleware.py +69 -0
- novacode_cli/skills/executable.py +161 -0
- novacode_cli/skills/libraries.py +102 -0
- novacode_cli/skills/load.py +248 -0
- novacode_cli/skills/prune.py +215 -0
- novacode_cli/skills/refreshing_middleware.py +896 -0
- novacode_cli/skills/retrieval.py +248 -0
- novacode_cli/skills/runtime.py +118 -0
- novacode_cli/skills/schema.py +254 -0
- novacode_cli/skills/skill_creation.py +1549 -0
- novacode_cli/skills/skill_lock.py +75 -0
- novacode_cli/skills/skill_system_prompt.py +16 -0
- novacode_cli/skills/skills_prefs.py +126 -0
- novacode_cli/skills/tool_resolver.py +31 -0
- novacode_cli/skills/upstream.py +50 -0
- novacode_cli/skills/versioning.py +291 -0
- novacode_cli/states/Session.py +847 -0
- novacode_cli/states/__init__.py +31 -0
- novacode_cli/states/slices/__init__.py +17 -0
- novacode_cli/states/slices/agent_runtime.py +249 -0
- novacode_cli/states/slices/background_tasks.py +21 -0
- novacode_cli/states/slices/notifications.py +74 -0
- novacode_cli/states/slices/remote_bridge.py +56 -0
- novacode_cli/states/slices/ui_settings.py +49 -0
- novacode_cli/states/slices/wiki.py +25 -0
- novacode_cli/teammates/__init__.py +1 -0
- novacode_cli/teammates/controller.py +557 -0
- novacode_cli/teammates/graph.py +104 -0
- novacode_cli/teammates/registry.py +175 -0
- novacode_cli/teammates/service.py +254 -0
- novacode_cli/teammates/worker.py +19 -0
- novacode_cli/teams/__init__.py +1 -0
- novacode_cli/teams/adapters/__init__.py +1 -0
- novacode_cli/teams/adapters/container.py +316 -0
- novacode_cli/teams/adapters/inprocess.py +206 -0
- novacode_cli/teams/adapters/process.py +364 -0
- novacode_cli/teams/bootstrap.py +246 -0
- novacode_cli/teams/container_git.py +67 -0
- novacode_cli/teams/context.py +34 -0
- novacode_cli/teams/coordinator.py +815 -0
- novacode_cli/teams/gateway.py +200 -0
- novacode_cli/teams/host.py +64 -0
- novacode_cli/teams/legacy.py +52 -0
- novacode_cli/teams/middleware.py +176 -0
- novacode_cli/teams/models.py +104 -0
- novacode_cli/teams/output.py +47 -0
- novacode_cli/teams/protocol.py +50 -0
- novacode_cli/teams/recovery.py +80 -0
- novacode_cli/teams/scheduler.py +44 -0
- novacode_cli/teams/store.py +631 -0
- novacode_cli/teams/worker.py +251 -0
- novacode_cli/teams/workspace.py +100 -0
- novacode_cli/token_utils.py +256 -0
- novacode_cli/tools/__init__.py +104 -0
- novacode_cli/tools/_shared.py +97 -0
- novacode_cli/tools/_types.py +24 -0
- novacode_cli/tools/artifact_tools.py +137 -0
- novacode_cli/tools/code_search_tools.py +330 -0
- novacode_cli/tools/computer_tools.py +77 -0
- novacode_cli/tools/cron_tools.py +65 -0
- novacode_cli/tools/daemon_tool.py +290 -0
- novacode_cli/tools/desktop_tools.py +161 -0
- novacode_cli/tools/fetch_tools.py +530 -0
- novacode_cli/tools/http_tools.py +279 -0
- novacode_cli/tools/inspection_tools.py +107 -0
- novacode_cli/tools/job_tools.py +143 -0
- novacode_cli/tools/knowledge_tools.py +427 -0
- novacode_cli/tools/memory_tools.py +461 -0
- novacode_cli/tools/memory_wiki_tools.py +40 -0
- novacode_cli/tools/notebook_tools.py +238 -0
- novacode_cli/tools/oracle_tool.py +83 -0
- novacode_cli/tools/plan_archive_tools.py +80 -0
- novacode_cli/tools/plan_mode_tools.py +315 -0
- novacode_cli/tools/python_kernel_loop.py +165 -0
- novacode_cli/tools/python_kernel_tool.py +222 -0
- novacode_cli/tools/reflection_tools.py +34 -0
- novacode_cli/tools/scraper_tools.py +377 -0
- novacode_cli/tools/skill_tools.py +275 -0
- novacode_cli/tools/speak_tool.py +51 -0
- novacode_cli/tools/store_memory_tools.py +227 -0
- novacode_cli/tools/ui_tools.py +62 -0
- novacode_cli/tools/waiter_tools.py +408 -0
- novacode_cli/tools/web_tools.py +349 -0
- novacode_cli/tools/wiki_tools.py +152 -0
- novacode_cli/tools/worktree_tools.py +219 -0
- novacode_cli/tracking/__init__.py +10 -0
- novacode_cli/tracking/file_tracker.py +826 -0
- novacode_cli/tracking/local_metrics.py +170 -0
- novacode_cli/tracking/loop_guard.py +507 -0
- novacode_cli/tracking/request_metrics.py +60 -0
- novacode_cli/tracking/tracing.py +692 -0
- novacode_cli/tracking/usage_tree.py +677 -0
- novacode_cli/tracking/workspace_anchoring.py +231 -0
- novacode_cli/tui/__init__.py +11 -0
- novacode_cli/tui/animation_rate.py +9 -0
- novacode_cli/tui/animations.py +332 -0
- novacode_cli/tui/app.py +19315 -0
- novacode_cli/tui/auth_display.py +87 -0
- novacode_cli/tui/auth_screens.py +826 -0
- novacode_cli/tui/avatar.py +294 -0
- novacode_cli/tui/avatar_frames.py +21 -0
- novacode_cli/tui/background_tasks.py +35 -0
- novacode_cli/tui/browser_settings_screen.py +70 -0
- novacode_cli/tui/caveman_screen.py +185 -0
- novacode_cli/tui/council_settings_screen.py +182 -0
- novacode_cli/tui/council_view.py +535 -0
- novacode_cli/tui/decision_settings.py +268 -0
- novacode_cli/tui/diff_preview.py +199 -0
- novacode_cli/tui/gc_tuning.py +63 -0
- novacode_cli/tui/handoff_screen.py +206 -0
- novacode_cli/tui/harness.py +244 -0
- novacode_cli/tui/history_tree_screen.py +179 -0
- novacode_cli/tui/home.py +328 -0
- novacode_cli/tui/home_scene.py +94 -0
- novacode_cli/tui/icons.py +81 -0
- novacode_cli/tui/interface_styles.tcss +327 -0
- novacode_cli/tui/matrix3.py +108 -0
- novacode_cli/tui/mcp_tools_screen.py +131 -0
- novacode_cli/tui/motion.py +178 -0
- novacode_cli/tui/output_body.py +136 -0
- novacode_cli/tui/output_buffer.py +59 -0
- novacode_cli/tui/palette.py +334 -0
- novacode_cli/tui/pickers.py +237 -0
- novacode_cli/tui/prime_panel.py +506 -0
- novacode_cli/tui/provider_signin.py +213 -0
- novacode_cli/tui/pty_shell.py +159 -0
- novacode_cli/tui/reference_screens.py +444 -0
- novacode_cli/tui/resume_picker.py +346 -0
- novacode_cli/tui/rooms.py +597 -0
- novacode_cli/tui/screens.py +7088 -0
- novacode_cli/tui/session_import.py +333 -0
- novacode_cli/tui/session_pane.py +242 -0
- novacode_cli/tui/session_tab.py +42 -0
- novacode_cli/tui/session_transcript.py +118 -0
- novacode_cli/tui/shell_output.py +7 -0
- novacode_cli/tui/stall_watch.py +174 -0
- novacode_cli/tui/statusline.py +40 -0
- novacode_cli/tui/statusline_screen.py +91 -0
- novacode_cli/tui/teammate_updates.py +162 -0
- novacode_cli/tui/teammates.py +548 -0
- novacode_cli/tui/terminal.py +289 -0
- novacode_cli/tui/terminal_view.py +235 -0
- novacode_cli/tui/themes.py +118 -0
- novacode_cli/tui/update_notice.py +84 -0
- novacode_cli/tui/voice_downloads.py +113 -0
- novacode_cli/tui/widgets.py +2038 -0
- novacode_cli/tui/windows_input.py +38 -0
- novacode_cli/tui/workspace_approval.py +165 -0
- novacode_cli/ui/council_web.py +113 -0
- novacode_cli/ui/council_workspace.py +72 -0
- novacode_cli/ui/cowork_web.py +41 -0
- novacode_cli/ui/diff_highlight.py +160 -0
- novacode_cli/ui/execution.py +1396 -0
- novacode_cli/ui/exit_summary.py +65 -0
- novacode_cli/ui/hitl_approval.py +196 -0
- novacode_cli/ui/input_preparation.py +2 -0
- novacode_cli/ui/interrupt_handlers.py +215 -0
- novacode_cli/ui/question_prompt.py +151 -0
- novacode_cli/ui/status_phrases.py +157 -0
- novacode_cli/ui/stream_preview.py +66 -0
- novacode_cli/ui/streaming.py +2 -0
- novacode_cli/ui/subagent_tracking.py +2 -0
- novacode_cli/ui/ui_elements.py +1585 -0
- novacode_cli/ui/web_workspace.py +244 -0
- novacode_cli/ui_events.py +299 -0
- novacode_cli/update_ui.py +243 -0
- novacode_cli/updates.py +489 -0
- novacode_cli/utils/backend_patches.py +399 -0
- novacode_cli/utils/backend_paths.py +467 -0
- novacode_cli/utils/lazy_providers.py +51 -0
- novacode_cli/utils/model_info.py +223 -0
- novacode_cli/utils/pdf_extraction.py +183 -0
- novacode_cli/utils/startup.py +29 -0
- novacode_cli/utils/tasks.py +42 -0
- novacode_cli/utils/windows.py +9 -0
- novacode_cli/vixie/hook_adapter.py +127 -0
- novacode_cli/vixie/server.py +375 -0
- novacode_cli/wiki/__init__.py +15 -0
- novacode_cli/wiki/ask.py +56 -0
- novacode_cli/wiki/file.py +71 -0
- novacode_cli/wiki/ingest.py +184 -0
- novacode_cli/wiki/manager.py +261 -0
- novacode_cli-1.2.0.dist-info/METADATA +271 -0
- novacode_cli-1.2.0.dist-info/RECORD +691 -0
- novacode_cli-1.2.0.dist-info/WHEEL +5 -0
- novacode_cli-1.2.0.dist-info/entry_points.txt +2 -0
- novacode_cli-1.2.0.dist-info/licenses/LICENSE +21 -0
- novacode_cli-1.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
"""Provider credential readiness — the one place that answers "can we call this?".
|
|
2
|
+
|
|
3
|
+
Providers and services are configured in several ways at once: a key in the OS
|
|
4
|
+
keychain, an exported environment variable, no key at all (Ollama), or an
|
|
5
|
+
endpoint that carries its own auth. Rendering that as a boolean loses the
|
|
6
|
+
distinction the UI needs — ``/auth`` badges and the ``/model`` provider headers
|
|
7
|
+
must say *why* a provider is or is not usable, and "missing" and "no key
|
|
8
|
+
required" read very differently to a user staring at a key input.
|
|
9
|
+
|
|
10
|
+
:func:`get_provider_auth_status` resolves that into a
|
|
11
|
+
:class:`ProviderAuthStatus`, and it is the only supported way to ask.
|
|
12
|
+
Reading ``os.environ`` directly is what made a keychain-saved key look missing
|
|
13
|
+
after a restart: the export into ``os.environ`` happens at startup, so any
|
|
14
|
+
check that runs before or outside that pass sees nothing.
|
|
15
|
+
|
|
16
|
+
Services are not chat model providers — they back features
|
|
17
|
+
such as web search — but their credentials are stored the same way, so they
|
|
18
|
+
appear in ``/auth`` alongside the providers.
|
|
19
|
+
|
|
20
|
+
LangSmith is deliberately absent: Nova reads ``LANGSMITH_API_KEY`` from the
|
|
21
|
+
environment only, never from the keychain, so a key accepted here would look
|
|
22
|
+
saved and do nothing.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
import os
|
|
28
|
+
from dataclasses import dataclass
|
|
29
|
+
from enum import StrEnum
|
|
30
|
+
|
|
31
|
+
from novacode_cli.config.credentials import CredentialStore
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ProviderAuthState(StrEnum):
|
|
35
|
+
"""Why a provider is or is not usable right now."""
|
|
36
|
+
|
|
37
|
+
CONFIGURED = "configured"
|
|
38
|
+
"""Credentials were found — see :attr:`ProviderAuthStatus.source`."""
|
|
39
|
+
|
|
40
|
+
MISSING = "missing"
|
|
41
|
+
"""A credential is required and none was found."""
|
|
42
|
+
|
|
43
|
+
NOT_REQUIRED = "not_required"
|
|
44
|
+
"""The provider needs no credential (a local endpoint, e.g. Ollama)."""
|
|
45
|
+
|
|
46
|
+
MANAGED = "managed"
|
|
47
|
+
"""The provider authenticates itself; Nova cannot see or supply a key."""
|
|
48
|
+
|
|
49
|
+
UNKNOWN = "unknown"
|
|
50
|
+
"""Nova knows nothing about this provider's credentials."""
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class ProviderAuthSource(StrEnum):
|
|
54
|
+
"""Where a ``CONFIGURED`` credential came from."""
|
|
55
|
+
|
|
56
|
+
STORED = "stored"
|
|
57
|
+
"""Entered through ``/auth`` and held in the OS credential store."""
|
|
58
|
+
|
|
59
|
+
ENV = "env"
|
|
60
|
+
"""Supplied as an environment variable."""
|
|
61
|
+
|
|
62
|
+
NONE = "none"
|
|
63
|
+
"""No credential (only paired with a non-``CONFIGURED`` state)."""
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass(frozen=True)
|
|
67
|
+
class ProviderAuthStatus:
|
|
68
|
+
"""Credential readiness for one provider or service.
|
|
69
|
+
|
|
70
|
+
Attributes:
|
|
71
|
+
name: Provider id (``"anthropic"``) or service id (``"tavily"``).
|
|
72
|
+
state: Whether the provider is usable and why not.
|
|
73
|
+
source: Where a configured credential came from.
|
|
74
|
+
env_var: The environment variable the credential is read as, when one
|
|
75
|
+
is known.
|
|
76
|
+
detail: Human-readable explanation, phrased for a UI badge or
|
|
77
|
+
indicator. ``None`` when the state needs no elaboration.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
name: str
|
|
81
|
+
state: ProviderAuthState
|
|
82
|
+
source: ProviderAuthSource = ProviderAuthSource.NONE
|
|
83
|
+
env_var: str | None = None
|
|
84
|
+
detail: str | None = None
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def is_usable(self) -> bool:
|
|
88
|
+
"""Whether a model for this provider could be constructed now."""
|
|
89
|
+
return self.state in (
|
|
90
|
+
ProviderAuthState.CONFIGURED,
|
|
91
|
+
ProviderAuthState.NOT_REQUIRED,
|
|
92
|
+
ProviderAuthState.MANAGED,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
def as_legacy_bool(self) -> bool | None:
|
|
96
|
+
"""Reduce the status to the historic tri-state contract.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
``True`` when usable, ``False`` when a known credential is absent,
|
|
100
|
+
``None`` when readiness cannot be determined.
|
|
101
|
+
"""
|
|
102
|
+
if self.state is ProviderAuthState.MISSING:
|
|
103
|
+
return False
|
|
104
|
+
if self.state is ProviderAuthState.UNKNOWN:
|
|
105
|
+
return None
|
|
106
|
+
return True
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
SERVICE_API_KEY_ENV: dict[str, str] = {
|
|
110
|
+
"tavily": "TAVILY_API_KEY",
|
|
111
|
+
"exa": "EXA_API_KEY",
|
|
112
|
+
"firecrawl": "FIRECRAWL_API_KEY",
|
|
113
|
+
"parallel": "PARALLEL_API_KEY",
|
|
114
|
+
"tinyfish": "TINYFISH_API_KEY",
|
|
115
|
+
"deepgram": "DEEPGRAM_API_KEY",
|
|
116
|
+
"elevenlabs": "ELEVENLABS_API_KEY",
|
|
117
|
+
"jev": "TYPESAFE_API_KEY",
|
|
118
|
+
"systemone": "SYSTEM_ONE_API_KEY",
|
|
119
|
+
}
|
|
120
|
+
"""Non-model services configurable through ``/auth``, mapped to their env var.
|
|
121
|
+
|
|
122
|
+
These back features rather than chat models — Tavily gates the ``web_search``
|
|
123
|
+
tool, Deepgram and ElevenLabs back the cloud voice backends — but their
|
|
124
|
+
credentials are stored exactly like a provider key, so they belong in the same
|
|
125
|
+
manager. Without them here, a voice key can only live in plaintext in
|
|
126
|
+
``Nova.config.json``.
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
SERVICE_DISPLAY_NAMES: dict[str, str] = {
|
|
130
|
+
"tavily": "Tavily (web search)",
|
|
131
|
+
"exa": "Exa",
|
|
132
|
+
"firecrawl": "Firecrawl",
|
|
133
|
+
"parallel": "Parallel",
|
|
134
|
+
"tinyfish": "TinyFish",
|
|
135
|
+
"deepgram": "Deepgram (speech to text)",
|
|
136
|
+
"elevenlabs": "ElevenLabs (text to speech)",
|
|
137
|
+
"jev": "Jev (System One compaction)",
|
|
138
|
+
"systemone": "Custom decision endpoint (optional API key)",
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def credential_section(name: str) -> str:
|
|
143
|
+
"""Return the feature section owning a credential in /auth."""
|
|
144
|
+
if name in {"deepgram", "elevenlabs"}:
|
|
145
|
+
return "voice"
|
|
146
|
+
if name in {"jev", "systemone"}:
|
|
147
|
+
return "decisions"
|
|
148
|
+
return "tools" if is_service(name) else "llms"
|
|
149
|
+
"""Capitalized names for the services in ``/auth``.
|
|
150
|
+
|
|
151
|
+
Services have no provider preset to carry a display name, and showing the raw
|
|
152
|
+
config key ("tavily") next to "OpenAI"/"Anthropic" reads like a bug.
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def service_env_var(service: str) -> str | None:
|
|
157
|
+
"""Return the env var holding a service's credential.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
service: Service id (e.g. ``"tavily"``).
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
The environment variable name, or ``None`` when the service is unknown.
|
|
164
|
+
"""
|
|
165
|
+
return SERVICE_API_KEY_ENV.get(service)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def is_service(name: str) -> bool:
|
|
169
|
+
"""Whether *name* is a service rather than a model provider.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
name: A credential name from either registry.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
``True`` for a service id.
|
|
176
|
+
"""
|
|
177
|
+
return name in SERVICE_API_KEY_ENV
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def credential_env_var(name: str) -> str | None:
|
|
181
|
+
"""Return the env var holding credentials for a provider or service.
|
|
182
|
+
|
|
183
|
+
Providers come from :data:`novacode_cli.config.model_manager.MODEL_PRESETS`
|
|
184
|
+
(imported lazily: ``model_manager`` imports this module's status function in
|
|
185
|
+
turn). Providers that need no key — Ollama — report ``None``.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
name: Provider id or service id.
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
The environment variable name, or ``None`` when unknown or not
|
|
192
|
+
applicable.
|
|
193
|
+
"""
|
|
194
|
+
service_var = SERVICE_API_KEY_ENV.get(name)
|
|
195
|
+
if service_var is not None:
|
|
196
|
+
return service_var
|
|
197
|
+
preset = _preset(name)
|
|
198
|
+
if not preset:
|
|
199
|
+
return None
|
|
200
|
+
var = preset.get("api_key_var")
|
|
201
|
+
return var if isinstance(var, str) and var else None
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def provider_display_name(name: str) -> str:
|
|
205
|
+
"""Return the name shown for a provider or service in the UI.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
name: Provider id or service id.
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
The display name, falling back to the id itself when unknown.
|
|
212
|
+
"""
|
|
213
|
+
preset = _preset(name)
|
|
214
|
+
if preset:
|
|
215
|
+
display = preset.get("name")
|
|
216
|
+
if isinstance(display, str) and display:
|
|
217
|
+
return display
|
|
218
|
+
return SERVICE_DISPLAY_NAMES.get(name, name)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def credential_names() -> dict[str, str]:
|
|
222
|
+
"""Return every credential Nova knows about, as ``name -> env var``.
|
|
223
|
+
|
|
224
|
+
Providers that require no key are omitted: there is nothing to store, so
|
|
225
|
+
listing them in the credential manager would offer a key input for a
|
|
226
|
+
provider that ignores it.
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
Mapping of provider/service id to its environment variable.
|
|
230
|
+
"""
|
|
231
|
+
names: dict[str, str] = {}
|
|
232
|
+
for provider, preset in _presets().items():
|
|
233
|
+
if not preset.get("api_key_var"):
|
|
234
|
+
continue
|
|
235
|
+
var = preset.get("api_key_var")
|
|
236
|
+
if isinstance(var, str) and var:
|
|
237
|
+
names[provider] = var
|
|
238
|
+
names.update(SERVICE_API_KEY_ENV)
|
|
239
|
+
return names
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def get_provider_auth_status(
|
|
243
|
+
name: str,
|
|
244
|
+
*,
|
|
245
|
+
store: CredentialStore | None = None,
|
|
246
|
+
) -> ProviderAuthStatus:
|
|
247
|
+
"""Return credential readiness for a provider or service.
|
|
248
|
+
|
|
249
|
+
Resolution order: unknown name -> ``UNKNOWN``; no key required ->
|
|
250
|
+
``NOT_REQUIRED``; a key in the credential store -> ``CONFIGURED`` from
|
|
251
|
+
``STORED``; a key in the environment -> ``CONFIGURED`` from ``ENV``; else
|
|
252
|
+
``MISSING``.
|
|
253
|
+
|
|
254
|
+
The store is checked before the environment so the badge can tell the user
|
|
255
|
+
where the key came from — the two are both "configured", but only one of
|
|
256
|
+
them can be replaced from inside ``/auth``.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
name: Provider id (``"anthropic"``) or service id (``"tavily"``).
|
|
260
|
+
store: Credential store to reuse across a pass over many names.
|
|
261
|
+
``None`` builds a single-use one.
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
The provider's readiness status.
|
|
265
|
+
"""
|
|
266
|
+
preset = _preset(name)
|
|
267
|
+
if preset is None and not is_service(name):
|
|
268
|
+
return ProviderAuthStatus(
|
|
269
|
+
name=name,
|
|
270
|
+
state=ProviderAuthState.UNKNOWN,
|
|
271
|
+
detail="credentials unknown",
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
env_var = credential_env_var(name)
|
|
275
|
+
if preset is not None:
|
|
276
|
+
from novacode_cli.config.provider_registry import missing_provider_settings
|
|
277
|
+
|
|
278
|
+
reason = preset.get("unavailable_reason")
|
|
279
|
+
missing = missing_provider_settings(name)
|
|
280
|
+
if reason or missing:
|
|
281
|
+
store = store if store is not None else CredentialStore()
|
|
282
|
+
source = ProviderAuthSource.NONE
|
|
283
|
+
if env_var and store.has_key(env_var):
|
|
284
|
+
source = ProviderAuthSource.STORED
|
|
285
|
+
elif env_var and _env_value(env_var):
|
|
286
|
+
source = ProviderAuthSource.ENV
|
|
287
|
+
state = ProviderAuthState.UNKNOWN if reason else ProviderAuthState.MISSING
|
|
288
|
+
detail = str(reason) if reason else "requires " + ", ".join(missing)
|
|
289
|
+
return ProviderAuthStatus(name=name, state=state,
|
|
290
|
+
source=source, env_var=env_var,
|
|
291
|
+
detail=detail)
|
|
292
|
+
if preset is not None and preset.get("protocol") == "vertex":
|
|
293
|
+
return ProviderAuthStatus(name=name, state=ProviderAuthState.MANAGED,
|
|
294
|
+
detail="Application Default Credentials (Google Cloud)")
|
|
295
|
+
if preset is not None and not preset.get("requires_api_key") and not env_var:
|
|
296
|
+
return ProviderAuthStatus(
|
|
297
|
+
name=name,
|
|
298
|
+
state=ProviderAuthState.NOT_REQUIRED,
|
|
299
|
+
detail="no API key required",
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
if env_var is None:
|
|
303
|
+
return ProviderAuthStatus(
|
|
304
|
+
name=name,
|
|
305
|
+
state=ProviderAuthState.UNKNOWN,
|
|
306
|
+
detail="credentials unknown",
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
google_mode = "auto"
|
|
310
|
+
if name == "google":
|
|
311
|
+
from novacode_cli.config.google_oauth_auth import has_credentials, selected_auth_mode
|
|
312
|
+
google_mode = selected_auth_mode()
|
|
313
|
+
if google_mode == "oauth":
|
|
314
|
+
connected = has_credentials()
|
|
315
|
+
return ProviderAuthStatus(
|
|
316
|
+
name=name,
|
|
317
|
+
state=ProviderAuthState.CONFIGURED if connected else ProviderAuthState.MISSING,
|
|
318
|
+
source=ProviderAuthSource.STORED if connected else ProviderAuthSource.NONE,
|
|
319
|
+
env_var=env_var,
|
|
320
|
+
detail=("Google OAuth sign-in" if connected
|
|
321
|
+
else "Google sign-in is selected but not connected"),
|
|
322
|
+
)
|
|
323
|
+
openai_mode = "auto"
|
|
324
|
+
if name == "openai":
|
|
325
|
+
from novacode_cli.config.openai_chatgpt_auth import selected_auth_mode
|
|
326
|
+
|
|
327
|
+
openai_mode = selected_auth_mode()
|
|
328
|
+
if openai_mode == "chatgpt":
|
|
329
|
+
from novacode_cli.config.openai_chatgpt_auth import has_credentials
|
|
330
|
+
|
|
331
|
+
configured = has_credentials()
|
|
332
|
+
return ProviderAuthStatus(
|
|
333
|
+
name=name,
|
|
334
|
+
state=(ProviderAuthState.CONFIGURED if configured else ProviderAuthState.MISSING),
|
|
335
|
+
source=(ProviderAuthSource.STORED if configured else ProviderAuthSource.NONE),
|
|
336
|
+
env_var=env_var,
|
|
337
|
+
detail=(
|
|
338
|
+
"ChatGPT plan sign-in"
|
|
339
|
+
if configured
|
|
340
|
+
else "ChatGPT sign-in is selected but not connected"
|
|
341
|
+
),
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
store = store if store is not None else CredentialStore()
|
|
345
|
+
if store.has_key(env_var):
|
|
346
|
+
return ProviderAuthStatus(
|
|
347
|
+
name=name,
|
|
348
|
+
state=ProviderAuthState.CONFIGURED,
|
|
349
|
+
source=ProviderAuthSource.STORED,
|
|
350
|
+
env_var=env_var,
|
|
351
|
+
detail="stored",
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
aliases = tuple(preset.get("key_aliases", ())) if preset else () # type: ignore[arg-type]
|
|
355
|
+
for var in (env_var, *aliases, *(("GEMINI_API_KEY",) if name == "google" else ())):
|
|
356
|
+
if _env_value(var):
|
|
357
|
+
return ProviderAuthStatus(
|
|
358
|
+
name=name,
|
|
359
|
+
state=ProviderAuthState.CONFIGURED,
|
|
360
|
+
source=ProviderAuthSource.ENV,
|
|
361
|
+
env_var=var,
|
|
362
|
+
detail=f"set in environment: {var}",
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
if name == "google" and google_mode == "auto":
|
|
366
|
+
from novacode_cli.config.google_oauth_auth import has_credentials
|
|
367
|
+
if has_credentials():
|
|
368
|
+
return ProviderAuthStatus(name=name, state=ProviderAuthState.CONFIGURED,
|
|
369
|
+
source=ProviderAuthSource.STORED, env_var=env_var, detail="Google OAuth sign-in")
|
|
370
|
+
|
|
371
|
+
# ChatGPT plan access is a separate OpenAI credential type. It must not be
|
|
372
|
+
# exported as OPENAI_API_KEY: its LangChain client uses Responses API mode.
|
|
373
|
+
if name == "openai" and openai_mode == "auto":
|
|
374
|
+
try:
|
|
375
|
+
from novacode_cli.config.openai_chatgpt_auth import has_credentials
|
|
376
|
+
|
|
377
|
+
if has_credentials():
|
|
378
|
+
return ProviderAuthStatus(
|
|
379
|
+
name=name,
|
|
380
|
+
state=ProviderAuthState.CONFIGURED,
|
|
381
|
+
source=ProviderAuthSource.STORED,
|
|
382
|
+
env_var=env_var,
|
|
383
|
+
detail="ChatGPT plan sign-in",
|
|
384
|
+
)
|
|
385
|
+
except Exception: # noqa: BLE001 — auth status must remain renderable
|
|
386
|
+
pass
|
|
387
|
+
|
|
388
|
+
if preset is not None and not preset.get("requires_api_key"):
|
|
389
|
+
return ProviderAuthStatus(name=name, state=ProviderAuthState.NOT_REQUIRED,
|
|
390
|
+
env_var=env_var, detail="optional API key")
|
|
391
|
+
|
|
392
|
+
return ProviderAuthStatus(
|
|
393
|
+
name=name,
|
|
394
|
+
state=ProviderAuthState.MISSING,
|
|
395
|
+
env_var=env_var,
|
|
396
|
+
detail=f"{env_var} is not set or is empty",
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
def get_all_auth_statuses(
|
|
401
|
+
*,
|
|
402
|
+
include_providers_without_keys: bool = False,
|
|
403
|
+
) -> dict[str, ProviderAuthStatus]:
|
|
404
|
+
"""Return readiness for every known provider and service.
|
|
405
|
+
|
|
406
|
+
One :class:`CredentialStore` is built and reused for the whole pass, so the
|
|
407
|
+
keychain backend is probed once rather than once per name.
|
|
408
|
+
|
|
409
|
+
Args:
|
|
410
|
+
include_providers_without_keys: Also report providers that need no
|
|
411
|
+
credential (Ollama), which the credential manager hides.
|
|
412
|
+
|
|
413
|
+
Returns:
|
|
414
|
+
Statuses keyed by provider/service id, in registry order.
|
|
415
|
+
"""
|
|
416
|
+
store = CredentialStore()
|
|
417
|
+
names: list[str] = list(_presets())
|
|
418
|
+
if not include_providers_without_keys:
|
|
419
|
+
names = [name for name in names if name in credential_names()]
|
|
420
|
+
names.extend(name for name in SERVICE_API_KEY_ENV if name not in names)
|
|
421
|
+
return {name: get_provider_auth_status(name, store=store) for name in names}
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def _presets() -> dict[str, dict[str, object]]:
|
|
425
|
+
"""Return the provider preset registry, imported lazily to avoid a cycle."""
|
|
426
|
+
from novacode_cli.config.model_manager import MODEL_PRESETS
|
|
427
|
+
|
|
428
|
+
return MODEL_PRESETS
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
def _preset(name: str) -> dict[str, object] | None:
|
|
432
|
+
"""Return one provider preset, or ``None`` when *name* is not a provider."""
|
|
433
|
+
return _presets().get(name)
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
def _env_value(env_var: str) -> str | None:
|
|
437
|
+
"""Read an environment variable, treating empty as unset."""
|
|
438
|
+
return os.environ.get(env_var) or None
|