@travisennis/acai 0.0.9 → 0.0.10

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 (371) hide show
  1. package/README.md +49 -762
  2. package/bin/acai +52 -0
  3. package/dist/agent/index.d.ts +12 -2
  4. package/dist/agent/index.d.ts.map +1 -1
  5. package/dist/agent/index.js +378 -199
  6. package/dist/agent/sub-agent.d.ts +23 -0
  7. package/dist/agent/sub-agent.d.ts.map +1 -0
  8. package/dist/agent/sub-agent.js +109 -0
  9. package/dist/cli/index.d.ts +26 -0
  10. package/dist/cli/index.d.ts.map +1 -0
  11. package/dist/{cli.js → cli/index.js} +84 -77
  12. package/dist/cli/stdin.d.ts.map +1 -0
  13. package/dist/{stdin.js → cli/stdin.js} +11 -0
  14. package/dist/commands/copy/index.js +2 -2
  15. package/dist/commands/copy/utils.d.ts.map +1 -1
  16. package/dist/commands/copy/utils.js +15 -13
  17. package/dist/commands/generate-rules/index.d.ts +1 -1
  18. package/dist/commands/generate-rules/index.d.ts.map +1 -1
  19. package/dist/commands/generate-rules/index.js +16 -101
  20. package/dist/commands/generate-rules/service.d.ts +21 -0
  21. package/dist/commands/generate-rules/service.d.ts.map +1 -0
  22. package/dist/commands/generate-rules/service.js +103 -0
  23. package/dist/commands/handoff/index.js +2 -2
  24. package/dist/commands/health/index.js +1 -1
  25. package/dist/commands/health/utils.d.ts.map +1 -1
  26. package/dist/commands/health/utils.js +6 -0
  27. package/dist/commands/history/index.d.ts +1 -1
  28. package/dist/commands/history/index.d.ts.map +1 -1
  29. package/dist/commands/history/index.js +17 -18
  30. package/dist/commands/history/types.d.ts +38 -0
  31. package/dist/commands/history/types.d.ts.map +1 -1
  32. package/dist/commands/history/utils.d.ts.map +1 -1
  33. package/dist/commands/history/utils.js +63 -58
  34. package/dist/commands/init/index.d.ts.map +1 -1
  35. package/dist/commands/init/index.js +3 -8
  36. package/dist/commands/init-project/index.d.ts.map +1 -1
  37. package/dist/commands/init-project/index.js +3 -3
  38. package/dist/commands/init-project/utils.d.ts.map +1 -1
  39. package/dist/commands/init-project/utils.js +10 -2
  40. package/dist/commands/list-tools/index.d.ts.map +1 -1
  41. package/dist/commands/list-tools/index.js +7 -31
  42. package/dist/commands/manager.d.ts +2 -2
  43. package/dist/commands/manager.d.ts.map +1 -1
  44. package/dist/commands/manager.js +55 -33
  45. package/dist/commands/model/index.d.ts.map +1 -1
  46. package/dist/commands/model/index.js +20 -151
  47. package/dist/commands/model/model-panel.d.ts +4 -0
  48. package/dist/commands/model/model-panel.d.ts.map +1 -0
  49. package/dist/commands/model/model-panel.js +144 -0
  50. package/dist/commands/paste/index.d.ts.map +1 -1
  51. package/dist/commands/paste/index.js +59 -62
  52. package/dist/commands/paste/utils.d.ts.map +1 -1
  53. package/dist/commands/paste/utils.js +88 -58
  54. package/dist/commands/pickup/index.d.ts.map +1 -1
  55. package/dist/commands/pickup/index.js +6 -3
  56. package/dist/commands/pickup/utils.js +3 -3
  57. package/dist/commands/resources/index.d.ts.map +1 -1
  58. package/dist/commands/resources/index.js +33 -50
  59. package/dist/commands/review/index.d.ts.map +1 -1
  60. package/dist/commands/review/index.js +3 -117
  61. package/dist/commands/review/review-panel.d.ts +3 -0
  62. package/dist/commands/review/review-panel.d.ts.map +1 -0
  63. package/dist/commands/review/review-panel.js +186 -0
  64. package/dist/commands/review/utils.d.ts +9 -0
  65. package/dist/commands/review/utils.d.ts.map +1 -1
  66. package/dist/commands/review/utils.js +127 -68
  67. package/dist/commands/session/index.d.ts +1 -1
  68. package/dist/commands/session/index.d.ts.map +1 -1
  69. package/dist/commands/session/index.js +124 -135
  70. package/dist/commands/shell/index.d.ts.map +1 -1
  71. package/dist/commands/shell/index.js +16 -1
  72. package/dist/commands/types.d.ts +2 -2
  73. package/dist/commands/types.d.ts.map +1 -1
  74. package/dist/{config.d.ts → config/index.d.ts} +20 -9
  75. package/dist/config/index.d.ts.map +1 -0
  76. package/dist/{config.js → config/index.js} +43 -42
  77. package/dist/execution/index.d.ts.map +1 -1
  78. package/dist/execution/index.js +75 -55
  79. package/dist/index.d.ts +1 -0
  80. package/dist/index.d.ts.map +1 -1
  81. package/dist/index.js +148 -141
  82. package/dist/middleware/cache.d.ts.map +1 -1
  83. package/dist/middleware/cache.js +18 -36
  84. package/dist/models/ai-config.d.ts +1 -0
  85. package/dist/models/ai-config.d.ts.map +1 -1
  86. package/dist/models/ai-config.js +4 -3
  87. package/dist/models/anthropic-provider.d.ts +2 -5
  88. package/dist/models/anthropic-provider.d.ts.map +1 -1
  89. package/dist/models/anthropic-provider.js +3 -70
  90. package/dist/models/deepseek-provider.d.ts +1 -0
  91. package/dist/models/deepseek-provider.d.ts.map +1 -1
  92. package/dist/models/google-provider.d.ts +2 -3
  93. package/dist/models/google-provider.d.ts.map +1 -1
  94. package/dist/models/google-provider.js +0 -26
  95. package/dist/models/groq-provider.d.ts +1 -0
  96. package/dist/models/groq-provider.d.ts.map +1 -1
  97. package/dist/models/manager.d.ts +13 -2
  98. package/dist/models/manager.d.ts.map +1 -1
  99. package/dist/models/manager.js +20 -8
  100. package/dist/models/openai-provider.d.ts +2 -5
  101. package/dist/models/openai-provider.d.ts.map +1 -1
  102. package/dist/models/openai-provider.js +0 -52
  103. package/dist/models/opencode-zen-provider.d.ts +7 -3
  104. package/dist/models/opencode-zen-provider.d.ts.map +1 -1
  105. package/dist/models/opencode-zen-provider.js +49 -10
  106. package/dist/models/openrouter-provider.d.ts +24 -31
  107. package/dist/models/openrouter-provider.d.ts.map +1 -1
  108. package/dist/models/openrouter-provider.js +84 -182
  109. package/dist/models/providers.d.ts +1 -1
  110. package/dist/models/providers.d.ts.map +1 -1
  111. package/dist/models/xai-provider.d.ts +4 -3
  112. package/dist/models/xai-provider.d.ts.map +1 -1
  113. package/dist/models/xai-provider.js +18 -18
  114. package/dist/modes/manager.d.ts +23 -0
  115. package/dist/modes/manager.d.ts.map +1 -0
  116. package/dist/modes/manager.js +77 -0
  117. package/dist/modes/prompts.d.ts +2 -0
  118. package/dist/modes/prompts.d.ts.map +1 -0
  119. package/dist/modes/prompts.js +143 -0
  120. package/dist/prompts/mentions.d.ts +11 -0
  121. package/dist/prompts/mentions.d.ts.map +1 -0
  122. package/dist/{mentions.js → prompts/mentions.js} +21 -80
  123. package/dist/{prompts.d.ts → prompts/system-prompt.d.ts} +7 -2
  124. package/dist/prompts/system-prompt.d.ts.map +1 -0
  125. package/dist/{prompts.js → prompts/system-prompt.js} +31 -16
  126. package/dist/repl/index.d.ts +174 -0
  127. package/dist/repl/index.d.ts.map +1 -0
  128. package/dist/{repl-new.js → repl/index.js} +389 -76
  129. package/dist/repl/project-status.d.ts +1 -0
  130. package/dist/repl/project-status.d.ts.map +1 -1
  131. package/dist/repl/project-status.js +4 -1
  132. package/dist/sessions/manager.d.ts +93 -1
  133. package/dist/sessions/manager.d.ts.map +1 -1
  134. package/dist/sessions/manager.js +262 -9
  135. package/dist/sessions/summary.d.ts +4 -0
  136. package/dist/sessions/summary.d.ts.map +1 -0
  137. package/dist/sessions/summary.js +30 -0
  138. package/dist/{skills.d.ts → skills/index.d.ts} +14 -2
  139. package/dist/skills/index.d.ts.map +1 -0
  140. package/dist/skills/index.js +294 -0
  141. package/dist/subagents/index.d.ts +15 -0
  142. package/dist/subagents/index.d.ts.map +1 -0
  143. package/dist/subagents/index.js +231 -0
  144. package/dist/terminal/control.d.ts +1 -1
  145. package/dist/terminal/control.d.ts.map +1 -1
  146. package/dist/terminal/control.js +3 -3
  147. package/dist/terminal/east-asian-width.d.ts.map +1 -1
  148. package/dist/terminal/east-asian-width.js +404 -351
  149. package/dist/terminal/keys.d.ts +17 -0
  150. package/dist/terminal/keys.d.ts.map +1 -1
  151. package/dist/terminal/keys.js +37 -0
  152. package/dist/terminal/select-prompt.d.ts.map +1 -1
  153. package/dist/terminal/select-prompt.js +24 -12
  154. package/dist/terminal/string-width.d.ts.map +1 -1
  155. package/dist/terminal/string-width.js +25 -27
  156. package/dist/terminal/style.d.ts.map +1 -1
  157. package/dist/terminal/style.js +4 -7
  158. package/dist/terminal/supports-color.d.ts.map +1 -1
  159. package/dist/terminal/supports-color.js +41 -27
  160. package/dist/terminal/table/cell.d.ts +12 -0
  161. package/dist/terminal/table/cell.d.ts.map +1 -1
  162. package/dist/terminal/table/cell.js +40 -25
  163. package/dist/terminal/table/layout-manager.d.ts.map +1 -1
  164. package/dist/terminal/table/layout-manager.js +100 -68
  165. package/dist/terminal/table/utils.d.ts.map +1 -1
  166. package/dist/terminal/table/utils.js +17 -10
  167. package/dist/terminal/wrap-ansi.d.ts.map +1 -1
  168. package/dist/terminal/wrap-ansi.js +172 -103
  169. package/dist/tokens/tracker.d.ts +1 -0
  170. package/dist/tokens/tracker.d.ts.map +1 -1
  171. package/dist/tokens/tracker.js +3 -0
  172. package/dist/tools/agent.d.ts +27 -0
  173. package/dist/tools/agent.d.ts.map +1 -0
  174. package/dist/tools/agent.js +81 -0
  175. package/dist/tools/bash.d.ts +4 -3
  176. package/dist/tools/bash.d.ts.map +1 -1
  177. package/dist/tools/bash.js +324 -137
  178. package/dist/tools/code-search.d.ts +41 -0
  179. package/dist/tools/code-search.d.ts.map +1 -0
  180. package/dist/tools/code-search.js +195 -0
  181. package/dist/tools/directory-tree.d.ts +3 -3
  182. package/dist/tools/directory-tree.d.ts.map +1 -1
  183. package/dist/tools/directory-tree.js +8 -5
  184. package/dist/tools/dynamic-tool-loader.d.ts +2 -5
  185. package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
  186. package/dist/tools/dynamic-tool-loader.js +20 -4
  187. package/dist/tools/edit-file.d.ts +7 -7
  188. package/dist/tools/edit-file.d.ts.map +1 -1
  189. package/dist/tools/edit-file.js +164 -66
  190. package/dist/tools/glob.d.ts +6 -6
  191. package/dist/tools/glob.d.ts.map +1 -1
  192. package/dist/tools/glob.js +95 -55
  193. package/dist/tools/grep.d.ts +15 -12
  194. package/dist/tools/grep.d.ts.map +1 -1
  195. package/dist/tools/grep.js +300 -192
  196. package/dist/tools/index.d.ts +143 -5
  197. package/dist/tools/index.d.ts.map +1 -1
  198. package/dist/tools/index.js +39 -24
  199. package/dist/tools/ls.d.ts +2 -2
  200. package/dist/tools/ls.d.ts.map +1 -1
  201. package/dist/tools/ls.js +7 -5
  202. package/dist/tools/read-file.d.ts +3 -3
  203. package/dist/tools/read-file.d.ts.map +1 -1
  204. package/dist/tools/read-file.js +74 -34
  205. package/dist/tools/save-file.d.ts +3 -3
  206. package/dist/tools/save-file.d.ts.map +1 -1
  207. package/dist/tools/save-file.js +11 -11
  208. package/dist/tools/skill.d.ts +23 -0
  209. package/dist/tools/skill.d.ts.map +1 -0
  210. package/dist/tools/skill.js +65 -0
  211. package/dist/tools/think.d.ts.map +1 -1
  212. package/dist/tools/think.js +2 -9
  213. package/dist/tools/utils.d.ts +2 -0
  214. package/dist/tools/utils.d.ts.map +1 -1
  215. package/dist/tools/utils.js +12 -0
  216. package/dist/tools/web-fetch.d.ts +62 -0
  217. package/dist/tools/web-fetch.d.ts.map +1 -0
  218. package/dist/tools/web-fetch.js +429 -0
  219. package/dist/tools/web-search.d.ts +62 -0
  220. package/dist/tools/web-search.d.ts.map +1 -0
  221. package/dist/tools/web-search.js +226 -0
  222. package/dist/tui/autocomplete/attachment-provider.d.ts +3 -6
  223. package/dist/tui/autocomplete/attachment-provider.d.ts.map +1 -1
  224. package/dist/tui/autocomplete/attachment-provider.js +25 -78
  225. package/dist/tui/autocomplete/base-provider.d.ts +1 -0
  226. package/dist/tui/autocomplete/base-provider.d.ts.map +1 -1
  227. package/dist/tui/autocomplete/combined-provider.d.ts +1 -4
  228. package/dist/tui/autocomplete/combined-provider.d.ts.map +1 -1
  229. package/dist/tui/autocomplete/combined-provider.js +3 -17
  230. package/dist/tui/autocomplete/command-provider.d.ts +1 -0
  231. package/dist/tui/autocomplete/command-provider.d.ts.map +1 -1
  232. package/dist/tui/autocomplete/command-provider.js +3 -0
  233. package/dist/tui/autocomplete/file-search-provider.d.ts +2 -1
  234. package/dist/tui/autocomplete/file-search-provider.d.ts.map +1 -1
  235. package/dist/tui/autocomplete/file-search-provider.js +36 -16
  236. package/dist/tui/autocomplete/skill-provider.d.ts +17 -0
  237. package/dist/tui/autocomplete/skill-provider.d.ts.map +1 -0
  238. package/dist/tui/autocomplete/skill-provider.js +49 -0
  239. package/dist/tui/autocomplete.d.ts +2 -2
  240. package/dist/tui/autocomplete.d.ts.map +1 -1
  241. package/dist/tui/autocomplete.js +3 -5
  242. package/dist/tui/components/assistant-message.d.ts.map +1 -1
  243. package/dist/tui/components/assistant-message.js +0 -4
  244. package/dist/tui/components/editor.d.ts +16 -2
  245. package/dist/tui/components/editor.d.ts.map +1 -1
  246. package/dist/tui/components/editor.js +211 -237
  247. package/dist/tui/components/footer.d.ts +6 -4
  248. package/dist/tui/components/footer.d.ts.map +1 -1
  249. package/dist/tui/components/footer.js +49 -25
  250. package/dist/tui/components/markdown.d.ts +8 -5
  251. package/dist/tui/components/markdown.d.ts.map +1 -1
  252. package/dist/tui/components/markdown.js +57 -39
  253. package/dist/tui/components/modal.d.ts.map +1 -1
  254. package/dist/tui/components/modal.js +35 -33
  255. package/dist/tui/components/notification.d.ts +13 -2
  256. package/dist/tui/components/notification.d.ts.map +1 -1
  257. package/dist/tui/components/notification.js +36 -2
  258. package/dist/tui/components/progress-bar.js +1 -1
  259. package/dist/tui/components/select-list.d.ts +1 -0
  260. package/dist/tui/components/select-list.d.ts.map +1 -1
  261. package/dist/tui/components/select-list.js +14 -11
  262. package/dist/tui/components/text.d.ts +16 -0
  263. package/dist/tui/components/text.d.ts.map +1 -1
  264. package/dist/tui/components/text.js +72 -57
  265. package/dist/tui/components/thinking-block.d.ts +9 -0
  266. package/dist/tui/components/thinking-block.d.ts.map +1 -1
  267. package/dist/tui/components/thinking-block.js +43 -11
  268. package/dist/tui/components/tool-execution.d.ts +5 -1
  269. package/dist/tui/components/tool-execution.d.ts.map +1 -1
  270. package/dist/tui/components/tool-execution.js +19 -10
  271. package/dist/tui/components/user-message.d.ts.map +1 -1
  272. package/dist/tui/components/user-message.js +0 -3
  273. package/dist/tui/components/welcome.js +2 -2
  274. package/dist/tui/terminal.d.ts.map +1 -1
  275. package/dist/tui/terminal.js +10 -2
  276. package/dist/tui/tui.d.ts +42 -0
  277. package/dist/tui/tui.d.ts.map +1 -1
  278. package/dist/tui/tui.js +157 -41
  279. package/dist/utils/bash/parse.d.ts +19 -0
  280. package/dist/utils/bash/parse.d.ts.map +1 -0
  281. package/dist/utils/bash/parse.js +223 -0
  282. package/dist/utils/bash/quote.d.ts +6 -0
  283. package/dist/utils/bash/quote.d.ts.map +1 -0
  284. package/dist/utils/bash/quote.js +23 -0
  285. package/dist/utils/bash.d.ts.map +1 -1
  286. package/dist/utils/bash.js +211 -126
  287. package/dist/utils/command-protection.d.ts +28 -0
  288. package/dist/utils/command-protection.d.ts.map +1 -0
  289. package/dist/utils/command-protection.js +324 -0
  290. package/dist/utils/dedent.d.ts.map +1 -0
  291. package/dist/utils/env-expand.d.ts +2 -0
  292. package/dist/utils/env-expand.d.ts.map +1 -0
  293. package/dist/utils/env-expand.js +8 -0
  294. package/dist/utils/filesystem/path-display.d.ts +11 -0
  295. package/dist/utils/filesystem/path-display.d.ts.map +1 -0
  296. package/dist/utils/filesystem/path-display.js +32 -0
  297. package/dist/utils/filesystem/security.d.ts +2 -2
  298. package/dist/utils/filesystem/security.d.ts.map +1 -1
  299. package/dist/utils/filesystem/security.js +28 -30
  300. package/dist/utils/formatting.d.ts.map +1 -0
  301. package/dist/{formatting.js → utils/formatting.js} +1 -1
  302. package/dist/utils/git.d.ts +4 -0
  303. package/dist/utils/git.d.ts.map +1 -1
  304. package/dist/utils/git.js +30 -0
  305. package/dist/utils/glob.d.ts +1 -1
  306. package/dist/utils/glob.d.ts.map +1 -1
  307. package/dist/utils/logger.d.ts.map +1 -0
  308. package/dist/{logger.js → utils/logger.js} +1 -1
  309. package/dist/utils/parsing.d.ts.map +1 -0
  310. package/dist/utils/process.d.ts.map +1 -1
  311. package/dist/utils/process.js +90 -37
  312. package/dist/utils/templates.d.ts +2 -0
  313. package/dist/utils/templates.d.ts.map +1 -0
  314. package/dist/utils/templates.js +24 -0
  315. package/dist/utils/version.d.ts.map +1 -0
  316. package/dist/{version.js → utils/version.js} +1 -1
  317. package/package.json +34 -25
  318. package/dist/cli.d.ts +0 -23
  319. package/dist/cli.d.ts.map +0 -1
  320. package/dist/commands/exit/index.d.ts +0 -10
  321. package/dist/commands/exit/index.d.ts.map +0 -1
  322. package/dist/commands/exit/index.js +0 -21
  323. package/dist/commands/exit/types.d.ts +0 -8
  324. package/dist/commands/exit/types.d.ts.map +0 -1
  325. package/dist/commands/exit/types.js +0 -1
  326. package/dist/commands/exit/utils.d.ts +0 -2
  327. package/dist/commands/exit/utils.d.ts.map +0 -1
  328. package/dist/commands/exit/utils.js +0 -13
  329. package/dist/commands/prompt/index.d.ts +0 -5
  330. package/dist/commands/prompt/index.d.ts.map +0 -1
  331. package/dist/commands/prompt/index.js +0 -122
  332. package/dist/commands/prompt/types.d.ts +0 -15
  333. package/dist/commands/prompt/types.d.ts.map +0 -1
  334. package/dist/commands/prompt/types.js +0 -1
  335. package/dist/commands/prompt/utils.d.ts +0 -12
  336. package/dist/commands/prompt/utils.d.ts.map +0 -1
  337. package/dist/commands/prompt/utils.js +0 -107
  338. package/dist/commands/reset/index.d.ts +0 -3
  339. package/dist/commands/reset/index.d.ts.map +0 -1
  340. package/dist/commands/reset/index.js +0 -25
  341. package/dist/commands/reset/types.d.ts +0 -1
  342. package/dist/commands/reset/types.d.ts.map +0 -1
  343. package/dist/commands/reset/types.js +0 -3
  344. package/dist/commands/save/index.d.ts +0 -3
  345. package/dist/commands/save/index.d.ts.map +0 -1
  346. package/dist/commands/save/index.js +0 -19
  347. package/dist/config.d.ts.map +0 -1
  348. package/dist/dedent.d.ts.map +0 -1
  349. package/dist/formatting.d.ts.map +0 -1
  350. package/dist/logger.d.ts.map +0 -1
  351. package/dist/mentions.d.ts +0 -14
  352. package/dist/mentions.d.ts.map +0 -1
  353. package/dist/parsing.d.ts.map +0 -1
  354. package/dist/prompts.d.ts.map +0 -1
  355. package/dist/repl-new.d.ts +0 -65
  356. package/dist/repl-new.d.ts.map +0 -1
  357. package/dist/skills.d.ts.map +0 -1
  358. package/dist/skills.js +0 -233
  359. package/dist/stdin.d.ts.map +0 -1
  360. package/dist/tui/autocomplete/path-provider.d.ts +0 -21
  361. package/dist/tui/autocomplete/path-provider.d.ts.map +0 -1
  362. package/dist/tui/autocomplete/path-provider.js +0 -164
  363. package/dist/version.d.ts.map +0 -1
  364. /package/dist/{stdin.d.ts → cli/stdin.d.ts} +0 -0
  365. /package/dist/{dedent.d.ts → utils/dedent.d.ts} +0 -0
  366. /package/dist/{dedent.js → utils/dedent.js} +0 -0
  367. /package/dist/{formatting.d.ts → utils/formatting.d.ts} +0 -0
  368. /package/dist/{logger.d.ts → utils/logger.d.ts} +0 -0
  369. /package/dist/{parsing.d.ts → utils/parsing.d.ts} +0 -0
  370. /package/dist/{parsing.js → utils/parsing.js} +0 -0
  371. /package/dist/{version.d.ts → utils/version.d.ts} +0 -0
