@opencode-ai/core 0.0.0-beta-18314 → 0.0.0-beta-18381

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 (779) hide show
  1. package/dist/account/sql.js +2 -2
  2. package/dist/agent.js +70 -70
  3. package/dist/aisdk-native.js +3 -3
  4. package/dist/aisdk.js +4 -4
  5. package/dist/app.js +2 -2
  6. package/dist/bus.js +68 -68
  7. package/dist/catalog.js +78 -78
  8. package/dist/chunks/{job-emgtfyfk.js → snapshot-00adz425.js} +6 -6
  9. package/dist/chunks/{job-02dbfq60.js → snapshot-02dbfq60.js} +1 -1
  10. package/dist/chunks/{job-9mhxn888.js → snapshot-03r4d3d7.js} +5 -5
  11. package/dist/chunks/{job-s3g94pz9.js → snapshot-03say0j6.js} +2 -2
  12. package/dist/chunks/{job-j1v3cm3s.js → snapshot-08757z4f.js} +3 -3
  13. package/dist/chunks/{job-swfajvmq.js → snapshot-08c11tpd.js} +10 -15
  14. package/dist/chunks/{job-q7kxpbqj.js → snapshot-0hz0tmad.js} +13 -13
  15. package/dist/chunks/{job-0kvmztkf.js → snapshot-0kvmztkf.js} +1 -1
  16. package/dist/chunks/{job-gv594dge.js → snapshot-0y8axsp8.js} +10 -14
  17. package/dist/chunks/{job-htvrdb86.js → snapshot-14b3y37g.js} +3 -3
  18. package/dist/chunks/{job-18pv8fg3.js → snapshot-18pv8fg3.js} +2 -2
  19. package/dist/chunks/{job-dw0e6gqz.js → snapshot-196w4y04.js} +58 -52
  20. package/dist/chunks/{job-41j8xasw.js → snapshot-1dysp5zg.js} +7 -7
  21. package/dist/chunks/{job-a72jeb24.js → snapshot-1p81j20r.js} +3 -3
  22. package/dist/chunks/{job-8c81waph.js → snapshot-1we70vc5.js} +10 -10
  23. package/dist/chunks/{job-vkvb1sb3.js → snapshot-29n7vfk2.js} +2 -1
  24. package/dist/chunks/{job-cz3dkvcz.js → snapshot-2m0hgr65.js} +6 -4
  25. package/dist/chunks/{job-cms3avjt.js → snapshot-2m73nq4z.js} +5 -5
  26. package/dist/chunks/{job-2nmyybe0.js → snapshot-2nmyybe0.js} +1 -1
  27. package/dist/chunks/{job-tqk65e1r.js → snapshot-2rdjsnre.js} +13 -13
  28. package/dist/chunks/{job-2wds5nk3.js → snapshot-2wds5nk3.js} +1 -1
  29. package/dist/chunks/{job-xw73njnh.js → snapshot-2x3r6x66.js} +22 -16
  30. package/dist/chunks/{job-d1sq95z9.js → snapshot-2xwhcp5e.js} +2 -2
  31. package/dist/chunks/{job-x92gabff.js → snapshot-3d9nr5nj.js} +6 -6
  32. package/dist/chunks/{job-by1b88kn.js → snapshot-3dap0q13.js} +15 -20
  33. package/dist/chunks/{job-3g8vftxb.js → snapshot-3g8vftxb.js} +2 -2
  34. package/dist/chunks/snapshot-3kdy3jz5.js +209 -0
  35. package/dist/chunks/{job-3qv8nf0b.js → snapshot-3qv8nf0b.js} +1 -1
  36. package/dist/chunks/{job-3thh6229.js → snapshot-3thh6229.js} +2 -2
  37. package/dist/chunks/{job-v3tbrwy6.js → snapshot-3x74d76a.js} +13 -20
  38. package/dist/chunks/{job-g0ms0rgy.js → snapshot-3zx24fbc.js} +4 -4
  39. package/dist/chunks/{job-awxbz613.js → snapshot-45y5aksg.js} +8 -8
  40. package/dist/chunks/{job-y5w7j7k0.js → snapshot-47ynegsy.js} +9 -9
  41. package/dist/chunks/{job-4s2xwh5d.js → snapshot-4s2xwh5d.js} +3 -3
  42. package/dist/chunks/{job-4zzdwbaz.js → snapshot-4zzdwbaz.js} +2 -2
  43. package/dist/chunks/{job-50jxp3hw.js → snapshot-50jxp3hw.js} +1 -1
  44. package/dist/chunks/{job-bt5jq058.js → snapshot-51nh63zp.js} +4 -4
  45. package/dist/chunks/{job-57tzwnz4.js → snapshot-57tzwnz4.js} +1 -1
  46. package/dist/chunks/{job-58xdvehb.js → snapshot-58xdvehb.js} +1 -1
  47. package/dist/chunks/{job-e023xh4m.js → snapshot-5a713ksd.js} +3 -3
  48. package/dist/chunks/{job-5cdnkd94.js → snapshot-5cdnkd94.js} +3 -3
  49. package/dist/chunks/{job-5fe026tx.js → snapshot-5fe026tx.js} +3 -3
  50. package/dist/chunks/{job-v87jc5jg.js → snapshot-5mjnegmn.js} +2 -2
  51. package/dist/chunks/{job-v3wya5xh.js → snapshot-5rnr84zy.js} +6 -6
  52. package/dist/chunks/{job-5rs65q6p.js → snapshot-5rs65q6p.js} +1 -1
  53. package/dist/chunks/{job-5vcssjzn.js → snapshot-5vcssjzn.js} +1 -1
  54. package/dist/chunks/{job-5z4zwtb4.js → snapshot-5z4zwtb4.js} +2 -2
  55. package/dist/chunks/{job-6272rtjg.js → snapshot-6272rtjg.js} +1 -1
  56. package/dist/chunks/{job-m1ey0mfv.js → snapshot-63vvna7k.js} +6 -6
  57. package/dist/chunks/{job-x2yhhk3x.js → snapshot-6fw15jmf.js} +7 -7
  58. package/dist/chunks/{job-6ky7rqk7.js → snapshot-6ky7rqk7.js} +1 -1
  59. package/dist/chunks/{job-ykhdtytp.js → snapshot-6qkbdayr.js} +48 -72
  60. package/dist/chunks/{job-80f2pyxq.js → snapshot-6s25njgp.js} +35 -33
  61. package/dist/chunks/{job-fcrk6m2k.js → snapshot-6tp65bqk.js} +4 -4
  62. package/dist/chunks/{job-6wkzvma0.js → snapshot-6wkzvma0.js} +2 -2
  63. package/dist/chunks/{job-vjt1s33f.js → snapshot-74ve57mp.js} +8 -8
  64. package/dist/chunks/{job-75h1hfe2.js → snapshot-75h1hfe2.js} +2 -2
  65. package/dist/chunks/{job-22mtntar.js → snapshot-7crkfncx.js} +5 -5
  66. package/dist/chunks/{job-7gqqz1s8.js → snapshot-7gqqz1s8.js} +1 -1
  67. package/dist/chunks/{job-80h0mrdr.js → snapshot-7h4d1ktr.js} +18 -24
  68. package/dist/chunks/{job-7khw64yh.js → snapshot-7khw64yh.js} +1 -1
  69. package/dist/chunks/{job-7mrpdsq5.js → snapshot-7mrpdsq5.js} +1 -1
  70. package/dist/chunks/{job-7thnevmq.js → snapshot-7thnevmq.js} +2 -2
  71. package/dist/chunks/{job-7wcmqxrc.js → snapshot-7wcmqxrc.js} +1 -1
  72. package/dist/chunks/{job-88jbfw8z.js → snapshot-88jbfw8z.js} +2 -2
  73. package/dist/chunks/{job-3675e63x.js → snapshot-89hw1mvm.js} +5 -5
  74. package/dist/chunks/{job-f5btf568.js → snapshot-8ken28ys.js} +15 -17
  75. package/dist/chunks/{job-c8k88b24.js → snapshot-8mfwtbzr.js} +37 -37
  76. package/dist/chunks/{job-8pngjawd.js → snapshot-8pngjawd.js} +2 -2
  77. package/dist/chunks/snapshot-8tv6syt7.js +46 -0
  78. package/dist/chunks/{job-g2rkrtc7.js → snapshot-8yrf0jrn.js} +9 -9
  79. package/dist/chunks/{job-4nvjkpcc.js → snapshot-8zdj5g8w.js} +5 -5
  80. package/dist/chunks/{job-999qd968.js → snapshot-999qd968.js} +1 -1
  81. package/dist/chunks/{job-9f0rnpkn.js → snapshot-9f0rnpkn.js} +1 -1
  82. package/dist/chunks/{job-0b17sr9d.js → snapshot-a09abg6q.js} +11 -14
  83. package/dist/chunks/{job-h846wrk2.js → snapshot-a9vdgkgd.js} +1 -1
  84. package/dist/chunks/{job-979eqq1k.js → snapshot-adhhpzkf.js} +15 -15
  85. package/dist/chunks/{job-t2nhz694.js → snapshot-avxmjs7d.js} +3 -3
  86. package/dist/chunks/{job-awg5d31a.js → snapshot-awg5d31a.js} +1 -1
  87. package/dist/chunks/{job-ejc7zsyk.js → snapshot-beenkza5.js} +3 -3
  88. package/dist/chunks/{job-bh1wr8rq.js → snapshot-bh1wr8rq.js} +2 -2
  89. package/dist/chunks/{job-mmg6vxx4.js → snapshot-bje3p123.js} +9 -9
  90. package/dist/chunks/{job-hh1wpw8n.js → snapshot-bk64s4dd.js} +2 -2
  91. package/dist/chunks/{job-bmknfyv0.js → snapshot-bmknfyv0.js} +2 -2
  92. package/dist/chunks/{job-56th4kc6.js → snapshot-bq0z9m2s.js} +3 -3
  93. package/dist/chunks/{job-byab506k.js → snapshot-byab506k.js} +1 -1
  94. package/dist/chunks/{job-b517em9p.js → snapshot-c0s2ts20.js} +10 -10
  95. package/dist/chunks/{job-594xzh81.js → snapshot-c4sv2ydx.js} +9 -9
  96. package/dist/chunks/{job-c4wcb9vc.js → snapshot-c4wcb9vc.js} +2 -2
  97. package/dist/chunks/{job-gv6vfy44.js → snapshot-c5r7nv49.js} +91 -91
  98. package/dist/chunks/{job-kw1zvwxg.js → snapshot-c5whbqdw.js} +7 -7
  99. package/dist/chunks/{job-wvkyq8sh.js → snapshot-ckmbwzgz.js} +5 -5
  100. package/dist/chunks/{job-m28e25wx.js → snapshot-cnee8f6y.js} +3 -3
  101. package/dist/chunks/{job-4b29ngba.js → snapshot-cp2m8bkb.js} +76 -31
  102. package/dist/chunks/{job-csrx180a.js → snapshot-csrx180a.js} +3 -3
  103. package/dist/chunks/{job-eb5hn8c3.js → snapshot-cver0dzq.js} +5 -5
  104. package/dist/chunks/{job-7y1ge8cm.js → snapshot-cvh07btz.js} +3 -3
  105. package/dist/chunks/{job-d2gk9vpf.js → snapshot-d2gk9vpf.js} +2 -2
  106. package/dist/chunks/{job-1v8zr5j1.js → snapshot-d2nk018e.js} +3 -3
  107. package/dist/chunks/{job-d4ax61k3.js → snapshot-d4ax61k3.js} +2 -2
  108. package/dist/chunks/{job-1fs6j1ee.js → snapshot-d9s19t2a.js} +10 -10
  109. package/dist/chunks/{job-s5s19g76.js → snapshot-dcerdtt9.js} +18 -67
  110. package/dist/chunks/{job-dhphtf1x.js → snapshot-dhphtf1x.js} +1 -1
  111. package/dist/chunks/{job-evme9j8h.js → snapshot-djs34hbz.js} +10 -10
  112. package/dist/chunks/{job-xhmx5xme.js → snapshot-drw2awgz.js} +2 -2
  113. package/dist/chunks/{job-cy8yjam4.js → snapshot-dwhqy6ej.js} +5 -5
  114. package/dist/chunks/{job-e6tqds24.js → snapshot-e1qk74dz.js} +7 -7
  115. package/dist/chunks/{job-e1z9a0ts.js → snapshot-e1z9a0ts.js} +2 -2
  116. package/dist/chunks/{job-6g380kj4.js → snapshot-e49v8j09.js} +9 -9
  117. package/dist/chunks/{job-9fke2v0v.js → snapshot-e6e4xn73.js} +4 -4
  118. package/dist/chunks/{job-bpfzp1b4.js → snapshot-eac0r68y.js} +22 -22
  119. package/dist/chunks/{job-ec8vrfw5.js → snapshot-ec8vrfw5.js} +1 -1
  120. package/dist/chunks/{job-d10138fy.js → snapshot-ee64mkrs.js} +12 -12
  121. package/dist/chunks/{job-efjyazj3.js → snapshot-efy08wzy.js} +11 -11
  122. package/dist/chunks/{job-enpg66yn.js → snapshot-enpg66yn.js} +1 -1
  123. package/dist/chunks/{job-87s75dvv.js → snapshot-f3p3rja9.js} +3 -3
  124. package/dist/chunks/{job-7ccgh94t.js → snapshot-f7q7a28y.js} +6 -6
  125. package/dist/chunks/{job-f9wt0tjw.js → snapshot-f9wt0tjw.js} +2 -2
  126. package/dist/chunks/{job-fb7nfzf2.js → snapshot-fb7nfzf2.js} +3 -3
  127. package/dist/chunks/{job-fgyjabww.js → snapshot-fgyjabww.js} +2 -2
  128. package/dist/chunks/{job-j3qn6z6c.js → snapshot-fmrrpnd6.js} +148 -148
  129. package/dist/chunks/{job-0b0fh8m6.js → snapshot-gap8nnk0.js} +6 -6
  130. package/dist/chunks/{job-gcay93cp.js → snapshot-gcay93cp.js} +1 -1
  131. package/dist/chunks/{job-gd2xppx8.js → snapshot-gd2xppx8.js} +1 -1
  132. package/dist/chunks/{job-qtwj4sct.js → snapshot-gj5b7zp8.js} +3 -3
  133. package/dist/chunks/{job-hqh8yks9.js → snapshot-gp6nnez7.js} +3 -3
  134. package/dist/chunks/{job-90zewg12.js → snapshot-gpy2ty3t.js} +5 -5
  135. package/dist/chunks/{job-gpybhmhb.js → snapshot-gpybhmhb.js} +3 -3
  136. package/dist/chunks/{job-f7x4n10r.js → snapshot-gy96pty5.js} +10 -10
  137. package/dist/chunks/{job-h12kt9pa.js → snapshot-h12kt9pa.js} +2 -2
  138. package/dist/chunks/{job-h94zdhz8.js → snapshot-h94zdhz8.js} +2 -2
  139. package/dist/chunks/{job-gfk86902.js → snapshot-h9jqdjpr.js} +5 -5
  140. package/dist/chunks/{job-x4fa0s7b.js → snapshot-hed1mxmy.js} +3 -3
  141. package/dist/chunks/{job-pff6q9k0.js → snapshot-hntswt6m.js} +4 -4
  142. package/dist/chunks/{job-hp6rpdnc.js → snapshot-hp6rpdnc.js} +1 -1
  143. package/dist/chunks/{job-zvcgsh8t.js → snapshot-hym5c3c0.js} +14 -14
  144. package/dist/chunks/{job-66kns9ss.js → snapshot-j37e0edx.js} +9 -9
  145. package/dist/chunks/{job-gyaadd27.js → snapshot-jcx5349t.js} +5 -5
  146. package/dist/chunks/{job-k42t1tha.js → snapshot-k42t1tha.js} +2 -2
  147. package/dist/chunks/{job-p7khmdc5.js → snapshot-k5fakw8s.js} +4 -4
  148. package/dist/chunks/{job-jwgf44xz.js → snapshot-kaw593bn.js} +4 -4
  149. package/dist/chunks/{job-kg1345f7.js → snapshot-kg1345f7.js} +1 -1
  150. package/dist/chunks/{job-kp1t5rcy.js → snapshot-kp1t5rcy.js} +1 -1
  151. package/dist/chunks/{job-krsqcmnj.js → snapshot-krsqcmnj.js} +1 -1
  152. package/dist/chunks/{job-v3mckd1j.js → snapshot-krxnrwxf.js} +6 -6
  153. package/dist/chunks/{job-30cqtyfe.js → snapshot-kwb0smgr.js} +3 -3
  154. package/dist/chunks/{job-zgj06aq9.js → snapshot-m4ywk5sr.js} +9 -9
  155. package/dist/chunks/{job-m55whf0h.js → snapshot-m55whf0h.js} +2 -2
  156. package/dist/chunks/{job-mf0hyk7z.js → snapshot-mf0hyk7z.js} +1 -1
  157. package/dist/chunks/{job-f4kwr62g.js → snapshot-mfjsqksh.js} +8 -8
  158. package/dist/chunks/{job-mh28new4.js → snapshot-mh28new4.js} +2 -2
  159. package/dist/chunks/{job-j5q8scqt.js → snapshot-mkaeg0rc.js} +8 -8
  160. package/dist/chunks/{job-hfrn4x7x.js → snapshot-mm5bk5a9.js} +6 -6
  161. package/dist/chunks/{job-mnb85w6b.js → snapshot-mnb85w6b.js} +2 -2
  162. package/dist/chunks/snapshot-msys3ym3.js +324 -0
  163. package/dist/chunks/{job-tb33ng7x.js → snapshot-mw2kp8b7.js} +107 -35
  164. package/dist/chunks/{job-c6agw9t5.js → snapshot-mwb02z4x.js} +16 -16
  165. package/dist/chunks/{job-mxvw03gv.js → snapshot-mxvw03gv.js} +1 -1
  166. package/dist/chunks/snapshot-n5wwh254.js +341 -0
  167. package/dist/chunks/{job-j624ajjr.js → snapshot-n8tkcj0b.js} +63 -63
  168. package/dist/chunks/{job-jg0n1jjh.js → snapshot-ncenzm7w.js} +5 -5
  169. package/dist/chunks/{job-nesb2rcz.js → snapshot-nesb2rcz.js} +2 -2
  170. package/dist/chunks/{job-nr76rjj3.js → snapshot-nr76rjj3.js} +2 -2
  171. package/dist/chunks/{job-kj73zjy7.js → snapshot-ns5zakmm.js} +3 -3
  172. package/dist/chunks/{job-ambzzkps.js → snapshot-nsb760q1.js} +8 -8
  173. package/dist/chunks/{job-mqanfv2e.js → snapshot-nshjhgk3.js} +4 -4
  174. package/dist/chunks/{job-nzrjycs5.js → snapshot-nzrjycs5.js} +1 -1
  175. package/dist/chunks/{job-jtsr1kyk.js → snapshot-p62hky5s.js} +4 -4
  176. package/dist/chunks/{job-03svsmyg.js → snapshot-p7kv2p3m.js} +14 -14
  177. package/dist/chunks/{job-6q0m15b3.js → snapshot-p8fr6x1v.js} +2 -2
  178. package/dist/chunks/{job-am5pnytv.js → snapshot-pbrtg6rm.js} +59 -59
  179. package/dist/chunks/{job-j2rwtkhe.js → snapshot-pdp9vdkd.js} +4 -4
  180. package/dist/chunks/{job-18bpd5mk.js → snapshot-pkm79cpk.js} +4 -4
  181. package/dist/chunks/{job-8za0sdpt.js → snapshot-pn6jhed5.js} +4 -4
  182. package/dist/chunks/{job-pq4b4pqk.js → snapshot-pq4b4pqk.js} +2 -2
  183. package/dist/chunks/{job-74sy20v2.js → snapshot-prx0wmsc.js} +85 -26
  184. package/dist/chunks/{job-r673n5v1.js → snapshot-pts35d3y.js} +10 -10
  185. package/dist/chunks/{job-6cb4pvvr.js → snapshot-pv38wsrj.js} +8 -8
  186. package/dist/chunks/{job-tmrzx1y1.js → snapshot-q5hvgavd.js} +7 -7
  187. package/dist/chunks/{job-q9b4qnv8.js → snapshot-q9b4qnv8.js} +2 -2
  188. package/dist/chunks/{job-qe0d689s.js → snapshot-qe0d689s.js} +2 -2
  189. package/dist/chunks/{job-x2zfy610.js → snapshot-qh9gbvw6.js} +9 -9
  190. package/dist/chunks/{job-wey5vt6z.js → snapshot-qrhnghma.js} +5 -5
  191. package/dist/chunks/{job-9v8sftqd.js → snapshot-qy7rwb66.js} +2 -2
  192. package/dist/chunks/{job-r13w8t0w.js → snapshot-r13w8t0w.js} +2 -2
  193. package/dist/chunks/{job-r3k9abhd.js → snapshot-r3k9abhd.js} +2 -2
  194. package/dist/chunks/{job-rahat93a.js → snapshot-rahat93a.js} +1 -1
  195. package/dist/chunks/{job-rameyvmv.js → snapshot-rameyvmv.js} +1 -1
  196. package/dist/chunks/{job-rbnp2c85.js → snapshot-rbnp2c85.js} +3 -3
  197. package/dist/chunks/{job-gcvth7mt.js → snapshot-rcenkehz.js} +6 -6
  198. package/dist/chunks/{job-rfbm65k8.js → snapshot-rfbm65k8.js} +1 -1
  199. package/dist/chunks/{job-x7gtn86w.js → snapshot-rrcg29fs.js} +13 -13
  200. package/dist/chunks/{job-se1aqaya.js → snapshot-rt37qqhk.js} +4 -3
  201. package/dist/chunks/{job-xs1a0k5e.js → snapshot-s2y2bmcn.js} +3 -3
  202. package/dist/chunks/{job-s33fw6zm.js → snapshot-s33fw6zm.js} +1 -1
  203. package/dist/chunks/{job-qdd4e9kv.js → snapshot-s7252bet.js} +10 -10
  204. package/dist/chunks/{job-sysphzh2.js → snapshot-s84e4gf4.js} +1 -1
  205. package/dist/chunks/{job-453chyz6.js → snapshot-s8kt5tga.js} +3 -3
  206. package/dist/chunks/{job-smpeg8c9.js → snapshot-smpeg8c9.js} +2 -2
  207. package/dist/chunks/{job-sw84ckhj.js → snapshot-sw84ckhj.js} +1 -1
  208. package/dist/chunks/{job-t14kykx1.js → snapshot-t14kykx1.js} +1 -1
  209. package/dist/chunks/{job-6y125m49.js → snapshot-t1r7k897.js} +6 -6
  210. package/dist/chunks/{job-kqp51j35.js → snapshot-tabz4g6h.js} +2 -2
  211. package/dist/chunks/{job-tcptxgyq.js → snapshot-tcptxgyq.js} +1 -1
  212. package/dist/chunks/{job-0wfeztgd.js → snapshot-tfprkz91.js} +4 -4
  213. package/dist/chunks/{job-tgbb2ckq.js → snapshot-tgbb2ckq.js} +2 -2
  214. package/dist/chunks/{job-emcftcn6.js → snapshot-tgx8ecrw.js} +4 -4
  215. package/dist/chunks/{job-thstd87d.js → snapshot-thstd87d.js} +1 -1
  216. package/dist/chunks/{job-v2wshkax.js → snapshot-v2wshkax.js} +1 -1
  217. package/dist/chunks/{job-v80zsxnb.js → snapshot-v80zsxnb.js} +1 -1
  218. package/dist/chunks/{job-v972xay6.js → snapshot-v972xay6.js} +1 -1
  219. package/dist/chunks/{job-v9bfv94f.js → snapshot-v9bfv94f.js} +1 -1
  220. package/dist/chunks/{job-vcwr2vpf.js → snapshot-vcwr2vpf.js} +1 -1
  221. package/dist/chunks/{job-83vq7eg1.js → snapshot-vgtdbe2x.js} +8 -8
  222. package/dist/chunks/{job-vqbmgfq1.js → snapshot-vqbmgfq1.js} +3 -3
  223. package/dist/chunks/{job-9fxjt5sk.js → snapshot-vycjsnjm.js} +17 -29
  224. package/dist/chunks/{job-vz89hfgr.js → snapshot-vz89hfgr.js} +1 -1
  225. package/dist/chunks/{job-szy0yc2m.js → snapshot-w7wsm18c.js} +3 -3
  226. package/dist/chunks/{job-wbkt8qpj.js → snapshot-wbkt8qpj.js} +1 -1
  227. package/dist/chunks/{job-752hq4tr.js → snapshot-wbt7vheq.js} +5 -5
  228. package/dist/chunks/{job-wd268jeg.js → snapshot-wd268jeg.js} +1 -1
  229. package/dist/chunks/{job-efh129a7.js → snapshot-wd9wya43.js} +3 -3
  230. package/dist/chunks/{job-whk0g8cz.js → snapshot-whk0g8cz.js} +4 -4
  231. package/dist/chunks/{job-gkwa729k.js → snapshot-wj1cy6w2.js} +4 -4
  232. package/dist/chunks/{job-7tan8bxz.js → snapshot-wjht6mwf.js} +6 -6
  233. package/dist/chunks/{job-vpex7vrq.js → snapshot-wmv6gawp.js} +20 -20
  234. package/dist/chunks/{job-wmxdh12w.js → snapshot-wmxdh12w.js} +1 -1
  235. package/dist/chunks/{job-wps8gh8n.js → snapshot-wps8gh8n.js} +2 -2
  236. package/dist/chunks/{job-cegwyrsy.js → snapshot-wqnb0rdj.js} +4 -4
  237. package/dist/chunks/{job-4s1gnawc.js → snapshot-wt898ny4.js} +10 -10
  238. package/dist/chunks/{job-5zxzwffr.js → snapshot-wy2qp8gn.js} +7 -7
  239. package/dist/chunks/{job-rf256wce.js → snapshot-wy66qwpc.js} +13 -13
  240. package/dist/chunks/{job-4yxq1tjg.js → snapshot-x2wpvvza.js} +89 -89
  241. package/dist/chunks/{job-dvagncbd.js → snapshot-x4139j55.js} +97 -85
  242. package/dist/chunks/{job-x89rah0x.js → snapshot-x89rah0x.js} +1 -1
  243. package/dist/chunks/{job-xczfw7dq.js → snapshot-xczfw7dq.js} +1 -1
  244. package/dist/chunks/{job-67qnaq06.js → snapshot-xe4vkbsa.js} +5 -5
  245. package/dist/chunks/{job-61ae575p.js → snapshot-xf1x0v67.js} +3 -3
  246. package/dist/chunks/{job-xgv25zxy.js → snapshot-xgv25zxy.js} +1 -1
  247. package/dist/chunks/{job-04cwzwc7.js → snapshot-xkfjdjay.js} +3 -3
  248. package/dist/chunks/{job-xwftk1fd.js → snapshot-xwftk1fd.js} +2 -2
  249. package/dist/chunks/{job-3pa0yq1v.js → snapshot-xxg4gb9n.js} +2 -2
  250. package/dist/chunks/{job-xxpvz42q.js → snapshot-xxpvz42q.js} +3 -3
  251. package/dist/chunks/{job-y0x38cee.js → snapshot-y0x38cee.js} +1 -1
  252. package/dist/chunks/{job-y198y2ra.js → snapshot-y198y2ra.js} +1 -1
  253. package/dist/chunks/{job-f3nzffq3.js → snapshot-y4rqcyeh.js} +4 -4
  254. package/dist/chunks/{job-y67x6rf6.js → snapshot-y67x6rf6.js} +1 -1
  255. package/dist/chunks/{job-y980s7ka.js → snapshot-y980s7ka.js} +3 -3
  256. package/dist/chunks/{job-ybhfpy64.js → snapshot-ybhfpy64.js} +2 -2
  257. package/dist/chunks/{job-yc2vxtaa.js → snapshot-yc2vxtaa.js} +2 -2
  258. package/dist/chunks/{job-yf0knd5z.js → snapshot-yf0knd5z.js} +2 -2
  259. package/dist/chunks/{job-ygy0xbqa.js → snapshot-ygy0xbqa.js} +3 -3
  260. package/dist/chunks/{job-yytvxvcy.js → snapshot-yptp00mq.js} +7 -7
  261. package/dist/chunks/{job-tn0pfbrf.js → snapshot-z9qfd23w.js} +4 -4
  262. package/dist/chunks/{job-zbqqnp0n.js → snapshot-zbqqnp0n.js} +1 -1
  263. package/dist/chunks/{job-zdkg1k91.js → snapshot-zdkg1k91.js} +1 -1
  264. package/dist/chunks/{job-8stkcvkk.js → snapshot-zmrwxzqm.js} +6 -6
  265. package/dist/chunks/{job-ztjk4rav.js → snapshot-ztjk4rav.js} +4 -4
  266. package/dist/chunks/{job-zxcy6vhn.js → snapshot-zxcy6vhn.js} +1 -1
  267. package/dist/chunks/{job-zxe9jjhn.js → snapshot-zxe9jjhn.js} +2 -2
  268. package/dist/chunks/{job-91crht0e.js → snapshot-zzzm04t5.js} +3 -3
  269. package/dist/codemode/catalog.js +2 -2
  270. package/dist/codemode/instructions.js +4 -4
  271. package/dist/codemode/tool.js +3 -3
  272. package/dist/command.js +70 -70
  273. package/dist/config/markdown.js +2 -2
  274. package/dist/config/normalize.js +20 -20
  275. package/dist/config/plugin/agent.js +136 -135
  276. package/dist/config/plugin/command.js +118 -118
  277. package/dist/config/plugin/compaction.js +150 -170
  278. package/dist/config/plugin/entry-observer.js +114 -114
  279. package/dist/config/plugin/formatter.js +119 -119
  280. package/dist/config/plugin/image.js +130 -130
  281. package/dist/config/plugin/instruction.js +90 -90
  282. package/dist/config/plugin/location-watcher.js +117 -117
  283. package/dist/config/plugin/mcp.js +127 -127
  284. package/dist/config/plugin/policy.js +116 -116
  285. package/dist/config/plugin/provider.js +115 -115
  286. package/dist/config/plugin/reference.js +119 -119
  287. package/dist/config/plugin/shell.js +118 -118
  288. package/dist/config/plugin/skill-file.js +109 -108
  289. package/dist/config/plugin/skill.js +139 -138
  290. package/dist/config/plugin/snapshot.js +117 -117
  291. package/dist/config/plugin/source.js +114 -114
  292. package/dist/config/plugin/tool-output.js +119 -119
  293. package/dist/config/plugin/websearch.js +115 -115
  294. package/dist/config/variable.js +4 -4
  295. package/dist/config.js +113 -113
  296. package/dist/credential/sql.js +3 -3
  297. package/dist/credential.js +71 -71
  298. package/dist/database/database.js +65 -65
  299. package/dist/database/drizzle/effect-sqlite/driver.js +13 -13
  300. package/dist/database/drizzle/effect-sqlite/index.js +13 -13
  301. package/dist/database/drizzle/effect-sqlite/session.js +12 -12
  302. package/dist/database/drizzle/index.js +14 -14
  303. package/dist/database/drizzle/internal/drizzle-utils.js +2 -2
  304. package/dist/database/drizzle/sqlite-core/effect/count.js +2 -2
  305. package/dist/database/drizzle/sqlite-core/effect/db.js +10 -10
  306. package/dist/database/drizzle/sqlite-core/effect/delete.js +3 -3
  307. package/dist/database/drizzle/sqlite-core/effect/index.js +17 -17
  308. package/dist/database/drizzle/sqlite-core/effect/insert.js +3 -3
  309. package/dist/database/drizzle/sqlite-core/effect/query.js +2 -2
  310. package/dist/database/drizzle/sqlite-core/effect/raw.js +2 -2
  311. package/dist/database/drizzle/sqlite-core/effect/select.js +3 -3
  312. package/dist/database/drizzle/sqlite-core/effect/session.js +11 -11
  313. package/dist/database/drizzle/sqlite-core/effect/update.js +3 -3
  314. package/dist/database/drizzle.js +15 -15
  315. package/dist/database/migration/20260127222353_familiar_lady_ursula.js +2 -2
  316. package/dist/database/migration/20260211171708_add_project_commands.js +2 -2
  317. package/dist/database/migration/20260213144116_wakeful_the_professor.js +2 -2
  318. package/dist/database/migration/20260225215848_workspace.js +2 -2
  319. package/dist/database/migration/20260227213759_add_session_workspace_id.js +2 -2
  320. package/dist/database/migration/20260228203230_blue_harpoon.js +2 -2
  321. package/dist/database/migration/20260303231226_add_workspace_fields.js +2 -2
  322. package/dist/database/migration/20260309230000_move_org_to_state.js +2 -2
  323. package/dist/database/migration/20260312043431_session_message_cursor.js +2 -2
  324. package/dist/database/migration/20260323234822_events.js +2 -2
  325. package/dist/database/migration/20260410174513_workspace-name.js +2 -2
  326. package/dist/database/migration/20260413175956_chief_energizer.js +2 -2
  327. package/dist/database/migration/20260423070820_add_icon_url_override.js +2 -2
  328. package/dist/database/migration/20260427172553_slow_nightmare.js +2 -2
  329. package/dist/database/migration/20260428004200_add_session_path.js +2 -2
  330. package/dist/database/migration/20260501142318_next_venus.js +2 -2
  331. package/dist/database/migration/20260504145000_add_sync_owner.js +2 -2
  332. package/dist/database/migration/20260507164347_add_workspace_time.js +2 -2
  333. package/dist/database/migration/20260510033149_session_usage.js +2 -2
  334. package/dist/database/migration/20260511000411_data_migration_state.js +2 -2
  335. package/dist/database/migration/20260511173437_session-metadata.js +2 -2
  336. package/dist/database/migration/20260601010001_normalize_storage_paths.js +2 -2
  337. package/dist/database/migration/20260601202201_amazing_prowler.js +2 -2
  338. package/dist/database/migration/20260602002951_lowly_union_jack.js +2 -2
  339. package/dist/database/migration/20260602182828_add_project_directories.js +2 -2
  340. package/dist/database/migration/20260603001617_session_message_projection_indexes.js +2 -2
  341. package/dist/database/migration/20260603040000_session_message_projection_order.js +2 -2
  342. package/dist/database/migration/20260603141458_session_input_inbox.js +2 -2
  343. package/dist/database/migration/20260603160727_jittery_ezekiel_stane.js +2 -2
  344. package/dist/database/migration/20260604172448_event_sourced_session_input.js +2 -2
  345. package/dist/database/migration/20260605003541_add_session_context_snapshot.js +2 -2
  346. package/dist/database/migration/20260605042240_add_context_epoch_agent.js +2 -2
  347. package/dist/database/migration/20260611035744_credential.js +2 -2
  348. package/dist/database/migration/20260611192811_lush_chimera.js +2 -2
  349. package/dist/database/migration/20260612174303_project_dir_strategy.js +2 -2
  350. package/dist/database/migration/20260622142730_simplify_session_context_epoch.js +2 -2
  351. package/dist/database/migration/20260622170816_reset_v2_session_state.js +2 -2
  352. package/dist/database/migration/20260622202450_simplify_session_input.js +2 -2
  353. package/dist/database/migration/20260804233008_loose_psylocke.js +2 -2
  354. package/dist/database/migration/20260805200742_import_legacy_credentials.js +2 -2
  355. package/dist/database/migration/20260808023530_workspace_domain.js +2 -2
  356. package/dist/database/migration/20260811161259_execution_claim_attempts.js +2 -2
  357. package/dist/database/migration/20260812181746_session_inbox.js +2 -2
  358. package/dist/database/migration/20260812213948_worktree.js +2 -2
  359. package/dist/database/migration/20260819222447_session_viewed_state.js +2 -2
  360. package/dist/database/migration/20260823191254_nullable_workspace_binding.js +2 -2
  361. package/dist/database/migration.gen.js +48 -48
  362. package/dist/database/migration.js +50 -50
  363. package/dist/database/path.js +3 -3
  364. package/dist/database/schema.gen.js +2 -2
  365. package/dist/database/schema.sql.js +2 -2
  366. package/dist/database/sqlite.bun.js +2 -2
  367. package/dist/database/sqlite.js +2 -2
  368. package/dist/database/sqlite.node.js +2 -2
  369. package/dist/database/sqlite.workerd.js +2 -2
  370. package/dist/database/v1-migration.bun.js +93 -77
  371. package/dist/database/v1-migration.js +2 -2
  372. package/dist/database/v1-migration.noop.js +1 -1
  373. package/dist/effect/app-node-builder.js +328 -326
  374. package/dist/effect/app-node-platform.js +3 -3
  375. package/dist/effect/keyed-mutex.js +2 -2
  376. package/dist/effect/websocket-constructor.js +2 -2
  377. package/dist/environment/driver.js +1 -1
  378. package/dist/environment/environment.js +91 -91
  379. package/dist/environment/exec-defaults.js +3 -3
  380. package/dist/environment/files.js +2 -2
  381. package/dist/environment/index.js +93 -93
  382. package/dist/environment/local.js +3 -3
  383. package/dist/environment/memory.js +3 -3
  384. package/dist/environment/unavailable.js +1 -1
  385. package/dist/event/sql.js +2 -2
  386. package/dist/event-logger.js +68 -68
  387. package/dist/file-mutation.js +92 -92
  388. package/dist/file-retention.js +2 -2
  389. package/dist/file.js +2 -2
  390. package/dist/filesystem/fff.bun.js +2 -2
  391. package/dist/filesystem/fff.js +2 -2
  392. package/dist/filesystem/fff.node.js +2 -2
  393. package/dist/filesystem/fff.workerd.js +2 -2
  394. package/dist/filesystem/ignore.js +1 -1
  395. package/dist/filesystem/location-watcher-policy.js +3 -3
  396. package/dist/filesystem/location-watcher.js +304 -306
  397. package/dist/filesystem/protected.js +2 -2
  398. package/dist/filesystem/search.js +96 -96
  399. package/dist/filesystem/watcher-binding.js +2 -2
  400. package/dist/filesystem/watcher.js +4 -4
  401. package/dist/filesystem.js +96 -96
  402. package/dist/form.js +69 -69
  403. package/dist/formatter/builtins.js +3 -3
  404. package/dist/formatter.js +85 -85
  405. package/dist/generate.js +84 -84
  406. package/dist/git.js +5 -5
  407. package/dist/github-copilot/chat/convert-to-openai-compatible-chat-messages.js +2 -2
  408. package/dist/github-copilot/chat/get-response-metadata.js +2 -2
  409. package/dist/github-copilot/chat/map-openai-compatible-finish-reason.js +2 -2
  410. package/dist/github-copilot/chat/openai-compatible-chat-language-model.js +8 -8
  411. package/dist/github-copilot/chat/openai-compatible-chat-options.js +2 -2
  412. package/dist/github-copilot/chat/openai-compatible-prepare-tools.js +2 -2
  413. package/dist/github-copilot/copilot-provider.js +18 -18
  414. package/dist/github-copilot/models.js +4 -4
  415. package/dist/github-copilot/openai-compatible-error.js +2 -2
  416. package/dist/github-copilot/responses/convert-to-openai-responses-input.js +2 -2
  417. package/dist/github-copilot/responses/map-openai-responses-finish-reason.js +2 -2
  418. package/dist/github-copilot/responses/openai-error.js +2 -2
  419. package/dist/github-copilot/responses/openai-responses-language-model.js +11 -11
  420. package/dist/github-copilot/responses/openai-responses-prepare-tools.js +7 -7
  421. package/dist/github-copilot/responses/tool/code-interpreter.js +2 -2
  422. package/dist/github-copilot/responses/tool/file-search.js +2 -2
  423. package/dist/github-copilot/responses/tool/image-generation.js +2 -2
  424. package/dist/github-copilot/responses/tool/web-search-preview.js +2 -2
  425. package/dist/github-copilot/responses/tool/web-search.js +2 -2
  426. package/dist/id/id.js +2 -2
  427. package/dist/image/photon-wasm.bun.js +1 -1
  428. package/dist/image/photon-wasm.node.js +1 -1
  429. package/dist/image/photon-wasm.workerd.js +1 -1
  430. package/dist/image/photon.js +98 -98
  431. package/dist/image.js +98 -98
  432. package/dist/instruction-discovery.js +72 -72
  433. package/dist/instructions/builtins.js +86 -86
  434. package/dist/instructions/index.js +2 -2
  435. package/dist/integration/connection.js +2 -2
  436. package/dist/integration.js +75 -75
  437. package/dist/job.js +72 -4
  438. package/dist/kv/sql.js +3 -3
  439. package/dist/kv.js +68 -68
  440. package/dist/location-activity.js +87 -87
  441. package/dist/location-mutation.js +84 -84
  442. package/dist/location-service-map.js +84 -84
  443. package/dist/location-services.js +328 -326
  444. package/dist/location.js +83 -83
  445. package/dist/mcp/client.js +96 -93
  446. package/dist/mcp/index.js +98 -98
  447. package/dist/mcp/instructions.js +129 -128
  448. package/dist/mcp/oauth.js +2 -2
  449. package/dist/mcp/stdio.js +92 -92
  450. package/dist/mime.js +2 -2
  451. package/dist/model-resolver.js +81 -81
  452. package/dist/model.js +3 -3
  453. package/dist/models-dev.js +75 -75
  454. package/dist/oauth/page.js +2 -2
  455. package/dist/permission/saved.js +84 -84
  456. package/dist/permission/sql.js +6 -6
  457. package/dist/permission.js +106 -105
  458. package/dist/persistent-pty/binary.bun.js +2 -2
  459. package/dist/persistent-pty/binary.node.js +1 -1
  460. package/dist/persistent-pty/binary.workerd.js +1 -1
  461. package/dist/persistent-pty/daemon.js +2 -2
  462. package/dist/persistent-pty/index.js +70 -70
  463. package/dist/persistent-pty/pty-binding.js +2 -2
  464. package/dist/persistent-pty.js +70 -70
  465. package/dist/plugin/agent.js +107 -106
  466. package/dist/plugin/command.js +99 -99
  467. package/dist/plugin/hooks.js +3 -3
  468. package/dist/plugin/host.js +171 -170
  469. package/dist/plugin/internal.js +298 -300
  470. package/dist/plugin/mcp-codemode-exclusion.js +2 -2
  471. package/dist/plugin/models-dev.js +76 -76
  472. package/dist/plugin/module.js +3 -3
  473. package/dist/plugin/plan.js +107 -106
  474. package/dist/plugin/promise.js +2 -2
  475. package/dist/plugin/provider/alibaba.js +3 -3
  476. package/dist/plugin/provider/amazon-bedrock.js +3 -3
  477. package/dist/plugin/provider/anthropic.js +3 -3
  478. package/dist/plugin/provider/azure.js +121 -121
  479. package/dist/plugin/provider/cerebras.js +3 -3
  480. package/dist/plugin/provider/cloudflare-ai-gateway.js +122 -122
  481. package/dist/plugin/provider/cloudflare-workers-ai.js +122 -122
  482. package/dist/plugin/provider/cohere.js +3 -3
  483. package/dist/plugin/provider/configured.js +119 -119
  484. package/dist/plugin/provider/dynamic.js +2 -2
  485. package/dist/plugin/provider/factory.js +2 -2
  486. package/dist/plugin/provider/gateway.js +3 -3
  487. package/dist/plugin/provider/github-copilot.js +82 -82
  488. package/dist/plugin/provider/gitlab.js +4 -4
  489. package/dist/plugin/provider/google-vertex.js +3 -3
  490. package/dist/plugin/provider/kilo.js +3 -3
  491. package/dist/plugin/provider/llmgateway.js +77 -77
  492. package/dist/plugin/provider/lmstudio.js +114 -114
  493. package/dist/plugin/provider/mistral.js +3 -3
  494. package/dist/plugin/provider/nvidia.js +3 -3
  495. package/dist/plugin/provider/ollama.js +114 -114
  496. package/dist/plugin/provider/openai-compatible.js +2 -2
  497. package/dist/plugin/provider/openai.js +79 -79
  498. package/dist/plugin/provider/opencode.js +93 -93
  499. package/dist/plugin/provider/openrouter.js +4 -4
  500. package/dist/plugin/provider/perplexity.js +3 -3
  501. package/dist/plugin/provider/sap-ai-core.js +3 -3
  502. package/dist/plugin/provider/snowflake-cortex.js +3 -3
  503. package/dist/plugin/provider/venice.js +3 -3
  504. package/dist/plugin/provider/vercel.js +3 -3
  505. package/dist/plugin/provider/vllm.js +114 -114
  506. package/dist/plugin/provider/xai.js +78 -78
  507. package/dist/plugin/provider/zenmux.js +3 -3
  508. package/dist/plugin/provider.js +157 -157
  509. package/dist/plugin/runtime.js +159 -156
  510. package/dist/plugin/sdk.js +69 -69
  511. package/dist/plugin/skill.js +137 -136
  512. package/dist/plugin/source-directory.js +2 -2
  513. package/dist/plugin/supervisor-service.js +2 -2
  514. package/dist/plugin/supervisor.js +303 -305
  515. package/dist/plugin/system-prompt.js +2 -2
  516. package/dist/plugin/variant.js +4 -4
  517. package/dist/plugin/vcs/git.js +85 -85
  518. package/dist/plugin/vcs/hg.js +85 -85
  519. package/dist/plugin/warming.js +115 -115
  520. package/dist/plugin/websearch/exa.js +4 -4
  521. package/dist/plugin/websearch/firecrawl.js +5 -5
  522. package/dist/plugin/websearch/index.js +9 -9
  523. package/dist/plugin/websearch/mcp.js +3 -3
  524. package/dist/plugin/websearch/parallel.js +5 -5
  525. package/dist/plugin/websearch/tavily.js +3 -3
  526. package/dist/plugin.js +172 -171
  527. package/dist/project/markers.js +74 -74
  528. package/dist/project/schema.js +3 -3
  529. package/dist/project/sql.js +5 -5
  530. package/dist/project.js +82 -82
  531. package/dist/provider.js +2 -2
  532. package/dist/pty/protocol.js +1 -1
  533. package/dist/pty/pty.bun.js +1 -1
  534. package/dist/pty/pty.node.js +1 -1
  535. package/dist/pty/pty.workerd.js +1 -1
  536. package/dist/pty/schema.js +2 -2
  537. package/dist/pty/ticket.js +70 -70
  538. package/dist/pty.js +89 -89
  539. package/dist/reference/instructions.js +77 -77
  540. package/dist/reference.js +75 -75
  541. package/dist/repository-cache.js +7 -7
  542. package/dist/repository.js +2 -2
  543. package/dist/ripgrep/binary.js +3 -3
  544. package/dist/ripgrep.js +94 -94
  545. package/dist/schema.js +2 -2
  546. package/dist/session/compaction.js +122 -142
  547. package/dist/session/context.js +313 -312
  548. package/dist/session/environment.js +3 -3
  549. package/dist/session/error.js +4 -4
  550. package/dist/session/event.js +2 -2
  551. package/dist/session/execution/restart.js +253 -129
  552. package/dist/session/execution.js +126 -121
  553. package/dist/session/generate-node.js +314 -313
  554. package/dist/session/generate.js +2 -2
  555. package/dist/session/history.js +94 -77
  556. package/dist/session/inbox.js +91 -77
  557. package/dist/session/info.js +92 -92
  558. package/dist/session/instruction-entry.js +90 -73
  559. package/dist/session/instruction-state.js +91 -10
  560. package/dist/session/instructions.js +102 -101
  561. package/dist/session/message-updater.js +4 -4
  562. package/dist/session/message.js +2 -2
  563. package/dist/session/model-request.js +139 -138
  564. package/dist/session/model-transport.js +5 -5
  565. package/dist/session/projector.js +101 -90
  566. package/dist/session/prompt-cache-diagnostics.js +2 -2
  567. package/dist/session/revert.js +94 -90
  568. package/dist/session/run-coordinator.js +2 -2
  569. package/dist/session/runner/index.js +87 -85
  570. package/dist/session/runner/llm.js +320 -318
  571. package/dist/session/runner/max-steps.js +2 -2
  572. package/dist/session/runner/model.js +83 -83
  573. package/dist/session/runner/publish-llm-event.js +4 -4
  574. package/dist/session/runner/retry.js +73 -75
  575. package/dist/session/runner/step.js +155 -0
  576. package/dist/session/runner/to-llm-message.js +2 -2
  577. package/dist/session/schema.js +2 -2
  578. package/dist/session/sql.js +87 -6
  579. package/dist/session/stats.js +87 -71
  580. package/dist/session/store.js +101 -100
  581. package/dist/session/system-prompt.js +2 -2
  582. package/dist/session/title.js +314 -140
  583. package/dist/session/to-session-error.js +117 -116
  584. package/dist/session/transfer.js +160 -157
  585. package/dist/session/usage.js +2 -2
  586. package/dist/session.js +157 -154
  587. package/dist/shell/parse.js +9 -6
  588. package/dist/shell/parser-wasm.bun.js +1 -1
  589. package/dist/shell/parser-wasm.node.js +1 -1
  590. package/dist/shell/parser-wasm.workerd.js +1 -1
  591. package/dist/shell/scan.js +1084 -365
  592. package/dist/shell/select.js +4 -4
  593. package/dist/shell.js +99 -99
  594. package/dist/skill/discovery.js +3 -3
  595. package/dist/skill/instructions.js +108 -107
  596. package/dist/skill.js +107 -106
  597. package/dist/snapshot.js +85 -85
  598. package/dist/state.js +2 -2
  599. package/dist/tool/html-markdown.js +2 -2
  600. package/dist/tool/http-body.js +2 -2
  601. package/dist/tool/mcp.js +128 -127
  602. package/dist/tool/plugin/edit.js +116 -115
  603. package/dist/tool/plugin/file-diff.js +2 -2
  604. package/dist/tool/plugin/glob.js +118 -117
  605. package/dist/tool/plugin/grep.js +118 -117
  606. package/dist/tool/plugin/patch.js +116 -115
  607. package/dist/tool/plugin/question.js +108 -107
  608. package/dist/tool/plugin/read.js +121 -120
  609. package/dist/tool/plugin/shell.js +187 -186
  610. package/dist/tool/plugin/skill.js +108 -107
  611. package/dist/tool/plugin/subagent.js +184 -183
  612. package/dist/tool/plugin/webfetch.js +109 -108
  613. package/dist/tool/plugin/websearch.js +111 -110
  614. package/dist/tool/plugin/write.js +116 -115
  615. package/dist/tool/read-filesystem.js +98 -98
  616. package/dist/tool/runtime.js +2 -2
  617. package/dist/tool-output.js +5 -5
  618. package/dist/tool.js +121 -120
  619. package/dist/types/bus.d.ts +3 -0
  620. package/dist/types/job.d.ts +45 -8
  621. package/dist/types/location-service-map.d.ts +2 -2
  622. package/dist/types/location-services.d.ts +1 -1
  623. package/dist/types/plugin/host.d.ts +4 -8
  624. package/dist/types/plugin/internal.d.ts +3 -3
  625. package/dist/types/plugin/runtime.d.ts +1 -6
  626. package/dist/types/plugin/supervisor.d.ts +1 -1
  627. package/dist/types/session/compaction.d.ts +8 -3
  628. package/dist/types/session/context.d.ts +11 -2
  629. package/dist/types/session/execution/restart.d.ts +6 -1
  630. package/dist/types/session/execution.d.ts +2 -1
  631. package/dist/types/session/generate-node.d.ts +1 -3
  632. package/dist/types/session/model-request.d.ts +1 -1
  633. package/dist/types/session/runner/index.d.ts +55 -6
  634. package/dist/types/session/runner/model.d.ts +2 -1
  635. package/dist/types/session/runner/publish-llm-event.d.ts +1 -8
  636. package/dist/types/session/runner/retry.d.ts +3 -7
  637. package/dist/types/session/runner/step.d.ts +58 -0
  638. package/dist/types/session/store.d.ts +5 -7
  639. package/dist/types/session/title.d.ts +2 -5
  640. package/dist/types/shell/parse.d.ts +8 -6
  641. package/dist/types/shell/scan.d.ts +6 -3
  642. package/dist/types/tool/plugin/shell.d.ts +1 -1
  643. package/dist/types/tool.d.ts +16 -5
  644. package/dist/util/array.js +1 -1
  645. package/dist/util/error.js +2 -2
  646. package/dist/util/identifier.js +1 -1
  647. package/dist/util/iife.js +2 -2
  648. package/dist/util/lazy.js +2 -2
  649. package/dist/util/process-lock-ffi.bun.js +1 -1
  650. package/dist/util/process-lock-ffi.node.js +1 -1
  651. package/dist/util/process-lock-ffi.workerd.js +1 -1
  652. package/dist/util/process-lock.js +1 -1
  653. package/dist/util/slug.js +2 -2
  654. package/dist/util/token.js +2 -2
  655. package/dist/util/which.js +2 -2
  656. package/dist/util/wildcard.js +2 -2
  657. package/dist/v1/config/agent.js +4 -4
  658. package/dist/v1/config/attachment.js +3 -3
  659. package/dist/v1/config/command.js +2 -2
  660. package/dist/v1/config/config.js +15 -15
  661. package/dist/v1/config/error.js +3 -3
  662. package/dist/v1/config/formatter.js +2 -2
  663. package/dist/v1/config/layout.js +2 -2
  664. package/dist/v1/config/lsp.js +2 -2
  665. package/dist/v1/config/mcp.js +3 -3
  666. package/dist/v1/config/migrate.js +19 -19
  667. package/dist/v1/config/permission.js +2 -2
  668. package/dist/v1/config/plugin.js +2 -2
  669. package/dist/v1/config/provider-options.js +2 -2
  670. package/dist/v1/config/provider.js +3 -3
  671. package/dist/v1/config/server.js +3 -3
  672. package/dist/v1/config/skills.js +2 -2
  673. package/dist/v1/permission.js +7 -43
  674. package/dist/vcs/patch.js +2 -2
  675. package/dist/vcs.js +86 -86
  676. package/dist/websearch.js +73 -73
  677. package/dist/wellknown/plugin.js +73 -73
  678. package/dist/wellknown.js +72 -72
  679. package/dist/workspace/driver.js +2 -2
  680. package/dist/workspace/sql.js +2 -2
  681. package/dist/workspace.js +69 -69
  682. package/dist/worktree/directory.js +3 -3
  683. package/dist/worktree/git.js +7 -7
  684. package/dist/worktree/sql.js +6 -6
  685. package/dist/worktree.js +87 -87
  686. package/package.json +8 -8
  687. package/dist/chunks/job-nv9gjhyw.js +0 -712
  688. package/dist/chunks/job-zn4b3ags.js +0 -539
  689. /package/dist/chunks/{job-0cgt0xh2.js → snapshot-0cgt0xh2.js} +0 -0
  690. /package/dist/chunks/{job-0f48qthw.js → snapshot-0f48qthw.js} +0 -0
  691. /package/dist/chunks/{job-0zz82cjq.js → snapshot-0zz82cjq.js} +0 -0
  692. /package/dist/chunks/{job-1fb7bmpf.js → snapshot-1fb7bmpf.js} +0 -0
  693. /package/dist/chunks/{job-1wcz8fvj.js → snapshot-1wcz8fvj.js} +0 -0
  694. /package/dist/chunks/{job-2qdx6zz3.js → snapshot-2qdx6zz3.js} +0 -0
  695. /package/dist/chunks/{job-2xb0r1c6.js → snapshot-2xb0r1c6.js} +0 -0
  696. /package/dist/chunks/{job-39ktntah.js → snapshot-39ktntah.js} +0 -0
  697. /package/dist/chunks/{job-3g3rpp2x.js → snapshot-3g3rpp2x.js} +0 -0
  698. /package/dist/chunks/{job-3q6gbwmd.js → snapshot-3q6gbwmd.js} +0 -0
  699. /package/dist/chunks/{job-3w3ybtfd.js → snapshot-3w3ybtfd.js} +0 -0
  700. /package/dist/chunks/{job-47ty4mvs.js → snapshot-47ty4mvs.js} +0 -0
  701. /package/dist/chunks/{job-4b2tz2m9.js → snapshot-4b2tz2m9.js} +0 -0
  702. /package/dist/chunks/{job-5a5ch9ts.js → snapshot-5a5ch9ts.js} +0 -0
  703. /package/dist/chunks/{job-5va1yh78.js → snapshot-5va1yh78.js} +0 -0
  704. /package/dist/chunks/{job-61ek4hj9.js → snapshot-61ek4hj9.js} +0 -0
  705. /package/dist/chunks/{job-69qrqpw0.js → snapshot-69qrqpw0.js} +0 -0
  706. /package/dist/chunks/{job-6zqxzw0a.js → snapshot-6zqxzw0a.js} +0 -0
  707. /package/dist/chunks/{job-7n9qwqk4.js → snapshot-7n9qwqk4.js} +0 -0
  708. /package/dist/chunks/{job-8nn8kqcn.js → snapshot-8nn8kqcn.js} +0 -0
  709. /package/dist/chunks/{job-8rpfd2h6.js → snapshot-8rpfd2h6.js} +0 -0
  710. /package/dist/chunks/{job-8sj3ajy5.js → snapshot-8sj3ajy5.js} +0 -0
  711. /package/dist/chunks/{job-8w9tzfz1.js → snapshot-8w9tzfz1.js} +0 -0
  712. /package/dist/chunks/{job-906y0b6d.js → snapshot-906y0b6d.js} +0 -0
  713. /package/dist/chunks/{job-9dct5xhx.js → snapshot-9dct5xhx.js} +0 -0
  714. /package/dist/chunks/{job-9sdtsapf.js → snapshot-9sdtsapf.js} +0 -0
  715. /package/dist/chunks/{job-a02svayp.js → snapshot-a02svayp.js} +0 -0
  716. /package/dist/chunks/{job-a83yvq99.js → snapshot-a83yvq99.js} +0 -0
  717. /package/dist/chunks/{job-ayevdmef.js → snapshot-ayevdmef.js} +0 -0
  718. /package/dist/chunks/{job-b02txbh8.js → snapshot-b02txbh8.js} +0 -0
  719. /package/dist/chunks/{job-bbqs2y60.js → snapshot-bbqs2y60.js} +0 -0
  720. /package/dist/chunks/{job-bjwj8hwv.js → snapshot-bjwj8hwv.js} +0 -0
  721. /package/dist/chunks/{job-brsh5f65.js → snapshot-brsh5f65.js} +0 -0
  722. /package/dist/chunks/{job-bxdhjb3y.js → snapshot-bxdhjb3y.js} +0 -0
  723. /package/dist/chunks/{job-c77ad0vh.js → snapshot-c77ad0vh.js} +0 -0
  724. /package/dist/chunks/{job-ck5pgha0.js → snapshot-ck5pgha0.js} +0 -0
  725. /package/dist/chunks/{job-cm67rqy2.js → snapshot-cm67rqy2.js} +0 -0
  726. /package/dist/chunks/{job-df3v2q6j.js → snapshot-df3v2q6j.js} +0 -0
  727. /package/dist/chunks/{job-dhcq6c44.js → snapshot-dhcq6c44.js} +0 -0
  728. /package/dist/chunks/{job-dht5baf0.js → snapshot-dht5baf0.js} +0 -0
  729. /package/dist/chunks/{job-dkmkay92.js → snapshot-dkmkay92.js} +0 -0
  730. /package/dist/chunks/{job-drean1vx.js → snapshot-drean1vx.js} +0 -0
  731. /package/dist/chunks/{job-ehj9csmv.js → snapshot-ehj9csmv.js} +0 -0
  732. /package/dist/chunks/{job-em6xpscd.js → snapshot-em6xpscd.js} +0 -0
  733. /package/dist/chunks/{job-emmqknsm.js → snapshot-emmqknsm.js} +0 -0
  734. /package/dist/chunks/{job-ezs3tagn.js → snapshot-ezs3tagn.js} +0 -0
  735. /package/dist/chunks/{job-f14r7hfz.js → snapshot-f14r7hfz.js} +0 -0
  736. /package/dist/chunks/{job-f4cp4g4a.js → snapshot-f4cp4g4a.js} +0 -0
  737. /package/dist/chunks/{job-faypg4r1.js → snapshot-faypg4r1.js} +0 -0
  738. /package/dist/chunks/{job-fgbfdq62.js → snapshot-fgbfdq62.js} +0 -0
  739. /package/dist/chunks/{job-gd5xeqc2.js → snapshot-gd5xeqc2.js} +0 -0
  740. /package/dist/chunks/{job-ghm4673n.js → snapshot-ghm4673n.js} +0 -0
  741. /package/dist/chunks/{job-ghwjy7my.js → snapshot-ghwjy7my.js} +0 -0
  742. /package/dist/chunks/{job-gqn2zsfg.js → snapshot-gqn2zsfg.js} +0 -0
  743. /package/dist/chunks/{job-gy500k2r.js → snapshot-gy500k2r.js} +0 -0
  744. /package/dist/chunks/{job-hzeg9cfr.js → snapshot-hzeg9cfr.js} +0 -0
  745. /package/dist/chunks/{job-j07kk359.js → snapshot-j07kk359.js} +0 -0
  746. /package/dist/chunks/{job-jve7t217.js → snapshot-jve7t217.js} +0 -0
  747. /package/dist/chunks/{job-k3e42drn.js → snapshot-k3e42drn.js} +0 -0
  748. /package/dist/chunks/{job-k8b45nas.js → snapshot-k8b45nas.js} +0 -0
  749. /package/dist/chunks/{job-kcacmy5c.js → snapshot-kcacmy5c.js} +0 -0
  750. /package/dist/chunks/{job-kpdbz7gn.js → snapshot-kpdbz7gn.js} +0 -0
  751. /package/dist/chunks/{job-kxy11nzk.js → snapshot-kxy11nzk.js} +0 -0
  752. /package/dist/chunks/{job-kyyqvx4s.js → snapshot-kyyqvx4s.js} +0 -0
  753. /package/dist/chunks/{job-m8cbvarh.js → snapshot-m8cbvarh.js} +0 -0
  754. /package/dist/chunks/{job-ma60vzgv.js → snapshot-ma60vzgv.js} +0 -0
  755. /package/dist/chunks/{job-n3m50c2t.js → snapshot-n3m50c2t.js} +0 -0
  756. /package/dist/chunks/{job-nkm1m8dz.js → snapshot-nkm1m8dz.js} +0 -0
  757. /package/dist/chunks/{job-nsc0c3zb.js → snapshot-nsc0c3zb.js} +0 -0
  758. /package/dist/chunks/{job-qaarhjrp.js → snapshot-qaarhjrp.js} +0 -0
  759. /package/dist/chunks/{job-qc167nrn.js → snapshot-qc167nrn.js} +0 -0
  760. /package/dist/chunks/{job-qp95y4jb.js → snapshot-qp95y4jb.js} +0 -0
  761. /package/dist/chunks/{job-r8f4w671.js → snapshot-r8f4w671.js} +0 -0
  762. /package/dist/chunks/{job-rdfev9jy.js → snapshot-rdfev9jy.js} +0 -0
  763. /package/dist/chunks/{job-rvfvac9x.js → snapshot-rvfvac9x.js} +0 -0
  764. /package/dist/chunks/{job-s7whb9gt.js → snapshot-s7whb9gt.js} +0 -0
  765. /package/dist/chunks/{job-se76j685.js → snapshot-se76j685.js} +0 -0
  766. /package/dist/chunks/{job-sem2g21k.js → snapshot-sem2g21k.js} +0 -0
  767. /package/dist/chunks/{job-sp575ygv.js → snapshot-sp575ygv.js} +0 -0
  768. /package/dist/chunks/{job-tmb1f636.js → snapshot-tmb1f636.js} +0 -0
  769. /package/dist/chunks/{job-ttxf0gsy.js → snapshot-ttxf0gsy.js} +0 -0
  770. /package/dist/chunks/{job-tvmhrvfj.js → snapshot-tvmhrvfj.js} +0 -0
  771. /package/dist/chunks/{job-v2adqbbe.js → snapshot-v2adqbbe.js} +0 -0
  772. /package/dist/chunks/{job-wj4sxzqa.js → snapshot-wj4sxzqa.js} +0 -0
  773. /package/dist/chunks/{job-wwntjmk1.js → snapshot-wwntjmk1.js} +0 -0
  774. /package/dist/chunks/{job-wyqjaaa5.js → snapshot-wyqjaaa5.js} +0 -0
  775. /package/dist/chunks/{job-x4q807cx.js → snapshot-x4q807cx.js} +0 -0
  776. /package/dist/chunks/{job-xt0068v8.js → snapshot-xt0068v8.js} +0 -0
  777. /package/dist/chunks/{job-yrqrg4vp.js → snapshot-yrqrg4vp.js} +0 -0
  778. /package/dist/chunks/{job-z47nswr2.js → snapshot-z47nswr2.js} +0 -0
  779. /package/dist/chunks/{job-zsf8rs93.js → snapshot-zsf8rs93.js} +0 -0
