@poe-platform/safe-bash 0.1.630 → 0.1.632

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 (357) hide show
  1. package/README.md +1 -0
  2. package/dist/office-package/compression.d.ts +19 -0
  3. package/dist/office-package/compression.js +186 -0
  4. package/dist/office-package/runtime.d.ts +11 -0
  5. package/dist/office-package/runtime.js +28 -0
  6. package/dist/safe-bash/chunks/{bz2-B2RXT4EX.js → bz2-ACU4EOVE.js} +2 -2
  7. package/dist/safe-bash/chunks/chunk-2E4KBFO6.js +239 -0
  8. package/dist/safe-bash/chunks/chunk-2E4KBFO6.js.map +7 -0
  9. package/dist/safe-bash/chunks/chunk-3E5M2WEL.js +33 -0
  10. package/dist/safe-bash/chunks/chunk-3E5M2WEL.js.map +7 -0
  11. package/dist/safe-bash/chunks/{chunk-KQ6J7JHQ.js → chunk-3LD67SER.js} +12 -10
  12. package/dist/safe-bash/chunks/{chunk-KQ6J7JHQ.js.map → chunk-3LD67SER.js.map} +1 -1
  13. package/dist/safe-bash/chunks/{chunk-6LSSEOG7.js → chunk-6HNK7Q66.js} +11 -7
  14. package/dist/safe-bash/chunks/{chunk-6LSSEOG7.js.map → chunk-6HNK7Q66.js.map} +1 -1
  15. package/dist/safe-bash/chunks/{chunk-AD7UAP5B.js → chunk-7EEWZY5S.js} +10 -8
  16. package/dist/safe-bash/chunks/{chunk-AD7UAP5B.js.map → chunk-7EEWZY5S.js.map} +1 -1
  17. package/dist/safe-bash/chunks/{chunk-RNKTWFEM.js → chunk-CDBQXRWL.js} +3 -3
  18. package/dist/safe-bash/chunks/{chunk-UYX72YHY.js → chunk-CHHAB5SS.js} +10 -74
  19. package/dist/safe-bash/chunks/{chunk-UYX72YHY.js.map → chunk-CHHAB5SS.js.map} +3 -3
  20. package/dist/safe-bash/chunks/{chunk-6YSBXTTJ.js → chunk-EI4X5ETX.js} +12 -10
  21. package/dist/safe-bash/chunks/{chunk-6YSBXTTJ.js.map → chunk-EI4X5ETX.js.map} +1 -1
  22. package/dist/safe-bash/chunks/{chunk-KZ7QCYNT.js → chunk-GIBLUW2U.js} +13 -9
  23. package/dist/safe-bash/chunks/{chunk-KZ7QCYNT.js.map → chunk-GIBLUW2U.js.map} +1 -1
  24. package/dist/safe-bash/chunks/chunk-GPV7ZFYS.js +1528 -0
  25. package/dist/safe-bash/chunks/chunk-GPV7ZFYS.js.map +7 -0
  26. package/dist/safe-bash/chunks/{chunk-N5CYTGBN.js → chunk-H3E67KTZ.js} +13 -9
  27. package/dist/safe-bash/chunks/{chunk-N5CYTGBN.js.map → chunk-H3E67KTZ.js.map} +1 -1
  28. package/dist/safe-bash/chunks/{chunk-AFH57PPL.js → chunk-IEKESMO4.js} +3 -3
  29. package/dist/safe-bash/chunks/{chunk-DPJWEGIX.js → chunk-JLBIUYT3.js} +2 -2
  30. package/dist/safe-bash/chunks/chunk-JZDO5MC3.js +77 -0
  31. package/dist/safe-bash/chunks/chunk-JZDO5MC3.js.map +7 -0
  32. package/dist/safe-bash/chunks/{chunk-GFZKQIPL.js → chunk-LA6BX562.js} +8 -6
  33. package/dist/safe-bash/chunks/{chunk-GFZKQIPL.js.map → chunk-LA6BX562.js.map} +1 -1
  34. package/dist/safe-bash/chunks/{chunk-PVJJFCGA.js → chunk-M3GPCYSP.js} +2 -2
  35. package/dist/safe-bash/chunks/{chunk-FWDMJTQO.js → chunk-NDCZ3UBP.js} +13 -9
  36. package/dist/safe-bash/chunks/{chunk-FWDMJTQO.js.map → chunk-NDCZ3UBP.js.map} +1 -1
  37. package/dist/safe-bash/chunks/{chunk-2KL6W6NB.js → chunk-O2EVBRKF.js} +1 -2
  38. package/dist/safe-bash/chunks/chunk-OFT77XIB.js +389 -0
  39. package/dist/safe-bash/chunks/chunk-OFT77XIB.js.map +7 -0
  40. package/dist/safe-bash/chunks/{chunk-PCLOK32J.js → chunk-PC6BEIAF.js} +13 -9
  41. package/dist/safe-bash/chunks/{chunk-PCLOK32J.js.map → chunk-PC6BEIAF.js.map} +1 -1
  42. package/dist/safe-bash/chunks/{chunk-3M5F7LD5.js → chunk-QWKP7ZU7.js} +13 -9
  43. package/dist/safe-bash/chunks/{chunk-3M5F7LD5.js.map → chunk-QWKP7ZU7.js.map} +1 -1
  44. package/dist/safe-bash/chunks/chunk-THXJ6CLF.js +53 -0
  45. package/dist/safe-bash/chunks/chunk-THXJ6CLF.js.map +7 -0
  46. package/dist/safe-bash/chunks/{chunk-K7W6Q6FN.js → chunk-V73A742N.js} +58 -16
  47. package/dist/safe-bash/chunks/chunk-V73A742N.js.map +7 -0
  48. package/dist/safe-bash/chunks/{chunk-4BYUV5PA.js → chunk-VN3ZGME3.js} +12 -8
  49. package/dist/safe-bash/chunks/{chunk-4BYUV5PA.js.map → chunk-VN3ZGME3.js.map} +1 -1
  50. package/dist/safe-bash/chunks/{chunk-3BZ5NQ73.js → chunk-WECHUK3Y.js} +369 -36
  51. package/dist/safe-bash/chunks/chunk-WECHUK3Y.js.map +7 -0
  52. package/dist/safe-bash/chunks/{chunk-X55AMTNM.js → chunk-WIOEUR7D.js} +14 -10
  53. package/dist/safe-bash/chunks/{chunk-X55AMTNM.js.map → chunk-WIOEUR7D.js.map} +1 -1
  54. package/dist/safe-bash/chunks/chunk-WPIOO4NX.js +443 -0
  55. package/dist/safe-bash/chunks/chunk-WPIOO4NX.js.map +7 -0
  56. package/dist/safe-bash/chunks/{chunk-C7QNJ3D4.js → chunk-WYTI64IU.js} +2 -2
  57. package/dist/safe-bash/chunks/{xz-AVXFDXW4.js → xz-U4QDTPZL.js} +2 -2
  58. package/dist/safe-bash/chunks/{zstd-R6RPHJYO.js → zstd-OG5RPYXO.js} +2 -2
  59. package/dist/safe-bash/commands/archive/zip/crc.d.ts +2 -0
  60. package/dist/safe-bash/commands/archive/zip/crc.d.ts.map +1 -0
  61. package/dist/safe-bash/commands/archive/zip/crc.js +7 -0
  62. package/dist/safe-bash/commands/archive/zip/crc.js.map +1 -0
  63. package/dist/safe-bash/commands/archive/zip/crypto.d.ts +4 -0
  64. package/dist/safe-bash/commands/archive/zip/crypto.d.ts.map +1 -0
  65. package/dist/safe-bash/commands/archive/zip/crypto.js +34 -0
  66. package/dist/safe-bash/commands/archive/zip/crypto.js.map +1 -0
  67. package/dist/safe-bash/commands/archive/zip/help.d.ts +3 -0
  68. package/dist/safe-bash/commands/archive/zip/help.d.ts.map +1 -0
  69. package/dist/safe-bash/commands/archive/zip/help.js +87 -0
  70. package/dist/safe-bash/commands/archive/zip/help.js.map +1 -0
  71. package/dist/safe-bash/commands/archive/zip/move.d.ts +12 -0
  72. package/dist/safe-bash/commands/archive/zip/move.d.ts.map +1 -0
  73. package/dist/safe-bash/commands/archive/zip/move.js +60 -0
  74. package/dist/safe-bash/commands/archive/zip/move.js.map +1 -0
  75. package/dist/safe-bash/commands/archive/zip/options.js +5 -5
  76. package/dist/safe-bash/commands/archive/zip/options.js.map +1 -1
  77. package/dist/safe-bash/commands/archive/zip-format.d.ts +1 -1
  78. package/dist/safe-bash/commands/archive/zip-format.d.ts.map +1 -1
  79. package/dist/safe-bash/commands/archive/zip-format.js +14 -17
  80. package/dist/safe-bash/commands/archive/zip-format.js.map +1 -1
  81. package/dist/safe-bash/commands/archive/zip.d.ts.map +1 -1
  82. package/dist/safe-bash/commands/archive/zip.js +45 -15
  83. package/dist/safe-bash/commands/archive/zip.js.map +1 -1
  84. package/dist/safe-bash/commands/bytes/compression/bounded-codec.d.ts +2 -0
  85. package/dist/safe-bash/commands/bytes/compression/bounded-codec.d.ts.map +1 -1
  86. package/dist/safe-bash/commands/bytes/compression/bounded-codec.js +4 -0
  87. package/dist/safe-bash/commands/bytes/compression/bounded-codec.js.map +1 -1
  88. package/dist/safe-bash/commands/bytes/compression/codec.d.ts +4 -24
  89. package/dist/safe-bash/commands/bytes/compression/codec.d.ts.map +1 -1
  90. package/dist/safe-bash/commands/bytes/compression/codec.js +12 -168
  91. package/dist/safe-bash/commands/bytes/compression/codec.js.map +1 -1
  92. package/dist/safe-bash/commands/cmp.js +1 -1
  93. package/dist/safe-bash/commands/cmp.js.map +1 -1
  94. package/dist/safe-bash/commands/csplit/index.browser.js +10 -7
  95. package/dist/safe-bash/commands/docx/index.browser.js +54 -0
  96. package/dist/safe-bash/commands/docx/index.browser.js.map +7 -0
  97. package/dist/safe-bash/commands/docx/index.d.ts +25 -0
  98. package/dist/safe-bash/commands/docx/index.d.ts.map +1 -0
  99. package/dist/safe-bash/commands/docx/index.js +42 -0
  100. package/dist/safe-bash/commands/docx/index.js.map +1 -0
  101. package/dist/safe-bash/commands/docx/io.d.ts +15 -0
  102. package/dist/safe-bash/commands/docx/io.d.ts.map +1 -0
  103. package/dist/safe-bash/commands/docx/io.js +16 -0
  104. package/dist/safe-bash/commands/docx/io.js.map +1 -0
  105. package/dist/safe-bash/commands/factor/index.browser.js +7 -5
  106. package/dist/safe-bash/commands/filesystem.d.ts.map +1 -1
  107. package/dist/safe-bash/commands/filesystem.js +9 -1
  108. package/dist/safe-bash/commands/filesystem.js.map +1 -1
  109. package/dist/safe-bash/commands/getopt/index.browser.js +7 -5
  110. package/dist/safe-bash/commands/hexdump/index.browser.js +8 -6
  111. package/dist/safe-bash/commands/iconv/index.browser.js +8 -6
  112. package/dist/safe-bash/commands/line-endings/index.browser.js +10 -7
  113. package/dist/safe-bash/commands/llm/index.browser.js +10 -8
  114. package/dist/safe-bash/commands/llm/providers/index.browser.js +3 -3
  115. package/dist/safe-bash/commands/network/index.browser.js +11 -8
  116. package/dist/safe-bash/commands/node/index.browser.js +8 -6
  117. package/dist/safe-bash/commands/op/index.browser.js +3 -3
  118. package/dist/safe-bash/commands/op/index.js +0 -1
  119. package/dist/safe-bash/commands/op/index.js.map +2 -2
  120. package/dist/safe-bash/commands/pptx/index.d.ts +29 -0
  121. package/dist/safe-bash/commands/pptx/index.d.ts.map +1 -0
  122. package/dist/safe-bash/commands/pptx/index.js +153 -0
  123. package/dist/safe-bash/commands/pptx/index.js.map +1 -0
  124. package/dist/safe-bash/commands/pr/index.browser.js +8 -6
  125. package/dist/safe-bash/commands/predicates.js +1 -1
  126. package/dist/safe-bash/commands/python/execution.d.ts +3 -0
  127. package/dist/safe-bash/commands/python/execution.d.ts.map +1 -0
  128. package/dist/safe-bash/commands/python/execution.js +193 -0
  129. package/dist/safe-bash/commands/python/execution.js.map +1 -0
  130. package/dist/safe-bash/commands/python/index.browser.js +21 -0
  131. package/dist/safe-bash/commands/python/index.browser.js.map +7 -0
  132. package/dist/safe-bash/commands/python/index.d.ts +49 -0
  133. package/dist/safe-bash/commands/python/index.d.ts.map +1 -0
  134. package/dist/safe-bash/commands/python/index.js +317 -0
  135. package/dist/safe-bash/commands/python/index.js.map +1 -0
  136. package/dist/safe-bash/commands/python/installation.d.ts +9 -0
  137. package/dist/safe-bash/commands/python/installation.d.ts.map +1 -0
  138. package/dist/safe-bash/commands/python/installation.js +80 -0
  139. package/dist/safe-bash/commands/python/installation.js.map +1 -0
  140. package/dist/safe-bash/commands/python/invocation.d.ts +10 -0
  141. package/dist/safe-bash/commands/python/invocation.d.ts.map +1 -0
  142. package/dist/safe-bash/commands/python/invocation.js +81 -0
  143. package/dist/safe-bash/commands/python/invocation.js.map +1 -0
  144. package/dist/safe-bash/commands/python/node.d.ts +12 -0
  145. package/dist/safe-bash/commands/python/node.d.ts.map +1 -0
  146. package/dist/safe-bash/commands/python/node.js +33 -0
  147. package/dist/safe-bash/commands/python/node.js.map +1 -0
  148. package/dist/safe-bash/commands/python/provisioning-runtime.d.ts +5 -0
  149. package/dist/safe-bash/commands/python/provisioning-runtime.d.ts.map +1 -0
  150. package/dist/safe-bash/commands/python/provisioning-runtime.js +179 -0
  151. package/dist/safe-bash/commands/python/provisioning-runtime.js.map +1 -0
  152. package/dist/safe-bash/commands/python/provisioning.d.ts +49 -0
  153. package/dist/safe-bash/commands/python/provisioning.d.ts.map +1 -0
  154. package/dist/safe-bash/commands/python/provisioning.js +320 -0
  155. package/dist/safe-bash/commands/python/provisioning.js.map +1 -0
  156. package/dist/safe-bash/commands/python/reply.d.ts +3 -0
  157. package/dist/safe-bash/commands/python/reply.d.ts.map +1 -0
  158. package/dist/safe-bash/commands/python/reply.js +103 -0
  159. package/dist/safe-bash/commands/python/reply.js.map +1 -0
  160. package/dist/safe-bash/commands/python/worker.browser.js +736 -0
  161. package/dist/safe-bash/commands/python/worker.browser.js.map +7 -0
  162. package/dist/safe-bash/commands/python/worker.d.ts +47 -0
  163. package/dist/safe-bash/commands/python/worker.d.ts.map +1 -0
  164. package/dist/safe-bash/commands/python/worker.js +373 -0
  165. package/dist/safe-bash/commands/python/worker.js.map +1 -0
  166. package/dist/safe-bash/commands/tsort/index.browser.js +8 -6
  167. package/dist/safe-bash/commands/xml/index.browser.js +9 -7
  168. package/dist/safe-bash/commands/yq/index.browser.js +10 -8
  169. package/dist/safe-bash/commands/yq/index.d.ts.map +1 -1
  170. package/dist/safe-bash/commands/yq/index.js +32 -4
  171. package/dist/safe-bash/commands/yq/index.js.map +1 -1
  172. package/dist/safe-bash/commands/yq/parser.d.ts.map +1 -1
  173. package/dist/safe-bash/commands/yq/parser.js +21 -5
  174. package/dist/safe-bash/commands/yq/parser.js.map +1 -1
  175. package/dist/safe-bash/contracts/command.d.ts +2 -0
  176. package/dist/safe-bash/contracts/command.d.ts.map +1 -1
  177. package/dist/safe-bash/contracts/command.js +6 -2
  178. package/dist/safe-bash/contracts/command.js.map +1 -1
  179. package/dist/safe-bash/contracts/filesystem-descriptor.d.ts +13 -0
  180. package/dist/safe-bash/contracts/filesystem-descriptor.d.ts.map +1 -0
  181. package/dist/safe-bash/contracts/filesystem-descriptor.js +189 -0
  182. package/dist/safe-bash/contracts/filesystem-descriptor.js.map +1 -0
  183. package/dist/safe-bash/contracts/filesystem-output-budget.d.ts +15 -0
  184. package/dist/safe-bash/contracts/filesystem-output-budget.d.ts.map +1 -0
  185. package/dist/safe-bash/contracts/filesystem-output-budget.js +69 -0
  186. package/dist/safe-bash/contracts/filesystem-output-budget.js.map +1 -0
  187. package/dist/safe-bash/contracts/filesystem-output.d.ts +11 -5
  188. package/dist/safe-bash/contracts/filesystem-output.d.ts.map +1 -1
  189. package/dist/safe-bash/contracts/filesystem-output.js +229 -20
  190. package/dist/safe-bash/contracts/filesystem-output.js.map +1 -1
  191. package/dist/safe-bash/contracts/io.d.ts +29 -0
  192. package/dist/safe-bash/contracts/io.d.ts.map +1 -1
  193. package/dist/safe-bash/contracts/io.js +317 -37
  194. package/dist/safe-bash/contracts/io.js.map +1 -1
  195. package/dist/safe-bash/core.browser.js +5502 -2210
  196. package/dist/safe-bash/core.browser.js.map +4 -4
  197. package/dist/safe-bash/core.d.ts +1 -0
  198. package/dist/safe-bash/core.d.ts.map +1 -1
  199. package/dist/safe-bash/core.js +1 -0
  200. package/dist/safe-bash/core.js.map +1 -1
  201. package/dist/safe-bash/opt-in/commands/cmp/compare.js +95 -0
  202. package/dist/safe-bash/opt-in/commands/cmp/index.d.ts +6 -0
  203. package/dist/safe-bash/opt-in/commands/cmp/index.js +99 -0
  204. package/dist/safe-bash/opt-in/commands/cmp/io.js +218 -0
  205. package/dist/safe-bash/opt-in/commands/cmp/options.d.ts +24 -0
  206. package/dist/safe-bash/opt-in/commands/cmp/options.js +195 -0
  207. package/dist/safe-bash/opt-in/commands/dd/conversions.js +152 -0
  208. package/dist/safe-bash/opt-in/commands/dd/index.d.ts +18 -0
  209. package/dist/safe-bash/opt-in/commands/dd/index.js +561 -0
  210. package/dist/safe-bash/opt-in/commands/dd/io.d.ts +31 -0
  211. package/dist/safe-bash/opt-in/commands/dd/io.js +244 -0
  212. package/dist/safe-bash/opt-in/commands/dd/options.js +184 -0
  213. package/dist/safe-bash/opt-in/commands/dd/report.js +69 -0
  214. package/dist/safe-bash/opt-in/commands/install/arguments.js +224 -0
  215. package/dist/safe-bash/opt-in/commands/install/index.d.ts +6 -0
  216. package/dist/safe-bash/opt-in/commands/install/index.js +678 -0
  217. package/dist/safe-bash/opt-in/commands/install/mode.js +71 -0
  218. package/dist/safe-bash/opt-in/commands/install/options.d.ts +36 -0
  219. package/dist/safe-bash/opt-in/commands/install/options.js +27 -0
  220. package/dist/safe-bash/opt-in/commands/shuf/args.js +179 -0
  221. package/dist/safe-bash/opt-in/commands/shuf/index.d.ts +6 -0
  222. package/dist/safe-bash/opt-in/commands/shuf/index.js +20 -0
  223. package/dist/safe-bash/opt-in/commands/shuf/input.js +93 -0
  224. package/dist/safe-bash/opt-in/commands/shuf/options.d.ts +9 -0
  225. package/dist/safe-bash/opt-in/commands/shuf/options.js +8 -0
  226. package/dist/safe-bash/opt-in/commands/shuf/random.js +114 -0
  227. package/dist/safe-bash/opt-in/commands/shuf/shuf.d.ts +3 -0
  228. package/dist/safe-bash/opt-in/commands/shuf/shuf.js +230 -0
  229. package/dist/safe-bash/opt-in/commands/shuf/usage.js +24 -0
  230. package/dist/safe-bash/opt-in/commands/truncate/arguments.js +186 -0
  231. package/dist/safe-bash/opt-in/commands/truncate/index.d.ts +9 -0
  232. package/dist/safe-bash/opt-in/commands/truncate/index.js +244 -0
  233. package/dist/safe-bash/opt-in/commands/yes/index.d.ts +11 -0
  234. package/dist/safe-bash/opt-in/commands/yes/index.js +167 -0
  235. package/dist/safe-bash/opt-in/commands/yq/arguments.js +177 -0
  236. package/dist/safe-bash/opt-in/commands/yq/evaluate.js +564 -0
  237. package/dist/safe-bash/opt-in/commands/yq/expression.js +183 -0
  238. package/dist/safe-bash/opt-in/commands/yq/inplace.js +65 -0
  239. package/dist/safe-bash/opt-in/commands/yq/mike.d.ts +9 -0
  240. package/dist/safe-bash/opt-in/commands/yq/mike.js +192 -0
  241. package/dist/safe-bash/opt-in/commands/yq/native-encoder.js +165 -0
  242. package/dist/safe-bash/opt-in/commands/yq/native-work.d.ts +44 -0
  243. package/dist/safe-bash/opt-in/commands/yq/native-work.js +188 -0
  244. package/dist/safe-bash/opt-in/commands/yq/nodes.js +621 -0
  245. package/dist/safe-bash/opt-in/entrypoints/arrays.d.ts +1 -0
  246. package/dist/safe-bash/opt-in/entrypoints/arrays.js +1 -0
  247. package/dist/safe-bash/opt-in/entrypoints/cmp.d.ts +2 -0
  248. package/dist/safe-bash/opt-in/entrypoints/cmp.js +1 -0
  249. package/dist/safe-bash/opt-in/entrypoints/dd.d.ts +2 -0
  250. package/dist/safe-bash/opt-in/entrypoints/dd.js +1 -0
  251. package/dist/safe-bash/opt-in/entrypoints/devices.d.ts +2 -0
  252. package/dist/safe-bash/opt-in/entrypoints/devices.js +1 -0
  253. package/dist/safe-bash/opt-in/entrypoints/install.d.ts +2 -0
  254. package/dist/safe-bash/opt-in/entrypoints/install.js +1 -0
  255. package/dist/safe-bash/opt-in/entrypoints/jobs.d.ts +1 -0
  256. package/dist/safe-bash/opt-in/entrypoints/jobs.js +1 -0
  257. package/dist/safe-bash/opt-in/entrypoints/mapfile.d.ts +1 -0
  258. package/dist/safe-bash/opt-in/entrypoints/mapfile.js +1 -0
  259. package/dist/safe-bash/opt-in/entrypoints/read.d.ts +2 -0
  260. package/dist/safe-bash/opt-in/entrypoints/read.js +1 -0
  261. package/dist/safe-bash/opt-in/entrypoints/shuf.d.ts +2 -0
  262. package/dist/safe-bash/opt-in/entrypoints/shuf.js +1 -0
  263. package/dist/safe-bash/opt-in/entrypoints/trap.d.ts +2 -0
  264. package/dist/safe-bash/opt-in/entrypoints/trap.js +1 -0
  265. package/dist/safe-bash/opt-in/entrypoints/truncate.d.ts +2 -0
  266. package/dist/safe-bash/opt-in/entrypoints/truncate.js +1 -0
  267. package/dist/safe-bash/opt-in/entrypoints/yes.d.ts +2 -0
  268. package/dist/safe-bash/opt-in/entrypoints/yes.js +1 -0
  269. package/dist/safe-bash/opt-in/entrypoints/yq.d.ts +3 -0
  270. package/dist/safe-bash/opt-in/entrypoints/yq.js +1 -0
  271. package/dist/safe-bash/opt-in/fs/devices/index.d.ts +8 -0
  272. package/dist/safe-bash/opt-in/fs/devices/index.js +292 -0
  273. package/dist/safe-bash/opt-in/optional.d.ts +28 -0
  274. package/dist/safe-bash/opt-in/optional.js +14 -0
  275. package/dist/safe-bash/opt-in/shell/extensions/arrays/index.d.ts +2 -0
  276. package/dist/safe-bash/opt-in/shell/extensions/arrays/index.js +4 -0
  277. package/dist/safe-bash/opt-in/shell/extensions/jobs/index.d.ts +2 -0
  278. package/dist/safe-bash/opt-in/shell/extensions/jobs/index.js +291 -0
  279. package/dist/safe-bash/opt-in/shell/extensions/jobs/state.js +374 -0
  280. package/dist/safe-bash/opt-in/shell/extensions/mapfile/index.d.ts +24 -0
  281. package/dist/safe-bash/opt-in/shell/extensions/mapfile/index.js +338 -0
  282. package/dist/safe-bash/opt-in/shell/extensions/read/index.d.ts +5 -0
  283. package/dist/safe-bash/opt-in/shell/extensions/read/index.js +351 -0
  284. package/dist/safe-bash/opt-in/shell/extensions/trap/index.d.ts +9 -0
  285. package/dist/safe-bash/opt-in/shell/extensions/trap/index.js +210 -0
  286. package/dist/safe-bash/optional-host.d.ts +5 -0
  287. package/dist/safe-bash/optional-host.d.ts.map +1 -0
  288. package/dist/safe-bash/optional-host.js +3 -0
  289. package/dist/safe-bash/optional-host.js.map +1 -0
  290. package/dist/safe-bash/shell/arrays/bindings.d.ts +15 -5
  291. package/dist/safe-bash/shell/arrays/bindings.d.ts.map +1 -1
  292. package/dist/safe-bash/shell/arrays/bindings.js +131 -23
  293. package/dist/safe-bash/shell/arrays/bindings.js.map +1 -1
  294. package/dist/safe-bash/shell/arrays/ledger.d.ts +1 -0
  295. package/dist/safe-bash/shell/arrays/ledger.d.ts.map +1 -1
  296. package/dist/safe-bash/shell/arrays/ledger.js +19 -0
  297. package/dist/safe-bash/shell/arrays/ledger.js.map +1 -1
  298. package/dist/safe-bash/shell/arrays/state.d.ts.map +1 -1
  299. package/dist/safe-bash/shell/arrays/state.js +3 -1
  300. package/dist/safe-bash/shell/arrays/state.js.map +1 -1
  301. package/dist/safe-bash/shell/arrays/syntax.d.ts +4 -1
  302. package/dist/safe-bash/shell/arrays/syntax.d.ts.map +1 -1
  303. package/dist/safe-bash/shell/arrays/syntax.js +3 -3
  304. package/dist/safe-bash/shell/arrays/syntax.js.map +1 -1
  305. package/dist/safe-bash/shell/conditional.js +1 -1
  306. package/dist/safe-bash/shell/descriptors.d.ts +31 -0
  307. package/dist/safe-bash/shell/descriptors.d.ts.map +1 -0
  308. package/dist/safe-bash/shell/descriptors.js +234 -0
  309. package/dist/safe-bash/shell/descriptors.js.map +1 -0
  310. package/dist/safe-bash/shell/diagnostic-name-ranges.d.ts +2 -0
  311. package/dist/safe-bash/shell/diagnostic-name-ranges.d.ts.map +1 -0
  312. package/dist/safe-bash/shell/diagnostic-name-ranges.js +717 -0
  313. package/dist/safe-bash/shell/diagnostic-name-ranges.js.map +1 -0
  314. package/dist/safe-bash/shell/diagnostic-name.d.ts +3 -0
  315. package/dist/safe-bash/shell/diagnostic-name.d.ts.map +1 -0
  316. package/dist/safe-bash/shell/diagnostic-name.js +89 -0
  317. package/dist/safe-bash/shell/diagnostic-name.js.map +1 -0
  318. package/dist/safe-bash/shell/display.js +1 -1
  319. package/dist/safe-bash/shell/display.js.map +1 -1
  320. package/dist/safe-bash/shell/extensions.d.ts +188 -0
  321. package/dist/safe-bash/shell/extensions.d.ts.map +1 -0
  322. package/dist/safe-bash/shell/extensions.js +141 -0
  323. package/dist/safe-bash/shell/extensions.js.map +1 -0
  324. package/dist/safe-bash/shell/input.d.ts +66 -14
  325. package/dist/safe-bash/shell/input.d.ts.map +1 -1
  326. package/dist/safe-bash/shell/input.js +947 -173
  327. package/dist/safe-bash/shell/input.js.map +1 -1
  328. package/dist/safe-bash/shell/parser.d.ts +38 -6
  329. package/dist/safe-bash/shell/parser.d.ts.map +1 -1
  330. package/dist/safe-bash/shell/parser.js +339 -52
  331. package/dist/safe-bash/shell/parser.js.map +1 -1
  332. package/dist/safe-bash/shell/runtime.d.ts +92 -20
  333. package/dist/safe-bash/shell/runtime.d.ts.map +1 -1
  334. package/dist/safe-bash/shell/runtime.js +2547 -689
  335. package/dist/safe-bash/shell/runtime.js.map +1 -1
  336. package/dist/safe-bash/shell/shell.d.ts.map +1 -1
  337. package/dist/safe-bash/shell/shell.js +52 -21
  338. package/dist/safe-bash/shell/shell.js.map +1 -1
  339. package/dist/safe-bash/shell/types.d.ts +4 -0
  340. package/dist/safe-bash/shell/types.d.ts.map +1 -1
  341. package/dist/safe-bash/shell/types.js.map +1 -1
  342. package/package.json +92 -4
  343. package/dist/safe-bash/chunks/chunk-3BZ5NQ73.js.map +0 -7
  344. package/dist/safe-bash/chunks/chunk-4DBWBEU7.js +0 -194
  345. package/dist/safe-bash/chunks/chunk-4DBWBEU7.js.map +0 -7
  346. package/dist/safe-bash/chunks/chunk-CXMIIXJA.js +0 -178
  347. package/dist/safe-bash/chunks/chunk-CXMIIXJA.js.map +0 -7
  348. package/dist/safe-bash/chunks/chunk-K7W6Q6FN.js.map +0 -7
  349. /package/dist/safe-bash/chunks/{bz2-B2RXT4EX.js.map → bz2-ACU4EOVE.js.map} +0 -0
  350. /package/dist/safe-bash/chunks/{chunk-RNKTWFEM.js.map → chunk-CDBQXRWL.js.map} +0 -0
  351. /package/dist/safe-bash/chunks/{chunk-AFH57PPL.js.map → chunk-IEKESMO4.js.map} +0 -0
  352. /package/dist/safe-bash/chunks/{chunk-DPJWEGIX.js.map → chunk-JLBIUYT3.js.map} +0 -0
  353. /package/dist/safe-bash/chunks/{chunk-PVJJFCGA.js.map → chunk-M3GPCYSP.js.map} +0 -0
  354. /package/dist/safe-bash/chunks/{chunk-2KL6W6NB.js.map → chunk-O2EVBRKF.js.map} +0 -0
  355. /package/dist/safe-bash/chunks/{chunk-C7QNJ3D4.js.map → chunk-WYTI64IU.js.map} +0 -0
  356. /package/dist/safe-bash/chunks/{xz-AVXFDXW4.js.map → xz-U4QDTPZL.js.map} +0 -0
  357. /package/dist/safe-bash/chunks/{zstd-R6RPHJYO.js.map → zstd-OG5RPYXO.js.map} +0 -0
