@poe-platform/safe-bash 0.1.630 → 0.1.631
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.
- package/README.md +1 -0
- package/dist/office-package/compression.d.ts +19 -0
- package/dist/office-package/compression.js +186 -0
- package/dist/office-package/runtime.d.ts +11 -0
- package/dist/office-package/runtime.js +28 -0
- package/dist/safe-bash/chunks/{bz2-B2RXT4EX.js → bz2-ACU4EOVE.js} +2 -2
- package/dist/safe-bash/chunks/chunk-2E4KBFO6.js +239 -0
- package/dist/safe-bash/chunks/chunk-2E4KBFO6.js.map +7 -0
- package/dist/safe-bash/chunks/chunk-3E5M2WEL.js +33 -0
- package/dist/safe-bash/chunks/chunk-3E5M2WEL.js.map +7 -0
- package/dist/safe-bash/chunks/{chunk-KQ6J7JHQ.js → chunk-3LD67SER.js} +12 -10
- package/dist/safe-bash/chunks/{chunk-KQ6J7JHQ.js.map → chunk-3LD67SER.js.map} +1 -1
- package/dist/safe-bash/chunks/{chunk-6LSSEOG7.js → chunk-6HNK7Q66.js} +11 -7
- package/dist/safe-bash/chunks/{chunk-6LSSEOG7.js.map → chunk-6HNK7Q66.js.map} +1 -1
- package/dist/safe-bash/chunks/{chunk-AD7UAP5B.js → chunk-7EEWZY5S.js} +10 -8
- package/dist/safe-bash/chunks/{chunk-AD7UAP5B.js.map → chunk-7EEWZY5S.js.map} +1 -1
- package/dist/safe-bash/chunks/{chunk-RNKTWFEM.js → chunk-CDBQXRWL.js} +3 -3
- package/dist/safe-bash/chunks/{chunk-UYX72YHY.js → chunk-CHHAB5SS.js} +10 -74
- package/dist/safe-bash/chunks/{chunk-UYX72YHY.js.map → chunk-CHHAB5SS.js.map} +3 -3
- package/dist/safe-bash/chunks/{chunk-6YSBXTTJ.js → chunk-EI4X5ETX.js} +12 -10
- package/dist/safe-bash/chunks/{chunk-6YSBXTTJ.js.map → chunk-EI4X5ETX.js.map} +1 -1
- package/dist/safe-bash/chunks/{chunk-KZ7QCYNT.js → chunk-GIBLUW2U.js} +13 -9
- package/dist/safe-bash/chunks/{chunk-KZ7QCYNT.js.map → chunk-GIBLUW2U.js.map} +1 -1
- package/dist/safe-bash/chunks/chunk-GPV7ZFYS.js +1528 -0
- package/dist/safe-bash/chunks/chunk-GPV7ZFYS.js.map +7 -0
- package/dist/safe-bash/chunks/{chunk-N5CYTGBN.js → chunk-H3E67KTZ.js} +13 -9
- package/dist/safe-bash/chunks/{chunk-N5CYTGBN.js.map → chunk-H3E67KTZ.js.map} +1 -1
- package/dist/safe-bash/chunks/{chunk-AFH57PPL.js → chunk-IEKESMO4.js} +3 -3
- package/dist/safe-bash/chunks/{chunk-DPJWEGIX.js → chunk-JLBIUYT3.js} +2 -2
- package/dist/safe-bash/chunks/chunk-JZDO5MC3.js +77 -0
- package/dist/safe-bash/chunks/chunk-JZDO5MC3.js.map +7 -0
- package/dist/safe-bash/chunks/{chunk-GFZKQIPL.js → chunk-LA6BX562.js} +8 -6
- package/dist/safe-bash/chunks/{chunk-GFZKQIPL.js.map → chunk-LA6BX562.js.map} +1 -1
- package/dist/safe-bash/chunks/{chunk-PVJJFCGA.js → chunk-M3GPCYSP.js} +2 -2
- package/dist/safe-bash/chunks/{chunk-FWDMJTQO.js → chunk-NDCZ3UBP.js} +13 -9
- package/dist/safe-bash/chunks/{chunk-FWDMJTQO.js.map → chunk-NDCZ3UBP.js.map} +1 -1
- package/dist/safe-bash/chunks/{chunk-2KL6W6NB.js → chunk-O2EVBRKF.js} +1 -2
- package/dist/safe-bash/chunks/chunk-OFT77XIB.js +389 -0
- package/dist/safe-bash/chunks/chunk-OFT77XIB.js.map +7 -0
- package/dist/safe-bash/chunks/{chunk-PCLOK32J.js → chunk-PC6BEIAF.js} +13 -9
- package/dist/safe-bash/chunks/{chunk-PCLOK32J.js.map → chunk-PC6BEIAF.js.map} +1 -1
- package/dist/safe-bash/chunks/{chunk-3M5F7LD5.js → chunk-QWKP7ZU7.js} +13 -9
- package/dist/safe-bash/chunks/{chunk-3M5F7LD5.js.map → chunk-QWKP7ZU7.js.map} +1 -1
- package/dist/safe-bash/chunks/chunk-THXJ6CLF.js +53 -0
- package/dist/safe-bash/chunks/chunk-THXJ6CLF.js.map +7 -0
- package/dist/safe-bash/chunks/{chunk-K7W6Q6FN.js → chunk-V73A742N.js} +58 -16
- package/dist/safe-bash/chunks/chunk-V73A742N.js.map +7 -0
- package/dist/safe-bash/chunks/{chunk-4BYUV5PA.js → chunk-VN3ZGME3.js} +12 -8
- package/dist/safe-bash/chunks/{chunk-4BYUV5PA.js.map → chunk-VN3ZGME3.js.map} +1 -1
- package/dist/safe-bash/chunks/{chunk-3BZ5NQ73.js → chunk-WECHUK3Y.js} +369 -36
- package/dist/safe-bash/chunks/chunk-WECHUK3Y.js.map +7 -0
- package/dist/safe-bash/chunks/{chunk-X55AMTNM.js → chunk-WIOEUR7D.js} +14 -10
- package/dist/safe-bash/chunks/{chunk-X55AMTNM.js.map → chunk-WIOEUR7D.js.map} +1 -1
- package/dist/safe-bash/chunks/chunk-WPIOO4NX.js +443 -0
- package/dist/safe-bash/chunks/chunk-WPIOO4NX.js.map +7 -0
- package/dist/safe-bash/chunks/{chunk-C7QNJ3D4.js → chunk-WYTI64IU.js} +2 -2
- package/dist/safe-bash/chunks/{xz-AVXFDXW4.js → xz-U4QDTPZL.js} +2 -2
- package/dist/safe-bash/chunks/{zstd-R6RPHJYO.js → zstd-OG5RPYXO.js} +2 -2
- package/dist/safe-bash/commands/archive/zip/crc.d.ts +2 -0
- package/dist/safe-bash/commands/archive/zip/crc.d.ts.map +1 -0
- package/dist/safe-bash/commands/archive/zip/crc.js +7 -0
- package/dist/safe-bash/commands/archive/zip/crc.js.map +1 -0
- package/dist/safe-bash/commands/archive/zip/crypto.d.ts +4 -0
- package/dist/safe-bash/commands/archive/zip/crypto.d.ts.map +1 -0
- package/dist/safe-bash/commands/archive/zip/crypto.js +34 -0
- package/dist/safe-bash/commands/archive/zip/crypto.js.map +1 -0
- package/dist/safe-bash/commands/archive/zip/help.d.ts +3 -0
- package/dist/safe-bash/commands/archive/zip/help.d.ts.map +1 -0
- package/dist/safe-bash/commands/archive/zip/help.js +87 -0
- package/dist/safe-bash/commands/archive/zip/help.js.map +1 -0
- package/dist/safe-bash/commands/archive/zip/move.d.ts +12 -0
- package/dist/safe-bash/commands/archive/zip/move.d.ts.map +1 -0
- package/dist/safe-bash/commands/archive/zip/move.js +60 -0
- package/dist/safe-bash/commands/archive/zip/move.js.map +1 -0
- package/dist/safe-bash/commands/archive/zip/options.js +5 -5
- package/dist/safe-bash/commands/archive/zip/options.js.map +1 -1
- package/dist/safe-bash/commands/archive/zip-format.d.ts +1 -1
- package/dist/safe-bash/commands/archive/zip-format.d.ts.map +1 -1
- package/dist/safe-bash/commands/archive/zip-format.js +14 -17
- package/dist/safe-bash/commands/archive/zip-format.js.map +1 -1
- package/dist/safe-bash/commands/archive/zip.d.ts.map +1 -1
- package/dist/safe-bash/commands/archive/zip.js +45 -15
- package/dist/safe-bash/commands/archive/zip.js.map +1 -1
- package/dist/safe-bash/commands/bytes/compression/bounded-codec.d.ts +2 -0
- package/dist/safe-bash/commands/bytes/compression/bounded-codec.d.ts.map +1 -1
- package/dist/safe-bash/commands/bytes/compression/bounded-codec.js +4 -0
- package/dist/safe-bash/commands/bytes/compression/bounded-codec.js.map +1 -1
- package/dist/safe-bash/commands/bytes/compression/codec.d.ts +4 -24
- package/dist/safe-bash/commands/bytes/compression/codec.d.ts.map +1 -1
- package/dist/safe-bash/commands/bytes/compression/codec.js +12 -168
- package/dist/safe-bash/commands/bytes/compression/codec.js.map +1 -1
- package/dist/safe-bash/commands/cmp.js +1 -1
- package/dist/safe-bash/commands/cmp.js.map +1 -1
- package/dist/safe-bash/commands/csplit/index.browser.js +10 -7
- package/dist/safe-bash/commands/docx/index.browser.js +54 -0
- package/dist/safe-bash/commands/docx/index.browser.js.map +7 -0
- package/dist/safe-bash/commands/docx/index.d.ts +25 -0
- package/dist/safe-bash/commands/docx/index.d.ts.map +1 -0
- package/dist/safe-bash/commands/docx/index.js +42 -0
- package/dist/safe-bash/commands/docx/index.js.map +1 -0
- package/dist/safe-bash/commands/docx/io.d.ts +15 -0
- package/dist/safe-bash/commands/docx/io.d.ts.map +1 -0
- package/dist/safe-bash/commands/docx/io.js +16 -0
- package/dist/safe-bash/commands/docx/io.js.map +1 -0
- package/dist/safe-bash/commands/factor/index.browser.js +7 -5
- package/dist/safe-bash/commands/filesystem.d.ts.map +1 -1
- package/dist/safe-bash/commands/filesystem.js +9 -1
- package/dist/safe-bash/commands/filesystem.js.map +1 -1
- package/dist/safe-bash/commands/getopt/index.browser.js +7 -5
- package/dist/safe-bash/commands/hexdump/index.browser.js +8 -6
- package/dist/safe-bash/commands/iconv/index.browser.js +8 -6
- package/dist/safe-bash/commands/line-endings/index.browser.js +10 -7
- package/dist/safe-bash/commands/llm/index.browser.js +10 -8
- package/dist/safe-bash/commands/llm/providers/index.browser.js +3 -3
- package/dist/safe-bash/commands/network/index.browser.js +11 -8
- package/dist/safe-bash/commands/node/index.browser.js +8 -6
- package/dist/safe-bash/commands/op/index.browser.js +3 -3
- package/dist/safe-bash/commands/op/index.js +0 -1
- package/dist/safe-bash/commands/op/index.js.map +2 -2
- package/dist/safe-bash/commands/pptx/index.d.ts +29 -0
- package/dist/safe-bash/commands/pptx/index.d.ts.map +1 -0
- package/dist/safe-bash/commands/pptx/index.js +153 -0
- package/dist/safe-bash/commands/pptx/index.js.map +1 -0
- package/dist/safe-bash/commands/pr/index.browser.js +8 -6
- package/dist/safe-bash/commands/predicates.js +1 -1
- package/dist/safe-bash/commands/python/execution.d.ts +3 -0
- package/dist/safe-bash/commands/python/execution.d.ts.map +1 -0
- package/dist/safe-bash/commands/python/execution.js +193 -0
- package/dist/safe-bash/commands/python/execution.js.map +1 -0
- package/dist/safe-bash/commands/python/index.browser.js +21 -0
- package/dist/safe-bash/commands/python/index.browser.js.map +7 -0
- package/dist/safe-bash/commands/python/index.d.ts +49 -0
- package/dist/safe-bash/commands/python/index.d.ts.map +1 -0
- package/dist/safe-bash/commands/python/index.js +317 -0
- package/dist/safe-bash/commands/python/index.js.map +1 -0
- package/dist/safe-bash/commands/python/installation.d.ts +9 -0
- package/dist/safe-bash/commands/python/installation.d.ts.map +1 -0
- package/dist/safe-bash/commands/python/installation.js +80 -0
- package/dist/safe-bash/commands/python/installation.js.map +1 -0
- package/dist/safe-bash/commands/python/invocation.d.ts +10 -0
- package/dist/safe-bash/commands/python/invocation.d.ts.map +1 -0
- package/dist/safe-bash/commands/python/invocation.js +81 -0
- package/dist/safe-bash/commands/python/invocation.js.map +1 -0
- package/dist/safe-bash/commands/python/node.d.ts +12 -0
- package/dist/safe-bash/commands/python/node.d.ts.map +1 -0
- package/dist/safe-bash/commands/python/node.js +33 -0
- package/dist/safe-bash/commands/python/node.js.map +1 -0
- package/dist/safe-bash/commands/python/provisioning-runtime.d.ts +5 -0
- package/dist/safe-bash/commands/python/provisioning-runtime.d.ts.map +1 -0
- package/dist/safe-bash/commands/python/provisioning-runtime.js +179 -0
- package/dist/safe-bash/commands/python/provisioning-runtime.js.map +1 -0
- package/dist/safe-bash/commands/python/provisioning.d.ts +49 -0
- package/dist/safe-bash/commands/python/provisioning.d.ts.map +1 -0
- package/dist/safe-bash/commands/python/provisioning.js +320 -0
- package/dist/safe-bash/commands/python/provisioning.js.map +1 -0
- package/dist/safe-bash/commands/python/reply.d.ts +3 -0
- package/dist/safe-bash/commands/python/reply.d.ts.map +1 -0
- package/dist/safe-bash/commands/python/reply.js +103 -0
- package/dist/safe-bash/commands/python/reply.js.map +1 -0
- package/dist/safe-bash/commands/python/worker.browser.js +736 -0
- package/dist/safe-bash/commands/python/worker.browser.js.map +7 -0
- package/dist/safe-bash/commands/python/worker.d.ts +47 -0
- package/dist/safe-bash/commands/python/worker.d.ts.map +1 -0
- package/dist/safe-bash/commands/python/worker.js +373 -0
- package/dist/safe-bash/commands/python/worker.js.map +1 -0
- package/dist/safe-bash/commands/tsort/index.browser.js +8 -6
- package/dist/safe-bash/commands/xml/index.browser.js +9 -7
- package/dist/safe-bash/commands/yq/index.browser.js +10 -8
- package/dist/safe-bash/commands/yq/index.d.ts.map +1 -1
- package/dist/safe-bash/commands/yq/index.js +32 -4
- package/dist/safe-bash/commands/yq/index.js.map +1 -1
- package/dist/safe-bash/commands/yq/parser.d.ts.map +1 -1
- package/dist/safe-bash/commands/yq/parser.js +21 -5
- package/dist/safe-bash/commands/yq/parser.js.map +1 -1
- package/dist/safe-bash/contracts/command.d.ts +2 -0
- package/dist/safe-bash/contracts/command.d.ts.map +1 -1
- package/dist/safe-bash/contracts/command.js +6 -2
- package/dist/safe-bash/contracts/command.js.map +1 -1
- package/dist/safe-bash/contracts/filesystem-descriptor.d.ts +13 -0
- package/dist/safe-bash/contracts/filesystem-descriptor.d.ts.map +1 -0
- package/dist/safe-bash/contracts/filesystem-descriptor.js +189 -0
- package/dist/safe-bash/contracts/filesystem-descriptor.js.map +1 -0
- package/dist/safe-bash/contracts/filesystem-output-budget.d.ts +15 -0
- package/dist/safe-bash/contracts/filesystem-output-budget.d.ts.map +1 -0
- package/dist/safe-bash/contracts/filesystem-output-budget.js +69 -0
- package/dist/safe-bash/contracts/filesystem-output-budget.js.map +1 -0
- package/dist/safe-bash/contracts/filesystem-output.d.ts +11 -5
- package/dist/safe-bash/contracts/filesystem-output.d.ts.map +1 -1
- package/dist/safe-bash/contracts/filesystem-output.js +229 -20
- package/dist/safe-bash/contracts/filesystem-output.js.map +1 -1
- package/dist/safe-bash/contracts/io.d.ts +29 -0
- package/dist/safe-bash/contracts/io.d.ts.map +1 -1
- package/dist/safe-bash/contracts/io.js +317 -37
- package/dist/safe-bash/contracts/io.js.map +1 -1
- package/dist/safe-bash/core.browser.js +5502 -2210
- package/dist/safe-bash/core.browser.js.map +4 -4
- package/dist/safe-bash/core.d.ts +1 -0
- package/dist/safe-bash/core.d.ts.map +1 -1
- package/dist/safe-bash/core.js +1 -0
- package/dist/safe-bash/core.js.map +1 -1
- package/dist/safe-bash/opt-in/commands/cmp/compare.js +95 -0
- package/dist/safe-bash/opt-in/commands/cmp/index.d.ts +6 -0
- package/dist/safe-bash/opt-in/commands/cmp/index.js +99 -0
- package/dist/safe-bash/opt-in/commands/cmp/io.js +218 -0
- package/dist/safe-bash/opt-in/commands/cmp/options.d.ts +24 -0
- package/dist/safe-bash/opt-in/commands/cmp/options.js +195 -0
- package/dist/safe-bash/opt-in/commands/dd/conversions.js +152 -0
- package/dist/safe-bash/opt-in/commands/dd/index.d.ts +18 -0
- package/dist/safe-bash/opt-in/commands/dd/index.js +561 -0
- package/dist/safe-bash/opt-in/commands/dd/io.d.ts +31 -0
- package/dist/safe-bash/opt-in/commands/dd/io.js +244 -0
- package/dist/safe-bash/opt-in/commands/dd/options.js +184 -0
- package/dist/safe-bash/opt-in/commands/dd/report.js +69 -0
- package/dist/safe-bash/opt-in/commands/install/arguments.js +224 -0
- package/dist/safe-bash/opt-in/commands/install/index.d.ts +6 -0
- package/dist/safe-bash/opt-in/commands/install/index.js +678 -0
- package/dist/safe-bash/opt-in/commands/install/mode.js +71 -0
- package/dist/safe-bash/opt-in/commands/install/options.d.ts +36 -0
- package/dist/safe-bash/opt-in/commands/install/options.js +27 -0
- package/dist/safe-bash/opt-in/commands/shuf/args.js +179 -0
- package/dist/safe-bash/opt-in/commands/shuf/index.d.ts +6 -0
- package/dist/safe-bash/opt-in/commands/shuf/index.js +20 -0
- package/dist/safe-bash/opt-in/commands/shuf/input.js +93 -0
- package/dist/safe-bash/opt-in/commands/shuf/options.d.ts +9 -0
- package/dist/safe-bash/opt-in/commands/shuf/options.js +8 -0
- package/dist/safe-bash/opt-in/commands/shuf/random.js +114 -0
- package/dist/safe-bash/opt-in/commands/shuf/shuf.d.ts +3 -0
- package/dist/safe-bash/opt-in/commands/shuf/shuf.js +230 -0
- package/dist/safe-bash/opt-in/commands/shuf/usage.js +24 -0
- package/dist/safe-bash/opt-in/commands/truncate/arguments.js +186 -0
- package/dist/safe-bash/opt-in/commands/truncate/index.d.ts +9 -0
- package/dist/safe-bash/opt-in/commands/truncate/index.js +244 -0
- package/dist/safe-bash/opt-in/commands/yes/index.d.ts +11 -0
- package/dist/safe-bash/opt-in/commands/yes/index.js +167 -0
- package/dist/safe-bash/opt-in/commands/yq/arguments.js +177 -0
- package/dist/safe-bash/opt-in/commands/yq/evaluate.js +564 -0
- package/dist/safe-bash/opt-in/commands/yq/expression.js +183 -0
- package/dist/safe-bash/opt-in/commands/yq/inplace.js +65 -0
- package/dist/safe-bash/opt-in/commands/yq/mike.d.ts +9 -0
- package/dist/safe-bash/opt-in/commands/yq/mike.js +192 -0
- package/dist/safe-bash/opt-in/commands/yq/native-encoder.js +165 -0
- package/dist/safe-bash/opt-in/commands/yq/native-work.d.ts +44 -0
- package/dist/safe-bash/opt-in/commands/yq/native-work.js +188 -0
- package/dist/safe-bash/opt-in/commands/yq/nodes.js +621 -0
- package/dist/safe-bash/opt-in/entrypoints/arrays.d.ts +1 -0
- package/dist/safe-bash/opt-in/entrypoints/arrays.js +1 -0
- package/dist/safe-bash/opt-in/entrypoints/cmp.d.ts +2 -0
- package/dist/safe-bash/opt-in/entrypoints/cmp.js +1 -0
- package/dist/safe-bash/opt-in/entrypoints/dd.d.ts +2 -0
- package/dist/safe-bash/opt-in/entrypoints/dd.js +1 -0
- package/dist/safe-bash/opt-in/entrypoints/devices.d.ts +2 -0
- package/dist/safe-bash/opt-in/entrypoints/devices.js +1 -0
- package/dist/safe-bash/opt-in/entrypoints/install.d.ts +2 -0
- package/dist/safe-bash/opt-in/entrypoints/install.js +1 -0
- package/dist/safe-bash/opt-in/entrypoints/jobs.d.ts +1 -0
- package/dist/safe-bash/opt-in/entrypoints/jobs.js +1 -0
- package/dist/safe-bash/opt-in/entrypoints/mapfile.d.ts +1 -0
- package/dist/safe-bash/opt-in/entrypoints/mapfile.js +1 -0
- package/dist/safe-bash/opt-in/entrypoints/read.d.ts +2 -0
- package/dist/safe-bash/opt-in/entrypoints/read.js +1 -0
- package/dist/safe-bash/opt-in/entrypoints/shuf.d.ts +2 -0
- package/dist/safe-bash/opt-in/entrypoints/shuf.js +1 -0
- package/dist/safe-bash/opt-in/entrypoints/trap.d.ts +2 -0
- package/dist/safe-bash/opt-in/entrypoints/trap.js +1 -0
- package/dist/safe-bash/opt-in/entrypoints/truncate.d.ts +2 -0
- package/dist/safe-bash/opt-in/entrypoints/truncate.js +1 -0
- package/dist/safe-bash/opt-in/entrypoints/yes.d.ts +2 -0
- package/dist/safe-bash/opt-in/entrypoints/yes.js +1 -0
- package/dist/safe-bash/opt-in/entrypoints/yq.d.ts +3 -0
- package/dist/safe-bash/opt-in/entrypoints/yq.js +1 -0
- package/dist/safe-bash/opt-in/fs/devices/index.d.ts +8 -0
- package/dist/safe-bash/opt-in/fs/devices/index.js +292 -0
- package/dist/safe-bash/opt-in/optional.d.ts +28 -0
- package/dist/safe-bash/opt-in/optional.js +14 -0
- package/dist/safe-bash/opt-in/shell/extensions/arrays/index.d.ts +2 -0
- package/dist/safe-bash/opt-in/shell/extensions/arrays/index.js +4 -0
- package/dist/safe-bash/opt-in/shell/extensions/jobs/index.d.ts +2 -0
- package/dist/safe-bash/opt-in/shell/extensions/jobs/index.js +291 -0
- package/dist/safe-bash/opt-in/shell/extensions/jobs/state.js +374 -0
- package/dist/safe-bash/opt-in/shell/extensions/mapfile/index.d.ts +24 -0
- package/dist/safe-bash/opt-in/shell/extensions/mapfile/index.js +338 -0
- package/dist/safe-bash/opt-in/shell/extensions/read/index.d.ts +5 -0
- package/dist/safe-bash/opt-in/shell/extensions/read/index.js +351 -0
- package/dist/safe-bash/opt-in/shell/extensions/trap/index.d.ts +9 -0
- package/dist/safe-bash/opt-in/shell/extensions/trap/index.js +210 -0
- package/dist/safe-bash/optional-host.d.ts +5 -0
- package/dist/safe-bash/optional-host.d.ts.map +1 -0
- package/dist/safe-bash/optional-host.js +3 -0
- package/dist/safe-bash/optional-host.js.map +1 -0
- package/dist/safe-bash/shell/arrays/bindings.d.ts +15 -5
- package/dist/safe-bash/shell/arrays/bindings.d.ts.map +1 -1
- package/dist/safe-bash/shell/arrays/bindings.js +131 -23
- package/dist/safe-bash/shell/arrays/bindings.js.map +1 -1
- package/dist/safe-bash/shell/arrays/ledger.d.ts +1 -0
- package/dist/safe-bash/shell/arrays/ledger.d.ts.map +1 -1
- package/dist/safe-bash/shell/arrays/ledger.js +19 -0
- package/dist/safe-bash/shell/arrays/ledger.js.map +1 -1
- package/dist/safe-bash/shell/arrays/state.d.ts.map +1 -1
- package/dist/safe-bash/shell/arrays/state.js +3 -1
- package/dist/safe-bash/shell/arrays/state.js.map +1 -1
- package/dist/safe-bash/shell/arrays/syntax.d.ts +4 -1
- package/dist/safe-bash/shell/arrays/syntax.d.ts.map +1 -1
- package/dist/safe-bash/shell/arrays/syntax.js +3 -3
- package/dist/safe-bash/shell/arrays/syntax.js.map +1 -1
- package/dist/safe-bash/shell/conditional.js +1 -1
- package/dist/safe-bash/shell/descriptors.d.ts +31 -0
- package/dist/safe-bash/shell/descriptors.d.ts.map +1 -0
- package/dist/safe-bash/shell/descriptors.js +234 -0
- package/dist/safe-bash/shell/descriptors.js.map +1 -0
- package/dist/safe-bash/shell/diagnostic-name-ranges.d.ts +2 -0
- package/dist/safe-bash/shell/diagnostic-name-ranges.d.ts.map +1 -0
- package/dist/safe-bash/shell/diagnostic-name-ranges.js +717 -0
- package/dist/safe-bash/shell/diagnostic-name-ranges.js.map +1 -0
- package/dist/safe-bash/shell/diagnostic-name.d.ts +3 -0
- package/dist/safe-bash/shell/diagnostic-name.d.ts.map +1 -0
- package/dist/safe-bash/shell/diagnostic-name.js +89 -0
- package/dist/safe-bash/shell/diagnostic-name.js.map +1 -0
- package/dist/safe-bash/shell/display.js +1 -1
- package/dist/safe-bash/shell/display.js.map +1 -1
- package/dist/safe-bash/shell/extensions.d.ts +188 -0
- package/dist/safe-bash/shell/extensions.d.ts.map +1 -0
- package/dist/safe-bash/shell/extensions.js +141 -0
- package/dist/safe-bash/shell/extensions.js.map +1 -0
- package/dist/safe-bash/shell/input.d.ts +66 -14
- package/dist/safe-bash/shell/input.d.ts.map +1 -1
- package/dist/safe-bash/shell/input.js +947 -173
- package/dist/safe-bash/shell/input.js.map +1 -1
- package/dist/safe-bash/shell/parser.d.ts +38 -6
- package/dist/safe-bash/shell/parser.d.ts.map +1 -1
- package/dist/safe-bash/shell/parser.js +339 -52
- package/dist/safe-bash/shell/parser.js.map +1 -1
- package/dist/safe-bash/shell/runtime.d.ts +92 -20
- package/dist/safe-bash/shell/runtime.d.ts.map +1 -1
- package/dist/safe-bash/shell/runtime.js +2547 -689
- package/dist/safe-bash/shell/runtime.js.map +1 -1
- package/dist/safe-bash/shell/shell.d.ts.map +1 -1
- package/dist/safe-bash/shell/shell.js +52 -21
- package/dist/safe-bash/shell/shell.js.map +1 -1
- package/dist/safe-bash/shell/types.d.ts +4 -0
- package/dist/safe-bash/shell/types.d.ts.map +1 -1
- package/dist/safe-bash/shell/types.js.map +1 -1
- package/package.json +92 -4
- package/dist/safe-bash/chunks/chunk-3BZ5NQ73.js.map +0 -7
- package/dist/safe-bash/chunks/chunk-4DBWBEU7.js +0 -194
- package/dist/safe-bash/chunks/chunk-4DBWBEU7.js.map +0 -7
- package/dist/safe-bash/chunks/chunk-CXMIIXJA.js +0 -178
- package/dist/safe-bash/chunks/chunk-CXMIIXJA.js.map +0 -7
- package/dist/safe-bash/chunks/chunk-K7W6Q6FN.js.map +0 -7
- /package/dist/safe-bash/chunks/{bz2-B2RXT4EX.js.map → bz2-ACU4EOVE.js.map} +0 -0
- /package/dist/safe-bash/chunks/{chunk-RNKTWFEM.js.map → chunk-CDBQXRWL.js.map} +0 -0
- /package/dist/safe-bash/chunks/{chunk-AFH57PPL.js.map → chunk-IEKESMO4.js.map} +0 -0
- /package/dist/safe-bash/chunks/{chunk-DPJWEGIX.js.map → chunk-JLBIUYT3.js.map} +0 -0
- /package/dist/safe-bash/chunks/{chunk-PVJJFCGA.js.map → chunk-M3GPCYSP.js.map} +0 -0
- /package/dist/safe-bash/chunks/{chunk-2KL6W6NB.js.map → chunk-O2EVBRKF.js.map} +0 -0
- /package/dist/safe-bash/chunks/{chunk-C7QNJ3D4.js.map → chunk-WYTI64IU.js.map} +0 -0
- /package/dist/safe-bash/chunks/{xz-AVXFDXW4.js.map → xz-U4QDTPZL.js.map} +0 -0
- /package/dist/safe-bash/chunks/{zstd-R6RPHJYO.js.map → zstd-OG5RPYXO.js.map} +0 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import { commandRuntimeIdentity } from "@poe-platform/safe-bash/contracts/command";
|
|
2
|
+
import { writeText } from "@poe-platform/safe-bash/contracts/io";
|
|
3
|
+
import { concatShellValues, shellValueBytes, shellValueFromBytes } from "@poe-platform/safe-bash/contracts/value";
|
|
4
|
+
import { createJobState } from "./state.js";
|
|
5
|
+
const maximumWaitProcessId = 2147483647;
|
|
6
|
+
function waitProcessId(operand, flexible = false) {
|
|
7
|
+
let value = 0;
|
|
8
|
+
let offset = 0;
|
|
9
|
+
let negative = false;
|
|
10
|
+
if (flexible) {
|
|
11
|
+
while (offset < operand.length && (operand.charCodeAt(offset) === 32 || operand.charCodeAt(offset) >= 9 && operand.charCodeAt(offset) <= 13))
|
|
12
|
+
offset++;
|
|
13
|
+
if (operand[offset] === "+" || operand[offset] === "-")
|
|
14
|
+
negative = operand[offset++] === "-";
|
|
15
|
+
}
|
|
16
|
+
const firstDigit = offset;
|
|
17
|
+
while (offset < operand.length) {
|
|
18
|
+
const code = operand.charCodeAt(offset);
|
|
19
|
+
if (code < 48 || code > 57)
|
|
20
|
+
break;
|
|
21
|
+
value = value * 10 + code - 48;
|
|
22
|
+
if (value > maximumWaitProcessId + Number(negative))
|
|
23
|
+
return undefined;
|
|
24
|
+
offset++;
|
|
25
|
+
}
|
|
26
|
+
if (offset === firstDigit)
|
|
27
|
+
return undefined;
|
|
28
|
+
while (offset < operand.length) {
|
|
29
|
+
const code = operand.charCodeAt(offset++);
|
|
30
|
+
if (code !== 32 && (code < 9 || code > 13))
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
return negative ? -value : value;
|
|
34
|
+
}
|
|
35
|
+
function instance(inherited) {
|
|
36
|
+
let latest = inherited;
|
|
37
|
+
let jobs;
|
|
38
|
+
let failure;
|
|
39
|
+
const children = new Map();
|
|
40
|
+
const status = (outcome) => {
|
|
41
|
+
if (outcome.kind === "failure") {
|
|
42
|
+
failure ??= { reason: outcome.reason };
|
|
43
|
+
throw outcome.reason;
|
|
44
|
+
}
|
|
45
|
+
return outcome.status;
|
|
46
|
+
};
|
|
47
|
+
const wait = async (context) => {
|
|
48
|
+
let reference;
|
|
49
|
+
let primary;
|
|
50
|
+
const ordinaryWait = async (targets) => {
|
|
51
|
+
if (context.waitInterruptibly)
|
|
52
|
+
return context.waitInterruptibly(signal => jobs.wait(targets, { signal }));
|
|
53
|
+
return { kind: "completed", value: await jobs.wait(targets, { signal: context.signal }) };
|
|
54
|
+
};
|
|
55
|
+
const execute = async () => {
|
|
56
|
+
let offset = 0;
|
|
57
|
+
let next = false;
|
|
58
|
+
let destination;
|
|
59
|
+
while (offset < context.args.length) {
|
|
60
|
+
context.signal.throwIfAborted();
|
|
61
|
+
const option = shellValueBytes(context.argumentValues[offset]);
|
|
62
|
+
if (option.length < 2 || option[0] !== 45)
|
|
63
|
+
break;
|
|
64
|
+
offset++;
|
|
65
|
+
if (option.length === 2 && option[1] === 45)
|
|
66
|
+
break;
|
|
67
|
+
for (let index = 1; index < option.length; index++) {
|
|
68
|
+
if (option[index] === 102)
|
|
69
|
+
continue;
|
|
70
|
+
if (option[index] === 110) {
|
|
71
|
+
next = true;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (option[index] === 112) {
|
|
75
|
+
if (index + 1 < option.length)
|
|
76
|
+
destination = shellValueFromBytes(option.subarray(index + 1));
|
|
77
|
+
else if (offset < context.args.length)
|
|
78
|
+
destination = context.argumentValues[offset++];
|
|
79
|
+
else {
|
|
80
|
+
await context.diagnostic("wait: -p: option requires an argument");
|
|
81
|
+
await writeText(context.stderr, "wait: usage: wait [-fn] [-p var] [id ...]\n");
|
|
82
|
+
return 2;
|
|
83
|
+
}
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
await context.diagnostic(concatShellValues(["wait: -", shellValueFromBytes(option.subarray(index, index + 1)), ": invalid option"]));
|
|
87
|
+
await writeText(context.stderr, "wait: usage: wait [-fn] [-p var] [id ...]\n");
|
|
88
|
+
return 2;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (destination !== undefined) {
|
|
92
|
+
const prepared = await context.bindings.prepareReference(destination);
|
|
93
|
+
if (!prepared.ok) {
|
|
94
|
+
await context.diagnostic(concatShellValues(["wait: ", prepared.diagnostic]));
|
|
95
|
+
return 1;
|
|
96
|
+
}
|
|
97
|
+
reference = prepared.value;
|
|
98
|
+
const removed = await reference.unbindName();
|
|
99
|
+
if (!removed.ok) {
|
|
100
|
+
await context.diagnostic(concatShellValues(["wait: ", removed.diagnostic]));
|
|
101
|
+
return 1;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const publish = async (result, processId) => {
|
|
105
|
+
if (reference && processId !== undefined) {
|
|
106
|
+
const assigned = await reference.assignInteger(processId);
|
|
107
|
+
if (!assigned.ok) {
|
|
108
|
+
await context.diagnostic(concatShellValues(["wait: ", assigned.diagnostic]));
|
|
109
|
+
return 1;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
};
|
|
114
|
+
if (next) {
|
|
115
|
+
for (let index = offset; index < context.args.length; index++) {
|
|
116
|
+
context.signal.throwIfAborted();
|
|
117
|
+
const processId = waitProcessId(context.args[index], true);
|
|
118
|
+
const handle = processId === undefined || processId < 0 ? undefined : children.get(processId);
|
|
119
|
+
const saved = handle && jobs.savedStatus(handle);
|
|
120
|
+
if (saved !== undefined)
|
|
121
|
+
return await publish(saved, processId);
|
|
122
|
+
}
|
|
123
|
+
const active = new Set(jobs.snapshot().filter(entry => entry.residency !== "saved").map(entry => entry.handle));
|
|
124
|
+
const targets = [];
|
|
125
|
+
for (let index = offset; index < context.args.length; index++) {
|
|
126
|
+
context.signal.throwIfAborted();
|
|
127
|
+
const operand = context.args[index];
|
|
128
|
+
const raw = context.argumentValues[index];
|
|
129
|
+
const processId = waitProcessId(operand, true);
|
|
130
|
+
const handle = processId === undefined ? undefined : children.get(processId);
|
|
131
|
+
if (handle && active.has(handle)) {
|
|
132
|
+
targets.push({ handle });
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if ((processId === undefined || processId === -1) && operand.length && operand[0] !== "%")
|
|
136
|
+
await context.diagnostic(concatShellValues(["wait: warning: ", raw, ": job specification requires leading `%'"]));
|
|
137
|
+
await context.diagnostic(concatShellValues(["wait: `", raw, operand[0] === "%" ? "': no such job" : "': not a pid or valid job spec"]));
|
|
138
|
+
}
|
|
139
|
+
if (offset < context.args.length && !targets.length)
|
|
140
|
+
return 127;
|
|
141
|
+
const selected = offset === context.args.length ? undefined : targets;
|
|
142
|
+
const waited = context.waitInterruptibly
|
|
143
|
+
? await context.waitInterruptibly(signal => jobs.waitNext(selected, { signal }))
|
|
144
|
+
: { kind: "completed", value: await jobs.waitNext(selected, { signal: context.signal }) };
|
|
145
|
+
if (waited.kind === "interrupted")
|
|
146
|
+
return waited.status;
|
|
147
|
+
const result = status(waited.value.outcome);
|
|
148
|
+
const processId = waited.value.handle && [...children].find(([, handle]) => handle === waited.value.handle)?.[0];
|
|
149
|
+
return await publish(result, processId);
|
|
150
|
+
}
|
|
151
|
+
if (offset === context.args.length) {
|
|
152
|
+
const result = await ordinaryWait();
|
|
153
|
+
if (result.kind === "interrupted")
|
|
154
|
+
return result.status;
|
|
155
|
+
children.clear();
|
|
156
|
+
return status(result.value.outcome);
|
|
157
|
+
}
|
|
158
|
+
const waitOperands = async (signal) => {
|
|
159
|
+
let result = 0;
|
|
160
|
+
let returnedProcessId;
|
|
161
|
+
for (; offset < context.args.length; offset++) {
|
|
162
|
+
signal.throwIfAborted();
|
|
163
|
+
const operand = context.args[offset];
|
|
164
|
+
const raw = context.argumentValues[offset];
|
|
165
|
+
const processId = waitProcessId(operand);
|
|
166
|
+
returnedProcessId = undefined;
|
|
167
|
+
if (processId === undefined) {
|
|
168
|
+
await context.diagnostic(concatShellValues(["wait: `", raw, "': not a pid or valid job spec"]));
|
|
169
|
+
if (operand.length && operand[0] >= "0" && operand[0] <= "9")
|
|
170
|
+
return { result: 1, processId: undefined };
|
|
171
|
+
result = 1;
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
const handle = children.get(processId);
|
|
175
|
+
if (!handle) {
|
|
176
|
+
await context.diagnostic(`wait: pid ${processId} is not a child of this shell`);
|
|
177
|
+
result = 127;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
const waited = await jobs.wait([{ handle }], { signal });
|
|
181
|
+
result = status(waited.outcome);
|
|
182
|
+
returnedProcessId = processId;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return { result, processId: returnedProcessId };
|
|
186
|
+
};
|
|
187
|
+
const waited = context.waitInterruptibly
|
|
188
|
+
? await context.waitInterruptibly(waitOperands)
|
|
189
|
+
: { kind: "completed", value: await waitOperands(context.signal) };
|
|
190
|
+
if (waited.kind === "interrupted")
|
|
191
|
+
return waited.status;
|
|
192
|
+
return await publish(waited.value.result, waited.value.processId);
|
|
193
|
+
};
|
|
194
|
+
let result = 0;
|
|
195
|
+
try {
|
|
196
|
+
result = await execute();
|
|
197
|
+
}
|
|
198
|
+
catch (reason) {
|
|
199
|
+
primary = { reason };
|
|
200
|
+
failure ??= primary;
|
|
201
|
+
}
|
|
202
|
+
try {
|
|
203
|
+
await reference?.close();
|
|
204
|
+
}
|
|
205
|
+
catch (reason) {
|
|
206
|
+
primary ??= { reason };
|
|
207
|
+
failure ??= primary;
|
|
208
|
+
}
|
|
209
|
+
if (primary)
|
|
210
|
+
throw primary.reason;
|
|
211
|
+
return result;
|
|
212
|
+
};
|
|
213
|
+
return {
|
|
214
|
+
builtins: [{ name: "wait", execute: wait }],
|
|
215
|
+
start(context) {
|
|
216
|
+
const registerExecutionCleanup = context.registerExecutionCleanup;
|
|
217
|
+
if (typeof registerExecutionCleanup !== "function")
|
|
218
|
+
throw new TypeError("Jobs require execution-scoped cleanup ownership");
|
|
219
|
+
let ownerSignal = context.signal;
|
|
220
|
+
let retired;
|
|
221
|
+
const retirement = new Promise(resolve => { retired = resolve; });
|
|
222
|
+
let completion;
|
|
223
|
+
const finish = () => {
|
|
224
|
+
retired();
|
|
225
|
+
if (!completion) {
|
|
226
|
+
completion = Promise.resolve().then(async () => {
|
|
227
|
+
if (jobs) {
|
|
228
|
+
try {
|
|
229
|
+
if (ownerSignal.aborted)
|
|
230
|
+
await jobs.close(ownerSignal.reason);
|
|
231
|
+
else
|
|
232
|
+
await jobs.finish();
|
|
233
|
+
}
|
|
234
|
+
catch (reason) {
|
|
235
|
+
failure ??= { reason };
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (failure)
|
|
239
|
+
throw failure.reason;
|
|
240
|
+
});
|
|
241
|
+
void completion.catch(() => undefined);
|
|
242
|
+
}
|
|
243
|
+
return completion;
|
|
244
|
+
};
|
|
245
|
+
try {
|
|
246
|
+
const signal = registerExecutionCleanup.call(context, async () => {
|
|
247
|
+
try {
|
|
248
|
+
await retirement;
|
|
249
|
+
await finish();
|
|
250
|
+
}
|
|
251
|
+
finally {
|
|
252
|
+
ownerSignal.removeEventListener("abort", retired);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
if (!(signal instanceof AbortSignal))
|
|
256
|
+
throw new TypeError("Execution cleanup must provide its owner cancellation signal");
|
|
257
|
+
ownerSignal = signal;
|
|
258
|
+
ownerSignal.addEventListener("abort", retired, { once: true });
|
|
259
|
+
if (ownerSignal.aborted)
|
|
260
|
+
retired();
|
|
261
|
+
context.registerCleanup(() => { void finish(); });
|
|
262
|
+
jobs = createJobState({ signal: ownerSignal });
|
|
263
|
+
}
|
|
264
|
+
catch (reason) {
|
|
265
|
+
void finish();
|
|
266
|
+
throw reason;
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
fork: () => instance(latest),
|
|
270
|
+
checkpoint() { jobs.retireNotified(); },
|
|
271
|
+
listTerminators: [{ operator: "&", async execute(context) {
|
|
272
|
+
let processId;
|
|
273
|
+
const handle = await jobs.start(async (task) => {
|
|
274
|
+
const child = await context.prepareChild({ ...task, stdin: "async-default" });
|
|
275
|
+
processId = child.processId;
|
|
276
|
+
return child;
|
|
277
|
+
});
|
|
278
|
+
children.set(processId, handle);
|
|
279
|
+
latest = processId;
|
|
280
|
+
return 0;
|
|
281
|
+
} }],
|
|
282
|
+
specialParameters: [{ name: "!", lookup: () => latest === undefined ? undefined : String(latest) }],
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
export function jobsExtension() {
|
|
286
|
+
return {
|
|
287
|
+
name: "jobs", runtimeIdentity: commandRuntimeIdentity,
|
|
288
|
+
syntax: { listTerminators: [{ operator: "&" }], specialParameters: [{ name: "!" }] },
|
|
289
|
+
create: () => instance(),
|
|
290
|
+
};
|
|
291
|
+
}
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
class JobRegistry {
|
|
2
|
+
limits;
|
|
3
|
+
#records = new Map();
|
|
4
|
+
#jobs = new Map();
|
|
5
|
+
#listeners = new Set();
|
|
6
|
+
#owner;
|
|
7
|
+
#abortOwner;
|
|
8
|
+
#accepting = true;
|
|
9
|
+
#cancelling = false;
|
|
10
|
+
#finished = false;
|
|
11
|
+
#waiters = 0;
|
|
12
|
+
#terminal;
|
|
13
|
+
constructor(limits, options) {
|
|
14
|
+
this.limits = limits;
|
|
15
|
+
this.#owner = options.signal;
|
|
16
|
+
this.#abortOwner = () => { void this.close(this.#owner.reason).catch(() => { }); };
|
|
17
|
+
options.registerCleanup?.(() => this.#terminal ?? this.close());
|
|
18
|
+
if (this.#owner?.aborted)
|
|
19
|
+
this.#abortOwner();
|
|
20
|
+
else
|
|
21
|
+
this.#owner?.addEventListener("abort", this.#abortOwner, { once: true });
|
|
22
|
+
}
|
|
23
|
+
async start(prepare) {
|
|
24
|
+
this.#owner?.throwIfAborted();
|
|
25
|
+
if (!this.#accepting)
|
|
26
|
+
throw new Error("job state is closed to admission");
|
|
27
|
+
if (typeof prepare !== "function")
|
|
28
|
+
throw new TypeError("job preparation must be a function");
|
|
29
|
+
if (this.#records.size >= this.limits.maxJobs)
|
|
30
|
+
throw new Error("job limit exceeded: maxJobs");
|
|
31
|
+
const occupied = [...this.#records.values()].filter(record => record.state === "preparing" || record.listed && !this.#canRetire(record));
|
|
32
|
+
const jobId = Math.max(0, ...occupied.map(record => record.handle.jobId)) + 1;
|
|
33
|
+
if (!Number.isSafeInteger(jobId))
|
|
34
|
+
throw new Error("job ID exhausted");
|
|
35
|
+
let complete;
|
|
36
|
+
const completion = new Promise(resolve => { complete = resolve; });
|
|
37
|
+
const handle = Object.freeze({ jobId, completion });
|
|
38
|
+
const record = {
|
|
39
|
+
handle, complete, controller: new AbortController(), cleanups: [], cleanupFailures: [],
|
|
40
|
+
listed: false, notified: false, saved: false, state: "preparing",
|
|
41
|
+
};
|
|
42
|
+
this.#records.set(handle, record);
|
|
43
|
+
this.#notify();
|
|
44
|
+
const context = Object.freeze({
|
|
45
|
+
signal: record.controller.signal,
|
|
46
|
+
registerCleanup: (cleanup) => {
|
|
47
|
+
if (record.cleaning || record.controller.signal.aborted || record.state === "done")
|
|
48
|
+
throw new Error("job cleanup admission is closed");
|
|
49
|
+
if (typeof cleanup !== "function")
|
|
50
|
+
throw new TypeError("job cleanup must be a function");
|
|
51
|
+
if (record.cleanups.length >= this.limits.maxCleanupsPerJob)
|
|
52
|
+
throw new Error("job limit exceeded: maxCleanupsPerJob");
|
|
53
|
+
record.cleanups.push(cleanup);
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
let run;
|
|
57
|
+
let failure;
|
|
58
|
+
try {
|
|
59
|
+
const prepared = await prepare(context);
|
|
60
|
+
if (!record.controller.signal.aborted) {
|
|
61
|
+
const runner = prepared?.run;
|
|
62
|
+
if (typeof runner !== "function")
|
|
63
|
+
throw new TypeError("job preparation must return a runner");
|
|
64
|
+
run = () => Reflect.apply(runner, prepared, []);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (reason) {
|
|
68
|
+
failure = { reason };
|
|
69
|
+
}
|
|
70
|
+
if (failure || record.controller.signal.aborted) {
|
|
71
|
+
await this.#settle(record, failure);
|
|
72
|
+
this.#forget(record);
|
|
73
|
+
throw record.outcome.reason;
|
|
74
|
+
}
|
|
75
|
+
this.retireNotified();
|
|
76
|
+
record.listed = true;
|
|
77
|
+
this.#jobs.set(jobId, record);
|
|
78
|
+
this.#notify();
|
|
79
|
+
queueMicrotask(() => { void this.#execute(record, run); });
|
|
80
|
+
return handle;
|
|
81
|
+
}
|
|
82
|
+
async #execute(record, run) {
|
|
83
|
+
let result = 0;
|
|
84
|
+
let failure;
|
|
85
|
+
if (!record.controller.signal.aborted) {
|
|
86
|
+
record.state = "running";
|
|
87
|
+
this.#notify();
|
|
88
|
+
try {
|
|
89
|
+
result = await run();
|
|
90
|
+
if (!Number.isInteger(result) || result < 0 || result > 255)
|
|
91
|
+
throw new TypeError("job exit status must be an integer from 0 to 255");
|
|
92
|
+
}
|
|
93
|
+
catch (reason) {
|
|
94
|
+
failure = { reason };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
await this.#settle(record, failure, result);
|
|
98
|
+
}
|
|
99
|
+
#clean(record) {
|
|
100
|
+
if (!record.cleaning) {
|
|
101
|
+
record.cleaning = Promise.resolve().then(async () => {
|
|
102
|
+
const results = await Promise.allSettled(record.cleanups.map(async (cleanup) => cleanup()));
|
|
103
|
+
for (const result of results)
|
|
104
|
+
if (result.status === "rejected")
|
|
105
|
+
record.cleanupFailures.push(result.reason);
|
|
106
|
+
record.cleanups.length = 0;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return record.cleaning;
|
|
110
|
+
}
|
|
111
|
+
async #settle(record, failure, result = 0) {
|
|
112
|
+
await this.#clean(record);
|
|
113
|
+
let outcome;
|
|
114
|
+
if (this.#owner?.aborted)
|
|
115
|
+
outcome = { kind: "failure", reason: this.#owner.reason };
|
|
116
|
+
else if (failure)
|
|
117
|
+
outcome = { kind: "failure", reason: failure.reason };
|
|
118
|
+
else if (record.controller.signal.aborted)
|
|
119
|
+
outcome = { kind: "failure", reason: record.controller.signal.reason };
|
|
120
|
+
else if (record.cleanupFailures.length)
|
|
121
|
+
outcome = { kind: "failure", reason: record.cleanupFailures[0] };
|
|
122
|
+
else
|
|
123
|
+
outcome = { kind: "status", status: result };
|
|
124
|
+
record.outcome = Object.freeze(outcome);
|
|
125
|
+
record.state = "done";
|
|
126
|
+
record.complete(record.outcome);
|
|
127
|
+
this.#notify();
|
|
128
|
+
}
|
|
129
|
+
#unlist(record) {
|
|
130
|
+
record.listed = false;
|
|
131
|
+
if (this.#jobs.get(record.handle.jobId) === record)
|
|
132
|
+
this.#jobs.delete(record.handle.jobId);
|
|
133
|
+
}
|
|
134
|
+
#forget(record) {
|
|
135
|
+
this.#unlist(record);
|
|
136
|
+
this.#records.delete(record.handle);
|
|
137
|
+
this.#notify();
|
|
138
|
+
}
|
|
139
|
+
#notify() {
|
|
140
|
+
for (const listener of [...this.#listeners])
|
|
141
|
+
listener();
|
|
142
|
+
}
|
|
143
|
+
snapshot() {
|
|
144
|
+
return Object.freeze([...this.#records.values()].map(record => Object.freeze({
|
|
145
|
+
handle: record.handle, listed: record.listed, notified: record.notified, state: record.state,
|
|
146
|
+
residency: record.saved ? "saved" : record.notified ? "active-notified" : "active-unnotified",
|
|
147
|
+
...(record.outcome === undefined ? {} : { outcome: record.outcome }),
|
|
148
|
+
})));
|
|
149
|
+
}
|
|
150
|
+
#canRetire(record) {
|
|
151
|
+
return !record.saved && record.state === "done" && record.notified && record.outcome?.kind === "status";
|
|
152
|
+
}
|
|
153
|
+
retireNotified() {
|
|
154
|
+
let changed = false;
|
|
155
|
+
for (const record of this.#records.values()) {
|
|
156
|
+
if (this.#canRetire(record)) {
|
|
157
|
+
record.saved = true;
|
|
158
|
+
this.#unlist(record);
|
|
159
|
+
changed = true;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (changed)
|
|
163
|
+
this.#notify();
|
|
164
|
+
}
|
|
165
|
+
savedStatus(handle) {
|
|
166
|
+
const record = this.#records.get(handle);
|
|
167
|
+
return record?.saved && record.outcome?.kind === "status" ? record.outcome.status : undefined;
|
|
168
|
+
}
|
|
169
|
+
#targets(targets) {
|
|
170
|
+
if (targets === undefined)
|
|
171
|
+
return undefined;
|
|
172
|
+
if (!Array.isArray(targets))
|
|
173
|
+
throw new TypeError("job targets must be an array");
|
|
174
|
+
if (targets.length === 0)
|
|
175
|
+
return undefined;
|
|
176
|
+
if (targets.length > this.limits.maxJobs)
|
|
177
|
+
throw new Error("job target limit exceeded");
|
|
178
|
+
const selected = [];
|
|
179
|
+
for (let index = 0; index < targets.length; index++) {
|
|
180
|
+
const target = targets[index];
|
|
181
|
+
if (!target || typeof target !== "object" || Reflect.ownKeys(target).length !== 1)
|
|
182
|
+
throw new TypeError("invalid job target");
|
|
183
|
+
if ("jobId" in target && Number.isSafeInteger(target.jobId) && target.jobId > 0)
|
|
184
|
+
selected.push(Object.freeze({ jobId: target.jobId }));
|
|
185
|
+
else if ("handle" in target && target.handle && typeof target.handle === "object")
|
|
186
|
+
selected.push(Object.freeze({ handle: target.handle }));
|
|
187
|
+
else
|
|
188
|
+
throw new TypeError("invalid job target");
|
|
189
|
+
}
|
|
190
|
+
return selected;
|
|
191
|
+
}
|
|
192
|
+
#lookup(target) {
|
|
193
|
+
return "handle" in target ? this.#records.get(target.handle) : this.#jobs.get(target.jobId);
|
|
194
|
+
}
|
|
195
|
+
#waitSignal(options) {
|
|
196
|
+
if (!options || typeof options !== "object" || Reflect.ownKeys(options).some(key => key !== "signal"))
|
|
197
|
+
throw new TypeError("invalid job wait options");
|
|
198
|
+
if (options.signal !== undefined && !(options.signal instanceof AbortSignal))
|
|
199
|
+
throw new TypeError("invalid job wait signal");
|
|
200
|
+
options.signal?.throwIfAborted();
|
|
201
|
+
return options.signal;
|
|
202
|
+
}
|
|
203
|
+
#changed(signal) {
|
|
204
|
+
return new Promise((resolve, reject) => {
|
|
205
|
+
const cleanup = () => { this.#listeners.delete(changed); signal?.removeEventListener("abort", aborted); };
|
|
206
|
+
const changed = () => { cleanup(); resolve(); };
|
|
207
|
+
const aborted = () => { cleanup(); reject(signal.reason); };
|
|
208
|
+
this.#listeners.add(changed);
|
|
209
|
+
if (signal?.aborted)
|
|
210
|
+
aborted();
|
|
211
|
+
else
|
|
212
|
+
signal?.addEventListener("abort", aborted, { once: true });
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
async wait(targets, options = {}) {
|
|
216
|
+
const selected = this.#targets(targets);
|
|
217
|
+
const signal = this.#waitSignal(options);
|
|
218
|
+
if (this.#waiters >= this.limits.maxWaiters)
|
|
219
|
+
throw new Error("job limit exceeded: maxWaiters");
|
|
220
|
+
this.#waiters++;
|
|
221
|
+
const unknown = [];
|
|
222
|
+
let outcome = Object.freeze({ kind: "status", status: 0 });
|
|
223
|
+
let failure;
|
|
224
|
+
try {
|
|
225
|
+
if (selected === undefined) {
|
|
226
|
+
const records = [...this.#records.values()];
|
|
227
|
+
for (const record of records) {
|
|
228
|
+
while (record.state !== "done") {
|
|
229
|
+
signal?.throwIfAborted();
|
|
230
|
+
await this.#changed(signal);
|
|
231
|
+
}
|
|
232
|
+
if (record.outcome.kind === "failure")
|
|
233
|
+
failure ??= record.outcome;
|
|
234
|
+
}
|
|
235
|
+
signal?.throwIfAborted();
|
|
236
|
+
for (const record of records)
|
|
237
|
+
this.#forget(record);
|
|
238
|
+
}
|
|
239
|
+
else
|
|
240
|
+
for (const target of selected) {
|
|
241
|
+
signal?.throwIfAborted();
|
|
242
|
+
const record = this.#lookup(target);
|
|
243
|
+
if (!record) {
|
|
244
|
+
unknown.push(target);
|
|
245
|
+
outcome = Object.freeze({ kind: "status", status: 127 });
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
while (record.state !== "done") {
|
|
249
|
+
signal?.throwIfAborted();
|
|
250
|
+
await this.#changed(signal);
|
|
251
|
+
}
|
|
252
|
+
signal?.throwIfAborted();
|
|
253
|
+
if (!record.saved)
|
|
254
|
+
this.retireNotified();
|
|
255
|
+
record.notified = true;
|
|
256
|
+
if ("handle" in target)
|
|
257
|
+
this.#unlist(record);
|
|
258
|
+
outcome = record.outcome;
|
|
259
|
+
if (outcome.kind === "failure")
|
|
260
|
+
failure ??= outcome;
|
|
261
|
+
this.#notify();
|
|
262
|
+
}
|
|
263
|
+
return Object.freeze({ outcome: failure ?? outcome, unknown: Object.freeze(unknown) });
|
|
264
|
+
}
|
|
265
|
+
finally {
|
|
266
|
+
this.#waiters--;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
async waitNext(targets, options = {}) {
|
|
270
|
+
const selected = this.#targets(targets);
|
|
271
|
+
const signal = this.#waitSignal(options);
|
|
272
|
+
if (this.#waiters >= this.limits.maxWaiters)
|
|
273
|
+
throw new Error("job limit exceeded: maxWaiters");
|
|
274
|
+
this.#waiters++;
|
|
275
|
+
const unknown = [];
|
|
276
|
+
const records = new Set();
|
|
277
|
+
if (selected === undefined) {
|
|
278
|
+
for (const record of this.#records.values())
|
|
279
|
+
if (!record.saved)
|
|
280
|
+
records.add(record);
|
|
281
|
+
}
|
|
282
|
+
else
|
|
283
|
+
for (const target of selected) {
|
|
284
|
+
const record = this.#lookup(target);
|
|
285
|
+
if (!record || record.saved)
|
|
286
|
+
unknown.push(target);
|
|
287
|
+
else
|
|
288
|
+
records.add(record);
|
|
289
|
+
}
|
|
290
|
+
try {
|
|
291
|
+
for (;;) {
|
|
292
|
+
signal?.throwIfAborted();
|
|
293
|
+
const eligible = [...records].filter(record => !record.saved && !record.notified).sort((first, second) => first.handle.jobId - second.handle.jobId);
|
|
294
|
+
const ready = eligible.find(record => record.state === "done");
|
|
295
|
+
if (ready) {
|
|
296
|
+
ready.notified = true;
|
|
297
|
+
ready.saved = ready.outcome.kind === "status";
|
|
298
|
+
this.#unlist(ready);
|
|
299
|
+
this.#notify();
|
|
300
|
+
return Object.freeze({ outcome: ready.outcome, handle: ready.handle, unknown: Object.freeze(unknown) });
|
|
301
|
+
}
|
|
302
|
+
if (!eligible.length)
|
|
303
|
+
return Object.freeze({ outcome: Object.freeze({ kind: "status", status: 127 }), unknown: Object.freeze(unknown) });
|
|
304
|
+
await this.#changed(signal);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
finally {
|
|
308
|
+
this.#waiters--;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
finish() {
|
|
312
|
+
this.#accepting = false;
|
|
313
|
+
return this.#drain();
|
|
314
|
+
}
|
|
315
|
+
close(reason = new Error("job state closed")) {
|
|
316
|
+
this.#accepting = false;
|
|
317
|
+
if (!this.#finished && !this.#cancelling) {
|
|
318
|
+
this.#cancelling = true;
|
|
319
|
+
for (const record of this.#records.values())
|
|
320
|
+
if (record.state !== "done") {
|
|
321
|
+
record.controller.abort(reason);
|
|
322
|
+
void this.#clean(record);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return this.#drain();
|
|
326
|
+
}
|
|
327
|
+
#drain() {
|
|
328
|
+
if (!this.#terminal) {
|
|
329
|
+
const records = [...this.#records.values()];
|
|
330
|
+
this.#terminal = (async () => {
|
|
331
|
+
try {
|
|
332
|
+
await Promise.all(records.map(record => record.handle.completion));
|
|
333
|
+
if (!this.#cancelling) {
|
|
334
|
+
const failure = records.find(record => record.outcome?.kind === "failure");
|
|
335
|
+
if (failure?.outcome?.kind === "failure")
|
|
336
|
+
throw failure.outcome.reason;
|
|
337
|
+
}
|
|
338
|
+
const errors = records.flatMap(record => record.cleanupFailures);
|
|
339
|
+
if (errors.length)
|
|
340
|
+
throw new AggregateError(errors, "job cleanup failed");
|
|
341
|
+
}
|
|
342
|
+
finally {
|
|
343
|
+
this.#finished = true;
|
|
344
|
+
this.#owner?.removeEventListener("abort", this.#abortOwner);
|
|
345
|
+
}
|
|
346
|
+
})();
|
|
347
|
+
void this.#terminal.catch(() => { });
|
|
348
|
+
}
|
|
349
|
+
return this.#terminal;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
export function createJobState(options = {}) {
|
|
353
|
+
if (!options || typeof options !== "object" || Array.isArray(options))
|
|
354
|
+
throw new TypeError("invalid job options");
|
|
355
|
+
const limits = { maxJobs: 256, maxWaiters: 64, maxCleanupsPerJob: 64 };
|
|
356
|
+
for (const key of Reflect.ownKeys(options)) {
|
|
357
|
+
if (key === "signal" || key === "registerCleanup")
|
|
358
|
+
continue;
|
|
359
|
+
if (typeof key !== "string" || !Object.hasOwn(limits, key))
|
|
360
|
+
throw new TypeError("unknown job option");
|
|
361
|
+
const name = key;
|
|
362
|
+
const value = options[name];
|
|
363
|
+
if (value === undefined)
|
|
364
|
+
continue;
|
|
365
|
+
if (!Number.isSafeInteger(value) || value < 1 || value > limits[name])
|
|
366
|
+
throw new TypeError(`invalid job limit: ${key}`);
|
|
367
|
+
limits[name] = value;
|
|
368
|
+
}
|
|
369
|
+
if (options.signal !== undefined && !(options.signal instanceof AbortSignal))
|
|
370
|
+
throw new TypeError("invalid job owner signal");
|
|
371
|
+
if (options.registerCleanup !== undefined && typeof options.registerCleanup !== "function")
|
|
372
|
+
throw new TypeError("invalid job owner cleanup registration");
|
|
373
|
+
return new JobRegistry(Object.freeze(limits), options);
|
|
374
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type ShellValue } from "@poe-platform/safe-bash/contracts/value";
|
|
2
|
+
import type { ShellExtension } from "@poe-platform/safe-bash/optional-host";
|
|
3
|
+
export interface MapfileOptions {
|
|
4
|
+
array: string;
|
|
5
|
+
clear: boolean;
|
|
6
|
+
count: number;
|
|
7
|
+
delimiter: number;
|
|
8
|
+
descriptor: number;
|
|
9
|
+
origin: number;
|
|
10
|
+
quantum: number;
|
|
11
|
+
skip: number;
|
|
12
|
+
trim: boolean;
|
|
13
|
+
callback?: ShellValue;
|
|
14
|
+
}
|
|
15
|
+
export declare class MapfileArgumentError extends Error {
|
|
16
|
+
readonly detail: ShellValue;
|
|
17
|
+
readonly status: number;
|
|
18
|
+
readonly usage: boolean;
|
|
19
|
+
constructor(detail: ShellValue, status: number, usage?: boolean);
|
|
20
|
+
}
|
|
21
|
+
export declare function parseMapfileArguments(args: readonly ShellValue[], selectDescriptor: (descriptor: number) => Promise<void>): Promise<MapfileOptions | "help">;
|
|
22
|
+
export declare function mapfileExtension(options?: {
|
|
23
|
+
readonly replace?: boolean;
|
|
24
|
+
}): ShellExtension;
|