@@ -1,92 +1,73 @@
1
1
  import {
2
2
  __export
3
- } from "../chunks/job-rvfvac9x.js";
3
+ } from "../chunks/snapshot-rvfvac9x.js";
4
4
 
5
5
  // src/shell/scan.ts
6
6
  var exports_scan = {};
7
7
  __export(exports_scan, {
8
8
  scanPowerShell: () => scanPowerShell,
9
9
  scan: () => scan,
10
- ShellScan: () => exports_scan,
11
- Nested: () => Nested
10
+ ShellScan: () => exports_scan
12
11
  });
13
- var Nested = Symbol("ShellScan.Nested");
14
- var BASH_COMPOUND_KEYWORDS = new Set([
15
- "if",
16
- "then",
17
- "elif",
18
- "else",
19
- "fi",
20
- "for",
21
- "while",
22
- "until",
23
- "case",
24
- "select",
25
- "function",
26
- "do",
27
- "done",
28
- "coproc"
29
- ]);
30
- var POWERSHELL_LOCATIONS = new Set(["set-location", "cd", "chdir", "sl", "push-location", "pushd"]);
31
12
  var BASH_REDIRECTS = ["&>>", "&>", "<<<", "<<-", "<<", "<>", "<&", ">&", ">|", ">>", ">", "<"];
