aria-code 0.167.0__py3-none-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (601) hide show
  1. aria_bots/__init__.py +7 -0
  2. aria_bots/channels/README.md +97 -0
  3. aria_bots/channels/__init__.py +1 -0
  4. aria_bots/channels/approvals.py +263 -0
  5. aria_bots/channels/conversation.py +280 -0
  6. aria_bots/channels/digest.py +186 -0
  7. aria_bots/channels/registry.py +95 -0
  8. aria_bots/engine.py +144 -0
  9. aria_bots/feishu_bot.py +1385 -0
  10. aria_bots/logistics/__init__.py +1 -0
  11. aria_bots/logistics/carriers.py +253 -0
  12. aria_bots/logistics/freight.py +154 -0
  13. aria_bots/logistics/inventory.py +242 -0
  14. aria_bots/logistics/mcp_server.py +156 -0
  15. aria_bots/logistics/records.py +119 -0
  16. aria_bots/logistics/tenancy.py +152 -0
  17. aria_bots/market.py +91 -0
  18. aria_bots/relay_client.py +326 -0
  19. aria_bots/telegram_bot.py +299 -0
  20. aria_code/__init__.py +111 -0
  21. aria_code/_bin/aria-native.exe +0 -0
  22. aria_code/_bin/aria-runtime.exe +0 -0
  23. aria_code/_version.py +20 -0
  24. aria_code/account_memory.py +296 -0
  25. aria_code/account_session.py +166 -0
  26. aria_code/adk_apps/__init__.py +1 -0
  27. aria_code/adk_apps/aria_code_review/__init__.py +1 -0
  28. aria_code/adk_apps/aria_code_review/agent.py +32 -0
  29. aria_code/adk_apps/aria_research/__init__.py +1 -0
  30. aria_code/adk_apps/aria_research/agent.py +31 -0
  31. aria_code/agents/__init__.py +49 -0
  32. aria_code/agents/base.py +329 -0
  33. aria_code/agents/code_review.py +200 -0
  34. aria_code/agents/deep/__init__.py +37 -0
  35. aria_code/agents/deep/calibration_loop.py +144 -0
  36. aria_code/agents/deep/critic.py +125 -0
  37. aria_code/agents/deep/deepen.py +193 -0
  38. aria_code/agents/deep/models.py +149 -0
  39. aria_code/agents/deep/pipeline.py +164 -0
  40. aria_code/agents/deep/quant_fusion.py +192 -0
  41. aria_code/agents/deep/themes.py +95 -0
  42. aria_code/agents/deep/tiers.py +106 -0
  43. aria_code/agents/engineering/__init__.py +14 -0
  44. aria_code/agents/engineering/coder.py +222 -0
  45. aria_code/agents/engineering/tester.py +145 -0
  46. aria_code/agents/financial/__init__.py +21 -0
  47. aria_code/agents/financial/cashflow_burn.py +119 -0
  48. aria_code/agents/financial/catalyst.py +279 -0
  49. aria_code/agents/financial/corporate_finance.py +175 -0
  50. aria_code/agents/financial/debate.py +224 -0
  51. aria_code/agents/financial/earnings.py +315 -0
  52. aria_code/agents/financial/fundamental.py +178 -0
  53. aria_code/agents/financial/macro.py +111 -0
  54. aria_code/agents/financial/news.py +231 -0
  55. aria_code/agents/financial/risk.py +146 -0
  56. aria_code/agents/financial/sector.py +279 -0
  57. aria_code/agents/financial/strategist.py +121 -0
  58. aria_code/agents/financial/stripe_revenue.py +127 -0
  59. aria_code/agents/financial/synthesis.py +274 -0
  60. aria_code/agents/financial/technical.py +277 -0
  61. aria_code/agents/orchestrator.py +44 -0
  62. aria_code/agents/portfolio_agent.py +392 -0
  63. aria_code/agents/realty/__init__.py +62 -0
  64. aria_code/agents/realty/asset_diagnosis.py +152 -0
  65. aria_code/agents/realty/business_match.py +166 -0
  66. aria_code/agents/realty/cashflow_verify.py +209 -0
  67. aria_code/agents/realty/contract_rules.py +210 -0
  68. aria_code/agents/realty/energy_anomaly.py +189 -0
  69. aria_code/agents/realty/exit_settlement.py +208 -0
  70. aria_code/agents/realty/fulfillment_risk.py +206 -0
  71. aria_code/agents/realty/ops_optimize.py +160 -0
  72. aria_code/agents/realty/revenue_share.py +215 -0
  73. aria_code/agents/registry.py +168 -0
  74. aria_code/agents/signal_scheme.py +111 -0
  75. aria_code/agents/sports/__init__.py +0 -0
  76. aria_code/agents/sports/football_agent.py +197 -0
  77. aria_code/agents/supervisor.py +113 -0
  78. aria_code/agents/team.py +500 -0
  79. aria_code/agents/video/__init__.py +16 -0
  80. aria_code/agents/video/director.py +376 -0
  81. aria_code/agents/video/qa_agent.py +143 -0
  82. aria_code/agents/video/script_doctor.py +112 -0
  83. aria_code/agents/warehouse/__init__.py +25 -0
  84. aria_code/agents/warehouse/contracts.py +26 -0
  85. aria_code/agents/warehouse/dashboard.py +155 -0
  86. aria_code/agents/warehouse/fulfillment_leadtime.py +95 -0
  87. aria_code/agents/warehouse/inbound_exceptions.py +25 -0
  88. aria_code/agents/warehouse/inventory_health.py +24 -0
  89. aria_code/agents/warehouse/local_run.py +71 -0
  90. aria_code/agents/warehouse/local_snapshot.py +132 -0
  91. aria_code/agents/warehouse/logistics_cost.py +84 -0
  92. aria_code/agents/warehouse/logistics_sync.py +21 -0
  93. aria_code/agents/warehouse/navigation.schema.json +110 -0
  94. aria_code/agents/warehouse/task_agent.py +172 -0
  95. aria_code/agents/warehouse/workflow.py +31 -0
  96. aria_code/aliyun_data_client.py +4 -0
  97. aria_code/apps/README.md +12 -0
  98. aria_code/apps/__init__.py +2 -0
  99. aria_code/apps/channels/README.md +9 -0
  100. aria_code/apps/channels/__init__.py +17 -0
  101. aria_code/apps/channels/approvals.py +11 -0
  102. aria_code/apps/channels/conversation.py +11 -0
  103. aria_code/apps/channels/digest.py +11 -0
  104. aria_code/apps/channels/intake.py +92 -0
  105. aria_code/apps/channels/registry.py +11 -0
  106. aria_code/apps/channels/tradingview.py +94 -0
  107. aria_code/apps/cli/README.md +13 -0
  108. aria_code/apps/cli/__init__.py +2 -0
  109. aria_code/apps/cli/_optional.py +120 -0
  110. aria_code/apps/cli/app_server.py +656 -0
  111. aria_code/apps/cli/auto_update.py +125 -0
  112. aria_code/apps/cli/bootstrap.py +206 -0
  113. aria_code/apps/cli/broker_render.py +206 -0
  114. aria_code/apps/cli/chat_turn.py +1327 -0
  115. aria_code/apps/cli/cloud_models.py +231 -0
  116. aria_code/apps/cli/codegen_paths.py +29 -0
  117. aria_code/apps/cli/commands/__init__.py +34 -0
  118. aria_code/apps/cli/commands/_business_render.py +78 -0
  119. aria_code/apps/cli/commands/_ui.py +71 -0
  120. aria_code/apps/cli/commands/analysis_cmds.py +378 -0
  121. aria_code/apps/cli/commands/ashare_prediction_cmds.py +327 -0
  122. aria_code/apps/cli/commands/auth_cmds.py +215 -0
  123. aria_code/apps/cli/commands/backtest_cmds.py +2518 -0
  124. aria_code/apps/cli/commands/broker_cmds.py +1236 -0
  125. aria_code/apps/cli/commands/business_workflow_cmds.py +379 -0
  126. aria_code/apps/cli/commands/canvas_cmds.py +77 -0
  127. aria_code/apps/cli/commands/catalog.py +189 -0
  128. aria_code/apps/cli/commands/core_cmds.py +2748 -0
  129. aria_code/apps/cli/commands/data_cmds.py +521 -0
  130. aria_code/apps/cli/commands/diagnostic_cmds.py +285 -0
  131. aria_code/apps/cli/commands/diagnostic_ops_cmds.py +813 -0
  132. aria_code/apps/cli/commands/engineering_cmds.py +399 -0
  133. aria_code/apps/cli/commands/file_cmds.py +312 -0
  134. aria_code/apps/cli/commands/finance_service_cmds.py +60 -0
  135. aria_code/apps/cli/commands/fx_commodity_cmds.py +123 -0
  136. aria_code/apps/cli/commands/market.py +544 -0
  137. aria_code/apps/cli/commands/market_cmds.py +1419 -0
  138. aria_code/apps/cli/commands/market_context.py +432 -0
  139. aria_code/apps/cli/commands/market_render.py +7 -0
  140. aria_code/apps/cli/commands/model_cmds.py +2374 -0
  141. aria_code/apps/cli/commands/ops_cmds.py +721 -0
  142. aria_code/apps/cli/commands/orchestrator_cmds.py +181 -0
  143. aria_code/apps/cli/commands/pdf_export_cmds.py +125 -0
  144. aria_code/apps/cli/commands/portfolio_cmds.py +1316 -0
  145. aria_code/apps/cli/commands/report.py +476 -0
  146. aria_code/apps/cli/commands/scaffold_templates.py +617 -0
  147. aria_code/apps/cli/commands/session_cmds.py +236 -0
  148. aria_code/apps/cli/commands/session_ux_cmds.py +359 -0
  149. aria_code/apps/cli/commands/team.py +723 -0
  150. aria_code/apps/cli/commands/team_render.py +8 -0
  151. aria_code/apps/cli/commands/ui_cmds.py +401 -0
  152. aria_code/apps/cli/commands/warehouse_cmds.py +297 -0
  153. aria_code/apps/cli/commands/workflow_cmds.py +629 -0
  154. aria_code/apps/cli/commands/workspace_cmds.py +1543 -0
  155. aria_code/apps/cli/config_paths.py +73 -0
  156. aria_code/apps/cli/config_store.py +158 -0
  157. aria_code/apps/cli/constants.py +88 -0
  158. aria_code/apps/cli/context.py +34 -0
  159. aria_code/apps/cli/conversation_policy.py +53 -0
  160. aria_code/apps/cli/deterministic.py +200 -0
  161. aria_code/apps/cli/direct.py +48 -0
  162. aria_code/apps/cli/earnings_view.py +172 -0
  163. aria_code/apps/cli/endpoint_migration.py +64 -0
  164. aria_code/apps/cli/exec_events.py +255 -0
  165. aria_code/apps/cli/file_references.py +155 -0
  166. aria_code/apps/cli/finance_service_catalog.py +111 -0
  167. aria_code/apps/cli/football_reports.py +231 -0
  168. aria_code/apps/cli/github_app_auth.py +135 -0
  169. aria_code/apps/cli/google_login.py +239 -0
  170. aria_code/apps/cli/handlers/__init__.py +11 -0
  171. aria_code/apps/cli/handlers/broker_handlers.py +122 -0
  172. aria_code/apps/cli/handlers/chart_handlers.py +1314 -0
  173. aria_code/apps/cli/handlers/market_handlers.py +2570 -0
  174. aria_code/apps/cli/handlers/realty_handlers.py +114 -0
  175. aria_code/apps/cli/handlers/sports_handlers.py +22 -0
  176. aria_code/apps/cli/handlers/strategy_advice.py +82 -0
  177. aria_code/apps/cli/headless.py +352 -0
  178. aria_code/apps/cli/helpers.py +326 -0
  179. aria_code/apps/cli/hooks.py +180 -0
  180. aria_code/apps/cli/i18n.py +310 -0
  181. aria_code/apps/cli/intent.py +136 -0
  182. aria_code/apps/cli/intent_router.py +305 -0
  183. aria_code/apps/cli/intent_shadow.py +72 -0
  184. aria_code/apps/cli/intent_signals.py +347 -0
  185. aria_code/apps/cli/lifecycle_hooks.py +48 -0
  186. aria_code/apps/cli/local_tool_schemas.py +550 -0
  187. aria_code/apps/cli/main.py +39 -0
  188. aria_code/apps/cli/market_hours.py +100 -0
  189. aria_code/apps/cli/market_metadata.py +135 -0
  190. aria_code/apps/cli/market_universe.py +487 -0
  191. aria_code/apps/cli/message_processing.py +310 -0
  192. aria_code/apps/cli/mixin_binding.py +32 -0
  193. aria_code/apps/cli/model_catalog.py +652 -0
  194. aria_code/apps/cli/model_probe.py +169 -0
  195. aria_code/apps/cli/model_retirement.py +65 -0
  196. aria_code/apps/cli/native_branding.py +12 -0
  197. aria_code/apps/cli/native_bridge.py +118 -0
  198. aria_code/apps/cli/native_entry.py +58 -0
  199. aria_code/apps/cli/pdf_report.py +977 -0
  200. aria_code/apps/cli/plan_mode.py +139 -0
  201. aria_code/apps/cli/plotly_html.py +15 -0
  202. aria_code/apps/cli/prediction_feedback.py +202 -0
  203. aria_code/apps/cli/preflight.py +502 -0
  204. aria_code/apps/cli/project_aria.py +60 -0
  205. aria_code/apps/cli/prompt_assembly.py +78 -0
  206. aria_code/apps/cli/prompts/__init__.py +0 -0
  207. aria_code/apps/cli/prompts/coding.py +71 -0
  208. aria_code/apps/cli/prompts/select.py +193 -0
  209. aria_code/apps/cli/prompts/system_prompts.py +562 -0
  210. aria_code/apps/cli/prompts/ui.py +436 -0
  211. aria_code/apps/cli/provider_endpoints.py +237 -0
  212. aria_code/apps/cli/provider_keys.py +73 -0
  213. aria_code/apps/cli/providers/__init__.py +1 -0
  214. aria_code/apps/cli/providers/base.py +775 -0
  215. aria_code/apps/cli/providers/chat_routing.py +139 -0
  216. aria_code/apps/cli/providers/collaboration.py +98 -0
  217. aria_code/apps/cli/providers/llm/__init__.py +1 -0
  218. aria_code/apps/cli/providers/llm/offline_responses.py +68 -0
  219. aria_code/apps/cli/providers/llm/ollama_stream.py +1574 -0
  220. aria_code/apps/cli/providers/llm/response_cache.py +60 -0
  221. aria_code/apps/cli/providers/llm/sse_stream.py +298 -0
  222. aria_code/apps/cli/providers/runtime_bridge.py +586 -0
  223. aria_code/apps/cli/providers/vertexai_stream.py +592 -0
  224. aria_code/apps/cli/release_download.py +159 -0
  225. aria_code/apps/cli/review_runner.py +111 -0
  226. aria_code/apps/cli/runtime_consumer.py +769 -0
  227. aria_code/apps/cli/sandbox.py +32 -0
  228. aria_code/apps/cli/session_export.py +120 -0
  229. aria_code/apps/cli/session_jsonl.py +208 -0
  230. aria_code/apps/cli/session_refresh.py +123 -0
  231. aria_code/apps/cli/session_store.py +125 -0
  232. aria_code/apps/cli/skills_catalog.py +273 -0
  233. aria_code/apps/cli/task_isolation.py +211 -0
  234. aria_code/apps/cli/terminal_chrome.py +412 -0
  235. aria_code/apps/cli/todo_tracker.py +190 -0
  236. aria_code/apps/cli/tool_executor.py +932 -0
  237. aria_code/apps/cli/tool_registry.py +34 -0
  238. aria_code/apps/cli/tool_scope.py +113 -0
  239. aria_code/apps/cli/tools/__init__.py +40 -0
  240. aria_code/apps/cli/tools/context.py +46 -0
  241. aria_code/apps/cli/tools/file_tools.py +181 -0
  242. aria_code/apps/cli/tools/market_tools.py +626 -0
  243. aria_code/apps/cli/tools/notebook_tools.py +111 -0
  244. aria_code/apps/cli/tools/system_tools.py +656 -0
  245. aria_code/apps/cli/tools/write_tools.py +961 -0
  246. aria_code/apps/cli/tradingview_bridge.py +529 -0
  247. aria_code/apps/cli/transactions.py +269 -0
  248. aria_code/apps/cli/turn_planning.py +137 -0
  249. aria_code/apps/cli/update_check.py +257 -0
  250. aria_code/apps/cli/updater.py +373 -0
  251. aria_code/apps/cli/utils/__init__.py +0 -0
  252. aria_code/apps/cli/utils/market_detect.py +1663 -0
  253. aria_code/apps/cli/web_login.py +136 -0
  254. aria_code/apps/cli/workflow_runner.py +127 -0
  255. aria_code/apps/cli/workspace_route.py +121 -0
  256. aria_code/apps/daemon/README.md +14 -0
  257. aria_code/apps/vscode/README.md +115 -0
  258. aria_code/apps/vscode/package.json +70 -0
  259. aria_code/aria_cli.py +5244 -0
  260. aria_code/aria_daemon.py +1372 -0
  261. aria_code/aria_feishu_bot.py +16 -0
  262. aria_code/aria_mcp_server.py +61 -0
  263. aria_code/aria_relay_client.py +4 -0
  264. aria_code/aria_telegram_bot.py +11 -0
  265. aria_code/ariarc.py +385 -0
  266. aria_code/artifacts.py +581 -0
  267. aria_code/backtest_engine.py +4 -0
  268. aria_code/backtest_report.py +4 -0
  269. aria_code/brokers/__init__.py +78 -0
  270. aria_code/brokers/automation.py +193 -0
  271. aria_code/brokers/base.py +231 -0
  272. aria_code/brokers/capabilities.py +264 -0
  273. aria_code/brokers/cn/__init__.py +10 -0
  274. aria_code/brokers/cn/easytrader_broker.py +193 -0
  275. aria_code/brokers/cn/futu_broker.py +194 -0
  276. aria_code/brokers/cn/longbridge_broker.py +190 -0
  277. aria_code/brokers/cn/tiger_broker.py +196 -0
  278. aria_code/brokers/cn/xtquant_broker.py +225 -0
  279. aria_code/brokers/config.py +414 -0
  280. aria_code/brokers/intl/__init__.py +5 -0
  281. aria_code/brokers/intl/alpaca_broker.py +183 -0
  282. aria_code/brokers/intl/ibkr_broker.py +215 -0
  283. aria_code/brokers/intl/trading212_broker.py +183 -0
  284. aria_code/brokers/intl/webull_broker.py +156 -0
  285. aria_code/brokers/paper_broker.py +266 -0
  286. aria_code/brokers/planning.py +296 -0
  287. aria_code/brokers/registry.py +213 -0
  288. aria_code/brokers/trading.py +267 -0
  289. aria_code/canva_client.py +4 -0
  290. aria_code/change_store.py +127 -0
  291. aria_code/clients/__init__.py +0 -0
  292. aria_code/clients/aliyun_data_client.py +660 -0
  293. aria_code/clients/aria_relay_client.py +16 -0
  294. aria_code/clients/canva_client.py +284 -0
  295. aria_code/clients/figma_client.py +100 -0
  296. aria_code/clients/football_data_client.py +1671 -0
  297. aria_code/clients/kling_video_client.py +182 -0
  298. aria_code/clients/market_data_client.py +1985 -0
  299. aria_code/clients/openai_image_client.py +242 -0
  300. aria_code/clients/runway_video_client.py +157 -0
  301. aria_code/clients/warehouse_erp_client.py +105 -0
  302. aria_code/cloud_memory.py +190 -0
  303. aria_code/command_safety.py +19 -0
  304. aria_code/computer_use_server.py +276 -0
  305. aria_code/computer_use_tools.py +4 -0
  306. aria_code/dashboard_generator.py +579 -0
  307. aria_code/data_analysis_tools.py +4 -0
  308. aria_code/data_cleaner.py +483 -0
  309. aria_code/data_service.py +513 -0
  310. aria_code/datasources/__init__.py +23 -0
  311. aria_code/datasources/base.py +166 -0
  312. aria_code/datasources/router.py +253 -0
  313. aria_code/datasources/sec_statements.py +217 -0
  314. aria_code/datasources/sources/__init__.py +15 -0
  315. aria_code/datasources/sources/akshare_source.py +269 -0
  316. aria_code/datasources/sources/alpha_vantage_source.py +203 -0
  317. aria_code/datasources/sources/edgar_source.py +219 -0
  318. aria_code/datasources/sources/finnhub_source.py +198 -0
  319. aria_code/datasources/sources/fred_source.py +223 -0
  320. aria_code/datasources/sources/tushare_source.py +143 -0
  321. aria_code/datasources/sources/web_scraper_source.py +278 -0
  322. aria_code/datasources/sources/world_bank_source.py +206 -0
  323. aria_code/datasources/sources/yfinance_source.py +152 -0
  324. aria_code/doctor.py +860 -0
  325. aria_code/domain/__init__.py +0 -0
  326. aria_code/domain/_finance_core/__init__.py +5 -0
  327. aria_code/domain/_finance_core/backtest_engine.py +325 -0
  328. aria_code/domain/_finance_core/performance_stats.py +101 -0
  329. aria_code/domain/backtest_engine.py +75 -0
  330. aria_code/domain/backtest_report.py +488 -0
  331. aria_code/domain/finance_formulas.py +389 -0
  332. aria_code/domain/performance_stats.py +6 -0
  333. aria_code/domain/portfolio_ledger.py +307 -0
  334. aria_code/domain/strategy_vault.py +421 -0
  335. aria_code/evals/__init__.py +37 -0
  336. aria_code/evals/behavior.py +113 -0
  337. aria_code/evals/gap.py +93 -0
  338. aria_code/evals/harness.py +949 -0
  339. aria_code/evals/review_probe.py +132 -0
  340. aria_code/evals/runner.py +425 -0
  341. aria_code/evals/scorecard.py +322 -0
  342. aria_code/evals/summary.py +125 -0
  343. aria_code/external_agent_runner.py +115 -0
  344. aria_code/figma_client.py +4 -0
  345. aria_code/file_analysis_tools.py +4 -0
  346. aria_code/finance_formulas.py +4 -0
  347. aria_code/football_data_client.py +4 -0
  348. aria_code/image_gen_tools.py +4 -0
  349. aria_code/intent_classifier.py +459 -0
  350. aria_code/kling_video_client.py +4 -0
  351. aria_code/licensing.py +151 -0
  352. aria_code/local_finance_tools.py +4 -0
  353. aria_code/local_image_provider.py +4 -0
  354. aria_code/local_llm_provider.py +4 -0
  355. aria_code/macro_tools.py +4 -0
  356. aria_code/markdown_pdf.py +289 -0
  357. aria_code/market_data_client.py +4 -0
  358. aria_code/mcp_client.py +744 -0
  359. aria_code/memory_manager.py +273 -0
  360. aria_code/model_capability.py +512 -0
  361. aria_code/notification_tools.py +4 -0
  362. aria_code/openai_image_client.py +4 -0
  363. aria_code/packages/__init__.py +26 -0
  364. aria_code/packages/adk_bridge/__init__.py +11 -0
  365. aria_code/packages/adk_bridge/code_review_tools.py +49 -0
  366. aria_code/packages/adk_bridge/market_tools.py +125 -0
  367. aria_code/packages/aria_agents/__init__.py +5 -0
  368. aria_code/packages/aria_agents/manifest.py +78 -0
  369. aria_code/packages/aria_core/__init__.py +34 -0
  370. aria_code/packages/aria_core/architecture.py +269 -0
  371. aria_code/packages/aria_core/export.py +147 -0
  372. aria_code/packages/aria_core/manifest.py +65 -0
  373. aria_code/packages/aria_core/paths.py +57 -0
  374. aria_code/packages/aria_core/secure_file.py +68 -0
  375. aria_code/packages/aria_infra/__init__.py +15 -0
  376. aria_code/packages/aria_infra/arthera.py +58 -0
  377. aria_code/packages/aria_infra/doctor.py +246 -0
  378. aria_code/packages/aria_infra/product.py +40 -0
  379. aria_code/packages/aria_mcp/__init__.py +25 -0
  380. aria_code/packages/aria_mcp/bridge.py +232 -0
  381. aria_code/packages/aria_mcp/circuit.py +82 -0
  382. aria_code/packages/aria_mcp/config.py +162 -0
  383. aria_code/packages/aria_mcp/installer.py +95 -0
  384. aria_code/packages/aria_mcp/server.py +1705 -0
  385. aria_code/packages/aria_mcp/tools.py +81 -0
  386. aria_code/packages/aria_sdk/__init__.py +19 -0
  387. aria_code/packages/aria_sdk/client.py +393 -0
  388. aria_code/packages/aria_sdk/providers.py +70 -0
  389. aria_code/packages/aria_sdk/streaming.py +75 -0
  390. aria_code/packages/aria_sdk/types.py +86 -0
  391. aria_code/packages/aria_services/__init__.py +92 -0
  392. aria_code/packages/aria_services/cache.py +60 -0
  393. aria_code/packages/aria_services/context.py +356 -0
  394. aria_code/packages/aria_services/context_checkpoints.py +157 -0
  395. aria_code/packages/aria_services/data.py +11 -0
  396. aria_code/packages/aria_services/provider_health.py +304 -0
  397. aria_code/packages/aria_services/references.py +247 -0
  398. aria_code/packages/aria_services/registry.py +249 -0
  399. aria_code/packages/aria_services/research_protocol.py +137 -0
  400. aria_code/packages/aria_services/research_quality.py +186 -0
  401. aria_code/packages/aria_services/settings.py +160 -0
  402. aria_code/packages/aria_services/usage.py +151 -0
  403. aria_code/packages/aria_skills/__init__.py +46 -0
  404. aria_code/packages/aria_skills/catalog.py +149 -0
  405. aria_code/packages/aria_skills/loader.py +455 -0
  406. aria_code/packages/aria_skills/registry.py +84 -0
  407. aria_code/packages/aria_tools/__init__.py +5 -0
  408. aria_code/packages/aria_tools/financial/__init__.py +5 -0
  409. aria_code/packages/aria_tools/financial/_paths.py +92 -0
  410. aria_code/packages/aria_tools/registry.py +129 -0
  411. aria_code/packages/quant_engine/__init__.py +33 -0
  412. aria_code/packages/quant_engine/_namespace.py +24 -0
  413. aria_code/packages/quant_engine/backtest/__init__.py +10 -0
  414. aria_code/packages/quant_engine/backtest/core.py +53 -0
  415. aria_code/packages/quant_engine/backtest/engine.py +102 -0
  416. aria_code/packages/quant_engine/portfolio/__init__.py +9 -0
  417. aria_code/packages/quant_engine/portfolio/optimizer.py +85 -0
  418. aria_code/packages/quant_engine/sports/__init__.py +76 -0
  419. aria_code/packages/quant_engine/sports/calibrator.py +354 -0
  420. aria_code/packages/quant_engine/sports/dixon_coles.py +234 -0
  421. aria_code/packages/quant_engine/sports/elo.py +300 -0
  422. aria_code/packages/quant_engine/sports/form.py +188 -0
  423. aria_code/packages/quant_engine/sports/h2h.py +195 -0
  424. aria_code/packages/quant_engine/sports/predictor.py +312 -0
  425. aria_code/packages/quant_engine/sports/tracker.py +665 -0
  426. aria_code/packages/quant_engine/stochastic/__init__.py +31 -0
  427. aria_code/packages/quant_engine/stochastic/gbm_enhanced.py +195 -0
  428. aria_code/packages/quant_engine/stochastic/ito_calculus.py +477 -0
  429. aria_code/packages/quant_engine/stochastic/kelly_criterion.py +181 -0
  430. aria_code/packages/quant_engine/stochastic/monte_carlo_advanced.py +95 -0
  431. aria_code/packages/quant_engine/stochastic/options_pricing.py +576 -0
  432. aria_code/packages/quant_engine/stochastic/stochastic_processes.py +90 -0
  433. aria_code/packs/__init__.py +85 -0
  434. aria_code/packs/base.py +168 -0
  435. aria_code/packs/finance/__init__.py +250 -0
  436. aria_code/packs/healthcare/__init__.py +40 -0
  437. aria_code/packs/logistics/__init__.py +171 -0
  438. aria_code/packs/payments/__init__.py +139 -0
  439. aria_code/packs/realty/__init__.py +190 -0
  440. aria_code/packs/registry.py +202 -0
  441. aria_code/packs/rules.py +90 -0
  442. aria_code/plan_utils.py +194 -0
  443. aria_code/plugin_loader.py +328 -0
  444. aria_code/portfolio_ledger.py +4 -0
  445. aria_code/preview_server.py +449 -0
  446. aria_code/privacy/__init__.py +5 -0
  447. aria_code/privacy/feedback.py +123 -0
  448. aria_code/project_review.py +278 -0
  449. aria_code/project_review_api.py +235 -0
  450. aria_code/project_review_server.py +18 -0
  451. aria_code/project_tools.py +4 -0
  452. aria_code/providers/__init__.py +30 -0
  453. aria_code/providers/google_video_provider.py +256 -0
  454. aria_code/providers/llm/__init__.py +19 -0
  455. aria_code/providers/llm/anthropic.py +184 -0
  456. aria_code/providers/llm/arthera_gateway.py +90 -0
  457. aria_code/providers/llm/autoconfig.py +213 -0
  458. aria_code/providers/llm/base.py +139 -0
  459. aria_code/providers/llm/custom.py +158 -0
  460. aria_code/providers/llm/ollama.py +137 -0
  461. aria_code/providers/llm/openai_compat.py +350 -0
  462. aria_code/providers/llm/registry.py +457 -0
  463. aria_code/providers/local_image_provider.py +202 -0
  464. aria_code/providers/local_llm_provider.py +549 -0
  465. aria_code/providers/ollama_models.py +79 -0
  466. aria_code/providers/openai_params.py +32 -0
  467. aria_code/providers/tool_messages.py +100 -0
  468. aria_code/realty_data_tools.py +4 -0
  469. aria_code/report_exporters.py +150 -0
  470. aria_code/report_generator.py +1764 -0
  471. aria_code/review_service.py +497 -0
  472. aria_code/runtime/__init__.py +176 -0
  473. aria_code/runtime/acceptance.py +632 -0
  474. aria_code/runtime/agent_loop.py +1851 -0
  475. aria_code/runtime/agent_profiles.py +75 -0
  476. aria_code/runtime/approval.py +71 -0
  477. aria_code/runtime/baseline.py +219 -0
  478. aria_code/runtime/budget.py +232 -0
  479. aria_code/runtime/checkpoints.py +481 -0
  480. aria_code/runtime/consult.py +65 -0
  481. aria_code/runtime/contract.py +282 -0
  482. aria_code/runtime/delivery.py +432 -0
  483. aria_code/runtime/events.py +113 -0
  484. aria_code/runtime/gateway.py +167 -0
  485. aria_code/runtime/lsp.py +484 -0
  486. aria_code/runtime/native_index.py +153 -0
  487. aria_code/runtime/orchestrator.py +55 -0
  488. aria_code/runtime/processes.py +343 -0
  489. aria_code/runtime/project_graph.py +614 -0
  490. aria_code/runtime/repo_map.py +712 -0
  491. aria_code/runtime/research_bundle.py +105 -0
  492. aria_code/runtime/review.py +269 -0
  493. aria_code/runtime/run_state.py +127 -0
  494. aria_code/runtime/run_store.py +522 -0
  495. aria_code/runtime/scoped_runs.py +113 -0
  496. aria_code/runtime/self_healing.py +422 -0
  497. aria_code/runtime/semantic_diff.py +171 -0
  498. aria_code/runtime/subagent.py +721 -0
  499. aria_code/runtime/symbol_edit.py +117 -0
  500. aria_code/runtime/task_brief.py +46 -0
  501. aria_code/runtime/task_context.py +145 -0
  502. aria_code/runtime/task_ledger.py +108 -0
  503. aria_code/runtime/task_orchestrator.py +90 -0
  504. aria_code/runtime/task_outcome.py +33 -0
  505. aria_code/runtime/task_verification.py +266 -0
  506. aria_code/runtime/task_worktree.py +448 -0
  507. aria_code/runtime/tool_executor.py +329 -0
  508. aria_code/runtime/tool_policy.py +107 -0
  509. aria_code/runtime/transactions.py +216 -0
  510. aria_code/runtime/windows_job.py +115 -0
  511. aria_code/runtime/workflows.py +222 -0
  512. aria_code/runtime/worktrees.py +215 -0
  513. aria_code/runway_video_client.py +4 -0
  514. aria_code/safety/__init__.py +27 -0
  515. aria_code/safety/client_isolation.py +178 -0
  516. aria_code/safety/permissions.py +339 -0
  517. aria_code/safety/risk.py +699 -0
  518. aria_code/safety/sandbox.py +148 -0
  519. aria_code/safety/service.py +102 -0
  520. aria_code/service_endpoints.py +14 -0
  521. aria_code/setup_wizard.py +684 -0
  522. aria_code/spreadsheet_tools.py +4 -0
  523. aria_code/strategy_vault.py +4 -0
  524. aria_code/tools/__init__.py +0 -0
  525. aria_code/tools/artifact_tools.py +252 -0
  526. aria_code/tools/broker_tools.py +92 -0
  527. aria_code/tools/build_quant_engine.py +97 -0
  528. aria_code/tools/code_audit_tools.py +192 -0
  529. aria_code/tools/computer_use_tools.py +509 -0
  530. aria_code/tools/data_analysis_tools.py +831 -0
  531. aria_code/tools/enterprise_finance_tools.py +202 -0
  532. aria_code/tools/extended_tools.py +240 -0
  533. aria_code/tools/file_analysis_tools.py +880 -0
  534. aria_code/tools/image_gen_tools.py +114 -0
  535. aria_code/tools/local_finance_tools.py +3488 -0
  536. aria_code/tools/logistics_carriers.py +11 -0
  537. aria_code/tools/logistics_inventory.py +11 -0
  538. aria_code/tools/logistics_io.py +11 -0
  539. aria_code/tools/logistics_tenancy.py +11 -0
  540. aria_code/tools/logistics_tools.py +11 -0
  541. aria_code/tools/macro_tools.py +412 -0
  542. aria_code/tools/notification_tools.py +249 -0
  543. aria_code/tools/project_tools.py +525 -0
  544. aria_code/tools/realty_data_tools.py +662 -0
  545. aria_code/tools/spreadsheet_tools.py +399 -0
  546. aria_code/tools/stripe_tools.py +115 -0
  547. aria_code/tools/video_tools.py +500 -0
  548. aria_code/training/__init__.py +1 -0
  549. aria_code/training/compare.py +117 -0
  550. aria_code/training/prelude_commands.py +111 -0
  551. aria_code/training/prelude_eval.py +390 -0
  552. aria_code/training/prelude_real.py +183 -0
  553. aria_code/training/prelude_train.py +248 -0
  554. aria_code/training/sft_dataset.py +230 -0
  555. aria_code/training/trajectory_dataset.py +263 -0
  556. aria_code/ui/__init__.py +105 -0
  557. aria_code/ui/banner.py +404 -0
  558. aria_code/ui/completer.py +571 -0
  559. aria_code/ui/console.py +285 -0
  560. aria_code/ui/input_box.py +505 -0
  561. aria_code/ui/mentions.py +206 -0
  562. aria_code/ui/picker.py +248 -0
  563. aria_code/ui/render/__init__.py +11 -0
  564. aria_code/ui/render/actions.py +297 -0
  565. aria_code/ui/render/finance.py +1732 -0
  566. aria_code/ui/render/market.py +253 -0
  567. aria_code/ui/render/output.py +954 -0
  568. aria_code/ui/render/responsive.py +75 -0
  569. aria_code/ui/render/team.py +367 -0
  570. aria_code/ui/robot.py +239 -0
  571. aria_code/ui/startup_dashboard.py +110 -0
  572. aria_code/video_analysis.py +147 -0
  573. aria_code/video_editor.py +518 -0
  574. aria_code/video_workflow/__init__.py +8 -0
  575. aria_code/video_workflow/__main__.py +61 -0
  576. aria_code/video_workflow/engines/__init__.py +18 -0
  577. aria_code/video_workflow/engines/base.py +69 -0
  578. aria_code/video_workflow/engines/custom_model.py +204 -0
  579. aria_code/video_workflow/engines/google_veo.py +94 -0
  580. aria_code/video_workflow/engines/local_engine.py +71 -0
  581. aria_code/video_workflow/engines/registry.py +98 -0
  582. aria_code/video_workflow/google_models.py +278 -0
  583. aria_code/video_workflow/music/__init__.py +5 -0
  584. aria_code/video_workflow/music/foley_service.py +132 -0
  585. aria_code/video_workflow/music/service.py +212 -0
  586. aria_code/video_workflow/pipeline.py +620 -0
  587. aria_code/video_workflow/plan.py +202 -0
  588. aria_code/video_workflow/session.py +297 -0
  589. aria_code/workspace/__init__.py +6 -0
  590. aria_code/workspace/files.py +219 -0
  591. aria_code/workspace/verify.py +167 -0
  592. aria_code/workspace_changes.py +199 -0
  593. aria_code/workspace_service.py +196 -0
  594. aria_code/workspace_tools.py +150 -0
  595. aria_code-0.167.0.dist-info/METADATA +330 -0
  596. aria_code-0.167.0.dist-info/RECORD +601 -0
  597. aria_code-0.167.0.dist-info/WHEEL +5 -0
  598. aria_code-0.167.0.dist-info/entry_points.txt +5 -0
  599. aria_code-0.167.0.dist-info/licenses/LICENSE +201 -0
  600. aria_code-0.167.0.dist-info/licenses/NOTICE +49 -0
  601. aria_code-0.167.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,699 @@
