zidane 7.2.4 → 8.0.4

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 (376) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +34 -6
  3. package/dist/{acp-D-tVyUjw.js → acp-DQDhi2dj.js} +230 -77
  4. package/dist/acp-DQDhi2dj.js.map +1 -0
  5. package/dist/acp-cli.d.ts +1 -1
  6. package/dist/acp-cli.js +9 -66
  7. package/dist/acp-cli.js.map +1 -1
  8. package/dist/acp.d.ts +10 -590
  9. package/dist/acp.d.ts.map +1 -1
  10. package/dist/acp.js +3 -3
  11. package/dist/{agent-D0zZnGbt.js → agent-DSLNmBp0.js} +14401 -13214
  12. package/dist/agent-DSLNmBp0.js.map +1 -0
  13. package/dist/agent.d.ts +1 -1
  14. package/dist/agent.js +3 -2
  15. package/dist/aliasing-lVFbm81n.js +217 -0
  16. package/dist/aliasing-lVFbm81n.js.map +1 -0
  17. package/dist/{anthropic-C2aole0G.js → anthropic-CD00LhUP.js} +1442 -1264
  18. package/dist/anthropic-CD00LhUP.js.map +1 -0
  19. package/dist/artifacts-CV2hUKnL.js.map +1 -1
  20. package/dist/{atomic-write-B7zr1ddF.js → atomic-write-Ijgf2Mhc.js} +13 -3
  21. package/dist/atomic-write-Ijgf2Mhc.js.map +1 -0
  22. package/dist/call-tool-dHlbGOIY.js +70 -0
  23. package/dist/call-tool-dHlbGOIY.js.map +1 -0
  24. package/dist/chat/pure.d.ts +372 -6
  25. package/dist/chat/pure.d.ts.map +1 -1
  26. package/dist/chat/pure.js +35 -244
  27. package/dist/chat/pure.js.map +1 -1
  28. package/dist/{approvals-DKaJZYlm.js → chat-JPJJ8uu5.js} +15879 -14631
  29. package/dist/chat-JPJJ8uu5.js.map +1 -0
  30. package/dist/chat.d.ts +4 -6
  31. package/dist/chat.js +23 -12
  32. package/dist/cli-shared-C-YCaglL.js +159 -0
  33. package/dist/cli-shared-C-YCaglL.js.map +1 -0
  34. package/dist/client-core-BQSyDALT.d.ts +2115 -0
  35. package/dist/client-core-BQSyDALT.d.ts.map +1 -0
  36. package/dist/codemode-worker.d.ts +1 -0
  37. package/dist/codemode-worker.js +155 -0
  38. package/dist/codemode-worker.js.map +1 -0
  39. package/dist/codemode.d.ts +352 -0
  40. package/dist/codemode.d.ts.map +1 -0
  41. package/dist/codemode.js +5 -0
  42. package/dist/connection-Dr-Js4yZ.d.ts +28 -0
  43. package/dist/connection-Dr-Js4yZ.d.ts.map +1 -0
  44. package/dist/connection-loop-gdh22LTI.js +112 -0
  45. package/dist/connection-loop-gdh22LTI.js.map +1 -0
  46. package/dist/context-segments-BHKlagL6.js +1016 -0
  47. package/dist/context-segments-BHKlagL6.js.map +1 -0
  48. package/dist/{context-transport-T_6AYIvy.js → context-transport-DSMTUsK1.js} +3 -3
  49. package/dist/{context-transport-T_6AYIvy.js.map → context-transport-DSMTUsK1.js.map} +1 -1
  50. package/dist/contexts/daytona.d.ts +19 -8
  51. package/dist/contexts/daytona.d.ts.map +1 -1
  52. package/dist/contexts/daytona.js +1 -440
  53. package/dist/contexts/docker.d.ts +36 -7
  54. package/dist/contexts/docker.d.ts.map +1 -1
  55. package/dist/contexts/docker.js +1 -456
  56. package/dist/contexts/e2b.d.ts +68 -13
  57. package/dist/contexts/e2b.d.ts.map +1 -1
  58. package/dist/contexts/e2b.js +1 -382
  59. package/dist/contexts/sandbox.d.ts +1 -1
  60. package/dist/contexts/sandbox.js +5 -0
  61. package/dist/contexts/sandbox.js.map +1 -1
  62. package/dist/{contexts-CRE9pw07.js → contexts-d7UolYot.js} +1059 -524
  63. package/dist/contexts-d7UolYot.js.map +1 -0
  64. package/dist/contexts.d.ts +3 -3
  65. package/dist/contexts.js +1 -1
  66. package/dist/cred-keys-GpBg71cP.js +105 -0
  67. package/dist/cred-keys-GpBg71cP.js.map +1 -0
  68. package/dist/{auth-BG2rVKSt.js → credentials-JttEuRON.js} +55 -206
  69. package/dist/credentials-JttEuRON.js.map +1 -0
  70. package/dist/{cursor-iojRXHF9.js → cursor-CdjaQTBW.js} +3 -3
  71. package/dist/{cursor-iojRXHF9.js.map → cursor-CdjaQTBW.js.map} +1 -1
  72. package/dist/daemon-cli.d.ts +1 -1
  73. package/dist/daemon-cli.js +3 -2
  74. package/dist/daemon-cli.js.map +1 -1
  75. package/dist/daytona-DG3omipZ.js +513 -0
  76. package/dist/daytona-DG3omipZ.js.map +1 -0
  77. package/dist/defaults-Cx3zvDOV.js +23 -0
  78. package/dist/defaults-Cx3zvDOV.js.map +1 -0
  79. package/dist/dispatcher-BMlu2BmZ.js +4941 -0
  80. package/dist/dispatcher-BMlu2BmZ.js.map +1 -0
  81. package/dist/docker-BZhMMJUp.js +727 -0
  82. package/dist/docker-BZhMMJUp.js.map +1 -0
  83. package/dist/e2b-CEVOdRib.js +480 -0
  84. package/dist/e2b-CEVOdRib.js.map +1 -0
  85. package/dist/edit-utils-EGosADZq.js +234 -0
  86. package/dist/edit-utils-EGosADZq.js.map +1 -0
  87. package/dist/environment-8wsKE2Ln.js +214 -0
  88. package/dist/environment-8wsKE2Ln.js.map +1 -0
  89. package/dist/eval-BNcvle_J.js +1595 -0
  90. package/dist/eval-BNcvle_J.js.map +1 -0
  91. package/dist/eval.d.ts +2 -2
  92. package/dist/eval.js +1 -1489
  93. package/dist/executor-Cx5-8yqi.js +621 -0
  94. package/dist/executor-Cx5-8yqi.js.map +1 -0
  95. package/dist/extension-authoring-DyGGmq9V.js +385 -0
  96. package/dist/extension-authoring-DyGGmq9V.js.map +1 -0
  97. package/dist/extensions.d.ts +2 -2
  98. package/dist/extensions.js +3 -3
  99. package/dist/{fetch-url-DX75gpL0.js → fetch-url-Ct2TjDWt.js} +4 -4
  100. package/dist/{fetch-url-DX75gpL0.js.map → fetch-url-Ct2TjDWt.js.map} +1 -1
  101. package/dist/{format-BF745pLL.js → format-C2NQEVUH.js} +39 -2
  102. package/dist/format-C2NQEVUH.js.map +1 -0
  103. package/dist/format-bytes-C7tfc3Zm.js +55 -0
  104. package/dist/format-bytes-C7tfc3Zm.js.map +1 -0
  105. package/dist/headless-C_rNUuYC.js +960 -0
  106. package/dist/headless-C_rNUuYC.js.map +1 -0
  107. package/dist/headless.d.ts +1 -1
  108. package/dist/headless.js +1 -413
  109. package/dist/{history-search-C4bk1Wz_.js → history-search-CcYzF8-0.js} +7 -3
  110. package/dist/history-search-CcYzF8-0.js.map +1 -0
  111. package/dist/history-search-worker.d.ts +1 -1
  112. package/dist/history-search-worker.js +1 -1
  113. package/dist/host-D7NrI03V.js +378 -0
  114. package/dist/host-D7NrI03V.js.map +1 -0
  115. package/dist/host-signals-BcP5QKUD.js +118 -0
  116. package/dist/host-signals-BcP5QKUD.js.map +1 -0
  117. package/dist/identity-CwfO8K-t.js +26 -0
  118. package/dist/identity-CwfO8K-t.js.map +1 -0
  119. package/dist/{index-BgN1T3lk.d.ts → index-BGe1fQT7.d.ts} +10987 -9320
  120. package/dist/index-BGe1fQT7.d.ts.map +1 -0
  121. package/dist/index-BVQsIKGn.d.ts +448 -0
  122. package/dist/index-BVQsIKGn.d.ts.map +1 -0
  123. package/dist/{index-C6NEd5y_.d.ts → index-CHABJd-L.d.ts} +3386 -502
  124. package/dist/index-CHABJd-L.d.ts.map +1 -0
  125. package/dist/{index-C37_ppWv.d.ts → index-D6a7qXpg.d.ts} +2 -3
  126. package/dist/index-D6a7qXpg.d.ts.map +1 -0
  127. package/dist/index.d.ts +6 -6
  128. package/dist/index.js +27 -23
  129. package/dist/{completion-core-BRo86R_L.js → inline-ghost-BVRQeGoL.js} +50 -2
  130. package/dist/inline-ghost-BVRQeGoL.js.map +1 -0
  131. package/dist/ipc/remote.d.ts +313 -0
  132. package/dist/ipc/remote.d.ts.map +1 -0
  133. package/dist/ipc/remote.js +4 -0
  134. package/dist/ipc.d.ts +6 -964
  135. package/dist/ipc.js +403 -4
  136. package/dist/ipc.js.map +1 -0
  137. package/dist/{isolation-Kfoof0MM.d.ts → isolation-D9L650W5.d.ts} +100 -15
  138. package/dist/isolation-D9L650W5.d.ts.map +1 -0
  139. package/dist/json-rpc--HXQti1E.js +350 -0
  140. package/dist/json-rpc--HXQti1E.js.map +1 -0
  141. package/dist/links-j8rED1sR.js +603 -0
  142. package/dist/links-j8rED1sR.js.map +1 -0
  143. package/dist/local-terminal-D8QThwo_.js +252 -0
  144. package/dist/local-terminal-D8QThwo_.js.map +1 -0
  145. package/dist/{logger--C1VQjwJ.js → logger-Gtqlayx8.js} +199 -173
  146. package/dist/logger-Gtqlayx8.js.map +1 -0
  147. package/dist/logs-view-CWG8aUAG.js.map +1 -1
  148. package/dist/{mcp-CgNd-f3F.js → mcp-_wecH9Qe.js} +608 -562
  149. package/dist/mcp-_wecH9Qe.js.map +1 -0
  150. package/dist/mcp.d.ts +2 -2
  151. package/dist/mcp.js +2 -2
  152. package/dist/media-sniff-UKijEaiQ.js.map +1 -1
  153. package/dist/{messages-2jcOA_5R.js → messages-BqiwcD2Q.js} +1017 -1014
  154. package/dist/messages-BqiwcD2Q.js.map +1 -0
  155. package/dist/{oauth-DxHO17JE.js → oauth-Px_pBB9W.js} +5 -5
  156. package/dist/{oauth-DxHO17JE.js.map → oauth-Px_pBB9W.js.map} +1 -1
  157. package/dist/{openai-compat-Dy56weK8.js → openai-compat-CFrpH7uq.js} +432 -589
  158. package/dist/openai-compat-CFrpH7uq.js.map +1 -0
  159. package/dist/orchestration-BCGmB8Ps.js +511 -0
  160. package/dist/orchestration-BCGmB8Ps.js.map +1 -0
  161. package/dist/output/stream-json.d.ts +1 -2
  162. package/dist/output/stream-json.d.ts.map +1 -1
  163. package/dist/output/stream-json.js +1 -1
  164. package/dist/output/terminal.d.ts +1 -2
  165. package/dist/output/terminal.d.ts.map +1 -1
  166. package/dist/output/terminal.js +13 -7
  167. package/dist/output/terminal.js.map +1 -1
  168. package/dist/{plugins-gbI7SBA6.js → plugins-DS7mahzZ.js} +20 -101
  169. package/dist/plugins-DS7mahzZ.js.map +1 -0
  170. package/dist/plugins.d.ts +1 -1
  171. package/dist/plugins.js +1 -2
  172. package/dist/prelude-Cxo4t74B.js +517 -0
  173. package/dist/prelude-Cxo4t74B.js.map +1 -0
  174. package/dist/presets.d.ts +1 -1
  175. package/dist/presets.js +1 -2
  176. package/dist/project-root-B8zADr4o.js +167 -0
  177. package/dist/project-root-B8zADr4o.js.map +1 -0
  178. package/dist/project-user-paths-BSgtrRxl.js +58 -0
  179. package/dist/project-user-paths-BSgtrRxl.js.map +1 -0
  180. package/dist/{prompts-Pqc3JdW_.d.ts → prompts-DYcvqShf.d.ts} +14 -11
  181. package/dist/prompts-DYcvqShf.d.ts.map +1 -0
  182. package/dist/protocol-DnhqqSmE.js +13 -0
  183. package/dist/protocol-DnhqqSmE.js.map +1 -0
  184. package/dist/providers/anthropic.d.ts +2 -2
  185. package/dist/providers/anthropic.js +1 -2
  186. package/dist/providers/arcee.d.ts +1 -1
  187. package/dist/providers/arcee.js +1 -1
  188. package/dist/providers/baseten.d.ts +1 -1
  189. package/dist/providers/baseten.js +1 -1
  190. package/dist/providers/cerebras.d.ts +1 -1
  191. package/dist/providers/cerebras.js +3 -2
  192. package/dist/providers/cerebras.js.map +1 -1
  193. package/dist/providers/local.d.ts +1 -1
  194. package/dist/providers/local.js +1 -1
  195. package/dist/providers/openai-compat.d.ts +1 -1
  196. package/dist/providers/openai-compat.js +1 -2
  197. package/dist/providers/openai.d.ts +1 -1
  198. package/dist/providers/openai.js +15 -12
  199. package/dist/providers/openai.js.map +1 -1
  200. package/dist/providers/openrouter.d.ts +1 -1
  201. package/dist/providers/openrouter.js +3 -2
  202. package/dist/providers/openrouter.js.map +1 -1
  203. package/dist/providers/xai.d.ts +1 -1
  204. package/dist/providers/xai.js +3 -3
  205. package/dist/{providers-BVhnFyiY.js → providers-XUR7F4Hi.js} +4 -4
  206. package/dist/{providers-BVhnFyiY.js.map → providers-XUR7F4Hi.js.map} +1 -1
  207. package/dist/providers.d.ts +1 -1
  208. package/dist/providers.js +4 -4
  209. package/dist/registry-D6ShBWJU.js +5234 -0
  210. package/dist/registry-D6ShBWJU.js.map +1 -0
  211. package/dist/remote-hosts-BtA_9ZGp.js +97 -0
  212. package/dist/remote-hosts-BtA_9ZGp.js.map +1 -0
  213. package/dist/restate.d.ts +2 -3
  214. package/dist/restate.d.ts.map +1 -1
  215. package/dist/restate.js +631 -572
  216. package/dist/restate.js.map +1 -1
  217. package/dist/run-summary-CklLiZ4y.js +288 -0
  218. package/dist/run-summary-CklLiZ4y.js.map +1 -0
  219. package/dist/{sandbox-BH0WQkXn.d.ts → sandbox-C5dR5DwQ.d.ts} +6 -3
  220. package/dist/sandbox-C5dR5DwQ.d.ts.map +1 -0
  221. package/dist/session/sqlite.d.ts +1 -2
  222. package/dist/session/sqlite.d.ts.map +1 -1
  223. package/dist/session/sqlite.js +1 -616
  224. package/dist/session-factory-BUGY5P40.js +1576 -0
  225. package/dist/session-factory-BUGY5P40.js.map +1 -0
  226. package/dist/{session-BqRP1hS7.js → session-xh9JXu6i.js} +94 -52
  227. package/dist/session-xh9JXu6i.js.map +1 -0
  228. package/dist/session.d.ts +1 -1
  229. package/dist/session.js +2 -2
  230. package/dist/settings-keys-Ckf29NeM.js +677 -0
  231. package/dist/settings-keys-Ckf29NeM.js.map +1 -0
  232. package/dist/shell-path-Dqaoow2J.js +412 -0
  233. package/dist/shell-path-Dqaoow2J.js.map +1 -0
  234. package/dist/{skills-BC3dodWp.js → skills-DKqZJm4X.js} +430 -470
  235. package/dist/skills-DKqZJm4X.js.map +1 -0
  236. package/dist/skills.d.ts +2 -2
  237. package/dist/skills.js +1 -2
  238. package/dist/source-mPExaUm8.js +381 -0
  239. package/dist/source-mPExaUm8.js.map +1 -0
  240. package/dist/sqlite-DV1DQzN2.js +698 -0
  241. package/dist/sqlite-DV1DQzN2.js.map +1 -0
  242. package/dist/{src-CkNQKFKr.js → src-BRMYRJib.js} +903 -1121
  243. package/dist/src-BRMYRJib.js.map +1 -0
  244. package/dist/{stdio-DPpBDPx5.js → stdio-C6YyoW3I.js} +4 -4
  245. package/dist/{stdio-DPpBDPx5.js.map → stdio-C6YyoW3I.js.map} +1 -1
  246. package/dist/{stdio-loader-Bbx19dMZ.js → stdio-loader-C830Vg-Z.js} +4 -4
  247. package/dist/{stdio-loader-Bbx19dMZ.js.map → stdio-loader-C830Vg-Z.js.map} +1 -1
  248. package/dist/system-prompt-MNVHatSD.d.ts.map +1 -1
  249. package/dist/timeout-DEaqslLO.d.ts.map +1 -1
  250. package/dist/todo-edits-Dn251YUP.js +1790 -0
  251. package/dist/todo-edits-Dn251YUP.js.map +1 -0
  252. package/dist/{turn-operations-DrbJlpq9.js → tool-formatters-IQFDrdrs.js} +1456 -2120
  253. package/dist/tool-formatters-IQFDrdrs.js.map +1 -0
  254. package/dist/tool-state-Dku6YqAB.js +989 -0
  255. package/dist/tool-state-Dku6YqAB.js.map +1 -0
  256. package/dist/tools/fetch-url.d.ts +1 -2
  257. package/dist/tools/fetch-url.d.ts.map +1 -1
  258. package/dist/tools/fetch-url.js +1 -2
  259. package/dist/tools/prompts.d.ts +1 -1
  260. package/dist/tools/prompts.js +7 -7
  261. package/dist/tools/prompts.js.map +1 -1
  262. package/dist/tools/web-search.d.ts +1 -2
  263. package/dist/tools/web-search.d.ts.map +1 -1
  264. package/dist/tools/web-search.js +2 -2
  265. package/dist/tools/web-search.js.map +1 -1
  266. package/dist/tools-_DnT3AGM.js +578 -0
  267. package/dist/tools-_DnT3AGM.js.map +1 -0
  268. package/dist/tools.d.ts +3 -3
  269. package/dist/tools.js +4 -2
  270. package/dist/tui.d.ts +534 -517
  271. package/dist/tui.d.ts.map +1 -1
  272. package/dist/tui.js +34933 -27242
  273. package/dist/tui.js.map +1 -1
  274. package/dist/turn-operations-B8sokwi5.js +333 -0
  275. package/dist/turn-operations-B8sokwi5.js.map +1 -0
  276. package/dist/turn-operations-DQX5ZZni.d.ts +3089 -0
  277. package/dist/turn-operations-DQX5ZZni.d.ts.map +1 -0
  278. package/dist/types-C7ZFOztE.d.ts +132 -0
  279. package/dist/types-C7ZFOztE.d.ts.map +1 -0
  280. package/dist/types-CH5XpIHw.js +114 -0
  281. package/dist/types-CH5XpIHw.js.map +1 -0
  282. package/dist/{types-CWgENVLY.js → types-Cu0ZGDu9.js} +10 -6
  283. package/dist/types-Cu0ZGDu9.js.map +1 -0
  284. package/dist/types-IqegbJEE.d.ts +624 -0
  285. package/dist/types-IqegbJEE.d.ts.map +1 -0
  286. package/dist/types.d.ts +4 -4
  287. package/dist/types.js +1 -1
  288. package/dist/url-D8HCl65b.js +1259 -0
  289. package/dist/url-D8HCl65b.js.map +1 -0
  290. package/dist/wasm-BVT-j5cl.js +33 -0
  291. package/dist/wasm-BVT-j5cl.js.map +1 -0
  292. package/dist/workspace-exec-stream-SV2R9d5S.js +355 -0
  293. package/dist/workspace-exec-stream-SV2R9d5S.js.map +1 -0
  294. package/dist/ws-CIHMvlSh.js +952 -0
  295. package/dist/ws-CIHMvlSh.js.map +1 -0
  296. package/dist/ws-client-N7NxzvQp.js +230 -0
  297. package/dist/ws-client-N7NxzvQp.js.map +1 -0
  298. package/dist/{xai-CazjStOK.js → xai-CvJTeLrI.js} +165 -5
  299. package/dist/xai-CvJTeLrI.js.map +1 -0
  300. package/dist/xdg-zweed0-t.js +117 -0
  301. package/dist/xdg-zweed0-t.js.map +1 -0
  302. package/docs/ACP.md +52 -0
  303. package/docs/ARCHITECTURE.md +103 -6
  304. package/docs/ARTIFACTS.md +8 -4
  305. package/docs/CHAT.md +165 -14
  306. package/docs/EXECUTION_CONTEXT.md +8 -0
  307. package/docs/EXTENSIONS.md +123 -2
  308. package/docs/HEADLESS.md +2 -0
  309. package/docs/IPC.md +775 -64
  310. package/docs/MACHINES.md +456 -0
  311. package/docs/PANELS.md +3 -0
  312. package/docs/README.md +4 -0
  313. package/docs/RESTATE.md +3 -2
  314. package/docs/RUN_IN_BACKGROUND.md +10 -2
  315. package/docs/SERVER.md +1085 -0
  316. package/docs/SKILL.md +6 -1
  317. package/docs/TERMINAL.md +75 -0
  318. package/docs/TUI.md +65 -14
  319. package/package.json +58 -26
  320. package/scripts/eval.ts +4 -0
  321. package/dist/acp-D-tVyUjw.js.map +0 -1
  322. package/dist/agent-D0zZnGbt.js.map +0 -1
  323. package/dist/anthropic-C2aole0G.js.map +0 -1
  324. package/dist/approvals-DKaJZYlm.js.map +0 -1
  325. package/dist/atomic-write-B7zr1ddF.js.map +0 -1
  326. package/dist/auth-BG2rVKSt.js.map +0 -1
  327. package/dist/completion-core-BRo86R_L.js.map +0 -1
  328. package/dist/contexts/daytona.js.map +0 -1
  329. package/dist/contexts/docker.js.map +0 -1
  330. package/dist/contexts/e2b.js.map +0 -1
  331. package/dist/contexts-CRE9pw07.js.map +0 -1
  332. package/dist/eval.js.map +0 -1
  333. package/dist/format-BF745pLL.js.map +0 -1
  334. package/dist/glob-DluQFSw1.js +0 -270
  335. package/dist/glob-DluQFSw1.js.map +0 -1
  336. package/dist/headless.js.map +0 -1
  337. package/dist/history-search-C4bk1Wz_.js.map +0 -1
  338. package/dist/index-BgN1T3lk.d.ts.map +0 -1
  339. package/dist/index-C37_ppWv.d.ts.map +0 -1
  340. package/dist/index-C6NEd5y_.d.ts.map +0 -1
  341. package/dist/ipc-zVSyo6K1.js +0 -331
  342. package/dist/ipc-zVSyo6K1.js.map +0 -1
  343. package/dist/ipc.d.ts.map +0 -1
  344. package/dist/isolation-Kfoof0MM.d.ts.map +0 -1
  345. package/dist/json-rpc-rSWMUh9b.js +0 -192
  346. package/dist/json-rpc-rSWMUh9b.js.map +0 -1
  347. package/dist/logger--C1VQjwJ.js.map +0 -1
  348. package/dist/mcp-CgNd-f3F.js.map +0 -1
  349. package/dist/messages-2jcOA_5R.js.map +0 -1
  350. package/dist/openai-compat-Dy56weK8.js.map +0 -1
  351. package/dist/output-cap-C9zukcCj.js +0 -100
  352. package/dist/output-cap-C9zukcCj.js.map +0 -1
  353. package/dist/panels-B6gRk4bf.js +0 -789
  354. package/dist/panels-B6gRk4bf.js.map +0 -1
  355. package/dist/plugins-gbI7SBA6.js.map +0 -1
  356. package/dist/prompts-Pqc3JdW_.d.ts.map +0 -1
  357. package/dist/run-summary-BU_NgwUT.js +0 -269
  358. package/dist/run-summary-BU_NgwUT.js.map +0 -1
  359. package/dist/sandbox-BH0WQkXn.d.ts.map +0 -1
  360. package/dist/session/sqlite.js.map +0 -1
  361. package/dist/session-BqRP1hS7.js.map +0 -1
  362. package/dist/shell-path-h5czzllR.js +0 -1549
  363. package/dist/shell-path-h5czzllR.js.map +0 -1
  364. package/dist/skills-BC3dodWp.js.map +0 -1
  365. package/dist/src-CkNQKFKr.js.map +0 -1
  366. package/dist/todo-edits-UOwgxGKu.js +0 -528
  367. package/dist/todo-edits-UOwgxGKu.js.map +0 -1
  368. package/dist/tool-formatters-DoRLnfuD.d.ts +0 -759
  369. package/dist/tool-formatters-DoRLnfuD.d.ts.map +0 -1
  370. package/dist/transcript-anchors-BeudMbXx.d.ts +0 -1762
  371. package/dist/transcript-anchors-BeudMbXx.d.ts.map +0 -1
  372. package/dist/turn-operations-C8bMBDl_.d.ts +0 -1258
  373. package/dist/turn-operations-C8bMBDl_.d.ts.map +0 -1
  374. package/dist/turn-operations-DrbJlpq9.js.map +0 -1
  375. package/dist/types-CWgENVLY.js.map +0 -1
  376. package/dist/xai-CazjStOK.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry-D6ShBWJU.js","names":[],"sources":["../src/chat/shell-parse.ts","../src/chat/safe-mode.ts","../src/chat/spawn-markers.ts","../src/chat/replay-runs.ts","../src/chat/store.ts","../src/chat/foreign-configs.ts","../src/chat/ruler-configs.ts","../src/chat/mcps-discovery.ts","../src/chat/system-md.ts","../src/chat/themes/catppuccin.ts","../src/chat/themes/crush.ts","../src/chat/themes/gruvbox.ts","../src/chat/themes/light.ts","../src/chat/themes/vaporwave.ts","../src/chat/theme.ts","../src/chat/settings-context.tsx","../src/chat/host-scoped-settings.ts","../src/chat/hosts/registry.ts"],"sourcesContent":["/**\n * Lightweight shell command parser for safelist enforcement.\n *\n * Extracts the head token (program name) of every command in a bash\n * command string — including chains (`&&`, `||`, `;`), pipes (`|`),\n * subshells (`(…)`), and command substitutions (`$(…)` and backticks).\n *\n * Handles quoting (`'…'`, `\"…\"`, `\\x`), variable assignments\n * (`NAME=val`), I/O redirection, here-documents (`<<`, `<<-`), `#`\n * comments, and the `!` negation prefix.\n *\n * Returns `null` when parsing fails so callers can fall back to\n * prompting (safe default).\n */\n\nexport function extractCommandHeads(command: string): string[] | null {\n try {\n const p = new ShellParser(command)\n p.list()\n return p.heads\n }\n catch {\n return null\n }\n}\n\n// Characters that unconditionally end an unquoted word.\nconst META = new Set(' \\t\\n\\r;|&()<>'.split(''))\n\ninterface PendingHeredoc {\n delim: string\n stripTabs: boolean\n /** Any quoting in the delimiter word disables expansion in the body. */\n quoted: boolean\n}\n\nclass ShellParser {\n readonly heads: string[] = []\n private i = 0\n /** Heredocs opened on the current line, bodies not yet consumed. */\n private pendingHeredocs: PendingHeredoc[] = []\n\n constructor(private readonly s: string) {}\n\n // -- public entry point ------------------------------------------------\n\n /** Command list — pipelines separated by `;`, `&&`, `||`, `\\n`, `&`. */\n list(closer?: string): void {\n for (;;) {\n this.ws()\n if (this.end(closer))\n return\n\n this.pipeline(closer)\n\n this.ws()\n if (this.end(closer))\n return\n const c = this.c()\n if (c === ';') { this.i++; continue }\n if (c === '\\n' || c === '\\r') { this.newline(); continue }\n if (this.is('&&') || this.is('||')) { this.i += 2; continue }\n if (c === '&') { this.i++; continue }\n break\n }\n }\n\n // -- grammar -----------------------------------------------------------\n\n /** Pipeline — simple commands separated by `|` (not `||`). */\n private pipeline(closer?: string): void {\n this.cmd(closer)\n for (;;) {\n this.ws()\n if (this.c() === '|' && !this.is('||')) { this.i++; this.cmd(closer) }\n else {\n break\n }\n }\n }\n\n /** Simple command — extract head, skip remaining arguments. */\n private cmd(closer?: string): void {\n this.ws()\n if (this.i >= this.s.length)\n return\n if (closer && this.c() === closer)\n return\n\n // Subshell.\n if (this.c() === '(') {\n this.i++\n this.list(')')\n return\n }\n\n // `!` negation prefix — skip when followed by whitespace.\n if (this.c() === '!' && this.i + 1 < this.s.length\n && (this.s[this.i + 1] === ' ' || this.s[this.i + 1] === '\\t')) {\n this.i++; this.ws()\n }\n\n // Read tokens, skipping leading variable assignments (NAME=val).\n while (this.i < this.s.length && !this.sep(closer)) {\n if (this.c() === '(') {\n this.i++\n this.list(')')\n break\n }\n const w = this.word()\n if (!w)\n break\n if (isAssignment(w)) { this.ws(); continue }\n this.heads.push(w)\n break\n }\n\n this.tail(closer)\n }\n\n // -- word-level --------------------------------------------------------\n\n /** Read one shell word, handling quoting and substitutions. */\n private word(): string {\n let out = ''\n while (this.i < this.s.length) {\n const c = this.c()\n if (META.has(c))\n break\n\n if (c === '\\\\' && this.i + 1 < this.s.length) {\n out += this.s[this.i + 1]\n this.i += 2\n continue\n }\n if (c === '\\'') {\n this.i++\n while (this.i < this.s.length && this.s[this.i] !== '\\'') out += this.s[this.i++]\n if (this.i < this.s.length)\n this.i++\n continue\n }\n if (c === '\"') { out += this.dquote(); continue }\n if (this.is('$(')) {\n this.i += 2\n this.list(')')\n continue\n }\n if (c === '`') { this.btick(); continue }\n out += c; this.i++\n }\n return out\n }\n\n /** Double-quoted string — returns literal chars, recurses into substitutions. */\n private dquote(): string {\n this.i++\n let out = ''\n while (this.i < this.s.length && this.s[this.i] !== '\"') {\n if (this.s[this.i] === '\\\\' && this.i + 1 < this.s.length) {\n out += this.s[this.i + 1]\n this.i += 2\n continue\n }\n if (this.is('$(')) {\n this.i += 2\n this.list(')')\n continue\n }\n if (this.s[this.i] === '`') { this.btick(); continue }\n out += this.s[this.i++]\n }\n if (this.i < this.s.length)\n this.i++\n return out\n }\n\n /** Backtick substitution — creates a sub-parser for the inner content. */\n private btick(): void {\n this.i++\n const close = this.s.indexOf('`', this.i)\n const inner = close < 0 ? this.s.slice(this.i) : this.s.slice(this.i, close)\n const sub = new ShellParser(inner)\n sub.list()\n this.heads.push(...sub.heads)\n this.i = close < 0 ? this.s.length : close + 1\n }\n\n // -- tail / redirections -----------------------------------------------\n\n /** Skip remaining arguments and redirections until the next command boundary. */\n private tail(closer?: string): void {\n while (this.i < this.s.length) {\n this.ws()\n if (this.i >= this.s.length || this.sep(closer))\n break\n if (this.redir())\n continue\n if (this.c() === '(') {\n this.i++\n this.list(')')\n continue\n }\n const w = this.word()\n if (!w)\n break\n }\n }\n\n /** Try to consume an I/O redirection operator + target. Returns true if consumed. */\n private redir(): boolean {\n const c = this.c()\n let yes = c === '<' || c === '>'\n if (!yes && c >= '0' && c <= '9' && this.i + 1 < this.s.length) {\n const n = this.s[this.i + 1]\n yes = n === '<' || n === '>'\n }\n if (!yes)\n return false\n\n while (this.i < this.s.length && this.s[this.i] >= '0' && this.s[this.i] <= '9') this.i++\n if (this.c() === '>') {\n this.i++\n if (this.c() === '>')\n this.i++\n if (this.c() === '&') {\n this.i++\n while (this.i < this.s.length && this.s[this.i] >= '0' && this.s[this.i] <= '9') this.i++\n return true\n }\n }\n else if (this.c() === '<') {\n this.i++\n if (this.c() === '<') {\n this.i++\n // `<<<` is a here-string: the operand is an ordinary word, not a\n // delimiter, so fall through to the generic target read below.\n if (this.c() === '<') {\n this.i++\n }\n else {\n let stripTabs = false\n if (this.c() === '-') { this.i++; stripTabs = true }\n this.ws()\n // `word()` strips the quotes of `<<'EOF'` / `<<\"EOF\"`; the\n // terminator line is the bare delimiter either way.\n const start = this.i\n const delim = this.word()\n const quoted = /['\"\\\\]/.test(this.s.slice(start, this.i))\n if (delim)\n this.pendingHeredocs.push({ delim, stripTabs, quoted })\n return true\n }\n }\n }\n this.ws()\n this.word()\n return true\n }\n\n /** Consume one newline (`\\r\\n` counts once) plus any heredoc bodies it opens. */\n private newline(): void {\n this.i += this.is('\\r\\n') ? 2 : 1\n this.heredocs()\n }\n\n /**\n * Skip the bodies of heredocs opened on the line just ended, in the order\n * they were introduced. Without this the body is tokenized as shell code\n * and each line's first word lands in `heads` — so a command that embeds a\n * script (`python3 - <<'PY' … PY`) yields a different head set on every\n * call and can never be safelisted.\n *\n * An unquoted delimiter (`<<EOF`) still expands `$(…)` and backticks in\n * the body, so those substitutions are parsed for heads.\n */\n private heredocs(): void {\n if (this.pendingHeredocs.length === 0)\n return\n const pending = this.pendingHeredocs\n this.pendingHeredocs = []\n for (const { delim, stripTabs, quoted } of pending) {\n const body: string[] = []\n while (this.i < this.s.length) {\n const nl = this.s.indexOf('\\n', this.i)\n const raw = nl < 0 ? this.s.slice(this.i) : this.s.slice(this.i, nl)\n this.i = nl < 0 ? this.s.length : nl + 1\n const line = raw.endsWith('\\r') ? raw.slice(0, -1) : raw\n if ((stripTabs ? line.replace(/^\\t+/, '') : line) === delim)\n break\n body.push(line)\n }\n if (!quoted)\n this.bodySubstitutions(body.join('\\n'))\n }\n }\n\n /** Collect heads of `$(…)` and backtick substitutions in an expanding heredoc body. */\n private bodySubstitutions(body: string): void {\n let k = 0\n while (k < body.length) {\n const c = body[k]\n if (c === '\\\\') { k += 2; continue }\n if (c === '$' && body[k + 1] === '(') {\n const sub = new ShellParser(body.slice(k + 2))\n sub.list(')')\n this.heads.push(...sub.heads)\n k += 2 + sub.i\n continue\n }\n if (c === '`') {\n const sub = new ShellParser(body.slice(k))\n sub.btick()\n this.heads.push(...sub.heads)\n k += sub.i\n continue\n }\n k++\n }\n }\n\n // -- predicates --------------------------------------------------------\n\n /** True at a command boundary (`;`, `\\n`, `&`, `|`, `)`, or closer). */\n private sep(closer?: string): boolean {\n const c = this.c()\n if (c === ';' || c === '\\n' || c === '\\r' || c === '&' || c === ')')\n return true\n if (c === '|')\n return true\n if (closer && c === closer)\n return true\n return false\n }\n\n /**\n * True when past end or at closer (closer is consumed).\n *\n * Throws when a group closes with a heredoc still pending: the parser has\n * no notion of arithmetic, so `$((x<<1))` / `(( x << 1 ))` reads the shift\n * as a heredoc whose body would swallow (and hide) the following lines.\n */\n private end(closer?: string): boolean {\n if (this.i >= this.s.length)\n return true\n if (closer && this.c() === closer) {\n if (this.pendingHeredocs.length > 0)\n throw new Error('heredoc pending at group close')\n this.i++\n return true\n }\n return false\n }\n\n private c(): string { return this.s[this.i] ?? '' }\n private is(s: string): boolean { return this.s.startsWith(s, this.i) }\n /**\n * Skip blanks, then a `#` comment when it starts a word (bash's rule): a\n * heredoc operator inside a comment must never register, or the lines\n * after it would be skipped as its body and hidden from the safelist.\n * Stops before the newline so the caller still sees the boundary.\n */\n private ws(): void {\n while (this.i < this.s.length && (this.s[this.i] === ' ' || this.s[this.i] === '\\t')) this.i++\n if (this.c() === '#' && (this.i === 0 || META.has(this.s[this.i - 1]))) {\n const nl = this.s.indexOf('\\n', this.i)\n this.i = nl < 0 ? this.s.length : nl\n }\n }\n}\n\n/** `NAME=…` where NAME is a valid shell identifier. */\nfunction isAssignment(w: string): boolean {\n const eq = w.indexOf('=')\n if (eq <= 0)\n return false\n return /^[A-Z_]\\w*$/i.test(w.slice(0, eq))\n}\n","/**\n * Safe-mode storage + matching for the TUI.\n *\n * Lives at `<dataDir>/projects.json` (default `~/.zidane/projects.json`). Each\n * top-level key is an absolute project directory; the value carries that\n * project's persisted tool-call `safelist`.\n *\n * ```json\n * {\n * \"/Users/me/proj-a\": { \"safelist\": [\"read_file\", \"shell:git:*\"] }\n * }\n * ```\n *\n * Two granularities for safelist entries:\n * - **bare tool name** — `\"read_file\"` matches every `read_file` call.\n * - **tool + first-arg token + wildcard** — `\"shell:git:*\"` matches `shell`\n * calls whose primary string argument starts with the token `git`\n * (followed by whitespace or end-of-string). Modelled on Claude Code's\n * `Bash(git:*)` syntax.\n *\n * A short list of read-only tools is **implicitly safe** without being\n * persisted — see {@link IMPLICITLY_SAFE_TOOLS}.\n */\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { writeFileAtomic } from '../atomic-write'\nimport { isLocalBrowserUrl, normalizeBrowserUrl } from './browser/url'\nimport { findGitRoot, projectRootOf } from './project-root'\nimport { extractCommandHeads } from './shell-parse'\n\n/**\n * The `projects.json` key for a working directory: its project root (the\n * main checkout for a linked worktree; the dir itself outside git) — the\n * same \"project\" the TUI scopes its safelist to, so a subdirectory session,\n * every worktree of the repo, and every host share one safelist.\n */\nexport function safelistProjectKey(cwd: string): string {\n return projectRootOf(cwd)\n}\n\n// ---------------------------------------------------------------------------\n// Persistence\n// ---------------------------------------------------------------------------\n\nexport interface ProjectEntry {\n safelist?: string[]\n}\n\nexport type ProjectsFile = Record<string, ProjectEntry>\n\n/** Resolve `projects.json`'s on-disk path given the TUI data directory. */\nexport function projectsFilePath(dataDir: string): string {\n return resolve(dataDir, 'projects.json')\n}\n\nexport function readProjects(dataDir: string): ProjectsFile {\n const path = projectsFilePath(dataDir)\n if (!existsSync(path))\n return {}\n try {\n const parsed = JSON.parse(readFileSync(path, 'utf-8'))\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed))\n return parsed as ProjectsFile\n }\n catch {\n // Corrupt file → treat as empty so the user can re-bootstrap.\n }\n return {}\n}\n\nexport function writeProjects(dataDir: string, file: ProjectsFile): void {\n writeFileAtomic(projectsFilePath(dataDir), JSON.stringify(file, null, 2), { ensureDir: true })\n}\n\n/**\n * Append one or more entries to the safelist for `projectDir`, dedup-aware.\n * Accepts a single string or a list (a compound shell command needs one\n * entry per command head — see {@link suggestSafelistEntries}). Writes once\n * and returns the updated entry list (post-write) so callers can render it\n * without re-reading. No write happens when every entry already exists.\n */\nexport function addToSafelist(\n dataDir: string,\n projectDir: string,\n entries: string | readonly string[],\n): readonly string[] {\n const toAdd = typeof entries === 'string' ? [entries] : entries\n const file = readProjects(dataDir)\n const existing = file[projectDir]?.safelist ?? []\n const next = [...existing]\n for (const entry of toAdd) {\n if (!next.includes(entry))\n next.push(entry)\n }\n if (next.length === existing.length)\n return existing\n file[projectDir] = { ...file[projectDir], safelist: next }\n writeProjects(dataDir, file)\n return next\n}\n\n/** Read the safelist for one project. Returns `[]` for unknown projects. */\nexport function getSafelist(dataDir: string, projectDir: string): readonly string[] {\n return readProjects(dataDir)[projectDir]?.safelist ?? []\n}\n\n/**\n * The safelist in effect for a working directory — what every host's gate\n * must read. The project's entries ({@link safelistProjectKey}), plus\n * entries saved under older keys for the same place, still honored but never\n * written again:\n *\n * - the CHECKOUT root — the TUI keyed a linked worktree by its own dir\n * before worktrees resolved to their main checkout;\n * - the exact `cwd` — the daemon/GUI keyed by raw cwd before keys were\n * normalized to the project.\n */\nexport function getSafelistForCwd(dataDir: string, cwd: string): readonly string[] {\n const file = readProjects(dataDir)\n const keys = new Set([safelistProjectKey(cwd), findGitRoot(cwd) ?? cwd, cwd])\n const merged: string[] = []\n for (const key of keys) {\n for (const entry of file[key]?.safelist ?? []) {\n if (!merged.includes(entry))\n merged.push(entry)\n }\n }\n return merged\n}\n\n/** {@link addToSafelist} under the project key for `cwd` — the write every host's gate uses. */\nexport function addToSafelistForCwd(dataDir: string, cwd: string, entries: string | readonly string[]): readonly string[] {\n return addToSafelist(dataDir, safelistProjectKey(cwd), entries)\n}\n\n// ---------------------------------------------------------------------------\n// Matching\n// ---------------------------------------------------------------------------\n\n/**\n * Tools that always pass without prompting. Four categories:\n *\n * - **Pure reads** (`read_file`, `list_files`, `glob`, `grep`) — no\n * side effects on disk or the model's own state.\n * - **Interaction tools** (`ask_user`, `present_plan`) — the call\n * itself surfaces a TUI picker the user has to answer, so prompting\n * for approval first would mean \"approve this prompt before you see\n * the prompt\": redundant + breaks the flow. The picker IS the gate.\n * - **Todos** (`todowrite`, `todoread`) — write to a slot on\n * `session.metadata.todos` and nothing else. No shell, no disk, no\n * network. The model uses these for checkpointing every few steps;\n * a per-call approval prompt would drown the conversation in\n * interruptions that buy no safety since the tool's surface is\n * read/write on a metadata bag we already trust the agent with.\n * - **Skill activation** (`skills_use`) — mutates a small per-agent\n * Map of active skills and returns the activated skill's bundled\n * instructions (or releases an entry on `mode: \"deactivate\"`).\n * Pure state on the agent — no shell, no disk writes, no network.\n * Gating it would also defeat the \"model recovers from\n * `AgentToolNotAllowedError` by calling\n * `skills_use({ mode: \"deactivate\", name })`\" path: a stuck model\n * would have to ask the user permission to *unstick* itself on\n * every retry. `skills_read` and `skills_run_script` are\n * intentionally NOT on this list — the former touches disk and\n * the latter executes arbitrary scripts, so both keep going\n * through the regular gate.\n *\n * Users who want to gate any of these must disable safe-mode entirely\n * (or fork this list in their own embedding).\n */\nexport const IMPLICITLY_SAFE_TOOLS: readonly string[] = [\n 'read_file',\n 'list_files',\n 'glob',\n 'grep',\n 'ask_user',\n 'present_plan',\n 'todowrite',\n 'todoread',\n 'skills_use',\n // The dev browser only loads http(s) pages in its own profile; the one\n // browser tool that runs arbitrary code in the page, `browser_evaluate`,\n // keeps going through the gate. `browser_open` / `browser_navigate` are\n // only implicit for loopback targets (see `isOnSafelist`), so the agent\n // can't point the browser at an arbitrary host by URL. This is not an\n // exfiltration barrier: clicks, form submits and redirects on a loaded\n // page can still reach any http(s) host without a prompt.\n 'browser_open',\n 'browser_navigate',\n 'browser_snapshot',\n 'browser_screenshot',\n 'browser_click',\n 'browser_type',\n 'browser_press',\n 'browser_scroll',\n 'browser_wait_for',\n 'browser_console',\n // Reading the session's terminals; the user can hide one from the agent.\n // `terminal_write` types into a shell, so it is gated like `shell`.\n 'terminal_list',\n 'terminal_read',\n]\n\n/** Common input keys carrying the \"primary argument\" we scope safelists on. */\nconst PRIMARY_ARG_KEYS = ['command', 'path', 'pattern', 'query'] as const\n\nfunction primaryArgValue(input: Record<string, unknown>): string {\n for (const key of PRIMARY_ARG_KEYS) {\n const v = input[key]\n if (typeof v === 'string' && v.length > 0)\n return v\n }\n return ''\n}\n\n/**\n * Extract the first whitespace-delimited token of the primary arg.\n * Leading whitespace is trimmed first so `\" git status\"` tokenizes to\n * `\"git\"`, not `\"\"` (an empty first element from `.split(/\\s+/)`).\n */\nfunction primaryArgToken(input: Record<string, unknown>): string {\n return primaryArgValue(input).trim().split(/\\s+/)[0] ?? ''\n}\n\n/**\n * Test whether a `{ tool, input }` pair is covered by one safelist entry.\n *\n * Supported entry shapes:\n * - `\"<tool>\"` — broad match on tool name.\n * - `\"<tool>:<token>:*\"` — match when the primary arg's first token\n * equals `<token>`.\n * - `\"browser_open:<host>\"` / `\"browser_navigate:<host>\"` — match a\n * load of that host (port included).\n *\n * This function matches a **single command** against a **single entry**.\n * For shell commands that chain multiple programs (`&&`, `||`, `;`,\n * `$(…)`, etc.), use {@link isOnSafelist} which parses the full command\n * and checks every head token independently.\n *\n * Entries that don't fit either shape are ignored (forward-compat for\n * future pattern syntax — readers shouldn't choke on entries written\n * by a newer version of the TUI).\n */\nexport function matchesSafelistEntry(\n entry: string,\n tool: string,\n input: Record<string, unknown>,\n): boolean {\n if (entry === tool)\n return true\n const sep = entry.indexOf(':')\n if (sep <= 0)\n return false\n if (entry.slice(0, sep) !== tool)\n return false\n const scope = entry.slice(sep + 1)\n if (scope.endsWith(':*'))\n return primaryArgToken(input) === scope.slice(0, -2)\n if (isBrowserLoadTool(tool))\n return browserScope(input) === scope\n return false\n}\n\n/**\n * True when a call matches ANY entry in the project's safelist (or is\n * implicitly safe).\n *\n * For `shell` commands, the full command string is parsed into individual\n * commands (handling `&&`, `||`, `;`, `|`, `$(…)`, backticks, subshells).\n * Every command head must be covered by at least one safelist entry for\n * the call to pass. If parsing fails, returns `false` (prompt the user).\n */\nexport function isOnSafelist(\n entries: readonly string[],\n tool: string,\n input: Record<string, unknown>,\n): boolean {\n if (IMPLICITLY_SAFE_TOOLS.includes(tool) && !isRemoteBrowserTarget(tool, input))\n return true\n\n if (tool === 'shell') {\n const cmd = typeof input.command === 'string' ? input.command : ''\n const heads = extractCommandHeads(cmd)\n if (heads === null)\n return false\n if (heads.length === 0)\n return entries.some(e => matchesSafelistEntry(e, tool, input))\n return heads.every(head =>\n entries.some(e => matchesSafelistEntry(e, tool, { ...input, command: head })),\n )\n }\n\n return entries.some(e => matchesSafelistEntry(e, tool, input))\n}\n\n/** A `browser_open` / `browser_navigate` call that would load a non-loopback address. */\nfunction isRemoteBrowserTarget(tool: string, input: Record<string, unknown>): boolean {\n if (!isBrowserLoadTool(tool))\n return false\n if (typeof input.url !== 'string' || !input.url.trim())\n return false\n const url = normalizeBrowserUrl(input.url)\n return !url || !isLocalBrowserUrl(url)\n}\n\nfunction isBrowserLoadTool(tool: string): boolean {\n return tool === 'browser_open' || tool === 'browser_navigate'\n}\n\n/** What a remembered browser load is scoped to: the URL's host, else the raw URL. */\nfunction browserScope(input: Record<string, unknown>): string {\n const raw = typeof input.url === 'string' ? input.url.trim() : ''\n const url = raw ? normalizeBrowserUrl(raw) : null\n let host = ''\n try {\n host = url ? new URL(url).host : ''\n }\n catch {}\n return host || raw\n}\n\n/**\n * Suggest the safelist entries to persist when the user picks \"accept and\n * remember\" (or \"accept for session\") for a `{ tool, input }`. Heuristic:\n *\n * - `shell` → one `shell:<head>:*` per DISTINCT command head, parsing the\n * command the SAME way {@link isOnSafelist} matches it (`&&`, `||`, `;`,\n * `|`, `$(…)`, subshells, backticks). So `cd dir && cat file` yields\n * `[\"shell:cd:*\", \"shell:cat:*\"]` — persisting the whole set is what\n * lets the next identical call skip the gate. A single first-token\n * entry would only cover `cd`, so `isOnSafelist`'s `every-head` check\n * would fail on `cat` and re-prompt forever.\n * - `shell` with an unparseable / empty command → first-token heuristic,\n * else the bare tool name.\n * - `browser_open` / `browser_navigate` to a non-loopback address →\n * `<tool>:<host>`: approving one site does not approve the web.\n * - anything else → bare tool name (broad).\n *\n * Always returns a non-empty list so the UI has a concrete set to render\n * and persist.\n */\nexport function suggestSafelistEntries(\n tool: string,\n input: Record<string, unknown>,\n): string[] {\n if (tool === 'shell') {\n const cmd = typeof input.command === 'string' ? input.command : ''\n const heads = extractCommandHeads(cmd)\n if (heads && heads.length > 0) {\n // Emit one entry per head, deriving the token EXACTLY as\n // `isOnSafelist` looks it up (`primaryArgToken({ command: head })`)\n // and skipping nothing — that symmetry is what guarantees the\n // round-trip: whatever we persist here re-approves the same command\n // next time, for any command the parser accepts (a degenerate head\n // that tokenizes to \"\" yields `shell::*`, which the matcher checks\n // for the same \"\" token, so it still round-trips).\n const out: string[] = []\n for (const head of heads) {\n const entry = `${tool}:${primaryArgToken({ command: head })}:*`\n if (!out.includes(entry))\n out.push(entry)\n }\n return out\n }\n // No heads (assignment-only like `FOO=bar`, or empty/whitespace cmd):\n // mirror `isOnSafelist`'s `heads.length === 0` branch, which matches\n // against the whole input. `extractCommandHeads` returning null is the\n // only case that can't round-trip — the matcher refuses a null parse\n // outright — so this stays a best-effort one-shot grant there.\n const token = primaryArgToken(input)\n if (token)\n return [`${tool}:${token}:*`]\n }\n if (isRemoteBrowserTarget(tool, input)) {\n const scope = browserScope(input)\n if (scope)\n return [`${tool}:${scope}`]\n }\n return [tool]\n}\n","/**\n * Pure builders for live subagent lifecycle markers — the `spawn-start` /\n * `spawn-end` StreamEvents the engine broadcasts from the `spawn:before` /\n * `spawn:complete` hooks — and from their nested `child:spawn:*`\n * re-emissions, whose `parentChildId` lands on `spawn.parentChildId`.\n *\n * Mirrors canonical replay's `pushSpawnStart` / `pushSpawnEnd`\n * (`src/chat/store.ts`) so a live GUI transcript and a reloaded one render\n * byte-identical markers. Extracted from `engine.ts` so the wire-text\n * shapes are unit-testable without an Electron harness.\n */\nimport type { AgentStats, SpawnQueuedContext } from '../types'\nimport type { StreamEvent } from './types'\nimport { flattenTurns, formatTokenUsage } from '../stats'\n\nimport { formatDuration, previewLine } from './format'\n\n/**\n * Wall-clock start + task preview per in-flight child, keyed by spawn id.\n * Captured at `spawn:before` and read back at `spawn:complete` — drives\n * the human-readable elapsed suffix on the spawn-end marker\n * (`done · 42s`) and copies the stable task preview onto the terminal\n * marker.\n */\nexport interface SpawnStartRecord {\n startedAt: number\n task: string\n model?: string\n}\n\n/** Upper bound on the task carried on a start marker: enough to read, not a payload. */\nexport const SPAWN_PROMPT_MAX = 20_000\n\n/** A worker's task as carried on its start marker. */\nexport function spawnPrompt(task: string): string {\n return task.length > SPAWN_PROMPT_MAX ? `${task.slice(0, SPAWN_PROMPT_MAX)}\\n\\n… (${task.length - SPAWN_PROMPT_MAX} more characters)` : task\n}\n\n/**\n * `spawn-start` marker for a child that just launched. `previewLine`\n * collapses inline newlines/tabs so the marker stays on one visual row\n * resumed children carry the label of the run they continue — same text\n * shape as the reload path.\n */\nexport function buildSpawnStartEvent(\n ctx: { id: string, task: string, callId?: string, depth?: number, model?: string, resumesChildId?: string, parentChildId?: string },\n startedAt: number,\n): StreamEvent {\n const taskPreview = previewLine(ctx.task, 80)\n\n return {\n kind: 'spawn-start',\n text: ctx.resumesChildId ? `resumes ${ctx.resumesChildId} · ${taskPreview}` : taskPreview,\n childId: ctx.id,\n depth: ctx.depth ?? 1,\n spawn: {\n startedAt,\n prompt: spawnPrompt(ctx.task),\n ...(ctx.parentChildId ? { parentChildId: ctx.parentChildId } : {}),\n ...(ctx.callId ? { callId: ctx.callId } : {}),\n },\n ...(ctx.model ? { model: ctx.model } : {}),\n }\n}\n\n/**\n * `spawn-queued` marker: a top-level spawn call waiting for a slot. On the\n * parent's own lane (only the top-level agent waits), live only.\n */\nexport function buildSpawnQueuedEvent(ctx: SpawnQueuedContext): StreamEvent {\n return {\n kind: 'spawn-queued',\n text: `waiting · starts when one of ${ctx.waitingFor.max} finishes`,\n ...(ctx.callId ? { callId: ctx.callId } : {}),\n waitingFor: ctx.waitingFor,\n }\n}\n\n/**\n * `spawn-end` marker: ` · `-joined optional segments — elapsed wall-clock\n * time, then USD cost summed across the child's whole turn tree (most\n * providers don't populate `cost`, so the segment usually collapses; no\n * \"$0.00\" lies) — followed by the token usage summary. `timeout` maps to\n * the `done` tag, matching the TUI.\n */\nexport function buildSpawnEndEvent(\n ctx: { id: string, depth?: number, status?: 'completed' | 'aborted' | 'timeout' | 'error', stats: AgentStats, parentChildId?: string },\n started: SpawnStartRecord | undefined,\n now = Date.now(),\n): StreamEvent {\n const tag = ctx.status === 'aborted' ? 'aborted' : ctx.status === 'error' ? 'error' : 'done'\n const startedAt = started?.startedAt\n const elapsed = startedAt !== undefined ? ` · ${formatDuration(now - startedAt)}` : ''\n const cost = flattenTurns(ctx.stats).reduce((sum, turn) => sum + (turn.cost ?? 0), 0)\n const costPart = cost > 0 ? ` · $${cost.toFixed(cost < 0.01 ? 4 : 2)}` : ''\n const segments = `${elapsed}${costPart}`\n const usage = formatTokenUsage(ctx.stats)\n\n return {\n kind: 'spawn-end',\n text: segments ? `${tag}${segments} · ${usage}` : `${tag} ${usage}`,\n childId: ctx.id,\n depth: ctx.depth ?? 1,\n spawn: {\n startedAt: startedAt ?? now,\n ...(started?.task ? { task: started.task } : {}),\n turns: ctx.stats.turns,\n ...(ctx.parentChildId ? { parentChildId: ctx.parentChildId } : {}),\n },\n ...(started?.model ? { model: started.model } : {}),\n }\n}\n","/**\n * Run-level reconstruction for transcript replay (`eventsFromTurns` in\n * `./store`): the run index (with records synthesized for legacy gaps),\n * `child-N` labels, ancestry and subtree totals, the spawn markers, and the\n * per-run receipts.\n */\nimport type { SessionRun } from '../session'\nimport type { SessionTurn } from '../types'\nimport type { StreamEvent } from './types'\nimport { formatTokenUsage } from '../stats'\nimport { toolResultToText } from '../types'\nimport { formatDuration, previewLine } from './format'\nimport { formatRunReceiptLine, hasRunReceipt, runReceiptFromRun } from './run-receipt'\nimport { spawnPrompt } from './spawn-markers'\n\n/**\n * The run records a replay works from, by id: `runs[]` first-write-wins, plus\n * synthesized records for runs the turns reference but `runs[]` lacks.\n */\nexport function indexReplayRuns(turns: SessionTurn[], runs: readonly SessionRun[]): Map<string, SessionRun> {\n // First-write-wins on duplicate ids. Historical sessions persisted\n // before the per-mint `initialRunCounter` re-sync (see `src/agent.ts`)\n // could have a child agent and its parent both registering runs with\n // the SAME `run_<n>` id — the subagent ran first (lands first in\n // `runs[]`), the parent's collision came later (lands last).\n // Last-write-wins would resolve the id to the collision (depth=0,\n // no parentRunId), the structural ancestry walk would return empty,\n // and the renderer would paint a subagent's transcript at depth 0:\n // indent gets crazy, spawn markers placed wrong, the whole block\n // looks \"off\". Preferring the FIRST entry keeps the depth + parent\n // info from the subagent record, which is what every turn under\n // that runId actually wants. Clean sessions have one entry per id,\n // so first/last makes no difference.\n const runById = new Map<string, SessionRun>()\n for (const run of runs) {\n if (!runById.has(run.id))\n runById.set(run.id, run)\n }\n\n // Defensive synthesis for legacy sessions whose `runs[]` is missing\n // entries the turns reference (e.g. the pre-fix `updateRun`-not-\n // upsert bug in the sqlite/memory stores dropped subagent records\n // silently). Without it, an orphan turn's `ancestryOf()` returns an\n // empty chain → depth = 0 → the subagent's user-text-block leaks\n // as a `user-prompt` event and pollutes the TUI's history.\n //\n // Inference is structural: walk turns chronologically, maintain a\n // stack of currently-open runIds, and decide whether a NEW runId\n // is nested or top-level based on whether the stack-top run has any\n // unresolved tool_calls. A nested runId pushes (depth grows); a\n // top-level runId resets the stack first. Tracked per-runId in\n // `pendingToolCallsPerRun` — incremented on `tool_call` blocks,\n // decremented on `tool_result` blocks.\n //\n // Without the nesting gate, the naive \"push every new runId, never\n // pop\" walk treated back-to-back top-level prompts as a deepening\n // chain of subagents, and synthesized depth grew unbounded —\n // `indentFor(36)` = 72 cells, which is the far-right rendering the\n // user reported for a session with many top-level chats plus one\n // missing run record. Real records (present in `runById`) are NEVER\n // overwritten — synthesis only fills the gap.\n const runStack: string[] = []\n const pendingToolCallsPerRun = new Map<string, Set<string>>()\n for (const turn of turns) {\n const rid = turn.runId\n if (!rid)\n continue\n const idxInStack = runStack.indexOf(rid)\n if (idxInStack >= 0) {\n // Already open — pop any deeper nesting that's now closed.\n runStack.length = idxInStack + 1\n }\n else {\n // New runId — nested only when the parent has a pending\n // SPAWN-shaped tool_call (the call that's waiting on a subagent).\n // Restricting to spawn-like names matters: a run killed mid-tool\n // (dev-loop restart, crash) leaves its ordinary tool_calls\n // unresolved FOREVER, and under the old \"any pending call\" gate\n // every subsequent top-level run with a missing record was\n // synthesized as that dead run's child — the user's own prompt\n // rendered as `child-N · <prompt>` with `0 / 0 out`.\n const top = runStack[runStack.length - 1]\n const parentHasPending = top !== undefined && (pendingToolCallsPerRun.get(top)?.size ?? 0) > 0\n if (!parentHasPending) {\n // Fresh top-level — drop the stack so a long chat history\n // doesn't accumulate phantom depth.\n runStack.length = 0\n }\n runStack.push(rid)\n\n if (!runById.has(rid))\n runById.set(rid, synthesizedRun(turn, rid, runStack))\n }\n\n // Update the pending-tool-calls set for this turn's runId. Tracked\n // here (not in the synthesis branch alone) so we have an accurate\n // running view for every turn — the stack-top check above reads\n // this for the next iteration.\n const pending = pendingToolCallsPerRun.get(rid) ?? new Set<string>()\n for (const block of turn.content) {\n // Only spawn-shaped calls can open a child run — tracking every\n // tool_call would let a run killed mid-`shell`/`read_file` adopt\n // unrelated later runs as phantom children (see gate above).\n if (block.type === 'tool_call' && /spawn/i.test(block.name))\n pending.add(block.id)\n else if (block.type === 'tool_result')\n pending.delete(block.callId)\n }\n pendingToolCallsPerRun.set(rid, pending)\n }\n return runById\n}\n\n/** The record synthesized for a run whose own record is missing, at its place in the open-run stack. */\nfunction synthesizedRun(turn: SessionTurn, rid: string, runStack: readonly string[]): SessionRun {\n // Missing record — synthesize. Depth = stack depth - 1 (zero-based).\n // Prompt: the first user text-block on this turn (when present)\n // so the `child-N` spawn-start marker renders with a meaningful\n // preview rather than an empty string. Empty when the first\n // turn isn't a user turn or has no text block — `pushSpawnStart`\n // then falls through to the bare label.\n const depth = runStack.length - 1\n const parentRunId = depth > 0 ? runStack[depth - 1] : undefined\n let inferredPrompt = ''\n if (turn.role === 'user') {\n for (const block of turn.content) {\n if (block.type === 'text' && block.text.trim()) {\n inferredPrompt = block.text\n break\n }\n }\n }\n return {\n id: rid,\n startedAt: turn.createdAt,\n prompt: inferredPrompt,\n status: 'completed',\n depth,\n ...(parentRunId ? { parentRunId } : {}),\n }\n}\n\n/** `runId` → its friendly `child-N` label (the run id itself when it has none). */\nexport function childLabeler(runById: ReadonlyMap<string, SessionRun>): (runId: string) => string {\n // Build a chronological mapping from the persisted `runId` (e.g. `run_2`) to\n // a friendly `child-N` label that mirrors what the spawn tool emits live\n // (see `src/tools/spawn.ts`'s local counter). Without this the reloaded\n // transcript labels its subagent block `[run_2]` while the persisted tool\n // result text inside that very block says `[sub-agent child-1]`.\n //\n // Reads from `runById` (NOT the raw `runs` param) so synthesized\n // fallback runs from `indexReplayRuns`' legacy-session synthesis also get\n // a proper `child-N` label.\n const childLabelByRunId = new Map<string, string>()\n const childRuns = [...runById.values()]\n .filter(r => (r.depth ?? 0) > 0)\n .sort((a, b) => a.startedAt - b.startedAt)\n // Prefer the label persisted at `startRun` (`SessionRun.label`) — the\n // positional fallback covers legacy sessions and synthesized runs, but\n // can desync from announced labels under concurrent spawns or counter\n // drift, which would mislabel resume targets.\n childRuns.forEach((r, i) => childLabelByRunId.set(r.id, r.label ?? `child-${i + 1}`))\n return (runId: string) => childLabelByRunId.get(runId) ?? runId\n}\n\n/** `callId` → the tool name its assistant `tool_call` named. */\nexport function toolNamesByCallId(turns: SessionTurn[]): Map<string, string> {\n // Build a `callId → toolName` map from the assistant `tool_call` blocks so\n // we can tag each user-role `tool_result` event with the tool it answers.\n // The renderer uses this for tool-aware filters (e.g. hiding the spawn\n // tool's result when `hideSubagentOutput` is on).\n const toolByCallId = new Map<string, string>()\n for (const turn of turns) {\n if (turn.role !== 'assistant')\n continue\n for (const block of turn.content) {\n if (block.type === 'tool_call')\n toolByCallId.set(block.id, block.name)\n }\n }\n return toolByCallId\n}\n\n/** `callId` → the text of its user-role `tool_result`. */\nexport function resultTextsByCallId(turns: SessionTurn[]): Map<string, string> {\n // Build a `callId → resultText` map so the replay path can attach per-\n // edit outcomes back onto the corresponding `tool` event. Live capture\n // mutates `_outcomes` on input before tool execution; on disk, only the\n // tool_result body carries the post-decision shape, so the replay\n // parses it (see `parseEditOutcomesFromResult`).\n const resultByCallId = new Map<string, string>()\n for (const turn of turns) {\n if (turn.role !== 'user')\n continue\n for (const block of turn.content) {\n if (block.type === 'tool_result') {\n resultByCallId.set(\n block.callId,\n typeof block.output === 'string' ? block.output : toolResultToText(block.output),\n )\n }\n }\n }\n return resultByCallId\n}\n\n/**\n * The `child-N` label of the subagent that spawned `run` — the live\n * `child:spawn:*` hook's `parentChildId`. Undefined for a direct child of a\n * top-level run (and for orphans whose parent record is gone).\n */\nexport function spawnerLabeler(\n runById: ReadonlyMap<string, SessionRun>,\n labelFor: (runId: string) => string,\n): (run: SessionRun) => string | undefined {\n return (run: SessionRun) => {\n const parent = run.parentRunId ? runById.get(run.parentRunId) : undefined\n return parent && (parent.depth ?? 0) > 0 ? labelFor(parent.id) : undefined\n }\n}\n\n/** A turn's run ancestry over `runById`. */\nexport function runAncestry(runById: ReadonlyMap<string, SessionRun>): (turnRunId: string | undefined) => SessionRun[] {\n // Ancestry chain for a turn's run — `[root child, …, the turn's own run]`,\n // excluding any depth-0 (top-level) ancestor since top-level runs don't\n // render spawn-start/spawn-end markers. Feeds the open-once /\n // close-after-last-subtree-turn logic in `eventsFromTurns`\n // (`./store`), so neither depth ≥ 2\n // (grandchild) sequences nor interleaved concurrent siblings emit\n // duplicate `spawn-start` / premature `spawn-end` markers.\n return (turnRunId: string | undefined): SessionRun[] => {\n if (!turnRunId)\n return []\n const chain: SessionRun[] = []\n let cursor: SessionRun | undefined = runById.get(turnRunId)\n const seen = new Set<string>()\n while (cursor) {\n // Defensive cycle guard — a corrupt run row pointing at its own\n // ancestor would otherwise loop forever.\n if (seen.has(cursor.id))\n break\n seen.add(cursor.id)\n if ((cursor.depth ?? 0) > 0)\n chain.unshift(cursor)\n cursor = cursor.parentRunId ? runById.get(cursor.parentRunId) : undefined\n }\n return chain\n }\n}\n\nexport interface SubtreeTotals { cost: number, tokensIn: number, tokensOut: number, cacheRead: number, cacheCreation: number }\n\n/** A run's totals summed over its whole subtree (itself and every descendant). */\nexport function runSubtreeTotals(runById: ReadonlyMap<string, SessionRun>): (root: SessionRun) => SubtreeTotals {\n // Children index for subtree aggregation. Run records are\n // deliberately per-run additive (children persist as their own runs —\n // folding cumulative totals into the parent would double-count, see\n // `completeRun` in agent.ts), while the live spawn-end marker reports\n // subtree totals: cost via the `flattenTurns` walk, tokens via the\n // grandchildren fold in agent.ts's `finalStats`. Walk descendants here\n // so live and reloaded markers agree for nested spawns — on BOTH\n // numbers, not just cost.\n const childRunsOf = new Map<string, SessionRun[]>()\n for (const run of runById.values()) {\n if (!run.parentRunId)\n continue\n const siblings = childRunsOf.get(run.parentRunId) ?? []\n siblings.push(run)\n childRunsOf.set(run.parentRunId, siblings)\n }\n return (root: SessionRun): SubtreeTotals => {\n const totals = { cost: 0, tokensIn: 0, tokensOut: 0, cacheRead: 0, cacheCreation: 0 }\n const queue = [root]\n const seen = new Set<string>()\n while (queue.length > 0) {\n const run = queue.pop() as SessionRun\n if (seen.has(run.id))\n continue\n seen.add(run.id)\n totals.cost += run.cost ?? run.turnUsage?.reduce((sum, u) => sum + (u.cost ?? 0), 0) ?? 0\n totals.tokensIn += run.tokensIn ?? run.totalUsage?.input ?? 0\n totals.tokensOut += run.tokensOut ?? run.totalUsage?.output ?? 0\n totals.cacheRead += run.totalUsage?.cacheRead ?? 0\n totals.cacheCreation += run.totalUsage?.cacheCreation ?? 0\n queue.push(...(childRunsOf.get(run.id) ?? []))\n }\n return totals\n }\n}\n\n/** The `spawn-end` marker closing a child run, carrying its subtree totals. */\nexport function spawnEndEvent(run: SessionRun, totals: SubtreeTotals, labelFor: (runId: string) => string, parentChildId?: string): StreamEvent {\n const tag = run.status === 'aborted' || run.status === 'error' ? run.status : 'done'\n // Same caching gotcha as the live path: `tokensIn` mirrors\n // `AgentStats.totalIn` (new uncached only). `formatTokenUsage` folds\n // cache reads/creations into the headline `in` number. Totals span\n // the run's whole subtree — the live marker formats the child's\n // `finalStats`, which already folds grandchildren in.\n const usage = formatTokenUsage({\n totalIn: totals.tokensIn,\n totalOut: totals.tokensOut,\n totalCacheRead: totals.cacheRead,\n totalCacheCreation: totals.cacheCreation,\n })\n // Optional ` · `-joined segments — keep the shape in sync with the live\n // `spawn:complete` hook (`buildSpawnEndEvent`, `src/chat/spawn-markers.ts`) so a reloaded transcript\n // renders byte-identical markers. `endedAt` is absent on runs\n // synthesized from bare turns (legacy sessions) — the segment drops.\n // Zero/unknown cost hides the segment (no \"$0.00\" lies).\n const elapsed = run.endedAt !== undefined ? ` · ${formatDuration(run.endedAt - run.startedAt)}` : ''\n const cost = totals.cost\n const costPart = cost > 0 ? ` · $${cost.toFixed(cost < 0.01 ? 4 : 2)}` : ''\n // Legacy runs with neither segment keep the bare `done in N / M out`\n // shape — no dangling `·` on sessions recorded before duration/cost.\n const segments = `${elapsed}${costPart}`\n const model = run.turnUsage?.find(u => u.modelId)?.modelId\n const turns = run.turns ?? run.turnUsage?.length\n return {\n kind: 'spawn-end',\n text: segments ? `${tag}${segments} · ${usage}` : `${tag} ${usage}`,\n childId: labelFor(run.id),\n depth: run.depth ?? 1,\n spawn: {\n startedAt: run.startedAt,\n task: previewLine(run.prompt, 80),\n ...(turns !== undefined ? { turns } : {}),\n ...(parentChildId ? { parentChildId } : {}),\n },\n ...(model ? { model } : {}),\n }\n}\n\n/** The `spawn-start` marker opening a child run. */\nexport function spawnStartEvent(run: SessionRun, labelFor: (runId: string) => string, parentChildId?: string): StreamEvent {\n // Single-line preview — newlines / tabs in the prompt collapse to\n // single spaces so the spawn-start marker stays on one visual row.\n // See the matching comment on `buildSpawnStartEvent` (`spawn-markers.ts`) for\n // the failure mode (multi-line prompt prints the marker across\n // multiple visual rows, the next event lands far right).\n const taskPreview = previewLine(run.prompt, 80)\n // Which model the child ran on — mirrors the live `spawn:before` hook's\n // `model`. Reconstructed from the first turn that recorded a model id\n // (providers echo it per turn; the run-level `totalUsage` aggregate\n // deliberately drops `modelId`, so per-turn usage is the only source).\n const model = run.turnUsage?.find(u => u.modelId)?.modelId\n // A resumed child (spawn `resume`) is tagged with the label of the run\n // it continues — mirrors the live `spawn:before` hook's `resumesChildId`.\n const resumes = run.resumedFromRunId ? labelFor(run.resumedFromRunId) : undefined\n return {\n kind: 'spawn-start',\n text: resumes ? `resumes ${resumes} · ${taskPreview}` : taskPreview,\n childId: labelFor(run.id),\n depth: run.depth ?? 1,\n spawn: {\n startedAt: run.startedAt,\n task: taskPreview,\n prompt: spawnPrompt(run.prompt),\n ...(parentChildId ? { parentChildId } : {}),\n ...(run.parentCallId ? { callId: run.parentCallId } : {}),\n },\n ...(model ? { model } : {}),\n }\n}\n\n/**\n * Insert each finished top-level run's receipt (and its error) after the last\n * event of its last turn. Returns the inserts, last position first (the order\n * they were made): `at` is the index the first inserted event took.\n */\nexport function insertRunReceipts(events: StreamEvent[], turns: SessionTurn[], runs: readonly SessionRun[]): Array<{ at: number, count: number }> {\n /*\n * Per-run receipts. For every finished TOP-LEVEL run, a `run-summary` lands\n * right after the last event of that run — the same record and the same\n * formatter the live path uses at `run:end`, so a reloaded session shows\n * exactly the line the user saw when the run ended. Child runs (subagents)\n * get no receipt of their own: their spawn-end marker already carries their\n * totals, and a receipt per child would bury the parent's.\n */\n const lastTurnIdByRun = new Map<string, string>()\n for (const turn of turns) {\n if (turn.runId)\n lastTurnIdByRun.set(turn.runId, turn.id)\n }\n const receiptAfterTurn = new Map<string, StreamEvent[]>()\n for (const run of runs) {\n if (run.parentRunId !== undefined || run.endedAt === undefined)\n continue\n const lastTurnId = lastTurnIdByRun.get(run.id)\n if (!lastTurnId)\n continue\n const ending: StreamEvent[] = []\n if (run.status === 'error' && run.error)\n ending.push({ kind: 'error', text: run.error, turnId: lastTurnId })\n const receipt = runReceiptFromRun(run)\n if (hasRunReceipt(receipt))\n ending.push({ kind: 'run-summary', text: formatRunReceiptLine(receipt), runSummary: receipt, turnId: lastTurnId })\n if (ending.length > 0)\n receiptAfterTurn.set(lastTurnId, ending)\n }\n const inserted: Array<{ at: number, count: number }> = []\n if (receiptAfterTurn.size > 0) {\n // Insert after the LAST event carrying that turn id (a turn can emit\n // several events — text, tool calls, spawn markers).\n const lastIndexByTurn = new Map<string, number>()\n events.forEach((e, idx) => {\n if (e.turnId && receiptAfterTurn.has(e.turnId))\n lastIndexByTurn.set(e.turnId, idx)\n })\n const inserts = [...lastIndexByTurn.entries()].sort((a, b) => b[1] - a[1])\n for (const [turnId, idx] of inserts) {\n const ending = receiptAfterTurn.get(turnId)!\n events.splice(idx + 1, 0, ...ending)\n inserted.push({ at: idx + 1, count: ending.length })\n }\n }\n return inserted\n}\n","import type { SessionData, SessionMetaRow, SessionRun, SessionStore } from '../session'\nimport type { JsonValue, SessionContentBlock, SessionTurn, ThinkingLevel, ToolResultContent } from '../types'\nimport type { ProviderKey } from './auth'\nimport type { ModelChainEntry } from './model-chain'\nimport type { EditOutcome, SessionEnvironmentSummary, SessionHeader, SessionMeta, Settings, StreamEvent } from './types'\nimport { Buffer } from 'node:buffer'\nimport { existsSync, mkdirSync, readFileSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { writeFileAtomic } from '../atomic-write'\nimport { errorMessage } from '../errors'\nimport { unwrapCallTool } from '../tools/call-tool'\nimport { toolResultToText } from '../types'\nimport { commandNoteText, commandStepLabel, parseCommandHeader } from './command-notes'\nimport { parseEditOutcomesFromResult } from './edit-approval'\nimport { extractEditPayload } from './edit-diff'\nimport { ENVIRONMENT_METADATA_KEY, LOCAL_ENVIRONMENT, readSessionEnvironment } from './environment'\nimport { isMainSession, parseSessionEventXml } from './orchestration'\nimport { inferPromptRefs } from './prompt-segments'\nimport { childLabeler, indexReplayRuns, insertRunReceipts, resultTextsByCallId, runAncestry, runSubtreeTotals, spawnEndEvent, spawnerLabeler, spawnStartEvent, toolNamesByCallId } from './replay-runs'\n\n// NOTE: `createTuiStore` moved to `src/session/sqlite.ts` so this module —\n// the public `zidane/chat` entry — does NOT statically import `bun:sqlite`.\n// A future GUI consumer that imports `zidane/chat` no longer transitively\n// pulls in the Bun-only sqlite binding. Hosts construct their own store\n// (e.g. via `createTuiStore` from `zidane/session/sqlite` for terminal hosts)\n// and pass it through `runTui({ store })` / `resolveConfig({ store })`.\n\nfunction ensureStateDir(path: string): void {\n const dir = dirname(path)\n if (existsSync(dir))\n return\n try {\n mkdirSync(dir, { recursive: true })\n }\n catch (err) {\n throw new Error(\n `Could not create TUI state directory at \"${dir}\". `\n + `Override the location via \\`runTui({ storageDir, prefix })\\` or the `\n + `\\`ZIDANE_STORAGE_DIR\\` env var. Original error: ${errorMessage(err)}`,\n )\n }\n}\n\n// ---------------------------------------------------------------------------\n// Persisted UI state — what to resume on next launch.\n//\n// `StateStoreApi` is a thin facade that binds load/save to a specific JSON\n// path, so the rest of the UI can persist state without knowing the layout.\n// ---------------------------------------------------------------------------\n\nexport interface TuiState {\n lastProvider?: ProviderKey\n lastSessionId?: string\n /**\n * The host key of the saved server `lastSessionId` lives on (for a server,\n * its host id: `src/chat/hosts/session-key`), absent for a session on this\n * computer. Resume reopens it there, and only with remote hosts on. A\n * `--host` session writes neither field (see `lastSessionId`).\n * Read from the older `lastSessionHostId` too ({@link loadState}).\n */\n lastSessionHostKey?: string\n /** Per-provider last-used model id. */\n lastModelByProvider?: Partial<Record<ProviderKey, string>>\n /**\n * Last-applied model fallback chain (entry 0 = primary, mirroring\n * `lastProvider` + `lastModelByProvider`; entries 1+ = fallbacks).\n * Additive — absent for single-model users and older state files.\n * Restored on launch only when entry 0 still matches the resolved\n * primary; entries are re-validated against the live registry.\n */\n lastModelChain?: ModelChainEntry[]\n /**\n * Per-model last-picked reasoning effort. Keyed by model id (not provider)\n * so switching the same model across providers preserves the user's\n * intent. Models without reasoning support are absent from the map.\n */\n lastEffortByModel?: Record<string, ThinkingLevel>\n /**\n * Per-model last-picked custom options (e.g. `{ fast: true }`). Keyed by\n * model id like {@link lastEffortByModel}, so a toggle follows the model\n * across providers. Models with no options are absent from the map.\n */\n lastModelOptionsByModel?: Record<string, Record<string, boolean>>\n /**\n * Last-active agent profile id (see {@link AgentRegistry}). Resumed on\n * launch so a returning user lands back in the same mode (Build / Plan /\n * a host profile). Falls back to the host's `defaultAgent` then the first\n * registry key if the id is no longer registered.\n */\n /**\n * @deprecated No longer read: the agent profile is per-session and fresh\n * sessions always start in the default. Kept so older state files parse.\n */\n lastAgent?: string\n /** User-toggled transcript filters. Persisted so they outlive a launch. */\n settings?: Partial<Settings>\n}\n\nexport interface StateStoreApi {\n load: () => TuiState\n save: (state: TuiState) => void\n}\n\nexport function createStateStore(path: string): StateStoreApi {\n return {\n load: () => loadState(path),\n save: state => saveState(path, state),\n }\n}\n\nexport function loadState(path: string): TuiState {\n if (!existsSync(path))\n return {}\n try {\n const parsed = JSON.parse(readFileSync(path, 'utf-8'))\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed))\n return withLegacyFields(parsed as TuiState & { lastSessionHostId?: unknown })\n }\n catch {\n // Corrupt state file → treat as absent so the user can reach the auth screen.\n }\n return {}\n}\n\n/** `lastSessionHostId` (earlier builds) is read as `lastSessionHostKey`, and leaves the state on its next save. */\nfunction withLegacyFields(state: TuiState & { lastSessionHostId?: unknown }): TuiState {\n const { lastSessionHostId: legacy, ...rest } = state\n if (rest.lastSessionHostKey === undefined && typeof legacy === 'string')\n return { ...rest, lastSessionHostKey: legacy }\n return rest\n}\n\nexport function saveState(path: string, state: TuiState): void {\n ensureStateDir(path)\n writeFileAtomic(path, JSON.stringify(state, null, 2))\n}\n\n// Re-export the model-info shape used by views below so callers don't have to\n// pull from `./config` for transcript helpers alone.\nexport type { ModelInfo } from './config'\n\n// ---------------------------------------------------------------------------\n// Session view helpers — derive UI-friendly shapes from persisted turns.\n// ---------------------------------------------------------------------------\n\n/**\n * Load every session and project it to the compact `SessionMeta` shape used by\n * the picker. Sorted by recency via the underlying store's `list()` contract\n * (sqlite store returns by `updated_at DESC`).\n *\n * Robust to per-row failures: `Promise.allSettled` so a single corrupt or\n * unreadable row (malformed JSON, partial write, transient I/O error)\n * doesn't take down the entire picker. Failed rows are silently skipped;\n * a stderr line is emitted under `ZIDANE_DEBUG` for diagnosis.\n */\nexport async function listSessionMeta(\n store: SessionStore,\n filter?: {\n /**\n * Restrict to sessions belonging to this project. Omit to ignore\n * the axis; pass `null` to ask for untagged (legacy) sessions\n * specifically. The TUI defaults to passing the current git root /\n * cwd here so each project sees only its own conversations.\n */\n projectRoot?: string | null\n },\n): Promise<SessionMeta[]> {\n // Fast path: stores with an indexed summary query (sqlite) answer in a\n // single round-trip without materializing any session. Falls back to\n // the generic fan-out below on error so a store with a broken/legacy\n // index degrades to slow-but-correct instead of an empty picker.\n if (store.listMeta) {\n try {\n const rows = await store.listMeta(filter)\n return rows.map(metaFromRow)\n }\n catch (err) {\n if (process.env.ZIDANE_DEBUG) {\n const cause = err instanceof Error ? err.message : String(err)\n process.stderr.write(`[zidane/chat] store.listMeta failed, falling back to full loads: ${cause}\\n`)\n }\n }\n }\n const ids = await store.list(filter)\n const settled = await Promise.allSettled(ids.map(async (id) => {\n const data = await store.load(id)\n return data ? metaFromData(id, data) : null\n }))\n const metas: SessionMeta[] = []\n for (let i = 0; i < settled.length; i++) {\n const result = settled[i]\n if (result.status === 'fulfilled' && result.value) {\n metas.push(result.value)\n }\n else if (result.status === 'rejected' && process.env.ZIDANE_DEBUG) {\n const cause = result.reason instanceof Error ? result.reason.message : String(result.reason)\n process.stderr.write(`[zidane/chat] failed to load session \"${ids[i]}\": ${cause}\\n`)\n }\n }\n return metas\n}\n\n/** Project a store header row to the picker's shape. */\nfunction metaFromRow(row: SessionMetaRow): SessionMeta {\n return {\n id: row.id,\n title: deriveSessionTitle(row.firstUserTurn ? [row.firstUserTurn] : [], row.metadata),\n turnCount: row.turnCount,\n userMessageCount: row.userMessageCount,\n runCount: row.runCount,\n ...(isMainSession(row.metadata) ? { isMain: true } : {}),\n ...(row.projectRoot ? { projectRoot: row.projectRoot } : {}),\n ...metaCwd(row.metadata),\n ...metaEnvironment(row.metadata),\n ...(typeof row.artifactCount === 'number' ? { artifactCount: row.artifactCount } : {}),\n updatedAt: row.updatedAt,\n }\n}\n\n/** Same projection from a fully materialized session (no header index). */\nfunction metaFromData(id: string, data: SessionData): SessionMeta {\n return {\n id,\n title: deriveSessionTitle(data.turns, data.metadata),\n turnCount: data.turns.length,\n userMessageCount: data.turns.reduce((n, t) => t.role === 'user' ? n + 1 : n, 0),\n runCount: data.runs.length,\n ...(isMainSession(data.metadata) ? { isMain: true } : {}),\n ...(data.projectRoot ? { projectRoot: data.projectRoot } : {}),\n ...metaCwd(data.metadata),\n ...metaEnvironment(data.metadata),\n updatedAt: data.updatedAt,\n }\n}\n\n/** The environment summary for list rows — omitted for local sessions (the common case). */\nexport function sessionEnvironmentSummary(metadata: Record<string, unknown> | undefined): SessionEnvironmentSummary | undefined {\n if (!metadata?.[ENVIRONMENT_METADATA_KEY])\n return undefined\n const environment = readSessionEnvironment(metadata)\n if (environment.kind === LOCAL_ENVIRONMENT.kind && environment.state === 'ready')\n return undefined\n return {\n kind: environment.kind,\n state: environment.state,\n ...(environment.branch ? { branch: environment.branch } : {}),\n ...(environment.error ? { error: environment.error } : {}),\n ...(environment.suspended ? { suspended: true } : {}),\n ...(environment.execCwd ? { workspaceRoot: environment.execCwd } : {}),\n }\n}\n\nfunction metaEnvironment(metadata: Record<string, unknown> | undefined): { environment?: SessionEnvironmentSummary } {\n const environment = sessionEnvironmentSummary(metadata)\n return environment ? { environment } : {}\n}\n\nfunction metaCwd(metadata: Record<string, unknown> | undefined): { cwd?: string } {\n const cwd = metadata?.cwd\n return typeof cwd === 'string' && cwd.length > 0 ? { cwd } : {}\n}\n\n/**\n * One session's `SessionMeta` BY ID — the by-id complement to\n * `listSessionMeta`.\n *\n * For rows a filtered list cannot return: the orchestration main is\n * directory-less, so no project-scoped query yields it, and re-listing the\n * whole store on every sessions refresh just to find that one row is O(store).\n * Uses the store's indexed header read when it has one; degrades to a full\n * load otherwise. `null` = no such session.\n */\nexport async function getSessionMeta(store: SessionStore, id: string): Promise<SessionMeta | null> {\n if (store.getMeta) {\n try {\n const row = await store.getMeta(id)\n return row ? metaFromRow(row) : null\n }\n catch (err) {\n if (process.env.ZIDANE_DEBUG) {\n const cause = err instanceof Error ? err.message : String(err)\n process.stderr.write(`[zidane/chat] store.getMeta failed, falling back to a full load: ${cause}\\n`)\n }\n }\n }\n const data = await store.load(id)\n return data ? metaFromData(id, data) : null\n}\n\n/** {@link SessionHeader} of a fully materialized session. */\nexport function headerFromData(data: SessionData): SessionHeader {\n return {\n ...metaFromData(data.id, data),\n ...(data.agentId ? { agentId: data.agentId } : {}),\n status: data.status,\n metadata: data.metadata,\n createdAt: data.createdAt,\n }\n}\n\n/**\n * One session's header, without reading its turns when the store keeps a\n * header index (`getMeta`). A full load when it doesn't, or when the title\n * still has to be derived from the first message.\n */\nexport async function getSessionHeader(store: SessionStore, id: string): Promise<SessionHeader | null> {\n const row = store.getMeta ? await store.getMeta(id).catch(() => null) : null\n const titled = typeof row?.metadata.title === 'string' && row.metadata.title.trim() !== ''\n if (row && row.status !== undefined && (titled || row.firstUserTurn !== undefined || row.userMessageCount === 0)) {\n return {\n ...metaFromRow(row),\n ...(row.agentId ? { agentId: row.agentId } : {}),\n status: row.status,\n metadata: row.metadata,\n ...(row.createdAt !== undefined ? { createdAt: row.createdAt } : {}),\n }\n }\n const data = await store.load(id)\n return data ? headerFromData({ ...data, id }) : null\n}\n\n/** Derive a short title from the first user message — returns null when empty. */\nexport function titleFromTurns(turns: SessionTurn[]): string | null {\n const first = turns.find(t => t.role === 'user')\n if (!first)\n return null\n for (const block of first.content) {\n if (block.type === 'text' && block.text.trim()) {\n const oneLine = block.text.replace(/\\s+/g, ' ').trim()\n return oneLine.length > 60 ? `${oneLine.slice(0, 60)}…` : oneLine\n }\n }\n return null\n}\n\n/**\n * Fallback title for a session with no stored `metadata.title` and no\n * turns to derive one from yet — i.e. a freshly created session. Shown\n * in the sessions list, chat header, and details modal until the first\n * message (or an explicitly generated title) gives it a real name.\n */\nexport const DEFAULT_SESSION_TITLE = 'New session'\n\n/**\n * Display title for a session — preferred sources, in order:\n *\n * 1. `metadata.title` if it's a non-empty string (typically set by\n * the session-details modal's \"generate title\" action).\n * 2. {@link titleFromTurns} — the first user message, one-line + clipped.\n * 3. {@link DEFAULT_SESSION_TITLE} (`'New session'`).\n *\n * Total / pure / defensive on non-string metadata values.\n */\nexport function deriveSessionTitle(\n turns: SessionTurn[],\n metadata?: Record<string, unknown>,\n): string {\n const stored = typeof metadata?.title === 'string' ? metadata.title.trim() : ''\n if (stored.length > 0)\n return stored\n return titleFromTurns(turns) ?? DEFAULT_SESSION_TITLE\n}\n\n/**\n * Replay persisted turns as a viewable transcript. Mirrors the event shape\n * produced live by the agent hooks so loaded and streaming history render\n * identically — including subagent ancestry when `runs` is supplied.\n *\n * Subagent reconstruction:\n * - Every turn carries a `runId`. We look that up in `runs` to get the\n * run's `depth` and tag the resulting events with `{ depth, childId }`\n * — the same shape the live `child:*` bubble hooks produce.\n * - We synthesize `spawn-start` / `spawn-end` markers at each child-run\n * boundary so the transcript reads the same as a live run did\n * (`🌱 [run-id] task` … child events … `🌳 [run-id] done · tokens`).\n * - For child runs (`depth > 0`), the user-role \"task\" text is suppressed\n * because `spawn-start` already shows it.\n *\n * Without `runs` (legacy callers / tests), the function falls back to the\n * old behavior: depth-0 events with no subagent grouping.\n */\n/**\n * Map a `compact-summary` content block to its `compact-summary` StreamEvent —\n * the single source of truth for the compaction boundary card. Used by\n * {@link eventsFromTurns} (reload / TUI live repaint) AND by chat hosts that\n * surface the boundary live without a full reload (the GUI broadcasts this\n * from the loop's `compact:end` hook), so the live card and the reloaded card\n * are byte-identical regardless of who created the marker (manual, the old\n * host trigger, or loop-native auto-compaction — all share this block shape).\n */\nexport function compactSummaryEvent(\n block: Extract<SessionContentBlock, { type: 'compact-summary' }>,\n turnId?: string,\n): StreamEvent {\n return {\n kind: 'compact-summary',\n text: block.summary,\n compact: {\n replacedCount: block.replacesTurnIds.length,\n model: block.model,\n compactedAt: block.compactedAt,\n inputTokens: block.usage.input ?? 0,\n outputTokens: block.usage.output ?? 0,\n cacheReadTokens: block.usage.cacheRead ?? 0,\n cacheCreationTokens: block.usage.cacheCreation ?? 0,\n ...(typeof block.usage.cost === 'number' && block.usage.cost > 0 ? { costUsd: block.usage.cost } : {}),\n },\n ...(turnId ? { turnId } : {}),\n }\n}\n\n/**\n * Decoded byte size of a base64 payload, computed arithmetically.\n * `Buffer.from(data, 'base64').length` decodes the whole attachment —\n * a full allocation per media block on EVERY `eventsFromTurns` replay\n * (session load/switch/export/search) just to label a chip with a size.\n */\nfunction base64DecodedSize(data: string): number {\n const padding = data.endsWith('==') ? 2 : data.endsWith('=') ? 1 : 0\n return Math.floor(data.length * 3 / 4) - padding\n}\n\n/** Severity values a persisted notice may carry. Anything else is ignored. */\nconst NOTICE_SEVERITIES = new Set(['info', 'warn', 'error'])\n\n/** A persisted notice, plus the origin the live event carried. */\ninterface PersistedNotice {\n notice: NonNullable<StreamEvent['notice']>\n /** Subagent that produced it, when the live event named one. */\n childId?: string\n /** Indent depth the live event rendered at. */\n depth?: number\n}\n\n/**\n * Read a persisted `metadata.command.notice` back into the event shape, or\n * `null` when the block is an ordinary command detail. Defensive because the\n * value round-tripped through JSON written by a possibly older build.\n */\nfunction readNoticeMeta(value: unknown): PersistedNotice | null {\n if (!value || typeof value !== 'object' || Array.isArray(value))\n return null\n const { severity, label, childId, depth } = value as {\n severity?: unknown\n label?: unknown\n childId?: unknown\n depth?: unknown\n }\n if (typeof severity !== 'string' || !NOTICE_SEVERITIES.has(severity))\n return null\n if (typeof label !== 'string' || label === '')\n return null\n return {\n notice: { severity: severity as NonNullable<StreamEvent['notice']>['severity'], label },\n ...(typeof childId === 'string' && childId !== '' ? { childId } : {}),\n ...(typeof depth === 'number' && Number.isFinite(depth) && depth >= 0 ? { depth: Math.floor(depth) } : {}),\n }\n}\n\n/** The notice a command block carries, or `null` for an ordinary detail block. */\nfunction noticeFromBlock(block: SessionTurn['content'][number]): PersistedNotice | null {\n if (block.type !== 'tool_result')\n return null\n const meta = block.metadata?.command\n if (!meta || typeof meta !== 'object' || Array.isArray(meta))\n return null\n return readNoticeMeta((meta as Record<string, unknown>).notice)\n}\n\n/**\n * Persisted form of a harness notice: a display-only `role: 'command'` turn,\n * which is the existing carrier for content that must survive a reload without\n * ever reaching the model.\n *\n * Pairs with the `readNoticeMeta` branch in {@link eventsFromTurns}. Callers\n * pre-mint `turnId` and emit the live event with the same id so the live row\n * and the reloaded row are the same row.\n *\n * `origin` carries the live event's `childId` / `depth`. A subagent notice is\n * persisted by the PARENT's depth-0 run, so without it the run-derived tag in\n * `eventsFromTurns` would reload the row un-indented and unattributed.\n */\nexport function noticeTurnContent(\n notice: NonNullable<StreamEvent['notice']>,\n text: string,\n origin: { childId?: string, depth?: number } = {},\n): SessionTurn['content'] {\n return [{\n type: 'tool_result' as const,\n callId: `notice_${crypto.randomUUID()}`,\n output: text,\n metadata: {\n command: {\n notice: {\n severity: notice.severity,\n label: notice.label,\n ...(origin.childId ? { childId: origin.childId } : {}),\n ...(origin.depth !== undefined ? { depth: origin.depth } : {}),\n },\n },\n },\n }]\n}\n\n/** The tag every event of one turn carries: its `turnId`, plus its subagent lane when nested. */\ninterface ReplayTag { turnId: string, childId?: string, depth?: number }\n\n/** What the per-turn replay reads and advances, turn after turn. */\ninterface ReplayState {\n events: StreamEvent[]\n runById: ReadonlyMap<string, SessionRun>\n toolByCallId: ReadonlyMap<string, string>\n resultByCallId: ReadonlyMap<string, string>\n /** True iff anything has been emitted at the active depth-0 level. Used to decide separators between top-level turns. */\n lastDepthAtEmission: number\n // The running `/` command's invocation (`/commit args`) until the next typed prompt.\n commandInvocation: string | null\n}\n\n/** Attachment chips for a typed prompt, reconstructed from the turn's sibling blocks. */\nfunction promptAttachments(turn: SessionTurn, block: SessionContentBlock): { name: string, mediaType: string, size: number }[] {\n // Reconstruct attachment metadata from sibling content\n // blocks so the transcript shows chips after session reload.\n const attachments: { name: string, mediaType: string, size: number }[] = []\n for (const sibling of turn.content) {\n if (sibling.type === 'image' || sibling.type === 'audio' || sibling.type === 'video') {\n attachments.push({\n name: sibling.name ?? sibling.type,\n mediaType: sibling.mediaType,\n size: typeof sibling.data === 'string'\n ? base64DecodedSize(sibling.data)\n : 0,\n })\n }\n else if (sibling.type === 'document') {\n // Documents are structured blocks, not <attachment>-tagged\n // text — surface their own chip. Covers base64 (e.g. a PDF\n // prompt) AND text encoding (the shape `paste.txt` /\n // dragged-text-file attachments persist as); text-encoded\n // ones were previously dropped from the reloaded transcript.\n attachments.push({\n name: sibling.name ?? 'document',\n mediaType: sibling.mediaType,\n size: typeof sibling.data !== 'string'\n ? 0\n : sibling.encoding === 'text'\n ? Buffer.byteLength(sibling.data)\n : base64DecodedSize(sibling.data),\n })\n }\n else if (sibling !== block && sibling.type === 'text') {\n const m = sibling.text.match(/^<attachment\\s+(?:name=\"([^\"]+)\"\\s*)?(?:media_type=\"([^\"]+)\")?/)\n if (m) {\n attachments.push({\n name: m[1] ?? 'attachment',\n mediaType: m[2] ?? 'text/plain',\n size: sibling.text.length,\n })\n }\n }\n }\n return attachments\n}\n\n/** Replay one non-blank text block of a user turn. */\nfunction replayUserText(\n state: ReplayState,\n turn: SessionTurn,\n block: Extract<SessionContentBlock, { type: 'text' }>,\n depth: number,\n tag: ReplayTag,\n marker: { emitted: boolean },\n): void {\n const { events } = state\n // Background-task completion notifications ride as text\n // blocks carrying `<task-notification>` XML (the format\n // `renderTaskNotificationXml` produces). Detect and emit\n // them as their own structured event so the TUI can render\n // a banner — and IMPORTANT: DON'T also emit a `user-prompt`\n // event for the same text, otherwise the raw XML would\n // double-paint alongside the banner. Same dedupe pattern\n // the compact-summary path uses.\n // Pass the FULL tag (turnId + optional childId/depth) so a\n // subagent's task notification renders under the right\n // `child-N` lane instead of bleeding up to depth 0.\n const taskEvent = parseTaskNotificationBlock(block.text, tag)\n if (taskEvent) {\n events.push(taskEvent)\n return\n }\n\n // Cross-session event delivered to a main session. Same dedupe\n // rule as the task notification above: emit the structured row,\n // and DON'T also emit the `user-prompt` echo of the same text —\n // the model-facing `<session-event>` block is not a user message\n // and must not paint as one.\n const sessionEvent = parseSessionEventXml(block.text)\n if (sessionEvent) {\n events.push({ kind: 'session-event', text: sessionEvent.summary, sessionEvent, ...tag })\n return\n }\n\n // For child runs the \"user\" text is the spawn task itself, already\n // rendered as the `spawn-start` marker above. Drop the duplicate.\n //\n // `user-prompt` carries the **raw** text; the renderer prepends the\n // `❯ ` chevron. No prefix in the payload means `refs` offsets stay\n // raw (no shift), and consumers building user-message indices or\n // history can read `event.text` directly.\n if (depth === 0) {\n // Inside a `/` command nothing opens a new exchange: the prompt\n // a command sub-run was given is a step of the command's work\n // (label = its short `display`, body = the full prompt), and a\n // note the command left for the model (`turn.display`, no run)\n // is its receipt line, or nothing for a model-only note (`''`).\n // Same shapes the live hosts emit.\n const commandOrigin = turn.runId ? state.runById.get(turn.runId)?.origin : undefined\n if (commandOrigin?.kind === 'command') {\n events.push({\n kind: 'command-detail',\n label: commandOrigin.display ? commandStepLabel(commandOrigin.display) : 'prompt',\n text: block.text,\n ...tag,\n })\n return\n }\n if (turn.display !== undefined && !turn.runId) {\n if (!marker.emitted && turn.display !== '')\n events.push({ kind: 'command-note', text: commandNoteText(turn.display, block.text, state.commandInvocation ?? undefined), ...tag })\n marker.emitted = true\n return\n }\n state.commandInvocation = null\n\n // Separator BEFORE the user prompt — matches the live\n // behavior, which only appends a separator when committing a\n // new prompt. The\n // previous \"fire on every depth-0 turn pair\" rule was too\n // aggressive: it inserted a separator between every\n // mid-exchange assistant tool turn and its paired\n // user-side tool_result turn, producing a 2-row gap\n // between consecutive `todowrite` calls in the replayed\n // transcript that's absent during the live cascade.\n if (state.lastDepthAtEmission === 0)\n events.push({ kind: 'separator', text: '' })\n\n const attachments = promptAttachments(turn, block)\n\n // Mentions typed through a completion are not persisted: recover the file chips from the text.\n const refs = inferPromptRefs(block.text)\n events.push({\n kind: 'user-prompt',\n text: block.text,\n turnId: turn.id,\n ...(refs.length > 0 ? { refs } : {}),\n ...(attachments.length > 0 ? { attachments } : {}),\n })\n }\n}\n\n/** Replay a user turn: typed prompts, notifications, tool results, compaction markers. */\nfunction replayUserTurn(state: ReplayState, turn: SessionTurn, depth: number, tag: ReplayTag): void {\n const { events } = state\n // A display-marker turn (command sub-run prompt, or a context note)\n // emits its `❯ marker` echo ONCE, even across multiple text blocks.\n const marker = { emitted: false }\n const attachmentOnly = !turn.content.some(block => block.type === 'text' && block.text.trim())\n && turn.content.some(block => ['document', 'image', 'audio', 'video'].includes(block.type))\n const displayContent: SessionContentBlock[] = attachmentOnly\n ? [{ type: 'text', text: '[Attachment]' }, ...turn.content]\n : turn.content\n for (const block of displayContent) {\n if (block.type === 'text' && block.text.trim()) {\n replayUserText(state, turn, block, depth, tag, marker)\n }\n else if (block.type === 'tool_result') {\n const tool = state.toolByCallId.get(block.callId)\n // Spawn tool-results duplicate the spawn-end marker's `Tokens: …`\n // line — and on pre-fix sessions the legacy \"N in / M out\" shape\n // disagrees with the cache-aware spawn-end. Strip it at the\n // display layer; the persisted output stays intact.\n const raw = toolResultText(block.output)\n const text = tool === 'spawn' ? stripSpawnTokensLine(raw) : raw\n events.push({\n kind: 'tool-result',\n text,\n ...(tool ? { tool } : {}),\n callId: block.callId,\n // Same error bit as the live event, so a resync doesn't flip a failed call to ok.\n ...(block.isError ? { isError: true as const } : {}),\n ...tag,\n })\n }\n else if (block.type === 'compact-summary') {\n // Compaction boundary — single event per marker block, via the\n // shared `compactSummaryEvent` mapper so the reloaded card matches\n // the live one byte-for-byte. The renderer reads `compact` for the\n // metadata badge; `text` carries the summary (the TUI keeps it\n // hidden by default so it doesn't read like new dialogue). Subagents\n // never produce these markers (compaction targets the top-level\n // conversation), so the ancestry tag isn't threaded — but `turnId`\n // is, so select-turn mode still highlights.\n events.push(compactSummaryEvent(block, turn.id))\n }\n }\n}\n\n/** The event a command turn's `tool_result` block replays as: a harness notice, a custom render, or a detail. */\nfunction commandToolResultEvent(block: Extract<SessionContentBlock, { type: 'tool_result' }>, tag: ReplayTag): StreamEvent {\n const meta = block.metadata?.command\n const commandMeta = (meta && typeof meta === 'object' && !Array.isArray(meta))\n ? meta as Record<string, unknown>\n : undefined\n // Harness notice (model fallback, repeat-guard trip, run error).\n // Replayed into the same `info` / `error` event the live path\n // emits, so a reopened conversation shows the identical row in\n // the same place instead of losing every harness event.\n const persistedNotice = readNoticeMeta(commandMeta?.notice)\n if (persistedNotice) {\n return {\n kind: persistedNotice.notice.severity === 'error' ? 'error' : 'info',\n text: toolResultText(block.output),\n notice: persistedNotice.notice,\n ...tag,\n // Origin wins over the run-derived tag: a subagent notice is\n // persisted by the parent's depth-0 run, so the tag alone would\n // reload it flat instead of indented under its child.\n ...(persistedNotice.childId ? { childId: persistedNotice.childId } : {}),\n ...(persistedNotice.depth !== undefined ? { depth: persistedNotice.depth } : {}),\n }\n }\n // Custom-rendered block: re-bind the renderer id + data; the\n // persisted output is the fallback (see commandBlocksToContent).\n const customMeta = commandMeta?.custom\n if (customMeta && typeof customMeta === 'object' && !Array.isArray(customMeta)\n && typeof (customMeta as { renderer?: unknown }).renderer === 'string') {\n // Persisted metadata is JsonValue by construction (see\n // commandBlocksToContent) — the cast re-narrows what JSON\n // round-tripping already guarantees.\n const bound = customMeta as { renderer: string, data?: JsonValue }\n return {\n kind: 'custom',\n text: toolResultText(block.output),\n custom: { renderer: bound.renderer, ...(bound.data !== undefined ? { data: bound.data } : {}) },\n ...tag,\n }\n }\n const label = typeof commandMeta?.label === 'string' ? commandMeta.label : undefined\n return {\n kind: 'command-detail',\n text: toolResultText(block.output),\n ...(label ? { label } : {}),\n ...(commandMeta?.syntax === 'diff' ? { syntax: 'diff' as const } : {}),\n ...tag,\n }\n}\n\n/** Replay a display-only `role: 'command'` turn. */\nfunction replayCommandTurn(state: ReplayState, turn: SessionTurn, tag: ReplayTag): void {\n const { events } = state\n // Display-only local output from a `/` command (never sent to the\n // model). Delimit from the prior exchange, then replay each block in\n // the same shape the live `emit()` path appends, so reloaded and live\n // command output look identical: plain text → full markdown;\n // `tool_result` blocks (detail output — diffs, logs) → a\n // `command-detail` event: dim label + line-capped body.\n //\n // Notice turns are exempt from the delimiter: live they are appended\n // straight into the running transcript with no separator, and\n // `marginTopFor` collapses consecutive ones into a single block. Pushing\n // one here would reload a burst of harness events as a double-spaced\n // ladder, and put a break mid-exchange that never existed live.\n //\n // The invocation header (`` `❯ /commit` ``, the first block of a\n // command's first turn) replays as the user's prompt; the command's\n // later turns continue that exchange, so they open no new one.\n const noticeOnly = turn.content.length > 0 && turn.content.every(block => noticeFromBlock(block) !== null)\n const first = turn.content[0]\n const invocation = first?.type === 'text' ? parseCommandHeader(first.text) : null\n if (invocation !== null)\n state.commandInvocation = invocation\n if (state.lastDepthAtEmission === 0 && !noticeOnly && (invocation !== null || state.commandInvocation === null))\n events.push({ kind: 'separator', text: '' })\n for (const block of turn.content) {\n if (invocation !== null && block === first) {\n events.push({ kind: 'user-prompt', text: invocation, synthetic: true, turnId: turn.id })\n }\n else if (block.type === 'text' && block.text.trim()) {\n events.push({ kind: 'markdown', text: block.text, streaming: false, ...tag })\n }\n else if (block.type === 'tool_result') {\n events.push(commandToolResultEvent(block, tag))\n }\n }\n}\n\n/** The `tool` event an assistant `tool_call` block replays as. */\nfunction toolCallEvent(\n block: Extract<SessionContentBlock, { type: 'tool_call' }>,\n resultByCallId: ReadonlyMap<string, string>,\n tag: ReplayTag,\n): StreamEvent {\n // Stable-tools dispatch persists the `call_tool { name, arguments }`\n // envelope (wire-valid history), but the LIVE `tool:before` hook\n // fired on the unwrapped inner call. Unwrap here too so a reloaded\n // transcript shows \"Coolify projects\" with its real arguments, not\n // \"Call tool\" — byte-for-byte the same event the live run emitted.\n const inner = unwrapCallTool(block.name, block.input)\n const { name, input } = inner ?? block\n // Historical replay has no pre-write snapshot for `write_file`\n // (the captured priorContent only exists at live-hook time).\n // `extractEditPayload` falls back to `oldString: ''` so the\n // diff renders as an all-add view — matches git's \"new file\"\n // convention and is the most honest reconstruction available.\n let edit = extractEditPayload(name, input)\n if (edit) {\n // Attach per-edit outcomes parsed out of the paired tool_result\n // body so a replayed transcript shows the same applied / denied\n // / skipped badges the live run displayed. Falls through when\n // the body is unstructured (legacy results, error preamble) —\n // the renderer treats absent outcomes as \"all applied\".\n const resultText = resultByCallId.get(block.id)\n if (resultText) {\n const outcomes = parseEditOutcomesFromResult(resultText)\n if (outcomes && outcomes.length === edit.hunks.length)\n edit = { ...edit, outcomes }\n }\n }\n return {\n kind: 'tool',\n text: toolCallPreview(name, input),\n tool: name,\n input,\n ...(edit ? { edit } : {}),\n callId: block.id,\n ...tag,\n }\n}\n\n/** Replay an assistant turn: text, reasoning, tool calls, server-tool blocks. */\nfunction replayAssistantTurn(state: ReplayState, turn: SessionTurn, tag: ReplayTag): void {\n const { events } = state\n for (const block of turn.content) {\n if (block.type === 'text' && block.text.trim()) {\n // Persisted turns are finalized — `streaming: false` so the markdown\n // renderer commits to the final layout (no heal pass needed).\n events.push({ kind: 'markdown', text: block.text, streaming: false, ...tag })\n }\n else if (block.type === 'thinking' && block.text.trim()) {\n // Reasoning is persisted as part of the assistant content (the\n // provider needs it echoed back), so replay it the same way the\n // live `stream:thinking` hook does: one event per line. The TUI\n // renderer gives consecutive thinking rows a fixed icon gutter so\n // replayed and streamed reasoning look identical. Without this,\n // reloading a session drops every trace.\n //\n // Blank lines are SKIPPED: a paragraph break inside one thinking\n // block would otherwise replay as an empty thinking event — a\n // bare icon row with no text, one per paragraph, in every\n // renderer (the GUI's \"double icon\" artifact).\n for (const line of block.text.split('\\n')) {\n if (line.trim())\n events.push({ kind: 'thinking', text: line, ...tag })\n }\n }\n else if (block.type === 'tool_call') {\n events.push(toolCallEvent(block, state.resultByCallId, tag))\n }\n else if (block.type === 'server_tool_use') {\n // Native server-tool invocation (Anthropic `web_search`). Live runs\n // emit the same shape from `stream:server_tool_use`; replay this\n // way so the transcript looks identical on reload.\n events.push({\n kind: 'tool',\n text: toolCallPreview(block.name, block.input),\n tool: block.name,\n input: block.input,\n callId: block.id,\n ...tag,\n })\n }\n else if (block.type === 'server_tool_result') {\n events.push({\n kind: 'tool-result',\n text: serverToolResultSummary(block.content),\n tool: block.toolName,\n callId: block.toolUseId,\n ...tag,\n })\n }\n }\n}\n\nexport function eventsFromTurns(\n turns: SessionTurn[],\n runs: readonly SessionRun[] = [],\n): StreamEvent[] {\n return replayTurns(turns, runs).events\n}\n\n/**\n * The whole replay, and where each turn's events start in it\n * (`turnStarts[turns.length]` = the end). A page of turns `[from, to)` is\n * `events.slice(turnStarts[from], turnStarts[to])`: consecutive pages\n * concatenate to exactly {@link eventsFromTurns} (exchange separators, run\n * receipts, subagent markers, tool names and command state as the whole\n * replay has them), because what a run or the turn before decides lands in\n * the page of the turn whose replay emitted it.\n */\nexport function replayTurns(\n turns: SessionTurn[],\n runs: readonly SessionRun[],\n): { events: StreamEvent[], turnStarts: number[] } {\n const runById = indexReplayRuns(turns, runs)\n const labelFor = childLabeler(runById)\n const toolByCallId = toolNamesByCallId(turns)\n const resultByCallId = resultTextsByCallId(turns)\n const ancestryOf = runAncestry(runById)\n const subtreeTotals = runSubtreeTotals(runById)\n const spawnerOf = spawnerLabeler(runById, labelFor)\n\n // Index of the last turn in each child run's subtree (its own turns and\n // its descendants'). Concurrent siblings interleave their turns, so\n // \"the run changed\" is no boundary: a run's `spawn-end` lands once, after\n // this turn, and its `spawn-start` once, at its first turn. Diffing an\n // open-run stack per turn instead closed and reopened siblings at every\n // switch — one \"Finished\" marker (all carrying the final totals) per switch.\n const chainByTurn = turns.map(turn => ancestryOf(turn.runId))\n const lastSubtreeTurn = new Map<string, number>()\n chainByTurn.forEach((chain, idx) => {\n for (const run of chain)\n lastSubtreeTurn.set(run.id, idx)\n })\n\n const events: StreamEvent[] = []\n /** Child runs whose `spawn-start` has been emitted. */\n const startedRuns = new Set<string>()\n /** Started runs still awaiting their `spawn-end`, in open order. */\n const openRuns: SessionRun[] = []\n const state: ReplayState = { events, runById, toolByCallId, resultByCallId, lastDepthAtEmission: -1, commandInvocation: null }\n\n const pushSpawnEnd = (run: SessionRun) => {\n events.push(spawnEndEvent(run, subtreeTotals(run), labelFor, spawnerOf(run)))\n }\n\n const pushSpawnStart = (run: SessionRun) => {\n events.push(spawnStartEvent(run, labelFor, spawnerOf(run)))\n }\n\n /**\n * Emit `spawn-end` for every open run whose subtree ended before turn\n * `beforeTurn` — innermost (most recently opened) first, so a depth ≥ 2\n * chain closes child before parent. Lands right before the next turn's\n * events, where the stack diff used to put it.\n */\n const closeFinishedRuns = (beforeTurn: number) => {\n for (let k = openRuns.length - 1; k >= 0; k--) {\n const run = openRuns[k]\n // Still running (a window reloaded mid-run): no \"finished\" marker, its\n // live events keep landing in an open box. Loads demote runs that died\n // with their process to `aborted` first (`demoteStaleRunningStatus`).\n if (run.status === 'running')\n continue\n if ((lastSubtreeTurn.get(run.id) ?? -1) < beforeTurn) {\n openRuns.splice(k, 1)\n pushSpawnEnd(run)\n }\n }\n }\n\n const turnStarts: number[] = []\n for (let i = 0; i < turns.length; i++) {\n turnStarts.push(events.length)\n const turn = turns[i]\n const targetChain = chainByTurn[i]\n const depth = targetChain.length // 0 for top-level, otherwise innermost depth\n\n closeFinishedRuns(i)\n // Open every not-yet-started run in the chain, outermost first.\n for (const run of targetChain) {\n if (startedRuns.has(run.id))\n continue\n startedRuns.add(run.id)\n openRuns.push(run)\n pushSpawnStart(run)\n }\n\n const subagentTag = depth > 0 && turn.runId ? { childId: labelFor(turn.runId), depth } : undefined\n // `turnId` tags every event so the TUI's select-turn mode can highlight\n // all events emitted by a single SessionTurn. Subagent ancestry stays in\n // a separate object so the spread order keeps existing tag overrides\n // (childId/depth) wins-last semantics intact.\n const tag = { turnId: turn.id, ...subagentTag }\n\n if (turn.role === 'user') {\n replayUserTurn(state, turn, depth, tag)\n state.lastDepthAtEmission = depth\n continue\n }\n\n if (turn.role === 'command') {\n replayCommandTurn(state, turn, tag)\n state.lastDepthAtEmission = depth\n continue\n }\n\n if (turn.role === 'assistant') {\n replayAssistantTurn(state, turn, tag)\n state.lastDepthAtEmission = depth\n }\n }\n\n // Drain any trailing open child runs (e.g. session ended mid-spawn). Pop\n // innermost-first so depth ≥ 2 chains emit `spawn-end` in the right order.\n closeFinishedRuns(turns.length)\n turnStarts.push(events.length)\n\n // A receipt lands after its run's last event: every turn starting at or past it moves down.\n for (const { at, count } of insertRunReceipts(events, turns, runs)) {\n for (let k = 0; k < turnStarts.length; k++) {\n if (turnStarts[k]! >= at)\n turnStarts[k]! += count\n }\n }\n\n return { events, turnStarts }\n}\n\n/** Shared formatter for the `↳ name(args)` line shown on tool calls. */\n/**\n * Pattern matching the leading `<task-notification>` shape that the\n * agent's notification-injection path produces (see\n * `renderTaskNotificationXml` in `src/agent.ts`). Anchored so a stray\n * notification-shaped phrase mid-prompt doesn't trigger a false-positive\n * detection — the model's wire format always starts the user-turn\n * content block with this exact opening tag.\n */\nconst TASK_NOTIFICATION_RE = /^\\s*<task-notification>([\\s\\S]*?)<\\/task-notification>\\s*$/\n\n/**\n * Per-field extractors. Compiled once at module load (parsing happens\n * on every session replay, and a fresh `new RegExp` per pick burns\n * cycles for no reason).\n */\nconst TASK_NOTIFICATION_FIELD_RES = {\n taskId: /<task-id>([\\s\\S]*?)<\\/task-id>/,\n status: /<status>([\\s\\S]*?)<\\/status>/,\n exitCode: /<exit-code>([\\s\\S]*?)<\\/exit-code>/,\n command: /<command>([\\s\\S]*?)<\\/command>/,\n outputFile: /<output-file>([\\s\\S]*?)<\\/output-file>/,\n durationMs: /<duration-ms>([\\s\\S]*?)<\\/duration-ms>/,\n summary: /<summary>([\\s\\S]*?)<\\/summary>/,\n} as const\n\n/**\n * Detect a `<task-notification>` text block on replay and convert it\n * into a structured `task-notification` StreamEvent so the TUI's banner\n * renderer can paint it cleanly. Returns `null` when the block isn't a\n * notification (the caller falls back to the normal user-prompt path).\n *\n * Reads every field DIRECTLY from its tag — does NOT parse `<summary>`\n * for the underlying data. The summary is a derived display string,\n * not a source of truth: changing its format (localization, signal in\n * the label, whatever) must NEVER break replay. Each field falls back\n * to a safe default so older transcripts pre-dating a tag addition\n * still render.\n */\nfunction parseTaskNotificationBlock(\n text: string,\n tag: { turnId: string, childId?: string, depth?: number },\n): StreamEvent | null {\n const m = text.match(TASK_NOTIFICATION_RE)\n if (!m)\n return null\n\n const body = m[1]\n const pick = (re: RegExp): string | undefined => {\n const inner = body.match(re)\n return inner ? unescapeXml(inner[1].trim()) : undefined\n }\n\n const taskId = pick(TASK_NOTIFICATION_FIELD_RES.taskId) ?? '?'\n const statusRaw = pick(TASK_NOTIFICATION_FIELD_RES.status) ?? 'exited'\n const status: 'exited' | 'killed' = statusRaw === 'killed' ? 'killed' : 'exited'\n const exitCode = Number.parseInt(pick(TASK_NOTIFICATION_FIELD_RES.exitCode) ?? '0', 10) || 0\n const command = pick(TASK_NOTIFICATION_FIELD_RES.command) ?? ''\n const outputPath = pick(TASK_NOTIFICATION_FIELD_RES.outputFile) ?? ''\n const durationMs = Number.parseInt(pick(TASK_NOTIFICATION_FIELD_RES.durationMs) ?? '0', 10) || 0\n const summary = pick(TASK_NOTIFICATION_FIELD_RES.summary)\n ?? `${taskId} ${statusRaw}${exitCode ? ` ${exitCode}` : ''}`\n\n return {\n kind: 'task-notification',\n text: summary,\n task: { taskId, status, exitCode, outputPath, command, durationMs },\n turnId: tag.turnId,\n ...(tag.childId !== undefined ? { childId: tag.childId } : {}),\n ...(tag.depth !== undefined ? { depth: tag.depth } : {}),\n }\n}\n\n/**\n * Reverse of `escapeXml` for the small set of entities the writer\n * emits. Not a full HTML entity decoder — just enough to round-trip\n * `<` / `>` / `&` / quotes through persistence.\n *\n * `&amp;` MUST be replaced last, otherwise `&amp;lt;` becomes `&lt;`\n * then `<` (data corruption — silent double-decode).\n */\nfunction unescapeXml(s: string): string {\n return s\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&quot;/g, '\"')\n .replace(/&apos;/g, '\\'')\n .replace(/&amp;/g, '&')\n}\n\nexport function toolCallPreview(name: string, input: Record<string, unknown>): string {\n const args = JSON.stringify(input)\n return args && args !== '{}' ? `${name}(${args})` : name\n}\n\n/**\n * One-line display summary for a server-tool-result block (currently only\n * Anthropic's `web_search_tool_result`). `content` is either an error object\n * (`{ error_code: '...' }`) or an array of result entries — we count the\n * latter and surface the code for the former. Kept terse on purpose; richer\n * formatting (titles + URLs per hit) is a separate UI pass.\n *\n * Falls back to `(opaque result)` for unrecognized shapes rather than an\n * empty string — an empty `text` field would render as a blank row in the\n * transcript with no signal that anything happened.\n */\nexport function serverToolResultSummary(content: unknown): string {\n if (Array.isArray(content)) {\n const n = content.length\n return n === 1 ? '1 result' : `${n} results`\n }\n if (content && typeof content === 'object') {\n const code = (content as { error_code?: unknown }).error_code\n if (typeof code === 'string')\n return `error: ${code}`\n }\n return '(opaque result)'\n}\n\n/**\n * Update the trailing `'tool'` event matching `callId` so its\n * `edit.outcomes` reflects the canonical merged outcomes the chat\n * layer's `tool:transform` hook just computed. Without this, the live\n * diff badges stay frozen at whatever the gate set (approval-side\n * outcomes) and never reflect body-side failures from `multi_edit`'s\n * best-effort run — only a session reload re-attaches the merged\n * outcomes via {@link eventsFromTurns}.\n *\n * Walks back-to-front because the matching event is overwhelmingly the\n * most recent (we're updating right after the body returned). Returns\n * the same reference when no match is found (or the event already\n * carries the target outcomes), so React skips the re-render.\n */\nexport function updateToolEventOutcomes(\n events: readonly StreamEvent[],\n callId: string,\n outcomes: readonly EditOutcome[],\n): StreamEvent[] {\n for (let i = events.length - 1; i >= 0; i--) {\n const e = events[i]\n if (e.kind !== 'tool' || e.callId !== callId || !e.edit)\n continue\n if (e.edit.outcomes === outcomes)\n return events as StreamEvent[]\n const next = events.slice()\n next[i] = { ...e, edit: { ...e.edit, outcomes } }\n return next\n }\n return events as StreamEvent[]\n}\n\n/** Render tool output as plain text, whether it's a string or structured content. */\nexport function toolResultText(output: string | ToolResultContent[]): string {\n return typeof output === 'string' ? output : toolResultToText(output)\n}\n\n/**\n * Strip the `Tokens: …` line from a spawn tool-result. The spawn-end marker\n * displayed right above already shows the same stats; keeping the line in the\n * rendered tool-result body just produces a visible duplicate (and, on\n * reloaded pre-fix sessions, an *inconsistent* duplicate — the persisted line\n * uses the old `13 in / 4075 out` shape while the freshly synthesized\n * spawn-end uses the cache-aware `in 92615 (cache 92602) / 4075 out` shape).\n *\n * Display-only: the persisted tool_result content is untouched, so the LLM\n * still sees the full string in its context window. Anchored to start-of-line\n * and matches both `Tokens: 13 in / 4075 out` (legacy) and `Tokens: in 13 …`\n * (post-`formatTokenUsage`) shapes.\n */\nexport function stripSpawnTokensLine(text: string): string {\n // Strict: only strip when the `Tokens: …` line is **immediately preceded\n // by** the spawn-tool header (`[sub-agent <id>] (Completed|Aborted|Failed|Timed) …`).\n // The previous `^Tokens:` multi-line regex would eat any body line that\n // happened to start with `Tokens:` — e.g. a model summarizing\n // \"Tokens: …\" inside its response. Anchored matching keeps the strip\n // local to the spawn header even if the model's response continues with\n // arbitrary content.\n //\n // `m` + `g` so every header in a multi-spawn result is handled, not just\n // the one at index 0. Today every spawn tool-result is single-spawn so\n // `g` is a no-op; the multiline anchor lets a future feature concatenating\n // multiple spawn outputs into one body strip every header's tokens line.\n return text.replace(\n /(^\\[sub-agent [^\\n]+\\n)Tokens:[^\\n]*\\n?/gm,\n '$1',\n )\n}\n\n// ---------------------------------------------------------------------------\n// Transcript visibility + select-turn navigation now live in the node-free\n// `./turn-selection` leaf so a browser-context renderer can import them via\n// `zidane/chat/pure`. Re-exported here (and through `zidane/tui`) so existing\n// `zidane/chat` consumers keep their import paths.\n// ---------------------------------------------------------------------------\nexport {\n BASH_CALL_ID_PREFIX,\n CACHE_NOTICE_LABEL,\n EDIT_TOOL_NAMES,\n isEditErrorResult,\n isTurnHighlighted,\n isUserBashEvent,\n isVisible,\n isVisibleDuringSearch,\n messageSelectionOwnership,\n promptHistoryFromEvents,\n retagUserPromptEvents,\n selectableTurnIds,\n selectionAfterTurnRemoval,\n streamEventSearchText,\n turnSelectionOwnership,\n} from './turn-selection'\n\n/**\n * Default top-margin per kind (in rows). Spacing intent:\n * - `info` / `markdown` / `tool` / `error` / `spawn-start` open a new\n * block, so they each get one row of breathing room above.\n * - `thinking` / `tool-result` / `spawn-end` continue the previous\n * block and stay flush.\n *\n * Context-aware overrides live in {@link marginTopFor}.\n */\nconst MARGIN_TOP: Record<StreamEvent['kind'], number> = {\n 'separator': 0,\n 'user-prompt': 1,\n 'info': 1,\n // A reasoning run opens with breathing room (like a markdown block); the\n // run's continuation lines collapse to 0 via the rule in `marginTopFor`.\n 'thinking': 1,\n 'tool': 1,\n 'tool-result': 0,\n // Command details open a labeled block of their own (like a tool call\n // line does), so they get the same one-row gap above.\n 'command-detail': 1,\n 'error': 1,\n 'markdown': 1,\n 'spawn-start': 1,\n 'spawn-end': 0,\n // Draws no row of its own (its spawn call's row shows the wait).\n 'spawn-queued': 0,\n // Compact-summary opens its own block; visually it's the \"before /\n // after\" hinge between elided history and current context, so it\n // deserves the breathing room a markdown / user-prompt event gets.\n 'compact-summary': 1,\n // Task-notification banners open a new logical block (a task is done,\n // here's what happened) so they get the same gap a `tool` line gets.\n // Consecutive task-notifications stack tight via the rule in\n // `marginTopFor` — a burst of completed tasks reads as one stacked\n // log column rather than scattered banners.\n 'task-notification': 1,\n // A worker report opens its own block, like a task notification does.\n 'session-event': 1,\n // One blank line above: the receipt is a footer set off from the prose it\n // totals. It paints its own blank line BELOW (see `RunSummaryLine`), and\n // `marginTopFor` gives the next block 0 so the gap stays exactly one row.\n 'run-summary': 1,\n // Custom-rendered rows are command output in spirit (a command or\n // extension chose the presentation) — same breathing room as\n // `command-detail` / `markdown`.\n 'custom': 1,\n // The command's receipt closes its output with one row of air, like the run receipt.\n 'command-note': 1,\n}\n\nconst TOOL_KINDS: ReadonlySet<StreamEvent['kind']> = new Set(['tool', 'tool-result'])\n\n/**\n * Resolve the top margin (in rows) for an event given the one rendered\n * just before it. Context-aware rules:\n *\n * - A `tool` / `tool-result` event right after another\n * `tool` / `tool-result` collapses to a tight list — call→result\n * pairs and back-to-back calls read as one logical block.\n * - Consecutive `task-notification` banners stack tight — a burst of\n * background-task completions reads as one log column rather than\n * scattered banners.\n *\n * NB: parent-level events (`depth === 0`) following a subagent block\n * (`depth > 0`) get their normal default margin. An earlier revision\n * collapsed this transition to 0 on the assumption that the subagent's\n * `🌳` end-marker provided enough visual separation — it didn't. A\n * 2-cell emoji on the same row as the close marker doesn't create a\n * vertical break, and in hide-subagent-output mode the SubagentBlock\n * box isn't rendered either, so the parent's follow-up markdown was\n * glued directly against the close line. Subagents should READ like\n * tool calls: open with breathing room, close tight inside, and open\n * a clean gap before the parent's next thought — that's the contract\n * the tool-call → markdown transition uses, mirrored here.\n *\n * Renderer-agnostic — TUI uses it as Yoga `marginTop`; a CSS host can\n * use the same number as the row's top margin in `em` / `rem`.\n */\nexport function marginTopFor(event: StreamEvent, previous: StreamEvent | undefined): number {\n // First-block exception: spacing is single-direction (marginTop-only),\n // so the very first rendered block has no neighbor above to space\n // against — a gap there would just indent the transcript from its\n // container edge. Matches `SubagentBlock`'s `previous ? 1 : 0` rule so\n // every block kind starts flush.\n if (!previous)\n return 0\n // NB: an event directly after a `separator` keeps its own margin. The\n // asymmetric rhythm that used to open a 2-row gap ABOVE user prompts\n // (reload / command / agent-injected paths) against the 1-row gap below\n // them is fixed at the RENDERER: a separator is a semantic exchange\n // boundary and paints zero rows (see `EventLineImpl`'s `'separator'`\n // case), so inter-block spacing is exclusively the next block's margin.\n // Collapsing the margin here too would leave those prompts with no gap\n // at all.\n if (TOOL_KINDS.has(event.kind) && TOOL_KINDS.has(previous.kind))\n return 0\n // A spawn marker directly below the `spawn` tool call that created it —\n // or stacked under a sibling marker — reads as one fluid block, same rule\n // as consecutive tool rows. The gap only opens after prose/other kinds.\n if (event.kind === 'spawn-start' && previous\n && (TOOL_KINDS.has(previous.kind) || previous.kind === 'spawn-start' || previous.kind === 'spawn-end')) {\n return 0\n }\n if (event.kind === 'task-notification' && previous?.kind === 'task-notification')\n return 0\n // The run receipt paints its own trailing blank row so the last run of a\n // transcript still ends with one; the block after it must not add a second.\n if (previous.kind === 'run-summary')\n return 0\n // Consecutive notice rows stack tight, same rule as task banners. A burst of\n // harness events (a fallback, then the repeat-guard trip, then the run error)\n // reads as one block instead of a double-spaced ladder.\n if (event.notice && previous?.notice)\n return 0\n // Continuation lines of one reasoning run stack tight — only the first\n // thinking line (run start) gets the top gap.\n if (event.kind === 'thinking' && previous?.kind === 'thinking' && previous.childId === event.childId)\n return 0\n return MARGIN_TOP[event.kind] ?? 0\n}\n\n/** Effective context size of the most recent assistant turn — drives the footer indicator. */\n/**\n * Walk from the end of `turns` and return the cache-aware input-token total\n * of the most recent **parent** (depth-0) assistant turn. Subagent turns\n * are skipped because their context window is the child's, not the parent's\n * — surfacing a subagent's `usage.input` as the footer's \"context used\"\n * after a session ends mid-spawn would be misleading. The next prompt\n * feeds the parent, so the parent's last view is what matters.\n *\n * Zero-context placeholder turns are also skipped. `executeTurn`\n * synthesizes an assistant turn with `usage: { input: 0, output: 0 }`\n * when the provider stream throws / aborts before any usage is reported\n * (see `src/loop.ts`'s catch path) — that turn is purely a shape\n * contract for resume, not a real context-window measurement. Without\n * the skip, an abort mid-stream shadows the prior real turn and the\n * footer reads `ctx 0` on the next session load even though earlier\n * turns accumulated meaningful context (and `run.cost`).\n *\n * `runs` is optional for backwards compatibility (older call sites and\n * tests that don't have ancestry info). Without it, this falls back to the\n * pre-fix behavior — depth is unknown so every assistant turn qualifies.\n */\nexport function lastContextSizeFromTurns(\n turns: SessionTurn[],\n runs: readonly SessionRun[] = [],\n): number {\n const childRunIds = new Set<string>()\n for (const run of runs) {\n if ((run.depth ?? 0) > 0)\n childRunIds.add(run.id)\n }\n for (let i = turns.length - 1; i >= 0; i--) {\n const turn = turns[i]\n if (turn.role !== 'assistant' || !turn.usage)\n continue\n if (turn.runId && childRunIds.has(turn.runId))\n continue\n const size = (turn.usage.input ?? 0)\n + (turn.usage.cacheRead ?? 0)\n + (turn.usage.cacheCreation ?? 0)\n if (size === 0)\n continue\n return size\n }\n return 0\n}\n\n/**\n * Sum provider-reported USD cost across every run in a session. Used to\n * seed the live cost indicator on session activation. Returns 0 when no\n * run carries a `cost` (most providers — only OpenRouter reports today).\n */\nexport function sumRunCosts(runs: readonly SessionRun[]): number {\n let total = 0\n for (const run of runs) {\n if (run.cost)\n total += run.cost\n }\n return total\n}\n\n/** Per-model token/spend totals across a session — see {@link usageByModel}. */\nexport interface ModelUsageSummary {\n /** Provider-echoed model id, or `\"unknown\"` for turns that never recorded one. */\n modelId: string\n turns: number\n /** Fresh (uncached) input tokens. */\n input: number\n output: number\n cacheRead: number\n cacheCreation: number\n /** Summed USD cost across turns that carried one (provider-reported or estimated). */\n cost: number\n /**\n * `false` when at least one turn had no cost figure (no published rate\n * for the model) — `cost` is then a floor, not a total.\n */\n costComplete: boolean\n}\n\n/**\n * Aggregate per-model token + spend totals across every run in a session.\n * Parent and subagent runs alike: each turn carries its own `modelId`, so\n * cost-tiered delegation (cheap spawn workers) shows up as separate rows\n * priced at their own rates. Sorted by cost (desc), then total tokens, so\n * the biggest spender reads first.\n */\nexport function usageByModel(runs: readonly SessionRun[]): ModelUsageSummary[] {\n const byModel = new Map<string, ModelUsageSummary>()\n for (const run of runs) {\n for (const u of run.turnUsage ?? []) {\n const key = u.modelId ?? 'unknown'\n let row = byModel.get(key)\n if (!row) {\n row = { modelId: key, turns: 0, input: 0, output: 0, cacheRead: 0, cacheCreation: 0, cost: 0, costComplete: true }\n byModel.set(key, row)\n }\n row.turns += 1\n row.input += u.input\n row.output += u.output\n row.cacheRead += u.cacheRead ?? 0\n row.cacheCreation += u.cacheCreation ?? 0\n if (u.cost !== undefined)\n row.cost += u.cost\n else\n row.costComplete = false\n }\n }\n const totalTokens = (r: ModelUsageSummary) => r.input + r.output + r.cacheRead + r.cacheCreation\n return [...byModel.values()].sort((a, b) => (b.cost - a.cost) || (totalTokens(b) - totalTokens(a)))\n}\n","/**\n * Read-only discovery of MCP servers + skills from OTHER coding agents'\n * config locations — Claude Code, Codex, and Pi — at both project and\n * user level. Gated behind the `importForeignConfigs` setting (default\n * off): the files belong to the other tools, so zidane only ever READS\n * them; installs, edits, and toggles keep writing to zidane's own\n * `.zidane` / `.agents` locations.\n *\n * Locations covered (missing files/dirs are skipped silently):\n *\n * MCP servers Skills\n * ── project ────────────────────────── ── project ───────────────\n * {root}/.mcp.json (Claude Code) {root}/.claude/skills\n * ~/.claude.json projects[{root}] (same) {root}/.codex/skills\n * {root}/.pi/mcps.json + mcp.json (Pi) {root}/.pi/skills\n * ── user ───────────────────────────── ── user ──────────────────\n * ~/.claude.json (Claude Code) ~/.claude/skills\n * ~/.codex/config.toml (Codex) ~/.codex/skills\n * ~/.pi/agent/mcps.json + mcp.json (Pi) ~/.pi/agent/skills\n *\n * `.agents/` is NOT here — it's the cross-agent convention zidane\n * already reads natively (see `project-user-paths.ts`), setting or no\n * setting.\n *\n * Precedence is decided by the callers (`mcps-discovery` /\n * `skills-discovery`): native locations always beat foreign ones, and\n * project beats user within each group.\n */\n\nimport type { McpServerConfig } from '../mcp'\nimport type { ProjectUserPath } from './project-user-paths'\nimport { realpathSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { resolve, sep } from 'node:path'\nimport { normalizeMcpServers } from '../mcp'\nimport { findGitRoot } from './project-root'\n\n/**\n * How a foreign MCP file is parsed:\n * - `json` — the shared `mcp(s).json` grammar (`parseMcpsFile` handles\n * wrappers, name-keyed maps, and flat arrays).\n * - `claude-user-state` — `~/.claude.json` is Claude Code's whole\n * user-state file; ONLY its `mcpServers` key is imported (treating\n * the rest as a name-keyed server map would produce garbage).\n * - `claude-project-state` — the same file's\n * `projects[\"<abs project root>\"].mcpServers` map: where `claude\n * mcp add` (default \"local\" scope) stores per-project servers.\n * - `codex-toml` — `~/.codex/config.toml` with `[mcp_servers.<name>]`\n * tables.\n */\nexport type ForeignMcpFormat = 'json' | 'claude-user-state' | 'claude-project-state' | 'codex-toml'\n\nexport interface ForeignMcpFile extends ProjectUserPath {\n format: ForeignMcpFormat\n}\n\ninterface ForeignPathOptions {\n /** Discovery cwd. Default: `process.cwd()`. */\n cwd?: string\n /** User home directory. Default: `os.homedir()`. */\n home?: string\n}\n\nfunction roots(opts: ForeignPathOptions): { projectRoot: string, home: string } {\n const cwd = opts.cwd ?? process.cwd()\n return {\n projectRoot: findGitRoot(cwd) ?? cwd,\n home: opts.home ?? homedir(),\n }\n}\n\n/**\n * MCP config files other agents maintain, project entries first.\n * Returned regardless of existence — callers `existsSync`-filter, same\n * contract as `defaultMcpsConfigPaths`.\n */\nexport function foreignMcpConfigFiles(opts: ForeignPathOptions = {}): ForeignMcpFile[] {\n const { projectRoot, home } = roots(opts)\n return [\n // Claude Code's project-scope convention: `.mcp.json` at the repo\n // root (mcpServers wrapper — the shared JSON grammar unwraps it).\n { path: resolve(projectRoot, '.mcp.json'), source: 'project', format: 'json' },\n // … and `claude mcp add`'s default \"local\" scope, which lives in the\n // USER state file keyed by absolute project path — project-sourced\n // because that's what it means, wherever it's stored.\n { path: resolve(home, '.claude.json'), source: 'project', format: 'claude-project-state' },\n { path: resolve(projectRoot, '.pi/mcps.json'), source: 'project', format: 'json' },\n { path: resolve(projectRoot, '.pi/mcp.json'), source: 'project', format: 'json' },\n { path: resolve(home, '.claude.json'), source: 'user', format: 'claude-user-state' },\n { path: resolve(home, '.codex/config.toml'), source: 'user', format: 'codex-toml' },\n { path: resolve(home, '.pi/agent/mcps.json'), source: 'user', format: 'json' },\n { path: resolve(home, '.pi/agent/mcp.json'), source: 'user', format: 'json' },\n ]\n}\n\n/**\n * Skill directories other agents maintain, project entries first. Feed\n * directly into `discoverSkills` — the SKILL.md format is shared across\n * the ecosystem, so foreign skills parse with the same lenient loader.\n */\nexport function foreignSkillScanPaths(opts: ForeignPathOptions = {}): ProjectUserPath[] {\n const { projectRoot, home } = roots(opts)\n return [\n { path: resolve(projectRoot, '.claude/skills'), source: 'project' },\n { path: resolve(projectRoot, '.codex/skills'), source: 'project' },\n { path: resolve(projectRoot, '.pi/skills'), source: 'project' },\n { path: resolve(home, '.claude/skills'), source: 'user' },\n { path: resolve(home, '.codex/skills'), source: 'user' },\n { path: resolve(home, '.pi/agent/skills'), source: 'user' },\n ]\n}\n\n/**\n * Parse the two foreign-only formats. The `json` format is NOT handled\n * here — callers route it through the shared `parseMcpsFile` (keeping\n * whitespace sanitizing + error hints in one place, and avoiding an\n * import cycle with `mcps-discovery`).\n */\nexport function parseForeignMcpConfig(\n text: string,\n format: Exclude<ForeignMcpFormat, 'json'>,\n opts: { projectRoot?: string } = {},\n): McpServerConfig[] {\n if (format === 'codex-toml')\n return parseCodexToml(text)\n return parseClaudeState(JSON.parse(text), format, opts.projectRoot)\n}\n\n/**\n * Extract MCP servers from a PRE-PARSED `~/.claude.json` state object.\n * Split from {@link parseForeignMcpConfig} so a discovery pass that reads\n * the file for BOTH scopes (user + project — it appears twice in the path\n * list) can read and `JSON.parse` the multi-MB state file once.\n *\n * - `claude-user-state` — ONLY the top-level `mcpServers` map; an\n * absent/malformed key means \"nothing to import\" rather than an error,\n * since the file legitimately exists without it.\n * - `claude-project-state` — `projects[<dir>].mcpServers`, where `claude\n * mcp add` (default \"local\" scope) stores per-project servers.\n */\nexport function parseClaudeState(\n state: unknown,\n format: 'claude-user-state' | 'claude-project-state',\n projectRoot?: string,\n): McpServerConfig[] {\n if (!state || typeof state !== 'object' || Array.isArray(state))\n return []\n if (format === 'claude-user-state')\n return normalizeForeignEntries((state as { mcpServers?: unknown }).mcpServers)\n return claudeProjectServers(state as { projects?: unknown }, projectRoot)\n}\n\n/**\n * Claude keys `projects` by the directory it was LAUNCHED from — for a\n * monorepo that's often a subdirectory of the git root we resolve to, and\n * paths surface in realpath variants (`/var` vs `/private/var` on macOS,\n * symlinked homes). Accept every key that realpath-normalizes to the root\n * or to a directory inside it; nearer-to-root keys win name collisions so\n * a root-registered server beats a subdirectory duplicate.\n */\nfunction claudeProjectServers(state: { projects?: unknown }, projectRoot: string | undefined): McpServerConfig[] {\n if (!projectRoot)\n return []\n const projects = state.projects\n if (!projects || typeof projects !== 'object' || Array.isArray(projects))\n return []\n const rootKey = normalizePathKey(projectRoot)\n const matches = Object.entries(projects as Record<string, unknown>)\n .map(([key, value]) => ({ key: normalizePathKey(key), value }))\n .filter(({ key }) => key === rootKey || key.startsWith(rootKey + sep))\n .sort((a, b) => a.key.length - b.key.length)\n const out: McpServerConfig[] = []\n const seen = new Set<string>()\n for (const { value } of matches) {\n const servers = value && typeof value === 'object' ? (value as { mcpServers?: unknown }).mcpServers : undefined\n for (const config of normalizeForeignEntries(servers)) {\n if (seen.has(config.name))\n continue\n seen.add(config.name)\n out.push(config)\n }\n }\n return out\n}\n\n/** Realpath-normalize for key comparison; deleted paths fall back to `resolve`. */\nfunction normalizePathKey(path: string): string {\n try {\n return realpathSync(path)\n }\n catch {\n return resolve(path)\n }\n}\n\n/**\n * Normalize a name-keyed server map ENTRY BY ENTRY, skipping the ones\n * `normalizeMcpServers` rejects (no inferrable transport, exotic shapes).\n * Whole-file normalization would let one bad entry drop every server in\n * a file the user doesn't own — and can't fix from zidane.\n */\nfunction normalizeForeignEntries(servers: unknown): McpServerConfig[] {\n if (!servers || typeof servers !== 'object' || Array.isArray(servers))\n return []\n const out: McpServerConfig[] = []\n for (const [name, entry] of Object.entries(servers as Record<string, unknown>)) {\n try {\n out.push(...normalizeMcpServers({ [name]: entry }))\n }\n catch {\n // Skip — the entry works (or fails) in its owning tool; not ours to error on.\n }\n }\n return out\n}\n\n/**\n * `~/.codex/config.toml` — `[mcp_servers.<name>]` tables. TOML parsing\n * rides Bun's built-in parser; on a non-Bun host the Codex import is\n * silently unavailable (returns `[]`) rather than pulling in a TOML\n * dependency for one optional file. Only the fields our config\n * understands are forwarded — Codex-specific extras\n * (`startup_timeout_ms`, …) are dropped before normalization.\n */\nfunction parseCodexToml(text: string): McpServerConfig[] {\n const toml = (globalThis as { Bun?: { TOML?: { parse: (t: string) => unknown } } }).Bun?.TOML\n if (!toml)\n return []\n const parsed = toml.parse(text) as { mcp_servers?: unknown }\n const tables = parsed && typeof parsed === 'object' ? parsed.mcp_servers : undefined\n if (!tables || typeof tables !== 'object' || Array.isArray(tables))\n return []\n const map: Record<string, unknown> = {}\n for (const [name, entry] of Object.entries(tables as Record<string, unknown>)) {\n if (!entry || typeof entry !== 'object')\n continue\n const raw = entry as Record<string, unknown>\n map[name] = {\n ...(raw.command !== undefined ? { command: raw.command } : {}),\n ...(raw.args !== undefined ? { args: raw.args } : {}),\n ...(raw.env !== undefined ? { env: raw.env } : {}),\n // Codex's experimental remote servers — normalize infers transport.\n ...(raw.url !== undefined ? { url: raw.url } : {}),\n }\n }\n return normalizeForeignEntries(map)\n}\n","/**\n * Read-only discovery of [Ruler](https://github.com/intellectronica/ruler)\n * `.ruler/` directories — MCP servers, skills, and instruction markdown.\n *\n * Ruler centralizes AI-agent configuration in one project directory and\n * GENERATES per-agent files from it (`ruler apply`). zidane reads the\n * SOURCES directly, so a ruler-managed repo works without running ruler:\n *\n * .ruler/ruler.toml `[mcp_servers.<name>]` tables — the same TOML\n * grammar as Codex's config, parsed by the shared\n * `codex-toml` handler in `foreign-configs.ts`.\n * .ruler/mcp.json legacy ruler MCP file — shared JSON grammar.\n * .ruler/skills/ `<name>/SKILL.md` — the ecosystem-shared format.\n * .ruler/*.md instruction files, concatenated by ruler into the\n * generated AGENTS.md; zidane loads them as per-file\n * sections instead. Recursive, excluding the\n * `skills/` and `agents/` subtrees (ruler does the\n * same). Ordering mirrors ruler: `AGENTS.md` first\n * (legacy `instructions.md` as fallback primary),\n * remaining files sorted by relative path.\n *\n * User scope is ruler's global config dir: `$XDG_CONFIG_HOME/ruler`\n * (default `~/.config/ruler`) — same three surfaces.\n *\n * CONTAINMENT CONTRACT: every piece of ruler knowledge lives in this\n * module. The discovery surfaces (`mcps-discovery`, `skills-discovery`,\n * `agents-md`) each make exactly one append/skip call into it, all gated\n * behind the `importRulerConfigs` setting — deleting this file and those\n * call sites removes the feature completely. zidane never WRITES to\n * `.ruler/`; installs and toggles keep landing in `.zidane` / `.agents`.\n */\n\nimport type { ForeignMcpFile } from './foreign-configs'\nimport type { ProjectUserPath } from './project-user-paths'\nimport { existsSync, readdirSync, realpathSync, statSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join, resolve } from 'node:path'\nimport { findGitRoot } from './project-root'\n\ninterface RulerPathOptions {\n /** Discovery cwd. Default: `process.cwd()`. */\n cwd?: string\n /** User home directory. Default: `os.homedir()`. */\n home?: string\n /** XDG config home override. Default: `$XDG_CONFIG_HOME`, else `<home>/.config`. */\n xdgConfigHome?: string\n}\n\n/** Subtrees of `.ruler/` that are NOT instruction markdown (mirrors ruler's own exclusions). */\nconst NON_INSTRUCTION_DIRS = new Set(['skills', 'agents'])\n\n/** Primary instruction file (ordered first), and ruler's legacy fallback primary. */\nconst PRIMARY_MD = 'AGENTS.md'\nconst LEGACY_PRIMARY_MD = 'instructions.md'\n\nfunction rulerRoots(opts: RulerPathOptions): { project: string, user: string } {\n const cwd = opts.cwd ?? process.cwd()\n const home = opts.home ?? homedir()\n // An explicitly injected `home` beats the process's $XDG_CONFIG_HOME:\n // callers that redirect the user scope (tests, hosts with virtual homes,\n // `discoverAgentsMd({ home })` which can't thread `xdgConfigHome`) must\n // not silently read the REAL user's global ruler dir through the env.\n const xdg = opts.xdgConfigHome\n ?? (opts.home !== undefined\n ? resolve(opts.home, '.config')\n : process.env.XDG_CONFIG_HOME ?? resolve(home, '.config'))\n return {\n project: resolve(findGitRoot(cwd) ?? cwd, '.ruler'),\n user: resolve(xdg, 'ruler'),\n }\n}\n\n/**\n * MCP config files ruler maintains, project first. Returned regardless of\n * existence (callers `existsSync`-filter — same contract as\n * `foreignMcpConfigFiles`). The `codex-toml` format tag names the shared\n * `[mcp_servers.<name>]` TOML *grammar*, not the tool: ruler.toml uses it\n * verbatim, so the existing parser applies unchanged.\n */\nexport function rulerMcpConfigFiles(opts: RulerPathOptions = {}): ForeignMcpFile[] {\n const { project, user } = rulerRoots(opts)\n return [\n { path: join(project, 'ruler.toml'), source: 'project', format: 'codex-toml' },\n { path: join(project, 'mcp.json'), source: 'project', format: 'json' },\n { path: join(user, 'ruler.toml'), source: 'user', format: 'codex-toml' },\n { path: join(user, 'mcp.json'), source: 'user', format: 'json' },\n ]\n}\n\n/**\n * Skill directories ruler maintains, project first. Feed directly into\n * `discoverSkills` — ruler's `skills/<name>/SKILL.md` layout is the\n * ecosystem-shared format the lenient loader already parses.\n */\nexport function rulerSkillScanPaths(opts: RulerPathOptions = {}): ProjectUserPath[] {\n const { project, user } = rulerRoots(opts)\n return [\n { path: join(project, 'skills'), source: 'project' },\n { path: join(user, 'skills'), source: 'user' },\n ]\n}\n\n/**\n * Instruction markdown files under both ruler roots, in ruler's own\n * concatenation order per root (primary first, rest sorted by relative\n * path), user scope before project scope so the narrower scope lands\n * closer to the conversation — matching `discoverAgentsMd`'s convention.\n *\n * Only existing files are returned (unlike the config-file lists above):\n * the walk itself has to touch the filesystem anyway, and callers feed\n * these straight into per-file readers.\n */\nexport function rulerInstructionFiles(opts: RulerPathOptions = {}): ProjectUserPath[] {\n const { project, user } = rulerRoots(opts)\n return [\n ...collectInstructionMd(user).map(path => ({ path, source: 'user' as const })),\n ...collectInstructionMd(project).map(path => ({ path, source: 'project' as const })),\n ]\n}\n\n/**\n * True when a generated file (e.g. the repo-root `AGENTS.md`) was written\n * by `ruler apply` — it aggregates the `.ruler/*.md` sources, so loading\n * both would double every instruction. Two signals, either suffices:\n * ruler's generation marker, and the per-section source comments older\n * versions emitted without the marker.\n */\nexport function isRulerGenerated(contents: string): boolean {\n return contents.includes('<!-- Generated by Ruler -->')\n || contents.includes('<!-- Source: .ruler/')\n}\n\n/**\n * Bounds for the instruction walk — same philosophy as the 64 KB per-file\n * cap in `agents-md.ts`: a `.ruler/docs -> $HOME` symlink or a huge\n * committed tree must not stall session activation (the walk runs on the\n * main path, per activation and per discovery refresh). Ruler setups in\n * the wild are a handful of files, two levels deep.\n */\nconst MAX_WALK_DEPTH = 6\nconst MAX_INSTRUCTION_FILES = 100\n\n/** Recursive `.md` walk under one ruler root, ruler-ordered. Missing/unreadable dirs → `[]`. */\nfunction collectInstructionMd(rulerDir: string): string[] {\n if (!existsSync(rulerDir))\n return []\n const collected: string[] = []\n // Symlinked dirs are followed (a linked instructions tree should load),\n // so guard against cycles: each REAL directory is walked at most once.\n const visited = new Set<string>([realpathOr(rulerDir)])\n const walk = (dir: string, top: boolean, depth: number): void => {\n if (depth > MAX_WALK_DEPTH || collected.length >= MAX_INSTRUCTION_FILES)\n return\n let entries\n try {\n entries = readdirSync(dir, { withFileTypes: true })\n }\n catch {\n return // permission glitch — tolerate, like every discovery surface\n }\n for (const entry of entries) {\n if (collected.length >= MAX_INSTRUCTION_FILES)\n return\n if (entry.name.startsWith('.'))\n continue\n const full = join(dir, entry.name)\n // `withFileTypes` reports symlinks as neither file nor dir — stat\n // through them so a symlinked instructions file still loads.\n const kind = entry.isSymbolicLink() ? statKind(full) : entry.isDirectory() ? 'dir' : entry.isFile() ? 'file' : 'other'\n if (kind === 'dir') {\n if (top && NON_INSTRUCTION_DIRS.has(entry.name))\n continue\n const real = realpathOr(full)\n if (visited.has(real))\n continue\n visited.add(real)\n walk(full, false, depth + 1)\n }\n else if (kind === 'file' && entry.name.endsWith('.md')) {\n collected.push(full)\n }\n }\n }\n walk(rulerDir, true, 0)\n // Ruler's ordering: top-level AGENTS.md is the primary (legacy\n // instructions.md when AGENTS.md is absent), everything else follows\n // in sorted order.\n const primary = join(rulerDir, PRIMARY_MD)\n const legacy = join(rulerDir, LEGACY_PRIMARY_MD)\n const first = collected.includes(primary) ? primary : collected.includes(legacy) ? legacy : undefined\n const rest = collected.filter(p => p !== first).sort()\n return first ? [first, ...rest] : rest\n}\n\nfunction realpathOr(path: string): string {\n try {\n return realpathSync(path)\n }\n catch {\n return path\n }\n}\n\nfunction statKind(path: string): 'dir' | 'file' | 'other' {\n try {\n const s = statSync(path)\n return s.isDirectory() ? 'dir' : s.isFile() ? 'file' : 'other'\n }\n catch {\n return 'other'\n }\n}\n","/**\n * MCP server discovery from project + user config files.\n *\n * Reads `mcps.json` (zidane's canonical name) AND `mcp.json` (Cursor /\n * common ecosystem alias) from both `.agents/` and `.{prefix}/` in\n * each of the project + user dirs — a list of `McpServerConfig`\n * shapes the SDK accepts. Files are normalized via the same path the\n * agent uses (`normalizeMcpServers`), and the user's enabled-toggle\n * list folds the result into a server array the agent picks up at\n * construction.\n *\n * Co-existing files merge by first-found-per-name: e.g.\n * `.agents/mcps.json` declares `linear`, `.agents/mcp.json` declares\n * `linear` + `notion` → discovery emits the `mcps.json` `linear` plus\n * `mcp.json`'s `notion`. Project always beats user across all files.\n *\n * Pattern mirrors `skills-discovery.ts` — the chat layer owns\n * discovery + UI, the agent receives the same `McpServerConfig[]` it\n * always did.\n */\n\nimport type { McpServerConfig } from '../mcp'\nimport type { ForeignMcpFormat } from './foreign-configs'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { errorMessage } from '../errors'\nimport { normalizeMcpServers } from '../mcp'\nimport { foreignMcpConfigFiles, parseClaudeState, parseForeignMcpConfig } from './foreign-configs'\nimport { findGitRoot } from './project-root'\nimport { projectUserPaths } from './project-user-paths'\nimport { rulerMcpConfigFiles } from './ruler-configs'\n\n/**\n * File names searched in each of the four project/user roots. Order\n * matters within a single directory — `mcps.json` (zidane's canonical\n * name) beats `mcp.json` (Cursor / common ecosystem alias) when both\n * exist side-by-side. Across files we merge per-name with first-found\n * winning, so co-existing `mcp.json` entries are folded in for names\n * not declared in the canonical file.\n */\nconst MCP_CONFIG_FILE_NAMES = ['mcps.json', 'mcp.json'] as const\n\n/**\n * One entry in the discovered list. `path` is the source file (one of\n * the `mcp(s).json` variants under `.agents/` or `.{prefix}/`) so a\n * Settings picker can show \"Defined in ~/.zidane/mcp.json\" tooltips\n * and the user can tell which file declared what.\n */\nexport interface DiscoveredMcp {\n config: McpServerConfig\n source: 'project' | 'user'\n path: string\n}\n\n/**\n * Search order for MCP config files — see {@link projectUserPaths}.\n *\n * Both `mcps.json` (zidane's canonical name) and `mcp.json` (Cursor /\n * common ecosystem alias) are picked up from every search root. The\n * canonical name wins within the same directory; across files the\n * usual first-found-by-name dedup applies, so `mcp.json` effectively\n * merges its non-overlapping entries on top of `mcps.json`.\n *\n * Order per scope (project beats user):\n * 1. `{project}/.agents/mcps.json`\n * 2. `{project}/.agents/mcp.json`\n * 3. `{project}/.{prefix}/mcps.json`\n * 4. `{project}/.{prefix}/mcp.json`\n * 5. `~/.agents/mcps.json`\n * 6. `~/.agents/mcp.json`\n * 7. `~/.{prefix}/mcps.json`\n * 8. `~/.{prefix}/mcp.json`\n *\n * Non-existent files are skipped without error.\n */\nexport function defaultMcpsConfigPaths(opts: {\n cwd?: string\n home?: string\n prefix?: string\n} = {}): { path: string, source: 'project' | 'user' }[] {\n // Build the path list per-filename via the shared helper, then\n // interleave so `<dir>/mcps.json` lands immediately before\n // `<dir>/mcp.json` for each scope. Same ordering invariant that\n // `projectUserPaths` already guarantees within a filename — the\n // interleave preserves it across filenames.\n const perName = MCP_CONFIG_FILE_NAMES.map(name => projectUserPaths({ subPath: name, ...opts }))\n const rootCount = perName[0].length\n const out: { path: string, source: 'project' | 'user' }[] = []\n for (let i = 0; i < rootCount; i++) {\n for (const list of perName)\n out.push(list[i])\n }\n return out\n}\n\n/**\n * Parse one `mcps.json` file. Canonical zidane shape is a flat array; the\n * other shapes exist for copy-paste from neighboring tools:\n *\n * - `McpServerConfig[]` — flat array (recommended).\n * - `{ name: {...} }` — name-keyed map.\n * - `{ \"mcpServers\": { name: {...} } }` — Claude Desktop / Claude Code /\n * Cursor wrapper. Unwrapped before normalization (otherwise\n * `normalizeMcpServers` would treat the whole wrapper as a single server).\n *\n * Per-entry `enabled: false` (Cursor runtime state) drops the entry — same\n * intent as the source tool. Use the TUI toggle list for \"show but disabled\".\n *\n * Tolerant to common copy-paste artifacts: when strict `JSON.parse` fails,\n * retries after normalizing invisible whitespace that's valid Unicode but\n * not valid JSON whitespace (BOM, NBSP, zero-width spaces, line/paragraph\n * separators) — only OUTSIDE string literals, so user data isn't mutated.\n * If the sanitized version still fails, throws the original error with a\n * targeted hint when NBSPs are present.\n *\n * Validation flows through `normalizeMcpServers` so the result matches\n * what `createAgent` accepts. Throws on truly malformed JSON; the caller\n * decides whether to surface or swallow.\n */\nexport function parseMcpsFile(text: string): McpServerConfig[] {\n const raw = parseJsonTolerant(text)\n const target: unknown = raw && typeof raw === 'object' && !Array.isArray(raw) && 'mcpServers' in raw\n ? (raw as { mcpServers: unknown }).mcpServers\n : raw\n return normalizeMcpServers(dropDisabledEntries(target))\n}\n\n/**\n * Strict `JSON.parse` with the whitespace-tolerance retry described on\n * {@link parseMcpsFile}, returning the RAW parsed value. Exported for the\n * write side (`mcps-write.ts`): a file that discovery reads fine MUST also\n * be editable — upsert/remove failing with \"Unrecognized token\" on an NBSP\n * the read path silently tolerates would strand the user.\n */\nexport function parseJsonTolerant(text: string): unknown {\n try {\n return JSON.parse(text)\n }\n catch (firstErr) {\n const sanitized = sanitizeJsonWhitespace(text)\n if (!sanitized.changed)\n throw firstErr\n try {\n return JSON.parse(sanitized.text)\n }\n catch {\n throw enhanceJsonError(firstErr, text)\n }\n }\n}\n\n/**\n * Code points that are valid Unicode whitespace but NOT valid JSON whitespace.\n * Copy-paste from rich-text contexts (markdown editors, chat UIs, web pages)\n * frequently slips these in:\n *\n * - `\\uFEFF` BOM — sometimes prepended by Windows editors.\n * - `\\u00A0` NBSP — markdown/HTML smart-replace common culprit.\n * - `\\u200B`-`\\u200D` zero-width family — often invisible in editors.\n * - `\\u2028` / `\\u2029` line/paragraph separators — valid in JS strings\n * pre-ES2019 but never in strict JSON.\n * - `\\u2060` word joiner.\n *\n * Replace with ASCII space (zero-width chars are removed; the others become\n * a single space). Replacements happen ONLY outside string literals so a\n * user's intentional NBSP inside a `url` or display name is left alone.\n */\nconst PROBLEMATIC_WHITESPACE = new Set<number>([\n 0xFEFF,\n 0x00A0,\n 0x200B,\n 0x200C,\n 0x200D,\n 0x2028,\n 0x2029,\n 0x2060,\n])\n\nfunction sanitizeJsonWhitespace(text: string): { text: string, changed: boolean } {\n let changed = false\n let inString = false\n let escaped = false\n const out: string[] = []\n for (let i = 0; i < text.length; i++) {\n const ch = text[i]\n if (inString) {\n out.push(ch)\n if (escaped)\n escaped = false\n else if (ch === '\\\\')\n escaped = true\n else if (ch === '\"')\n inString = false\n continue\n }\n if (ch === '\"') {\n inString = true\n out.push(ch)\n continue\n }\n const code = ch.charCodeAt(0)\n if (PROBLEMATIC_WHITESPACE.has(code)) {\n changed = true\n // Zero-width chars (200B-200D, 2060, FEFF) erased; visible whitespace\n // replacements become a single space so token boundaries are preserved.\n if (code === 0x00A0 || code === 0x2028 || code === 0x2029)\n out.push(' ')\n continue\n }\n out.push(ch)\n }\n return { text: out.join(''), changed }\n}\n\nfunction enhanceJsonError(err: unknown, text: string): Error {\n const orig = err instanceof Error ? err : new Error(String(err))\n const hints: string[] = []\n if (text.includes('\\u00A0'))\n hints.push('the file contains non-breaking spaces (U+00A0), likely from copy-paste. Replace them with regular spaces')\n if (text.charCodeAt(0) === 0xFEFF)\n hints.push('the file starts with a BOM (U+FEFF), which strict JSON.parse rejects')\n if (hints.length === 0)\n return orig\n return new Error(`${orig.message}. ${hints.join('; ')}`)\n}\n\n/**\n * Strip `enabled: false` entries before normalization — same intent as the\n * source tool that wrote them (Cursor flips this when the user toggles a\n * server off in its UI). One pass over array OR map shape, O(N).\n *\n * Done pre-normalize so we don't have to teach `normalizeMcpServers` about\n * the flag — the canonical `McpServerConfig` has no `enabled` field.\n */\nfunction dropDisabledEntries(target: unknown): unknown {\n if (Array.isArray(target))\n return target.filter(e => !isEntryDisabled(e))\n if (target && typeof target === 'object') {\n const filtered: Record<string, unknown> = {}\n for (const [name, entry] of Object.entries(target as Record<string, unknown>)) {\n if (!isEntryDisabled(entry))\n filtered[name] = entry\n }\n return filtered\n }\n return target\n}\n\nfunction isEntryDisabled(entry: unknown): boolean {\n return !!entry && typeof entry === 'object'\n && (entry as { enabled?: unknown }).enabled === false\n}\n\n/**\n * Per-file failure surfaced from {@link discoverProjectMcps}. The TUI shows\n * these in the MCP settings empty / preamble state so a malformed\n * `mcps.json` doesn't look identical to a missing one.\n */\nexport interface DiscoveryError {\n path: string\n source: 'project' | 'user'\n message: string\n /**\n * A deliberate, documented behavior being reported (e.g. the ruler stdio\n * security carve-out) rather than a failure. Hosts should style these as\n * info, not error — crying wolf over a working default trains users to\n * ignore the channel that also carries real parse failures.\n */\n informational?: boolean\n}\n\n/**\n * Result of {@link discoverProjectMcps}. `servers` is the per-source-priority\n * merged list (project beats user, first-found wins on name collision).\n * `errors` is one entry per file that existed but failed to parse, plus\n * informational entries for servers a security gate skipped (ruler stdio\n * without the foreign-agent opt-in) — empty on the happy path.\n */\nexport interface DiscoveryResult {\n servers: DiscoveredMcp[]\n errors: DiscoveryError[]\n}\n\n/**\n * Walk the default config paths, parse every file that exists, and return\n * `{ servers, errors }` in source-priority order. Project entries appear\n * before user entries; first occurrence of a `name` wins (later\n * duplicates dropped).\n *\n * Parse failures are captured into `errors` rather than thrown — the picker\n * surfaces them while still showing whatever DID parse. A `ZIDANE_DEBUG`\n * log line is also emitted for ops visibility.\n */\nexport function discoverProjectMcps(opts: {\n cwd?: string\n home?: string\n prefix?: string\n /**\n * Also read MCP configs other agents maintain (Claude Code, Codex,\n * Pi) — see `foreign-configs.ts`. Mirrors the `importForeignConfigs`\n * setting; native locations always win name collisions, and project\n * beats user within each group.\n */\n foreignAgents?: boolean\n /**\n * Also read Ruler MCP configs (`.ruler/ruler.toml` + `mcp.json`,\n * project and XDG-global) — see `ruler-configs.ts`. Mirrors the\n * `importRulerConfigs` setting; same collision rules as above.\n */\n ruler?: boolean\n} = {}): DiscoveryResult {\n const paths = mcpsDiscoveryPaths(opts).filter(p => existsSync(p.path))\n // Claude's \"local\"-scope servers are keyed by absolute project path\n // inside the user state file — resolve once for the whole pass.\n const projectRoot = findGitRoot(opts.cwd ?? process.cwd()) ?? (opts.cwd ?? process.cwd())\n const seen = new Set<string>()\n // Pass-level record of names already reported as stdio-dropped — a server\n // declared in BOTH `.ruler/ruler.toml` and `.ruler/mcp.json` would\n // otherwise appear in two informational notices, inflating the count.\n const droppedStdioSeen = new Set<string>()\n const servers: DiscoveredMcp[] = []\n const errors: DiscoveryError[] = []\n // `~/.claude.json` appears TWICE in the path list (project + user scopes)\n // and runs to multiple MB in the wild (it embeds per-project history) —\n // read + `JSON.parse` it once per pass. Caching the failure too collapses\n // a torn read (a live Claude Code session rewriting the file) into ONE\n // transient error instead of two.\n const claudeStateCache = new Map<string, { state: unknown } | { failed: true }>()\n for (const { path, source, format, dropStdio } of paths) {\n const isClaudeState = format === 'claude-user-state' || format === 'claude-project-state'\n const cached = isClaudeState ? claudeStateCache.get(path) : undefined\n if (cached && 'failed' in cached)\n continue // parse failure already recorded for this path this pass\n let configs: McpServerConfig[]\n try {\n if (isClaudeState) {\n let state: unknown\n if (cached && 'state' in cached) {\n state = cached.state\n }\n else {\n try {\n state = JSON.parse(readFileSync(path, 'utf8')) as unknown\n }\n catch (err) {\n claudeStateCache.set(path, { failed: true })\n throw err\n }\n claudeStateCache.set(path, { state })\n }\n configs = parseClaudeState(state, format, projectRoot)\n }\n else {\n const text = readFileSync(path, 'utf8')\n configs = format === 'json' ? parseMcpsFile(text) : parseForeignMcpConfig(text, format, { projectRoot })\n }\n }\n catch (err) {\n const message = errorMessage(err)\n errors.push({ path, source, message })\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/chat] failed to parse \"${path}\": ${message}\\n`)\n continue\n }\n const droppedStdio: string[] = []\n for (const config of configs) {\n if (seen.has(config.name))\n continue\n // Ruler stdio servers require the explicit stdio opt-in (see\n // `mcpsDiscoveryPaths`) — a `command` from a repo-committed file\n // would otherwise execute on the first bootstrap of a freshly\n // cloned (possibly hostile) repo, since `importRulerConfigs`\n // defaults ON and discovered servers are enabled by default.\n // (Checked AFTER the dedup guard so a server that already imported\n // from a native location isn't misreported as dropped.)\n if (dropStdio && config.transport === 'stdio') {\n if (!droppedStdioSeen.has(config.name)) {\n droppedStdioSeen.add(config.name)\n droppedStdio.push(config.name)\n }\n continue\n }\n seen.add(config.name)\n servers.push({ config, source, path })\n }\n // Surface the security carve-out instead of vanishing silently — the\n // picker renders these alongside parse errors, so the user learns WHY\n // a `.ruler` stdio server is missing and which switch enables it.\n if (droppedStdio.length > 0) {\n errors.push({\n path,\n source,\n message: `${droppedStdio.length} stdio server${droppedStdio.length === 1 ? '' : 's'} (${droppedStdio.join(', ')}) skipped. Running stdio commands from Ruler files needs “Import configurations from other agents” enabled.`,\n informational: true, // working security default, not a failure\n })\n }\n }\n return { servers, errors }\n}\n\n/**\n * Full path list a discovery pass reads, formats attached — native\n * `mcp(s).json` locations first (they win name collisions), then the\n * foreign-agent files when enabled.\n *\n * Ruler files carry `dropStdio` unless the foreign-agent opt-in is ALSO\n * set: `importRulerConfigs` defaults ON (it's an intentional committed\n * config source), but stdio servers execute local commands — the exact\n * risk `importForeignConfigs` exists to gate (`types.ts`: \"importing them\n * is an explicit opt-in\"). Remote (url) ruler servers import by default;\n * `command`-based ones wait for the same opt-in as every other foreign\n * stdio source.\n */\nfunction mcpsDiscoveryPaths(opts: {\n cwd?: string\n home?: string\n prefix?: string\n foreignAgents?: boolean\n ruler?: boolean\n} = {}): { path: string, source: 'project' | 'user', format: ForeignMcpFormat, dropStdio?: boolean }[] {\n const native = defaultMcpsConfigPaths(opts).map(p => ({ ...p, format: 'json' as const }))\n return [\n ...native,\n ...(opts.foreignAgents ? foreignMcpConfigFiles(opts) : []),\n ...(opts.ruler ? rulerMcpConfigFiles(opts).map(p => ({ ...p, dropStdio: opts.foreignAgents !== true })) : []),\n ]\n}\n\n/**\n * Map a user-toggled enable list onto the `mcpServers` array the agent\n * receives. Conventions match `buildSkillsConfig`:\n *\n * - `enabled === undefined` → every discovered server enabled (default).\n * - `enabled === []` → no servers (the agent runs MCP-less).\n * - `enabled === [names]` → allowlist; servers not in the list are\n * dropped.\n *\n * `disabledTools` is the per-server tool deny-list from\n * `Settings.disabledMcpTools`. For each server that survives the\n * server-level enable filter, the per-tool names are merged into\n * `McpServerConfig.disabledTools` via **union** with anything the JSON\n * file already pinned — a tool listed in either source is dropped.\n * Union (not override) keeps JSON-side policy stable: a server file\n * that pins `disabledTools: ['dangerous_tool']` can't be re-enabled\n * via the UI by accident.\n *\n * `enabledTools` (JSON-side allowlist) takes precedence over the\n * UI-side deny-list when both are set on the same server — the\n * allowlist's \"only these\" semantics would be meaningless if a UI\n * deny-list could subtract from it again. We don't emit `disabledTools`\n * when `enabledTools` is present.\n *\n * Returns a fresh array — callers can mutate without affecting the\n * underlying discovery list. Per-server config objects are also fresh\n * copies (shallow), so the merged `disabledTools` doesn't leak back\n * onto the discovery catalog.\n */\nexport function buildMcpServers(opts: {\n discovered: readonly DiscoveredMcp[]\n enabled?: readonly string[]\n disabledTools?: Record<string, readonly string[]>\n}): McpServerConfig[] {\n const survivors = filterByEnabled(opts.discovered, opts.enabled)\n const deny = opts.disabledTools\n if (!deny || Object.keys(deny).length === 0)\n return survivors.map(d => ({ ...d.config }))\n\n return survivors.map((d) => {\n const next: McpServerConfig = { ...d.config }\n const uiDeny = deny[d.config.name]\n if (!uiDeny || uiDeny.length === 0)\n return next\n // `enabledTools` is JSON-side authority — see JSDoc.\n if (next.enabledTools && next.enabledTools.length > 0)\n return next\n const merged = new Set<string>(next.disabledTools ?? [])\n for (const name of uiDeny)\n merged.add(name)\n next.disabledTools = [...merged].sort()\n return next\n })\n}\n\n/**\n * Dedup a merged MCP-server list by `name`. First entry wins.\n *\n * Applied at agent build across every source that can contribute a server —\n * `mcps.json`, Agent Plugins, launch options, extensions — so the earliest\n * source in that order takes precedence.\n *\n * Drops are REPORTED rather than silent, via `onDropped`. A plugin shipping a\n * `github` server loses to a `github` in `mcps.json`, and nothing downstream\n * says so: the plugin's settings row still counts the server it shipped,\n * because the row renders what the PACKAGE declares and only this merge knows\n * what survived. That mirrors how the skills side reports the same class of\n * event — `resolveSkills` emits `name-collision-shadowed` on the winner rather\n * than annotating the loser.\n *\n * The reporter is injected rather than calling a logger directly so this stays\n * a pure function of its input, testable without a logging shim. It lives here\n * beside {@link buildMcpServers} rather than in the TUI because merge\n * precedence is a config concern, not a rendering one.\n */\nexport function dedupMcpServersByName<T extends { name: string }>(\n servers: readonly T[],\n onDropped?: (names: readonly string[]) => void,\n): T[] {\n const seen = new Set<string>()\n const out: T[] = []\n const dropped: string[] = []\n for (const server of servers) {\n if (seen.has(server.name)) {\n dropped.push(server.name)\n continue\n }\n seen.add(server.name)\n out.push(server)\n }\n if (dropped.length > 0)\n onDropped?.(dropped)\n return out\n}\n\n/**\n * Anchor host-spawned stdio servers without an explicit `cwd` at the\n * session's directory. Otherwise they inherit the host process's cwd —\n * the session dir in a TUI that chdir'd, but an arbitrary dir in the daemon\n * or GUI, so relative args / project-scoped servers would see the wrong\n * tree. Context-scoped servers run inside the execution context and are\n * left alone.\n */\nexport function withSessionStdioCwd(servers: readonly McpServerConfig[], cwd: string): McpServerConfig[] {\n return servers.map(server =>\n server.transport === 'stdio' && server.scope !== 'context' && !server.cwd\n ? { ...server, cwd }\n : server,\n )\n}\n\nfunction filterByEnabled(\n discovered: readonly DiscoveredMcp[],\n enabled: readonly string[] | undefined,\n): readonly DiscoveredMcp[] {\n if (enabled === undefined)\n return discovered\n if (enabled.length === 0)\n return []\n const allow = new Set(enabled)\n return discovered.filter(d => allow.has(d.config.name))\n}\n","/**\n * System-prompt override discovery — load a `SYSTEM.md` that REPLACES the\n * built-in doctrine.\n *\n * The sibling of `agents-md.ts`, with deliberately inverted semantics:\n *\n * | | `AGENTS.md` | `SYSTEM.md` |\n * |------------|------------------------------|---------------------------------|\n * | effect | appends to the doctrine | replaces the doctrine |\n * | multiples | every match loads, in order | exactly one wins |\n * | precedence | broad → narrow, all present | project beats user, rest shadowed |\n *\n * Concatenating overrides would be incoherent — two files each claiming to BE\n * the system prompt can't both be it — so a single winner is picked and the\n * losers are reported in {@link SystemMdResult.shadowed} for the UI to show.\n * A surprising precedence should be visible, not mysterious.\n *\n * Search order (winner first):\n *\n * 1. `<project root>/SYSTEM.md` — project scope, most specific, wins\n * 2. `~/.{prefix}/SYSTEM.md` — user scope (`~/.zidane/SYSTEM.md`)\n *\n * What the override does NOT replace: the `AGENTS.md` block (a separate,\n * additive layer) and the `<env>` section below the prompt-cache boundary.\n * Stripping `<env>` would take the agent's cwd + project root with it and\n * silently break path resolution in the file tools — an override is for\n * rewriting the agent's instructions, not amputating its sense of place.\n */\n\nimport type { AgentsMdScope } from './agents-md'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport { errorMessage } from '../errors'\nimport { findGitRoot } from './project-root'\n\n/** A discovered `SYSTEM.md`. */\nexport interface SystemMdFile {\n path: string\n source: 'project' | 'user'\n contents: string\n}\n\n/** Result of {@link discoverSystemMd}. */\nexport interface SystemMdResult {\n /**\n * The winning override, or `null` when no `SYSTEM.md` exists (the built-in\n * doctrine then applies unchanged).\n */\n file: SystemMdFile | null\n /**\n * Files that exist but lost to `file` on precedence. Non-empty only when the\n * user has both a project and a user `SYSTEM.md`. Surfaced so the UI can mark\n * them as inactive instead of leaving the user wondering why edits to one of\n * them changed nothing.\n */\n shadowed: readonly SystemMdFile[]\n}\n\n/** Same per-file cap as `agents-md.ts` — a runaway file shouldn't blow the prompt. */\nconst MAX_BYTES_PER_FILE = 64 * 1024\n\nexport interface DiscoverSystemMdOptions {\n /** Discovery cwd. Default: `process.cwd()`. */\n cwd?: string\n /** User home directory. Default: `os.homedir()`. */\n home?: string\n /** Storage prefix. Leading dot tolerated. Default: `'.zidane'`. */\n prefix?: string\n /**\n * Which scopes may contribute an override — the same\n * {@link AgentsMdScope} the host applies to `AGENTS.md`, so one setting\n * governs both surfaces:\n * - `'none'` — no override, ever. Short-circuits before any FS probe.\n * - `'user'` — only `~/.{prefix}/SYSTEM.md`. The repo's file is IGNORED,\n * which is the whole point of the setting: it is how a user\n * says \"do not trust this checkout\".\n * - `'project'` — only `<root>/SYSTEM.md`.\n * - `'both'` — union, project winning (default).\n *\n * Previously a boolean that only implemented `'none'`, so `'user'` still let a\n * repo-root `SYSTEM.md` replace the entire doctrine — exactly the case the\n * setting exists to prevent.\n */\n scope?: AgentsMdScope\n}\n\n/**\n * Absolute path of the USER-scope `SYSTEM.md` — the file the TUI creates when\n * the user asks for an override and none exists yet.\n *\n * Exported so the host doesn't hardcode the layout and can't drift from what\n * discovery actually reads.\n */\nexport function userSystemMdPath(opts: { home?: string, prefix?: string } = {}): string {\n const home = opts.home ?? homedir()\n const prefix = (opts.prefix ?? '.zidane').replace(/^\\./, '')\n return join(home, `.${prefix}`, 'SYSTEM.md')\n}\n\n/**\n * Whether a USER-scope `SYSTEM.md` would be loaded under `scope`.\n *\n * Mirrors the candidate filter in {@link discoverSystemMd} so a host can ask\n * \"would writing `~/.{prefix}/SYSTEM.md` accomplish anything?\" without\n * re-deriving the rule and drifting from it. `'project'` excludes the user\n * candidate and `'none'` skips discovery altogether, so under either setting\n * creating that file is a silent no-op.\n */\nexport function userScopeOverridesLoad(scope: AgentsMdScope | undefined): boolean {\n const effective: AgentsMdScope = scope ?? 'both'\n return effective !== 'project' && effective !== 'none'\n}\n\n/**\n * Whether a PROJECT-scope `SYSTEM.md` would be loaded under `scope`.\n *\n * The mirror of {@link userScopeOverridesLoad}, against the same candidate\n * filter. Used by {@link renderSystemMdSeed} to decide whether telling the user\n * \"a repo file outranks this one\" is true: under `'user'` the project candidate\n * is never even probed, so claiming a checkout can outrank them contradicts the\n * setting they chose precisely to distrust checkouts.\n */\nexport function projectScopeOverridesLoad(scope: AgentsMdScope | undefined): boolean {\n const effective: AgentsMdScope = scope ?? 'both'\n return effective !== 'user' && effective !== 'none'\n}\n\n/**\n * Find the active `SYSTEM.md` override, if any.\n *\n * Project paths anchor at the git root when one exists above `cwd`, else at\n * `cwd` — the same anchor as skills / mcps / AGENTS.md discovery, so all four\n * surfaces agree on what \"this project\" means.\n *\n * Tolerant: an unreadable or empty file is treated as absent (logged under\n * `ZIDANE_DEBUG`) and the next candidate gets its turn. Never throws — this\n * runs on the session-activation path.\n *\n * Candidates are filtered by {@link DiscoverSystemMdOptions.scope}, mirroring\n * how `discoverAgentsMd` builds its own list.\n */\nexport function discoverSystemMd(opts: DiscoverSystemMdOptions = {}): SystemMdResult {\n const scope: AgentsMdScope = opts.scope ?? 'both'\n // Short-circuit before touching the filesystem, same as `discoverAgentsMd`.\n if (scope === 'none')\n return { file: null, shadowed: [] }\n\n const cwd = opts.cwd ?? process.cwd()\n const projectRoot = findGitRoot(cwd) ?? cwd\n\n const candidates: { path: string, source: 'project' | 'user' }[] = []\n if (scope !== 'user')\n candidates.push({ path: join(projectRoot, 'SYSTEM.md'), source: 'project' })\n if (scope !== 'project')\n candidates.push({ path: userSystemMdPath(opts), source: 'user' })\n\n const found: SystemMdFile[] = []\n const seen = new Set<string>()\n for (const c of candidates) {\n // Dedup by absolute path. The two candidates can only ever be the same\n // file when `prefix` is empty or dot-only: `userSystemMdPath` then\n // collapses to `<home>/SYSTEM.md`, which equals the project candidate if\n // `projectRoot` is also `<home>`. With any real prefix (`.zidane`) they are\n // `<root>/SYSTEM.md` and `<home>/.zidane/SYSTEM.md` — distinct whether or\n // not `$HOME` happens to be a git repo. Without the guard that one case\n // would report the file as shadowing itself.\n if (seen.has(c.path))\n continue\n seen.add(c.path)\n const file = readIfPresent(c.path, c.source)\n if (file)\n found.push(file)\n }\n\n const [winner, ...shadowed] = found\n return { file: winner ?? null, shadowed }\n}\n\nfunction readIfPresent(path: string, source: 'project' | 'user'): SystemMdFile | null {\n if (!existsSync(path))\n return null\n let raw: string\n try {\n raw = readFileSync(path, 'utf8')\n }\n catch (err) {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/chat] system-md: failed to read \"${path}\": ${errorMessage(err)}\\n`)\n return null\n }\n const contents = raw.length > MAX_BYTES_PER_FILE\n ? `${raw.slice(0, MAX_BYTES_PER_FILE)}\\n\\n[... truncated; ${raw.length - MAX_BYTES_PER_FILE} more bytes in source file ...]`\n : raw\n // An empty override is almost certainly an accident (a file created but not\n // yet written). Treating it as absent keeps the built-in doctrine in place\n // rather than handing the model a blank prompt.\n if (contents.trim().length === 0)\n return null\n return { path, source, contents }\n}\n\n/**\n * Seed contents for a freshly created `SYSTEM.md` override, built from the\n * built-in doctrine.\n *\n * Seeding with the real doctrine (rather than an empty file) means creating the\n * override is a behavioral no-op until the user edits it. An empty seed would\n * silently delete every line of doctrine the moment the file appeared, making\n * the agent measurably worse with no visible cause.\n *\n * `currentSystem` should be DOCTRINE ONLY — callers pass\n * `splitSystemPrompt(doctrineOnlySystem()).static`, which excludes both the\n * generated `<env>` block (rebuilt per turn) and the `AGENTS.md` block. Baking\n * the latter in would duplicate it, since it is re-appended below the override\n * on every compose.\n *\n * `scope` is the active `userInstructionsScope`; it decides whether the seed's\n * precedence note is true — see {@link projectScopeOverridesLoad}.\n */\nexport function renderSystemMdSeed(currentSystem: string, scope?: AgentsMdScope): string {\n return [\n '<!--',\n ' SYSTEM.md replaces zidane\\'s built-in system prompt.',\n '',\n ' It was seeded with the built-in doctrine, so right now it changes nothing.',\n ' Edit freely.',\n '',\n ' Still applied on top of whatever you write here:',\n ' - your AGENTS.md / CLAUDE.md instructions (appended below this text)',\n ' - the <env> block (cwd, project root, date, platform)',\n '',\n // Only true when the project candidate is actually probed. Under\n // `userInstructionsScope: 'user'` it is not, and creation is still allowed\n // there — so printing this unconditionally told the one user who opted out\n // of project files that a checkout outranks them.\n ...(projectScopeOverridesLoad(scope)\n ? [' A project-level SYSTEM.md at the repo root takes precedence over this one.']\n : [' userInstructionsScope is \"user\", so a repo-level SYSTEM.md is ignored and', ' this file always wins.']),\n ' Delete this file to restore the built-in prompt.',\n '-->',\n '',\n currentSystem.trim(),\n '',\n ].join('\\n')\n}\n","import type { Theme } from '../theme'\n\n// ---------------------------------------------------------------------------\n// Catppuccin — four flavors built from the official palette.\n//\n// Hex values mirror catppuccin/palette v1.8.0 verbatim. The palette is the\n// data; `catppuccinTheme()` is the mapping into our `Theme` shape — accent\n// → role colors, semantic UI tokens (mantle = modal), and Tree-sitter syntax\n// token mappings that line up with the official Catppuccin styleguide.\n//\n// `Latte` is a light flavor (`base = #eff1f5`, `text = #4c4f69`) and only\n// looks correct in a light terminal — same caveat as the upstream VSCode\n// theme. The other three are dark.\n// ---------------------------------------------------------------------------\n\n/**\n * One Catppuccin flavor as a flat hex map. Mirrors the structure of\n * `catppuccin/palette` so the builder below maps named colors → roles\n * without any per-flavor branching.\n */\ninterface CatppuccinPalette {\n rosewater: string\n flamingo: string\n pink: string\n mauve: string\n red: string\n maroon: string\n peach: string\n yellow: string\n green: string\n teal: string\n sky: string\n sapphire: string\n blue: string\n lavender: string\n text: string\n subtext1: string\n subtext0: string\n overlay2: string\n overlay1: string\n overlay0: string\n surface2: string\n surface1: string\n surface0: string\n base: string\n mantle: string\n crust: string\n}\n\nconst LATTE: CatppuccinPalette = {\n rosewater: '#dc8a78',\n flamingo: '#dd7878',\n pink: '#ea76cb',\n mauve: '#8839ef',\n red: '#d20f39',\n maroon: '#e64553',\n peach: '#fe640b',\n yellow: '#df8e1d',\n green: '#40a02b',\n teal: '#179299',\n sky: '#04a5e5',\n sapphire: '#209fb5',\n blue: '#1e66f5',\n lavender: '#7287fd',\n text: '#4c4f69',\n subtext1: '#5c5f77',\n subtext0: '#6c6f85',\n overlay2: '#7c7f93',\n overlay1: '#8c8fa1',\n overlay0: '#9ca0b0',\n surface2: '#acb0be',\n surface1: '#bcc0cc',\n surface0: '#ccd0da',\n base: '#eff1f5',\n mantle: '#e6e9ef',\n crust: '#dce0e8',\n}\n\nconst FRAPPE: CatppuccinPalette = {\n rosewater: '#f2d5cf',\n flamingo: '#eebebe',\n pink: '#f4b8e4',\n mauve: '#ca9ee6',\n red: '#e78284',\n maroon: '#ea999c',\n peach: '#ef9f76',\n yellow: '#e5c890',\n green: '#a6d189',\n teal: '#81c8be',\n sky: '#99d1db',\n sapphire: '#85c1dc',\n blue: '#8caaee',\n lavender: '#babbf1',\n text: '#c6d0f5',\n subtext1: '#b5bfe2',\n subtext0: '#a5adce',\n overlay2: '#949cbb',\n overlay1: '#838ba7',\n overlay0: '#737994',\n surface2: '#626880',\n surface1: '#51576d',\n surface0: '#414559',\n base: '#303446',\n mantle: '#292c3c',\n crust: '#232634',\n}\n\nconst MACCHIATO: CatppuccinPalette = {\n rosewater: '#f4dbd6',\n flamingo: '#f0c6c6',\n pink: '#f5bde6',\n mauve: '#c6a0f6',\n red: '#ed8796',\n maroon: '#ee99a0',\n peach: '#f5a97f',\n yellow: '#eed49f',\n green: '#a6da95',\n teal: '#8bd5ca',\n sky: '#91d7e3',\n sapphire: '#7dc4e4',\n blue: '#8aadf4',\n lavender: '#b7bdf8',\n text: '#cad3f5',\n subtext1: '#b8c0e0',\n subtext0: '#a5adcb',\n overlay2: '#939ab7',\n overlay1: '#8087a2',\n overlay0: '#6e738d',\n surface2: '#5b6078',\n surface1: '#494d64',\n surface0: '#363a4f',\n base: '#24273a',\n mantle: '#1e2030',\n crust: '#181926',\n}\n\nconst MOCHA: CatppuccinPalette = {\n rosewater: '#f5e0dc',\n flamingo: '#f2cdcd',\n pink: '#f5c2e7',\n mauve: '#cba6f7',\n red: '#f38ba8',\n maroon: '#eba0ac',\n peach: '#fab387',\n yellow: '#f9e2af',\n green: '#a6e3a1',\n teal: '#94e2d5',\n sky: '#89dceb',\n sapphire: '#74c7ec',\n blue: '#89b4fa',\n lavender: '#b4befe',\n text: '#cdd6f4',\n subtext1: '#bac2de',\n subtext0: '#a6adc8',\n overlay2: '#9399b2',\n overlay1: '#7f849c',\n overlay0: '#6c7086',\n surface2: '#585b70',\n surface1: '#45475a',\n surface0: '#313244',\n base: '#1e1e2e',\n mantle: '#181825',\n crust: '#11111b',\n}\n\n/**\n * Compose a `Theme` from a Catppuccin palette flavor.\n *\n * Role-color picks follow the upstream Catppuccin styleguide:\n * - `mauve` is the canonical accent — used here as the brand color.\n * - `green` / `red` / `yellow` keep their universal semantic meaning.\n * - `blue` carries function / model identity (matches the VSCode plugin's\n * `support.function` mapping).\n * - `subtext1` / `overlay0` form the dim/mute pair (one step apart so the\n * two tiers stay visually distinct on every flavor).\n * - `surface1` / `overlay0` give the resting/active border pair.\n *\n * Syntax token mappings line up with the official Catppuccin token rules\n * (keyword = mauve, string = green, function = blue, type = yellow, …) so\n * code fences match what users see in their editor.\n */\nfunction catppuccinTheme(id: string, label: string, p: CatppuccinPalette): Theme {\n return {\n id,\n label,\n colors: {\n brand: p.mauve,\n accent: p.green,\n model: p.blue,\n warn: p.yellow,\n error: p.red,\n dim: p.subtext1,\n mute: p.overlay0,\n border: p.surface1,\n borderActive: p.overlay0,\n // Throbber sweeps mauve → pink — keeps the gradient inside\n // Catppuccin's warm violet/pink family. The fallback `brand →\n // accent` would interpolate mauve → green through grey.\n throbber: { from: p.mauve, to: p.pink },\n },\n select: {\n backgroundColor: 'transparent',\n focusedBackgroundColor: 'transparent',\n selectedBackgroundColor: 'transparent',\n selectedTextColor: p.mauve,\n textColor: p.subtext1,\n descriptionColor: p.overlay0,\n selectedDescriptionColor: p.subtext0,\n },\n surfaces: {\n // `crust` is the deepest tier in the palette — one step below\n // `mantle`, so the root surface stays distinct from the modal\n // elevation on every flavor (including Latte, where `crust` is\n // the darkest light-flavor tone).\n background: p.crust,\n // `mantle` is one shade darker than `base`, mirroring how the upstream\n // VSCode theme paints the sidebar against the editor — a subtle but\n // present elevation cue for the modal panel.\n modal: p.mantle,\n // Chip pills — skills on `mauve` (the canonical Catppuccin accent,\n // matches the brand role) and files on `blue` (function/identifier\n // accent in the upstream styleguide, so file mentions visually\n // rhyme with code references). Foreground is `base` for all\n // pills so dark flavors read light-on-dark and Latte's mauve/blue\n // are dark enough that `base` (`#eff1f5`) contrasts.\n chips: {\n default: { bg: p.mauve, fg: p.base },\n skills: { bg: p.mauve, fg: p.base },\n files: { bg: p.blue, fg: p.base },\n },\n // `surface0` is Catppuccin's canonical \"row highlight\" tier — one\n // step above `base`, designed for subtle elevation. Works on every\n // flavor including Latte (where it darkens against the light base).\n selection: p.surface0,\n // Diff blocks ride the palette's `green` / `red` accents pre-mixed\n // against `base`. We lean on `surface0` / `surface1` for the row\n // paint and the brighter palette accents for the sign glyph so the\n // `+` / `-` markers pop against the dimmer row tint. Catppuccin\n // doesn't ship `*Container` tokens, so we just compose with the\n // surface tiers — works on every flavor (including Latte by\n // virtue of `surface*` darkening against the light base).\n diff: {\n addBg: p.surface0,\n removeBg: p.surface0,\n addContentBg: p.surface1,\n removeContentBg: p.surface1,\n addFg: p.green,\n removeFg: p.red,\n },\n },\n syntax: {\n 'default': { fg: p.text },\n\n // ---- markdown structure ----\n 'markup.heading': { fg: p.mauve, bold: true },\n 'markup.heading.1': { fg: p.mauve, bold: true },\n 'markup.heading.2': { fg: p.lavender, bold: true },\n 'markup.heading.3': { fg: p.blue, bold: true },\n 'markup.bold': { fg: p.text, bold: true },\n 'markup.strong': { fg: p.text, bold: true },\n 'markup.italic': { fg: p.text, italic: true },\n 'markup.link': { fg: p.sky, underline: true },\n 'markup.link.url': { fg: p.sky, underline: true },\n 'markup.list': { fg: p.peach },\n 'markup.raw': { fg: p.green },\n 'markup.raw.block': { fg: p.green },\n 'markup.quote': { fg: p.overlay2, italic: true },\n\n // ---- code ----\n 'keyword': { fg: p.mauve, bold: true },\n 'keyword.import': { fg: p.pink, bold: true },\n 'keyword.operator': { fg: p.sky },\n 'string': { fg: p.green },\n 'string.escape': { fg: p.pink, bold: true },\n 'character': { fg: p.teal },\n 'comment': { fg: p.overlay1, italic: true },\n 'number': { fg: p.peach },\n 'boolean': { fg: p.peach },\n 'constant': { fg: p.peach },\n 'constant.builtin': { fg: p.peach },\n 'function': { fg: p.blue },\n 'function.call': { fg: p.blue },\n 'function.method': { fg: p.blue },\n 'function.method.call': { fg: p.blue },\n 'function.builtin': { fg: p.blue },\n 'function.macro': { fg: p.teal },\n 'type': { fg: p.yellow },\n 'type.builtin': { fg: p.yellow },\n 'constructor': { fg: p.yellow },\n 'attribute': { fg: p.yellow },\n 'tag': { fg: p.lavender },\n 'variable': { fg: p.text },\n 'variable.builtin': { fg: p.red },\n 'variable.parameter': { fg: p.maroon, italic: true },\n 'variable.member': { fg: p.text },\n 'property': { fg: p.lavender },\n 'operator': { fg: p.sky },\n 'punctuation': { fg: p.overlay2 },\n 'punctuation.bracket': { fg: p.overlay2 },\n 'punctuation.delimiter': { fg: p.overlay2 },\n 'label': { fg: p.sapphire },\n },\n }\n}\n\nexport const CATPPUCCIN_MOCHA = catppuccinTheme('catppuccin-mocha', 'Catppuccin Mocha', MOCHA)\nexport const CATPPUCCIN_MACCHIATO = catppuccinTheme('catppuccin-macchiato', 'Catppuccin Macchiato', MACCHIATO)\nexport const CATPPUCCIN_FRAPPE = catppuccinTheme('catppuccin-frappe', 'Catppuccin Frappé', FRAPPE)\n// Latte assumes a *light* terminal background (`base = #eff1f5`,\n// `text = #4c4f69`). The label is suffixed so the picker reads correctly\n// regardless of where in the cycle it lands.\nexport const CATPPUCCIN_LATTE = catppuccinTheme('catppuccin-latte', 'Catppuccin Latte (light)', LATTE)\n","import type { Theme } from '../theme'\n\n// ---------------------------------------------------------------------------\n// Crush — Charm's CharmTone \"Pantera\" dark theme.\n//\n// Palette hex values are copied verbatim from\n// `charmbracelet/x/exp/charmtone/charmtone.go`. Role assignments and visual\n// paint follow `charmbracelet/crush`'s `internal/ui/styles/quickstyle.go`\n// (the actual `Styles` struct populated for Pantera), not just the\n// `quickStyleOpts` palette — because the Chroma map, Glamour heading\n// banner, link split, and diff overrides all diverge from a naive\n// \"primary → brand\" reading.\n//\n// Notable Pantera idiosyncrasies preserved here:\n// - Headings ride `info` (Malibu blue) + bold, not the brand violet. The\n// brand violet only appears as H1's *banner background*, with `Zest`\n// yellow body text. See `quickstyle.go` `Heading` / `H1`.\n// - Inline code is `destructive` (Coral) on `bgLessVisible` (Charcoal).\n// - LinkText is `successMostSubtle` (Guac) bold; URLs are `Zinc` teal\n// with underline.\n// - Diff line / symbol / code colors are *muted* forest/maroon\n// (`#629657` / `#a45c59`) on `#323931` / `#383030`, overriding the\n// brighter `Turtle` / `Cherry` defaults in `diffview/style.go`.\n// - Surface tier cascade is Pepper → BBQ (modal) → Charcoal (selection),\n// matching `bgBase` → `bgLeastVisible` → `bgLessVisible` in Crush.\n// ---------------------------------------------------------------------------\n\nconst CHARMTONE = {\n // warm / red\n cumin: '#BF976F',\n bengal: '#FF6E63',\n sriracha: '#EB4268',\n coral: '#FF577D',\n salmon: '#FF7F90',\n cherry: '#FF388B',\n // pinks / magentas\n cheeky: '#FF79D0',\n blush: '#FF84FF',\n dolly: '#FF60FF',\n pony: '#FF4FBF',\n // purples\n mauve: '#D46EFF',\n hazy: '#8B75FF',\n charple: '#6B50FF',\n // blues\n guppy: '#7272FF',\n malibu: '#00A4FF',\n sardine: '#4FBEFE',\n // greens / teals\n zinc: '#10B1AE',\n turtle: '#0ADCD9',\n guac: '#12C78F',\n julep: '#00FFB2',\n bok: '#68FFD6',\n // yellows\n mustard: '#F5EF34',\n citron: '#E8FF27',\n zest: '#E8FE96',\n // neutrals (dark → light)\n pepper: '#201F26',\n bbq: '#2D2C35',\n charcoal: '#3A3943',\n iron: '#4D4C57',\n oyster: '#605F6B',\n squid: '#858392',\n smoke: '#BFBCC8',\n ash: '#DFDBDD',\n salt: '#F1EFEF',\n butter: '#FFFAF1',\n} as const\n\nconst c = CHARMTONE\n\nexport const CRUSH_THEME: Theme = {\n id: 'crush',\n label: 'Crush (Pantera)',\n colors: {\n // `Charple` is Pantera's `primary` — Crush dialog frames, focused\n // user-message borders, completions selection all paint with this.\n brand: c.charple,\n // `Bok` is the `accent` role (see `themes.go`). Soft mint that reads\n // as \"alive\" without competing with the brand violet.\n accent: c.bok,\n // `Malibu` is Pantera's `info` — also where headings and tool names\n // land, so it doubles as the model-identity tone here.\n model: c.malibu,\n warn: c.julep,\n // `Zest` is Charmtone's dim-yellow; reserved here for the footer's\n // cost indicator so the money figure reads as money even though\n // Crush's `warn` role intentionally stays mint (see above).\n money: c.zest,\n error: c.sriracha,\n // `Smoke` is `fgSubtle` — the body color Markdown documents inherit.\n dim: c.smoke,\n // `Oyster` is `fgMostSubtle` — tertiary tone, dimmer than `dim`.\n mute: c.oyster,\n // `Charcoal` is `separator` / `bgLessVisible` — Crush's resting border.\n border: c.charcoal,\n // Focused elements in Crush get a `primary` (Charple) rim — dialog\n // frames, focused message borders, the compact details panel.\n borderActive: c.charple,\n // Working-throbber gradient: `primary` → `secondary`, exactly the\n // `WorkingGradFromColor` / `WorkingGradToColor` pair Crush's\n // `quickStyle` populates for the `Anim` spinner.\n throbber: { from: c.charple, to: c.dolly },\n },\n select: {\n backgroundColor: 'transparent',\n focusedBackgroundColor: 'transparent',\n selectedBackgroundColor: 'transparent',\n selectedTextColor: c.charple,\n textColor: c.smoke,\n descriptionColor: c.oyster,\n selectedDescriptionColor: c.squid,\n },\n surfaces: {\n // Surface cascade mirrors Crush's neutral tier ladder:\n // Pepper (bgBase) → BBQ (bgLeastVisible) → Charcoal (bgLessVisible).\n background: c.pepper,\n modal: c.bbq,\n // Chips:\n // - skills (slash commands) ride `primary` / `onPrimary` — the same\n // pair Crush uses for `Completions.Focused` and\n // `Dialog.SelectedItem`.\n // - files ride `info` / `onPrimary` — `info` carries tool / file /\n // reference identity throughout Crush (JobToolName, MCPName).\n chips: {\n default: { bg: c.charple, fg: c.butter },\n skills: { bg: c.charple, fg: c.butter },\n files: { bg: c.malibu, fg: c.butter },\n },\n // Selected-turn lift — `Charcoal`, the same tier Crush uses for\n // separators and resting borders. One step above `modal` (BBQ).\n selection: c.charcoal,\n // Diff blocks — values from Crush's `Styles.Diff` overrides in\n // `quickstyle.go` (lines ~480–500), not the brighter `DefaultDarkStyle`\n // in `diffview/style.go`. Symbol fg `#629657` / `#a45c59` rides the\n // muted forest / maroon Crush actually renders.\n diff: {\n addBg: '#2b322a',\n removeBg: '#312929',\n addContentBg: '#323931',\n removeContentBg: '#383030',\n addFg: '#629657',\n removeFg: '#a45c59',\n },\n },\n syntax: {\n // Chroma `Text` → `fgSubtle` (Smoke). Code body reads one tier below\n // `Ash` / `Salt` — matches Crush's `CodeBlock.Chroma.Text` color.\n 'default': { fg: c.smoke },\n\n // ---- markdown structure ----\n // Heading parent block: `info` + bold. H2-H5 inherit this in Crush\n // (they only add prefix tokens), so we replicate Malibu+bold across\n // levels and override H1 with the brand banner below.\n 'markup.heading': { fg: c.malibu, bold: true },\n // H1 is Crush's signature: bold body text on a `primary` (Charple)\n // background banner. Crush ships `warningSubtle` (Zest yellow) text\n // there; we use `onPrimary` (Butter) cream instead — same banner\n // vibe, drops the yellow that was bleeding into the rest of the UI.\n 'markup.heading.1': { fg: c.butter, bg: c.charple, bold: true },\n 'markup.heading.2': { fg: c.malibu, bold: true },\n 'markup.heading.3': { fg: c.malibu, bold: true },\n // Strong / Emph in Crush set only weight/slant — color inherits from\n // the Document (Smoke). We match by keeping `fg: smoke`.\n 'markup.bold': { fg: c.smoke, bold: true },\n 'markup.strong': { fg: c.smoke, bold: true },\n 'markup.italic': { fg: c.smoke, italic: true },\n // Crush splits links: `LinkText` (the visible label) is\n // `successMostSubtle` (Guac) + bold; `Link` (the URL) is `Zinc`\n // (teal) + underline.\n 'markup.link': { fg: c.guac, bold: true },\n 'markup.link.url': { fg: c.zinc, underline: true },\n // List `Item` in Crush has no color override — bullets inherit\n // Document color (Smoke).\n 'markup.list': { fg: c.smoke },\n // Inline `Code`: `destructive` (Coral) on `bgLessVisible` (Charcoal).\n 'markup.raw': { fg: c.coral, bg: c.charcoal },\n 'markup.raw.block': { fg: c.coral, bg: c.charcoal },\n // BlockQuote in Crush is just indented with `│ ` — no color or italic.\n // We keep `fg: smoke` to match Document inheritance.\n 'markup.quote': { fg: c.smoke },\n\n // ---- code (Chroma mapping from `quickstyle.go`) ----\n 'keyword': { fg: c.malibu }, // Chroma `Keyword` → info\n 'keyword.import': { fg: c.pony }, // KeywordNamespace\n 'keyword.operator': { fg: c.salmon }, // Operator\n 'string': { fg: c.cumin }, // LiteralString\n 'string.escape': { fg: c.bok }, // LiteralStringEscape → successMoreSubtle\n 'character': { fg: c.cumin },\n 'comment': { fg: c.oyster, italic: true }, // fgMostSubtle (italic kept for legibility)\n 'number': { fg: c.julep }, // LiteralNumber → success\n 'boolean': { fg: c.julep },\n 'constant': { fg: c.julep },\n 'constant.builtin': { fg: c.julep },\n 'function': { fg: c.guac }, // NameFunction → successMostSubtle\n 'function.call': { fg: c.guac },\n 'function.method': { fg: c.guac },\n 'function.method.call': { fg: c.guac },\n 'function.builtin': { fg: c.cheeky }, // NameBuiltin\n 'function.macro': { fg: c.bok }, // NameDecorator\n 'type': { fg: c.guppy }, // KeywordType\n 'type.builtin': { fg: c.guppy },\n // `NameClass` in Crush is `Salt` + bold + underline. We drop underline\n // (noisy for non-class types in our broader `constructor` capture).\n 'constructor': { fg: c.salt, bold: true },\n 'attribute': { fg: c.hazy }, // NameAttribute\n 'tag': { fg: c.mauve }, // NameTag\n 'variable': { fg: c.smoke }, // Name → fgSubtle\n 'variable.builtin': { fg: c.cheeky },\n 'variable.parameter': { fg: c.smoke, italic: true },\n 'variable.member': { fg: c.smoke },\n 'property': { fg: c.smoke },\n 'operator': { fg: c.salmon },\n // Crush maps `Punctuation → warningSubtle` (Zest), but at our token\n // granularity that paints every bracket / comma / dot yellow — too\n // much yellow in dense code. Drop to `Squid` (fgMoreSubtle) so\n // punctuation recedes behind the colored tokens it separates.\n 'punctuation': { fg: c.squid },\n 'punctuation.bracket': { fg: c.squid },\n 'punctuation.delimiter': { fg: c.squid },\n 'label': { fg: c.malibu },\n },\n}\n","import type { Theme } from '../theme'\n\ninterface GruvboxPalette {\n dark: boolean\n bg0: string\n bg1: string\n bg2: string\n bg3: string\n bg4: string\n fg0: string\n fg1: string\n fg2: string\n fg3: string\n fg4: string\n red: string\n green: string\n yellow: string\n blue: string\n purple: string\n aqua: string\n orange: string\n gray: string\n}\n\nconst DARK: GruvboxPalette = {\n dark: true,\n bg0: '#282828',\n bg1: '#3c3836',\n bg2: '#504945',\n bg3: '#665c54',\n bg4: '#7c6f64',\n fg0: '#fbf1c7',\n fg1: '#ebdbb2',\n fg2: '#d5c4a1',\n fg3: '#bdae93',\n fg4: '#a89984',\n red: '#fb4934',\n green: '#b8bb26',\n yellow: '#fabd2f',\n blue: '#83a598',\n purple: '#d3869b',\n aqua: '#8ec07c',\n orange: '#fe8019',\n gray: '#928374',\n}\n\nconst LIGHT: GruvboxPalette = {\n dark: false,\n bg0: '#fbf1c7',\n bg1: '#ebdbb2',\n bg2: '#d5c4a1',\n bg3: '#bdae93',\n bg4: '#a89984',\n fg0: '#282828',\n fg1: '#3c3836',\n fg2: '#504945',\n fg3: '#665c54',\n fg4: '#7c6f64',\n red: '#cc241d',\n green: '#98971a',\n yellow: '#d79921',\n blue: '#458588',\n purple: '#b16286',\n aqua: '#689d6a',\n orange: '#d65d0e',\n gray: '#928374',\n}\n\nfunction gruvboxTheme(id: string, label: string, p: GruvboxPalette): Theme {\n return {\n id,\n label,\n colors: {\n brand: p.yellow,\n accent: p.green,\n model: p.blue,\n warn: p.orange,\n error: p.red,\n dim: p.fg3,\n mute: p.gray,\n border: p.bg2,\n borderActive: p.bg4,\n throbber: { from: p.yellow, to: p.orange },\n money: p.yellow,\n },\n select: {\n backgroundColor: 'transparent',\n focusedBackgroundColor: 'transparent',\n selectedBackgroundColor: 'transparent',\n selectedTextColor: p.yellow,\n textColor: p.fg2,\n descriptionColor: p.fg4,\n selectedDescriptionColor: p.fg3,\n },\n surfaces: {\n background: p.dark ? '#1d2021' : '#f9f5d7',\n modal: p.bg0,\n chips: {\n default: { bg: p.yellow, fg: p.dark ? p.bg0 : p.fg0 },\n skills: { bg: p.yellow, fg: p.dark ? p.bg0 : p.fg0 },\n files: { bg: p.blue, fg: p.dark ? p.bg0 : '#fbf1c7' },\n },\n selection: p.bg1,\n diff: {\n addBg: p.bg1,\n removeBg: p.bg1,\n addContentBg: p.bg2,\n removeContentBg: p.bg2,\n addFg: p.green,\n removeFg: p.red,\n },\n },\n syntax: {\n 'default': { fg: p.fg1 },\n 'markup.heading': { fg: p.yellow, bold: true },\n 'markup.heading.1': { fg: p.yellow, bold: true },\n 'markup.heading.2': { fg: p.orange, bold: true },\n 'markup.heading.3': { fg: p.blue, bold: true },\n 'markup.bold': { fg: p.fg0, bold: true },\n 'markup.strong': { fg: p.fg0, bold: true },\n 'markup.italic': { fg: p.fg1, italic: true },\n 'markup.link': { fg: p.blue, underline: true },\n 'markup.link.url': { fg: p.blue, underline: true },\n 'markup.list': { fg: p.orange },\n 'markup.raw': { fg: p.green },\n 'markup.raw.block': { fg: p.green },\n 'markup.quote': { fg: p.fg4, italic: true },\n\n 'keyword': { fg: p.red, bold: true },\n 'keyword.import': { fg: p.red, bold: true },\n 'keyword.operator': { fg: p.orange },\n 'string': { fg: p.green },\n 'string.escape': { fg: p.orange, bold: true },\n 'character': { fg: p.aqua },\n 'comment': { fg: p.gray, italic: true },\n 'number': { fg: p.purple },\n 'boolean': { fg: p.purple },\n 'constant': { fg: p.purple },\n 'constant.builtin': { fg: p.purple },\n 'function': { fg: p.blue },\n 'function.call': { fg: p.blue },\n 'function.method': { fg: p.blue },\n 'function.method.call': { fg: p.blue },\n 'function.builtin': { fg: p.blue },\n 'function.macro': { fg: p.aqua },\n 'type': { fg: p.yellow },\n 'type.builtin': { fg: p.yellow },\n 'constructor': { fg: p.yellow },\n 'attribute': { fg: p.aqua },\n 'tag': { fg: p.aqua },\n 'variable': { fg: p.fg1 },\n 'variable.builtin': { fg: p.red },\n 'variable.parameter': { fg: p.orange, italic: true },\n 'variable.member': { fg: p.fg1 },\n 'property': { fg: p.blue },\n 'operator': { fg: p.orange },\n 'punctuation': { fg: p.fg4 },\n 'punctuation.bracket': { fg: p.fg2 },\n 'punctuation.delimiter': { fg: p.fg4 },\n 'label': { fg: p.aqua },\n },\n }\n}\n\nexport const GRUVBOX_DARK = gruvboxTheme('gruvbox-dark', 'Gruvbox Dark', DARK)\nexport const GRUVBOX_LIGHT = gruvboxTheme('gruvbox-light', 'Gruvbox Light', LIGHT)\n","import type { Theme } from '../theme'\n\n// ---------------------------------------------------------------------------\n// Light — the vanilla light theme every mainstream app ships (Slack, VS Code,\n// Zed, google.com): white background, near-black text, one restrained blue\n// brand accent, conventional green / red / amber for success / error / warn.\n// Not a \"flavor\" of any palette family — deliberately neutral so users who\n// just want \"regular light mode\" have an opt-in that isn't a special theme.\n//\n// Palette draws from the GitHub Light register because it's the most widely\n// recognized neutral light palette in developer tooling and reads correctly\n// on every light terminal background.\n// ---------------------------------------------------------------------------\n\nconst TEXT = '#1f2328' // primary foreground — graphite, not pure black\nconst DIM = '#656d76' // secondary text — captions, helper rows\nconst MUTE = '#8c959f' // tertiary text — separators, the `┃` bar\nconst BORDER = '#d0d7de' // resting border\nconst BORDER_ACTIVE = '#0969da' // brand blue — focused / active rims\n\nconst BRAND = '#0969da' // GitHub link blue — the universal \"click me\" hue\nconst ACCENT = '#1a7f37' // success green\nconst MODEL = '#0550ae' // deeper brand sibling — model id, links\nconst WARN = '#9a6700' // amber on light — readable, doesn't blow out\nconst ERROR = '#d1242f' // danger red\n\nexport const LIGHT_THEME: Theme = {\n id: 'light',\n label: 'Light',\n colors: {\n brand: BRAND,\n accent: ACCENT,\n model: MODEL,\n warn: WARN,\n error: ERROR,\n dim: DIM,\n mute: MUTE,\n border: BORDER,\n borderActive: BORDER_ACTIVE,\n // Throbber sweeps the two brand-blue siblings — stays in-family\n // without detouring through green via the fallback.\n throbber: { from: BRAND, to: MODEL },\n },\n select: {\n backgroundColor: 'transparent',\n focusedBackgroundColor: 'transparent',\n selectedBackgroundColor: 'transparent',\n selectedTextColor: BRAND,\n textColor: TEXT,\n descriptionColor: MUTE,\n selectedDescriptionColor: DIM,\n },\n surfaces: {\n background: '#ffffff',\n // One tier up from the body — same elevation cue every light app\n // uses (GitHub `canvas.subtle`, VS Code light sidebar, …).\n modal: '#f6f8fa',\n // Skills get the saturated brand pill (blue bg, near-white fg).\n // Files get the inverse — pale blue bg with deep brand fg — so\n // the two reference kinds read as paired counterparts on light.\n chips: {\n default: { bg: BRAND, fg: '#ffffff' },\n skills: { bg: BRAND, fg: '#ffffff' },\n files: { bg: '#ddf4ff', fg: '#0550ae' },\n },\n // Neutral, one step below the page: lifted, not tinted.\n selection: '#eceef1',\n // GitHub diff palette. Row paint is the pale `*Subtle` tier; the\n // content column punches a half-tier deeper so syntax-highlighted\n // code contrasts cleanly against the gutter.\n diff: {\n addBg: '#dafbe1',\n removeBg: '#ffebe9',\n addContentBg: '#aceebb',\n removeContentBg: '#ffcecb',\n addFg: ACCENT,\n removeFg: ERROR,\n },\n },\n syntax: {\n // ---- markdown structure ----\n // Headings cascade through brand blue → deeper brand → graphite so\n // the outline reads as one related family. Body rides `TEXT`.\n 'default': { fg: TEXT },\n 'markup.heading': { fg: BRAND, bold: true },\n 'markup.heading.1': { fg: BRAND, bold: true },\n 'markup.heading.2': { fg: MODEL, bold: true },\n 'markup.heading.3': { fg: TEXT, bold: true },\n 'markup.bold': { fg: TEXT, bold: true },\n 'markup.strong': { fg: TEXT, bold: true },\n 'markup.italic': { fg: TEXT, italic: true },\n 'markup.link': { fg: BRAND, underline: true },\n 'markup.link.url': { fg: BRAND, underline: true },\n 'markup.list': { fg: '#953800' }, // warm orange — stands apart from headings + body\n 'markup.raw': { fg: '#953800' },\n 'markup.raw.block': { fg: '#953800' },\n 'markup.quote': { fg: DIM, italic: true },\n\n // ---- code (GitHub Light token mapping) ----\n 'keyword': { fg: '#cf222e', bold: true },\n 'keyword.import': { fg: '#cf222e', bold: true },\n 'keyword.operator': { fg: '#cf222e' },\n 'string': { fg: '#0a3069' },\n 'string.escape': { fg: '#0a3069', bold: true },\n 'character': { fg: '#0a3069' },\n 'comment': { fg: '#6e7781', italic: true },\n 'number': { fg: '#0550ae' },\n 'boolean': { fg: '#0550ae' },\n 'constant': { fg: '#0550ae' },\n 'constant.builtin': { fg: '#0550ae' },\n 'function': { fg: '#8250df' },\n 'function.call': { fg: '#8250df' },\n 'function.method': { fg: '#8250df' },\n 'function.method.call': { fg: '#8250df' },\n 'function.builtin': { fg: '#8250df' },\n 'function.macro': { fg: '#8250df' },\n 'type': { fg: '#953800' },\n 'type.builtin': { fg: '#953800' },\n 'constructor': { fg: '#953800' },\n 'attribute': { fg: '#0550ae' },\n 'tag': { fg: '#116329' },\n 'variable': { fg: TEXT },\n 'variable.builtin': { fg: '#0550ae' },\n 'variable.parameter': { fg: '#953800' },\n 'variable.member': { fg: '#0550ae' },\n 'property': { fg: '#0550ae' },\n 'operator': { fg: '#cf222e' },\n 'punctuation': { fg: DIM },\n 'punctuation.bracket': { fg: TEXT },\n 'punctuation.delimiter': { fg: TEXT },\n 'label': { fg: '#0550ae' },\n },\n}\n","import type { Theme } from '../theme'\n\n// ---------------------------------------------------------------------------\n// Vaporwave — neon-on-dark, ported from this-fifo/vaporwave-theme-vscode.\n//\n// Hex values come straight from the upstream `vaporwave-color-theme.json`\n// (terminal ANSI table + tokenColors). The signature pink (#E95378) carries\n// the brand role; the bright pink (#FF71CE) is reserved for the keyword\n// token so headings and keywords visually rhyme without competing.\n// ---------------------------------------------------------------------------\n\nconst PALETTE = {\n pink: '#E95378',\n pinkBright: '#FF71CE',\n cyan: '#01CDFE',\n cyanBright: '#59E1E3',\n blue: '#94D0FF',\n green: '#29D398',\n greenBright: '#09F7A0',\n yellow: '#FFFB96',\n red: '#F43E5C',\n text: '#D5D8DA',\n /**\n * ~70% of `text` — used for captions / helper / \"dim\" text so that\n * secondary copy is visually distinct from primary copy. Matches the\n * upstream theme's sidebar foreground (`#b7c5d3`) tonality.\n */\n textDim: '#B7C5D3',\n textBright: '#EEFFFF',\n comment: '#BBBBBB',\n muted: '#6C6F93',\n surface: '#2E303E',\n panel: '#232530',\n // One step below `panel` — mirrors the upstream theme's editor background\n // relative to widgets so modals continue to read as elevated.\n bgDeep: '#1a1c26',\n}\n\nexport const VAPORWAVE_THEME: Theme = {\n id: 'vaporwave',\n label: 'Vaporwave',\n colors: {\n brand: PALETTE.pink,\n accent: PALETTE.greenBright,\n model: PALETTE.blue,\n warn: PALETTE.yellow,\n error: PALETTE.red,\n dim: PALETTE.textDim,\n mute: PALETTE.muted,\n border: PALETTE.surface,\n borderActive: PALETTE.muted,\n // The iconic vaporwave gradient — hot pink to electric cyan. The\n // fallback `brand → accent` would sweep pink → neon green, which\n // misses the synth-cassette aesthetic entirely.\n throbber: { from: PALETTE.pink, to: PALETTE.cyan },\n },\n select: {\n backgroundColor: 'transparent',\n focusedBackgroundColor: 'transparent',\n selectedBackgroundColor: 'transparent',\n selectedTextColor: PALETTE.pink,\n textColor: PALETTE.text,\n descriptionColor: PALETTE.muted,\n selectedDescriptionColor: PALETTE.text,\n },\n surfaces: {\n // Root paint — sits one tier below `modal` so overlaid panels still\n // read as elevated.\n background: PALETTE.bgDeep,\n // Upstream uses `#232530` for editor widgets / dropdowns — same elevation\n // role as our modal panels.\n modal: PALETTE.panel,\n // Chip pills — skills on the signature vaporwave pink (brand role)\n // and files on cyan (the upstream's secondary neon accent). Both\n // read unmistakably against the dark panel foreground.\n chips: {\n default: { bg: PALETTE.pink, fg: PALETTE.panel },\n skills: { bg: PALETTE.pink, fg: PALETTE.panel },\n files: { bg: PALETTE.cyan, fg: PALETTE.panel },\n },\n // `surface` is one shade above `panel` — a quiet purple-grey lift\n // that reads as \"active row\" without clashing with the neon pink.\n selection: PALETTE.surface,\n // Diff blocks — vaporwave doesn't ship desaturated red/green palette\n // tones, so we hand-mix dark wines + dark teals against `panel` for\n // the row paint and brighter neon `green` / `red` for the sign\n // glyph. Keeps the neon vibe without drowning the syntax-highlighted\n // code under saturated bands.\n diff: {\n addBg: '#1a3528',\n removeBg: '#3a1a23',\n addContentBg: '#234c39',\n removeContentBg: '#52232f',\n addFg: PALETTE.greenBright,\n removeFg: PALETTE.red,\n },\n },\n syntax: {\n 'default': { fg: PALETTE.text },\n\n // ---- markdown structure ----\n 'markup.heading': { fg: PALETTE.pink, bold: true },\n 'markup.heading.1': { fg: PALETTE.pink, bold: true },\n 'markup.heading.2': { fg: PALETTE.pinkBright, bold: true },\n 'markup.heading.3': { fg: PALETTE.blue, bold: true },\n 'markup.bold': { fg: PALETTE.textBright, bold: true },\n 'markup.strong': { fg: PALETTE.textBright, bold: true },\n 'markup.italic': { fg: PALETTE.greenBright, italic: true },\n 'markup.link': { fg: PALETTE.yellow, underline: true },\n 'markup.link.url': { fg: PALETTE.yellow, underline: true },\n 'markup.list': { fg: PALETTE.textBright },\n 'markup.raw': { fg: PALETTE.yellow },\n 'markup.raw.block': { fg: PALETTE.yellow },\n 'markup.quote': { fg: PALETTE.yellow, italic: true },\n\n // ---- code (mirrors the upstream tokenColors mapping) ----\n 'keyword': { fg: PALETTE.pinkBright, bold: true },\n 'keyword.import': { fg: PALETTE.pinkBright, bold: true },\n 'keyword.operator': { fg: PALETTE.comment },\n 'string': { fg: PALETTE.yellow },\n 'string.escape': { fg: PALETTE.greenBright, bold: true },\n 'character': { fg: PALETTE.yellow },\n 'comment': { fg: PALETTE.comment, italic: true },\n 'number': { fg: PALETTE.textBright },\n 'boolean': { fg: PALETTE.textBright },\n 'constant': { fg: PALETTE.textBright },\n 'constant.builtin': { fg: PALETTE.textBright },\n 'function': { fg: PALETTE.greenBright },\n 'function.call': { fg: PALETTE.greenBright },\n 'function.method': { fg: PALETTE.greenBright },\n 'function.method.call': { fg: PALETTE.greenBright },\n 'function.builtin': { fg: PALETTE.greenBright },\n 'function.macro': { fg: PALETTE.greenBright },\n 'type': { fg: PALETTE.greenBright },\n 'type.builtin': { fg: PALETTE.greenBright },\n 'constructor': { fg: PALETTE.greenBright },\n 'attribute': { fg: PALETTE.yellow },\n 'tag': { fg: PALETTE.blue },\n 'variable': { fg: PALETTE.blue },\n 'variable.builtin': { fg: PALETTE.cyanBright },\n 'variable.parameter': { fg: PALETTE.text },\n 'variable.member': { fg: PALETTE.blue },\n 'property': { fg: PALETTE.blue },\n 'operator': { fg: PALETTE.comment },\n 'punctuation': { fg: PALETTE.comment },\n 'punctuation.bracket': { fg: PALETTE.textBright },\n 'punctuation.delimiter': { fg: PALETTE.comment },\n 'label': { fg: PALETTE.cyan },\n },\n}\n","/**\n * Renderer-agnostic theme system.\n *\n * A `Theme` bundles every variable that can change visually between\n * \"themes\" — colors, select-row styling, code/markdown syntax highlight\n * tokens, panel backgrounds. Plain JSON: no OpenTUI dependency, no React,\n * no functions. The TUI consumes the theme by reading from `useTheme()`\n * and converting hex strings into OpenTUI's `RGBA`/`SyntaxStyle`; a future\n * GUI consumes the same theme by converting into CSS variables or Tailwind\n * tokens.\n *\n * Components should always read theme values through `useTheme()` /\n * `useColors()` so a runtime theme switch (Settings → Theme) re-paints\n * the whole tree. Importing a raw theme object directly bypasses the\n * context and pins the component to a single look.\n *\n * Built-in flavors (Catppuccin, Vaporwave) live in `./themes/`. This file\n * just defines the shape + the default theme + the registry.\n */\n\nimport {\n CATPPUCCIN_FRAPPE,\n CATPPUCCIN_LATTE,\n CATPPUCCIN_MACCHIATO,\n CATPPUCCIN_MOCHA,\n} from './themes/catppuccin'\nimport { CRUSH_THEME } from './themes/crush'\nimport { GRUVBOX_DARK, GRUVBOX_LIGHT } from './themes/gruvbox'\nimport { LIGHT_THEME } from './themes/light'\nimport { VAPORWAVE_THEME } from './themes/vaporwave'\n\n/** Role-named color palette. Reused throughout the UI for text, borders, accents. */\nexport interface ThemeColors {\n /** Primary accent — selected text, brand emphasis (e.g. `▶` markers). */\n brand: string\n /** Success / progress accent — used sparingly. */\n accent: string\n /** Model badge accent (provider/model name in the footer, links). */\n model: string\n /** Warnings — busy spinner, approval picker border, esc hints. */\n warn: string\n /** Errors — `✗` prefix on error events, validation messages. */\n error: string\n /** Secondary text — captions, helper text, dim transcript lines. */\n dim: string\n /** Tertiary text — separators, descriptions, the `┃` tool-result bar. */\n mute: string\n /** Resting border color. */\n border: string\n /** Border color on focused / active elements. */\n borderActive: string\n /**\n * Optional gradient endpoints for the in-chat working throbber\n * (`<CrushThrobber>`). Falls back to `[brand, accent]` when unset.\n * Themes can pin a richer pair here — e.g. Crush's `Charple` →\n * `Dolly` purple-to-pink — without having to repurpose `accent`.\n */\n throbber?: { from: string, to: string }\n /**\n * Optional tone for the footer's session-cost indicator. Falls back\n * to `warn` when unset. Carved out as its own role because some\n * themes (e.g. Crush) intentionally bind `warn` to a non-yellow tone\n * and a separate \"money\" color reads more naturally on the footer.\n */\n money?: string\n}\n\n/** Select-component styling. Plain prop shape; both OpenTUI's `<select>` and any GUI equivalent can consume this. */\nexport interface ThemeSelect {\n backgroundColor: string\n focusedBackgroundColor: string\n selectedBackgroundColor: string\n selectedTextColor: string\n textColor: string\n descriptionColor: string\n selectedDescriptionColor: string\n}\n\n/** Background + foreground pair for a completion-reference chip pill. */\nexport interface ChipColor {\n /** Background paint — the pill itself. High-saturation by convention. */\n bg: string\n /** Foreground paint — the chip text. Pre-paired with {@link ChipColor.bg} for legibility. */\n fg: string\n}\n\n/**\n * Chip colors keyed by completion-provider id (`'skills'`, `'files'`, …).\n * `default` is the required fallback used by any provider id without an\n * explicit entry — keeps host-registered providers themable out of the\n * box. Use {@link resolveChipColor} to perform the kind-specific → default\n * lookup rather than indexing the map directly.\n */\n/**\n * Map of provider id → chip color pair. `default` is required so callers\n * always have a fallback; every other key is optional so direct indexing\n * (`chips['unknown']`) surfaces as `ChipColor | undefined` and nudges\n * consumers toward {@link resolveChipColor}, which encodes the fallback.\n */\nexport type ChipColorMap = { default: ChipColor } & Partial<Record<string, ChipColor>>\n\n/**\n * Look up the chip color pair for a provider id, falling back to\n * `chips.default` when the theme has no kind-specific entry. Mirrors\n * `resolveChipStyleId` so both rendering surfaces (submitted echo +\n * live textarea) share one canonical lookup rule.\n */\nexport function resolveChipColor(chips: ChipColorMap, providerId: string): ChipColor {\n return chips[providerId] ?? chips.default\n}\n\n/** Panel / surface backgrounds. */\nexport interface ThemeSurfaces {\n /**\n * Solid paint for the app's root surface. Covers the whole TUI viewport\n * so transparent / translucent terminals don't show desktop windows\n * underneath. Conventionally one tier deeper than {@link modal} so\n * modal panels still read as elevated above the body.\n */\n background: string\n /** Background of an overlaid modal panel (settings, model picker, …). */\n modal: string\n /**\n * Completion-chip color pairs keyed by provider id. Built-in themes\n * ship distinct `skills` + `files` tones so the two reference kinds\n * read differently in both the submitted echo and the live textarea.\n */\n chips: ChipColorMap\n /**\n * Background paint for the selected turn's events in select-turn mode.\n * Subtle, low-saturation lift from the terminal default so the whole\n * span of the selected turn reads as one continuous highlighted block\n * without overpowering the foreground text. Inverse-tinted on the\n * light flavor (Latte) so the same visual role works there.\n */\n selection: string\n /**\n * Edit-diff color block. Drives the native `<diff>` renderable used\n * by {@link Settings.showEditDiffs}. Pre-mixed against each theme's\n * primary surface so terminals without true alpha-blend get a\n * legible \"subtle red / subtle green\" effect rather than a flat\n * saturated band.\n *\n * - `*Bg` row-level paint (gutter + content)\n * - `*ContentBg` content-only paint (overrides `*Bg` on the text\n * column). Set when a deeper hue should punch\n * through behind the syntax-highlighted code; omit\n * to let `*Bg` carry the full row.\n * - `*Fg` color for the `+` / `-` glyph in the sign gutter.\n */\n diff: DiffSurfaces\n}\n\n/** Per-row paints used by the native `<diff>` renderable. */\nexport interface DiffSurfaces {\n addBg: string\n removeBg: string\n contextBg?: string\n addContentBg?: string\n removeContentBg?: string\n addFg: string\n removeFg: string\n}\n\n/**\n * One entry in a `SyntaxStyles` map — what OpenTUI's `SyntaxStyle.fromStyles`\n * accepts, minus the `RGBA` conversion. Renderer-agnostic JSON.\n */\nexport interface SyntaxTokenStyle {\n fg?: string\n bg?: string\n bold?: boolean\n italic?: boolean\n underline?: boolean\n dim?: boolean\n}\n\n/**\n * Map of Tree-sitter / markdown capture group → token style.\n *\n * Two flavours of keys live in the same table:\n * - `markup.*` — the markdown structure captures (heading, bold, italic,\n * list, quote, raw inline + block, link). OpenTUI's markdown parser\n * emits these for the markdown text itself.\n * - bare token names (`keyword`, `string`, `function`, …) — emitted by\n * the embedded language Tree-sitter grammars when a code fence\n * declares a language. OpenTUI passes the same `SyntaxStyle` down to\n * the fenced-code renderable, so this map drives both surfaces.\n */\nexport type SyntaxStyles = Record<string, SyntaxTokenStyle>\n\n/** Full theme bundle. */\nexport interface Theme {\n /** Stable identifier, used as the key in `BUILTIN_THEMES` and `Settings.theme`. */\n id: string\n /** Human-readable label shown in the settings picker. */\n label: string\n colors: ThemeColors\n select: ThemeSelect\n surfaces: ThemeSurfaces\n syntax: SyntaxStyles\n}\n\n// ---------------------------------------------------------------------------\n// Default theme — a cool blue-accent palette mapped to our role-named slots\n//\n// Source: a dark design-system palette + dark-theme semantic tokens. We\n// pick the dark variants because the TUI almost always renders on dark\n// terminals; the few light-terminal users get the same hues a step\n// brighter / cooler than the comparable light-theme tokens, which still\n// reads as \"brand blue / orange / red / green\" and remains accessible.\n//\n// Color-role mapping. Every \"accent\" slot stays inside the blue brand\n// cascade (brand-300 → brand-400 → brand-500 → brand-600) so the\n// chrome reads as one cool family rather than a mosaic of warm + cool\n// dots. Warm tones (orange, red) are reserved for genuine error /\n// danger contexts only:\n//\n// brand-600 borderActive #1488fc focused / active rims\n// brand-500 brand #2ba6ff signature accent — session title, ▶\n// brand-400 warn #53c4ff shortcut keys, spinner, accent numbers\n// brand-300 model #8adaff model id, links, soft brand sibling\n// green-500 accent #22c55e success — spawn markers, ✓\n// red-500 error #ef4444 errors, ✗ glyphs\n// neutral-400 dim #a3a3ac secondary text\n// neutral-600 mute #525258 separators, `┃` bar\n// neutral-700 border #3c3c41 resting borders\n//\n// `warn` lives in the brand cascade rather than orange so the hint\n// rows (which use it for every shortcut key) don't strafe orange dots\n// across an otherwise cool surface. The spinner + approval picker\n// pick up the same brand-tinted accent — reads as \"working / attention\"\n// without competing with the red of `error`.\n//\n// Defined as a local constant first so `BUILTIN_THEMES` references it\n// by name, and so the markdown-structure entries can interpolate the\n// role-named colors without redeclaring them.\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_COLORS: ThemeColors = {\n brand: '#2ba6ff', // brand-500\n accent: '#22c55e', // green-500 (success)\n model: '#8adaff', // brand-300 (soft sky)\n warn: '#53c4ff', // brand-400 (cool accent — keys, spinner, \"attention\")\n error: '#ef4444', // red-500 (danger)\n dim: '#a3a3ac', // neutral-400\n mute: '#525258', // neutral-600\n border: '#3c3c41', // neutral-700\n borderActive: '#1488fc', // brand-600\n // Throbber sweeps brand-500 → brand-300 — a brand-family blue\n // gradient that stays on-message instead of detouring through\n // `accent` green via the fallback.\n throbber: { from: '#2ba6ff', to: '#8adaff' },\n}\n\nexport const DEFAULT_THEME: Theme = {\n id: 'default',\n label: 'Default',\n colors: DEFAULT_COLORS,\n select: {\n // Transparent backgrounds keep the highlight bar from filling with a\n // different color than the surrounding box. The `▶` marker + brand-\n // colored selected text carry the focus affordance instead.\n backgroundColor: 'transparent',\n focusedBackgroundColor: 'transparent',\n selectedBackgroundColor: 'transparent',\n selectedTextColor: DEFAULT_COLORS.brand,\n textColor: DEFAULT_COLORS.dim,\n descriptionColor: DEFAULT_COLORS.mute,\n selectedDescriptionColor: DEFAULT_COLORS.dim,\n },\n surfaces: {\n // One tier below `modal` — neutral-1000-ish — so modal panels still\n // read as elevated above the body when both paint at the same time.\n background: '#0a0a0c',\n // The `--surface` dark tone — neutral-950.\n modal: '#111114',\n // Skills (slash-commands, user verbs) get the signature bold-brand\n // pill — saturated `brand-500` background with very light brand\n // text on top: primary action, attention-getting. Files (resource\n // references) get the *inverted* sibling — bright `brand-300`\n // background with deep `brand-950` text. Both pills are vibrant\n // and clearly in the brand family, but they sit on opposite ends\n // of the saturation/lightness axis, so they read as deliberately\n // paired counterparts rather than two pills competing for the\n // same visual role.\n chips: {\n default: { bg: DEFAULT_COLORS.brand, fg: '#eef9ff' },\n skills: { bg: DEFAULT_COLORS.brand, fg: '#eef9ff' },\n files: { bg: '#8adaff', fg: '#122f59' },\n },\n // A neutral lift: a selected turn reads as lifted, not as a blue wash\n // over the whole reply.\n selection: '#1c1c21',\n // Diff blocks — `green-950` / `red-950` pre-mixed over neutral-950 at\n // ~12% (the row paint) with brighter `green-900` / `red-900` at ~25%\n // for the content column so the code text contrasts cleanly against\n // the gutter. Sign glyph fg rides the role colors (`accent` / `error`)\n // for instant visual parity with `✓` / `✗`.\n diff: {\n addBg: '#0e2218',\n removeBg: '#2a1414',\n addContentBg: '#143728',\n removeContentBg: '#3d1d1d',\n addFg: '#22c55e',\n removeFg: '#ef4444',\n },\n },\n syntax: {\n // ---- markdown structure ----\n // Headings cascade through brand-500 → brand-400 → brand-300 so the\n // outline reads as one related family rather than three random\n // accents. Body text rides `--textPrimary` (`#fefeff`).\n 'default': { fg: '#fefeff' },\n 'markup.heading': { fg: '#2ba6ff', bold: true },\n 'markup.heading.1': { fg: '#2ba6ff', bold: true },\n 'markup.heading.2': { fg: '#53c4ff', bold: true },\n 'markup.heading.3': { fg: '#8adaff', bold: true },\n 'markup.bold': { fg: '#ffffff', bold: true },\n 'markup.strong': { fg: '#ffffff', bold: true },\n 'markup.italic': { fg: '#fefeff', italic: true },\n 'markup.link': { fg: DEFAULT_COLORS.model, underline: true },\n 'markup.link.url': { fg: DEFAULT_COLORS.model, underline: true },\n // Bullet markers in markdown rides the warm `orange-400` rather\n // than `warn` (which is now cool brand-400). Lists are dense and\n // benefit from a hue that stands apart from headings + body text,\n // and warm tones are appropriate inside the rendered-markdown\n // surface where they don't accumulate into the chrome.\n 'markup.list': { fg: '#fb923c' },\n // Inline / block `code` rides brand-200 — readable on dark, distinct\n // from regular text + headings without leaving the brand family.\n 'markup.raw': { fg: '#bae7ff' },\n 'markup.raw.block': { fg: '#bae7ff' },\n 'markup.quote': { fg: DEFAULT_COLORS.dim, italic: true },\n\n // ---- code (Tree-sitter language tokens inside fenced blocks) ----\n // The palette has no purple/violet step, so we lean on green for functions\n // (callable / \"alive\") and reserve orange for types + parameters.\n // String constants live in brand-200, numeric/property tokens in\n // brand-300 so they read as one cool family against the warm types.\n 'keyword': { fg: '#f87171', bold: true }, // dangerHighlight\n 'keyword.import': { fg: '#f87171', bold: true },\n 'keyword.operator': { fg: '#f87171' },\n 'string': { fg: '#bae7ff' }, // brand-200\n 'string.escape': { fg: '#bae7ff', bold: true },\n 'character': { fg: '#bae7ff' },\n 'comment': { fg: '#73737b', italic: true }, // neutral-500\n 'number': { fg: '#8adaff' }, // brand-300\n 'boolean': { fg: '#8adaff' },\n 'constant': { fg: '#8adaff' },\n 'constant.builtin': { fg: '#8adaff' },\n 'function': { fg: '#86efac' }, // green-300\n 'function.call': { fg: '#86efac' },\n 'function.method': { fg: '#86efac' },\n 'function.method.call': { fg: '#86efac' },\n 'function.builtin': { fg: '#86efac' },\n 'function.macro': { fg: '#86efac' },\n 'type': { fg: '#fb923c' }, // warningHighlight (orange-400)\n 'type.builtin': { fg: '#fb923c' },\n 'constructor': { fg: '#fb923c' },\n 'attribute': { fg: '#fb923c' },\n 'tag': { fg: '#4ade80' }, // green-400\n 'variable': { fg: '#fefeff' },\n 'variable.builtin': { fg: '#8adaff' },\n 'variable.parameter': { fg: '#fb923c' },\n 'variable.member': { fg: '#8adaff' },\n 'property': { fg: '#8adaff' },\n 'operator': { fg: '#f87171' },\n 'punctuation': { fg: DEFAULT_COLORS.mute },\n 'punctuation.bracket': { fg: '#fefeff' },\n 'punctuation.delimiter': { fg: '#d4d4dd' }, // neutral-300\n 'label': { fg: '#8adaff' },\n },\n}\n\n/**\n * Built-in theme registry, keyed by `theme.id`. The TUI looks up the active\n * theme here using `Settings.theme`; unknown ids fall back to\n * `DEFAULT_THEME`. Hosts can extend this by passing additional themes to a\n * future `runTui({ themes })` option (not yet wired).\n *\n * Insertion order is the picker cycle order — keep `default` first so a\n * fresh install (no `theme` in `state.json`) sees the familiar yellow theme\n * before the others.\n */\nexport const BUILTIN_THEMES: Readonly<Record<string, Theme>> = {\n [DEFAULT_THEME.id]: DEFAULT_THEME,\n [LIGHT_THEME.id]: LIGHT_THEME,\n [CATPPUCCIN_MOCHA.id]: CATPPUCCIN_MOCHA,\n [CATPPUCCIN_MACCHIATO.id]: CATPPUCCIN_MACCHIATO,\n [CATPPUCCIN_FRAPPE.id]: CATPPUCCIN_FRAPPE,\n [CATPPUCCIN_LATTE.id]: CATPPUCCIN_LATTE,\n [GRUVBOX_DARK.id]: GRUVBOX_DARK,\n [GRUVBOX_LIGHT.id]: GRUVBOX_LIGHT,\n [CRUSH_THEME.id]: CRUSH_THEME,\n [VAPORWAVE_THEME.id]: VAPORWAVE_THEME,\n}\n\n/** Resolve a theme id to its full `Theme`, falling back to default on unknown ids. */\nexport function resolveTheme(\n id: string | undefined,\n extraThemes?: Readonly<Record<string, Theme>>,\n): Theme {\n if (id) {\n // Built-ins win on id collision so a third-party theme can't shadow\n // the user's \"default\" / \"catppuccin-mocha\" pick — those names are\n // the contract surface for everyone.\n if (BUILTIN_THEMES[id])\n return BUILTIN_THEMES[id]\n if (extraThemes && extraThemes[id])\n return extraThemes[id]\n }\n return DEFAULT_THEME\n}\n","import type { ReactNode } from 'react'\nimport type { Settings } from './types'\nimport { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'\nimport { DEFAULT_SETTINGS } from './settings-defaults'\nimport { BUILTIN_THEMES } from './theme'\n\nexport { DEFAULT_SETTINGS }\n\n// ---------------------------------------------------------------------------\n// Bounds\n// ---------------------------------------------------------------------------\n\n/**\n * Hard-clamp a `targetFps` value to a safe range before handing it to\n * the renderer. Defends against an out-of-band edit to `state.json`\n * (`0`, negative, `NaN`, absurd values) silently pegging the loop or\n * tripping the frame-time math. The settings modal only exposes\n * `30 / 60 / 120` so the typical path never trips the clamp; this\n * guard exists for the \"user hand-edited state.json\" case.\n */\nconst MIN_TARGET_FPS = 1\nconst MAX_TARGET_FPS = 240\n\nexport function clampFps(value: number): number {\n if (!Number.isFinite(value) || value <= 0)\n return DEFAULT_SETTINGS.targetFps\n return Math.min(MAX_TARGET_FPS, Math.max(MIN_TARGET_FPS, Math.round(value)))\n}\n\n// ---------------------------------------------------------------------------\n// SettingsProvider — single source of truth for the transcript filters.\n//\n// `onChange` is called with the latest settings whenever a row toggles, so\n// the host can persist them. Persistence pathing lives outside this module\n// to keep the settings layer portable across renderers (TUI, GUI, …).\n// ---------------------------------------------------------------------------\n\nexport interface SettingsContextValue {\n settings: Settings\n /** Flip a boolean setting in place. Restricted at the type level to boolean-valued keys. */\n toggle: (key: BooleanSettingKey) => void\n /** Write any setting key to a new value. Used by string-valued choice rows. */\n setSetting: <K extends keyof Settings>(key: K, value: Settings[K]) => void\n /** One line the Settings modal shows (a server refused the last write); cleared by the next change. */\n status?: string | null\n /**\n * Settings sync markers, while the modal edits a server another computer\n * syncs to (`docs/SERVER.md` § Settings sync): which setting came from\n * which device, which was edited on the server since (an override), and\n * dropping an override. Absent elsewhere.\n */\n sync?: SettingsSyncMarks\n}\n\n/** A setting's sync state on the server the modal edits. */\nexport interface SettingsSyncMarks {\n marker: (key: string) => { kind: 'synced' | 'override', device: string } | null\n /** Drop the override on `key`; false when it has none. */\n reset: (key: string) => boolean\n}\n\nconst SettingsContext = createContext<SettingsContextValue | null>(null)\n\nexport function SettingsProvider({\n initial,\n onChange,\n children,\n}: {\n initial: Settings\n onChange?: (settings: Settings) => void\n children: ReactNode\n}) {\n // Normalized on load too: an older build (or a hand edit) may have persisted\n // a dependent toggle without its requirement.\n const [settings, setSettings] = useState<Settings>(() => enforceSettingsInvariants(initial))\n\n // `onChange` runs as a side-effect *after* commit, not inside the state\n // updater. Two reasons:\n // 1. React 18 strict-mode dev runs invoke state updaters twice for\n // every transition; a `disk.save(...)` inside the updater would\n // double-fire there.\n // 2. Pure-update is the React contract — updaters must be free of\n // observable side-effects. Persisting from inside breaks the\n // contract regardless of strict mode.\n //\n // A ref keeps the latest `onChange` reachable from the effect without\n // forcing the effect to re-run on every render the parent re-renders.\n // The `initialMount` ref skips the very first commit (we don't want to\n // persist the initial state we just loaded from disk).\n const onChangeRef = useRef(onChange)\n onChangeRef.current = onChange\n const initialMount = useRef(true)\n useEffect(() => {\n if (initialMount.current) {\n initialMount.current = false\n return\n }\n onChangeRef.current?.(settings)\n }, [settings])\n\n const toggle = useCallback((key: BooleanSettingKey) => {\n setSettings(prev => enforceSettingsInvariants({ ...prev, [key]: !prev[key] }))\n }, [])\n\n const setSetting = useCallback(<K extends keyof Settings>(key: K, value: Settings[K]) => {\n setSettings(prev => (prev[key] === value ? prev : enforceSettingsInvariants({ ...prev, [key]: value })))\n }, [])\n\n const value = useMemo<SettingsContextValue>(\n () => ({ settings, toggle, setSetting }),\n [settings, toggle, setSetting],\n )\n\n return <SettingsContext.Provider value={value}>{children}</SettingsContext.Provider>\n}\n\n/**\n * Re-provides settings to a subtree with other values and writers: a\n * surface that edits somewhere else than this window (the TUI's Settings\n * modal while it edits a remote host) reuses every settings-reading\n * component unchanged.\n */\nexport function SettingsOverride({ value, children }: { value: SettingsContextValue, children: ReactNode }) {\n return <SettingsContext.Provider value={value}>{children}</SettingsContext.Provider>\n}\n\nexport function useSettings(): SettingsContextValue {\n const ctx = useContext(SettingsContext)\n if (!ctx)\n throw new Error('useSettings must be used inside <SettingsProvider>')\n return ctx\n}\n\n/**\n * Keys of `Settings` whose value type is exactly `boolean`. Used to type\n * the toggle table so `SETTINGS_TOGGLES.key` only ever points to a\n * boolean-valued setting — string- and array-valued settings (theme,\n * enabledSkills, …) live in `SETTINGS_CHOICES` or actions.\n *\n * `-?` strips optionality from the mapped output so `Settings[K]` doesn't\n * silently broaden into `T | undefined` and short-circuit the `extends\n * boolean` check via `undefined`.\n */\nexport type BooleanSettingKey = {\n [K in keyof Settings]-?: Settings[K] extends boolean ? K : never\n}[keyof Settings]\n\n/**\n * Setting categories — drives the tab grouping in the TUI's\n * `SettingsModal` and, more importantly, gives any embedder (GUI,\n * web settings panel, …) a stable taxonomy to bucket settings under\n * without re-hardcoding the split.\n *\n * - `'agent'` — agent behaviour, capabilities, persistence,\n * data handling, auth. \"What zidane DOES.\"\n * - `'ui'` — display, rendering, theming, animations,\n * chrome density, keybindings. \"How zidane LOOKS\n * and feels.\"\n *\n * Borderline calls (`showAllProjects`, `hideSubagentOutput`,\n * `resumeLastSession`) are documented inline at each row.\n */\nexport type SettingsCategory = 'agent' | 'ui'\n\nexport interface SettingsCategoryDescriptor {\n id: SettingsCategory\n /** Display label — used by the TUI tab strip + any GUI tab/section header. */\n label: string\n /** One-line gloss the GUI can show as a section subtitle. The TUI omits this. */\n description: string\n}\n\n/**\n * Ordered list of categories. Display order in any consumer (TUI tabs,\n * GUI sidebar, settings JSON dump) should match this array — keeps\n * mental model consistent across surfaces.\n */\nexport const SETTINGS_CATEGORIES: readonly SettingsCategoryDescriptor[] = [\n { id: 'agent', label: 'Agent', description: 'behavior, capabilities, persistence, auth' },\n { id: 'ui', label: 'UI', description: 'display, rendering, theming, animations, keybindings' },\n]\n\n/**\n * Static description of every togglable setting, in display order. The TUI's\n * `SettingsModal` and any future GUI settings panel build their row list\n * from this so labels/descriptions stay in one place.\n */\nexport interface SettingsToggle {\n key: BooleanSettingKey\n label: string\n description: string\n category: SettingsCategory\n /**\n * Another boolean setting this one is meaningless without. Renderers grey\n * the row out and say so while the requirement is off; the write layer\n * (`enforceSettingsInvariants`) guarantees the value can never be `true`\n * while the requirement is `false`, whichever client or file wrote it.\n */\n requires?: BooleanSettingKey\n /**\n * The setting drives something only the desktop app shows (its browser,\n * its terminals). The TUI still lets you change it, and says so.\n */\n desktopOnly?: true\n /**\n * Env var of the feature gate's kill switch (`FEATURE_GATES`). While it is\n * `'1'` the feature is off whatever the setting says, so renderers grey the\n * row out and name the variable.\n */\n killSwitchEnv?: string\n}\n\n/**\n * Section headers for the settings lists: each tab shows its rows grouped\n * under these titles, in this order. A key missing from the table lands in\n * `Other` at the end, so a new setting still shows up somewhere.\n */\nexport const SETTINGS_SECTIONS: readonly { title: string, keys: readonly string[] }[] = [\n { title: 'Sessions', keys: ['resumeLastSession', 'useDaemon', 'remoteHosts', 'orchestration', 'checkForUpdates', 'showAllProjects'] },\n { title: 'Guardrails', keys: ['safeMode', 'interactionMode'] },\n { title: 'Sandbox', keys: ['sandbox', 'sandboxNetwork', 'sandboxAllowWrite'] },\n { title: 'Project trust', keys: ['loadProjectExtensions', 'importForeignConfigs', 'importRulerConfigs'] },\n { title: 'Context', keys: ['autoCompact', 'autoCompactThreshold', 'persistToolResults', 'stableToolList', 'userInstructionsScope', 'thinkingBinding'] },\n { title: 'Experimental', keys: ['codemode'] },\n { title: 'Models', keys: ['subagentModels', 'resumeOnMaxTokens', 'maxOutputTokens', 'retryMaxAttempts', 'reauth'] },\n { title: 'Run limits', keys: ['maxTurns', 'maxCostUsd', 'maxTotalTokens', 'maxWallMinutes'] },\n { title: 'Composer', keys: ['queueMessages', 'attachmentsEnabled', 'externalEditor', 'inlineAutocomplete'] },\n { title: 'Usage', keys: ['subscriptionUsage', 'showUsageIndicator'] },\n { title: 'Transcript', keys: ['transcriptDensity', 'showThinking', 'hideSubagentOutput', 'showToolResults', 'toolCallDisplay', 'groupToolCalls', 'showEditDiffs', 'editDiffDisplay', 'showFullShellOutput', 'showRunReceipt', 'showCacheNotices', 'showCompactionSummary', 'smoothStreaming', 'showThrobber', 'artifacts'] },\n { title: 'Footer', keys: ['uiMode', 'showTodoIndicator'] },\n { title: 'Look and feel', keys: ['theme', 'targetFps', 'mouseInteractions', 'ctrlCBehavior', 'openIn', 'keybindings'] },\n { title: 'Terminal tab', keys: ['terminalTitle', 'sessionIcon', 'attentionIcon', 'activeIcon'] },\n { title: 'Desktop app', keys: ['browser', 'browserAutoShow', 'browserAgent', 'terminal', 'terminalAgent', 'terminalAgentTasks', 'closeTerminalOnCleanExit', 'confirmGitSync', 'sidebarRunDetails'] },\n { title: 'Logs', keys: ['fileLogging'] },\n]\n\n/** The section a settings key belongs to, and its position for sorting (section, then row). */\nexport function settingsSectionOf(key: string): { title: string, order: number } {\n const i = SETTINGS_SECTIONS.findIndex(section => section.keys.includes(key))\n return i < 0\n ? { title: 'Other', order: SETTINGS_SECTIONS.length * 100 }\n : { title: SETTINGS_SECTIONS[i]!.title, order: i * 100 + SETTINGS_SECTIONS[i]!.keys.indexOf(key) }\n}\n\nexport const SETTINGS_TOGGLES: readonly SettingsToggle[] = [\n // ----- Agent (behaviour / data handling) -------------------------------\n { category: 'agent', key: 'safeMode', label: 'Safe mode', description: 'Ask before each tool call, except commands you safelisted.' },\n { category: 'agent', key: 'orchestration', requires: 'useDaemon', label: 'Main session', description: 'Pin a session that starts, steers and reads your other sessions. Needs the daemon.' },\n { category: 'agent', key: 'useDaemon', label: 'Use daemon runtime', description: 'Keep runs going when windows close and share them across every window. Applies to new sessions.' },\n { category: 'agent', key: 'remoteHosts', killSwitchEnv: 'ZIDANE_NO_REMOTE', label: 'Remote hosts', description: 'Run sessions on other machines through zidane-server.' },\n { category: 'agent', key: 'resumeLastSession', label: 'Start from last session', description: 'Open the last session on launch instead of the sessions list.' },\n { category: 'agent', key: 'persistToolResults', label: 'Persist large tool results', description: 'Save tool outputs over 8 KB to disk and keep a preview in the chat.' },\n { category: 'agent', key: 'stableToolList', label: 'Stable tool list (call_tool)', description: 'Use found MCP tools through call_tool so the prompt cache stays valid. Applies to new sessions.' },\n { category: 'agent', key: 'codemode', label: 'Codemode', description: 'Let the model batch tool calls in one short script, run in a sandbox.' },\n { category: 'agent', key: 'sandbox', label: 'Sandbox shell commands', description: 'Limit the agent\\'s commands and edits to the project, with credentials hidden. MCP servers and your ! commands are not covered. Applies to new sessions.' },\n { category: 'agent', key: 'loadProjectExtensions', label: 'Load project extensions', description: 'Run this project\\'s extensions. They can run arbitrary local code.' },\n { category: 'agent', key: 'importForeignConfigs', label: 'Import configurations from other agents', description: 'Use other agents\\' servers, skills, commands and subagents. Imported servers run commands from files zidane does not own.' },\n { category: 'agent', key: 'importRulerConfigs', label: 'Support Ruler configuration (.ruler)', description: 'Read .ruler folders. Their servers need \"Import configurations from other agents\".' },\n { category: 'agent', key: 'attachmentsEnabled', label: 'Paste attachments', description: 'Turn dropped files and long pastes into attachments.' },\n { category: 'agent', key: 'externalEditor', label: 'Edit prompt in $EDITOR', description: 'Press ctrl+g to write the prompt in $EDITOR.' },\n { category: 'agent', key: 'inlineAutocomplete', label: 'Inline autocomplete', description: 'Suggest the rest of a path or command as you type. Tab accepts.' },\n { category: 'agent', key: 'autoCompact', label: 'Auto-compact', description: 'Summarize the conversation when the context passes the threshold below.' },\n { category: 'agent', key: 'queueMessages', label: 'Queue messages', description: 'Hold messages sent during a run until it ends. Off sends them into the running turn.' },\n { category: 'agent', key: 'subagentModels', label: 'Allow subagents to use different models', description: 'Let the agent hand work to cheaper models.' },\n { category: 'agent', key: 'resumeOnMaxTokens', label: 'Auto-resume on output limit', description: 'Keep going when an answer hits the model\\'s output limit.' },\n { category: 'agent', key: 'checkForUpdates', label: 'Check for updates', description: 'Check daily for a new release and show it in the footer.' },\n { category: 'agent', key: 'subscriptionUsage', label: 'Read subscription usage', description: 'Fetch plan limits and credits from signed-in providers.' },\n // ----- UI (display / rendering) ----------------------------------------\n // `showAllProjects` / `hideSubagentOutput` are arguably feature flags\n // but their visible effect is purely \"what shows up in the transcript /\n // sessions list\" — bucketing as UI keeps the Agent tab focused on\n // behaviour the agent observes, not what the user sees.\n { category: 'ui', key: 'showAllProjects', label: 'All projects', description: 'List sessions from every project, not only this one.' },\n { category: 'ui', key: 'hideSubagentOutput', label: 'Hide subagent output', description: 'Fold subagent runs down to their start and finish lines.' },\n { category: 'ui', key: 'showThinking', label: 'Thinking blocks', description: 'Show the agent\\'s reasoning in the chat.' },\n { category: 'ui', key: 'showToolResults', label: 'Tool outputs', description: 'Show the output under each tool call.' },\n { category: 'ui', key: 'groupToolCalls', label: 'Group tool calls', description: 'Fold each exchange\\'s tool calls into one row.' },\n { category: 'ui', key: 'showFullShellOutput', label: 'Full shell output', description: 'Show every line of ! command output, not just the last 10.' },\n { category: 'ui', key: 'showRunReceipt', label: 'Run receipt', description: 'Show model, time, cost and tokens after each run.' },\n { category: 'ui', key: 'showCacheNotices', label: 'Cache notices', description: 'Show a row in the chat when the prompt cache expires or resets.' },\n { category: 'ui', key: 'showEditDiffs', label: 'Edit diffs', description: 'Show file edits as diffs.' },\n { category: 'ui', key: 'showCompactionSummary', label: 'Compaction summaries', description: 'Show the summary text under the compaction line.' },\n { category: 'ui', key: 'smoothStreaming', label: 'Smooth streaming', description: 'Reveal replies character by character as they stream.' },\n { category: 'ui', key: 'showTodoIndicator', label: 'Todo indicator', description: 'Show the todo count in the footer. ctrl+t opens the list.' },\n { category: 'ui', key: 'showUsageIndicator', label: 'Usage indicator', description: 'Show plan usage in the footer. ctrl+p opens the panel.' },\n { category: 'ui', key: 'showThrobber', label: 'Streaming throbber', description: 'Animate an indicator while the agent works.' },\n { category: 'ui', key: 'artifacts', label: 'Artifacts', description: 'Track each session\\'s pull requests, branches, commits and files.' },\n { category: 'ui', key: 'browser', desktopOnly: true, label: 'Browser tab', description: 'A browser tab next to the chat to preview your app.' },\n // No `requires: 'browser'` on these two: that would force them off for good while\n // the browser is off. They are simply ignored then, and come back as they were.\n { category: 'ui', key: 'browserAutoShow', desktopOnly: true, label: 'Show the browser when the agent uses it', description: 'Open the browser tab when the agent starts using it.' },\n { category: 'agent', key: 'browserAgent', desktopOnly: true, label: 'Agent can use the browser', description: 'Let the agent open, read, click and type in pages to check its work.' },\n { category: 'ui', key: 'terminal', desktopOnly: true, label: 'Terminals', description: 'Terminals next to the chat, running where the session runs.' },\n { category: 'agent', key: 'terminalAgent', desktopOnly: true, requires: 'terminal', label: 'Agent can use your terminals', description: 'Let the agent read your terminals and type in them after you approve.' },\n { category: 'agent', key: 'terminalAgentTasks', desktopOnly: true, requires: 'terminal', label: 'Agent\\'s background tasks in terminals', description: 'Give each background command the agent starts its own terminal tab.' },\n { category: 'ui', key: 'closeTerminalOnCleanExit', desktopOnly: true, requires: 'terminal', label: 'Close terminals that exit cleanly', description: 'Close a terminal once its shell exits cleanly. Failed ones stay open.' },\n { category: 'ui', key: 'confirmGitSync', desktopOnly: true, label: 'Ask before syncing', description: 'Confirm before the git bar pulls, pushes or publishes your branch.' },\n { category: 'ui', key: 'sidebarRunDetails', desktopOnly: true, label: 'Run details in the sidebar', description: 'Show each run\\'s activity, time, commits and pull requests in the sidebar.' },\n { category: 'ui', key: 'fileLogging', label: 'File logging', description: 'Save this session\\'s logs to ~/.zidane/logs.' },\n { category: 'ui', key: 'mouseInteractions', label: 'Clickable UI', description: 'Click, hover and scroll rows. When off, the terminal\\'s own selection works.' },\n]\n\n/**\n * Cross-setting invariants, applied at EVERY write.\n *\n * Settings are a shared file with three writers (the TUI, the GUI main\n * process, the daemon) and no lock; a rule enforced in one client is a rule\n * the others break. So this is the single definition, derived from the\n * `requires` declarations on the toggle rows themselves — adding a\n * dependency is one field on one row, and the UI hint and the write-time\n * guarantee follow from it together.\n *\n * Pure and idempotent: returns the same object when nothing changes, so React\n * state and file writers can short-circuit on identity.\n */\n/**\n * Return type of {@link enforceSettingsInvariants}: the input shape with every\n * boolean setting widened to `boolean`. The function exists to flip toggles,\n * so a literal `true` from a call-site object literal must not survive into\n * the result type — it would let `expect(next.x).toBe(false)` fail to compile\n * against a value that is, in fact, `false`.\n */\nexport type WithInvariants<T> = { [K in keyof T]: K extends BooleanSettingKey ? boolean : T[K] }\n\nexport function enforceSettingsInvariants<T extends Partial<Settings>>(settings: T): WithInvariants<T> {\n let next: T | null = null\n for (const row of SETTINGS_TOGGLES) {\n if (!row.requires)\n continue\n const current = (next ?? settings)[row.key]\n const requirement = (next ?? settings)[row.requires]\n if (current === true && requirement !== true)\n next = { ...(next ?? settings), [row.key]: false }\n }\n return (next ?? settings) as WithInvariants<T>\n}\n\n/**\n * String-valued settings that pick between a known set of options. The\n * `SettingsModal` renders these as one row showing the active label, where\n * `enter` cycles to the next option (wrapping back to the first). Same\n * shape any GUI settings panel can consume — render the options array as a\n * dropdown or segmented control.\n *\n * Keep `options` in stable display order; cycling depends on it.\n */\nexport interface SettingsChoice<K extends keyof Settings = keyof Settings> {\n key: K\n label: string\n description: string\n options: readonly { value: Settings[K], label: string }[]\n category: SettingsCategory\n}\n\nexport const SETTINGS_CHOICES: readonly SettingsChoice[] = [\n // ----- Agent (behaviour / data handling) -------------------------------\n {\n category: 'agent',\n key: 'interactionMode',\n label: 'Interaction mode',\n description: 'Ask you, answer from the repository on its own, or turn questions off.',\n options: [\n { value: 'ask', label: 'Ask normally' },\n { value: 'skip', label: 'Skip interactions' },\n { value: 'disabled', label: 'Disable tools' },\n ],\n },\n {\n category: 'ui',\n key: 'openIn',\n label: 'Open files and diffs in',\n description: 'Where clicked files and diffs open: your editor or the desktop panels.',\n options: [\n { value: 'editor', label: '$EDITOR' },\n { value: 'panel', label: 'Panels' },\n ],\n },\n {\n category: 'agent',\n key: 'sandboxNetwork',\n label: 'Sandbox network',\n description: 'Allow keeps installs and git working. Deny blocks every connection.',\n options: [\n { value: 'allow', label: 'Allow' },\n { value: 'deny', label: 'Deny' },\n ],\n },\n {\n category: 'agent',\n key: 'autoCompactThreshold',\n label: 'Auto-compact threshold',\n description: 'How full the context gets before it is summarized.',\n options: [\n { value: 0.6, label: '60%' },\n { value: 0.7, label: '70%' },\n { value: 0.8, label: '80%' },\n { value: 0.9, label: '90%' },\n ],\n },\n {\n category: 'agent',\n key: 'userInstructionsScope',\n label: 'User instructions',\n description: 'Which AGENTS.md and CLAUDE.md files the agent reads.',\n options: [\n { value: 'both', label: 'Both (merged)' },\n { value: 'user', label: 'User only' },\n { value: 'project', label: 'Project only' },\n { value: 'none', label: 'None' },\n ],\n },\n {\n category: 'agent',\n key: 'maxOutputTokens',\n label: 'Max output tokens',\n description: 'The most the model may write per turn.',\n options: [\n { value: 0, label: 'Model max' },\n { value: 8192, label: '8K' },\n { value: 16384, label: '16K' },\n { value: 32000, label: '32K' },\n { value: 64000, label: '64K' },\n ],\n },\n {\n category: 'agent',\n key: 'retryMaxAttempts',\n label: 'Provider retry attempts',\n description: 'How many times to retry a failed or stalled provider call.',\n options: [\n { value: 0, label: 'Default (3)' },\n { value: 1, label: '1 (no retry)' },\n { value: 2, label: '2' },\n { value: 3, label: '3' },\n { value: 5, label: '5' },\n { value: 8, label: '8' },\n ],\n },\n {\n category: 'agent',\n key: 'maxTurns',\n label: 'Max turns per run',\n description: 'Stop a run after this many turns.',\n options: [\n { value: 0, label: 'Unlimited' },\n { value: 25, label: '25' },\n { value: 50, label: '50' },\n { value: 100, label: '100' },\n { value: 200, label: '200' },\n ],\n },\n {\n category: 'agent',\n key: 'maxCostUsd',\n label: 'Max cost per run',\n description: 'Stop a run once its estimated cost passes this amount.',\n options: [\n { value: 0, label: 'Unlimited' },\n { value: 1, label: '$1' },\n { value: 5, label: '$5' },\n { value: 10, label: '$10' },\n { value: 25, label: '$25' },\n ],\n },\n {\n category: 'agent',\n key: 'maxTotalTokens',\n label: 'Max tokens per run',\n description: 'Stop a run once it has used this many tokens.',\n options: [\n { value: 0, label: 'Unlimited' },\n { value: 500_000, label: '500K' },\n { value: 1_000_000, label: '1M' },\n { value: 2_000_000, label: '2M' },\n { value: 5_000_000, label: '5M' },\n ],\n },\n {\n category: 'agent',\n key: 'maxWallMinutes',\n label: 'Max run time',\n description: 'Stop a run after this much time.',\n options: [\n { value: 0, label: 'Unlimited' },\n { value: 5, label: '5 min' },\n { value: 15, label: '15 min' },\n { value: 30, label: '30 min' },\n { value: 60, label: '60 min' },\n ],\n },\n {\n category: 'agent',\n key: 'thinkingBinding',\n label: 'Preserved thinking (Anthropic only)',\n description: 'What to do with reasoning that no longer matches the conversation.',\n options: [\n { value: 'drop_block', label: 'Drop silently' },\n { value: 'error', label: 'Fail the run' },\n { value: 'off', label: 'Account default' },\n ],\n },\n // ----- UI (display / rendering) ----------------------------------------\n {\n category: 'ui',\n key: 'toolCallDisplay',\n label: 'Tool calls display',\n description: 'Show tool calls as a summary, their full input, or not at all.',\n options: [\n { value: 'formatted', label: 'Formatted' },\n { value: 'full', label: 'Full' },\n { value: 'hidden', label: 'Hidden' },\n ],\n },\n {\n category: 'ui',\n key: 'transcriptDensity',\n label: 'Transcript density',\n description: 'Full shows every step. Compact folds each exchange\\'s work into one row.',\n options: [\n { value: 'full', label: 'Full' },\n { value: 'compact', label: 'Compact' },\n ],\n },\n {\n category: 'ui',\n key: 'editDiffDisplay',\n label: 'Edit diff density',\n description: 'Show edits as a full diff or a short summary.',\n options: [\n { value: 'full', label: 'Full' },\n { value: 'compact', label: 'Compact' },\n ],\n },\n {\n category: 'ui',\n key: 'theme',\n label: 'Theme',\n description: 'Colors for the interface, markdown and code.',\n options: Object.values(BUILTIN_THEMES).map(t => ({ value: t.id, label: t.label })),\n },\n {\n category: 'ui',\n key: 'uiMode',\n label: 'UI mode',\n description: 'Full shows every shortcut in the footer. Minimal hides them; ctrl+y shows all.',\n options: [\n { value: 'full', label: 'Full' },\n { value: 'minimal', label: 'Minimal' },\n ],\n },\n {\n category: 'ui',\n key: 'targetFps',\n label: 'Renderer FPS',\n description: '30 saves power, 60 is recommended, 120 suits fast displays.',\n options: [\n { value: 30, label: '30 fps' },\n { value: 60, label: '60 fps' },\n { value: 120, label: '120 fps' },\n ],\n },\n {\n category: 'ui',\n key: 'ctrlCBehavior',\n label: 'Ctrl+C behavior',\n description: 'Quit right away, ask first, or stop what is running and quit on a second press.',\n options: [\n { value: 'quit', label: 'Quit' },\n { value: 'quit-confirm', label: 'Confirm' },\n { value: 'stop-then-quit', label: 'Stop, then quit' },\n ],\n },\n {\n category: 'ui',\n key: 'terminalTitle',\n label: 'Terminal title',\n description: 'What the terminal tab title shows.',\n options: [\n { value: 'off', label: 'Off' },\n { value: 'app', label: 'zidane' },\n { value: 'session', label: 'Session title' },\n { value: 'icon-session', label: 'Icon + session' },\n ],\n },\n]\n\n/**\n * Keys of `Settings` whose value type is exactly `string`. Bounds the\n * input table's `key` the same way {@link BooleanSettingKey} bounds the\n * toggle table — a free-text row can only point at a string-valued\n * setting.\n */\nexport type StringSettingKey = {\n [K in keyof Settings]-?: Settings[K] extends string ? K : never\n}[keyof Settings]\n\n/**\n * Free-text settings edited via a single-line input. The `SettingsModal`\n * renders these as a row showing the current value (or `placeholder` when\n * empty); `enter` opens an inline editor. Same shape a GUI can consume as\n * a text field.\n */\nexport interface SettingsInput {\n key: StringSettingKey\n label: string\n description: string\n /** Shown when the value is empty — also the conventional \"default\" hint. */\n placeholder: string\n category: SettingsCategory\n}\n\nexport const SETTINGS_INPUTS: readonly SettingsInput[] = [\n {\n category: 'agent',\n key: 'sandboxAllowWrite',\n label: 'Sandbox writable paths',\n description: 'Extra folders sandboxed commands may write to, comma separated.',\n placeholder: '~/.cache, ~/.bun/install/cache',\n },\n {\n category: 'ui',\n key: 'sessionIcon',\n label: 'Session icon',\n description: 'Shown before the session title in the terminal tab.',\n placeholder: '⚽',\n },\n {\n category: 'ui',\n key: 'attentionIcon',\n label: 'Attention icon',\n description: 'Replaces the session icon while zidane waits on you.',\n placeholder: '⚠️',\n },\n {\n category: 'ui',\n key: 'activeIcon',\n label: 'Active icon',\n description: 'Replaces the session icon while zidane works.',\n placeholder: '⚡',\n },\n]\n","/**\n * Which settings a host owns when a window edits it (the active session\n * runs on a server), and which stay the window's. Shared by the TUI's and\n * the GUI's Settings surfaces.\n *\n * Window-only: how the window looks and behaves (the UI category, theme,\n * fps, icons, keyboard and editor habits) and which hosts it uses\n * (`WINDOW_LOCAL_SETTINGS`). Everything else (safe mode, sandbox, limits,\n * compaction, the enabled skills / MCP servers / extensions…) shapes the\n * host's agents, so it is read with `settings.get` and written with\n * `settings.set` on that host, never into this computer's `state.json`.\n */\nimport type { Settings } from './types'\nimport { SETTINGS_CHOICES, SETTINGS_INPUTS, SETTINGS_TOGGLES } from './settings-context'\n\n/**\n * Settings that belong to the window even while a host owns the settings\n * file (daemon or remote mode): which host the next launch uses.\n */\nexport const WINDOW_LOCAL_SETTINGS = ['useDaemon', 'remoteHosts'] as const satisfies readonly (keyof Settings)[]\n\n/** Agent-category keys that are still about the window, not the agents. */\nconst WINDOW_ONLY_KEYS: readonly (keyof Settings)[] = [\n 'theme',\n 'targetFps',\n 'mouseInteractions',\n 'uiMode',\n 'ctrlCBehavior',\n 'terminalTitle',\n 'sessionIcon',\n 'attentionIcon',\n 'activeIcon',\n 'thinkingBinding',\n 'toolCallDisplay',\n 'editDiffDisplay',\n 'transcriptDensity',\n 'resumeLastSession',\n 'externalEditor',\n 'inlineAutocomplete',\n 'checkForUpdates',\n 'subscriptionUsage',\n 'openIn',\n]\n\nconst WINDOW_ONLY: ReadonlySet<string> = new Set<string>([\n ...WINDOW_LOCAL_SETTINGS,\n ...WINDOW_ONLY_KEYS,\n ...[...SETTINGS_TOGGLES, ...SETTINGS_CHOICES, ...SETTINGS_INPUTS].filter(row => row.category === 'ui').map(row => row.key),\n])\n\nexport function isWindowOnlySetting(key: keyof Settings | string): boolean {\n return WINDOW_ONLY.has(key)\n}\n\n/** The allowlists a host leaving them unset means \"everything enabled\" for. */\nexport const HOST_ENABLED_LISTS = ['enabledSkills', 'enabledMcps', 'enabledExtensions', 'enabledPlugins', 'disabledMcpTools'] as const satisfies readonly (keyof Settings)[]\n\n/** `local` with the host's values for every key the host owns. */\nexport function overlayHostSettings<S extends Settings>(local: S, host: Partial<Settings>): S {\n const merged = { ...local } as Record<string, unknown>\n for (const [key, value] of Object.entries(host)) {\n if (!isWindowOnlySetting(key))\n merged[key] = value\n }\n // Allowlists the host leaves unset mean \"everything enabled\": not this window's lists.\n for (const key of HOST_ENABLED_LISTS) {\n if (!(key in host))\n delete merged[key]\n }\n return merged as S\n}\n\n/** Split a settings patch into the window's part and the host's part. */\nexport function splitHostSettingsPatch<S extends Partial<Settings>>(patch: S): { window: Partial<S>, host: Partial<S> } {\n const window: Record<string, unknown> = {}\n const host: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(patch))\n (isWindowOnlySetting(key) ? window : host)[key] = value\n return { window: window as Partial<S>, host: host as Partial<S> }\n}\n","/**\n * The client's saved hosts: `<dataDir>/hosts.json` (0600, atomic writes) for\n * the entries, the credentials store (`credentials.json`, entry\n * `hosts:<id>`) for their tokens, so tokens sit with every other secret and\n * never in the listable file.\n *\n * Every call reads the files fresh: TUI and GUI windows on one machine share\n * them. Connecting is injected (`probe`): `src/chat` cannot reach the\n * WebSocket client, `createWsHostRegistry` (`zidane/ipc`) wires it.\n */\nimport type { HostEntry, HostProbe, HostProbeResult, HostTestResult } from './types'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { OWNER_ONLY, writeJsonFileAtomic } from '../../atomic-write'\nimport { readCredentialEntry, writeCredentialEntry } from '../credentials'\nimport { HostRegistryError } from './types'\nimport { displayHostUrl, parseRemoteHostUrl, RemoteHostError, urlCarriesSecrets } from './url'\n\nconst FILE_VERSION = 1\n\ninterface HostsFile {\n version: typeof FILE_VERSION\n hosts: HostEntry[]\n}\n\nexport function hostsFilePath(dataDir: string): string {\n return resolve(dataDir, 'hosts.json')\n}\n\n/** Where a host's token lives in the credentials store. */\nexport function hostCredentialKey(id: string): string {\n return `hosts:${id}`\n}\n\nexport interface HostRegistry {\n list: () => HostEntry[]\n get: (id: string) => HostEntry | undefined\n /**\n * Verify the host (it must answer as a zidane-server with this token),\n * then save it and its token. Adding a host already saved (same server\n * id) updates its URL and token in place, keeping its name unless one is\n * given. Throws {@link HostRegistryError}.\n */\n add: (input: { url: string, token: string, name?: string }) => Promise<HostEntry>\n /** Forget the entry and its token; `false` when it wasn't saved. */\n remove: (id: string) => boolean\n rename: (id: string, name: string) => HostEntry\n /** Connect with the saved token and say who answered; refreshes `lastConnectedAt` on success. */\n test: (id: string) => Promise<HostTestResult>\n /** The saved token, for transports. Never display it. */\n token: (id: string) => string | undefined\n}\n\nfunction isEntry(value: unknown): value is HostEntry {\n const e = value as Partial<HostEntry> | null\n return !!e && typeof e === 'object' && typeof e.id === 'string' && typeof e.name === 'string' && typeof e.url === 'string' && typeof e.addedAt === 'number'\n}\n\n/** An entry saved before URLs were checked for credentials: read without them (it fails auth, the user re-adds it). */\nfunction withoutUrlSecrets(entry: HostEntry): HostEntry {\n const raw = entry.url\n return urlCarriesSecrets(raw) ? { ...entry, url: displayHostUrl(raw) } : entry\n}\n\nfunction readHosts(dataDir: string): HostEntry[] {\n const path = hostsFilePath(dataDir)\n if (!existsSync(path))\n return []\n try {\n const parsed = JSON.parse(readFileSync(path, 'utf8')) as Partial<HostsFile>\n return Array.isArray(parsed.hosts) ? parsed.hosts.filter(isEntry).map(withoutUrlSecrets) : []\n }\n catch {\n return []\n }\n}\n\nfunction writeHosts(dataDir: string, hosts: HostEntry[]): void {\n const file: HostsFile = { version: FILE_VERSION, hosts }\n writeJsonFileAtomic(hostsFilePath(dataDir), file, OWNER_ONLY)\n}\n\nfunction cleanName(name: string): string {\n const trimmed = name.trim()\n if (!trimmed)\n throw new HostRegistryError('invalid-name', 'A host needs a name.')\n return trimmed\n}\n\nfunction checkedUrl(raw: string): string {\n try {\n return parseRemoteHostUrl(raw)\n }\n catch (err) {\n throw new HostRegistryError('invalid-url', err instanceof RemoteHostError ? err.message : String(err))\n }\n}\n\n/** The URL and token an `add` (or an unsaved test) takes, checked; throws {@link HostRegistryError}. */\nexport function checkHostInput(input: { url: string, token: string }): { url: string, token: string } {\n const url = checkedUrl(input.url)\n const token = input.token.trim()\n if (!token)\n throw new HostRegistryError('invalid-token', 'A host needs a token (zidane server token create --name <device>).')\n return { url, token }\n}\n\n/** A probe's answer, refused unless a zidane-server answered. */\nfunction asServer(url: string, probed: HostProbeResult): HostProbeResult {\n if (probed.ok && probed.hostRef.kind !== 'server')\n return { ok: false, error: 'protocol', message: `${url} is a ${probed.hostRef.kind} host, not a zidane-server.` }\n return probed\n}\n\n/** The add form's \"test\": `add`'s checks and probe, saving nothing. Never throws. */\nexport async function probeUnsavedHost(probe: HostProbe, input: { url: string, token: string }): Promise<HostProbeResult> {\n let checked: { url: string, token: string }\n try {\n checked = checkHostInput(input)\n }\n catch (err) {\n if (err instanceof HostRegistryError)\n return { ok: false, error: err.code, message: err.message }\n throw err\n }\n return asServer(checked.url, await probe(checked))\n}\n\nexport function createHostRegistry(options: { dataDir: string, probe: HostProbe, now?: () => number }): HostRegistry {\n const { dataDir, probe } = options\n const now = options.now ?? Date.now\n const list = (): HostEntry[] => readHosts(dataDir)\n const get = (id: string): HostEntry | undefined => list().find(h => h.id === id)\n const token = (id: string): string | undefined => {\n const cred = readCredentialEntry(dataDir, hostCredentialKey(id))\n return cred?.kind === 'apikey' && cred.value ? cred.value : undefined\n }\n const update = (id: string, patch: (entry: HostEntry) => HostEntry): HostEntry | undefined => {\n const hosts = list()\n const i = hosts.findIndex(h => h.id === id)\n if (i < 0)\n return undefined\n hosts[i] = patch(hosts[i]!)\n writeHosts(dataDir, hosts)\n return hosts[i]\n }\n\n return {\n list,\n get,\n token,\n async add(input) {\n const { url, token: secret } = checkHostInput(input)\n const name = input.name === undefined ? undefined : cleanName(input.name)\n const probed = asServer(url, await probe({ url, token: secret }))\n if (!probed.ok)\n throw new HostRegistryError(probed.error, probed.message)\n const at = now()\n const fresh: Pick<HostEntry, 'url' | 'lastConnectedAt' | 'hostKind' | 'serverName' | 'serverVersion'> = {\n url,\n lastConnectedAt: at,\n hostKind: 'server',\n serverName: probed.hostRef.name,\n ...(probed.serverVersion !== undefined ? { serverVersion: probed.serverVersion } : {}),\n }\n const id = probed.hostRef.id\n // Token first: an entry is never saved without its token.\n writeCredentialEntry(dataDir, hostCredentialKey(id), { kind: 'apikey', value: secret })\n const hosts = list()\n const existing = hosts.find(h => h.id === id)\n const entry: HostEntry = existing\n ? { ...existing, ...fresh, ...(name !== undefined ? { name } : {}) }\n : { id, name: name ?? probed.hostRef.name, addedAt: at, ...fresh }\n writeHosts(dataDir, existing ? hosts.map(h => (h.id === id ? entry : h)) : [...hosts, entry])\n return entry\n },\n remove(id) {\n const hosts = list()\n const kept = hosts.filter(h => h.id !== id)\n const had = kept.length !== hosts.length\n if (had)\n writeHosts(dataDir, kept)\n const hadToken = token(id) !== undefined\n writeCredentialEntry(dataDir, hostCredentialKey(id), undefined)\n return had || hadToken\n },\n rename(id, name) {\n const clean = cleanName(name)\n const entry = update(id, e => ({ ...e, name: clean }))\n if (!entry)\n throw new HostRegistryError('unknown-host', `No host \"${id}\".`)\n return entry\n },\n async test(id) {\n const entry = get(id)\n const secret = entry ? token(id) : undefined\n if (!entry || secret === undefined)\n return { ok: false, error: 'unknown-host', message: entry ? `No token saved for \"${entry.name}\": add it again.` : `No host \"${id}\".` }\n const probed = await probe({ url: entry.url, token: secret })\n if (!probed.ok)\n return probed\n if (probed.hostRef.id !== entry.id)\n return { ok: false, error: 'identity', message: `A different host (\"${probed.hostRef.name}\") answers at ${entry.url}. Remove \"${entry.name}\" and add it again if it was reinstalled.` }\n update(id, e => ({\n ...e,\n lastConnectedAt: now(),\n serverName: probed.hostRef.name,\n ...(probed.serverVersion !== undefined ? { serverVersion: probed.serverVersion } : {}),\n }))\n return probed\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAeA,SAAgB,oBAAoB,SAAkC;CACpE,IAAI;EACF,MAAM,IAAI,IAAI,YAAY,OAAO;EACjC,EAAE,KAAK;EACP,OAAO,EAAE;CACX,QACM;EACJ,OAAO;CACT;AACF;AAGA,MAAM,OAAO,IAAI,IAAI,gBAAiB,MAAM,EAAE,CAAC;AAS/C,IAAM,cAAN,MAAM,YAAY;CAMa;CAL7B,QAA2B,CAAC;CAC5B,IAAY;;CAEZ,kBAA4C,CAAC;CAE7C,YAAY,GAA4B;EAAX,KAAA,IAAA;CAAY;;CAKzC,KAAK,QAAuB;EAC1B,SAAS;GACP,KAAK,GAAG;GACR,IAAI,KAAK,IAAI,MAAM,GACjB;GAEF,KAAK,SAAS,MAAM;GAEpB,KAAK,GAAG;GACR,IAAI,KAAK,IAAI,MAAM,GACjB;GACF,MAAM,IAAI,KAAK,EAAE;GACjB,IAAI,MAAM,KAAK;IAAE,KAAK;IAAK;GAAS;GACpC,IAAI,MAAM,QAAQ,MAAM,MAAM;IAAE,KAAK,QAAQ;IAAG;GAAS;GACzD,IAAI,KAAK,GAAG,IAAI,KAAK,KAAK,GAAG,IAAI,GAAG;IAAE,KAAK,KAAK;IAAG;GAAS;GAC5D,IAAI,MAAM,KAAK;IAAE,KAAK;IAAK;GAAS;GACpC;EACF;CACF;;CAKA,SAAiB,QAAuB;EACtC,KAAK,IAAI,MAAM;EACf,SAAS;GACP,KAAK,GAAG;GACR,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,KAAK,GAAG,IAAI,GAAG;IAAE,KAAK;IAAK,KAAK,IAAI,MAAM;GAAE,OAEnE;EAEJ;CACF;;CAGA,IAAY,QAAuB;EACjC,KAAK,GAAG;EACR,IAAI,KAAK,KAAK,KAAK,EAAE,QACnB;EACF,IAAI,UAAU,KAAK,EAAE,MAAM,QACzB;EAGF,IAAI,KAAK,EAAE,MAAM,KAAK;GACpB,KAAK;GACL,KAAK,KAAK,GAAG;GACb;EACF;EAGA,IAAI,KAAK,EAAE,MAAM,OAAO,KAAK,IAAI,IAAI,KAAK,EAAE,WACtC,KAAK,EAAE,KAAK,IAAI,OAAO,OAAO,KAAK,EAAE,KAAK,IAAI,OAAO,MAAO;GAChE,KAAK;GAAK,KAAK,GAAG;EACpB;EAGA,OAAO,KAAK,IAAI,KAAK,EAAE,UAAU,CAAC,KAAK,IAAI,MAAM,GAAG;GAClD,IAAI,KAAK,EAAE,MAAM,KAAK;IACpB,KAAK;IACL,KAAK,KAAK,GAAG;IACb;GACF;GACA,MAAM,IAAI,KAAK,KAAK;GACpB,IAAI,CAAC,GACH;GACF,IAAI,aAAa,CAAC,GAAG;IAAE,KAAK,GAAG;IAAG;GAAS;GAC3C,KAAK,MAAM,KAAK,CAAC;GACjB;EACF;EAEA,KAAK,KAAK,MAAM;CAClB;;CAKA,OAAuB;EACrB,IAAI,MAAM;EACV,OAAO,KAAK,IAAI,KAAK,EAAE,QAAQ;GAC7B,MAAM,IAAI,KAAK,EAAE;GACjB,IAAI,KAAK,IAAI,CAAC,GACZ;GAEF,IAAI,MAAM,QAAQ,KAAK,IAAI,IAAI,KAAK,EAAE,QAAQ;IAC5C,OAAO,KAAK,EAAE,KAAK,IAAI;IACvB,KAAK,KAAK;IACV;GACF;GACA,IAAI,MAAM,KAAM;IACd,KAAK;IACL,OAAO,KAAK,IAAI,KAAK,EAAE,UAAU,KAAK,EAAE,KAAK,OAAO,KAAM,OAAO,KAAK,EAAE,KAAK;IAC7E,IAAI,KAAK,IAAI,KAAK,EAAE,QAClB,KAAK;IACP;GACF;GACA,IAAI,MAAM,MAAK;IAAE,OAAO,KAAK,OAAO;IAAG;GAAS;GAChD,IAAI,KAAK,GAAG,IAAI,GAAG;IACjB,KAAK,KAAK;IACV,KAAK,KAAK,GAAG;IACb;GACF;GACA,IAAI,MAAM,KAAK;IAAE,KAAK,MAAM;IAAG;GAAS;GACxC,OAAO;GAAG,KAAK;EACjB;EACA,OAAO;CACT;;CAGA,SAAyB;EACvB,KAAK;EACL,IAAI,MAAM;EACV,OAAO,KAAK,IAAI,KAAK,EAAE,UAAU,KAAK,EAAE,KAAK,OAAO,MAAK;GACvD,IAAI,KAAK,EAAE,KAAK,OAAO,QAAQ,KAAK,IAAI,IAAI,KAAK,EAAE,QAAQ;IACzD,OAAO,KAAK,EAAE,KAAK,IAAI;IACvB,KAAK,KAAK;IACV;GACF;GACA,IAAI,KAAK,GAAG,IAAI,GAAG;IACjB,KAAK,KAAK;IACV,KAAK,KAAK,GAAG;IACb;GACF;GACA,IAAI,KAAK,EAAE,KAAK,OAAO,KAAK;IAAE,KAAK,MAAM;IAAG;GAAS;GACrD,OAAO,KAAK,EAAE,KAAK;EACrB;EACA,IAAI,KAAK,IAAI,KAAK,EAAE,QAClB,KAAK;EACP,OAAO;CACT;;CAGA,QAAsB;EACpB,KAAK;EACL,MAAM,QAAQ,KAAK,EAAE,QAAQ,KAAK,KAAK,CAAC;EACxC,MAAM,QAAQ,QAAQ,IAAI,KAAK,EAAE,MAAM,KAAK,CAAC,IAAI,KAAK,EAAE,MAAM,KAAK,GAAG,KAAK;EAC3E,MAAM,MAAM,IAAI,YAAY,KAAK;EACjC,IAAI,KAAK;EACT,KAAK,MAAM,KAAK,GAAG,IAAI,KAAK;EAC5B,KAAK,IAAI,QAAQ,IAAI,KAAK,EAAE,SAAS,QAAQ;CAC/C;;CAKA,KAAa,QAAuB;EAClC,OAAO,KAAK,IAAI,KAAK,EAAE,QAAQ;GAC7B,KAAK,GAAG;GACR,IAAI,KAAK,KAAK,KAAK,EAAE,UAAU,KAAK,IAAI,MAAM,GAC5C;GACF,IAAI,KAAK,MAAM,GACb;GACF,IAAI,KAAK,EAAE,MAAM,KAAK;IACpB,KAAK;IACL,KAAK,KAAK,GAAG;IACb;GACF;GAEA,IAAI,CADM,KAAK,KACV,GACH;EACJ;CACF;;CAGA,QAAyB;EACvB,MAAM,IAAI,KAAK,EAAE;EACjB,IAAI,MAAM,MAAM,OAAO,MAAM;EAC7B,IAAI,CAAC,OAAO,KAAK,OAAO,KAAK,OAAO,KAAK,IAAI,IAAI,KAAK,EAAE,QAAQ;GAC9D,MAAM,IAAI,KAAK,EAAE,KAAK,IAAI;GAC1B,MAAM,MAAM,OAAO,MAAM;EAC3B;EACA,IAAI,CAAC,KACH,OAAO;EAET,OAAO,KAAK,IAAI,KAAK,EAAE,UAAU,KAAK,EAAE,KAAK,MAAM,OAAO,KAAK,EAAE,KAAK,MAAM,KAAK,KAAK;EACtF,IAAI,KAAK,EAAE,MAAM,KAAK;GACpB,KAAK;GACL,IAAI,KAAK,EAAE,MAAM,KACf,KAAK;GACP,IAAI,KAAK,EAAE,MAAM,KAAK;IACpB,KAAK;IACL,OAAO,KAAK,IAAI,KAAK,EAAE,UAAU,KAAK,EAAE,KAAK,MAAM,OAAO,KAAK,EAAE,KAAK,MAAM,KAAK,KAAK;IACtF,OAAO;GACT;EACF,OACK,IAAI,KAAK,EAAE,MAAM,KAAK;GACzB,KAAK;GACL,IAAI,KAAK,EAAE,MAAM,KAAK;IACpB,KAAK;IAGL,IAAI,KAAK,EAAE,MAAM,KACf,KAAK;SAEF;KACH,IAAI,YAAY;KAChB,IAAI,KAAK,EAAE,MAAM,KAAK;MAAE,KAAK;MAAK,YAAY;KAAK;KACnD,KAAK,GAAG;KAGR,MAAM,QAAQ,KAAK;KACnB,MAAM,QAAQ,KAAK,KAAK;KACxB,MAAM,SAAS,SAAS,KAAK,KAAK,EAAE,MAAM,OAAO,KAAK,CAAC,CAAC;KACxD,IAAI,OACF,KAAK,gBAAgB,KAAK;MAAE;MAAO;MAAW;KAAO,CAAC;KACxD,OAAO;IACT;GACF;EACF;EACA,KAAK,GAAG;EACR,KAAK,KAAK;EACV,OAAO;CACT;;CAGA,UAAwB;EACtB,KAAK,KAAK,KAAK,GAAG,MAAM,IAAI,IAAI;EAChC,KAAK,SAAS;CAChB;;;;;;;;;;;CAYA,WAAyB;EACvB,IAAI,KAAK,gBAAgB,WAAW,GAClC;EACF,MAAM,UAAU,KAAK;EACrB,KAAK,kBAAkB,CAAC;EACxB,KAAK,MAAM,EAAE,OAAO,WAAW,YAAY,SAAS;GAClD,MAAM,OAAiB,CAAC;GACxB,OAAO,KAAK,IAAI,KAAK,EAAE,QAAQ;IAC7B,MAAM,KAAK,KAAK,EAAE,QAAQ,MAAM,KAAK,CAAC;IACtC,MAAM,MAAM,KAAK,IAAI,KAAK,EAAE,MAAM,KAAK,CAAC,IAAI,KAAK,EAAE,MAAM,KAAK,GAAG,EAAE;IACnE,KAAK,IAAI,KAAK,IAAI,KAAK,EAAE,SAAS,KAAK;IACvC,MAAM,OAAO,IAAI,SAAS,IAAI,IAAI,IAAI,MAAM,GAAG,EAAE,IAAI;IACrD,KAAK,YAAY,KAAK,QAAQ,QAAQ,EAAE,IAAI,UAAU,OACpD;IACF,KAAK,KAAK,IAAI;GAChB;GACA,IAAI,CAAC,QACH,KAAK,kBAAkB,KAAK,KAAK,IAAI,CAAC;EAC1C;CACF;;CAGA,kBAA0B,MAAoB;EAC5C,IAAI,IAAI;EACR,OAAO,IAAI,KAAK,QAAQ;GACtB,MAAM,IAAI,KAAK;GACf,IAAI,MAAM,MAAM;IAAE,KAAK;IAAG;GAAS;GACnC,IAAI,MAAM,OAAO,KAAK,IAAI,OAAO,KAAK;IACpC,MAAM,MAAM,IAAI,YAAY,KAAK,MAAM,IAAI,CAAC,CAAC;IAC7C,IAAI,KAAK,GAAG;IACZ,KAAK,MAAM,KAAK,GAAG,IAAI,KAAK;IAC5B,KAAK,IAAI,IAAI;IACb;GACF;GACA,IAAI,MAAM,KAAK;IACb,MAAM,MAAM,IAAI,YAAY,KAAK,MAAM,CAAC,CAAC;IACzC,IAAI,MAAM;IACV,KAAK,MAAM,KAAK,GAAG,IAAI,KAAK;IAC5B,KAAK,IAAI;IACT;GACF;GACA;EACF;CACF;;CAKA,IAAY,QAA0B;EACpC,MAAM,IAAI,KAAK,EAAE;EACjB,IAAI,MAAM,OAAO,MAAM,QAAQ,MAAM,QAAQ,MAAM,OAAO,MAAM,KAC9D,OAAO;EACT,IAAI,MAAM,KACR,OAAO;EACT,IAAI,UAAU,MAAM,QAClB,OAAO;EACT,OAAO;CACT;;;;;;;;CASA,IAAY,QAA0B;EACpC,IAAI,KAAK,KAAK,KAAK,EAAE,QACnB,OAAO;EACT,IAAI,UAAU,KAAK,EAAE,MAAM,QAAQ;GACjC,IAAI,KAAK,gBAAgB,SAAS,GAChC,MAAM,IAAI,MAAM,gCAAgC;GAClD,KAAK;GACL,OAAO;EACT;EACA,OAAO;CACT;CAEA,IAAoB;EAAE,OAAO,KAAK,EAAE,KAAK,MAAM;CAAG;CAClD,GAAW,GAAoB;EAAE,OAAO,KAAK,EAAE,WAAW,GAAG,KAAK,CAAC;CAAE;;;;;;;CAOrE,KAAmB;EACjB,OAAO,KAAK,IAAI,KAAK,EAAE,WAAW,KAAK,EAAE,KAAK,OAAO,OAAO,KAAK,EAAE,KAAK,OAAO,MAAO,KAAK;EAC3F,IAAI,KAAK,EAAE,MAAM,QAAQ,KAAK,MAAM,KAAK,KAAK,IAAI,KAAK,EAAE,KAAK,IAAI,EAAE,IAAI;GACtE,MAAM,KAAK,KAAK,EAAE,QAAQ,MAAM,KAAK,CAAC;GACtC,KAAK,IAAI,KAAK,IAAI,KAAK,EAAE,SAAS;EACpC;CACF;AACF;;AAGA,SAAS,aAAa,GAAoB;CACxC,MAAM,KAAK,EAAE,QAAQ,GAAG;CACxB,IAAI,MAAM,GACR,OAAO;CACT,OAAO,eAAe,KAAK,EAAE,MAAM,GAAG,EAAE,CAAC;AAC3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpVA,SAAgB,mBAAmB,KAAqB;CACtD,OAAO,cAAc,GAAG;AAC1B;;AAaA,SAAgB,iBAAiB,SAAyB;CACxD,OAAO,QAAQ,SAAS,eAAe;AACzC;AAEA,SAAgB,aAAa,SAA+B;CAC1D,MAAM,OAAO,iBAAiB,OAAO;CACrC,IAAI,CAAC,WAAW,IAAI,GAClB,OAAO,CAAC;CACV,IAAI;EACF,MAAM,SAAS,KAAK,MAAM,aAAa,MAAM,OAAO,CAAC;EACrD,IAAI,UAAU,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,MAAM,GAC/D,OAAO;CACX,QACM,CAEN;CACA,OAAO,CAAC;AACV;AAEA,SAAgB,cAAc,SAAiB,MAA0B;CACvE,gBAAgB,iBAAiB,OAAO,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG,EAAE,WAAW,KAAK,CAAC;AAC/F;;;;;;;;AASA,SAAgB,cACd,SACA,YACA,SACmB;CACnB,MAAM,QAAQ,OAAO,YAAY,WAAW,CAAC,OAAO,IAAI;CACxD,MAAM,OAAO,aAAa,OAAO;CACjC,MAAM,WAAW,KAAK,WAAW,EAAE,YAAY,CAAC;CAChD,MAAM,OAAO,CAAC,GAAG,QAAQ;CACzB,KAAK,MAAM,SAAS,OAClB,IAAI,CAAC,KAAK,SAAS,KAAK,GACtB,KAAK,KAAK,KAAK;CAEnB,IAAI,KAAK,WAAW,SAAS,QAC3B,OAAO;CACT,KAAK,cAAc;EAAE,GAAG,KAAK;EAAa,UAAU;CAAK;CACzD,cAAc,SAAS,IAAI;CAC3B,OAAO;AACT;;AAGA,SAAgB,YAAY,SAAiB,YAAuC;CAClF,OAAO,aAAa,OAAO,CAAC,CAAC,WAAW,EAAE,YAAY,CAAC;AACzD;;;;;;;;;;;;AAaA,SAAgB,kBAAkB,SAAiB,KAAgC;CACjF,MAAM,OAAO,aAAa,OAAO;CACjC,MAAM,uBAAO,IAAI,IAAI;EAAC,mBAAmB,GAAG;EAAG,YAAY,GAAG,KAAK;EAAK;CAAG,CAAC;CAC5E,MAAM,SAAmB,CAAC;CAC1B,KAAK,MAAM,OAAO,MAChB,KAAK,MAAM,SAAS,KAAK,IAAI,EAAE,YAAY,CAAC,GAC1C,IAAI,CAAC,OAAO,SAAS,KAAK,GACxB,OAAO,KAAK,KAAK;CAGvB,OAAO;AACT;;AAGA,SAAgB,oBAAoB,SAAiB,KAAa,SAAwD;CACxH,OAAO,cAAc,SAAS,mBAAmB,GAAG,GAAG,OAAO;AAChE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,MAAa,wBAA2C;CACtD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAQA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;AACF;;AAGA,MAAM,mBAAmB;CAAC;CAAW;CAAQ;CAAW;AAAO;AAE/D,SAAS,gBAAgB,OAAwC;CAC/D,KAAK,MAAM,OAAO,kBAAkB;EAClC,MAAM,IAAI,MAAM;EAChB,IAAI,OAAO,MAAM,YAAY,EAAE,SAAS,GACtC,OAAO;CACX;CACA,OAAO;AACT;;;;;;AAOA,SAAS,gBAAgB,OAAwC;CAC/D,OAAO,gBAAgB,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;AAC1D;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,qBACd,OACA,MACA,OACS;CACT,IAAI,UAAU,MACZ,OAAO;CACT,MAAM,MAAM,MAAM,QAAQ,GAAG;CAC7B,IAAI,OAAO,GACT,OAAO;CACT,IAAI,MAAM,MAAM,GAAG,GAAG,MAAM,MAC1B,OAAO;CACT,MAAM,QAAQ,MAAM,MAAM,MAAM,CAAC;CACjC,IAAI,MAAM,SAAS,IAAI,GACrB,OAAO,gBAAgB,KAAK,MAAM,MAAM,MAAM,GAAG,EAAE;CACrD,IAAI,kBAAkB,IAAI,GACxB,OAAO,aAAa,KAAK,MAAM;CACjC,OAAO;AACT;;;;;;;;;;AAWA,SAAgB,aACd,SACA,MACA,OACS;CACT,IAAI,sBAAsB,SAAS,IAAI,KAAK,CAAC,sBAAsB,MAAM,KAAK,GAC5E,OAAO;CAET,IAAI,SAAS,SAAS;EAEpB,MAAM,QAAQ,oBADF,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU,EAC3B;EACrC,IAAI,UAAU,MACZ,OAAO;EACT,IAAI,MAAM,WAAW,GACnB,OAAO,QAAQ,MAAK,MAAK,qBAAqB,GAAG,MAAM,KAAK,CAAC;EAC/D,OAAO,MAAM,OAAM,SACjB,QAAQ,MAAK,MAAK,qBAAqB,GAAG,MAAM;GAAE,GAAG;GAAO,SAAS;EAAK,CAAC,CAAC,CAC9E;CACF;CAEA,OAAO,QAAQ,MAAK,MAAK,qBAAqB,GAAG,MAAM,KAAK,CAAC;AAC/D;;AAGA,SAAS,sBAAsB,MAAc,OAAyC;CACpF,IAAI,CAAC,kBAAkB,IAAI,GACzB,OAAO;CACT,IAAI,OAAO,MAAM,QAAQ,YAAY,CAAC,MAAM,IAAI,KAAK,GACnD,OAAO;CACT,MAAM,MAAM,oBAAoB,MAAM,GAAG;CACzC,OAAO,CAAC,OAAO,CAAC,kBAAkB,GAAG;AACvC;AAEA,SAAS,kBAAkB,MAAuB;CAChD,OAAO,SAAS,kBAAkB,SAAS;AAC7C;;AAGA,SAAS,aAAa,OAAwC;CAC5D,MAAM,MAAM,OAAO,MAAM,QAAQ,WAAW,MAAM,IAAI,KAAK,IAAI;CAC/D,MAAM,MAAM,MAAM,oBAAoB,GAAG,IAAI;CAC7C,IAAI,OAAO;CACX,IAAI;EACF,OAAO,MAAM,IAAI,IAAI,GAAG,CAAC,CAAC,OAAO;CACnC,QACM,CAAC;CACP,OAAO,QAAQ;AACjB;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,uBACd,MACA,OACU;CACV,IAAI,SAAS,SAAS;EAEpB,MAAM,QAAQ,oBADF,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU,EAC3B;EACrC,IAAI,SAAS,MAAM,SAAS,GAAG;GAQ7B,MAAM,MAAgB,CAAC;GACvB,KAAK,MAAM,QAAQ,OAAO;IACxB,MAAM,QAAQ,GAAG,KAAK,GAAG,gBAAgB,EAAE,SAAS,KAAK,CAAC,EAAE;IAC5D,IAAI,CAAC,IAAI,SAAS,KAAK,GACrB,IAAI,KAAK,KAAK;GAClB;GACA,OAAO;EACT;EAMA,MAAM,QAAQ,gBAAgB,KAAK;EACnC,IAAI,OACF,OAAO,CAAC,GAAG,KAAK,GAAG,MAAM,GAAG;CAChC;CACA,IAAI,sBAAsB,MAAM,KAAK,GAAG;EACtC,MAAM,QAAQ,aAAa,KAAK;EAChC,IAAI,OACF,OAAO,CAAC,GAAG,KAAK,GAAG,OAAO;CAC9B;CACA,OAAO,CAAC,IAAI;AACd;;;;AC7VA,MAAa,mBAAmB;;AAGhC,SAAgB,YAAY,MAAsB;CAChD,OAAO,KAAK,SAAA,MAA4B,GAAG,KAAK,MAAM,GAAG,gBAAgB,EAAE,SAAS,KAAK,SAAS,iBAAiB,qBAAqB;AAC1I;;;;;;;AAQA,SAAgB,qBACd,KACA,WACa;CACb,MAAM,cAAc,YAAY,IAAI,MAAM,EAAE;CAE5C,OAAO;EACL,MAAM;EACN,MAAM,IAAI,iBAAiB,WAAW,IAAI,eAAe,KAAK,gBAAgB;EAC9E,SAAS,IAAI;EACb,OAAO,IAAI,SAAS;EACpB,OAAO;GACL;GACA,QAAQ,YAAY,IAAI,IAAI;GAC5B,GAAI,IAAI,gBAAgB,EAAE,eAAe,IAAI,cAAc,IAAI,CAAC;GAChE,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;EAC7C;EACA,GAAI,IAAI,QAAQ,EAAE,OAAO,IAAI,MAAM,IAAI,CAAC;CAC1C;AACF;;;;;AAMA,SAAgB,sBAAsB,KAAsC;CAC1E,OAAO;EACL,MAAM;EACN,MAAM,gCAAgC,IAAI,WAAW,IAAI;EACzD,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;EAC3C,YAAY,IAAI;CAClB;AACF;;;;;;;;AASA,SAAgB,mBACd,KACA,SACA,MAAM,KAAK,IAAI,GACF;CACb,MAAM,MAAM,IAAI,WAAW,YAAY,YAAY,IAAI,WAAW,UAAU,UAAU;CACtF,MAAM,YAAY,SAAS;CAC3B,MAAM,UAAU,cAAc,KAAA,IAAY,MAAM,eAAe,MAAM,SAAS,MAAM;CACpF,MAAM,OAAO,aAAa,IAAI,KAAK,CAAC,CAAC,QAAQ,KAAK,SAAS,OAAO,KAAK,QAAQ,IAAI,CAAC;CAEpF,MAAM,WAAW,GAAG,UADH,OAAO,IAAI,OAAO,KAAK,QAAQ,OAAO,MAAO,IAAI,CAAC,MAAM;CAEzE,MAAM,QAAQ,iBAAiB,IAAI,KAAK;CAExC,OAAO;EACL,MAAM;EACN,MAAM,WAAW,GAAG,MAAM,SAAS,KAAK,UAAU,GAAG,IAAI,GAAG;EAC5D,SAAS,IAAI;EACb,OAAO,IAAI,SAAS;EACpB,OAAO;GACL,WAAW,aAAa;GACxB,GAAI,SAAS,OAAO,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;GAC9C,OAAO,IAAI,MAAM;GACjB,GAAI,IAAI,gBAAgB,EAAE,eAAe,IAAI,cAAc,IAAI,CAAC;EAClE;EACA,GAAI,SAAS,QAAQ,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;CACnD;AACF;;;;;;;AC5FA,SAAgB,gBAAgB,OAAsB,MAAsD;CAc1G,MAAM,0BAAU,IAAI,IAAwB;CAC5C,KAAK,MAAM,OAAO,MAChB,IAAI,CAAC,QAAQ,IAAI,IAAI,EAAE,GACrB,QAAQ,IAAI,IAAI,IAAI,GAAG;CAyB3B,MAAM,WAAqB,CAAC;CAC5B,MAAM,yCAAyB,IAAI,IAAyB;CAC5D,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,MAAM,KAAK;EACjB,IAAI,CAAC,KACH;EACF,MAAM,aAAa,SAAS,QAAQ,GAAG;EACvC,IAAI,cAAc,GAEhB,SAAS,SAAS,aAAa;OAE5B;GASH,MAAM,MAAM,SAAS,SAAS,SAAS;GAEvC,IAAI,EADqB,QAAQ,KAAA,MAAc,uBAAuB,IAAI,GAAG,CAAC,EAAE,QAAQ,KAAK,IAI3F,SAAS,SAAS;GAEpB,SAAS,KAAK,GAAG;GAEjB,IAAI,CAAC,QAAQ,IAAI,GAAG,GAClB,QAAQ,IAAI,KAAK,eAAe,MAAM,KAAK,QAAQ,CAAC;EACxD;EAMA,MAAM,UAAU,uBAAuB,IAAI,GAAG,qBAAK,IAAI,IAAY;EACnE,KAAK,MAAM,SAAS,KAAK,SAIvB,IAAI,MAAM,SAAS,eAAe,SAAS,KAAK,MAAM,IAAI,GACxD,QAAQ,IAAI,MAAM,EAAE;OACjB,IAAI,MAAM,SAAS,eACtB,QAAQ,OAAO,MAAM,MAAM;EAE/B,uBAAuB,IAAI,KAAK,OAAO;CACzC;CACA,OAAO;AACT;;AAGA,SAAS,eAAe,MAAmB,KAAa,UAAyC;CAO/F,MAAM,QAAQ,SAAS,SAAS;CAChC,MAAM,cAAc,QAAQ,IAAI,SAAS,QAAQ,KAAK,KAAA;CACtD,IAAI,iBAAiB;CACrB,IAAI,KAAK,SAAS,QACX;OAAA,MAAM,SAAS,KAAK,SACvB,IAAI,MAAM,SAAS,UAAU,MAAM,KAAK,KAAK,GAAG;GAC9C,iBAAiB,MAAM;GACvB;EACF;;CAGJ,OAAO;EACL,IAAI;EACJ,WAAW,KAAK;EAChB,QAAQ;EACR,QAAQ;EACR;EACA,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;CACvC;AACF;;AAGA,SAAgB,aAAa,SAAqE;CAUhG,MAAM,oCAAoB,IAAI,IAAoB;CAQlD,CAPmB,GAAG,QAAQ,OAAO,CAAC,CAAC,CACpC,QAAO,OAAM,EAAE,SAAS,KAAK,CAAC,CAAC,CAC/B,MAAM,GAAG,MAAM,EAAE,YAAY,EAAE,SAK1B,CAAC,CAAC,SAAS,GAAG,MAAM,kBAAkB,IAAI,EAAE,IAAI,EAAE,SAAS,SAAS,IAAI,GAAG,CAAC;CACpF,QAAQ,UAAkB,kBAAkB,IAAI,KAAK,KAAK;AAC5D;;AAGA,SAAgB,kBAAkB,OAA2C;CAK3E,MAAM,+BAAe,IAAI,IAAoB;CAC7C,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,KAAK,SAAS,aAChB;EACF,KAAK,MAAM,SAAS,KAAK,SACvB,IAAI,MAAM,SAAS,aACjB,aAAa,IAAI,MAAM,IAAI,MAAM,IAAI;CAE3C;CACA,OAAO;AACT;;AAGA,SAAgB,oBAAoB,OAA2C;CAM7E,MAAM,iCAAiB,IAAI,IAAoB;CAC/C,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,KAAK,SAAS,QAChB;EACF,KAAK,MAAM,SAAS,KAAK,SACvB,IAAI,MAAM,SAAS,eACjB,eAAe,IACb,MAAM,QACN,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS,iBAAiB,MAAM,MAAM,CACjF;CAGN;CACA,OAAO;AACT;;;;;;AAOA,SAAgB,eACd,SACA,UACyC;CACzC,QAAQ,QAAoB;EAC1B,MAAM,SAAS,IAAI,cAAc,QAAQ,IAAI,IAAI,WAAW,IAAI,KAAA;EAChE,OAAO,WAAW,OAAO,SAAS,KAAK,IAAI,SAAS,OAAO,EAAE,IAAI,KAAA;CACnE;AACF;;AAGA,SAAgB,YAAY,SAA2F;CAQrH,QAAQ,cAAgD;EACtD,IAAI,CAAC,WACH,OAAO,CAAC;EACV,MAAM,QAAsB,CAAC;EAC7B,IAAI,SAAiC,QAAQ,IAAI,SAAS;EAC1D,MAAM,uBAAO,IAAI,IAAY;EAC7B,OAAO,QAAQ;GAGb,IAAI,KAAK,IAAI,OAAO,EAAE,GACpB;GACF,KAAK,IAAI,OAAO,EAAE;GAClB,KAAK,OAAO,SAAS,KAAK,GACxB,MAAM,QAAQ,MAAM;GACtB,SAAS,OAAO,cAAc,QAAQ,IAAI,OAAO,WAAW,IAAI,KAAA;EAClE;EACA,OAAO;CACT;AACF;;AAKA,SAAgB,iBAAiB,SAA+E;CAS9G,MAAM,8BAAc,IAAI,IAA0B;CAClD,KAAK,MAAM,OAAO,QAAQ,OAAO,GAAG;EAClC,IAAI,CAAC,IAAI,aACP;EACF,MAAM,WAAW,YAAY,IAAI,IAAI,WAAW,KAAK,CAAC;EACtD,SAAS,KAAK,GAAG;EACjB,YAAY,IAAI,IAAI,aAAa,QAAQ;CAC3C;CACA,QAAQ,SAAoC;EAC1C,MAAM,SAAS;GAAE,MAAM;GAAG,UAAU;GAAG,WAAW;GAAG,WAAW;GAAG,eAAe;EAAE;EACpF,MAAM,QAAQ,CAAC,IAAI;EACnB,MAAM,uBAAO,IAAI,IAAY;EAC7B,OAAO,MAAM,SAAS,GAAG;GACvB,MAAM,MAAM,MAAM,IAAI;GACtB,IAAI,KAAK,IAAI,IAAI,EAAE,GACjB;GACF,KAAK,IAAI,IAAI,EAAE;GACf,OAAO,QAAQ,IAAI,QAAQ,IAAI,WAAW,QAAQ,KAAK,MAAM,OAAO,EAAE,QAAQ,IAAI,CAAC,KAAK;GACxF,OAAO,YAAY,IAAI,YAAY,IAAI,YAAY,SAAS;GAC5D,OAAO,aAAa,IAAI,aAAa,IAAI,YAAY,UAAU;GAC/D,OAAO,aAAa,IAAI,YAAY,aAAa;GACjD,OAAO,iBAAiB,IAAI,YAAY,iBAAiB;GACzD,MAAM,KAAK,GAAI,YAAY,IAAI,IAAI,EAAE,KAAK,CAAC,CAAE;EAC/C;EACA,OAAO;CACT;AACF;;AAGA,SAAgB,cAAc,KAAiB,QAAuB,UAAqC,eAAqC;CAC9I,MAAM,MAAM,IAAI,WAAW,aAAa,IAAI,WAAW,UAAU,IAAI,SAAS;CAM9E,MAAM,QAAQ,iBAAiB;EAC7B,SAAS,OAAO;EAChB,UAAU,OAAO;EACjB,gBAAgB,OAAO;EACvB,oBAAoB,OAAO;CAC7B,CAAC;CAMD,MAAM,UAAU,IAAI,YAAY,KAAA,IAAY,MAAM,eAAe,IAAI,UAAU,IAAI,SAAS,MAAM;CAClG,MAAM,OAAO,OAAO;CAIpB,MAAM,WAAW,GAAG,UAHH,OAAO,IAAI,OAAO,KAAK,QAAQ,OAAO,MAAO,IAAI,CAAC,MAAM;CAIzE,MAAM,QAAQ,IAAI,WAAW,MAAK,MAAK,EAAE,OAAO,CAAC,EAAE;CACnD,MAAM,QAAQ,IAAI,SAAS,IAAI,WAAW;CAC1C,OAAO;EACL,MAAM;EACN,MAAM,WAAW,GAAG,MAAM,SAAS,KAAK,UAAU,GAAG,IAAI,GAAG;EAC5D,SAAS,SAAS,IAAI,EAAE;EACxB,OAAO,IAAI,SAAS;EACpB,OAAO;GACL,WAAW,IAAI;GACf,MAAM,YAAY,IAAI,QAAQ,EAAE;GAChC,GAAI,UAAU,KAAA,IAAY,EAAE,MAAM,IAAI,CAAC;GACvC,GAAI,gBAAgB,EAAE,cAAc,IAAI,CAAC;EAC3C;EACA,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;CAC3B;AACF;;AAGA,SAAgB,gBAAgB,KAAiB,UAAqC,eAAqC;CAMzH,MAAM,cAAc,YAAY,IAAI,QAAQ,EAAE;CAK9C,MAAM,QAAQ,IAAI,WAAW,MAAK,MAAK,EAAE,OAAO,CAAC,EAAE;CAGnD,MAAM,UAAU,IAAI,mBAAmB,SAAS,IAAI,gBAAgB,IAAI,KAAA;CACxE,OAAO;EACL,MAAM;EACN,MAAM,UAAU,WAAW,QAAQ,KAAK,gBAAgB;EACxD,SAAS,SAAS,IAAI,EAAE;EACxB,OAAO,IAAI,SAAS;EACpB,OAAO;GACL,WAAW,IAAI;GACf,MAAM;GACN,QAAQ,YAAY,IAAI,MAAM;GAC9B,GAAI,gBAAgB,EAAE,cAAc,IAAI,CAAC;GACzC,GAAI,IAAI,eAAe,EAAE,QAAQ,IAAI,aAAa,IAAI,CAAC;EACzD;EACA,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;CAC3B;AACF;;;;;;AAOA,SAAgB,kBAAkB,QAAuB,OAAsB,MAAmE;CAShJ,MAAM,kCAAkB,IAAI,IAAoB;CAChD,KAAK,MAAM,QAAQ,OACjB,IAAI,KAAK,OACP,gBAAgB,IAAI,KAAK,OAAO,KAAK,EAAE;CAE3C,MAAM,mCAAmB,IAAI,IAA2B;CACxD,KAAK,MAAM,OAAO,MAAM;EACtB,IAAI,IAAI,gBAAgB,KAAA,KAAa,IAAI,YAAY,KAAA,GACnD;EACF,MAAM,aAAa,gBAAgB,IAAI,IAAI,EAAE;EAC7C,IAAI,CAAC,YACH;EACF,MAAM,SAAwB,CAAC;EAC/B,IAAI,IAAI,WAAW,WAAW,IAAI,OAChC,OAAO,KAAK;GAAE,MAAM;GAAS,MAAM,IAAI;GAAO,QAAQ;EAAW,CAAC;EACpE,MAAM,UAAU,kBAAkB,GAAG;EACrC,IAAI,cAAc,OAAO,GACvB,OAAO,KAAK;GAAE,MAAM;GAAe,MAAM,qBAAqB,OAAO;GAAG,YAAY;GAAS,QAAQ;EAAW,CAAC;EACnH,IAAI,OAAO,SAAS,GAClB,iBAAiB,IAAI,YAAY,MAAM;CAC3C;CACA,MAAM,WAAiD,CAAC;CACxD,IAAI,iBAAiB,OAAO,GAAG;EAG7B,MAAM,kCAAkB,IAAI,IAAoB;EAChD,OAAO,SAAS,GAAG,QAAQ;GACzB,IAAI,EAAE,UAAU,iBAAiB,IAAI,EAAE,MAAM,GAC3C,gBAAgB,IAAI,EAAE,QAAQ,GAAG;EACrC,CAAC;EACD,MAAM,UAAU,CAAC,GAAG,gBAAgB,QAAQ,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,EAAE;EACzE,KAAK,MAAM,CAAC,QAAQ,QAAQ,SAAS;GACnC,MAAM,SAAS,iBAAiB,IAAI,MAAM;GAC1C,OAAO,OAAO,MAAM,GAAG,GAAG,GAAG,MAAM;GACnC,SAAS,KAAK;IAAE,IAAI,MAAM;IAAG,OAAO,OAAO;GAAO,CAAC;EACrD;CACF;CACA,OAAO;AACT;;;ACrYA,SAAS,eAAe,MAAoB;CAC1C,MAAM,MAAM,QAAQ,IAAI;CACxB,IAAI,WAAW,GAAG,GAChB;CACF,IAAI;EACF,UAAU,KAAK,EAAE,WAAW,KAAK,CAAC;CACpC,SACO,KAAK;EACV,MAAM,IAAI,MACR,4CAA4C,IAAI,yHAEK,aAAa,GAAG,GACvE;CACF;AACF;AA8DA,SAAgB,iBAAiB,MAA6B;CAC5D,OAAO;EACL,YAAY,UAAU,IAAI;EAC1B,OAAM,UAAS,UAAU,MAAM,KAAK;CACtC;AACF;AAEA,SAAgB,UAAU,MAAwB;CAChD,IAAI,CAAC,WAAW,IAAI,GAClB,OAAO,CAAC;CACV,IAAI;EACF,MAAM,SAAS,KAAK,MAAM,aAAa,MAAM,OAAO,CAAC;EACrD,IAAI,UAAU,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,MAAM,GAC/D,OAAO,iBAAiB,MAAoD;CAChF,QACM,CAEN;CACA,OAAO,CAAC;AACV;;AAGA,SAAS,iBAAiB,OAA6D;CACrF,MAAM,EAAE,mBAAmB,QAAQ,GAAG,SAAS;CAC/C,IAAI,KAAK,uBAAuB,KAAA,KAAa,OAAO,WAAW,UAC7D,OAAO;EAAE,GAAG;EAAM,oBAAoB;CAAO;CAC/C,OAAO;AACT;AAEA,SAAgB,UAAU,MAAc,OAAuB;CAC7D,eAAe,IAAI;CACnB,gBAAgB,MAAM,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AACtD;;;;;;;;;;;AAoBA,eAAsB,gBACpB,OACA,QASwB;CAKxB,IAAI,MAAM,UACR,IAAI;EAEF,QAAO,MADY,MAAM,SAAS,MAAM,EAAA,CAC5B,IAAI,WAAW;CAC7B,SACO,KAAK;EACV,IAAI,QAAQ,IAAI,cAAc;GAC5B,MAAM,QAAQ,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;GAC7D,QAAQ,OAAO,MAAM,oEAAoE,MAAM,GAAG;EACpG;CACF;CAEF,MAAM,MAAM,MAAM,MAAM,KAAK,MAAM;CACnC,MAAM,UAAU,MAAM,QAAQ,WAAW,IAAI,IAAI,OAAO,OAAO;EAC7D,MAAM,OAAO,MAAM,MAAM,KAAK,EAAE;EAChC,OAAO,OAAO,aAAa,IAAI,IAAI,IAAI;CACzC,CAAC,CAAC;CACF,MAAM,QAAuB,CAAC;CAC9B,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;EACvC,MAAM,SAAS,QAAQ;EACvB,IAAI,OAAO,WAAW,eAAe,OAAO,OAC1C,MAAM,KAAK,OAAO,KAAK;OAEpB,IAAI,OAAO,WAAW,cAAc,QAAQ,IAAI,cAAc;GACjE,MAAM,QAAQ,OAAO,kBAAkB,QAAQ,OAAO,OAAO,UAAU,OAAO,OAAO,MAAM;GAC3F,QAAQ,OAAO,MAAM,yCAAyC,IAAI,GAAG,KAAK,MAAM,GAAG;EACrF;CACF;CACA,OAAO;AACT;;AAGA,SAAS,YAAY,KAAkC;CACrD,OAAO;EACL,IAAI,IAAI;EACR,OAAO,mBAAmB,IAAI,gBAAgB,CAAC,IAAI,aAAa,IAAI,CAAC,GAAG,IAAI,QAAQ;EACpF,WAAW,IAAI;EACf,kBAAkB,IAAI;EACtB,UAAU,IAAI;EACd,GAAI,cAAc,IAAI,QAAQ,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;EACtD,GAAI,IAAI,cAAc,EAAE,aAAa,IAAI,YAAY,IAAI,CAAC;EAC1D,GAAG,QAAQ,IAAI,QAAQ;EACvB,GAAG,gBAAgB,IAAI,QAAQ;EAC/B,GAAI,OAAO,IAAI,kBAAkB,WAAW,EAAE,eAAe,IAAI,cAAc,IAAI,CAAC;EACpF,WAAW,IAAI;CACjB;AACF;;AAGA,SAAS,aAAa,IAAY,MAAgC;CAChE,OAAO;EACL;EACA,OAAO,mBAAmB,KAAK,OAAO,KAAK,QAAQ;EACnD,WAAW,KAAK,MAAM;EACtB,kBAAkB,KAAK,MAAM,QAAQ,GAAG,MAAM,EAAE,SAAS,SAAS,IAAI,IAAI,GAAG,CAAC;EAC9E,UAAU,KAAK,KAAK;EACpB,GAAI,cAAc,KAAK,QAAQ,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;EACvD,GAAI,KAAK,cAAc,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;EAC5D,GAAG,QAAQ,KAAK,QAAQ;EACxB,GAAG,gBAAgB,KAAK,QAAQ;EAChC,WAAW,KAAK;CAClB;AACF;;AAGA,SAAgB,0BAA0B,UAAsF;CAC9H,IAAI,CAAC,WAAA,gBACH,OAAO,KAAA;CACT,MAAM,cAAc,uBAAuB,QAAQ;CACnD,IAAI,YAAY,SAAS,kBAAkB,QAAQ,YAAY,UAAU,SACvE,OAAO,KAAA;CACT,OAAO;EACL,MAAM,YAAY;EAClB,OAAO,YAAY;EACnB,GAAI,YAAY,SAAS,EAAE,QAAQ,YAAY,OAAO,IAAI,CAAC;EAC3D,GAAI,YAAY,QAAQ,EAAE,OAAO,YAAY,MAAM,IAAI,CAAC;EACxD,GAAI,YAAY,YAAY,EAAE,WAAW,KAAK,IAAI,CAAC;EACnD,GAAI,YAAY,UAAU,EAAE,eAAe,YAAY,QAAQ,IAAI,CAAC;CACtE;AACF;AAEA,SAAS,gBAAgB,UAA4F;CACnH,MAAM,cAAc,0BAA0B,QAAQ;CACtD,OAAO,cAAc,EAAE,YAAY,IAAI,CAAC;AAC1C;AAEA,SAAS,QAAQ,UAAiE;CAChF,MAAM,MAAM,UAAU;CACtB,OAAO,OAAO,QAAQ,YAAY,IAAI,SAAS,IAAI,EAAE,IAAI,IAAI,CAAC;AAChE;;;;;;;;;;;AAYA,eAAsB,eAAe,OAAqB,IAAyC;CACjG,IAAI,MAAM,SACR,IAAI;EACF,MAAM,MAAM,MAAM,MAAM,QAAQ,EAAE;EAClC,OAAO,MAAM,YAAY,GAAG,IAAI;CAClC,SACO,KAAK;EACV,IAAI,QAAQ,IAAI,cAAc;GAC5B,MAAM,QAAQ,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;GAC7D,QAAQ,OAAO,MAAM,oEAAoE,MAAM,GAAG;EACpG;CACF;CAEF,MAAM,OAAO,MAAM,MAAM,KAAK,EAAE;CAChC,OAAO,OAAO,aAAa,IAAI,IAAI,IAAI;AACzC;;AAGA,SAAgB,eAAe,MAAkC;CAC/D,OAAO;EACL,GAAG,aAAa,KAAK,IAAI,IAAI;EAC7B,GAAI,KAAK,UAAU,EAAE,SAAS,KAAK,QAAQ,IAAI,CAAC;EAChD,QAAQ,KAAK;EACb,UAAU,KAAK;EACf,WAAW,KAAK;CAClB;AACF;;;;;;AAOA,eAAsB,iBAAiB,OAAqB,IAA2C;CACrG,MAAM,MAAM,MAAM,UAAU,MAAM,MAAM,QAAQ,EAAE,CAAC,CAAC,YAAY,IAAI,IAAI;CACxE,MAAM,SAAS,OAAO,KAAK,SAAS,UAAU,YAAY,IAAI,SAAS,MAAM,KAAK,MAAM;CACxF,IAAI,OAAO,IAAI,WAAW,KAAA,MAAc,UAAU,IAAI,kBAAkB,KAAA,KAAa,IAAI,qBAAqB,IAC5G,OAAO;EACL,GAAG,YAAY,GAAG;EAClB,GAAI,IAAI,UAAU,EAAE,SAAS,IAAI,QAAQ,IAAI,CAAC;EAC9C,QAAQ,IAAI;EACZ,UAAU,IAAI;EACd,GAAI,IAAI,cAAc,KAAA,IAAY,EAAE,WAAW,IAAI,UAAU,IAAI,CAAC;CACpE;CAEF,MAAM,OAAO,MAAM,MAAM,KAAK,EAAE;CAChC,OAAO,OAAO,eAAe;EAAE,GAAG;EAAM;CAAG,CAAC,IAAI;AAClD;;AAGA,SAAgB,eAAe,OAAqC;CAClE,MAAM,QAAQ,MAAM,MAAK,MAAK,EAAE,SAAS,MAAM;CAC/C,IAAI,CAAC,OACH,OAAO;CACT,KAAK,MAAM,SAAS,MAAM,SACxB,IAAI,MAAM,SAAS,UAAU,MAAM,KAAK,KAAK,GAAG;EAC9C,MAAM,UAAU,MAAM,KAAK,QAAQ,QAAQ,GAAG,CAAC,CAAC,KAAK;EACrD,OAAO,QAAQ,SAAS,KAAK,GAAG,QAAQ,MAAM,GAAG,EAAE,EAAE,KAAK;CAC5D;CAEF,OAAO;AACT;;;;;;;AAQA,MAAa,wBAAwB;;;;;;;;;;;AAYrC,SAAgB,mBACd,OACA,UACQ;CACR,MAAM,SAAS,OAAO,UAAU,UAAU,WAAW,SAAS,MAAM,KAAK,IAAI;CAC7E,IAAI,OAAO,SAAS,GAClB,OAAO;CACT,OAAO,eAAe,KAAK,KAAA;AAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,SAAgB,oBACd,OACA,QACa;CACb,OAAO;EACL,MAAM;EACN,MAAM,MAAM;EACZ,SAAS;GACP,eAAe,MAAM,gBAAgB;GACrC,OAAO,MAAM;GACb,aAAa,MAAM;GACnB,aAAa,MAAM,MAAM,SAAS;GAClC,cAAc,MAAM,MAAM,UAAU;GACpC,iBAAiB,MAAM,MAAM,aAAa;GAC1C,qBAAqB,MAAM,MAAM,iBAAiB;GAClD,GAAI,OAAO,MAAM,MAAM,SAAS,YAAY,MAAM,MAAM,OAAO,IAAI,EAAE,SAAS,MAAM,MAAM,KAAK,IAAI,CAAC;EACtG;EACA,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;CAC7B;AACF;;;;;;;AAQA,SAAS,kBAAkB,MAAsB;CAC/C,MAAM,UAAU,KAAK,SAAS,IAAI,IAAI,IAAI,KAAK,SAAS,GAAG,IAAI,IAAI;CACnE,OAAO,KAAK,MAAM,KAAK,SAAS,IAAI,CAAC,IAAI;AAC3C;;AAGA,MAAM,oCAAoB,IAAI,IAAI;CAAC;CAAQ;CAAQ;AAAO,CAAC;;;;;;AAgB3D,SAAS,eAAe,OAAwC;CAC9D,IAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAC5D,OAAO;CACT,MAAM,EAAE,UAAU,OAAO,SAAS,UAAU;CAM5C,IAAI,OAAO,aAAa,YAAY,CAAC,kBAAkB,IAAI,QAAQ,GACjE,OAAO;CACT,IAAI,OAAO,UAAU,YAAY,UAAU,IACzC,OAAO;CACT,OAAO;EACL,QAAQ;GAAY;GAA4D;EAAM;EACtF,GAAI,OAAO,YAAY,YAAY,YAAY,KAAK,EAAE,QAAQ,IAAI,CAAC;EACnE,GAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,KAAK,SAAS,IAAI,EAAE,OAAO,KAAK,MAAM,KAAK,EAAE,IAAI,CAAC;CAC1G;AACF;;AAGA,SAAS,gBAAgB,OAA+D;CACtF,IAAI,MAAM,SAAS,eACjB,OAAO;CACT,MAAM,OAAO,MAAM,UAAU;CAC7B,IAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,IAAI,GACzD,OAAO;CACT,OAAO,eAAgB,KAAiC,MAAM;AAChE;;;;;;;;;;;;;;AAeA,SAAgB,kBACd,QACA,MACA,SAA+C,CAAC,GACxB;CACxB,OAAO,CAAC;EACN,MAAM;EACN,QAAQ,UAAU,OAAO,WAAW;EACpC,QAAQ;EACR,UAAU,EACR,SAAS,EACP,QAAQ;GACN,UAAU,OAAO;GACjB,OAAO,OAAO;GACd,GAAI,OAAO,UAAU,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;GACpD,GAAI,OAAO,UAAU,KAAA,IAAY,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;EAC9D,EACF,EACF;CACF,CAAC;AACH;;AAkBA,SAAS,kBAAkB,MAAmB,OAAiF;CAG7H,MAAM,cAAmE,CAAC;CAC1E,KAAK,MAAM,WAAW,KAAK,SACzB,IAAI,QAAQ,SAAS,WAAW,QAAQ,SAAS,WAAW,QAAQ,SAAS,SAC3E,YAAY,KAAK;EACf,MAAM,QAAQ,QAAQ,QAAQ;EAC9B,WAAW,QAAQ;EACnB,MAAM,OAAO,QAAQ,SAAS,WAC1B,kBAAkB,QAAQ,IAAI,IAC9B;CACN,CAAC;MAEE,IAAI,QAAQ,SAAS,YAMxB,YAAY,KAAK;EACf,MAAM,QAAQ,QAAQ;EACtB,WAAW,QAAQ;EACnB,MAAM,OAAO,QAAQ,SAAS,WAC1B,IACA,QAAQ,aAAa,SACnB,OAAO,WAAW,QAAQ,IAAI,IAC9B,kBAAkB,QAAQ,IAAI;CACtC,CAAC;MAEE,IAAI,YAAY,SAAS,QAAQ,SAAS,QAAQ;EACrD,MAAM,IAAI,QAAQ,KAAK,MAAM,gEAAgE;EAC7F,IAAI,GACF,YAAY,KAAK;GACf,MAAM,EAAE,MAAM;GACd,WAAW,EAAE,MAAM;GACnB,MAAM,QAAQ,KAAK;EACrB,CAAC;CAEL;CAEF,OAAO;AACT;;AAGA,SAAS,eACP,OACA,MACA,OACA,OACA,KACA,QACM;CACN,MAAM,EAAE,WAAW;CAYnB,MAAM,YAAY,2BAA2B,MAAM,MAAM,GAAG;CAC5D,IAAI,WAAW;EACb,OAAO,KAAK,SAAS;EACrB;CACF;CAOA,MAAM,eAAe,qBAAqB,MAAM,IAAI;CACpD,IAAI,cAAc;EAChB,OAAO,KAAK;GAAE,MAAM;GAAiB,MAAM,aAAa;GAAS;GAAc,GAAG;EAAI,CAAC;EACvF;CACF;CASA,IAAI,UAAU,GAAG;EAOf,MAAM,gBAAgB,KAAK,QAAQ,MAAM,QAAQ,IAAI,KAAK,KAAK,CAAC,EAAE,SAAS,KAAA;EAC3E,IAAI,eAAe,SAAS,WAAW;GACrC,OAAO,KAAK;IACV,MAAM;IACN,OAAO,cAAc,UAAU,iBAAiB,cAAc,OAAO,IAAI;IACzE,MAAM,MAAM;IACZ,GAAG;GACL,CAAC;GACD;EACF;EACA,IAAI,KAAK,YAAY,KAAA,KAAa,CAAC,KAAK,OAAO;GAC7C,IAAI,CAAC,OAAO,WAAW,KAAK,YAAY,IACtC,OAAO,KAAK;IAAE,MAAM;IAAgB,MAAM,gBAAgB,KAAK,SAAS,MAAM,MAAM,MAAM,qBAAqB,KAAA,CAAS;IAAG,GAAG;GAAI,CAAC;GACrI,OAAO,UAAU;GACjB;EACF;EACA,MAAM,oBAAoB;EAW1B,IAAI,MAAM,wBAAwB,GAChC,OAAO,KAAK;GAAE,MAAM;GAAa,MAAM;EAAG,CAAC;EAE7C,MAAM,cAAc,kBAAkB,MAAM,KAAK;EAGjD,MAAM,OAAO,gBAAgB,MAAM,IAAI;EACvC,OAAO,KAAK;GACV,MAAM;GACN,MAAM,MAAM;GACZ,QAAQ,KAAK;GACb,GAAI,KAAK,SAAS,IAAI,EAAE,KAAK,IAAI,CAAC;GAClC,GAAI,YAAY,SAAS,IAAI,EAAE,YAAY,IAAI,CAAC;EAClD,CAAC;CACH;AACF;;AAGA,SAAS,eAAe,OAAoB,MAAmB,OAAe,KAAsB;CAClG,MAAM,EAAE,WAAW;CAGnB,MAAM,SAAS,EAAE,SAAS,MAAM;CAGhC,MAAM,iBAFiB,CAAC,KAAK,QAAQ,MAAK,UAAS,MAAM,SAAS,UAAU,MAAM,KAAK,KAAK,CAAC,KACxF,KAAK,QAAQ,MAAK,UAAS;EAAC;EAAY;EAAS;EAAS;CAAO,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,IAExF,CAAC;EAAE,MAAM;EAAQ,MAAM;CAAe,GAAG,GAAG,KAAK,OAAO,IACxD,KAAK;CACT,KAAK,MAAM,SAAS,gBAClB,IAAI,MAAM,SAAS,UAAU,MAAM,KAAK,KAAK,GAC3C,eAAe,OAAO,MAAM,OAAO,OAAO,KAAK,MAAM;MAElD,IAAI,MAAM,SAAS,eAAe;EACrC,MAAM,OAAO,MAAM,aAAa,IAAI,MAAM,MAAM;EAKhD,MAAM,MAAM,eAAe,MAAM,MAAM;EACvC,MAAM,OAAO,SAAS,UAAU,qBAAqB,GAAG,IAAI;EAC5D,OAAO,KAAK;GACV,MAAM;GACN;GACA,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;GACvB,QAAQ,MAAM;GAEd,GAAI,MAAM,UAAU,EAAE,SAAS,KAAc,IAAI,CAAC;GAClD,GAAG;EACL,CAAC;CACH,OACK,IAAI,MAAM,SAAS,mBAStB,OAAO,KAAK,oBAAoB,OAAO,KAAK,EAAE,CAAC;AAGrD;;AAGA,SAAS,uBAAuB,OAA8D,KAA6B;CACzH,MAAM,OAAO,MAAM,UAAU;CAC7B,MAAM,cAAe,QAAQ,OAAO,SAAS,YAAY,CAAC,MAAM,QAAQ,IAAI,IACxE,OACA,KAAA;CAKJ,MAAM,kBAAkB,eAAe,aAAa,MAAM;CAC1D,IAAI,iBACF,OAAO;EACL,MAAM,gBAAgB,OAAO,aAAa,UAAU,UAAU;EAC9D,MAAM,eAAe,MAAM,MAAM;EACjC,QAAQ,gBAAgB;EACxB,GAAG;EAIH,GAAI,gBAAgB,UAAU,EAAE,SAAS,gBAAgB,QAAQ,IAAI,CAAC;EACtE,GAAI,gBAAgB,UAAU,KAAA,IAAY,EAAE,OAAO,gBAAgB,MAAM,IAAI,CAAC;CAChF;CAIF,MAAM,aAAa,aAAa;CAChC,IAAI,cAAc,OAAO,eAAe,YAAY,CAAC,MAAM,QAAQ,UAAU,KACxE,OAAQ,WAAsC,aAAa,UAAU;EAIxE,MAAM,QAAQ;EACd,OAAO;GACL,MAAM;GACN,MAAM,eAAe,MAAM,MAAM;GACjC,QAAQ;IAAE,UAAU,MAAM;IAAU,GAAI,MAAM,SAAS,KAAA,IAAY,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;GAAG;GAC9F,GAAG;EACL;CACF;CACA,MAAM,QAAQ,OAAO,aAAa,UAAU,WAAW,YAAY,QAAQ,KAAA;CAC3E,OAAO;EACL,MAAM;EACN,MAAM,eAAe,MAAM,MAAM;EACjC,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;EACzB,GAAI,aAAa,WAAW,SAAS,EAAE,QAAQ,OAAgB,IAAI,CAAC;EACpE,GAAG;CACL;AACF;;AAGA,SAAS,kBAAkB,OAAoB,MAAmB,KAAsB;CACtF,MAAM,EAAE,WAAW;CAiBnB,MAAM,aAAa,KAAK,QAAQ,SAAS,KAAK,KAAK,QAAQ,OAAM,UAAS,gBAAgB,KAAK,MAAM,IAAI;CACzG,MAAM,QAAQ,KAAK,QAAQ;CAC3B,MAAM,aAAa,OAAO,SAAS,SAAS,mBAAmB,MAAM,IAAI,IAAI;CAC7E,IAAI,eAAe,MACjB,MAAM,oBAAoB;CAC5B,IAAI,MAAM,wBAAwB,KAAK,CAAC,eAAe,eAAe,QAAQ,MAAM,sBAAsB,OACxG,OAAO,KAAK;EAAE,MAAM;EAAa,MAAM;CAAG,CAAC;CAC7C,KAAK,MAAM,SAAS,KAAK,SACvB,IAAI,eAAe,QAAQ,UAAU,OACnC,OAAO,KAAK;EAAE,MAAM;EAAe,MAAM;EAAY,WAAW;EAAM,QAAQ,KAAK;CAAG,CAAC;MAEpF,IAAI,MAAM,SAAS,UAAU,MAAM,KAAK,KAAK,GAChD,OAAO,KAAK;EAAE,MAAM;EAAY,MAAM,MAAM;EAAM,WAAW;EAAO,GAAG;CAAI,CAAC;MAEzE,IAAI,MAAM,SAAS,eACtB,OAAO,KAAK,uBAAuB,OAAO,GAAG,CAAC;AAGpD;;AAGA,SAAS,cACP,OACA,gBACA,KACa;CAOb,MAAM,EAAE,MAAM,UADA,eAAe,MAAM,MAAM,MAAM,KACnB,KAAK;CAMjC,IAAI,OAAO,mBAAmB,MAAM,KAAK;CACzC,IAAI,MAAM;EAMR,MAAM,aAAa,eAAe,IAAI,MAAM,EAAE;EAC9C,IAAI,YAAY;GACd,MAAM,WAAW,4BAA4B,UAAU;GACvD,IAAI,YAAY,SAAS,WAAW,KAAK,MAAM,QAC7C,OAAO;IAAE,GAAG;IAAM;GAAS;EAC/B;CACF;CACA,OAAO;EACL,MAAM;EACN,MAAM,gBAAgB,MAAM,KAAK;EACjC,MAAM;EACN;EACA,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;EACvB,QAAQ,MAAM;EACd,GAAG;CACL;AACF;;AAGA,SAAS,oBAAoB,OAAoB,MAAmB,KAAsB;CACxF,MAAM,EAAE,WAAW;CACnB,KAAK,MAAM,SAAS,KAAK,SACvB,IAAI,MAAM,SAAS,UAAU,MAAM,KAAK,KAAK,GAG3C,OAAO,KAAK;EAAE,MAAM;EAAY,MAAM,MAAM;EAAM,WAAW;EAAO,GAAG;CAAI,CAAC;MAEzE,IAAI,MAAM,SAAS,cAAc,MAAM,KAAK,KAAK,GAY/C;OAAA,MAAM,QAAQ,MAAM,KAAK,MAAM,IAAI,GACtC,IAAI,KAAK,KAAK,GACZ,OAAO,KAAK;GAAE,MAAM;GAAY,MAAM;GAAM,GAAG;EAAI,CAAC;CAAA,OAGrD,IAAI,MAAM,SAAS,aACtB,OAAO,KAAK,cAAc,OAAO,MAAM,gBAAgB,GAAG,CAAC;MAExD,IAAI,MAAM,SAAS,mBAItB,OAAO,KAAK;EACV,MAAM;EACN,MAAM,gBAAgB,MAAM,MAAM,MAAM,KAAK;EAC7C,MAAM,MAAM;EACZ,OAAO,MAAM;EACb,QAAQ,MAAM;EACd,GAAG;CACL,CAAC;MAEE,IAAI,MAAM,SAAS,sBACtB,OAAO,KAAK;EACV,MAAM;EACN,MAAM,wBAAwB,MAAM,OAAO;EAC3C,MAAM,MAAM;EACZ,QAAQ,MAAM;EACd,GAAG;CACL,CAAC;AAGP;AAEA,SAAgB,gBACd,OACA,OAA8B,CAAC,GAChB;CACf,OAAO,YAAY,OAAO,IAAI,CAAC,CAAC;AAClC;;;;;;;;;;AAWA,SAAgB,YACd,OACA,MACiD;CACjD,MAAM,UAAU,gBAAgB,OAAO,IAAI;CAC3C,MAAM,WAAW,aAAa,OAAO;CACrC,MAAM,eAAe,kBAAkB,KAAK;CAC5C,MAAM,iBAAiB,oBAAoB,KAAK;CAChD,MAAM,aAAa,YAAY,OAAO;CACtC,MAAM,gBAAgB,iBAAiB,OAAO;CAC9C,MAAM,YAAY,eAAe,SAAS,QAAQ;CAQlD,MAAM,cAAc,MAAM,KAAI,SAAQ,WAAW,KAAK,KAAK,CAAC;CAC5D,MAAM,kCAAkB,IAAI,IAAoB;CAChD,YAAY,SAAS,OAAO,QAAQ;EAClC,KAAK,MAAM,OAAO,OAChB,gBAAgB,IAAI,IAAI,IAAI,GAAG;CACnC,CAAC;CAED,MAAM,SAAwB,CAAC;;CAE/B,MAAM,8BAAc,IAAI,IAAY;;CAEpC,MAAM,WAAyB,CAAC;CAChC,MAAM,QAAqB;EAAE;EAAQ;EAAS;EAAc;EAAgB,qBAAqB;EAAI,mBAAmB;CAAK;CAE7H,MAAM,gBAAgB,QAAoB;EACxC,OAAO,KAAK,cAAc,KAAK,cAAc,GAAG,GAAG,UAAU,UAAU,GAAG,CAAC,CAAC;CAC9E;CAEA,MAAM,kBAAkB,QAAoB;EAC1C,OAAO,KAAK,gBAAgB,KAAK,UAAU,UAAU,GAAG,CAAC,CAAC;CAC5D;;;;;;;CAQA,MAAM,qBAAqB,eAAuB;EAChD,KAAK,IAAI,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;GAC7C,MAAM,MAAM,SAAS;GAIrB,IAAI,IAAI,WAAW,WACjB;GACF,KAAK,gBAAgB,IAAI,IAAI,EAAE,KAAK,MAAM,YAAY;IACpD,SAAS,OAAO,GAAG,CAAC;IACpB,aAAa,GAAG;GAClB;EACF;CACF;CAEA,MAAM,aAAuB,CAAC;CAC9B,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,WAAW,KAAK,OAAO,MAAM;EAC7B,MAAM,OAAO,MAAM;EACnB,MAAM,cAAc,YAAY;EAChC,MAAM,QAAQ,YAAY;EAE1B,kBAAkB,CAAC;EAEnB,KAAK,MAAM,OAAO,aAAa;GAC7B,IAAI,YAAY,IAAI,IAAI,EAAE,GACxB;GACF,YAAY,IAAI,IAAI,EAAE;GACtB,SAAS,KAAK,GAAG;GACjB,eAAe,GAAG;EACpB;EAEA,MAAM,cAAc,QAAQ,KAAK,KAAK,QAAQ;GAAE,SAAS,SAAS,KAAK,KAAK;GAAG;EAAM,IAAI,KAAA;EAKzF,MAAM,MAAM;GAAE,QAAQ,KAAK;GAAI,GAAG;EAAY;EAE9C,IAAI,KAAK,SAAS,QAAQ;GACxB,eAAe,OAAO,MAAM,OAAO,GAAG;GACtC,MAAM,sBAAsB;GAC5B;EACF;EAEA,IAAI,KAAK,SAAS,WAAW;GAC3B,kBAAkB,OAAO,MAAM,GAAG;GAClC,MAAM,sBAAsB;GAC5B;EACF;EAEA,IAAI,KAAK,SAAS,aAAa;GAC7B,oBAAoB,OAAO,MAAM,GAAG;GACpC,MAAM,sBAAsB;EAC9B;CACF;CAIA,kBAAkB,MAAM,MAAM;CAC9B,WAAW,KAAK,OAAO,MAAM;CAG7B,KAAK,MAAM,EAAE,IAAI,WAAW,kBAAkB,QAAQ,OAAO,IAAI,GAC/D,KAAK,IAAI,IAAI,GAAG,IAAI,WAAW,QAAQ,KACrC,IAAI,WAAW,MAAO,IACpB,WAAW,MAAO;CAIxB,OAAO;EAAE;EAAQ;CAAW;AAC9B;;;;;;;;;;AAWA,MAAM,uBAAuB;;;;;;AAO7B,MAAM,8BAA8B;CAClC,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,SAAS;CACT,YAAY;CACZ,YAAY;CACZ,SAAS;AACX;;;;;;;;;;;;;;AAeA,SAAS,2BACP,MACA,KACoB;CACpB,MAAM,IAAI,KAAK,MAAM,oBAAoB;CACzC,IAAI,CAAC,GACH,OAAO;CAET,MAAM,OAAO,EAAE;CACf,MAAM,QAAQ,OAAmC;EAC/C,MAAM,QAAQ,KAAK,MAAM,EAAE;EAC3B,OAAO,QAAQ,YAAY,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,KAAA;CAChD;CAEA,MAAM,SAAS,KAAK,4BAA4B,MAAM,KAAK;CAC3D,MAAM,YAAY,KAAK,4BAA4B,MAAM,KAAK;CAC9D,MAAM,SAA8B,cAAc,WAAW,WAAW;CACxE,MAAM,WAAW,OAAO,SAAS,KAAK,4BAA4B,QAAQ,KAAK,KAAK,EAAE,KAAK;CAC3F,MAAM,UAAU,KAAK,4BAA4B,OAAO,KAAK;CAC7D,MAAM,aAAa,KAAK,4BAA4B,UAAU,KAAK;CACnE,MAAM,aAAa,OAAO,SAAS,KAAK,4BAA4B,UAAU,KAAK,KAAK,EAAE,KAAK;CAI/F,OAAO;EACL,MAAM;EACN,MALc,KAAK,4BAA4B,OAAO,KACnD,GAAG,OAAO,GAAG,YAAY,WAAW,IAAI,aAAa;EAKxD,MAAM;GAAE;GAAQ;GAAQ;GAAU;GAAY;GAAS;EAAW;EAClE,QAAQ,IAAI;EACZ,GAAI,IAAI,YAAY,KAAA,IAAY,EAAE,SAAS,IAAI,QAAQ,IAAI,CAAC;EAC5D,GAAI,IAAI,UAAU,KAAA,IAAY,EAAE,OAAO,IAAI,MAAM,IAAI,CAAC;CACxD;AACF;;;;;;;;;AAUA,SAAS,YAAY,GAAmB;CACtC,OAAO,EACJ,QAAQ,SAAS,GAAG,CAAC,CACrB,QAAQ,SAAS,GAAG,CAAC,CACrB,QAAQ,WAAW,IAAG,CAAC,CACvB,QAAQ,WAAW,GAAI,CAAC,CACxB,QAAQ,UAAU,GAAG;AAC1B;AAEA,SAAgB,gBAAgB,MAAc,OAAwC;CACpF,MAAM,OAAO,KAAK,UAAU,KAAK;CACjC,OAAO,QAAQ,SAAS,OAAO,GAAG,KAAK,GAAG,KAAK,KAAK;AACtD;;;;;;;;;;;;AAaA,SAAgB,wBAAwB,SAA0B;CAChE,IAAI,MAAM,QAAQ,OAAO,GAAG;EAC1B,MAAM,IAAI,QAAQ;EAClB,OAAO,MAAM,IAAI,aAAa,GAAG,EAAE;CACrC;CACA,IAAI,WAAW,OAAO,YAAY,UAAU;EAC1C,MAAM,OAAQ,QAAqC;EACnD,IAAI,OAAO,SAAS,UAClB,OAAO,UAAU;CACrB;CACA,OAAO;AACT;;;;;;;;;;;;;;;AAgBA,SAAgB,wBACd,QACA,QACA,UACe;CACf,KAAK,IAAI,IAAI,OAAO,SAAS,GAAG,KAAK,GAAG,KAAK;EAC3C,MAAM,IAAI,OAAO;EACjB,IAAI,EAAE,SAAS,UAAU,EAAE,WAAW,UAAU,CAAC,EAAE,MACjD;EACF,IAAI,EAAE,KAAK,aAAa,UACtB,OAAO;EACT,MAAM,OAAO,OAAO,MAAM;EAC1B,KAAK,KAAK;GAAE,GAAG;GAAG,MAAM;IAAE,GAAG,EAAE;IAAM;GAAS;EAAE;EAChD,OAAO;CACT;CACA,OAAO;AACT;;AAGA,SAAgB,eAAe,QAA8C;CAC3E,OAAO,OAAO,WAAW,WAAW,SAAS,iBAAiB,MAAM;AACtE;;;;;;;;;;;;;;AAeA,SAAgB,qBAAqB,MAAsB;CAazD,OAAO,KAAK,QACV,6CACA,IACF;AACF;;;;;;;;;;AAmCA,MAAM,aAAkD;CACtD,aAAa;CACb,eAAe;CACf,QAAQ;CAGR,YAAY;CACZ,QAAQ;CACR,eAAe;CAGf,kBAAkB;CAClB,SAAS;CACT,YAAY;CACZ,eAAe;CACf,aAAa;CAEb,gBAAgB;CAIhB,mBAAmB;CAMnB,qBAAqB;CAErB,iBAAiB;CAIjB,eAAe;CAIf,UAAU;CAEV,gBAAgB;AAClB;AAEA,MAAM,6BAA+C,IAAI,IAAI,CAAC,QAAQ,aAAa,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BpF,SAAgB,aAAa,OAAoB,UAA2C;CAM1F,IAAI,CAAC,UACH,OAAO;CAST,IAAI,WAAW,IAAI,MAAM,IAAI,KAAK,WAAW,IAAI,SAAS,IAAI,GAC5D,OAAO;CAIT,IAAI,MAAM,SAAS,iBAAiB,aAC9B,WAAW,IAAI,SAAS,IAAI,KAAK,SAAS,SAAS,iBAAiB,SAAS,SAAS,cAC1F,OAAO;CAET,IAAI,MAAM,SAAS,uBAAuB,UAAU,SAAS,qBAC3D,OAAO;CAGT,IAAI,SAAS,SAAS,eACpB,OAAO;CAIT,IAAI,MAAM,UAAU,UAAU,QAC5B,OAAO;CAGT,IAAI,MAAM,SAAS,cAAc,UAAU,SAAS,cAAc,SAAS,YAAY,MAAM,SAC3F,OAAO;CACT,OAAO,WAAW,MAAM,SAAS;AACnC;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,yBACd,OACA,OAA8B,CAAC,GACvB;CACR,MAAM,8BAAc,IAAI,IAAY;CACpC,KAAK,MAAM,OAAO,MAChB,KAAK,IAAI,SAAS,KAAK,GACrB,YAAY,IAAI,IAAI,EAAE;CAE1B,KAAK,IAAI,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK;EAC1C,MAAM,OAAO,MAAM;EACnB,IAAI,KAAK,SAAS,eAAe,CAAC,KAAK,OACrC;EACF,IAAI,KAAK,SAAS,YAAY,IAAI,KAAK,KAAK,GAC1C;EACF,MAAM,QAAQ,KAAK,MAAM,SAAS,MAC7B,KAAK,MAAM,aAAa,MACxB,KAAK,MAAM,iBAAiB;EACjC,IAAI,SAAS,GACX;EACF,OAAO;CACT;CACA,OAAO;AACT;;;;;;AAOA,SAAgB,YAAY,MAAqC;CAC/D,IAAI,QAAQ;CACZ,KAAK,MAAM,OAAO,MAChB,IAAI,IAAI,MACN,SAAS,IAAI;CAEjB,OAAO;AACT;;;;;;;;AA4BA,SAAgB,aAAa,MAAkD;CAC7E,MAAM,0BAAU,IAAI,IAA+B;CACnD,KAAK,MAAM,OAAO,MAChB,KAAK,MAAM,KAAK,IAAI,aAAa,CAAC,GAAG;EACnC,MAAM,MAAM,EAAE,WAAW;EACzB,IAAI,MAAM,QAAQ,IAAI,GAAG;EACzB,IAAI,CAAC,KAAK;GACR,MAAM;IAAE,SAAS;IAAK,OAAO;IAAG,OAAO;IAAG,QAAQ;IAAG,WAAW;IAAG,eAAe;IAAG,MAAM;IAAG,cAAc;GAAK;GACjH,QAAQ,IAAI,KAAK,GAAG;EACtB;EACA,IAAI,SAAS;EACb,IAAI,SAAS,EAAE;EACf,IAAI,UAAU,EAAE;EAChB,IAAI,aAAa,EAAE,aAAa;EAChC,IAAI,iBAAiB,EAAE,iBAAiB;EACxC,IAAI,EAAE,SAAS,KAAA,GACb,IAAI,QAAQ,EAAE;OAEd,IAAI,eAAe;CACvB;CAEF,MAAM,eAAe,MAAyB,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE;CACnF,OAAO,CAAC,GAAG,QAAQ,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,MAAO,EAAE,OAAO,EAAE,QAAU,YAAY,CAAC,IAAI,YAAY,CAAC,CAAE;AACpG;;;ACj4CA,SAAS,MAAM,MAAiE;CAC9E,MAAM,MAAM,KAAK,OAAO,QAAQ,IAAI;CACpC,OAAO;EACL,aAAa,YAAY,GAAG,KAAK;EACjC,MAAM,KAAK,QAAQ,QAAQ;CAC7B;AACF;;;;;;AAOA,SAAgB,sBAAsB,OAA2B,CAAC,GAAqB;CACrF,MAAM,EAAE,aAAa,SAAS,MAAM,IAAI;CACxC,OAAO;EAGL;GAAE,MAAM,QAAQ,aAAa,WAAW;GAAG,QAAQ;GAAW,QAAQ;EAAO;EAI7E;GAAE,MAAM,QAAQ,MAAM,cAAc;GAAG,QAAQ;GAAW,QAAQ;EAAuB;EACzF;GAAE,MAAM,QAAQ,aAAa,eAAe;GAAG,QAAQ;GAAW,QAAQ;EAAO;EACjF;GAAE,MAAM,QAAQ,aAAa,cAAc;GAAG,QAAQ;GAAW,QAAQ;EAAO;EAChF;GAAE,MAAM,QAAQ,MAAM,cAAc;GAAG,QAAQ;GAAQ,QAAQ;EAAoB;EACnF;GAAE,MAAM,QAAQ,MAAM,oBAAoB;GAAG,QAAQ;GAAQ,QAAQ;EAAa;EAClF;GAAE,MAAM,QAAQ,MAAM,qBAAqB;GAAG,QAAQ;GAAQ,QAAQ;EAAO;EAC7E;GAAE,MAAM,QAAQ,MAAM,oBAAoB;GAAG,QAAQ;GAAQ,QAAQ;EAAO;CAC9E;AACF;;;;;;AAOA,SAAgB,sBAAsB,OAA2B,CAAC,GAAsB;CACtF,MAAM,EAAE,aAAa,SAAS,MAAM,IAAI;CACxC,OAAO;EACL;GAAE,MAAM,QAAQ,aAAa,gBAAgB;GAAG,QAAQ;EAAU;EAClE;GAAE,MAAM,QAAQ,aAAa,eAAe;GAAG,QAAQ;EAAU;EACjE;GAAE,MAAM,QAAQ,aAAa,YAAY;GAAG,QAAQ;EAAU;EAC9D;GAAE,MAAM,QAAQ,MAAM,gBAAgB;GAAG,QAAQ;EAAO;EACxD;GAAE,MAAM,QAAQ,MAAM,eAAe;GAAG,QAAQ;EAAO;EACvD;GAAE,MAAM,QAAQ,MAAM,kBAAkB;GAAG,QAAQ;EAAO;CAC5D;AACF;;;;;;;AAQA,SAAgB,sBACd,MACA,QACA,OAAiC,CAAC,GACf;CACnB,IAAI,WAAW,cACb,OAAO,eAAe,IAAI;CAC5B,OAAO,iBAAiB,KAAK,MAAM,IAAI,GAAG,QAAQ,KAAK,WAAW;AACpE;;;;;;;;;;;;;AAcA,SAAgB,iBACd,OACA,QACA,aACmB;CACnB,IAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAC5D,OAAO,CAAC;CACV,IAAI,WAAW,qBACb,OAAO,wBAAyB,MAAmC,UAAU;CAC/E,OAAO,qBAAqB,OAAiC,WAAW;AAC1E;;;;;;;;;AAUA,SAAS,qBAAqB,OAA+B,aAAoD;CAC/G,IAAI,CAAC,aACH,OAAO,CAAC;CACV,MAAM,WAAW,MAAM;CACvB,IAAI,CAAC,YAAY,OAAO,aAAa,YAAY,MAAM,QAAQ,QAAQ,GACrE,OAAO,CAAC;CACV,MAAM,UAAU,iBAAiB,WAAW;CAC5C,MAAM,UAAU,OAAO,QAAQ,QAAmC,CAAC,CAChE,KAAK,CAAC,KAAK,YAAY;EAAE,KAAK,iBAAiB,GAAG;EAAG;CAAM,EAAE,CAAC,CAC9D,QAAQ,EAAE,UAAU,QAAQ,WAAW,IAAI,WAAW,UAAU,GAAG,CAAC,CAAC,CACrE,MAAM,GAAG,MAAM,EAAE,IAAI,SAAS,EAAE,IAAI,MAAM;CAC7C,MAAM,MAAyB,CAAC;CAChC,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,EAAE,WAAW,SAAS;EAC/B,MAAM,UAAU,SAAS,OAAO,UAAU,WAAY,MAAmC,aAAa,KAAA;EACtG,KAAK,MAAM,UAAU,wBAAwB,OAAO,GAAG;GACrD,IAAI,KAAK,IAAI,OAAO,IAAI,GACtB;GACF,KAAK,IAAI,OAAO,IAAI;GACpB,IAAI,KAAK,MAAM;EACjB;CACF;CACA,OAAO;AACT;;AAGA,SAAS,iBAAiB,MAAsB;CAC9C,IAAI;EACF,OAAO,aAAa,IAAI;CAC1B,QACM;EACJ,OAAO,QAAQ,IAAI;CACrB;AACF;;;;;;;AAQA,SAAS,wBAAwB,SAAqC;CACpE,IAAI,CAAC,WAAW,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,GAClE,OAAO,CAAC;CACV,MAAM,MAAyB,CAAC;CAChC,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,OAAkC,GAC3E,IAAI;EACF,IAAI,KAAK,GAAG,oBAAoB,GAAG,OAAO,MAAM,CAAC,CAAC;CACpD,QACM,CAEN;CAEF,OAAO;AACT;;;;;;;;;AAUA,SAAS,eAAe,MAAiC;CACvD,MAAM,OAAQ,WAAsE,KAAK;CACzF,IAAI,CAAC,MACH,OAAO,CAAC;CACV,MAAM,SAAS,KAAK,MAAM,IAAI;CAC9B,MAAM,SAAS,UAAU,OAAO,WAAW,WAAW,OAAO,cAAc,KAAA;CAC3E,IAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAC/D,OAAO,CAAC;CACV,MAAM,MAA+B,CAAC;CACtC,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,MAAiC,GAAG;EAC7E,IAAI,CAAC,SAAS,OAAO,UAAU,UAC7B;EACF,MAAM,MAAM;EACZ,IAAI,QAAQ;GACV,GAAI,IAAI,YAAY,KAAA,IAAY,EAAE,SAAS,IAAI,QAAQ,IAAI,CAAC;GAC5D,GAAI,IAAI,SAAS,KAAA,IAAY,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;GACnD,GAAI,IAAI,QAAQ,KAAA,IAAY,EAAE,KAAK,IAAI,IAAI,IAAI,CAAC;GAEhD,GAAI,IAAI,QAAQ,KAAA,IAAY,EAAE,KAAK,IAAI,IAAI,IAAI,CAAC;EAClD;CACF;CACA,OAAO,wBAAwB,GAAG;AACpC;;;;ACrMA,MAAM,uCAAuB,IAAI,IAAI,CAAC,UAAU,QAAQ,CAAC;;AAGzD,MAAM,aAAa;AACnB,MAAM,oBAAoB;AAE1B,SAAS,WAAW,MAA2D;CAC7E,MAAM,MAAM,KAAK,OAAO,QAAQ,IAAI;CACpC,MAAM,OAAO,KAAK,QAAQ,QAAQ;CAKlC,MAAM,MAAM,KAAK,kBACX,KAAK,SAAS,KAAA,IACd,QAAQ,KAAK,MAAM,SAAS,IAC5B,QAAQ,IAAI,mBAAmB,QAAQ,MAAM,SAAS;CAC5D,OAAO;EACL,SAAS,QAAQ,YAAY,GAAG,KAAK,KAAK,QAAQ;EAClD,MAAM,QAAQ,KAAK,OAAO;CAC5B;AACF;;;;;;;;AASA,SAAgB,oBAAoB,OAAyB,CAAC,GAAqB;CACjF,MAAM,EAAE,SAAS,SAAS,WAAW,IAAI;CACzC,OAAO;EACL;GAAE,MAAM,KAAK,SAAS,YAAY;GAAG,QAAQ;GAAW,QAAQ;EAAa;EAC7E;GAAE,MAAM,KAAK,SAAS,UAAU;GAAG,QAAQ;GAAW,QAAQ;EAAO;EACrE;GAAE,MAAM,KAAK,MAAM,YAAY;GAAG,QAAQ;GAAQ,QAAQ;EAAa;EACvE;GAAE,MAAM,KAAK,MAAM,UAAU;GAAG,QAAQ;GAAQ,QAAQ;EAAO;CACjE;AACF;;;;;;AAOA,SAAgB,oBAAoB,OAAyB,CAAC,GAAsB;CAClF,MAAM,EAAE,SAAS,SAAS,WAAW,IAAI;CACzC,OAAO,CACL;EAAE,MAAM,KAAK,SAAS,QAAQ;EAAG,QAAQ;CAAU,GACnD;EAAE,MAAM,KAAK,MAAM,QAAQ;EAAG,QAAQ;CAAO,CAC/C;AACF;;;;;;;;;;;AAYA,SAAgB,sBAAsB,OAAyB,CAAC,GAAsB;CACpF,MAAM,EAAE,SAAS,SAAS,WAAW,IAAI;CACzC,OAAO,CACL,GAAG,qBAAqB,IAAI,CAAC,CAAC,KAAI,UAAS;EAAE;EAAM,QAAQ;CAAgB,EAAE,GAC7E,GAAG,qBAAqB,OAAO,CAAC,CAAC,KAAI,UAAS;EAAE;EAAM,QAAQ;CAAmB,EAAE,CACrF;AACF;;;;;;;;AASA,SAAgB,iBAAiB,UAA2B;CAC1D,OAAO,SAAS,SAAS,6BAA6B,KACjD,SAAS,SAAS,sBAAsB;AAC/C;;;;;;;;AASA,MAAM,iBAAiB;AACvB,MAAM,wBAAwB;;AAG9B,SAAS,qBAAqB,UAA4B;CACxD,IAAI,CAAC,WAAW,QAAQ,GACtB,OAAO,CAAC;CACV,MAAM,YAAsB,CAAC;CAG7B,MAAM,0BAAU,IAAI,IAAY,CAAC,WAAW,QAAQ,CAAC,CAAC;CACtD,MAAM,QAAQ,KAAa,KAAc,UAAwB;EAC/D,IAAI,QAAQ,kBAAkB,UAAU,UAAU,uBAChD;EACF,IAAI;EACJ,IAAI;GACF,UAAU,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;EACpD,QACM;GACJ;EACF;EACA,KAAK,MAAM,SAAS,SAAS;GAC3B,IAAI,UAAU,UAAU,uBACtB;GACF,IAAI,MAAM,KAAK,WAAW,GAAG,GAC3B;GACF,MAAM,OAAO,KAAK,KAAK,MAAM,IAAI;GAGjC,MAAM,OAAO,MAAM,eAAe,IAAI,SAAS,IAAI,IAAI,MAAM,YAAY,IAAI,QAAQ,MAAM,OAAO,IAAI,SAAS;GAC/G,IAAI,SAAS,OAAO;IAClB,IAAI,OAAO,qBAAqB,IAAI,MAAM,IAAI,GAC5C;IACF,MAAM,OAAO,WAAW,IAAI;IAC5B,IAAI,QAAQ,IAAI,IAAI,GAClB;IACF,QAAQ,IAAI,IAAI;IAChB,KAAK,MAAM,OAAO,QAAQ,CAAC;GAC7B,OACK,IAAI,SAAS,UAAU,MAAM,KAAK,SAAS,KAAK,GACnD,UAAU,KAAK,IAAI;EAEvB;CACF;CACA,KAAK,UAAU,MAAM,CAAC;CAItB,MAAM,UAAU,KAAK,UAAU,UAAU;CACzC,MAAM,SAAS,KAAK,UAAU,iBAAiB;CAC/C,MAAM,QAAQ,UAAU,SAAS,OAAO,IAAI,UAAU,UAAU,SAAS,MAAM,IAAI,SAAS,KAAA;CAC5F,MAAM,OAAO,UAAU,QAAO,MAAK,MAAM,KAAK,CAAC,CAAC,KAAK;CACrD,OAAO,QAAQ,CAAC,OAAO,GAAG,IAAI,IAAI;AACpC;AAEA,SAAS,WAAW,MAAsB;CACxC,IAAI;EACF,OAAO,aAAa,IAAI;CAC1B,QACM;EACJ,OAAO;CACT;AACF;AAEA,SAAS,SAAS,MAAwC;CACxD,IAAI;EACF,MAAM,IAAI,SAAS,IAAI;EACvB,OAAO,EAAE,YAAY,IAAI,QAAQ,EAAE,OAAO,IAAI,SAAS;CACzD,QACM;EACJ,OAAO;CACT;AACF;;;;;;;;;;;AC5KA,MAAM,wBAAwB,CAAC,aAAa,UAAU;;;;;;;;;;;;;;;;;;;;;;AAmCtD,SAAgB,uBAAuB,OAInC,CAAC,GAAmD;CAMtD,MAAM,UAAU,sBAAsB,KAAI,SAAQ,iBAAiB;EAAE,SAAS;EAAM,GAAG;CAAK,CAAC,CAAC;CAC9F,MAAM,YAAY,QAAQ,EAAE,CAAC;CAC7B,MAAM,MAAsD,CAAC;CAC7D,KAAK,IAAI,IAAI,GAAG,IAAI,WAAW,KAC7B,KAAK,MAAM,QAAQ,SACjB,IAAI,KAAK,KAAK,EAAE;CAEpB,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,cAAc,MAAiC;CAC7D,MAAM,MAAM,kBAAkB,IAAI;CAClC,MAAM,SAAkB,OAAO,OAAO,QAAQ,YAAY,CAAC,MAAM,QAAQ,GAAG,KAAK,gBAAgB,MAC5F,IAAgC,aACjC;CACJ,OAAO,oBAAoB,oBAAoB,MAAM,CAAC;AACxD;;;;;;;;AASA,SAAgB,kBAAkB,MAAuB;CACvD,IAAI;EACF,OAAO,KAAK,MAAM,IAAI;CACxB,SACO,UAAU;EACf,MAAM,YAAY,uBAAuB,IAAI;EAC7C,IAAI,CAAC,UAAU,SACb,MAAM;EACR,IAAI;GACF,OAAO,KAAK,MAAM,UAAU,IAAI;EAClC,QACM;GACJ,MAAM,iBAAiB,UAAU,IAAI;EACvC;CACF;AACF;;;;;;;;;;;;;;;;;AAkBA,MAAM,yCAAyB,IAAI,IAAY;CAC7C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAS,uBAAuB,MAAkD;CAChF,IAAI,UAAU;CACd,IAAI,WAAW;CACf,IAAI,UAAU;CACd,MAAM,MAAgB,CAAC;CACvB,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,KAAK,KAAK;EAChB,IAAI,UAAU;GACZ,IAAI,KAAK,EAAE;GACX,IAAI,SACF,UAAU;QACP,IAAI,OAAO,MACd,UAAU;QACP,IAAI,OAAO,MACd,WAAW;GACb;EACF;EACA,IAAI,OAAO,MAAK;GACd,WAAW;GACX,IAAI,KAAK,EAAE;GACX;EACF;EACA,MAAM,OAAO,GAAG,WAAW,CAAC;EAC5B,IAAI,uBAAuB,IAAI,IAAI,GAAG;GACpC,UAAU;GAGV,IAAI,SAAS,OAAU,SAAS,QAAU,SAAS,MACjD,IAAI,KAAK,GAAG;GACd;EACF;EACA,IAAI,KAAK,EAAE;CACb;CACA,OAAO;EAAE,MAAM,IAAI,KAAK,EAAE;EAAG;CAAQ;AACvC;AAEA,SAAS,iBAAiB,KAAc,MAAqB;CAC3D,MAAM,OAAO,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;CAC/D,MAAM,QAAkB,CAAC;CACzB,IAAI,KAAK,SAAS,MAAQ,GACxB,MAAM,KAAK,0GAA0G;CACvH,IAAI,KAAK,WAAW,CAAC,MAAM,OACzB,MAAM,KAAK,sEAAsE;CACnF,IAAI,MAAM,WAAW,GACnB,OAAO;CACT,uBAAO,IAAI,MAAM,GAAG,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,GAAG;AACzD;;;;;;;;;AAUA,SAAS,oBAAoB,QAA0B;CACrD,IAAI,MAAM,QAAQ,MAAM,GACtB,OAAO,OAAO,QAAO,MAAK,CAAC,gBAAgB,CAAC,CAAC;CAC/C,IAAI,UAAU,OAAO,WAAW,UAAU;EACxC,MAAM,WAAoC,CAAC;EAC3C,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,MAAiC,GAC1E,IAAI,CAAC,gBAAgB,KAAK,GACxB,SAAS,QAAQ;EAErB,OAAO;CACT;CACA,OAAO;AACT;AAEA,SAAS,gBAAgB,OAAyB;CAChD,OAAO,CAAC,CAAC,SAAS,OAAO,UAAU,YAC7B,MAAgC,YAAY;AACpD;;;;;;;;;;;AA0CA,SAAgB,oBAAoB,OAiBhC,CAAC,GAAoB;CACvB,MAAM,QAAQ,mBAAmB,IAAI,CAAC,CAAC,QAAO,MAAK,WAAW,EAAE,IAAI,CAAC;CAGrE,MAAM,cAAc,YAAY,KAAK,OAAO,QAAQ,IAAI,CAAC,KAAM,KAAK,OAAO,QAAQ,IAAI;CACvF,MAAM,uBAAO,IAAI,IAAY;CAI7B,MAAM,mCAAmB,IAAI,IAAY;CACzC,MAAM,UAA2B,CAAC;CAClC,MAAM,SAA2B,CAAC;CAMlC,MAAM,mCAAmB,IAAI,IAAmD;CAChF,KAAK,MAAM,EAAE,MAAM,QAAQ,QAAQ,eAAe,OAAO;EACvD,MAAM,gBAAgB,WAAW,uBAAuB,WAAW;EACnE,MAAM,SAAS,gBAAgB,iBAAiB,IAAI,IAAI,IAAI,KAAA;EAC5D,IAAI,UAAU,YAAY,QACxB;EACF,IAAI;EACJ,IAAI;GACF,IAAI,eAAe;IACjB,IAAI;IACJ,IAAI,UAAU,WAAW,QACvB,QAAQ,OAAO;SAEZ;KACH,IAAI;MACF,QAAQ,KAAK,MAAM,aAAa,MAAM,MAAM,CAAC;KAC/C,SACO,KAAK;MACV,iBAAiB,IAAI,MAAM,EAAE,QAAQ,KAAK,CAAC;MAC3C,MAAM;KACR;KACA,iBAAiB,IAAI,MAAM,EAAE,MAAM,CAAC;IACtC;IACA,UAAU,iBAAiB,OAAO,QAAQ,WAAW;GACvD,OACK;IACH,MAAM,OAAO,aAAa,MAAM,MAAM;IACtC,UAAU,WAAW,SAAS,cAAc,IAAI,IAAI,sBAAsB,MAAM,QAAQ,EAAE,YAAY,CAAC;GACzG;EACF,SACO,KAAK;GACV,MAAM,UAAU,aAAa,GAAG;GAChC,OAAO,KAAK;IAAE;IAAM;IAAQ;GAAQ,CAAC;GACrC,IAAI,QAAQ,IAAI,cACd,QAAQ,OAAO,MAAM,kCAAkC,KAAK,KAAK,QAAQ,GAAG;GAC9E;EACF;EACA,MAAM,eAAyB,CAAC;EAChC,KAAK,MAAM,UAAU,SAAS;GAC5B,IAAI,KAAK,IAAI,OAAO,IAAI,GACtB;GAQF,IAAI,aAAa,OAAO,cAAc,SAAS;IAC7C,IAAI,CAAC,iBAAiB,IAAI,OAAO,IAAI,GAAG;KACtC,iBAAiB,IAAI,OAAO,IAAI;KAChC,aAAa,KAAK,OAAO,IAAI;IAC/B;IACA;GACF;GACA,KAAK,IAAI,OAAO,IAAI;GACpB,QAAQ,KAAK;IAAE;IAAQ;IAAQ;GAAK,CAAC;EACvC;EAIA,IAAI,aAAa,SAAS,GACxB,OAAO,KAAK;GACV;GACA;GACA,SAAS,GAAG,aAAa,OAAO,eAAe,aAAa,WAAW,IAAI,KAAK,IAAI,IAAI,aAAa,KAAK,IAAI,EAAE;GAChH,eAAe;EACjB,CAAC;CAEL;CACA,OAAO;EAAE;EAAS;CAAO;AAC3B;;;;;;;;;;;;;;AAeA,SAAS,mBAAmB,OAMxB,CAAC,GAAkG;CAErG,OAAO;EACL,GAFa,uBAAuB,IAAI,CAAC,CAAC,KAAI,OAAM;GAAE,GAAG;GAAG,QAAQ;EAAgB,EAE5E;EACR,GAAI,KAAK,gBAAgB,sBAAsB,IAAI,IAAI,CAAC;EACxD,GAAI,KAAK,QAAQ,oBAAoB,IAAI,CAAC,CAAC,KAAI,OAAM;GAAE,GAAG;GAAG,WAAW,KAAK,kBAAkB;EAAK,EAAE,IAAI,CAAC;CAC7G;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,gBAAgB,MAIV;CACpB,MAAM,YAAY,gBAAgB,KAAK,YAAY,KAAK,OAAO;CAC/D,MAAM,OAAO,KAAK;CAClB,IAAI,CAAC,QAAQ,OAAO,KAAK,IAAI,CAAC,CAAC,WAAW,GACxC,OAAO,UAAU,KAAI,OAAM,EAAE,GAAG,EAAE,OAAO,EAAE;CAE7C,OAAO,UAAU,KAAK,MAAM;EAC1B,MAAM,OAAwB,EAAE,GAAG,EAAE,OAAO;EAC5C,MAAM,SAAS,KAAK,EAAE,OAAO;EAC7B,IAAI,CAAC,UAAU,OAAO,WAAW,GAC/B,OAAO;EAET,IAAI,KAAK,gBAAgB,KAAK,aAAa,SAAS,GAClD,OAAO;EACT,MAAM,SAAS,IAAI,IAAY,KAAK,iBAAiB,CAAC,CAAC;EACvD,KAAK,MAAM,QAAQ,QACjB,OAAO,IAAI,IAAI;EACjB,KAAK,gBAAgB,CAAC,GAAG,MAAM,CAAC,CAAC,KAAK;EACtC,OAAO;CACT,CAAC;AACH;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,sBACd,SACA,WACK;CACL,MAAM,uBAAO,IAAI,IAAY;CAC7B,MAAM,MAAW,CAAC;CAClB,MAAM,UAAoB,CAAC;CAC3B,KAAK,MAAM,UAAU,SAAS;EAC5B,IAAI,KAAK,IAAI,OAAO,IAAI,GAAG;GACzB,QAAQ,KAAK,OAAO,IAAI;GACxB;EACF;EACA,KAAK,IAAI,OAAO,IAAI;EACpB,IAAI,KAAK,MAAM;CACjB;CACA,IAAI,QAAQ,SAAS,GACnB,YAAY,OAAO;CACrB,OAAO;AACT;;;;;;;;;AAUA,SAAgB,oBAAoB,SAAqC,KAAgC;CACvG,OAAO,QAAQ,KAAI,WACjB,OAAO,cAAc,WAAW,OAAO,UAAU,aAAa,CAAC,OAAO,MAClE;EAAE,GAAG;EAAQ;CAAI,IACjB,MACN;AACF;AAEA,SAAS,gBACP,YACA,SAC0B;CAC1B,IAAI,YAAY,KAAA,GACd,OAAO;CACT,IAAI,QAAQ,WAAW,GACrB,OAAO,CAAC;CACV,MAAM,QAAQ,IAAI,IAAI,OAAO;CAC7B,OAAO,WAAW,QAAO,MAAK,MAAM,IAAI,EAAE,OAAO,IAAI,CAAC;AACxD;;;;ACxeA,MAAM,qBAAqB;;;;;;;;AAkC3B,SAAgB,iBAAiB,OAA2C,CAAC,GAAW;CACtF,MAAM,OAAO,KAAK,QAAQ,QAAQ;CAClC,MAAM,UAAU,KAAK,UAAU,UAAA,CAAW,QAAQ,OAAO,EAAE;CAC3D,OAAO,KAAK,MAAM,IAAI,UAAU,WAAW;AAC7C;;;;;;;;;;AAWA,SAAgB,uBAAuB,OAA2C;CAChF,MAAM,YAA2B,SAAS;CAC1C,OAAO,cAAc,aAAa,cAAc;AAClD;;;;;;;;;;AAWA,SAAgB,0BAA0B,OAA2C;CACnF,MAAM,YAA2B,SAAS;CAC1C,OAAO,cAAc,UAAU,cAAc;AAC/C;;;;;;;;;;;;;;;AAgBA,SAAgB,iBAAiB,OAAgC,CAAC,GAAmB;CACnF,MAAM,QAAuB,KAAK,SAAS;CAE3C,IAAI,UAAU,QACZ,OAAO;EAAE,MAAM;EAAM,UAAU,CAAC;CAAE;CAEpC,MAAM,MAAM,KAAK,OAAO,QAAQ,IAAI;CACpC,MAAM,cAAc,YAAY,GAAG,KAAK;CAExC,MAAM,aAA6D,CAAC;CACpE,IAAI,UAAU,QACZ,WAAW,KAAK;EAAE,MAAM,KAAK,aAAa,WAAW;EAAG,QAAQ;CAAU,CAAC;CAC7E,IAAI,UAAU,WACZ,WAAW,KAAK;EAAE,MAAM,iBAAiB,IAAI;EAAG,QAAQ;CAAO,CAAC;CAElE,MAAM,QAAwB,CAAC;CAC/B,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,KAAK,YAAY;EAQ1B,IAAI,KAAK,IAAI,EAAE,IAAI,GACjB;EACF,KAAK,IAAI,EAAE,IAAI;EACf,MAAM,OAAO,cAAc,EAAE,MAAM,EAAE,MAAM;EAC3C,IAAI,MACF,MAAM,KAAK,IAAI;CACnB;CAEA,MAAM,CAAC,QAAQ,GAAG,YAAY;CAC9B,OAAO;EAAE,MAAM,UAAU;EAAM;CAAS;AAC1C;AAEA,SAAS,cAAc,MAAc,QAAiD;CACpF,IAAI,CAAC,WAAW,IAAI,GAClB,OAAO;CACT,IAAI;CACJ,IAAI;EACF,MAAM,aAAa,MAAM,MAAM;CACjC,SACO,KAAK;EACV,IAAI,QAAQ,IAAI,cACd,QAAQ,OAAO,MAAM,4CAA4C,KAAK,KAAK,aAAa,GAAG,EAAE,GAAG;EAClG,OAAO;CACT;CACA,MAAM,WAAW,IAAI,SAAS,qBAC1B,GAAG,IAAI,MAAM,GAAG,kBAAkB,EAAE,sBAAsB,IAAI,SAAS,mBAAmB,mCAC1F;CAIJ,IAAI,SAAS,KAAK,CAAC,CAAC,WAAW,GAC7B,OAAO;CACT,OAAO;EAAE;EAAM;EAAQ;CAAS;AAClC;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,mBAAmB,eAAuB,OAA+B;CACvF,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAKA,GAAI,0BAA0B,KAAK,IAC/B,CAAC,8EAA8E,IAC/E,CAAC,iFAA+E,0BAA0B;EAC9G;EACA;EACA;EACA,cAAc,KAAK;EACnB;CACF,CAAC,CAAC,KAAK,IAAI;AACb;;;ACpMA,MAAM,QAA2B;CAC/B,WAAW;CACX,UAAU;CACV,MAAM;CACN,OAAO;CACP,KAAK;CACL,QAAQ;CACR,OAAO;CACP,QAAQ;CACR,OAAO;CACP,MAAM;CACN,KAAK;CACL,UAAU;CACV,MAAM;CACN,UAAU;CACV,MAAM;CACN,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,MAAM;CACN,QAAQ;CACR,OAAO;AACT;AAEA,MAAM,SAA4B;CAChC,WAAW;CACX,UAAU;CACV,MAAM;CACN,OAAO;CACP,KAAK;CACL,QAAQ;CACR,OAAO;CACP,QAAQ;CACR,OAAO;CACP,MAAM;CACN,KAAK;CACL,UAAU;CACV,MAAM;CACN,UAAU;CACV,MAAM;CACN,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,MAAM;CACN,QAAQ;CACR,OAAO;AACT;AAEA,MAAM,YAA+B;CACnC,WAAW;CACX,UAAU;CACV,MAAM;CACN,OAAO;CACP,KAAK;CACL,QAAQ;CACR,OAAO;CACP,QAAQ;CACR,OAAO;CACP,MAAM;CACN,KAAK;CACL,UAAU;CACV,MAAM;CACN,UAAU;CACV,MAAM;CACN,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,MAAM;CACN,QAAQ;CACR,OAAO;AACT;AAEA,MAAM,QAA2B;CAC/B,WAAW;CACX,UAAU;CACV,MAAM;CACN,OAAO;CACP,KAAK;CACL,QAAQ;CACR,OAAO;CACP,QAAQ;CACR,OAAO;CACP,MAAM;CACN,KAAK;CACL,UAAU;CACV,MAAM;CACN,UAAU;CACV,MAAM;CACN,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,MAAM;CACN,QAAQ;CACR,OAAO;AACT;;;;;;;;;;;;;;;;;AAkBA,SAAS,gBAAgB,IAAY,OAAe,GAA6B;CAC/E,OAAO;EACL;EACA;EACA,QAAQ;GACN,OAAO,EAAE;GACT,QAAQ,EAAE;GACV,OAAO,EAAE;GACT,MAAM,EAAE;GACR,OAAO,EAAE;GACT,KAAK,EAAE;GACP,MAAM,EAAE;GACR,QAAQ,EAAE;GACV,cAAc,EAAE;GAIhB,UAAU;IAAE,MAAM,EAAE;IAAO,IAAI,EAAE;GAAK;EACxC;EACA,QAAQ;GACN,iBAAiB;GACjB,wBAAwB;GACxB,yBAAyB;GACzB,mBAAmB,EAAE;GACrB,WAAW,EAAE;GACb,kBAAkB,EAAE;GACpB,0BAA0B,EAAE;EAC9B;EACA,UAAU;GAKR,YAAY,EAAE;GAId,OAAO,EAAE;GAOT,OAAO;IACL,SAAS;KAAE,IAAI,EAAE;KAAO,IAAI,EAAE;IAAK;IACnC,QAAQ;KAAE,IAAI,EAAE;KAAO,IAAI,EAAE;IAAK;IAClC,OAAO;KAAE,IAAI,EAAE;KAAM,IAAI,EAAE;IAAK;GAClC;GAIA,WAAW,EAAE;GAQb,MAAM;IACJ,OAAO,EAAE;IACT,UAAU,EAAE;IACZ,cAAc,EAAE;IAChB,iBAAiB,EAAE;IACnB,OAAO,EAAE;IACT,UAAU,EAAE;GACd;EACF;EACA,QAAQ;GACN,WAAW,EAAE,IAAI,EAAE,KAAK;GAGxB,kBAAkB;IAAE,IAAI,EAAE;IAAO,MAAM;GAAK;GAC5C,oBAAoB;IAAE,IAAI,EAAE;IAAO,MAAM;GAAK;GAC9C,oBAAoB;IAAE,IAAI,EAAE;IAAU,MAAM;GAAK;GACjD,oBAAoB;IAAE,IAAI,EAAE;IAAM,MAAM;GAAK;GAC7C,eAAe;IAAE,IAAI,EAAE;IAAM,MAAM;GAAK;GACxC,iBAAiB;IAAE,IAAI,EAAE;IAAM,MAAM;GAAK;GAC1C,iBAAiB;IAAE,IAAI,EAAE;IAAM,QAAQ;GAAK;GAC5C,eAAe;IAAE,IAAI,EAAE;IAAK,WAAW;GAAK;GAC5C,mBAAmB;IAAE,IAAI,EAAE;IAAK,WAAW;GAAK;GAChD,eAAe,EAAE,IAAI,EAAE,MAAM;GAC7B,cAAc,EAAE,IAAI,EAAE,MAAM;GAC5B,oBAAoB,EAAE,IAAI,EAAE,MAAM;GAClC,gBAAgB;IAAE,IAAI,EAAE;IAAU,QAAQ;GAAK;GAG/C,WAAW;IAAE,IAAI,EAAE;IAAO,MAAM;GAAK;GACrC,kBAAkB;IAAE,IAAI,EAAE;IAAM,MAAM;GAAK;GAC3C,oBAAoB,EAAE,IAAI,EAAE,IAAI;GAChC,UAAU,EAAE,IAAI,EAAE,MAAM;GACxB,iBAAiB;IAAE,IAAI,EAAE;IAAM,MAAM;GAAK;GAC1C,aAAa,EAAE,IAAI,EAAE,KAAK;GAC1B,WAAW;IAAE,IAAI,EAAE;IAAU,QAAQ;GAAK;GAC1C,UAAU,EAAE,IAAI,EAAE,MAAM;GACxB,WAAW,EAAE,IAAI,EAAE,MAAM;GACzB,YAAY,EAAE,IAAI,EAAE,MAAM;GAC1B,oBAAoB,EAAE,IAAI,EAAE,MAAM;GAClC,YAAY,EAAE,IAAI,EAAE,KAAK;GACzB,iBAAiB,EAAE,IAAI,EAAE,KAAK;GAC9B,mBAAmB,EAAE,IAAI,EAAE,KAAK;GAChC,wBAAwB,EAAE,IAAI,EAAE,KAAK;GACrC,oBAAoB,EAAE,IAAI,EAAE,KAAK;GACjC,kBAAkB,EAAE,IAAI,EAAE,KAAK;GAC/B,QAAQ,EAAE,IAAI,EAAE,OAAO;GACvB,gBAAgB,EAAE,IAAI,EAAE,OAAO;GAC/B,eAAe,EAAE,IAAI,EAAE,OAAO;GAC9B,aAAa,EAAE,IAAI,EAAE,OAAO;GAC5B,OAAO,EAAE,IAAI,EAAE,SAAS;GACxB,YAAY,EAAE,IAAI,EAAE,KAAK;GACzB,oBAAoB,EAAE,IAAI,EAAE,IAAI;GAChC,sBAAsB;IAAE,IAAI,EAAE;IAAQ,QAAQ;GAAK;GACnD,mBAAmB,EAAE,IAAI,EAAE,KAAK;GAChC,YAAY,EAAE,IAAI,EAAE,SAAS;GAC7B,YAAY,EAAE,IAAI,EAAE,IAAI;GACxB,eAAe,EAAE,IAAI,EAAE,SAAS;GAChC,uBAAuB,EAAE,IAAI,EAAE,SAAS;GACxC,yBAAyB,EAAE,IAAI,EAAE,SAAS;GAC1C,SAAS,EAAE,IAAI,EAAE,SAAS;EAC5B;CACF;AACF;AAEA,MAAa,mBAAmB,gBAAgB,oBAAoB,oBAAoB,KAAK;AAC7F,MAAa,uBAAuB,gBAAgB,wBAAwB,wBAAwB,SAAS;AAC7G,MAAa,oBAAoB,gBAAgB,qBAAqB,qBAAqB,MAAM;AAIjG,MAAa,mBAAmB,gBAAgB,oBAAoB,4BAA4B,KAAK;;;AChPrG,MAAM,IAAI;CA1CR,OAAO;CACP,QAAQ;CACR,UAAU;CACV,OAAO;CACP,QAAQ;CACR,QAAQ;CAER,QAAQ;CACR,OAAO;CACP,OAAO;CACP,MAAM;CAEN,OAAO;CACP,MAAM;CACN,SAAS;CAET,OAAO;CACP,QAAQ;CACR,SAAS;CAET,MAAM;CACN,QAAQ;CACR,MAAM;CACN,OAAO;CACP,KAAK;CAEL,SAAS;CACT,QAAQ;CACR,MAAM;CAEN,QAAQ;CACR,KAAK;CACL,UAAU;CACV,MAAM;CACN,QAAQ;CACR,OAAO;CACP,OAAO;CACP,KAAK;CACL,MAAM;CACN,QAAQ;AAGQ;AAElB,MAAa,cAAqB;CAChC,IAAI;CACJ,OAAO;CACP,QAAQ;EAGN,OAAO,EAAE;EAGT,QAAQ,EAAE;EAGV,OAAO,EAAE;EACT,MAAM,EAAE;EAIR,OAAO,EAAE;EACT,OAAO,EAAE;EAET,KAAK,EAAE;EAEP,MAAM,EAAE;EAER,QAAQ,EAAE;EAGV,cAAc,EAAE;EAIhB,UAAU;GAAE,MAAM,EAAE;GAAS,IAAI,EAAE;EAAM;CAC3C;CACA,QAAQ;EACN,iBAAiB;EACjB,wBAAwB;EACxB,yBAAyB;EACzB,mBAAmB,EAAE;EACrB,WAAW,EAAE;EACb,kBAAkB,EAAE;EACpB,0BAA0B,EAAE;CAC9B;CACA,UAAU;EAGR,YAAY,EAAE;EACd,OAAO,EAAE;EAOT,OAAO;GACL,SAAS;IAAE,IAAI,EAAE;IAAS,IAAI,EAAE;GAAO;GACvC,QAAQ;IAAE,IAAI,EAAE;IAAS,IAAI,EAAE;GAAO;GACtC,OAAO;IAAE,IAAI,EAAE;IAAQ,IAAI,EAAE;GAAO;EACtC;EAGA,WAAW,EAAE;EAKb,MAAM;GACJ,OAAO;GACP,UAAU;GACV,cAAc;GACd,iBAAiB;GACjB,OAAO;GACP,UAAU;EACZ;CACF;CACA,QAAQ;EAGN,WAAW,EAAE,IAAI,EAAE,MAAM;EAMzB,kBAAkB;GAAE,IAAI,EAAE;GAAQ,MAAM;EAAK;EAK7C,oBAAoB;GAAE,IAAI,EAAE;GAAQ,IAAI,EAAE;GAAS,MAAM;EAAK;EAC9D,oBAAoB;GAAE,IAAI,EAAE;GAAQ,MAAM;EAAK;EAC/C,oBAAoB;GAAE,IAAI,EAAE;GAAQ,MAAM;EAAK;EAG/C,eAAe;GAAE,IAAI,EAAE;GAAO,MAAM;EAAK;EACzC,iBAAiB;GAAE,IAAI,EAAE;GAAO,MAAM;EAAK;EAC3C,iBAAiB;GAAE,IAAI,EAAE;GAAO,QAAQ;EAAK;EAI7C,eAAe;GAAE,IAAI,EAAE;GAAM,MAAM;EAAK;EACxC,mBAAmB;GAAE,IAAI,EAAE;GAAM,WAAW;EAAK;EAGjD,eAAe,EAAE,IAAI,EAAE,MAAM;EAE7B,cAAc;GAAE,IAAI,EAAE;GAAO,IAAI,EAAE;EAAS;EAC5C,oBAAoB;GAAE,IAAI,EAAE;GAAO,IAAI,EAAE;EAAS;EAGlD,gBAAgB,EAAE,IAAI,EAAE,MAAM;EAG9B,WAAW,EAAE,IAAI,EAAE,OAAO;EAC1B,kBAAkB,EAAE,IAAI,EAAE,KAAK;EAC/B,oBAAoB,EAAE,IAAI,EAAE,OAAO;EACnC,UAAU,EAAE,IAAI,EAAE,MAAM;EACxB,iBAAiB,EAAE,IAAI,EAAE,IAAI;EAC7B,aAAa,EAAE,IAAI,EAAE,MAAM;EAC3B,WAAW;GAAE,IAAI,EAAE;GAAQ,QAAQ;EAAK;EACxC,UAAU,EAAE,IAAI,EAAE,MAAM;EACxB,WAAW,EAAE,IAAI,EAAE,MAAM;EACzB,YAAY,EAAE,IAAI,EAAE,MAAM;EAC1B,oBAAoB,EAAE,IAAI,EAAE,MAAM;EAClC,YAAY,EAAE,IAAI,EAAE,KAAK;EACzB,iBAAiB,EAAE,IAAI,EAAE,KAAK;EAC9B,mBAAmB,EAAE,IAAI,EAAE,KAAK;EAChC,wBAAwB,EAAE,IAAI,EAAE,KAAK;EACrC,oBAAoB,EAAE,IAAI,EAAE,OAAO;EACnC,kBAAkB,EAAE,IAAI,EAAE,IAAI;EAC9B,QAAQ,EAAE,IAAI,EAAE,MAAM;EACtB,gBAAgB,EAAE,IAAI,EAAE,MAAM;EAG9B,eAAe;GAAE,IAAI,EAAE;GAAM,MAAM;EAAK;EACxC,aAAa,EAAE,IAAI,EAAE,KAAK;EAC1B,OAAO,EAAE,IAAI,EAAE,MAAM;EACrB,YAAY,EAAE,IAAI,EAAE,MAAM;EAC1B,oBAAoB,EAAE,IAAI,EAAE,OAAO;EACnC,sBAAsB;GAAE,IAAI,EAAE;GAAO,QAAQ;EAAK;EAClD,mBAAmB,EAAE,IAAI,EAAE,MAAM;EACjC,YAAY,EAAE,IAAI,EAAE,MAAM;EAC1B,YAAY,EAAE,IAAI,EAAE,OAAO;EAK3B,eAAe,EAAE,IAAI,EAAE,MAAM;EAC7B,uBAAuB,EAAE,IAAI,EAAE,MAAM;EACrC,yBAAyB,EAAE,IAAI,EAAE,MAAM;EACvC,SAAS,EAAE,IAAI,EAAE,OAAO;CAC1B;AACF;;;ACxMA,MAAM,OAAuB;CAC3B,MAAM;CACN,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,OAAO;CACP,QAAQ;CACR,MAAM;CACN,QAAQ;CACR,MAAM;CACN,QAAQ;CACR,MAAM;AACR;AAEA,MAAM,QAAwB;CAC5B,MAAM;CACN,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,OAAO;CACP,QAAQ;CACR,MAAM;CACN,QAAQ;CACR,MAAM;CACN,QAAQ;CACR,MAAM;AACR;AAEA,SAAS,aAAa,IAAY,OAAe,GAA0B;CACzE,OAAO;EACL;EACA;EACA,QAAQ;GACN,OAAO,EAAE;GACT,QAAQ,EAAE;GACV,OAAO,EAAE;GACT,MAAM,EAAE;GACR,OAAO,EAAE;GACT,KAAK,EAAE;GACP,MAAM,EAAE;GACR,QAAQ,EAAE;GACV,cAAc,EAAE;GAChB,UAAU;IAAE,MAAM,EAAE;IAAQ,IAAI,EAAE;GAAO;GACzC,OAAO,EAAE;EACX;EACA,QAAQ;GACN,iBAAiB;GACjB,wBAAwB;GACxB,yBAAyB;GACzB,mBAAmB,EAAE;GACrB,WAAW,EAAE;GACb,kBAAkB,EAAE;GACpB,0BAA0B,EAAE;EAC9B;EACA,UAAU;GACR,YAAY,EAAE,OAAO,YAAY;GACjC,OAAO,EAAE;GACT,OAAO;IACL,SAAS;KAAE,IAAI,EAAE;KAAQ,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE;IAAI;IACpD,QAAQ;KAAE,IAAI,EAAE;KAAQ,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE;IAAI;IACnD,OAAO;KAAE,IAAI,EAAE;KAAM,IAAI,EAAE,OAAO,EAAE,MAAM;IAAU;GACtD;GACA,WAAW,EAAE;GACb,MAAM;IACJ,OAAO,EAAE;IACT,UAAU,EAAE;IACZ,cAAc,EAAE;IAChB,iBAAiB,EAAE;IACnB,OAAO,EAAE;IACT,UAAU,EAAE;GACd;EACF;EACA,QAAQ;GACN,WAAW,EAAE,IAAI,EAAE,IAAI;GACvB,kBAAkB;IAAE,IAAI,EAAE;IAAQ,MAAM;GAAK;GAC7C,oBAAoB;IAAE,IAAI,EAAE;IAAQ,MAAM;GAAK;GAC/C,oBAAoB;IAAE,IAAI,EAAE;IAAQ,MAAM;GAAK;GAC/C,oBAAoB;IAAE,IAAI,EAAE;IAAM,MAAM;GAAK;GAC7C,eAAe;IAAE,IAAI,EAAE;IAAK,MAAM;GAAK;GACvC,iBAAiB;IAAE,IAAI,EAAE;IAAK,MAAM;GAAK;GACzC,iBAAiB;IAAE,IAAI,EAAE;IAAK,QAAQ;GAAK;GAC3C,eAAe;IAAE,IAAI,EAAE;IAAM,WAAW;GAAK;GAC7C,mBAAmB;IAAE,IAAI,EAAE;IAAM,WAAW;GAAK;GACjD,eAAe,EAAE,IAAI,EAAE,OAAO;GAC9B,cAAc,EAAE,IAAI,EAAE,MAAM;GAC5B,oBAAoB,EAAE,IAAI,EAAE,MAAM;GAClC,gBAAgB;IAAE,IAAI,EAAE;IAAK,QAAQ;GAAK;GAE1C,WAAW;IAAE,IAAI,EAAE;IAAK,MAAM;GAAK;GACnC,kBAAkB;IAAE,IAAI,EAAE;IAAK,MAAM;GAAK;GAC1C,oBAAoB,EAAE,IAAI,EAAE,OAAO;GACnC,UAAU,EAAE,IAAI,EAAE,MAAM;GACxB,iBAAiB;IAAE,IAAI,EAAE;IAAQ,MAAM;GAAK;GAC5C,aAAa,EAAE,IAAI,EAAE,KAAK;GAC1B,WAAW;IAAE,IAAI,EAAE;IAAM,QAAQ;GAAK;GACtC,UAAU,EAAE,IAAI,EAAE,OAAO;GACzB,WAAW,EAAE,IAAI,EAAE,OAAO;GAC1B,YAAY,EAAE,IAAI,EAAE,OAAO;GAC3B,oBAAoB,EAAE,IAAI,EAAE,OAAO;GACnC,YAAY,EAAE,IAAI,EAAE,KAAK;GACzB,iBAAiB,EAAE,IAAI,EAAE,KAAK;GAC9B,mBAAmB,EAAE,IAAI,EAAE,KAAK;GAChC,wBAAwB,EAAE,IAAI,EAAE,KAAK;GACrC,oBAAoB,EAAE,IAAI,EAAE,KAAK;GACjC,kBAAkB,EAAE,IAAI,EAAE,KAAK;GAC/B,QAAQ,EAAE,IAAI,EAAE,OAAO;GACvB,gBAAgB,EAAE,IAAI,EAAE,OAAO;GAC/B,eAAe,EAAE,IAAI,EAAE,OAAO;GAC9B,aAAa,EAAE,IAAI,EAAE,KAAK;GAC1B,OAAO,EAAE,IAAI,EAAE,KAAK;GACpB,YAAY,EAAE,IAAI,EAAE,IAAI;GACxB,oBAAoB,EAAE,IAAI,EAAE,IAAI;GAChC,sBAAsB;IAAE,IAAI,EAAE;IAAQ,QAAQ;GAAK;GACnD,mBAAmB,EAAE,IAAI,EAAE,IAAI;GAC/B,YAAY,EAAE,IAAI,EAAE,KAAK;GACzB,YAAY,EAAE,IAAI,EAAE,OAAO;GAC3B,eAAe,EAAE,IAAI,EAAE,IAAI;GAC3B,uBAAuB,EAAE,IAAI,EAAE,IAAI;GACnC,yBAAyB,EAAE,IAAI,EAAE,IAAI;GACrC,SAAS,EAAE,IAAI,EAAE,KAAK;EACxB;CACF;AACF;AAEA,MAAa,eAAe,aAAa,gBAAgB,gBAAgB,IAAI;AAC7E,MAAa,gBAAgB,aAAa,iBAAiB,iBAAiB,KAAK;;;ACvJjF,MAAM,OAAO;AACb,MAAM,MAAM;AACZ,MAAM,OAAO;AACb,MAAM,SAAS;AACf,MAAM,gBAAgB;AAEtB,MAAM,QAAQ;AACd,MAAM,SAAS;AACf,MAAM,QAAQ;AACd,MAAM,OAAO;AACb,MAAM,QAAQ;AAEd,MAAa,cAAqB;CAChC,IAAI;CACJ,OAAO;CACP,QAAQ;EACN,OAAO;EACP,QAAQ;EACR,OAAO;EACP,MAAM;EACN,OAAO;EACP,KAAK;EACL,MAAM;EACN,QAAQ;EACR,cAAc;EAGd,UAAU;GAAE,MAAM;GAAO,IAAI;EAAM;CACrC;CACA,QAAQ;EACN,iBAAiB;EACjB,wBAAwB;EACxB,yBAAyB;EACzB,mBAAmB;EACnB,WAAW;EACX,kBAAkB;EAClB,0BAA0B;CAC5B;CACA,UAAU;EACR,YAAY;EAGZ,OAAO;EAIP,OAAO;GACL,SAAS;IAAE,IAAI;IAAO,IAAI;GAAU;GACpC,QAAQ;IAAE,IAAI;IAAO,IAAI;GAAU;GACnC,OAAO;IAAE,IAAI;IAAW,IAAI;GAAU;EACxC;EAEA,WAAW;EAIX,MAAM;GACJ,OAAO;GACP,UAAU;GACV,cAAc;GACd,iBAAiB;GACjB,OAAO;GACP,UAAU;EACZ;CACF;CACA,QAAQ;EAIN,WAAW,EAAE,IAAI,KAAK;EACtB,kBAAkB;GAAE,IAAI;GAAO,MAAM;EAAK;EAC1C,oBAAoB;GAAE,IAAI;GAAO,MAAM;EAAK;EAC5C,oBAAoB;GAAE,IAAI;GAAO,MAAM;EAAK;EAC5C,oBAAoB;GAAE,IAAI;GAAM,MAAM;EAAK;EAC3C,eAAe;GAAE,IAAI;GAAM,MAAM;EAAK;EACtC,iBAAiB;GAAE,IAAI;GAAM,MAAM;EAAK;EACxC,iBAAiB;GAAE,IAAI;GAAM,QAAQ;EAAK;EAC1C,eAAe;GAAE,IAAI;GAAO,WAAW;EAAK;EAC5C,mBAAmB;GAAE,IAAI;GAAO,WAAW;EAAK;EAChD,eAAe,EAAE,IAAI,UAAU;EAC/B,cAAc,EAAE,IAAI,UAAU;EAC9B,oBAAoB,EAAE,IAAI,UAAU;EACpC,gBAAgB;GAAE,IAAI;GAAK,QAAQ;EAAK;EAGxC,WAAW;GAAE,IAAI;GAAW,MAAM;EAAK;EACvC,kBAAkB;GAAE,IAAI;GAAW,MAAM;EAAK;EAC9C,oBAAoB,EAAE,IAAI,UAAU;EACpC,UAAU,EAAE,IAAI,UAAU;EAC1B,iBAAiB;GAAE,IAAI;GAAW,MAAM;EAAK;EAC7C,aAAa,EAAE,IAAI,UAAU;EAC7B,WAAW;GAAE,IAAI;GAAW,QAAQ;EAAK;EACzC,UAAU,EAAE,IAAI,UAAU;EAC1B,WAAW,EAAE,IAAI,UAAU;EAC3B,YAAY,EAAE,IAAI,UAAU;EAC5B,oBAAoB,EAAE,IAAI,UAAU;EACpC,YAAY,EAAE,IAAI,UAAU;EAC5B,iBAAiB,EAAE,IAAI,UAAU;EACjC,mBAAmB,EAAE,IAAI,UAAU;EACnC,wBAAwB,EAAE,IAAI,UAAU;EACxC,oBAAoB,EAAE,IAAI,UAAU;EACpC,kBAAkB,EAAE,IAAI,UAAU;EAClC,QAAQ,EAAE,IAAI,UAAU;EACxB,gBAAgB,EAAE,IAAI,UAAU;EAChC,eAAe,EAAE,IAAI,UAAU;EAC/B,aAAa,EAAE,IAAI,UAAU;EAC7B,OAAO,EAAE,IAAI,UAAU;EACvB,YAAY,EAAE,IAAI,KAAK;EACvB,oBAAoB,EAAE,IAAI,UAAU;EACpC,sBAAsB,EAAE,IAAI,UAAU;EACtC,mBAAmB,EAAE,IAAI,UAAU;EACnC,YAAY,EAAE,IAAI,UAAU;EAC5B,YAAY,EAAE,IAAI,UAAU;EAC5B,eAAe,EAAE,IAAI,IAAI;EACzB,uBAAuB,EAAE,IAAI,KAAK;EAClC,yBAAyB,EAAE,IAAI,KAAK;EACpC,SAAS,EAAE,IAAI,UAAU;CAC3B;AACF;;;ACzHA,MAAM,UAAU;CACd,MAAM;CACN,YAAY;CACZ,MAAM;CACN,YAAY;CACZ,MAAM;CACN,OAAO;CACP,aAAa;CACb,QAAQ;CACR,KAAK;CACL,MAAM;;;;;;CAMN,SAAS;CACT,YAAY;CACZ,SAAS;CACT,OAAO;CACP,SAAS;CACT,OAAO;CAGP,QAAQ;AACV;AAEA,MAAa,kBAAyB;CACpC,IAAI;CACJ,OAAO;CACP,QAAQ;EACN,OAAO,QAAQ;EACf,QAAQ,QAAQ;EAChB,OAAO,QAAQ;EACf,MAAM,QAAQ;EACd,OAAO,QAAQ;EACf,KAAK,QAAQ;EACb,MAAM,QAAQ;EACd,QAAQ,QAAQ;EAChB,cAAc,QAAQ;EAItB,UAAU;GAAE,MAAM,QAAQ;GAAM,IAAI,QAAQ;EAAK;CACnD;CACA,QAAQ;EACN,iBAAiB;EACjB,wBAAwB;EACxB,yBAAyB;EACzB,mBAAmB,QAAQ;EAC3B,WAAW,QAAQ;EACnB,kBAAkB,QAAQ;EAC1B,0BAA0B,QAAQ;CACpC;CACA,UAAU;EAGR,YAAY,QAAQ;EAGpB,OAAO,QAAQ;EAIf,OAAO;GACL,SAAS;IAAE,IAAI,QAAQ;IAAM,IAAI,QAAQ;GAAM;GAC/C,QAAQ;IAAE,IAAI,QAAQ;IAAM,IAAI,QAAQ;GAAM;GAC9C,OAAO;IAAE,IAAI,QAAQ;IAAM,IAAI,QAAQ;GAAM;EAC/C;EAGA,WAAW,QAAQ;EAMnB,MAAM;GACJ,OAAO;GACP,UAAU;GACV,cAAc;GACd,iBAAiB;GACjB,OAAO,QAAQ;GACf,UAAU,QAAQ;EACpB;CACF;CACA,QAAQ;EACN,WAAW,EAAE,IAAI,QAAQ,KAAK;EAG9B,kBAAkB;GAAE,IAAI,QAAQ;GAAM,MAAM;EAAK;EACjD,oBAAoB;GAAE,IAAI,QAAQ;GAAM,MAAM;EAAK;EACnD,oBAAoB;GAAE,IAAI,QAAQ;GAAY,MAAM;EAAK;EACzD,oBAAoB;GAAE,IAAI,QAAQ;GAAM,MAAM;EAAK;EACnD,eAAe;GAAE,IAAI,QAAQ;GAAY,MAAM;EAAK;EACpD,iBAAiB;GAAE,IAAI,QAAQ;GAAY,MAAM;EAAK;EACtD,iBAAiB;GAAE,IAAI,QAAQ;GAAa,QAAQ;EAAK;EACzD,eAAe;GAAE,IAAI,QAAQ;GAAQ,WAAW;EAAK;EACrD,mBAAmB;GAAE,IAAI,QAAQ;GAAQ,WAAW;EAAK;EACzD,eAAe,EAAE,IAAI,QAAQ,WAAW;EACxC,cAAc,EAAE,IAAI,QAAQ,OAAO;EACnC,oBAAoB,EAAE,IAAI,QAAQ,OAAO;EACzC,gBAAgB;GAAE,IAAI,QAAQ;GAAQ,QAAQ;EAAK;EAGnD,WAAW;GAAE,IAAI,QAAQ;GAAY,MAAM;EAAK;EAChD,kBAAkB;GAAE,IAAI,QAAQ;GAAY,MAAM;EAAK;EACvD,oBAAoB,EAAE,IAAI,QAAQ,QAAQ;EAC1C,UAAU,EAAE,IAAI,QAAQ,OAAO;EAC/B,iBAAiB;GAAE,IAAI,QAAQ;GAAa,MAAM;EAAK;EACvD,aAAa,EAAE,IAAI,QAAQ,OAAO;EAClC,WAAW;GAAE,IAAI,QAAQ;GAAS,QAAQ;EAAK;EAC/C,UAAU,EAAE,IAAI,QAAQ,WAAW;EACnC,WAAW,EAAE,IAAI,QAAQ,WAAW;EACpC,YAAY,EAAE,IAAI,QAAQ,WAAW;EACrC,oBAAoB,EAAE,IAAI,QAAQ,WAAW;EAC7C,YAAY,EAAE,IAAI,QAAQ,YAAY;EACtC,iBAAiB,EAAE,IAAI,QAAQ,YAAY;EAC3C,mBAAmB,EAAE,IAAI,QAAQ,YAAY;EAC7C,wBAAwB,EAAE,IAAI,QAAQ,YAAY;EAClD,oBAAoB,EAAE,IAAI,QAAQ,YAAY;EAC9C,kBAAkB,EAAE,IAAI,QAAQ,YAAY;EAC5C,QAAQ,EAAE,IAAI,QAAQ,YAAY;EAClC,gBAAgB,EAAE,IAAI,QAAQ,YAAY;EAC1C,eAAe,EAAE,IAAI,QAAQ,YAAY;EACzC,aAAa,EAAE,IAAI,QAAQ,OAAO;EAClC,OAAO,EAAE,IAAI,QAAQ,KAAK;EAC1B,YAAY,EAAE,IAAI,QAAQ,KAAK;EAC/B,oBAAoB,EAAE,IAAI,QAAQ,WAAW;EAC7C,sBAAsB,EAAE,IAAI,QAAQ,KAAK;EACzC,mBAAmB,EAAE,IAAI,QAAQ,KAAK;EACtC,YAAY,EAAE,IAAI,QAAQ,KAAK;EAC/B,YAAY,EAAE,IAAI,QAAQ,QAAQ;EAClC,eAAe,EAAE,IAAI,QAAQ,QAAQ;EACrC,uBAAuB,EAAE,IAAI,QAAQ,WAAW;EAChD,yBAAyB,EAAE,IAAI,QAAQ,QAAQ;EAC/C,SAAS,EAAE,IAAI,QAAQ,KAAK;CAC9B;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1CA,SAAgB,iBAAiB,OAAqB,YAA+B;CACnF,OAAO,MAAM,eAAe,MAAM;AACpC;AAkIA,MAAM,iBAA8B;CAClC,OAAO;CACP,QAAQ;CACR,OAAO;CACP,MAAM;CACN,OAAO;CACP,KAAK;CACL,MAAM;CACN,QAAQ;CACR,cAAc;CAId,UAAU;EAAE,MAAM;EAAW,IAAI;CAAU;AAC7C;AAEA,MAAa,gBAAuB;CAClC,IAAI;CACJ,OAAO;CACP,QAAQ;CACR,QAAQ;EAIN,iBAAiB;EACjB,wBAAwB;EACxB,yBAAyB;EACzB,mBAAmB,eAAe;EAClC,WAAW,eAAe;EAC1B,kBAAkB,eAAe;EACjC,0BAA0B,eAAe;CAC3C;CACA,UAAU;EAGR,YAAY;EAEZ,OAAO;EAUP,OAAO;GACL,SAAS;IAAE,IAAI,eAAe;IAAO,IAAI;GAAU;GACnD,QAAQ;IAAE,IAAI,eAAe;IAAO,IAAI;GAAU;GAClD,OAAO;IAAE,IAAI;IAAW,IAAI;GAAU;EACxC;EAGA,WAAW;EAMX,MAAM;GACJ,OAAO;GACP,UAAU;GACV,cAAc;GACd,iBAAiB;GACjB,OAAO;GACP,UAAU;EACZ;CACF;CACA,QAAQ;EAKN,WAAW,EAAE,IAAI,UAAU;EAC3B,kBAAkB;GAAE,IAAI;GAAW,MAAM;EAAK;EAC9C,oBAAoB;GAAE,IAAI;GAAW,MAAM;EAAK;EAChD,oBAAoB;GAAE,IAAI;GAAW,MAAM;EAAK;EAChD,oBAAoB;GAAE,IAAI;GAAW,MAAM;EAAK;EAChD,eAAe;GAAE,IAAI;GAAW,MAAM;EAAK;EAC3C,iBAAiB;GAAE,IAAI;GAAW,MAAM;EAAK;EAC7C,iBAAiB;GAAE,IAAI;GAAW,QAAQ;EAAK;EAC/C,eAAe;GAAE,IAAI,eAAe;GAAO,WAAW;EAAK;EAC3D,mBAAmB;GAAE,IAAI,eAAe;GAAO,WAAW;EAAK;EAM/D,eAAe,EAAE,IAAI,UAAU;EAG/B,cAAc,EAAE,IAAI,UAAU;EAC9B,oBAAoB,EAAE,IAAI,UAAU;EACpC,gBAAgB;GAAE,IAAI,eAAe;GAAK,QAAQ;EAAK;EAOvD,WAAW;GAAE,IAAI;GAAW,MAAM;EAAK;EACvC,kBAAkB;GAAE,IAAI;GAAW,MAAM;EAAK;EAC9C,oBAAoB,EAAE,IAAI,UAAU;EACpC,UAAU,EAAE,IAAI,UAAU;EAC1B,iBAAiB;GAAE,IAAI;GAAW,MAAM;EAAK;EAC7C,aAAa,EAAE,IAAI,UAAU;EAC7B,WAAW;GAAE,IAAI;GAAW,QAAQ;EAAK;EACzC,UAAU,EAAE,IAAI,UAAU;EAC1B,WAAW,EAAE,IAAI,UAAU;EAC3B,YAAY,EAAE,IAAI,UAAU;EAC5B,oBAAoB,EAAE,IAAI,UAAU;EACpC,YAAY,EAAE,IAAI,UAAU;EAC5B,iBAAiB,EAAE,IAAI,UAAU;EACjC,mBAAmB,EAAE,IAAI,UAAU;EACnC,wBAAwB,EAAE,IAAI,UAAU;EACxC,oBAAoB,EAAE,IAAI,UAAU;EACpC,kBAAkB,EAAE,IAAI,UAAU;EAClC,QAAQ,EAAE,IAAI,UAAU;EACxB,gBAAgB,EAAE,IAAI,UAAU;EAChC,eAAe,EAAE,IAAI,UAAU;EAC/B,aAAa,EAAE,IAAI,UAAU;EAC7B,OAAO,EAAE,IAAI,UAAU;EACvB,YAAY,EAAE,IAAI,UAAU;EAC5B,oBAAoB,EAAE,IAAI,UAAU;EACpC,sBAAsB,EAAE,IAAI,UAAU;EACtC,mBAAmB,EAAE,IAAI,UAAU;EACnC,YAAY,EAAE,IAAI,UAAU;EAC5B,YAAY,EAAE,IAAI,UAAU;EAC5B,eAAe,EAAE,IAAI,eAAe,KAAK;EACzC,uBAAuB,EAAE,IAAI,UAAU;EACvC,yBAAyB,EAAE,IAAI,UAAU;EACzC,SAAS,EAAE,IAAI,UAAU;CAC3B;AACF;;;;;;;;;;;AAYA,MAAa,iBAAkD;EAC5D,cAAc,KAAK;EACnB,YAAY,KAAK;EACjB,iBAAiB,KAAK;EACtB,qBAAqB,KAAK;EAC1B,kBAAkB,KAAK;EACvB,iBAAiB,KAAK;EACtB,aAAa,KAAK;EAClB,cAAc,KAAK;EACnB,YAAY,KAAK;EACjB,gBAAgB,KAAK;AACxB;;AAGA,SAAgB,aACd,IACA,aACO;CACP,IAAI,IAAI;EAIN,IAAI,eAAe,KACjB,OAAO,eAAe;EACxB,IAAI,eAAe,YAAY,KAC7B,OAAO,YAAY;CACvB;CACA,OAAO;AACT;;;;;;;;;;;ACzYA,MAAM,iBAAiB;AACvB,MAAM,iBAAiB;AAEvB,SAAgB,SAAS,OAAuB;CAC9C,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,GACtC,OAAO,iBAAiB;CAC1B,OAAO,KAAK,IAAI,gBAAgB,KAAK,IAAI,gBAAgB,KAAK,MAAM,KAAK,CAAC,CAAC;AAC7E;AAkCA,MAAM,kBAAkB,cAA2C,IAAI;AAEvE,SAAgB,iBAAiB,EAC/B,SACA,UACA,YAKC;CAGD,MAAM,CAAC,UAAU,eAAe,eAAyB,0BAA0B,OAAO,CAAC;CAe3F,MAAM,cAAc,OAAO,QAAQ;CACnC,YAAY,UAAU;CACtB,MAAM,eAAe,OAAO,IAAI;CAChC,gBAAgB;EACd,IAAI,aAAa,SAAS;GACxB,aAAa,UAAU;GACvB;EACF;EACA,YAAY,UAAU,QAAQ;CAChC,GAAG,CAAC,QAAQ,CAAC;CAEb,MAAM,SAAS,aAAa,QAA2B;EACrD,aAAY,SAAQ,0BAA0B;GAAE,GAAG;IAAO,MAAM,CAAC,KAAK;EAAK,CAAC,CAAC;CAC/E,GAAG,CAAC,CAAC;CAEL,MAAM,aAAa,aAAuC,KAAQ,UAAuB;EACvF,aAAY,SAAS,KAAK,SAAS,QAAQ,OAAO,0BAA0B;GAAE,GAAG;IAAO,MAAM;EAAM,CAAC,CAAE;CACzG,GAAG,CAAC,CAAC;CAEL,MAAM,QAAQ,eACL;EAAE;EAAU;EAAQ;CAAW,IACtC;EAAC;EAAU;EAAQ;CAAU,CAC/B;CAEA,OAAO,oBAAC,gBAAgB,UAAjB;EAAiC;EAAQ;CAAmC,CAAA;AACrF;;;;;;;AAQA,SAAgB,iBAAiB,EAAE,OAAO,YAAkE;CAC1G,OAAO,oBAAC,gBAAgB,UAAjB;EAAiC;EAAQ;CAAmC,CAAA;AACrF;AAEA,SAAgB,cAAoC;CAClD,MAAM,MAAM,WAAW,eAAe;CACtC,IAAI,CAAC,KACH,MAAM,IAAI,MAAM,oDAAoD;CACtE,OAAO;AACT;;;;;;AA8CA,MAAa,sBAA6D,CACxE;CAAE,IAAI;CAAS,OAAO;CAAS,aAAa;AAA4C,GACxF;CAAE,IAAI;CAAM,OAAO;CAAM,aAAa;AAAuD,CAC/F;;;;;;AAqCA,MAAa,oBAA2E;CACtF;EAAE,OAAO;EAAY,MAAM;GAAC;GAAqB;GAAa;GAAe;GAAiB;GAAmB;EAAiB;CAAE;CACpI;EAAE,OAAO;EAAc,MAAM,CAAC,YAAY,iBAAiB;CAAE;CAC7D;EAAE,OAAO;EAAW,MAAM;GAAC;GAAW;GAAkB;EAAmB;CAAE;CAC7E;EAAE,OAAO;EAAiB,MAAM;GAAC;GAAyB;GAAwB;EAAoB;CAAE;CACxG;EAAE,OAAO;EAAW,MAAM;GAAC;GAAe;GAAwB;GAAsB;GAAkB;GAAyB;EAAiB;CAAE;CACtJ;EAAE,OAAO;EAAgB,MAAM,CAAC,UAAU;CAAE;CAC5C;EAAE,OAAO;EAAU,MAAM;GAAC;GAAkB;GAAqB;GAAmB;GAAoB;EAAQ;CAAE;CAClH;EAAE,OAAO;EAAc,MAAM;GAAC;GAAY;GAAc;GAAkB;EAAgB;CAAE;CAC5F;EAAE,OAAO;EAAY,MAAM;GAAC;GAAiB;GAAsB;GAAkB;EAAoB;CAAE;CAC3G;EAAE,OAAO;EAAS,MAAM,CAAC,qBAAqB,oBAAoB;CAAE;CACpE;EAAE,OAAO;EAAc,MAAM;GAAC;GAAqB;GAAgB;GAAsB;GAAmB;GAAmB;GAAkB;GAAiB;GAAmB;GAAuB;GAAkB;GAAoB;GAAyB;GAAmB;GAAgB;EAAW;CAAE;CAC3T;EAAE,OAAO;EAAU,MAAM,CAAC,UAAU,mBAAmB;CAAE;CACzD;EAAE,OAAO;EAAiB,MAAM;GAAC;GAAS;GAAa;GAAqB;GAAiB;GAAU;EAAa;CAAE;CACtH;EAAE,OAAO;EAAgB,MAAM;GAAC;GAAiB;GAAe;GAAiB;EAAY;CAAE;CAC/F;EAAE,OAAO;EAAe,MAAM;GAAC;GAAW;GAAmB;GAAgB;GAAY;GAAiB;GAAsB;GAA4B;GAAkB;EAAmB;CAAE;CACnM;EAAE,OAAO;EAAQ,MAAM,CAAC,aAAa;CAAE;AACzC;;AAGA,SAAgB,kBAAkB,KAA+C;CAC/E,MAAM,IAAI,kBAAkB,WAAU,YAAW,QAAQ,KAAK,SAAS,GAAG,CAAC;CAC3E,OAAO,IAAI,IACP;EAAE,OAAO;EAAS,OAAO,kBAAkB,SAAS;CAAI,IACxD;EAAE,OAAO,kBAAkB,EAAE,CAAE;EAAO,OAAO,IAAI,MAAM,kBAAkB,EAAE,CAAE,KAAK,QAAQ,GAAG;CAAE;AACrG;AAEA,MAAa,mBAA8C;CAEzD;EAAE,UAAU;EAAS,KAAK;EAAY,OAAO;EAAa,aAAa;CAA6D;CACpI;EAAE,UAAU;EAAS,KAAK;EAAiB,UAAU;EAAa,OAAO;EAAgB,aAAa;CAAqF;CAC3L;EAAE,UAAU;EAAS,KAAK;EAAa,OAAO;EAAsB,aAAa;CAAkG;CACnL;EAAE,UAAU;EAAS,KAAK;EAAe,eAAe;EAAoB,OAAO;EAAgB,aAAa;CAAwD;CACxK;EAAE,UAAU;EAAS,KAAK;EAAqB,OAAO;EAA2B,aAAa;CAAgE;CAC9J;EAAE,UAAU;EAAS,KAAK;EAAsB,OAAO;EAA8B,aAAa;CAAsE;CACxK;EAAE,UAAU;EAAS,KAAK;EAAkB,OAAO;EAAgC,aAAa;CAAkG;CAClM;EAAE,UAAU;EAAS,KAAK;EAAY,OAAO;EAAY,aAAa;CAAwE;CAC9I;EAAE,UAAU;EAAS,KAAK;EAAW,OAAO;EAA0B,aAAa;CAA2J;CAC9O;EAAE,UAAU;EAAS,KAAK;EAAyB,OAAO;EAA2B,aAAa;CAAqE;CACvK;EAAE,UAAU;EAAS,KAAK;EAAwB,OAAO;EAA2C,aAAa;CAA4H;CAC7O;EAAE,UAAU;EAAS,KAAK;EAAsB,OAAO;EAAwC,aAAa;CAAqF;CACjM;EAAE,UAAU;EAAS,KAAK;EAAsB,OAAO;EAAqB,aAAa;CAAuD;CAChJ;EAAE,UAAU;EAAS,KAAK;EAAkB,OAAO;EAA0B,aAAa;CAA+C;CACzI;EAAE,UAAU;EAAS,KAAK;EAAsB,OAAO;EAAuB,aAAa;CAAkE;CAC7J;EAAE,UAAU;EAAS,KAAK;EAAe,OAAO;EAAgB,aAAa;CAA0E;CACvJ;EAAE,UAAU;EAAS,KAAK;EAAiB,OAAO;EAAkB,aAAa;CAAuF;CACxK;EAAE,UAAU;EAAS,KAAK;EAAkB,OAAO;EAA2C,aAAa;CAA6C;CACxJ;EAAE,UAAU;EAAS,KAAK;EAAqB,OAAO;EAA+B,aAAa;CAA4D;CAC9J;EAAE,UAAU;EAAS,KAAK;EAAmB,OAAO;EAAqB,aAAa;CAA2D;CACjJ;EAAE,UAAU;EAAS,KAAK;EAAqB,OAAO;EAA2B,aAAa;CAA0D;CAMxJ;EAAE,UAAU;EAAM,KAAK;EAAmB,OAAO;EAAgB,aAAa;CAAuD;CACrI;EAAE,UAAU;EAAM,KAAK;EAAsB,OAAO;EAAwB,aAAa;CAA2D;CACpJ;EAAE,UAAU;EAAM,KAAK;EAAgB,OAAO;EAAmB,aAAa;CAA2C;CACzH;EAAE,UAAU;EAAM,KAAK;EAAmB,OAAO;EAAgB,aAAa;CAAwC;CACtH;EAAE,UAAU;EAAM,KAAK;EAAkB,OAAO;EAAoB,aAAa;CAAiD;CAClI;EAAE,UAAU;EAAM,KAAK;EAAuB,OAAO;EAAqB,aAAa;CAA6D;CACpJ;EAAE,UAAU;EAAM,KAAK;EAAkB,OAAO;EAAe,aAAa;CAAoD;CAChI;EAAE,UAAU;EAAM,KAAK;EAAoB,OAAO;EAAiB,aAAa;CAAkE;CAClJ;EAAE,UAAU;EAAM,KAAK;EAAiB,OAAO;EAAc,aAAa;CAA4B;CACtG;EAAE,UAAU;EAAM,KAAK;EAAyB,OAAO;EAAwB,aAAa;CAAmD;CAC/I;EAAE,UAAU;EAAM,KAAK;EAAmB,OAAO;EAAoB,aAAa;CAAwD;CAC1I;EAAE,UAAU;EAAM,KAAK;EAAqB,OAAO;EAAkB,aAAa;CAA4D;CAC9I;EAAE,UAAU;EAAM,KAAK;EAAsB,OAAO;EAAmB,aAAa;CAAyD;CAC7I;EAAE,UAAU;EAAM,KAAK;EAAgB,OAAO;EAAsB,aAAa;CAA8C;CAC/H;EAAE,UAAU;EAAM,KAAK;EAAa,OAAO;EAAa,aAAa;CAAoE;CACzI;EAAE,UAAU;EAAM,KAAK;EAAW,aAAa;EAAM,OAAO;EAAe,aAAa;CAAsD;CAG9I;EAAE,UAAU;EAAM,KAAK;EAAmB,aAAa;EAAM,OAAO;EAA2C,aAAa;CAAuD;CACnL;EAAE,UAAU;EAAS,KAAK;EAAgB,aAAa;EAAM,OAAO;EAA6B,aAAa;CAAuE;CACrL;EAAE,UAAU;EAAM,KAAK;EAAY,aAAa;EAAM,OAAO;EAAa,aAAa;CAA8D;CACrJ;EAAE,UAAU;EAAS,KAAK;EAAiB,aAAa;EAAM,UAAU;EAAY,OAAO;EAAgC,aAAa;CAAwE;CAChN;EAAE,UAAU;EAAS,KAAK;EAAsB,aAAa;EAAM,UAAU;EAAY,OAAO;EAA0C,aAAa;CAAsE;CAC7N;EAAE,UAAU;EAAM,KAAK;EAA4B,aAAa;EAAM,UAAU;EAAY,OAAO;EAAqC,aAAa;CAAwE;CAC7N;EAAE,UAAU;EAAM,KAAK;EAAkB,aAAa;EAAM,OAAO;EAAsB,aAAa;CAAqE;CAC3K;EAAE,UAAU;EAAM,KAAK;EAAqB,aAAa;EAAM,OAAO;EAA8B,aAAa;CAA6E;CAC9L;EAAE,UAAU;EAAM,KAAK;EAAe,OAAO;EAAgB,aAAa;CAA+C;CACzH;EAAE,UAAU;EAAM,KAAK;EAAqB,OAAO;EAAgB,aAAa;CAA+E;AACjK;AAwBA,SAAgB,0BAAuD,UAAgC;CACrG,IAAI,OAAiB;CACrB,KAAK,MAAM,OAAO,kBAAkB;EAClC,IAAI,CAAC,IAAI,UACP;EACF,MAAM,WAAW,QAAQ,SAAA,CAAU,IAAI;EACvC,MAAM,eAAe,QAAQ,SAAA,CAAU,IAAI;EAC3C,IAAI,YAAY,QAAQ,gBAAgB,MACtC,OAAO;GAAE,GAAI,QAAQ;IAAY,IAAI,MAAM;EAAM;CACrD;CACA,OAAQ,QAAQ;AAClB;AAmBA,MAAa,mBAA8C;CAEzD;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,SAAS;GACP;IAAE,OAAO;IAAO,OAAO;GAAe;GACtC;IAAE,OAAO;IAAQ,OAAO;GAAoB;GAC5C;IAAE,OAAO;IAAY,OAAO;GAAgB;EAC9C;CACF;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,SAAS,CACP;GAAE,OAAO;GAAU,OAAO;EAAU,GACpC;GAAE,OAAO;GAAS,OAAO;EAAS,CACpC;CACF;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,SAAS,CACP;GAAE,OAAO;GAAS,OAAO;EAAQ,GACjC;GAAE,OAAO;GAAQ,OAAO;EAAO,CACjC;CACF;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,SAAS;GACP;IAAE,OAAO;IAAK,OAAO;GAAM;GAC3B;IAAE,OAAO;IAAK,OAAO;GAAM;GAC3B;IAAE,OAAO;IAAK,OAAO;GAAM;GAC3B;IAAE,OAAO;IAAK,OAAO;GAAM;EAC7B;CACF;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,SAAS;GACP;IAAE,OAAO;IAAQ,OAAO;GAAgB;GACxC;IAAE,OAAO;IAAQ,OAAO;GAAY;GACpC;IAAE,OAAO;IAAW,OAAO;GAAe;GAC1C;IAAE,OAAO;IAAQ,OAAO;GAAO;EACjC;CACF;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,SAAS;GACP;IAAE,OAAO;IAAG,OAAO;GAAY;GAC/B;IAAE,OAAO;IAAM,OAAO;GAAK;GAC3B;IAAE,OAAO;IAAO,OAAO;GAAM;GAC7B;IAAE,OAAO;IAAO,OAAO;GAAM;GAC7B;IAAE,OAAO;IAAO,OAAO;GAAM;EAC/B;CACF;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,SAAS;GACP;IAAE,OAAO;IAAG,OAAO;GAAc;GACjC;IAAE,OAAO;IAAG,OAAO;GAAe;GAClC;IAAE,OAAO;IAAG,OAAO;GAAI;GACvB;IAAE,OAAO;IAAG,OAAO;GAAI;GACvB;IAAE,OAAO;IAAG,OAAO;GAAI;GACvB;IAAE,OAAO;IAAG,OAAO;GAAI;EACzB;CACF;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,SAAS;GACP;IAAE,OAAO;IAAG,OAAO;GAAY;GAC/B;IAAE,OAAO;IAAI,OAAO;GAAK;GACzB;IAAE,OAAO;IAAI,OAAO;GAAK;GACzB;IAAE,OAAO;IAAK,OAAO;GAAM;GAC3B;IAAE,OAAO;IAAK,OAAO;GAAM;EAC7B;CACF;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,SAAS;GACP;IAAE,OAAO;IAAG,OAAO;GAAY;GAC/B;IAAE,OAAO;IAAG,OAAO;GAAK;GACxB;IAAE,OAAO;IAAG,OAAO;GAAK;GACxB;IAAE,OAAO;IAAI,OAAO;GAAM;GAC1B;IAAE,OAAO;IAAI,OAAO;GAAM;EAC5B;CACF;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,SAAS;GACP;IAAE,OAAO;IAAG,OAAO;GAAY;GAC/B;IAAE,OAAO;IAAS,OAAO;GAAO;GAChC;IAAE,OAAO;IAAW,OAAO;GAAK;GAChC;IAAE,OAAO;IAAW,OAAO;GAAK;GAChC;IAAE,OAAO;IAAW,OAAO;GAAK;EAClC;CACF;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,SAAS;GACP;IAAE,OAAO;IAAG,OAAO;GAAY;GAC/B;IAAE,OAAO;IAAG,OAAO;GAAQ;GAC3B;IAAE,OAAO;IAAI,OAAO;GAAS;GAC7B;IAAE,OAAO;IAAI,OAAO;GAAS;GAC7B;IAAE,OAAO;IAAI,OAAO;GAAS;EAC/B;CACF;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,SAAS;GACP;IAAE,OAAO;IAAc,OAAO;GAAgB;GAC9C;IAAE,OAAO;IAAS,OAAO;GAAe;GACxC;IAAE,OAAO;IAAO,OAAO;GAAkB;EAC3C;CACF;CAEA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,SAAS;GACP;IAAE,OAAO;IAAa,OAAO;GAAY;GACzC;IAAE,OAAO;IAAQ,OAAO;GAAO;GAC/B;IAAE,OAAO;IAAU,OAAO;GAAS;EACrC;CACF;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,SAAS,CACP;GAAE,OAAO;GAAQ,OAAO;EAAO,GAC/B;GAAE,OAAO;GAAW,OAAO;EAAU,CACvC;CACF;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,SAAS,CACP;GAAE,OAAO;GAAQ,OAAO;EAAO,GAC/B;GAAE,OAAO;GAAW,OAAO;EAAU,CACvC;CACF;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,SAAS,OAAO,OAAO,cAAc,CAAC,CAAC,KAAI,OAAM;GAAE,OAAO,EAAE;GAAI,OAAO,EAAE;EAAM,EAAE;CACnF;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,SAAS,CACP;GAAE,OAAO;GAAQ,OAAO;EAAO,GAC/B;GAAE,OAAO;GAAW,OAAO;EAAU,CACvC;CACF;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,SAAS;GACP;IAAE,OAAO;IAAI,OAAO;GAAS;GAC7B;IAAE,OAAO;IAAI,OAAO;GAAS;GAC7B;IAAE,OAAO;IAAK,OAAO;GAAU;EACjC;CACF;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,SAAS;GACP;IAAE,OAAO;IAAQ,OAAO;GAAO;GAC/B;IAAE,OAAO;IAAgB,OAAO;GAAU;GAC1C;IAAE,OAAO;IAAkB,OAAO;GAAkB;EACtD;CACF;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,SAAS;GACP;IAAE,OAAO;IAAO,OAAO;GAAM;GAC7B;IAAE,OAAO;IAAO,OAAO;GAAS;GAChC;IAAE,OAAO;IAAW,OAAO;GAAgB;GAC3C;IAAE,OAAO;IAAgB,OAAO;GAAiB;EACnD;CACF;AACF;AA2BA,MAAa,kBAA4C;CACvD;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,aAAa;CACf;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,aAAa;CACf;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,aAAa;CACf;CACA;EACE,UAAU;EACV,KAAK;EACL,OAAO;EACP,aAAa;EACb,aAAa;CACf;AACF;;;;;;;AC7mBA,MAAa,wBAAwB,CAAC,aAAa,aAAa;;AAGhE,MAAM,mBAAgD;CACpD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,8BAAmC,IAAI,IAAY;CACvD,GAAG;CACH,GAAG;CACH,GAAG;EAAC,GAAG;EAAkB,GAAG;EAAkB,GAAG;CAAe,CAAC,CAAC,QAAO,QAAO,IAAI,aAAa,IAAI,CAAC,CAAC,KAAI,QAAO,IAAI,GAAG;AAC3H,CAAC;AAED,SAAgB,oBAAoB,KAAuC;CACzE,OAAO,YAAY,IAAI,GAAG;AAC5B;;AAGA,MAAa,qBAAqB;CAAC;CAAiB;CAAe;CAAqB;CAAkB;AAAkB;;AAG5H,SAAgB,oBAAwC,OAAU,MAA4B;CAC5F,MAAM,SAAS,EAAE,GAAG,MAAM;CAC1B,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,GAC5C,IAAI,CAAC,oBAAoB,GAAG,GAC1B,OAAO,OAAO;CAGlB,KAAK,MAAM,OAAO,oBAChB,IAAI,EAAE,OAAO,OACX,OAAO,OAAO;CAElB,OAAO;AACT;;AAGA,SAAgB,uBAAoD,OAAoD;CACtH,MAAM,SAAkC,CAAC;CACzC,MAAM,OAAgC,CAAC;CACvC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAC7C,CAAC,oBAAoB,GAAG,IAAI,SAAS,KAAA,CAAM,OAAO;CACpD,OAAO;EAAU;EAA4B;CAAmB;AAClE;;;AC7DA,MAAM,eAAe;AAOrB,SAAgB,cAAc,SAAyB;CACrD,OAAO,QAAQ,SAAS,YAAY;AACtC;;AAGA,SAAgB,kBAAkB,IAAoB;CACpD,OAAO,SAAS;AAClB;AAqBA,SAAS,QAAQ,OAAoC;CACnD,MAAM,IAAI;CACV,OAAO,CAAC,CAAC,KAAK,OAAO,MAAM,YAAY,OAAO,EAAE,OAAO,YAAY,OAAO,EAAE,SAAS,YAAY,OAAO,EAAE,QAAQ,YAAY,OAAO,EAAE,YAAY;AACrJ;;AAGA,SAAS,kBAAkB,OAA6B;CACtD,MAAM,MAAM,MAAM;CAClB,OAAO,kBAAkB,GAAG,IAAI;EAAE,GAAG;EAAO,KAAK,eAAe,GAAG;CAAE,IAAI;AAC3E;AAEA,SAAS,UAAU,SAA8B;CAC/C,MAAM,OAAO,cAAc,OAAO;CAClC,IAAI,CAAC,WAAW,IAAI,GAClB,OAAO,CAAC;CACV,IAAI;EACF,MAAM,SAAS,KAAK,MAAM,aAAa,MAAM,MAAM,CAAC;EACpD,OAAO,MAAM,QAAQ,OAAO,KAAK,IAAI,OAAO,MAAM,OAAO,OAAO,CAAC,CAAC,IAAI,iBAAiB,IAAI,CAAC;CAC9F,QACM;EACJ,OAAO,CAAC;CACV;AACF;AAEA,SAAS,WAAW,SAAiB,OAA0B;CAC7D,MAAM,OAAkB;EAAE,SAAS;EAAc;CAAM;CACvD,oBAAoB,cAAc,OAAO,GAAG,MAAM,UAAU;AAC9D;AAEA,SAAS,UAAU,MAAsB;CACvC,MAAM,UAAU,KAAK,KAAK;CAC1B,IAAI,CAAC,SACH,MAAM,IAAI,kBAAkB,gBAAgB,sBAAsB;CACpE,OAAO;AACT;AAEA,SAAS,WAAW,KAAqB;CACvC,IAAI;EACF,OAAO,mBAAmB,GAAG;CAC/B,SACO,KAAK;EACV,MAAM,IAAI,kBAAkB,eAAe,eAAe,kBAAkB,IAAI,UAAU,OAAO,GAAG,CAAC;CACvG;AACF;;AAGA,SAAgB,eAAe,OAAuE;CACpG,MAAM,MAAM,WAAW,MAAM,GAAG;CAChC,MAAM,QAAQ,MAAM,MAAM,KAAK;CAC/B,IAAI,CAAC,OACH,MAAM,IAAI,kBAAkB,iBAAiB,oEAAoE;CACnH,OAAO;EAAE;EAAK;CAAM;AACtB;;AAGA,SAAS,SAAS,KAAa,QAA0C;CACvE,IAAI,OAAO,MAAM,OAAO,QAAQ,SAAS,UACvC,OAAO;EAAE,IAAI;EAAO,OAAO;EAAY,SAAS,GAAG,IAAI,QAAQ,OAAO,QAAQ,KAAK;CAA6B;CAClH,OAAO;AACT;;AAGA,eAAsB,iBAAiB,OAAkB,OAAiE;CACxH,IAAI;CACJ,IAAI;EACF,UAAU,eAAe,KAAK;CAChC,SACO,KAAK;EACV,IAAI,eAAe,mBACjB,OAAO;GAAE,IAAI;GAAO,OAAO,IAAI;GAAM,SAAS,IAAI;EAAQ;EAC5D,MAAM;CACR;CACA,OAAO,SAAS,QAAQ,KAAK,MAAM,MAAM,OAAO,CAAC;AACnD;AAEA,SAAgB,mBAAmB,SAAkF;CACnH,MAAM,EAAE,SAAS,UAAU;CAC3B,MAAM,MAAM,QAAQ,OAAO,KAAK;CAChC,MAAM,aAA0B,UAAU,OAAO;CACjD,MAAM,OAAO,OAAsC,KAAK,CAAC,CAAC,MAAK,MAAK,EAAE,OAAO,EAAE;CAC/E,MAAM,SAAS,OAAmC;EAChD,MAAM,OAAO,oBAAoB,SAAS,kBAAkB,EAAE,CAAC;EAC/D,OAAO,MAAM,SAAS,YAAY,KAAK,QAAQ,KAAK,QAAQ,KAAA;CAC9D;CACA,MAAM,UAAU,IAAY,UAAkE;EAC5F,MAAM,QAAQ,KAAK;EACnB,MAAM,IAAI,MAAM,WAAU,MAAK,EAAE,OAAO,EAAE;EAC1C,IAAI,IAAI,GACN,OAAO,KAAA;EACT,MAAM,KAAK,MAAM,MAAM,EAAG;EAC1B,WAAW,SAAS,KAAK;EACzB,OAAO,MAAM;CACf;CAEA,OAAO;EACL;EACA;EACA;EACA,MAAM,IAAI,OAAO;GACf,MAAM,EAAE,KAAK,OAAO,WAAW,eAAe,KAAK;GACnD,MAAM,OAAO,MAAM,SAAS,KAAA,IAAY,KAAA,IAAY,UAAU,MAAM,IAAI;GACxE,MAAM,SAAS,SAAS,KAAK,MAAM,MAAM;IAAE;IAAK,OAAO;GAAO,CAAC,CAAC;GAChE,IAAI,CAAC,OAAO,IACV,MAAM,IAAI,kBAAkB,OAAO,OAAO,OAAO,OAAO;GAC1D,MAAM,KAAK,IAAI;GACf,MAAM,QAAkG;IACtG;IACA,iBAAiB;IACjB,UAAU;IACV,YAAY,OAAO,QAAQ;IAC3B,GAAI,OAAO,kBAAkB,KAAA,IAAY,EAAE,eAAe,OAAO,cAAc,IAAI,CAAC;GACtF;GACA,MAAM,KAAK,OAAO,QAAQ;GAE1B,qBAAqB,SAAS,kBAAkB,EAAE,GAAG;IAAE,MAAM;IAAU,OAAO;GAAO,CAAC;GACtF,MAAM,QAAQ,KAAK;GACnB,MAAM,WAAW,MAAM,MAAK,MAAK,EAAE,OAAO,EAAE;GAC5C,MAAM,QAAmB,WACrB;IAAE,GAAG;IAAU,GAAG;IAAO,GAAI,SAAS,KAAA,IAAY,EAAE,KAAK,IAAI,CAAC;GAAG,IACjE;IAAE;IAAI,MAAM,QAAQ,OAAO,QAAQ;IAAM,SAAS;IAAI,GAAG;GAAM;GACnE,WAAW,SAAS,WAAW,MAAM,KAAI,MAAM,EAAE,OAAO,KAAK,QAAQ,CAAE,IAAI,CAAC,GAAG,OAAO,KAAK,CAAC;GAC5F,OAAO;EACT;EACA,OAAO,IAAI;GACT,MAAM,QAAQ,KAAK;GACnB,MAAM,OAAO,MAAM,QAAO,MAAK,EAAE,OAAO,EAAE;GAC1C,MAAM,MAAM,KAAK,WAAW,MAAM;GAClC,IAAI,KACF,WAAW,SAAS,IAAI;GAC1B,MAAM,WAAW,MAAM,EAAE,MAAM,KAAA;GAC/B,qBAAqB,SAAS,kBAAkB,EAAE,GAAG,KAAA,CAAS;GAC9D,OAAO,OAAO;EAChB;EACA,OAAO,IAAI,MAAM;GACf,MAAM,QAAQ,UAAU,IAAI;GAC5B,MAAM,QAAQ,OAAO,KAAI,OAAM;IAAE,GAAG;IAAG,MAAM;GAAM,EAAE;GACrD,IAAI,CAAC,OACH,MAAM,IAAI,kBAAkB,gBAAgB,YAAY,GAAG,GAAG;GAChE,OAAO;EACT;EACA,MAAM,KAAK,IAAI;GACb,MAAM,QAAQ,IAAI,EAAE;GACpB,MAAM,SAAS,QAAQ,MAAM,EAAE,IAAI,KAAA;GACnC,IAAI,CAAC,SAAS,WAAW,KAAA,GACvB,OAAO;IAAE,IAAI;IAAO,OAAO;IAAgB,SAAS,QAAQ,uBAAuB,MAAM,KAAK,oBAAoB,YAAY,GAAG;GAAI;GACvI,MAAM,SAAS,MAAM,MAAM;IAAE,KAAK,MAAM;IAAK,OAAO;GAAO,CAAC;GAC5D,IAAI,CAAC,OAAO,IACV,OAAO;GACT,IAAI,OAAO,QAAQ,OAAO,MAAM,IAC9B,OAAO;IAAE,IAAI;IAAO,OAAO;IAAY,SAAS,sBAAsB,OAAO,QAAQ,KAAK,gBAAgB,MAAM,IAAI,YAAY,MAAM,KAAK;GAA2C;GACxL,OAAO,KAAI,OAAM;IACf,GAAG;IACH,iBAAiB,IAAI;IACrB,YAAY,OAAO,QAAQ;IAC3B,GAAI,OAAO,kBAAkB,KAAA,IAAY,EAAE,eAAe,OAAO,cAAc,IAAI,CAAC;GACtF,EAAE;GACF,OAAO;EACT;CACF;AACF"}