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,448 @@
|
|
|
1
|
+
"""One git worktree per coding task, applied to the workspace on approval.
|
|
2
|
+
|
|
3
|
+
A coding turn used to edit the user's files directly; a bad edit was undone
|
|
4
|
+
file by file from checkpoints. With a task worktree the turn works on a copy:
|
|
5
|
+
the user's files do not change until they approve the result, and declining
|
|
6
|
+
it leaves nothing to undo.
|
|
7
|
+
|
|
8
|
+
The copy starts from what the user actually has, not from HEAD. Most people
|
|
9
|
+
ask for a change with uncommitted work in the tree, and a worktree of HEAD
|
|
10
|
+
would hand the model files the user has already moved past. ``snapshot``
|
|
11
|
+
records the working tree as a commit through a scratch index, so neither the
|
|
12
|
+
user's index nor their files are touched, and the worktree is checked out at
|
|
13
|
+
that commit.
|
|
14
|
+
|
|
15
|
+
A task lasts until it is applied or discarded, across as many turns as it
|
|
16
|
+
takes. While it has no changes it follows the workspace: each turn re-takes
|
|
17
|
+
the snapshot (about 0.15s for a thousand files) and rebuilds the worktree
|
|
18
|
+
only when the user's files moved. Applying is ``git apply`` of the task's
|
|
19
|
+
diff against that snapshot; when the user has since changed the same lines it
|
|
20
|
+
refuses and the worktree stays, so nothing is overwritten.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import hashlib
|
|
26
|
+
import json
|
|
27
|
+
import os
|
|
28
|
+
import shutil
|
|
29
|
+
import subprocess
|
|
30
|
+
import tempfile
|
|
31
|
+
import time
|
|
32
|
+
import uuid
|
|
33
|
+
from dataclasses import asdict, dataclass
|
|
34
|
+
from pathlib import Path
|
|
35
|
+
from typing import Optional, Sequence
|
|
36
|
+
|
|
37
|
+
# Ignored at the top of most repositories and needed to run anything: a
|
|
38
|
+
# worktree has none of them, so the task's tests would fail on imports. Linked
|
|
39
|
+
# into the worktree when the workspace has them and git ignores them.
|
|
40
|
+
DEPENDENCY_DIRS = ("node_modules", ".venv", "venv", "env", ".tox")
|
|
41
|
+
|
|
42
|
+
# Bytecode in a repository that does not ignore it would otherwise be copied
|
|
43
|
+
# into every snapshot. A copied .pyc whose source is then rewritten within the
|
|
44
|
+
# same second at the same size still validates, and Python runs the old code.
|
|
45
|
+
_NEVER_SNAPSHOT = (":(exclude,glob)**/__pycache__/**", ":(exclude,glob)**/*.py[co]")
|
|
46
|
+
|
|
47
|
+
_SNAPSHOT_IDENTITY = {
|
|
48
|
+
"GIT_AUTHOR_NAME": "Aria Code",
|
|
49
|
+
"GIT_AUTHOR_EMAIL": "aria@localhost",
|
|
50
|
+
"GIT_COMMITTER_NAME": "Aria Code",
|
|
51
|
+
"GIT_COMMITTER_EMAIL": "aria@localhost",
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class TaskWorktreeError(RuntimeError):
|
|
56
|
+
"""A task worktree could not be created, applied or removed."""
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass
|
|
60
|
+
class TaskWorktree:
|
|
61
|
+
task_id: str
|
|
62
|
+
repository: str
|
|
63
|
+
path: str
|
|
64
|
+
base: str # snapshot commit the worktree started from
|
|
65
|
+
base_tree: str # its tree, to tell whether the workspace has moved
|
|
66
|
+
created_at: float
|
|
67
|
+
linked: tuple[str, ...] = ()
|
|
68
|
+
|
|
69
|
+
def to_dict(self) -> dict:
|
|
70
|
+
data = asdict(self)
|
|
71
|
+
data["linked"] = list(self.linked)
|
|
72
|
+
return data
|
|
73
|
+
|
|
74
|
+
@classmethod
|
|
75
|
+
def from_dict(cls, data: dict) -> "TaskWorktree":
|
|
76
|
+
return cls(
|
|
77
|
+
task_id=str(data["task_id"]), repository=str(data["repository"]),
|
|
78
|
+
path=str(data["path"]), base=str(data["base"]),
|
|
79
|
+
base_tree=str(data["base_tree"]), created_at=float(data.get("created_at") or 0.0),
|
|
80
|
+
linked=tuple(data.get("linked") or ()),
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@dataclass(frozen=True)
|
|
85
|
+
class TaskChange:
|
|
86
|
+
status: str # A, M, D, R…, as git reports it
|
|
87
|
+
path: str
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _git(*args: str, cwd: Path | str, env: Optional[dict] = None,
|
|
91
|
+
input_data: Optional[bytes] = None, timeout: int = 60) -> bytes:
|
|
92
|
+
try:
|
|
93
|
+
completed = subprocess.run(
|
|
94
|
+
["git", *args], cwd=str(cwd), input=input_data, capture_output=True,
|
|
95
|
+
# Automated Git commands must not inherit the application protocol
|
|
96
|
+
# pipe (or wait for keyboard input). Explicit patch/blob input still
|
|
97
|
+
# gets its own pipe, closed by communicate().
|
|
98
|
+
stdin=subprocess.DEVNULL if input_data is None else None,
|
|
99
|
+
timeout=timeout, check=False, env={**os.environ, **(env or {})},
|
|
100
|
+
)
|
|
101
|
+
except (OSError, subprocess.SubprocessError) as exc:
|
|
102
|
+
raise TaskWorktreeError(f"Unable to run git: {exc}") from exc
|
|
103
|
+
if completed.returncode != 0:
|
|
104
|
+
detail = (completed.stderr or completed.stdout).decode("utf-8", errors="replace").strip()
|
|
105
|
+
raise TaskWorktreeError(detail or f"git {' '.join(args)} failed")
|
|
106
|
+
return completed.stdout
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _text(*args: str, cwd: Path | str, **kwargs) -> str:
|
|
110
|
+
return _git(*args, cwd=cwd, **kwargs).decode("utf-8", errors="replace").strip()
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def repository_root(workspace: Path | str) -> Optional[Path]:
|
|
114
|
+
"""The repository containing ``workspace``, or None outside one."""
|
|
115
|
+
try:
|
|
116
|
+
return Path(_text("rev-parse", "--show-toplevel", cwd=Path(workspace).expanduser())).resolve()
|
|
117
|
+
except (TaskWorktreeError, OSError):
|
|
118
|
+
return None
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def snapshot(repository: Path | str) -> tuple[str, str]:
|
|
122
|
+
"""Record the working tree as a commit; returns ``(commit, tree)``.
|
|
123
|
+
|
|
124
|
+
Tracked and untracked files alike, ignored ones excluded, exactly as
|
|
125
|
+
``git add -A`` would stage them — into a scratch index, so the user's
|
|
126
|
+
index and files are left as they were.
|
|
127
|
+
"""
|
|
128
|
+
repo = Path(repository)
|
|
129
|
+
with tempfile.TemporaryDirectory(prefix="aria-snapshot-") as scratch:
|
|
130
|
+
env = {"GIT_INDEX_FILE": str(Path(scratch) / "index"), **_SNAPSHOT_IDENTITY}
|
|
131
|
+
try:
|
|
132
|
+
head = _text("rev-parse", "--verify", "-q", "HEAD", cwd=repo)
|
|
133
|
+
except TaskWorktreeError:
|
|
134
|
+
head = ""
|
|
135
|
+
if head:
|
|
136
|
+
_git("read-tree", head, cwd=repo, env=env)
|
|
137
|
+
_git("add", "-A", "--", ".", *_NEVER_SNAPSHOT, cwd=repo, env=env)
|
|
138
|
+
tree = _text("write-tree", cwd=repo, env=env)
|
|
139
|
+
parents = ["-p", head] if head else []
|
|
140
|
+
commit = _text("commit-tree", tree, *parents, "-m", "aria: task base snapshot", cwd=repo, env=env)
|
|
141
|
+
return commit, tree
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def checkout(repo: Path, commit: str, destination: Path) -> list[str]:
|
|
145
|
+
"""A detached worktree of ``commit`` at ``destination``, dependencies linked.
|
|
146
|
+
|
|
147
|
+
Returns the dependency directories linked in from ``repo``.
|
|
148
|
+
"""
|
|
149
|
+
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
150
|
+
try:
|
|
151
|
+
_git("worktree", "add", "--detach", str(destination), commit, cwd=repo, timeout=300)
|
|
152
|
+
except TaskWorktreeError:
|
|
153
|
+
shutil.rmtree(destination, ignore_errors=True)
|
|
154
|
+
raise
|
|
155
|
+
linked = []
|
|
156
|
+
for name in DEPENDENCY_DIRS:
|
|
157
|
+
source = repo / name
|
|
158
|
+
if not source.is_dir() or (destination / name).exists():
|
|
159
|
+
continue
|
|
160
|
+
try:
|
|
161
|
+
_git("check-ignore", "-q", name, cwd=repo)
|
|
162
|
+
except TaskWorktreeError:
|
|
163
|
+
continue # tracked or not ignored: it came with the checkout
|
|
164
|
+
(destination / name).symlink_to(source, target_is_directory=True)
|
|
165
|
+
linked.append(name)
|
|
166
|
+
return linked
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def remove_checkout(repo: Path | str, destination: Path | str, linked: Sequence[str] = ()) -> None:
|
|
170
|
+
for name in linked:
|
|
171
|
+
link = Path(destination) / name
|
|
172
|
+
if link.is_symlink():
|
|
173
|
+
link.unlink()
|
|
174
|
+
try:
|
|
175
|
+
_git("worktree", "remove", "--force", str(destination), cwd=repo)
|
|
176
|
+
except TaskWorktreeError:
|
|
177
|
+
shutil.rmtree(destination, ignore_errors=True)
|
|
178
|
+
try:
|
|
179
|
+
_git("worktree", "prune", cwd=repo)
|
|
180
|
+
except TaskWorktreeError:
|
|
181
|
+
pass
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _load_toml(text: str) -> dict:
|
|
185
|
+
"""tomllib on 3.11+; on 3.10, tomli or the copy pip vendors."""
|
|
186
|
+
try:
|
|
187
|
+
import tomllib as toml
|
|
188
|
+
except ImportError:
|
|
189
|
+
try:
|
|
190
|
+
import tomli as toml
|
|
191
|
+
except ImportError:
|
|
192
|
+
from pip._vendor import tomli as toml
|
|
193
|
+
return toml.loads(text)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def python_source_roots(root: Path | str) -> list[Path]:
|
|
197
|
+
"""Where a Python project's importable code lives, most specific first.
|
|
198
|
+
|
|
199
|
+
A project installed with ``pip install -e`` imports from the checkout it
|
|
200
|
+
was installed from. Run its tests in a task worktree and they import the
|
|
201
|
+
user's files, not the task's edits, and pass or fail for the wrong code.
|
|
202
|
+
Putting these roots first on PYTHONPATH makes the worktree's copy win:
|
|
203
|
+
PYTHONPATH precedes site-packages and the editable install's hooks.
|
|
204
|
+
|
|
205
|
+
Read from pytest's ``pythonpath``, setuptools' ``package-dir`` (in
|
|
206
|
+
pyproject.toml or setup.cfg), a ``src/`` layout, and the root itself.
|
|
207
|
+
"""
|
|
208
|
+
root = Path(root)
|
|
209
|
+
found: list[Path] = []
|
|
210
|
+
|
|
211
|
+
def add(relative) -> None:
|
|
212
|
+
for item in ([relative] if isinstance(relative, str) else list(relative or ())):
|
|
213
|
+
candidate = (root / str(item)).resolve()
|
|
214
|
+
if candidate.is_dir() and candidate not in found:
|
|
215
|
+
found.append(candidate)
|
|
216
|
+
|
|
217
|
+
try:
|
|
218
|
+
data = _load_toml((root / "pyproject.toml").read_text(encoding="utf-8"))
|
|
219
|
+
tool = data.get("tool") or {}
|
|
220
|
+
add((tool.get("pytest", {}).get("ini_options") or {}).get("pythonpath"))
|
|
221
|
+
setuptools = tool.get("setuptools") or {}
|
|
222
|
+
add((setuptools.get("package-dir") or {}).get(""))
|
|
223
|
+
add(((setuptools.get("packages") or {}).get("find") or {}).get("where") if isinstance(
|
|
224
|
+
setuptools.get("packages"), dict) else None)
|
|
225
|
+
except (OSError, ValueError, ImportError, AttributeError):
|
|
226
|
+
pass
|
|
227
|
+
try:
|
|
228
|
+
import configparser
|
|
229
|
+
|
|
230
|
+
parser = configparser.ConfigParser()
|
|
231
|
+
parser.read(root / "setup.cfg", encoding="utf-8")
|
|
232
|
+
mapping = parser.get("options", "package_dir", fallback="")
|
|
233
|
+
for line in mapping.splitlines():
|
|
234
|
+
key, _, value = line.partition("=")
|
|
235
|
+
if not key.strip() and value.strip():
|
|
236
|
+
add(value.strip())
|
|
237
|
+
except (configparser.Error, OSError):
|
|
238
|
+
pass
|
|
239
|
+
src = root / "src"
|
|
240
|
+
if src.is_dir() and any(child.suffix == ".py" or (child / "__init__.py").is_file() for child in src.iterdir()):
|
|
241
|
+
add("src")
|
|
242
|
+
add(".")
|
|
243
|
+
return found
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def worktree_command_env(workspace: str, origin: str, base_env: Optional[dict] = None) -> Optional[dict]:
|
|
247
|
+
"""The environment for a command run in a task worktree; None elsewhere."""
|
|
248
|
+
if not workspace or not origin:
|
|
249
|
+
return None
|
|
250
|
+
top = repository_root(workspace) or Path(workspace)
|
|
251
|
+
env = dict(os.environ if base_env is None else base_env)
|
|
252
|
+
roots = [str(path) for path in python_source_roots(top)]
|
|
253
|
+
existing = env.get("PYTHONPATH", "")
|
|
254
|
+
env["PYTHONPATH"] = os.pathsep.join([*roots, *([existing] if existing else [])])
|
|
255
|
+
return env
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def _exclusions(task: TaskWorktree) -> list[str]:
|
|
259
|
+
return [f":(exclude){name}" for name in task.linked]
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
class TaskWorktrees:
|
|
263
|
+
"""The active task worktree for each repository, persisted across restarts."""
|
|
264
|
+
|
|
265
|
+
def __init__(self, root: Path | str, state_file: Path | str | None = None) -> None:
|
|
266
|
+
self.root = Path(root).expanduser()
|
|
267
|
+
self.state_file = Path(state_file).expanduser() if state_file else self.root / "tasks.json"
|
|
268
|
+
|
|
269
|
+
# ── state ──────────────────────────────────────────────────────────────
|
|
270
|
+
|
|
271
|
+
def _load(self) -> dict:
|
|
272
|
+
try:
|
|
273
|
+
data = json.loads(self.state_file.read_text(encoding="utf-8"))
|
|
274
|
+
return data if isinstance(data, dict) else {}
|
|
275
|
+
except (OSError, ValueError):
|
|
276
|
+
return {}
|
|
277
|
+
|
|
278
|
+
def _save(self, data: dict) -> None:
|
|
279
|
+
self.state_file.parent.mkdir(parents=True, exist_ok=True)
|
|
280
|
+
temp = self.state_file.with_suffix(".tmp")
|
|
281
|
+
temp.write_text(json.dumps(data, indent=2, sort_keys=True), encoding="utf-8")
|
|
282
|
+
os.replace(temp, self.state_file)
|
|
283
|
+
|
|
284
|
+
def active(self, workspace: Path | str) -> Optional[TaskWorktree]:
|
|
285
|
+
"""The open task for ``workspace``'s repository, if its worktree still exists."""
|
|
286
|
+
repo = repository_root(workspace)
|
|
287
|
+
if repo is None:
|
|
288
|
+
return None
|
|
289
|
+
record = self._load().get(str(repo))
|
|
290
|
+
if not record:
|
|
291
|
+
return None
|
|
292
|
+
try:
|
|
293
|
+
task = TaskWorktree.from_dict(record)
|
|
294
|
+
except (KeyError, TypeError, ValueError):
|
|
295
|
+
return None
|
|
296
|
+
return task if Path(task.path).is_dir() else None
|
|
297
|
+
|
|
298
|
+
def _remember(self, task: TaskWorktree) -> None:
|
|
299
|
+
data = self._load()
|
|
300
|
+
data[task.repository] = task.to_dict()
|
|
301
|
+
self._save(data)
|
|
302
|
+
|
|
303
|
+
def _forget(self, task: TaskWorktree) -> None:
|
|
304
|
+
data = self._load()
|
|
305
|
+
if data.pop(task.repository, None) is not None:
|
|
306
|
+
self._save(data)
|
|
307
|
+
|
|
308
|
+
# ── lifecycle ──────────────────────────────────────────────────────────
|
|
309
|
+
|
|
310
|
+
def ensure(self, workspace: Path | str) -> Optional[TaskWorktree]:
|
|
311
|
+
"""The worktree this turn should work in; None outside a repository.
|
|
312
|
+
|
|
313
|
+
Keeps a task that has changes. One without changes is kept only while
|
|
314
|
+
the workspace still matches its snapshot, and rebuilt otherwise.
|
|
315
|
+
"""
|
|
316
|
+
repo = repository_root(workspace)
|
|
317
|
+
if repo is None:
|
|
318
|
+
return None
|
|
319
|
+
task = self.active(repo)
|
|
320
|
+
if task is not None and self.changes(task):
|
|
321
|
+
return task
|
|
322
|
+
commit, tree = snapshot(repo)
|
|
323
|
+
if task is not None:
|
|
324
|
+
if task.base_tree == tree:
|
|
325
|
+
return task
|
|
326
|
+
self.discard(task)
|
|
327
|
+
return self._create(repo, commit, tree)
|
|
328
|
+
|
|
329
|
+
def _create(self, repo: Path, commit: str, tree: str) -> TaskWorktree:
|
|
330
|
+
task_id = uuid.uuid4().hex[:8]
|
|
331
|
+
digest = hashlib.sha1(str(repo).encode("utf-8")).hexdigest()[:8]
|
|
332
|
+
destination = (self.root / f"{repo.name}-{digest}" / task_id).resolve()
|
|
333
|
+
linked = checkout(repo, commit, destination)
|
|
334
|
+
task = TaskWorktree(task_id=task_id, repository=str(repo), path=str(destination),
|
|
335
|
+
base=commit, base_tree=tree, created_at=time.time(),
|
|
336
|
+
linked=tuple(linked))
|
|
337
|
+
self._remember(task)
|
|
338
|
+
return task
|
|
339
|
+
|
|
340
|
+
def _stage(self, task: TaskWorktree) -> None:
|
|
341
|
+
# The worktree's own index; the user's is never involved.
|
|
342
|
+
_git("add", "-A", "--", ".", *_exclusions(task), cwd=task.path)
|
|
343
|
+
|
|
344
|
+
def changes(self, task: TaskWorktree) -> list[TaskChange]:
|
|
345
|
+
"""What the task changed relative to the snapshot it started from."""
|
|
346
|
+
self._stage(task)
|
|
347
|
+
output = _text("diff", "--cached", "--name-status", "--no-renames", task.base, cwd=task.path)
|
|
348
|
+
changes = []
|
|
349
|
+
for line in output.splitlines():
|
|
350
|
+
status, _, path = line.partition("\t")
|
|
351
|
+
if path:
|
|
352
|
+
changes.append(TaskChange(status=status.strip(), path=path.strip()))
|
|
353
|
+
return changes
|
|
354
|
+
|
|
355
|
+
def diff(self, task: TaskWorktree, *, stat: bool = False) -> str:
|
|
356
|
+
self._stage(task)
|
|
357
|
+
args = ["diff", "--cached", "--no-renames"]
|
|
358
|
+
if stat:
|
|
359
|
+
args.append("--stat")
|
|
360
|
+
return _text(*args, task.base, cwd=task.path)
|
|
361
|
+
|
|
362
|
+
def patch(self, task: TaskWorktree) -> str:
|
|
363
|
+
"""The task's changes as a binary-safe patch against its snapshot."""
|
|
364
|
+
self._stage(task)
|
|
365
|
+
return _git("diff", "--cached", "--binary", "--no-renames", task.base,
|
|
366
|
+
cwd=task.path).decode("utf-8", errors="replace")
|
|
367
|
+
|
|
368
|
+
def reset_to_patch(self, task: TaskWorktree, patch: str) -> None:
|
|
369
|
+
"""Make the worktree exactly its snapshot plus ``patch``.
|
|
370
|
+
|
|
371
|
+
Covers every change since, including those a shell command made, which
|
|
372
|
+
have no file checkpoint. Linked dependency directories are left alone.
|
|
373
|
+
"""
|
|
374
|
+
_git("reset", "-q", "--hard", task.base, cwd=task.path)
|
|
375
|
+
_git("clean", "-fdq", *[arg for name in task.linked for arg in ("-e", name)], cwd=task.path)
|
|
376
|
+
self.restore_patch(task, patch)
|
|
377
|
+
|
|
378
|
+
def restore_patch(self, task: TaskWorktree, patch: str) -> None:
|
|
379
|
+
"""Put a saved patch back into a task's worktree (a rewound task)."""
|
|
380
|
+
if patch.strip():
|
|
381
|
+
_git("apply", "-", cwd=task.path, input_data=patch.encode("utf-8"))
|
|
382
|
+
|
|
383
|
+
def apply(self, task: TaskWorktree, *, session_id: str = "") -> list[TaskChange]:
|
|
384
|
+
"""Apply the task to the workspace, record checkpoints, then remove it.
|
|
385
|
+
|
|
386
|
+
Refuses, keeping the worktree, when the workspace changed the same
|
|
387
|
+
lines in the meantime.
|
|
388
|
+
"""
|
|
389
|
+
changes = self.changes(task)
|
|
390
|
+
if not changes:
|
|
391
|
+
raise TaskWorktreeError("The task has no changes to apply.")
|
|
392
|
+
repo = Path(task.repository)
|
|
393
|
+
patch = _git("diff", "--cached", "--binary", "--no-renames", task.base, cwd=task.path)
|
|
394
|
+
try:
|
|
395
|
+
_git("apply", "--check", "-", cwd=repo, input_data=patch)
|
|
396
|
+
except TaskWorktreeError as exc:
|
|
397
|
+
raise TaskWorktreeError(
|
|
398
|
+
f"Your files changed where the task did, so applying would overwrite them: {exc}. "
|
|
399
|
+
f"The task is kept at {task.path}."
|
|
400
|
+
) from exc
|
|
401
|
+
before = {}
|
|
402
|
+
for change in changes:
|
|
403
|
+
target = repo / change.path
|
|
404
|
+
try:
|
|
405
|
+
before[change.path] = (True, target.read_text(encoding="utf-8"), target.stat().st_mode & 0o777)
|
|
406
|
+
except FileNotFoundError:
|
|
407
|
+
before[change.path] = (False, "", None)
|
|
408
|
+
except (OSError, UnicodeDecodeError):
|
|
409
|
+
continue
|
|
410
|
+
_git("apply", "-", cwd=repo, input_data=patch)
|
|
411
|
+
_record_checkpoints(repo, changes, before, task=task, session_id=session_id)
|
|
412
|
+
self.discard(task)
|
|
413
|
+
return changes
|
|
414
|
+
|
|
415
|
+
def discard(self, task: TaskWorktree) -> None:
|
|
416
|
+
"""Remove the worktree and forget the task. The workspace is untouched."""
|
|
417
|
+
remove_checkout(task.repository, task.path, task.linked)
|
|
418
|
+
self._forget(task)
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def _record_checkpoints(repo: Path, changes, before: dict, *, task: TaskWorktree, session_id: str) -> None:
|
|
422
|
+
"""Make an applied task undoable with ``/rewind``, as an edit would be."""
|
|
423
|
+
try:
|
|
424
|
+
from .checkpoints import CheckpointStore
|
|
425
|
+
store = CheckpointStore()
|
|
426
|
+
except Exception:
|
|
427
|
+
return
|
|
428
|
+
for change in changes:
|
|
429
|
+
target = repo / change.path
|
|
430
|
+
prior = before.get(change.path)
|
|
431
|
+
if prior is None or not target.is_file():
|
|
432
|
+
continue
|
|
433
|
+
try:
|
|
434
|
+
store.record_change(
|
|
435
|
+
path=target, before_content=prior[1],
|
|
436
|
+
after_content=target.read_text(encoding="utf-8"),
|
|
437
|
+
existed_before=prior[0], before_mode=prior[2], source="task_apply",
|
|
438
|
+
session_id=session_id, label=f"task {task.task_id}: {change.path}",
|
|
439
|
+
metadata={"task_id": task.task_id, "worktree": task.path},
|
|
440
|
+
)
|
|
441
|
+
except Exception:
|
|
442
|
+
continue
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def default_task_worktrees() -> TaskWorktrees:
|
|
446
|
+
from ..packages.aria_core.paths import aria_home
|
|
447
|
+
|
|
448
|
+
return TaskWorktrees(aria_home() / "worktrees" / "tasks")
|