alysis-code 0.13.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.
- alysis_code/__init__.py +3 -0
- alysis_code/__main__.py +4 -0
- alysis_code/_build_info.py +14 -0
- alysis_code/account_login.py +468 -0
- alysis_code/agent/README.md +35 -0
- alysis_code/agent/__init__.py +11 -0
- alysis_code/agent/acceptance_contract.py +2217 -0
- alysis_code/agent/blast_radius.py +1403 -0
- alysis_code/agent/cache_keepalive.py +227 -0
- alysis_code/agent/completion_certificate.py +366 -0
- alysis_code/agent/completion_gate.py +306 -0
- alysis_code/agent/empty_response_stall.py +403 -0
- alysis_code/agent/errors.py +28 -0
- alysis_code/agent/llm_calls.py +475 -0
- alysis_code/agent/mutation_classification.py +227 -0
- alysis_code/agent/prompt_context.py +2508 -0
- alysis_code/agent/read_ledger.py +253 -0
- alysis_code/agent/regression_baseline.py +642 -0
- alysis_code/agent/reproduction_first.py +610 -0
- alysis_code/agent/sensitive_output.py +629 -0
- alysis_code/agent/session.py +3218 -0
- alysis_code/agent/steering.py +191 -0
- alysis_code/agent/subagent_execution.py +5177 -0
- alysis_code/agent/subagent_workspace.py +666 -0
- alysis_code/agent/tools_assembly.py +4728 -0
- alysis_code/agent/turn/__init__.py +101 -0
- alysis_code/agent/turn/core.py +8483 -0
- alysis_code/agent/turn/events.py +113 -0
- alysis_code/agent/turn/exploration.py +590 -0
- alysis_code/agent/turn/interventions.py +65 -0
- alysis_code/agent/turn/read_cache.py +420 -0
- alysis_code/agent/turn/snapshot.py +179 -0
- alysis_code/agent/turn_contract.py +661 -0
- alysis_code/agent/turn_path.py +129 -0
- alysis_code/agent/verification.py +2885 -0
- alysis_code/agent/verification_commands.py +512 -0
- alysis_code/agent/verification_evidence.py +738 -0
- alysis_code/agent_loop.py +693 -0
- alysis_code/agent_runtimes/__init__.py +51 -0
- alysis_code/agent_runtimes/base.py +114 -0
- alysis_code/agent_runtimes/builtins.py +129 -0
- alysis_code/agent_runtimes/codex_cli.py +664 -0
- alysis_code/agent_runtimes/host.py +263 -0
- alysis_code/agent_runtimes/registry.py +64 -0
- alysis_code/agent_runtimes/service.py +150 -0
- alysis_code/agentbox_client.py +416 -0
- alysis_code/agentbox_integration.py +310 -0
- alysis_code/alysis_cloud.py +152 -0
- alysis_code/approval_scope.py +276 -0
- alysis_code/assets/README.md +33 -0
- alysis_code/assets/__init__.py +126 -0
- alysis_code/assets/asset_read_core.py +281 -0
- alysis_code/assets/budget_allocator.py +456 -0
- alysis_code/assets/comprehender.py +759 -0
- alysis_code/assets/index.py +654 -0
- alysis_code/assets/ingestion.py +275 -0
- alysis_code/assets/legacy_migration.py +413 -0
- alysis_code/assets/models.py +263 -0
- alysis_code/assets/ocr.py +239 -0
- alysis_code/assets/owl/ascii/f-000.txt +13 -0
- alysis_code/assets/owl/ascii/f-001.txt +13 -0
- alysis_code/assets/owl/ascii/f-002.txt +13 -0
- alysis_code/assets/owl/ascii/f-003.txt +13 -0
- alysis_code/assets/owl/ascii/f-004.txt +13 -0
- alysis_code/assets/owl/ascii/f-005.txt +13 -0
- alysis_code/assets/owl/ascii/f-006.txt +13 -0
- alysis_code/assets/owl/ascii/f-007.txt +13 -0
- alysis_code/assets/owl/ascii/f-008.txt +13 -0
- alysis_code/assets/owl/ascii/f-009.txt +13 -0
- alysis_code/assets/owl/ascii/f-010.txt +13 -0
- alysis_code/assets/owl/ascii/f-011.txt +13 -0
- alysis_code/assets/owl/ascii/f-012.txt +13 -0
- alysis_code/assets/owl/ascii/f-013.txt +13 -0
- alysis_code/assets/owl/ascii/f-014.txt +13 -0
- alysis_code/assets/owl/ascii/f-015.txt +13 -0
- alysis_code/assets/owl/ascii/f-016.txt +13 -0
- alysis_code/assets/owl/ascii/f-017.txt +13 -0
- alysis_code/assets/owl/ascii/f-018.txt +13 -0
- alysis_code/assets/owl/ascii/f-019.txt +13 -0
- alysis_code/assets/owl/ascii/f-020.txt +13 -0
- alysis_code/assets/owl/index.html +98 -0
- alysis_code/assets/owl/show-owl.sh +761 -0
- alysis_code/assets/paths.py +49 -0
- alysis_code/assets/plan_binding.py +326 -0
- alysis_code/assets/planner_context.py +466 -0
- alysis_code/assets/planner_tools.py +184 -0
- alysis_code/assets/prompts.py +101 -0
- alysis_code/assets/replanner_context.py +239 -0
- alysis_code/assets/surface.py +521 -0
- alysis_code/assets/untrusted_content.py +48 -0
- alysis_code/assets/usage_logger.py +94 -0
- alysis_code/assets/worker_mirror.py +428 -0
- alysis_code/assets/worker_section.py +303 -0
- alysis_code/assets/worker_tools.py +468 -0
- alysis_code/atomic_io.py +83 -0
- alysis_code/auth_diagnostics.py +272 -0
- alysis_code/background_runner.py +366 -0
- alysis_code/branding.py +270 -0
- alysis_code/budget_policy.py +390 -0
- alysis_code/build_identity.py +465 -0
- alysis_code/builtin_hooks/__init__.py +7 -0
- alysis_code/builtin_hooks/notify_done_windows.py +65 -0
- alysis_code/bwrap_etc.py +76 -0
- alysis_code/cancellation.py +41 -0
- alysis_code/capabilities.py +137 -0
- alysis_code/chatgpt_codex_static_provider.py +133 -0
- alysis_code/cli.py +51 -0
- alysis_code/cli_impl/__init__.py +1 -0
- alysis_code/cli_impl/assets_cli.py +537 -0
- alysis_code/cli_impl/assets_modal.py +412 -0
- alysis_code/cli_impl/chat/__init__.py +156 -0
- alysis_code/cli_impl/chat/commands.py +2616 -0
- alysis_code/cli_impl/chat/loop.py +4508 -0
- alysis_code/cli_impl/chat/mid_turn_policy.py +125 -0
- alysis_code/cli_impl/chat/rendering.py +444 -0
- alysis_code/cli_impl/chat/state.py +124 -0
- alysis_code/cli_impl/chat_resume.py +830 -0
- alysis_code/cli_impl/chat_slash_completer.py +258 -0
- alysis_code/cli_impl/commands/__init__.py +11 -0
- alysis_code/cli_impl/commands/_shared.py +89 -0
- alysis_code/cli_impl/commands/auth.py +623 -0
- alysis_code/cli_impl/commands/chat_resume_helpers.py +1531 -0
- alysis_code/cli_impl/commands/chat_state.py +158 -0
- alysis_code/cli_impl/commands/chat_status.py +1248 -0
- alysis_code/cli_impl/commands/chat_terminal.py +942 -0
- alysis_code/cli_impl/commands/chat_tui_panels.py +1018 -0
- alysis_code/cli_impl/commands/cli_common.py +1223 -0
- alysis_code/cli_impl/commands/cli_surface.py +77 -0
- alysis_code/cli_impl/commands/config.py +131 -0
- alysis_code/cli_impl/commands/conventions.py +85 -0
- alysis_code/cli_impl/commands/execution_helpers.py +350 -0
- alysis_code/cli_impl/commands/extensions.py +401 -0
- alysis_code/cli_impl/commands/forge.py +1282 -0
- alysis_code/cli_impl/commands/forge_asset_view.py +121 -0
- alysis_code/cli_impl/commands/forge_helpers.py +1215 -0
- alysis_code/cli_impl/commands/hooks.py +737 -0
- alysis_code/cli_impl/commands/ide_bridge.py +31 -0
- alysis_code/cli_impl/commands/mcp.py +700 -0
- alysis_code/cli_impl/commands/profile.py +453 -0
- alysis_code/cli_impl/commands/prompt_helpers.py +307 -0
- alysis_code/cli_impl/commands/report.py +88 -0
- alysis_code/cli_impl/commands/root.py +1118 -0
- alysis_code/cli_impl/commands/sandbox.py +184 -0
- alysis_code/cli_impl/commands/server.py +54 -0
- alysis_code/cli_impl/commands/sessions.py +252 -0
- alysis_code/cli_impl/commands/skills.py +404 -0
- alysis_code/cli_impl/commands/startup.py +946 -0
- alysis_code/cli_impl/commands/tools.py +335 -0
- alysis_code/cli_impl/commands/update.py +364 -0
- alysis_code/cli_impl/commands/welcome.py +972 -0
- alysis_code/cli_impl/config_menu.py +3882 -0
- alysis_code/cli_impl/forge.py +4509 -0
- alysis_code/cli_impl/forge_recovery.py +485 -0
- alysis_code/cli_impl/setup_wizard.py +2409 -0
- alysis_code/cli_impl/tui/__init__.py +58 -0
- alysis_code/cli_impl/tui/app.py +4551 -0
- alysis_code/cli_impl/tui/config.py +32 -0
- alysis_code/cli_impl/tui/config_flow.py +2754 -0
- alysis_code/cli_impl/tui/config_overlay.py +566 -0
- alysis_code/cli_impl/tui/content.py +78 -0
- alysis_code/cli_impl/tui/footer.py +218 -0
- alysis_code/cli_impl/tui/forge_status.py +136 -0
- alysis_code/cli_impl/tui/markdown.py +244 -0
- alysis_code/cli_impl/tui/owl.py +109 -0
- alysis_code/cli_impl/tui/plan_meta.py +477 -0
- alysis_code/cli_impl/tui/setup_app.py +519 -0
- alysis_code/cli_impl/tui/setup_flow.py +1622 -0
- alysis_code/cli_impl/tui/state.py +101 -0
- alysis_code/cli_impl/tui/subagent_identity.py +66 -0
- alysis_code/cli_impl/tui/subagent_panel.py +186 -0
- alysis_code/cli_impl/tui/surface.py +796 -0
- alysis_code/cli_impl/tui/transcript.py +514 -0
- alysis_code/cli_impl/tui/update_prompt.py +79 -0
- alysis_code/cli_impl/tui/workspace_guard.py +384 -0
- alysis_code/clipboard.py +172 -0
- alysis_code/code_review.py +1211 -0
- alysis_code/compaction/__init__.py +28 -0
- alysis_code/compaction/conversation_compactor.py +2932 -0
- alysis_code/compaction/importance.py +177 -0
- alysis_code/compaction/settings.py +297 -0
- alysis_code/compaction/tool_output_offload.py +447 -0
- alysis_code/config.py +3509 -0
- alysis_code/conflict_auto_resolver.py +895 -0
- alysis_code/context/__init__.py +1 -0
- alysis_code/context/tool_schema_budgeter.py +220 -0
- alysis_code/crash_diagnostics.py +282 -0
- alysis_code/custom_tools/README.md +34 -0
- alysis_code/custom_tools/__init__.py +43 -0
- alysis_code/custom_tools/discovery.py +903 -0
- alysis_code/custom_tools/runtime.py +1516 -0
- alysis_code/custom_tools/session.py +227 -0
- alysis_code/custom_tools/trust.py +232 -0
- alysis_code/diff_paths.py +113 -0
- alysis_code/direction_change.py +293 -0
- alysis_code/dispatch_timing.py +306 -0
- alysis_code/durable_service_manager.py +1236 -0
- alysis_code/edit_discipline.py +659 -0
- alysis_code/error_text.py +73 -0
- alysis_code/execution_budget.py +411 -0
- alysis_code/execution_context.py +915 -0
- alysis_code/execution_deadline.py +1065 -0
- alysis_code/execution_shared.py +1904 -0
- alysis_code/extensions/README.md +30 -0
- alysis_code/extensions/__init__.py +93 -0
- alysis_code/extensions/activation.py +138 -0
- alysis_code/extensions/install.py +1436 -0
- alysis_code/extensions/manifest.py +487 -0
- alysis_code/extensions/models.py +74 -0
- alysis_code/extensions/paths.py +56 -0
- alysis_code/extensions/registry.json +4 -0
- alysis_code/extensions/registry.py +52 -0
- alysis_code/extensions/state.py +83 -0
- alysis_code/extensions/workspace_trust.py +101 -0
- alysis_code/failed_task_evidence.py +369 -0
- alysis_code/failure_category.py +315 -0
- alysis_code/feedback_report.py +1647 -0
- alysis_code/file_classification.py +485 -0
- alysis_code/forge.py +2064 -0
- alysis_code/forge_completion.py +362 -0
- alysis_code/forge_events.py +475 -0
- alysis_code/frontmatter_utils.py +95 -0
- alysis_code/git_evidence.py +1181 -0
- alysis_code/git_ops.py +560 -0
- alysis_code/git_safe.py +62 -0
- alysis_code/git_worktrees.py +190 -0
- alysis_code/hooks/README.md +33 -0
- alysis_code/hooks/__init__.py +67 -0
- alysis_code/hooks/audit.py +171 -0
- alysis_code/hooks/config.py +225 -0
- alysis_code/hooks/dispatcher.py +1110 -0
- alysis_code/hooks/models.py +447 -0
- alysis_code/hooks/trust.py +202 -0
- alysis_code/host_actions.py +543 -0
- alysis_code/host_browser.py +103 -0
- alysis_code/ide/__init__.py +5 -0
- alysis_code/ide/activity_events.py +399 -0
- alysis_code/ide/approvals.py +337 -0
- alysis_code/ide/artifacts.py +153 -0
- alysis_code/ide/browser_egress_proxy.py +1076 -0
- alysis_code/ide/cdp_websocket_transport.py +1192 -0
- alysis_code/ide/change_ledger.py +1721 -0
- alysis_code/ide/context_blocks.py +979 -0
- alysis_code/ide/event_stream.py +531 -0
- alysis_code/ide/forge_protocol.py +3112 -0
- alysis_code/ide/forge_request_ledger.py +737 -0
- alysis_code/ide/health.py +965 -0
- alysis_code/ide/managed_browser.py +2251 -0
- alysis_code/ide/management_protocol.py +3414 -0
- alysis_code/ide/mcp_oauth_coordinator.py +744 -0
- alysis_code/ide/mcp_oauth_lifecycle.py +1504 -0
- alysis_code/ide/prompt_queue.py +1070 -0
- alysis_code/ide/protocol.py +191 -0
- alysis_code/ide/resumable_swarm.py +1543 -0
- alysis_code/ide/session_search.py +295 -0
- alysis_code/ide/stdio_bridge.py +9935 -0
- alysis_code/ide/structured_state.py +1579 -0
- alysis_code/ide/swarm_protocol.py +816 -0
- alysis_code/integration_gate.py +506 -0
- alysis_code/interactive_input_guard.py +39 -0
- alysis_code/interactive_plan_mode.py +26 -0
- alysis_code/internal_artifacts.py +179 -0
- alysis_code/knowledge_base.py +1409 -0
- alysis_code/knowledge_capture.py +1190 -0
- alysis_code/knowledge_librarian.py +605 -0
- alysis_code/language_policy.py +34 -0
- alysis_code/litellm_static_provider.py +535 -0
- alysis_code/llm/__init__.py +1 -0
- alysis_code/llm/anthropic_messages.py +2288 -0
- alysis_code/llm/base.py +71 -0
- alysis_code/llm/cache_capabilities.py +985 -0
- alysis_code/llm/cache_control_blocks.py +244 -0
- alysis_code/llm/cache_policy.py +388 -0
- alysis_code/llm/factory.py +373 -0
- alysis_code/llm/gemini_generate_content.py +2652 -0
- alysis_code/llm/gemini_interactions.py +739 -0
- alysis_code/llm/metadata.py +450 -0
- alysis_code/llm/openai_compat.py +2947 -0
- alysis_code/llm/openai_responses.py +2604 -0
- alysis_code/llm/protocols.py +609 -0
- alysis_code/llm/provider_limits.py +525 -0
- alysis_code/llm/request_plan.py +389 -0
- alysis_code/llm/request_shape.py +238 -0
- alysis_code/llm/streaming.py +108 -0
- alysis_code/llm/temperature_compat.py +78 -0
- alysis_code/llm/types.py +195 -0
- alysis_code/llm/usage_normalization.py +222 -0
- alysis_code/llm_error_display.py +315 -0
- alysis_code/logging_redaction.py +326 -0
- alysis_code/managed_host_deadline.py +196 -0
- alysis_code/mcp/README.md +33 -0
- alysis_code/mcp/__init__.py +24 -0
- alysis_code/mcp/client.py +1137 -0
- alysis_code/mcp/config.py +597 -0
- alysis_code/mcp/errors.py +113 -0
- alysis_code/mcp/forge_scope.py +154 -0
- alysis_code/mcp/jsonrpc.py +214 -0
- alysis_code/mcp/manager.py +2308 -0
- alysis_code/mcp/models.py +666 -0
- alysis_code/mcp/oauth.py +972 -0
- alysis_code/mcp/oauth_runtime.py +310 -0
- alysis_code/mcp/oauth_store.py +276 -0
- alysis_code/mcp/prompts.py +329 -0
- alysis_code/mcp/resources.py +295 -0
- alysis_code/mcp/roots.py +106 -0
- alysis_code/mcp/server_requests.py +75 -0
- alysis_code/mcp/token_store.py +859 -0
- alysis_code/mcp/transport_http.py +1338 -0
- alysis_code/mcp/transport_stdio.py +1267 -0
- alysis_code/mcp/untrusted_content.py +119 -0
- alysis_code/merge_conflict_reviewer.py +729 -0
- alysis_code/model_catalog/__init__.py +1 -0
- alysis_code/model_catalog/chatgpt_codex_subscription_snapshot.json +186 -0
- alysis_code/model_catalog/litellm_model_prices_snapshot.json +44715 -0
- alysis_code/model_catalog/litellm_model_prices_snapshot.meta.json +17 -0
- alysis_code/model_metadata_policy.py +223 -0
- alysis_code/model_metadata_utils.py +103 -0
- alysis_code/model_registry.py +1420 -0
- alysis_code/model_router.py +147 -0
- alysis_code/permission_policy.py +1016 -0
- alysis_code/personas.py +451 -0
- alysis_code/pipeline_facts.py +233 -0
- alysis_code/plan_assistant.py +4763 -0
- alysis_code/plan_mode.py +393 -0
- alysis_code/plan_reconciliation.py +1228 -0
- alysis_code/plan_repair.py +652 -0
- alysis_code/plan_validation.py +1099 -0
- alysis_code/planning_constraints.py +904 -0
- alysis_code/policy.py +95 -0
- alysis_code/preview_server.py +457 -0
- alysis_code/process_reaping.py +566 -0
- alysis_code/profile_presets.py +1834 -0
- alysis_code/profiles.py +666 -0
- alysis_code/provider_auth/__init__.py +29 -0
- alysis_code/provider_auth/base.py +99 -0
- alysis_code/provider_auth/openai_codex.py +951 -0
- alysis_code/provider_auth/registry.py +76 -0
- alysis_code/provider_auth/store.py +125 -0
- alysis_code/provider_diagnostics.py +1209 -0
- alysis_code/provider_model_catalog.py +685 -0
- alysis_code/provider_telemetry.py +1699 -0
- alysis_code/provider_url.py +75 -0
- alysis_code/reasoning_contracts.py +911 -0
- alysis_code/remote_sync.py +350 -0
- alysis_code/replanning.py +1195 -0
- alysis_code/repo_scan.py +1152 -0
- alysis_code/request_estimation.py +296 -0
- alysis_code/review_gate.py +617 -0
- alysis_code/run_lock.py +1141 -0
- alysis_code/run_outcome.py +58 -0
- alysis_code/run_provenance.py +774 -0
- alysis_code/run_state.py +445 -0
- alysis_code/runtime_artifacts.py +116 -0
- alysis_code/runtime_context_features.py +78 -0
- alysis_code/runtime_kind.py +52 -0
- alysis_code/safety/__init__.py +11 -0
- alysis_code/safety/mcp_sanitize.py +29 -0
- alysis_code/safety/safe_http.py +297 -0
- alysis_code/safety/subagent_report.py +184 -0
- alysis_code/sandbox_doctor.py +682 -0
- alysis_code/sandbox_runner.py +1025 -0
- alysis_code/sandbox_settings.py +423 -0
- alysis_code/serialized_paths.py +355 -0
- alysis_code/server/__init__.py +3 -0
- alysis_code/server/app.py +367 -0
- alysis_code/server/auth.py +34 -0
- alysis_code/server/job_config.py +30 -0
- alysis_code/server/settings.py +215 -0
- alysis_code/server/store.py +193 -0
- alysis_code/server/worker_runner.py +657 -0
- alysis_code/service_persistence.py +355 -0
- alysis_code/session_artifacts.py +108 -0
- alysis_code/session_metrics.py +331 -0
- alysis_code/session_store.py +624 -0
- alysis_code/skills/README.md +34 -0
- alysis_code/skills/__init__.py +104 -0
- alysis_code/skills/conventions.py +84 -0
- alysis_code/skills/discovery.py +176 -0
- alysis_code/skills/eval_models.py +232 -0
- alysis_code/skills/eval_runner.py +372 -0
- alysis_code/skills/evals.py +1344 -0
- alysis_code/skills/install.py +293 -0
- alysis_code/skills/loader.py +118 -0
- alysis_code/skills/matching.py +103 -0
- alysis_code/skills/models.py +71 -0
- alysis_code/skills/paths.py +56 -0
- alysis_code/skills/prompting.py +500 -0
- alysis_code/skills/scaffold.py +142 -0
- alysis_code/skills/state.py +441 -0
- alysis_code/skills/transactions.py +125 -0
- alysis_code/skills/validation.py +304 -0
- alysis_code/step_budget.py +238 -0
- alysis_code/subagent_labels.py +49 -0
- alysis_code/subagents.py +1072 -0
- alysis_code/surface/__init__.py +80 -0
- alysis_code/surface/base.py +305 -0
- alysis_code/surface/console.py +387 -0
- alysis_code/surface/events.py +372 -0
- alysis_code/surface/hidden_surface.py +529 -0
- alysis_code/surface/noop_surface.py +219 -0
- alysis_code/surface/rich_surface.py +1555 -0
- alysis_code/surface/styles.py +67 -0
- alysis_code/surface/theme.py +455 -0
- alysis_code/surface/types.py +100 -0
- alysis_code/swarm_backend.py +926 -0
- alysis_code/swarm_orchestrator.py +4020 -0
- alysis_code/swarm_scheduler.py +441 -0
- alysis_code/swarm_trace.py +429 -0
- alysis_code/swarm_worker.py +2119 -0
- alysis_code/swarm_write_guard.py +348 -0
- alysis_code/task_dependencies.py +170 -0
- alysis_code/task_readiness.py +992 -0
- alysis_code/task_scope.py +2148 -0
- alysis_code/terminal_manager.py +762 -0
- alysis_code/terminal_ownership.py +460 -0
- alysis_code/text_normalization.py +30 -0
- alysis_code/token_budget.py +97 -0
- alysis_code/tools/README.md +34 -0
- alysis_code/tools/__init__.py +1 -0
- alysis_code/tools/artifacts.py +127 -0
- alysis_code/tools/availability.py +188 -0
- alysis_code/tools/fs.py +1456 -0
- alysis_code/tools/git.py +461 -0
- alysis_code/tools/history.py +229 -0
- alysis_code/tools/http_timeout.py +78 -0
- alysis_code/tools/image_generation.py +552 -0
- alysis_code/tools/registry.py +2936 -0
- alysis_code/tools/repo_map.py +476 -0
- alysis_code/tools/search.py +563 -0
- alysis_code/tools/shell.py +135 -0
- alysis_code/tools/symbols.py +1350 -0
- alysis_code/tools/test_discovery.py +643 -0
- alysis_code/tools/web.py +482 -0
- alysis_code/tools/web_search.py +2012 -0
- alysis_code/tools/web_search_dashscope.py +557 -0
- alysis_code/tools/web_search_ddgs.py +221 -0
- alysis_code/tools/web_search_provider_adapters.py +1429 -0
- alysis_code/tools/web_search_tavily.py +194 -0
- alysis_code/updates.py +933 -0
- alysis_code/usage_tracker.py +1990 -0
- alysis_code/verification_command_analysis.py +1004 -0
- alysis_code/verification_contract.py +574 -0
- alysis_code/verification_failure_summary.py +273 -0
- alysis_code/verification_repair.py +385 -0
- alysis_code/verify_gate.py +3129 -0
- alysis_code/web_research.py +1872 -0
- alysis_code/web_search_adapters.py +66 -0
- alysis_code/web_search_policy.py +27 -0
- alysis_code/workspace_binding.py +389 -0
- alysis_code/workspace_binding_ui.py +408 -0
- alysis_code/workspace_context.py +273 -0
- alysis_code/workspace_isolation.py +138 -0
- alysis_code/workspace_provisioning.py +455 -0
- alysis_code-0.13.0.dist-info/METADATA +507 -0
- alysis_code-0.13.0.dist-info/RECORD +458 -0
- alysis_code-0.13.0.dist-info/WHEEL +4 -0
- alysis_code-0.13.0.dist-info/entry_points.txt +3 -0
- alysis_code-0.13.0.dist-info/licenses/LICENSE +176 -0
- alysis_code-0.13.0.dist-info/licenses/NOTICE +4 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from ..config import ConfigError
|
|
7
|
+
from .models import normalize_server_id
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass(frozen=True)
|
|
11
|
+
class ForgeAllowedMcpTool:
|
|
12
|
+
server_id: str
|
|
13
|
+
tool_name: str
|
|
14
|
+
|
|
15
|
+
def as_payload(self) -> dict[str, str]:
|
|
16
|
+
return {
|
|
17
|
+
"server_id": self.server_id,
|
|
18
|
+
"tool_name": self.tool_name,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass(frozen=True)
|
|
23
|
+
class ForgeTaskMcpScope:
|
|
24
|
+
allow_resources: bool = False
|
|
25
|
+
allowed_tools: tuple[ForgeAllowedMcpTool, ...] = ()
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def is_empty(self) -> bool:
|
|
29
|
+
return not self.allow_resources and not self.allowed_tools
|
|
30
|
+
|
|
31
|
+
def as_payload(self) -> dict[str, Any]:
|
|
32
|
+
payload: dict[str, Any] = {}
|
|
33
|
+
if self.allow_resources:
|
|
34
|
+
payload["allow_resources"] = True
|
|
35
|
+
if self.allowed_tools:
|
|
36
|
+
payload["allowed_tools"] = [item.as_payload() for item in self.allowed_tools]
|
|
37
|
+
return payload
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def serialize_task_mcp_scope(scope: ForgeTaskMcpScope | None) -> dict[str, Any] | None:
|
|
41
|
+
if scope is None or scope.is_empty:
|
|
42
|
+
return None
|
|
43
|
+
return scope.as_payload()
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def describe_task_mcp_scope(scope: ForgeTaskMcpScope | None) -> str:
|
|
47
|
+
if scope is None or scope.is_empty:
|
|
48
|
+
return "disabled (default deny-by-default)"
|
|
49
|
+
parts = [
|
|
50
|
+
(
|
|
51
|
+
"generic MCP resources allowed"
|
|
52
|
+
if scope.allow_resources
|
|
53
|
+
else "generic MCP resources blocked"
|
|
54
|
+
),
|
|
55
|
+
(
|
|
56
|
+
"allowed live MCP tools: "
|
|
57
|
+
+ ", ".join(f"{item.server_id}/{item.tool_name}" for item in scope.allowed_tools)
|
|
58
|
+
if scope.allowed_tools
|
|
59
|
+
else "allowed live MCP tools: (none)"
|
|
60
|
+
),
|
|
61
|
+
]
|
|
62
|
+
return "; ".join(parts)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def normalize_task_mcp_scope(
|
|
66
|
+
value: Any,
|
|
67
|
+
*,
|
|
68
|
+
warning_prefix: str,
|
|
69
|
+
) -> tuple[ForgeTaskMcpScope | None, list[str]]:
|
|
70
|
+
if value is None:
|
|
71
|
+
return None, []
|
|
72
|
+
|
|
73
|
+
warnings: list[str] = []
|
|
74
|
+
if not isinstance(value, dict):
|
|
75
|
+
return None, [f"{warning_prefix}: dropped invalid mcp_scope: expected an object."]
|
|
76
|
+
|
|
77
|
+
allow_resources = False
|
|
78
|
+
if "allow_resources" in value:
|
|
79
|
+
raw_allow_resources = value.get("allow_resources")
|
|
80
|
+
if isinstance(raw_allow_resources, bool):
|
|
81
|
+
allow_resources = raw_allow_resources
|
|
82
|
+
else:
|
|
83
|
+
warnings.append(
|
|
84
|
+
f"{warning_prefix}: dropped invalid mcp_scope.allow_resources value; expected true/false."
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
allowed_tools: list[ForgeAllowedMcpTool] = []
|
|
88
|
+
seen_tool_keys: set[tuple[str, str]] = set()
|
|
89
|
+
if "allowed_tools" in value:
|
|
90
|
+
raw_allowed_tools = value.get("allowed_tools")
|
|
91
|
+
if not isinstance(raw_allowed_tools, list):
|
|
92
|
+
warnings.append(
|
|
93
|
+
f"{warning_prefix}: dropped invalid mcp_scope.allowed_tools value; expected an array."
|
|
94
|
+
)
|
|
95
|
+
else:
|
|
96
|
+
for index, raw_item in enumerate(raw_allowed_tools):
|
|
97
|
+
normalized_tool, tool_warnings = _normalize_allowed_tool_entry(
|
|
98
|
+
raw_item,
|
|
99
|
+
warning_prefix=warning_prefix,
|
|
100
|
+
index=index,
|
|
101
|
+
)
|
|
102
|
+
warnings.extend(tool_warnings)
|
|
103
|
+
if normalized_tool is None:
|
|
104
|
+
continue
|
|
105
|
+
dedupe_key = (
|
|
106
|
+
normalized_tool.server_id,
|
|
107
|
+
normalized_tool.tool_name.casefold(),
|
|
108
|
+
)
|
|
109
|
+
if dedupe_key in seen_tool_keys:
|
|
110
|
+
continue
|
|
111
|
+
seen_tool_keys.add(dedupe_key)
|
|
112
|
+
allowed_tools.append(normalized_tool)
|
|
113
|
+
|
|
114
|
+
scope = ForgeTaskMcpScope(
|
|
115
|
+
allow_resources=allow_resources,
|
|
116
|
+
allowed_tools=tuple(allowed_tools),
|
|
117
|
+
)
|
|
118
|
+
if scope.is_empty:
|
|
119
|
+
warnings.append(
|
|
120
|
+
f"{warning_prefix}: normalized empty mcp_scope; MCP execution remains deny-by-default."
|
|
121
|
+
)
|
|
122
|
+
return None, warnings
|
|
123
|
+
return scope, warnings
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _normalize_allowed_tool_entry(
|
|
127
|
+
raw_item: Any,
|
|
128
|
+
*,
|
|
129
|
+
warning_prefix: str,
|
|
130
|
+
index: int,
|
|
131
|
+
) -> tuple[ForgeAllowedMcpTool | None, list[str]]:
|
|
132
|
+
item_label = f"{warning_prefix}: dropped invalid mcp_scope.allowed_tools[{index}] entry"
|
|
133
|
+
if not isinstance(raw_item, dict):
|
|
134
|
+
return None, [f"{item_label}: expected an object."]
|
|
135
|
+
|
|
136
|
+
raw_server_id = raw_item.get("server_id")
|
|
137
|
+
if not isinstance(raw_server_id, str):
|
|
138
|
+
return None, [f"{item_label}: server_id must be a string."]
|
|
139
|
+
server_id_value = raw_server_id.strip()
|
|
140
|
+
if not server_id_value:
|
|
141
|
+
return None, [f"{item_label}: server_id cannot be empty."]
|
|
142
|
+
try:
|
|
143
|
+
server_id = normalize_server_id(server_id_value)
|
|
144
|
+
except ConfigError as exc:
|
|
145
|
+
return None, [f"{item_label}: {exc}"]
|
|
146
|
+
|
|
147
|
+
raw_tool_name = raw_item.get("tool_name")
|
|
148
|
+
if not isinstance(raw_tool_name, str):
|
|
149
|
+
return None, [f"{item_label}: tool_name must be a string."]
|
|
150
|
+
tool_name = raw_tool_name.strip()
|
|
151
|
+
if not tool_name:
|
|
152
|
+
return None, [f"{item_label}: tool_name cannot be empty."]
|
|
153
|
+
|
|
154
|
+
return ForgeAllowedMcpTool(server_id=server_id, tool_name=tool_name), []
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Any, TypeAlias
|
|
6
|
+
|
|
7
|
+
from .errors import McpProtocolError
|
|
8
|
+
|
|
9
|
+
JsonRpcId: TypeAlias = int | str
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class JsonRpcProtocolError(McpProtocolError):
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _validate_request_id(value: object, *, field_name: str = "id") -> JsonRpcId:
|
|
17
|
+
if isinstance(value, bool):
|
|
18
|
+
raise JsonRpcProtocolError(f"JSON-RPC {field_name} must be a string or integer.")
|
|
19
|
+
if isinstance(value, int):
|
|
20
|
+
return value
|
|
21
|
+
if isinstance(value, str):
|
|
22
|
+
cleaned = value.strip()
|
|
23
|
+
if not cleaned:
|
|
24
|
+
raise JsonRpcProtocolError(f"JSON-RPC {field_name} cannot be empty.")
|
|
25
|
+
return cleaned
|
|
26
|
+
raise JsonRpcProtocolError(f"JSON-RPC {field_name} must be a string or integer.")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _validate_method(value: object) -> str:
|
|
30
|
+
if not isinstance(value, str):
|
|
31
|
+
raise JsonRpcProtocolError("JSON-RPC method must be a string.")
|
|
32
|
+
cleaned = value.strip()
|
|
33
|
+
if not cleaned:
|
|
34
|
+
raise JsonRpcProtocolError("JSON-RPC method cannot be empty.")
|
|
35
|
+
return cleaned
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _validate_envelope_version(payload: dict[str, Any]) -> None:
|
|
39
|
+
if payload.get("jsonrpc") != "2.0":
|
|
40
|
+
raise JsonRpcProtocolError("JSON-RPC envelope must include jsonrpc='2.0'.")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass(frozen=True)
|
|
44
|
+
class JsonRpcErrorObject:
|
|
45
|
+
code: int
|
|
46
|
+
message: str
|
|
47
|
+
data: Any | None = None
|
|
48
|
+
|
|
49
|
+
@classmethod
|
|
50
|
+
def from_payload(cls, payload: object) -> JsonRpcErrorObject:
|
|
51
|
+
if not isinstance(payload, dict):
|
|
52
|
+
raise JsonRpcProtocolError("JSON-RPC error payload must be an object.")
|
|
53
|
+
code = payload.get("code")
|
|
54
|
+
message = payload.get("message")
|
|
55
|
+
if isinstance(code, bool) or not isinstance(code, int):
|
|
56
|
+
raise JsonRpcProtocolError("JSON-RPC error.code must be an integer.")
|
|
57
|
+
if not isinstance(message, str) or not message.strip():
|
|
58
|
+
raise JsonRpcProtocolError("JSON-RPC error.message must be a non-empty string.")
|
|
59
|
+
return cls(code=code, message=message.strip(), data=payload.get("data"))
|
|
60
|
+
|
|
61
|
+
def as_payload(self) -> dict[str, Any]:
|
|
62
|
+
payload = {
|
|
63
|
+
"code": self.code,
|
|
64
|
+
"message": self.message,
|
|
65
|
+
}
|
|
66
|
+
if self.data is not None:
|
|
67
|
+
payload["data"] = self.data
|
|
68
|
+
return payload
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass(frozen=True)
|
|
72
|
+
class JsonRpcRequest:
|
|
73
|
+
id: JsonRpcId
|
|
74
|
+
method: str
|
|
75
|
+
params: Any | None = None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@dataclass(frozen=True)
|
|
79
|
+
class JsonRpcNotification:
|
|
80
|
+
method: str
|
|
81
|
+
params: Any | None = None
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@dataclass(frozen=True)
|
|
85
|
+
class JsonRpcResponse:
|
|
86
|
+
id: JsonRpcId
|
|
87
|
+
result: Any | None = None
|
|
88
|
+
error: JsonRpcErrorObject | None = None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
JsonRpcMessage: TypeAlias = JsonRpcRequest | JsonRpcNotification | JsonRpcResponse
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class JsonRpcIdGenerator:
|
|
95
|
+
def __init__(self, *, start: int = 1) -> None:
|
|
96
|
+
self._next_id = int(start)
|
|
97
|
+
|
|
98
|
+
def next(self) -> int:
|
|
99
|
+
request_id = self._next_id
|
|
100
|
+
self._next_id += 1
|
|
101
|
+
return request_id
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def encode_jsonrpc_message(payload: dict[str, Any]) -> str:
|
|
105
|
+
return json.dumps(payload, ensure_ascii=True, separators=(",", ":"))
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def build_jsonrpc_request(
|
|
109
|
+
*,
|
|
110
|
+
request_id: JsonRpcId,
|
|
111
|
+
method: str,
|
|
112
|
+
params: Any | None = None,
|
|
113
|
+
) -> dict[str, Any]:
|
|
114
|
+
payload: dict[str, Any] = {
|
|
115
|
+
"jsonrpc": "2.0",
|
|
116
|
+
"id": _validate_request_id(request_id),
|
|
117
|
+
"method": _validate_method(method),
|
|
118
|
+
}
|
|
119
|
+
if params is not None:
|
|
120
|
+
payload["params"] = params
|
|
121
|
+
return payload
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def build_jsonrpc_notification(
|
|
125
|
+
*,
|
|
126
|
+
method: str,
|
|
127
|
+
params: Any | None = None,
|
|
128
|
+
) -> dict[str, Any]:
|
|
129
|
+
payload: dict[str, Any] = {
|
|
130
|
+
"jsonrpc": "2.0",
|
|
131
|
+
"method": _validate_method(method),
|
|
132
|
+
}
|
|
133
|
+
if params is not None:
|
|
134
|
+
payload["params"] = params
|
|
135
|
+
return payload
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def build_jsonrpc_result_response(
|
|
139
|
+
*,
|
|
140
|
+
request_id: JsonRpcId,
|
|
141
|
+
result: Any,
|
|
142
|
+
) -> dict[str, Any]:
|
|
143
|
+
return {
|
|
144
|
+
"jsonrpc": "2.0",
|
|
145
|
+
"id": _validate_request_id(request_id),
|
|
146
|
+
"result": result,
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def build_jsonrpc_error_response(
|
|
151
|
+
*,
|
|
152
|
+
request_id: JsonRpcId,
|
|
153
|
+
code: int,
|
|
154
|
+
message: str,
|
|
155
|
+
data: Any | None = None,
|
|
156
|
+
) -> dict[str, Any]:
|
|
157
|
+
error = JsonRpcErrorObject(code=code, message=str(message).strip(), data=data)
|
|
158
|
+
return {
|
|
159
|
+
"jsonrpc": "2.0",
|
|
160
|
+
"id": _validate_request_id(request_id),
|
|
161
|
+
"error": error.as_payload(),
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def _parse_jsonrpc_message(payload: object) -> JsonRpcMessage:
|
|
166
|
+
if not isinstance(payload, dict):
|
|
167
|
+
raise JsonRpcProtocolError("JSON-RPC message must be an object.")
|
|
168
|
+
_validate_envelope_version(payload)
|
|
169
|
+
|
|
170
|
+
has_method = "method" in payload
|
|
171
|
+
has_id = "id" in payload
|
|
172
|
+
has_result = "result" in payload
|
|
173
|
+
has_error = "error" in payload
|
|
174
|
+
|
|
175
|
+
if has_method:
|
|
176
|
+
method = _validate_method(payload.get("method"))
|
|
177
|
+
if has_result or has_error:
|
|
178
|
+
raise JsonRpcProtocolError(
|
|
179
|
+
"JSON-RPC request/notification cannot include result or error fields."
|
|
180
|
+
)
|
|
181
|
+
params = payload.get("params")
|
|
182
|
+
if has_id:
|
|
183
|
+
return JsonRpcRequest(
|
|
184
|
+
id=_validate_request_id(payload.get("id")),
|
|
185
|
+
method=method,
|
|
186
|
+
params=params,
|
|
187
|
+
)
|
|
188
|
+
return JsonRpcNotification(method=method, params=params)
|
|
189
|
+
|
|
190
|
+
if not has_id:
|
|
191
|
+
raise JsonRpcProtocolError("JSON-RPC response must include an id field.")
|
|
192
|
+
if has_result == has_error:
|
|
193
|
+
raise JsonRpcProtocolError("JSON-RPC response must include exactly one of result or error.")
|
|
194
|
+
request_id = _validate_request_id(payload.get("id"))
|
|
195
|
+
if has_error:
|
|
196
|
+
return JsonRpcResponse(
|
|
197
|
+
id=request_id, error=JsonRpcErrorObject.from_payload(payload["error"])
|
|
198
|
+
)
|
|
199
|
+
return JsonRpcResponse(id=request_id, result=payload.get("result"))
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def parse_jsonrpc_line(raw_line: str) -> tuple[JsonRpcMessage, ...]:
|
|
203
|
+
text = str(raw_line).strip()
|
|
204
|
+
if not text:
|
|
205
|
+
raise JsonRpcProtocolError("JSON-RPC line cannot be empty.")
|
|
206
|
+
try:
|
|
207
|
+
payload = json.loads(text)
|
|
208
|
+
except json.JSONDecodeError as exc:
|
|
209
|
+
raise JsonRpcProtocolError(f"Malformed JSON-RPC JSON: {exc.msg}") from exc
|
|
210
|
+
if isinstance(payload, list):
|
|
211
|
+
if not payload:
|
|
212
|
+
raise JsonRpcProtocolError("JSON-RPC batch payload cannot be empty.")
|
|
213
|
+
return tuple(_parse_jsonrpc_message(item) for item in payload)
|
|
214
|
+
return (_parse_jsonrpc_message(payload),)
|