@@ -1,8 +1,290 @@
1
- import { PublicDiagnostic } from "../diagnostics.js";
2
1
  import { FsError, toByteSource } from "../contracts/index.js";
3
- import { yieldTurn } from "../contracts/yield.js";
2
+ import { monotonicNow, yieldTurn } from "../contracts/yield.js";
4
3
  import { Budget, interruptible } from "./runtime.js";
5
- import { concatShellValues, shellValueFromBytes } from "../contracts/value.js";
4
+ import { concatShellValues, shellValueBytes, shellValueFromBytes, shellValueText } from "../contracts/value.js";
5
+ import { openCommandFile } from "../contracts/filesystem-descriptor.js";
6
+ const inputBuffers = new WeakMap();
7
+ const inputByteLength = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(Uint8Array.prototype), "byteLength").get;
8
+ export function inputBufferUsage(budget) {
9
+ let bytes = 0;
10
+ const leases = inputBuffers.get(budget);
11
+ if (leases)
12
+ for (const lease of leases)
13
+ bytes += lease.capacity;
14
+ return Object.freeze({ bytes, buffers: leases?.size ?? 0 });
15
+ }
16
+ class InputBufferLease {
17
+ budget;
18
+ capacity;
19
+ bytes;
20
+ constructor(budget, capacity, allocate) {
21
+ this.budget = budget;
22
+ this.capacity = capacity;
23
+ budget.signal.throwIfAborted();
24
+ if (!Number.isSafeInteger(capacity) || capacity <= 0 || capacity > Math.max(1, budget.limits.maxInputBytes)) {
25
+ throw new FsError("EFBIG", { syscall: "read" });
26
+ }
27
+ let leases = inputBuffers.get(budget);
28
+ if (!leases) {
29
+ leases = new Set();
30
+ inputBuffers.set(budget, leases);
31
+ }
32
+ leases.add(this);
33
+ try {
34
+ this.bytes = allocate();
35
+ budget.signal.throwIfAborted();
36
+ }
37
+ catch (error) {
38
+ this.release();
39
+ budget.signal.throwIfAborted();
40
+ throw error;
41
+ }
42
+ }
43
+ release() {
44
+ this.bytes = undefined;
45
+ const leases = inputBuffers.get(this.budget);
46
+ leases?.delete(this);
47
+ if (!leases?.size)
48
+ inputBuffers.delete(this.budget);
49
+ }
50
+ }
51
+ export function prepareBytesInput(value, budget) {
52
+ budget.signal.throwIfAborted();
53
+ if (typeof value !== "string" && !(value instanceof Uint8Array))
54
+ throw new TypeError("Shell input must be a string or Uint8Array");
55
+ const length = typeof value === "string" ? Buffer.byteLength(value) : inputByteLength.call(value);
56
+ if (length > budget.limits.maxInputBytes)
57
+ throw new FsError("EFBIG", { syscall: "read" });
58
+ let buffer;
59
+ let sent = false;
60
+ let closed = false;
61
+ let closing;
62
+ const close = () => {
63
+ closed = true;
64
+ buffer?.release();
65
+ buffer = undefined;
66
+ budget.signal.removeEventListener("abort", aborted);
67
+ return closing ??= Promise.resolve();
68
+ };
69
+ const aborted = () => { void close(); };
70
+ try {
71
+ if (length) {
72
+ buffer = new InputBufferLease(budget, length, () => typeof value === "string" ? new TextEncoder().encode(value) : new Uint8Array(value));
73
+ }
74
+ budget.signal.addEventListener("abort", aborted, { once: true });
75
+ const source = {
76
+ [Symbol.asyncIterator]() { return this; },
77
+ async next() {
78
+ budget.signal.throwIfAborted();
79
+ const bytes = buffer?.bytes;
80
+ if (closed || sent || !bytes?.byteLength)
81
+ return { done: true, value: undefined };
82
+ sent = true;
83
+ return { done: false, value: bytes };
84
+ },
85
+ async return() { await close(); return { done: true, value: undefined }; },
86
+ };
87
+ return Object.freeze({ source, close, options: Object.freeze({ provenance: "stream", poll: () => {
88
+ budget.signal.throwIfAborted();
89
+ if (closed)
90
+ throw new Error("Prepared input is closed");
91
+ return !sent && length ? "ready" : "eof";
92
+ } }) });
93
+ }
94
+ catch (error) {
95
+ void close();
96
+ throw error;
97
+ }
98
+ }
99
+ export async function prepareFileInput(context, path, budget, inputProfile = context.fs, admittedStat) {
100
+ const { fs, signal: parent, registerCleanup: register, cleanupFailurePrioritySignal } = context;
101
+ const registerCleanup = register.bind(context);
102
+ const signal = AbortSignal.any([parent, budget.signal]);
103
+ const readerController = new AbortController();
104
+ const readSignal = AbortSignal.any([signal, readerController.signal]);
105
+ let descriptor;
106
+ let legacy;
107
+ let legacySource;
108
+ let stat;
109
+ let accepting = true;
110
+ let ended = false;
111
+ let buffer;
112
+ let size = 0;
113
+ let pendingReads = 0;
114
+ let work = Promise.resolve();
115
+ let admitted;
116
+ const acquisition = new Promise(resolve => { admitted = resolve; });
117
+ let closing;
118
+ let teardownFailed = false;
119
+ const close = () => {
120
+ accepting = false;
121
+ if (pendingReads && !readerController.signal.aborted)
122
+ readerController.abort(new FsError("EBADF", { syscall: "read", path }));
123
+ closing ??= (async () => {
124
+ await acquisition;
125
+ await work;
126
+ try {
127
+ if (descriptor)
128
+ await descriptor.close();
129
+ else
130
+ await legacy?.return?.();
131
+ }
132
+ catch (error) {
133
+ teardownFailed = true;
134
+ (cleanupFailurePrioritySignal ?? signal).throwIfAborted();
135
+ throw error;
136
+ }
137
+ finally {
138
+ descriptor = undefined;
139
+ legacy = undefined;
140
+ legacySource = undefined;
141
+ buffer?.release();
142
+ buffer = undefined;
143
+ signal.removeEventListener("abort", aborted);
144
+ }
145
+ signal.throwIfAborted();
146
+ })();
147
+ void closing.catch(() => { });
148
+ return closing;
149
+ };
150
+ const aborted = () => { void close().catch(() => { }); };
151
+ const check = () => {
152
+ signal.throwIfAborted();
153
+ if (!accepting)
154
+ throw new FsError("EBADF", { syscall: "read", path });
155
+ };
156
+ try {
157
+ registerCleanup(cleanupFailurePrioritySignal === undefined ? close : async () => {
158
+ try {
159
+ await close();
160
+ }
161
+ catch (error) {
162
+ if (teardownFailed)
163
+ cleanupFailurePrioritySignal.throwIfAborted();
164
+ throw error;
165
+ }
166
+ });
167
+ signal.addEventListener("abort", aborted, { once: true });
168
+ check();
169
+ const capabilities = await fs.capabilitiesFor?.(path, { signal }) ?? fs.capabilities;
170
+ check();
171
+ let provenance = "unknown";
172
+ if (capabilities.open === true || capabilities.open !== false && typeof fs.open === "function") {
173
+ descriptor = await openCommandFile({ fs, signal, registerCleanup, cleanupFailurePrioritySignal }, path, { access: "read", signal });
174
+ }
175
+ else {
176
+ stat = admittedStat ?? await fs.stat(path, { signal });
177
+ check();
178
+ legacySource = await fileInput(fs, path, budget.limits.maxInputBytes, readSignal, inputProfile, { stat, registerCleanup });
179
+ legacy = legacySource[Symbol.asyncIterator]();
180
+ stat = legacySource.stat ?? stat;
181
+ }
182
+ check();
183
+ if (descriptor) {
184
+ stat = await descriptor.stat({ signal });
185
+ check();
186
+ }
187
+ if (stat) {
188
+ if (stat.type === "directory")
189
+ throw new FsError("EISDIR", { syscall: "read", path });
190
+ if (descriptor || legacySource?.stat)
191
+ provenance = stat.type === "file" ? "regular" : stat.type === "character" ? "stream" : "unknown";
192
+ }
193
+ const source = {
194
+ [Symbol.asyncIterator]() { return this; },
195
+ next(maximum = 64 * 1024) {
196
+ try {
197
+ signal.throwIfAborted();
198
+ if (!Number.isSafeInteger(maximum) || maximum <= 0)
199
+ throw new RangeError("Input chunk size must be a positive safe integer");
200
+ if (ended)
201
+ return Promise.resolve({ done: true, value: undefined });
202
+ check();
203
+ }
204
+ catch (error) {
205
+ return Promise.reject(error);
206
+ }
207
+ pendingReads++;
208
+ const operation = work.then(async () => {
209
+ signal.throwIfAborted();
210
+ if (ended)
211
+ return { done: true, value: undefined };
212
+ check();
213
+ if (legacy) {
214
+ const result = await (legacySource?.readChunk ? legacySource.readChunk(maximum) : legacy.next());
215
+ check();
216
+ ended = result.done === true && provenance !== "regular";
217
+ return result;
218
+ }
219
+ if (!buffer) {
220
+ const capacity = Math.min(64 * 1024, budget.limits.maxInputBytes) || 1;
221
+ buffer = new InputBufferLease(budget, capacity, () => new Uint8Array(capacity));
222
+ }
223
+ const bytes = buffer.bytes;
224
+ const remaining = budget.limits.maxInputBytes - size;
225
+ const chunk = bytes.subarray(0, Math.min(maximum, remaining >= bytes.length ? bytes.length : remaining + 1));
226
+ const length = await descriptor.read(chunk, null, { signal: readSignal });
227
+ check();
228
+ if (!Number.isSafeInteger(length) || length < 0 || length > chunk.length)
229
+ throw new FsError("EIO", { syscall: "read", path });
230
+ if (length > budget.limits.maxInputBytes - size)
231
+ throw new FsError("EFBIG", { syscall: "read", path });
232
+ size += length;
233
+ const done = length === 0;
234
+ ended = done && provenance !== "regular";
235
+ return done ? { done: true, value: undefined } : { done: false, value: chunk.subarray(0, length) };
236
+ });
237
+ work = operation.then(() => { pendingReads--; }, () => { pendingReads--; });
238
+ return operation.then(async (result) => {
239
+ if (result.done && provenance !== "regular") {
240
+ if (legacy)
241
+ await close();
242
+ else {
243
+ buffer?.release();
244
+ buffer = undefined;
245
+ }
246
+ }
247
+ signal.throwIfAborted();
248
+ return result;
249
+ }, async (error) => {
250
+ try {
251
+ await close();
252
+ }
253
+ catch { }
254
+ signal.throwIfAborted();
255
+ throw error;
256
+ });
257
+ },
258
+ async return() { await close(); return { done: true, value: undefined }; },
259
+ };
260
+ admitted();
261
+ const seek = legacySource?.seek;
262
+ return Object.freeze({ source, close, options: Object.freeze({
263
+ provenance, eof: provenance === "regular" ? "retryable" : "terminal",
264
+ ...(descriptor ? { descriptor } : {}), ...(stat ? { stat } : {}),
265
+ readChunk: source.next.bind(source),
266
+ ...(seek ? { async seek(position, callerSignal) {
267
+ callerSignal.throwIfAborted();
268
+ check();
269
+ await work;
270
+ check();
271
+ callerSignal.throwIfAborted();
272
+ await seek.call(legacySource, position, callerSignal);
273
+ check();
274
+ ended = false;
275
+ } } : {}),
276
+ }) });
277
+ }
278
+ catch (error) {
279
+ admitted();
280
+ try {
281
+ await close();
282
+ }
283
+ catch { }
284
+ signal.throwIfAborted();
285
+ throw error;
286
+ }
287
+ }
6
288
  export async function fileInput(fs, path, maxBytes, signal, inputProfile = fs, ownership) {
7
289
  let admittedCapabilities;
8
290
  if (ownership?.stat.type === "file") {
@@ -18,7 +300,6 @@ export async function fileInput(fs, path, maxBytes, signal, inputProfile = fs, o
18
300
  })();
19
301
  return closing;
20
302
  };