1
+ """Risk assessment for agent actions: what an action can touch, and how badly.
2
+
3
+ ``classify_command_risk`` answers one question — low, medium or high — and the
4
+ policy layer decides from that whether a command may run. That is enough to
5
+ gate, not enough to explain. "Allow `npm install jose`? [y/N]" asks a person to
6
+ judge a command; what they actually need to judge is its consequences: it
7
+ reaches the npm registry, it rewrites package.json and the lockfile, and it can
8
+ be undone. This module turns an action into that description.
9
+
10
+ An assessment carries:
11
+
12
+ - a **level**, L0–L4, the unit approvals are decided in:
13
+
14
+ ==== =============================== ===============================
15
+ L0 read / inspect / verify ls, cat, rg, git diff, pytest
16
+ L1 change inside the workspace edit a source file, git add
17
+ L2 change the environment npm install, pip install, curl
18
+ L3 act outside the machine's repo git commit/push, gh pr create
19
+ L4 destructive or production rm, force push, migrate, deploy,
20
+ secrets, sudo
21
+ ==== =============================== ===============================
22
+
23
+ - a **score** (0–100) for ordering and display within a level;
24
+ - the **capabilities** used (``network.read``, ``package.install``,
25
+ ``git.push`` …) — finer than a permission mode, and what a Change Contract
26
+ names when it forbids something;
27
+ - whether it is **reversible**, the **reasons**, and its **scope** (hosts,
28
+ files, systems) — the blast radius.
29
+
30
+ It never lowers what the existing policy says: a command
31
+ ``classify_command_risk`` calls high is at least L3 here. Assessment is
32
+ description; whether to run stays with ``evaluate_command_policy``.
33
+ """
34
+
35
+ from __future__ import annotations
36
+
37
+ import re
38
+ import shlex
39
+ from dataclasses import dataclass, field
40
+ from pathlib import Path
41
+ from typing import Any, Iterable, Mapping, Optional
42
+ from urllib.parse import urlparse
43
+
44
+ from .permissions import (
45
+ classify_command_risk,
46
+ has_shell_control,
47
+ is_verification_command,
48
+ normalize_command,
49
+ writes_a_device,
50
+ )
51
+
52
+ LEVEL_NAMES = {0: "none", 1: "low", 2: "medium", 3: "high", 4: "critical"}
53
+ _BASE_SCORE = {0: 5, 1: 20, 2: 40, 3: 65, 4: 85}
54
+
55
+ # Every capability an assessment can name. A contract that forbids one not in
56
+ # this set is a typo, and is reported as one.
57
+ CAPABILITIES = frozenset({
58
+ "filesystem.read", "filesystem.write", "filesystem.delete",
59
+ "process.execute",
60
+ "network.read", "network.write",
61
+ "package.install",
62
+ "git.stage", "git.commit", "git.push", "git.history",
63
+ "github.pr",
64
+ "database.read", "database.write",
65
+ "secret.read",
66
+ "cloud.deploy",
67
+ "system.admin",
68
+ # Physical: acting on a device or a robot, which cannot be undone with a checkpoint.
69
+ "hardware.flash", "actuator.command",
70
+ # The live desktop: reading the screen and driving the mouse and keyboard.
71
+ "screen.capture", "desktop.control",
72
+ })
73
+
74
+
75
+ @dataclass(frozen=True)
76
+ class RiskAssessment:
77
+ level: int
78
+ score: int
79
+ capabilities: frozenset = frozenset()
80
+ reversible: bool = True
81
+ reasons: tuple = ()
82
+ # Blast radius: what the action reaches, by kind.
83
+ hosts: tuple = ()
84
+ files: tuple = ()
85
+ systems: tuple = ()
86
+ summary: str = ""
87
+
88
+ @property
89
+ def name(self) -> str:
90
+ return LEVEL_NAMES[self.level]
91
+
92
+ @property
93
+ def legacy_risk(self) -> str:
94
+ """The low/medium/high the older policy layer speaks."""
95
+ return "low" if self.level == 0 else "high" if self.level >= 3 else "medium"
96
+
97
+ def as_dict(self) -> dict:
98
+ return {
99
+ "level": self.level,
100
+ "name": self.name,
101
+ "score": self.score,
102
+ "capabilities": sorted(self.capabilities),
103
+ "reversible": self.reversible,
104
+ "reasons": list(self.reasons),
105
+ "hosts": list(self.hosts),
106
+ "files": list(self.files),
107
+ "systems": list(self.systems),
108
+ "summary": self.summary,
109
+ }
110
+
111
+
112
+ @dataclass
113
+ class _Draft:
114
+ level: int = 0
115
+ capabilities: set = field(default_factory=set)
116
+ reversible: bool = True
117
+ reasons: list = field(default_factory=list)
118
+ hosts: list = field(default_factory=list)
119
+ files: list = field(default_factory=list)
120
+ systems: list = field(default_factory=list)
121
+ summary: str = ""
122
+
123
+ def raise_to(self, level: int, reason: str = "", *, reversible: Optional[bool] = None) -> None:
124
+ self.level = max(self.level, level)
125
+ if reason and reason not in self.reasons:
126
+ self.reasons.append(reason)
127
+ if reversible is False:
128
+ self.reversible = False
129
+
130
+ def merge(self, other: "_Draft") -> None:
131
+ self.level = max(self.level, other.level)
132
+ self.capabilities |= other.capabilities
133
+ self.reversible = self.reversible and other.reversible
134
+ for mine, theirs in ((self.reasons, other.reasons), (self.hosts, other.hosts),
135
+ (self.files, other.files), (self.systems, other.systems)):
136
+ mine.extend(item for item in theirs if item not in mine)
137
+ self.summary = self.summary or other.summary
138
+
139
+ def freeze(self, *, extra: int = 0) -> RiskAssessment:
140
+ score = _BASE_SCORE[self.level] + extra
141
+ if not self.reversible:
142
+ score += 8
143
+ if "network.write" in self.capabilities or "network.read" in self.capabilities:
144
+ score += 3
145
+ return RiskAssessment(
146
+ level=self.level,
147
+ score=max(0, min(100, score)),
148
+ capabilities=frozenset(self.capabilities),
149
+ reversible=self.reversible,
150
+ reasons=tuple(self.reasons),
151
+ hosts=tuple(self.hosts),
152
+ files=tuple(self.files),
153
+ systems=tuple(self.systems),
154
+ summary=self.summary,
155
+ )
156
+
157
+
158
+ # ── commands ──────────────────────────────────────────────────────────────────
159
+
160
+ _SEGMENTS = re.compile(r"\|\||&&|[|;&\n]")
161
+ _READ_COMMANDS = {
162
+ "ls", "pwd", "echo", "cat", "head", "tail", "less", "more", "wc", "rg", "grep", "find",
163
+ "fd", "tree", "which", "whoami", "date", "uname", "file", "stat", "du", "df", "diff",
164
+ "sort", "uniq", "cut", "awk", "sed", "jq", "true", "false", "test", "basename", "dirname",
165
+ }
166
+ _GIT_READ = {"status", "diff", "log", "show", "blame", "branch", "rev-parse", "ls-files",
167
+ "remote", "describe", "shortlog", "grep", "config"}
168
+ _INSTALLERS = {
169
+ # tool -> (subcommands that install, files rewritten, registry host)
170
+ "npm": ({"install", "i", "add", "ci", "update", "uninstall", "remove"},
171
+ ("package.json", "package-lock.json"), "registry.npmjs.org"),
172
+ "pnpm": ({"install", "i", "add", "update", "remove"}, ("package.json", "pnpm-lock.yaml"),
173
+ "registry.npmjs.org"),
174
+ "yarn": ({"install", "add", "upgrade", "remove", ""}, ("package.json", "yarn.lock"),
175
+ "registry.yarnpkg.com"),
176
+ "bun": ({"install", "add", "i", "remove"}, ("package.json", "bun.lockb"), "registry.npmjs.org"),
177
+ "pip": ({"install", "uninstall"}, (), "pypi.org"),
178
+ "pip3": ({"install", "uninstall"}, (), "pypi.org"),
179
+ "uv": ({"add", "pip", "sync", "remove"}, ("pyproject.toml", "uv.lock"), "pypi.org"),
180
+ "poetry": ({"add", "install", "update", "remove"}, ("pyproject.toml", "poetry.lock"), "pypi.org"),
181
+ "cargo": ({"add", "install", "update", "remove"}, ("Cargo.toml", "Cargo.lock"), "crates.io"),
182
+ "go": ({"get", "install"}, ("go.mod", "go.sum"), "proxy.golang.org"),
183
+ "gem": ({"install", "uninstall"}, (), "rubygems.org"),
184
+ "bundle": ({"install", "add", "update"}, ("Gemfile", "Gemfile.lock"), "rubygems.org"),
185
+ "brew": ({"install", "uninstall", "upgrade"}, (), "formulae.brew.sh"),
186
+ "apt": ({"install", "remove"}, (), "deb.debian.org"),
187
+ "apt-get": ({"install", "remove"}, (), "deb.debian.org"),
188
+ }
189
+ _DEPLOY = (
190
+ re.compile(r"^vercel\b.*--prod"), re.compile(r"^(fly|flyctl) deploy\b"),
191
+ re.compile(r"^netlify deploy\b.*--prod"), re.compile(r"^firebase deploy\b"),
192
+ re.compile(r"^gcloud (app|run|functions) deploy\b"), re.compile(r"^terraform (apply|destroy)\b"),
193
+ re.compile(r"^pulumi (up|destroy)\b"), re.compile(r"^kubectl (apply|delete|rollout|scale)\b"),
194
+ re.compile(r"^helm (install|upgrade|uninstall)\b"), re.compile(r"^docker push\b"),
195
+ re.compile(r"^(npm|pnpm|yarn) publish\b"), re.compile(r"^twine upload\b"),
196
+ re.compile(r"^cargo publish\b"), re.compile(r"^aws .*\b(deploy|update-function-code|s3 (rm|sync|cp))\b"),
197
+ re.compile(r"^serverless deploy\b"), re.compile(r"^sls deploy\b"),
198
+ )
199
+ _MIGRATIONS = (
200
+ re.compile(r"\bmigrate\b"), re.compile(r"\balembic (upgrade|downgrade)\b"),
201
+ re.compile(r"\bprisma (migrate|db push)\b"), re.compile(r"\bdb:(migrate|rollback|drop|reset)\b"),
202
+ re.compile(r"\bknex migrate\b"), re.compile(r"\bflyway migrate\b"),
203
+ )
204
+ # Programmers that write firmware to a device: (command, the words that mean "write").
205
+ _FLASHERS = {
206
+ "esptool": {"write_flash", "write-flash", "erase_flash", "erase-flash", "erase_region", "erase-region"},
207
+ "esptool.py": {"write_flash", "write-flash", "erase_flash", "erase-flash", "erase_region", "erase-region"},
208
+ "dfu-util": {"-D", "--download"},
209
+ "st-flash": {"write", "erase"},
210
+ "stm32flash": {"-w"},
211
+ "nrfjprog": {"--program", "--eraseall", "--recover"},
212
+ "picotool": {"load", "erase"},
213
+ "fastboot": {"flash", "flashall", "erase", "update"},
214
+ "arduino-cli": {"upload"},
215
+ "pio": {"upload"},
216
+ "platformio": {"upload"},
217
+ "idf.py": {"flash", "erase-flash", "erase_flash"},
218
+ "west": {"flash"},
219
+ }
220
+ def _writes_firmware(head: str, words: list, lowered: str) -> bool:
221
+ """True for a programmer invoked to write or erase a device, not to read it."""
222
+ if head == "openocd":
223
+ return bool(re.search(r"\b(program|flash write_image)\b", lowered))
224
+ if head == "avrdude":
225
+ return bool(re.search(r"flash:w", lowered))
226
+ verbs = _FLASHERS.get(head)
227
+ return verbs is not None and any(word in verbs for word in words[1:])
228
+
229
+
230
+ # `ros2 <noun> <verb>` that send a command to a running robot.
231
+ _ROS_ACTUATION = {("topic", "pub"), ("service", "call"), ("action", "send_goal"),
232
+ ("param", "set"), ("lifecycle", "set")}
233
+ _SQL_WRITE = re.compile(r"\b(insert|update|delete|drop|alter|truncate|create)\b", re.IGNORECASE)
234
+ _DB_CLIENTS = {"psql", "mysql", "sqlite3", "mongosh", "mongo", "redis-cli", "cqlsh"}
235
+ _SECRET_PATH = re.compile(
236
+ r"(^|[\s/'\"])(\.env(\.[\w-]+)?|\.npmrc|\.pypirc|\.netrc|id_rsa|id_ed25519|"
237
+ r"[\w.-]+\.pem|[\w.-]+\.key|credentials(\.json)?|\.aws/credentials|\.ssh/)(\s|$|['\"])"
238
+ )
239
+ _URL = re.compile(r"https?://[^\s'\"]+")
240
+ _PIPE_TO_SHELL = re.compile(r"\b(curl|wget)\b[^|;&]*\|\s*(sudo\s+)?(ba|z|da)?sh\b")
241
+ _HTTP_WRITE = re.compile(r"(\s-X\s*(POST|PUT|PATCH|DELETE)\b|\s--data\b|\s-d\s|\s--data-\w+|\s-F\s|\s--form\b)",
242
+ re.IGNORECASE)
243
+
244
+
245
+ def _words(segment: str) -> list[str]:
246
+ try:
247
+ return shlex.split(segment)
248
+ except ValueError:
249
+ return segment.split()
250
+
251
+
252
+ def _hosts(segment: str) -> list[str]:
253
+ hosts = []
254
+ for url in _URL.findall(segment):
255
+ host = urlparse(url).hostname
256
+ if host and host not in hosts:
257
+ hosts.append(host)
258
+ return hosts
259
+
260
+
261
+ def _targets(words: list[str]) -> list[str]:
262
+ return [w for w in words[1:] if not w.startswith("-")]
263
+
264
+
265
+ def _assess_segment(segment: str) -> _Draft:
266
+ draft = _Draft()
267
+ words = _words(segment)
268
+ if not words:
269
+ return draft
270
+ # `VAR=1 cmd`, `sudo cmd`, `time cmd`: judge the command, note the wrapper.
271
+ while words and re.match(r"^\w+=", words[0]):
272
+ words = words[1:]
273
+ if words and words[0] == "sudo":
274
+ draft.capabilities.add("system.admin")
275
+ draft.raise_to(4, "Runs with administrator privileges", reversible=False)
276
+ draft.systems.append("Operating system")
277
+ words = words[1:]
278
+ while words and words[0] in {"time", "nice", "nohup", "env"} and len(words) > 1:
279
+ words = words[1:]
280
+ if not words:
281
+ return draft
282
+ head = Path(words[0]).name
283
+ sub = words[1] if len(words) > 1 else ""
284
+ lowered = segment.lower().strip()
285
+ draft.capabilities.add("process.execute")
286
+
287
+ if _SECRET_PATH.search(" " + segment + " ") and head in _READ_COMMANDS | {"source", "."}:
288
+ draft.capabilities.add("secret.read")
289
+ draft.raise_to(4, "Reads a credentials or secrets file", reversible=False)
290
+ draft.summary = "Read secrets"
291
+ return draft
292
+ if head in {"env", "printenv"}:
293
+ draft.capabilities.add("secret.read")
294
+ draft.raise_to(3, "Prints environment variables, which may hold secrets")
295
+ draft.summary = "Print environment"
296
+ return draft
297
+
298
+ if head == "git":
299
+ return _assess_git(words, draft)
300
+ if head == "gh":
301
+ return _assess_gh(words, draft)
302
+ if head in _INSTALLERS:
303
+ installs, files, host = _INSTALLERS[head]
304
+ if sub in installs:
305
+ draft.capabilities |= {"package.install", "network.read"}
306
+ draft.raise_to(2, f"Changes installed dependencies ({head} {sub})".strip())
307
+ draft.hosts.append(host)
308
+ draft.files.extend(files)
309
+ if not files:
310
+ draft.systems.append("Python environment" if head.startswith("pip") else "System packages"
311
+ if head in {"brew", "apt", "apt-get"} else f"{head} environment")
312
+ draft.summary = "Install dependency"
313
+ return draft
314
+ if _writes_firmware(head, words, lowered):
315
+ draft.capabilities.add("hardware.flash")
316
+ draft.raise_to(4, "Writes firmware to a device; a bad image can leave it unusable", reversible=False)
317
+ draft.systems.append("Device firmware")
318
+ draft.summary = "Flash firmware"
319
+ return draft
320
+ if head == "ros2" and len(words) >= 3 and (words[1], words[2]) in _ROS_ACTUATION:
321
+ draft.capabilities.add("actuator.command")
322
+ draft.raise_to(4, f"Sends a command to a running robot (ros2 {words[1]} {words[2]}); it may move hardware",
323
+ reversible=False)
324
+ draft.systems.append("Robot / actuators")
325
+ draft.summary = "Command a robot"
326
+ return draft
327
+ for pattern in _DEPLOY:
328
+ if pattern.search(lowered):
329
+ draft.capabilities |= {"cloud.deploy", "network.write"}
330
+ draft.raise_to(4, "Deploys or publishes outside this machine", reversible=False)
331
+ draft.systems.append("Production / remote environment")
332
+ draft.summary = "Deploy or publish"
333
+ return draft
334
+ if any(pattern.search(lowered) for pattern in _MIGRATIONS):
335
+ draft.capabilities.add("database.write")
336
+ draft.raise_to(4, "Runs a database migration", reversible=False)
337
+ draft.systems.append("Database schema")
338
+ draft.summary = "Database migration"
339
+ return draft
340
+ if head in _DB_CLIENTS:
341
+ if _SQL_WRITE.search(segment):
342
+ draft.capabilities.add("database.write")
343
+ draft.raise_to(4, "Writes to a database", reversible=False)
344
+ draft.systems.append("Database")
345
+ draft.summary = "Database write"
346
+ else:
347
+ draft.capabilities.add("database.read")
348
+ draft.raise_to(2, "Connects to a database")
349
+ draft.systems.append("Database")
350
+ draft.summary = "Database query"
351
+ return draft
352
+ if head in {"curl", "wget", "http", "https", "httpie", "xh"}:
353
+ hosts = _hosts(segment)
354
+ draft.hosts.extend(hosts)
355
+ if head in {"curl", "http", "https", "httpie", "xh"} and _HTTP_WRITE.search(" " + segment + " "):
356
+ draft.capabilities.add("network.write")
357
+ draft.raise_to(3, "Sends data to a remote server", reversible=False)
358
+ draft.summary = "Network write"
359
+ else:
360
+ draft.capabilities.add("network.read")
361
+ draft.raise_to(2, "Fetches from the network")
362
+ draft.summary = "Network request"
363
+ return draft
364
+ if head == "rm" or head == "rmdir" or head == "shred" or head == "unlink":
365
+ draft.capabilities.add("filesystem.delete")
366
+ targets = _targets(words)
367
+ draft.files.extend(targets)
368
+ draft.raise_to(4, "Deletes files without a checkpoint", reversible=False)
369
+ if any(t in {"/", "~", "*", ".", ".."} or t.startswith(("/", "~")) for t in targets):
370
+ draft.raise_to(4, "Deletes outside the workspace or a whole tree")
371
+ draft.summary = "Delete files"
372
+ return draft
373
+ if head in {"mv", "cp", "touch", "mkdir", "ln", "tee"}:
374
+ draft.capabilities.add("filesystem.write")
375
+ draft.files.extend(_targets(words)[-1:])
376
+ draft.raise_to(1, "Changes files in the workspace")
377
+ draft.summary = "Change files"
378
+ return draft
379
+ if head in {"chmod", "chown", "mkfs", "dd", "shutdown", "reboot", "systemctl", "launchctl", "passwd", "kill",
380
+ "killall", "pkill", "docker", "kubectl"}:
381
+ draft.capabilities.add("system.admin")
382
+ draft.raise_to(3 if head in {"kill", "pkill", "killall", "docker"} else 4,
383
+ "Changes system state outside the workspace", reversible=False)
384
+ draft.systems.append("Operating system")
385
+ draft.summary = "System change"
386
+ return draft
387
+ if is_verification_command(segment):
388
+ draft.capabilities.add("filesystem.read")
389
+ draft.summary = "Verify"
390
+ return draft
391
+ if head in _READ_COMMANDS:
392
+ if head == "sed" and re.search(r"\s-i\b", segment):
393
+ draft.capabilities.add("filesystem.write")
394
+ draft.raise_to(1, "Edits files in place")
395
+ draft.files.extend(_targets(words)[-1:])
396
+ draft.summary = "Change files"
397
+ else:
398
+ draft.capabilities.add("filesystem.read")
399
+ draft.summary = "Inspect"
400
+ return draft
401
+ # A program we cannot see into: it runs code and may write.
402
+ draft.capabilities |= {"filesystem.write"}
403
+ draft.raise_to(1, f"Runs {head}, which may change files in the workspace")
404
+ draft.summary = f"Run {head}"
405
+ return draft
406
+
407
+
408
+ def _assess_git(words: list[str], draft: _Draft) -> _Draft:
409
+ args = [w for w in words[1:] if not w.startswith("-C")]
410
+ sub = next((w for w in args if not w.startswith("-")), "")
411
+ flags = set(words)
412
+ if sub in _GIT_READ:
413
+ draft.capabilities.add("filesystem.read")
414
+ draft.summary = "Inspect repository"
415
+ return draft
416
+ if sub in {"fetch", "pull", "clone"}:
417
+ draft.capabilities |= {"network.read", "git.history"} if sub != "clone" else {"network.read",
418
+ "filesystem.write"}
419
+ draft.raise_to(2, f"git {sub} reaches a remote")
420
+ draft.summary = f"git {sub}"
421
+ return draft
422
+ if sub in {"add", "rm", "mv", "restore", "stash", "switch", "checkout", "worktree"}:
423
+ draft.capabilities.add("git.stage")
424
+ draft.raise_to(1, f"git {sub} changes the working tree or index")
425
+ discards = (sub == "checkout" and "--" in words) or (sub == "restore" and "--staged" not in flags)
426
+ if discards:
427
+ draft.raise_to(4, "Discards uncommitted changes", reversible=False)
428
+ draft.summary = f"git {sub}"
429
+ return draft
430
+ if sub in {"commit", "merge", "rebase", "cherry-pick", "revert", "tag", "am"}:
431
+ draft.capabilities.add("git.commit")
432
+ draft.raise_to(3, f"git {sub} writes repository history")
433
+ draft.summary = f"git {sub}"
434
+ return draft
435
+ if sub == "push":
436
+ draft.capabilities |= {"git.push", "network.write"}
437
+ draft.hosts.append("git remote")
438
+ if flags & {"--force", "-f", "--force-with-lease", "--mirror", "--delete", "-d"} or any(
439
+ w.startswith("+") for w in args[1:]):
440
+ draft.raise_to(4, "Rewrites or deletes history on the remote", reversible=False)
441
+ draft.summary = "Force push"
442
+ else:
443
+ draft.raise_to(3, "Publishes commits to the remote", reversible=False)
444
+ draft.summary = "git push"
445
+ return draft
446
+ if sub in {"reset", "clean"}:
447
+ draft.capabilities.add("git.history")
448
+ if "--hard" in flags or sub == "clean":
449
+ draft.raise_to(4, "Discards uncommitted work", reversible=False)
450
+ else:
451
+ draft.raise_to(1, "Moves the index")
452
+ draft.summary = f"git {sub}"
453
+ return draft
454
+ draft.capabilities.add("git.history")
455
+ draft.raise_to(1, f"git {sub or 'command'}")
456
+ draft.summary = f"git {sub}".strip()
457
+ return draft
458
+
459
+
460
+ def _assess_gh(words: list[str], draft: _Draft) -> _Draft:
461
+ sub = words[1] if len(words) > 1 else ""
462
+ action = words[2] if len(words) > 2 else ""
463
+ draft.hosts.append("github.com")
464
+ if sub == "pr" and action in {"create", "merge", "close", "edit", "comment", "review", "ready"}:
465
+ draft.capabilities |= {"github.pr", "network.write"}
466
+ draft.raise_to(4 if action == "merge" else 3, f"gh pr {action} acts on GitHub", reversible=action != "merge")
467
+ draft.summary = f"gh pr {action}"
468
+ return draft
469
+ if sub in {"release", "repo", "secret", "workflow", "api"} and action not in {"view", "list", "status", ""}:
470
+ draft.capabilities.add("network.write")
471
+ draft.raise_to(4 if sub in {"secret", "release", "repo"} else 3, f"gh {sub} {action} changes GitHub",
472
+ reversible=False)
473
+ draft.summary = f"gh {sub} {action}"
474
+ return draft
475
+ draft.capabilities.add("network.read")
476
+ draft.raise_to(2, "Reads from GitHub")
477
+ draft.summary = f"gh {sub}".strip()
478
+ return draft
479
+
480
+
481
+ def assess_command(command: Any) -> RiskAssessment:
482
+ """What running *command* touches, and how badly. Never raises."""
483
+ normalized = normalize_command(command)
484
+ if not normalized:
485
+ return _Draft().freeze()
486
+ draft = _Draft()
487
+ segments = [s.strip() for s in _SEGMENTS.split(normalized) if s.strip()] or [normalized]
488
+ for segment in segments:
489
+ draft.merge(_assess_segment(segment))
490
+ if len(segments) > 1:
491
+ draft.summary = draft.summary or "Compound command"
492
+ # Segments are judged one by one, so this has to look across the pipe.
493
+ if _PIPE_TO_SHELL.search(normalized):
494
+ draft.capabilities.add("network.read")
495
+ draft.raise_to(4, "Runs a downloaded script without reading it", reversible=False)
496
+ draft.summary = "Download and run"
497
+ if writes_a_device(normalized):
498
+ draft.capabilities.add("system.admin")
499
+ draft.raise_to(4, "Writes to a device", reversible=False)
500
+ if re.search(r">>?\s*[^&\s]", normalized) and "filesystem.write" not in draft.capabilities:
501
+ draft.capabilities.add("filesystem.write")
502
+ draft.raise_to(1, "Redirects output into a file")
503
+ # Never describe as safer than the gate treats it.
504
+ legacy = classify_command_risk(normalized)
505
+ if legacy == "high" and draft.level < 3:
506
+ draft.raise_to(3, "Classified high-risk by the command policy")
507
+ if legacy == "medium" and draft.level == 0 and not is_verification_command(normalized):
508
+ draft.raise_to(1)
509
+ extra = 4 if has_shell_control(normalized) and len(segments) > 1 else 0
510
+ return draft.freeze(extra=extra)
511
+
512
+
513
+ # ── tools ─────────────────────────────────────────────────────────────────────
514
+
515
+ READ_TOOLS = frozenset({
516
+ "read_file", "list_files", "search_code", "glob", "project_context", "git_status", "git_diff",
517
+ "repo_map", "find_symbol", "analyze_file", "notebook_read", "update_todos",
518
+ })
519
+ WRITE_TOOLS = frozenset({
520
+ "write_file", "edit_file", "multi_edit", "apply_change", "apply_patch", "notebook_edit",
521
+ })
522
+ NETWORK_READ_TOOLS = frozenset({
523
+ "web_fetch", "web_search", "get_market_data", "get_market_history", "browser_navigate", "browser_screenshot",
524
+ })
525
+ #: Tools that act on, or read, the person's own screen. None is ever approved automatically,
526
+ #: and a blanket "allow all tools" does not cover them (see tool_executor).
527
+ DESKTOP_TOOLS = frozenset({"computer_action", "computer_screenshot"})
528
+ _POINTER_QUIET = frozenset({"move", "scroll"})
529
+ _KEY_ALIASES = {"command": "cmd", "option": "alt", "opt": "alt", "control": "ctrl", "del": "delete",
530
+ "return": "enter", "escape": "esc"}
531
+ # Combinations that close, quit, delete or reboot whatever has focus.
532
+ _KEY_DESTRUCTIVE = (
533
+ {"cmd", "q"}, {"cmd", "alt", "q"}, {"cmd", "shift", "q"}, {"alt", "f4"}, {"ctrl", "alt", "delete"},
534
+ {"cmd", "alt", "esc"}, {"cmd", "delete"}, {"cmd", "backspace"}, {"ctrl", "shift", "delete"},
535
+ {"cmd", "shift", "delete"}, {"ctrl", "shift", "q"},
536
+ )
537
+
538
+
539
+ def _key_parts(key: Any) -> set[str]:
540
+ parts = [p for p in re.split(r"[\s+]+", str(key or "").lower()) if p]
541
+ return {_KEY_ALIASES.get(p, p) for p in parts}
542
+
543
+
544
+ def _assess_desktop(name: str, params: Mapping[str, Any]) -> RiskAssessment:
545
+ draft = _Draft()
546
+ draft.systems.append("This computer's screen")
547
+ if name == "computer_screenshot":
548
+ draft.capabilities.add("screen.capture")
549
+ draft.raise_to(3, "Captures everything visible on screen, which may include private content")
550
+ draft.summary = "Capture the screen"
551
+ return draft.freeze()
552
+ action = str(params.get("action") or "").strip().lower()
553
+ draft.capabilities.add("desktop.control")
554
+ if action in _POINTER_QUIET:
555
+ draft.raise_to(2, "Moves the pointer or scrolls on the live desktop")
556
+ draft.summary = f"Desktop {action}"
557
+ return draft.freeze()
558
+ draft.raise_to(3, "Drives the mouse or keyboard of the live desktop", reversible=False)
559
+ draft.summary = f"Desktop {action or 'input'}"
560
+ if action == "type":
561
+ text = str(params.get("text") or "")
562
+ if "\n" in text or "\r" in text:
563
+ draft.raise_to(4, "Types a line break, which submits or runs whatever is focused", reversible=False)
564
+ elif action == "key":
565
+ parts = _key_parts(params.get("key"))
566
+ if any(combo <= parts for combo in _KEY_DESTRUCTIVE):
567
+ draft.raise_to(4, "Key combination that quits, closes or deletes", reversible=False)
568
+ return draft.freeze()
569
+ _PATH_KEYS = ("path", "file_path", "filename", "target", "notebook_path")
570
+
571
+
572
+ def tool_paths(params: Mapping[str, Any] | None) -> list[str]:
573
+ """The file paths a tool call names."""
574
+ paths = []
575
+ for key in _PATH_KEYS:
576
+ value = (params or {}).get(key)
577
+ if isinstance(value, str) and value.strip():
578
+ paths.append(value.strip())
579
+ patch = (params or {}).get("patch")
580
+ if isinstance(patch, str):
581
+ for match in re.finditer(r"^\+\+\+ (?:b/)?(\S+)", patch, re.MULTILINE):
582
+ if match.group(1) != "/dev/null":
583
+ paths.append(match.group(1))
584
+ return paths
585
+
586
+
587
+ def _inside(path: str, root: Optional[Path]) -> bool:
588
+ if root is None:
589
+ return True
590
+ try:
591
+ candidate = Path(path).expanduser()
592
+ candidate = candidate if candidate.is_absolute() else root / candidate
593
+ candidate.resolve().relative_to(root.resolve())
594
+ return True
595
+ except (ValueError, OSError):
596
+ return False
597
+
598
+
599
+ def assess_tool(tool: str, params: Mapping[str, Any] | None = None, *,
600
+ root: Optional[Path | str] = None) -> RiskAssessment:
601
+ """What one tool call touches, and how badly. Never raises."""
602
+ name = (tool or "").strip()
603
+ params = params or {}
604
+ root_path = Path(root).expanduser() if root else None
605
+ if name == "run_command":
606
+ return assess_command(params.get("command", ""))
607
+ draft = _Draft()
608
+ if name in READ_TOOLS:
609
+ draft.capabilities.add("filesystem.read")
610
+ draft.summary = "Inspect"
611
+ return draft.freeze()
612
+ if name in WRITE_TOOLS:
613
+ paths = tool_paths(params)
614
+ draft.capabilities.add("filesystem.write")
615
+ draft.files.extend(paths)
616
+ draft.raise_to(1, "Edits files in the workspace (checkpointed)")
617
+ outside = [p for p in paths if not _inside(p, root_path)]
618
+ if outside:
619
+ draft.raise_to(3, "Writes outside the workspace: " + ", ".join(outside))
620
+ secrets = [p for p in paths if _SECRET_PATH.search(" " + p + " ")]
621
+ if secrets:
622
+ draft.capabilities.add("secret.read")
623
+ draft.raise_to(4, "Writes a credentials or secrets file")
624
+ draft.summary = "Edit files"
625
+ return draft.freeze()
626
+ if name in DESKTOP_TOOLS:
627
+ return _assess_desktop(name, params)
628
+ if name in NETWORK_READ_TOOLS:
629
+ draft.capabilities.add("network.read")
630
+ url = params.get("url")
631
+ if isinstance(url, str):
632
+ draft.hosts.extend(_hosts(url))
633
+ draft.raise_to(2, "Fetches from the network")
634
+ draft.summary = "Network request"
635
+ return draft.freeze()
636
+ if name == "github":
637
+ action = str(params.get("action") or params.get("command") or "")
638
+ return assess_command(f"gh {action}") if action else _gh_read()
639
+ if name in {"broker_order"}:
640
+ draft.capabilities.add("network.write")
641
+ draft.raise_to(4, "Places an order with a broker", reversible=False)
642
+ draft.systems.append("Brokerage account")
643
+ draft.summary = "Broker order"
644
+ return draft.freeze()
645
+ draft.capabilities.add("process.execute")
646
+ draft.raise_to(1, f"Runs the {name or 'unknown'} tool")
647
+ draft.summary = f"Run {name}" if name else "Unknown tool"
648
+ return draft.freeze()
649
+
650
+
651
+ def _gh_read() -> RiskAssessment:
652
+ draft = _Draft(capabilities={"network.read"}, hosts=["github.com"], summary="Read GitHub")
653
+ draft.raise_to(2, "Reads from GitHub")
654
+ return draft.freeze()
655
+
656
+
657
+ APPROVAL_MODES = ("manual", "risk")
658
+ # The highest level approval_mode=risk may run without asking. L3 (acting
659
+ # outside the repo) and L4 (destructive) are never automatic.
660
+ MAX_AUTO_LEVEL = 2
661
+
662
+
663
+ def approval_requirement(assessment: RiskAssessment, *, mode: str = "manual", auto_level: int = 1) -> str:
664
+ """How an action that would otherwise need approval should get it.
665
+
666
+ ``"always"`` — L4: ask, even when this session already allowed the tool or
667
+ the command prefix. A standing "yes" was given for something milder.
668
+ ``"auto"`` — ``mode="risk"`` and the action is at or below
669
+ ``auto_level`` (capped at :data:`MAX_AUTO_LEVEL`): run without asking.
670
+ ``"ask"`` — everything else: the usual prompt.
671
+ """
672
+ if assessment.level >= 4:
673
+ return "always"
674
+ try:
675
+ ceiling = max(0, min(MAX_AUTO_LEVEL, int(auto_level)))
676
+ except (TypeError, ValueError):
677
+ ceiling = 1
678
+ if mode == "risk" and assessment.level <= ceiling:
679
+ return "auto"
680
+ return "ask"
681
+
682
+
683
+ def unknown_capabilities(names: Iterable[str]) -> list[str]:
684
+ """Names that are not capabilities (a contract typo), in input order."""
685
+ return [name for name in names if name not in CAPABILITIES]
686
+
687
+
688
+ __all__ = [
689
+ "APPROVAL_MODES",
690
+ "CAPABILITIES",
691
+ "MAX_AUTO_LEVEL",
692
+ "approval_requirement",
693
+ "LEVEL_NAMES",
694
+ "RiskAssessment",
695
+ "assess_command",
696
+ "assess_tool",
697
+ "tool_paths",
698
+ "unknown_capabilities",
699
+ ]