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.
Files changed (478) hide show
  1. aria_code/__init__.py +42 -0
  2. aria_code/_version.py +20 -0
  3. aria_code/adk_apps/__init__.py +1 -0
  4. aria_code/adk_apps/aria_code_review/__init__.py +1 -0
  5. aria_code/adk_apps/aria_code_review/agent.py +32 -0
  6. aria_code/adk_apps/aria_research/__init__.py +1 -0
  7. aria_code/adk_apps/aria_research/agent.py +31 -0
  8. aria_code/agents/__init__.py +34 -0
  9. aria_code/agents/base.py +318 -0
  10. aria_code/agents/code_review.py +200 -0
  11. aria_code/agents/deep/__init__.py +37 -0
  12. aria_code/agents/deep/calibration_loop.py +144 -0
  13. aria_code/agents/deep/critic.py +125 -0
  14. aria_code/agents/deep/deepen.py +193 -0
  15. aria_code/agents/deep/models.py +149 -0
  16. aria_code/agents/deep/pipeline.py +164 -0
  17. aria_code/agents/deep/quant_fusion.py +192 -0
  18. aria_code/agents/deep/themes.py +95 -0
  19. aria_code/agents/deep/tiers.py +106 -0
  20. aria_code/agents/engineering/__init__.py +14 -0
  21. aria_code/agents/engineering/coder.py +222 -0
  22. aria_code/agents/engineering/tester.py +145 -0
  23. aria_code/agents/financial/__init__.py +21 -0
  24. aria_code/agents/financial/cashflow_burn.py +119 -0
  25. aria_code/agents/financial/catalyst.py +279 -0
  26. aria_code/agents/financial/corporate_finance.py +175 -0
  27. aria_code/agents/financial/debate.py +224 -0
  28. aria_code/agents/financial/earnings.py +303 -0
  29. aria_code/agents/financial/fundamental.py +191 -0
  30. aria_code/agents/financial/macro.py +99 -0
  31. aria_code/agents/financial/news.py +207 -0
  32. aria_code/agents/financial/risk.py +165 -0
  33. aria_code/agents/financial/sector.py +279 -0
  34. aria_code/agents/financial/strategist.py +121 -0
  35. aria_code/agents/financial/stripe_revenue.py +127 -0
  36. aria_code/agents/financial/synthesis.py +274 -0
  37. aria_code/agents/financial/technical.py +258 -0
  38. aria_code/agents/orchestrator.py +44 -0
  39. aria_code/agents/portfolio_agent.py +363 -0
  40. aria_code/agents/realty/__init__.py +62 -0
  41. aria_code/agents/realty/asset_diagnosis.py +152 -0
  42. aria_code/agents/realty/business_match.py +166 -0
  43. aria_code/agents/realty/cashflow_verify.py +209 -0
  44. aria_code/agents/realty/contract_rules.py +210 -0
  45. aria_code/agents/realty/energy_anomaly.py +189 -0
  46. aria_code/agents/realty/exit_settlement.py +208 -0
  47. aria_code/agents/realty/fulfillment_risk.py +206 -0
  48. aria_code/agents/realty/ops_optimize.py +160 -0
  49. aria_code/agents/realty/revenue_share.py +215 -0
  50. aria_code/agents/registry.py +158 -0
  51. aria_code/agents/signal_scheme.py +111 -0
  52. aria_code/agents/sports/__init__.py +0 -0
  53. aria_code/agents/sports/football_agent.py +197 -0
  54. aria_code/agents/supervisor.py +113 -0
  55. aria_code/agents/team.py +492 -0
  56. aria_code/agents/warehouse/__init__.py +25 -0
  57. aria_code/agents/warehouse/contracts.py +26 -0
  58. aria_code/agents/warehouse/dashboard.py +155 -0
  59. aria_code/agents/warehouse/fulfillment_leadtime.py +95 -0
  60. aria_code/agents/warehouse/inbound_exceptions.py +25 -0
  61. aria_code/agents/warehouse/inventory_health.py +24 -0
  62. aria_code/agents/warehouse/local_run.py +71 -0
  63. aria_code/agents/warehouse/local_snapshot.py +132 -0
  64. aria_code/agents/warehouse/logistics_cost.py +84 -0
  65. aria_code/agents/warehouse/logistics_sync.py +21 -0
  66. aria_code/agents/warehouse/workflow.py +31 -0
  67. aria_code/aliyun_data_client.py +4 -0
  68. aria_code/apps/README.md +12 -0
  69. aria_code/apps/__init__.py +2 -0
  70. aria_code/apps/channels/README.md +15 -0
  71. aria_code/apps/channels/__init__.py +17 -0
  72. aria_code/apps/channels/intake.py +92 -0
  73. aria_code/apps/channels/registry.py +95 -0
  74. aria_code/apps/channels/tradingview.py +94 -0
  75. aria_code/apps/cli/README.md +13 -0
  76. aria_code/apps/cli/__init__.py +2 -0
  77. aria_code/apps/cli/_optional.py +120 -0
  78. aria_code/apps/cli/bootstrap.py +145 -0
  79. aria_code/apps/cli/broker_render.py +206 -0
  80. aria_code/apps/cli/codegen_paths.py +29 -0
  81. aria_code/apps/cli/commands/__init__.py +16 -0
  82. aria_code/apps/cli/commands/_business_render.py +78 -0
  83. aria_code/apps/cli/commands/_ui.py +71 -0
  84. aria_code/apps/cli/commands/analysis_cmds.py +369 -0
  85. aria_code/apps/cli/commands/ashare_prediction_cmds.py +327 -0
  86. aria_code/apps/cli/commands/auth_cmds.py +239 -0
  87. aria_code/apps/cli/commands/backtest_cmds.py +2543 -0
  88. aria_code/apps/cli/commands/broker_cmds.py +1234 -0
  89. aria_code/apps/cli/commands/business_workflow_cmds.py +319 -0
  90. aria_code/apps/cli/commands/canvas_cmds.py +77 -0
  91. aria_code/apps/cli/commands/catalog.py +87 -0
  92. aria_code/apps/cli/commands/core_cmds.py +2520 -0
  93. aria_code/apps/cli/commands/data_cmds.py +457 -0
  94. aria_code/apps/cli/commands/diagnostic_cmds.py +230 -0
  95. aria_code/apps/cli/commands/diagnostic_ops_cmds.py +813 -0
  96. aria_code/apps/cli/commands/file_cmds.py +312 -0
  97. aria_code/apps/cli/commands/finance_service_cmds.py +60 -0
  98. aria_code/apps/cli/commands/fx_commodity_cmds.py +123 -0
  99. aria_code/apps/cli/commands/market.py +434 -0
  100. aria_code/apps/cli/commands/market_cmds.py +1381 -0
  101. aria_code/apps/cli/commands/market_context.py +425 -0
  102. aria_code/apps/cli/commands/market_render.py +7 -0
  103. aria_code/apps/cli/commands/model_cmds.py +2153 -0
  104. aria_code/apps/cli/commands/ops_cmds.py +721 -0
  105. aria_code/apps/cli/commands/orchestrator_cmds.py +179 -0
  106. aria_code/apps/cli/commands/pdf_export_cmds.py +125 -0
  107. aria_code/apps/cli/commands/portfolio_cmds.py +1278 -0
  108. aria_code/apps/cli/commands/report.py +437 -0
  109. aria_code/apps/cli/commands/scaffold_templates.py +617 -0
  110. aria_code/apps/cli/commands/session_cmds.py +236 -0
  111. aria_code/apps/cli/commands/session_ux_cmds.py +359 -0
  112. aria_code/apps/cli/commands/team.py +669 -0
  113. aria_code/apps/cli/commands/team_render.py +8 -0
  114. aria_code/apps/cli/commands/ui_cmds.py +401 -0
  115. aria_code/apps/cli/commands/warehouse_cmds.py +79 -0
  116. aria_code/apps/cli/commands/workflow_cmds.py +480 -0
  117. aria_code/apps/cli/commands/workspace_cmds.py +1494 -0
  118. aria_code/apps/cli/config_paths.py +73 -0
  119. aria_code/apps/cli/config_store.py +78 -0
  120. aria_code/apps/cli/constants.py +88 -0
  121. aria_code/apps/cli/context.py +34 -0
  122. aria_code/apps/cli/deterministic.py +191 -0
  123. aria_code/apps/cli/direct.py +48 -0
  124. aria_code/apps/cli/finance_service_catalog.py +111 -0
  125. aria_code/apps/cli/football_reports.py +231 -0
  126. aria_code/apps/cli/github_app_auth.py +135 -0
  127. aria_code/apps/cli/google_login.py +196 -0
  128. aria_code/apps/cli/handlers/__init__.py +11 -0
  129. aria_code/apps/cli/handlers/broker_handlers.py +122 -0
  130. aria_code/apps/cli/handlers/chart_handlers.py +1309 -0
  131. aria_code/apps/cli/handlers/market_handlers.py +2513 -0
  132. aria_code/apps/cli/handlers/realty_handlers.py +114 -0
  133. aria_code/apps/cli/handlers/sports_handlers.py +22 -0
  134. aria_code/apps/cli/handlers/strategy_advice.py +82 -0
  135. aria_code/apps/cli/helpers.py +302 -0
  136. aria_code/apps/cli/hooks.py +180 -0
  137. aria_code/apps/cli/i18n.py +297 -0
  138. aria_code/apps/cli/intent.py +136 -0
  139. aria_code/apps/cli/intent_router.py +276 -0
  140. aria_code/apps/cli/intent_signals.py +344 -0
  141. aria_code/apps/cli/lifecycle_hooks.py +48 -0
  142. aria_code/apps/cli/local_tool_schemas.py +536 -0
  143. aria_code/apps/cli/main.py +29 -0
  144. aria_code/apps/cli/market_metadata.py +135 -0
  145. aria_code/apps/cli/market_universe.py +487 -0
  146. aria_code/apps/cli/message_processing.py +310 -0
  147. aria_code/apps/cli/model_catalog.py +620 -0
  148. aria_code/apps/cli/pdf_report.py +977 -0
  149. aria_code/apps/cli/plan_mode.py +139 -0
  150. aria_code/apps/cli/plotly_html.py +15 -0
  151. aria_code/apps/cli/prediction_feedback.py +202 -0
  152. aria_code/apps/cli/preflight.py +502 -0
  153. aria_code/apps/cli/project_aria.py +60 -0
  154. aria_code/apps/cli/prompt_assembly.py +59 -0
  155. aria_code/apps/cli/prompts/__init__.py +0 -0
  156. aria_code/apps/cli/prompts/coding.py +53 -0
  157. aria_code/apps/cli/prompts/select.py +142 -0
  158. aria_code/apps/cli/prompts/system_prompts.py +552 -0
  159. aria_code/apps/cli/prompts/ui.py +436 -0
  160. aria_code/apps/cli/provider_endpoints.py +237 -0
  161. aria_code/apps/cli/provider_keys.py +73 -0
  162. aria_code/apps/cli/providers/__init__.py +1 -0
  163. aria_code/apps/cli/providers/base.py +521 -0
  164. aria_code/apps/cli/providers/chat_routing.py +128 -0
  165. aria_code/apps/cli/providers/collaboration.py +98 -0
  166. aria_code/apps/cli/providers/llm/__init__.py +1 -0
  167. aria_code/apps/cli/providers/llm/offline_responses.py +68 -0
  168. aria_code/apps/cli/providers/llm/ollama_stream.py +1594 -0
  169. aria_code/apps/cli/providers/llm/response_cache.py +60 -0
  170. aria_code/apps/cli/providers/llm/sse_stream.py +257 -0
  171. aria_code/apps/cli/providers/runtime_bridge.py +353 -0
  172. aria_code/apps/cli/providers/vertexai_stream.py +316 -0
  173. aria_code/apps/cli/runtime_consumer.py +657 -0
  174. aria_code/apps/cli/sandbox.py +32 -0
  175. aria_code/apps/cli/session_export.py +120 -0
  176. aria_code/apps/cli/session_jsonl.py +208 -0
  177. aria_code/apps/cli/session_store.py +112 -0
  178. aria_code/apps/cli/skills_catalog.py +273 -0
  179. aria_code/apps/cli/todo_tracker.py +190 -0
  180. aria_code/apps/cli/tool_executor.py +823 -0
  181. aria_code/apps/cli/tool_registry.py +34 -0
  182. aria_code/apps/cli/tool_scope.py +106 -0
  183. aria_code/apps/cli/tools/__init__.py +40 -0
  184. aria_code/apps/cli/tools/context.py +46 -0
  185. aria_code/apps/cli/tools/file_tools.py +180 -0
  186. aria_code/apps/cli/tools/market_tools.py +620 -0
  187. aria_code/apps/cli/tools/notebook_tools.py +111 -0
  188. aria_code/apps/cli/tools/system_tools.py +726 -0
  189. aria_code/apps/cli/tools/write_tools.py +845 -0
  190. aria_code/apps/cli/tradingview_bridge.py +529 -0
  191. aria_code/apps/cli/turn_planning.py +137 -0
  192. aria_code/apps/cli/update_check.py +153 -0
  193. aria_code/apps/cli/utils/__init__.py +0 -0
  194. aria_code/apps/cli/utils/market_detect.py +1597 -0
  195. aria_code/apps/daemon/README.md +14 -0
  196. aria_code/apps/vscode/README.md +115 -0
  197. aria_code/apps/vscode/package.json +70 -0
  198. aria_code/aria_cli.py +6743 -0
  199. aria_code/aria_daemon.py +1398 -0
  200. aria_code/aria_feishu_bot.py +1423 -0
  201. aria_code/aria_mcp_server.py +7 -0
  202. aria_code/aria_relay_client.py +4 -0
  203. aria_code/aria_relay_server.py +490 -0
  204. aria_code/aria_telegram_bot.py +202 -0
  205. aria_code/ariarc.py +385 -0
  206. aria_code/artifacts.py +581 -0
  207. aria_code/backtest_engine.py +4 -0
  208. aria_code/backtest_report.py +4 -0
  209. aria_code/brokers/__init__.py +78 -0
  210. aria_code/brokers/automation.py +193 -0
  211. aria_code/brokers/base.py +231 -0
  212. aria_code/brokers/capabilities.py +264 -0
  213. aria_code/brokers/cn/__init__.py +10 -0
  214. aria_code/brokers/cn/easytrader_broker.py +193 -0
  215. aria_code/brokers/cn/futu_broker.py +194 -0
  216. aria_code/brokers/cn/longbridge_broker.py +190 -0
  217. aria_code/brokers/cn/tiger_broker.py +196 -0
  218. aria_code/brokers/cn/xtquant_broker.py +225 -0
  219. aria_code/brokers/config.py +414 -0
  220. aria_code/brokers/intl/__init__.py +5 -0
  221. aria_code/brokers/intl/alpaca_broker.py +183 -0
  222. aria_code/brokers/intl/ibkr_broker.py +215 -0
  223. aria_code/brokers/intl/trading212_broker.py +183 -0
  224. aria_code/brokers/intl/webull_broker.py +156 -0
  225. aria_code/brokers/paper_broker.py +266 -0
  226. aria_code/brokers/planning.py +296 -0
  227. aria_code/brokers/registry.py +213 -0
  228. aria_code/brokers/trading.py +267 -0
  229. aria_code/canva_client.py +4 -0
  230. aria_code/change_store.py +127 -0
  231. aria_code/clients/__init__.py +0 -0
  232. aria_code/clients/aliyun_data_client.py +660 -0
  233. aria_code/clients/aria_relay_client.py +182 -0
  234. aria_code/clients/canva_client.py +284 -0
  235. aria_code/clients/figma_client.py +100 -0
  236. aria_code/clients/football_data_client.py +1671 -0
  237. aria_code/clients/kling_video_client.py +182 -0
  238. aria_code/clients/market_data_client.py +1976 -0
  239. aria_code/clients/openai_image_client.py +242 -0
  240. aria_code/clients/runway_video_client.py +157 -0
  241. aria_code/clients/warehouse_erp_client.py +105 -0
  242. aria_code/cloud_memory.py +181 -0
  243. aria_code/command_safety.py +19 -0
  244. aria_code/computer_use_tools.py +4 -0
  245. aria_code/dashboard_generator.py +579 -0
  246. aria_code/data_analysis_tools.py +4 -0
  247. aria_code/data_cleaner.py +483 -0
  248. aria_code/data_service.py +513 -0
  249. aria_code/datasources/__init__.py +23 -0
  250. aria_code/datasources/base.py +166 -0
  251. aria_code/datasources/router.py +253 -0
  252. aria_code/datasources/sources/__init__.py +15 -0
  253. aria_code/datasources/sources/akshare_source.py +269 -0
  254. aria_code/datasources/sources/alpha_vantage_source.py +203 -0
  255. aria_code/datasources/sources/edgar_source.py +219 -0
  256. aria_code/datasources/sources/finnhub_source.py +198 -0
  257. aria_code/datasources/sources/fred_source.py +223 -0
  258. aria_code/datasources/sources/tushare_source.py +143 -0
  259. aria_code/datasources/sources/web_scraper_source.py +278 -0
  260. aria_code/datasources/sources/world_bank_source.py +206 -0
  261. aria_code/datasources/sources/yfinance_source.py +152 -0
  262. aria_code/demo_player.py +207 -0
  263. aria_code/doctor.py +813 -0
  264. aria_code/domain/__init__.py +0 -0
  265. aria_code/domain/backtest_engine.py +354 -0
  266. aria_code/domain/backtest_report.py +472 -0
  267. aria_code/domain/finance_formulas.py +389 -0
  268. aria_code/domain/portfolio_ledger.py +307 -0
  269. aria_code/domain/strategy_vault.py +421 -0
  270. aria_code/evals/__init__.py +37 -0
  271. aria_code/evals/harness.py +598 -0
  272. aria_code/evals/runner.py +238 -0
  273. aria_code/external_agent_runner.py +115 -0
  274. aria_code/figma_client.py +4 -0
  275. aria_code/file_analysis_tools.py +4 -0
  276. aria_code/finance_formulas.py +4 -0
  277. aria_code/football_data_client.py +4 -0
  278. aria_code/image_gen_tools.py +4 -0
  279. aria_code/intent_classifier.py +386 -0
  280. aria_code/kling_video_client.py +4 -0
  281. aria_code/licensing.py +151 -0
  282. aria_code/local_finance_tools.py +4 -0
  283. aria_code/local_image_provider.py +4 -0
  284. aria_code/local_llm_provider.py +4 -0
  285. aria_code/macro_tools.py +4 -0
  286. aria_code/markdown_pdf.py +289 -0
  287. aria_code/market_data_client.py +4 -0
  288. aria_code/mcp_client.py +639 -0
  289. aria_code/memory_manager.py +246 -0
  290. aria_code/model_capability.py +486 -0
  291. aria_code/notification_tools.py +4 -0
  292. aria_code/openai_image_client.py +4 -0
  293. aria_code/packages/__init__.py +23 -0
  294. aria_code/packages/adk_bridge/__init__.py +11 -0
  295. aria_code/packages/adk_bridge/code_review_tools.py +49 -0
  296. aria_code/packages/adk_bridge/market_tools.py +125 -0
  297. aria_code/packages/aria_agents/__init__.py +5 -0
  298. aria_code/packages/aria_agents/manifest.py +78 -0
  299. aria_code/packages/aria_core/__init__.py +34 -0
  300. aria_code/packages/aria_core/architecture.py +269 -0
  301. aria_code/packages/aria_core/export.py +147 -0
  302. aria_code/packages/aria_core/manifest.py +65 -0
  303. aria_code/packages/aria_core/paths.py +57 -0
  304. aria_code/packages/aria_core/secure_file.py +68 -0
  305. aria_code/packages/aria_infra/__init__.py +15 -0
  306. aria_code/packages/aria_infra/arthera.py +52 -0
  307. aria_code/packages/aria_infra/doctor.py +246 -0
  308. aria_code/packages/aria_infra/product.py +40 -0
  309. aria_code/packages/aria_mcp/__init__.py +25 -0
  310. aria_code/packages/aria_mcp/bridge.py +201 -0
  311. aria_code/packages/aria_mcp/circuit.py +82 -0
  312. aria_code/packages/aria_mcp/config.py +111 -0
  313. aria_code/packages/aria_mcp/installer.py +95 -0
  314. aria_code/packages/aria_mcp/server.py +1550 -0
  315. aria_code/packages/aria_mcp/tools.py +81 -0
  316. aria_code/packages/aria_sdk/__init__.py +19 -0
  317. aria_code/packages/aria_sdk/client.py +396 -0
  318. aria_code/packages/aria_sdk/providers.py +70 -0
  319. aria_code/packages/aria_sdk/streaming.py +79 -0
  320. aria_code/packages/aria_sdk/types.py +86 -0
  321. aria_code/packages/aria_services/__init__.py +92 -0
  322. aria_code/packages/aria_services/cache.py +60 -0
  323. aria_code/packages/aria_services/context.py +356 -0
  324. aria_code/packages/aria_services/context_checkpoints.py +157 -0
  325. aria_code/packages/aria_services/data.py +11 -0
  326. aria_code/packages/aria_services/provider_health.py +268 -0
  327. aria_code/packages/aria_services/references.py +247 -0
  328. aria_code/packages/aria_services/registry.py +249 -0
  329. aria_code/packages/aria_services/research_protocol.py +57 -0
  330. aria_code/packages/aria_services/research_quality.py +186 -0
  331. aria_code/packages/aria_services/settings.py +157 -0
  332. aria_code/packages/aria_services/usage.py +151 -0
  333. aria_code/packages/aria_skills/__init__.py +46 -0
  334. aria_code/packages/aria_skills/catalog.py +149 -0
  335. aria_code/packages/aria_skills/loader.py +455 -0
  336. aria_code/packages/aria_skills/registry.py +84 -0
  337. aria_code/packages/aria_tools/__init__.py +5 -0
  338. aria_code/packages/aria_tools/financial/__init__.py +8 -0
  339. aria_code/packages/aria_tools/financial/_paths.py +130 -0
  340. aria_code/packages/aria_tools/financial/compliance.py +31 -0
  341. aria_code/packages/aria_tools/financial/factors.py +33 -0
  342. aria_code/packages/aria_tools/financial/risk_tools.py +33 -0
  343. aria_code/packages/aria_tools/financial/strategy.py +31 -0
  344. aria_code/packages/aria_tools/registry.py +128 -0
  345. aria_code/packages/quant_engine/__init__.py +34 -0
  346. aria_code/packages/quant_engine/_namespace.py +62 -0
  347. aria_code/packages/quant_engine/backtest/__init__.py +14 -0
  348. aria_code/packages/quant_engine/backtest/core.py +53 -0
  349. aria_code/packages/quant_engine/backtest/engine.py +96 -0
  350. aria_code/packages/quant_engine/portfolio/__init__.py +13 -0
  351. aria_code/packages/quant_engine/portfolio/optimizer.py +85 -0
  352. aria_code/packages/quant_engine/sports/__init__.py +80 -0
  353. aria_code/packages/quant_engine/sports/calibrator.py +354 -0
  354. aria_code/packages/quant_engine/sports/dixon_coles.py +234 -0
  355. aria_code/packages/quant_engine/sports/elo.py +300 -0
  356. aria_code/packages/quant_engine/sports/form.py +188 -0
  357. aria_code/packages/quant_engine/sports/h2h.py +195 -0
  358. aria_code/packages/quant_engine/sports/ml_model.py +377 -0
  359. aria_code/packages/quant_engine/sports/predictor.py +312 -0
  360. aria_code/packages/quant_engine/sports/tracker.py +665 -0
  361. aria_code/packages/quant_engine/stochastic/__init__.py +35 -0
  362. aria_code/packages/quant_engine/stochastic/gbm_enhanced.py +195 -0
  363. aria_code/packages/quant_engine/stochastic/ito_calculus.py +477 -0
  364. aria_code/packages/quant_engine/stochastic/kelly_criterion.py +181 -0
  365. aria_code/packages/quant_engine/stochastic/monte_carlo_advanced.py +95 -0
  366. aria_code/packages/quant_engine/stochastic/options_pricing.py +576 -0
  367. aria_code/packages/quant_engine/stochastic/stochastic_processes.py +90 -0
  368. aria_code/packs/__init__.py +85 -0
  369. aria_code/packs/base.py +168 -0
  370. aria_code/packs/finance/__init__.py +250 -0
  371. aria_code/packs/logistics/__init__.py +169 -0
  372. aria_code/packs/payments/__init__.py +139 -0
  373. aria_code/packs/realty/__init__.py +190 -0
  374. aria_code/packs/registry.py +202 -0
  375. aria_code/packs/rules.py +90 -0
  376. aria_code/plan_utils.py +194 -0
  377. aria_code/plugin_loader.py +328 -0
  378. aria_code/portfolio_ledger.py +4 -0
  379. aria_code/preview_server.py +449 -0
  380. aria_code/privacy/__init__.py +5 -0
  381. aria_code/privacy/feedback.py +123 -0
  382. aria_code/project_review.py +278 -0
  383. aria_code/project_review_api.py +235 -0
  384. aria_code/project_review_server.py +18 -0
  385. aria_code/project_tools.py +4 -0
  386. aria_code/providers/__init__.py +30 -0
  387. aria_code/providers/llm/__init__.py +19 -0
  388. aria_code/providers/llm/anthropic.py +184 -0
  389. aria_code/providers/llm/autoconfig.py +213 -0
  390. aria_code/providers/llm/base.py +139 -0
  391. aria_code/providers/llm/custom.py +158 -0
  392. aria_code/providers/llm/ollama.py +129 -0
  393. aria_code/providers/llm/openai_compat.py +313 -0
  394. aria_code/providers/llm/registry.py +444 -0
  395. aria_code/providers/local_image_provider.py +202 -0
  396. aria_code/providers/local_llm_provider.py +589 -0
  397. aria_code/realty_data_tools.py +4 -0
  398. aria_code/report_exporters.py +150 -0
  399. aria_code/report_generator.py +1764 -0
  400. aria_code/runtime/__init__.py +169 -0
  401. aria_code/runtime/acceptance.py +481 -0
  402. aria_code/runtime/agent_loop.py +1520 -0
  403. aria_code/runtime/approval.py +57 -0
  404. aria_code/runtime/budget.py +232 -0
  405. aria_code/runtime/checkpoints.py +432 -0
  406. aria_code/runtime/crash_report.py +174 -0
  407. aria_code/runtime/events.py +113 -0
  408. aria_code/runtime/gateway.py +150 -0
  409. aria_code/runtime/lsp.py +484 -0
  410. aria_code/runtime/orchestrator.py +55 -0
  411. aria_code/runtime/repo_map.py +700 -0
  412. aria_code/runtime/run_state.py +127 -0
  413. aria_code/runtime/run_store.py +450 -0
  414. aria_code/runtime/self_healing.py +422 -0
  415. aria_code/runtime/subagent.py +547 -0
  416. aria_code/runtime/task_ledger.py +86 -0
  417. aria_code/runtime/task_orchestrator.py +90 -0
  418. aria_code/runtime/tool_executor.py +217 -0
  419. aria_code/runtime/tool_policy.py +107 -0
  420. aria_code/runtime/worktrees.py +215 -0
  421. aria_code/runway_video_client.py +4 -0
  422. aria_code/safety/__init__.py +23 -0
  423. aria_code/safety/permissions.py +306 -0
  424. aria_code/safety/service.py +102 -0
  425. aria_code/setup_wizard.py +673 -0
  426. aria_code/spreadsheet_tools.py +4 -0
  427. aria_code/strategy_vault.py +4 -0
  428. aria_code/tools/__init__.py +0 -0
  429. aria_code/tools/artifact_tools.py +252 -0
  430. aria_code/tools/broker_tools.py +92 -0
  431. aria_code/tools/build_quant_engine.py +97 -0
  432. aria_code/tools/code_audit_tools.py +192 -0
  433. aria_code/tools/computer_use_tools.py +504 -0
  434. aria_code/tools/data_analysis_tools.py +809 -0
  435. aria_code/tools/enterprise_finance_tools.py +156 -0
  436. aria_code/tools/extended_tools.py +240 -0
  437. aria_code/tools/file_analysis_tools.py +885 -0
  438. aria_code/tools/image_gen_tools.py +114 -0
  439. aria_code/tools/local_finance_tools.py +3417 -0
  440. aria_code/tools/logistics_tools.py +135 -0
  441. aria_code/tools/macro_tools.py +369 -0
  442. aria_code/tools/notification_tools.py +249 -0
  443. aria_code/tools/project_tools.py +525 -0
  444. aria_code/tools/realty_data_tools.py +659 -0
  445. aria_code/tools/spreadsheet_tools.py +388 -0
  446. aria_code/tools/stripe_tools.py +115 -0
  447. aria_code/ui/__init__.py +105 -0
  448. aria_code/ui/banner.py +508 -0
  449. aria_code/ui/completer.py +501 -0
  450. aria_code/ui/console.py +281 -0
  451. aria_code/ui/image_render.py +243 -0
  452. aria_code/ui/input_box.py +488 -0
  453. aria_code/ui/picker.py +201 -0
  454. aria_code/ui/render/__init__.py +11 -0
  455. aria_code/ui/render/finance.py +1705 -0
  456. aria_code/ui/render/market.py +225 -0
  457. aria_code/ui/render/output.py +775 -0
  458. aria_code/ui/render/responsive.py +75 -0
  459. aria_code/ui/render/team.py +354 -0
  460. aria_code/ui/robot.py +235 -0
  461. aria_code/ui/startup_dashboard.py +109 -0
  462. aria_code/utils/vscode_uri.py +37 -0
  463. aria_code/video_analysis.py +147 -0
  464. aria_code/video_editor.py +271 -0
  465. aria_code/workspace/__init__.py +6 -0
  466. aria_code/workspace/files.py +193 -0
  467. aria_code/workspace/verify.py +113 -0
  468. aria_code/workspace_changes.py +199 -0
  469. aria_code/workspace_context.py +233 -0
  470. aria_code/workspace_service.py +196 -0
  471. aria_code/workspace_tools.py +150 -0
  472. aria_code-0.52.0.dist-info/METADATA +237 -0
  473. aria_code-0.52.0.dist-info/RECORD +478 -0
  474. aria_code-0.52.0.dist-info/WHEEL +5 -0
  475. aria_code-0.52.0.dist-info/entry_points.txt +3 -0
  476. aria_code-0.52.0.dist-info/licenses/LICENSE +201 -0
  477. aria_code-0.52.0.dist-info/licenses/NOTICE +49 -0
  478. aria_code-0.52.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,480 @@
