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,488 @@
1
+ """Prompt-toolkit input panel — lightweight Claude Code-style input block.
2
+
3
+ Layout:
4
+ ────────────────────────────────────────────── ← subtle top rule
5
+ › cursor_ ← padded input row
6
+ ────────────────────────────────────────────── ← subtle bottom rule
7
+ model · ~/workspace ← dim status bar
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import asyncio
13
+ import os
14
+ import shutil
15
+ import subprocess
16
+ import sys
17
+ import time
18
+ from contextlib import contextmanager
19
+ from dataclasses import dataclass, replace
20
+ from typing import Callable, Optional
21
+
22
+ try:
23
+ from prompt_toolkit.application import Application
24
+ from prompt_toolkit.buffer import Buffer
25
+ from prompt_toolkit.key_binding import KeyBindings
26
+ from prompt_toolkit.layout.dimension import Dimension
27
+ from prompt_toolkit.layout import Float, FloatContainer, HSplit, Layout, VSplit, Window
28
+ from prompt_toolkit.layout.controls import FormattedTextControl
29
+ from prompt_toolkit.layout.menus import CompletionsMenu
30
+ from prompt_toolkit.layout.processors import Processor, Transformation
31
+ from prompt_toolkit.styles import Style
32
+ from prompt_toolkit.widgets import TextArea
33
+ HAS_PROMPT_TOOLKIT = True
34
+ except ImportError:
35
+ HAS_PROMPT_TOOLKIT = False
36
+
37
+ class Processor: # type: ignore[no-redef]
38
+ pass
39
+
40
+ class Transformation: # type: ignore[no-redef]
41
+ def __init__(self, fragments, source_to_display=None, display_to_source=None):
42
+ self.fragments = fragments
43
+ self.source_to_display = source_to_display or (lambda i: i)
44
+ self.display_to_source = display_to_source or (lambda i: i)
45
+
46
+ class Style: # type: ignore[no-redef]
47
+ @staticmethod
48
+ def from_dict(values):
49
+ return values
50
+
51
+ Application = Buffer = KeyBindings = Dimension = None # type: ignore
52
+ Float = FloatContainer = HSplit = Layout = VSplit = Window = None # type: ignore
53
+ FormattedTextControl = CompletionsMenu = TextArea = None # type: ignore
54
+
55
+
56
+ # ── Theme detection ────────────────────────────────────────────────────────────
57
+
58
+ def detect_terminal_theme() -> str:
59
+ explicit = os.getenv("ARIA_INPUT_THEME", "").strip().lower()
60
+ if explicit in {"dark", "light"}:
61
+ return explicit
62
+ colorfgbg = os.getenv("COLORFGBG", "")
63
+ if colorfgbg:
64
+ try:
65
+ return "dark" if int(colorfgbg.split(";")[-1]) < 8 else "light"
66
+ except ValueError:
67
+ pass
68
+ if os.getenv("TERM_PROGRAM", "") == "Apple_Terminal":
69
+ return "light"
70
+ # os.uname() is Unix-only — doesn't exist on Windows at all.
71
+ if sys.platform == "darwin":
72
+ try:
73
+ r = subprocess.run(
74
+ ["defaults", "read", "-g", "AppleInterfaceStyle"],
75
+ capture_output=True, text=True, timeout=0.2, check=False,
76
+ )
77
+ return "dark" if (r.returncode == 0 and "dark" in r.stdout.lower()) else "light"
78
+ except Exception:
79
+ pass
80
+ return "dark"
81
+
82
+
83
+ # ── Config ─────────────────────────────────────────────────────────────────────
84
+
85
+ @dataclass
86
+ class PanelInputConfig:
87
+ prompt: str = "› "
88
+ placeholder: str = ""
89
+ theme: str = "auto"
90
+ lang: str = "en"
91
+
92
+ est_tokens: int = 0
93
+ max_tokens: int = 131072
94
+
95
+ # Status bar display
96
+ model_label: str = ""
97
+ cwd: str = ""
98
+
99
+ # Robot mascot — show animated dot in status bar
100
+ show_robot: bool = True
101
+
102
+ # Legacy fields kept for call-site compatibility
103
+ privacy: str = "local-only"
104
+ tools_count: int = 0
105
+ skills_count: int = 0
106
+ ollama_status: str = ""
107
+ pending_file: str = ""
108
+ permission_mode: str = "workspace-write"
109
+ git_branch: str = ""
110
+ git_dirty: bool = False
111
+ mcp_running: int = 0
112
+ mcp_total: int = 0
113
+ mcp_tool_count: int = 0
114
+
115
+ # Resolved by .resolved()
116
+ fg: str = ""
117
+ accent: str = ""
118
+ accent_y: str = ""
119
+ accent_b: str = ""
120
+ muted: str = ""
121
+ dim: str = ""
122
+ sep: str = ""
123
+ input_bg: str = "" # intentional input-area background
124
+ ph_color: str = "" # very dim placeholder
125
+ box: str = "" # rounded border color
126
+
127
+ # Completion menu palette (copper, theme-aware)
128
+ menu_bg: str = ""
129
+ menu_fg: str = ""
130
+ menu_sel_bg: str = ""
131
+ menu_sel_fg: str = ""
132
+ menu_meta: str = ""
133
+ menu_meta_cur: str = ""
134
+ scroll_bg: str = ""
135
+ scroll_btn: str = ""
136
+ hi: str = "" # fuzzy-match highlight (copper)
137
+
138
+ def resolved(self) -> "PanelInputConfig":
139
+ theme = self.theme if self.theme != "auto" else detect_terminal_theme()
140
+ is_zh = self.lang.lower().startswith("zh")
141
+ placeholder = self.placeholder or (
142
+ "问 Aria、编辑文件或运行命令… / 命令 @ 上下文 ! shell"
143
+ if is_zh
144
+ else "Ask Aria, edit files, or run commands… / commands @ context ! shell"
145
+ )
146
+ if theme == "dark":
147
+ return replace(self, theme=theme, placeholder=placeholder,
148
+ fg="#ffffff",
149
+ accent="#3fb950", accent_y="#d29922", accent_b="#79c0ff",
150
+ muted="#6e7781", dim="#484f58", sep="#2d333b",
151
+ input_bg="default", # transparent — box border defines the zone
152
+ ph_color="#6e7781", # secondary text, readable on dark terminals
153
+ box="#C08050", # copper — Aria's brand accent on the frame
154
+ menu_bg="#161b22", menu_fg="#c9d1d9",
155
+ menu_sel_bg="#3a2e20", menu_sel_fg="#e8c9a6",
156
+ menu_meta="#6e7681", menu_meta_cur="#c0a585",
157
+ scroll_bg="#161b22", scroll_btn="#C08050",
158
+ hi="#C08050",
159
+ )
160
+ return replace(self, theme="light", placeholder=placeholder,
161
+ fg="#24292f",
162
+ accent="#1a7f37", accent_y="#9a6700", accent_b="#0969da",
163
+ muted="#57606a", dim="#8c959f", sep="#d0d7de",
164
+ input_bg="default",
165
+ ph_color="#6e7781",
166
+ box="#9a6700",
167
+ menu_bg="#f2eee4", menu_fg="#24292f",
168
+ menu_sel_bg="#e7e1d3", menu_sel_fg="#8a5a00",
169
+ menu_meta="#6e7781", menu_meta_cur="#8a5a00",
170
+ scroll_bg="#e7e1d3", scroll_btn="#9a6700",
171
+ hi="#9a6700",
172
+ )
173
+
174
+
175
+ # ── Processor (mode badge + placeholder) ──────────────────────────────────────
176
+
177
+ class PromptAndPlaceholderProcessor(Processor):
178
+ def __init__(self, get_prefix: Callable[[], list], placeholder: str,
179
+ is_empty: Callable[[], bool]) -> None:
180
+ self.get_prefix = get_prefix
181
+ self.placeholder = placeholder
182
+ self.is_empty = is_empty
183
+
184
+ def apply_transformation(self, ti) -> Transformation:
185
+ if ti.lineno == 0:
186
+ empty = self.is_empty()
187
+ prefix = self.get_prefix()
188
+ pw = sum(len(t) for _, t in prefix)
189
+ frags = list(prefix)
190
+ if empty:
191
+ frags.append(("class:ph", self.placeholder))
192
+ frags.extend(ti.fragments)
193
+ return Transformation(
194
+ frags,
195
+ source_to_display=lambda i: pw + i,
196
+ display_to_source=lambda i: 0 if (i <= pw or empty) else max(0, i - pw),
197
+ )
198
+ return Transformation(ti.fragments)
199
+
200
+
201
+ PlaceholderProcessor = PromptAndPlaceholderProcessor
202
+
203
+
204
+ INPUT_MAX_HEIGHT = 6
205
+
206
+
207
+ # ── Style ──────────────────────────────────────────────────────────────────────
208
+
209
+ def _build_style(cfg: PanelInputConfig) -> Style:
210
+ return Style.from_dict({
211
+ # Input row: transparent bg — the rounded box border defines the zone
212
+ "input-bg": cfg.fg if cfg.input_bg == "default" else f"{cfg.fg} bg:{cfg.input_bg}",
213
+ "ph": cfg.ph_color,
214
+ # Rounded box border (Claude Code style)
215
+ "box": cfg.box,
216
+ # Mode prompt glyph — always copper (brand). 5-color discipline:
217
+ # red/green are reserved for 涨跌 semantics, never for chrome.
218
+ "mode-chat": f"bold {cfg.box}",
219
+ "mode-cmd": f"bold {cfg.box}",
220
+ "mode-file": f"bold {cfg.box}",
221
+ "prompt": cfg.muted,
222
+ # Divider (transparent bg — terminal bg shows through)
223
+ "divider": cfg.sep,
224
+ # Status bar (transparent bg)
225
+ "st-model": cfg.muted,
226
+ "st-sep": cfg.dim,
227
+ "st-cwd": cfg.dim,
228
+ "tok-warn": cfg.box, # copper — context-pressure caution
229
+ "tok-crit": "#f85149", # red — critical only
230
+ # Completion menu — theme-aware copper palette (matches terminal theme)
231
+ "completion-menu": f"bg:{cfg.menu_bg} {cfg.menu_fg}",
232
+ "completion-menu.completion": f"bg:{cfg.menu_bg} {cfg.menu_fg}",
233
+ "completion-menu.completion.current": f"bg:{cfg.menu_sel_bg} {cfg.menu_sel_fg} bold",
234
+ "completion-menu.meta.completion": f"bg:{cfg.menu_bg} {cfg.menu_meta}",
235
+ "completion-menu.meta.completion.current": f"bg:{cfg.menu_sel_bg} {cfg.menu_meta_cur}",
236
+ "completion-menu.multi-column-meta": f"bg:{cfg.menu_bg} {cfg.menu_meta}",
237
+ "scrollbar.background": f"bg:{cfg.scroll_bg}",
238
+ "scrollbar.button": f"bg:{cfg.scroll_btn}",
239
+ # Fuzzy-match highlight classes (shared with ui/completer.py) — copper
240
+ "fz-hi": f"bold {cfg.hi}",
241
+ "fz-cat": cfg.dim,
242
+ })
243
+
244
+
245
+ # ── Row builders ───────────────────────────────────────────────────────────────
246
+
247
+ def _input_rule(cfg: PanelInputConfig) -> list:
248
+ w = shutil.get_terminal_size((80, 24)).columns
249
+ return [("class:divider", "─" * w)]
250
+
251
+
252
+ def _input_pad() -> list:
253
+ return [("", " ")]
254
+
255
+
256
+ def _mode_prefix(cfg: PanelInputConfig, text_getter: Callable[[], str]) -> list:
257
+ """Claude Code-style › glyph — color shifts by detected input mode."""
258
+ txt = text_getter().lstrip()
259
+ if txt.startswith("/"):
260
+ return [("class:mode-cmd", "› ")]
261
+ if txt.startswith("@") or txt.startswith("!"):
262
+ return [("class:mode-file", "› ")]
263
+ return [("class:mode-chat", "› ")]
264
+
265
+
266
+ def _status_bar(cfg: PanelInputConfig) -> list:
267
+ """Compact runtime row: model · workspace · MCP · permissions · context."""
268
+ from .robot import get_status_dot
269
+
270
+ tick = int(time.monotonic() * 4) # 4 fps tick without a background thread
271
+ parts: list = []
272
+
273
+ if cfg.show_robot:
274
+ dot_frags = get_status_dot(tick)
275
+ parts.extend(dot_frags)
276
+ parts.append(("class:st-sep", " "))
277
+
278
+ width = shutil.get_terminal_size((80, 24)).columns
279
+ model_label = cfg.model_label
280
+ model_limit = 24 if width >= 90 else 19
281
+ if len(model_label) > model_limit:
282
+ model_label = model_label[: model_limit - 1] + "…"
283
+ if model_label:
284
+ parts.append(("class:st-model", model_label))
285
+
286
+ workspace = cfg.git_branch or os.path.basename(cfg.cwd.rstrip(os.sep))
287
+ if workspace:
288
+ if model_label:
289
+ parts.append(("class:st-sep", " · "))
290
+ if cfg.git_branch and cfg.git_dirty:
291
+ workspace += "*"
292
+ parts.append(("class:st-cwd", workspace))
293
+
294
+ if cfg.mcp_total:
295
+ mcp_label = (
296
+ f"MCP {cfg.mcp_tool_count}"
297
+ if cfg.mcp_running == cfg.mcp_total and cfg.mcp_tool_count
298
+ else f"MCP {cfg.mcp_running}/{cfg.mcp_total}"
299
+ )
300
+ parts += [("class:st-sep", " · "), ("class:st-cwd", mcp_label)]
301
+
302
+ is_zh = cfg.lang.lower().startswith("zh")
303
+ permission_labels = {
304
+ "read-only": "只读" if is_zh else "ro",
305
+ "workspace-write": "可写" if is_zh else "rw",
306
+ "full-access": "完整权限" if is_zh else "full",
307
+ }
308
+ permission = permission_labels.get(cfg.permission_mode, cfg.permission_mode)
309
+ if permission:
310
+ parts += [("class:st-sep", " · "), ("class:st-cwd", permission)]
311
+
312
+ ratio = cfg.est_tokens / max(cfg.max_tokens, 1)
313
+ tc = "tok-crit" if ratio >= 0.85 else ("tok-warn" if ratio >= 0.60 else "st-cwd")
314
+ # ratio<1% 一律显示 "<1%"(含估算为 0 的首帧)——"ctx 0%" 是误导:
315
+ # 系统提示/skills 一定占用了上下文,只是估算看不见。
316
+ context_prefix = "上下文" if is_zh else "ctx "
317
+ context_label = (
318
+ f"{context_prefix}<1%" if ratio < 0.01
319
+ else f"{context_prefix}{ratio:.0%}"
320
+ )
321
+ parts += [("class:st-sep", " · "), (f"class:{tc}", context_label)]
322
+
323
+ shortcuts = (
324
+ "? 快捷键 · / 命令 · @ 上下文 · ! shell"
325
+ if cfg.lang.lower().startswith("zh")
326
+ else "? shortcuts · / commands · @ context · ! shell"
327
+ )
328
+ used = sum(len(text) for _, text in parts)
329
+ if width >= 110 and used + len(shortcuts) + 4 <= width:
330
+ parts += [("class:st-sep", " "), ("class:st-cwd", shortcuts)]
331
+
332
+ return parts
333
+
334
+
335
+ # ── Main ───────────────────────────────────────────────────────────────────────
336
+
337
+ def _build_panel_input_application(
338
+ *,
339
+ completer=None,
340
+ history=None,
341
+ status_text: Callable[[], str] | str = "", # kept for compat
342
+ config: Optional[PanelInputConfig] = None,
343
+ ) -> Optional[Application]:
344
+ cfg = (config or PanelInputConfig()).resolved()
345
+ if not HAS_PROMPT_TOOLKIT:
346
+ return None
347
+
348
+ def _accept(buf: Buffer) -> bool:
349
+ app.exit(result=buf.text)
350
+ return True
351
+
352
+ def _get_text() -> str:
353
+ try:
354
+ return text_area.text
355
+ except Exception:
356
+ return ""
357
+
358
+ text_area = TextArea(
359
+ height=Dimension(min=1, max=INPUT_MAX_HEIGHT),
360
+ multiline=True,
361
+ wrap_lines=True,
362
+ dont_extend_height=True,
363
+ completer=completer,
364
+ complete_while_typing=True,
365
+ history=history,
366
+ prompt="",
367
+ input_processors=[
368
+ PromptAndPlaceholderProcessor(
369
+ lambda: _mode_prefix(cfg, _get_text),
370
+ cfg.placeholder,
371
+ lambda: _get_text() == "",
372
+ ),
373
+ ],
374
+ accept_handler=_accept,
375
+ style="class:input-bg", # only the input row gets the subtle bg
376
+ )
377
+
378
+ kb = KeyBindings()
379
+
380
+ @kb.add("escape")
381
+ def _cancel(event) -> None:
382
+ event.app.exit(result="")
383
+
384
+ @kb.add("enter", eager=True)
385
+ def _submit(event) -> None:
386
+ event.app.exit(result=text_area.text)
387
+
388
+ @kb.add("s-tab")
389
+ def _shift_tab(event) -> None:
390
+ event.app.current_buffer.complete_previous()
391
+
392
+ root = FloatContainer(
393
+ content=HSplit([
394
+ # Lightweight terminal-native input section.
395
+ Window(height=1,
396
+ content=FormattedTextControl(lambda: _input_rule(cfg), focusable=False)),
397
+ VSplit([
398
+ Window(width=1, content=FormattedTextControl(_input_pad, focusable=False)),
399
+ text_area,
400
+ Window(width=1, content=FormattedTextControl(_input_pad, focusable=False)),
401
+ ]),
402
+ Window(height=1,
403
+ content=FormattedTextControl(lambda: _input_rule(cfg), focusable=False)),
404
+ # Status bar: transparent bg, dim model · cwd
405
+ Window(height=1,
406
+ content=FormattedTextControl(lambda: _status_bar(cfg), focusable=False)),
407
+ ]),
408
+ floats=[
409
+ Float(
410
+ xcursor=True,
411
+ ycursor=True,
412
+ content=CompletionsMenu(max_height=12, scroll_offset=2),
413
+ )
414
+ ],
415
+ )
416
+
417
+ app: Application = Application(
418
+ layout=Layout(root, focused_element=text_area),
419
+ key_bindings=kb,
420
+ style=_build_style(cfg),
421
+ full_screen=False,
422
+ erase_when_done=False,
423
+ mouse_support=False,
424
+ refresh_interval=0.25, # drives robot dot animation at 4 fps
425
+ )
426
+ return app
427
+
428
+
429
+ @contextmanager
430
+ def _without_cpr_probe():
431
+ """Disable CPR for this inline panel, which owns a fixed-height layout."""
432
+ key = "PROMPT_TOOLKIT_NO_CPR"
433
+ previous = os.environ.get(key)
434
+ os.environ[key] = "1"
435
+ try:
436
+ yield
437
+ finally:
438
+ if previous is None:
439
+ os.environ.pop(key, None)
440
+ else:
441
+ os.environ[key] = previous
442
+
443
+
444
+ def run_panel_input(
445
+ *,
446
+ completer=None,
447
+ history=None,
448
+ status_text: Callable[[], str] | str = "",
449
+ config: Optional[PanelInputConfig] = None,
450
+ ) -> str:
451
+ """Run the panel synchronously for compatibility with non-async callers."""
452
+ app = _build_panel_input_application(
453
+ completer=completer,
454
+ history=history,
455
+ status_text=status_text,
456
+ config=config,
457
+ )
458
+ if app is None:
459
+ try:
460
+ return input((config or PanelInputConfig()).prompt)
461
+ except EOFError:
462
+ return ""
463
+ with _without_cpr_probe():
464
+ return app.run() or ""
465
+
466
+
467
+ async def run_panel_input_async(
468
+ *,
469
+ completer=None,
470
+ history=None,
471
+ status_text: Callable[[], str] | str = "",
472
+ config: Optional[PanelInputConfig] = None,
473
+ ) -> str:
474
+ """Run the panel on the active event loop to preserve IME input state."""
475
+ app = _build_panel_input_application(
476
+ completer=completer,
477
+ history=history,
478
+ status_text=status_text,
479
+ config=config,
480
+ )
481
+ if app is None:
482
+ loop = asyncio.get_running_loop()
483
+ try:
484
+ return await loop.run_in_executor(None, input, (config or PanelInputConfig()).prompt)
485
+ except EOFError:
486
+ return ""
487
+ with _without_cpr_probe():
488
+ return (await app.run_async()) or ""
aria_code/ui/picker.py ADDED
@@ -0,0 +1,201 @@
1
+ """Arrow-key selector and async wrapper used by model/skill picker dialogs.
2
+
3
+ from ui.picker import arrow_select, run_picker_in_thread
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import asyncio
9
+ import os
10
+ import sys
11
+
12
+ from aria_code.ui.console import _HAS_TERMIOS, _esc_watcher
13
+
14
+ if _HAS_TERMIOS:
15
+ import termios
16
+ import tty
17
+ import select as _select
18
+
19
+
20
+ def arrow_select(options: list, selected: int = 0, title: str = "",
21
+ max_visible: int = 10,
22
+ controls_hint: str = "↑↓ Enter Esc/q Cancel") -> int:
23
+ """Interactive arrow-key selector with scrolling.
24
+
25
+ Args:
26
+ options: list of ``(label, description)`` tuples or plain strings
27
+ selected: initially highlighted index
28
+ title: optional header line
29
+ max_visible: max rows shown at once; scrolls when list is larger
30
+ Returns:
31
+ index of chosen option, or -1 if cancelled
32
+ """
33
+ if not options:
34
+ return -1
35
+
36
+ if not _HAS_TERMIOS or not sys.stdin.isatty():
37
+ if title:
38
+ print(f"\n {title}\n")
39
+ for i, opt in enumerate(options):
40
+ label = opt[0] if isinstance(opt, tuple) else opt
41
+ marker = "❯" if i == selected else " "
42
+ print(f" {marker} {i + 1:2d}. {label}")
43
+ try:
44
+ c = input("\n Enter number (or Enter to keep current): ").strip()
45
+ if not c:
46
+ return selected
47
+ idx = int(c) - 1
48
+ return idx if 0 <= idx < len(options) else -1
49
+ except (ValueError, EOFError, KeyboardInterrupt):
50
+ return -1
51
+
52
+ n = len(options)
53
+ visible = min(max_visible, n)
54
+ scroll = max(0, selected - visible + 1)
55
+
56
+ fd = sys.stdin.fileno()
57
+ old_settings = termios.tcgetattr(fd)
58
+
59
+ try:
60
+ _tcols = os.get_terminal_size(fd).columns
61
+ except Exception:
62
+ _tcols = 80
63
+
64
+ _rule = "─" * min(_tcols, 72)
65
+
66
+ def _display_width(s: str) -> int:
67
+ import re as _re
68
+ clean = _re.sub(r'\x1b\[[0-9;]*[mJKHABCDfGrs]', '', s)
69
+ w = 0
70
+ for ch in clean:
71
+ cp = ord(ch)
72
+ if (0x1100 <= cp <= 0x115F or 0x2E80 <= cp <= 0xA4CF or
73
+ 0xAC00 <= cp <= 0xD7AF or 0xF900 <= cp <= 0xFAFF or
74
+ 0xFE10 <= cp <= 0xFE1F or 0xFE30 <= cp <= 0xFE4F or
75
+ 0xFF01 <= cp <= 0xFF60 or 0xFFE0 <= cp <= 0xFFE6 or
76
+ 0x3000 <= cp <= 0x303F):
77
+ w += 2
78
+ else:
79
+ w += 1
80
+ return w
81
+
82
+ def _physical_lines(text: str) -> int:
83
+ dw = _display_width(text)
84
+ return max(1, (dw + _tcols - 1) // _tcols)
85
+
86
+ def _raw(s: str):
87
+ os.write(1, s.encode())
88
+
89
+ def _render():
90
+ nonlocal scroll
91
+ if selected < scroll:
92
+ scroll = selected
93
+ elif selected >= scroll + visible:
94
+ scroll = selected - visible + 1
95
+
96
+ buf = ""
97
+ if _render.drawn:
98
+ buf += f"\033[{_render.last_phys_height}A"
99
+
100
+ phys_height = 0
101
+ for row in range(visible):
102
+ idx = scroll + row
103
+ opt = options[idx]
104
+ label = opt[0] if isinstance(opt, tuple) else opt
105
+ desc = opt[1] if isinstance(opt, tuple) and len(opt) > 1 else ""
106
+ if label.strip().startswith("──"):
107
+ line = f" \033[2m{label}\033[0m"
108
+ elif idx == selected:
109
+ _accent = os.getenv("ARIA_ACCENT_COLOR", "192;128;80")
110
+ line = f" \033[1m\033[38;2;{_accent}m❯\033[0m \033[1m{label}\033[0m"
111
+ if desc:
112
+ line += f" \033[2m{desc}\033[0m"
113
+ else:
114
+ line = f" {label}"
115
+ if desc:
116
+ line += f" \033[2m{desc}\033[0m"
117
+ buf += f"\033[2K{line}\n"
118
+ phys_height += _physical_lines(line)
119
+
120
+ if n > visible:
121
+ hint = f" \033[2m{selected + 1}/{n}\033[0m"
122
+ buf += f"\033[2K{hint}\n"
123
+ else:
124
+ buf += "\033[2K\n"
125
+ phys_height += 1
126
+
127
+ _render.last_phys_height = phys_height
128
+ _raw(buf)
129
+ _render.drawn = True
130
+
131
+ _render.drawn = False
132
+ _render.last_phys_height = visible + 1
133
+
134
+ try:
135
+ _esc_watcher.pause()
136
+ tty.setcbreak(fd)
137
+ sys.stdout.flush()
138
+
139
+ # Top boundary
140
+ _raw(f"\n \033[2m{_rule}\033[0m\n")
141
+ if title:
142
+ _raw(f" \033[1m{title}\033[0m \033[2m{controls_hint}\033[0m\n\n")
143
+ else:
144
+ _raw(f" \033[2m{controls_hint}\033[0m\n\n")
145
+
146
+ _render()
147
+
148
+ while True:
149
+ ch = os.read(fd, 1)
150
+ if ch == b'\x1b':
151
+ seq = b''
152
+ if _select.select([fd], [], [], 0.05)[0]:
153
+ seq = os.read(fd, 2)
154
+ if seq == b'[A':
155
+ selected = (selected - 1) % n; _render()
156
+ elif seq == b'[B':
157
+ selected = (selected + 1) % n; _render()
158
+ elif seq == b'[5~':
159
+ selected = max(0, selected - visible); _render()
160
+ elif seq == b'[6~':
161
+ selected = min(n - 1, selected + visible); _render()
162
+ elif not seq:
163
+ return -1
164
+ elif ch in (b'\r', b'\n'):
165
+ return selected
166
+ elif ch == b'q':
167
+ return -1
168
+ elif ch == b'k':
169
+ selected = (selected - 1) % n; _render()
170
+ elif ch == b'j':
171
+ selected = (selected + 1) % n; _render()
172
+ elif ch == b'g':
173
+ selected = 0; _render()
174
+ elif ch == b'G':
175
+ selected = n - 1; _render()
176
+ elif ch in (b'\x03', b'\x04'):
177
+ return -1
178
+ except (EOFError, KeyboardInterrupt, OSError):
179
+ return -1
180
+ finally:
181
+ termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
182
+ _esc_watcher.resume()
183
+ _raw(f" \033[2m{_rule}\033[0m\n\n")
184
+
185
+
186
+ async def run_picker_in_thread(options: list, current_idx: int,
187
+ title: str, max_visible: int = 14,
188
+ controls_hint: str = "↑↓ Enter Esc/q Cancel") -> int:
189
+ """Run arrow_select in an executor thread to avoid kqueue conflicts on macOS."""
190
+ loop = asyncio.get_running_loop()
191
+ return await loop.run_in_executor(
192
+ None,
193
+ lambda: arrow_select(
194
+ options, current_idx, title, max_visible, controls_hint
195
+ ),
196
+ )
197
+
198
+
199
+ # Back-compat aliases used by aria_cli.py
200
+ _arrow_select = arrow_select
201
+ _run_picker_in_thread = run_picker_in_thread
@@ -0,0 +1,11 @@
1
+ """UI rendering helpers — team, finance, market output formatters."""
2
+
3
+ from .team import render_verdict_banner, render_team_table
4
+ from .finance import render_macro_result, render_cb_rates, render_econ_calendar
5
+ from .market import print_quote_result, print_ta_result
6
+
7
+ __all__ = [
8
+ "render_verdict_banner", "render_team_table",
9
+ "render_macro_result", "render_cb_rates", "render_econ_calendar",
10
+ "print_quote_result", "print_ta_result",
11
+ ]