21
- ownership.registerCleanup(close);
22
303
  const work = async (operation) => {
23
304
  signal.throwIfAborted();
24
305
  if (closed)
@@ -31,6 +312,7 @@ export async function fileInput(fs, path, maxBytes, signal, inputProfile = fs, o
31
312
  try {
32
313
  const capabilities = admittedCapabilities = await work(() => Promise.resolve(fs.capabilitiesFor?.(path, { signal }) ?? fs.capabilities));
33
314
  if (capabilities.retainedRead === true && fs.openReadFile) {
315
+ ownership.registerCleanup(close);
34
316
  try {
35
317
  await work(async () => { handle = await fs.openReadFile(path, { signal }); });
36
318
  }
@@ -161,8 +443,80 @@ export async function fileInput(fs, path, maxBytes, signal, inputProfile = fs, o
161
443
  }),
162
444
  };
163
445
  }
446
+ const inputClock = {
447
+ now: monotonicNow,
448
+ schedule(delayMs, expire) {
449
+ const timer = setTimeout(expire, Math.min(delayMs, 2_147_483_647));
450
+ return () => clearTimeout(timer);
451
+ },
452
+ };
453
+ class InputDeadline {
454
+ clock;
455
+ parent;
456
+ #controller = new AbortController();
457
+ #expiresAt;
458
+ #cancel;
459
+ #closed = false;
460
+ signal;
461
+ constructor(clock, timeoutMs, parent) {
462
+ this.clock = clock;
463
+ this.parent = parent;
464
+ const now = clock.now();
465
+ this.#expiresAt = now + timeoutMs;
466
+ if (!Number.isFinite(now) || !Number.isFinite(this.#expiresAt))
467
+ throw new RangeError("Invalid input clock deadline");
468
+ this.signal = AbortSignal.any([parent, this.#controller.signal]);
469
+ parent.throwIfAborted();
470
+ parent.addEventListener("abort", this.close, { once: true });
471
+ try {
472
+ this.#schedule();
473
+ }
474
+ catch (error) {
475
+ this.close();
476
+ throw error;
477
+ }
478
+ }
479
+ expired() {
480
+ this.parent.throwIfAborted();
481
+ if (!this.#closed && this.clock.now() >= this.#expiresAt) {
482
+ this.#controller.abort();
483
+ this.close();
484
+ }
485
+ return this.#controller.signal.aborted;
486
+ }
487
+ #schedule() {
488
+ const cancel = this.clock.schedule(Math.max(0, this.#expiresAt - this.clock.now()), () => {
489
+ this.#cancel = undefined;
490
+ if (this.#closed || this.parent.aborted)
491
+ return;
492
+ if (!this.expired())
493
+ this.#schedule();
494
+ });
495
+ if (this.#closed)
496
+ cancel();
497
+ else
498
+ this.#cancel = cancel;
499
+ }
500
+ close = () => {
501
+ this.#closed = true;
502
+ const cancel = this.#cancel;
503
+ this.#cancel = undefined;
504
+ this.parent.removeEventListener("abort", this.close);
505
+ try {
506
+ cancel?.();
507
+ }
508
+ catch (error) {
509
+ if (!this.parent.aborted)
510
+ throw error;
511
+ }
512
+ };
513
+ }
164
514
  class InputCursor {
165
515
  #iterator;
516
+ #provenance;
517
+ #eof;
518
+ #poll;
519
+ #clock;
166
520
  #readChunk;
167
521
  #budget;
168
522
  stat;
@@ -171,28 +525,49 @@ class InputCursor {
171
525
  remainder;
172
526
  #unread = [];
173
527
  #read;
528
+ #readResult;
529
+ #readError;
530
+ #readSettled = false;
174
531
  #readFailed = false;
175
532
  #turn = Promise.resolve();
176
533
  #returned;
177
534
  #ended = false;
178
535
  #closed = false;
536
+ #active = false;
179
537
  #produced = 0;
180
538
  #boundedReads = false;
181
- constructor(source, provenance, budget) {
539
+ constructor(source, options, budget) {
540
+ const { provenance = options.stat?.type === "file" ? "regular" : options.stat?.type === "character" ? "stream" : "unknown", eof = "terminal", poll, clock = inputClock } = options;
541
+ if (provenance !== "unknown" && provenance !== "regular" && provenance !== "stream")
542
+ throw new TypeError("Invalid input provenance");
543
+ if (eof !== "terminal" && eof !== "retryable" || eof === "retryable" && provenance !== "regular")
544
+ throw new TypeError("Retryable input EOF requires regular provenance");
545
+ if (poll !== undefined && typeof poll !== "function")
546
+ throw new TypeError("Invalid input polling capability");
547
+ const { now, schedule } = clock;
548
+ if (typeof now !== "function" || typeof schedule !== "function")
549
+ throw new TypeError("Invalid input clock");
550
+ this.#provenance = provenance;
551
+ this.#eof = eof;
552
+ this.#poll = poll?.bind(options);
553
+ this.#clock = Object.freeze({ now: now.bind(clock), schedule: schedule.bind(clock) });
182
554
  this.#iterator = source[Symbol.asyncIterator]();
183
- this.#readChunk = provenance.readChunk;
555
+ this.#readChunk = options.readChunk?.bind(options);
184
556
  this.#budget = budget;
185
- if (provenance.stat)
186
- this.stat = provenance.stat;
187
- if (provenance.seek)
557
+ if (options.stat)
558
+ this.stat = options.stat;
559
+ if (options.seek)
188
560
  this.seek = async (position, signal) => {
189
561
  if (this.#read)
190
562
  await interruptible(this.#read, signal);
191
563
  signal.throwIfAborted();
192
- await provenance.seek(position, signal);
564
+ await options.seek(position, signal);
193
565
  this.remainder = undefined;
194
566
  this.#unread.length = 0;
195
567
  this.#read = undefined;
568
+ this.#readResult = undefined;
569
+ this.#readError = undefined;
570
+ this.#readSettled = false;
196
571
  this.#ended = false;
197
572
  this.position = position;
198
573
  };
@@ -209,16 +584,78 @@ class InputCursor {
209
584
  if (this.#produced > this.#budget.limits.maxInputBytes)
210
585
  this.#budget.fail("maxInputBytes");
211
586
  }
212
- async consume(signal, operation) {
587
+ get bufferedBytes() {
588
+ if (this.#active)
589
+ return 0;
590
+ return (this.remainder?.length ?? 0) + this.#unread.reduce((length, chunk) => length + chunk.length, 0)
591
+ + (this.#readResult && !this.#readResult.done ? this.#readResult.value.length : 0);
592
+ }
593
+ readiness() {
594
+ if (this.#active)
595
+ return "blocked";
596
+ if (this.remainder?.length || this.#unread.some(chunk => chunk.length))
597
+ return "ready";
598
+ if (this.#readError)
599
+ throw this.#readError.reason;
600
+ if (this.#ended || this.#readResult?.done)
601
+ return "eof";
602
+ if (this.#readResult && this.#readResult.value.length)
603
+ return "ready";
604
+ if (this.#closed)
605
+ throw new Error("Shell input cursor is closed");
606
+ if (this.#provenance === "regular")
607
+ return "ready";
608
+ const readiness = this.#poll?.() ?? "unknown";
609
+ if (!["ready", "eof", "blocked", "unknown"].includes(readiness))
610
+ throw new TypeError("Invalid input readiness");
611
+ if (readiness === "eof" && this.#read && !this.#readSettled)
612
+ return "unknown";
613
+ return readiness;
614
+ }
615
+ probeRead() {
616
+ const readiness = this.readiness();
617
+ return { readiness: readiness === "eof" ? "ready" : readiness,
618
+ timeout: this.#provenance === "regular" ? "ignore" : this.#provenance === "stream" ? "honor" : "unknown" };
619
+ }
620
+ deadline(timeoutMs, signal, scope) {
621
+ if (timeoutMs === undefined)
622
+ return undefined;
623
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)
624
+ throw new RangeError("Read timeout must be positive and finite; use readiness for zero timeout");
625
+ if (this.#provenance === "unknown")
626
+ throw new TypeError("Read timeout requires explicit input provenance");
627
+ if (this.#provenance === "regular")
628
+ return undefined;
629
+ scope.reserve(192, 3);
630
+ return new InputDeadline(this.#clock, timeoutMs, signal);
631
+ }
632
+ async consume(signal, operation, interrupted) {
633
+ if (signal.aborted && interrupted)
634
+ return interrupted(signal.reason);
213
635
  signal.throwIfAborted();
214
636
  const previous = this.#turn;
215
637
  let release;
216
638
  const completed = new Promise((resolve) => { release = resolve; });
217
639
  this.#turn = previous.then(() => completed);
218
640
  try {
219
- await interruptible(previous, signal);
220
- signal.throwIfAborted();
221
- return await operation();
641
+ try {
642
+ await interruptible(previous, signal);
643
+ signal.throwIfAborted();
644
+ }
645
+ catch (error) {
646
+ if (signal.aborted && interrupted)
647
+ return await interrupted(error);
648
+ throw error;
649
+ }
650
+ if (this.#eof === "retryable")
651
+ this.#ended = false;
652
+ this.#active = true;
653
+ try {
654
+ return await operation();
655
+ }
656
+ finally {
657
+ this.#active = false;
658
+ }
222
659
  }
223
660
  finally {
224
661
  release();
@@ -237,6 +674,8 @@ class InputCursor {
237
674
  if (this.#ended || this.#closed)
238
675
  return { value: undefined, done: true };
239
676
  if (!this.#read) {
677
+ this.#readSettled = false;
678
+ this.#readResult = undefined;
240
679
  this.#read = Promise.resolve().then(() => this.#closed ? { value: undefined, done: true } : this.#readChunk ? this.#readChunk(maxBytes) : this.#iterator.next()).then((result) => {
241
680
  if (result.done)
242
681
  return { value: undefined, done: true };
@@ -245,13 +684,15 @@ class InputCursor {
245
684
  if (this.#boundedReads && result.value.byteLength > this.#budget.limits.maxInputBytes - this.#produced)
246
685
  this.#budget.fail("maxInputBytes");
247
686
  this.#produced += result.value.byteLength;
248
- return { value: new Uint8Array(result.value), done: false };
687
+ return { value: this.#boundedReads ? new Uint8Array(result.value) : result.value, done: false };
249
688
  });
689
+ void this.#read.then(result => { this.#readSettled = true; this.#readResult = result; }, reason => { this.#readSettled = true; this.#readError = { reason }; });
250
690
  }
251
691
  try {
252
692
  const result = await interruptible(this.#read, signal);
253
693
  signal.throwIfAborted();
254
694
  this.#read = undefined;
695
+ this.#readResult = undefined;
255
696
  if (result.done)
256
697
  this.#ended = true;
257
698
  return result;
@@ -266,7 +707,7 @@ class InputCursor {
266
707
  }
267
708
  }
268
709
  async close(signal) {
269
- if (this.#ended && !this.seek) {
710
+ if (this.#ended && this.#eof === "terminal" && !this.seek) {
270
711
  signal.throwIfAborted();
271
712
  return;
272
713
  }
@@ -285,36 +726,75 @@ class InputCursor {
285
726
  signal.throwIfAborted();
286
727
  }
287
728
  }
288
- class ReadText {
289
- #chunks = [];
290
- #pending = [];
291
- append(value) {
292
- if (!value)
293
- return;
294
- this.#pending.push(value);
295
- if (this.#pending.length === 1024) {
296
- this.#chunks.push(this.#pending.join(""));
297
- this.#pending.length = 0;
729
+ class ReadBuffer {
730
+ scope;
731
+ maximum;
732
+ #buffer = new Uint8Array();
733
+ #reservation;
734
+ length = 0;
735
+ constructor(scope, maximum) {
736
+ this.scope = scope;
737
+ this.maximum = maximum;
738
+ }
739
+ append(byte) {
740
+ if (this.length === this.#buffer.length) {
741
+ const capacity = Math.min(this.maximum, Math.max(64, this.#buffer.length * 2));
742
+ const reservation = this.scope.reserve(capacity + 64, 1);
743
+ try {
744
+ const buffer = new Uint8Array(capacity);
745
+ buffer.set(this.#buffer);
746
+ reservation.commit(buffer);
747
+ this.#reservation?.release();
748
+ this.#reservation = reservation;
749
+ this.#buffer = buffer;
750
+ }
751
+ catch (error) {
752
+ reservation.release();
753
+ throw error;
754
+ }
298
755
  }
756
+ this.#buffer[this.length++] = byte;
299
757
  }
300
- finish() { return this.#chunks.join("") + this.#pending.join(""); }
758
+ bytes() { return this.#buffer.subarray(0, this.length); }
759
+ }
760
+ function utf8Length(first) {
761
+ return first >= 0xc2 && first <= 0xdf ? 2 : first >= 0xe0 && first <= 0xef ? 3 : first >= 0xf0 && first <= 0xf4 ? 4 : 1;
762
+ }
763
+ function utf8Continuation(first, position, byte) {
764
+ if (byte < 0x80 || byte > 0xbf)
765
+ return false;
766
+ return position !== 1 || (first !== 0xe0 || byte >= 0xa0) && (first !== 0xed || byte < 0xa0)
767
+ && (first !== 0xf0 || byte >= 0x90) && (first !== 0xf4 || byte < 0x90);
768
+ }
769
+ function displayWidth(bytes, offset) {
770
+ const first = bytes[offset];
771
+ const width = utf8Length(first);
772
+ let consumed = 1;
773
+ while (consumed < width && offset + consumed < bytes.length && utf8Continuation(first, consumed, bytes[offset + consumed]))
774
+ consumed++;
775
+ return consumed;
301
776
  }
302
777
  export class ShellInput {
303
778
  budget;
779
+ descriptor;
304
780
  #cursor;
305
781
  #owned;
306
782
  #lifetime = new AbortController();
307
783
  #cleanupSignal;
308
784
  signal;
785
+ #reads = new Set();
309
786
  stat;
310
787
  seek;
311
788
  #closing;
312
- constructor(source, budget, signal = budget.signal, provenance = {}) {
789
+ constructor(source, budget, signal = budget.signal, options) {
313
790
  this.budget = budget;
314
791
  this.#owned = !(source instanceof ShellInput);
315
- this.#cursor = source instanceof ShellInput ? source.#cursor : new InputCursor(source, provenance, budget);
792
+ if (!this.#owned && options !== undefined)
793
+ throw new TypeError("Borrowed input cannot replace cursor capabilities");
794
+ this.#cursor = source instanceof ShellInput ? source.#cursor : new InputCursor(source, options ?? {}, budget);
795
+ this.descriptor = source instanceof ShellInput ? source.descriptor : options?.descriptor;
316
796
  this.#cleanupSignal = signal;
317
- this.signal = AbortSignal.any([signal, this.#lifetime.signal]);
797
+ this.signal = AbortSignal.any([budget.signal, signal, this.#lifetime.signal]);
318
798
  if (this.#cursor.stat)
319
799
  this.stat = this.#cursor.stat;
320
800
  if (this.#cursor.seek)
@@ -327,6 +807,22 @@ export class ShellInput {
327
807
  });
328
808
  };
329
809
  }
810
+ get bufferedBytes() {
811
+ this.signal.throwIfAborted();
812
+ return this.#cursor.bufferedBytes;
813
+ }
814
+ readiness() {
815
+ this.signal.throwIfAborted();
816
+ const readiness = this.#cursor.readiness();
817
+ this.signal.throwIfAborted();
818
+ return readiness;
819
+ }
820
+ probeRead() {
821
+ this.signal.throwIfAborted();
822
+ const result = this.#cursor.probeRead();
823
+ this.signal.throwIfAborted();
824
+ return result;
825
+ }
330
826
  get position() { return this.#cursor.position; }
331
827
  read(maxBytes, callerSignal) {
332
828
  const signal = AbortSignal.any([this.signal, callerSignal]);
@@ -388,9 +884,10 @@ export class ShellInput {
388
884
  next() {
389
885
  return this.#cursor.consume(this.signal, async () => {
390
886
  const result = await this.#cursor.take(this.signal);
391
- if (!result.done)
392
- this.#cursor.position += result.value.byteLength;
393
- return result;
887
+ if (result.done)
888
+ return result;
889
+ this.#cursor.position += result.value.byteLength;
890
+ return { done: false, value: new Uint8Array(result.value) };
394
891
  });
395
892
  }
396
893
  [Symbol.asyncIterator]() {
@@ -417,7 +914,7 @@ export class ShellInput {
417
914
  this.#cursor.position += end;
418
915
  this.budget.source(end);
419
916
  if (end)
420
- chunks.push(result.value.subarray(0, end));
917
+ chunks.push(new Uint8Array(result.value.subarray(0, end)));
421
918
  length += end;
422
919
  if (newline >= 0)
423
920
  break;
@@ -431,8 +928,86 @@ export class ShellInput {
431
928
  return bytes;
432
929
  });
433
930
  }
434
- line(raw, options) {
435
- return this.#cursor.consume(this.signal, () => options ? this.readBounded(raw, options) : this.readLine(raw));
931
+ async record(options = {}) {
932
+ this.signal.throwIfAborted();
933
+ const { delimiter = 10 } = options;
934
+ this.signal.throwIfAborted();
935
+ if (!Number.isInteger(delimiter) || delimiter < 0 || delimiter > 255)
936
+ throw new RangeError("Invalid raw record delimiter");
937
+ const scope = this.budget.values.scope();
938
+ let active = true;
939
+ let completion;
940
+ let resolve;
941
+ const finish = () => {
942
+ if (!completion || active)
943
+ return;
944
+ this.#reads.delete(release);
945
+ scope.close();
946
+ resolve();
947
+ };
948
+ const release = () => {
949
+ if (!completion) {
950
+ completion = new Promise(done => { resolve = done; });
951
+ finish();
952
+ }
953
+ return completion;
954
+ };
955
+ try {
956
+ scope.reserve(128, 2);
957
+ this.#reads.add(release);
958
+ const result = await this.#cursor.consume(this.signal, async () => {
959
+ const buffer = new ReadBuffer(scope, this.budget.limits.maxOutputBytes);
960
+ let chunk = new Uint8Array();
961
+ let offset = 0;
962
+ let pulls = 0;
963
+ let reason = "eof";
964
+ try {
965
+ while (true) {
966
+ this.signal.throwIfAborted();
967
+ if (offset === chunk.length) {
968
+ if (++pulls % 128 === 0)
969
+ await yieldTurn(this.signal);
970
+ const next = await this.#cursor.take(this.signal);
971
+ if (next.done)
972
+ break;
973
+ chunk = next.value;
974
+ offset = 0;
975
+ if (!chunk.length)
976
+ continue;
977
+ }
978
+ if (buffer.length >= this.budget.limits.maxOutputBytes)
979
+ this.budget.fail("maxOutputBytes");
980
+ const byte = chunk[offset++];
981
+ this.#cursor.position++;
982
+ buffer.append(byte);
983
+ if (byte === delimiter) {
984
+ reason = "delimiter";
985
+ break;
986
+ }
987
+ if (buffer.length % 1024 === 0)
988
+ await yieldTurn(this.signal);
989
+ }
990
+ const shellValue = shellValueFromBytes(buffer.bytes(), scope);
991
+ this.signal.throwIfAborted();
992
+ return Object.freeze({ shellValue, reason, release });
993
+ }
994
+ finally {
995
+ if (offset < chunk.length)
996
+ this.#cursor.remainder = chunk.subarray(offset);
997
+ }
998
+ });
999
+ this.signal.throwIfAborted();
1000
+ return result;
1001
+ }
1002
+ catch (error) {
1003
+ void release();
1004
+ this.signal.throwIfAborted();
1005
+ throw error;
1006
+ }
1007
+ finally {
1008
+ active = false;
1009
+ finish();
1010
+ }
436
1011
  }
437
1012
  /** Select uses read's escape rules without projecting raw REPLY bytes to text. */
438
1013
  selectLine(allocation) {
@@ -543,160 +1118,359 @@ export class ShellInput {
543
1118
  }
544
1119
  });
545
1120
  }
546
- async readBounded(raw, options) {
547
- const text = new ReadText();
548
- let characters = 0;
549
- const escaped = new Set();
550
- const decoder = new TextDecoder("utf-8", { fatal: true });
551
- const delimiter = options.delimiter ?? 10;
1121
+ async line(raw, options = {}) {
1122
+ const { count, delimiter = 10, byteCount = false, exact = false, timeoutMs } = options;
1123
+ this.signal.throwIfAborted();
1124
+ if (count !== undefined && (!Number.isSafeInteger(count) || count < 0))
1125
+ throw new RangeError("Invalid read count");
1126
+ if (!Number.isInteger(delimiter) || delimiter < 0 || delimiter > 255)
1127
+ throw new RangeError("Invalid read delimiter");
1128
+ const scope = this.budget.values.scope();
1129
+ let active = 1;
1130
+ let closed = false;
1131
+ let completion;
1132
+ let resolve;
1133
+ const finish = () => {
1134
+ if (!closed || active)
1135
+ return;
1136
+ this.#reads.delete(release);
1137
+ scope.close();
1138
+ resolve();
1139
+ };
1140
+ const release = () => {
1141
+ if (!completion) {
1142
+ completion = new Promise(done => { resolve = done; });
1143
+ closed = true;
1144
+ finish();
1145
+ }
1146
+ return completion;
1147
+ };
1148
+ const assertOpen = () => {
1149
+ this.signal.throwIfAborted();
1150
+ if (closed)
1151
+ throw new Error("Read result is closed");
1152
+ scope.assertOpen();
1153
+ };
552
1154
  let chunk = new Uint8Array();
553
1155
  let offset = 0;
554
- let length = 0;
555
- let escaping = false;
556
- let escapedCharacter = false;
557
- let units = 0;
558
- let pulls = 0;
559
- let terminated = options.count === 0;
1156
+ let deadline;
560
1157
  try {
561
- while (!terminated) {
562
- if (offset === chunk.length) {
563
- if (++pulls % 128 === 0)
564
- await yieldTurn(this.signal);
565
- const result = await this.#cursor.take(this.signal);
566
- if (result.done) {
567
- break;
1158
+ scope.reserve(256, 3);
1159
+ this.#reads.add(release);
1160
+ deadline = this.#cursor.deadline(timeoutMs, this.signal, scope);
1161
+ const read = async () => {
1162
+ try {
1163
+ const buffer = new ReadBuffer(scope, this.budget.limits.maxOutputBytes);
1164
+ const escapedByteOffsets = [];
1165
+ let escaping = false;
1166
+ let visible = true;
1167
+ let units = 0;
1168
+ let consumed = 0;
1169
+ let checkpoint = 0;
1170
+ let pulls = 0;
1171
+ let terminated = count === 0;
1172
+ const outcome = { reason: terminated ? "count" : "eof" };
1173
+ const nextByte = async () => {
1174
+ this.signal.throwIfAborted();
1175
+ if (deadline?.expired()) {
1176
+ outcome.reason = "timeout";
1177
+ return undefined;
1178
+ }
1179
+ while (offset === chunk.length) {
1180
+ if (++pulls % 128 === 0)
1181
+ await yieldTurn(this.signal);
1182
+ let result;
1183
+ try {
1184
+ result = await this.#cursor.take(deadline?.signal ?? this.signal);
1185
+ }
1186
+ catch (error) {
1187
+ this.signal.throwIfAborted();
1188
+ if (deadline?.expired()) {
1189
+ outcome.reason = "timeout";
1190
+ return undefined;
1191
+ }
1192
+ throw error;
1193
+ }
1194
+ if (result.done) {
1195
+ if (deadline?.expired())
1196
+ outcome.reason = "timeout";
1197
+ return undefined;
1198
+ }
1199
+ chunk = result.value;
1200
+ offset = 0;
1201
+ if (deadline?.expired()) {
1202
+ outcome.reason = "timeout";
1203
+ return undefined;
1204
+ }
1205
+ }
1206
+ this.signal.throwIfAborted();
1207
+ this.#cursor.position++;
1208
+ return chunk[offset++];
1209
+ };
1210
+ const account = () => {
1211
+ if (++consumed > this.budget.limits.maxOutputBytes)
1212
+ this.budget.fail("maxOutputBytes");
1213
+ };
1214
+ while (!terminated) {
1215
+ if (consumed - checkpoint >= 1024) {
1216
+ checkpoint = consumed;
1217
+ await yieldTurn(this.signal);
1218
+ }
1219
+ const first = await nextByte();
1220
+ if (first === undefined) {
1221
+ if (escaping && visible && !buffer.length && outcome.reason === "eof")
1222
+ buffer.append(1);
1223
+ break;
1224
+ }
1225
+ const quoted = escaping;
1226
+ escaping = false;
1227
+ if (quoted && first === 10) {
1228
+ account();
1229
+ continue;
1230
+ }
1231
+ if (!quoted && !raw && first === 92) {
1232
+ account();
1233
+ escaping = true;
1234
+ continue;
1235
+ }
1236
+ if (!quoted && !exact && first === delimiter) {
1237
+ terminated = true;
1238
+ outcome.reason = "delimiter";
1239
+ break;
1240
+ }
1241
+ account();
1242
+ if (!quoted && first === 0)
1243
+ continue;
1244
+ if (quoted && visible && first !== 0) {
1245
+ scope.reserve(64, 2);
1246
+ escapedByteOffsets.push(buffer.length);
1247
+ }
1248
+ if (visible && first === 0) {
1249
+ if (quoted && !buffer.length)
1250
+ buffer.append(1);
1251
+ visible = false;
1252
+ }
1253
+ else if (visible)
1254
+ buffer.append(first);
1255
+ const width = byteCount ? 1 : utf8Length(first);
1256
+ const committedLength = buffer.length;
1257
+ for (let position = 1; position < width; position++) {
1258
+ const next = await nextByte();
1259
+ if (next === undefined)
1260
+ break;
1261
+ account();
1262
+ if (next === 0)
1263
+ visible = false;
1264
+ else if (visible)
1265
+ buffer.append(next);
1266
+ if (!utf8Continuation(first, position, next))
1267
+ break;
1268
+ }
1269
+ if (outcome.reason === "timeout") {
1270
+ buffer.length = committedLength;
1271
+ break;
1272
+ }
1273
+ units++;
1274
+ if (units === count) {
1275
+ terminated = true;
1276
+ outcome.reason = "count";
1277
+ }
1278
+ if (units % 1024 === 0)
1279
+ await yieldTurn(this.signal);
568
1280
  }
569
- chunk = result.value;
570
- offset = 0;
571
- if (!chunk.length)
572
- continue;
573
- }
574
- const byte = chunk[offset++];
575
- this.#cursor.position++;
576
- if (!options.exact && !escaping && byte === delimiter) {
577
- terminated = true;
578
- break;
579
- }
580
- if (++length > this.budget.limits.maxOutputBytes)
581
- this.budget.fail("maxOutputBytes");
582
- if (length % 1024 === 0) {
583
- await yieldTurn(this.signal);
584
1281
  this.signal.throwIfAborted();
585
- }
586
- if (byte === 0)
587
- continue;
588
- if (!raw && !escaping && byte === 92) {
589
- escaping = true;
590
- continue;
591
- }
592
- if (escaping) {
593
- escaping = false;
594
- if (byte === 10)
595
- continue;
596
- escapedCharacter = true;
597
- }
598
- const decoded = decoder.decode(Uint8Array.of(byte), { stream: true });
599
- let decodedCharacters = 0;
600
- for (const character of decoded) {
601
- if (escapedCharacter) {
602
- escapedCharacter = false;
603
- escaped.add(characters);
1282
+ deadline?.close();
1283
+ const reason = outcome.reason;
1284
+ let bytes = buffer.bytes();
1285
+ if (reason === "timeout" && (escapedByteOffsets.length || escaping && visible)) {
1286
+ const projected = new ReadBuffer(scope, this.budget.limits.maxOutputBytes);
1287
+ let escape = 0;
1288
+ for (let position = 0; position < bytes.length; position++) {
1289
+ if (escapedByteOffsets[escape] === position) {
1290
+ projected.append(1);
1291
+ escapedByteOffsets[escape++] = projected.length;
1292
+ }
1293
+ projected.append(bytes[position]);
1294
+ if (position % 1024 === 0)
1295
+ await yieldTurn(this.signal);
1296
+ }
1297
+ if (escaping && visible) {
1298
+ scope.reserve(64, 2);
1299
+ escapedByteOffsets.push(projected.length);
1300
+ projected.append(1);
1301
+ }
1302
+ bytes = projected.bytes();
604
1303
  }
605
- text.append(character);
606
- characters++;
607
- decodedCharacters++;
1304
+ const shellValue = shellValueFromBytes(bytes, scope);
1305
+ const escaped = new Set();
1306
+ let escapeIndex = 0;
1307
+ let characters = 0;
1308
+ for (let start = 0; start < bytes.length; start += displayWidth(bytes, start)) {
1309
+ if (escapedByteOffsets[escapeIndex] === start) {
1310
+ escaped.add(characters);
1311
+ escapeIndex++;
1312
+ }
1313
+ if (++characters % 1024 === 0)
1314
+ await yieldTurn(this.signal);
1315
+ }
1316
+ Object.freeze(escapedByteOffsets);
1317
+ const result = {
1318
+ value: shellValueText(shellValue), shellValue, escaped, escapedByteOffsets, terminated, reason, release,
1319
+ fields: async (ifs, maximum) => {
1320
+ assertOpen();
1321
+ active++;
1322
+ try {
1323
+ if (maximum !== undefined && (!Number.isSafeInteger(maximum) || maximum < 0))
1324
+ throw new RangeError("Invalid read field count");
1325
+ const separators = shellValueBytes(ifs, scope);
1326
+ scope.reserve(128, 2);
1327
+ const keys = new Set();
1328
+ const escapedStart = (start) => {
1329
+ let lower = 0;
1330
+ let upper = escapedByteOffsets.length;
1331
+ while (lower < upper) {
1332
+ const middle = lower + Math.floor((upper - lower) / 2);
1333
+ const offset = escapedByteOffsets[middle];
1334
+ if (offset === start)
1335
+ return true;
1336
+ if (offset < start)
1337
+ lower = middle + 1;
1338
+ else
1339
+ upper = middle;
1340
+ }
1341
+ return false;
1342
+ };
1343
+ const width = (input, start) => {
1344
+ if (input === bytes && reason === "timeout" && bytes[start] === 1 && escapedStart(start + 1))
1345
+ return 2;
1346
+ if (byteCount || input === bytes && escapedStart(start))
1347
+ return 1;
1348
+ const length = displayWidth(input, start);
1349
+ return length === utf8Length(input[start]) ? length : 1;
1350
+ };
1351
+ const key = (input, start) => {
1352
+ let value = 1;
1353
+ for (let position = start, end = start + width(input, start); position < end; position++)
1354
+ value = value * 257 + input[position];
1355
+ return value;
1356
+ };
1357
+ let steps = 0;
1358
+ for (let start = 0; start < separators.length; start += width(separators, start)) {
1359
+ const value = key(separators, start);
1360
+ if (!keys.has(value)) {
1361
+ scope.reserve(32, 1);
1362
+ keys.add(value);
1363
+ }
1364
+ for (let position = start, end = start + width(separators, start); position < end; position++) {
1365
+ const byteKey = 257 + separators[position];
1366
+ if (!keys.has(byteKey)) {
1367
+ scope.reserve(32, 1);
1368
+ keys.add(byteKey);
1369
+ }
1370
+ }
1371
+ if (++steps % 1024 === 0) {
1372
+ await yieldTurn(this.signal);
1373
+ assertOpen();
1374
+ }
1375
+ }
1376
+ const separator = (start) => !escapedStart(start)
1377
+ && !(reason === "timeout" && bytes[start] === 1 && escapedStart(start + 1)) && keys.has(key(bytes, start));
1378
+ const whitespace = (start) => (bytes[start] === 32 || bytes[start] === 9 || bytes[start] === 10) && separator(start);
1379
+ let end = 0;
1380
+ for (let start = 0; start < bytes.length; start += width(bytes, start)) {
1381
+ if (!whitespace(start))
1382
+ end = start + width(bytes, start);
1383
+ if (++steps % 1024 === 0) {
1384
+ await yieldTurn(this.signal);
1385
+ assertOpen();
1386
+ }
1387
+ }
1388
+ let position = 0;
1389
+ const advance = () => {
1390
+ assertOpen();
1391
+ position += width(bytes, position);
1392
+ if (++steps % 1024 === 0)
1393
+ return yieldTurn(this.signal);
1394
+ return undefined;
1395
+ };
1396
+ const fields = [];
1397
+ while (position < end && whitespace(position)) {
1398
+ const pending = advance();
1399
+ if (pending)
1400
+ await pending;
1401
+ }
1402
+ while (position < end && fields.length < (maximum ?? Number.MAX_SAFE_INTEGER)) {
1403
+ const start = position;
1404
+ while (position < end && !separator(position)) {
1405
+ const pending = advance();
1406
+ if (pending)
1407
+ await pending;
1408
+ }
1409
+ let fieldEnd = position;
1410
+ while (position < end && whitespace(position)) {
1411
+ const pending = advance();
1412
+ if (pending)
1413
+ await pending;
1414
+ }
1415
+ if (position < end && separator(position)) {
1416
+ const pending = advance();
1417
+ if (pending)
1418
+ await pending;
1419
+ }
1420
+ while (position < end && whitespace(position)) {
1421
+ const pending = advance();
1422
+ if (pending)
1423
+ await pending;
1424
+ }
1425
+ if (maximum !== undefined && fields.length === maximum - 1 && position < end)
1426
+ fieldEnd = end;
1427
+ scope.reserve(64, 1);
1428
+ fields.push(Object.freeze({ start, end: fieldEnd, value: shellValueFromBytes(bytes.subarray(start, fieldEnd), scope) }));
1429
+ }
1430
+ assertOpen();
1431
+ return Object.freeze(fields);
1432
+ }
1433
+ finally {
1434
+ active--;
1435
+ finish();
1436
+ }
1437
+ },
1438
+ };
1439
+ assertOpen();
1440
+ return Object.freeze(result);
608
1441
  }
609
- units += options.byteCount ? 1 : decodedCharacters;
610
- if (units === options.count)
611
- terminated = true;
612
- }
613
- decoder.decode();
614
- return { value: text.finish(), escaped, terminated };
1442
+ finally {
1443
+ if (offset < chunk.length)
1444
+ this.#cursor.remainder = chunk.subarray(offset);
1445
+ }
1446
+ };
1447
+ const result = await this.#cursor.consume(deadline?.signal ?? this.signal, read, async (error) => {
1448
+ this.signal.throwIfAborted();
1449
+ if (deadline?.expired())
1450
+ return read();
1451
+ throw error;
1452
+ });
1453
+ this.signal.throwIfAborted();
1454
+ return result;
615
1455
  }
616
1456
  catch (error) {
617
- if (error instanceof TypeError && error.message.includes("encoded data"))
618
- throw new PublicDiagnostic("read: unsupported non-UTF-8 text boundary");
1457
+ void release();
1458
+ this.signal.throwIfAborted();
619
1459
  throw error;
620
1460
  }
621
1461
  finally {
622
- if (offset < chunk.length)
623
- this.#cursor.remainder = chunk.subarray(offset);
1462
+ deadline?.close();
1463
+ active--;
1464
+ finish();
624
1465
  }
625
1466
  }
626
- async readLine(raw) {
627
- const chunks = [];
628
- let length = 0;
629
- let terminated = false;
630
- while (true) {
631
- const result = await this.#cursor.take(this.signal);
632
- if (result.done)
633
- break;
634
- const newline = result.value.indexOf(10);
635
- this.#cursor.position += newline < 0 ? result.value.byteLength : newline + 1;
636
- const chunk = newline < 0 ? result.value : result.value.subarray(0, newline);
637
- if (chunk.byteLength > this.budget.limits.maxOutputBytes - length)
638
- this.budget.fail("maxOutputBytes");
639
- chunks.push(new Uint8Array(chunk));
640
- length += chunk.byteLength;
641
- if (newline >= 0) {
642
- if (newline + 1 < result.value.length)
643
- this.#cursor.remainder = result.value.subarray(newline + 1);
644
- let slashes = 0;
645
- if (!raw) {
646
- for (let chunkIndex = chunks.length - 1; chunkIndex >= 0; chunkIndex--) {
647
- const bytes = chunks[chunkIndex];
648
- let offset = bytes.length - 1;
649
- while (offset >= 0 && bytes[offset] === 92) {
650
- slashes++;
651
- offset--;
652
- }
653
- if (offset >= 0)
654
- break;
655
- }
656
- }
657
- if (slashes % 2 === 1) {
658
- while (chunks.at(-1)?.length === 0)
659
- chunks.pop();
660
- chunks[chunks.length - 1] = chunks.at(-1).subarray(0, -1);
661
- length--;
662
- }
663
- else {
664
- terminated = true;
665
- break;
666
- }
667
- }
668
- }
669
- const bytes = new Uint8Array(length);
670
- let offset = 0;
671
- for (const chunk of chunks) {
672
- bytes.set(chunk, offset);
673
- offset += chunk.length;
674
- }
675
- const value = new TextDecoder().decode(bytes).replace(/\0/gu, "");
676
- const escaped = new Set();
677
- if (raw || !value.includes("\\"))
678
- return { value, escaped, terminated };
679
- const text = new ReadText();
680
- let characters = 0;
681
- for (let index = 0; index < value.length;) {
682
- const slash = value.indexOf("\\", index);
683
- const span = value.slice(index, slash < 0 ? value.length : slash);
684
- text.append(span);
685
- for (let pointOffset = 0; pointOffset < span.length; pointOffset += span.codePointAt(pointOffset) > 0xffff ? 2 : 1)
686
- characters++;
687
- if (slash < 0 || slash + 1 === value.length)
688
- break;
689
- const character = String.fromCodePoint(value.codePointAt(slash + 1));
690
- escaped.add(characters++);
691
- text.append(character);
692
- index = slash + 1 + character.length;
693
- }
694
- return { value: text.finish(), escaped, terminated };
695
- }
696
1467
  close() {
697
1468
  if (!this.#closing) {
698
1469
  this.#lifetime.abort(new Error("Shell input view closed"));
699
- this.#closing = this.#owned ? this.#cursor.close(this.#cleanupSignal) : Promise.resolve();
1470
+ const pending = [...this.#reads].map(release => release());
1471
+ if (this.#owned)
1472
+ pending.push(this.#cursor.close(this.#cleanupSignal));
1473
+ this.#closing = Promise.all(pending).then(() => undefined);
700
1474
  }
701
1475
  return this.#closing;
702
1476
  }