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,448 @@
1
+ """One git worktree per coding task, applied to the workspace on approval.
2
+
3
+ A coding turn used to edit the user's files directly; a bad edit was undone
4
+ file by file from checkpoints. With a task worktree the turn works on a copy:
5
+ the user's files do not change until they approve the result, and declining
6
+ it leaves nothing to undo.
7
+
8
+ The copy starts from what the user actually has, not from HEAD. Most people
9
+ ask for a change with uncommitted work in the tree, and a worktree of HEAD
10
+ would hand the model files the user has already moved past. ``snapshot``
11
+ records the working tree as a commit through a scratch index, so neither the
12
+ user's index nor their files are touched, and the worktree is checked out at
13
+ that commit.
14
+
15
+ A task lasts until it is applied or discarded, across as many turns as it
16
+ takes. While it has no changes it follows the workspace: each turn re-takes
17
+ the snapshot (about 0.15s for a thousand files) and rebuilds the worktree
18
+ only when the user's files moved. Applying is ``git apply`` of the task's
19
+ diff against that snapshot; when the user has since changed the same lines it
20
+ refuses and the worktree stays, so nothing is overwritten.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import hashlib
26
+ import json
27
+ import os
28
+ import shutil
29
+ import subprocess
30
+ import tempfile
31
+ import time
32
+ import uuid
33
+ from dataclasses import asdict, dataclass
34
+ from pathlib import Path
35
+ from typing import Optional, Sequence
36
+
37
+ # Ignored at the top of most repositories and needed to run anything: a
38
+ # worktree has none of them, so the task's tests would fail on imports. Linked
39
+ # into the worktree when the workspace has them and git ignores them.
40
+ DEPENDENCY_DIRS = ("node_modules", ".venv", "venv", "env", ".tox")
41
+
42
+ # Bytecode in a repository that does not ignore it would otherwise be copied
43
+ # into every snapshot. A copied .pyc whose source is then rewritten within the
44
+ # same second at the same size still validates, and Python runs the old code.
45
+ _NEVER_SNAPSHOT = (":(exclude,glob)**/__pycache__/**", ":(exclude,glob)**/*.py[co]")
46
+
47
+ _SNAPSHOT_IDENTITY = {
48
+ "GIT_AUTHOR_NAME": "Aria Code",
49
+ "GIT_AUTHOR_EMAIL": "aria@localhost",
50
+ "GIT_COMMITTER_NAME": "Aria Code",
51
+ "GIT_COMMITTER_EMAIL": "aria@localhost",
52
+ }
53
+
54
+
55
+ class TaskWorktreeError(RuntimeError):
56
+ """A task worktree could not be created, applied or removed."""
57
+
58
+
59
+ @dataclass
60
+ class TaskWorktree:
61
+ task_id: str
62
+ repository: str
63
+ path: str
64
+ base: str # snapshot commit the worktree started from
65
+ base_tree: str # its tree, to tell whether the workspace has moved
66
+ created_at: float
67
+ linked: tuple[str, ...] = ()
68
+
69
+ def to_dict(self) -> dict:
70
+ data = asdict(self)
71
+ data["linked"] = list(self.linked)
72
+ return data
73
+
74
+ @classmethod
75
+ def from_dict(cls, data: dict) -> "TaskWorktree":
76
+ return cls(
77
+ task_id=str(data["task_id"]), repository=str(data["repository"]),
78
+ path=str(data["path"]), base=str(data["base"]),
79
+ base_tree=str(data["base_tree"]), created_at=float(data.get("created_at") or 0.0),
80
+ linked=tuple(data.get("linked") or ()),
81
+ )
82
+
83
+
84
+ @dataclass(frozen=True)
85
+ class TaskChange:
86
+ status: str # A, M, D, R…, as git reports it
87
+ path: str
88
+
89
+
90
+ def _git(*args: str, cwd: Path | str, env: Optional[dict] = None,
91
+ input_data: Optional[bytes] = None, timeout: int = 60) -> bytes:
92
+ try:
93
+ completed = subprocess.run(
94
+ ["git", *args], cwd=str(cwd), input=input_data, capture_output=True,
95
+ # Automated Git commands must not inherit the application protocol
96
+ # pipe (or wait for keyboard input). Explicit patch/blob input still
97
+ # gets its own pipe, closed by communicate().
98
+ stdin=subprocess.DEVNULL if input_data is None else None,
99
+ timeout=timeout, check=False, env={**os.environ, **(env or {})},
100
+ )
101
+ except (OSError, subprocess.SubprocessError) as exc:
102
+ raise TaskWorktreeError(f"Unable to run git: {exc}") from exc
103
+ if completed.returncode != 0:
104
+ detail = (completed.stderr or completed.stdout).decode("utf-8", errors="replace").strip()
105
+ raise TaskWorktreeError(detail or f"git {' '.join(args)} failed")
106
+ return completed.stdout
107
+
108
+
109
+ def _text(*args: str, cwd: Path | str, **kwargs) -> str:
110
+ return _git(*args, cwd=cwd, **kwargs).decode("utf-8", errors="replace").strip()
111
+
112
+
113
+ def repository_root(workspace: Path | str) -> Optional[Path]:
114
+ """The repository containing ``workspace``, or None outside one."""
115
+ try:
116
+ return Path(_text("rev-parse", "--show-toplevel", cwd=Path(workspace).expanduser())).resolve()
117
+ except (TaskWorktreeError, OSError):
118
+ return None
119
+
120
+
121
+ def snapshot(repository: Path | str) -> tuple[str, str]:
122
+ """Record the working tree as a commit; returns ``(commit, tree)``.
123
+
124
+ Tracked and untracked files alike, ignored ones excluded, exactly as
125
+ ``git add -A`` would stage them — into a scratch index, so the user's
126
+ index and files are left as they were.
127
+ """
128
+ repo = Path(repository)
129
+ with tempfile.TemporaryDirectory(prefix="aria-snapshot-") as scratch:
130
+ env = {"GIT_INDEX_FILE": str(Path(scratch) / "index"), **_SNAPSHOT_IDENTITY}
131
+ try:
132
+ head = _text("rev-parse", "--verify", "-q", "HEAD", cwd=repo)
133
+ except TaskWorktreeError:
134
+ head = ""
135
+ if head:
136
+ _git("read-tree", head, cwd=repo, env=env)
137
+ _git("add", "-A", "--", ".", *_NEVER_SNAPSHOT, cwd=repo, env=env)
138
+ tree = _text("write-tree", cwd=repo, env=env)
139
+ parents = ["-p", head] if head else []
140
+ commit = _text("commit-tree", tree, *parents, "-m", "aria: task base snapshot", cwd=repo, env=env)
141
+ return commit, tree
142
+
143
+
144
+ def checkout(repo: Path, commit: str, destination: Path) -> list[str]:
145
+ """A detached worktree of ``commit`` at ``destination``, dependencies linked.
146
+
147
+ Returns the dependency directories linked in from ``repo``.
148
+ """
149
+ destination.parent.mkdir(parents=True, exist_ok=True)
150
+ try:
151
+ _git("worktree", "add", "--detach", str(destination), commit, cwd=repo, timeout=300)
152
+ except TaskWorktreeError:
153
+ shutil.rmtree(destination, ignore_errors=True)
154
+ raise
155
+ linked = []
156
+ for name in DEPENDENCY_DIRS:
157
+ source = repo / name
158
+ if not source.is_dir() or (destination / name).exists():
159
+ continue
160
+ try:
161
+ _git("check-ignore", "-q", name, cwd=repo)
162
+ except TaskWorktreeError:
163
+ continue # tracked or not ignored: it came with the checkout
164
+ (destination / name).symlink_to(source, target_is_directory=True)
165
+ linked.append(name)
166
+ return linked
167
+
168
+
169
+ def remove_checkout(repo: Path | str, destination: Path | str, linked: Sequence[str] = ()) -> None:
170
+ for name in linked:
171
+ link = Path(destination) / name
172
+ if link.is_symlink():
173
+ link.unlink()
174
+ try:
175
+ _git("worktree", "remove", "--force", str(destination), cwd=repo)
176
+ except TaskWorktreeError:
177
+ shutil.rmtree(destination, ignore_errors=True)
178
+ try:
179
+ _git("worktree", "prune", cwd=repo)
180
+ except TaskWorktreeError:
181
+ pass
182
+
183
+
184
+ def _load_toml(text: str) -> dict:
185
+ """tomllib on 3.11+; on 3.10, tomli or the copy pip vendors."""
186
+ try:
187
+ import tomllib as toml
188
+ except ImportError:
189
+ try:
190
+ import tomli as toml
191
+ except ImportError:
192
+ from pip._vendor import tomli as toml
193
+ return toml.loads(text)
194
+
195
+
196
+ def python_source_roots(root: Path | str) -> list[Path]:
197
+ """Where a Python project's importable code lives, most specific first.
198
+
199
+ A project installed with ``pip install -e`` imports from the checkout it
200
+ was installed from. Run its tests in a task worktree and they import the
201
+ user's files, not the task's edits, and pass or fail for the wrong code.
202
+ Putting these roots first on PYTHONPATH makes the worktree's copy win:
203
+ PYTHONPATH precedes site-packages and the editable install's hooks.
204
+
205
+ Read from pytest's ``pythonpath``, setuptools' ``package-dir`` (in
206
+ pyproject.toml or setup.cfg), a ``src/`` layout, and the root itself.
207
+ """
208
+ root = Path(root)
209
+ found: list[Path] = []
210
+
211
+ def add(relative) -> None:
212
+ for item in ([relative] if isinstance(relative, str) else list(relative or ())):
213
+ candidate = (root / str(item)).resolve()
214
+ if candidate.is_dir() and candidate not in found:
215
+ found.append(candidate)
216
+
217
+ try:
218
+ data = _load_toml((root / "pyproject.toml").read_text(encoding="utf-8"))
219
+ tool = data.get("tool") or {}
220
+ add((tool.get("pytest", {}).get("ini_options") or {}).get("pythonpath"))
221
+ setuptools = tool.get("setuptools") or {}
222
+ add((setuptools.get("package-dir") or {}).get(""))
223
+ add(((setuptools.get("packages") or {}).get("find") or {}).get("where") if isinstance(
224
+ setuptools.get("packages"), dict) else None)
225
+ except (OSError, ValueError, ImportError, AttributeError):
226
+ pass
227
+ try:
228
+ import configparser
229
+
230
+ parser = configparser.ConfigParser()
231
+ parser.read(root / "setup.cfg", encoding="utf-8")
232
+ mapping = parser.get("options", "package_dir", fallback="")
233
+ for line in mapping.splitlines():
234
+ key, _, value = line.partition("=")
235
+ if not key.strip() and value.strip():
236
+ add(value.strip())
237
+ except (configparser.Error, OSError):
238
+ pass
239
+ src = root / "src"
240
+ if src.is_dir() and any(child.suffix == ".py" or (child / "__init__.py").is_file() for child in src.iterdir()):
241
+ add("src")
242
+ add(".")
243
+ return found
244
+
245
+
246
+ def worktree_command_env(workspace: str, origin: str, base_env: Optional[dict] = None) -> Optional[dict]:
247
+ """The environment for a command run in a task worktree; None elsewhere."""
248
+ if not workspace or not origin:
249
+ return None
250
+ top = repository_root(workspace) or Path(workspace)
251
+ env = dict(os.environ if base_env is None else base_env)
252
+ roots = [str(path) for path in python_source_roots(top)]
253
+ existing = env.get("PYTHONPATH", "")
254
+ env["PYTHONPATH"] = os.pathsep.join([*roots, *([existing] if existing else [])])
255
+ return env
256
+
257
+
258
+ def _exclusions(task: TaskWorktree) -> list[str]:
259
+ return [f":(exclude){name}" for name in task.linked]
260
+
261
+
262
+ class TaskWorktrees:
263
+ """The active task worktree for each repository, persisted across restarts."""
264
+
265
+ def __init__(self, root: Path | str, state_file: Path | str | None = None) -> None:
266
+ self.root = Path(root).expanduser()
267
+ self.state_file = Path(state_file).expanduser() if state_file else self.root / "tasks.json"
268
+
269
+ # ── state ──────────────────────────────────────────────────────────────
270
+
271
+ def _load(self) -> dict:
272
+ try:
273
+ data = json.loads(self.state_file.read_text(encoding="utf-8"))
274
+ return data if isinstance(data, dict) else {}
275
+ except (OSError, ValueError):
276
+ return {}
277
+
278
+ def _save(self, data: dict) -> None:
279
+ self.state_file.parent.mkdir(parents=True, exist_ok=True)
280
+ temp = self.state_file.with_suffix(".tmp")
281
+ temp.write_text(json.dumps(data, indent=2, sort_keys=True), encoding="utf-8")
282
+ os.replace(temp, self.state_file)
283
+
284
+ def active(self, workspace: Path | str) -> Optional[TaskWorktree]:
285
+ """The open task for ``workspace``'s repository, if its worktree still exists."""
286
+ repo = repository_root(workspace)
287
+ if repo is None:
288
+ return None
289
+ record = self._load().get(str(repo))
290
+ if not record:
291
+ return None
292
+ try:
293
+ task = TaskWorktree.from_dict(record)
294
+ except (KeyError, TypeError, ValueError):
295
+ return None
296
+ return task if Path(task.path).is_dir() else None
297
+
298
+ def _remember(self, task: TaskWorktree) -> None:
299
+ data = self._load()
300
+ data[task.repository] = task.to_dict()
301
+ self._save(data)
302
+
303
+ def _forget(self, task: TaskWorktree) -> None:
304
+ data = self._load()
305
+ if data.pop(task.repository, None) is not None:
306
+ self._save(data)
307
+
308
+ # ── lifecycle ──────────────────────────────────────────────────────────
309
+
310
+ def ensure(self, workspace: Path | str) -> Optional[TaskWorktree]:
311
+ """The worktree this turn should work in; None outside a repository.
312
+
313
+ Keeps a task that has changes. One without changes is kept only while
314
+ the workspace still matches its snapshot, and rebuilt otherwise.
315
+ """
316
+ repo = repository_root(workspace)
317
+ if repo is None:
318
+ return None
319
+ task = self.active(repo)
320
+ if task is not None and self.changes(task):
321
+ return task
322
+ commit, tree = snapshot(repo)
323
+ if task is not None:
324
+ if task.base_tree == tree:
325
+ return task
326
+ self.discard(task)
327
+ return self._create(repo, commit, tree)
328
+
329
+ def _create(self, repo: Path, commit: str, tree: str) -> TaskWorktree:
330
+ task_id = uuid.uuid4().hex[:8]
331
+ digest = hashlib.sha1(str(repo).encode("utf-8")).hexdigest()[:8]
332
+ destination = (self.root / f"{repo.name}-{digest}" / task_id).resolve()
333
+ linked = checkout(repo, commit, destination)
334
+ task = TaskWorktree(task_id=task_id, repository=str(repo), path=str(destination),
335
+ base=commit, base_tree=tree, created_at=time.time(),
336
+ linked=tuple(linked))
337
+ self._remember(task)
338
+ return task
339
+
340
+ def _stage(self, task: TaskWorktree) -> None:
341
+ # The worktree's own index; the user's is never involved.
342
+ _git("add", "-A", "--", ".", *_exclusions(task), cwd=task.path)
343
+
344
+ def changes(self, task: TaskWorktree) -> list[TaskChange]:
345
+ """What the task changed relative to the snapshot it started from."""
346
+ self._stage(task)
347
+ output = _text("diff", "--cached", "--name-status", "--no-renames", task.base, cwd=task.path)
348
+ changes = []
349
+ for line in output.splitlines():
350
+ status, _, path = line.partition("\t")
351
+ if path:
352
+ changes.append(TaskChange(status=status.strip(), path=path.strip()))
353
+ return changes
354
+
355
+ def diff(self, task: TaskWorktree, *, stat: bool = False) -> str:
356
+ self._stage(task)
357
+ args = ["diff", "--cached", "--no-renames"]
358
+ if stat:
359
+ args.append("--stat")
360
+ return _text(*args, task.base, cwd=task.path)
361
+
362
+ def patch(self, task: TaskWorktree) -> str:
363
+ """The task's changes as a binary-safe patch against its snapshot."""
364
+ self._stage(task)
365
+ return _git("diff", "--cached", "--binary", "--no-renames", task.base,
366
+ cwd=task.path).decode("utf-8", errors="replace")
367
+
368
+ def reset_to_patch(self, task: TaskWorktree, patch: str) -> None:
369
+ """Make the worktree exactly its snapshot plus ``patch``.
370
+
371
+ Covers every change since, including those a shell command made, which
372
+ have no file checkpoint. Linked dependency directories are left alone.
373
+ """
374
+ _git("reset", "-q", "--hard", task.base, cwd=task.path)
375
+ _git("clean", "-fdq", *[arg for name in task.linked for arg in ("-e", name)], cwd=task.path)
376
+ self.restore_patch(task, patch)
377
+
378
+ def restore_patch(self, task: TaskWorktree, patch: str) -> None:
379
+ """Put a saved patch back into a task's worktree (a rewound task)."""
380
+ if patch.strip():
381
+ _git("apply", "-", cwd=task.path, input_data=patch.encode("utf-8"))
382
+
383
+ def apply(self, task: TaskWorktree, *, session_id: str = "") -> list[TaskChange]:
384
+ """Apply the task to the workspace, record checkpoints, then remove it.
385
+
386
+ Refuses, keeping the worktree, when the workspace changed the same
387
+ lines in the meantime.
388
+ """
389
+ changes = self.changes(task)
390
+ if not changes:
391
+ raise TaskWorktreeError("The task has no changes to apply.")
392
+ repo = Path(task.repository)
393
+ patch = _git("diff", "--cached", "--binary", "--no-renames", task.base, cwd=task.path)
394
+ try:
395
+ _git("apply", "--check", "-", cwd=repo, input_data=patch)
396
+ except TaskWorktreeError as exc:
397
+ raise TaskWorktreeError(
398
+ f"Your files changed where the task did, so applying would overwrite them: {exc}. "
399
+ f"The task is kept at {task.path}."
400
+ ) from exc
401
+ before = {}
402
+ for change in changes:
403
+ target = repo / change.path
404
+ try:
405
+ before[change.path] = (True, target.read_text(encoding="utf-8"), target.stat().st_mode & 0o777)
406
+ except FileNotFoundError:
407
+ before[change.path] = (False, "", None)
408
+ except (OSError, UnicodeDecodeError):
409
+ continue
410
+ _git("apply", "-", cwd=repo, input_data=patch)
411
+ _record_checkpoints(repo, changes, before, task=task, session_id=session_id)
412
+ self.discard(task)
413
+ return changes
414
+
415
+ def discard(self, task: TaskWorktree) -> None:
416
+ """Remove the worktree and forget the task. The workspace is untouched."""
417
+ remove_checkout(task.repository, task.path, task.linked)
418
+ self._forget(task)
419
+
420
+
421
+ def _record_checkpoints(repo: Path, changes, before: dict, *, task: TaskWorktree, session_id: str) -> None:
422
+ """Make an applied task undoable with ``/rewind``, as an edit would be."""
423
+ try:
424
+ from .checkpoints import CheckpointStore
425
+ store = CheckpointStore()
426
+ except Exception:
427
+ return
428
+ for change in changes:
429
+ target = repo / change.path
430
+ prior = before.get(change.path)
431
+ if prior is None or not target.is_file():
432
+ continue
433
+ try:
434
+ store.record_change(
435
+ path=target, before_content=prior[1],
436
+ after_content=target.read_text(encoding="utf-8"),
437
+ existed_before=prior[0], before_mode=prior[2], source="task_apply",
438
+ session_id=session_id, label=f"task {task.task_id}: {change.path}",
439
+ metadata={"task_id": task.task_id, "worktree": task.path},
440
+ )
441
+ except Exception:
442
+ continue
443
+
444
+
445
+ def default_task_worktrees() -> TaskWorktrees:
446
+ from ..packages.aria_core.paths import aria_home
447
+
448
+ return TaskWorktrees(aria_home() / "worktrees" / "tasks")