aria-code 0.167.0__py3-none-win_amd64.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.
- aria_bots/__init__.py +7 -0
- aria_bots/channels/README.md +97 -0
- aria_bots/channels/__init__.py +1 -0
- aria_bots/channels/approvals.py +263 -0
- aria_bots/channels/conversation.py +280 -0
- aria_bots/channels/digest.py +186 -0
- aria_bots/channels/registry.py +95 -0
- aria_bots/engine.py +144 -0
- aria_bots/feishu_bot.py +1385 -0
- aria_bots/logistics/__init__.py +1 -0
- aria_bots/logistics/carriers.py +253 -0
- aria_bots/logistics/freight.py +154 -0
- aria_bots/logistics/inventory.py +242 -0
- aria_bots/logistics/mcp_server.py +156 -0
- aria_bots/logistics/records.py +119 -0
- aria_bots/logistics/tenancy.py +152 -0
- aria_bots/market.py +91 -0
- aria_bots/relay_client.py +326 -0
- aria_bots/telegram_bot.py +299 -0
- aria_code/__init__.py +111 -0
- aria_code/_bin/aria-native.exe +0 -0
- aria_code/_bin/aria-runtime.exe +0 -0
- aria_code/_version.py +20 -0
- aria_code/account_memory.py +296 -0
- aria_code/account_session.py +166 -0
- aria_code/adk_apps/__init__.py +1 -0
- aria_code/adk_apps/aria_code_review/__init__.py +1 -0
- aria_code/adk_apps/aria_code_review/agent.py +32 -0
- aria_code/adk_apps/aria_research/__init__.py +1 -0
- aria_code/adk_apps/aria_research/agent.py +31 -0
- aria_code/agents/__init__.py +49 -0
- aria_code/agents/base.py +329 -0
- aria_code/agents/code_review.py +200 -0
- aria_code/agents/deep/__init__.py +37 -0
- aria_code/agents/deep/calibration_loop.py +144 -0
- aria_code/agents/deep/critic.py +125 -0
- aria_code/agents/deep/deepen.py +193 -0
- aria_code/agents/deep/models.py +149 -0
- aria_code/agents/deep/pipeline.py +164 -0
- aria_code/agents/deep/quant_fusion.py +192 -0
- aria_code/agents/deep/themes.py +95 -0
- aria_code/agents/deep/tiers.py +106 -0
- aria_code/agents/engineering/__init__.py +14 -0
- aria_code/agents/engineering/coder.py +222 -0
- aria_code/agents/engineering/tester.py +145 -0
- aria_code/agents/financial/__init__.py +21 -0
- aria_code/agents/financial/cashflow_burn.py +119 -0
- aria_code/agents/financial/catalyst.py +279 -0
- aria_code/agents/financial/corporate_finance.py +175 -0
- aria_code/agents/financial/debate.py +224 -0
- aria_code/agents/financial/earnings.py +315 -0
- aria_code/agents/financial/fundamental.py +178 -0
- aria_code/agents/financial/macro.py +111 -0
- aria_code/agents/financial/news.py +231 -0
- aria_code/agents/financial/risk.py +146 -0
- aria_code/agents/financial/sector.py +279 -0
- aria_code/agents/financial/strategist.py +121 -0
- aria_code/agents/financial/stripe_revenue.py +127 -0
- aria_code/agents/financial/synthesis.py +274 -0
- aria_code/agents/financial/technical.py +277 -0
- aria_code/agents/orchestrator.py +44 -0
- aria_code/agents/portfolio_agent.py +392 -0
- aria_code/agents/realty/__init__.py +62 -0
- aria_code/agents/realty/asset_diagnosis.py +152 -0
- aria_code/agents/realty/business_match.py +166 -0
- aria_code/agents/realty/cashflow_verify.py +209 -0
- aria_code/agents/realty/contract_rules.py +210 -0
- aria_code/agents/realty/energy_anomaly.py +189 -0
- aria_code/agents/realty/exit_settlement.py +208 -0
- aria_code/agents/realty/fulfillment_risk.py +206 -0
- aria_code/agents/realty/ops_optimize.py +160 -0
- aria_code/agents/realty/revenue_share.py +215 -0
- aria_code/agents/registry.py +168 -0
- aria_code/agents/signal_scheme.py +111 -0
- aria_code/agents/sports/__init__.py +0 -0
- aria_code/agents/sports/football_agent.py +197 -0
- aria_code/agents/supervisor.py +113 -0
- aria_code/agents/team.py +500 -0
- aria_code/agents/video/__init__.py +16 -0
- aria_code/agents/video/director.py +376 -0
- aria_code/agents/video/qa_agent.py +143 -0
- aria_code/agents/video/script_doctor.py +112 -0
- aria_code/agents/warehouse/__init__.py +25 -0
- aria_code/agents/warehouse/contracts.py +26 -0
- aria_code/agents/warehouse/dashboard.py +155 -0
- aria_code/agents/warehouse/fulfillment_leadtime.py +95 -0
- aria_code/agents/warehouse/inbound_exceptions.py +25 -0
- aria_code/agents/warehouse/inventory_health.py +24 -0
- aria_code/agents/warehouse/local_run.py +71 -0
- aria_code/agents/warehouse/local_snapshot.py +132 -0
- aria_code/agents/warehouse/logistics_cost.py +84 -0
- aria_code/agents/warehouse/logistics_sync.py +21 -0
- aria_code/agents/warehouse/navigation.schema.json +110 -0
- aria_code/agents/warehouse/task_agent.py +172 -0
- aria_code/agents/warehouse/workflow.py +31 -0
- aria_code/aliyun_data_client.py +4 -0
- aria_code/apps/README.md +12 -0
- aria_code/apps/__init__.py +2 -0
- aria_code/apps/channels/README.md +9 -0
- aria_code/apps/channels/__init__.py +17 -0
- aria_code/apps/channels/approvals.py +11 -0
- aria_code/apps/channels/conversation.py +11 -0
- aria_code/apps/channels/digest.py +11 -0
- aria_code/apps/channels/intake.py +92 -0
- aria_code/apps/channels/registry.py +11 -0
- aria_code/apps/channels/tradingview.py +94 -0
- aria_code/apps/cli/README.md +13 -0
- aria_code/apps/cli/__init__.py +2 -0
- aria_code/apps/cli/_optional.py +120 -0
- aria_code/apps/cli/app_server.py +656 -0
- aria_code/apps/cli/auto_update.py +125 -0
- aria_code/apps/cli/bootstrap.py +206 -0
- aria_code/apps/cli/broker_render.py +206 -0
- aria_code/apps/cli/chat_turn.py +1327 -0
- aria_code/apps/cli/cloud_models.py +231 -0
- aria_code/apps/cli/codegen_paths.py +29 -0
- aria_code/apps/cli/commands/__init__.py +34 -0
- aria_code/apps/cli/commands/_business_render.py +78 -0
- aria_code/apps/cli/commands/_ui.py +71 -0
- aria_code/apps/cli/commands/analysis_cmds.py +378 -0
- aria_code/apps/cli/commands/ashare_prediction_cmds.py +327 -0
- aria_code/apps/cli/commands/auth_cmds.py +215 -0
- aria_code/apps/cli/commands/backtest_cmds.py +2518 -0
- aria_code/apps/cli/commands/broker_cmds.py +1236 -0
- aria_code/apps/cli/commands/business_workflow_cmds.py +379 -0
- aria_code/apps/cli/commands/canvas_cmds.py +77 -0
- aria_code/apps/cli/commands/catalog.py +189 -0
- aria_code/apps/cli/commands/core_cmds.py +2748 -0
- aria_code/apps/cli/commands/data_cmds.py +521 -0
- aria_code/apps/cli/commands/diagnostic_cmds.py +285 -0
- aria_code/apps/cli/commands/diagnostic_ops_cmds.py +813 -0
- aria_code/apps/cli/commands/engineering_cmds.py +399 -0
- aria_code/apps/cli/commands/file_cmds.py +312 -0
- aria_code/apps/cli/commands/finance_service_cmds.py +60 -0
- aria_code/apps/cli/commands/fx_commodity_cmds.py +123 -0
- aria_code/apps/cli/commands/market.py +544 -0
- aria_code/apps/cli/commands/market_cmds.py +1419 -0
- aria_code/apps/cli/commands/market_context.py +432 -0
- aria_code/apps/cli/commands/market_render.py +7 -0
- aria_code/apps/cli/commands/model_cmds.py +2374 -0
- aria_code/apps/cli/commands/ops_cmds.py +721 -0
- aria_code/apps/cli/commands/orchestrator_cmds.py +181 -0
- aria_code/apps/cli/commands/pdf_export_cmds.py +125 -0
- aria_code/apps/cli/commands/portfolio_cmds.py +1316 -0
- aria_code/apps/cli/commands/report.py +476 -0
- aria_code/apps/cli/commands/scaffold_templates.py +617 -0
- aria_code/apps/cli/commands/session_cmds.py +236 -0
- aria_code/apps/cli/commands/session_ux_cmds.py +359 -0
- aria_code/apps/cli/commands/team.py +723 -0
- aria_code/apps/cli/commands/team_render.py +8 -0
- aria_code/apps/cli/commands/ui_cmds.py +401 -0
- aria_code/apps/cli/commands/warehouse_cmds.py +297 -0
- aria_code/apps/cli/commands/workflow_cmds.py +629 -0
- aria_code/apps/cli/commands/workspace_cmds.py +1543 -0
- aria_code/apps/cli/config_paths.py +73 -0
- aria_code/apps/cli/config_store.py +158 -0
- aria_code/apps/cli/constants.py +88 -0
- aria_code/apps/cli/context.py +34 -0
- aria_code/apps/cli/conversation_policy.py +53 -0
- aria_code/apps/cli/deterministic.py +200 -0
- aria_code/apps/cli/direct.py +48 -0
- aria_code/apps/cli/earnings_view.py +172 -0
- aria_code/apps/cli/endpoint_migration.py +64 -0
- aria_code/apps/cli/exec_events.py +255 -0
- aria_code/apps/cli/file_references.py +155 -0
- aria_code/apps/cli/finance_service_catalog.py +111 -0
- aria_code/apps/cli/football_reports.py +231 -0
- aria_code/apps/cli/github_app_auth.py +135 -0
- aria_code/apps/cli/google_login.py +239 -0
- aria_code/apps/cli/handlers/__init__.py +11 -0
- aria_code/apps/cli/handlers/broker_handlers.py +122 -0
- aria_code/apps/cli/handlers/chart_handlers.py +1314 -0
- aria_code/apps/cli/handlers/market_handlers.py +2570 -0
- aria_code/apps/cli/handlers/realty_handlers.py +114 -0
- aria_code/apps/cli/handlers/sports_handlers.py +22 -0
- aria_code/apps/cli/handlers/strategy_advice.py +82 -0
- aria_code/apps/cli/headless.py +352 -0
- aria_code/apps/cli/helpers.py +326 -0
- aria_code/apps/cli/hooks.py +180 -0
- aria_code/apps/cli/i18n.py +310 -0
- aria_code/apps/cli/intent.py +136 -0
- aria_code/apps/cli/intent_router.py +305 -0
- aria_code/apps/cli/intent_shadow.py +72 -0
- aria_code/apps/cli/intent_signals.py +347 -0
- aria_code/apps/cli/lifecycle_hooks.py +48 -0
- aria_code/apps/cli/local_tool_schemas.py +550 -0
- aria_code/apps/cli/main.py +39 -0
- aria_code/apps/cli/market_hours.py +100 -0
- aria_code/apps/cli/market_metadata.py +135 -0
- aria_code/apps/cli/market_universe.py +487 -0
- aria_code/apps/cli/message_processing.py +310 -0
- aria_code/apps/cli/mixin_binding.py +32 -0
- aria_code/apps/cli/model_catalog.py +652 -0
- aria_code/apps/cli/model_probe.py +169 -0
- aria_code/apps/cli/model_retirement.py +65 -0
- aria_code/apps/cli/native_branding.py +12 -0
- aria_code/apps/cli/native_bridge.py +118 -0
- aria_code/apps/cli/native_entry.py +58 -0
- aria_code/apps/cli/pdf_report.py +977 -0
- aria_code/apps/cli/plan_mode.py +139 -0
- aria_code/apps/cli/plotly_html.py +15 -0
- aria_code/apps/cli/prediction_feedback.py +202 -0
- aria_code/apps/cli/preflight.py +502 -0
- aria_code/apps/cli/project_aria.py +60 -0
- aria_code/apps/cli/prompt_assembly.py +78 -0
- aria_code/apps/cli/prompts/__init__.py +0 -0
- aria_code/apps/cli/prompts/coding.py +71 -0
- aria_code/apps/cli/prompts/select.py +193 -0
- aria_code/apps/cli/prompts/system_prompts.py +562 -0
- aria_code/apps/cli/prompts/ui.py +436 -0
- aria_code/apps/cli/provider_endpoints.py +237 -0
- aria_code/apps/cli/provider_keys.py +73 -0
- aria_code/apps/cli/providers/__init__.py +1 -0
- aria_code/apps/cli/providers/base.py +775 -0
- aria_code/apps/cli/providers/chat_routing.py +139 -0
- aria_code/apps/cli/providers/collaboration.py +98 -0
- aria_code/apps/cli/providers/llm/__init__.py +1 -0
- aria_code/apps/cli/providers/llm/offline_responses.py +68 -0
- aria_code/apps/cli/providers/llm/ollama_stream.py +1574 -0
- aria_code/apps/cli/providers/llm/response_cache.py +60 -0
- aria_code/apps/cli/providers/llm/sse_stream.py +298 -0
- aria_code/apps/cli/providers/runtime_bridge.py +586 -0
- aria_code/apps/cli/providers/vertexai_stream.py +592 -0
- aria_code/apps/cli/release_download.py +159 -0
- aria_code/apps/cli/review_runner.py +111 -0
- aria_code/apps/cli/runtime_consumer.py +769 -0
- aria_code/apps/cli/sandbox.py +32 -0
- aria_code/apps/cli/session_export.py +120 -0
- aria_code/apps/cli/session_jsonl.py +208 -0
- aria_code/apps/cli/session_refresh.py +123 -0
- aria_code/apps/cli/session_store.py +125 -0
- aria_code/apps/cli/skills_catalog.py +273 -0
- aria_code/apps/cli/task_isolation.py +211 -0
- aria_code/apps/cli/terminal_chrome.py +412 -0
- aria_code/apps/cli/todo_tracker.py +190 -0
- aria_code/apps/cli/tool_executor.py +932 -0
- aria_code/apps/cli/tool_registry.py +34 -0
- aria_code/apps/cli/tool_scope.py +113 -0
- aria_code/apps/cli/tools/__init__.py +40 -0
- aria_code/apps/cli/tools/context.py +46 -0
- aria_code/apps/cli/tools/file_tools.py +181 -0
- aria_code/apps/cli/tools/market_tools.py +626 -0
- aria_code/apps/cli/tools/notebook_tools.py +111 -0
- aria_code/apps/cli/tools/system_tools.py +656 -0
- aria_code/apps/cli/tools/write_tools.py +961 -0
- aria_code/apps/cli/tradingview_bridge.py +529 -0
- aria_code/apps/cli/transactions.py +269 -0
- aria_code/apps/cli/turn_planning.py +137 -0
- aria_code/apps/cli/update_check.py +257 -0
- aria_code/apps/cli/updater.py +373 -0
- aria_code/apps/cli/utils/__init__.py +0 -0
- aria_code/apps/cli/utils/market_detect.py +1663 -0
- aria_code/apps/cli/web_login.py +136 -0
- aria_code/apps/cli/workflow_runner.py +127 -0
- aria_code/apps/cli/workspace_route.py +121 -0
- aria_code/apps/daemon/README.md +14 -0
- aria_code/apps/vscode/README.md +115 -0
- aria_code/apps/vscode/package.json +70 -0
- aria_code/aria_cli.py +5244 -0
- aria_code/aria_daemon.py +1372 -0
- aria_code/aria_feishu_bot.py +16 -0
- aria_code/aria_mcp_server.py +61 -0
- aria_code/aria_relay_client.py +4 -0
- aria_code/aria_telegram_bot.py +11 -0
- aria_code/ariarc.py +385 -0
- aria_code/artifacts.py +581 -0
- aria_code/backtest_engine.py +4 -0
- aria_code/backtest_report.py +4 -0
- aria_code/brokers/__init__.py +78 -0
- aria_code/brokers/automation.py +193 -0
- aria_code/brokers/base.py +231 -0
- aria_code/brokers/capabilities.py +264 -0
- aria_code/brokers/cn/__init__.py +10 -0
- aria_code/brokers/cn/easytrader_broker.py +193 -0
- aria_code/brokers/cn/futu_broker.py +194 -0
- aria_code/brokers/cn/longbridge_broker.py +190 -0
- aria_code/brokers/cn/tiger_broker.py +196 -0
- aria_code/brokers/cn/xtquant_broker.py +225 -0
- aria_code/brokers/config.py +414 -0
- aria_code/brokers/intl/__init__.py +5 -0
- aria_code/brokers/intl/alpaca_broker.py +183 -0
- aria_code/brokers/intl/ibkr_broker.py +215 -0
- aria_code/brokers/intl/trading212_broker.py +183 -0
- aria_code/brokers/intl/webull_broker.py +156 -0
- aria_code/brokers/paper_broker.py +266 -0
- aria_code/brokers/planning.py +296 -0
- aria_code/brokers/registry.py +213 -0
- aria_code/brokers/trading.py +267 -0
- aria_code/canva_client.py +4 -0
- aria_code/change_store.py +127 -0
- aria_code/clients/__init__.py +0 -0
- aria_code/clients/aliyun_data_client.py +660 -0
- aria_code/clients/aria_relay_client.py +16 -0
- aria_code/clients/canva_client.py +284 -0
- aria_code/clients/figma_client.py +100 -0
- aria_code/clients/football_data_client.py +1671 -0
- aria_code/clients/kling_video_client.py +182 -0
- aria_code/clients/market_data_client.py +1985 -0
- aria_code/clients/openai_image_client.py +242 -0
- aria_code/clients/runway_video_client.py +157 -0
- aria_code/clients/warehouse_erp_client.py +105 -0
- aria_code/cloud_memory.py +190 -0
- aria_code/command_safety.py +19 -0
- aria_code/computer_use_server.py +276 -0
- aria_code/computer_use_tools.py +4 -0
- aria_code/dashboard_generator.py +579 -0
- aria_code/data_analysis_tools.py +4 -0
- aria_code/data_cleaner.py +483 -0
- aria_code/data_service.py +513 -0
- aria_code/datasources/__init__.py +23 -0
- aria_code/datasources/base.py +166 -0
- aria_code/datasources/router.py +253 -0
- aria_code/datasources/sec_statements.py +217 -0
- aria_code/datasources/sources/__init__.py +15 -0
- aria_code/datasources/sources/akshare_source.py +269 -0
- aria_code/datasources/sources/alpha_vantage_source.py +203 -0
- aria_code/datasources/sources/edgar_source.py +219 -0
- aria_code/datasources/sources/finnhub_source.py +198 -0
- aria_code/datasources/sources/fred_source.py +223 -0
- aria_code/datasources/sources/tushare_source.py +143 -0
- aria_code/datasources/sources/web_scraper_source.py +278 -0
- aria_code/datasources/sources/world_bank_source.py +206 -0
- aria_code/datasources/sources/yfinance_source.py +152 -0
- aria_code/doctor.py +860 -0
- aria_code/domain/__init__.py +0 -0
- aria_code/domain/_finance_core/__init__.py +5 -0
- aria_code/domain/_finance_core/backtest_engine.py +325 -0
- aria_code/domain/_finance_core/performance_stats.py +101 -0
- aria_code/domain/backtest_engine.py +75 -0
- aria_code/domain/backtest_report.py +488 -0
- aria_code/domain/finance_formulas.py +389 -0
- aria_code/domain/performance_stats.py +6 -0
- aria_code/domain/portfolio_ledger.py +307 -0
- aria_code/domain/strategy_vault.py +421 -0
- aria_code/evals/__init__.py +37 -0
- aria_code/evals/behavior.py +113 -0
- aria_code/evals/gap.py +93 -0
- aria_code/evals/harness.py +949 -0
- aria_code/evals/review_probe.py +132 -0
- aria_code/evals/runner.py +425 -0
- aria_code/evals/scorecard.py +322 -0
- aria_code/evals/summary.py +125 -0
- aria_code/external_agent_runner.py +115 -0
- aria_code/figma_client.py +4 -0
- aria_code/file_analysis_tools.py +4 -0
- aria_code/finance_formulas.py +4 -0
- aria_code/football_data_client.py +4 -0
- aria_code/image_gen_tools.py +4 -0
- aria_code/intent_classifier.py +459 -0
- aria_code/kling_video_client.py +4 -0
- aria_code/licensing.py +151 -0
- aria_code/local_finance_tools.py +4 -0
- aria_code/local_image_provider.py +4 -0
- aria_code/local_llm_provider.py +4 -0
- aria_code/macro_tools.py +4 -0
- aria_code/markdown_pdf.py +289 -0
- aria_code/market_data_client.py +4 -0
- aria_code/mcp_client.py +744 -0
- aria_code/memory_manager.py +273 -0
- aria_code/model_capability.py +512 -0
- aria_code/notification_tools.py +4 -0
- aria_code/openai_image_client.py +4 -0
- aria_code/packages/__init__.py +26 -0
- aria_code/packages/adk_bridge/__init__.py +11 -0
- aria_code/packages/adk_bridge/code_review_tools.py +49 -0
- aria_code/packages/adk_bridge/market_tools.py +125 -0
- aria_code/packages/aria_agents/__init__.py +5 -0
- aria_code/packages/aria_agents/manifest.py +78 -0
- aria_code/packages/aria_core/__init__.py +34 -0
- aria_code/packages/aria_core/architecture.py +269 -0
- aria_code/packages/aria_core/export.py +147 -0
- aria_code/packages/aria_core/manifest.py +65 -0
- aria_code/packages/aria_core/paths.py +57 -0
- aria_code/packages/aria_core/secure_file.py +68 -0
- aria_code/packages/aria_infra/__init__.py +15 -0
- aria_code/packages/aria_infra/arthera.py +58 -0
- aria_code/packages/aria_infra/doctor.py +246 -0
- aria_code/packages/aria_infra/product.py +40 -0
- aria_code/packages/aria_mcp/__init__.py +25 -0
- aria_code/packages/aria_mcp/bridge.py +232 -0
- aria_code/packages/aria_mcp/circuit.py +82 -0
- aria_code/packages/aria_mcp/config.py +162 -0
- aria_code/packages/aria_mcp/installer.py +95 -0
- aria_code/packages/aria_mcp/server.py +1705 -0
- aria_code/packages/aria_mcp/tools.py +81 -0
- aria_code/packages/aria_sdk/__init__.py +19 -0
- aria_code/packages/aria_sdk/client.py +393 -0
- aria_code/packages/aria_sdk/providers.py +70 -0
- aria_code/packages/aria_sdk/streaming.py +75 -0
- aria_code/packages/aria_sdk/types.py +86 -0
- aria_code/packages/aria_services/__init__.py +92 -0
- aria_code/packages/aria_services/cache.py +60 -0
- aria_code/packages/aria_services/context.py +356 -0
- aria_code/packages/aria_services/context_checkpoints.py +157 -0
- aria_code/packages/aria_services/data.py +11 -0
- aria_code/packages/aria_services/provider_health.py +304 -0
- aria_code/packages/aria_services/references.py +247 -0
- aria_code/packages/aria_services/registry.py +249 -0
- aria_code/packages/aria_services/research_protocol.py +137 -0
- aria_code/packages/aria_services/research_quality.py +186 -0
- aria_code/packages/aria_services/settings.py +160 -0
- aria_code/packages/aria_services/usage.py +151 -0
- aria_code/packages/aria_skills/__init__.py +46 -0
- aria_code/packages/aria_skills/catalog.py +149 -0
- aria_code/packages/aria_skills/loader.py +455 -0
- aria_code/packages/aria_skills/registry.py +84 -0
- aria_code/packages/aria_tools/__init__.py +5 -0
- aria_code/packages/aria_tools/financial/__init__.py +5 -0
- aria_code/packages/aria_tools/financial/_paths.py +92 -0
- aria_code/packages/aria_tools/registry.py +129 -0
- aria_code/packages/quant_engine/__init__.py +33 -0
- aria_code/packages/quant_engine/_namespace.py +24 -0
- aria_code/packages/quant_engine/backtest/__init__.py +10 -0
- aria_code/packages/quant_engine/backtest/core.py +53 -0
- aria_code/packages/quant_engine/backtest/engine.py +102 -0
- aria_code/packages/quant_engine/portfolio/__init__.py +9 -0
- aria_code/packages/quant_engine/portfolio/optimizer.py +85 -0
- aria_code/packages/quant_engine/sports/__init__.py +76 -0
- aria_code/packages/quant_engine/sports/calibrator.py +354 -0
- aria_code/packages/quant_engine/sports/dixon_coles.py +234 -0
- aria_code/packages/quant_engine/sports/elo.py +300 -0
- aria_code/packages/quant_engine/sports/form.py +188 -0
- aria_code/packages/quant_engine/sports/h2h.py +195 -0
- aria_code/packages/quant_engine/sports/predictor.py +312 -0
- aria_code/packages/quant_engine/sports/tracker.py +665 -0
- aria_code/packages/quant_engine/stochastic/__init__.py +31 -0
- aria_code/packages/quant_engine/stochastic/gbm_enhanced.py +195 -0
- aria_code/packages/quant_engine/stochastic/ito_calculus.py +477 -0
- aria_code/packages/quant_engine/stochastic/kelly_criterion.py +181 -0
- aria_code/packages/quant_engine/stochastic/monte_carlo_advanced.py +95 -0
- aria_code/packages/quant_engine/stochastic/options_pricing.py +576 -0
- aria_code/packages/quant_engine/stochastic/stochastic_processes.py +90 -0
- aria_code/packs/__init__.py +85 -0
- aria_code/packs/base.py +168 -0
- aria_code/packs/finance/__init__.py +250 -0
- aria_code/packs/healthcare/__init__.py +40 -0
- aria_code/packs/logistics/__init__.py +171 -0
- aria_code/packs/payments/__init__.py +139 -0
- aria_code/packs/realty/__init__.py +190 -0
- aria_code/packs/registry.py +202 -0
- aria_code/packs/rules.py +90 -0
- aria_code/plan_utils.py +194 -0
- aria_code/plugin_loader.py +328 -0
- aria_code/portfolio_ledger.py +4 -0
- aria_code/preview_server.py +449 -0
- aria_code/privacy/__init__.py +5 -0
- aria_code/privacy/feedback.py +123 -0
- aria_code/project_review.py +278 -0
- aria_code/project_review_api.py +235 -0
- aria_code/project_review_server.py +18 -0
- aria_code/project_tools.py +4 -0
- aria_code/providers/__init__.py +30 -0
- aria_code/providers/google_video_provider.py +256 -0
- aria_code/providers/llm/__init__.py +19 -0
- aria_code/providers/llm/anthropic.py +184 -0
- aria_code/providers/llm/arthera_gateway.py +90 -0
- aria_code/providers/llm/autoconfig.py +213 -0
- aria_code/providers/llm/base.py +139 -0
- aria_code/providers/llm/custom.py +158 -0
- aria_code/providers/llm/ollama.py +137 -0
- aria_code/providers/llm/openai_compat.py +350 -0
- aria_code/providers/llm/registry.py +457 -0
- aria_code/providers/local_image_provider.py +202 -0
- aria_code/providers/local_llm_provider.py +549 -0
- aria_code/providers/ollama_models.py +79 -0
- aria_code/providers/openai_params.py +32 -0
- aria_code/providers/tool_messages.py +100 -0
- aria_code/realty_data_tools.py +4 -0
- aria_code/report_exporters.py +150 -0
- aria_code/report_generator.py +1764 -0
- aria_code/review_service.py +497 -0
- aria_code/runtime/__init__.py +176 -0
- aria_code/runtime/acceptance.py +632 -0
- aria_code/runtime/agent_loop.py +1851 -0
- aria_code/runtime/agent_profiles.py +75 -0
- aria_code/runtime/approval.py +71 -0
- aria_code/runtime/baseline.py +219 -0
- aria_code/runtime/budget.py +232 -0
- aria_code/runtime/checkpoints.py +481 -0
- aria_code/runtime/consult.py +65 -0
- aria_code/runtime/contract.py +282 -0
- aria_code/runtime/delivery.py +432 -0
- aria_code/runtime/events.py +113 -0
- aria_code/runtime/gateway.py +167 -0
- aria_code/runtime/lsp.py +484 -0
- aria_code/runtime/native_index.py +153 -0
- aria_code/runtime/orchestrator.py +55 -0
- aria_code/runtime/processes.py +343 -0
- aria_code/runtime/project_graph.py +614 -0
- aria_code/runtime/repo_map.py +712 -0
- aria_code/runtime/research_bundle.py +105 -0
- aria_code/runtime/review.py +269 -0
- aria_code/runtime/run_state.py +127 -0
- aria_code/runtime/run_store.py +522 -0
- aria_code/runtime/scoped_runs.py +113 -0
- aria_code/runtime/self_healing.py +422 -0
- aria_code/runtime/semantic_diff.py +171 -0
- aria_code/runtime/subagent.py +721 -0
- aria_code/runtime/symbol_edit.py +117 -0
- aria_code/runtime/task_brief.py +46 -0
- aria_code/runtime/task_context.py +145 -0
- aria_code/runtime/task_ledger.py +108 -0
- aria_code/runtime/task_orchestrator.py +90 -0
- aria_code/runtime/task_outcome.py +33 -0
- aria_code/runtime/task_verification.py +266 -0
- aria_code/runtime/task_worktree.py +448 -0
- aria_code/runtime/tool_executor.py +329 -0
- aria_code/runtime/tool_policy.py +107 -0
- aria_code/runtime/transactions.py +216 -0
- aria_code/runtime/windows_job.py +115 -0
- aria_code/runtime/workflows.py +222 -0
- aria_code/runtime/worktrees.py +215 -0
- aria_code/runway_video_client.py +4 -0
- aria_code/safety/__init__.py +27 -0
- aria_code/safety/client_isolation.py +178 -0
- aria_code/safety/permissions.py +339 -0
- aria_code/safety/risk.py +699 -0
- aria_code/safety/sandbox.py +148 -0
- aria_code/safety/service.py +102 -0
- aria_code/service_endpoints.py +14 -0
- aria_code/setup_wizard.py +684 -0
- aria_code/spreadsheet_tools.py +4 -0
- aria_code/strategy_vault.py +4 -0
- aria_code/tools/__init__.py +0 -0
- aria_code/tools/artifact_tools.py +252 -0
- aria_code/tools/broker_tools.py +92 -0
- aria_code/tools/build_quant_engine.py +97 -0
- aria_code/tools/code_audit_tools.py +192 -0
- aria_code/tools/computer_use_tools.py +509 -0
- aria_code/tools/data_analysis_tools.py +831 -0
- aria_code/tools/enterprise_finance_tools.py +202 -0
- aria_code/tools/extended_tools.py +240 -0
- aria_code/tools/file_analysis_tools.py +880 -0
- aria_code/tools/image_gen_tools.py +114 -0
- aria_code/tools/local_finance_tools.py +3488 -0
- aria_code/tools/logistics_carriers.py +11 -0
- aria_code/tools/logistics_inventory.py +11 -0
- aria_code/tools/logistics_io.py +11 -0
- aria_code/tools/logistics_tenancy.py +11 -0
- aria_code/tools/logistics_tools.py +11 -0
- aria_code/tools/macro_tools.py +412 -0
- aria_code/tools/notification_tools.py +249 -0
- aria_code/tools/project_tools.py +525 -0
- aria_code/tools/realty_data_tools.py +662 -0
- aria_code/tools/spreadsheet_tools.py +399 -0
- aria_code/tools/stripe_tools.py +115 -0
- aria_code/tools/video_tools.py +500 -0
- aria_code/training/__init__.py +1 -0
- aria_code/training/compare.py +117 -0
- aria_code/training/prelude_commands.py +111 -0
- aria_code/training/prelude_eval.py +390 -0
- aria_code/training/prelude_real.py +183 -0
- aria_code/training/prelude_train.py +248 -0
- aria_code/training/sft_dataset.py +230 -0
- aria_code/training/trajectory_dataset.py +263 -0
- aria_code/ui/__init__.py +105 -0
- aria_code/ui/banner.py +404 -0
- aria_code/ui/completer.py +571 -0
- aria_code/ui/console.py +285 -0
- aria_code/ui/input_box.py +505 -0
- aria_code/ui/mentions.py +206 -0
- aria_code/ui/picker.py +248 -0
- aria_code/ui/render/__init__.py +11 -0
- aria_code/ui/render/actions.py +297 -0
- aria_code/ui/render/finance.py +1732 -0
- aria_code/ui/render/market.py +253 -0
- aria_code/ui/render/output.py +954 -0
- aria_code/ui/render/responsive.py +75 -0
- aria_code/ui/render/team.py +367 -0
- aria_code/ui/robot.py +239 -0
- aria_code/ui/startup_dashboard.py +110 -0
- aria_code/video_analysis.py +147 -0
- aria_code/video_editor.py +518 -0
- aria_code/video_workflow/__init__.py +8 -0
- aria_code/video_workflow/__main__.py +61 -0
- aria_code/video_workflow/engines/__init__.py +18 -0
- aria_code/video_workflow/engines/base.py +69 -0
- aria_code/video_workflow/engines/custom_model.py +204 -0
- aria_code/video_workflow/engines/google_veo.py +94 -0
- aria_code/video_workflow/engines/local_engine.py +71 -0
- aria_code/video_workflow/engines/registry.py +98 -0
- aria_code/video_workflow/google_models.py +278 -0
- aria_code/video_workflow/music/__init__.py +5 -0
- aria_code/video_workflow/music/foley_service.py +132 -0
- aria_code/video_workflow/music/service.py +212 -0
- aria_code/video_workflow/pipeline.py +620 -0
- aria_code/video_workflow/plan.py +202 -0
- aria_code/video_workflow/session.py +297 -0
- aria_code/workspace/__init__.py +6 -0
- aria_code/workspace/files.py +219 -0
- aria_code/workspace/verify.py +167 -0
- aria_code/workspace_changes.py +199 -0
- aria_code/workspace_service.py +196 -0
- aria_code/workspace_tools.py +150 -0
- aria_code-0.167.0.dist-info/METADATA +330 -0
- aria_code-0.167.0.dist-info/RECORD +601 -0
- aria_code-0.167.0.dist-info/WHEEL +5 -0
- aria_code-0.167.0.dist-info/entry_points.txt +5 -0
- aria_code-0.167.0.dist-info/licenses/LICENSE +201 -0
- aria_code-0.167.0.dist-info/licenses/NOTICE +49 -0
- aria_code-0.167.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
"""Project graph — what a change reaches before it is made.
|
|
2
|
+
|
|
3
|
+
``repo_map`` answers "where is X defined and who mentions it" for one name at
|
|
4
|
+
a time. Deciding whether an edit is safe needs the other direction, walked:
|
|
5
|
+
change ``session.py`` and which files import it, which import those, which
|
|
6
|
+
tests exercise any of them, which deployable service ships them. That is what
|
|
7
|
+
this builds, from four kinds of node and the edges between them:
|
|
8
|
+
|
|
9
|
+
* files, and the symbols they define (``repo_map``'s scan);
|
|
10
|
+
* ``imports`` between files — Python resolved with ``ast``, JS/TS relative
|
|
11
|
+
specifiers resolved against the tree; other languages fall back to
|
|
12
|
+
references;
|
|
13
|
+
* ``references`` — a file naming a symbol another file defines, using the
|
|
14
|
+
same filters that keep ``repo_map``'s ranking honest (no names under four
|
|
15
|
+
characters, none defined in more than a handful of files);
|
|
16
|
+
* tests (files under ``tests/``, ``test_*``, ``*.test.ts`` …), which cover
|
|
17
|
+
what they import or reference;
|
|
18
|
+
|
|
19
|
+
Impact follows imports up to three hops but not through a package
|
|
20
|
+
``__init__`` or a file importing more than twenty others: past those,
|
|
21
|
+
everything reaches everything.
|
|
22
|
+
* services — a ``docker-compose`` service's build context, or a directory
|
|
23
|
+
with its own ``pyproject.toml`` / ``package.json`` / ``go.mod`` /
|
|
24
|
+
``Cargo.toml`` — which contain the files below them.
|
|
25
|
+
|
|
26
|
+
The graph is saved per repository under ``<aria home>/graphs``. A session
|
|
27
|
+
that finds every file at the size and mtime it was saved with reuses it after
|
|
28
|
+
a stat per file; otherwise it is rebuilt, re-parsing only changed files'
|
|
29
|
+
imports.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import ast
|
|
35
|
+
import hashlib
|
|
36
|
+
import json
|
|
37
|
+
import os
|
|
38
|
+
import re
|
|
39
|
+
import time
|
|
40
|
+
from collections import deque
|
|
41
|
+
from dataclasses import dataclass, field
|
|
42
|
+
from pathlib import Path
|
|
43
|
+
from typing import Iterable, Optional, Sequence
|
|
44
|
+
|
|
45
|
+
from . import native_index
|
|
46
|
+
from .repo_map import RepoMap
|
|
47
|
+
|
|
48
|
+
GRAPH_VERSION = 1
|
|
49
|
+
|
|
50
|
+
_TEST_PATH = re.compile(r"(^|/)(tests?|__tests__|spec)/|(^|/)test_[^/]+$|_test\.[a-z]+$|\.(test|spec)\.[a-z]+$")
|
|
51
|
+
_JS_IMPORT = re.compile(
|
|
52
|
+
r"""(?:\bimport\s[^'"]*?\bfrom\s*|\bimport\s*\(\s*|\brequire\s*\(\s*|\bexport\s[^'"]*?\bfrom\s*|\bimport\s+)"""
|
|
53
|
+
r"""['"](\.{1,2}/[^'"]+)['"]"""
|
|
54
|
+
)
|
|
55
|
+
_JS_EXTENSIONS = (".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".vue", ".svelte")
|
|
56
|
+
_PACKAGE_MARKERS = ("pyproject.toml", "setup.py", "package.json", "go.mod", "Cargo.toml")
|
|
57
|
+
_COMPOSE_FILES = ("docker-compose.yml", "docker-compose.yaml", "compose.yml", "compose.yaml")
|
|
58
|
+
|
|
59
|
+
# Same thresholds as repo_map's ranking: a short or widely defined name says
|
|
60
|
+
# nothing about which file a mention depends on.
|
|
61
|
+
_MIN_NAME = 4
|
|
62
|
+
_MAX_DEFINING_FILES = 3
|
|
63
|
+
_TRANSITIVE_DEPTH = 3
|
|
64
|
+
# A file importing this many others is an aggregator (a CLI entry point, an
|
|
65
|
+
# app factory). It is reached, but the walk does not continue through it, nor
|
|
66
|
+
# through a package ``__init__``: past either, everything imports everything
|
|
67
|
+
# and "reached through imports" would list the whole repository.
|
|
68
|
+
_HUB_FAN_OUT = 20
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def is_test_path(path: str) -> bool:
|
|
72
|
+
return bool(_TEST_PATH.search(path.replace("\\", "/")))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@dataclass
|
|
76
|
+
class Impact:
|
|
77
|
+
targets: list[str]
|
|
78
|
+
unresolved: list[str] = field(default_factory=list)
|
|
79
|
+
direct: list[str] = field(default_factory=list) # import or reference a target
|
|
80
|
+
indirect: list[str] = field(default_factory=list) # import those, up to three hops
|
|
81
|
+
tests: list[str] = field(default_factory=list)
|
|
82
|
+
services: list[str] = field(default_factory=list)
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def breadth(self) -> str:
|
|
86
|
+
reach = len(self.direct) + len(self.indirect)
|
|
87
|
+
if reach == 0:
|
|
88
|
+
return "isolated"
|
|
89
|
+
if reach <= 5:
|
|
90
|
+
return "narrow"
|
|
91
|
+
if reach <= 25:
|
|
92
|
+
return "moderate"
|
|
93
|
+
return "wide"
|
|
94
|
+
|
|
95
|
+
def as_dict(self, *, limit: int = 40) -> dict:
|
|
96
|
+
return {
|
|
97
|
+
"targets": self.targets,
|
|
98
|
+
"unresolved": self.unresolved,
|
|
99
|
+
"breadth": self.breadth,
|
|
100
|
+
"direct_dependents": self.direct[:limit],
|
|
101
|
+
"indirect_dependents": self.indirect[:limit],
|
|
102
|
+
"tests": self.tests[:limit],
|
|
103
|
+
"services": self.services,
|
|
104
|
+
"counts": {"direct": len(self.direct), "indirect": len(self.indirect),
|
|
105
|
+
"tests": len(self.tests)},
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
def render(self, *, limit: int = 12) -> str:
|
|
109
|
+
def block(title: str, items: Sequence[str]) -> list[str]:
|
|
110
|
+
if not items:
|
|
111
|
+
return []
|
|
112
|
+
shown = [f" {item}" for item in items[:limit]]
|
|
113
|
+
if len(items) > limit:
|
|
114
|
+
shown.append(f" … and {len(items) - limit} more")
|
|
115
|
+
return [f" {title} ({len(items)})", *shown]
|
|
116
|
+
|
|
117
|
+
lines = [f"Impact of {', '.join(self.targets) or '(nothing)'}: {self.breadth}"]
|
|
118
|
+
if self.unresolved:
|
|
119
|
+
lines.append(f" not found: {', '.join(self.unresolved)}")
|
|
120
|
+
lines += block("Used directly by", self.direct)
|
|
121
|
+
lines += block("Reached through imports", self.indirect)
|
|
122
|
+
lines += block("Tests", self.tests)
|
|
123
|
+
if self.services:
|
|
124
|
+
lines.append(f" Services {', '.join(self.services)}")
|
|
125
|
+
if not (self.direct or self.indirect or self.tests):
|
|
126
|
+
lines.append(" Nothing else in the repository depends on it.")
|
|
127
|
+
return "\n".join(lines)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class ProjectGraph:
|
|
131
|
+
def __init__(self, root: Path | str) -> None:
|
|
132
|
+
self.root = Path(root).expanduser().resolve()
|
|
133
|
+
self.files: dict[str, dict] = {} # path -> {mtime, size, language, imports, symbols}
|
|
134
|
+
self.services: dict[str, str] = {} # name -> directory ("" for the root)
|
|
135
|
+
self.refs: dict[str, list[str]] = {} # symbol name -> files mentioning it
|
|
136
|
+
self.defs: dict[str, list[str]] = {} # symbol name -> files defining it
|
|
137
|
+
self.built_at = 0.0
|
|
138
|
+
|
|
139
|
+
# ── building ───────────────────────────────────────────────────────────
|
|
140
|
+
|
|
141
|
+
def build(self, previous: Optional["ProjectGraph"] = None) -> "ProjectGraph":
|
|
142
|
+
repo = RepoMap(self.root).build()
|
|
143
|
+
prior = previous.files if previous is not None else {}
|
|
144
|
+
modules = _module_index(repo.files)
|
|
145
|
+
stale = [path for path, entry in repo.files.items()
|
|
146
|
+
if not ((cached := prior.get(path))
|
|
147
|
+
and cached.get("mtime") == entry.mtime and cached.get("size") == entry.size)]
|
|
148
|
+
native = native_index.resolve_imports(
|
|
149
|
+
self.root, [(path, entry.language) for path, entry in repo.files.items()], stale)
|
|
150
|
+
resolved, python_side = native if native is not None else ({}, stale)
|
|
151
|
+
for path in python_side:
|
|
152
|
+
entry = repo.files[path]
|
|
153
|
+
resolved[path] = _imports(self.root, path, entry.language, modules, repo.files)
|
|
154
|
+
files: dict[str, dict] = {}
|
|
155
|
+
for path, entry in repo.files.items():
|
|
156
|
+
if path in resolved:
|
|
157
|
+
imports = resolved[path]
|
|
158
|
+
else:
|
|
159
|
+
imports = prior[path].get("imports") or []
|
|
160
|
+
files[path] = {
|
|
161
|
+
"mtime": entry.mtime, "size": entry.size, "language": entry.language,
|
|
162
|
+
"imports": sorted(set(imports) - {path}),
|
|
163
|
+
"symbols": [[s.name, s.kind, s.line, s.parent] for s in entry.symbols],
|
|
164
|
+
}
|
|
165
|
+
self.files = files
|
|
166
|
+
self.defs = {name: sorted({path for path, _symbol in places}) for name, places in repo.defs.items()}
|
|
167
|
+
self.refs = {name: sorted(paths) for name, paths in repo.refs.items()
|
|
168
|
+
if len(name) >= _MIN_NAME and len(self.defs.get(name, ())) <= _MAX_DEFINING_FILES}
|
|
169
|
+
self.services = _services(self.root, files)
|
|
170
|
+
self.built_at = time.time()
|
|
171
|
+
return self
|
|
172
|
+
|
|
173
|
+
def is_current(self) -> bool:
|
|
174
|
+
"""Every saved file still at its size and mtime, and no new ones."""
|
|
175
|
+
repo = RepoMap(self.root)
|
|
176
|
+
seen = 0
|
|
177
|
+
for path in repo._walk():
|
|
178
|
+
try:
|
|
179
|
+
rel = str(path.relative_to(self.root))
|
|
180
|
+
stat = path.stat()
|
|
181
|
+
except (OSError, ValueError):
|
|
182
|
+
return False
|
|
183
|
+
if stat.st_size > repo.max_file_bytes:
|
|
184
|
+
continue
|
|
185
|
+
saved = self.files.get(rel)
|
|
186
|
+
if saved is None or saved.get("mtime") != stat.st_mtime or saved.get("size") != stat.st_size:
|
|
187
|
+
return False
|
|
188
|
+
seen += 1
|
|
189
|
+
return seen == len(self.files)
|
|
190
|
+
|
|
191
|
+
# ── persistence ────────────────────────────────────────────────────────
|
|
192
|
+
|
|
193
|
+
def to_dict(self) -> dict:
|
|
194
|
+
return {"version": GRAPH_VERSION, "root": str(self.root), "built_at": self.built_at,
|
|
195
|
+
"files": self.files, "services": self.services, "refs": self.refs, "defs": self.defs}
|
|
196
|
+
|
|
197
|
+
@classmethod
|
|
198
|
+
def from_dict(cls, data: dict) -> "ProjectGraph":
|
|
199
|
+
graph = cls(data["root"])
|
|
200
|
+
graph.files = dict(data.get("files") or {})
|
|
201
|
+
graph.services = dict(data.get("services") or {})
|
|
202
|
+
graph.refs = dict(data.get("refs") or {})
|
|
203
|
+
graph.defs = dict(data.get("defs") or {})
|
|
204
|
+
graph.built_at = float(data.get("built_at") or 0.0)
|
|
205
|
+
return graph
|
|
206
|
+
|
|
207
|
+
# ── edges ──────────────────────────────────────────────────────────────
|
|
208
|
+
|
|
209
|
+
def importers(self) -> dict[str, set[str]]:
|
|
210
|
+
reverse: dict[str, set[str]] = {}
|
|
211
|
+
for path, info in self.files.items():
|
|
212
|
+
for target in info.get("imports") or ():
|
|
213
|
+
reverse.setdefault(target, set()).add(path)
|
|
214
|
+
return reverse
|
|
215
|
+
|
|
216
|
+
def service_of(self, path: str) -> Optional[str]:
|
|
217
|
+
best, best_len = None, -1
|
|
218
|
+
for name, directory in self.services.items():
|
|
219
|
+
if directory == "" or path == directory or path.startswith(directory.rstrip("/") + "/"):
|
|
220
|
+
if len(directory) > best_len:
|
|
221
|
+
best, best_len = name, len(directory)
|
|
222
|
+
return best
|
|
223
|
+
|
|
224
|
+
def _is_hub(self, path: str) -> bool:
|
|
225
|
+
return (Path(path).name == "__init__.py"
|
|
226
|
+
or len(self.files.get(path, {}).get("imports") or ()) > _HUB_FAN_OUT)
|
|
227
|
+
|
|
228
|
+
def _symbol_users(self, dotted: str) -> tuple[set[str], set[str]]:
|
|
229
|
+
"""(defining files, mentioning files) for ``name`` or ``Class.method``."""
|
|
230
|
+
parts = [part for part in dotted.split(".") if part]
|
|
231
|
+
if not parts:
|
|
232
|
+
return set(), set()
|
|
233
|
+
defining = set(self.defs.get(parts[-1], ()))
|
|
234
|
+
users = set(self.refs.get(parts[-1], ()))
|
|
235
|
+
for outer in parts[:-1]:
|
|
236
|
+
users &= set(self.refs.get(outer, ()))
|
|
237
|
+
defining &= set(self.defs.get(outer, ())) or defining
|
|
238
|
+
return defining, users
|
|
239
|
+
|
|
240
|
+
def _file_users(self, path: str) -> set[str]:
|
|
241
|
+
users = set(self.importers().get(path, ()))
|
|
242
|
+
for name, _kind, _line, parent in self.files.get(path, {}).get("symbols") or ():
|
|
243
|
+
if parent:
|
|
244
|
+
continue # a method is reached through its class
|
|
245
|
+
if path in self.defs.get(name, ()) and name in self.refs:
|
|
246
|
+
users |= set(self.refs[name])
|
|
247
|
+
users.discard(path)
|
|
248
|
+
return users
|
|
249
|
+
|
|
250
|
+
def _resolve(self, target: str) -> Optional[str]:
|
|
251
|
+
raw = target.strip()
|
|
252
|
+
candidate = Path(raw).expanduser()
|
|
253
|
+
if candidate.is_absolute():
|
|
254
|
+
try:
|
|
255
|
+
raw = str(candidate.resolve().relative_to(self.root))
|
|
256
|
+
except ValueError:
|
|
257
|
+
return None
|
|
258
|
+
raw = raw.removeprefix("./")
|
|
259
|
+
if raw in self.files:
|
|
260
|
+
return raw
|
|
261
|
+
matches = [path for path in self.files if path.endswith("/" + raw)]
|
|
262
|
+
return matches[0] if len(matches) == 1 else None
|
|
263
|
+
|
|
264
|
+
# ── impact ─────────────────────────────────────────────────────────────
|
|
265
|
+
|
|
266
|
+
def impact(self, targets: Iterable[str]) -> Impact:
|
|
267
|
+
wanted = [str(t).strip() for t in targets if str(t).strip()]
|
|
268
|
+
result = Impact(targets=wanted)
|
|
269
|
+
origin: set[str] = set()
|
|
270
|
+
changed_files: set[str] = set() # walked from; a symbol's file is not
|
|
271
|
+
direct: set[str] = set()
|
|
272
|
+
for target in wanted:
|
|
273
|
+
path = self._resolve(target)
|
|
274
|
+
if path is not None:
|
|
275
|
+
origin.add(path)
|
|
276
|
+
changed_files.add(path)
|
|
277
|
+
direct |= self._file_users(path)
|
|
278
|
+
continue
|
|
279
|
+
# Importing the file that defines a symbol is not using it: only
|
|
280
|
+
# files that name it are affected, and the walk starts from them.
|
|
281
|
+
defining, users = self._symbol_users(target)
|
|
282
|
+
if defining or users:
|
|
283
|
+
origin |= defining
|
|
284
|
+
direct |= users
|
|
285
|
+
else:
|
|
286
|
+
result.unresolved.append(target)
|
|
287
|
+
direct -= origin
|
|
288
|
+
|
|
289
|
+
importers = self.importers()
|
|
290
|
+
indirect: set[str] = set()
|
|
291
|
+
frontier = deque((path, 1) for path in direct | changed_files)
|
|
292
|
+
visited = set(direct | origin)
|
|
293
|
+
while frontier:
|
|
294
|
+
path, depth = frontier.popleft()
|
|
295
|
+
if depth > _TRANSITIVE_DEPTH or (path not in changed_files and self._is_hub(path)):
|
|
296
|
+
continue
|
|
297
|
+
for parent in importers.get(path, ()):
|
|
298
|
+
if parent not in visited:
|
|
299
|
+
visited.add(parent)
|
|
300
|
+
indirect.add(parent)
|
|
301
|
+
frontier.append((parent, depth + 1))
|
|
302
|
+
|
|
303
|
+
reached = origin | direct | indirect
|
|
304
|
+
result.direct = sorted(direct)
|
|
305
|
+
result.indirect = sorted(indirect - direct)
|
|
306
|
+
result.tests = sorted(path for path in (direct | indirect) if is_test_path(path))
|
|
307
|
+
result.services = sorted({s for s in (self.service_of(p) for p in reached) if s})
|
|
308
|
+
return result
|
|
309
|
+
|
|
310
|
+
def summary(self) -> dict:
|
|
311
|
+
edges = sum(len(info.get("imports") or ()) for info in self.files.values())
|
|
312
|
+
return {"files": len(self.files), "tests": sum(1 for p in self.files if is_test_path(p)),
|
|
313
|
+
"import_edges": edges, "symbols": len(self.defs), "services": dict(self.services),
|
|
314
|
+
"built_at": self.built_at}
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
# ── imports ────────────────────────────────────────────────────────────────
|
|
318
|
+
|
|
319
|
+
def _module_index(files) -> dict[str, list[str]]:
|
|
320
|
+
"""Dotted module names, every suffix of the path, mapped to Python files.
|
|
321
|
+
|
|
322
|
+
``src/aria_code/runtime/agent.py`` is ``agent``, ``runtime.agent``,
|
|
323
|
+
``aria_code.runtime.agent`` and ``src.aria_code.runtime.agent``: which of
|
|
324
|
+
those an import uses depends on what the project puts on its path.
|
|
325
|
+
"""
|
|
326
|
+
index: dict[str, list[str]] = {}
|
|
327
|
+
for path, entry in files.items():
|
|
328
|
+
if entry.language != "python":
|
|
329
|
+
continue
|
|
330
|
+
parts = list(Path(path).with_suffix("").parts)
|
|
331
|
+
if parts and parts[-1] == "__init__":
|
|
332
|
+
parts = parts[:-1]
|
|
333
|
+
for start in range(len(parts)):
|
|
334
|
+
index.setdefault(".".join(parts[start:]), []).append(path)
|
|
335
|
+
return index
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def _pick(candidates: Sequence[str], importer: str) -> Optional[str]:
|
|
339
|
+
if not candidates:
|
|
340
|
+
return None
|
|
341
|
+
if len(candidates) == 1:
|
|
342
|
+
return candidates[0]
|
|
343
|
+
# Several files answer to a short name: prefer the one sharing most of the
|
|
344
|
+
# importer's directory.
|
|
345
|
+
importer_parts = Path(importer).parts
|
|
346
|
+
def shared(path: str) -> int:
|
|
347
|
+
count = 0
|
|
348
|
+
for a, b in zip(Path(path).parts, importer_parts):
|
|
349
|
+
if a != b:
|
|
350
|
+
break
|
|
351
|
+
count += 1
|
|
352
|
+
return count
|
|
353
|
+
ranked = sorted(candidates, key=shared, reverse=True)
|
|
354
|
+
return ranked[0] if shared(ranked[0]) > shared(ranked[1]) else None
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def _python_imports(root: Path, path: str, modules: dict) -> list[str]:
|
|
358
|
+
try:
|
|
359
|
+
tree = ast.parse((root / path).read_text(encoding="utf-8-sig", errors="replace"))
|
|
360
|
+
except (SyntaxError, ValueError, OSError, RecursionError):
|
|
361
|
+
return []
|
|
362
|
+
package = list(Path(path).parent.parts)
|
|
363
|
+
found: list[str] = []
|
|
364
|
+
|
|
365
|
+
def resolve(name: str) -> Optional[str]:
|
|
366
|
+
return _pick(modules.get(name, ()), path)
|
|
367
|
+
|
|
368
|
+
for node in ast.walk(tree):
|
|
369
|
+
if isinstance(node, ast.Import):
|
|
370
|
+
for alias in node.names:
|
|
371
|
+
hit = resolve(alias.name)
|
|
372
|
+
if hit:
|
|
373
|
+
found.append(hit)
|
|
374
|
+
elif isinstance(node, ast.ImportFrom):
|
|
375
|
+
if node.level:
|
|
376
|
+
base_parts = package[: len(package) - (node.level - 1)] if node.level > 1 else package
|
|
377
|
+
base = ".".join(base_parts + ([node.module] if node.module else []))
|
|
378
|
+
else:
|
|
379
|
+
base = node.module or ""
|
|
380
|
+
for alias in node.names:
|
|
381
|
+
hit = resolve(f"{base}.{alias.name}" if base else alias.name) or (resolve(base) if base else None)
|
|
382
|
+
if hit:
|
|
383
|
+
found.append(hit)
|
|
384
|
+
return found
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def _js_imports(root: Path, path: str, files) -> list[str]:
|
|
388
|
+
try:
|
|
389
|
+
source = (root / path).read_text(encoding="utf-8-sig", errors="replace")
|
|
390
|
+
except OSError:
|
|
391
|
+
return []
|
|
392
|
+
found = []
|
|
393
|
+
folder = Path(path).parent
|
|
394
|
+
for spec in _JS_IMPORT.findall(source):
|
|
395
|
+
base = os.path.normpath(str(folder / spec))
|
|
396
|
+
candidates = [base, *(base + ext for ext in _JS_EXTENSIONS),
|
|
397
|
+
*(os.path.join(base, f"index{ext}") for ext in _JS_EXTENSIONS)]
|
|
398
|
+
hit = next((c for c in candidates if c in files), None)
|
|
399
|
+
if hit:
|
|
400
|
+
found.append(hit)
|
|
401
|
+
return found
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
def _imports(root: Path, path: str, language: str, modules: dict, files) -> list[str]:
|
|
405
|
+
if language == "python":
|
|
406
|
+
return _python_imports(root, path, modules)
|
|
407
|
+
if path.endswith(_JS_EXTENSIONS):
|
|
408
|
+
return _js_imports(root, path, files)
|
|
409
|
+
return []
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
# ── services ───────────────────────────────────────────────────────────────
|
|
413
|
+
|
|
414
|
+
def _services(root: Path, files: dict) -> dict[str, str]:
|
|
415
|
+
services: dict[str, str] = {}
|
|
416
|
+
for name in _COMPOSE_FILES:
|
|
417
|
+
compose = root / name
|
|
418
|
+
if not compose.is_file():
|
|
419
|
+
continue
|
|
420
|
+
try:
|
|
421
|
+
import yaml
|
|
422
|
+
|
|
423
|
+
data = yaml.safe_load(compose.read_text(encoding="utf-8")) or {}
|
|
424
|
+
except Exception:
|
|
425
|
+
continue
|
|
426
|
+
for service, spec in (data.get("services") or {}).items():
|
|
427
|
+
build = (spec or {}).get("build") if isinstance(spec, dict) else None
|
|
428
|
+
context = build.get("context") if isinstance(build, dict) else build
|
|
429
|
+
if isinstance(context, str):
|
|
430
|
+
directory = os.path.normpath(context)
|
|
431
|
+
services[str(service)] = "" if directory in (".", "") else directory
|
|
432
|
+
directories = {str(parent) for p in files for parent in Path(p).parents}
|
|
433
|
+
for directory in sorted(directories):
|
|
434
|
+
if directory in (".", "") or directory in services.values():
|
|
435
|
+
continue
|
|
436
|
+
if any((root / directory / marker).is_file() for marker in _PACKAGE_MARKERS):
|
|
437
|
+
services.setdefault(Path(directory).name, directory)
|
|
438
|
+
return services
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
# ── loading ────────────────────────────────────────────────────────────────
|
|
442
|
+
|
|
443
|
+
def _graph_file(root: Path) -> Path:
|
|
444
|
+
from ..packages.aria_core.paths import aria_home
|
|
445
|
+
|
|
446
|
+
digest = hashlib.sha1(str(root).encode("utf-8")).hexdigest()[:12]
|
|
447
|
+
return aria_home() / "graphs" / f"{root.name}-{digest}.json"
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
_CACHE: dict[str, ProjectGraph] = {}
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def load_project_graph(root: Path | str = ".", *, refresh: bool = True) -> ProjectGraph:
|
|
454
|
+
"""The graph for ``root``: from memory, then disk, rebuilt when stale."""
|
|
455
|
+
resolved = Path(root).expanduser().resolve()
|
|
456
|
+
key = str(resolved)
|
|
457
|
+
graph = _CACHE.get(key)
|
|
458
|
+
path = _graph_file(resolved)
|
|
459
|
+
if graph is None:
|
|
460
|
+
try:
|
|
461
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
462
|
+
if data.get("version") == GRAPH_VERSION and data.get("root") == key:
|
|
463
|
+
graph = ProjectGraph.from_dict(data)
|
|
464
|
+
except (OSError, ValueError, KeyError, TypeError):
|
|
465
|
+
graph = None
|
|
466
|
+
if graph is not None and (not refresh or graph.is_current()):
|
|
467
|
+
_CACHE[key] = graph
|
|
468
|
+
return graph
|
|
469
|
+
fresh = ProjectGraph(resolved).build(previous=graph)
|
|
470
|
+
_CACHE[key] = fresh
|
|
471
|
+
try:
|
|
472
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
473
|
+
temp = path.with_suffix(".tmp")
|
|
474
|
+
temp.write_text(json.dumps(fresh.to_dict()), encoding="utf-8")
|
|
475
|
+
os.replace(temp, path)
|
|
476
|
+
except OSError:
|
|
477
|
+
pass
|
|
478
|
+
return fresh
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def clear_cache() -> None:
|
|
482
|
+
_CACHE.clear()
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
def cached_graph(root: Path | str) -> Optional[ProjectGraph]:
|
|
486
|
+
"""The graph already in memory or on disk; never builds one.
|
|
487
|
+
|
|
488
|
+
For approval cards and reports, which must not stall on a first scan.
|
|
489
|
+
It may be a little stale, which is fine for a hint.
|
|
490
|
+
"""
|
|
491
|
+
resolved = Path(root).expanduser().resolve()
|
|
492
|
+
graph = _CACHE.get(str(resolved))
|
|
493
|
+
if graph is not None:
|
|
494
|
+
return graph
|
|
495
|
+
try:
|
|
496
|
+
data = json.loads(_graph_file(resolved).read_text(encoding="utf-8"))
|
|
497
|
+
if data.get("version") == GRAPH_VERSION and data.get("root") == str(resolved):
|
|
498
|
+
graph = ProjectGraph.from_dict(data)
|
|
499
|
+
_CACHE[str(resolved)] = graph
|
|
500
|
+
return graph
|
|
501
|
+
except (OSError, ValueError, KeyError, TypeError):
|
|
502
|
+
pass
|
|
503
|
+
return None
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
def _repository_of(path: Path) -> Optional[tuple[Path, str]]:
|
|
507
|
+
"""``(repository root, path inside it)`` — a task worktree maps to its repository."""
|
|
508
|
+
import subprocess
|
|
509
|
+
|
|
510
|
+
folder = path if path.is_dir() else path.parent
|
|
511
|
+
while not folder.exists() and folder != folder.parent:
|
|
512
|
+
folder = folder.parent
|
|
513
|
+
try:
|
|
514
|
+
out = subprocess.run(["git", "rev-parse", "--show-toplevel", "--git-common-dir"], cwd=folder,
|
|
515
|
+
capture_output=True, text=True, timeout=5, check=True).stdout.splitlines()
|
|
516
|
+
except (OSError, subprocess.SubprocessError):
|
|
517
|
+
out = []
|
|
518
|
+
if len(out) < 2:
|
|
519
|
+
# Not a git repository: the nearest folder that has a graph.
|
|
520
|
+
for parent in [folder, *folder.parents]:
|
|
521
|
+
if str(parent.resolve()) in _CACHE or _graph_file(parent.resolve()).is_file():
|
|
522
|
+
try:
|
|
523
|
+
return parent.resolve(), str(path.resolve().relative_to(parent.resolve()))
|
|
524
|
+
except ValueError:
|
|
525
|
+
return None
|
|
526
|
+
return None
|
|
527
|
+
top = Path(out[0]).resolve()
|
|
528
|
+
common = Path(out[1])
|
|
529
|
+
common = (folder / common).resolve() if not common.is_absolute() else common.resolve()
|
|
530
|
+
origin = common.parent if common.name == ".git" else top
|
|
531
|
+
try:
|
|
532
|
+
return origin, str(path.resolve().relative_to(top))
|
|
533
|
+
except ValueError:
|
|
534
|
+
return None
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
def impact_of_paths(paths: Sequence[str]) -> Optional[Impact]:
|
|
538
|
+
"""Impact of changing these absolute paths, from a cached graph only."""
|
|
539
|
+
targets: list[str] = []
|
|
540
|
+
graph: Optional[ProjectGraph] = None
|
|
541
|
+
for raw in paths:
|
|
542
|
+
located = _repository_of(Path(raw))
|
|
543
|
+
if located is None:
|
|
544
|
+
continue
|
|
545
|
+
root, relative = located
|
|
546
|
+
candidate = cached_graph(root)
|
|
547
|
+
if candidate is None or (graph is not None and candidate.root != graph.root):
|
|
548
|
+
continue
|
|
549
|
+
graph = candidate
|
|
550
|
+
targets.append(relative)
|
|
551
|
+
if graph is None or not targets:
|
|
552
|
+
return None
|
|
553
|
+
return graph.impact(targets)
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
def impact_line(impact: Optional[Impact]) -> str:
|
|
557
|
+
"""One line for a card or report: ``9 files · 7 tests · api``."""
|
|
558
|
+
if impact is None or not impact.targets or impact.unresolved == impact.targets:
|
|
559
|
+
return ""
|
|
560
|
+
reach = len(impact.direct) + len(impact.indirect)
|
|
561
|
+
parts = [f"{impact.breadth}", f"{reach} file{'s' if reach != 1 else ''} depend on it",
|
|
562
|
+
f"{len(impact.tests)} test{'s' if len(impact.tests) != 1 else ''}"]
|
|
563
|
+
if impact.services:
|
|
564
|
+
parts.append(", ".join(impact.services))
|
|
565
|
+
return " · ".join(parts)
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
# ── model-facing tool ──────────────────────────────────────────────────────
|
|
569
|
+
|
|
570
|
+
def tool_impact_analysis(params: dict) -> dict:
|
|
571
|
+
"""What a change to these files or symbols reaches, before making it."""
|
|
572
|
+
try:
|
|
573
|
+
targets = params.get("targets") or params.get("target") or []
|
|
574
|
+
if isinstance(targets, str):
|
|
575
|
+
targets = [targets]
|
|
576
|
+
targets = [str(t) for t in targets if str(t).strip()]
|
|
577
|
+
if not targets:
|
|
578
|
+
return {"success": False, "error": "Missing 'targets': file paths or symbol names"}
|
|
579
|
+
graph = load_project_graph(params.get("path") or ".")
|
|
580
|
+
impact = graph.impact(targets)
|
|
581
|
+
return {"success": True, "data": {**impact.as_dict(), "report": impact.render()}}
|
|
582
|
+
except Exception as exc:
|
|
583
|
+
return {"success": False, "error": f"impact_analysis failed: {exc}"}
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
PROJECT_GRAPH_TOOLS = {
|
|
587
|
+
"impact_analysis": (tool_impact_analysis,
|
|
588
|
+
"What depends on a file or symbol: callers, importers, tests, services"),
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
PROJECT_GRAPH_SCHEMAS = [
|
|
592
|
+
{
|
|
593
|
+
"name": "impact_analysis",
|
|
594
|
+
"description": (
|
|
595
|
+
"Before editing, find what a change would reach. Give file paths and/or symbol "
|
|
596
|
+
"names (`Class.method` for a method). Returns the files that use them directly, "
|
|
597
|
+
"the files reached through imports (up to three hops), the tests that cover any "
|
|
598
|
+
"of those, the services (compose services, packages) that ship them, and a "
|
|
599
|
+
"breadth rating. Unknown targets are listed as not found rather than guessed."
|
|
600
|
+
),
|
|
601
|
+
"parameters": {
|
|
602
|
+
"type": "object",
|
|
603
|
+
"properties": {
|
|
604
|
+
"targets": {
|
|
605
|
+
"type": "array",
|
|
606
|
+
"items": {"type": "string"},
|
|
607
|
+
"description": "Repository-relative paths or symbol names, e.g. src/auth/session.py, Session.refresh",
|
|
608
|
+
},
|
|
609
|
+
"path": {"type": "string", "description": "Repository root (default: current directory)"},
|
|
610
|
+
},
|
|
611
|
+
"required": ["targets"],
|
|
612
|
+
},
|
|
613
|
+
},
|
|
614
|
+
]
|