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,412 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
from rich.panel import Panel
|
|
10
|
+
from rich.table import Table
|
|
11
|
+
|
|
12
|
+
from ..assets import (
|
|
13
|
+
AssetAlreadyExistsError,
|
|
14
|
+
AssetError,
|
|
15
|
+
AssetSurface,
|
|
16
|
+
AssetSurfaceDetail,
|
|
17
|
+
)
|
|
18
|
+
from ..assets.ingestion import _classify_asset
|
|
19
|
+
from ..assets.surface import build_asset_surface
|
|
20
|
+
from ..branding import env_get
|
|
21
|
+
from ..config import AppConfig
|
|
22
|
+
from ..forge import RunPaths, load_plan
|
|
23
|
+
from ..surface.console import make_console
|
|
24
|
+
|
|
25
|
+
_STATUS_EMOJI = {
|
|
26
|
+
"ready": "🟢",
|
|
27
|
+
"pending": "🟡",
|
|
28
|
+
"running": "🟡",
|
|
29
|
+
"failed": "🔴",
|
|
30
|
+
"minimal": "⚪",
|
|
31
|
+
}
|
|
32
|
+
_STATUS_TEXT = {
|
|
33
|
+
"ready": "[ready]",
|
|
34
|
+
"pending": "[pending]",
|
|
35
|
+
"running": "[running]",
|
|
36
|
+
"failed": "[failed]",
|
|
37
|
+
"minimal": "[minimal]",
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def run_assets_modal(
|
|
42
|
+
*,
|
|
43
|
+
cfg: AppConfig,
|
|
44
|
+
run_paths: RunPaths,
|
|
45
|
+
surface: AssetSurface | None = None,
|
|
46
|
+
console: Console | None = None,
|
|
47
|
+
) -> None:
|
|
48
|
+
console = console or make_console()
|
|
49
|
+
if surface is None:
|
|
50
|
+
load_plan(run_paths)
|
|
51
|
+
surface = build_asset_surface(cfg=cfg, run_paths=run_paths)
|
|
52
|
+
if not sys.stdin.isatty():
|
|
53
|
+
console.print("Assets modal is unavailable when stdin is not a terminal.")
|
|
54
|
+
return
|
|
55
|
+
while True:
|
|
56
|
+
choice = _prompt_choice(
|
|
57
|
+
console=console,
|
|
58
|
+
title=f"Assets · run {run_paths.run_id}",
|
|
59
|
+
choices=[
|
|
60
|
+
("add", "Add a new asset"),
|
|
61
|
+
("list", f"See all assets ({len(surface.list_assets())})"),
|
|
62
|
+
("back", "Back"),
|
|
63
|
+
],
|
|
64
|
+
)
|
|
65
|
+
if choice in {None, "back"}:
|
|
66
|
+
return
|
|
67
|
+
if choice == "add":
|
|
68
|
+
_add_asset_flow(console=console, surface=surface, run_paths=run_paths)
|
|
69
|
+
elif choice == "list":
|
|
70
|
+
_list_flow(console=console, surface=surface)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def status_label(status: str, *, pinned: bool = False, emoji: bool | None = None) -> str:
|
|
74
|
+
use_emoji = terminal_supports_emoji() if emoji is None else emoji
|
|
75
|
+
status_key = str(status or "pending").strip().lower()
|
|
76
|
+
if use_emoji:
|
|
77
|
+
prefix = "📌" if pinned else ""
|
|
78
|
+
return f"{prefix}{_STATUS_EMOJI.get(status_key, _STATUS_EMOJI['pending'])}"
|
|
79
|
+
prefix = "[pinned]" if pinned else ""
|
|
80
|
+
return f"{prefix}{_STATUS_TEXT.get(status_key, _STATUS_TEXT['pending'])}"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def terminal_supports_emoji() -> bool:
|
|
84
|
+
if env_get("ALYSIS_NO_EMOJI") in {"1", "true", "yes", "on"}:
|
|
85
|
+
return False
|
|
86
|
+
encoding = getattr(sys.stdout, "encoding", None) or "utf-8"
|
|
87
|
+
try:
|
|
88
|
+
"🟢📌".encode(encoding)
|
|
89
|
+
except UnicodeEncodeError:
|
|
90
|
+
return False
|
|
91
|
+
return True
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _add_asset_flow(*, console: Console, surface: AssetSurface, run_paths: RunPaths) -> None:
|
|
95
|
+
source = _prompt_path(console=console, root=run_paths.root)
|
|
96
|
+
if source is None:
|
|
97
|
+
return
|
|
98
|
+
title = _prompt_limited_text(console, "Title", required=True, max_chars=80)
|
|
99
|
+
if title is None:
|
|
100
|
+
return
|
|
101
|
+
description = _prompt_limited_text(console, "Description", required=False, max_chars=240)
|
|
102
|
+
if description is None:
|
|
103
|
+
return
|
|
104
|
+
pinned = typer.confirm("Pinned", default=False)
|
|
105
|
+
console.print(
|
|
106
|
+
Panel(
|
|
107
|
+
"\n".join(
|
|
108
|
+
[
|
|
109
|
+
f"Path: {source}",
|
|
110
|
+
f"Title: {title}",
|
|
111
|
+
f"Description: {description or '-'}",
|
|
112
|
+
f"Pinned: {'yes' if pinned else 'no'}",
|
|
113
|
+
]
|
|
114
|
+
),
|
|
115
|
+
title="Confirm Asset",
|
|
116
|
+
border_style="bright_black",
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
if not typer.confirm("Add asset", default=True):
|
|
120
|
+
console.print("Cancelled.")
|
|
121
|
+
return
|
|
122
|
+
try:
|
|
123
|
+
result = surface.add_asset(
|
|
124
|
+
source,
|
|
125
|
+
title=title,
|
|
126
|
+
description=description,
|
|
127
|
+
pinned=pinned,
|
|
128
|
+
added_by={"phase": "modal", "command": "/assets"},
|
|
129
|
+
comprehend="async",
|
|
130
|
+
dedupe_policy="reject",
|
|
131
|
+
)
|
|
132
|
+
except AssetAlreadyExistsError as exc:
|
|
133
|
+
_handle_collision(
|
|
134
|
+
console=console, surface=surface, source=source, existing_id=exc.existing_id
|
|
135
|
+
)
|
|
136
|
+
return
|
|
137
|
+
except AssetError as exc:
|
|
138
|
+
console.print(f"[red]{exc}[/red]")
|
|
139
|
+
return
|
|
140
|
+
console.print(f"Asset added: {result.record.id}")
|
|
141
|
+
if result.comprehension_handle is not None:
|
|
142
|
+
console.print("Comprehension started in background.")
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _handle_collision(
|
|
146
|
+
*,
|
|
147
|
+
console: Console,
|
|
148
|
+
surface: AssetSurface,
|
|
149
|
+
source: Path,
|
|
150
|
+
existing_id: str,
|
|
151
|
+
) -> None:
|
|
152
|
+
existing = surface.index.get(existing_id, include_deleted=True)
|
|
153
|
+
choice = _prompt_choice(
|
|
154
|
+
console=console,
|
|
155
|
+
title="Duplicate Asset",
|
|
156
|
+
choices=[
|
|
157
|
+
("use", f'Use existing asset ({existing.id} - "{existing.title}")'),
|
|
158
|
+
("link", "Return existing asset"),
|
|
159
|
+
("cancel", "Cancel"),
|
|
160
|
+
],
|
|
161
|
+
)
|
|
162
|
+
if choice == "use":
|
|
163
|
+
console.print(f"Using existing asset: {existing.id}")
|
|
164
|
+
return
|
|
165
|
+
if choice != "link":
|
|
166
|
+
console.print("Cancelled.")
|
|
167
|
+
return
|
|
168
|
+
result = surface.add_asset(
|
|
169
|
+
source,
|
|
170
|
+
title=existing.title,
|
|
171
|
+
description=existing.description,
|
|
172
|
+
pinned=existing.pinned,
|
|
173
|
+
added_by={"phase": "modal", "command": "/assets"},
|
|
174
|
+
comprehend="async",
|
|
175
|
+
dedupe_policy="link",
|
|
176
|
+
)
|
|
177
|
+
console.print(f"Using existing asset: {result.record.id}")
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _list_flow(*, console: Console, surface: AssetSurface) -> None:
|
|
181
|
+
while True:
|
|
182
|
+
entries = surface.list_assets()
|
|
183
|
+
if not entries:
|
|
184
|
+
console.print("No assets attached.")
|
|
185
|
+
return
|
|
186
|
+
table = Table(title="Assets")
|
|
187
|
+
table.add_column("status")
|
|
188
|
+
table.add_column("kind")
|
|
189
|
+
table.add_column("id")
|
|
190
|
+
table.add_column("title")
|
|
191
|
+
table.add_column("size")
|
|
192
|
+
for entry in entries:
|
|
193
|
+
table.add_row(
|
|
194
|
+
status_label(entry.comprehension_status, pinned=entry.record.pinned),
|
|
195
|
+
"img" if entry.record.kind == "image" else "txt",
|
|
196
|
+
entry.record.id,
|
|
197
|
+
entry.record.title,
|
|
198
|
+
_format_size(entry.record.size_bytes),
|
|
199
|
+
)
|
|
200
|
+
console.print(table)
|
|
201
|
+
choice = _prompt_choice(
|
|
202
|
+
console=console,
|
|
203
|
+
title="Assets",
|
|
204
|
+
choices=[
|
|
205
|
+
*(
|
|
206
|
+
(entry.record.id, f"{entry.record.id} - {entry.record.title}")
|
|
207
|
+
for entry in entries
|
|
208
|
+
),
|
|
209
|
+
("refresh", "Refresh status"),
|
|
210
|
+
("back", "Back"),
|
|
211
|
+
],
|
|
212
|
+
)
|
|
213
|
+
if choice in {None, "back"}:
|
|
214
|
+
return
|
|
215
|
+
if choice == "refresh":
|
|
216
|
+
continue
|
|
217
|
+
_detail_flow(console=console, surface=surface, asset_id=choice)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def _detail_flow(*, console: Console, surface: AssetSurface, asset_id: str) -> None:
|
|
221
|
+
while True:
|
|
222
|
+
try:
|
|
223
|
+
detail = surface.show_asset(asset_id)
|
|
224
|
+
except AssetError as exc:
|
|
225
|
+
console.print(f"[red]{exc}[/red]")
|
|
226
|
+
return
|
|
227
|
+
console.print(_detail_panel(detail))
|
|
228
|
+
deleted = detail.record.deleted_at is not None
|
|
229
|
+
choices = [("back", "Back")]
|
|
230
|
+
if not deleted:
|
|
231
|
+
choices = [
|
|
232
|
+
("edit", "Edit metadata"),
|
|
233
|
+
("toggle", "Toggle pinned"),
|
|
234
|
+
("refresh", "Refresh comprehension"),
|
|
235
|
+
("text", "View extracted text"),
|
|
236
|
+
("json", "View comprehension JSON"),
|
|
237
|
+
("delete", "Delete"),
|
|
238
|
+
("back", "Back"),
|
|
239
|
+
]
|
|
240
|
+
choice = _prompt_choice(console=console, title=detail.record.id, choices=choices)
|
|
241
|
+
if choice in {None, "back"}:
|
|
242
|
+
return
|
|
243
|
+
if choice == "edit":
|
|
244
|
+
_edit_metadata(console=console, surface=surface, detail=detail)
|
|
245
|
+
elif choice == "toggle":
|
|
246
|
+
surface.edit_asset(detail.record.id, pinned=not detail.record.pinned)
|
|
247
|
+
elif choice == "refresh":
|
|
248
|
+
surface.refresh_comprehension(detail.record.id, mode="async")
|
|
249
|
+
console.print("Refresh started - status will update on next refresh.")
|
|
250
|
+
elif choice == "text":
|
|
251
|
+
console.print(detail.extracted_text_preview or "No extracted text available")
|
|
252
|
+
elif choice == "json":
|
|
253
|
+
payload = detail.comprehension.to_dict() if detail.comprehension is not None else {}
|
|
254
|
+
console.print(json.dumps(payload, indent=2, sort_keys=True, ensure_ascii=False))
|
|
255
|
+
elif choice == "delete" and typer.confirm(f"Delete {detail.record.id}?", default=False):
|
|
256
|
+
surface.delete_asset(detail.record.id)
|
|
257
|
+
return
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def _detail_panel(detail: AssetSurfaceDetail) -> Panel:
|
|
261
|
+
record = detail.record
|
|
262
|
+
comprehension = detail.comprehension
|
|
263
|
+
status = "deleted" if record.deleted_at is not None else detail.comprehension_status
|
|
264
|
+
lines = [
|
|
265
|
+
f"Status: {status}",
|
|
266
|
+
f"Kind: {record.kind} · {_format_size(record.size_bytes)} · {record.mime}",
|
|
267
|
+
f"Original file: {record.original_filename}",
|
|
268
|
+
f"Pinned: {'yes' if record.pinned else 'no'}",
|
|
269
|
+
f"Versions: {', '.join(str(version) for version in detail.versions) or '-'}",
|
|
270
|
+
"",
|
|
271
|
+
"Description:",
|
|
272
|
+
f" {record.description or '-'}",
|
|
273
|
+
]
|
|
274
|
+
if record.deleted_at is not None:
|
|
275
|
+
lines.insert(1, f"Deleted at: {record.deleted_at}")
|
|
276
|
+
if comprehension is not None:
|
|
277
|
+
lines.extend(
|
|
278
|
+
[
|
|
279
|
+
"",
|
|
280
|
+
f"Detected lang: {comprehension.detected_language or '-'}",
|
|
281
|
+
f"Source: {comprehension.source}",
|
|
282
|
+
"",
|
|
283
|
+
"Comprehension summary:",
|
|
284
|
+
f" {comprehension.data.semantic_summary or '-'}",
|
|
285
|
+
]
|
|
286
|
+
)
|
|
287
|
+
if comprehension.data.stated_facts:
|
|
288
|
+
lines.append("")
|
|
289
|
+
lines.append("Stated facts:")
|
|
290
|
+
lines.extend(f" - {fact}" for fact in comprehension.data.stated_facts[:8])
|
|
291
|
+
return Panel("\n".join(lines), title=f'{record.id} - "{record.title}"')
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def _edit_metadata(*, console: Console, surface: AssetSurface, detail: AssetSurfaceDetail) -> None:
|
|
295
|
+
title = _prompt_limited_text(
|
|
296
|
+
console,
|
|
297
|
+
"Title",
|
|
298
|
+
required=True,
|
|
299
|
+
max_chars=80,
|
|
300
|
+
default=detail.record.title,
|
|
301
|
+
)
|
|
302
|
+
if title is None:
|
|
303
|
+
return
|
|
304
|
+
description = _prompt_limited_text(
|
|
305
|
+
console,
|
|
306
|
+
"Description",
|
|
307
|
+
required=False,
|
|
308
|
+
max_chars=240,
|
|
309
|
+
default=detail.record.description,
|
|
310
|
+
)
|
|
311
|
+
if description is None:
|
|
312
|
+
return
|
|
313
|
+
surface.edit_asset(detail.record.id, title=title, description=description)
|
|
314
|
+
console.print(
|
|
315
|
+
"Title/description changed. Comprehension reflects previous metadata. "
|
|
316
|
+
"Use 'Refresh comprehension' to update."
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def _prompt_path(*, console: Console, root: Path) -> Path | None:
|
|
321
|
+
try:
|
|
322
|
+
raw = typer.prompt("Path", default="", show_default=False)
|
|
323
|
+
except (EOFError, KeyboardInterrupt):
|
|
324
|
+
console.print("")
|
|
325
|
+
return None
|
|
326
|
+
if not str(raw).strip():
|
|
327
|
+
return None
|
|
328
|
+
candidate = Path(str(raw)).expanduser()
|
|
329
|
+
if not candidate.is_absolute():
|
|
330
|
+
candidate = root / candidate
|
|
331
|
+
candidate = candidate.resolve()
|
|
332
|
+
try:
|
|
333
|
+
candidate.relative_to(root.resolve())
|
|
334
|
+
except ValueError:
|
|
335
|
+
console.print("[red]Asset path must stay inside the workspace root.[/red]")
|
|
336
|
+
return None
|
|
337
|
+
try:
|
|
338
|
+
raw_bytes = candidate.read_bytes()
|
|
339
|
+
except OSError as exc:
|
|
340
|
+
console.print(f"[red]Cannot read asset file: {exc}[/red]")
|
|
341
|
+
return None
|
|
342
|
+
try:
|
|
343
|
+
_classify_asset(candidate, raw_bytes)
|
|
344
|
+
except AssetError as exc:
|
|
345
|
+
console.print(f"[red]{exc}[/red]")
|
|
346
|
+
return None
|
|
347
|
+
return candidate
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def _prompt_limited_text(
|
|
351
|
+
console: Console,
|
|
352
|
+
label: str,
|
|
353
|
+
*,
|
|
354
|
+
required: bool,
|
|
355
|
+
max_chars: int,
|
|
356
|
+
default: str = "",
|
|
357
|
+
) -> str | None:
|
|
358
|
+
while True:
|
|
359
|
+
try:
|
|
360
|
+
value = str(typer.prompt(label, default=default, show_default=bool(default))).strip()
|
|
361
|
+
except (EOFError, KeyboardInterrupt):
|
|
362
|
+
console.print("")
|
|
363
|
+
return None
|
|
364
|
+
if not value and required:
|
|
365
|
+
console.print(f"[red]{label} is required.[/red]")
|
|
366
|
+
continue
|
|
367
|
+
if len(value) > max_chars:
|
|
368
|
+
console.print(f"[red]{label} must be {max_chars} characters or fewer.[/red]")
|
|
369
|
+
continue
|
|
370
|
+
return value
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
def _prompt_choice(
|
|
374
|
+
*,
|
|
375
|
+
console: Console,
|
|
376
|
+
title: str,
|
|
377
|
+
choices: list[tuple[str, str]],
|
|
378
|
+
) -> str | None:
|
|
379
|
+
error_message: str | None = None
|
|
380
|
+
while True:
|
|
381
|
+
console.print()
|
|
382
|
+
console.print(f"[bold]{title}[/bold]")
|
|
383
|
+
if error_message:
|
|
384
|
+
console.print(f"[red]{error_message}[/red]")
|
|
385
|
+
for index, (_value, label) in enumerate(choices, start=1):
|
|
386
|
+
console.print(f" {index}) {label}")
|
|
387
|
+
try:
|
|
388
|
+
raw = str(typer.prompt("Choice", default="", show_default=False)).strip()
|
|
389
|
+
except (EOFError, KeyboardInterrupt):
|
|
390
|
+
console.print("")
|
|
391
|
+
return None
|
|
392
|
+
if not raw:
|
|
393
|
+
return None
|
|
394
|
+
if raw.lower() in {"q", "quit", "cancel", "back"}:
|
|
395
|
+
return None
|
|
396
|
+
if raw.isdigit():
|
|
397
|
+
index = int(raw) - 1
|
|
398
|
+
if 0 <= index < len(choices):
|
|
399
|
+
return choices[index][0]
|
|
400
|
+
for value, label in choices:
|
|
401
|
+
if raw.lower() in {value.lower(), label.lower()}:
|
|
402
|
+
return value
|
|
403
|
+
error_message = "Unknown choice."
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def _format_size(size_bytes: int) -> str:
|
|
407
|
+
size = float(size_bytes)
|
|
408
|
+
for unit in ("B", "KB", "MB", "GB"):
|
|
409
|
+
if size < 1024 or unit == "GB":
|
|
410
|
+
return f"{size:.0f} {unit}" if unit == "B" else f"{size:.1f} {unit}"
|
|
411
|
+
size /= 1024
|
|
412
|
+
return f"{size_bytes} B"
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
_PUBLIC_FACADE_NAMES = {
|
|
7
|
+
"_PUBLIC_LOOP_COPY_VALUES",
|
|
8
|
+
"_copy_loop_globals_to_public",
|
|
9
|
+
"_apply_chat_effective_mode",
|
|
10
|
+
"_apply_chat_persona",
|
|
11
|
+
"_handle_chat_command",
|
|
12
|
+
"_handle_chat_command_impl",
|
|
13
|
+
"_handle_forge_chat_command",
|
|
14
|
+
"_handle_forge_chat_command_impl",
|
|
15
|
+
"_run_plan_mode_approval_loop",
|
|
16
|
+
"_run_plan_mode_approval_loop_impl",
|
|
17
|
+
"_sync_cli_globals",
|
|
18
|
+
"_sync_loop_globals_from_public",
|
|
19
|
+
"chat_impl",
|
|
20
|
+
"run_impl",
|
|
21
|
+
}
|
|
22
|
+
_PUBLIC_LOOP_COPY_VALUES: dict[str, Any] = {}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _loop_module() -> Any:
|
|
26
|
+
return importlib.import_module(f"{__name__}.loop")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _commands_module() -> Any:
|
|
30
|
+
return importlib.import_module(f"{__name__}.commands")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _copy_loop_globals_to_public(*, overwrite: bool = False) -> None:
|
|
34
|
+
module_globals = globals()
|
|
35
|
+
for name, value in _loop_module().__dict__.items():
|
|
36
|
+
if name.startswith("__") or name in _PUBLIC_FACADE_NAMES:
|
|
37
|
+
continue
|
|
38
|
+
if overwrite or name not in module_globals:
|
|
39
|
+
module_globals[name] = value
|
|
40
|
+
_PUBLIC_LOOP_COPY_VALUES[name] = value
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _public_global_overrides() -> dict[str, Any]:
|
|
44
|
+
loop = _loop_module()
|
|
45
|
+
loop_globals = loop.__dict__
|
|
46
|
+
overrides: dict[str, Any] = {}
|
|
47
|
+
for name, value in globals().items():
|
|
48
|
+
if name.startswith("__") or name in _PUBLIC_FACADE_NAMES:
|
|
49
|
+
continue
|
|
50
|
+
if name not in loop_globals or loop_globals[name] is value:
|
|
51
|
+
continue
|
|
52
|
+
if _PUBLIC_LOOP_COPY_VALUES.get(name) is value:
|
|
53
|
+
continue
|
|
54
|
+
if callable(value) and getattr(value, "__module__", None) == loop.__name__:
|
|
55
|
+
continue
|
|
56
|
+
if name in loop_globals:
|
|
57
|
+
overrides[name] = value
|
|
58
|
+
return overrides
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _sync_loop_globals_from_public() -> None:
|
|
62
|
+
loop_globals = _loop_module().__dict__
|
|
63
|
+
for name, value in globals().items():
|
|
64
|
+
if name.startswith("__") or name in _PUBLIC_FACADE_NAMES:
|
|
65
|
+
continue
|
|
66
|
+
if _PUBLIC_LOOP_COPY_VALUES.get(name) is value:
|
|
67
|
+
continue
|
|
68
|
+
loop_globals[name] = value
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _sync_cli_globals(cli_mod: Any) -> None:
|
|
72
|
+
public_overrides = _public_global_overrides()
|
|
73
|
+
loop = _loop_module()
|
|
74
|
+
loop._sync_cli_globals(cli_mod)
|
|
75
|
+
for name, value in public_overrides.items():
|
|
76
|
+
setattr(loop, name, value)
|
|
77
|
+
_copy_loop_globals_to_public(overwrite=True)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _handle_chat_command(*args: Any, **kwargs: Any) -> Any:
|
|
81
|
+
_commands_module()._sync_command_globals(globals())
|
|
82
|
+
return _commands_module()._handle_chat_command(*args, **kwargs)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _handle_forge_chat_command(*args: Any, **kwargs: Any) -> Any:
|
|
86
|
+
_commands_module()._sync_command_globals(globals())
|
|
87
|
+
return _commands_module()._handle_forge_chat_command(*args, **kwargs)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _run_plan_mode_approval_loop(*args: Any, **kwargs: Any) -> Any:
|
|
91
|
+
_sync_loop_globals_from_public()
|
|
92
|
+
return _loop_module()._run_plan_mode_approval_loop(*args, **kwargs)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _apply_chat_effective_mode(*args: Any, **kwargs: Any) -> Any:
|
|
96
|
+
_sync_loop_globals_from_public()
|
|
97
|
+
return _loop_module()._apply_chat_effective_mode(*args, **kwargs)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _apply_chat_persona(*args: Any, **kwargs: Any) -> Any:
|
|
101
|
+
_sync_loop_globals_from_public()
|
|
102
|
+
return _loop_module()._apply_chat_persona(*args, **kwargs)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _handle_chat_command_impl(cli_mod: Any, *args: Any, **kwargs: Any) -> Any:
|
|
106
|
+
_sync_cli_globals(cli_mod)
|
|
107
|
+
return _handle_chat_command(*args, **kwargs)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _handle_forge_chat_command_impl(cli_mod: Any, *args: Any, **kwargs: Any) -> Any:
|
|
111
|
+
_sync_cli_globals(cli_mod)
|
|
112
|
+
return _handle_forge_chat_command(*args, **kwargs)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _run_plan_mode_approval_loop_impl(cli_mod: Any, *args: Any, **kwargs: Any) -> Any:
|
|
116
|
+
_sync_cli_globals(cli_mod)
|
|
117
|
+
return _run_plan_mode_approval_loop(*args, **kwargs)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _print_chat_context_impl(cli_mod: Any, *args: Any, **kwargs: Any) -> Any:
|
|
121
|
+
_sync_cli_globals(cli_mod)
|
|
122
|
+
_sync_loop_globals_from_public()
|
|
123
|
+
return _loop_module()._print_chat_context(*args, **kwargs)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def chat_impl(cli_mod: Any, *args: Any, **kwargs: Any) -> Any:
|
|
127
|
+
_sync_cli_globals(cli_mod)
|
|
128
|
+
_sync_loop_globals_from_public()
|
|
129
|
+
return _loop_module().chat(*args, **kwargs)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def run_impl(cli_mod: Any, *args: Any, **kwargs: Any) -> Any:
|
|
133
|
+
_sync_cli_globals(cli_mod)
|
|
134
|
+
_sync_loop_globals_from_public()
|
|
135
|
+
return _loop_module().run(*args, **kwargs)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def __getattr__(name: str) -> Any:
|
|
139
|
+
_copy_loop_globals_to_public()
|
|
140
|
+
if name in globals():
|
|
141
|
+
return globals()[name]
|
|
142
|
+
value = getattr(_loop_module(), name)
|
|
143
|
+
globals()[name] = value
|
|
144
|
+
return value
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _exported_names() -> set[str]:
|
|
148
|
+
_copy_loop_globals_to_public()
|
|
149
|
+
return {name for name in globals() if not name.startswith("__") or name == "__version__"}
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def __dir__() -> list[str]:
|
|
153
|
+
return sorted(_exported_names())
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
__all__ = tuple(sorted(_exported_names()))
|