1
+ """WorkflowCommandsMixin — hooks, regen, undo, retry, note, review commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ import os
7
+ import pathlib
8
+ from datetime import datetime
9
+
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ import json
15
+ import asyncio
16
+ import datetime
17
+ import time
18
+ import shlex
19
+ from typing import Dict, Any, Optional
20
+
21
+ def _run_event_hook(*args, **kwargs):
22
+ from aria_cli import _run_event_hook as fn
23
+ return fn(*args, **kwargs)
24
+ def _load_hooks(*args, **kwargs):
25
+ from aria_cli import _load_hooks as fn
26
+ return fn(*args, **kwargs)
27
+ # display_path lives in ui.render.output; aria_cli only re-exports it under a
28
+ # private alias, so going through aria_cli was a pointless second hop.
29
+ from aria_code.ui.render.output import display_path as _display_path
30
+ def _get_MODELS():
31
+ from aria_code.apps.cli.model_catalog import MODELS as val
32
+ return val
33
+ def _get__HAS_JSON_HOOKS():
34
+ from aria_cli import _HAS_JSON_HOOKS as val
35
+ return val
36
+ def _tool_run_command(*args, **kwargs):
37
+ from aria_cli import _tool_run_command as fn
38
+ return fn(*args, **kwargs)
39
+ def resolve_model_key(*args, **kwargs):
40
+ from ..model_catalog import resolve_model_key as fn
41
+ return fn(*args, **kwargs)
42
+ def _load_project_context(*args, **kwargs):
43
+ from aria_code.apps.cli.helpers import _load_project_context as fn
44
+ return fn(*args, **kwargs)
45
+ def _fire_json_hook(*args, **kwargs):
46
+ from aria_cli import _fire_json_hook as fn
47
+ return fn(*args, **kwargs)
48
+ def _print_phase(*args, **kwargs):
49
+ from aria_cli import _print_phase as fn
50
+ return fn(*args, **kwargs)
51
+ def _get_CONFIG_DIR():
52
+ from aria_cli import CONFIG_DIR as val
53
+ return val
54
+
55
+ import json
56
+ import asyncio
57
+ import datetime
58
+ import time
59
+ import shlex
60
+ import sys
61
+ import os
62
+ from typing import Dict, Any, Optional
63
+
64
+
65
+ import json
66
+ import asyncio
67
+ import datetime
68
+ import time
69
+ import shlex
70
+ import sys
71
+ import os
72
+ from typing import Dict, Any, Optional
73
+
74
+
75
+ class WorkflowCommandsMixin:
76
+ """Mixin: interactive workflow and edit-review commands."""
77
+
78
+ def cmd_hooks(self, args: str):
79
+ global _JSON_HOOKS
80
+ hooks_dirs = [
81
+ _get_CONFIG_DIR() / "hooks",
82
+ pathlib.Path.cwd() / ".aria" / "hooks",
83
+ ]
84
+ parts = args.strip().split(maxsplit=1)
85
+ sub = parts[0].lower() if parts else "list"
86
+ rest = parts[1].strip() if len(parts) > 1 else ""
87
+
88
+ if sub == "reload":
89
+ if _get__HAS_JSON_HOOKS():
90
+ try:
91
+ _JSON_HOOKS = _load_hooks()
92
+ n = sum(len(v) for v in _JSON_HOOKS.values())
93
+ if self.context.has_rich:
94
+ self.context.console.print(f" [green]✓[/green] [dim]hooks.json reloaded ({n} entries)[/dim]")
95
+ else:
96
+ print(f" hooks.json reloaded ({n} entries)")
97
+ except Exception as exc:
98
+ if self.context.has_rich:
99
+ self.context.console.print(f" [red]✗ reload failed: {exc}[/red]")
100
+ else:
101
+ print(f" reload failed: {exc}")
102
+ return
103
+
104
+ if sub == "list":
105
+ if _get__HAS_JSON_HOOKS():
106
+ try:
107
+ from apps.cli.hooks import list_hooks as _list_json_hooks
108
+ _json_rows = _list_json_hooks()
109
+ if _json_rows:
110
+ if self.context.has_rich:
111
+ self.context.console.print()
112
+ self.context.console.print(" [bold]JSON Hooks[/bold] [dim](~/.arthera/hooks.json)[/dim]")
113
+ for r in _json_rows:
114
+ _block = " [red][blocking][/red]" if r["blocking"] else ""
115
+ _tool = f"[{r['tool']}]" if r["tool"] != "*" else ""
116
+ self.context.console.print(
117
+ f" [cyan]{r['event']:<16}[/cyan]{_tool:<14} "
118
+ f"[dim]{r['command']}[/dim]{_block}"
119
+ )
120
+ else:
121
+ for r in _json_rows:
122
+ print(f" {r['event']:<16} {r['tool']:<12} {r['command']}")
123
+ except Exception:
124
+ pass
125
+
126
+ found: list[tuple] = []
127
+ for hdir in hooks_dirs:
128
+ if hdir.exists():
129
+ for f in sorted(hdir.iterdir()):
130
+ if f.is_file() and not f.name.startswith("."):
131
+ found.append((str(hdir), f.name, str(f)))
132
+ if not found:
133
+ if self.context.has_rich:
134
+ self.context.console.print(" [dim]No hooks found.[/dim]")
135
+ self.context.console.print(" [dim]Hook dirs:[/dim]")
136
+ for d in hooks_dirs:
137
+ self.context.console.print(f" [dim]{_display_path(d, fallback='hook dir')}[/dim]")
138
+ self.context.console.print(" [dim]Events: prompt_submit response_done tool_use compact[/dim]")
139
+ else:
140
+ print("No hooks. Dirs:", [str(d) for d in hooks_dirs])
141
+ return
142
+ if self.context.has_rich:
143
+ self.context.console.print()
144
+ for hdir, name, path in found:
145
+ self.context.console.print(f" [dim]{name:<28}[/dim] {_display_path(path, fallback='hook')}")
146
+ self.context.console.print()
147
+ else:
148
+ for hdir, name, path in found:
149
+ print(f" {name} {_display_path(path, fallback='hook')}")
150
+
151
+ elif sub == "edit":
152
+ if not rest:
153
+ if _get__HAS_JSON_HOOKS():
154
+ from apps.cli.hooks import hooks_file_path, create_example_hooks
155
+ _hpath = hooks_file_path("global")
156
+ create_example_hooks(_hpath)
157
+ editor = os.getenv("EDITOR", "nano")
158
+ try:
159
+ import subprocess as _sp
160
+ _sp.run([editor, str(_hpath)])
161
+ _JSON_HOOKS = _load_hooks()
162
+ except Exception as exc:
163
+ if self.context.has_rich:
164
+ self.context.console.print(f"[red]Could not open editor: {exc}[/red]")
165
+ else:
166
+ print(f"Could not open editor: {exc}")
167
+ return
168
+ event = rest
169
+ hdir = _get_CONFIG_DIR() / "hooks"
170
+ hdir.mkdir(parents=True, exist_ok=True)
171
+ script = hdir / f"{event}.sh"
172
+ if not script.exists():
173
+ script.write_text(
174
+ f"#!/bin/bash\n# Aria hook: {event}\n# "
175
+ f"Env vars: ARIA_EVENT ARIA_TOOL ARIA_TOOL_PARAMS ARIA_RESPONSE ARIA_SESSION\n\n"
176
+ f'echo "Hook {event} fired"\n',
177
+ encoding="utf-8"
178
+ )
179
+ script.chmod(0o755)
180
+ editor = os.getenv("EDITOR", "nano")
181
+ try:
182
+ import subprocess as _sp
183
+ _sp.run([editor, str(script)])
184
+ except Exception as exc:
185
+ self.context.console.print(f"[red]Could not open editor: {exc}[/red]" if self.context.has_rich else str(exc))
186
+
187
+ elif sub == "run":
188
+ event = rest or "ResponseDone"
189
+ if _get__HAS_JSON_HOOKS():
190
+ _fire_json_hook(event, session_id=getattr(self.terminal, "session_id", ""), hooks=_JSON_HOOKS)
191
+ _run_event_hook(event, {"ARIA_EVENT": event, "ARIA_SESSION": getattr(self.terminal, "session_id", "")})
192
+ if self.context.has_rich:
193
+ self.context.console.print(f" [dim]Hook '{event}' triggered[/dim]")
194
+ else:
195
+ print(f"Hook '{event}' triggered")
196
+
197
+ else:
198
+ if self.context.has_rich:
199
+ self.context.console.print("[dim]Usage: /hooks list|edit [event]|reload|run [event][/dim]")
200
+ else:
201
+ print("Usage: /hooks list|edit [event]|reload|run [event]")
202
+
203
+ async def cmd_regen(self, args: str):
204
+ last_user_msg = None
205
+ for i in range(len(self.terminal.conversation) - 1, -1, -1):
206
+ if self.terminal.conversation[i]["role"] == "assistant":
207
+ self.terminal.conversation.pop(i)
208
+ break
209
+ for msg in reversed(self.terminal.conversation):
210
+ if msg["role"] == "user":
211
+ last_user_msg = msg["content"]
212
+ break
213
+ if last_user_msg:
214
+ for i in range(len(self.terminal.conversation) - 1, -1, -1):
215
+ if self.terminal.conversation[i]["role"] == "user" and self.terminal.conversation[i]["content"] == last_user_msg:
216
+ self.terminal.conversation.pop(i)
217
+ break
218
+ self.context.console.print("[dim]Regenerating...[/dim]" if self.context.has_rich else "Regenerating...")
219
+ await self.terminal.send_message(last_user_msg)
220
+ else:
221
+ self.context.console.print("[dim]No message to regenerate[/dim]" if self.context.has_rich else "Nothing to regenerate")
222
+
223
+ def cmd_undo(self, args: str):
224
+ if len(self.terminal.conversation) < 2:
225
+ self.context.console.print("[dim]Nothing to undo[/dim]" if self.context.has_rich else "Nothing to undo")
226
+ return
227
+ removed = 0
228
+ for role in ("assistant", "user"):
229
+ for i in range(len(self.terminal.conversation) - 1, -1, -1):
230
+ if self.terminal.conversation[i]["role"] == role:
231
+ self.terminal.conversation.pop(i)
232
+ removed += 1
233
+ break
234
+ if self.context.has_rich:
235
+ self.context.console.print(f"[dim]Undone ({removed} messages removed, {len(self.terminal.conversation)} remaining)[/dim]")
236
+ else:
237
+ print(f"Undone ({removed} removed)")
238
+
239
+ def cmd_rewind(self, args: str):
240
+ """Restore code checkpoints, conversation history, or both."""
241
+ from runtime.checkpoints import (
242
+ CheckpointConflictError,
243
+ CheckpointNotFoundError,
244
+ CheckpointStore,
245
+ )
246
+
247
+ parts = [part for part in args.strip().split() if part]
248
+ assume_yes = "--yes" in parts or "-y" in parts
249
+ parts = [part for part in parts if part not in {"--yes", "-y"}]
250
+ mode = parts[0].lower() if parts else "code"
251
+ identifier = parts[1] if len(parts) > 1 else ""
252
+ is_zh = str(self.terminal.config.get("ui_lang", "en")).lower().startswith("zh")
253
+
254
+ if mode in {"conversation", "chat"}:
255
+ self.cmd_undo("")
256
+ return
257
+ if mode not in {"code", "both", "list"}:
258
+ identifier = parts[0]
259
+ mode = "code"
260
+
261
+ try:
262
+ store = CheckpointStore()
263
+ except Exception as exc:
264
+ message = f"无法打开检查点存储: {exc}" if is_zh else f"Cannot open checkpoint store: {exc}"
265
+ self.context.console.print(f"[red]{message}[/red]" if self.context.has_rich else message)
266
+ return
267
+
268
+ if mode == "list":
269
+ records = store.list(session_id=self.terminal.session_id, status="active", limit=12)
270
+ if not records:
271
+ records = store.list(status="active", limit=12)
272
+ if not records:
273
+ message = "没有可恢复的代码检查点" if is_zh else "No active code checkpoints"
274
+ self.context.console.print(f"[dim]{message}[/dim]" if self.context.has_rich else message)
275
+ return
276
+ if self.context.has_rich:
277
+ self.context.console.print()
278
+ self.context.console.print(" [bold]Code checkpoints[/bold]")
279
+ for record in records:
280
+ paths = ", ".join(pathlib.Path(item.path).name for item in record.files)
281
+ run_label = (record.run_id or "standalone")[:10]
282
+ self.context.console.print(
283
+ f" [#C08050]{record.checkpoint_id[:10]}[/#C08050] "
284
+ f"[dim]{run_label:<10} · {record.source:<10} · {paths}[/dim]"
285
+ )
286
+ self.context.console.print()
287
+ else:
288
+ for record in records:
289
+ paths = ", ".join(pathlib.Path(item.path).name for item in record.files)
290
+ print(f"{record.checkpoint_id[:10]} {record.run_id or '-'} {record.source} {paths}")
291
+ return
292
+
293
+ if not assume_yes:
294
+ prompt = (
295
+ " 恢复代码到检查点状态?检查点之后的修改不会被覆盖,存在冲突时会停止。 [y/N] "
296
+ if is_zh else
297
+ " Rewind code to its checkpoint? Later changes are protected by conflict checks. [y/N] "
298
+ )
299
+ try:
300
+ answer = (self.context.console.input(prompt) if self.context.has_rich else input(prompt)).strip().lower()
301
+ except (EOFError, KeyboardInterrupt):
302
+ return
303
+ if answer not in {"y", "yes"}:
304
+ message = "已取消" if is_zh else "Cancelled"
305
+ self.context.console.print(f"[dim]{message}[/dim]" if self.context.has_rich else message)
306
+ return
307
+
308
+ try:
309
+ if identifier:
310
+ checkpoint = store.get(identifier)
311
+ if checkpoint is not None:
312
+ result = store.restore_checkpoint(checkpoint.checkpoint_id)
313
+ else:
314
+ result = store.restore_run(identifier)
315
+ else:
316
+ try:
317
+ result = store.restore_latest(session_id=self.terminal.session_id)
318
+ except CheckpointNotFoundError:
319
+ result = store.restore_latest()
320
+ except CheckpointConflictError as exc:
321
+ message = f"恢复已停止: {exc}" if is_zh else f"Rewind stopped: {exc}"
322
+ self.context.console.print(f"[red]{message}[/red]" if self.context.has_rich else message)
323
+ return
324
+ except CheckpointNotFoundError:
325
+ message = "未找到可恢复的检查点" if is_zh else "No restorable checkpoint found"
326
+ self.context.console.print(f"[dim]{message}[/dim]" if self.context.has_rich else message)
327
+ return
328
+ except Exception as exc:
329
+ message = f"恢复失败: {exc}" if is_zh else f"Rewind failed: {exc}"
330
+ self.context.console.print(f"[red]{message}[/red]" if self.context.has_rich else message)
331
+ return
332
+
333
+ if mode == "both":
334
+ self.cmd_undo("")
335
+ count = len(result.restored_paths)
336
+ message = (
337
+ f"已恢复 {count} 个文件" if is_zh else f"Rewound {count} file{'s' if count != 1 else ''}"
338
+ )
339
+ if self.context.has_rich:
340
+ self.context.console.print(f"[green]✓[/green] [dim]{message}[/dim]")
341
+ for path in result.restored_paths:
342
+ self.context.console.print(f" [dim]{path}[/dim]")
343
+ else:
344
+ print(message)
345
+ for path in result.restored_paths:
346
+ print(f" {path}")
347
+
348
+ async def cmd_retry(self, args: str):
349
+ last_user_msg = None
350
+ for i in range(len(self.terminal.conversation) - 1, -1, -1):
351
+ if self.terminal.conversation[i]["role"] == "assistant":
352
+ self.terminal.conversation.pop(i)
353
+ break
354
+ for msg in reversed(self.terminal.conversation):
355
+ if msg["role"] == "user":
356
+ last_user_msg = msg["content"]
357
+ break
358
+ if not last_user_msg:
359
+ self.context.console.print("[dim]No message to retry[/dim]" if self.context.has_rich else "Nothing to retry")
360
+ return
361
+ for i in range(len(self.terminal.conversation) - 1, -1, -1):
362
+ if self.terminal.conversation[i]["role"] == "user" and self.terminal.conversation[i]["content"] == last_user_msg:
363
+ self.terminal.conversation.pop(i)
364
+ break
365
+ orig_model_key = resolve_model_key(self.terminal.config.get("model", "qwen2.5:7b"))
366
+ _fallback_model = _get_MODELS().get("qwen-fast") or _get_MODELS().get("qwen7b") or next(iter(_get_MODELS().values()))
367
+ orig_temp = _get_MODELS().get(orig_model_key, _fallback_model).get("temperature", 0.3)
368
+ _get_MODELS()[orig_model_key]["temperature"] = min(0.9, orig_temp + 0.3)
369
+ if self.context.has_rich:
370
+ self.context.console.print(f"[dim]Retrying with temperature {_get_MODELS()[orig_model_key]['temperature']:.1f}...[/dim]")
371
+ else:
372
+ print("Retrying (temp +0.3)...")
373
+ try:
374
+ await self.terminal.send_message(last_user_msg)
375
+ finally:
376
+ _get_MODELS()[orig_model_key]["temperature"] = orig_temp
377
+
378
+ def cmd_note(self, args: str):
379
+ text = args.strip()
380
+ if not text:
381
+ self.context.console.print("[dim]Usage: /note <text>[/dim]" if self.context.has_rich else "Usage: /note <text>")
382
+ return
383
+ aria_md = pathlib.Path.cwd() / "ARIA.md"
384
+ now_str = datetime.now().strftime("%Y-%m-%d %H:%M")
385
+ entry = f"\n- [{now_str}] {text}"
386
+ if aria_md.exists():
387
+ content = aria_md.read_text(encoding="utf-8")
388
+ if "## Notes" not in content:
389
+ content += "\n\n## Notes\n"
390
+ content += entry
391
+ else:
392
+ content = f"# Aria Project Notes\n\n## Notes\n{entry}\n"
393
+ aria_md.write_text(content, encoding="utf-8")
394
+ global _PROJECT_CONTEXT
395
+ _PROJECT_CONTEXT = _load_project_context()
396
+ if self.context.has_rich:
397
+ self.context.console.print(f"[dim]Note saved to {aria_md.name}[/dim]")
398
+ else:
399
+ print(f"Saved to {aria_md.name}")
400
+
401
+ async def cmd_review(self, args: str):
402
+ raw = args.strip()
403
+ policy = self.terminal.config.get("command_policy", "safe")
404
+
405
+ if raw and not raw.startswith("--"):
406
+ p = pathlib.Path(raw).expanduser()
407
+ if not p.exists():
408
+ msg = f"File not found: {raw}"
409
+ self.context.console.print(f"[red]{msg}[/red]") if self.context.has_rich else print(msg)
410
+ return
411
+ _print_phase("Reading file")
412
+ try:
413
+ content = p.read_text(errors="replace")[:12000]
414
+ except Exception as e:
415
+ self.context.console.print(f"[red]Cannot read file: {e}[/red]") if self.context.has_rich else print(f"Cannot read: {e}")
416
+ return
417
+ line_count = content.count("\n")
418
+ if self.context.has_rich:
419
+ self.context.console.print(f" [dim]↳ {p.name} · {line_count} lines[/dim]")
420
+ _print_phase("AI Review")
421
+ prompt = (
422
+ f"请对以下 `{p.name}` 的代码进行专业审查,查找 Bug、安全问题和改进点。\n"
423
+ f"每条发现用严重程度标签开头:**BUG**、**IMPROVEMENT**、**NIT**。\n"
424
+ f"按文件组织输出,直接给结论,不要重复贴出全部代码。\n\n"
425
+ f"```\n{content}\n```"
426
+ )
427
+ review_source, review_name, review_is_diff = content, p.name, False
428
+ else:
429
+ diff_cmd = "git diff --staged" if raw.startswith("--staged") else "git diff HEAD"
430
+ _print_phase("Reading diff")
431
+ tr = _tool_run_command({"command": diff_cmd})
432
+ if not tr.get("success"):
433
+ msg = tr.get("error", "git diff failed")
434
+ self.context.console.print(f"[red]{msg}[/red]") if self.context.has_rich else print(msg)
435
+ return
436
+ diff_text = (tr.get("data") or {}).get("stdout", "").strip()
437
+ if not diff_text:
438
+ self.context.console.print("[dim]No changes to review.[/dim]") if self.context.has_rich else print("No changes to review.")
439
+ return
440
+ _adds = diff_text.count("\n+") - diff_text.count("\n+++")
441
+ _dels = diff_text.count("\n-") - diff_text.count("\n---")
442
+ _files = diff_text.count("\ndiff --git")
443
+ if self.context.has_rich:
444
+ self.context.console.print(f" [dim]↳ {_files} files · +{_adds} −{_dels} lines[/dim]")
445
+ diff_text = diff_text[:12000]
446
+ _print_phase("AI Review")
447
+ prompt = (
448
+ "请审查以下 git diff,找出 Bug、潜在回归、安全问题和代码质量问题。\n"
449
+ "每条发现用严重程度标签开头:**BUG**、**IMPROVEMENT**、**NIT**。\n"
450
+ "按文件分组,直接给出结论。\n\n"
451
+ f"```diff\n{diff_text}\n```"
452
+ )
453
+ review_source, review_name, review_is_diff = diff_text, "staged.diff", True
454
+
455
+ # Run a bounded, deterministic first pass. The conversational model
456
+ # receives it as evidence and must not pretend it accessed anything
457
+ # beyond the supplied file or diff.
458
+ try:
459
+ from agents.code_review import CodeReviewAgent
460
+
461
+ findings = CodeReviewAgent.review_source(
462
+ review_source,
463
+ filename=review_name,
464
+ is_diff=review_is_diff,
465
+ )
466
+ static_review = CodeReviewAgent.format_findings(findings)
467
+ if self.context.has_rich:
468
+ self.context.console.print("[bold]Deterministic Review[/bold]")
469
+ self.context.console.print(static_review)
470
+ else:
471
+ print("Deterministic Review\n" + static_review)
472
+ prompt = (
473
+ "以下是只基于提交文本的确定性检查结果。保留有证据的发现,补充语义、"
474
+ "回归和可测试性审查;不要声称执行过测试或读取过其他文件。\n\n"
475
+ f"{static_review}\n\n{prompt}"
476
+ )
477
+ except Exception as exc:
478
+ logger.debug("Deterministic review unavailable: %s", exc)
479
+
480
+ await self.terminal.send_message(prompt)