package/dist/tui/tui.js CHANGED
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Minimal TUI implementation with differential rendering
3
3
  */
4
- import { getTerminalSize, isCtrlC, isCtrlZ, isEscape, } from "../terminal/control.js";
4
+ import { getTerminalSize, isCtrlC, isCtrlD, isCtrlM, isCtrlN, isCtrlO, isCtrlR, isCtrlZ, isEscape, } from "../terminal/control.js";
5
+ import { isShiftTab } from "../terminal/keys.js";
5
6
  import style from "../terminal/style.js";
6
7
  import { visibleWidth } from "./utils.js";
7
8
  export { visibleWidth };
@@ -28,6 +29,14 @@ export class Container {
28
29
  }
29
30
  /**
30
31
  * TUI - Main class for managing terminal UI with differential rendering
32
+ *
33
+ * The TUI splits its children into two regions:
34
+ * - Scrollable content: children added before setFixedFooterStart()
35
+ * - Fixed footer: children added after setFixedFooterStart()
36
+ *
37
+ * The scrollable content region supports virtual scrolling via trackpad/mouse
38
+ * wheel. The fixed footer (editor, footer bar, notifications) is always
39
+ * pinned to the bottom of the terminal.
31
40
  */
32
41
  // biome-ignore lint/style/useNamingConvention: override
