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,401 @@
1
+ """UiCommandsMixin — vision, browser, screenshot, input, and context commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from ._ui import Panel, print_error, rich_box
6
+
7
+ import base64
8
+ import io
9
+ import pathlib
10
+ from urllib.parse import urlsplit
11
+
12
+
13
+ import json
14
+ import asyncio
15
+ import datetime
16
+ import time
17
+ import shlex
18
+ import sys
19
+ import os
20
+ from typing import Dict, Any, Optional
21
+
22
+ def get_model_capability(*args, **kwargs):
23
+ from aria_code.apps.cli._optional import get_model_capability as fn
24
+ return fn(*args, **kwargs)
25
+ def _get__HAS_COMPUTER_USE():
26
+ from aria_cli import _HAS_COMPUTER_USE as val
27
+ return val
28
+ def _get__PROJECT_CONTEXT():
29
+ from aria_cli import _PROJECT_CONTEXT as val
30
+ return val
31
+ def _get__HAS_MODEL_CAP():
32
+ from aria_code.apps.cli._optional import HAS_MODEL_CAP as val
33
+ return val
34
+ def _get_rich_box():
35
+ # Resolved locally now — see ._ui; no aria_cli round-trip.
36
+ return rich_box
37
+ def get_model_cfg(*args, **kwargs):
38
+ from ..model_catalog import get_model_cfg as fn
39
+ return fn(*args, **kwargs)
40
+ def _get_Panel():
41
+ # Resolved locally now — see ._ui; no aria_cli round-trip.
42
+ return Panel
43
+
44
+ import json
45
+ import asyncio
46
+ import datetime
47
+ import time
48
+ import shlex
49
+ import sys
50
+ import os
51
+ from typing import Dict, Any, Optional
52
+
53
+
54
+ class UiCommandsMixin:
55
+ """Mixin: visual input and terminal UI commands."""
56
+
57
+ @staticmethod
58
+ def _short_url_label(url: str) -> str:
59
+ try:
60
+ from urllib.parse import urlsplit
61
+ parsed = urlsplit(url if url.startswith(("http://", "https://")) else f"https://{url}")
62
+ host = parsed.netloc or parsed.path
63
+ path = parsed.path.rstrip("/")
64
+ if len(path) > 32:
65
+ path = path[:29] + "..."
66
+ return f"{host}{path}" if path and path != "/" else host
67
+ except Exception:
68
+ return url[:48]
69
+
70
+ @staticmethod
71
+ def _load_image_source(path_or_url: str) -> dict:
72
+ """Load an image from a local path, URL, or clipboard."""
73
+ raw = (path_or_url or "").strip().strip("\"'")
74
+ if not raw:
75
+ raise ValueError("Missing image source")
76
+
77
+ mime_map = {
78
+ "png": "image/png",
79
+ "jpg": "image/jpeg",
80
+ "jpeg": "image/jpeg",
81
+ "gif": "image/gif",
82
+ "webp": "image/webp",
83
+ }
84
+
85
+ def _from_bytes(data: bytes, mime: str, label: str) -> dict:
86
+ if not data:
87
+ raise ValueError("Empty image data")
88
+ return {
89
+ "label": label,
90
+ "mime": mime,
91
+ "b64": base64.b64encode(data).decode(),
92
+ "size_kb": max(1, len(data) // 1024),
93
+ }
94
+
95
+ if raw.lower() in {"clipboard", "clip", "paste"}:
96
+ try:
97
+ from PIL import ImageGrab
98
+ img = ImageGrab.grabclipboard()
99
+ if img is None:
100
+ raise ValueError("Clipboard does not contain an image")
101
+ if isinstance(img, list):
102
+ for item in img:
103
+ p = pathlib.Path(str(item))
104
+ if p.is_file() and p.suffix.lstrip(".").lower() in mime_map:
105
+ return UiCommandsMixin._load_image_source(str(p))
106
+ raise ValueError("Clipboard does not contain a supported image file")
107
+ if hasattr(img, "save"):
108
+ buf = io.BytesIO()
109
+ img.save(buf, format="PNG")
110
+ return _from_bytes(buf.getvalue(), "image/png", "clipboard")
111
+ raise ValueError("Clipboard image format not supported")
112
+ except Exception as exc:
113
+ raise ValueError(str(exc)) from exc
114
+
115
+ if raw.startswith(("http://", "https://", "www.")):
116
+ try:
117
+ import requests
118
+ url = raw if raw.startswith(("http://", "https://")) else f"https://{raw}"
119
+ resp = requests.get(url, timeout=20, headers={"User-Agent": "Mozilla/5.0"})
120
+ resp.raise_for_status()
121
+ content_type = (resp.headers.get("content-type") or "").split(";", 1)[0].strip().lower()
122
+ mime = content_type if content_type.startswith("image/") else "image/png"
123
+ if mime == "application/octet-stream":
124
+ mime = "image/png"
125
+ return _from_bytes(resp.content, mime, UiCommandsMixin._short_url_label(url))
126
+ except Exception as exc:
127
+ raise ValueError(f"Cannot download image: {exc}") from exc
128
+
129
+ path = pathlib.Path(raw).expanduser().resolve()
130
+ if not path.exists():
131
+ raise FileNotFoundError(f"File not found: {path}")
132
+ suffix = path.suffix.lstrip(".").lower()
133
+ mime = mime_map.get(suffix)
134
+ if not mime:
135
+ raise ValueError(f"Unsupported image type: .{suffix}")
136
+ return _from_bytes(path.read_bytes(), mime, path.name)
137
+
138
+ def cmd_vision(self, args: str):
139
+ _curr_model = self.terminal.config.get("model", "")
140
+ if _curr_model and _get__HAS_MODEL_CAP():
141
+ _vcap = get_model_capability(_curr_model)
142
+ if not _vcap.vision:
143
+ _warn = (
144
+ f"[yellow]⚠[/yellow] 当前模型 [bold]{_curr_model}[/bold] 不支持图片输入。\n"
145
+ f"[dim]支持视觉的模型:llama3.2:11b · gemma3 · llava · qwen2-vl · moondream[/dim]"
146
+ )
147
+ if self.context.has_rich:
148
+ self.context.console.print(_get_Panel()(_warn, border_style="yellow", box=_get_rich_box().ROUNDED, padding=(0, 1)))
149
+ else:
150
+ print(f"Warning: model {_curr_model} does not support vision input.")
151
+ return
152
+
153
+ path_str = args.strip().strip("\"'")
154
+ if not path_str:
155
+ msg = "Usage: /vision <image_path|image_url|clipboard> (e.g. /vision ~/Pictures/chart.png)"
156
+ self.context.console.print(f"[dim]{msg}[/dim]" if self.context.has_rich else msg)
157
+ return
158
+
159
+ try:
160
+ payload = self._load_image_source(path_str)
161
+ except Exception as e:
162
+ print_error(self.context, str(e), "vision")
163
+ return
164
+
165
+ self.terminal._pending_image = {
166
+ "type": "image_url",
167
+ "image_url": {"url": f"data:{payload['mime']};base64,{payload['b64']}"},
168
+ }
169
+ size_kb = payload["size_kb"]
170
+ if self.context.has_rich:
171
+ self.context.console.print(_get_Panel()(
172
+ f"[green]✓[/green] [dim]{payload['label']}[/dim] [dim]{size_kb} KB · {payload['mime']}[/dim]\n"
173
+ f"[dim]Image queued — ask your question now[/dim]",
174
+ border_style="dim",
175
+ box=_get_rich_box().ROUNDED,
176
+ padding=(0, 1),
177
+ ))
178
+ else:
179
+ print(f"Image loaded: {payload['label']} ({size_kb} KB) — send your question now")
180
+
181
+ async def cmd_browser(self, args: str):
182
+ """Open a URL in a headless browser."""
183
+ if not _get__HAS_COMPUTER_USE():
184
+ print_error(self.context,
185
+ "computer_use_tools not available.",
186
+ "Install: pip install playwright mss pyautogui pillow && playwright install chromium",
187
+ )
188
+ return
189
+ from computer_use_tools import _tool_browser_navigate, _tool_browser_screenshot
190
+
191
+ parts = args.strip().split(maxsplit=1)
192
+ if not parts:
193
+ if self.context.has_rich:
194
+ self.context.console.print("[dim]Usage: /browser <url> or /browser screenshot <url>[/dim]")
195
+ return
196
+
197
+ if parts[0].lower() == "screenshot" and len(parts) > 1:
198
+ url = parts[1].strip()
199
+ if self.context.has_rich:
200
+ with self.context.console.status(f"[dim]Screenshotting {self._short_url_label(url)}…[/dim]", spinner="dots"):
201
+ result = _tool_browser_screenshot({"url": url})
202
+ else:
203
+ result = _tool_browser_screenshot({"url": url})
204
+ if result.get("success"):
205
+ d = result["data"]
206
+ from computer_use_tools import pop_pending_vision_image
207
+ b64 = pop_pending_vision_image()
208
+ if b64:
209
+ self.terminal._pending_image = {
210
+ "type": "image_url",
211
+ "image_url": {"url": f"data:image/png;base64,{b64}"},
212
+ }
213
+ if self.context.has_rich:
214
+ self.context.console.print(_get_Panel()(
215
+ f"[green]✓[/green] [bold]{d.get('title','')[:60]}[/bold]\n"
216
+ f"[dim]{self._short_url_label(url)} · {d.get('size_kb', 0)} KB[/dim]\n"
217
+ f"[dim]Screenshot queued — ask your question now[/dim]",
218
+ border_style="dim", box=_get_rich_box().ROUNDED, padding=(0, 1),
219
+ ))
220
+ else:
221
+ print(f"Screenshot ready ({d.get('size_kb', 0)} KB) — send your question")
222
+ else:
223
+ print_error(self.context, result.get("error", "Screenshot failed"), "browser screenshot")
224
+ else:
225
+ url = parts[0].strip()
226
+ if self.context.has_rich:
227
+ with self.context.console.status(f"[dim]Opening {self._short_url_label(url)}…[/dim]", spinner="dots"):
228
+ result = _tool_browser_navigate({"url": url})
229
+ else:
230
+ result = _tool_browser_navigate({"url": url})
231
+ if result.get("success"):
232
+ d = result["data"]
233
+ title = d.get("title", "")
234
+ text = d.get("text", "")[:2000]
235
+ links = d.get("links", [])[:5]
236
+ engine = d.get("engine", "")
237
+ if self.context.has_rich:
238
+ link_str = "\n".join(f" {l}" for l in links) if links else " (none)"
239
+ self.context.console.print(_get_Panel()(
240
+ f"[bold]{title[:80]}[/bold] [dim]({engine})[/dim]\n\n"
241
+ f"{text}\n\n[dim]Links:[/dim]\n{link_str}",
242
+ border_style="dim", box=_get_rich_box().ROUNDED, padding=(0, 1),
243
+ title=f"[dim]{self._short_url_label(url)}[/dim]", title_align="left",
244
+ ))
245
+ else:
246
+ print(f"Title: {title}\n{text[:500]}")
247
+ else:
248
+ print_error(self.context, result.get("error", "Navigation failed"), "browser")
249
+
250
+ async def cmd_screenshot(self, args: str):
251
+ if not _get__HAS_COMPUTER_USE():
252
+ print_error(self.context,
253
+ "computer_use_tools not available.",
254
+ "Install: pip install mss pillow",
255
+ )
256
+ return
257
+ from computer_use_tools import _tool_computer_screenshot, pop_pending_vision_image
258
+
259
+ monitor = int(args.strip()) if args.strip().isdigit() else 1
260
+ if self.context.has_rich:
261
+ with self.context.console.status("[dim]Capturing screen…[/dim]", spinner="dots"):
262
+ result = _tool_computer_screenshot({"monitor": monitor})
263
+ else:
264
+ result = _tool_computer_screenshot({"monitor": monitor})
265
+
266
+ if result.get("success"):
267
+ d = result["data"]
268
+ b64 = pop_pending_vision_image()
269
+ if b64:
270
+ self.terminal._pending_image = {
271
+ "type": "image_url",
272
+ "image_url": {"url": f"data:image/png;base64,{b64}"},
273
+ }
274
+ if self.context.has_rich:
275
+ self.context.console.print(_get_Panel()(
276
+ f"[green]✓[/green] [dim]{d['width']}×{d['height']} · {d['size_kb']} KB[/dim]\n"
277
+ f"[dim]Screenshot queued — ask your question now[/dim]",
278
+ border_style="dim", box=_get_rich_box().ROUNDED, padding=(0, 1),
279
+ ))
280
+ else:
281
+ print(f"Screenshot {d['width']}×{d['height']} ({d['size_kb']} KB) — send your question")
282
+ else:
283
+ print_error(self.context, result.get("error", "Screenshot failed"), "screenshot")
284
+
285
+ def cmd_input(self, args: str):
286
+ raw = args.strip().lower()
287
+ cfg = self.terminal.config
288
+ valid_styles = {"panel", "box", "plain"}
289
+ valid_themes = {"auto", "dark", "light"}
290
+
291
+ def _save_and_show(message: str) -> None:
292
+ self.context.save_config(cfg)
293
+ if self.context.has_rich:
294
+ self.context.console.print(f"[green]✓[/green] {message}")
295
+ self.context.console.print(
296
+ f" [dim]style[/dim] {cfg.get('input_style', 'panel')} "
297
+ f"[dim]theme[/dim] {cfg.get('input_theme', 'auto')}"
298
+ )
299
+ else:
300
+ print(message)
301
+ print(f" style {cfg.get('input_style', 'panel')} theme {cfg.get('input_theme', 'auto')}")
302
+
303
+ if not raw or raw in {"status", "show"}:
304
+ style = cfg.get("input_style", "panel")
305
+ theme = cfg.get("input_theme", "auto")
306
+ if self.context.has_rich:
307
+ self.context.console.print(_get_Panel()(
308
+ f"[bold]style[/bold] {style}\n"
309
+ f"[bold]theme[/bold] {theme}\n\n"
310
+ "[dim]Use[/dim] /input panel [dim]for the Codex-style input block[/dim]\n"
311
+ "[dim]Use[/dim] /input theme auto [dim]to follow the terminal/system theme[/dim]",
312
+ title="Input UI",
313
+ border_style="dim",
314
+ box=_get_rich_box().ROUNDED,
315
+ padding=(0, 1),
316
+ ))
317
+ else:
318
+ print(f"input style: {style}")
319
+ print(f"input theme: {theme}")
320
+ print("Usage: /input panel|box|plain | /input theme auto|dark|light")
321
+ return
322
+
323
+ if raw == "reset":
324
+ cfg["input_style"] = "panel"
325
+ cfg["input_theme"] = "auto"
326
+ _save_and_show("input UI reset to panel · auto")
327
+ return
328
+
329
+ parts = raw.split()
330
+ if parts[0] == "theme":
331
+ if len(parts) != 2 or parts[1] not in valid_themes:
332
+ msg = "Usage: /input theme auto|dark|light"
333
+ self.context.console.print(f"[red]{msg}[/red]" if self.context.has_rich else msg)
334
+ return
335
+ cfg["input_theme"] = parts[1]
336
+ _save_and_show(f"input theme set to {parts[1]}")
337
+ return
338
+
339
+ if parts[0] in valid_themes and len(parts) == 1:
340
+ cfg["input_theme"] = parts[0]
341
+ _save_and_show(f"input theme set to {parts[0]}")
342
+ return
343
+
344
+ if parts[0] in valid_styles and len(parts) == 1:
345
+ cfg["input_style"] = parts[0]
346
+ _save_and_show(f"input style set to {parts[0]}")
347
+ return
348
+
349
+ msg = "Usage: /input panel|box|plain | /input theme auto|dark|light | /input reset"
350
+ self.context.console.print(f"[red]{msg}[/red]" if self.context.has_rich else msg)
351
+
352
+ def cmd_context(self, args: str):
353
+ cfg = self.terminal.config
354
+ conv = self.terminal.conversation
355
+ conv_len = len(conv)
356
+ model_id = cfg.get("model", "qwen2.5:7b")
357
+ thinking = cfg.get("thinking_mode", "auto")
358
+ has_auth = bool(cfg.get("auth_token"))
359
+ local_mode = cfg.get("local_mode", False)
360
+ auto_compact = bool(cfg.get("auto_compact_context", True))
361
+ try:
362
+ auto_compact_threshold = float(cfg.get("auto_compact_threshold", 0.78))
363
+ except Exception:
364
+ auto_compact_threshold = 0.78
365
+ auto_compact_count = int(getattr(self.terminal, "_auto_compact_count", 0) or 0)
366
+
367
+ total_chars = sum(len(m.get("content", "")) for m in conv)
368
+ est_tokens = total_chars // 3
369
+ max_ctx = get_model_cfg(model_id).get("num_ctx", 16384)
370
+ ctx_pct = min(100, int(est_tokens / max_ctx * 100))
371
+ ctx_color = "green" if ctx_pct < 60 else ("yellow" if ctx_pct < 85 else "red")
372
+
373
+ if self.context.has_rich:
374
+ self.context.console.print()
375
+ self.context.console.print("[bold]Current Context[/bold]")
376
+ self.context.console.print()
377
+ self.context.console.print(f" [dim]{'Model':<20s}[/dim]{model_id}")
378
+ self.context.console.print(f" [dim]{'Provider':<20s}[/dim]{'[green]Local (Ollama)[/green]' if local_mode else 'AWS → Ollama fallback'}")
379
+ self.context.console.print(f" [dim]{'Thinking':<20s}[/dim]{thinking}")
380
+ self.context.console.print(f" [dim]{'Messages':<20s}[/dim]{conv_len}")
381
+ self.context.console.print(f" [dim]{'Est. tokens':<20s}[/dim][{ctx_color}]{est_tokens:,} / {max_ctx:,} ({ctx_pct}%)[/{ctx_color}]")
382
+ self.context.console.print(f" [dim]{'Authenticated':<20s}[/dim]{'yes' if has_auth else 'no'}")
383
+ self.context.console.print(
384
+ f" [dim]{'Auto compact':<20s}[/dim]"
385
+ f"{'on' if auto_compact else 'off'}"
386
+ f" · threshold {int(auto_compact_threshold * 100)}%"
387
+ f" · runs {auto_compact_count}"
388
+ )
389
+ self.context.console.print(f" [dim]{'Session':<20s}[/dim]{self.terminal.session_id}")
390
+ self.context.console.print(f" [dim]{'Project context':<20s}[/dim]{'loaded' if _get__PROJECT_CONTEXT() else 'none'}")
391
+ wl = cfg.get("watchlist", [])
392
+ if wl:
393
+ self.context.console.print(f" [dim]{'Watchlist':<20s}[/dim]{', '.join(wl)}")
394
+ if ctx_pct >= 80:
395
+ self.context.console.print(f"\n [yellow]⚠ Context {ctx_pct}% full — use /compact to free space[/yellow]")
396
+ self.context.console.print()
397
+ else:
398
+ print(f" Model: {model_id} ({'local' if local_mode else 'aws'})")
399
+ print(f" Messages: {conv_len} Tokens: ~{est_tokens:,}/{max_ctx:,} ({ctx_pct}%)")
400
+ print(f" Auto compact: {'on' if auto_compact else 'off'} threshold={int(auto_compact_threshold * 100)}% runs={auto_compact_count}")
401
+ print(f" Session: {self.terminal.session_id}")
@@ -0,0 +1,79 @@
1
+ """Warehouse ERP command; globals are rebound by the legacy CLI bridge."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+
7
+
8
+ import json
9
+ import asyncio
10
+ import datetime
11
+ import time
12
+ import shlex
13
+ from typing import Dict, Any, Optional
14
+
15
+
16
+ import json
17
+ import asyncio
18
+ import datetime
19
+ import time
20
+ import shlex
21
+ import sys
22
+ import os
23
+ from typing import Dict, Any, Optional
24
+
25
+
26
+ import json
27
+ import asyncio
28
+ import datetime
29
+ import time
30
+ import shlex
31
+ import sys
32
+ import os
33
+ from typing import Dict, Any, Optional
34
+
35
+
36
+ class WarehouseCommandsMixin:
37
+ """Read-only warehouse ERP analysis commands."""
38
+
39
+ async def cmd_warehouse(self, args: str):
40
+ """Run `/warehouse <warehouse_id> [--json]` against the configured ERP."""
41
+ parts = args.strip().split()
42
+ as_json = "--json" in parts
43
+ identifiers = [part for part in parts if not part.startswith("--")]
44
+ if len(identifiers) != 1:
45
+ message = "用法: /warehouse <仓库编号> [--json],例如 /warehouse WH-CN-01"
46
+ self.context.console.print(f"[yellow]{message}[/yellow]") if self.context.has_rich else print(message)
47
+ return
48
+
49
+ from agents.warehouse.workflow import run_warehouse_analysis
50
+ from clients.warehouse_erp_client import WarehouseERPConfigurationError, WarehouseERPRequestError
51
+
52
+ try:
53
+ result, snapshot = await run_warehouse_analysis(identifiers[0])
54
+ except (WarehouseERPConfigurationError, WarehouseERPRequestError) as exc:
55
+ message = str(exc)
56
+ self.context.console.print(f"[red]{message}[/red]") if self.context.has_rich else print(message)
57
+ return
58
+
59
+ payload = {
60
+ "warehouse_id": identifiers[0],
61
+ "signal": result.final_signal,
62
+ "confidence": result.confidence,
63
+ "agents": [item.to_dict() for item in result.results],
64
+ "snapshot_counts": {key: len(snapshot.get(key, [])) for key in ("connectors", "inbounds", "skus", "locations")},
65
+ }
66
+ if as_json:
67
+ print(json.dumps(payload, ensure_ascii=False, indent=2))
68
+ return
69
+
70
+ lines = [
71
+ f"仓库 {identifiers[0]} · {result.final_signal} · 置信度 {result.confidence:.0%}",
72
+ f"货代 {payload['snapshot_counts']['connectors']} · 入库单 {payload['snapshot_counts']['inbounds']} · "
73
+ f"SKU {payload['snapshot_counts']['skus']} · 库位 {payload['snapshot_counts']['locations']}",
74
+ ]
75
+ for item in result.results:
76
+ summary = item.key_points[0] if item.key_points else item.analysis
77
+ lines.append(f"- {item.agent}: {item.signal} — {summary}")
78
+ output = "\n".join(lines)
79
+ self.context.console.print(output) if self.context.has_rich else print(output)