aria-code 0.52.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aria_code/__init__.py +42 -0
- aria_code/_version.py +20 -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 +34 -0
- aria_code/agents/base.py +318 -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 +303 -0
- aria_code/agents/financial/fundamental.py +191 -0
- aria_code/agents/financial/macro.py +99 -0
- aria_code/agents/financial/news.py +207 -0
- aria_code/agents/financial/risk.py +165 -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 +258 -0
- aria_code/agents/orchestrator.py +44 -0
- aria_code/agents/portfolio_agent.py +363 -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 +158 -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 +492 -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/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 +15 -0
- aria_code/apps/channels/__init__.py +17 -0
- aria_code/apps/channels/intake.py +92 -0
- aria_code/apps/channels/registry.py +95 -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/bootstrap.py +145 -0
- aria_code/apps/cli/broker_render.py +206 -0
- aria_code/apps/cli/codegen_paths.py +29 -0
- aria_code/apps/cli/commands/__init__.py +16 -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 +369 -0
- aria_code/apps/cli/commands/ashare_prediction_cmds.py +327 -0
- aria_code/apps/cli/commands/auth_cmds.py +239 -0
- aria_code/apps/cli/commands/backtest_cmds.py +2543 -0
- aria_code/apps/cli/commands/broker_cmds.py +1234 -0
- aria_code/apps/cli/commands/business_workflow_cmds.py +319 -0
- aria_code/apps/cli/commands/canvas_cmds.py +77 -0
- aria_code/apps/cli/commands/catalog.py +87 -0
- aria_code/apps/cli/commands/core_cmds.py +2520 -0
- aria_code/apps/cli/commands/data_cmds.py +457 -0
- aria_code/apps/cli/commands/diagnostic_cmds.py +230 -0
- aria_code/apps/cli/commands/diagnostic_ops_cmds.py +813 -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 +434 -0
- aria_code/apps/cli/commands/market_cmds.py +1381 -0
- aria_code/apps/cli/commands/market_context.py +425 -0
- aria_code/apps/cli/commands/market_render.py +7 -0
- aria_code/apps/cli/commands/model_cmds.py +2153 -0
- aria_code/apps/cli/commands/ops_cmds.py +721 -0
- aria_code/apps/cli/commands/orchestrator_cmds.py +179 -0
- aria_code/apps/cli/commands/pdf_export_cmds.py +125 -0
- aria_code/apps/cli/commands/portfolio_cmds.py +1278 -0
- aria_code/apps/cli/commands/report.py +437 -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 +669 -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 +79 -0
- aria_code/apps/cli/commands/workflow_cmds.py +480 -0
- aria_code/apps/cli/commands/workspace_cmds.py +1494 -0
- aria_code/apps/cli/config_paths.py +73 -0
- aria_code/apps/cli/config_store.py +78 -0
- aria_code/apps/cli/constants.py +88 -0
- aria_code/apps/cli/context.py +34 -0
- aria_code/apps/cli/deterministic.py +191 -0
- aria_code/apps/cli/direct.py +48 -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 +196 -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 +1309 -0
- aria_code/apps/cli/handlers/market_handlers.py +2513 -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/helpers.py +302 -0
- aria_code/apps/cli/hooks.py +180 -0
- aria_code/apps/cli/i18n.py +297 -0
- aria_code/apps/cli/intent.py +136 -0
- aria_code/apps/cli/intent_router.py +276 -0
- aria_code/apps/cli/intent_signals.py +344 -0
- aria_code/apps/cli/lifecycle_hooks.py +48 -0
- aria_code/apps/cli/local_tool_schemas.py +536 -0
- aria_code/apps/cli/main.py +29 -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/model_catalog.py +620 -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 +59 -0
- aria_code/apps/cli/prompts/__init__.py +0 -0
- aria_code/apps/cli/prompts/coding.py +53 -0
- aria_code/apps/cli/prompts/select.py +142 -0
- aria_code/apps/cli/prompts/system_prompts.py +552 -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 +521 -0
- aria_code/apps/cli/providers/chat_routing.py +128 -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 +1594 -0
- aria_code/apps/cli/providers/llm/response_cache.py +60 -0
- aria_code/apps/cli/providers/llm/sse_stream.py +257 -0
- aria_code/apps/cli/providers/runtime_bridge.py +353 -0
- aria_code/apps/cli/providers/vertexai_stream.py +316 -0
- aria_code/apps/cli/runtime_consumer.py +657 -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_store.py +112 -0
- aria_code/apps/cli/skills_catalog.py +273 -0
- aria_code/apps/cli/todo_tracker.py +190 -0
- aria_code/apps/cli/tool_executor.py +823 -0
- aria_code/apps/cli/tool_registry.py +34 -0
- aria_code/apps/cli/tool_scope.py +106 -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 +180 -0
- aria_code/apps/cli/tools/market_tools.py +620 -0
- aria_code/apps/cli/tools/notebook_tools.py +111 -0
- aria_code/apps/cli/tools/system_tools.py +726 -0
- aria_code/apps/cli/tools/write_tools.py +845 -0
- aria_code/apps/cli/tradingview_bridge.py +529 -0
- aria_code/apps/cli/turn_planning.py +137 -0
- aria_code/apps/cli/update_check.py +153 -0
- aria_code/apps/cli/utils/__init__.py +0 -0
- aria_code/apps/cli/utils/market_detect.py +1597 -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 +6743 -0
- aria_code/aria_daemon.py +1398 -0
- aria_code/aria_feishu_bot.py +1423 -0
- aria_code/aria_mcp_server.py +7 -0
- aria_code/aria_relay_client.py +4 -0
- aria_code/aria_relay_server.py +490 -0
- aria_code/aria_telegram_bot.py +202 -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 +182 -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 +1976 -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 +181 -0
- aria_code/command_safety.py +19 -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/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/demo_player.py +207 -0
- aria_code/doctor.py +813 -0
- aria_code/domain/__init__.py +0 -0
- aria_code/domain/backtest_engine.py +354 -0
- aria_code/domain/backtest_report.py +472 -0
- aria_code/domain/finance_formulas.py +389 -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/harness.py +598 -0
- aria_code/evals/runner.py +238 -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 +386 -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 +639 -0
- aria_code/memory_manager.py +246 -0
- aria_code/model_capability.py +486 -0
- aria_code/notification_tools.py +4 -0
- aria_code/openai_image_client.py +4 -0
- aria_code/packages/__init__.py +23 -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 +52 -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 +201 -0
- aria_code/packages/aria_mcp/circuit.py +82 -0
- aria_code/packages/aria_mcp/config.py +111 -0
- aria_code/packages/aria_mcp/installer.py +95 -0
- aria_code/packages/aria_mcp/server.py +1550 -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 +396 -0
- aria_code/packages/aria_sdk/providers.py +70 -0
- aria_code/packages/aria_sdk/streaming.py +79 -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 +268 -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 +57 -0
- aria_code/packages/aria_services/research_quality.py +186 -0
- aria_code/packages/aria_services/settings.py +157 -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 +8 -0
- aria_code/packages/aria_tools/financial/_paths.py +130 -0
- aria_code/packages/aria_tools/financial/compliance.py +31 -0
- aria_code/packages/aria_tools/financial/factors.py +33 -0
- aria_code/packages/aria_tools/financial/risk_tools.py +33 -0
- aria_code/packages/aria_tools/financial/strategy.py +31 -0
- aria_code/packages/aria_tools/registry.py +128 -0
- aria_code/packages/quant_engine/__init__.py +34 -0
- aria_code/packages/quant_engine/_namespace.py +62 -0
- aria_code/packages/quant_engine/backtest/__init__.py +14 -0
- aria_code/packages/quant_engine/backtest/core.py +53 -0
- aria_code/packages/quant_engine/backtest/engine.py +96 -0
- aria_code/packages/quant_engine/portfolio/__init__.py +13 -0
- aria_code/packages/quant_engine/portfolio/optimizer.py +85 -0
- aria_code/packages/quant_engine/sports/__init__.py +80 -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/ml_model.py +377 -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 +35 -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/logistics/__init__.py +169 -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/llm/__init__.py +19 -0
- aria_code/providers/llm/anthropic.py +184 -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 +129 -0
- aria_code/providers/llm/openai_compat.py +313 -0
- aria_code/providers/llm/registry.py +444 -0
- aria_code/providers/local_image_provider.py +202 -0
- aria_code/providers/local_llm_provider.py +589 -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/runtime/__init__.py +169 -0
- aria_code/runtime/acceptance.py +481 -0
- aria_code/runtime/agent_loop.py +1520 -0
- aria_code/runtime/approval.py +57 -0
- aria_code/runtime/budget.py +232 -0
- aria_code/runtime/checkpoints.py +432 -0
- aria_code/runtime/crash_report.py +174 -0
- aria_code/runtime/events.py +113 -0
- aria_code/runtime/gateway.py +150 -0
- aria_code/runtime/lsp.py +484 -0
- aria_code/runtime/orchestrator.py +55 -0
- aria_code/runtime/repo_map.py +700 -0
- aria_code/runtime/run_state.py +127 -0
- aria_code/runtime/run_store.py +450 -0
- aria_code/runtime/self_healing.py +422 -0
- aria_code/runtime/subagent.py +547 -0
- aria_code/runtime/task_ledger.py +86 -0
- aria_code/runtime/task_orchestrator.py +90 -0
- aria_code/runtime/tool_executor.py +217 -0
- aria_code/runtime/tool_policy.py +107 -0
- aria_code/runtime/worktrees.py +215 -0
- aria_code/runway_video_client.py +4 -0
- aria_code/safety/__init__.py +23 -0
- aria_code/safety/permissions.py +306 -0
- aria_code/safety/service.py +102 -0
- aria_code/setup_wizard.py +673 -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 +504 -0
- aria_code/tools/data_analysis_tools.py +809 -0
- aria_code/tools/enterprise_finance_tools.py +156 -0
- aria_code/tools/extended_tools.py +240 -0
- aria_code/tools/file_analysis_tools.py +885 -0
- aria_code/tools/image_gen_tools.py +114 -0
- aria_code/tools/local_finance_tools.py +3417 -0
- aria_code/tools/logistics_tools.py +135 -0
- aria_code/tools/macro_tools.py +369 -0
- aria_code/tools/notification_tools.py +249 -0
- aria_code/tools/project_tools.py +525 -0
- aria_code/tools/realty_data_tools.py +659 -0
- aria_code/tools/spreadsheet_tools.py +388 -0
- aria_code/tools/stripe_tools.py +115 -0
- aria_code/ui/__init__.py +105 -0
- aria_code/ui/banner.py +508 -0
- aria_code/ui/completer.py +501 -0
- aria_code/ui/console.py +281 -0
- aria_code/ui/image_render.py +243 -0
- aria_code/ui/input_box.py +488 -0
- aria_code/ui/picker.py +201 -0
- aria_code/ui/render/__init__.py +11 -0
- aria_code/ui/render/finance.py +1705 -0
- aria_code/ui/render/market.py +225 -0
- aria_code/ui/render/output.py +775 -0
- aria_code/ui/render/responsive.py +75 -0
- aria_code/ui/render/team.py +354 -0
- aria_code/ui/robot.py +235 -0
- aria_code/ui/startup_dashboard.py +109 -0
- aria_code/utils/vscode_uri.py +37 -0
- aria_code/video_analysis.py +147 -0
- aria_code/video_editor.py +271 -0
- aria_code/workspace/__init__.py +6 -0
- aria_code/workspace/files.py +193 -0
- aria_code/workspace/verify.py +113 -0
- aria_code/workspace_changes.py +199 -0
- aria_code/workspace_context.py +233 -0
- aria_code/workspace_service.py +196 -0
- aria_code/workspace_tools.py +150 -0
- aria_code-0.52.0.dist-info/METADATA +237 -0
- aria_code-0.52.0.dist-info/RECORD +478 -0
- aria_code-0.52.0.dist-info/WHEEL +5 -0
- aria_code-0.52.0.dist-info/entry_points.txt +3 -0
- aria_code-0.52.0.dist-info/licenses/LICENSE +201 -0
- aria_code-0.52.0.dist-info/licenses/NOTICE +49 -0
- aria_code-0.52.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
"""FileCommandsMixin — Claude Code-style file ops: read/write/edit/ls/search + staged changes.
|
|
2
|
+
|
|
3
|
+
Method bodies use aria_cli module globals (self.context.console, self.context.has_rich, the _tool_* file
|
|
4
|
+
tools, _display_path, pathlib, _get_Syntax(), _get__SYNTAX_THEME(), _get_GLOBAL_CHANGE_STORE()), which
|
|
5
|
+
are bound at import time by aria_cli._rebind_mixin_globals(FileCommandsMixin).
|
|
6
|
+
Note cmd_read uses `pathlib.Path` (a bound global), not a bare `Path`, so no
|
|
7
|
+
local import is required.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
import json
|
|
14
|
+
import asyncio
|
|
15
|
+
import datetime
|
|
16
|
+
import time
|
|
17
|
+
import shlex
|
|
18
|
+
import sys
|
|
19
|
+
import os
|
|
20
|
+
from typing import Dict, Any, Optional
|
|
21
|
+
|
|
22
|
+
# display_path lives in ui.render.output; aria_cli only re-exports it under a
|
|
23
|
+
# private alias, so going through aria_cli was a pointless second hop.
|
|
24
|
+
from aria_code.ui.render.output import display_path as _display_path
|
|
25
|
+
def _tool_read_file(*args, **kwargs):
|
|
26
|
+
from aria_cli import _tool_read_file as fn
|
|
27
|
+
return fn(*args, **kwargs)
|
|
28
|
+
def _get_GLOBAL_CHANGE_STORE():
|
|
29
|
+
from aria_cli import GLOBAL_CHANGE_STORE as val
|
|
30
|
+
return val
|
|
31
|
+
def _get_Syntax():
|
|
32
|
+
from ._ui import Syntax as val
|
|
33
|
+
return val
|
|
34
|
+
def _get__SYNTAX_THEME():
|
|
35
|
+
from aria_cli import _SYNTAX_THEME as val
|
|
36
|
+
return val
|
|
37
|
+
def _tool_list_files(*args, **kwargs):
|
|
38
|
+
from aria_cli import _tool_list_files as fn
|
|
39
|
+
return fn(*args, **kwargs)
|
|
40
|
+
import pathlib
|
|
41
|
+
def _tool_write_file(*args, **kwargs):
|
|
42
|
+
from aria_cli import _tool_write_file as fn
|
|
43
|
+
return fn(*args, **kwargs)
|
|
44
|
+
def _tool_search_code(*args, **kwargs):
|
|
45
|
+
from aria_cli import _tool_search_code as fn
|
|
46
|
+
return fn(*args, **kwargs)
|
|
47
|
+
|
|
48
|
+
import json
|
|
49
|
+
import asyncio
|
|
50
|
+
import datetime
|
|
51
|
+
import time
|
|
52
|
+
import shlex
|
|
53
|
+
import sys
|
|
54
|
+
import os
|
|
55
|
+
from typing import Dict, Any, Optional
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class FileCommandsMixin:
|
|
59
|
+
"""Mixin: file read/write/edit/list/search and staged-change commands."""
|
|
60
|
+
|
|
61
|
+
def cmd_read(self, args: str):
|
|
62
|
+
"""Read a file: /read <path> [offset] [limit]"""
|
|
63
|
+
parts = args.split()
|
|
64
|
+
if not parts:
|
|
65
|
+
self.context.console.print("[dim]Usage: /read <file_path> [start_line] [num_lines][/dim]" if self.context.has_rich
|
|
66
|
+
else "Usage: /read <path> [offset] [limit]")
|
|
67
|
+
return
|
|
68
|
+
params = {"path": parts[0]}
|
|
69
|
+
if len(parts) > 1:
|
|
70
|
+
try:
|
|
71
|
+
params["offset"] = int(parts[1])
|
|
72
|
+
except ValueError:
|
|
73
|
+
pass
|
|
74
|
+
if len(parts) > 2:
|
|
75
|
+
try:
|
|
76
|
+
params["limit"] = int(parts[2])
|
|
77
|
+
except ValueError:
|
|
78
|
+
pass
|
|
79
|
+
result = _tool_read_file(params)
|
|
80
|
+
if result["success"]:
|
|
81
|
+
content = result["data"]["content"]
|
|
82
|
+
if self.context.has_rich:
|
|
83
|
+
# Use _get_Syntax() for code files
|
|
84
|
+
path = result["data"]["path"]
|
|
85
|
+
ext = pathlib.Path(path).suffix
|
|
86
|
+
lang_map = {".py": "python", ".js": "javascript", ".ts": "typescript",
|
|
87
|
+
".tsx": "typescript", ".jsx": "javascript", ".json": "json",
|
|
88
|
+
".yaml": "yaml", ".yml": "yaml", ".md": "markdown",
|
|
89
|
+
".swift": "swift", ".html": "html", ".css": "css",
|
|
90
|
+
".sh": "bash", ".sql": "sql", ".rs": "rust", ".go": "go"}
|
|
91
|
+
lang = lang_map.get(ext, "text")
|
|
92
|
+
# Strip line numbers we added, use _get_Syntax()'s own
|
|
93
|
+
raw = "\n".join(line.split("│ ", 1)[1] if "│ " in line else line
|
|
94
|
+
for line in content.split("\n"))
|
|
95
|
+
self.context.console.print(f"\n[dim]{_display_path(path)} ({result['data']['lines']} lines)[/dim]")
|
|
96
|
+
self.context.console.print(_get_Syntax()(raw, lang, line_numbers=True, theme=_get__SYNTAX_THEME()))
|
|
97
|
+
else:
|
|
98
|
+
print(f"\n{_display_path(result['data']['path'])} ({result['data']['lines']} lines)")
|
|
99
|
+
print(content)
|
|
100
|
+
else:
|
|
101
|
+
self.context.console.print(f"[red]{result['error']}[/red]" if self.context.has_rich else result["error"])
|
|
102
|
+
|
|
103
|
+
def cmd_write(self, args: str):
|
|
104
|
+
"""Write a file: /write [--stage] <path> then paste content, end with EOF line."""
|
|
105
|
+
parts = args.strip().split()
|
|
106
|
+
stage_only = False
|
|
107
|
+
if "--stage" in parts:
|
|
108
|
+
stage_only = True
|
|
109
|
+
parts = [p for p in parts if p != "--stage"]
|
|
110
|
+
path = " ".join(parts).strip()
|
|
111
|
+
if not path:
|
|
112
|
+
self.context.console.print("[dim]Usage: /write [--stage] <file_path>[/dim]" if self.context.has_rich
|
|
113
|
+
else "Usage: /write [--stage] <path>")
|
|
114
|
+
self.context.console.print("[dim]Then paste content, end with a line containing only 'EOF'[/dim]" if self.context.has_rich
|
|
115
|
+
else "Paste content, end with EOF")
|
|
116
|
+
return
|
|
117
|
+
if self.context.has_rich:
|
|
118
|
+
mode = "Staging" if stage_only else "Writing"
|
|
119
|
+
self.context.console.print(f"[dim]{mode} {_display_path(path)} — paste content, end with 'EOF' on a new line:[/dim]")
|
|
120
|
+
else:
|
|
121
|
+
print(f"{'Staging' if stage_only else 'Writing'} {_display_path(path)} — paste content, end with EOF:")
|
|
122
|
+
lines = []
|
|
123
|
+
try:
|
|
124
|
+
while True:
|
|
125
|
+
line = input()
|
|
126
|
+
if line.strip() == "EOF":
|
|
127
|
+
break
|
|
128
|
+
lines.append(line)
|
|
129
|
+
except (EOFError, KeyboardInterrupt):
|
|
130
|
+
self.context.console.print("[dim]Cancelled[/dim]" if self.context.has_rich else "Cancelled")
|
|
131
|
+
return
|
|
132
|
+
content = "\n".join(lines) + "\n"
|
|
133
|
+
result = _tool_write_file({"path": path, "content": content, "stage_only": stage_only})
|
|
134
|
+
if not result["success"]:
|
|
135
|
+
self.context.console.print(f"[red]{result['error']}[/red]" if self.context.has_rich else result["error"])
|
|
136
|
+
elif stage_only:
|
|
137
|
+
change_id = result.get("data", {}).get("change_id", "")
|
|
138
|
+
msg = f"Staged change {change_id}. Review with /changes, apply with /apply-change {change_id}."
|
|
139
|
+
self.context.console.print(f"[dim]{msg}[/dim]" if self.context.has_rich else msg)
|
|
140
|
+
|
|
141
|
+
async def cmd_edit(self, args: str):
|
|
142
|
+
"""Edit a file interactively: /edit <path> — AI edits based on instruction."""
|
|
143
|
+
parts = args.strip().split(maxsplit=1)
|
|
144
|
+
if not parts:
|
|
145
|
+
self.context.console.print("[dim]Usage: /edit <file_path> <instruction>[/dim]" if self.context.has_rich
|
|
146
|
+
else "Usage: /edit <path> <instruction>")
|
|
147
|
+
return
|
|
148
|
+
path = parts[0]
|
|
149
|
+
instruction = parts[1] if len(parts) > 1 else None
|
|
150
|
+
|
|
151
|
+
# Read the file first
|
|
152
|
+
read_result = _tool_read_file({"path": path})
|
|
153
|
+
if not read_result["success"]:
|
|
154
|
+
self.context.console.print(f"[red]{read_result['error']}[/red]" if self.context.has_rich else read_result["error"])
|
|
155
|
+
return
|
|
156
|
+
|
|
157
|
+
if not instruction:
|
|
158
|
+
# Show file and ask for instruction
|
|
159
|
+
if self.context.has_rich:
|
|
160
|
+
self.context.console.print(f"[dim]{_display_path(read_result['data']['path'])} ({read_result['data']['lines']} lines)[/dim]")
|
|
161
|
+
try:
|
|
162
|
+
instruction = (self.context.console.input("[bold]>[/bold] What to change: ") if self.context.has_rich
|
|
163
|
+
else input("What to change: ")).strip()
|
|
164
|
+
except (EOFError, KeyboardInterrupt):
|
|
165
|
+
return
|
|
166
|
+
if not instruction:
|
|
167
|
+
return
|
|
168
|
+
|
|
169
|
+
# Send to AI with file context and ask for edit
|
|
170
|
+
file_content = read_result["data"]["content"]
|
|
171
|
+
prompt = (
|
|
172
|
+
f"I need you to edit the file `{path}`.\n\n"
|
|
173
|
+
f"Current file content:\n```\n{file_content[:8000]}\n```\n\n"
|
|
174
|
+
f"Instruction: {instruction}\n\n"
|
|
175
|
+
f"Use the edit_file tool to make the changes. Remember to use the exact old_string from the file."
|
|
176
|
+
)
|
|
177
|
+
await self.terminal.send_message(prompt)
|
|
178
|
+
|
|
179
|
+
def cmd_ls(self, args: str):
|
|
180
|
+
"""List files: /ls [path] [pattern]"""
|
|
181
|
+
parts = args.split()
|
|
182
|
+
path = parts[0] if parts else "."
|
|
183
|
+
pattern = parts[1] if len(parts) > 1 else "*"
|
|
184
|
+
result = _tool_list_files({"path": path, "pattern": pattern})
|
|
185
|
+
if result["success"]:
|
|
186
|
+
items = result["data"]["items"]
|
|
187
|
+
if self.context.has_rich:
|
|
188
|
+
self.context.console.print(f"\n[dim]{_display_path(result['data']['path'], fallback='directory')} ({result['data']['count']} items)[/dim]\n")
|
|
189
|
+
for item in items:
|
|
190
|
+
if item["type"] == "dir":
|
|
191
|
+
self.context.console.print(f" [bold]{item['name']}/[/bold]")
|
|
192
|
+
else:
|
|
193
|
+
size = item["size"]
|
|
194
|
+
size_str = f"{size:,}" if size < 10000 else f"{size/1024:.1f}K"
|
|
195
|
+
self.context.console.print(f" {item['name']} [dim]{size_str}[/dim]")
|
|
196
|
+
else:
|
|
197
|
+
for item in items:
|
|
198
|
+
suffix = "/" if item["type"] == "dir" else ""
|
|
199
|
+
print(f" {item['name']}{suffix}")
|
|
200
|
+
else:
|
|
201
|
+
self.context.console.print(f"[red]{result['error']}[/red]" if self.context.has_rich else result["error"])
|
|
202
|
+
|
|
203
|
+
def cmd_search(self, args: str):
|
|
204
|
+
"""Search code: /search <pattern> [path] [glob]
|
|
205
|
+
|
|
206
|
+
If the second word doesn't look like a file path (no / or .), the whole
|
|
207
|
+
args string is treated as the pattern and CWD is searched.
|
|
208
|
+
"""
|
|
209
|
+
args = args.strip().strip('"\'')
|
|
210
|
+
parts = args.split()
|
|
211
|
+
if not parts:
|
|
212
|
+
self.context.console.print("[dim]Usage: /search <pattern> [path] [file_glob][/dim]" if self.context.has_rich
|
|
213
|
+
else "Usage: /search <pattern> [path] [glob]")
|
|
214
|
+
return
|
|
215
|
+
|
|
216
|
+
# Determine if second token looks like a file path or directory
|
|
217
|
+
def _looks_like_path(s: str) -> bool:
|
|
218
|
+
return bool(s) and any(c in s for c in "/\\.")
|
|
219
|
+
|
|
220
|
+
_QUOTES = '"\'`'
|
|
221
|
+
if len(parts) == 1:
|
|
222
|
+
# Single token: use as pattern, search CWD
|
|
223
|
+
params = {"pattern": parts[0].strip(_QUOTES)}
|
|
224
|
+
elif len(parts) >= 2 and _looks_like_path(parts[1]):
|
|
225
|
+
# Second token is a path
|
|
226
|
+
params = {"pattern": parts[0].strip(_QUOTES)}
|
|
227
|
+
params["path"] = parts[1]
|
|
228
|
+
if len(parts) > 2:
|
|
229
|
+
params["glob"] = parts[2]
|
|
230
|
+
else:
|
|
231
|
+
# Multi-word pattern with no path (e.g. /search def cmd_model)
|
|
232
|
+
# Find where the path arg starts (if any)
|
|
233
|
+
path_idx = None
|
|
234
|
+
for i, p in enumerate(parts[1:], 1):
|
|
235
|
+
if _looks_like_path(p):
|
|
236
|
+
path_idx = i
|
|
237
|
+
break
|
|
238
|
+
if path_idx:
|
|
239
|
+
params = {"pattern": " ".join(parts[:path_idx]).strip(_QUOTES)}
|
|
240
|
+
params["path"] = parts[path_idx]
|
|
241
|
+
if path_idx + 1 < len(parts):
|
|
242
|
+
params["glob"] = parts[path_idx + 1]
|
|
243
|
+
else:
|
|
244
|
+
# Whole args is the pattern
|
|
245
|
+
params = {"pattern": args.strip(_QUOTES)}
|
|
246
|
+
result = _tool_search_code(params)
|
|
247
|
+
if result["success"]:
|
|
248
|
+
matches = result["data"]["matches"]
|
|
249
|
+
if self.context.has_rich:
|
|
250
|
+
self.context.console.print(f"\n[dim]{result['data']['count']} matches for '{result['data']['pattern']}'[/dim]\n")
|
|
251
|
+
for m in matches[:30]:
|
|
252
|
+
self.context.console.print(f" [dim]{m['file']}:{m['line']}[/dim] {m['content'][:100]}")
|
|
253
|
+
else:
|
|
254
|
+
print(f"\n{result['data']['count']} matches:")
|
|
255
|
+
for m in matches[:30]:
|
|
256
|
+
print(f" {m['file']}:{m['line']} {m['content'][:100]}")
|
|
257
|
+
else:
|
|
258
|
+
self.context.console.print(f"[red]{result['error']}[/red]" if self.context.has_rich else result["error"])
|
|
259
|
+
|
|
260
|
+
def cmd_changes(self, args: str):
|
|
261
|
+
"""List staged file changes."""
|
|
262
|
+
include_closed = "--all" in args.split()
|
|
263
|
+
changes = _get_GLOBAL_CHANGE_STORE().list(include_closed=include_closed)
|
|
264
|
+
if not changes:
|
|
265
|
+
msg = "No staged changes."
|
|
266
|
+
self.context.console.print(f"[dim]{msg}[/dim]" if self.context.has_rich else msg)
|
|
267
|
+
return
|
|
268
|
+
if self.context.has_rich:
|
|
269
|
+
self.context.console.print()
|
|
270
|
+
for change in changes:
|
|
271
|
+
added = sum(1 for line in change.diff.splitlines() if line.startswith("+") and not line.startswith("+++"))
|
|
272
|
+
removed = sum(1 for line in change.diff.splitlines() if line.startswith("-") and not line.startswith("---"))
|
|
273
|
+
status = "applied" if change.applied else "rejected" if change.rejected else "pending"
|
|
274
|
+
color = "green" if change.applied else "red" if change.rejected else "yellow"
|
|
275
|
+
self.context.console.print(f"[{color}]{change.change_id}[/{color}] [bold]{change.path}[/bold] [dim]{status} +{added}/-{removed}[/dim]")
|
|
276
|
+
preview = "\n".join(change.diff.splitlines()[:18])
|
|
277
|
+
if preview:
|
|
278
|
+
self.context.console.print(_get_Syntax()(preview, "diff", theme=_get__SYNTAX_THEME()))
|
|
279
|
+
self.context.console.print()
|
|
280
|
+
else:
|
|
281
|
+
for change in changes:
|
|
282
|
+
status = "applied" if change.applied else "rejected" if change.rejected else "pending"
|
|
283
|
+
print(f"{change.change_id} {status} {change.path}")
|
|
284
|
+
print("\n".join(change.diff.splitlines()[:18]))
|
|
285
|
+
|
|
286
|
+
def cmd_apply_change(self, args: str):
|
|
287
|
+
"""Apply a staged file change."""
|
|
288
|
+
change_id = args.strip()
|
|
289
|
+
if not change_id:
|
|
290
|
+
self.context.console.print("[dim]Usage: /apply-change <change_id>[/dim]" if self.context.has_rich
|
|
291
|
+
else "Usage: /apply-change <change_id>")
|
|
292
|
+
return
|
|
293
|
+
try:
|
|
294
|
+
change = _get_GLOBAL_CHANGE_STORE().apply(change_id)
|
|
295
|
+
msg = f"Applied change {change.change_id}: {change.path}"
|
|
296
|
+
self.context.console.print(f"[green]{msg}[/green]" if self.context.has_rich else msg)
|
|
297
|
+
except Exception as exc:
|
|
298
|
+
self.context.console.print(f"[red]{exc}[/red]" if self.context.has_rich else str(exc))
|
|
299
|
+
|
|
300
|
+
def cmd_reject_change(self, args: str):
|
|
301
|
+
"""Reject a staged file change."""
|
|
302
|
+
change_id = args.strip()
|
|
303
|
+
if not change_id:
|
|
304
|
+
self.context.console.print("[dim]Usage: /reject-change <change_id>[/dim]" if self.context.has_rich
|
|
305
|
+
else "Usage: /reject-change <change_id>")
|
|
306
|
+
return
|
|
307
|
+
try:
|
|
308
|
+
change = _get_GLOBAL_CHANGE_STORE().reject(change_id)
|
|
309
|
+
msg = f"Rejected change {change.change_id}: {change.path}"
|
|
310
|
+
self.context.console.print(f"[dim]{msg}[/dim]" if self.context.has_rich else msg)
|
|
311
|
+
except Exception as exc:
|
|
312
|
+
self.context.console.print(f"[red]{exc}[/red]" if self.context.has_rich else str(exc))
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""CLI discovery for supported financial-market services."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import asyncio
|
|
8
|
+
import datetime
|
|
9
|
+
import time
|
|
10
|
+
import shlex
|
|
11
|
+
from typing import Dict, Any, Optional
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
import json
|
|
15
|
+
import asyncio
|
|
16
|
+
import datetime
|
|
17
|
+
import time
|
|
18
|
+
import shlex
|
|
19
|
+
import sys
|
|
20
|
+
import os
|
|
21
|
+
from typing import Dict, Any, Optional
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
import json
|
|
25
|
+
import asyncio
|
|
26
|
+
import datetime
|
|
27
|
+
import time
|
|
28
|
+
import shlex
|
|
29
|
+
import sys
|
|
30
|
+
import os
|
|
31
|
+
from typing import Dict, Any, Optional
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class FinanceServiceCommandsMixin:
|
|
35
|
+
def cmd_markets(self, args: str):
|
|
36
|
+
"""Show the applicable finance-service contract for a market/query."""
|
|
37
|
+
from apps.cli.finance_service_catalog import market_service_summary
|
|
38
|
+
|
|
39
|
+
summary = market_service_summary(args)
|
|
40
|
+
selected = summary["selected"]
|
|
41
|
+
if self.context.has_rich:
|
|
42
|
+
from rich.table import Table
|
|
43
|
+
|
|
44
|
+
self.context.console.print()
|
|
45
|
+
title = "金融市场服务" if not selected else f"金融市场服务 · {selected}"
|
|
46
|
+
table = Table(title=title, show_header=True, header_style="bold cyan")
|
|
47
|
+
table.add_column("市场", style="bold", no_wrap=True)
|
|
48
|
+
table.add_column("已接入服务")
|
|
49
|
+
table.add_column("分析框架")
|
|
50
|
+
for item in summary["markets"]:
|
|
51
|
+
prediction = item["prediction"]
|
|
52
|
+
services = " · ".join(item["services"])
|
|
53
|
+
if prediction:
|
|
54
|
+
services += f"\n预测:{prediction}"
|
|
55
|
+
table.add_row(item["label"], services, " · ".join(item["analysis"]))
|
|
56
|
+
self.context.console.print(table)
|
|
57
|
+
self.context.console.print("[dim]说明:实时结论必须先取得可用数据;数据缺失、过期或覆盖不足时将明确降级,不生成伪精确预测。[/dim]")
|
|
58
|
+
else:
|
|
59
|
+
for item in summary["markets"]:
|
|
60
|
+
print(f"{item['label']}: {', '.join(item['services'])}")
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""FxCommodityCommandsMixin — /crypto, /forex, /commodity.
|
|
2
|
+
|
|
3
|
+
Rendering goes through self.context; the market-data client comes from
|
|
4
|
+
apps/cli/_optional.py. The note that used to be here described binding by
|
|
5
|
+
aria_cli._rebind_mixin_globals, which 40f23c8 stopped calling — this module no
|
|
6
|
+
longer reaches into aria_cli at all.
|
|
7
|
+
|
|
8
|
+
self._run_in_executor / self._run_parallel / self._fetch_and_display_finance
|
|
9
|
+
are still resolved through the SlashCommands MRO at call time, not as module
|
|
10
|
+
globals.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
import asyncio
|
|
18
|
+
import datetime
|
|
19
|
+
import time
|
|
20
|
+
import shlex
|
|
21
|
+
from typing import Dict, Any, Optional
|
|
22
|
+
|
|
23
|
+
def _get__HAS_MDC():
|
|
24
|
+
from .._optional import HAS_MDC as val
|
|
25
|
+
return val
|
|
26
|
+
def _get_mdc(*args, **kwargs):
|
|
27
|
+
from .._optional import get_mdc as fn
|
|
28
|
+
return fn(*args, **kwargs)
|
|
29
|
+
|
|
30
|
+
import json
|
|
31
|
+
import asyncio
|
|
32
|
+
import datetime
|
|
33
|
+
import time
|
|
34
|
+
import shlex
|
|
35
|
+
import sys
|
|
36
|
+
import os
|
|
37
|
+
from typing import Dict, Any, Optional
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
import json
|
|
41
|
+
import asyncio
|
|
42
|
+
import datetime
|
|
43
|
+
import time
|
|
44
|
+
import shlex
|
|
45
|
+
import sys
|
|
46
|
+
import os
|
|
47
|
+
from typing import Dict, Any, Optional
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class FxCommodityCommandsMixin:
|
|
51
|
+
"""Mixin: crypto, forex, and commodity quote commands."""
|
|
52
|
+
|
|
53
|
+
async def cmd_crypto(self, args: str):
|
|
54
|
+
"""Crypto data: /crypto BTC ETH · /crypto account (read-only balance)"""
|
|
55
|
+
# ── Read-only account view: /crypto account [exchange] ───────────────
|
|
56
|
+
if args.strip().lower().split()[:1] == ["account"]:
|
|
57
|
+
_parts = args.strip().split()
|
|
58
|
+
_exch = _parts[1].lower() if len(_parts) > 1 else "binance"
|
|
59
|
+
if not _get__HAS_MDC():
|
|
60
|
+
self.context.console.print("[yellow]market_data_client 不可用[/yellow]" if self.context.has_rich else "unavailable")
|
|
61
|
+
return
|
|
62
|
+
acct = await self._run_in_executor(
|
|
63
|
+
lambda: _get_mdc().crypto_account(_exch)
|
|
64
|
+
)
|
|
65
|
+
if not acct.get("success"):
|
|
66
|
+
_err = acct.get("error", "")
|
|
67
|
+
if _err == "no_api_key":
|
|
68
|
+
msg = (f"未配置 {_exch.upper()} 只读 API key。\n"
|
|
69
|
+
f" 设置环境变量:{_exch.upper()}_API_KEY 和 {_exch.upper()}_SECRET\n"
|
|
70
|
+
f" [dim]建议用「只读」权限的 key — Aria 永不下单[/dim]")
|
|
71
|
+
else:
|
|
72
|
+
msg = f"读取失败:{_err}"
|
|
73
|
+
self.context.console.print(f" [yellow]{msg}[/yellow]" if self.context.has_rich else msg)
|
|
74
|
+
return
|
|
75
|
+
holdings = acct.get("holdings", [])
|
|
76
|
+
if self.context.has_rich:
|
|
77
|
+
self.context.console.print(f"\n [bold]{_exch.capitalize()} 账户[/bold] "
|
|
78
|
+
f"[dim]只读 · {len(holdings)} 个资产[/dim]")
|
|
79
|
+
for h in holdings[:15]:
|
|
80
|
+
self.context.console.print(f" {h['asset']:<8} [bold]{h['amount']:,.6g}[/bold]"
|
|
81
|
+
f" [dim]可用 {h['free']:,.6g}[/dim]")
|
|
82
|
+
else:
|
|
83
|
+
print(f"{_exch} account ({len(holdings)} assets):")
|
|
84
|
+
for h in holdings[:15]:
|
|
85
|
+
print(f" {h['asset']:<8} {h['amount']:.6g}")
|
|
86
|
+
return
|
|
87
|
+
|
|
88
|
+
symbols = args.upper().split() if args else ["BTC"]
|
|
89
|
+
if self.context.has_rich:
|
|
90
|
+
self.context.console.print()
|
|
91
|
+
for sym in symbols:
|
|
92
|
+
# yfinance crypto symbol: BTC → BTC-USD, ETH → ETH-USD
|
|
93
|
+
yf_sym = sym + "-USD" if not sym.endswith("-USD") and "/" not in sym else sym
|
|
94
|
+
await self._fetch_and_display_finance(
|
|
95
|
+
"get_crypto_data", {"symbol": sym},
|
|
96
|
+
label=sym, mdc_fallback_symbol=yf_sym
|
|
97
|
+
)
|
|
98
|
+
if self.context.has_rich:
|
|
99
|
+
self.context.console.print()
|
|
100
|
+
|
|
101
|
+
async def cmd_forex(self, args: str):
|
|
102
|
+
"""Forex rates: /forex EUR/USD USD/CNY (with yfinance fallback)"""
|
|
103
|
+
pairs = args.upper().split() if args else ["EUR/USD"]
|
|
104
|
+
if self.context.has_rich:
|
|
105
|
+
self.context.console.print()
|
|
106
|
+
for pair in pairs:
|
|
107
|
+
# yfinance forex symbol: EUR/USD → EURUSD=X
|
|
108
|
+
yf_pair = pair.replace("/", "") + "=X"
|
|
109
|
+
await self._fetch_and_display_finance(
|
|
110
|
+
"get_forex_data", {"pair": pair},
|
|
111
|
+
label=pair, mdc_fallback_symbol=yf_pair
|
|
112
|
+
)
|
|
113
|
+
if self.context.has_rich:
|
|
114
|
+
self.context.console.print()
|
|
115
|
+
|
|
116
|
+
async def cmd_commodity(self, args: str):
|
|
117
|
+
"""Commodities: /commodity gold oil silver (parallel fetch)"""
|
|
118
|
+
items = args.lower().split() if args else ["gold"]
|
|
119
|
+
await self._run_parallel(
|
|
120
|
+
"get_commodities_data",
|
|
121
|
+
[{"commodity": c} for c in items],
|
|
122
|
+
label_fn=lambda p: f"commodity {p['commodity']}",
|
|
123
|
+
)
|