@jerryan/just-bash 3.6.0 → 3.7.0
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/CHANGELOG.md +349 -316
- package/LICENSE +201 -201
- package/README.md +827 -827
- package/dist/agent-sandbox.d.ts +5 -0
- package/dist/bin/chunks/chmod-G2BCCQGF.js +3 -0
- package/dist/bin/chunks/{chunk-B2GCIQI2.js → chunk-2UKTHDUM.js} +1 -1
- package/dist/bin/{shell/chunks/chunk-7WBCA2BB.js → chunks/chunk-3DWQCLNP.js} +1 -1
- package/dist/bin/chunks/chunk-66UHJFN6.js +11 -0
- package/dist/bin/{shell/chunks/chunk-67XYNGRV.js → chunks/chunk-6O4Z6BQT.js} +1 -1
- package/dist/bin/chunks/{chunk-QFTZKD5O.js → chunk-6TUILMPB.js} +1 -1
- package/dist/bin/chunks/{chunk-M7SIPZZZ.js → chunk-7KMOGI3N.js} +1 -1
- package/dist/bin/{shell/chunks/chunk-6ESRNSO7.js → chunks/chunk-ADI36B7X.js} +1 -1
- package/dist/bin/chunks/chunk-CN4JKMTR.js +8 -0
- package/dist/bin/{shell/chunks/chunk-DZAFUADN.js → chunks/chunk-E26NQEH2.js} +1 -1
- package/dist/bin/chunks/chunk-E54Z6VIE.js +12 -0
- package/dist/bin/chunks/chunk-F2PYTUMR.js +9 -0
- package/dist/bin/chunks/chunk-FO7XJH3J.js +13 -0
- package/dist/bin/chunks/chunk-HWK7KFGB.js +3 -0
- package/dist/bin/{shell/chunks/chunk-LE2XKKGQ.js → chunks/chunk-HYLF56CC.js} +1 -1
- package/dist/bin/chunks/chunk-KNTDFP7X.js +12 -0
- package/dist/bin/{shell/chunks/chunk-MF3GVFLC.js → chunks/chunk-L345YZ6R.js} +1 -1
- package/dist/bin/chunks/chunk-NBTZL3VS.js +3 -0
- package/dist/bin/chunks/chunk-OHFB3M3X.js +3 -0
- package/dist/bin/{shell/chunks/chunk-HQ63MFHG.js → chunks/chunk-PEUGMGJJ.js} +1 -1
- package/dist/bin/chunks/chunk-QKJAAJ7J.js +3 -0
- package/dist/bin/{shell/chunks/chunk-JELR4642.js → chunks/chunk-R76AK3KD.js} +12 -12
- package/dist/bin/chunks/{chunk-NLU5LALY.js → chunk-RRECHBUS.js} +1 -1
- package/dist/bin/chunks/{chunk-ZMGLTHSU.js → chunk-THFQI5LV.js} +1 -1
- package/dist/bin/chunks/{chunk-CL7IYCGG.js → chunk-U7YR5CDD.js} +1 -1
- package/dist/bin/chunks/cp-TMDR6USI.js +3 -0
- package/dist/bin/chunks/du-UKFUX7KM.js +3 -0
- package/dist/bin/chunks/find-W2RZWTOF.js +3 -0
- package/dist/bin/chunks/{flag-coverage-C7PB2MO7.js → flag-coverage-QJ5ZQKCF.js} +1 -1
- package/dist/bin/{shell/chunks/grep-CVU5V66H.js → chunks/grep-IHDO3L72.js} +1 -1
- package/dist/bin/chunks/gzip-WUK63QLL.js +3 -0
- package/dist/bin/{shell/chunks/js-exec-DJQLXWCS.js → chunks/js-exec-BE37X4L2.js} +7 -7
- package/dist/bin/chunks/js-exec-worker.js +296 -116
- package/dist/bin/chunks/ln-XVC53673.js +3 -0
- package/dist/bin/chunks/ls-EROTXGTC.js +3 -0
- package/dist/bin/chunks/mkdir-YJ3SOVRP.js +3 -0
- package/dist/bin/chunks/mv-HDNKXPO6.js +3 -0
- package/dist/bin/{shell/chunks/python3-JCJHSX4Z.js → chunks/python3-TJ6DCPIA.js} +1 -1
- package/dist/bin/chunks/readlink-ZUIECKQC.js +3 -0
- package/dist/bin/chunks/rg-ODJAYIKX.js +3 -0
- package/dist/bin/chunks/rm-B4LVIG7A.js +3 -0
- package/dist/bin/chunks/rmdir-W5NBOJ7E.js +3 -0
- package/dist/bin/{shell/chunks/sleep-DVFE2GSF.js → chunks/sleep-MOJQBZMY.js} +1 -1
- package/dist/bin/chunks/split-TVJYLTIJ.js +3 -0
- package/dist/bin/chunks/sqlite3-5BGAK7VX.js +3 -0
- package/dist/bin/chunks/{timeout-YGFHQJKX.js → timeout-RQOWSWYG.js} +1 -1
- package/dist/bin/chunks/worker.js +233 -108
- package/dist/bin/just-bash.js +381 -376
- package/dist/bin/shell/chunks/chmod-G2BCCQGF.js +3 -0
- package/dist/bin/shell/chunks/{chunk-B2GCIQI2.js → chunk-2UKTHDUM.js} +1 -1
- package/dist/bin/{chunks/chunk-7WBCA2BB.js → shell/chunks/chunk-3DWQCLNP.js} +1 -1
- package/dist/bin/shell/chunks/chunk-66UHJFN6.js +11 -0
- package/dist/bin/{chunks/chunk-67XYNGRV.js → shell/chunks/chunk-6O4Z6BQT.js} +1 -1
- package/dist/bin/shell/chunks/{chunk-QFTZKD5O.js → chunk-6TUILMPB.js} +1 -1
- package/dist/bin/shell/chunks/{chunk-M7SIPZZZ.js → chunk-7KMOGI3N.js} +1 -1
- package/dist/bin/{chunks/chunk-6ESRNSO7.js → shell/chunks/chunk-ADI36B7X.js} +1 -1
- package/dist/bin/shell/chunks/chunk-CN4JKMTR.js +8 -0
- package/dist/bin/{chunks/chunk-DZAFUADN.js → shell/chunks/chunk-E26NQEH2.js} +1 -1
- package/dist/bin/shell/chunks/chunk-E54Z6VIE.js +12 -0
- package/dist/bin/shell/chunks/chunk-F2PYTUMR.js +9 -0
- package/dist/bin/shell/chunks/chunk-FO7XJH3J.js +13 -0
- package/dist/bin/shell/chunks/chunk-HWK7KFGB.js +3 -0
- package/dist/bin/{chunks/chunk-LE2XKKGQ.js → shell/chunks/chunk-HYLF56CC.js} +1 -1
- package/dist/bin/shell/chunks/chunk-KNTDFP7X.js +12 -0
- package/dist/bin/{chunks/chunk-MF3GVFLC.js → shell/chunks/chunk-L345YZ6R.js} +1 -1
- package/dist/bin/shell/chunks/chunk-NBTZL3VS.js +3 -0
- package/dist/bin/shell/chunks/chunk-OHFB3M3X.js +3 -0
- package/dist/bin/{chunks/chunk-HQ63MFHG.js → shell/chunks/chunk-PEUGMGJJ.js} +1 -1
- package/dist/bin/shell/chunks/chunk-QKJAAJ7J.js +3 -0
- package/dist/bin/{chunks/chunk-JELR4642.js → shell/chunks/chunk-R76AK3KD.js} +12 -12
- package/dist/bin/shell/chunks/{chunk-NLU5LALY.js → chunk-RRECHBUS.js} +1 -1
- package/dist/bin/shell/chunks/{chunk-ZMGLTHSU.js → chunk-THFQI5LV.js} +1 -1
- package/dist/bin/shell/chunks/{chunk-CL7IYCGG.js → chunk-U7YR5CDD.js} +1 -1
- package/dist/bin/shell/chunks/cp-TMDR6USI.js +3 -0
- package/dist/bin/shell/chunks/du-UKFUX7KM.js +3 -0
- package/dist/bin/shell/chunks/find-W2RZWTOF.js +3 -0
- package/dist/bin/shell/chunks/{flag-coverage-C7PB2MO7.js → flag-coverage-QJ5ZQKCF.js} +1 -1
- package/dist/bin/{chunks/grep-CVU5V66H.js → shell/chunks/grep-IHDO3L72.js} +1 -1
- package/dist/bin/shell/chunks/gzip-WUK63QLL.js +3 -0
- package/dist/bin/{chunks/js-exec-DJQLXWCS.js → shell/chunks/js-exec-BE37X4L2.js} +7 -7
- package/dist/bin/shell/chunks/ln-XVC53673.js +3 -0
- package/dist/bin/shell/chunks/ls-EROTXGTC.js +3 -0
- package/dist/bin/shell/chunks/mkdir-YJ3SOVRP.js +3 -0
- package/dist/bin/shell/chunks/mv-HDNKXPO6.js +3 -0
- package/dist/bin/{chunks/python3-JCJHSX4Z.js → shell/chunks/python3-TJ6DCPIA.js} +1 -1
- package/dist/bin/shell/chunks/readlink-ZUIECKQC.js +3 -0
- package/dist/bin/shell/chunks/rg-ODJAYIKX.js +3 -0
- package/dist/bin/shell/chunks/rm-B4LVIG7A.js +3 -0
- package/dist/bin/shell/chunks/rmdir-W5NBOJ7E.js +3 -0
- package/dist/bin/{chunks/sleep-DVFE2GSF.js → shell/chunks/sleep-MOJQBZMY.js} +1 -1
- package/dist/bin/shell/chunks/split-TVJYLTIJ.js +3 -0
- package/dist/bin/shell/chunks/sqlite3-5BGAK7VX.js +3 -0
- package/dist/bin/shell/chunks/{timeout-YGFHQJKX.js → timeout-RQOWSWYG.js} +1 -1
- package/dist/bin/shell/shell.js +385 -380
- package/dist/bundle/browser.js +643 -638
- package/dist/bundle/chunks/chmod-XZNKTJHL.js +2 -0
- package/dist/bundle/chunks/{chunk-XVSR5HHH.js → chunk-2T7PBFL4.js} +1 -1
- package/dist/bundle/chunks/chunk-3BMWRGU2.js +10 -0
- package/dist/bundle/chunks/chunk-3CIDHL5V.js +11 -0
- package/dist/bundle/chunks/chunk-4CC3OZPU.js +2 -0
- package/dist/bundle/chunks/{chunk-FIMF2TLE.js → chunk-5DMO6LFU.js} +12 -12
- package/dist/bundle/chunks/{chunk-N3A4JVFJ.js → chunk-6IA4DXG2.js} +1 -1
- package/dist/bundle/chunks/chunk-A257L6QO.js +7 -0
- package/dist/bundle/chunks/{chunk-6DDRR56B.js → chunk-ACVD6PQF.js} +1 -1
- package/dist/bundle/chunks/chunk-BS6EJR2R.js +11 -0
- package/dist/bundle/chunks/chunk-D5FHVW27.js +2 -0
- package/dist/bundle/chunks/{chunk-24NLAR7R.js → chunk-E3ABCXE4.js} +1 -1
- package/dist/bundle/chunks/{chunk-FSJ6TTCC.js → chunk-HMM3NGUJ.js} +1 -1
- package/dist/bundle/chunks/chunk-IYJLVOVE.js +12 -0
- package/dist/bundle/chunks/chunk-LRFR25IP.js +8 -0
- package/dist/bundle/chunks/{chunk-NBNI7G66.js → chunk-OPYVVD5P.js} +1 -1
- package/dist/bundle/chunks/{chunk-F6XU52K3.js → chunk-OR544SGH.js} +1 -1
- package/dist/bundle/chunks/{chunk-RPKJJFGZ.js → chunk-PMBXJ3OQ.js} +1 -1
- package/dist/bundle/chunks/chunk-PS2RJNZZ.js +2 -0
- package/dist/bundle/chunks/{chunk-UC76ZOWM.js → chunk-SBOTR4JQ.js} +1 -1
- package/dist/bundle/chunks/chunk-T5ZEIOJ3.js +2 -0
- package/dist/bundle/chunks/{chunk-DMWNBCXJ.js → chunk-TLPMB3FO.js} +1 -1
- package/dist/bundle/chunks/{chunk-XV2V56NQ.js → chunk-YFFU74KY.js} +1 -1
- package/dist/bundle/chunks/{chunk-DAKEIWT3.js → chunk-YNYC232D.js} +1 -1
- package/dist/bundle/chunks/{chunk-ZXFELXJH.js → chunk-YUOBBH7P.js} +1 -1
- package/dist/bundle/chunks/cp-NWITRTH3.js +2 -0
- package/dist/bundle/chunks/du-IFLWEM6M.js +2 -0
- package/dist/bundle/chunks/find-EW6OHRPJ.js +2 -0
- package/dist/bundle/chunks/{flag-coverage-XTIQGK65.js → flag-coverage-PIF5QRO7.js} +1 -1
- package/dist/bundle/chunks/{grep-4AYF3A5J.js → grep-QDFNKAUW.js} +1 -1
- package/dist/bundle/chunks/gzip-HBDKZBIP.js +2 -0
- package/dist/bundle/chunks/{js-exec-XKF2B7C3.js → js-exec-IREGAOMH.js} +7 -7
- package/dist/bundle/chunks/js-exec-worker.js +296 -116
- package/dist/bundle/chunks/ln-CEM7GDB5.js +2 -0
- package/dist/bundle/chunks/ls-WJ7EIFVM.js +2 -0
- package/dist/bundle/chunks/mkdir-Z6MMWH3D.js +2 -0
- package/dist/bundle/chunks/mv-E2NFLGRQ.js +2 -0
- package/dist/bundle/chunks/{python3-F5S5TYGS.js → python3-W4UMQJAQ.js} +1 -1
- package/dist/bundle/chunks/readlink-XCFO7YD2.js +2 -0
- package/dist/bundle/chunks/rg-J7XDRV3B.js +2 -0
- package/dist/bundle/chunks/rm-IGPLE632.js +2 -0
- package/dist/bundle/chunks/rmdir-UMUDM2L2.js +2 -0
- package/dist/bundle/chunks/{sleep-PPRBTSVR.js → sleep-25QUPVDK.js} +1 -1
- package/dist/bundle/chunks/split-D4HPO4G5.js +2 -0
- package/dist/bundle/chunks/sqlite3-3HL2ECCQ.js +2 -0
- package/dist/bundle/chunks/{timeout-C6WDYPLV.js → timeout-37GM7IIL.js} +1 -1
- package/dist/bundle/chunks/worker.js +233 -108
- package/dist/bundle/index.cjs +975 -970
- package/dist/bundle/index.js +357 -352
- package/dist/commands/js-exec/js-exec.d.ts +4 -0
- package/dist/commands/worker-bridge/bridge-handler.d.ts +9 -3
- package/dist/commands/worker-bridge/protocol.d.ts +72 -21
- package/dist/commands/worker-bridge/sync-backend.d.ts +3 -0
- package/dist/fs/fs-error.d.ts +43 -0
- package/dist/fs/interface.d.ts +13 -0
- package/dist/fs/mountable-fs/mountable-fs.d.ts +20 -0
- package/dist/fs/overlay-fs/apply.d.ts +15 -1
- package/dist/fs/overlay-fs/index.d.ts +1 -0
- package/dist/fs/overlay-fs/overlay-fs.d.ts +31 -0
- package/dist/fs/overlay-fs/overlay-tree.d.ts +39 -0
- package/dist/fs/path-utils.d.ts +5 -0
- package/dist/fs/vfs-template.d.ts +74 -0
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/interpreter/builtin-dispatch.d.ts +10 -0
- package/dist/interpreter/builtin-manifest.d.ts +273 -0
- package/dist/interpreter/builtins/help.d.ts +6 -0
- package/dist/interpreter/builtins/shopt.d.ts +3 -0
- package/dist/interpreter/helpers/shell-constants.d.ts +0 -20
- package/dist/timers.d.ts +9 -0
- package/package.json +135 -136
- package/vendor/cpython-emscripten/python.cjs +2 -2
- package/dist/bin/chunks/chmod-WYYTXGVB.js +0 -3
- package/dist/bin/chunks/chunk-43E7AR6A.js +0 -3
- package/dist/bin/chunks/chunk-6LDOIBU7.js +0 -9
- package/dist/bin/chunks/chunk-AI7JUA46.js +0 -13
- package/dist/bin/chunks/chunk-GQKQEK5N.js +0 -11
- package/dist/bin/chunks/chunk-JQM3DKCH.js +0 -12
- package/dist/bin/chunks/chunk-OLEQNRKX.js +0 -8
- package/dist/bin/chunks/chunk-PPVF2N6C.js +0 -3
- package/dist/bin/chunks/chunk-WEHA3JFD.js +0 -3
- package/dist/bin/chunks/chunk-YQEKKZTU.js +0 -12
- package/dist/bin/chunks/cp-OMVKM35F.js +0 -3
- package/dist/bin/chunks/du-LUFPVLNW.js +0 -3
- package/dist/bin/chunks/find-AWH2KOY7.js +0 -3
- package/dist/bin/chunks/gzip-FDPA6EKG.js +0 -3
- package/dist/bin/chunks/ln-B35EKC2Q.js +0 -3
- package/dist/bin/chunks/ls-Q6ZZ6SQ2.js +0 -3
- package/dist/bin/chunks/mkdir-74BP5NTG.js +0 -3
- package/dist/bin/chunks/mv-76LAHXFR.js +0 -3
- package/dist/bin/chunks/readlink-EHXJNW62.js +0 -3
- package/dist/bin/chunks/rg-PXNKNIMY.js +0 -3
- package/dist/bin/chunks/rm-TF2NJQIA.js +0 -3
- package/dist/bin/chunks/rmdir-7ZIVFZJX.js +0 -3
- package/dist/bin/chunks/split-ZNNNHKSP.js +0 -3
- package/dist/bin/chunks/sqlite3-KP42NNIY.js +0 -3
- package/dist/bin/shell/chunks/chmod-WYYTXGVB.js +0 -3
- package/dist/bin/shell/chunks/chunk-43E7AR6A.js +0 -3
- package/dist/bin/shell/chunks/chunk-6LDOIBU7.js +0 -9
- package/dist/bin/shell/chunks/chunk-AI7JUA46.js +0 -13
- package/dist/bin/shell/chunks/chunk-GQKQEK5N.js +0 -11
- package/dist/bin/shell/chunks/chunk-JQM3DKCH.js +0 -12
- package/dist/bin/shell/chunks/chunk-OLEQNRKX.js +0 -8
- package/dist/bin/shell/chunks/chunk-PPVF2N6C.js +0 -3
- package/dist/bin/shell/chunks/chunk-WEHA3JFD.js +0 -3
- package/dist/bin/shell/chunks/chunk-YQEKKZTU.js +0 -12
- package/dist/bin/shell/chunks/cp-OMVKM35F.js +0 -3
- package/dist/bin/shell/chunks/du-LUFPVLNW.js +0 -3
- package/dist/bin/shell/chunks/find-AWH2KOY7.js +0 -3
- package/dist/bin/shell/chunks/gzip-FDPA6EKG.js +0 -3
- package/dist/bin/shell/chunks/ln-B35EKC2Q.js +0 -3
- package/dist/bin/shell/chunks/ls-Q6ZZ6SQ2.js +0 -3
- package/dist/bin/shell/chunks/mkdir-74BP5NTG.js +0 -3
- package/dist/bin/shell/chunks/mv-76LAHXFR.js +0 -3
- package/dist/bin/shell/chunks/readlink-EHXJNW62.js +0 -3
- package/dist/bin/shell/chunks/rg-PXNKNIMY.js +0 -3
- package/dist/bin/shell/chunks/rm-TF2NJQIA.js +0 -3
- package/dist/bin/shell/chunks/rmdir-7ZIVFZJX.js +0 -3
- package/dist/bin/shell/chunks/split-ZNNNHKSP.js +0 -3
- package/dist/bin/shell/chunks/sqlite3-KP42NNIY.js +0 -3
- package/dist/bundle/chunks/chmod-WM2JFFQC.js +0 -2
- package/dist/bundle/chunks/chunk-7IJWBG4I.js +0 -2
- package/dist/bundle/chunks/chunk-MLIO3BK2.js +0 -7
- package/dist/bundle/chunks/chunk-PIRTX3D3.js +0 -8
- package/dist/bundle/chunks/chunk-TBVD66LC.js +0 -10
- package/dist/bundle/chunks/chunk-W2Z6LYL6.js +0 -11
- package/dist/bundle/chunks/chunk-WN54B5NQ.js +0 -12
- package/dist/bundle/chunks/chunk-WXPNKIIH.js +0 -2
- package/dist/bundle/chunks/chunk-YJKHREBZ.js +0 -11
- package/dist/bundle/chunks/chunk-YUSFCOM7.js +0 -2
- package/dist/bundle/chunks/cp-2KZIPZJS.js +0 -2
- package/dist/bundle/chunks/du-7AZCLKR6.js +0 -2
- package/dist/bundle/chunks/find-END3EAHV.js +0 -2
- package/dist/bundle/chunks/gzip-RQOBR22H.js +0 -2
- package/dist/bundle/chunks/ln-OPY2ZVGQ.js +0 -2
- package/dist/bundle/chunks/ls-ZPXGZX63.js +0 -2
- package/dist/bundle/chunks/mkdir-WDDKK2P3.js +0 -2
- package/dist/bundle/chunks/mv-ZF6UBVRB.js +0 -2
- package/dist/bundle/chunks/readlink-U5OM5A3M.js +0 -2
- package/dist/bundle/chunks/rg-NAMXBYKS.js +0 -2
- package/dist/bundle/chunks/rm-OAZOF7XI.js +0 -2
- package/dist/bundle/chunks/rmdir-YJKPQVCK.js +0 -2
- package/dist/bundle/chunks/split-JICLAMP6.js +0 -2
- package/dist/bundle/chunks/sqlite3-4EZ4GXVD.js +0 -2
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
* This command is Node.js only (uses worker_threads).
|
|
8
8
|
*/
|
|
9
9
|
import type { RuntimeCommand } from "../../types.js";
|
|
10
|
+
/** @internal Set the idle-teardown delay — for focused lifecycle tests only. */
|
|
11
|
+
export declare function _setJsExecWorkerIdleTimeoutMsForTests(ms: number): void;
|
|
12
|
+
/** @internal Whether the shared worker is currently alive — for tests only. */
|
|
13
|
+
export declare function _hasSharedJsExecWorkerForTests(): boolean;
|
|
10
14
|
/** @internal Reset singleton worker state — for focused protocol tests only. */
|
|
11
15
|
export declare function _resetJsExecWorkerForTests(): void;
|
|
12
16
|
export declare const jsExecCommand: RuntimeCommand;
|
|
@@ -12,9 +12,6 @@ export interface BridgeOutput {
|
|
|
12
12
|
stderr: string;
|
|
13
13
|
exitCode: number;
|
|
14
14
|
}
|
|
15
|
-
/**
|
|
16
|
-
* Handles requests from a worker thread.
|
|
17
|
-
*/
|
|
18
15
|
export declare class BridgeHandler {
|
|
19
16
|
private fs;
|
|
20
17
|
private cwd;
|
|
@@ -29,6 +26,10 @@ export declare class BridgeHandler {
|
|
|
29
26
|
private outputLimitExceeded;
|
|
30
27
|
private startTime;
|
|
31
28
|
private timeoutMs;
|
|
29
|
+
/** Complete buffer of the last published oversized result, retained
|
|
30
|
+
* so the worker can fetch it in READ_RESULT_RANGE slices. Replaced on
|
|
31
|
+
* every publish. */
|
|
32
|
+
private lastResult;
|
|
32
33
|
constructor(sharedBuffer: SharedArrayBuffer, fs: IFileSystem, cwd: string, commandName: string, secureFetch?: SecureFetch | undefined, maxOutputSize?: number, exec?: ((command: string, options: CommandExecOptions) => Promise<ExecResult>) | undefined, invokeTool?: ((path: string, argsJson: string) => Promise<string>) | undefined);
|
|
33
34
|
/**
|
|
34
35
|
* Returns remaining milliseconds before the overall execution deadline.
|
|
@@ -45,8 +46,13 @@ export declare class BridgeHandler {
|
|
|
45
46
|
run(timeoutMs: number): Promise<BridgeOutput>;
|
|
46
47
|
stop(): void;
|
|
47
48
|
private handleOperation;
|
|
49
|
+
/** Publish a result of any size; oversized results are fetched by the
|
|
50
|
+
* worker in READ_RESULT_RANGE slices from the retained buffer. */
|
|
51
|
+
private publishResult;
|
|
52
|
+
private handleReadResultRange;
|
|
48
53
|
private resolvePath;
|
|
49
54
|
private handleReadFile;
|
|
55
|
+
private handleWriteFileRange;
|
|
50
56
|
private handleWriteFile;
|
|
51
57
|
private handleStat;
|
|
52
58
|
private handleLstat;
|
|
@@ -33,6 +33,8 @@ export declare const OpCode: {
|
|
|
33
33
|
readonly REALPATH: 13;
|
|
34
34
|
readonly RENAME: 14;
|
|
35
35
|
readonly COPY_FILE: 15;
|
|
36
|
+
readonly WRITE_FILE_RANGE: 17;
|
|
37
|
+
readonly READ_RESULT_RANGE: 18;
|
|
36
38
|
readonly WRITE_STDOUT: 100;
|
|
37
39
|
readonly WRITE_STDERR: 101;
|
|
38
40
|
readonly EXIT: 102;
|
|
@@ -41,14 +43,34 @@ export declare const OpCode: {
|
|
|
41
43
|
readonly INVOKE_TOOL: 400;
|
|
42
44
|
};
|
|
43
45
|
export type OpCodeType = (typeof OpCode)[keyof typeof OpCode];
|
|
44
|
-
/**
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Two-word request/result state. The previous single STATUS word was
|
|
48
|
+
* written by THREE actors with TWO meanings (worker READY = "request
|
|
49
|
+
* published", host SUCCESS/ERROR = "result published", stop() READY =
|
|
50
|
+
* "wake for cancel") — a worker waiting for a result could observe a
|
|
51
|
+
* request-channel value and read a torn buffer (the CI flake class).
|
|
52
|
+
* Splitting the channels makes the torn state unrepresentable: a
|
|
53
|
+
* result wait is only ever woken by a result write. A state outside
|
|
54
|
+
* the tables on wake is a genuine protocol bug and fails loudly.
|
|
55
|
+
*/
|
|
56
|
+
/** Worker + stop() write; the host waits on this word. */
|
|
57
|
+
export declare const RequestState: {
|
|
58
|
+
readonly IDLE: 0;
|
|
59
|
+
/** Worker has published an op. */
|
|
60
|
+
readonly REQUEST: 1;
|
|
61
|
+
/** stop() cancellation wake. The host treats any non-REQUEST wake as
|
|
62
|
+
* loop-abort (stop() also flips its `running` flag). */
|
|
63
|
+
readonly CANCELLED: 2;
|
|
50
64
|
};
|
|
51
|
-
|
|
65
|
+
type RequestStateType = (typeof RequestState)[keyof typeof RequestState];
|
|
66
|
+
/** Host writes; the worker waits on this word. stop() never touches
|
|
67
|
+
* it, so a result wait cannot be torn by cancellation. */
|
|
68
|
+
export declare const ResultState: {
|
|
69
|
+
readonly NONE: 0;
|
|
70
|
+
readonly SUCCESS: 1;
|
|
71
|
+
readonly ERROR: 2;
|
|
72
|
+
};
|
|
73
|
+
type ResultStateType = (typeof ResultState)[keyof typeof ResultState];
|
|
52
74
|
/** Error codes */
|
|
53
75
|
export declare const ErrorCode: {
|
|
54
76
|
readonly NONE: 0;
|
|
@@ -59,11 +81,35 @@ export declare const ErrorCode: {
|
|
|
59
81
|
readonly PERMISSION_DENIED: 5;
|
|
60
82
|
readonly INVALID_PATH: 6;
|
|
61
83
|
readonly IO_ERROR: 7;
|
|
62
|
-
readonly TIMEOUT: 8;
|
|
63
84
|
readonly NETWORK_ERROR: 9;
|
|
64
85
|
readonly NETWORK_NOT_CONFIGURED: 10;
|
|
86
|
+
readonly NOT_EMPTY: 11;
|
|
87
|
+
readonly LOOP: 12;
|
|
88
|
+
readonly FILE_TOO_LARGE: 13;
|
|
89
|
+
readonly NO_SPACE: 14;
|
|
90
|
+
readonly BUSY: 15;
|
|
91
|
+
readonly READ_ONLY: 16;
|
|
92
|
+
readonly CROSS_DEVICE: 17;
|
|
65
93
|
};
|
|
66
94
|
export type ErrorCodeType = (typeof ErrorCode)[keyof typeof ErrorCode];
|
|
95
|
+
/**
|
|
96
|
+
* The canonical errno-name <-> wire-code table. Both bridge sides ship
|
|
97
|
+
* together, so the table lives here (not per-side copies): the host
|
|
98
|
+
* maps thrown errnos to wire codes with it, and workers derive guest-
|
|
99
|
+
* facing codes from its inverse via wireToErrnoName(). EPERM precedes
|
|
100
|
+
* EACCES so the inverse prefers the common node spelling.
|
|
101
|
+
*/
|
|
102
|
+
export declare const ERRNO_TO_WIRE: Record<string, ErrorCodeType>;
|
|
103
|
+
/** Errno name for a wire code, or undefined for non-errno wire codes
|
|
104
|
+
* (NONE, IO_ERROR, network conditions). PERMISSION_DENIED inverts to
|
|
105
|
+
* EACCES (the more common spelling in node guests). */
|
|
106
|
+
export declare function wireToErrnoName(code: number): string | undefined;
|
|
107
|
+
/** Buffer sizes */
|
|
108
|
+
export declare const Size: {
|
|
109
|
+
readonly PATH_BUFFER: 4096;
|
|
110
|
+
readonly DATA_BUFFER: 8388608;
|
|
111
|
+
readonly TOTAL: 8392740;
|
|
112
|
+
};
|
|
67
113
|
/** Flags for operations */
|
|
68
114
|
export declare const Flags: {
|
|
69
115
|
readonly NONE: 0;
|
|
@@ -82,8 +128,10 @@ export declare class ProtocolBuffer {
|
|
|
82
128
|
constructor(buffer: SharedArrayBuffer);
|
|
83
129
|
getOpCode(): OpCodeType;
|
|
84
130
|
setOpCode(code: OpCodeType): void;
|
|
85
|
-
|
|
86
|
-
|
|
131
|
+
getRequest(): RequestStateType;
|
|
132
|
+
setRequest(request: RequestStateType): void;
|
|
133
|
+
getResultState(): ResultStateType;
|
|
134
|
+
setResultState(state: ResultStateType): void;
|
|
87
135
|
getPathLength(): number;
|
|
88
136
|
setPathLength(length: number): void;
|
|
89
137
|
getDataLength(): number;
|
|
@@ -104,6 +152,13 @@ export declare class ProtocolBuffer {
|
|
|
104
152
|
setDataFromString(str: string): void;
|
|
105
153
|
getResult(): Uint8Array;
|
|
106
154
|
setResult(data: Uint8Array): void;
|
|
155
|
+
/**
|
|
156
|
+
* Publish a result of ANY size: the first DATA_BUFFER bytes land in
|
|
157
|
+
* the data region and RESULT_LENGTH carries the FULL length. The
|
|
158
|
+
* worker detects the overflow and fetches the rest with
|
|
159
|
+
* READ_RESULT_RANGE ops (served from the host's retained buffer).
|
|
160
|
+
*/
|
|
161
|
+
setResultPrefix(data: Uint8Array): void;
|
|
107
162
|
getResultAsString(): string;
|
|
108
163
|
setResultFromString(str: string): void;
|
|
109
164
|
encodeStat(stat: {
|
|
@@ -122,20 +177,16 @@ export declare class ProtocolBuffer {
|
|
|
122
177
|
size: number;
|
|
123
178
|
mtime: Date;
|
|
124
179
|
};
|
|
125
|
-
waitForReady(timeout?: number): "ok" | "timed-out" | "not-equal";
|
|
126
|
-
waitForReadyAsync(timeout?: number): {
|
|
127
|
-
async: false;
|
|
128
|
-
value: "not-equal" | "timed-out";
|
|
129
|
-
} | {
|
|
130
|
-
async: true;
|
|
131
|
-
value: Promise<"ok" | "timed-out">;
|
|
132
|
-
};
|
|
133
180
|
/**
|
|
134
|
-
* Wait for
|
|
135
|
-
* Returns immediately if
|
|
181
|
+
* Wait for the request word to become REQUEST.
|
|
182
|
+
* Returns immediately if already REQUEST; CANCELLED or any unexpected
|
|
183
|
+
* state returns false (the caller's running-flag check aborts the loop).
|
|
136
184
|
*/
|
|
137
185
|
waitUntilReady(timeout: number): Promise<boolean>;
|
|
186
|
+
/** Worker-side blocking wait on the RESULT word (host writes). */
|
|
138
187
|
waitForResult(timeout?: number): "ok" | "timed-out" | "not-equal";
|
|
139
|
-
|
|
188
|
+
notifyRequest(): number;
|
|
189
|
+
notifyResult(): number;
|
|
140
190
|
reset(): void;
|
|
141
191
|
}
|
|
192
|
+
export {};
|
|
@@ -12,6 +12,9 @@ export declare class SyncBackend {
|
|
|
12
12
|
private operationTimeoutMs;
|
|
13
13
|
constructor(sharedBuffer: SharedArrayBuffer, operationTimeoutMs?: number);
|
|
14
14
|
private execSync;
|
|
15
|
+
/** Build an op failure that preserves the bridge's numeric error code,
|
|
16
|
+
* so downstream errno mapping prefers it over substring matching. */
|
|
17
|
+
private opError_;
|
|
15
18
|
readFile(path: string): Uint8Array;
|
|
16
19
|
writeFile(path: string, data: Uint8Array): void;
|
|
17
20
|
stat(path: string): {
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem error carrying its errno as a STRUCTURED field.
|
|
3
|
+
*
|
|
4
|
+
* The contract: the errno is chosen at the throw site and carried on
|
|
5
|
+
* `.code`; consumers read `.code` and never re-derive it from message
|
|
6
|
+
* prose. There is deliberately NO message-parsing fallback here —
|
|
7
|
+
* parsing "CODE:" prefixes back out of strings is the legacy path this
|
|
8
|
+
* module replaces, and keeping it would leave two sources of truth
|
|
9
|
+
* (the field and the phrasing) with an illusion of robustness.
|
|
10
|
+
*
|
|
11
|
+
* Message format is preserved as a DISPLAY convention only: FsError
|
|
12
|
+
* renders `${code}: ${message}` so existing user-facing text and
|
|
13
|
+
* message-asserting tests are unchanged. The prefix is produced FROM
|
|
14
|
+
* the code, never parsed back INTO one.
|
|
15
|
+
*
|
|
16
|
+
* Contract for IFileSystem implementations (documented on the
|
|
17
|
+
* interface): throw FsError, or any node-style error with a string
|
|
18
|
+
* `.code`. Errors without a structured code are coerced to EIO at
|
|
19
|
+
* classification boundaries (toFsError) — an honest unknown, never a
|
|
20
|
+
* fabricated specific errno.
|
|
21
|
+
*/
|
|
22
|
+
export declare class FsError extends Error {
|
|
23
|
+
readonly code: string;
|
|
24
|
+
/** The message WITHOUT the "CODE: " transport prefix — what
|
|
25
|
+
* user-facing display paths should render. */
|
|
26
|
+
readonly bareMessage: string;
|
|
27
|
+
constructor(code: string, message: string);
|
|
28
|
+
}
|
|
29
|
+
/** Extract a structured errno from any thrown value, or undefined when
|
|
30
|
+
* the value carries none (bare Errors, strings, foreign objects). */
|
|
31
|
+
export declare function fsErrorCode(err: unknown): string | undefined;
|
|
32
|
+
/** True when the error carries the given structured errno. */
|
|
33
|
+
export declare function isFsErrorCode(err: unknown, code: string): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Classify any thrown value at a boundary: structured codes pass
|
|
36
|
+
* through unchanged; everything else becomes the fallback (EIO by
|
|
37
|
+
* default) with the original message preserved. Provided as PUBLIC API
|
|
38
|
+
* for custom IFileSystem implementations and host-side adapters that
|
|
39
|
+
* need to normalize third-party errors before handing them to
|
|
40
|
+
* just-bash internals. Internally, boundaries that only need the code
|
|
41
|
+
* (e.g. the worker bridge) read fsErrorCode directly instead.
|
|
42
|
+
*/
|
|
43
|
+
export declare function toFsError(err: unknown, fallbackCode?: string): FsError;
|
package/dist/fs/interface.d.ts
CHANGED
|
@@ -96,6 +96,19 @@ export interface CpOptions {
|
|
|
96
96
|
* - InMemoryFs (in-memory, default)
|
|
97
97
|
* - Real filesystem (via node:fs)
|
|
98
98
|
* - Custom implementations (e.g., remote storage, browser IndexedDB)
|
|
99
|
+
*
|
|
100
|
+
* ERROR CONTRACT: implementations signal failure kind by throwing
|
|
101
|
+
* {@link FsError} (or any node-style error with a string `.code`
|
|
102
|
+
* property) using POSIX errno names — `"ENOENT"`, `"EACCES"`,
|
|
103
|
+
* `"EEXIST"`, `"ENOTDIR"`, `"EISDIR"`, `"ENOTEMPTY"`, `"EPERM"`,
|
|
104
|
+
* `"EINVAL"`, `"EBUSY"`, `"ELOOP"`, `"EFBIG"`, `"EXDEV"`, `"ENOSPC"`,
|
|
105
|
+
* `"EROFS"`, `"EIO"`. Consumers
|
|
106
|
+
* (commands, bridged runtimes like python3, and error mappings) read
|
|
107
|
+
* the code from `.code`; they never parse it out of message prose.
|
|
108
|
+
* Errors with no structured code are classified at the boundary as
|
|
109
|
+
* EIO — an honest unknown, never a fabricated specific errno.
|
|
110
|
+
* Message text is free-form; by convention FsError renders
|
|
111
|
+
* `"ECODE: message"` for display.
|
|
99
112
|
*/
|
|
100
113
|
export interface IFileSystem {
|
|
101
114
|
/**
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ByteString } from "../../encoding.js";
|
|
2
2
|
import type { BufferEncoding, CpOptions, FileContent, FsStat, IFileSystem, MkdirOptions, ReadFileOptions, RmOptions, WriteFileOptions } from "../interface.js";
|
|
3
|
+
import type { OverlayDiff } from "../overlay-fs/overlay-fs.js";
|
|
3
4
|
/**
|
|
4
5
|
* Configuration for a mount point
|
|
5
6
|
*/
|
|
@@ -58,6 +59,25 @@ export declare class MountableFs implements IFileSystem {
|
|
|
58
59
|
mountPoint: string;
|
|
59
60
|
filesystem: IFileSystem;
|
|
60
61
|
}>;
|
|
62
|
+
/**
|
|
63
|
+
* Combined change set across all diff-capable mounts. `space` selects
|
|
64
|
+
* the path form: "vfs" (default) keeps full virtual paths (mount
|
|
65
|
+
* prefix retained — directly replayable by a template merge);
|
|
66
|
+
* "host" maps each entry to its real-absolute host path (for
|
|
67
|
+
* template.apply / applyDiffToRealFs). The base fs is shared scratch
|
|
68
|
+
* and is not diffed. Mounts without a diff() method fail loudly —
|
|
69
|
+
* a merged view cannot silently omit a mount's changes.
|
|
70
|
+
*/
|
|
71
|
+
diff(options?: {
|
|
72
|
+
space?: "vfs" | "host";
|
|
73
|
+
}): OverlayDiff;
|
|
74
|
+
/**
|
|
75
|
+
* Reconciliation support (template merge replay): set the changedAt
|
|
76
|
+
* ordering stamp of the node at `path` and its ancestors, routing to
|
|
77
|
+
* the owning mount. Paths outside every mount (shared scratch) have
|
|
78
|
+
* no stampable overlay and are ignored.
|
|
79
|
+
*/
|
|
80
|
+
restamp(path: string, changedAt: number, scope?: "full" | "ancestors"): void;
|
|
61
81
|
/**
|
|
62
82
|
* Check if a path is exactly a mount point.
|
|
63
83
|
*/
|
|
@@ -17,6 +17,20 @@ export declare function removeFromRealFs(path: string): void;
|
|
|
17
17
|
* symlinks are recreated with the recorded target; files get the recorded
|
|
18
18
|
* content (unless metadataOnly — a chmod/utimes copy-up), the recorded
|
|
19
19
|
* mode (POSIX only — mode bits are advisory on Windows), and the recorded
|
|
20
|
-
* mtime restored after the content write.
|
|
20
|
+
* mtime restored after the content write. A type-conflicting on-disk
|
|
21
|
+
* target is replaced (the change-set supersedes the base).
|
|
21
22
|
*/
|
|
22
23
|
export declare function applyWriteToRealFs(path: string, write: Omit<OverlayWrite, "path">): void;
|
|
24
|
+
/**
|
|
25
|
+
* Apply a change set with real absolute paths to the real filesystem:
|
|
26
|
+
* deletions first (deepest path first, so subtrees go before their
|
|
27
|
+
* parents), then writes (shallowest first, so explicit directory
|
|
28
|
+
* entries land before their children). Standalone counterpart of
|
|
29
|
+
* AgentSandbox.applyChanges for the fork model — no overlay instance
|
|
30
|
+
* is involved and nothing is dropped; the caller owns the overlays'
|
|
31
|
+
* lifecycle (typically: discard after diff()).
|
|
32
|
+
*/
|
|
33
|
+
export declare function applyDiffToRealFs(diff: {
|
|
34
|
+
writes: OverlayWrite[];
|
|
35
|
+
deletions: string[];
|
|
36
|
+
}): void;
|
|
@@ -48,6 +48,13 @@ export interface OverlayWrite {
|
|
|
48
48
|
mode: number;
|
|
49
49
|
/** Modification time; hosts may apply it (utimes) for fidelity. */
|
|
50
50
|
mtime: Date;
|
|
51
|
+
/**
|
|
52
|
+
* Wall-clock time the overlay recorded this mutation (attach or last
|
|
53
|
+
* in-place change). Unlike `mtime` this cannot be set from inside the
|
|
54
|
+
* sandbox, which makes it the trustworthy ordering key for merging
|
|
55
|
+
* change sets from independent overlays (see mergeDiffs).
|
|
56
|
+
*/
|
|
57
|
+
changedAt?: number;
|
|
51
58
|
/**
|
|
52
59
|
* When true, only metadata changed (chmod/utimes via a metacopy shadow):
|
|
53
60
|
* apply `mode` and `mtime` and never touch file content.
|
|
@@ -70,6 +77,13 @@ export interface OverlayDiff {
|
|
|
70
77
|
* never nest, so each entry is a top-most deletion covering its subtree.
|
|
71
78
|
*/
|
|
72
79
|
deletions: string[];
|
|
80
|
+
/**
|
|
81
|
+
* Wall-clock creation time of each whiteout, aligned with `deletions`
|
|
82
|
+
* (same order). Overlay-assigned and untamperable — the ordering key
|
|
83
|
+
* for merging deletions against writes from other overlays. Present
|
|
84
|
+
* whenever `deletions` is non-empty; absent otherwise.
|
|
85
|
+
*/
|
|
86
|
+
deletionChangedAt?: number[];
|
|
73
87
|
}
|
|
74
88
|
export interface OverlayFsOptions {
|
|
75
89
|
/**
|
|
@@ -116,6 +130,20 @@ export declare class OverlayFs implements IFileSystem {
|
|
|
116
130
|
private readonly allowSymlinks;
|
|
117
131
|
private readonly tree;
|
|
118
132
|
private nextMemoryIdentity;
|
|
133
|
+
/** The real directory this overlay reads through and diffs against. */
|
|
134
|
+
get rootDir(): string;
|
|
135
|
+
/**
|
|
136
|
+
* Reconciliation support (template merge replay, host-side change-set
|
|
137
|
+
* application): stamp the node at `path` with `changedAt` (the
|
|
138
|
+
* replayed entry's own stamp), and correct any NEWER stamps among its
|
|
139
|
+
* ancestors and descendants. Post-sort, a newer stamp can only be a
|
|
140
|
+
* fresh wall-clock stamp minted by the replay op itself (ensured
|
|
141
|
+
* parents, resurrection whiteouts) — those belong to the replayed
|
|
142
|
+
* entry and take its stamp; earlier replayed entries (older stamps)
|
|
143
|
+
* are never touched. This is a host-side reconciliation API, not a
|
|
144
|
+
* guest operation: changedAt is the ordering key merges rely on.
|
|
145
|
+
*/
|
|
146
|
+
restamp(path: string, changedAt: number, scope?: "full" | "ancestors"): void;
|
|
119
147
|
private identityFor;
|
|
120
148
|
constructor(options: OverlayFsOptions);
|
|
121
149
|
/**
|
|
@@ -285,6 +313,9 @@ export declare class OverlayFs implements IFileSystem {
|
|
|
285
313
|
*/
|
|
286
314
|
private inheritedMode;
|
|
287
315
|
appendFile(path: string, content: FileContent, options?: WriteFileOptions | BufferEncoding): Promise<void>;
|
|
316
|
+
/** Append to an existing upper file node, completing a metacopy
|
|
317
|
+
* copy-up first when needed (preserving the node's upper mode). */
|
|
318
|
+
private appendToExisting_;
|
|
288
319
|
exists(path: string): Promise<boolean>;
|
|
289
320
|
stat(path: string, seen?: Set<string>): Promise<FsStat>;
|
|
290
321
|
lstat(path: string): Promise<FsStat>;
|
|
@@ -36,6 +36,21 @@ export interface OverlayFileNode {
|
|
|
36
36
|
lowerSize?: number;
|
|
37
37
|
/** Append segments retained without copying the complete file per append. */
|
|
38
38
|
appendChunks?: Uint8Array[];
|
|
39
|
+
/**
|
|
40
|
+
* Mutation sequence stamp (tree-local, monotonically increasing).
|
|
41
|
+
* Set by in-place mutations (appendChunk, chmod, utimes) so sync()
|
|
42
|
+
* can compare-and-swap: an entry checked against disk is only
|
|
43
|
+
* detached if it has not been mutated since the check began.
|
|
44
|
+
* Node replacement (attach/detach) needs no stamp — object identity
|
|
45
|
+
* already changes. Undefined means never mutated in place.
|
|
46
|
+
*/
|
|
47
|
+
seq?: number;
|
|
48
|
+
/**
|
|
49
|
+
* Wall-clock time of the last mutation (attach/touch), stamped by the
|
|
50
|
+
* tree. Distinct from `mtime`: user-visible and utimes-able, whereas
|
|
51
|
+
* changedAt is the untamperable ordering key mergeDiffs relies on.
|
|
52
|
+
*/
|
|
53
|
+
changedAt?: number;
|
|
39
54
|
mode: number;
|
|
40
55
|
mtime: Date;
|
|
41
56
|
identity?: string;
|
|
@@ -44,6 +59,10 @@ export interface OverlayDirNode {
|
|
|
44
59
|
type: "directory";
|
|
45
60
|
/** Child nodes keyed by name segment, in insertion order. */
|
|
46
61
|
children: Map<string, OverlayNode>;
|
|
62
|
+
/** In-place mutation stamp (see OverlayFileNode.seq). */
|
|
63
|
+
seq?: number;
|
|
64
|
+
/** Wall-clock time of the last mutation (see OverlayFileNode.changedAt). */
|
|
65
|
+
changedAt?: number;
|
|
47
66
|
mode: number;
|
|
48
67
|
mtime: Date;
|
|
49
68
|
identity?: string;
|
|
@@ -51,12 +70,18 @@ export interface OverlayDirNode {
|
|
|
51
70
|
export interface OverlaySymlinkNode {
|
|
52
71
|
type: "symlink";
|
|
53
72
|
target: string;
|
|
73
|
+
/** In-place mutation stamp (see OverlayFileNode.seq). */
|
|
74
|
+
seq?: number;
|
|
75
|
+
/** Wall-clock time of the last mutation (see OverlayFileNode.changedAt). */
|
|
76
|
+
changedAt?: number;
|
|
54
77
|
mode: number;
|
|
55
78
|
mtime: Date;
|
|
56
79
|
}
|
|
57
80
|
/** Leaf marker hiding a lower-layer (real-FS) path and everything under it. */
|
|
58
81
|
export interface OverlayWhiteoutNode {
|
|
59
82
|
type: "whiteout";
|
|
83
|
+
/** Wall-clock time the whiteout was created (merge ordering). */
|
|
84
|
+
changedAt?: number;
|
|
60
85
|
}
|
|
61
86
|
export type OverlayEntryNode = OverlayFileNode | OverlayDirNode | OverlaySymlinkNode;
|
|
62
87
|
export type OverlayNode = OverlayEntryNode | OverlayWhiteoutNode;
|
|
@@ -101,6 +126,7 @@ export declare class OverlayTree {
|
|
|
101
126
|
private readonly maxMemoryBytes;
|
|
102
127
|
private rootNode;
|
|
103
128
|
private bytes;
|
|
129
|
+
private mutationSeq_;
|
|
104
130
|
constructor(maxMemoryBytes: number);
|
|
105
131
|
/** The root directory node — the VFS root ("/"). */
|
|
106
132
|
get root(): OverlayDirNode;
|
|
@@ -160,6 +186,19 @@ export declare class OverlayTree {
|
|
|
160
186
|
* Append a chunk to a file node, accounting its bytes against capacity.
|
|
161
187
|
*/
|
|
162
188
|
appendChunk(node: OverlayFileNode, chunk: Uint8Array): void;
|
|
189
|
+
/** Stamp a node as mutated in place (see OverlayFileNode.seq). */
|
|
190
|
+
touch(node: {
|
|
191
|
+
seq?: number;
|
|
192
|
+
changedAt?: number;
|
|
193
|
+
}): void;
|
|
194
|
+
/**
|
|
195
|
+
* Compare-and-swap detach: remove the node at `path` only if it is
|
|
196
|
+
* still the exact same object with the same mutation sequence — i.e.
|
|
197
|
+
* nothing changed it while the caller's (async) verification ran.
|
|
198
|
+
* Also refuses to detach a directory that has gained children.
|
|
199
|
+
* Returns whether the detach happened.
|
|
200
|
+
*/
|
|
201
|
+
detachIfUnchanged(path: string, node: OverlayNode, seq?: number): boolean;
|
|
163
202
|
/**
|
|
164
203
|
* Yield every node, parents before children (pre-order), starting with the
|
|
165
204
|
* root at path "/". Whiteouts are included; callers filter as needed.
|
package/dist/fs/path-utils.d.ts
CHANGED
|
@@ -39,6 +39,11 @@ export declare function resolvePath(base: string, path: string): string;
|
|
|
39
39
|
* Join a parent path with a child name.
|
|
40
40
|
* Handles the root-path edge case (`"/" + "child"` → `"/child"`).
|
|
41
41
|
*/
|
|
42
|
+
/** Convert an OS-form path fragment to VFS slash form (win32
|
|
43
|
+
* backslashes become slashes; on POSIX this is a no-op). VFS paths are
|
|
44
|
+
* always slash-form — use when reconstructing a virtual path from a
|
|
45
|
+
* real-OS path (e.g. slicing off a real root). */
|
|
46
|
+
export declare function toVirtualSlashes(path: string): string;
|
|
42
47
|
export declare function joinPath(parent: string, child: string): string;
|
|
43
48
|
/**
|
|
44
49
|
* Resolve a symlink target relative to the symlink's location.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { MountableFs } from "./mountable-fs/mountable-fs.js";
|
|
2
|
+
import type { OverlayDiff } from "./overlay-fs/overlay-fs.js";
|
|
3
|
+
/** One privatized subtree: virtual mount point + real backing root. */
|
|
4
|
+
export interface VfsTemplateMount {
|
|
5
|
+
/** Virtual absolute path the overlay serves (e.g. "/project"). */
|
|
6
|
+
at: string;
|
|
7
|
+
/** Real absolute directory the overlay reads through and diffs against. */
|
|
8
|
+
root: string;
|
|
9
|
+
}
|
|
10
|
+
export interface VfsTemplateOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Subtrees privatized per fork. Everything else (/, /tmp, ...) lives
|
|
13
|
+
* in the template's shared scratch memory fs: writes there are
|
|
14
|
+
* visible to every fork immediately and never appear in diffs.
|
|
15
|
+
*/
|
|
16
|
+
mounts: VfsTemplateMount[];
|
|
17
|
+
/**
|
|
18
|
+
* Per-overlay content-byte budget (OverlayFs maxMemoryBytes),
|
|
19
|
+
* bounding each fork's copy-up memory. Default: the OverlayFs
|
|
20
|
+
* default.
|
|
21
|
+
*/
|
|
22
|
+
maxMemoryBytes?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Template for cheap parallel forks (see
|
|
26
|
+
* docs/design/vfs-template-fork-model.md). The template owns the shared
|
|
27
|
+
* scratch fs and the mount configuration; each fork() stamps out a
|
|
28
|
+
* ready MountableFs with fresh copy-on-write overlays over every
|
|
29
|
+
* mounted real root. Forks are unmanaged: the template keeps no
|
|
30
|
+
* registry, consumes nothing, and never tracks lifecycles.
|
|
31
|
+
*
|
|
32
|
+
* MERGE IS A REPLAY. `merge` combines the given change sets (fork
|
|
33
|
+
* instances are diffed in vfs space; plain diffs pass through), orders
|
|
34
|
+
* every entry by (changedAt, input order), and applies the entries to a
|
|
35
|
+
* fresh fork with the stock filesystem operations — the same codepath
|
|
36
|
+
* the forks themselves used, over the same lower. Anything the
|
|
37
|
+
* filesystem refuses (write under a file, chmod of a deleted path, ...)
|
|
38
|
+
* is skipped, which keeps conflicting (racy) input deterministic and
|
|
39
|
+
* contained to the conflicted path. After each replayed operation the
|
|
40
|
+
* touched node's changedAt is rewritten from the replay position, so
|
|
41
|
+
* merged output is byte-deterministic and wall-clock-free. The merged
|
|
42
|
+
* fork is returned: diff it and discard it, or keep working on it.
|
|
43
|
+
*
|
|
44
|
+
* ```ts
|
|
45
|
+
* const tpl = createVfsTemplate({ mounts: [{ at: "/project", root: projDir }] });
|
|
46
|
+
* const a = tpl.fork();
|
|
47
|
+
* const b = tpl.fork();
|
|
48
|
+
* await Promise.all([runAgent(a), runAgent(b)]);
|
|
49
|
+
* const merged = await tpl.merge([a, b]);
|
|
50
|
+
* tpl.apply(merged.diff({ space: "host" }));
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export interface VfsTemplate {
|
|
54
|
+
/** A fresh per-call filesystem: shared scratch + fresh overlays. */
|
|
55
|
+
fork(): MountableFs;
|
|
56
|
+
/**
|
|
57
|
+
* Replay the given sources' change sets onto a fresh fork and return
|
|
58
|
+
* it. Sources may be fork instances (diffed in vfs space) or plain
|
|
59
|
+
* diffs (e.g. serialized across a process boundary). Array order is
|
|
60
|
+
* the tie-break for equal changedAt stamps. Entries outside every
|
|
61
|
+
* mount point replay into the shared scratch (ordinary fork
|
|
62
|
+
* semantics, never reported in diff()) — merge expects diffs in
|
|
63
|
+
* this template's vfs space.
|
|
64
|
+
*/
|
|
65
|
+
merge(sources: Array<MountableFs | OverlayDiff>): Promise<MountableFs>;
|
|
66
|
+
/**
|
|
67
|
+
* Validate a merged host-space diff against the mount map (every
|
|
68
|
+
* entry inside a registered root, no symlink writes, no root-self
|
|
69
|
+
* deletion) and apply it to the real filesystem. Type-conflicting
|
|
70
|
+
* on-disk targets are replaced (the change-set supersedes the base).
|
|
71
|
+
*/
|
|
72
|
+
apply(merged: OverlayDiff): void;
|
|
73
|
+
}
|
|
74
|
+
export declare function createVfsTemplate(options: VfsTemplateOptions): VfsTemplate;
|
package/dist/index.d.cts
CHANGED
|
@@ -8,11 +8,13 @@ export type { CommandContextOptions, CustomCommand, LazyCommand, } from "./custo
|
|
|
8
8
|
export { createCommandContext, defineCommand, } from "./custom-commands.js";
|
|
9
9
|
export type { ByteString, OutputKind } from "./encoding.js";
|
|
10
10
|
export { bytesOutput, decodeBytesToUtf8, EMPTY_BYTES, encodeUtf8ToBytes, latin1FromBytes, stdoutAsBytes, stdoutKind, textOutput, unsafeBytesFromLatin1, } from "./encoding.js";
|
|
11
|
+
export { FsError, fsErrorCode, isFsErrorCode, toFsError, } from "./fs/fs-error.js";
|
|
11
12
|
export { InMemoryFs } from "./fs/in-memory-fs/index.js";
|
|
12
13
|
export type { BufferEncoding, CpOptions, DirectoryEntry, FileContent, FileEntry, FileInit, FileSystemFactory, FsEntry, FsStat, InitialFiles, LazyFileEntry, LazyFileProvider, MkdirOptions, RmOptions, SymlinkEntry, } from "./fs/interface.js";
|
|
13
14
|
export { MountableFs, type MountableFsOptions, type MountConfig, } from "./fs/mountable-fs/index.js";
|
|
14
|
-
export { type OverlayDiff, OverlayFs, type OverlayFsOptions, type OverlayNodeType, type OverlayWrite, } from "./fs/overlay-fs/index.js";
|
|
15
|
+
export { applyDiffToRealFs, type OverlayDiff, OverlayFs, type OverlayFsOptions, type OverlayNodeType, type OverlayWrite, } from "./fs/overlay-fs/index.js";
|
|
15
16
|
export { ReadWriteFs, type ReadWriteFsOptions, } from "./fs/read-write-fs/index.js";
|
|
17
|
+
export { createVfsTemplate, type VfsTemplate, type VfsTemplateMount, type VfsTemplateOptions, } from "./fs/vfs-template.js";
|
|
16
18
|
export type { AllowedUrl, AllowedUrlEntry, NetworkConfig, RequestTransform, SecureFetch, } from "./network/index.js";
|
|
17
19
|
export { NetworkAccessDeniedError, RedirectNotAllowedError, TooManyRedirectsError, } from "./network/index.js";
|
|
18
20
|
export { parse } from "./parser/parser.js";
|
package/dist/index.d.ts
CHANGED
|
@@ -8,11 +8,13 @@ export type { CommandContextOptions, CustomCommand, LazyCommand, } from "./custo
|
|
|
8
8
|
export { createCommandContext, defineCommand, } from "./custom-commands.js";
|
|
9
9
|
export type { ByteString, OutputKind } from "./encoding.js";
|
|
10
10
|
export { bytesOutput, decodeBytesToUtf8, EMPTY_BYTES, encodeUtf8ToBytes, latin1FromBytes, stdoutAsBytes, stdoutKind, textOutput, unsafeBytesFromLatin1, } from "./encoding.js";
|
|
11
|
+
export { FsError, fsErrorCode, isFsErrorCode, toFsError, } from "./fs/fs-error.js";
|
|
11
12
|
export { InMemoryFs } from "./fs/in-memory-fs/index.js";
|
|
12
13
|
export type { BufferEncoding, CpOptions, DirectoryEntry, FileContent, FileEntry, FileInit, FileSystemFactory, FsEntry, FsStat, InitialFiles, LazyFileEntry, LazyFileProvider, MkdirOptions, RmOptions, SymlinkEntry, } from "./fs/interface.js";
|
|
13
14
|
export { MountableFs, type MountableFsOptions, type MountConfig, } from "./fs/mountable-fs/index.js";
|
|
14
|
-
export { type OverlayDiff, OverlayFs, type OverlayFsOptions, type OverlayNodeType, type OverlayWrite, } from "./fs/overlay-fs/index.js";
|
|
15
|
+
export { applyDiffToRealFs, type OverlayDiff, OverlayFs, type OverlayFsOptions, type OverlayNodeType, type OverlayWrite, } from "./fs/overlay-fs/index.js";
|
|
15
16
|
export { ReadWriteFs, type ReadWriteFsOptions, } from "./fs/read-write-fs/index.js";
|
|
17
|
+
export { createVfsTemplate, type VfsTemplate, type VfsTemplateMount, type VfsTemplateOptions, } from "./fs/vfs-template.js";
|
|
16
18
|
export type { AllowedUrl, AllowedUrlEntry, NetworkConfig, RequestTransform, SecureFetch, } from "./network/index.js";
|
|
17
19
|
export { NetworkAccessDeniedError, RedirectNotAllowedError, TooManyRedirectsError, } from "./network/index.js";
|
|
18
20
|
export { parse } from "./parser/parser.js";
|
|
@@ -21,6 +21,16 @@ export type ExecuteUserScriptFn = (scriptPath: string, args: string[], stdin?: s
|
|
|
21
21
|
/**
|
|
22
22
|
* Dispatch context containing dependencies needed for builtin dispatch
|
|
23
23
|
*/
|
|
24
|
+
/** Stdio contract passed to builtin handlers. */
|
|
25
|
+
export interface BuiltinIo {
|
|
26
|
+
stdin: string;
|
|
27
|
+
/** True when a redirection gave this command its own fd 0. `stdin`
|
|
28
|
+
* alone cannot express it: `cmd < empty-file` and an unredirected
|
|
29
|
+
* command both arrive as `""`, but only the first means EOF rather
|
|
30
|
+
* than "inherit the shell's stdin". */
|
|
31
|
+
stdinRedirected: boolean;
|
|
32
|
+
stdinSourceFd: number;
|
|
33
|
+
}
|
|
24
34
|
export interface BuiltinDispatchContext {
|
|
25
35
|
ctx: InterpreterContext;
|
|
26
36
|
runCommand: RunCommandFn;
|