32
- var MAX_BASH_INPUT_LENGTH = 64 * 1024;
13
+ var BASH_DECLARATIONS = new Set(["declare", "typeset", "export", "readonly", "local", "unset", "unsetenv"]);
14
+ var MAX_INPUT_LENGTH = 64 * 1024;
33
15
  var MAX_SUBSTITUTION_DEPTH = 32;
34
16
  function scan(input) {
35
- return scanBash(input, 0);
17
+ return scanBash(input, 0, { remaining: MAX_INPUT_LENGTH * MAX_SUBSTITUTION_DEPTH });
36
18
  }
37
- function scanBash(input, depth) {
38
- if (input.length > MAX_BASH_INPUT_LENGTH)
19
+ function scanBash(input, depth, budget) {
20
+ budget.remaining -= input.length;
21
+ if (input.length > MAX_INPUT_LENGTH || budget.remaining < 0 || depth > MAX_SUBSTITUTION_DEPTH)
39
22
  return { kind: "opaque", reason: "invalid-structure" };
40
- const group = bashLeadingGroup(input);
41
- if (group) {
42
- if (depth >= MAX_SUBSTITUTION_DEPTH)
43
- return { kind: "opaque", reason: "invalid-structure" };
44
- const nested = scanBash(group.source, depth + 1);
45
- if (nested.kind === "opaque")
46
- return nested;
47
- const suffix = input.slice(group.end + 1).trim();
48
- if (!suffix)
49
- return nested;
50
- const separator = /^(?:&&|\|\||\|&|[;&|])/.exec(suffix)?.[0];
51
- const remaining = separator ? suffix.slice(separator.length).trim() : suffix;
52
- if (separator && !remaining)
53
- return nested;
54
- const prefixed = separator ? remaining : /^[<>]/.test(remaining) ? `: ${remaining}` : undefined;
55
- if (!prefixed)
56
- return { kind: "opaque", reason: "compound-command" };
57
- const rest = scanBash(prefixed, depth + 1);
58
- if (rest.kind === "opaque")
59
- return rest;
60
- return {
61
- kind: "scanned",
62
- commands: nested.commands.concat(rest.commands.filter((command) => command.words[0] !== ":"))
63
- };
64
- }
65
23
  const commands = [];
66
24
  const nestedCommands = [];
67
25
  const words = [];
26
+ const rawWords = [];
68
27
  const assignmentWords = [];
69
28
  let word = "";
70
29
  let wordStarted = false;
30
+ let wordStart = 0;
31
+ let wordEnd = 0;
32
+ let commandEnd = 0;
33
+ let resourceEnd;
34
+ let redirectWordCount;
71
35
  let assignmentWord = false;
72
36
  let assignmentHeadUnsafe = false;
73
37
  let segment = 0;
74
38
  let quote;
75
- let compound = false;
76
39
  let invalidRedirect = false;
77
40
  let invalidStructure = false;
78
41
  let separated = false;
79
- let comment;
80
- let heredoc = false;
81
42
  let redirectTarget = false;
82
43
  let hasRedirect = false;
83
- let terminalBackground = false;
44
+ let dangling = false;
45
+ let inList = false;
46
+ let compoundEnd = false;
47
+ const heredocs = [];
48
+ const structures = [];
49
+ const addSubstitutions = (substitution) => {
50
+ for (const source of substitution.substitutions ?? [substitution.source]) {
51
+ const result = scanBash(source, depth + 1, budget);
52
+ if (result.kind === "opaque")
53
+ return result;
54
+ nestedCommands.push(...result.commands);
55
+ }
56
+ };
57
+ const statement = () => {
58
+ const structure = structures.at(-1);
59
+ if (structure)
60
+ structure.count++;
61
+ };
62
+ const header = () => ["header", "pattern", "do"].includes(structures.at(-1)?.phase ?? "");
84
63
  const finishWord = () => {
85
64
  if (!wordStarted)
86
65
  return;
87
66
  if (!redirectTarget) {
88
67
  words.push(word);
68
+ rawWords.push(input.slice(wordStart, wordEnd));
89
69
  assignmentWords.push(assignmentWord);
70
+ commandEnd = wordEnd;
90
71
  }
91
72
  redirectTarget = false;
92
73
  word = "";
@@ -94,29 +75,185 @@ function scanBash(input, depth) {
94
75
  assignmentWord = false;
95
76
  assignmentHeadUnsafe = false;
96
77
  };
97
- const finishCommand = (end, boundary = false) => {
78
+ const finishCommand = (boundary = false) => {
98
79
  finishWord();
99
- const resource = input.slice(segment, end).trim();
80
+ if (redirectTarget)
81
+ invalidRedirect = true;
82
+ redirectTarget = false;
83
+ if (compoundEnd && words.length > 0)
84
+ invalidStructure = true;
85
+ const resource = input.slice(segment, resourceEnd ?? wordEnd).replace(/^[ \t\n]+|[ \t\n]+$/g, "");
100
86
  const name = assignmentWords.findIndex((assignment) => !assignment);
101
- if (name >= 0 && /[*?[]/.test(words[name]))
102
- compound = true;
103
- if (resource && name >= 0)
104
- commands.push({
105
- resource,
106
- words: words.slice(name)
107
- });
108
- else if (!(assignmentWords.length > 0 && assignmentWords.every(Boolean)) && (hasRedirect || boundary || separated))
87
+ if (name >= 0 && !words[name])
109
88
  invalidStructure = true;
89
+ if (rawWords[name] === "}")
90
+ invalidStructure = true;
91
+ if (resource && name >= 0 && !header()) {
92
+ const command = {
93
+ resource,
94
+ words: words.slice(name),
95
+ rawWords: rawWords.slice(name),
96
+ ...name === 0 && BASH_DECLARATIONS.has(rawWords[0]) && resource.startsWith(rawWords[0]) ? { declaration: true } : {},
97
+ ...redirectWordCount !== undefined && redirectWordCount < words.length ? { redirectWordCount: redirectWordCount - name } : {}
98
+ };
99
+ commands.push(command);
100
+ if (resourceEnd === undefined) {
101
+ for (const heredoc of heredocs) {
102
+ if (heredoc.command)
103
+ continue;
104
+ heredoc.command = command;
105
+ heredoc.start = segment;
106
+ }
107
+ }
108
+ } else if (!header() && !compoundEnd && (hasRedirect || boundary || separated)) {
109
+ const assignmentOnly = assignmentWords.length > 0 && assignmentWords.every(Boolean);
110
+ if (!assignmentOnly && !hasRedirect)
111
+ invalidStructure = true;
112
+ }
110
113
  commands.push(...nestedCommands.splice(0));
114
+ if (!header() && (words.length > 0 || hasRedirect))
115
+ statement();
111
116
  words.length = 0;
117
+ rawWords.length = 0;
112
118
  assignmentWords.length = 0;
113
119
  separated = true;
114
120
  hasRedirect = false;
121
+ resourceEnd = undefined;
122
+ redirectWordCount = undefined;
123
+ compoundEnd = false;
115
124
  };
116
125
  for (let index = 0;index < input.length; index++) {
117
126
  const char = input[index];
127
+ if (!wordStarted)
128
+ wordStart = index;
129
+ if (!quote && !wordStarted) {
130
+ const structure = structures.at(-1);
131
+ const token = /^[A-Za-z_][A-Za-z0-9_]*(?=[ \t\n;()<>]|$)/.exec(input.slice(index))?.[0];
132
+ if (structure?.kind === "case" && structure.phase === "header" && token === "in") {
133
+ finishCommand();
134
+ structure.phase = "pattern";
135
+ index += token.length - 1;
136
+ segment = index + 1;
137
+ continue;
138
+ }
139
+ if (structure?.phase === "pattern" && (char === "(" || char === "|"))
140
+ continue;
141
+ if (structure?.phase === "pattern" && char === ")") {
142
+ finishCommand();
143
+ structure.phase = "body";
144
+ structure.count = 0;
145
+ segment = index + 1;
146
+ continue;
147
+ }
148
+ if (!words.length && !hasRedirect && !compoundEnd) {
149
+ const definition = /^(?:function[ \t]+[A-Za-z_][A-Za-z0-9_]*(?:[ \t]*\([ \t]*\))?|[A-Za-z_][A-Za-z0-9_]*[ \t]*\([ \t]*\))[ \t\n]*(?=[{(])/.exec(input.slice(index));
150
+ if (definition && !header()) {
151
+ index += definition[0].length - 1;
152
+ segment = index + 1;
153
+ continue;
154
+ }
155
+ if (!header() && (token === "if" || token === "while" || token === "until" || token === "for" || token === "select" || token === "case")) {
156
+ if (depth + structures.length >= MAX_SUBSTITUTION_DEPTH)
157
+ return { kind: "opaque", reason: "compound-command" };
158
+ structures.push({
159
+ kind: token === "select" ? "for" : token,
160
+ phase: ["for", "select", "case"].includes(token) ? "header" : "condition",
161
+ count: 0
162
+ });
163
+ index += token.length - 1;
164
+ segment = index + 1;
165
+ inList = false;
166
+ continue;
167
+ }
168
+ if (token && ["then", "elif", "else", "fi", "do", "done", "esac"].includes(token) && (!header() || token === "do" && structure?.phase === "do" || token === "esac" && structure?.phase === "pattern")) {
169
+ if (!structure || dangling)
170
+ return { kind: "opaque", reason: "compound-command" };
171
+ if (token === "then") {
172
+ if (structure.kind !== "if" || structure.phase !== "condition" || !structure.count)
173
+ return { kind: "opaque", reason: "compound-command" };
174
+ structure.phase = "body";
175
+ } else if (token === "elif" || token === "else") {
176
+ if (structure.kind !== "if" || structure.phase !== "body" || !structure.count || structure.sawElse)
177
+ return { kind: "opaque", reason: "compound-command" };
178
+ structure.phase = token === "elif" ? "condition" : "body";
179
+ structure.sawElse = token === "else";
180
+ } else if (token === "do") {
181
+ if (!["for", "while", "until"].includes(structure.kind) || !["condition", "do"].includes(structure.phase) || structure.kind !== "for" && !structure.count)
182
+ return { kind: "opaque", reason: "compound-command" };
183
+ structure.phase = "body";
184
+ } else {
185
+ if (token === "fi" && (structure.kind !== "if" || structure.phase !== "body" || !structure.count) || token === "done" && (!["for", "while", "until"].includes(structure.kind) || structure.phase !== "body" || !structure.count) || token === "esac" && (structure.kind !== "case" || structure.phase === "header"))
186
+ return { kind: "opaque", reason: "compound-command" };
187
+ structures.pop();
188
+ statement();
189
+ compoundEnd = true;
190
+ dangling = false;
191
+ }
192
+ structure.count = 0;
193
+ index += token.length - 1;
194
+ segment = index + 1;
195
+ inList = false;
196
+ continue;
197
+ }
198
+ if (!header() && (char === "!" && /[ \t\n]/.test(input[index + 1] ?? "") || token === "coproc" && /^coproc[ \t]+(?:[A-Za-z_][A-Za-z0-9_]*[ \t]+)?(?:[{(]|(?:if|while|until|for|case)\b)/.test(input.slice(index)) || token === "time" && /^time[ \t]+(?:-p[ \t]+)?(?:[{(]|(?:if|while|until|for|case)\b)/.test(input.slice(index)))) {
199
+ index += token ? token.length - 1 : 0;
200
+ if (token === "time")
201
+ index += /^[ \t]+-p\b/.exec(input.slice(index + 1))?.[0].length ?? 0;
202
+ if (token === "coproc")
203
+ index += /^[ \t]+[A-Za-z_][A-Za-z0-9_]*[ \t]+(?=[{(]|(?:if|while|until|for|case)\b)/.exec(input.slice(index + 1))?.[0].length ?? 0;
204
+ segment = index + 1;
205
+ continue;
206
+ }
207
+ }
208
+ if ((!words.length && !hasRedirect && !header() || structure?.kind === "for" && structure.phase === "header") && input.startsWith("((", index)) {
209
+ const expression = bashExpansion(input, index, depth, "arithmetic");
210
+ if (!expression)
211
+ return { kind: "opaque", reason: "invalid-structure" };
212
+ const failure = addSubstitutions(expression);
213
+ if (failure)
214
+ return failure;
215
+ commands.push(...nestedCommands.splice(0));
216
+ statement();
217
+ compoundEnd = !header();
218
+ dangling = false;
219
+ index = expression.end;
220
+ segment = index + 1;
221
+ continue;
222
+ }
223
+ if (!words.length && !hasRedirect && !header() && (char === "(" || char === "{" && /[ \t\n]/.test(input[index + 1] ?? ""))) {
224
+ const group = bashDelimited(input, index, depth);
225
+ if (!group || !group.source.trim())
226
+ return { kind: "opaque", reason: "invalid-structure" };
227
+ const result = scanBash(group.source, depth + 1, budget);
228
+ if (result.kind === "opaque")
229
+ return result;
230
+ commands.push(...result.commands);
231
+ statement();
232
+ compoundEnd = true;
233
+ dangling = false;
234
+ index = group.end;
235
+ segment = index + 1;
236
+ continue;
237
+ }
238
+ if (!words.length && !hasRedirect && input.startsWith("[[", index)) {
239
+ const expression = bashExpansion(input, index, depth, "test");
240
+ if (!expression)
241
+ return { kind: "opaque", reason: "invalid-structure" };
242
+ const failure = addSubstitutions(expression);
243
+ if (failure)
244
+ return failure;
245
+ commands.push(...nestedCommands.splice(0));
246
+ statement();
247
+ compoundEnd = true;
248
+ dangling = false;
249
+ index = expression.end;
250
+ segment = index + 1;
251
+ continue;
252
+ }
253
+ }
118
254
  if (quote === "single") {
119
255
  wordStarted = true;
256
+ wordEnd = index + 1;
120
257
  if (char === "'")
121
258
  quote = undefined;
122
259
  else
@@ -136,28 +273,44 @@ function scanBash(input, depth) {
136
273
  word += next2;
137
274
  } else
138
275
  word += char;
139
- } else if (char === "$" && input[index + 1] === "(" || char === "`") {
140
- const substitution = bashSubstitution(input, index);
276
+ } else if (char === "$" && "({[".includes(input[index + 1] ?? "\x00") || char === "`") {
277
+ const substitution = bashExpansion(input, index, depth, undefined, true);
141
278
  if (!substitution || depth >= MAX_SUBSTITUTION_DEPTH)
142
279
  return { kind: "opaque", reason: "command-substitution" };
143
- const result = scanBash(substitution.source, depth + 1);
144
- if (result.kind === "opaque")
145
- return result;
146
- nestedCommands.push(...result.commands.map(markNested));
280
+ const failure = addSubstitutions(substitution);
281
+ if (failure)
282
+ return failure;
147
283
  word += input.slice(index, substitution.end + 1);
148
284
  index = substitution.end;
149
- } else {
150
- if (char === "$" && /^\$\{[^}:@]+@P\}/.test(input.slice(index)))
151
- return { kind: "opaque", reason: "dynamic-execution" };
152
- if (char === "$" && /^\$\{\([^)]*e[^)]*\)/.test(input.slice(index)))
153
- return { kind: "opaque", reason: "dynamic-execution" };
285
+ } else
154
286
  word += char;
155
- }
287
+ wordEnd = index + 1;
288
+ continue;
289
+ }
290
+ if (char === "$" && input[index + 1] === "'") {
291
+ const literal = bashAnsiQuote(input, index + 1);
292
+ if (!literal)
293
+ return { kind: "opaque", reason: "unterminated-quote" };
294
+ wordStarted = true;
295
+ if (!assignmentWord)
296
+ assignmentHeadUnsafe = true;
297
+ word += literal.value;
298
+ index = literal.end;
299
+ wordEnd = index + 1;
300
+ continue;
301
+ }
302
+ if (char === "$" && input[index + 1] === '"') {
303
+ quote = "double";
304
+ wordStarted = true;
305
+ if (!assignmentWord)
306
+ assignmentHeadUnsafe = true;
307
+ wordEnd = ++index + 1;
156
308
  continue;
157
309
  }
158
310
  if (char === "'") {
159
311
  quote = "single";
160
312
  wordStarted = true;
313
+ wordEnd = index + 1;
161
314
  if (!assignmentWord)
162
315
  assignmentHeadUnsafe = true;
163
316
  continue;
@@ -165,6 +318,7 @@ function scanBash(input, depth) {
165
318
  if (char === '"') {
166
319
  quote = "double";
167
320
  wordStarted = true;
321
+ wordEnd = index + 1;
168
322
  if (!assignmentWord)
169
323
  assignmentHeadUnsafe = true;
170
324
  continue;
@@ -172,60 +326,56 @@ function scanBash(input, depth) {
172
326
  if (char === "\\") {
173
327
  if (index + 1 >= input.length)
174
328
  return { kind: "opaque", reason: "unterminated-escape" };
175
- wordStarted = true;
176
329
  if (input[index + 1] === `
177
330
  `)
178
331
  index++;
179
332
  else {
333
+ wordStarted = true;
180
334
  if (!assignmentWord)
181
335
  assignmentHeadUnsafe = true;
182
336
  word += input[++index];
337
+ wordEnd = index + 1;
183
338
  }
184
339
  continue;
185
340
  }
186
- if (char === "$" && input[index + 1] === "(" || char === "`") {
187
- const substitution = bashSubstitution(input, index);
341
+ if (char === "$" && "({[".includes(input[index + 1] ?? "\x00") || char === "`" || char === "[" && /^[A-Za-z_][A-Za-z0-9_]*$/.test(word) && /^\[[\s\S]*?\]\+?=/.test(input.slice(index)) || char === "(" && (assignmentWord || /[?*+@!]$/.test(word))) {
342
+ const substitution = char === "(" ? bashExpansion(input, index, depth, assignmentWord ? "array" : "pattern") : char === "[" ? bashExpansion(input, index, depth, "subscript") : bashExpansion(input, index, depth);
188
343
  if (!substitution || depth >= MAX_SUBSTITUTION_DEPTH)
189
344
  return { kind: "opaque", reason: "command-substitution" };
190
- const result = scanBash(substitution.source, depth + 1);
191
- if (result.kind === "opaque")
192
- return result;
193
- nestedCommands.push(...result.commands.map(markNested));
345
+ const failure = addSubstitutions(substitution);
346
+ if (failure)
347
+ return failure;
194
348
  wordStarted = true;
195
349
  word += input.slice(index, substitution.end + 1);
196
350
  index = substitution.end;
351
+ wordEnd = index + 1;
197
352
  continue;
198
353
  }
199
- if ((char === "<" || char === ">") && input[index + 1] === "(") {
200
- const substitution = bashParenthesized(input, index + 1);
354
+ if ((char === "<" || char === ">" || char === "=" && !wordStarted) && input[index + 1] === "(") {
355
+ const substitution = bashDelimited(input, index + 1, depth);
201
356
  if (!substitution || depth >= MAX_SUBSTITUTION_DEPTH)
202
357
  return { kind: "opaque", reason: "command-substitution" };
203
- const result = scanBash(substitution.source, depth + 1);
204
- if (result.kind === "opaque")
205
- return result;
206
- nestedCommands.push(...result.commands.map(markNested));
358
+ const failure = addSubstitutions(substitution);
359
+ if (failure)
360
+ return failure;
207
361
  wordStarted = true;
208
362
  word += input.slice(index, substitution.end + 1);
209
363
  index = substitution.end;
364
+ wordEnd = index + 1;
210
365
  continue;
211
366
  }
212
- if (char === "$" && input[index + 1] === "{" && /^\$\{[^}:@]+@P\}/.test(input.slice(index)))
213
- return { kind: "opaque", reason: "dynamic-execution" };
214
- if (char === "$" && /^\$\{\([^)]*e[^)]*\)/.test(input.slice(index)))
215
- return { kind: "opaque", reason: "dynamic-execution" };
216
- if (char === "$" && input[index + 1] === "[")
217
- return { kind: "opaque", reason: "dynamic-execution" };
218
- if (char === "<" && input[index + 1] === "<")
219
- heredoc = true;
220
367
  if (char === "#" && !wordStarted) {
221
- finishCommand(index);
222
- comment = index;
223
368
  const newline = input.indexOf(`
224
369
  `, index);
370
+ if (words.length > 0 || hasRedirect) {
371
+ finishCommand();
372
+ dangling = false;
373
+ inList = false;
374
+ }
225
375
  if (newline === -1)
226
376
  break;
227
- index = newline;
228
- segment = newline + 1;
377
+ index = newline - 1;
378
+ segment = newline;
229
379
  continue;
230
380
  }
231
381
  const redirect = "<>&".includes(char) ? BASH_REDIRECTS.find((candidate) => input.startsWith(candidate, index)) : undefined;
@@ -233,19 +383,43 @@ function scanBash(input, depth) {
233
383
  hasRedirect = true;
234
384
  if (redirectTarget)
235
385
  invalidRedirect = true;
236
- if (wordStarted && /^\d+$/.test(word)) {
386
+ if (wordStarted && !assignmentHeadUnsafe && /^(?:\d+|\{[A-Za-z_][A-Za-z0-9_]*\})$/.test(word)) {
387
+ if (wordEnd < index)
388
+ commandEnd = wordEnd;
237
389
  word = "";
238
390
  wordStarted = false;
239
391
  } else
240
392
  finishWord();
393
+ if (redirectWordCount === undefined && assignmentWords.some((assignment) => !assignment)) {
394
+ redirectWordCount = words.length;
395
+ if (inList)
396
+ resourceEnd = commandEnd;
397
+ }
398
+ if (redirect === "<<" || redirect === "<<-") {
399
+ const delimiter = bashHeredocDelimiter(input, index);
400
+ if (!delimiter)
401
+ return { kind: "opaque", reason: "invalid-redirect" };
402
+ heredocs.push(delimiter);
403
+ wordEnd = delimiter.end + 1;
404
+ index = delimiter.end;
405
+ redirectTarget = false;
406
+ continue;
407
+ }
241
408
  redirectTarget = true;
242
409
  index += redirect.length - 1;
243
410
  continue;
244
411
  }
245
- if ("()".includes(char) || char === "!" && !wordStarted)
246
- compound = true;
247
- if (/\s/.test(char) && char !== `
248
- `) {
412
+ if (structures.at(-1)?.phase === "pattern" && (char === ")" || char === "|")) {
413
+ finishWord();
414
+ index--;
415
+ continue;
416
+ }
417
+ if ("()".includes(char))
418
+ return { kind: "opaque", reason: "compound-command" };
419
+ if (/\s/.test(char) && !`
420
+ `.includes(char))
421
+ return { kind: "opaque", reason: "invalid-structure" };
422
+ if (char === " " || char === "\t") {
249
423
  finishWord();
250
424
  continue;
251
425
  }
@@ -253,315 +427,578 @@ function scanBash(input, depth) {
253
427
  const separator = char === "&" && next === "&" || char === "|" && (next === "|" || next === "&") ? char + next : char === ";" || char === "|" || char === "&" || char === `
254
428
  ` ? char : undefined;
255
429
  if (separator) {
256
- finishCommand(index, true);
257
- if (redirectTarget)
258
- invalidRedirect = true;
259
- terminalBackground = separator === "&" || separator === ";" || separator === `
430
+ const structure = structures.at(-1);
431
+ if (char === ";" && structure?.kind === "case" && structure.phase === "body" && (next === ";" || next === "&")) {
432
+ if (wordStarted || words.length || hasRedirect || compoundEnd)
433
+ finishCommand();
434
+ structure.phase = "pattern";
435
+ index += input.startsWith(";;&", index) ? 2 : 1;
436
+ segment = index + 1;
437
+ inList = false;
438
+ continue;
439
+ }
440
+ if (separator === `
441
+ ` && !wordStarted && words.length === 0 && !hasRedirect && !compoundEnd) {
442
+ if (heredocs.length) {
443
+ for (const heredoc of heredocs.splice(0)) {
444
+ const body = bashHeredoc(input, index + 1, heredoc);
445
+ if (!body)
446
+ return { kind: "opaque", reason: "heredoc" };
447
+ if (heredoc.command)
448
+ heredoc.command.resource = input.slice(heredoc.start, body.end).trim();
449
+ if (!heredoc.quoted) {
450
+ const expansion = bashExpansion(body.source, 0, depth, "heredoc");
451
+ if (!expansion)
452
+ return { kind: "opaque", reason: "command-substitution" };
453
+ const failure = addSubstitutions(expansion);
454
+ if (failure)
455
+ return failure;
456
+ commands.push(...nestedCommands.splice(0));
457
+ }
458
+ index = body.end;
459
+ }
460
+ }
461
+ segment = index + 1;
462
+ continue;
463
+ }
464
+ finishCommand(true);
465
+ if (structure?.kind === "for" && structure.phase === "header")
466
+ structure.phase = "do";
467
+ dangling = separator !== "&" && separator !== ";" && separator !== `
260
468
  `;
469
+ inList = dangling;
470
+ if (separator === `
471
+ ` && heredocs.length) {
472
+ index--;
473
+ continue;
474
+ }
261
475
  index += separator.length - 1;
262
476
  segment = index + 1;
263
477
  continue;
264
478
  }
265
- terminalBackground = false;
266
479
  wordStarted = true;
267
- if (char === "=" && !assignmentHeadUnsafe && /^[A-Za-z_][A-Za-z0-9_]*\+?$/.test(word))
480
+ if (char === "=" && !assignmentHeadUnsafe && /^[A-Za-z_][A-Za-z0-9_]*(?:\[.*\])?\+?$/.test(word))
268
481
  assignmentWord = true;
269
482
  word += char;
483
+ wordEnd = index + 1;
270
484
  }
271
485
  if (quote)
272
486
  return { kind: "opaque", reason: "unterminated-quote" };
273
- if (heredoc)
487
+ if (heredocs.length)
274
488
  return { kind: "opaque", reason: "heredoc" };
275
- if (!terminalBackground && (comment === undefined || input.includes(`
276
- `, comment)))
277
- finishCommand(input.length);
278
- if (redirectTarget)
279
- invalidRedirect = true;
280
- if (separated && !terminalBackground && comment === undefined && !input.slice(segment).trim())
489
+ if (wordStarted || words.length > 0 || hasRedirect) {
490
+ finishCommand();
491
+ dangling = false;
492
+ }
493
+ if (dangling)
281
494
  invalidStructure = true;
282
495
  if (invalidStructure)
283
496
  return { kind: "opaque", reason: "invalid-structure" };
284
497
  if (invalidRedirect)
285
498
  return { kind: "opaque", reason: "invalid-redirect" };
286
- const conditional = bashConditionalCommands(commands);
287
- if (conditional)
288
- commands.splice(0, commands.length, ...conditional);
289
- if (compound || commands.some((command) => BASH_COMPOUND_KEYWORDS.has(command.words[0] ?? "")))
499
+ if (structures.length)
290
500
  return { kind: "opaque", reason: "compound-command" };
291
- if (commands.some((command) => /[$`]/.test(command.words[0] ?? "")))
292
- return { kind: "opaque", reason: "dynamic-command-name" };
293
- if (commands.some((command) => command.words[0]?.startsWith("=")))
294
- return { kind: "opaque", reason: "dynamic-command-name" };
295
501
  return { kind: "scanned", commands };
296
502
  }
297
- function bashConditionalCommands(commands) {
298
- if (commands[0]?.words[0] !== "if" || commands.at(-1)?.words[0] !== "fi")
503
+ function bashDelimited(input, start, depth) {
504
+ if (depth >= MAX_SUBSTITUTION_DEPTH)
299
505
  return;
300
- const keywords = new Set(["if", "then", "elif", "else", "fi"]);
301
- if (commands.some((command) => BASH_COMPOUND_KEYWORDS.has(command.words[0] ?? "") && !keywords.has(command.words[0])))
302
- return;
303
- const normalized = [];
304
- let phase = "condition";
305
- let hasCommand = false;
306
- let sawElse = false;
307
- for (const [index, command] of commands.entries()) {
308
- const keyword = command.words[0];
309
- if (!keywords.has(keyword ?? "")) {
310
- normalized.push(command);
311
- hasCommand = true;
312
- continue;
313
- }
314
- const offset = command.resource.indexOf(keyword) + keyword.length;
315
- const inline = command.words.length > 1 ? { resource: command.resource.slice(offset).trim(), words: command.words.slice(1) } : undefined;
316
- if (index === 0) {
317
- if (inline)
318
- normalized.push(inline);
319
- hasCommand = Boolean(inline);
320
- continue;
321
- }
322
- if (keyword === "then") {
323
- if (phase !== "condition" || !hasCommand)
324
- return;
325
- phase = "body";
326
- hasCommand = Boolean(inline);
506
+ const close = input[start] === "{" ? "}" : ")";
507
+ const cases = [];
508
+ const heredocs = [];
509
+ let commandStart = true;
510
+ for (let index = start + 1;index < input.length; index++) {
511
+ const char = input[index];
512
+ if (char === "\\") {
513
+ if (input[index + 1] !== `
514
+ `)
515
+ commandStart = false;
516
+ index++;
517
+ continue;
327
518
  }
328
- if (keyword === "elif") {
329
- if (phase !== "body" || !hasCommand || sawElse)
519
+ if (char === "'" || char === '"' || char === "`" || char === "$" && `({['"`.includes(input[index + 1] ?? "\x00")) {
520
+ commandStart = false;
521
+ if (char === "'" || input.startsWith("$'", index)) {
522
+ const end = char === "'" ? input.indexOf("'", index + 1) : bashAnsiQuote(input, index + 1)?.end;
523
+ if (end === undefined || end < 0)
524
+ return;
525
+ index = end;
526
+ continue;
527
+ }
528
+ const nested = char === '"' || input.startsWith('$"', index) ? bashExpansion(input, index + (char === "$" ? 1 : 0), depth + 1, "double") : bashExpansion(input, index, depth + 1);
529
+ if (!nested)
330
530
  return;
331
- phase = "condition";
332
- hasCommand = Boolean(inline);
531
+ index = nested.end;
532
+ continue;
333
533
  }
334
- if (keyword === "else") {
335
- if (phase !== "body" || !hasCommand || sawElse)
534
+ const boundary = index === start + 1 || /[ \t\n;|&(){}]/.test(input[index - 1]);
535
+ if (char === "#" && boundary) {
536
+ const newline = input.indexOf(`
537
+ `, index);
538
+ if (newline < 0)
336
539
  return;
337
- phase = "else";
338
- sawElse = true;
339
- hasCommand = Boolean(inline);
540
+ index = newline - 1;
541
+ continue;
340
542
  }
341
- if (keyword === "fi") {
342
- if (index !== commands.length - 1 || phase === "condition" || !hasCommand || inline)
543
+ if (input.startsWith("<<<", index)) {
544
+ index += 2;
545
+ continue;
546
+ }
547
+ if (input.startsWith("<<", index)) {
548
+ const delimiter = bashHeredocDelimiter(input, index);
549
+ if (!delimiter)
343
550
  return;
551
+ heredocs.push(delimiter);
552
+ index = delimiter.end;
344
553
  continue;
345
554
  }
346
- if (inline)
347
- normalized.push(inline);
348
- }
349
- return normalized;
350
- }
351
- function bashLeadingGroup(input) {
352
- const start = input.search(/\S/);
353
- if (start < 0)
354
- return;
355
- if (input[start] === "{") {
356
- const group = bashBraced(input, start);
357
- if (!group)
358
- return;
359
- const source = group.source.trim();
360
- if (!source.endsWith(";"))
361
- return;
362
- return { source: source.slice(0, -1), end: group.end };
363
- }
364
- if (input[start] !== "(")
365
- return;
366
- return bashParenthesized(input, start);
367
- }
368
- function bashBraced(input, start) {
369
- let quote;
370
- let level = 1;
371
- for (let index = start + 1;index < input.length; index++) {
372
- const char = input[index];
373
- if (quote === "single") {
374
- if (char === "'")
375
- quote = undefined;
555
+ if (char === `
556
+ ` && heredocs.length) {
557
+ for (const heredoc of heredocs.splice(0)) {
558
+ const body = bashHeredoc(input, index + 1, heredoc);
559
+ if (!body)
560
+ return;
561
+ index = body.end;
562
+ }
563
+ commandStart = true;
376
564
  continue;
377
565
  }
378
- if (char === "\\") {
379
- index++;
566
+ const token = boundary ? /^[A-Za-z_][A-Za-z0-9_]*(?=[ \t\n;()<>]|$)/.exec(input.slice(index))?.[0] : undefined;
567
+ if (token === "case" && commandStart)
568
+ cases.push("header");
569
+ if (token === "in" && cases.at(-1) === "header")
570
+ cases[cases.length - 1] = "pattern";
571
+ if (token === "esac" && (commandStart || cases.at(-1) === "pattern"))
572
+ cases.pop();
573
+ if (token) {
574
+ commandStart = commandStart && ["if", "while", "until", "then", "elif", "else", "do"].includes(token);
575
+ index += token.length - 1;
380
576
  continue;
381
577
  }
382
- if (char === "'") {
383
- quote = "single";
578
+ if (cases.length && char === ";" && /[;&]/.test(input[index + 1] ?? ""))
579
+ cases[cases.length - 1] = "pattern";
580
+ if (cases.at(-1) === "pattern" && char === "(")
581
+ continue;
582
+ if (cases.at(-1) === "pattern" && char === ")") {
583
+ cases[cases.length - 1] = "body";
584
+ commandStart = true;
384
585
  continue;
385
586
  }
386
- if (char === '"') {
387
- quote = quote === "double" ? undefined : "double";
587
+ if (input.startsWith("((", index)) {
588
+ const nested = bashExpansion(input, index, depth + 1, "arithmetic");
589
+ if (!nested)
590
+ return;
591
+ index = nested.end;
592
+ commandStart = false;
388
593
  continue;
389
594
  }
390
- if (char === "{" && quote !== "double")
391
- level++;
392
- if (char !== "}" || quote === "double" || --level)
595
+ if (char === "(" || char === "{" && boundary && /[ \t\n]/.test(input[index + 1] ?? "")) {
596
+ const nested = bashDelimited(input, index, depth + 1);
597
+ if (!nested)
598
+ return;
599
+ index = nested.end;
600
+ commandStart = false;
393
601
  continue;
394
- return { source: input.slice(start + 1, index), end: index };
602
+ }
603
+ if (char === close && (close === ")" || boundary))
604
+ return { source: input.slice(start + 1, index), end: index };
605
+ if (/[\n;&|]/.test(char))
606
+ commandStart = true;
607
+ else if (!/[ \t]/.test(char))
608
+ commandStart = false;
395
609
  }
396
610
  }
397
- function bashParenthesized(input, start) {
398
- let quote;
399
- let level = 1;
400
- for (let index = start + 1;index < input.length; index++) {
611
+ function bashExpansion(input, start, depth, mode, quoted = false) {
612
+ if (depth >= MAX_SUBSTITUTION_DEPTH)
613
+ return;
614
+ if (!mode && input[start] === "`") {
615
+ let source = "";
616
+ for (let index = start + 1;index < input.length; index++) {
617
+ if (input[index] === "`")
618
+ return { source, end: index };
619
+ if (input[index] === "\\" && "$`\\\n".includes(input[index + 1] ?? "\x00")) {
620
+ if (input[++index] !== `
621
+ `)
622
+ source += input[index];
623
+ continue;
624
+ }
625
+ source += input[index];
626
+ }
627
+ return;
628
+ }
629
+ if (!mode && input.startsWith("$(", start) && !input.startsWith("$((", start))
630
+ return bashDelimited(input, start + 1, depth);
631
+ if (!mode && /^\$\{[ \t\n|]/.test(input.slice(start))) {
632
+ const nested = bashDelimited(input, start + 1, depth);
633
+ if (!nested)
634
+ return;
635
+ return { ...nested, source: nested.source.startsWith("|") ? nested.source.slice(1) : nested.source };
636
+ }
637
+ const kind = mode ?? (input[start + 1] === "{" ? "parameter" : input[start + 1] === "[" ? "subscript" : "arithmetic");
638
+ const arithmetic = ["arithmetic", "arithmetic-group", "subscript"].includes(kind);
639
+ const offset = mode ? kind === "heredoc" ? 0 : kind === "arithmetic" || kind === "test" ? 2 : 1 : kind === "arithmetic" ? 3 : 2;
640
+ const close = kind === "heredoc" ? undefined : kind === "double" ? '"' : kind === "parameter" ? "}" : kind === "subscript" ? "]" : kind === "test" ? "]]" : kind === "arithmetic" ? "))" : ")";
641
+ const substitutions = [];
642
+ for (let index = start + offset;index < input.length; index++) {
401
643
  const char = input[index];
402
- if (quote === "single") {
403
- if (char === "'")
404
- quote = undefined;
644
+ if (close && input.startsWith(close, index))
645
+ return { source: input.slice(start + offset, index), end: index + close.length - 1, substitutions };
646
+ if (char === "\\") {
647
+ if (kind !== "heredoc" && kind !== "double" || '$`\\\n"'.includes(input[index + 1] ?? "\x00"))
648
+ index++;
405
649
  continue;
406
650
  }
407
- if (char === "\\") {
408
- index++;
651
+ if ((char === "'" || input.startsWith("$'", index)) && kind !== "double" && kind !== "heredoc" && !arithmetic && !(kind === "parameter" && quoted)) {
652
+ const end = char === "'" ? input.indexOf("'", index + 1) : bashAnsiQuote(input, index + 1)?.end;
653
+ if (end === undefined || end < 0)
654
+ return;
655
+ index = end;
409
656
  continue;
410
657
  }
411
- if (char === "'") {
412
- quote = "single";
658
+ if (char === '"' && kind !== "heredoc") {
659
+ const nested = bashExpansion(input, index, depth + 1, "double");
660
+ if (!nested)
661
+ return;
662
+ substitutions.push(...nested.substitutions);
663
+ index = nested.end;
413
664
  continue;
414
665
  }
415
- if (char === '"') {
416
- quote = quote === "double" ? undefined : "double";
666
+ if (char === "`" || char === "$" && "({[".includes(input[index + 1] ?? "\x00")) {
667
+ const nested = bashExpansion(input, index, depth + 1, undefined, kind === "double" || quoted);
668
+ if (!nested)
669
+ return;
670
+ substitutions.push(...nested.substitutions ?? [nested.source]);
671
+ index = nested.end;
417
672
  continue;
418
673
  }
419
- if (char === "(" && quote !== "double")
420
- level++;
421
- if (char !== ")" || quote === "double" || --level)
674
+ if (kind === "array" && "<>=".includes(char) && input[index + 1] === "(") {
675
+ const nested = bashDelimited(input, index + 1, depth + 1);
676
+ if (!nested)
677
+ return;
678
+ substitutions.push(nested.source);
679
+ index = nested.end;
680
+ continue;
681
+ }
682
+ if ((arithmetic || kind === "array" || kind === "pattern") && (char === "(" || char === "[") || kind === "parameter" && char === "[" && /^[!#]?[A-Za-z_][A-Za-z0-9_]*$/.test(input.slice(start + offset, index))) {
683
+ const nested = bashExpansion(input, index, depth + 1, char === "[" ? "subscript" : arithmetic ? "arithmetic-group" : kind);
684
+ if (!nested)
685
+ return;
686
+ substitutions.push(...nested.substitutions);
687
+ index = nested.end;
422
688
  continue;
423
- return { source: input.slice(start + 1, index), end: index };
689
+ }
690
+ if (!mode && kind === "arithmetic" && char === ";")
691
+ return;
424
692
  }
693
+ if (kind === "heredoc")
694
+ return { source: input.slice(start), end: input.length - 1, substitutions };
425
695
  }
426
- function bashSubstitution(input, start) {
427
- if (input[start] === "`") {
428
- for (let index = start + 1;index < input.length; index++) {
429
- if (input[index] === "\\")
430
- index++;
431
- else if (input[index] === "`")
432
- return { source: input.slice(start + 1, index).replaceAll("\\`", "`"), end: index };
696
+ function bashAnsiQuote(input, start) {
697
+ let value = "";
698
+ for (let index = start + 1;index < input.length; index++) {
699
+ if (input[index] === "'")
700
+ return { value, end: index };
701
+ if (input[index] !== "\\") {
702
+ value += input[index];
703
+ continue;
704
+ }
705
+ const escaped = input[++index];
706
+ const simple = {
707
+ a: "\x07",
708
+ b: "\b",
709
+ e: "\x1B",
710
+ E: "\x1B",
711
+ f: "\f",
712
+ n: `
713
+ `,
714
+ r: "\r",
715
+ t: "\t",
716
+ v: "\v",
717
+ "\\": "\\",
718
+ "'": "'",
719
+ '"': '"',
720
+ "?": "?"
721
+ };
722
+ if (escaped in simple)
723
+ value += simple[escaped];
724
+ else if (escaped === "c" && index + 1 < input.length)
725
+ value += String.fromCharCode(input[++index].toUpperCase().charCodeAt(0) & 31);
726
+ else {
727
+ const digits = escaped === "x" ? /^[\da-fA-F]{1,2}/.exec(input.slice(index + 1))?.[0] : escaped === "u" ? /^[\da-fA-F]{1,4}/.exec(input.slice(index + 1))?.[0] : escaped === "U" ? /^[\da-fA-F]{1,8}/.exec(input.slice(index + 1))?.[0] : /[0-7]/.test(escaped ?? "") ? /^[0-7]{1,3}/.exec(input.slice(index))?.[0] : undefined;
728
+ if (!digits)
729
+ value += `\\${escaped}`;
730
+ else {
731
+ const octal = /[0-7]/.test(escaped);
732
+ const point = parseInt(digits, octal ? 8 : 16);
733
+ value += point <= 1114111 ? String.fromCodePoint(point) : "";
734
+ index += digits.length - (octal ? 1 : 0);
735
+ }
433
736
  }
434
- return;
435
737
  }
436
- if (input.slice(start, start + 3) === "$((")
437
- return;
738
+ }
739
+ function bashHeredocDelimiter(input, start) {
740
+ const tabs = input[start + 2] === "-";
741
+ let delimiter = "";
742
+ let quoted = false;
438
743
  let quote;
439
- let level = 1;
440
- for (let index = start + 2;index < input.length; index++) {
744
+ let end = start;
745
+ let started = false;
746
+ for (let index = start + (tabs ? 3 : 2);index < input.length; index++) {
441
747
  const char = input[index];
442
- if (quote === "single") {
443
- if (char === "'")
444
- quote = undefined;
748
+ if (!started && /[ \t]/.test(char))
445
749
  continue;
446
- }
447
- if (char === "\\") {
448
- index++;
750
+ if (!started && char === "#")
751
+ return;
752
+ if (!quote && /[ \t\n;&|()<>]/.test(char))
753
+ return started ? { delimiter, quoted, tabs, end } : undefined;
754
+ if (!quote && input.startsWith("$'", index)) {
755
+ const literal = bashAnsiQuote(input, index + 1);
756
+ if (!literal)
757
+ return;
758
+ delimiter += literal.value;
759
+ quoted = true;
760
+ started = true;
761
+ index = literal.end;
762
+ end = index;
449
763
  continue;
450
764
  }
451
- if (char === "'") {
452
- quote = "single";
765
+ if (!quote && input.startsWith('$"', index)) {
766
+ quote = '"';
767
+ quoted = true;
768
+ started = true;
769
+ end = ++index;
453
770
  continue;
454
771
  }
455
- if (quote !== "double" && char === "#" && (index === start + 2 || /[\s;&|()]/.test(input[index - 1] ?? "")))
456
- return;
457
- if (char === '"') {
458
- quote = quote === "double" ? undefined : "double";
772
+ if (char === quote) {
773
+ quote = undefined;
774
+ end = index;
459
775
  continue;
460
776
  }
461
- if (char === "`" && quote !== "double") {
462
- const nested = bashSubstitution(input, index);
463
- if (!nested)
777
+ if (char === "\\" && quote !== "'") {
778
+ const next = input[index + 1];
779
+ if (next === undefined)
464
780
  return;
465
- index = nested.end;
466
- continue;
467
- }
468
- if (quote === "double") {
469
- if (char === "$" && input[index + 1] === "(") {
470
- level++;
781
+ if (next === `
782
+ `) {
471
783
  index++;
472
- } else if (char === ")" && level > 1)
473
- level--;
784
+ continue;
785
+ }
786
+ if (!quote || '$`"\\'.includes(next)) {
787
+ quoted = true;
788
+ started = true;
789
+ delimiter += input[++index];
790
+ end = index;
791
+ continue;
792
+ }
793
+ }
794
+ if (!quote && (char === "'" || char === '"')) {
795
+ quote = char;
796
+ quoted = true;
797
+ started = true;
798
+ end = index;
474
799
  continue;
475
800
  }
476
- if (char === "(")
477
- level++;
478
- if (char !== ")" || --level)
801
+ delimiter += char;
802
+ started = true;
803
+ end = index;
804
+ }
805
+ if (started && !quote)
806
+ return { delimiter, quoted, tabs, end };
807
+ }
808
+ function bashHeredoc(input, start, delimiter) {
809
+ const bodyStart = start;
810
+ let lineStart = start;
811
+ let line = "";
812
+ for (let index = start;index <= input.length; index++) {
813
+ if (index < input.length && input[index] !== `
814
+ `)
479
815
  continue;
480
- return { source: input.slice(start + 2, index), end: index };
816
+ const text = input.slice(start, index);
817
+ line += delimiter.tabs ? text.replace(/^\t+/, "") : text;
818
+ if (!delimiter.quoted && /(?<!\\)(?:\\\\)*\\$/.test(line) && index < input.length) {
819
+ line = line.slice(0, -1);
820
+ start = index + 1;
821
+ continue;
822
+ }
823
+ if (line === delimiter.delimiter)
824
+ return { source: input.slice(bodyStart, lineStart), end: index };
825
+ line = "";
826
+ start = index + 1;
827
+ lineStart = start;
481
828
  }
482
829
  }
483
830
  function scanPowerShell(input) {
484
- return scanPowerShellNested(input, 0);
831
+ return scanPowerShellNested(input, 0, { remaining: MAX_INPUT_LENGTH * MAX_SUBSTITUTION_DEPTH });
485
832
  }
486
- function scanPowerShellNested(input, depth) {
487
- if (input.length > MAX_BASH_INPUT_LENGTH || depth >= MAX_SUBSTITUTION_DEPTH)
833
+ function scanPowerShellNested(input, depth, budget, hash = false) {
834
+ budget.remaining -= input.length;
835
+ if (input.length > MAX_INPUT_LENGTH || depth >= MAX_SUBSTITUTION_DEPTH || budget.remaining < 0)
836
+ return { kind: "opaque", reason: "invalid-structure" };
837
+ if (/[\0\u0085\u2013-\u2015\u2018-\u201e\ufeff]/.test(input))
488
838
  return { kind: "opaque", reason: "invalid-structure" };
489
839
  const commands = [];
490
840
  const nestedCommands = [];
491
841
  const words = [];
842
+ const rawWords = [];
843
+ const wordEnds = [];
492
844
  let segment = 0;
493
845
  let word = "";
494
846
  let started = false;
847
+ let wordStart = 0;
495
848
  let quote;
496
- let dynamic = false;
849
+ let standalone = false;
850
+ let expression = hash;
851
+ let compound = false;
852
+ let stopParsing = false;
853
+ let commandEnd = 0;
854
+ let statementHead = true;
497
855
  let invalid = false;
498
856
  let redirectTarget = false;
499
857
  let comment = false;
500
- let separated = false;
501
858
  let dangling = false;
502
- const finishWord = () => {
859
+ let invocation = false;
860
+ const finishWord = (end) => {
503
861
  if (!started)
504
862
  return;
505
- if (!redirectTarget)
863
+ if (word === "--%" && words.length > 0 && !expression && !/['"]/.test(input[wordStart]))
864
+ stopParsing = true;
865
+ if (!redirectTarget) {
866
+ if (!words.length && !invocation && !expression)
867
+ segment = wordStart;
506
868
  words.push(word);
869
+ rawWords.push(input.slice(wordStart, end));
870
+ wordEnds.push(end);
871
+ dangling = false;
872
+ }
873
+ commandEnd = end;
507
874
  redirectTarget = false;
508
875
  word = "";
509
876
  started = false;
510
877
  };
511
- const finishCommand = (end, boundary = false) => {
512
- finishWord();
513
- const resource = input.slice(segment, end).trim();
514
- if (resource)
515
- commands.push({ resource, words: [...words] });
516
- else if (boundary && separated)
878
+ const finishCommand = (end, required = false) => {
879
+ finishWord(end);
880
+ const start = segment + input.slice(segment, commandEnd).search(/\S|$/);
881
+ const resource = input.slice(start, commandEnd).trimEnd();
882
+ if (words.length && !expression)
883
+ commands.push({
884
+ resource,
885
+ words: [...words],
886
+ rawWords: [...rawWords],
887
+ wordEnds: wordEnds.map((end2) => end2 - start),
888
+ ...statementHead && !invocation ? { statementHead: true } : {}
889
+ });
890
+ else if (!expression && invocation || required && !words.length && !nestedCommands.length)
891
+ invalid = true;
892
+ if (redirectTarget)
517
893
  invalid = true;
518
894
  commands.push(...nestedCommands.splice(0));
519
895
  words.length = 0;
520
- separated ||= Boolean(resource);
896
+ rawWords.length = 0;
897
+ wordEnds.length = 0;
898
+ redirectTarget = false;
899
+ invocation = false;
900
+ expression = hash;
901
+ compound = false;
902
+ stopParsing = false;
521
903
  };
522
904
  for (let index = 0;index < input.length; index++) {
523
905
  const char = input[index];
524
- if (quote) {
906
+ if (!started)
907
+ wordStart = index;
908
+ if (stopParsing) {
909
+ const stop = powerShellStopParsing(input, index);
910
+ const text = input.slice(index, stop).trim();
911
+ if (text) {
912
+ wordStart = index + input.slice(index, stop).search(/\S/);
913
+ word = text;
914
+ started = true;
915
+ finishWord(wordStart + text.length);
916
+ }
917
+ stopParsing = false;
918
+ index = stop - 1;
919
+ continue;
920
+ }
921
+ if (quote === "single") {
525
922
  started = true;
526
- if (quote === "single" && char === "'" && input[index + 1] === "'") {
923
+ if (char === "'" && input[index + 1] === "'") {
527
924
  word += "'";
528
925
  index++;
529
- } else if (quote === "single" && char === "'" || quote === "double" && char === '"')
926
+ } else if (char === "'") {
530
927
  quote = undefined;
531
- else if (char === "`" && index + 1 < input.length)
532
- word += input[++index];
533
- else {
534
- if (quote === "double" && char === "$" && input[index + 1] === "(")
535
- dynamic = true;
928
+ if (standalone)
929
+ finishWord(index + 1);
930
+ } else
931
+ word += char;
932
+ continue;
933
+ }
934
+ if (quote === "double") {
935
+ if (char === '"' && input[index + 1] === '"') {
936
+ word += '"';
937
+ index++;
938
+ } else if (char === '"') {
939
+ quote = undefined;
940
+ if (standalone)
941
+ finishWord(index + 1);
942
+ } else if (char === "`") {
943
+ const escape = powerShellEscape(input, index);
944
+ if (!escape)
945
+ return { kind: "opaque", reason: "unterminated-escape" };
946
+ word += escape.value;
947
+ index = escape.end;
948
+ } else if (char === "$" && input[index + 1] === "(") {
949
+ const block = powerShellBlock(input, index + 1, depth);
950
+ if (!block)
951
+ return { kind: "opaque", reason: "invalid-structure" };
952
+ const result = scanPowerShellNested(block.source, depth + 1, budget);
953
+ if (result.kind === "opaque")
954
+ return result;
955
+ nestedCommands.push(...result.commands);
956
+ word += input.slice(index, block.end + 1);
957
+ index = block.end;
958
+ } else
536
959
  word += char;
537
- }
538
960
  continue;
539
961
  }
540
962
  if (char === "'" || char === '"') {
963
+ if (!started && words.length === 0 && !invocation)
964
+ expression = true;
541
965
  quote = char === "'" ? "single" : "double";
966
+ standalone = !started;
542
967
  started = true;
543
968
  continue;
544
969
  }
545
- if (char === "`" && index + 1 < input.length) {
546
- if (input[index + 1] === "\r" || input[index + 1] === `
547
- `)
548
- return { kind: "opaque", reason: "invalid-structure" };
549
- if (";&|".includes(input[index + 1]))
550
- return { kind: "opaque", reason: "invalid-structure" };
551
- if (words.length === 0)
552
- dynamic = true;
970
+ if (char === "`") {
971
+ const escape = powerShellEscape(input, index);
972
+ if (!escape)
973
+ return { kind: "opaque", reason: "unterminated-escape" };
974
+ if (started || /\S/.test(escape.value)) {
975
+ started = true;
976
+ word += escape.value;
977
+ }
978
+ index = escape.end;
979
+ continue;
980
+ }
981
+ if (!started && words.length > 0 && !expression && /^--%(?=$|[\s;|&(){}])/.test(input.slice(index))) {
982
+ word = "--%";
553
983
  started = true;
554
- word += input[++index];
984
+ finishWord(index + 3);
985
+ stopParsing = true;
986
+ index += 2;
555
987
  continue;
556
988
  }
557
- if (char === "`")
558
- return { kind: "opaque", reason: "unterminated-escape" };
559
- if (char === "<" && input[index + 1] === "#")
560
- return { kind: "opaque", reason: "dynamic-execution" };
561
- if (char === "#" && !started) {
562
- if (/^#requires\b/i.test(input.slice(index)))
563
- return { kind: "opaque", reason: "dynamic-execution" };
564
- finishCommand(index);
989
+ if (char === "<" && input[index + 1] === "#" && !started) {
990
+ const end = powerShellComment(input, index);
991
+ if (end === undefined)
992
+ return { kind: "opaque", reason: "invalid-structure" };
993
+ if (!words.length && !invocation)
994
+ segment = end + 1;
995
+ index = end;
996
+ continue;
997
+ }
998
+ if (char === "#" && (!started || expression)) {
999
+ if (words.length || started || invocation)
1000
+ finishCommand(index);
1001
+ statementHead = !dangling;
565
1002
  comment = true;
566
1003
  const endings = [input.indexOf(`
567
1004
  `, index), input.indexOf("\r", index)].filter((ending) => ending >= 0);
@@ -571,40 +1008,130 @@ function scanPowerShellNested(input, depth) {
571
1008
  comment = false;
572
1009
  index = input[newline] === "\r" && input[newline + 1] === `
573
1010
  ` ? newline + 1 : newline;
574
- segment = newline + 1;
1011
+ segment = index + 1;
575
1012
  continue;
576
1013
  }
577
- const redirect = char === ">" || !started && (char === "*" || /\d/.test(char)) ? powerShellRedirect(input, index) : undefined;
1014
+ const redirect = !started && (char === ">" || char === "*" || /\d/.test(char)) ? powerShellRedirect(input, index) : undefined;
1015
+ if (redirect === false)
1016
+ return { kind: "opaque", reason: "invalid-redirect" };
578
1017
  if (redirect) {
579
- finishWord();
1018
+ if (redirectTarget)
1019
+ return { kind: "opaque", reason: "invalid-redirect" };
1020
+ if (words.length === 0)
1021
+ return { kind: "opaque", reason: "invalid-redirect" };
580
1022
  redirectTarget = !redirect.includes("&");
581
1023
  index += redirect.length - 1;
1024
+ commandEnd = index + 1;
1025
+ continue;
1026
+ }
1027
+ if (!started && !words.length && !invocation && !expression && /[A-Za-z]/.test(char)) {
1028
+ const keyword = /^[A-Za-z]+(?=$|[\s({])/.exec(input.slice(index))?.[0]?.toLowerCase();
1029
+ if (keyword && /^(?:if|elseif|else|for|while|do|until|switch|function|filter|try|catch|finally|begin|process|end|clean|param|trap|class|enum|data|dynamicparam|using)$/.test(keyword)) {
1030
+ expression = true;
1031
+ compound = true;
1032
+ index += keyword.length - 1;
1033
+ continue;
1034
+ }
1035
+ if (keyword === "foreach" && /^foreach\s*\(/i.test(input.slice(index))) {
1036
+ expression = true;
1037
+ compound = true;
1038
+ index += keyword.length - 1;
1039
+ continue;
1040
+ }
1041
+ if (keyword && /^(?:return|throw|exit|break|continue)$/.test(keyword)) {
1042
+ index += keyword.length - 1;
1043
+ segment = index + 1;
1044
+ continue;
1045
+ }
1046
+ }
1047
+ if (expression && !compound && (char === "=" || /[-+*/%]/.test(char) && input[index + 1] === "=")) {
1048
+ finishWord(index);
1049
+ words.length = 0;
1050
+ rawWords.length = 0;
1051
+ wordEnds.length = 0;
1052
+ expression = false;
1053
+ if (char !== "=")
1054
+ index++;
1055
+ segment = index + 1;
1056
+ continue;
1057
+ }
1058
+ if (expression && !started && /^in\b/i.test(input.slice(index))) {
1059
+ words.length = 0;
1060
+ rawWords.length = 0;
1061
+ wordEnds.length = 0;
1062
+ expression = false;
1063
+ index++;
1064
+ segment = index + 1;
582
1065
  continue;
583
1066
  }
584
- if (char === "{" && !started) {
585
- const block = powerShellBlock(input, index);
1067
+ if (char === "@" && /['"]/.test(input[index + 1] ?? "")) {
1068
+ const literal = powerShellHereString(input, index);
1069
+ if (!literal)
1070
+ return { kind: "opaque", reason: "unterminated-quote" };
1071
+ if (!words.length && !invocation)
1072
+ expression = true;
1073
+ if (input[index + 1] === '"') {
1074
+ const result = powerShellExpansions(literal.source, depth + 1, budget);
1075
+ if (result.kind === "opaque")
1076
+ return result;
1077
+ nestedCommands.push(...result.commands);
1078
+ }
1079
+ word = literal.source;
1080
+ started = true;
1081
+ index = literal.end;
1082
+ finishWord(index + 1);
1083
+ continue;
1084
+ }
1085
+ if (char === "$" && input[index + 1] === "{") {
1086
+ const end = input.indexOf("}", index + 2);
1087
+ if (end < 0)
1088
+ return { kind: "opaque", reason: "invalid-structure" };
1089
+ if (!started && !words.length && !invocation)
1090
+ expression = true;
1091
+ word += input.slice(index, end + 1);
1092
+ started = true;
1093
+ index = end;
1094
+ continue;
1095
+ }
1096
+ const opener = (char === "$" || char === "@") && input[index + 1] === "(" ? index + 1 : char === "@" && input[index + 1] === "{" ? index + 1 : char === "(" || char === "{" || char === "[" && (expression || !started) ? index : undefined;
1097
+ if (opener !== undefined) {
1098
+ if (started && (char === "{" || char === "(")) {
1099
+ finishWord(index);
1100
+ wordStart = index;
1101
+ }
1102
+ if (!started && !words.length && !invocation)
1103
+ expression = true;
1104
+ const block = powerShellBlock(input, opener, depth);
586
1105
  if (!block)
587
1106
  return { kind: "opaque", reason: "invalid-structure" };
588
- const result = scanPowerShellNested(block.source, depth + 1);
1107
+ const result = scanPowerShellNested(block.source, depth + 1, budget, input[opener] === "[" || char === "@" && input[opener] === "{");
589
1108
  if (result.kind === "opaque")
590
1109
  return result;
591
- nestedCommands.push(...result.commands.map(markNested));
1110
+ nestedCommands.push(...result.commands);
592
1111
  started = true;
593
1112
  word += input.slice(index, block.end + 1);
594
1113
  index = block.end;
1114
+ if (input[opener] === "{" || char === "(")
1115
+ finishWord(index + 1);
1116
+ if (compound && input[opener] === "{") {
1117
+ finishCommand(index + 1);
1118
+ segment = index + 1;
1119
+ }
595
1120
  continue;
596
1121
  }
597
- if (char === "}")
1122
+ if (char === "}" || char === ")")
598
1123
  return { kind: "opaque", reason: "invalid-structure" };
599
- if (char === "&" && !started && words.length === 0)
600
- continue;
601
- if (char === "." && !started && words.length === 0 && (/\s/.test(input[index + 1] ?? "") || !input[index + 1]))
1124
+ if (!started && words.length === 0 && (char === "&" && input[index + 1] !== "&" || char === "." && (/\s/.test(input[index + 1] ?? "") || !input[index + 1]))) {
1125
+ if (invocation)
1126
+ return { kind: "opaque", reason: "invalid-structure" };
1127
+ invocation = true;
602
1128
  continue;
603
- if ("@()".includes(char))
604
- dynamic = true;
1129
+ }
1130
+ if (!started && !words.length && !invocation && powerShellExpression(input.slice(index)))
1131
+ expression = true;
605
1132
  if (/\s/.test(char) && char !== `
606
1133
  ` && char !== "\r") {
607
- finishWord();
1134
+ finishWord(index);
608
1135
  continue;
609
1136
  }
610
1137
  const next = input[index + 1];
@@ -612,14 +1139,22 @@ function scanPowerShellNested(input, depth) {
612
1139
  ` ? char + next : char === "&" && next === "&" || char === "|" && next === "|" ? char + next : char === ";" || char === "|" || char === "&" || char === `
613
1140
  ` || char === "\r" ? char : undefined;
614
1141
  if (separator) {
615
- finishCommand(index, true);
616
- if (redirectTarget)
617
- invalid = true;
1142
+ if ((separator === `
1143
+ ` || separator === "\r" || separator === `\r
1144
+ `) && !started && !words.length && !invocation) {
1145
+ index += separator.length - 1;
1146
+ segment = index + 1;
1147
+ continue;
1148
+ }
1149
+ finishCommand(index, dangling || ![";", `
1150
+ `, "\r", `\r
1151
+ `].includes(separator));
618
1152
  dangling = ![";", "&", `
619
1153
  `, "\r", `\r
620
1154
  `].includes(separator);
1155
+ statementHead = !dangling;
621
1156
  index += separator.length - 1;
622
- segment = separator === "&" ? index : index + 1;
1157
+ segment = index + 1;
623
1158
  continue;
624
1159
  }
625
1160
  started = true;
@@ -632,76 +1167,263 @@ function scanPowerShellNested(input, depth) {
632
1167
  finishCommand(input.length);
633
1168
  if (redirectTarget || invalid || dangling)
634
1169
  return { kind: "opaque", reason: "invalid-structure" };
635
- const reason = dynamic ? "dynamic-execution" : commands.reduce((result, command) => result ?? powerShellOpaqueReason(command), undefined);
636
- if (reason)
637
- return { kind: "opaque", reason };
1170
+ if (commands.some((command) => !command.words[0]))
1171
+ return { kind: "opaque", reason: "dynamic-command-name" };
638
1172
  return { kind: "scanned", commands };
639
1173
  }
640
- function powerShellBlock(input, start) {
1174
+ function powerShellBlock(input, start, depth) {
1175
+ if (depth >= MAX_SUBSTITUTION_DEPTH)
1176
+ return;
641
1177
  let quote;
642
- let level = 1;
1178
+ let standalone = false;
1179
+ let started = false;
1180
+ let head = true;
1181
+ let expression = false;
1182
+ let token = "";
1183
+ const close = input[start] === "(" ? ")" : input[start] === "[" ? "]" : "}";
643
1184
  for (let index = start + 1;index < input.length; index++) {
644
1185
  const char = input[index];
645
1186
  if (quote === "single") {
646
- if (char === "'" && input[index + 1] === "'")
1187
+ if (char === "'" && input[index + 1] === "'") {
1188
+ token += "'";
1189
+ index++;
1190
+ } else if (char === "'") {
1191
+ quote = undefined;
1192
+ started = !standalone;
1193
+ if (standalone)
1194
+ token = "";
1195
+ } else
1196
+ token += char;
1197
+ continue;
1198
+ }
1199
+ if (quote === "double") {
1200
+ if (char === "`") {
1201
+ const escape = powerShellEscape(input, index);
1202
+ if (!escape)
1203
+ return;
1204
+ token += escape.value;
1205
+ index = escape.end;
1206
+ } else if (char === '"' && input[index + 1] === '"') {
1207
+ token += '"';
647
1208
  index++;
648
- else if (char === "'")
1209
+ } else if (char === '"') {
649
1210
  quote = undefined;
1211
+ started = !standalone;
1212
+ if (standalone)
1213
+ token = "";
1214
+ } else if (char === "$" && input[index + 1] === "(") {
1215
+ const nested = powerShellBlock(input, index + 1, depth + 1);
1216
+ if (!nested)
1217
+ return;
1218
+ index = nested.end;
1219
+ } else
1220
+ token += char;
650
1221
  continue;
651
1222
  }
652
1223
  if (char === "`") {
653
- index++;
1224
+ const escape = powerShellEscape(input, index);
1225
+ if (!escape)
1226
+ return;
1227
+ if (started || /\S/.test(escape.value)) {
1228
+ started = true;
1229
+ token += escape.value;
1230
+ }
1231
+ index = escape.end;
654
1232
  continue;
655
1233
  }
656
- if (char === "#" && quote !== "double") {
657
- const newline = input.indexOf(`
658
- `, index);
1234
+ if (char === "<" && input[index + 1] === "#" && !started) {
1235
+ const end = powerShellComment(input, index);
1236
+ if (end === undefined)
1237
+ return;
1238
+ index = end;
1239
+ continue;
1240
+ }
1241
+ if (char === "#" && (!started || expression)) {
1242
+ const endings = [input.indexOf(`
1243
+ `, index), input.indexOf("\r", index)].filter((ending) => ending >= 0);
1244
+ const newline = endings.length > 0 ? Math.min(...endings) : -1;
659
1245
  if (newline < 0)
660
1246
  return;
661
1247
  index = newline;
1248
+ started = false;
1249
+ head = true;
1250
+ expression = false;
1251
+ token = "";
1252
+ continue;
1253
+ }
1254
+ if (char === "@" && /['"]/.test(input[index + 1] ?? "")) {
1255
+ const literal = powerShellHereString(input, index);
1256
+ if (!literal)
1257
+ return;
1258
+ index = literal.end;
1259
+ started = false;
1260
+ head = false;
1261
+ continue;
1262
+ }
1263
+ if (head && !started && (char === "&" && input[index + 1] !== "&" || char === "." && /\s/.test(input[index + 1] ?? ""))) {
1264
+ head = false;
662
1265
  continue;
663
1266
  }
664
- if (char === "<" && input[index + 1] === "#" && quote !== "double") {
665
- const end = input.indexOf("#>", index + 2);
1267
+ if (expression && (char === "=" || !started && /^in\b/i.test(input.slice(index)))) {
1268
+ if (char !== "=")
1269
+ index++;
1270
+ expression = false;
1271
+ head = true;
1272
+ started = false;
1273
+ token = "";
1274
+ continue;
1275
+ }
1276
+ if (char === "'" || char === '"') {
1277
+ quote = char === "'" ? "single" : "double";
1278
+ standalone = !started;
1279
+ if (head && !started)
1280
+ expression = true;
1281
+ started = true;
1282
+ continue;
1283
+ }
1284
+ const redirect = !started && (char === ">" || char === "*" || /\d/.test(char)) ? powerShellRedirect(input, index) : undefined;
1285
+ if (redirect === false)
1286
+ return;
1287
+ if (redirect) {
1288
+ index += redirect.length - 1;
1289
+ token = "";
1290
+ continue;
1291
+ }
1292
+ if (char === "$" && input[index + 1] === "{") {
1293
+ const end = input.indexOf("}", index + 2);
666
1294
  if (end < 0)
667
1295
  return;
668
- index = end + 1;
1296
+ if (head && !started)
1297
+ expression = true;
1298
+ index = end;
1299
+ started = true;
669
1300
  continue;
670
1301
  }
671
- if (char === "'") {
672
- quote = "single";
1302
+ if (!started && !head && !expression && /^--%(?=$|[\s;|&(){}])/.test(input.slice(index))) {
1303
+ index = powerShellStopParsing(input, index + 3) - 1;
673
1304
  continue;
674
1305
  }
675
- if (char === '"') {
676
- quote = quote === "double" ? undefined : "double";
1306
+ if (char === close)
1307
+ return { source: input.slice(start + 1, index), end: index };
1308
+ if (char === "(" || char === "{" || char === "[" && (!started || expression)) {
1309
+ if (head && !started)
1310
+ expression = true;
1311
+ const nested = powerShellBlock(input, index, depth + 1);
1312
+ if (!nested)
1313
+ return;
1314
+ index = nested.end;
1315
+ started = false;
1316
+ head = false;
1317
+ token = "";
677
1318
  continue;
678
1319
  }
679
- if (char === "{" && quote !== "double")
680
- level++;
681
- if (char !== "}" || quote === "double" || --level)
1320
+ if (/[\s;&|]/.test(char)) {
1321
+ if (token === "--%" && !expression) {
1322
+ index = powerShellStopParsing(input, index) - 1;
1323
+ token = "";
1324
+ continue;
1325
+ }
1326
+ if (/[;&|\r\n]/.test(char)) {
1327
+ head = true;
1328
+ expression = false;
1329
+ } else if (started)
1330
+ head = false;
1331
+ started = false;
1332
+ token = "";
682
1333
  continue;
683
- return { source: input.slice(start + 1, index), end: index };
1334
+ }
1335
+ if (head && !started && powerShellExpression(input.slice(index)))
1336
+ expression = true;
1337
+ started = true;
1338
+ token += char;
684
1339
  }
685
1340
  }
686
- function shellCommandName(word) {
687
- const value = (word ?? "").toLowerCase();
688
- return value.slice(Math.max(value.lastIndexOf("/"), value.lastIndexOf("\\")) + 1);
1341
+ var POWERSHELL_ESCAPES = {
1342
+ "0": "\x00",
1343
+ a: "\x07",
1344
+ b: "\b",
1345
+ e: "\x1B",
1346
+ f: "\f",
1347
+ n: `
1348
+ `,
1349
+ r: "\r",
1350
+ t: "\t",
1351
+ v: "\v"
1352
+ };
1353
+ function powerShellEscape(input, start) {
1354
+ const char = input[start + 1];
1355
+ if (char === undefined)
1356
+ return;
1357
+ if (char === "\r" || char === `
1358
+ `)
1359
+ return {
1360
+ value: char === "\r" && input[start + 2] === `
1361
+ ` ? `\r
1362
+ ` : char,
1363
+ end: start + (char === "\r" && input[start + 2] === `
1364
+ ` ? 2 : 1)
1365
+ };
1366
+ if (char === "u" && input[start + 2] === "{") {
1367
+ const code = /^u\{([0-9a-f]{1,6})\}/i.exec(input.slice(start + 1));
1368
+ if (!code || Number.parseInt(code[1], 16) > 1114111)
1369
+ return;
1370
+ return { value: String.fromCodePoint(Number.parseInt(code[1], 16)), end: start + code[0].length };
1371
+ }
1372
+ return { value: POWERSHELL_ESCAPES[char] ?? char, end: start + 1 };
1373
+ }
1374
+ function powerShellExpression(input) {
1375
+ return /^(?:[$!,+]|[+-]?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?(?:[dDlLnNuU]|[kKmMgGtTpP][bB])?(?![\w'"`])|0[xX][\da-fA-F]+\b|0[bB][01]+\b|\.[0-9]|-(?:not|bnot|join|split)\b)/i.test(input);
1376
+ }
1377
+ function powerShellStopParsing(input, start) {
1378
+ let quoted = false;
1379
+ for (let index = start;index < input.length; index++) {
1380
+ if (input[index] === '"')
1381
+ quoted = !quoted;
1382
+ if (input[index] === "\r" || input[index] === `
1383
+ ` || input[index] === "|" && !quoted)
1384
+ return index;
1385
+ }
1386
+ return input.length;
689
1387
  }
690
- function powerShellOpaqueReason(command) {
691
- const head = command.words[0] ?? "";
692
- if (head.includes("\\") && !/^[A-Za-z]:\\/.test(head) && !/^[A-Za-z_][A-Za-z0-9_.-]*\\[A-Za-z_][A-Za-z0-9_.-]*$/.test(head) || head.includes("$") || head.includes("@"))
693
- return "dynamic-execution";
694
- const name = shellCommandName(head);
695
- if (["return", "throw", "exit", "break", "continue"].includes(name) && command.words.length > 1)
696
- return "dynamic-execution";
697
- if (!POWERSHELL_LOCATIONS.has(name))
1388
+ function powerShellComment(input, start) {
1389
+ const end = input.indexOf("#>", start + 2);
1390
+ return end < 0 ? undefined : end + 1;
1391
+ }
1392
+ function powerShellHereString(input, start) {
1393
+ const header = /^@['"][ \t]*(?:\r\n|\r|\n)/.exec(input.slice(start));
1394
+ if (!header)
698
1395
  return;
699
- if (command.words.some((word, index) => index > 0 && (word.includes("(") || word.includes("$") && !knownPowerShellDirectory(word) || /^[A-Za-z]+:/.test(word) && !/^[A-Za-z]:[\\/]/.test(word))))
700
- return "dynamic-directory";
1396
+ const body = start + header[0].length;
1397
+ for (let index = body;index < input.length; index++) {
1398
+ if (index !== body && input[index - 1] !== "\r" && input[index - 1] !== `
1399
+ `)
1400
+ continue;
1401
+ if (input[index] !== input[start + 1] || input[index + 1] !== "@")
1402
+ continue;
1403
+ const end = index > body && input[index - 1] === `
1404
+ ` && input[index - 2] === "\r" ? index - 2 : index > body ? index - 1 : index;
1405
+ return { source: input.slice(body, end), end: index + 1 };
1406
+ }
701
1407
  }
702
- function knownPowerShellDirectory(word) {
703
- const variable = /^(?:\$(?:PWD|HOME|PSHOME)|\$env:[A-Za-z_][A-Za-z0-9_]*|\$\{env:[^}]+\})(?:[\\/]|$)/i.exec(word);
704
- return Boolean(variable) && !word.slice(variable?.[0].length).includes("$");
1408
+ function powerShellExpansions(input, depth, budget) {
1409
+ const commands = [];
1410
+ for (let index = 0;index < input.length; index++) {
1411
+ if (input[index] === "`") {
1412
+ index++;
1413
+ continue;
1414
+ }
1415
+ if (!input.startsWith("$(", index))
1416
+ continue;
1417
+ const block = powerShellBlock(input, index + 1, depth);
1418
+ if (!block)
1419
+ return { kind: "opaque", reason: "invalid-structure" };
1420
+ const result = scanPowerShellNested(block.source, depth + 1, budget);
1421
+ if (result.kind === "opaque")
1422
+ return result;
1423
+ commands.push(...result.commands);
1424
+ index = block.end;
1425
+ }
1426
+ return { kind: "scanned", commands };
705
1427
  }
706
1428
  function powerShellRedirect(input, index) {
707
1429
  let cursor = index;
@@ -720,14 +1442,11 @@ function powerShellRedirect(input, index) {
720
1442
  while (/\d/.test(input[cursor] ?? ""))
721
1443
  cursor++;
722
1444
  }
723
- return input.slice(index, cursor);
724
- }
725
- function markNested(command) {
726
- return Object.defineProperty({ ...command }, Nested, { value: true });
1445
+ const redirect = input.slice(index, cursor);
1446
+ return /^(?:(?:[1-6]|\*)?>>?|[2-6*]>&1)$/.test(redirect) ? redirect : false;
727
1447
  }
728
1448
  export {
729
1449
  scanPowerShell,
730
1450
  scan,
731
- exports_scan as ShellScan,
732
- Nested
1451
+ exports_scan as ShellScan
733
1452
  };