poe-code 14.0.21 → 14.0.23
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/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/metafile.json +1 -1
- package/package.json +1 -1
- package/packages/safe-bash/dist/browser.d.ts +5 -0
- package/packages/safe-bash/dist/browser.d.ts.map +1 -1
- package/packages/safe-bash/dist/browser.js +981 -134
- package/packages/safe-bash/dist/browser.js.map +4 -4
- package/packages/safe-bash/dist/commands/apply-patch/shared.js +2 -2
- package/packages/safe-bash/dist/commands/apply-patch/shared.js.map +1 -1
- package/packages/safe-bash/dist/commands/archive/internal.d.ts.map +1 -1
- package/packages/safe-bash/dist/commands/archive/internal.js +3 -2
- package/packages/safe-bash/dist/commands/archive/internal.js.map +1 -1
- package/packages/safe-bash/dist/commands/bytes/checksums/index.d.ts.map +1 -1
- package/packages/safe-bash/dist/commands/bytes/checksums/index.js +3 -2
- package/packages/safe-bash/dist/commands/bytes/checksums/index.js.map +1 -1
- package/packages/safe-bash/dist/commands/bytes/compression/gunzip.js +2 -2
- package/packages/safe-bash/dist/commands/bytes/compression/gunzip.js.map +1 -1
- package/packages/safe-bash/dist/commands/bytes/compression/stream.js +2 -2
- package/packages/safe-bash/dist/commands/bytes/compression/stream.js.map +1 -1
- package/packages/safe-bash/dist/commands/bytes/encoding/shared.js +3 -3
- package/packages/safe-bash/dist/commands/bytes/encoding/shared.js.map +1 -1
- package/packages/safe-bash/dist/commands/column/internal.d.ts.map +1 -1
- package/packages/safe-bash/dist/commands/column/internal.js +2 -1
- package/packages/safe-bash/dist/commands/column/internal.js.map +1 -1
- package/packages/safe-bash/dist/commands/diff-patch/shared.js +2 -2
- package/packages/safe-bash/dist/commands/diff-patch/shared.js.map +1 -1
- package/packages/safe-bash/dist/commands/du/budget.d.ts.map +1 -1
- package/packages/safe-bash/dist/commands/du/budget.js +3 -2
- package/packages/safe-bash/dist/commands/du/budget.js.map +1 -1
- package/packages/safe-bash/dist/commands/env-split.d.ts.map +1 -1
- package/packages/safe-bash/dist/commands/env-split.js +2 -1
- package/packages/safe-bash/dist/commands/env-split.js.map +1 -1
- package/packages/safe-bash/dist/commands/expr/internal.d.ts.map +1 -1
- package/packages/safe-bash/dist/commands/expr/internal.js +2 -1
- package/packages/safe-bash/dist/commands/expr/internal.js.map +1 -1
- package/packages/safe-bash/dist/commands/file/shared.d.ts.map +1 -1
- package/packages/safe-bash/dist/commands/file/shared.js +3 -2
- package/packages/safe-bash/dist/commands/file/shared.js.map +1 -1
- package/packages/safe-bash/dist/commands/find.d.ts.map +1 -1
- package/packages/safe-bash/dist/commands/find.js +12 -31
- package/packages/safe-bash/dist/commands/find.js.map +1 -1
- package/packages/safe-bash/dist/commands/html-to-markdown/budget.js +2 -2
- package/packages/safe-bash/dist/commands/html-to-markdown/budget.js.map +1 -1
- package/packages/safe-bash/dist/commands/metadata/internal.d.ts.map +1 -1
- package/packages/safe-bash/dist/commands/metadata/internal.js +2 -1
- package/packages/safe-bash/dist/commands/metadata/internal.js.map +1 -1
- package/packages/safe-bash/dist/commands/move.d.ts.map +1 -1
- package/packages/safe-bash/dist/commands/move.js +2 -1
- package/packages/safe-bash/dist/commands/move.js.map +1 -1
- package/packages/safe-bash/dist/commands/network/authorizer.d.ts +7 -0
- package/packages/safe-bash/dist/commands/network/authorizer.d.ts.map +1 -0
- package/packages/safe-bash/dist/commands/network/authorizer.js +48 -0
- package/packages/safe-bash/dist/commands/network/authorizer.js.map +1 -0
- package/packages/safe-bash/dist/commands/network/body.js +2 -2
- package/packages/safe-bash/dist/commands/network/body.js.map +1 -1
- package/packages/safe-bash/dist/commands/network/curl.js +2 -2
- package/packages/safe-bash/dist/commands/network/curl.js.map +1 -1
- package/packages/safe-bash/dist/commands/network/fetch-transport.d.ts +6 -0
- package/packages/safe-bash/dist/commands/network/fetch-transport.d.ts.map +1 -0
- package/packages/safe-bash/dist/commands/network/fetch-transport.js +82 -0
- package/packages/safe-bash/dist/commands/network/fetch-transport.js.map +1 -0
- package/packages/safe-bash/dist/commands/network/index.d.ts +2 -0
- package/packages/safe-bash/dist/commands/network/index.d.ts.map +1 -1
- package/packages/safe-bash/dist/commands/network/index.js +2 -0
- package/packages/safe-bash/dist/commands/network/index.js.map +1 -1
- package/packages/safe-bash/dist/commands/network/types.d.ts +1 -0
- package/packages/safe-bash/dist/commands/network/types.d.ts.map +1 -1
- package/packages/safe-bash/dist/commands/network/types.js +10 -0
- package/packages/safe-bash/dist/commands/network/types.js.map +1 -1
- package/packages/safe-bash/dist/commands/regex-execution/ere/limits.js +2 -2
- package/packages/safe-bash/dist/commands/regex-execution/ere/limits.js.map +1 -1
- package/packages/safe-bash/dist/commands/safejs/io.js +2 -2
- package/packages/safe-bash/dist/commands/safejs/io.js.map +1 -1
- package/packages/safe-bash/dist/commands/search/shared.js +2 -2
- package/packages/safe-bash/dist/commands/search/shared.js.map +1 -1
- package/packages/safe-bash/dist/commands/split/io.js +2 -2
- package/packages/safe-bash/dist/commands/split/io.js.map +1 -1
- package/packages/safe-bash/dist/commands/stream-format/shared.d.ts.map +1 -1
- package/packages/safe-bash/dist/commands/stream-format/shared.js +2 -1
- package/packages/safe-bash/dist/commands/stream-format/shared.js.map +1 -1
- package/packages/safe-bash/dist/commands/stream-inspection/shared.d.ts.map +1 -1
- package/packages/safe-bash/dist/commands/stream-inspection/shared.js +2 -1
- package/packages/safe-bash/dist/commands/stream-inspection/shared.js.map +1 -1
- package/packages/safe-bash/dist/commands/streams.d.ts.map +1 -1
- package/packages/safe-bash/dist/commands/streams.js +114 -13
- package/packages/safe-bash/dist/commands/streams.js.map +1 -1
- package/packages/safe-bash/dist/commands/structured/limits.js +2 -2
- package/packages/safe-bash/dist/commands/structured/limits.js.map +1 -1
- package/packages/safe-bash/dist/commands/table-text/internal.d.ts.map +1 -1
- package/packages/safe-bash/dist/commands/table-text/internal.js +2 -1
- package/packages/safe-bash/dist/commands/table-text/internal.js.map +1 -1
- package/packages/safe-bash/dist/commands/text-programs/shared.js +2 -2
- package/packages/safe-bash/dist/commands/text-programs/shared.js.map +1 -1
- package/packages/safe-bash/dist/commands/tree/io.js +2 -2
- package/packages/safe-bash/dist/commands/tree/io.js.map +1 -1
- package/packages/safe-bash/dist/contracts/yield.d.ts +13 -0
- package/packages/safe-bash/dist/contracts/yield.d.ts.map +1 -0
- package/packages/safe-bash/dist/contracts/yield.js +41 -0
- package/packages/safe-bash/dist/contracts/yield.js.map +1 -0
- package/packages/safe-bash/dist/shell/arithmetic.js +1 -1
- package/packages/safe-bash/dist/shell/arithmetic.js.map +1 -1
- package/packages/safe-bash/dist/shell/arrays/ledger.d.ts.map +1 -1
- package/packages/safe-bash/dist/shell/arrays/ledger.js +2 -9
- package/packages/safe-bash/dist/shell/arrays/ledger.js.map +1 -1
- package/packages/safe-bash/dist/shell/conditional.d.ts.map +1 -1
- package/packages/safe-bash/dist/shell/conditional.js +2 -1
- package/packages/safe-bash/dist/shell/conditional.js.map +1 -1
- package/packages/safe-bash/dist/shell/env-warning.d.ts +2 -0
- package/packages/safe-bash/dist/shell/env-warning.d.ts.map +1 -0
- package/packages/safe-bash/dist/shell/env-warning.js +12 -0
- package/packages/safe-bash/dist/shell/env-warning.js.map +1 -0
- package/packages/safe-bash/dist/shell/index.d.ts +1 -0
- package/packages/safe-bash/dist/shell/index.d.ts.map +1 -1
- package/packages/safe-bash/dist/shell/index.js +1 -0
- package/packages/safe-bash/dist/shell/index.js.map +1 -1
- package/packages/safe-bash/dist/shell/input.d.ts.map +1 -1
- package/packages/safe-bash/dist/shell/input.js +4 -3
- package/packages/safe-bash/dist/shell/input.js.map +1 -1
- package/packages/safe-bash/dist/shell/parser.d.ts.map +1 -1
- package/packages/safe-bash/dist/shell/parser.js +15 -1
- package/packages/safe-bash/dist/shell/parser.js.map +1 -1
- package/packages/safe-bash/dist/shell/pattern.d.ts.map +1 -1
- package/packages/safe-bash/dist/shell/pattern.js +3 -2
- package/packages/safe-bash/dist/shell/pattern.js.map +1 -1
- package/packages/safe-bash/dist/shell/runtime.d.ts +3 -2
- package/packages/safe-bash/dist/shell/runtime.d.ts.map +1 -1
- package/packages/safe-bash/dist/shell/runtime.js +57 -55
- package/packages/safe-bash/dist/shell/runtime.js.map +1 -1
- package/packages/safe-bash/dist/shell/shell.d.ts.map +1 -1
- package/packages/safe-bash/dist/shell/shell.js +4 -1
- package/packages/safe-bash/dist/shell/shell.js.map +1 -1
- package/packages/safe-bash/dist/shell/types.d.ts +2 -0
- package/packages/safe-bash/dist/shell/types.d.ts.map +1 -1
- package/packages/safe-bash/dist/shell/types.js.map +1 -1
- package/packages/safe-bash/dist/shell/worker-limits.d.ts +3 -0
- package/packages/safe-bash/dist/shell/worker-limits.d.ts.map +1 -0
- package/packages/safe-bash/dist/shell/worker-limits.js +14 -0
- package/packages/safe-bash/dist/shell/worker-limits.js.map +1 -0
- package/packages/safe-fs/dist/contracts/filesystem.d.ts +1 -0
- package/packages/safe-fs/dist/core.d.ts +1 -0
- package/packages/safe-fs/dist/fs/quota/index.d.ts +9 -0
- package/packages/safe-fs/dist/index.d.ts +1 -0
- package/packages/safe-js/dist/browser/chunks/{chunk-QGN6DKT5.js → chunk-EMJUKJ6C.js} +111 -1
- package/packages/safe-js/dist/browser/chunks/chunk-EMJUKJ6C.js.map +7 -0
- package/packages/safe-js/dist/browser/safe-fs-core.js +7 -3
- package/packages/safe-js/dist/browser/safe-fs.js +7 -3
- package/packages/safe-js/dist/chunks/{chunk-7M2SJPSZ.js → chunk-AFVEPD3R.js} +2 -2
- package/packages/safe-js/dist/chunks/{chunk-5XRQ3GNN.js → chunk-WGUFH7HF.js} +3 -3
- package/packages/safe-js/dist/chunks/{chunk-2QRYPKQQ.js → chunk-WMZQYBLB.js} +111 -1
- package/packages/safe-js/dist/chunks/chunk-WMZQYBLB.js.map +7 -0
- package/packages/safe-js/dist/cli.js +3 -3
- package/packages/safe-js/dist/index.js +3 -3
- package/packages/safe-js/dist/safe-fs-core.js +7 -3
- package/packages/safe-js/dist/safe-fs-core.js.map +1 -1
- package/packages/safe-js/dist/safe-fs-node.js +8 -4
- package/packages/safe-js/dist/safe-fs.js +8 -4
- package/packages/safe-js/dist/browser/chunks/chunk-QGN6DKT5.js.map +0 -7
- package/packages/safe-js/dist/chunks/chunk-2QRYPKQQ.js.map +0 -7
- /package/packages/safe-js/dist/chunks/{chunk-7M2SJPSZ.js.map → chunk-AFVEPD3R.js.map} +0 -0
- /package/packages/safe-js/dist/chunks/{chunk-5XRQ3GNN.js.map → chunk-WGUFH7HF.js.map} +0 -0
|
@@ -1816,14 +1816,12 @@ var require_buffer = __commonJS({
|
|
|
1816
1816
|
});
|
|
1817
1817
|
|
|
1818
1818
|
// packages/safe-bash/browser/platform.mjs
|
|
1819
|
-
var import_buffer, TransformStream
|
|
1819
|
+
var import_buffer, TransformStream;
|
|
1820
1820
|
var init_platform = __esm({
|
|
1821
1821
|
"packages/safe-bash/browser/platform.mjs"() {
|
|
1822
1822
|
"use strict";
|
|
1823
1823
|
import_buffer = __toESM(require_buffer(), 1);
|
|
1824
1824
|
TransformStream = globalThis.TransformStream;
|
|
1825
|
-
setImmediate = (callback, ...args) => setTimeout(callback, 0, ...args);
|
|
1826
|
-
clearImmediate = clearTimeout;
|
|
1827
1825
|
}
|
|
1828
1826
|
});
|
|
1829
1827
|
|
|
@@ -1833,9 +1831,6 @@ init_platform();
|
|
|
1833
1831
|
// packages/safe-bash/src/commands/basic.ts
|
|
1834
1832
|
init_platform();
|
|
1835
1833
|
|
|
1836
|
-
// packages/safe-bash/src/contracts/index.ts
|
|
1837
|
-
init_platform();
|
|
1838
|
-
|
|
1839
1834
|
// packages/safe-bash/src/contracts/command.ts
|
|
1840
1835
|
init_platform();
|
|
1841
1836
|
|
|
@@ -3054,6 +3049,44 @@ async function compareObservedEntries(fs, path, stat, peer, peerPath, peerStat,
|
|
|
3054
3049
|
|
|
3055
3050
|
// packages/safe-bash/src/commands/move.ts
|
|
3056
3051
|
init_platform();
|
|
3052
|
+
|
|
3053
|
+
// packages/safe-bash/src/contracts/yield.ts
|
|
3054
|
+
init_platform();
|
|
3055
|
+
var checkpoints = /* @__PURE__ */ new WeakMap();
|
|
3056
|
+
function monotonicNow() {
|
|
3057
|
+
return globalThis.performance?.now() ?? Date.now();
|
|
3058
|
+
}
|
|
3059
|
+
function registerYieldCheckpoint(signal, checkpoint) {
|
|
3060
|
+
checkpoints.set(signal, checkpoint);
|
|
3061
|
+
}
|
|
3062
|
+
function scheduleTurn(callback) {
|
|
3063
|
+
const host = globalThis;
|
|
3064
|
+
return host.setImmediate ? { kind: "immediate", value: host.setImmediate(callback) } : { kind: "timeout", value: setTimeout(callback, 0) };
|
|
3065
|
+
}
|
|
3066
|
+
function cancelTurn(handle) {
|
|
3067
|
+
if (handle?.kind === "immediate") globalThis.clearImmediate?.(handle.value);
|
|
3068
|
+
else if (handle) clearTimeout(handle.value);
|
|
3069
|
+
}
|
|
3070
|
+
function yieldTurn(signal) {
|
|
3071
|
+
signal?.throwIfAborted();
|
|
3072
|
+
if (signal) checkpoints.get(signal)?.();
|
|
3073
|
+
return new Promise((resolve, reject) => {
|
|
3074
|
+
let handle;
|
|
3075
|
+
const finish = () => {
|
|
3076
|
+
signal?.removeEventListener("abort", abort);
|
|
3077
|
+
resolve();
|
|
3078
|
+
};
|
|
3079
|
+
const abort = () => {
|
|
3080
|
+
cancelTurn(handle);
|
|
3081
|
+
reject(signal.reason);
|
|
3082
|
+
};
|
|
3083
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
3084
|
+
if (signal?.aborted) abort();
|
|
3085
|
+
else handle = scheduleTurn(finish);
|
|
3086
|
+
});
|
|
3087
|
+
}
|
|
3088
|
+
|
|
3089
|
+
// packages/safe-bash/src/commands/move.ts
|
|
3057
3090
|
var MoveBudget = class {
|
|
3058
3091
|
constructor(signal) {
|
|
3059
3092
|
this.signal = signal;
|
|
@@ -3066,7 +3099,7 @@ var MoveBudget = class {
|
|
|
3066
3099
|
async step() {
|
|
3067
3100
|
this.signal.throwIfAborted();
|
|
3068
3101
|
if (++this.steps > 1e5) throw new FsError("EFBIG", { message: "cross-device move entry limit exceeded" });
|
|
3069
|
-
if (this.steps % 128 === 0) await
|
|
3102
|
+
if (this.steps % 128 === 0) await yieldTurn();
|
|
3070
3103
|
this.signal.throwIfAborted();
|
|
3071
3104
|
}
|
|
3072
3105
|
};
|
|
@@ -3801,7 +3834,7 @@ function headTail(name2) {
|
|
|
3801
3834
|
});
|
|
3802
3835
|
}
|
|
3803
3836
|
function characterSet(specification) {
|
|
3804
|
-
const
|
|
3837
|
+
const classes2 = {
|
|
3805
3838
|
lower: Array.from({ length: 26 }, (_, offset) => 97 + offset),
|
|
3806
3839
|
upper: Array.from({ length: 26 }, (_, offset) => 65 + offset),
|
|
3807
3840
|
digit: Array.from({ length: 10 }, (_, offset) => 48 + offset),
|
|
@@ -3811,15 +3844,15 @@ function characterSet(specification) {
|
|
|
3811
3844
|
graph: Array.from({ length: 94 }, (_, offset) => 33 + offset),
|
|
3812
3845
|
print: Array.from({ length: 95 }, (_, offset) => 32 + offset)
|
|
3813
3846
|
};
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3847
|
+
classes2.alpha = [...classes2.upper, ...classes2.lower];
|
|
3848
|
+
classes2.alnum = [...classes2.digit, ...classes2.alpha];
|
|
3849
|
+
classes2.xdigit = [...classes2.digit, ...classes2.upper.slice(0, 6), ...classes2.lower.slice(0, 6)];
|
|
3850
|
+
classes2.punct = classes2.graph.filter((byte) => !classes2.alnum.includes(byte));
|
|
3818
3851
|
const tokens2 = [];
|
|
3819
3852
|
for (let offset = 0; offset < specification.length; ) {
|
|
3820
3853
|
const classMatch = /^\[:([a-z]+):\]/u.exec(specification.slice(offset));
|
|
3821
3854
|
if (classMatch) {
|
|
3822
|
-
const bytes =
|
|
3855
|
+
const bytes = classes2[classMatch[1]];
|
|
3823
3856
|
if (!bytes) throw new UsageError(`unknown character class '${classMatch[1]}'`);
|
|
3824
3857
|
tokens2.push({ bytes, literal: false });
|
|
3825
3858
|
offset += classMatch[0].length;
|
|
@@ -3992,32 +4025,128 @@ function streamCommands() {
|
|
|
3992
4025
|
}),
|
|
3993
4026
|
define("tee", async (context) => {
|
|
3994
4027
|
const parsed = options(context.args, "a", { append: "a" });
|
|
3995
|
-
const
|
|
4028
|
+
const paths = [];
|
|
4029
|
+
const streams = [];
|
|
3996
4030
|
let exitCode = 0;
|
|
4031
|
+
let closed = false;
|
|
4032
|
+
let cleanup;
|
|
4033
|
+
const closeStreams = () => {
|
|
4034
|
+
closed = true;
|
|
4035
|
+
return cleanup ??= Promise.allSettled(streams.map(async (target) => {
|
|
4036
|
+
await target.pipe.abort(context.signal.aborted ? context.signal.reason : void 0);
|
|
4037
|
+
await target.task;
|
|
4038
|
+
})).then(() => {
|
|
4039
|
+
});
|
|
4040
|
+
};
|
|
4041
|
+
context.registerCleanup?.(closeStreams);
|
|
4042
|
+
const report = async (target, error) => {
|
|
4043
|
+
target.active = false;
|
|
4044
|
+
if (target.reported) return;
|
|
4045
|
+
target.reported = true;
|
|
4046
|
+
await diagnostic(context, error);
|
|
4047
|
+
exitCode = 1;
|
|
4048
|
+
};
|
|
4049
|
+
const fallback = async (target) => {
|
|
4050
|
+
if (context.fs.capabilities.append === false || target.accepted || !(target.failure instanceof FsError) || target.failure.code !== "ENOTSUP") return false;
|
|
4051
|
+
await context.fs.writeFile(target.path, new Uint8Array(), { flag: target.flag, signal: context.signal });
|
|
4052
|
+
target.active = false;
|
|
4053
|
+
paths.push(target.path);
|
|
4054
|
+
return true;
|
|
4055
|
+
};
|
|
4056
|
+
const recover = async (target, error) => {
|
|
4057
|
+
try {
|
|
4058
|
+
if (await fallback(target)) return;
|
|
4059
|
+
} catch (fallbackError) {
|
|
4060
|
+
context.signal.throwIfAborted();
|
|
4061
|
+
await report(target, fallbackError);
|
|
4062
|
+
return;
|
|
4063
|
+
}
|
|
4064
|
+
await report(target, error);
|
|
4065
|
+
};
|
|
4066
|
+
const streaming = context.fs.capabilities.streamingWrite !== false && typeof context.fs.writeStream === "function";
|
|
3997
4067
|
for (const operand of parsed.operands) {
|
|
3998
4068
|
try {
|
|
3999
4069
|
const path = pathOf(context, operand);
|
|
4000
|
-
|
|
4001
|
-
|
|
4070
|
+
if (closed) throw new FsError("ECANCELED", { syscall: "tee", path });
|
|
4071
|
+
const flag = parsed.flags.has("a") ? "a" : "w";
|
|
4072
|
+
if (streaming) {
|
|
4073
|
+
const pipe = createBytePipe({ signal: context.signal });
|
|
4074
|
+
const target = {
|
|
4075
|
+
path,
|
|
4076
|
+
flag,
|
|
4077
|
+
pipe,
|
|
4078
|
+
task: Promise.resolve(),
|
|
4079
|
+
failed: false,
|
|
4080
|
+
accepted: false,
|
|
4081
|
+
reported: false,
|
|
4082
|
+
active: true
|
|
4083
|
+
};
|
|
4084
|
+
const source = (async function* () {
|
|
4085
|
+
for await (const chunk of pipe.readable) {
|
|
4086
|
+
target.accepted = true;
|
|
4087
|
+
yield chunk;
|
|
4088
|
+
}
|
|
4089
|
+
})();
|
|
4090
|
+
target.task = context.fs.writeStream(path, source, { flag, signal: context.signal }).catch(async (error) => {
|
|
4091
|
+
target.failed = true;
|
|
4092
|
+
target.failure = error;
|
|
4093
|
+
await pipe.abort(error);
|
|
4094
|
+
});
|
|
4095
|
+
streams.push(target);
|
|
4096
|
+
} else {
|
|
4097
|
+
if (context.fs.capabilities.append === false) {
|
|
4098
|
+
throw new FsError(context.fs.capabilities.readOnly === true ? "EROFS" : "ENOTSUP", { syscall: "tee", path });
|
|
4099
|
+
}
|
|
4100
|
+
await context.fs.writeFile(path, new Uint8Array(), { flag, signal: context.signal });
|
|
4101
|
+
paths.push(path);
|
|
4102
|
+
}
|
|
4002
4103
|
} catch (error) {
|
|
4104
|
+
context.signal.throwIfAborted();
|
|
4003
4105
|
await diagnostic(context, error);
|
|
4004
4106
|
exitCode = 1;
|
|
4005
4107
|
}
|
|
4006
4108
|
}
|
|
4007
|
-
|
|
4008
|
-
await
|
|
4009
|
-
|
|
4109
|
+
try {
|
|
4110
|
+
for await (const chunk of input(context)) {
|
|
4111
|
+
await output(context, chunk);
|
|
4112
|
+
for (const target of streams) {
|
|
4113
|
+
if (!target.active) continue;
|
|
4114
|
+
try {
|
|
4115
|
+
await target.pipe.writable.write(chunk);
|
|
4116
|
+
} catch (error) {
|
|
4117
|
+
context.signal.throwIfAborted();
|
|
4118
|
+
await target.task;
|
|
4119
|
+
await recover(target, target.failed ? target.failure : error);
|
|
4120
|
+
}
|
|
4121
|
+
}
|
|
4122
|
+
for (let index = 0; index < paths.length; ) {
|
|
4123
|
+
try {
|
|
4124
|
+
await context.fs.appendFile(paths[index], chunk, { signal: context.signal });
|
|
4125
|
+
index++;
|
|
4126
|
+
} catch (error) {
|
|
4127
|
+
context.signal.throwIfAborted();
|
|
4128
|
+
await diagnostic(context, error);
|
|
4129
|
+
paths.splice(index, 1);
|
|
4130
|
+
exitCode = 1;
|
|
4131
|
+
}
|
|
4132
|
+
}
|
|
4133
|
+
}
|
|
4134
|
+
for (const target of streams) {
|
|
4135
|
+
if (!target.active) continue;
|
|
4010
4136
|
try {
|
|
4011
|
-
await
|
|
4012
|
-
|
|
4137
|
+
await target.pipe.close();
|
|
4138
|
+
await target.task;
|
|
4139
|
+
if (target.failed) await recover(target, target.failure);
|
|
4013
4140
|
} catch (error) {
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4141
|
+
context.signal.throwIfAborted();
|
|
4142
|
+
await target.task;
|
|
4143
|
+
await recover(target, target.failed ? target.failure : error);
|
|
4017
4144
|
}
|
|
4018
4145
|
}
|
|
4146
|
+
return { exitCode };
|
|
4147
|
+
} finally {
|
|
4148
|
+
await closeStreams();
|
|
4019
4149
|
}
|
|
4020
|
-
return { exitCode };
|
|
4021
4150
|
}),
|
|
4022
4151
|
define("tr", async (context) => {
|
|
4023
4152
|
const parsed = options(context.args, "dscC", { delete: "d", "squeeze-repeats": "s", complement: "c" });
|
|
@@ -4444,6 +4573,17 @@ init_platform();
|
|
|
4444
4573
|
// packages/safe-bash/src/shell/shell.ts
|
|
4445
4574
|
init_platform();
|
|
4446
4575
|
|
|
4576
|
+
// packages/safe-bash/src/shell/env-warning.ts
|
|
4577
|
+
init_platform();
|
|
4578
|
+
var warned = /* @__PURE__ */ new WeakSet();
|
|
4579
|
+
function warnIfHostProcessEnv(env) {
|
|
4580
|
+
if (!env || typeof process === "undefined" || !process.env) return;
|
|
4581
|
+
if (warned.has(env)) return;
|
|
4582
|
+
if (env !== process.env) return;
|
|
4583
|
+
warned.add(env);
|
|
4584
|
+
console.warn("[safe-bash] warning: the shell `env` is the host `process.env`. Scripts executed in this shell can read every value in it, including secrets; on Cloudflare Workers with nodejs_compat, process.env contains the Worker's secret bindings. Pass only the variables your scripts need. See docs/issues/safe-bash-cloudflare-security-audit.md (finding 1).");
|
|
4585
|
+
}
|
|
4586
|
+
|
|
4447
4587
|
// packages/safe-bash/src/shell/parser.ts
|
|
4448
4588
|
init_platform();
|
|
4449
4589
|
|
|
@@ -4538,7 +4678,7 @@ function integer2(text) {
|
|
|
4538
4678
|
for (const character of match[2]) {
|
|
4539
4679
|
const digit2 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@_".indexOf(base <= 36 ? character.toLowerCase() : character);
|
|
4540
4680
|
if (digit2 >= base || digit2 < 0) throw new Error("Digit exceeds arithmetic base");
|
|
4541
|
-
value2 = value2 * BigInt(base) + BigInt(digit2);
|
|
4681
|
+
value2 = BigInt.asIntN(64, value2 * BigInt(base) + BigInt(digit2));
|
|
4542
4682
|
}
|
|
4543
4683
|
return value2;
|
|
4544
4684
|
}
|
|
@@ -4864,7 +5004,7 @@ async function tokens(pattern, work) {
|
|
|
4864
5004
|
let steps = 0;
|
|
4865
5005
|
const tick = () => {
|
|
4866
5006
|
if (--work.remaining < 0) work.exhausted();
|
|
4867
|
-
if (++steps % 1024 === 0) return
|
|
5007
|
+
if (++steps % 1024 === 0) return yieldTurn(work.signal);
|
|
4868
5008
|
return void 0;
|
|
4869
5009
|
};
|
|
4870
5010
|
for (let index = 0; index < characters.length; index++) {
|
|
@@ -4941,7 +5081,7 @@ async function matchTokens(patternTokens, value2, work) {
|
|
|
4941
5081
|
while (position < characters.length) {
|
|
4942
5082
|
if (--work.remaining < 0) work.exhausted();
|
|
4943
5083
|
if (++steps % 1024 === 0) {
|
|
4944
|
-
await
|
|
5084
|
+
await yieldTurn(work.signal);
|
|
4945
5085
|
work.signal.throwIfAborted();
|
|
4946
5086
|
}
|
|
4947
5087
|
const token = patternTokens[tokenIndex];
|
|
@@ -4974,7 +5114,7 @@ async function charge(context, amount = 1) {
|
|
|
4974
5114
|
const previous = context.work.remaining;
|
|
4975
5115
|
context.work.remaining -= amount;
|
|
4976
5116
|
if (previous >>> 10 !== context.work.remaining >>> 10) {
|
|
4977
|
-
await
|
|
5117
|
+
await yieldTurn();
|
|
4978
5118
|
context.signal.throwIfAborted();
|
|
4979
5119
|
}
|
|
4980
5120
|
}
|
|
@@ -5176,6 +5316,7 @@ var Lexer = class {
|
|
|
5176
5316
|
this.documentLine = documentLine;
|
|
5177
5317
|
this.partial = partial;
|
|
5178
5318
|
if (depth > 64) throw new ShellSyntaxError("Syntax nesting exceeds 64", 0);
|
|
5319
|
+
for (let offset = source.indexOf("\n"); offset !== -1; offset = source.indexOf("\n", offset + 1)) this.newlineOffsets.push(offset);
|
|
5179
5320
|
}
|
|
5180
5321
|
source;
|
|
5181
5322
|
depth;
|
|
@@ -5191,8 +5332,16 @@ var Lexer = class {
|
|
|
5191
5332
|
conditional = false;
|
|
5192
5333
|
conditionalPattern;
|
|
5193
5334
|
documents = [];
|
|
5335
|
+
newlineOffsets = [];
|
|
5194
5336
|
lineAt(position) {
|
|
5195
|
-
|
|
5337
|
+
let low = 0;
|
|
5338
|
+
let high = this.newlineOffsets.length;
|
|
5339
|
+
while (low < high) {
|
|
5340
|
+
const middle = low + Math.floor((high - low) / 2);
|
|
5341
|
+
if (this.newlineOffsets[middle] < position) low = middle + 1;
|
|
5342
|
+
else high = middle;
|
|
5343
|
+
}
|
|
5344
|
+
return this.lineOffset + low + 1;
|
|
5196
5345
|
}
|
|
5197
5346
|
error(message2, unclosedQuote) {
|
|
5198
5347
|
throw new ShellSyntaxError(message2, this.position, 2, void 0, unclosedQuote);
|
|
@@ -6614,7 +6763,7 @@ var SplitWork = class {
|
|
|
6614
6763
|
return this.work >= this.nextYield;
|
|
6615
6764
|
}
|
|
6616
6765
|
async pause() {
|
|
6617
|
-
await
|
|
6766
|
+
await yieldTurn();
|
|
6618
6767
|
this.signal.throwIfAborted();
|
|
6619
6768
|
this.nextYield = this.work + 4096;
|
|
6620
6769
|
}
|
|
@@ -7884,14 +8033,7 @@ var ArrayLedger = class _ArrayLedger {
|
|
|
7884
8033
|
this.#checkpoint += units;
|
|
7885
8034
|
if (this.#checkpoint >= 128) {
|
|
7886
8035
|
this.#checkpoint %= 128;
|
|
7887
|
-
return
|
|
7888
|
-
try {
|
|
7889
|
-
signal?.throwIfAborted();
|
|
7890
|
-
resolve();
|
|
7891
|
-
} catch (error) {
|
|
7892
|
-
reject(error);
|
|
7893
|
-
}
|
|
7894
|
-
}));
|
|
8036
|
+
return yieldTurn(signal);
|
|
7895
8037
|
}
|
|
7896
8038
|
}
|
|
7897
8039
|
};
|
|
@@ -8768,43 +8910,17 @@ async function publishPipelineStatus(state, statuses, signal, scope) {
|
|
|
8768
8910
|
throwCleanupFailures(scope.failures);
|
|
8769
8911
|
}
|
|
8770
8912
|
|
|
8771
|
-
// packages/safe-bash/
|
|
8772
|
-
init_platform();
|
|
8773
|
-
var EreTransportRoot = class {
|
|
8774
|
-
constructor() {
|
|
8775
|
-
throw new ConditionalUnsupported("[[ =~ ]] is not supported by the browser shell entry");
|
|
8776
|
-
}
|
|
8777
|
-
};
|
|
8778
|
-
|
|
8779
|
-
// packages/safe-bash/src/commands/regex-execution/ere/transport/protocol.ts
|
|
8913
|
+
// packages/safe-bash/src/commands/regex-execution/ere/errors.ts
|
|
8780
8914
|
init_platform();
|
|
8781
|
-
var
|
|
8782
|
-
|
|
8783
|
-
|
|
8784
|
-
constructor(resource, limit) {
|
|
8785
|
-
super(`ERE transport profile limit exceeded: ${resource} (${limit})`);
|
|
8786
|
-
this.resource = resource;
|
|
8787
|
-
this.limit = limit;
|
|
8788
|
-
this.name = "EreTransportProfileLimitError";
|
|
8789
|
-
}
|
|
8790
|
-
resource;
|
|
8791
|
-
limit;
|
|
8792
|
-
status = 3;
|
|
8793
|
-
};
|
|
8794
|
-
var EreTransportSemanticError = class extends Error {
|
|
8795
|
-
constructor(category, offset) {
|
|
8796
|
-
super(category === "syntax" ? "invalid ERE" : "unsupported ERE profile");
|
|
8797
|
-
this.category = category;
|
|
8915
|
+
var EreSyntaxError = class extends Error {
|
|
8916
|
+
constructor(message2, offset) {
|
|
8917
|
+
super(`invalid ERE at ${offset}: ${message2}`);
|
|
8798
8918
|
this.offset = offset;
|
|
8799
|
-
this.name = "
|
|
8919
|
+
this.name = "EreSyntaxError";
|
|
8800
8920
|
}
|
|
8801
|
-
category;
|
|
8802
8921
|
offset;
|
|
8803
8922
|
status = 2;
|
|
8804
8923
|
};
|
|
8805
|
-
|
|
8806
|
-
// packages/safe-bash/src/commands/regex-execution/ere/errors.ts
|
|
8807
|
-
init_platform();
|
|
8808
8924
|
var EreUnsupportedError = class extends Error {
|
|
8809
8925
|
constructor(message2, offset) {
|
|
8810
8926
|
super(`unsupported ERE profile at ${offset}: ${message2}`);
|
|
@@ -8825,6 +8941,564 @@ var EreProfileLimitError = class extends Error {
|
|
|
8825
8941
|
limit;
|
|
8826
8942
|
status = 3;
|
|
8827
8943
|
};
|
|
8944
|
+
var EreUsageUnknownError = class extends Error {
|
|
8945
|
+
status = 3;
|
|
8946
|
+
constructor(reason) {
|
|
8947
|
+
super("ERE invocation usage is unknown; further work is refused", { cause: reason });
|
|
8948
|
+
this.name = "EreUsageUnknownError";
|
|
8949
|
+
}
|
|
8950
|
+
};
|
|
8951
|
+
|
|
8952
|
+
// packages/safe-bash/src/commands/regex-execution/ere/limits.ts
|
|
8953
|
+
init_platform();
|
|
8954
|
+
var resources = Object.freeze([
|
|
8955
|
+
"patternBytes",
|
|
8956
|
+
"subjectBytes",
|
|
8957
|
+
"work",
|
|
8958
|
+
"states",
|
|
8959
|
+
"allocationUnits",
|
|
8960
|
+
"captureBytes",
|
|
8961
|
+
"captureSlots"
|
|
8962
|
+
]);
|
|
8963
|
+
function integer5(value2) {
|
|
8964
|
+
if (!Number.isSafeInteger(value2) || value2 < 0) throw new TypeError("ERE bounds must be nonnegative safe integers");
|
|
8965
|
+
}
|
|
8966
|
+
function multiply(value2, factor, ceiling) {
|
|
8967
|
+
return value2 > Math.floor(ceiling / factor) ? ceiling : value2 * factor;
|
|
8968
|
+
}
|
|
8969
|
+
function deriveEreLimits(bounds) {
|
|
8970
|
+
integer5(bounds.maxExpansionBytes);
|
|
8971
|
+
integer5(bounds.maxExpansionFields);
|
|
8972
|
+
const bytes = bounds.maxExpansionBytes;
|
|
8973
|
+
const fields = bounds.maxExpansionFields;
|
|
8974
|
+
const byteUnits = multiply(bytes, 8, 4e6);
|
|
8975
|
+
const fieldUnits = multiply(fields, 128, 4e6);
|
|
8976
|
+
return Object.freeze({
|
|
8977
|
+
patternBytes: Math.min(bytes, 65536),
|
|
8978
|
+
subjectBytes: Math.min(bytes, 1048576),
|
|
8979
|
+
work: multiply(bytes, 32, 5e7),
|
|
8980
|
+
states: multiply(fields, 8, 65536),
|
|
8981
|
+
allocationUnits: byteUnits >= 4e6 - fieldUnits ? 4e6 : byteUnits + fieldUnits,
|
|
8982
|
+
captureBytes: bytes,
|
|
8983
|
+
captureSlots: fields
|
|
8984
|
+
});
|
|
8985
|
+
}
|
|
8986
|
+
var EreLedger = class {
|
|
8987
|
+
limits;
|
|
8988
|
+
#usage = {
|
|
8989
|
+
patternBytes: 0,
|
|
8990
|
+
subjectBytes: 0,
|
|
8991
|
+
work: 0,
|
|
8992
|
+
states: 0,
|
|
8993
|
+
allocationUnits: 0,
|
|
8994
|
+
captureBytes: 0,
|
|
8995
|
+
captureSlots: 0
|
|
8996
|
+
};
|
|
8997
|
+
#poison;
|
|
8998
|
+
#lastYield = 0;
|
|
8999
|
+
constructor(bounds, lowering = {}) {
|
|
9000
|
+
const limits = { ...deriveEreLimits(bounds) };
|
|
9001
|
+
for (const resource of Object.keys(lowering)) {
|
|
9002
|
+
if (!resources.includes(resource)) throw new TypeError("unknown ERE limit");
|
|
9003
|
+
const key = resource;
|
|
9004
|
+
const value2 = lowering[key];
|
|
9005
|
+
if (value2 === void 0) throw new TypeError("undefined ERE limit");
|
|
9006
|
+
integer5(value2);
|
|
9007
|
+
if (value2 > limits[key]) throw new RangeError("ERE limits may only be lowered");
|
|
9008
|
+
limits[key] = value2;
|
|
9009
|
+
}
|
|
9010
|
+
this.limits = Object.freeze(limits);
|
|
9011
|
+
}
|
|
9012
|
+
get usage() {
|
|
9013
|
+
return Object.freeze({ ...this.#usage });
|
|
9014
|
+
}
|
|
9015
|
+
check(signal) {
|
|
9016
|
+
if (signal?.aborted) throw signal.reason;
|
|
9017
|
+
if (this.#poison) throw this.#poison;
|
|
9018
|
+
}
|
|
9019
|
+
charge(resource, amount, signal) {
|
|
9020
|
+
this.check(signal);
|
|
9021
|
+
integer5(amount);
|
|
9022
|
+
if (amount > this.limits[resource] - this.#usage[resource]) {
|
|
9023
|
+
throw new EreProfileLimitError(resource, this.limits[resource]);
|
|
9024
|
+
}
|
|
9025
|
+
this.#usage[resource] += amount;
|
|
9026
|
+
}
|
|
9027
|
+
admitInput(resource, length, signal) {
|
|
9028
|
+
this.check(signal);
|
|
9029
|
+
integer5(length);
|
|
9030
|
+
if (length > this.limits[resource]) throw new EreProfileLimitError(resource, this.limits[resource]);
|
|
9031
|
+
this.#usage[resource] = Math.max(this.#usage[resource], length);
|
|
9032
|
+
}
|
|
9033
|
+
async checkpoint(signal) {
|
|
9034
|
+
this.check(signal);
|
|
9035
|
+
if (this.#usage.work - this.#lastYield >= 256) {
|
|
9036
|
+
this.#lastYield = this.#usage.work;
|
|
9037
|
+
await yieldTurn(signal);
|
|
9038
|
+
this.check(signal);
|
|
9039
|
+
}
|
|
9040
|
+
}
|
|
9041
|
+
markUnknownUsage(reason) {
|
|
9042
|
+
this.#poison ??= new EreUsageUnknownError(reason);
|
|
9043
|
+
}
|
|
9044
|
+
};
|
|
9045
|
+
|
|
9046
|
+
// packages/safe-bash/src/commands/regex-execution/ere/syntax.ts
|
|
9047
|
+
init_platform();
|
|
9048
|
+
var programs = /* @__PURE__ */ new WeakMap();
|
|
9049
|
+
var special = "\\.^$[]()|*+?{}";
|
|
9050
|
+
var classes = /* @__PURE__ */ new Set(["alnum", "alpha", "blank", "cntrl", "digit", "graph", "lower", "print", "punct", "space", "upper", "xdigit"]);
|
|
9051
|
+
function classMember(name2, code) {
|
|
9052
|
+
const upper = code >= 65 && code <= 90;
|
|
9053
|
+
const lower = code >= 97 && code <= 122;
|
|
9054
|
+
const digit2 = code >= 48 && code <= 57;
|
|
9055
|
+
switch (name2) {
|
|
9056
|
+
case "alnum":
|
|
9057
|
+
return upper || lower || digit2;
|
|
9058
|
+
case "alpha":
|
|
9059
|
+
return upper || lower;
|
|
9060
|
+
case "blank":
|
|
9061
|
+
return code === 9 || code === 32;
|
|
9062
|
+
case "cntrl":
|
|
9063
|
+
return code < 32 || code === 127;
|
|
9064
|
+
case "digit":
|
|
9065
|
+
return digit2;
|
|
9066
|
+
case "graph":
|
|
9067
|
+
return code >= 33 && code <= 126;
|
|
9068
|
+
case "lower":
|
|
9069
|
+
return lower;
|
|
9070
|
+
case "print":
|
|
9071
|
+
return code >= 32 && code <= 126;
|
|
9072
|
+
case "punct":
|
|
9073
|
+
return code >= 33 && code <= 126 && !upper && !lower && !digit2;
|
|
9074
|
+
case "space":
|
|
9075
|
+
return code === 32 || code >= 9 && code <= 13;
|
|
9076
|
+
case "upper":
|
|
9077
|
+
return upper;
|
|
9078
|
+
case "xdigit":
|
|
9079
|
+
return digit2 || code >= 65 && code <= 70 || code >= 97 && code <= 102;
|
|
9080
|
+
default:
|
|
9081
|
+
return false;
|
|
9082
|
+
}
|
|
9083
|
+
}
|
|
9084
|
+
async function admitAscii(text, ledger, signal) {
|
|
9085
|
+
for (let offset = 0; offset < text.length; offset++) {
|
|
9086
|
+
ledger.charge("work", 1, signal);
|
|
9087
|
+
const code = text.charCodeAt(offset);
|
|
9088
|
+
if (code === 0 || code > 127) throw new EreUnsupportedError("only non-NUL ASCII in the C/POSIX profile", offset);
|
|
9089
|
+
await ledger.checkpoint(signal);
|
|
9090
|
+
}
|
|
9091
|
+
}
|
|
9092
|
+
async function flatten(input2, ledger, signal) {
|
|
9093
|
+
if (typeof input2 === "string") {
|
|
9094
|
+
ledger.admitInput("patternBytes", input2.length, signal);
|
|
9095
|
+
await admitAscii(input2, ledger, signal);
|
|
9096
|
+
return { pattern: input2, quoted: null };
|
|
9097
|
+
}
|
|
9098
|
+
let size = 0;
|
|
9099
|
+
for (const fragment of input2) {
|
|
9100
|
+
if (typeof fragment.text !== "string" || typeof fragment.literal !== "boolean") throw new TypeError("invalid ERE fragment");
|
|
9101
|
+
ledger.charge("work", 1, signal);
|
|
9102
|
+
await ledger.checkpoint(signal);
|
|
9103
|
+
ledger.admitInput("patternBytes", fragment.text.length, signal);
|
|
9104
|
+
await admitAscii(fragment.text, ledger, signal);
|
|
9105
|
+
if (fragment.text.length > ledger.limits.patternBytes - size) ledger.admitInput("patternBytes", ledger.limits.patternBytes + 1, signal);
|
|
9106
|
+
size += fragment.text.length;
|
|
9107
|
+
ledger.admitInput("patternBytes", size, signal);
|
|
9108
|
+
}
|
|
9109
|
+
ledger.charge("allocationUnits", size * 2 + input2.length + 2, signal);
|
|
9110
|
+
const output2 = [];
|
|
9111
|
+
const quoted = [];
|
|
9112
|
+
for (const fragment of input2) {
|
|
9113
|
+
for (let offset = 0; offset < fragment.text.length; offset++) {
|
|
9114
|
+
ledger.charge("work", 1, signal);
|
|
9115
|
+
await ledger.checkpoint(signal);
|
|
9116
|
+
quoted.push(fragment.literal);
|
|
9117
|
+
}
|
|
9118
|
+
output2.push(fragment.text);
|
|
9119
|
+
await ledger.checkpoint(signal);
|
|
9120
|
+
}
|
|
9121
|
+
return { pattern: output2.join(""), quoted: Object.freeze(quoted) };
|
|
9122
|
+
}
|
|
9123
|
+
var Parser2 = class {
|
|
9124
|
+
constructor(pattern, quoted, ledger, signal) {
|
|
9125
|
+
this.pattern = pattern;
|
|
9126
|
+
this.quoted = quoted;
|
|
9127
|
+
this.ledger = ledger;
|
|
9128
|
+
this.signal = signal;
|
|
9129
|
+
}
|
|
9130
|
+
pattern;
|
|
9131
|
+
quoted;
|
|
9132
|
+
ledger;
|
|
9133
|
+
signal;
|
|
9134
|
+
offset = 0;
|
|
9135
|
+
groups = 0;
|
|
9136
|
+
nodes = 0;
|
|
9137
|
+
at(character, offset = this.offset) {
|
|
9138
|
+
return !this.quoted?.[offset] && this.pattern[offset] === character;
|
|
9139
|
+
}
|
|
9140
|
+
node(create) {
|
|
9141
|
+
if (this.nodes >= 4096) throw new EreUnsupportedError("4096-node grammar ceiling", this.offset);
|
|
9142
|
+
this.ledger.charge("allocationUnits", 8, this.signal);
|
|
9143
|
+
this.nodes++;
|
|
9144
|
+
return Object.freeze(create());
|
|
9145
|
+
}
|
|
9146
|
+
async expression(depth) {
|
|
9147
|
+
if (depth > 64) throw new EreUnsupportedError("64-level grammar ceiling", this.offset);
|
|
9148
|
+
this.ledger.charge("allocationUnits", 1, this.signal);
|
|
9149
|
+
const alternatives = [];
|
|
9150
|
+
while (true) {
|
|
9151
|
+
const child = await this.sequence(depth);
|
|
9152
|
+
this.ledger.charge("allocationUnits", 1, this.signal);
|
|
9153
|
+
alternatives.push(child);
|
|
9154
|
+
if (!this.at("|")) break;
|
|
9155
|
+
this.offset++;
|
|
9156
|
+
}
|
|
9157
|
+
if (alternatives.length === 1) return alternatives[0];
|
|
9158
|
+
this.ledger.charge("work", alternatives.length * 2, this.signal);
|
|
9159
|
+
await this.ledger.checkpoint(this.signal);
|
|
9160
|
+
return this.node(() => ({ kind: "alternative", children: Object.freeze(alternatives), nullable: alternatives.some((value2) => value2.nullable), captured: alternatives.some((value2) => value2.captured) }));
|
|
9161
|
+
}
|
|
9162
|
+
async sequence(depth) {
|
|
9163
|
+
this.ledger.charge("allocationUnits", 1, this.signal);
|
|
9164
|
+
const children = [];
|
|
9165
|
+
while (this.offset < this.pattern.length && !this.at("|") && !this.at(")")) {
|
|
9166
|
+
this.ledger.charge("work", 1, this.signal);
|
|
9167
|
+
await this.ledger.checkpoint(this.signal);
|
|
9168
|
+
let child = await this.atom(depth);
|
|
9169
|
+
const operator = this.quoted?.[this.offset] ? void 0 : this.pattern[this.offset];
|
|
9170
|
+
if (operator === "*" || operator === "+" || operator === "?" || operator === "{") {
|
|
9171
|
+
const begin = this.offset++;
|
|
9172
|
+
let min = operator === "+" ? 1 : 0;
|
|
9173
|
+
let max = operator === "?" ? 1 : Infinity;
|
|
9174
|
+
if (operator === "{") {
|
|
9175
|
+
min = await this.count();
|
|
9176
|
+
max = min;
|
|
9177
|
+
if (this.at(",")) {
|
|
9178
|
+
this.offset++;
|
|
9179
|
+
max = this.at("}") ? Infinity : await this.count();
|
|
9180
|
+
}
|
|
9181
|
+
if (!this.at("}") || max < min) throw new EreSyntaxError("invalid interval", begin);
|
|
9182
|
+
this.offset++;
|
|
9183
|
+
}
|
|
9184
|
+
if (child.kind === "start" || child.kind === "end") throw new EreUnsupportedError("repeated anchor", begin);
|
|
9185
|
+
if (child.nullable && child.captured && max > 1) throw new EreUnsupportedError("nullable captured repetition", begin);
|
|
9186
|
+
const repeated = child;
|
|
9187
|
+
child = this.node(() => ({ kind: "repeat", child: repeated, min, max, nullable: min === 0 || repeated.nullable, captured: repeated.captured }));
|
|
9188
|
+
const next = this.quoted?.[this.offset] ? void 0 : this.pattern[this.offset];
|
|
9189
|
+
if (next === "*" || next === "+" || next === "?" || next === "{") throw new EreUnsupportedError("stacked repetition", this.offset);
|
|
9190
|
+
}
|
|
9191
|
+
this.ledger.charge("allocationUnits", 1, this.signal);
|
|
9192
|
+
children.push(child);
|
|
9193
|
+
}
|
|
9194
|
+
if (children.length === 0) return this.node(() => ({ kind: "empty", nullable: true, captured: false }));
|
|
9195
|
+
if (children.length === 1) return children[0];
|
|
9196
|
+
this.ledger.charge("work", children.length * 2, this.signal);
|
|
9197
|
+
await this.ledger.checkpoint(this.signal);
|
|
9198
|
+
return this.node(() => ({ kind: "sequence", children: Object.freeze(children), nullable: children.every((value2) => value2.nullable), captured: children.some((value2) => value2.captured) }));
|
|
9199
|
+
}
|
|
9200
|
+
async count() {
|
|
9201
|
+
const begin = this.offset;
|
|
9202
|
+
let value2 = 0;
|
|
9203
|
+
while (!this.quoted?.[this.offset] && this.pattern[this.offset] !== void 0 && this.pattern[this.offset] >= "0" && this.pattern[this.offset] <= "9") {
|
|
9204
|
+
this.ledger.charge("work", 1, this.signal);
|
|
9205
|
+
await this.ledger.checkpoint(this.signal);
|
|
9206
|
+
value2 = value2 * 10 + this.pattern.charCodeAt(this.offset++) - 48;
|
|
9207
|
+
if (value2 > 255) throw new EreUnsupportedError("interval counts exceed 255", begin);
|
|
9208
|
+
}
|
|
9209
|
+
if (begin === this.offset) throw new EreSyntaxError("missing interval count", begin);
|
|
9210
|
+
return value2;
|
|
9211
|
+
}
|
|
9212
|
+
async atom(depth) {
|
|
9213
|
+
const begin = this.offset;
|
|
9214
|
+
const character = this.pattern[this.offset++];
|
|
9215
|
+
if (this.quoted?.[begin]) return this.node(() => ({ kind: "literal", code: character.charCodeAt(0), nullable: false, captured: false }));
|
|
9216
|
+
if (character === "(") {
|
|
9217
|
+
if (this.at("?")) throw new EreUnsupportedError("extended group syntax", begin);
|
|
9218
|
+
if (this.groups >= 32) throw new EreUnsupportedError("32-group grammar ceiling", begin);
|
|
9219
|
+
const index = ++this.groups;
|
|
9220
|
+
const child = await this.expression(depth + 1);
|
|
9221
|
+
if (!this.at(")")) throw new EreSyntaxError("unclosed group", begin);
|
|
9222
|
+
this.offset++;
|
|
9223
|
+
return this.node(() => ({ kind: "group", index, child, nullable: child.nullable, captured: true }));
|
|
9224
|
+
}
|
|
9225
|
+
if (character === "[") return this.set(begin);
|
|
9226
|
+
if (character === "\\") {
|
|
9227
|
+
const escaped = this.pattern[this.offset++];
|
|
9228
|
+
if (escaped === void 0) throw new EreSyntaxError("trailing escape", begin);
|
|
9229
|
+
if (!special.includes(escaped)) throw new EreUnsupportedError("backreference or escape extension", begin);
|
|
9230
|
+
return this.node(() => ({ kind: "literal", code: escaped.charCodeAt(0), nullable: false, captured: false }));
|
|
9231
|
+
}
|
|
9232
|
+
if (character === "*" || character === "+" || character === "?" || character === "{") throw new EreSyntaxError("repetition without operand", begin);
|
|
9233
|
+
if (character === ".") return this.node(() => ({ kind: "dot", nullable: false, captured: false }));
|
|
9234
|
+
if (character === "^") return this.node(() => ({ kind: "start", nullable: true, captured: false }));
|
|
9235
|
+
if (character === "$") return this.node(() => ({ kind: "end", nullable: true, captured: false }));
|
|
9236
|
+
return this.node(() => ({ kind: "literal", code: character.charCodeAt(0), nullable: false, captured: false }));
|
|
9237
|
+
}
|
|
9238
|
+
async set(begin) {
|
|
9239
|
+
this.ledger.charge("allocationUnits", 128, this.signal);
|
|
9240
|
+
const members = new Array(128).fill(false);
|
|
9241
|
+
const negate = this.at("^");
|
|
9242
|
+
if (negate) this.offset++;
|
|
9243
|
+
let first = true;
|
|
9244
|
+
while (this.offset < this.pattern.length) {
|
|
9245
|
+
this.ledger.charge("work", 1, this.signal);
|
|
9246
|
+
await this.ledger.checkpoint(this.signal);
|
|
9247
|
+
if (this.at("]") && !first) {
|
|
9248
|
+
this.offset++;
|
|
9249
|
+
if (negate) for (let code = 1; code < 128; code++) {
|
|
9250
|
+
this.ledger.charge("work", 1, this.signal);
|
|
9251
|
+
await this.ledger.checkpoint(this.signal);
|
|
9252
|
+
members[code] = !members[code];
|
|
9253
|
+
}
|
|
9254
|
+
return this.node(() => ({ kind: "set", members: Object.freeze(members), nullable: false, captured: false }));
|
|
9255
|
+
}
|
|
9256
|
+
first = false;
|
|
9257
|
+
if (this.at("[") && (this.at(".", this.offset + 1) || this.at("=", this.offset + 1))) {
|
|
9258
|
+
throw new EreUnsupportedError("collating or equivalence element", this.offset);
|
|
9259
|
+
}
|
|
9260
|
+
if (this.at("[") && this.at(":", this.offset + 1)) {
|
|
9261
|
+
const classBegin = this.offset;
|
|
9262
|
+
this.offset += 2;
|
|
9263
|
+
let name2 = "";
|
|
9264
|
+
while (this.offset < this.pattern.length && !this.at(":")) {
|
|
9265
|
+
this.ledger.charge("work", 1, this.signal);
|
|
9266
|
+
await this.ledger.checkpoint(this.signal);
|
|
9267
|
+
if (name2.length >= 6) throw new EreSyntaxError("unknown character class", classBegin);
|
|
9268
|
+
name2 += this.pattern[this.offset++];
|
|
9269
|
+
}
|
|
9270
|
+
if (!this.at(":") || !this.at("]", this.offset + 1) || !classes.has(name2)) throw new EreSyntaxError("unknown character class", classBegin);
|
|
9271
|
+
this.offset += 2;
|
|
9272
|
+
for (let code = 1; code < 128; code++) {
|
|
9273
|
+
this.ledger.charge("work", 1, this.signal);
|
|
9274
|
+
await this.ledger.checkpoint(this.signal);
|
|
9275
|
+
if (classMember(name2, code)) members[code] = true;
|
|
9276
|
+
}
|
|
9277
|
+
if (this.at("-") && !this.at("]", this.offset + 1)) throw new EreSyntaxError("class cannot be a range endpoint", this.offset);
|
|
9278
|
+
} else {
|
|
9279
|
+
const lower = this.pattern.charCodeAt(this.offset++);
|
|
9280
|
+
if (this.at("-") && !this.at("]", this.offset + 1) && this.pattern[this.offset + 1] !== void 0) {
|
|
9281
|
+
this.offset++;
|
|
9282
|
+
if (this.at("[")) throw new EreSyntaxError("nonliteral range endpoint", this.offset);
|
|
9283
|
+
const upper = this.pattern.charCodeAt(this.offset++);
|
|
9284
|
+
if (lower > upper) throw new EreSyntaxError("descending range", this.offset - 3);
|
|
9285
|
+
for (let code = lower; code <= upper; code++) {
|
|
9286
|
+
this.ledger.charge("work", 1, this.signal);
|
|
9287
|
+
await this.ledger.checkpoint(this.signal);
|
|
9288
|
+
members[code] = true;
|
|
9289
|
+
}
|
|
9290
|
+
} else members[lower] = true;
|
|
9291
|
+
}
|
|
9292
|
+
}
|
|
9293
|
+
throw new EreSyntaxError("unclosed bracket expression", begin);
|
|
9294
|
+
}
|
|
9295
|
+
};
|
|
9296
|
+
async function compileEre(input2, ledger, signal) {
|
|
9297
|
+
ledger.check(signal);
|
|
9298
|
+
const { pattern, quoted } = await flatten(input2, ledger, signal);
|
|
9299
|
+
const parser = new Parser2(pattern, quoted, ledger, signal);
|
|
9300
|
+
const root = await parser.expression(0);
|
|
9301
|
+
if (parser.offset !== pattern.length) throw new EreSyntaxError("unmatched closing group", parser.offset);
|
|
9302
|
+
ledger.charge("allocationUnits", 3, signal);
|
|
9303
|
+
const program = Object.freeze({ pattern, groups: parser.groups });
|
|
9304
|
+
programs.set(program, { root, ledger });
|
|
9305
|
+
return program;
|
|
9306
|
+
}
|
|
9307
|
+
function resolveEreProgram(program, ledger) {
|
|
9308
|
+
const entry = programs.get(program);
|
|
9309
|
+
if (!entry || entry.ledger !== ledger) throw new TypeError("ERE program is not bound to this invocation ledger");
|
|
9310
|
+
return entry.root;
|
|
9311
|
+
}
|
|
9312
|
+
|
|
9313
|
+
// packages/safe-bash/src/commands/regex-execution/ere/matcher.ts
|
|
9314
|
+
init_platform();
|
|
9315
|
+
function spanOrder(left, right) {
|
|
9316
|
+
if (left === null) return right === null ? 0 : -1;
|
|
9317
|
+
if (right === null) return 1;
|
|
9318
|
+
const length = left.end - left.start - (right.end - right.start);
|
|
9319
|
+
return length === 0 ? right.start - left.start : length;
|
|
9320
|
+
}
|
|
9321
|
+
async function historyOrder(left, right, ledger, signal) {
|
|
9322
|
+
const leftCount = left?.count ?? 0;
|
|
9323
|
+
const rightCount = right?.count ?? 0;
|
|
9324
|
+
for (let ordinal = 1; ordinal <= Math.min(leftCount, rightCount); ordinal++) {
|
|
9325
|
+
ledger.charge("work", 1, signal);
|
|
9326
|
+
await ledger.checkpoint(signal);
|
|
9327
|
+
let leftEntry = left;
|
|
9328
|
+
let rightEntry = right;
|
|
9329
|
+
for (let remaining = leftCount; remaining > ordinal; remaining--) {
|
|
9330
|
+
ledger.charge("work", 1, signal);
|
|
9331
|
+
await ledger.checkpoint(signal);
|
|
9332
|
+
leftEntry = leftEntry.previous;
|
|
9333
|
+
}
|
|
9334
|
+
for (let remaining = rightCount; remaining > ordinal; remaining--) {
|
|
9335
|
+
ledger.charge("work", 1, signal);
|
|
9336
|
+
await ledger.checkpoint(signal);
|
|
9337
|
+
rightEntry = rightEntry.previous;
|
|
9338
|
+
}
|
|
9339
|
+
const compared = spanOrder(leftEntry.span, rightEntry.span);
|
|
9340
|
+
if (compared !== 0) return compared;
|
|
9341
|
+
}
|
|
9342
|
+
return leftCount - rightCount;
|
|
9343
|
+
}
|
|
9344
|
+
async function preferred(candidate, incumbent, ledger, signal) {
|
|
9345
|
+
if (candidate.position !== incumbent.position) return candidate.position > incumbent.position;
|
|
9346
|
+
for (let group = 1; group < candidate.captures.length; group++) {
|
|
9347
|
+
ledger.charge("work", 1, signal);
|
|
9348
|
+
const compared = await historyOrder(candidate.histories[group], incumbent.histories[group], ledger, signal);
|
|
9349
|
+
if (compared !== 0) return compared > 0;
|
|
9350
|
+
}
|
|
9351
|
+
return false;
|
|
9352
|
+
}
|
|
9353
|
+
async function resetDescendants(node, previous, ledger, signal) {
|
|
9354
|
+
ledger.charge("allocationUnits", previous.length + 3, signal);
|
|
9355
|
+
const captures = previous.slice();
|
|
9356
|
+
const pending = [node];
|
|
9357
|
+
while (pending.length > 0) {
|
|
9358
|
+
ledger.charge("work", 1, signal);
|
|
9359
|
+
await ledger.checkpoint(signal);
|
|
9360
|
+
const current = pending.pop();
|
|
9361
|
+
if (current.kind === "group") captures[current.index] = null;
|
|
9362
|
+
if (current.kind === "group" || current.kind === "repeat") {
|
|
9363
|
+
if (current.child.captured) {
|
|
9364
|
+
ledger.charge("allocationUnits", 1, signal);
|
|
9365
|
+
pending.push(current.child);
|
|
9366
|
+
}
|
|
9367
|
+
} else if (current.kind === "sequence" || current.kind === "alternative") {
|
|
9368
|
+
for (const child of current.children) {
|
|
9369
|
+
ledger.charge("work", 1, signal);
|
|
9370
|
+
await ledger.checkpoint(signal);
|
|
9371
|
+
if (child.captured) {
|
|
9372
|
+
ledger.charge("allocationUnits", 1, signal);
|
|
9373
|
+
pending.push(child);
|
|
9374
|
+
}
|
|
9375
|
+
}
|
|
9376
|
+
}
|
|
9377
|
+
}
|
|
9378
|
+
return captures;
|
|
9379
|
+
}
|
|
9380
|
+
async function matchEre(program, subject, ledger, signal) {
|
|
9381
|
+
ledger.check(signal);
|
|
9382
|
+
const root = resolveEreProgram(program, ledger);
|
|
9383
|
+
ledger.admitInput("subjectBytes", subject.length, signal);
|
|
9384
|
+
await admitAscii(subject, ledger, signal);
|
|
9385
|
+
const width = program.groups + 1;
|
|
9386
|
+
ledger.charge("allocationUnits", width * 2 + 1, signal);
|
|
9387
|
+
const emptyCaptures = Object.freeze(new Array(width).fill(null));
|
|
9388
|
+
const emptyHistories = Object.freeze(new Array(width).fill(null));
|
|
9389
|
+
const pending = [];
|
|
9390
|
+
const task = (create) => {
|
|
9391
|
+
ledger.charge("allocationUnits", 5, signal);
|
|
9392
|
+
return create();
|
|
9393
|
+
};
|
|
9394
|
+
const push = (position, next, captures, histories) => {
|
|
9395
|
+
ledger.charge("states", 1, signal);
|
|
9396
|
+
ledger.charge("allocationUnits", 5, signal);
|
|
9397
|
+
pending.push({ position, task: next, captures, histories });
|
|
9398
|
+
};
|
|
9399
|
+
for (let start = 0; start <= subject.length; start++) {
|
|
9400
|
+
push(start, task(() => ({ kind: "node", node: root, next: null })), emptyCaptures, emptyHistories);
|
|
9401
|
+
let best;
|
|
9402
|
+
while (pending.length > 0) {
|
|
9403
|
+
ledger.charge("work", 1, signal);
|
|
9404
|
+
await ledger.checkpoint(signal);
|
|
9405
|
+
const state = pending.pop();
|
|
9406
|
+
const current = state.task;
|
|
9407
|
+
if (current === null) {
|
|
9408
|
+
if (!best || await preferred(state, best, ledger, signal)) best = state;
|
|
9409
|
+
continue;
|
|
9410
|
+
}
|
|
9411
|
+
if (current.kind === "close") {
|
|
9412
|
+
ledger.charge("allocationUnits", width * 2 + 6, signal);
|
|
9413
|
+
const span = Object.freeze({ start: current.start, end: state.position });
|
|
9414
|
+
const captures = state.captures.slice();
|
|
9415
|
+
captures[current.group] = span;
|
|
9416
|
+
const histories = state.histories.slice();
|
|
9417
|
+
const previous = histories[current.group];
|
|
9418
|
+
histories[current.group] = { span, previous, count: (previous?.count ?? 0) + 1 };
|
|
9419
|
+
push(state.position, current.next, captures, histories);
|
|
9420
|
+
continue;
|
|
9421
|
+
}
|
|
9422
|
+
if (current.kind === "repeat") {
|
|
9423
|
+
const { node: node2, count } = current;
|
|
9424
|
+
if (count >= node2.min) push(state.position, current.next, state.captures, state.histories);
|
|
9425
|
+
const noProgress = count > 0 && state.position === current.previous;
|
|
9426
|
+
if (count < node2.max && (!noProgress || count < node2.min)) {
|
|
9427
|
+
const repeat = task(() => ({ kind: "repeat", node: node2, count: count + 1, previous: state.position, next: current.next }));
|
|
9428
|
+
push(state.position, task(() => ({ kind: "node", node: node2.child, next: repeat })), state.captures, state.histories);
|
|
9429
|
+
}
|
|
9430
|
+
continue;
|
|
9431
|
+
}
|
|
9432
|
+
const node = current.node;
|
|
9433
|
+
switch (node.kind) {
|
|
9434
|
+
case "empty":
|
|
9435
|
+
push(state.position, current.next, state.captures, state.histories);
|
|
9436
|
+
break;
|
|
9437
|
+
case "start":
|
|
9438
|
+
if (state.position === 0) push(state.position, current.next, state.captures, state.histories);
|
|
9439
|
+
break;
|
|
9440
|
+
case "end":
|
|
9441
|
+
if (state.position === subject.length) push(state.position, current.next, state.captures, state.histories);
|
|
9442
|
+
break;
|
|
9443
|
+
case "dot":
|
|
9444
|
+
case "literal":
|
|
9445
|
+
case "set": {
|
|
9446
|
+
const code = subject.charCodeAt(state.position);
|
|
9447
|
+
if (state.position < subject.length && (node.kind === "dot" || node.kind === "literal" && node.code === code || node.kind === "set" && node.members[code])) {
|
|
9448
|
+
push(state.position + 1, current.next, state.captures, state.histories);
|
|
9449
|
+
}
|
|
9450
|
+
break;
|
|
9451
|
+
}
|
|
9452
|
+
case "sequence": {
|
|
9453
|
+
let next = current.next;
|
|
9454
|
+
for (let index = node.children.length - 1; index >= 0; index--) {
|
|
9455
|
+
ledger.charge("work", 1, signal);
|
|
9456
|
+
await ledger.checkpoint(signal);
|
|
9457
|
+
const following = next;
|
|
9458
|
+
next = task(() => ({ kind: "node", node: node.children[index], next: following }));
|
|
9459
|
+
}
|
|
9460
|
+
push(state.position, next, state.captures, state.histories);
|
|
9461
|
+
break;
|
|
9462
|
+
}
|
|
9463
|
+
case "alternative":
|
|
9464
|
+
for (let index = node.children.length - 1; index >= 0; index--) {
|
|
9465
|
+
ledger.charge("work", 1, signal);
|
|
9466
|
+
await ledger.checkpoint(signal);
|
|
9467
|
+
push(state.position, task(() => ({ kind: "node", node: node.children[index], next: current.next })), state.captures, state.histories);
|
|
9468
|
+
}
|
|
9469
|
+
break;
|
|
9470
|
+
case "group": {
|
|
9471
|
+
const captures = node.child.captured ? await resetDescendants(node.child, state.captures, ledger, signal) : state.captures;
|
|
9472
|
+
const close = task(() => ({ kind: "close", group: node.index, start: state.position, next: current.next }));
|
|
9473
|
+
push(state.position, task(() => ({ kind: "node", node: node.child, next: close })), captures, state.histories);
|
|
9474
|
+
break;
|
|
9475
|
+
}
|
|
9476
|
+
case "repeat":
|
|
9477
|
+
push(state.position, task(() => ({ kind: "repeat", node, count: 0, previous: -1, next: current.next })), state.captures, state.histories);
|
|
9478
|
+
break;
|
|
9479
|
+
}
|
|
9480
|
+
}
|
|
9481
|
+
if (best) {
|
|
9482
|
+
ledger.charge("captureSlots", width, signal);
|
|
9483
|
+
let bytes = best.position - start;
|
|
9484
|
+
for (let group = 1; group < width; group++) {
|
|
9485
|
+
ledger.charge("work", 1, signal);
|
|
9486
|
+
const span = best.captures[group];
|
|
9487
|
+
if (span) bytes += span.end - span.start;
|
|
9488
|
+
}
|
|
9489
|
+
ledger.charge("captureBytes", bytes, signal);
|
|
9490
|
+
ledger.charge("allocationUnits", width * 2 + bytes + 4, signal);
|
|
9491
|
+
const captures = best.captures.slice();
|
|
9492
|
+
captures[0] = Object.freeze({ start, end: best.position });
|
|
9493
|
+
const values = captures.map((span) => span === null ? "" : subject.slice(span.start, span.end));
|
|
9494
|
+
ledger.check(signal);
|
|
9495
|
+
return Object.freeze({ matched: true, captures: Object.freeze(captures), values: Object.freeze(values) });
|
|
9496
|
+
}
|
|
9497
|
+
}
|
|
9498
|
+
ledger.charge("allocationUnits", 3, signal);
|
|
9499
|
+
ledger.check(signal);
|
|
9500
|
+
return Object.freeze({ matched: false, captures: Object.freeze([]), values: Object.freeze([]) });
|
|
9501
|
+
}
|
|
8828
9502
|
|
|
8829
9503
|
// packages/safe-bash/src/shell/runtime.ts
|
|
8830
9504
|
var defaultLimits = {
|
|
@@ -8836,6 +9510,8 @@ var defaultLimits = {
|
|
|
8836
9510
|
maxSourceBytes: 1024 * 1024,
|
|
8837
9511
|
maxExpansionFields: 1e4,
|
|
8838
9512
|
maxExpansionBytes: 16 * 1024 * 1024,
|
|
9513
|
+
maxWallClockMs: 3e4,
|
|
9514
|
+
maxCpuMs: 3e4,
|
|
8839
9515
|
pipeHighWaterMark: 64 * 1024
|
|
8840
9516
|
};
|
|
8841
9517
|
var shellBuiltinNames = /* @__PURE__ */ new Set([
|
|
@@ -8915,6 +9591,8 @@ var Budget = class {
|
|
|
8915
9591
|
this.limits = limits;
|
|
8916
9592
|
this.signal = signal ? AbortSignal.any([signal, this.controller.signal]) : this.controller.signal;
|
|
8917
9593
|
this.values = new ValueArena(limits.maxExpansionBytes, limits.maxExpansionFields, () => this.signal.throwIfAborted(), (limit) => this.fail(limit));
|
|
9594
|
+
this.#wallClockDeadline = Date.now() + limits.maxWallClockMs;
|
|
9595
|
+
this.#armWallClock();
|
|
8918
9596
|
}
|
|
8919
9597
|
limits;
|
|
8920
9598
|
values;
|
|
@@ -8924,12 +9602,34 @@ var Budget = class {
|
|
|
8924
9602
|
sourceBytes = 0;
|
|
8925
9603
|
controller = new AbortController();
|
|
8926
9604
|
signal;
|
|
9605
|
+
#wallClockTimer;
|
|
9606
|
+
#wallClockDeadline = 0;
|
|
9607
|
+
#cpuStarted = monotonicNow();
|
|
9608
|
+
#armWallClock() {
|
|
9609
|
+
const remaining = this.#wallClockDeadline - Date.now();
|
|
9610
|
+
if (remaining <= 0) {
|
|
9611
|
+
this.controller.abort(new ShellLimitError("maxWallClockMs"));
|
|
9612
|
+
return;
|
|
9613
|
+
}
|
|
9614
|
+
this.#wallClockTimer = setTimeout(() => this.#armWallClock(), Math.min(remaining, 2147483647));
|
|
9615
|
+
const timer = this.#wallClockTimer;
|
|
9616
|
+
timer.unref?.();
|
|
9617
|
+
}
|
|
9618
|
+
close() {
|
|
9619
|
+
if (this.#wallClockTimer !== void 0) clearTimeout(this.#wallClockTimer);
|
|
9620
|
+
this.#wallClockTimer = void 0;
|
|
9621
|
+
}
|
|
8927
9622
|
fail(limit) {
|
|
8928
9623
|
const error = new ShellLimitError(limit);
|
|
8929
9624
|
this.controller.abort(error);
|
|
8930
9625
|
throw error;
|
|
8931
9626
|
}
|
|
9627
|
+
cpuCheckpoint() {
|
|
9628
|
+
this.signal.throwIfAborted();
|
|
9629
|
+
if (monotonicNow() - this.#cpuStarted > this.limits.maxCpuMs) this.fail("maxCpuMs");
|
|
9630
|
+
}
|
|
8932
9631
|
tick() {
|
|
9632
|
+
this.cpuCheckpoint();
|
|
8933
9633
|
this.signal.throwIfAborted();
|
|
8934
9634
|
if (++this.commands > this.limits.maxCommands) this.fail("maxCommands");
|
|
8935
9635
|
}
|
|
@@ -9328,7 +10028,7 @@ var CdLookup = class {
|
|
|
9328
10028
|
amount -= step;
|
|
9329
10029
|
if (this.spent % 128 === 0) {
|
|
9330
10030
|
this.signal.throwIfAborted();
|
|
9331
|
-
await
|
|
10031
|
+
await yieldTurn(this.signal);
|
|
9332
10032
|
this.signal.throwIfAborted();
|
|
9333
10033
|
}
|
|
9334
10034
|
}
|
|
@@ -9424,7 +10124,7 @@ var DirectoryStackWork = class {
|
|
|
9424
10124
|
async flushWork() {
|
|
9425
10125
|
this.signal.throwIfAborted();
|
|
9426
10126
|
if (this.flushed === this.spent) return;
|
|
9427
|
-
await
|
|
10127
|
+
await yieldTurn(this.signal);
|
|
9428
10128
|
this.signal.throwIfAborted();
|
|
9429
10129
|
this.flushed = this.spent;
|
|
9430
10130
|
}
|
|
@@ -9745,6 +10445,7 @@ var Runtime = class _Runtime {
|
|
|
9745
10445
|
this.cancellationDepth = cancellationDepth;
|
|
9746
10446
|
this.cancellationMaxDepth = cancellationMaxDepth;
|
|
9747
10447
|
this.outcomeFrame = outcomeFrame;
|
|
10448
|
+
registerYieldCheckpoint(this.signal, () => this.budget.cpuCheckpoint());
|
|
9748
10449
|
}
|
|
9749
10450
|
fs;
|
|
9750
10451
|
commands;
|
|
@@ -9760,19 +10461,6 @@ var Runtime = class _Runtime {
|
|
|
9760
10461
|
cancellationDepth;
|
|
9761
10462
|
cancellationMaxDepth;
|
|
9762
10463
|
outcomeFrame;
|
|
9763
|
-
static #ereRoots = /* @__PURE__ */ new WeakMap();
|
|
9764
|
-
static registerEreRoot(budget, scope) {
|
|
9765
|
-
const entry = { closed: false };
|
|
9766
|
-
scope.register(async () => {
|
|
9767
|
-
entry.closed = true;
|
|
9768
|
-
try {
|
|
9769
|
-
await entry.cleanup?.();
|
|
9770
|
-
} finally {
|
|
9771
|
-
_Runtime.#ereRoots.delete(budget);
|
|
9772
|
-
}
|
|
9773
|
-
});
|
|
9774
|
-
_Runtime.#ereRoots.set(budget, entry);
|
|
9775
|
-
}
|
|
9776
10464
|
async ereDiagnostic(io, detail) {
|
|
9777
10465
|
try {
|
|
9778
10466
|
await this.diagnostic(io, detail);
|
|
@@ -9821,32 +10509,21 @@ var Runtime = class _Runtime {
|
|
|
9821
10509
|
await textToken(operation, subject, this.signal);
|
|
9822
10510
|
const name2 = "BASH_REMATCH";
|
|
9823
10511
|
const watch = await store.watch(name2, operation, this.signal);
|
|
9824
|
-
const
|
|
9825
|
-
|
|
9826
|
-
|
|
9827
|
-
scope.assertOpen();
|
|
9828
|
-
if (entry.closed) throw new Error("ERE invocation owner is closed");
|
|
9829
|
-
entry.cleanup = cleanup;
|
|
10512
|
+
const ledger = new EreLedger({
|
|
10513
|
+
maxExpansionBytes: this.budget.limits.maxExpansionBytes,
|
|
10514
|
+
maxExpansionFields: this.budget.limits.maxExpansionFields
|
|
9830
10515
|
});
|
|
9831
|
-
const session = entry.root.openSession((cleanup) => scope.register(cleanup));
|
|
9832
10516
|
let result;
|
|
9833
|
-
let sessionEscaping = false;
|
|
9834
10517
|
try {
|
|
9835
|
-
|
|
10518
|
+
const program = await compileEre(fragments, ledger, this.signal);
|
|
10519
|
+
result = await matchEre(program, subject, ledger, this.signal);
|
|
9836
10520
|
} catch (error) {
|
|
9837
|
-
sessionEscaping = true;
|
|
9838
10521
|
this.signal.throwIfAborted();
|
|
9839
|
-
if (error instanceof
|
|
10522
|
+
if (error instanceof EreSyntaxError || error instanceof EreUnsupportedError) {
|
|
9840
10523
|
await this.ereDiagnostic(io, `[[ ${error.message}`);
|
|
9841
|
-
sessionEscaping = false;
|
|
9842
10524
|
return 2;
|
|
9843
10525
|
}
|
|
9844
10526
|
throw error;
|
|
9845
|
-
} finally {
|
|
9846
|
-
await session.close().catch((error) => {
|
|
9847
|
-
if (sessionEscaping) scope.failures.push(error);
|
|
9848
|
-
else throw new NounsetDiagnosticFailure(error);
|
|
9849
|
-
});
|
|
9850
10527
|
}
|
|
9851
10528
|
const status = result.matched ? 0 : 1;
|
|
9852
10529
|
this.signal.throwIfAborted();
|
|
@@ -9861,8 +10538,8 @@ var Runtime = class _Runtime {
|
|
|
9861
10538
|
const tickets = operation.reserve({ generation: true, version: true, epoch: true, work: 8 });
|
|
9862
10539
|
const prepared = await store.prepareName(name2, operation, this.signal);
|
|
9863
10540
|
staged = IndexedBinding.create(store.owner);
|
|
9864
|
-
if (result.matched) for (let index = 0; index < result.
|
|
9865
|
-
const span = result.
|
|
10541
|
+
if (result.matched) for (let index = 0; index < result.captures.length; index++) {
|
|
10542
|
+
const span = result.captures[index];
|
|
9866
10543
|
const size = span === null ? 0 : span.end - span.start;
|
|
9867
10544
|
operation.reserve({ payload: size, metadata: 32, work: size + 2 });
|
|
9868
10545
|
const value2 = span === null ? "" : subject.slice(span.start, span.end);
|
|
@@ -10024,6 +10701,7 @@ var Runtime = class _Runtime {
|
|
|
10024
10701
|
writeVariable(state, name2, value2, origin = "assignment") {
|
|
10025
10702
|
if (arrayStore(state)?.get(name2)) throw new ArrayFailure(origin === "arithmetic" ? "indexed arithmetic is unsupported" : "indexed write requires prepared publication");
|
|
10026
10703
|
if (state.readonlyVariables?.has(name2)) throw new Error(`${name2}: readonly variable`);
|
|
10704
|
+
if (shellValueByteLength(value2) > this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
|
|
10027
10705
|
if (name2 === "OPTIND" && state.getopts?.integer && origin !== "arithmetic") {
|
|
10028
10706
|
try {
|
|
10029
10707
|
value2 = String(evaluateArithmetic(prepareArithmetic(shellValueText(value2) || "0"), this.arithmeticVariables(state)));
|
|
@@ -10533,7 +11211,7 @@ var Runtime = class _Runtime {
|
|
|
10533
11211
|
completed.add(index);
|
|
10534
11212
|
if (incoming) {
|
|
10535
11213
|
const upstream = index - 1;
|
|
10536
|
-
const close =
|
|
11214
|
+
const close = scheduleTurn(() => {
|
|
10537
11215
|
closing.delete(close);
|
|
10538
11216
|
if (written.has(upstream) && !completed.has(upstream)) controllers[upstream].abort(new PipelineClosed());
|
|
10539
11217
|
});
|
|
@@ -10560,7 +11238,7 @@ var Runtime = class _Runtime {
|
|
|
10560
11238
|
try {
|
|
10561
11239
|
statuses = await interruptible(Promise.all(tasks), this.signal);
|
|
10562
11240
|
} finally {
|
|
10563
|
-
for (const close of closing)
|
|
11241
|
+
for (const close of closing) cancelTurn(close);
|
|
10564
11242
|
for (const [index, controller] of controllers.entries()) if (!completed.has(index) || written.has(index)) controller.abort(new PipelineClosed());
|
|
10565
11243
|
await Promise.all(pipes.map((pipe) => pipe.abort()));
|
|
10566
11244
|
}
|
|
@@ -10625,7 +11303,7 @@ var Runtime = class _Runtime {
|
|
|
10625
11303
|
originalIO = { ...originalIO, diagnosticLine, substitutionDiagnosticLine: originalIO.substitutionDiagnosticLines?.get(command) ?? diagnosticLine };
|
|
10626
11304
|
if (command.kind === "subshell") originalIO = isolateIO(originalIO);
|
|
10627
11305
|
this.budget.tick();
|
|
10628
|
-
if (this.budget.commands % 128 === 0) await
|
|
11306
|
+
if (this.budget.commands % 128 === 0) await yieldTurn(this.signal);
|
|
10629
11307
|
this.signal.throwIfAborted();
|
|
10630
11308
|
const inputs = /* @__PURE__ */ new Set();
|
|
10631
11309
|
const outputs = /* @__PURE__ */ new Set();
|
|
@@ -10672,7 +11350,7 @@ var Runtime = class _Runtime {
|
|
|
10672
11350
|
diagnosticFailure = error;
|
|
10673
11351
|
throw error;
|
|
10674
11352
|
}
|
|
10675
|
-
if (error instanceof EreProfileLimitError
|
|
11353
|
+
if (error instanceof EreProfileLimitError) {
|
|
10676
11354
|
try {
|
|
10677
11355
|
await this.diagnostic(io, `[[ ${error.message}`);
|
|
10678
11356
|
} catch (reason) {
|
|
@@ -10741,7 +11419,7 @@ var Runtime = class _Runtime {
|
|
|
10741
11419
|
for (const clause of command.clauses) {
|
|
10742
11420
|
let matched = fallthrough;
|
|
10743
11421
|
if (!matched) for (const word of clause.patterns) {
|
|
10744
|
-
if (++patterns % 128 === 0) await
|
|
11422
|
+
if (++patterns % 128 === 0) await yieldTurn(this.signal);
|
|
10745
11423
|
const pattern = (await this.word(word, state, io, false, true)).join("");
|
|
10746
11424
|
if (await matchesPattern(pattern, subject, work)) {
|
|
10747
11425
|
matched = true;
|
|
@@ -10862,7 +11540,7 @@ var Runtime = class _Runtime {
|
|
|
10862
11540
|
this.signal.throwIfAborted();
|
|
10863
11541
|
for (const warning of warnings.splice(0)) await writeText(io.stderr, `shell: warning: ${warning}
|
|
10864
11542
|
`);
|
|
10865
|
-
if (++words % 128 === 0) await
|
|
11543
|
+
if (++words % 128 === 0) await yieldTurn(this.signal);
|
|
10866
11544
|
const part = (await this.word(word, state, io, false)).join("");
|
|
10867
11545
|
size += import_buffer.Buffer.byteLength(part);
|
|
10868
11546
|
if (size > this.budget.limits.maxExpansionBytes) this.budget.fail("maxExpansionBytes");
|
|
@@ -11056,7 +11734,7 @@ var Runtime = class _Runtime {
|
|
|
11056
11734
|
}
|
|
11057
11735
|
const wordValues = await this.valueWords(commandWords, state, originalIO, ["export", "local", "readonly"].includes(commandWords[declarationIndex]?.plain ?? ""));
|
|
11058
11736
|
const words = wordValues.map(shellValueText);
|
|
11059
|
-
const
|
|
11737
|
+
const special2 = state.profile === "sh" && specialBuiltinNames.has(words[0] ?? "");
|
|
11060
11738
|
const inlineInput = command.redirects.some((redirect) => redirect.document || redirect.operator === "<<<");
|
|
11061
11739
|
const functionCommand = words.length > 0 && state.functions.has(words[0]);
|
|
11062
11740
|
const isolatedInlineInput = inlineInput && words.length > 0 && !shellBuiltinNames.has(words[0]) && !functionCommand;
|
|
@@ -11084,7 +11762,7 @@ var Runtime = class _Runtime {
|
|
|
11084
11762
|
if (assignment.append) value2 = concatShellValues([stateMonitor(state)?.values.get(assignment.name, state.variables[assignment.name] ?? "") ?? state.variables[assignment.name] ?? "", value2], io[valueScope]);
|
|
11085
11763
|
if (state.readonlyVariables?.has(assignment.name)) {
|
|
11086
11764
|
await this.diagnostic(io, `${assignment.name}: readonly variable`);
|
|
11087
|
-
if (state.profile === "sh" || !words.length) throw new Flow("exit", state.profile === "sh" && (
|
|
11765
|
+
if (state.profile === "sh" || !words.length) throw new Flow("exit", state.profile === "sh" && (special2 || !words.length) ? 127 : 1);
|
|
11088
11766
|
continue;
|
|
11089
11767
|
}
|
|
11090
11768
|
if (!previous.has(assignment.name)) {
|
|
@@ -11175,7 +11853,7 @@ var Runtime = class _Runtime {
|
|
|
11175
11853
|
if (error instanceof Flow) throw error;
|
|
11176
11854
|
this.signal.throwIfAborted();
|
|
11177
11855
|
const original = error instanceof ExecutionFailure ? error.original : error;
|
|
11178
|
-
if (
|
|
11856
|
+
if (special2 && !(original instanceof ShellLimitError) && !(original instanceof ExpansionFailure) && !(original instanceof Flow) && !(original instanceof ShellSyntaxError)) {
|
|
11179
11857
|
throw new ExecutionFailure(new FatalCommandFailure(message(original), 1), error instanceof ExecutionFailure ? error.io : io, error instanceof ExecutionFailure ? error.diagnostic : void 0);
|
|
11180
11858
|
}
|
|
11181
11859
|
if (error instanceof ExecutionFailure) throw error;
|
|
@@ -11415,16 +12093,16 @@ var Runtime = class _Runtime {
|
|
|
11415
12093
|
}
|
|
11416
12094
|
if (selected?.kind === "builtin") {
|
|
11417
12095
|
if (context2.command === "command" || context2.command === "builtin" || context2.command === "type") return { exitCode: await this.discoveryBuiltin(context2, state, io, assignments2) };
|
|
11418
|
-
const
|
|
11419
|
-
if (
|
|
11420
|
-
if (context2.command === "." || context2.command === "source") return { exitCode: await this.sourceBuiltin(context2, state, { ...io, ...context2 },
|
|
11421
|
-
if (context2.command === "eval") return { exitCode: await this.evalBuiltin(context2, state, { ...io, ...context2 },
|
|
12096
|
+
const special2 = state.profile === "sh" && !bypassFunctions && specialBuiltinNames.has(context2.command);
|
|
12097
|
+
if (special2) assignments2.clear();
|
|
12098
|
+
if (context2.command === "." || context2.command === "source") return { exitCode: await this.sourceBuiltin(context2, state, { ...io, ...context2 }, special2) };
|
|
12099
|
+
if (context2.command === "eval") return { exitCode: await this.evalBuiltin(context2, state, { ...io, ...context2 }, special2) };
|
|
11422
12100
|
const builtinWork = this.builtin(context2, state, assignments2, (error, diagnostic2) => {
|
|
11423
12101
|
builtinFailure = { error, diagnostic: diagnostic2 };
|
|
11424
12102
|
}, bypassFunctions);
|
|
11425
12103
|
const builtin = arrayStore(state) ? await interruptible(builtinWork, this.signal) : await builtinWork;
|
|
11426
12104
|
if (builtin !== void 0) {
|
|
11427
|
-
if (
|
|
12105
|
+
if (special2 && builtin !== 0 && context2.command !== "shift") throw new Flow("exit", builtin);
|
|
11428
12106
|
return { exitCode: builtin };
|
|
11429
12107
|
}
|
|
11430
12108
|
}
|
|
@@ -11736,7 +12414,7 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
|
|
|
11736
12414
|
let status = 0;
|
|
11737
12415
|
let lines2 = 0;
|
|
11738
12416
|
while (true) {
|
|
11739
|
-
if (++lines2 % 32 === 0) await
|
|
12417
|
+
if (++lines2 % 32 === 0) await yieldTurn(this.signal);
|
|
11740
12418
|
this.signal.throwIfAborted();
|
|
11741
12419
|
const bytes = await input2.sourceLine();
|
|
11742
12420
|
const eof = bytes === void 0;
|
|
@@ -12056,13 +12734,13 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
|
|
|
12056
12734
|
return status2;
|
|
12057
12735
|
}
|
|
12058
12736
|
}
|
|
12059
|
-
async evalBuiltin(context, state, io,
|
|
12737
|
+
async evalBuiltin(context, state, io, special2) {
|
|
12060
12738
|
const args = [...context.args];
|
|
12061
12739
|
if (args[0] === "--") args.shift();
|
|
12062
12740
|
else if (args[0]?.startsWith("-") && args[0] !== "-") {
|
|
12063
12741
|
await this.diagnostic(io, `eval: -${args[0][1]}: invalid option`);
|
|
12064
12742
|
await writeText(io.stderr, "eval: usage: eval [arg ...]\n");
|
|
12065
|
-
if (
|
|
12743
|
+
if (special2) throw new Flow("exit", 2);
|
|
12066
12744
|
return 2;
|
|
12067
12745
|
}
|
|
12068
12746
|
if (!args.length) return 0;
|
|
@@ -12078,7 +12756,7 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
|
|
|
12078
12756
|
throw error;
|
|
12079
12757
|
}
|
|
12080
12758
|
try {
|
|
12081
|
-
return await this.runCurrentText(source, state, { ...io, diagnosticOffset: (io.diagnosticLine ?? 1) - 1 },
|
|
12759
|
+
return await this.runCurrentText(source, state, { ...io, diagnosticOffset: (io.diagnosticLine ?? 1) - 1 }, special2, `${io.scriptName ?? "shell"}: eval`);
|
|
12082
12760
|
} finally {
|
|
12083
12761
|
const restore = () => {
|
|
12084
12762
|
state.depth--;
|
|
@@ -12087,12 +12765,12 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
|
|
|
12087
12765
|
else restore();
|
|
12088
12766
|
}
|
|
12089
12767
|
}
|
|
12090
|
-
async sourceBuiltin(context, state, io,
|
|
12768
|
+
async sourceBuiltin(context, state, io, special2) {
|
|
12091
12769
|
const args = [...context.args];
|
|
12092
12770
|
if (args[0] === "--") args.shift();
|
|
12093
12771
|
else if (args[0]?.startsWith("-") && args[0] !== "-") {
|
|
12094
12772
|
await this.diagnostic(io, `${context.command}: ${args[0]}: unsupported option`);
|
|
12095
|
-
if (
|
|
12773
|
+
if (special2) throw new Flow("exit", 2);
|
|
12096
12774
|
return 2;
|
|
12097
12775
|
}
|
|
12098
12776
|
const filename = args.shift();
|
|
@@ -12100,7 +12778,7 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
|
|
|
12100
12778
|
await this.diagnostic(io, `${context.command}: filename argument required`);
|
|
12101
12779
|
await writeText(io.stderr, `${context.command}: usage: ${context.command} [-p path] filename [arguments]
|
|
12102
12780
|
`);
|
|
12103
|
-
if (
|
|
12781
|
+
if (special2) throw new Flow("exit", 2);
|
|
12104
12782
|
return 2;
|
|
12105
12783
|
}
|
|
12106
12784
|
if (state.depth >= this.budget.limits.maxSubstitutionDepth) this.budget.fail("maxSubstitutionDepth");
|
|
@@ -12146,7 +12824,7 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
|
|
|
12146
12824
|
if (error instanceof ShellLimitError) throw error;
|
|
12147
12825
|
if (errorCode(error) === "EFBIG") this.budget.fail("maxSourceBytes");
|
|
12148
12826
|
const diagnostic2 = error instanceof CommandFailure ? error.message : filesystemDiagnostic(error, target) ?? `${target}: ${message(error)}`;
|
|
12149
|
-
if (
|
|
12827
|
+
if (special2) throw new FatalCommandFailure(diagnostic2, 1);
|
|
12150
12828
|
throw new CommandFailure(diagnostic2, error instanceof CommandFailure ? error.status : 1);
|
|
12151
12829
|
}
|
|
12152
12830
|
const positional = state.positional;
|
|
@@ -12175,7 +12853,7 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
|
|
|
12175
12853
|
throw error;
|
|
12176
12854
|
}
|
|
12177
12855
|
try {
|
|
12178
|
-
return await this.runCurrentText(source, state, { ...io, scriptName: target, diagnosticOffset: 0, diagnosticLine: 1 },
|
|
12856
|
+
return await this.runCurrentText(source, state, { ...io, scriptName: target, diagnosticOffset: 0, diagnosticLine: 1 }, special2);
|
|
12179
12857
|
} catch (error) {
|
|
12180
12858
|
if (error instanceof Flow && error.kind === "return") return error.status;
|
|
12181
12859
|
throw error;
|
|
@@ -12317,7 +12995,7 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
|
|
|
12317
12995
|
};
|
|
12318
12996
|
const checkpoint = async () => {
|
|
12319
12997
|
this.signal.throwIfAborted();
|
|
12320
|
-
await
|
|
12998
|
+
await yieldTurn(this.signal);
|
|
12321
12999
|
this.signal.throwIfAborted();
|
|
12322
13000
|
};
|
|
12323
13001
|
const { args } = context;
|
|
@@ -12362,7 +13040,7 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
|
|
|
12362
13040
|
};
|
|
12363
13041
|
const checkpoint = async () => {
|
|
12364
13042
|
this.signal.throwIfAborted();
|
|
12365
|
-
await
|
|
13043
|
+
await yieldTurn(this.signal);
|
|
12366
13044
|
this.signal.throwIfAborted();
|
|
12367
13045
|
};
|
|
12368
13046
|
if (!Array.isArray(context.args)) throw new CommandFailure("getopts: argument array required", 2);
|
|
@@ -13395,7 +14073,7 @@ ${prefix2} line ${offset + line}: \`${source.split("\n")[line - 1] ?? ""}'
|
|
|
13395
14073
|
const match = async (start, end) => {
|
|
13396
14074
|
work.remaining -= end - start + 1;
|
|
13397
14075
|
if (work.remaining < 0) work.exhausted();
|
|
13398
|
-
if (++attempts % 256 === 0) await
|
|
14076
|
+
if (++attempts % 256 === 0) await yieldTurn(this.signal);
|
|
13399
14077
|
this.signal.throwIfAborted();
|
|
13400
14078
|
if (owner) await owner.ledger.checkpoint(this.signal, end - start + 1);
|
|
13401
14079
|
return matches(slice(start, end));
|
|
@@ -13904,7 +14582,7 @@ var ShellInput = class _ShellInput {
|
|
|
13904
14582
|
let length = 0;
|
|
13905
14583
|
let pulls = 0;
|
|
13906
14584
|
while (true) {
|
|
13907
|
-
if (++pulls % 128 === 0) await
|
|
14585
|
+
if (++pulls % 128 === 0) await yieldTurn(this.signal);
|
|
13908
14586
|
const result = await this.#cursor.take(this.signal);
|
|
13909
14587
|
if (result.done) {
|
|
13910
14588
|
if (!length) return void 0;
|
|
@@ -13946,7 +14624,7 @@ var ShellInput = class _ShellInput {
|
|
|
13946
14624
|
try {
|
|
13947
14625
|
while (!terminated) {
|
|
13948
14626
|
if (offset === chunk.length) {
|
|
13949
|
-
if (++pulls % 128 === 0) await
|
|
14627
|
+
if (++pulls % 128 === 0) await yieldTurn(this.signal);
|
|
13950
14628
|
const result = await this.#cursor.take(this.signal);
|
|
13951
14629
|
if (result.done) {
|
|
13952
14630
|
break;
|
|
@@ -13962,7 +14640,7 @@ var ShellInput = class _ShellInput {
|
|
|
13962
14640
|
}
|
|
13963
14641
|
if (++length > this.budget.limits.maxOutputBytes) this.budget.fail("maxOutputBytes");
|
|
13964
14642
|
if (length % 1024 === 0) {
|
|
13965
|
-
await
|
|
14643
|
+
await yieldTurn(this.signal);
|
|
13966
14644
|
this.signal.throwIfAborted();
|
|
13967
14645
|
}
|
|
13968
14646
|
if (byte === 0) continue;
|
|
@@ -14155,6 +14833,7 @@ var Shell = class {
|
|
|
14155
14833
|
#active = /* @__PURE__ */ new Set();
|
|
14156
14834
|
constructor(options2) {
|
|
14157
14835
|
if (!options2?.fs) throw new TypeError("Shell requires an explicit filesystem");
|
|
14836
|
+
warnIfHostProcessEnv(options2.env);
|
|
14158
14837
|
resolveLimits(options2.limits);
|
|
14159
14838
|
this.#options = { ...options2, cwd: resolvePath("/", options2.cwd ?? "/"), env: { ...options2.env }, limits: { ...options2.limits } };
|
|
14160
14839
|
this.commands = options2.commands ?? new CommandRegistry();
|
|
@@ -14217,6 +14896,7 @@ var Shell = class {
|
|
|
14217
14896
|
}
|
|
14218
14897
|
async exec(source, options2 = {}) {
|
|
14219
14898
|
if (this.#disposed) throw new Error("Shell is disposed");
|
|
14899
|
+
warnIfHostProcessEnv(options2.env);
|
|
14220
14900
|
const budget = new Budget(resolveLimits(this.#options.limits, options2.limits), options2.signal);
|
|
14221
14901
|
const scope = new InvocationScope(options2.signal);
|
|
14222
14902
|
const cancellationState = new RuntimeCancellationState();
|
|
@@ -14227,7 +14907,6 @@ var Shell = class {
|
|
|
14227
14907
|
controls: [{ role: "budget-control", signal: budget.controller.signal }]
|
|
14228
14908
|
});
|
|
14229
14909
|
try {
|
|
14230
|
-
Runtime.registerEreRoot(budget, scope);
|
|
14231
14910
|
owner.activate(boundary);
|
|
14232
14911
|
} catch (error) {
|
|
14233
14912
|
scope.failures.push(...boundary.close().failures);
|
|
@@ -14241,6 +14920,7 @@ var Shell = class {
|
|
|
14241
14920
|
try {
|
|
14242
14921
|
captured = await owner.capture(() => this.#execute(source, options2, scope, budget, boundary, cancellationState, owner));
|
|
14243
14922
|
} finally {
|
|
14923
|
+
budget.close();
|
|
14244
14924
|
await scope.close();
|
|
14245
14925
|
}
|
|
14246
14926
|
const selection = owner.finish(captured);
|
|
@@ -14413,6 +15093,22 @@ shell: -c: line ${line}: \`${source.split("\n")[line - 1] ?? ""}'
|
|
|
14413
15093
|
}
|
|
14414
15094
|
};
|
|
14415
15095
|
|
|
15096
|
+
// packages/safe-bash/src/shell/worker-limits.ts
|
|
15097
|
+
init_platform();
|
|
15098
|
+
var cloudflareWorkerLimits = Object.freeze({
|
|
15099
|
+
maxInputBytes: 4 * 1024 * 1024,
|
|
15100
|
+
maxOutputBytes: 4 * 1024 * 1024,
|
|
15101
|
+
maxCommands: 1e3,
|
|
15102
|
+
maxLoopIterations: 1e3,
|
|
15103
|
+
maxSubstitutionDepth: 16,
|
|
15104
|
+
maxSourceBytes: 256 * 1024,
|
|
15105
|
+
maxExpansionFields: 1e3,
|
|
15106
|
+
maxExpansionBytes: 4 * 1024 * 1024,
|
|
15107
|
+
maxWallClockMs: 1e4,
|
|
15108
|
+
maxCpuMs: 1e4,
|
|
15109
|
+
pipeHighWaterMark: 16 * 1024
|
|
15110
|
+
});
|
|
15111
|
+
|
|
14416
15112
|
// packages/safe-bash/src/fs/memory/index.ts
|
|
14417
15113
|
init_platform();
|
|
14418
15114
|
import { createMemoryFileSystem, MemoryFileSystem } from "poe-code/safe-fs/core";
|
|
@@ -14429,6 +15125,153 @@ import { createMountFileSystem, MountFileSystem } from "poe-code/safe-fs/core";
|
|
|
14429
15125
|
init_platform();
|
|
14430
15126
|
import { createOverlayFileSystem, OverlayFileSystem } from "poe-code/safe-fs/core";
|
|
14431
15127
|
|
|
15128
|
+
// packages/safe-bash/src/commands/network/fetch-transport.ts
|
|
15129
|
+
init_platform();
|
|
15130
|
+
|
|
15131
|
+
// packages/safe-bash/src/commands/network/types.ts
|
|
15132
|
+
init_platform();
|
|
15133
|
+
var defaultNetworkLimits = Object.freeze({
|
|
15134
|
+
maxUploadBytes: 64 * 1024 * 1024,
|
|
15135
|
+
maxDownloadBytes: 64 * 1024 * 1024,
|
|
15136
|
+
maxBufferBytes: 8 * 1024 * 1024,
|
|
15137
|
+
maxHeaderBytes: 64 * 1024,
|
|
15138
|
+
maxRedirects: 10,
|
|
15139
|
+
maxRetries: 5,
|
|
15140
|
+
maxUrls: 32,
|
|
15141
|
+
maxTimeMs: 12e4
|
|
15142
|
+
});
|
|
15143
|
+
var cloudflareWorkerNetworkLimits = Object.freeze({
|
|
15144
|
+
maxUploadBytes: 4 * 1024 * 1024,
|
|
15145
|
+
maxDownloadBytes: 4 * 1024 * 1024,
|
|
15146
|
+
maxBufferBytes: 1024 * 1024,
|
|
15147
|
+
maxHeaderBytes: 32 * 1024,
|
|
15148
|
+
maxRedirects: 2,
|
|
15149
|
+
maxRetries: 1,
|
|
15150
|
+
maxUrls: 8,
|
|
15151
|
+
maxTimeMs: 1e4
|
|
15152
|
+
});
|
|
15153
|
+
var CurlError = class extends Error {
|
|
15154
|
+
constructor(exitCode, message2) {
|
|
15155
|
+
super(message2);
|
|
15156
|
+
this.exitCode = exitCode;
|
|
15157
|
+
this.name = "CurlError";
|
|
15158
|
+
}
|
|
15159
|
+
exitCode;
|
|
15160
|
+
};
|
|
15161
|
+
|
|
15162
|
+
// packages/safe-bash/src/commands/network/fetch-transport.ts
|
|
15163
|
+
function requestBody(source, signal) {
|
|
15164
|
+
if (!source) return void 0;
|
|
15165
|
+
const iterator = source[Symbol.asyncIterator]();
|
|
15166
|
+
return new ReadableStream({
|
|
15167
|
+
async pull(controller) {
|
|
15168
|
+
try {
|
|
15169
|
+
signal.throwIfAborted();
|
|
15170
|
+
const next = await iterator.next();
|
|
15171
|
+
if (next.done) controller.close();
|
|
15172
|
+
else controller.enqueue(next.value);
|
|
15173
|
+
} catch (error) {
|
|
15174
|
+
controller.error(error);
|
|
15175
|
+
}
|
|
15176
|
+
},
|
|
15177
|
+
async cancel(reason) {
|
|
15178
|
+
await iterator.return?.(reason);
|
|
15179
|
+
}
|
|
15180
|
+
});
|
|
15181
|
+
}
|
|
15182
|
+
function createFetchTransport(options2 = {}) {
|
|
15183
|
+
const fetchRequest = options2.fetch ?? globalThis.fetch;
|
|
15184
|
+
if (typeof fetchRequest !== "function") throw new TypeError("Fetch is unavailable");
|
|
15185
|
+
return async (input2) => {
|
|
15186
|
+
input2.signal.throwIfAborted();
|
|
15187
|
+
const url = new URL(input2.url);
|
|
15188
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") throw new CurlError(1, "Unsupported protocol");
|
|
15189
|
+
const stopped = new AbortController();
|
|
15190
|
+
const signal = AbortSignal.any([input2.signal, stopped.signal]);
|
|
15191
|
+
const body = requestBody(input2.body, signal);
|
|
15192
|
+
const headers = new Headers();
|
|
15193
|
+
for (const [name2, value2] of input2.headers) headers.append(name2, value2);
|
|
15194
|
+
const request = new Request(url, {
|
|
15195
|
+
method: input2.method,
|
|
15196
|
+
headers,
|
|
15197
|
+
body,
|
|
15198
|
+
credentials: "omit",
|
|
15199
|
+
redirect: "manual",
|
|
15200
|
+
signal,
|
|
15201
|
+
...body ? { duplex: "half" } : {}
|
|
15202
|
+
});
|
|
15203
|
+
let response;
|
|
15204
|
+
const dispose = async () => {
|
|
15205
|
+
stopped.abort();
|
|
15206
|
+
if (response?.body) await response.body.cancel().catch(() => void 0);
|
|
15207
|
+
};
|
|
15208
|
+
input2.registerCleanup?.(dispose);
|
|
15209
|
+
response = await fetchRequest(request);
|
|
15210
|
+
const reader = response.body?.getReader();
|
|
15211
|
+
const responseBody = reader ? (async function* () {
|
|
15212
|
+
try {
|
|
15213
|
+
while (true) {
|
|
15214
|
+
input2.signal.throwIfAborted();
|
|
15215
|
+
const next = await reader.read();
|
|
15216
|
+
if (next.done) return;
|
|
15217
|
+
yield next.value;
|
|
15218
|
+
}
|
|
15219
|
+
} finally {
|
|
15220
|
+
reader.releaseLock();
|
|
15221
|
+
}
|
|
15222
|
+
})() : (async function* () {
|
|
15223
|
+
})();
|
|
15224
|
+
return {
|
|
15225
|
+
status: response.status,
|
|
15226
|
+
statusText: response.statusText,
|
|
15227
|
+
headers: [...response.headers.entries()],
|
|
15228
|
+
body: responseBody,
|
|
15229
|
+
dispose
|
|
15230
|
+
};
|
|
15231
|
+
};
|
|
15232
|
+
}
|
|
15233
|
+
|
|
15234
|
+
// packages/safe-bash/src/commands/network/authorizer.ts
|
|
15235
|
+
init_platform();
|
|
15236
|
+
function privateHostname(input2) {
|
|
15237
|
+
const hostname = input2.toLowerCase().replace(/\.$/u, "").replace(/^\[|\]$/gu, "");
|
|
15238
|
+
if (hostname === "localhost" || hostname.endsWith(".localhost") || hostname === "::1") return true;
|
|
15239
|
+
if (hostname.includes(":")) {
|
|
15240
|
+
const first2 = hostname.split(":", 1)[0] ?? "";
|
|
15241
|
+
return first2.startsWith("fc") || first2.startsWith("fd") || ["fe8", "fe9", "fea", "feb"].some((prefix2) => first2.startsWith(prefix2));
|
|
15242
|
+
}
|
|
15243
|
+
const parts = hostname.split(".");
|
|
15244
|
+
if (parts.length !== 4 || parts.some((part) => !part || Array.from(part).some((character) => character < "0" || character > "9"))) return false;
|
|
15245
|
+
const octets = parts.map(Number);
|
|
15246
|
+
if (octets.some((value2) => value2 < 0 || value2 > 255)) return false;
|
|
15247
|
+
const [first, second] = octets;
|
|
15248
|
+
return first === 10 || first === 127 || first === 0 || first === 169 && second === 254 || first === 192 && second === 168 || first === 172 && second >= 16 && second <= 31;
|
|
15249
|
+
}
|
|
15250
|
+
function createOriginAuthorizer(allowlist = "*", options2 = {}) {
|
|
15251
|
+
const origins = /* @__PURE__ */ new Set();
|
|
15252
|
+
const hosts = /* @__PURE__ */ new Set();
|
|
15253
|
+
for (const entry of allowlist === "*" ? [] : allowlist) {
|
|
15254
|
+
const value2 = entry.trim();
|
|
15255
|
+
if (!value2) throw new TypeError("Origin allowlist entries must not be empty");
|
|
15256
|
+
if (value2.includes("://")) {
|
|
15257
|
+
const url = new URL(value2);
|
|
15258
|
+
if (url.pathname !== "/" || url.search || url.hash || url.username || url.password) {
|
|
15259
|
+
throw new TypeError(`Origin allowlist entry must be an origin: ${entry}`);
|
|
15260
|
+
}
|
|
15261
|
+
origins.add(url.origin);
|
|
15262
|
+
} else {
|
|
15263
|
+
if (value2.includes("/") || value2.includes("@")) throw new TypeError(`Invalid hostname allowlist entry: ${entry}`);
|
|
15264
|
+
hosts.add(value2.toLowerCase().replace(/\.$/u, ""));
|
|
15265
|
+
}
|
|
15266
|
+
}
|
|
15267
|
+
return (request) => {
|
|
15268
|
+
const url = new URL(request.url);
|
|
15269
|
+
const hostname = url.hostname.toLowerCase().replace(/\.$/u, "");
|
|
15270
|
+
if (options2.denyPrivateNetworks && privateHostname(hostname)) return false;
|
|
15271
|
+
return allowlist === "*" || origins.has(url.origin) || hosts.has(hostname);
|
|
15272
|
+
};
|
|
15273
|
+
}
|
|
15274
|
+
|
|
14432
15275
|
// packages/safe-bash/src/browser.ts
|
|
14433
15276
|
function createBrowserCommands() {
|
|
14434
15277
|
return [
|
|
@@ -14467,14 +15310,18 @@ export {
|
|
|
14467
15310
|
assertPathWithin,
|
|
14468
15311
|
basename,
|
|
14469
15312
|
browserCommands,
|
|
15313
|
+
cloudflareWorkerLimits,
|
|
15314
|
+
cloudflareWorkerNetworkLimits,
|
|
14470
15315
|
collectBytes2 as collectBytes,
|
|
14471
15316
|
collectText,
|
|
14472
15317
|
composeMiddleware,
|
|
14473
15318
|
createBrowserCommands,
|
|
14474
15319
|
createBytePipe,
|
|
14475
15320
|
createCommandArguments,
|
|
15321
|
+
createFetchTransport,
|
|
14476
15322
|
createMemoryFileSystem,
|
|
14477
15323
|
createMountFileSystem,
|
|
15324
|
+
createOriginAuthorizer,
|
|
14478
15325
|
createOutputOperation,
|
|
14479
15326
|
createOverlayFileSystem,
|
|
14480
15327
|
createReadOnlyFileSystem,
|