33
42
  export class TUI extends Container {
@@ -37,14 +46,41 @@ export class TUI extends Container {
37
46
  isRendering = false;
38
47
  renderAgain = false;
39
48
  activeModal = null;
49
+ scrollOffset = 0;
50
+ lastScrollableHeight = 0;
51
+ fixedFooterIndex = -1;
52
+ isUserScrolledUp = false;
40
53
  onCtrlC;
54
+ onCtrlD;
55
+ onReconstructSession;
56
+ onCtrlN;
57
+ onCtrlO;
58
+ /** Callback invoked when Ctrl+M is pressed - opens model selector. */
59
+ onCtrlM;
60
+ onCtrlR;
61
+ onShiftTab;
41
62
  constructor(terminal) {
42
63
  super();
43
64
  this.terminal = terminal;
44
65
  }
66
+ /**
67
+ * Mark the boundary between scrollable content and fixed footer.
68
+ * All children added after this call will be rendered as fixed
69
+ * footer content pinned to the bottom of the terminal.
70
+ */
71
+ setFixedFooterStart() {
72
+ this.fixedFooterIndex = this.children.length;
73
+ }
45
74
  setFocus(component) {
46
75
  this.focusedComponent = component;
47
76
  }
77
+ /**
78
+ * Get the underlying terminal instance for external mode operations.
79
+ * Used primarily for spawning external editors.
80
+ */
81
+ getTerminal() {
82
+ return this.terminal;
83
+ }
48
84
  start() {
49
85
  this.terminal.start((data) => this.handleInput(data), () => this.requestRender());
50
86
  this.terminal.onResume(() => this.requestRender());
@@ -69,7 +105,15 @@ export class TUI extends Container {
69
105
  });
70
106
  }
71
107
  inBracketedPaste = false;
108
+ focusedComponentWantsNavigation() {
109
+ return this.focusedComponent?.wantsNavigationKeys?.() ?? false;
110
+ }
72
111
  handleInput(data) {
112
+ // Handle mouse tracking events (SGR format: \x1b[<button;x;yM)
113
+ if (data.startsWith("\x1b[<")) {
114
+ this.handleMouseEvent(data);
115
+ return;
116
+ }
73
117
  if (data.includes("\x1b[200~")) {
74
118
  this.inBracketedPaste = true;
75
119
  }
@@ -94,6 +138,36 @@ export class TUI extends Container {
94
138
  process.exit(0);
95
139
  }
96
140
  }
141
+ // Handle Ctrl+D - exit only if editor is empty (handled by Repl)
142
+ if (isCtrlD(data)) {
143
+ if (this.onCtrlD) {
144
+ this.onCtrlD();
145
+ }
146
+ return;
147
+ }
148
+ const keyBindings = [
149
+ { check: isCtrlO, handler: this.onCtrlO },
150
+ { check: isCtrlR, handler: this.onCtrlR },
151
+ { check: isCtrlN, handler: this.onCtrlN },
152
+ { check: isCtrlM, handler: this.onCtrlM },
153
+ ];
154
+ for (const binding of keyBindings) {
155
+ if (binding.check(data)) {
156
+ binding.handler?.();
157
+ return;
158
+ }
159
+ }
160
+ // Handle Shift+Tab - cycle mode only when no modal is active,
161
+ // the focused component won't handle navigation (e.g., model selector),
162
+ // and the editor isn't showing autocomplete
163
+ if (isShiftTab(data) && !this.inBracketedPaste) {
164
+ if (!this.activeModal && !this.focusedComponentWantsNavigation()) {
165
+ if (this.onShiftTab) {
166
+ this.onShiftTab();
167
+ }
168
+ return;
169
+ }
170
+ }
97
171
  // Handle Escape key to close modal if one is active
98
172
  if (isEscape(data) && this.activeModal) {
99
173
  this.hideModal();
@@ -106,9 +180,69 @@ export class TUI extends Container {
106
180
  }
107
181
  else if (this.focusedComponent?.handleInput) {
108
182
  this.focusedComponent.handleInput(data);
183
+ this.scrollToBottom();
184
+ this.requestRender();
185
+ }
186
+ }
187
+ handleMouseEvent(data) {
188
+ // SGR mouse format: \x1b[<button;x;yM (press) or \x1b[<button;x;ym (release)
189
+ // Extract button code between "<" and first ";"
190
+ const start = data.indexOf("<");
191
+ const semi = data.indexOf(";", start);
192
+ if (start === -1 || semi === -1)
193
+ return;
194
+ const button = Number.parseInt(data.slice(start + 1, semi), 10);
195
+ const scrollLines = 3;
196
+ const { rows } = getTerminalSize();
197
+ const fixedHeight = this.getFixedFooterHeight(this.terminal.columns);
198
+ const scrollableViewport = rows - fixedHeight;
199
+ // Button 64 = scroll up, button 65 = scroll down
200
+ if (button === 64) {
201
+ this.scrollOffset = Math.max(0, this.scrollOffset - scrollLines);
202
+ const maxOffset = Math.max(0, this.lastScrollableHeight - scrollableViewport);
203
+ this.isUserScrolledUp = this.scrollOffset < maxOffset;
204
+ this.requestRender();
205
+ }
206
+ else if (button === 65) {
207
+ const maxOffset = Math.max(0, this.lastScrollableHeight - scrollableViewport);
208
+ this.scrollOffset = Math.min(maxOffset, this.scrollOffset + scrollLines);
209
+ this.isUserScrolledUp = this.scrollOffset < maxOffset;
109
210
  this.requestRender();
110
211
  }
111
212
  }
213
+ scrollToBottom() {
214
+ const { rows } = getTerminalSize();
215
+ const fixedHeight = this.getFixedFooterHeight(this.terminal.columns);
216
+ const scrollableViewport = rows - fixedHeight;
217
+ this.scrollOffset = Math.max(0, this.lastScrollableHeight - scrollableViewport);
218
+ this.isUserScrolledUp = false;
219
+ }
220
+ getFixedFooterHeight(width) {
221
+ if (this.fixedFooterIndex < 0)
222
+ return 0;
223
+ let height = 0;
224
+ for (let i = this.fixedFooterIndex; i < this.children.length; i++) {
225
+ height += this.children[i].render(width).length;
226
+ }
227
+ return height;
228
+ }
229
+ renderScrollableContent(width) {
230
+ const end = this.fixedFooterIndex >= 0 ? this.fixedFooterIndex : this.children.length;
231
+ const lines = [];
232
+ for (let i = 0; i < end; i++) {
233
+ lines.push(...this.children[i].render(width));
234
+ }
235
+ return lines;
236
+ }
237
+ renderFixedFooter(width) {
238
+ if (this.fixedFooterIndex < 0)
239
+ return [];
240
+ const lines = [];
241
+ for (let i = this.fixedFooterIndex; i < this.children.length; i++) {
242
+ lines.push(...this.children[i].render(width));
243
+ }
244
+ return lines;
245
+ }
112
246
  doRender() {
113
247
  if (this.isRendering) {
114
248
  this.renderAgain = true;
@@ -117,13 +251,32 @@ export class TUI extends Container {
117
251
  this.isRendering = true;
118
252
  try {
119
253
  const width = this.terminal.columns;
120
- // Render all components to get new lines
121
- const newLines = this.render(width);
254
+ const { rows } = getTerminalSize();
255
+ // Render fixed footer and scrollable content separately
256
+ const fixedLines = this.renderFixedFooter(width);
257
+ const scrollableLines = this.renderScrollableContent(width);
258
+ this.lastScrollableHeight = scrollableLines.length;
259
+ const fixedHeight = fixedLines.length;
260
+ const scrollableViewport = rows - fixedHeight;
261
+ // Auto-scroll to bottom when new content arrives,
262
+ // unless the user has explicitly scrolled up
263
+ if (!this.isUserScrolledUp) {
264
+ this.scrollOffset = Math.max(0, scrollableLines.length - scrollableViewport);
265
+ }
266
+ // Clamp scroll offset
267
+ const maxOffset = Math.max(0, scrollableLines.length - scrollableViewport);
268
+ if (this.scrollOffset > maxOffset) {
269
+ this.scrollOffset = maxOffset;
270
+ }
271
+ // Apply scroll offset to get visible scrollable lines
272
+ const visibleScrollable = scrollableLines.slice(this.scrollOffset, this.scrollOffset + scrollableViewport);
273
+ // Combine visible scrollable content with fixed footer
274
+ const visibleLines = [...visibleScrollable, ...fixedLines];
122
275
  // Build output buffer using array join (more efficient than string concat)
123
276
  const bufferParts = [
124
277
  "\x1b[?2026h", // Begin synchronized output
125
278
  "\x1b[3J\x1b[2J\x1b[H", // Clear scrollback, screen, and home
126
- newLines.join("\r\n"),
279
+ visibleLines.join("\r\n"),
127
280
  ];
128
281
  // Render modal on top if active
129
282
  if (this.activeModal) {
@@ -154,43 +307,6 @@ export class TUI extends Container {
154
307
  }
155
308
  }
156
309
  }
157
- // private positionCursor(
158
- // componentCursorPos: [number, number] | null,
159
- // ): void {
160
- // if (!componentCursorPos) {
161
- // // No cursor position from component, hide cursor
162
- // this.terminal.hideCursor();
163
- // return;
164
- // }
165
- // const [cursorRow, cursorCol] = componentCursorPos;
166
- //
167
- // // Calculate absolute cursor position in the terminal
168
- // // We need to find which line in newLines corresponds to the component's cursor row
169
- // // and then position the cursor at that line and column
170
- //
171
- // // Find the line offset for the focused component
172
- // let componentStartLine = 0;
173
- // if (this.focusedComponent) {
174
- // // Find the line where this component starts by summing heights of previous components
175
- // for (const child of this.children) {
176
- // if (child === this.focusedComponent) {
177
- // break;
178
- // }
179
- // // Use the already-rendered lines to calculate height, not re-render
180
- // const childLines = child.render(this.terminal.columns);
181
- // componentStartLine += childLines.length;
182
- // }
183
- // }
184
- //
185
- // const absoluteRow = componentStartLine + cursorRow;
186
- // const absoluteCol = cursorCol;
187
- //
188
- // // Position cursor using absolute positioning
189
- // // Move to home position first, then move down to row, then right to column
190
- // // Note: terminal rows/columns are 1-indexed, so we add 1
191
- // this.terminal.write(`\x1b[H\x1b[${absoluteRow + 1}B\x1b[${absoluteCol + 1}G`);
192
- // this.terminal.showCursor();
193
- // }
194
310
  /**
195
311
  * Show a modal dialog
196
312
  */
@@ -0,0 +1,19 @@
1
+ interface ControlOperator {
2
+ op: "||" | "&&" | ";;" | "|&" | "<(" | "<<<" | ">>" | ">&" | "&" | ";" | "(" | ")" | "|" | "<" | ">";
3
+ }
4
+ interface GlobOperator {
5
+ op: "glob";
6
+ pattern: string;
7
+ }
8
+ interface CommentOperator {
9
+ comment: string;
10
+ }
11
+ type ParseEntry = string | ControlOperator | GlobOperator | CommentOperator;
12
+ interface ParseOptions {
13
+ escape?: string;
14
+ }
15
+ type EnvFunction = (key: string) => unknown;
16
+ export declare function parse(s: string, env?: Record<string, string | undefined> | EnvFunction, opts?: ParseOptions): ParseEntry[];
17
+ export declare function parse<T extends object | string>(s: string, env: (key: string) => T | undefined, opts?: ParseOptions): (ParseEntry | T)[];
18
+ export {};
19
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../../source/utils/bash/parse.ts"],"names":[],"mappings":"AA+BA,UAAU,eAAe;IACvB,EAAE,EACE,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,KAAK,GACL,IAAI,GACJ,IAAI,GACJ,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,CAAC;CACT;AAED,UAAU,YAAY;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,KAAK,UAAU,GAAG,MAAM,GAAG,eAAe,GAAG,YAAY,GAAG,eAAe,CAAC;AAE5E,UAAU,YAAY;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,KAAK,WAAW,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;AA8L5C,wBAAgB,KAAK,CACnB,CAAC,EAAE,MAAM,EACT,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,WAAW,EACtD,IAAI,CAAC,EAAE,YAAY,GAClB,UAAU,EAAE,CAAC;AAChB,wBAAgB,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EAC7C,CAAC,EAAE,MAAM,EACT,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,CAAC,GAAG,SAAS,EACnC,IAAI,CAAC,EAAE,YAAY,GAClB,CAAC,UAAU,GAAG,CAAC,CAAC,EAAE,CAAC"}
@@ -0,0 +1,223 @@
1
+ // '<(' is process substitution operator and
2
+ // can be parsed the same as control operator
3
+ const CONTROL = `(?:${[
4
+ "\\|\\|",
5
+ "\\&\\&",
6
+ ";;",
7
+ "\\|\\&",
8
+ "\\<\\(",
9
+ "\\<\\<\\<",
10
+ ">>",
11
+ ">\\&",
12
+ "<\\&",
13
+ "[&;()|<>]",
14
+ ].join("|")})`;
15
+ const controlRe = new RegExp(`^${CONTROL}$`);
16
+ const META = "|&;()<> \t";
17
+ const SINGLE_QUOTE = '"((\\\\"|[^"])*?)"';
18
+ const DOUBLE_QUOTE = "'((\\\\'|[^'])*?)'";
19
+ const hash = /^#$/;
20
+ const SQ = "'";
21
+ const DQ = '"';
22
+ const DS = "$";
23
+ let Token = "";
24
+ const mult = 0x100000000; // Math.pow(16, 8);
25
+ for (let i = 0; i < 4; i++) {
26
+ Token += (mult * Math.random()).toString(16);
27
+ }
28
+ const startsWithToken = new RegExp(`^${Token}`);
29
+ function matchAll(s, r) {
30
+ const origIndex = r.lastIndex;
31
+ const matches = [];
32
+ let matchObj = r.exec(s);
33
+ while (matchObj !== null) {
34
+ matches.push(matchObj);
35
+ if (r.lastIndex === matchObj.index) {
36
+ r.lastIndex += 1;
37
+ }
38
+ matchObj = r.exec(s);
39
+ }
40
+ r.lastIndex = origIndex;
41
+ return matches;
42
+ }
43
+ function getVar(env, pre, key) {
44
+ let r = typeof env === "function" ? env(key) : env[key];
45
+ if (typeof r === "undefined" && key !== "") {
46
+ r = "";
47
+ }
48
+ else if (typeof r === "undefined") {
49
+ r = "$";
50
+ }
51
+ if (typeof r === "object") {
52
+ return pre + Token + JSON.stringify(r) + Token;
53
+ }
54
+ return pre + String(r);
55
+ }
56
+ function parseInternal(string, env, opts = {}) {
57
+ const Bs = opts.escape || "\\";
58
+ const Bareword = `(\\${Bs}["'${META}]|[^\\s'""${META}])+`;
59
+ const chunker = new RegExp([
60
+ `(${CONTROL})`, // control chars
61
+ `(${Bareword}|${SINGLE_QUOTE}|${DOUBLE_QUOTE})+`,
62
+ ].join("|"), "g");
63
+ const matches = matchAll(string, chunker);
64
+ if (matches.length === 0) {
65
+ return [];
66
+ }
67
+ const envToUse = env ?? {};
68
+ let commented = false;
69
+ return matches
70
+ .map(
71
+ // biome-ignore lint:noExcessiveCognitiveComplexity
72
+ (match) => {
73
+ const s = match[0];
74
+ if (!s || commented) {
75
+ return undefined;
76
+ }
77
+ if (controlRe.test(s)) {
78
+ return { op: s };
79
+ }
80
+ // Hand-written scanner/parser for Bash quoting rules:
81
+ //
82
+ // 1. inside single quotes, all characters are printed literally.
83
+ // 2. inside double quotes, all characters are printed literally
84
+ // except variables prefixed by '$' and backslashes followed by
85
+ // either a double quote or another backslash.
86
+ // 3. outside of any quotes, backslashes are treated as escape
87
+ // characters and not printed (unless they are themselves escaped)
88
+ // 4. quote context can switch mid-token if there is no whitespace
89
+ // between the two quote contexts (e.g. all'one'"token" parses as
90
+ // "allonetoken")
91
+ let quote = false;
92
+ let esc = false;
93
+ let out = "";
94
+ let isGlob = false;
95
+ let i = 0;
96
+ function parseEnvVar() {
97
+ i += 1;
98
+ let varend;
99
+ let varname;
100
+ const char = s.charAt(i);
101
+ if (char === "{") {
102
+ i += 1;
103
+ if (s.charAt(i) === "}") {
104
+ throw new Error(`Bad substitution: ${s.slice(i - 2, i + 1)}`);
105
+ }
106
+ varend = s.indexOf("}", i);
107
+ if (varend < 0) {
108
+ throw new Error(`Bad substitution: ${s.slice(i)}`);
109
+ }
110
+ varname = s.slice(i, varend);
111
+ i = varend;
112
+ }
113
+ else if (/[*@#?$!_-]/.test(char)) {
114
+ varname = char;
115
+ i += 1;
116
+ }
117
+ else {
118
+ const slicedFromI = s.slice(i);
119
+ const varendMatch = slicedFromI.match(/[^\w\d_]/);
120
+ if (!varendMatch) {
121
+ varname = slicedFromI;
122
+ i = s.length;
123
+ }
124
+ else {
125
+ varname = slicedFromI.slice(0, varendMatch.index);
126
+ i += (varendMatch.index ?? 0) - 1;
127
+ }
128
+ }
129
+ return getVar(envToUse, "", varname);
130
+ }
131
+ for (i = 0; i < s.length; i++) {
132
+ const c = s.charAt(i);
133
+ isGlob = isGlob || (!quote && (c === "*" || c === "?"));
134
+ if (esc) {
135
+ out += c;
136
+ esc = false;
137
+ }
138
+ else if (quote) {
139
+ if (c === quote) {
140
+ quote = false;
141
+ }
142
+ else if (quote === SQ) {
143
+ out += c;
144
+ }
145
+ else {
146
+ // Double quote
147
+ if (c === Bs) {
148
+ i += 1;
149
+ const charAtI = s.charAt(i);
150
+ if (charAtI === DQ || charAtI === Bs || charAtI === DS) {
151
+ out += charAtI;
152
+ }
153
+ else {
154
+ out += Bs + charAtI;
155
+ }
156
+ }
157
+ else if (c === DS) {
158
+ out += parseEnvVar();
159
+ }
160
+ else {
161
+ out += c;
162
+ }
163
+ }
164
+ }
165
+ else if (c === DQ || c === SQ) {
166
+ quote = c;
167
+ }
168
+ else if (controlRe.test(c)) {
169
+ return { op: s };
170
+ }
171
+ else if (hash.test(c)) {
172
+ commented = true;
173
+ const matchIndex = match.index;
174
+ const commentObj = {
175
+ comment: string.slice((matchIndex ?? 0) + i + 1),
176
+ };
177
+ if (out.length) {
178
+ return [out, commentObj];
179
+ }
180
+ return [commentObj];
181
+ }
182
+ else if (c === Bs) {
183
+ esc = true;
184
+ }
185
+ else if (c === DS) {
186
+ out += parseEnvVar();
187
+ }
188
+ else {
189
+ out += c;
190
+ }
191
+ }
192
+ if (isGlob) {
193
+ return { op: "glob", pattern: out };
194
+ }
195
+ return out;
196
+ })
197
+ .reduce((prev, arg) => {
198
+ // TODO: replace this whole reduce with a concat
199
+ return typeof arg === "undefined" ? prev : prev.concat(arg);
200
+ }, []);
201
+ }
202
+ export function parse(s, env = {}, opts) {
203
+ const mapped = parseInternal(s, env, opts);
204
+ if (typeof env !== "function") {
205
+ return mapped;
206
+ }
207
+ return mapped.reduce((acc, s) => {
208
+ if (typeof s === "object") {
209
+ return acc.concat(s);
210
+ }
211
+ const xs = s.split(RegExp(`(${Token}.*?${Token})`, "g"));
212
+ if (xs.length === 1) {
213
+ return acc.concat(xs[0]);
214
+ }
215
+ return acc.concat(xs.filter(Boolean).map((x) => {
216
+ if (startsWithToken.test(x)) {
217
+ const parts = x.split(Token);
218
+ return JSON.parse(parts[1]);
219
+ }
220
+ return x;
221
+ }));
222
+ }, []);
223
+ }
@@ -0,0 +1,6 @@
1
+ type QuoteArg = string | number | boolean | {
2
+ op: string;
3
+ } | null | undefined;
4
+ export declare function quote(xs: readonly QuoteArg[]): string;
5
+ export {};
6
+ //# sourceMappingURL=quote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quote.d.ts","sourceRoot":"","sources":["../../../source/utils/bash/quote.ts"],"names":[],"mappings":"AAAA,KAAK,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,CAAC;AAE9E,wBAAgB,KAAK,CAAC,EAAE,EAAE,SAAS,QAAQ,EAAE,GAAG,MAAM,CAyBrD"}
@@ -0,0 +1,23 @@
1
+ export function quote(xs) {
2
+ return xs
3
+ .map((s) => {
4
+ if (s === null || s === undefined) {
5
+ return String(s);
6
+ }
7
+ const str = String(s);
8
+ if (str === "") {
9
+ return "''";
10
+ }
11
+ if (s && typeof s === "object") {
12
+ return s.op.replace(/(.)/g, "\\$1");
13
+ }
14
+ if (/["\s\\]/.test(str) && !/'/.test(str)) {
15
+ return `'${str.replace(/(['])/g, "\\$1")}'`;
16
+ }
17
+ if (/["'\s]/.test(str)) {
18
+ return `"${str.replace(/(["\\$`!])/g, "\\$1")}"`;
19
+ }
20
+ return str.replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@[\\\]^`{|}])/g, "$1\\$2");
21
+ })
22
+ .join(" ");
23
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../source/utils/bash.ts"],"names":[],"mappings":"AAMA,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EAAE,EACrB,GAAG,EAAE,MAAM,GACV;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CA0EtC;AAED,eAAO,MAAM,UAAU,GACrB,UAAU,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,YAAY,MAAM,EAClB,cAAc,MAAM,EAAE,KACrB,MAkEF,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,YAAY,MAAM,KAAG,OAmHtD,CAAC"}
1
+ {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../source/utils/bash.ts"],"names":[],"mappings":"AAuJA,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EAAE,EACrB,GAAG,EAAE,MAAM,GACV;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAiDtC;AAED,eAAO,MAAM,UAAU,GACrB,UAAU,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,YAAY,MAAM,EAClB,cAAc,MAAM,EAAE,KACrB,MAkEF,CAAC;AA6FF,eAAO,MAAM,iBAAiB,GAAI,YAAY,MAAM,KAAG,OAetD,CAAC"}