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,712 @@
|
|
|
1
|
+
"""Repo map — what is defined where, ranked by what the rest of the repo needs.
|
|
2
|
+
|
|
3
|
+
Why this exists
|
|
4
|
+
---------------
|
|
5
|
+
Before this module, Aria's only way to find anything in an unfamiliar repository
|
|
6
|
+
was to guess a string and grep for it. That works in a 20-file project and
|
|
7
|
+
falls apart in an enterprise one: the model burns four or five rounds probing
|
|
8
|
+
names that do not exist, and a small local model — the configuration this
|
|
9
|
+
project is actually built around — never recovers, because it has no prior about
|
|
10
|
+
what this codebase calls things.
|
|
11
|
+
|
|
12
|
+
A file tree does not fix that; it says where files are, not what is in them.
|
|
13
|
+
What a model needs on the first round is a *symbol* map: the classes and
|
|
14
|
+
functions this repository defines, which file each lives in, and — critically —
|
|
15
|
+
which of them the rest of the repository actually depends on.
|
|
16
|
+
|
|
17
|
+
Ranking is the whole difference
|
|
18
|
+
-------------------------------
|
|
19
|
+
Every real repo has far more symbols than fit in a context window, so an
|
|
20
|
+
unranked dump is just a differently-shaped grep. This module ranks a file by
|
|
21
|
+
how much the *rest of the codebase* reaches into it: for each symbol a file
|
|
22
|
+
defines, how many other files mention that symbol. A widely-referenced module
|
|
23
|
+
scores high; a leaf script nothing imports scores near zero. That ordering is
|
|
24
|
+
what makes a budgeted map useful — the first 8 KB describe the parts of the
|
|
25
|
+
system a change is most likely to touch.
|
|
26
|
+
|
|
27
|
+
Three corrections keep that number honest, each for an observed way the naive
|
|
28
|
+
count lies:
|
|
29
|
+
|
|
30
|
+
- Names under four characters are ignored. ``id``, ``get``, ``run``, ``fn``
|
|
31
|
+
collide with ordinary vocabulary and would rank whichever file happened to
|
|
32
|
+
define them above everything else.
|
|
33
|
+
- A name defined in more than a handful of files contributes nothing. A
|
|
34
|
+
``main`` or ``setup`` defined in thirty places tells you nothing about which
|
|
35
|
+
of the thirty matters.
|
|
36
|
+
- One symbol's contribution is capped, so a single popular helper cannot
|
|
37
|
+
outvote a file that is broadly depended on.
|
|
38
|
+
|
|
39
|
+
No new dependencies
|
|
40
|
+
-------------------
|
|
41
|
+
Python is parsed with the stdlib ``ast`` — exact, including nesting. Every
|
|
42
|
+
other language is matched by declaration regex. This is deliberately less
|
|
43
|
+
precise than tree-sitter, and the trade is worth it: an approximate map that
|
|
44
|
+
installs everywhere beats an exact one gated behind a native build, because the
|
|
45
|
+
map's job is to point the model at the right file, and ``read_file`` is what
|
|
46
|
+
establishes the truth once it gets there.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
from __future__ import annotations
|
|
50
|
+
|
|
51
|
+
import ast
|
|
52
|
+
import os
|
|
53
|
+
import re
|
|
54
|
+
import time
|
|
55
|
+
from dataclasses import dataclass, field
|
|
56
|
+
from pathlib import Path
|
|
57
|
+
from typing import Dict, Iterable, List, Optional, Sequence, Set, Tuple
|
|
58
|
+
|
|
59
|
+
from . import native_index
|
|
60
|
+
|
|
61
|
+
__all__ = [
|
|
62
|
+
"REPO_MAP_SCHEMAS",
|
|
63
|
+
"REPO_MAP_TOOLS",
|
|
64
|
+
"RepoMap",
|
|
65
|
+
"Symbol",
|
|
66
|
+
"tool_find_symbol",
|
|
67
|
+
"tool_repo_map",
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# Directories that are never the user's own code. Skipped by name at any
|
|
72
|
+
# depth: a single unpruned ``.venv`` or ``node_modules`` outweighs the entire
|
|
73
|
+
# repository and would dominate both the scan time and the ranking.
|
|
74
|
+
SKIP_DIRS = frozenset({
|
|
75
|
+
".git", ".hg", ".svn", "__pycache__", "node_modules", ".venv", "venv",
|
|
76
|
+
"env", ".env", "site-packages", "dist", "build", "target", ".next",
|
|
77
|
+
".nuxt", ".cache", ".mypy_cache", ".pytest_cache", ".ruff_cache",
|
|
78
|
+
".tox", ".gradle", ".idea", ".vscode", "vendor", "coverage",
|
|
79
|
+
"htmlcov", ".terraform", "Pods", "DerivedData", ".dart_tool",
|
|
80
|
+
"bower_components", "jspm_packages", ".serverless", "out",
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
# Extension → language label. Membership here is also what decides whether a
|
|
84
|
+
# file is scanned at all.
|
|
85
|
+
LANGUAGES: Dict[str, str] = {
|
|
86
|
+
".py": "python", ".pyi": "python",
|
|
87
|
+
".js": "javascript", ".jsx": "javascript", ".mjs": "javascript", ".cjs": "javascript",
|
|
88
|
+
".ts": "typescript", ".tsx": "typescript",
|
|
89
|
+
".go": "go",
|
|
90
|
+
".rs": "rust",
|
|
91
|
+
".java": "java",
|
|
92
|
+
".kt": "kotlin", ".kts": "kotlin",
|
|
93
|
+
".swift": "swift",
|
|
94
|
+
".rb": "ruby",
|
|
95
|
+
".php": "php",
|
|
96
|
+
".cs": "csharp",
|
|
97
|
+
".c": "c", ".h": "c",
|
|
98
|
+
".cc": "cpp", ".cpp": "cpp", ".cxx": "cpp", ".hpp": "cpp",
|
|
99
|
+
".scala": "scala",
|
|
100
|
+
".sh": "shell", ".bash": "shell",
|
|
101
|
+
".sql": "sql",
|
|
102
|
+
".lua": "lua",
|
|
103
|
+
".dart": "dart",
|
|
104
|
+
".ex": "elixir", ".exs": "elixir",
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
# Declaration patterns per language. Each yields (kind, name). These match
|
|
108
|
+
# declarations, not uses — anchored at line start (modulo indentation and
|
|
109
|
+
# modifiers) so a call like ``foo(function() {})`` is not read as a definition.
|
|
110
|
+
_DECL_PATTERNS: Dict[str, Sequence[Tuple[str, re.Pattern]]] = {
|
|
111
|
+
"javascript": (
|
|
112
|
+
("class", re.compile(r"^\s*(?:export\s+)?(?:default\s+)?class\s+([A-Za-z_$][\w$]*)")),
|
|
113
|
+
("function", re.compile(r"^\s*(?:export\s+)?(?:default\s+)?(?:async\s+)?function\s*\*?\s*([A-Za-z_$][\w$]*)")),
|
|
114
|
+
("function", re.compile(r"^\s*(?:export\s+)?(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:async\s*)?(?:\([^)]*\)|[A-Za-z_$][\w$]*)\s*=>")),
|
|
115
|
+
),
|
|
116
|
+
"go": (
|
|
117
|
+
("func", re.compile(r"^func\s+(?:\([^)]*\)\s*)?([A-Za-z_][\w]*)")),
|
|
118
|
+
("type", re.compile(r"^type\s+([A-Za-z_][\w]*)")),
|
|
119
|
+
),
|
|
120
|
+
"rust": (
|
|
121
|
+
("fn", re.compile(r"^\s*(?:pub(?:\([^)]*\))?\s+)?(?:async\s+)?fn\s+([A-Za-z_][\w]*)")),
|
|
122
|
+
("struct", re.compile(r"^\s*(?:pub(?:\([^)]*\))?\s+)?struct\s+([A-Za-z_][\w]*)")),
|
|
123
|
+
("enum", re.compile(r"^\s*(?:pub(?:\([^)]*\))?\s+)?enum\s+([A-Za-z_][\w]*)")),
|
|
124
|
+
("trait", re.compile(r"^\s*(?:pub(?:\([^)]*\))?\s+)?trait\s+([A-Za-z_][\w]*)")),
|
|
125
|
+
("impl", re.compile(r"^\s*impl(?:<[^>]*>)?\s+(?:[\w:<>, ]+\s+for\s+)?([A-Za-z_][\w]*)")),
|
|
126
|
+
),
|
|
127
|
+
"java": (
|
|
128
|
+
("class", re.compile(r"^\s*(?:public|private|protected|abstract|final|static|\s)*class\s+([A-Za-z_][\w]*)")),
|
|
129
|
+
("interface", re.compile(r"^\s*(?:public|private|protected|abstract|\s)*interface\s+([A-Za-z_][\w]*)")),
|
|
130
|
+
("enum", re.compile(r"^\s*(?:public|private|protected|\s)*enum\s+([A-Za-z_][\w]*)")),
|
|
131
|
+
),
|
|
132
|
+
"ruby": (
|
|
133
|
+
("class", re.compile(r"^\s*class\s+([A-Za-z_][\w]*)")),
|
|
134
|
+
("module", re.compile(r"^\s*module\s+([A-Za-z_][\w]*)")),
|
|
135
|
+
("def", re.compile(r"^\s*def\s+(?:self\.)?([A-Za-z_][\w]*[?!=]?)")),
|
|
136
|
+
),
|
|
137
|
+
"php": (
|
|
138
|
+
("class", re.compile(r"^\s*(?:abstract\s+|final\s+)?class\s+([A-Za-z_][\w]*)")),
|
|
139
|
+
("function", re.compile(r"^\s*(?:public\s+|private\s+|protected\s+|static\s+)*function\s+([A-Za-z_][\w]*)")),
|
|
140
|
+
),
|
|
141
|
+
"csharp": (
|
|
142
|
+
("class", re.compile(r"^\s*(?:public|private|protected|internal|abstract|sealed|static|partial|\s)*class\s+([A-Za-z_][\w]*)")),
|
|
143
|
+
("interface", re.compile(r"^\s*(?:public|private|protected|internal|\s)*interface\s+([A-Za-z_][\w]*)")),
|
|
144
|
+
("record", re.compile(r"^\s*(?:public|private|protected|internal|\s)*record\s+([A-Za-z_][\w]*)")),
|
|
145
|
+
),
|
|
146
|
+
"swift": (
|
|
147
|
+
("class", re.compile(r"^\s*(?:public\s+|private\s+|internal\s+|open\s+|final\s+)*class\s+([A-Za-z_][\w]*)")),
|
|
148
|
+
("struct", re.compile(r"^\s*(?:public\s+|private\s+|internal\s+)?struct\s+([A-Za-z_][\w]*)")),
|
|
149
|
+
("protocol", re.compile(r"^\s*(?:public\s+|private\s+|internal\s+)?protocol\s+([A-Za-z_][\w]*)")),
|
|
150
|
+
("func", re.compile(r"^\s*(?:public\s+|private\s+|internal\s+|static\s+|override\s+|@\w+\s+)*func\s+([A-Za-z_][\w]*)")),
|
|
151
|
+
),
|
|
152
|
+
"kotlin": (
|
|
153
|
+
("class", re.compile(r"^\s*(?:public\s+|private\s+|internal\s+|open\s+|data\s+|sealed\s+|abstract\s+)*class\s+([A-Za-z_][\w]*)")),
|
|
154
|
+
("object", re.compile(r"^\s*(?:public\s+|private\s+|internal\s+)?object\s+([A-Za-z_][\w]*)")),
|
|
155
|
+
("fun", re.compile(r"^\s*(?:public\s+|private\s+|internal\s+|suspend\s+|override\s+)*fun\s+(?:<[^>]*>\s*)?([A-Za-z_][\w]*)")),
|
|
156
|
+
),
|
|
157
|
+
"c": (
|
|
158
|
+
("struct", re.compile(r"^\s*(?:typedef\s+)?struct\s+([A-Za-z_][\w]*)")),
|
|
159
|
+
("function", re.compile(r"^[A-Za-z_][\w \*]*\s+\*?([A-Za-z_][\w]*)\s*\([^;]*\)\s*\{")),
|
|
160
|
+
),
|
|
161
|
+
"scala": (
|
|
162
|
+
("class", re.compile(r"^\s*(?:case\s+)?class\s+([A-Za-z_][\w]*)")),
|
|
163
|
+
("object", re.compile(r"^\s*(?:case\s+)?object\s+([A-Za-z_][\w]*)")),
|
|
164
|
+
("trait", re.compile(r"^\s*trait\s+([A-Za-z_][\w]*)")),
|
|
165
|
+
("def", re.compile(r"^\s*def\s+([A-Za-z_][\w]*)")),
|
|
166
|
+
),
|
|
167
|
+
"shell": (
|
|
168
|
+
("function", re.compile(r"^\s*(?:function\s+)?([A-Za-z_][\w]*)\s*\(\s*\)\s*\{")),
|
|
169
|
+
),
|
|
170
|
+
"sql": (
|
|
171
|
+
("table", re.compile(r"(?i)^\s*create\s+table\s+(?:if\s+not\s+exists\s+)?[`\"\[]?([A-Za-z_][\w]*)")),
|
|
172
|
+
("view", re.compile(r"(?i)^\s*create\s+(?:or\s+replace\s+)?view\s+[`\"\[]?([A-Za-z_][\w]*)")),
|
|
173
|
+
("function", re.compile(r"(?i)^\s*create\s+(?:or\s+replace\s+)?function\s+[`\"\[]?([A-Za-z_][\w]*)")),
|
|
174
|
+
),
|
|
175
|
+
"lua": (
|
|
176
|
+
("function", re.compile(r"^\s*(?:local\s+)?function\s+([A-Za-z_][\w.:]*)")),
|
|
177
|
+
),
|
|
178
|
+
"dart": (
|
|
179
|
+
("class", re.compile(r"^\s*(?:abstract\s+)?class\s+([A-Za-z_][\w]*)")),
|
|
180
|
+
),
|
|
181
|
+
"elixir": (
|
|
182
|
+
("defmodule", re.compile(r"^\s*defmodule\s+([A-Za-z_][\w.]*)")),
|
|
183
|
+
("def", re.compile(r"^\s*defp?\s+([a-z_][\w]*[?!]?)")),
|
|
184
|
+
),
|
|
185
|
+
}
|
|
186
|
+
_DECL_PATTERNS["typescript"] = _DECL_PATTERNS["javascript"] + (
|
|
187
|
+
("interface", re.compile(r"^\s*(?:export\s+)?interface\s+([A-Za-z_$][\w$]*)")),
|
|
188
|
+
("type", re.compile(r"^\s*(?:export\s+)?type\s+([A-Za-z_$][\w$]*)\s*=")),
|
|
189
|
+
("enum", re.compile(r"^\s*(?:export\s+)?(?:const\s+)?enum\s+([A-Za-z_$][\w$]*)")),
|
|
190
|
+
)
|
|
191
|
+
_DECL_PATTERNS["cpp"] = _DECL_PATTERNS["c"] + (
|
|
192
|
+
("class", re.compile(r"^\s*class\s+([A-Za-z_][\w]*)")),
|
|
193
|
+
("namespace", re.compile(r"^\s*namespace\s+([A-Za-z_][\w]*)")),
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
_IDENTIFIER = re.compile(r"[A-Za-z_][A-Za-z0-9_]*")
|
|
197
|
+
|
|
198
|
+
# Ranking guards — see the module docstring for what each one corrects.
|
|
199
|
+
_MIN_RANKED_NAME = 4
|
|
200
|
+
_MAX_DEFINING_FILES = 5
|
|
201
|
+
_MAX_SYMBOL_CONTRIBUTION = 20
|
|
202
|
+
|
|
203
|
+
# Rendering budget: how many files a map should try to touch, and roughly what
|
|
204
|
+
# one symbol line costs. Together these turn a char budget into a per-file
|
|
205
|
+
# symbol cap, so breadth survives a small budget.
|
|
206
|
+
_TARGET_FILES = 28
|
|
207
|
+
_AVG_SYMBOL_LINE = 46
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
@dataclass(frozen=True)
|
|
211
|
+
class Symbol:
|
|
212
|
+
"""One definition found in one file."""
|
|
213
|
+
|
|
214
|
+
name: str
|
|
215
|
+
kind: str
|
|
216
|
+
line: int
|
|
217
|
+
parent: str = ""
|
|
218
|
+
|
|
219
|
+
@property
|
|
220
|
+
def qualified(self) -> str:
|
|
221
|
+
return f"{self.parent}.{self.name}" if self.parent else self.name
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
@dataclass
|
|
225
|
+
class FileEntry:
|
|
226
|
+
path: str
|
|
227
|
+
language: str
|
|
228
|
+
symbols: List[Symbol] = field(default_factory=list)
|
|
229
|
+
mtime: float = 0.0
|
|
230
|
+
size: int = 0
|
|
231
|
+
score: float = 0.0
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def _python_symbols(source: str) -> List[Symbol]:
|
|
235
|
+
"""Exact symbols for Python, including one level of class nesting.
|
|
236
|
+
|
|
237
|
+
Methods are kept with their class as ``parent`` rather than flattened: a
|
|
238
|
+
map that lists ``run`` without saying it is ``AcceptanceGate.run`` sends
|
|
239
|
+
the model to the wrong file about as often as it helps.
|
|
240
|
+
"""
|
|
241
|
+
try:
|
|
242
|
+
tree = ast.parse(source)
|
|
243
|
+
except (SyntaxError, ValueError, RecursionError):
|
|
244
|
+
return []
|
|
245
|
+
|
|
246
|
+
out: List[Symbol] = []
|
|
247
|
+
|
|
248
|
+
def _kind(node: ast.AST) -> str:
|
|
249
|
+
if isinstance(node, ast.AsyncFunctionDef):
|
|
250
|
+
return "async def"
|
|
251
|
+
if isinstance(node, ast.FunctionDef):
|
|
252
|
+
return "def"
|
|
253
|
+
return "class"
|
|
254
|
+
|
|
255
|
+
for node in tree.body:
|
|
256
|
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
|
|
257
|
+
out.append(Symbol(name=node.name, kind=_kind(node), line=node.lineno))
|
|
258
|
+
if isinstance(node, ast.ClassDef):
|
|
259
|
+
for child in node.body:
|
|
260
|
+
if isinstance(child, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
261
|
+
out.append(Symbol(
|
|
262
|
+
name=child.name, kind=_kind(child),
|
|
263
|
+
line=child.lineno, parent=node.name,
|
|
264
|
+
))
|
|
265
|
+
elif isinstance(node, (ast.Assign, ast.AnnAssign)):
|
|
266
|
+
# Module-level constants are part of a module's surface: registries
|
|
267
|
+
# like LOCAL_TOOLS and SKIP_DIRS are exactly what a caller looks up.
|
|
268
|
+
targets = node.targets if isinstance(node, ast.Assign) else [node.target]
|
|
269
|
+
for target in targets:
|
|
270
|
+
if isinstance(target, ast.Name) and target.id.isupper() and len(target.id) > 2:
|
|
271
|
+
out.append(Symbol(name=target.id, kind="const", line=node.lineno))
|
|
272
|
+
return out
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def _regex_symbols(source: str, language: str) -> List[Symbol]:
|
|
276
|
+
patterns = _DECL_PATTERNS.get(language)
|
|
277
|
+
if not patterns:
|
|
278
|
+
return []
|
|
279
|
+
out: List[Symbol] = []
|
|
280
|
+
seen: Set[Tuple[str, int]] = set()
|
|
281
|
+
for lineno, line in enumerate(source.splitlines(), 1):
|
|
282
|
+
if len(line) > 400: # minified or generated; never a readable declaration
|
|
283
|
+
continue
|
|
284
|
+
for kind, pattern in patterns:
|
|
285
|
+
match = pattern.match(line)
|
|
286
|
+
if match:
|
|
287
|
+
name = match.group(1)
|
|
288
|
+
key = (name, lineno)
|
|
289
|
+
if key not in seen:
|
|
290
|
+
seen.add(key)
|
|
291
|
+
out.append(Symbol(name=name, kind=kind, line=lineno))
|
|
292
|
+
break
|
|
293
|
+
return out
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def extract_symbols(source: str, language: str) -> List[Symbol]:
|
|
297
|
+
"""Definitions in *source*. Never raises — an unparseable file has none."""
|
|
298
|
+
try:
|
|
299
|
+
if language == "python":
|
|
300
|
+
return _python_symbols(source)
|
|
301
|
+
return _regex_symbols(source, language)
|
|
302
|
+
except Exception:
|
|
303
|
+
return []
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
class RepoMap:
|
|
307
|
+
"""A scanned, ranked symbol index for one repository root."""
|
|
308
|
+
|
|
309
|
+
def __init__(
|
|
310
|
+
self,
|
|
311
|
+
root: str | Path = ".",
|
|
312
|
+
*,
|
|
313
|
+
max_files: int = 4000,
|
|
314
|
+
max_file_bytes: int = 400_000,
|
|
315
|
+
extra_skip_dirs: Iterable[str] = (),
|
|
316
|
+
) -> None:
|
|
317
|
+
self.root = Path(root).expanduser().resolve()
|
|
318
|
+
self.max_files = max(1, int(max_files))
|
|
319
|
+
self.max_file_bytes = max(1, int(max_file_bytes))
|
|
320
|
+
self.skip_dirs = SKIP_DIRS | {str(d) for d in extra_skip_dirs}
|
|
321
|
+
self.files: Dict[str, FileEntry] = {}
|
|
322
|
+
self.defs: Dict[str, List[Tuple[str, Symbol]]] = {}
|
|
323
|
+
self.refs: Dict[str, Set[str]] = {}
|
|
324
|
+
self.built_at: float = 0.0
|
|
325
|
+
self.truncated: bool = False
|
|
326
|
+
self.scan_seconds: float = 0.0
|
|
327
|
+
|
|
328
|
+
# ── scanning ──────────────────────────────────────────────────────────
|
|
329
|
+
|
|
330
|
+
def _walk(self) -> List[Path]:
|
|
331
|
+
found: List[Path] = []
|
|
332
|
+
stack = [self.root]
|
|
333
|
+
while stack and len(found) < self.max_files:
|
|
334
|
+
current = stack.pop()
|
|
335
|
+
try:
|
|
336
|
+
entries = list(current.iterdir())
|
|
337
|
+
except (OSError, PermissionError):
|
|
338
|
+
continue
|
|
339
|
+
for entry in entries:
|
|
340
|
+
name = entry.name
|
|
341
|
+
if name.startswith(".") and name not in (".github",):
|
|
342
|
+
if entry.is_dir():
|
|
343
|
+
continue
|
|
344
|
+
try:
|
|
345
|
+
if entry.is_dir():
|
|
346
|
+
if name not in self.skip_dirs:
|
|
347
|
+
stack.append(entry)
|
|
348
|
+
continue
|
|
349
|
+
if entry.suffix.lower() in LANGUAGES:
|
|
350
|
+
found.append(entry)
|
|
351
|
+
if len(found) >= self.max_files:
|
|
352
|
+
self.truncated = True
|
|
353
|
+
break
|
|
354
|
+
except OSError:
|
|
355
|
+
continue
|
|
356
|
+
return found
|
|
357
|
+
|
|
358
|
+
def build(self, *, force: bool = False) -> "RepoMap":
|
|
359
|
+
"""Scan the tree. Unchanged files keep their cached symbols.
|
|
360
|
+
|
|
361
|
+
Incremental by mtime and size so a rebuild between turns costs a stat
|
|
362
|
+
per file rather than a reparse — the map is only useful if refreshing
|
|
363
|
+
it is cheaper than the grep round it replaces.
|
|
364
|
+
"""
|
|
365
|
+
started = time.time()
|
|
366
|
+
paths = self._walk()
|
|
367
|
+
previous = self.files if not force else {}
|
|
368
|
+
files: Dict[str, FileEntry] = {}
|
|
369
|
+
order: List[str] = [] # walk order, which ranking ties fall back on
|
|
370
|
+
stale: List[Tuple[str, Path, os.stat_result, str]] = []
|
|
371
|
+
|
|
372
|
+
for path in paths:
|
|
373
|
+
try:
|
|
374
|
+
stat = path.stat()
|
|
375
|
+
except OSError:
|
|
376
|
+
continue
|
|
377
|
+
if stat.st_size > self.max_file_bytes:
|
|
378
|
+
continue
|
|
379
|
+
try:
|
|
380
|
+
rel = str(path.relative_to(self.root))
|
|
381
|
+
except ValueError:
|
|
382
|
+
rel = str(path)
|
|
383
|
+
|
|
384
|
+
order.append(rel)
|
|
385
|
+
cached = previous.get(rel)
|
|
386
|
+
if cached is not None and cached.mtime == stat.st_mtime and cached.size == stat.st_size:
|
|
387
|
+
files[rel] = cached
|
|
388
|
+
continue
|
|
389
|
+
stale.append((rel, path, stat, LANGUAGES.get(path.suffix.lower(), "")))
|
|
390
|
+
|
|
391
|
+
# Python definitions come from the native indexer when it can answer
|
|
392
|
+
# (one parallel pass); everything it does not is extracted here.
|
|
393
|
+
native = native_index.python_symbols(
|
|
394
|
+
self.root, [rel for rel, _path, _stat, language in stale if language == "python"])
|
|
395
|
+
parsed = native[0] if native is not None else {}
|
|
396
|
+
|
|
397
|
+
for rel, path, stat, language in stale:
|
|
398
|
+
if rel in parsed:
|
|
399
|
+
symbols = [Symbol(name=n, kind=k, line=line, parent=p) for n, k, line, p in parsed[rel]]
|
|
400
|
+
else:
|
|
401
|
+
try:
|
|
402
|
+
source = path.read_text(encoding="utf-8-sig", errors="replace")
|
|
403
|
+
except (OSError, UnicodeError):
|
|
404
|
+
continue
|
|
405
|
+
symbols = extract_symbols(source, language)
|
|
406
|
+
files[rel] = FileEntry(path=rel, language=language, symbols=symbols,
|
|
407
|
+
mtime=stat.st_mtime, size=stat.st_size)
|
|
408
|
+
|
|
409
|
+
self.files = {rel: files[rel] for rel in order if rel in files}
|
|
410
|
+
self._index()
|
|
411
|
+
self.built_at = time.time()
|
|
412
|
+
self.scan_seconds = self.built_at - started
|
|
413
|
+
return self
|
|
414
|
+
|
|
415
|
+
def _index(self) -> None:
|
|
416
|
+
"""Build the definition table, the reference table, and the ranking."""
|
|
417
|
+
defs: Dict[str, List[Tuple[str, Symbol]]] = {}
|
|
418
|
+
for entry in self.files.values():
|
|
419
|
+
for symbol in entry.symbols:
|
|
420
|
+
defs.setdefault(symbol.name, []).append((entry.path, symbol))
|
|
421
|
+
self.defs = defs
|
|
422
|
+
|
|
423
|
+
# References: identifiers a file mentions that some *other* file
|
|
424
|
+
# defines. Re-reading each file here is what a second pass costs; it
|
|
425
|
+
# is bounded by max_file_bytes and only runs on a real rebuild.
|
|
426
|
+
known = set(defs)
|
|
427
|
+
refs: Dict[str, Set[str]] = {}
|
|
428
|
+
for entry in self.files.values():
|
|
429
|
+
path = self.root / entry.path
|
|
430
|
+
try:
|
|
431
|
+
source = path.read_text(encoding="utf-8-sig", errors="replace")
|
|
432
|
+
except (OSError, UnicodeError):
|
|
433
|
+
continue
|
|
434
|
+
own = {symbol.name for symbol in entry.symbols}
|
|
435
|
+
for token in set(_IDENTIFIER.findall(source)):
|
|
436
|
+
if token in known and token not in own:
|
|
437
|
+
refs.setdefault(token, set()).add(entry.path)
|
|
438
|
+
self.refs = refs
|
|
439
|
+
|
|
440
|
+
for entry in self.files.values():
|
|
441
|
+
entry.score = self._score(entry)
|
|
442
|
+
|
|
443
|
+
def _effective_refs(self, name: str) -> int:
|
|
444
|
+
"""Reference count, with the two names that always lie zeroed out.
|
|
445
|
+
|
|
446
|
+
A name under four characters (``get``, ``run``, ``id``) collides with
|
|
447
|
+
ordinary vocabulary, and a name defined in more than a handful of files
|
|
448
|
+
(``main``, ``setup``, ``status``) cannot tell you which of them is the
|
|
449
|
+
one that matters. Both would otherwise dominate every ranking.
|
|
450
|
+
"""
|
|
451
|
+
if len(name) < _MIN_RANKED_NAME:
|
|
452
|
+
return 0
|
|
453
|
+
if len(self.defs.get(name, ())) > _MAX_DEFINING_FILES:
|
|
454
|
+
return 0
|
|
455
|
+
return len(self.refs.get(name, ()))
|
|
456
|
+
|
|
457
|
+
def _score(self, entry: FileEntry) -> float:
|
|
458
|
+
total = 0.0
|
|
459
|
+
counted: Set[str] = set()
|
|
460
|
+
for symbol in entry.symbols:
|
|
461
|
+
if symbol.name in counted:
|
|
462
|
+
continue
|
|
463
|
+
counted.add(symbol.name)
|
|
464
|
+
total += min(self._effective_refs(symbol.name), _MAX_SYMBOL_CONTRIBUTION)
|
|
465
|
+
return total
|
|
466
|
+
|
|
467
|
+
# ── querying ──────────────────────────────────────────────────────────
|
|
468
|
+
|
|
469
|
+
def ranked(self, *, focus: Sequence[str] = ()) -> List[FileEntry]:
|
|
470
|
+
"""Files, most depended-upon first.
|
|
471
|
+
|
|
472
|
+
``focus`` promotes paths the caller already knows are relevant (the
|
|
473
|
+
files in the current diff, say) above the global ranking, because what
|
|
474
|
+
the rest of the repo needs and what *this task* needs are different
|
|
475
|
+
questions and the caller often knows the second one.
|
|
476
|
+
"""
|
|
477
|
+
wanted = tuple(f for f in focus if f)
|
|
478
|
+
|
|
479
|
+
def _is_focused(entry: FileEntry) -> bool:
|
|
480
|
+
return any(token in entry.path for token in wanted)
|
|
481
|
+
|
|
482
|
+
return sorted(
|
|
483
|
+
(e for e in self.files.values() if e.symbols),
|
|
484
|
+
key=lambda e: (0 if _is_focused(e) else 1, -e.score, e.path),
|
|
485
|
+
)
|
|
486
|
+
|
|
487
|
+
def notable(self, entry: FileEntry, limit: int) -> List[Symbol]:
|
|
488
|
+
"""The *limit* symbols in this file worth naming, in source order.
|
|
489
|
+
|
|
490
|
+
Two rules, in order. Top-level definitions come before methods: a class
|
|
491
|
+
name is the handle a caller navigates by, and three of its methods say
|
|
492
|
+
less about the file than the class itself does. Within a level, the
|
|
493
|
+
most-referenced name wins.
|
|
494
|
+
|
|
495
|
+
Listing a file's first N definitions instead — the obvious
|
|
496
|
+
implementation — is what makes a map read like noise: the top of a
|
|
497
|
+
large module is usually private constants and local helpers, so the
|
|
498
|
+
budget gets spent on the exact symbols no outside caller will ever
|
|
499
|
+
ask about.
|
|
500
|
+
"""
|
|
501
|
+
if len(entry.symbols) <= limit:
|
|
502
|
+
return list(entry.symbols)
|
|
503
|
+
ranked = sorted(
|
|
504
|
+
entry.symbols,
|
|
505
|
+
key=lambda s: (
|
|
506
|
+
bool(s.parent),
|
|
507
|
+
s.name.startswith("_"),
|
|
508
|
+
-self._effective_refs(s.name),
|
|
509
|
+
s.line,
|
|
510
|
+
),
|
|
511
|
+
)[:limit]
|
|
512
|
+
return sorted(ranked, key=lambda s: s.line)
|
|
513
|
+
|
|
514
|
+
def render(self, *, budget_chars: int = 8000, focus: Sequence[str] = ()) -> str:
|
|
515
|
+
"""The map, as compact text, cut to fit *budget_chars*."""
|
|
516
|
+
if not self.files:
|
|
517
|
+
return "(repo map empty — no source files found)"
|
|
518
|
+
|
|
519
|
+
header = (
|
|
520
|
+
f"# Repo map — {self.root.name}\n"
|
|
521
|
+
f"# {len(self.files)} files indexed, "
|
|
522
|
+
f"{sum(len(e.symbols) for e in self.files.values())} symbols, "
|
|
523
|
+
f"ranked by how much the rest of the repo references them.\n"
|
|
524
|
+
f"# Use read_file for the actual code; this map only says where to look.\n"
|
|
525
|
+
)
|
|
526
|
+
if self.truncated:
|
|
527
|
+
header += f"# (truncated at {self.max_files} files)\n"
|
|
528
|
+
|
|
529
|
+
blocks: List[str] = []
|
|
530
|
+
used = len(header)
|
|
531
|
+
shown = 0
|
|
532
|
+
entries = self.ranked(focus=focus)
|
|
533
|
+
|
|
534
|
+
# Spread the budget across files instead of letting the first one eat
|
|
535
|
+
# it. A map that covers thirty files shallowly is navigable; one that
|
|
536
|
+
# covers a single file exhaustively is a worse `read_file`.
|
|
537
|
+
per_file = max(3, min(12, budget_chars // (_TARGET_FILES * _AVG_SYMBOL_LINE)))
|
|
538
|
+
|
|
539
|
+
for entry in entries:
|
|
540
|
+
lines = [f"\n{entry.path}"]
|
|
541
|
+
listed = self.notable(entry, per_file)
|
|
542
|
+
for symbol in listed:
|
|
543
|
+
lines.append(f" {symbol.line:>5} {symbol.kind} {symbol.qualified}")
|
|
544
|
+
if len(entry.symbols) > len(listed):
|
|
545
|
+
lines.append(f" … +{len(entry.symbols) - len(listed)} more")
|
|
546
|
+
block = "\n".join(lines)
|
|
547
|
+
if used + len(block) > budget_chars:
|
|
548
|
+
break
|
|
549
|
+
blocks.append(block)
|
|
550
|
+
used += len(block)
|
|
551
|
+
shown += 1
|
|
552
|
+
|
|
553
|
+
footer = ""
|
|
554
|
+
if shown < len(entries):
|
|
555
|
+
footer = (
|
|
556
|
+
f"\n\n… {len(entries) - shown} lower-ranked files omitted. "
|
|
557
|
+
"Use find_symbol(name) to locate anything not listed here."
|
|
558
|
+
)
|
|
559
|
+
return header + "".join(blocks) + footer
|
|
560
|
+
|
|
561
|
+
def find_symbol(self, name: str, *, limit: int = 20) -> dict:
|
|
562
|
+
"""Where *name* is defined and which files mention it.
|
|
563
|
+
|
|
564
|
+
This is the call that replaces a speculative grep: it answers "does
|
|
565
|
+
this repo have such a thing, and where" in one round instead of three.
|
|
566
|
+
"""
|
|
567
|
+
query = (name or "").strip()
|
|
568
|
+
if not query:
|
|
569
|
+
return {"symbol": "", "definitions": [], "referenced_by": [], "error": "empty name"}
|
|
570
|
+
|
|
571
|
+
definitions = [
|
|
572
|
+
{"file": path, "line": symbol.line, "kind": symbol.kind, "name": symbol.qualified}
|
|
573
|
+
for path, symbol in self.defs.get(query, ())
|
|
574
|
+
]
|
|
575
|
+
|
|
576
|
+
if not definitions:
|
|
577
|
+
# An exact miss is the common case for a half-remembered name, so
|
|
578
|
+
# answer with the near misses rather than an empty result.
|
|
579
|
+
lowered = query.lower()
|
|
580
|
+
near = sorted(
|
|
581
|
+
(n for n in self.defs if lowered in n.lower()),
|
|
582
|
+
key=lambda n: (len(n), n),
|
|
583
|
+
)[:limit]
|
|
584
|
+
return {
|
|
585
|
+
"symbol": query,
|
|
586
|
+
"definitions": [],
|
|
587
|
+
"referenced_by": [],
|
|
588
|
+
"did_you_mean": near,
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
return {
|
|
592
|
+
"symbol": query,
|
|
593
|
+
"definitions": definitions[:limit],
|
|
594
|
+
"referenced_by": sorted(self.refs.get(query, ()))[:limit],
|
|
595
|
+
"reference_count": len(self.refs.get(query, ())),
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
def summary(self) -> dict:
|
|
599
|
+
return {
|
|
600
|
+
"root": str(self.root),
|
|
601
|
+
"files": len(self.files),
|
|
602
|
+
"symbols": sum(len(e.symbols) for e in self.files.values()),
|
|
603
|
+
"truncated": self.truncated,
|
|
604
|
+
"scan_seconds": round(self.scan_seconds, 3),
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
# ── tool surface ──────────────────────────────────────────────────────────
|
|
609
|
+
# One cached map per root: rebuilding is incremental, so a repeated call in the
|
|
610
|
+
# same session costs a stat per file rather than a full reparse.
|
|
611
|
+
|
|
612
|
+
_CACHE: Dict[str, RepoMap] = {}
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
def get_repo_map(root: str | Path = ".", *, refresh: bool = True) -> RepoMap:
|
|
616
|
+
key = str(Path(root).expanduser().resolve())
|
|
617
|
+
existing = _CACHE.get(key)
|
|
618
|
+
if existing is None:
|
|
619
|
+
existing = RepoMap(key)
|
|
620
|
+
_CACHE[key] = existing
|
|
621
|
+
return existing.build()
|
|
622
|
+
if refresh:
|
|
623
|
+
existing.build()
|
|
624
|
+
return existing
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
def clear_cache() -> None:
|
|
628
|
+
_CACHE.clear()
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
def tool_repo_map(params: dict) -> dict:
|
|
632
|
+
"""Model-facing: an overview of what this repository defines."""
|
|
633
|
+
try:
|
|
634
|
+
root = params.get("path") or "."
|
|
635
|
+
budget = int(params.get("budget_chars") or 8000)
|
|
636
|
+
focus = params.get("focus") or []
|
|
637
|
+
if isinstance(focus, str):
|
|
638
|
+
focus = [focus]
|
|
639
|
+
repo = get_repo_map(root)
|
|
640
|
+
return {
|
|
641
|
+
"success": True,
|
|
642
|
+
"data": {
|
|
643
|
+
"map": repo.render(budget_chars=max(500, min(budget, 40000)), focus=focus),
|
|
644
|
+
**repo.summary(),
|
|
645
|
+
},
|
|
646
|
+
}
|
|
647
|
+
except Exception as exc:
|
|
648
|
+
return {"success": False, "error": f"repo_map failed: {exc}"}
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
def tool_find_symbol(params: dict) -> dict:
|
|
652
|
+
"""Model-facing: where one named thing is defined, and who uses it."""
|
|
653
|
+
try:
|
|
654
|
+
name = str(params.get("name") or params.get("symbol") or "").strip()
|
|
655
|
+
if not name:
|
|
656
|
+
return {"success": False, "error": "Missing 'name' parameter"}
|
|
657
|
+
repo = get_repo_map(params.get("path") or ".")
|
|
658
|
+
return {"success": True, "data": repo.find_symbol(name)}
|
|
659
|
+
except Exception as exc:
|
|
660
|
+
return {"success": False, "error": f"find_symbol failed: {exc}"}
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
REPO_MAP_TOOLS = {
|
|
664
|
+
"repo_map": (tool_repo_map,
|
|
665
|
+
"Ranked map of what this repository defines and where"),
|
|
666
|
+
"find_symbol": (tool_find_symbol,
|
|
667
|
+
"Locate a class/function by name and see which files reference it"),
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
REPO_MAP_SCHEMAS = [
|
|
671
|
+
{
|
|
672
|
+
"name": "repo_map",
|
|
673
|
+
"description": (
|
|
674
|
+
"Get a ranked map of the classes, functions and constants this repository "
|
|
675
|
+
"defines, with file paths and line numbers. Files are ordered by how much "
|
|
676
|
+
"the rest of the codebase references them, so the top of the map is where "
|
|
677
|
+
"a change most likely belongs. CALL THIS FIRST when working in an "
|
|
678
|
+
"unfamiliar repository — it replaces several rounds of guessing filenames "
|
|
679
|
+
"and grepping. Then use read_file on the files it points to."
|
|
680
|
+
),
|
|
681
|
+
"parameters": {
|
|
682
|
+
"type": "object",
|
|
683
|
+
"properties": {
|
|
684
|
+
"path": {"type": "string", "description": "Repository root (default: current directory)"},
|
|
685
|
+
"budget_chars": {"type": "integer", "description": "Max size of the returned map (default 8000)"},
|
|
686
|
+
"focus": {
|
|
687
|
+
"type": "array",
|
|
688
|
+
"items": {"type": "string"},
|
|
689
|
+
"description": "Path fragments to list first, e.g. files you are already editing",
|
|
690
|
+
},
|
|
691
|
+
},
|
|
692
|
+
"required": [],
|
|
693
|
+
},
|
|
694
|
+
},
|
|
695
|
+
{
|
|
696
|
+
"name": "find_symbol",
|
|
697
|
+
"description": (
|
|
698
|
+
"Find where a class, function or constant is defined and which files "
|
|
699
|
+
"reference it. Use this instead of guessing a path or grepping for a name: "
|
|
700
|
+
"it returns exact file:line definitions, and near-miss suggestions when the "
|
|
701
|
+
"name does not exist, so a wrong guess costs one round instead of four."
|
|
702
|
+
),
|
|
703
|
+
"parameters": {
|
|
704
|
+
"type": "object",
|
|
705
|
+
"properties": {
|
|
706
|
+
"name": {"type": "string", "description": "Symbol name to look up"},
|
|
707
|
+
"path": {"type": "string", "description": "Repository root (default: current directory)"},
|
|
708
|
+
},
|
|
709
|
+
"required": ["name"],
|
|
710
|
+
},
|
|
711
|
+
},
|
|
712
|
+
]
|