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,432 @@
|
|
|
1
|
+
"""Tools the background agents name in their ``tools:`` frontmatter.
|
|
2
|
+
|
|
3
|
+
Moved here from the per-agent graph modules when those agents became markdown
|
|
4
|
+
files (``default_subagents/builtin/``). ``_specialist.build_specialist_graph``
|
|
5
|
+
resolves a declared tool name against ``novacode_cli.tools`` and then this module.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import subprocess
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
from langchain_core.tools import tool
|
|
15
|
+
|
|
16
|
+
# run_tests is named by test-runner-agent.md; it lives with its command allowlist.
|
|
17
|
+
from novacode_cli.agents.async_agents._test_commands import run_tests # noqa: F401
|
|
18
|
+
from novacode_cli.agents.async_workspace import workspace_root
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# from code_review.py
|
|
22
|
+
@tool
|
|
23
|
+
def get_changed_files(base_ref: str = "HEAD~1") -> str:
|
|
24
|
+
"""List files changed between the base ref and HEAD.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
base_ref: Git reference to compare against (default HEAD~1).
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
List of changed files with status (M/A/D).
|
|
31
|
+
"""
|
|
32
|
+
try:
|
|
33
|
+
result = subprocess.run(
|
|
34
|
+
["git", "diff", "--name-status", base_ref],
|
|
35
|
+
capture_output=True,
|
|
36
|
+
text=True,
|
|
37
|
+
cwd=workspace_root(),
|
|
38
|
+
timeout=30,
|
|
39
|
+
)
|
|
40
|
+
return (
|
|
41
|
+
result.stdout or "No changes found."
|
|
42
|
+
if result.returncode == 0
|
|
43
|
+
else f"Error: {result.stderr}"
|
|
44
|
+
)
|
|
45
|
+
except Exception as e:
|
|
46
|
+
return f"Error: {e}"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# from code_review.py
|
|
50
|
+
@tool
|
|
51
|
+
def get_diff_for_file(file_path: str, base_ref: str = "HEAD~1") -> str:
|
|
52
|
+
"""Get the diff for a specific file between base ref and HEAD.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
file_path: Path to the file relative to project root.
|
|
56
|
+
base_ref: Git reference to compare against.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Unified diff output for the file.
|
|
60
|
+
"""
|
|
61
|
+
try:
|
|
62
|
+
result = subprocess.run(
|
|
63
|
+
["git", "diff", base_ref, "--", file_path],
|
|
64
|
+
capture_output=True,
|
|
65
|
+
text=True,
|
|
66
|
+
cwd=workspace_root(),
|
|
67
|
+
timeout=30,
|
|
68
|
+
)
|
|
69
|
+
return (
|
|
70
|
+
result.stdout or "No diff."
|
|
71
|
+
if result.returncode == 0
|
|
72
|
+
else f"Error: {result.stderr}"
|
|
73
|
+
)
|
|
74
|
+
except Exception as e:
|
|
75
|
+
return f"Error: {e}"
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
# from dependency_audit.py
|
|
79
|
+
@tool
|
|
80
|
+
def check_outdated_packages() -> str:
|
|
81
|
+
"""Check for outdated Python packages using pip.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
List of outdated packages with current and latest versions.
|
|
85
|
+
"""
|
|
86
|
+
try:
|
|
87
|
+
result = subprocess.run(
|
|
88
|
+
["uv", "pip", "list", "--outdated", "--format=json"],
|
|
89
|
+
capture_output=True, text=True, cwd=workspace_root(), timeout=60,
|
|
90
|
+
)
|
|
91
|
+
if result.returncode != 0:
|
|
92
|
+
return f"Error: {result.stderr}"
|
|
93
|
+
packages = json.loads(result.stdout)
|
|
94
|
+
if not packages:
|
|
95
|
+
return "All packages are up to date."
|
|
96
|
+
lines = ["Outdated packages:", ""]
|
|
97
|
+
for pkg in packages:
|
|
98
|
+
lines.append(f" {pkg['name']}: {pkg['version']} → {pkg['latest_version']}")
|
|
99
|
+
return "\n".join(lines)
|
|
100
|
+
except json.JSONDecodeError:
|
|
101
|
+
return "Could not parse package list."
|
|
102
|
+
except FileNotFoundError:
|
|
103
|
+
return "uv is not available."
|
|
104
|
+
except Exception as e:
|
|
105
|
+
return f"Error: {e}"
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
# from dependency_audit.py
|
|
109
|
+
@tool
|
|
110
|
+
def check_security_advisories() -> str:
|
|
111
|
+
"""Check for known security vulnerabilities in dependencies.
|
|
112
|
+
|
|
113
|
+
Uses pip-audit if available, otherwise falls back to safety or pip.
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
Security advisory report.
|
|
117
|
+
"""
|
|
118
|
+
try:
|
|
119
|
+
result = subprocess.run(
|
|
120
|
+
["uv", "run", "pip-audit", "--format=markdown"],
|
|
121
|
+
capture_output=True, text=True, cwd=workspace_root(), timeout=120,
|
|
122
|
+
)
|
|
123
|
+
if result.returncode == 0:
|
|
124
|
+
return result.stdout or "No known vulnerabilities found."
|
|
125
|
+
return result.stdout or result.stderr or "pip-audit check completed with warnings."
|
|
126
|
+
except FileNotFoundError:
|
|
127
|
+
return "pip-audit is not installed. Install with: uv pip install pip-audit"
|
|
128
|
+
except subprocess.TimeoutExpired:
|
|
129
|
+
return "Security audit timed out."
|
|
130
|
+
except Exception as e:
|
|
131
|
+
return f"Error: {e}"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
# from dependency_audit.py
|
|
135
|
+
@tool
|
|
136
|
+
def get_dependency_tree() -> str:
|
|
137
|
+
"""Show the full dependency tree.
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
Dependency tree output.
|
|
141
|
+
"""
|
|
142
|
+
try:
|
|
143
|
+
result = subprocess.run(
|
|
144
|
+
["uv", "tree"],
|
|
145
|
+
capture_output=True, text=True, cwd=workspace_root(), timeout=60,
|
|
146
|
+
)
|
|
147
|
+
return result.stdout if result.returncode == 0 else f"Error: {result.stderr}"
|
|
148
|
+
except FileNotFoundError:
|
|
149
|
+
return "uv is not available."
|
|
150
|
+
except Exception as e:
|
|
151
|
+
return f"Error: {e}"
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
# from documentation_update.py
|
|
155
|
+
@tool
|
|
156
|
+
def get_recent_commits(count: int = 10) -> str:
|
|
157
|
+
"""Get the most recent commit messages and hashes from the project.
|
|
158
|
+
|
|
159
|
+
Useful for understanding what changed since the last documentation update.
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
count: Number of recent commits to retrieve (default 10).
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
Formatted commit log with hash, author, date, and message.
|
|
166
|
+
"""
|
|
167
|
+
try:
|
|
168
|
+
result = subprocess.run(
|
|
169
|
+
["git", "log", f"-{count}", "--pretty=format:%h %an %ad %s", "--date=short"],
|
|
170
|
+
capture_output=True,
|
|
171
|
+
text=True,
|
|
172
|
+
cwd=workspace_root(),
|
|
173
|
+
timeout=30,
|
|
174
|
+
)
|
|
175
|
+
if result.returncode == 0:
|
|
176
|
+
return result.stdout or "No commits found."
|
|
177
|
+
return f"Git error: {result.stderr}"
|
|
178
|
+
except FileNotFoundError:
|
|
179
|
+
return "Git is not available in this environment."
|
|
180
|
+
except subprocess.TimeoutExpired:
|
|
181
|
+
return "Git log timed out."
|
|
182
|
+
except Exception as e:
|
|
183
|
+
return f"Error reading git log: {e}"
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
# from documentation_update.py
|
|
187
|
+
@tool
|
|
188
|
+
def get_commit_diff(commit_hash: str) -> str:
|
|
189
|
+
"""Get the full diff for a specific commit.
|
|
190
|
+
|
|
191
|
+
Use this to understand exactly what files changed and how.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
commit_hash: The commit hash (full or abbreviated).
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
The full diff output for the given commit.
|
|
198
|
+
"""
|
|
199
|
+
try:
|
|
200
|
+
result = subprocess.run(
|
|
201
|
+
["git", "show", commit_hash, "--stat", "--patch"],
|
|
202
|
+
capture_output=True,
|
|
203
|
+
text=True,
|
|
204
|
+
cwd=workspace_root(),
|
|
205
|
+
timeout=60,
|
|
206
|
+
)
|
|
207
|
+
if result.returncode == 0:
|
|
208
|
+
return result.stdout or "No diff available."
|
|
209
|
+
return f"Git error: {result.stderr}"
|
|
210
|
+
except FileNotFoundError:
|
|
211
|
+
return "Git is not available in this environment."
|
|
212
|
+
except subprocess.TimeoutExpired:
|
|
213
|
+
return "Git diff timed out."
|
|
214
|
+
except Exception as e:
|
|
215
|
+
return f"Error reading diff: {e}"
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
# from documentation_update.py
|
|
219
|
+
@tool
|
|
220
|
+
def get_changed_files_since(tag_or_hash: str = "HEAD~1") -> str:
|
|
221
|
+
"""List files that have changed since a given reference.
|
|
222
|
+
|
|
223
|
+
Useful for identifying which documentation files may need updating.
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
tag_or_hash: Git reference (tag, commit hash, or relative like HEAD~5).
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
List of changed files with change type (modified/added/deleted).
|
|
230
|
+
"""
|
|
231
|
+
try:
|
|
232
|
+
result = subprocess.run(
|
|
233
|
+
["git", "diff", "--name-status", tag_or_hash],
|
|
234
|
+
capture_output=True,
|
|
235
|
+
text=True,
|
|
236
|
+
cwd=workspace_root(),
|
|
237
|
+
timeout=30,
|
|
238
|
+
)
|
|
239
|
+
if result.returncode == 0:
|
|
240
|
+
return result.stdout or "No changes found."
|
|
241
|
+
return f"Git error: {result.stderr}"
|
|
242
|
+
except FileNotFoundError:
|
|
243
|
+
return "Git is not available in this environment."
|
|
244
|
+
except subprocess.TimeoutExpired:
|
|
245
|
+
return "Git diff timed out."
|
|
246
|
+
except Exception as e:
|
|
247
|
+
return f"Error listing changed files: {e}"
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
# from refactoring.py
|
|
251
|
+
@tool
|
|
252
|
+
def run_linter(file_path: str) -> str:
|
|
253
|
+
"""Run ruff linter on a specific file and return issues.
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
file_path: Path relative to project root.
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
Linter output with line numbers and issue descriptions.
|
|
260
|
+
"""
|
|
261
|
+
try:
|
|
262
|
+
result = subprocess.run(
|
|
263
|
+
["uv", "run", "ruff", "check", file_path],
|
|
264
|
+
capture_output=True, text=True, cwd=workspace_root(), timeout=30,
|
|
265
|
+
)
|
|
266
|
+
return result.stdout or "No linting issues found." if result.returncode == 0 else result.stdout
|
|
267
|
+
except Exception as e:
|
|
268
|
+
return f"Error: {e}"
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
# from refactoring.py
|
|
272
|
+
@tool
|
|
273
|
+
def get_file_line_count(file_path: str) -> str:
|
|
274
|
+
"""Get line count and basic metrics for a file.
|
|
275
|
+
|
|
276
|
+
Args:
|
|
277
|
+
file_path: Path relative to project root.
|
|
278
|
+
|
|
279
|
+
Returns:
|
|
280
|
+
File metrics (lines, functions, classes).
|
|
281
|
+
"""
|
|
282
|
+
try:
|
|
283
|
+
full_path = workspace_root() / file_path
|
|
284
|
+
if not full_path.exists():
|
|
285
|
+
return f"File not found: {file_path}"
|
|
286
|
+
content = full_path.read_text(encoding="utf-8")
|
|
287
|
+
lines = content.split("\n")
|
|
288
|
+
func_count = content.count("def ")
|
|
289
|
+
class_count = content.count("class ")
|
|
290
|
+
return (
|
|
291
|
+
f"File: {file_path}\n"
|
|
292
|
+
f" Total lines: {len(lines)}\n"
|
|
293
|
+
f" Code lines: {sum(1 for l in lines if l.strip() and not l.strip().startswith('#'))}\n"
|
|
294
|
+
f" Functions: {func_count}\n"
|
|
295
|
+
f" Classes: {class_count}"
|
|
296
|
+
)
|
|
297
|
+
except Exception as e:
|
|
298
|
+
return f"Error: {e}"
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
# from refactoring.py
|
|
302
|
+
@tool
|
|
303
|
+
def run_format_check(file_path: str) -> str:
|
|
304
|
+
"""Check if a file is properly formatted according to ruff.
|
|
305
|
+
|
|
306
|
+
Args:
|
|
307
|
+
file_path: Path relative to project root.
|
|
308
|
+
|
|
309
|
+
Returns:
|
|
310
|
+
Formatting diff or confirmation.
|
|
311
|
+
"""
|
|
312
|
+
try:
|
|
313
|
+
result = subprocess.run(
|
|
314
|
+
["uv", "run", "ruff", "format", "--check", "--diff", file_path],
|
|
315
|
+
capture_output=True, text=True, cwd=workspace_root(), timeout=30,
|
|
316
|
+
)
|
|
317
|
+
if result.returncode == 0:
|
|
318
|
+
return "File is properly formatted."
|
|
319
|
+
return result.stdout or "Formatting issues found."
|
|
320
|
+
except Exception as e:
|
|
321
|
+
return f"Error: {e}"
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
# from plan_scout.py
|
|
325
|
+
@tool
|
|
326
|
+
def scan_directory(directory: str = ".", max_depth: int = 4) -> str:
|
|
327
|
+
"""List the directory tree relevant to planning, up to a depth.
|
|
328
|
+
|
|
329
|
+
Args:
|
|
330
|
+
directory: Path relative to project root (default ".").
|
|
331
|
+
max_depth: How deep to recurse (default 4).
|
|
332
|
+
|
|
333
|
+
Returns:
|
|
334
|
+
A tree of files and directories, skipping common vendored/ignored
|
|
335
|
+
dirs (.git, node_modules, __pycache__, .venv, dist, build, .nova).
|
|
336
|
+
"""
|
|
337
|
+
SKIP_DIRS = {
|
|
338
|
+
".git", "node_modules", "__pycache__", ".venv", "venv", "dist",
|
|
339
|
+
"build", ".nova", ".pytest_cache", ".ruff_cache", ".mypy_cache",
|
|
340
|
+
".venv2", "site-packages", ".tox", ".eggs", "target", "coverage",
|
|
341
|
+
}
|
|
342
|
+
root = workspace_root() / directory
|
|
343
|
+
root = root.resolve()
|
|
344
|
+
if not root.exists():
|
|
345
|
+
return f"Path not found: {directory}"
|
|
346
|
+
|
|
347
|
+
lines: list[str] = []
|
|
348
|
+
|
|
349
|
+
def walk(path: Path, depth: int) -> None:
|
|
350
|
+
if depth > max_depth:
|
|
351
|
+
return
|
|
352
|
+
try:
|
|
353
|
+
entries = sorted(path.iterdir(), key=lambda p: (p.is_file(), p.name.lower()))
|
|
354
|
+
except PermissionError:
|
|
355
|
+
return
|
|
356
|
+
for entry in entries:
|
|
357
|
+
if entry.is_dir() and entry.name in SKIP_DIRS:
|
|
358
|
+
continue
|
|
359
|
+
rel = entry.relative_to(root).as_posix()
|
|
360
|
+
if entry.is_dir():
|
|
361
|
+
lines.append(f"{rel}/")
|
|
362
|
+
walk(entry, depth + 1)
|
|
363
|
+
else:
|
|
364
|
+
lines.append(rel)
|
|
365
|
+
|
|
366
|
+
walk(root, 0)
|
|
367
|
+
if not lines:
|
|
368
|
+
return f"No files under {directory}"
|
|
369
|
+
return "\n".join(lines)
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
# from plan_scout.py
|
|
373
|
+
@tool
|
|
374
|
+
def summarize_file(file_path: str, max_lines: int = 80) -> str:
|
|
375
|
+
"""Return the first lines of a file as a planning preview.
|
|
376
|
+
|
|
377
|
+
Args:
|
|
378
|
+
file_path: Path relative to project root.
|
|
379
|
+
max_lines: How many leading lines to return (default 80).
|
|
380
|
+
|
|
381
|
+
Returns:
|
|
382
|
+
The file's head, with a one-line header noting total length.
|
|
383
|
+
"""
|
|
384
|
+
full_path = (workspace_root() / file_path).resolve()
|
|
385
|
+
if not full_path.exists():
|
|
386
|
+
return f"File not found: {file_path}"
|
|
387
|
+
try:
|
|
388
|
+
content = full_path.read_text(encoding="utf-8", errors="replace")
|
|
389
|
+
except OSError as e:
|
|
390
|
+
return f"Error reading {file_path}: {e}"
|
|
391
|
+
lines = content.splitlines()
|
|
392
|
+
head = lines[:max_lines]
|
|
393
|
+
total = len(lines)
|
|
394
|
+
preview = "\n".join(head)
|
|
395
|
+
return f"--- {file_path} ({total} lines, showing first {min(max_lines, total)}) ---\n{preview}"
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
# from plan_scout.py
|
|
399
|
+
@tool
|
|
400
|
+
def search_references(pattern: str, path: str = ".", extensions: str = "py,ts,tsx,js,md") -> str:
|
|
401
|
+
"""Search files for a literal pattern (grep-style), returning matches.
|
|
402
|
+
|
|
403
|
+
Args:
|
|
404
|
+
pattern: The literal text to search for.
|
|
405
|
+
path: Directory to search, relative to project root (default ".").
|
|
406
|
+
extensions: Comma-separated file extensions to include.
|
|
407
|
+
|
|
408
|
+
Returns:
|
|
409
|
+
Matching lines with file:line prefixes, or "No matches found."
|
|
410
|
+
"""
|
|
411
|
+
EXTS = {f".{e.strip().lstrip('.')}" for e in extensions.split(",") if e.strip()}
|
|
412
|
+
root = (workspace_root() / path).resolve()
|
|
413
|
+
if not root.exists():
|
|
414
|
+
return f"Path not found: {path}"
|
|
415
|
+
hits: list[str] = []
|
|
416
|
+
for file in root.rglob("*"):
|
|
417
|
+
if not file.is_file() or file.suffix.lower() not in EXTS:
|
|
418
|
+
continue
|
|
419
|
+
if any(part in {".git", "node_modules", "__pycache__", ".venv", "dist", "build", ".nova"}
|
|
420
|
+
for part in file.parts):
|
|
421
|
+
continue
|
|
422
|
+
try:
|
|
423
|
+
for lineno, line in enumerate(file.read_text(encoding="utf-8", errors="replace").splitlines(), 1):
|
|
424
|
+
if pattern in line:
|
|
425
|
+
rel = file.relative_to(workspace_root()).as_posix()
|
|
426
|
+
hits.append(f"{rel}:{lineno}:{line.strip()[:200]}")
|
|
427
|
+
if len(hits) >= 200:
|
|
428
|
+
hits.append("... (truncated at 200 matches)")
|
|
429
|
+
return "\n".join(hits)
|
|
430
|
+
except OSError:
|
|
431
|
+
continue
|
|
432
|
+
return "\n".join(hits) if hits else "No matches found."
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""General-purpose delegation on Nova's background agent server."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def build_graph() -> Any:
|
|
9
|
+
"""Build with the server's workspace, async model role and unattended policy."""
|
|
10
|
+
from deepagents import create_deep_agent
|
|
11
|
+
from novacode_cli.context.snapshot import background_context_middleware
|
|
12
|
+
from deepagents.backends.filesystem import FilesystemBackend
|
|
13
|
+
|
|
14
|
+
from novacode_cli.agents.async_agents._specialist import BACKGROUND_NOTE
|
|
15
|
+
from novacode_cli.agents.async_context import AsyncModelOverrideMiddleware, NovaAsyncContext
|
|
16
|
+
from novacode_cli.agents.async_workspace import workspace_root
|
|
17
|
+
from novacode_cli.config.model_create import build_async_agent_model
|
|
18
|
+
from novacode_cli.prompts import render_template
|
|
19
|
+
from novacode_cli.security.delegated_approval import DelegatedApprovalMiddleware
|
|
20
|
+
from novacode_cli.shell.middleware import ShellMiddleware
|
|
21
|
+
from novacode_cli.skills.libraries import background_library
|
|
22
|
+
from novacode_cli.tools import docs_search, fetch_url, web_search
|
|
23
|
+
|
|
24
|
+
root = workspace_root()
|
|
25
|
+
return create_deep_agent(
|
|
26
|
+
name="general-purpose-async",
|
|
27
|
+
model=build_async_agent_model(),
|
|
28
|
+
tools=[web_search, docs_search, fetch_url],
|
|
29
|
+
backend=FilesystemBackend(root_dir=str(root), virtual_mode=True),
|
|
30
|
+
system_prompt=render_template("async_agents/general_purpose.jinja") + BACKGROUND_NOTE,
|
|
31
|
+
middleware=[
|
|
32
|
+
AsyncModelOverrideMiddleware(),
|
|
33
|
+
DelegatedApprovalMiddleware(),
|
|
34
|
+
ShellMiddleware(workspace_root=str(root)),
|
|
35
|
+
background_library("general-purpose-async"),
|
|
36
|
+
*background_context_middleware(),
|
|
37
|
+
],
|
|
38
|
+
context_schema=NovaAsyncContext,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
graph = build_graph()
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Web research, in the background: the ``web-researcher`` specialist.
|
|
2
|
+
|
|
3
|
+
Searching and reading sources takes minutes and needs nothing from the session,
|
|
4
|
+
which makes it the clearest case for a background run.
|
|
5
|
+
|
|
6
|
+
Exports:
|
|
7
|
+
graph: Compiled graph served by the async agent server.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from novacode_cli.agents.async_agents._specialist import build_specialist_graph
|
|
13
|
+
from novacode_cli.agents.default_subagents.prompt import WEB_RESEARCHER
|
|
14
|
+
|
|
15
|
+
graph = build_specialist_graph(
|
|
16
|
+
"research-agent",
|
|
17
|
+
WEB_RESEARCHER,
|
|
18
|
+
note=(
|
|
19
|
+
"\nWrite the findings file as instructed, and ALSO give the key findings and their"
|
|
20
|
+
" sources in your final message: here the reply is what gets reported back.\n"
|
|
21
|
+
),
|
|
22
|
+
)
|