just-bash 2.6.0 → 2.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/README.md +1 -1
- package/dist/AGENTS.md +1 -1
- package/dist/bin/chunks/python3-JGT65AEB.js +14 -0
- package/dist/bin/chunks/worker.js +1038 -0
- package/dist/bin/just-bash.js +37 -37
- package/dist/bin/shell/chunks/python3-JGT65AEB.js +14 -0
- package/dist/bin/shell/shell.js +37 -37
- package/dist/bundle/browser.js +27 -27
- package/dist/bundle/chunks/python3-3OP7EKER.js +13 -0
- package/dist/bundle/chunks/worker.js +1038 -0
- package/dist/bundle/index.js +31 -31
- package/dist/commands/python3/fs-bridge-handler.d.ts +50 -0
- package/dist/commands/python3/protocol.d.ts +138 -0
- package/dist/commands/python3/python3.d.ts +11 -0
- package/dist/commands/python3/sync-fs-backend.d.ts +59 -0
- package/dist/commands/python3/worker.d.ts +16 -0
- package/dist/commands/registry.d.ts +1 -1
- package/dist/limits.d.ts +2 -0
- package/package.json +7 -5
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main thread filesystem bridge handler
|
|
3
|
+
*
|
|
4
|
+
* Runs on the main thread and processes filesystem requests from the worker thread.
|
|
5
|
+
* Uses SharedArrayBuffer + Atomics for synchronization.
|
|
6
|
+
*/
|
|
7
|
+
import type { IFileSystem } from "../../fs/interface.js";
|
|
8
|
+
import type { SecureFetch } from "../../network/fetch.js";
|
|
9
|
+
export interface FsBridgeOutput {
|
|
10
|
+
stdout: string;
|
|
11
|
+
stderr: string;
|
|
12
|
+
exitCode: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Handles filesystem requests from the worker thread.
|
|
16
|
+
*/
|
|
17
|
+
export declare class FsBridgeHandler {
|
|
18
|
+
private fs;
|
|
19
|
+
private cwd;
|
|
20
|
+
private secureFetch;
|
|
21
|
+
private protocol;
|
|
22
|
+
private running;
|
|
23
|
+
private output;
|
|
24
|
+
constructor(sharedBuffer: SharedArrayBuffer, fs: IFileSystem, cwd: string, secureFetch?: SecureFetch | undefined);
|
|
25
|
+
/**
|
|
26
|
+
* Run the handler loop until EXIT operation or timeout.
|
|
27
|
+
*/
|
|
28
|
+
run(timeoutMs: number): Promise<FsBridgeOutput>;
|
|
29
|
+
stop(): void;
|
|
30
|
+
private handleOperation;
|
|
31
|
+
private resolvePath;
|
|
32
|
+
private handleReadFile;
|
|
33
|
+
private handleWriteFile;
|
|
34
|
+
private handleStat;
|
|
35
|
+
private handleLstat;
|
|
36
|
+
private handleReaddir;
|
|
37
|
+
private handleMkdir;
|
|
38
|
+
private handleRm;
|
|
39
|
+
private handleExists;
|
|
40
|
+
private handleAppendFile;
|
|
41
|
+
private handleSymlink;
|
|
42
|
+
private handleReadlink;
|
|
43
|
+
private handleChmod;
|
|
44
|
+
private handleRealpath;
|
|
45
|
+
private handleWriteStdout;
|
|
46
|
+
private handleWriteStderr;
|
|
47
|
+
private handleExit;
|
|
48
|
+
private handleHttpRequest;
|
|
49
|
+
private setErrorFromException;
|
|
50
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SharedArrayBuffer protocol for synchronous filesystem bridge
|
|
3
|
+
*
|
|
4
|
+
* This protocol enables synchronous filesystem access from a worker thread
|
|
5
|
+
* (where Pyodide/Python runs) to the main thread (which has async IFileSystem).
|
|
6
|
+
*/
|
|
7
|
+
declare global {
|
|
8
|
+
interface Atomics {
|
|
9
|
+
waitAsync(typedArray: Int32Array, index: number, value: number, timeout?: number): {
|
|
10
|
+
async: false;
|
|
11
|
+
value: "not-equal" | "timed-out";
|
|
12
|
+
} | {
|
|
13
|
+
async: true;
|
|
14
|
+
value: Promise<"ok" | "timed-out">;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Operation codes */
|
|
19
|
+
export declare const OpCode: {
|
|
20
|
+
readonly NOOP: 0;
|
|
21
|
+
readonly READ_FILE: 1;
|
|
22
|
+
readonly WRITE_FILE: 2;
|
|
23
|
+
readonly STAT: 3;
|
|
24
|
+
readonly READDIR: 4;
|
|
25
|
+
readonly MKDIR: 5;
|
|
26
|
+
readonly RM: 6;
|
|
27
|
+
readonly EXISTS: 7;
|
|
28
|
+
readonly APPEND_FILE: 8;
|
|
29
|
+
readonly SYMLINK: 9;
|
|
30
|
+
readonly READLINK: 10;
|
|
31
|
+
readonly LSTAT: 11;
|
|
32
|
+
readonly CHMOD: 12;
|
|
33
|
+
readonly REALPATH: 13;
|
|
34
|
+
readonly WRITE_STDOUT: 100;
|
|
35
|
+
readonly WRITE_STDERR: 101;
|
|
36
|
+
readonly EXIT: 102;
|
|
37
|
+
readonly HTTP_REQUEST: 200;
|
|
38
|
+
};
|
|
39
|
+
export type OpCodeType = (typeof OpCode)[keyof typeof OpCode];
|
|
40
|
+
/** Status codes for synchronization */
|
|
41
|
+
export declare const Status: {
|
|
42
|
+
readonly PENDING: 0;
|
|
43
|
+
readonly READY: 1;
|
|
44
|
+
readonly SUCCESS: 2;
|
|
45
|
+
readonly ERROR: 3;
|
|
46
|
+
};
|
|
47
|
+
export type StatusType = (typeof Status)[keyof typeof Status];
|
|
48
|
+
/** Error codes */
|
|
49
|
+
export declare const ErrorCode: {
|
|
50
|
+
readonly NONE: 0;
|
|
51
|
+
readonly NOT_FOUND: 1;
|
|
52
|
+
readonly IS_DIRECTORY: 2;
|
|
53
|
+
readonly NOT_DIRECTORY: 3;
|
|
54
|
+
readonly EXISTS: 4;
|
|
55
|
+
readonly PERMISSION_DENIED: 5;
|
|
56
|
+
readonly INVALID_PATH: 6;
|
|
57
|
+
readonly IO_ERROR: 7;
|
|
58
|
+
readonly TIMEOUT: 8;
|
|
59
|
+
readonly NETWORK_ERROR: 9;
|
|
60
|
+
readonly NETWORK_NOT_CONFIGURED: 10;
|
|
61
|
+
};
|
|
62
|
+
export type ErrorCodeType = (typeof ErrorCode)[keyof typeof ErrorCode];
|
|
63
|
+
/** Flags for operations */
|
|
64
|
+
export declare const Flags: {
|
|
65
|
+
readonly NONE: 0;
|
|
66
|
+
readonly RECURSIVE: 1;
|
|
67
|
+
readonly FORCE: 2;
|
|
68
|
+
readonly MKDIR_RECURSIVE: 1;
|
|
69
|
+
};
|
|
70
|
+
/** Create a new SharedArrayBuffer for the protocol */
|
|
71
|
+
export declare function createSharedBuffer(): SharedArrayBuffer;
|
|
72
|
+
/**
|
|
73
|
+
* Helper class for reading/writing protocol data
|
|
74
|
+
*/
|
|
75
|
+
export declare class ProtocolBuffer {
|
|
76
|
+
private int32View;
|
|
77
|
+
private uint8View;
|
|
78
|
+
private dataView;
|
|
79
|
+
constructor(buffer: SharedArrayBuffer);
|
|
80
|
+
getOpCode(): OpCodeType;
|
|
81
|
+
setOpCode(code: OpCodeType): void;
|
|
82
|
+
getStatus(): StatusType;
|
|
83
|
+
setStatus(status: StatusType): void;
|
|
84
|
+
getPathLength(): number;
|
|
85
|
+
setPathLength(length: number): void;
|
|
86
|
+
getDataLength(): number;
|
|
87
|
+
setDataLength(length: number): void;
|
|
88
|
+
getResultLength(): number;
|
|
89
|
+
setResultLength(length: number): void;
|
|
90
|
+
getErrorCode(): ErrorCodeType;
|
|
91
|
+
setErrorCode(code: ErrorCodeType): void;
|
|
92
|
+
getFlags(): number;
|
|
93
|
+
setFlags(flags: number): void;
|
|
94
|
+
getMode(): number;
|
|
95
|
+
setMode(mode: number): void;
|
|
96
|
+
getPath(): string;
|
|
97
|
+
setPath(path: string): void;
|
|
98
|
+
getData(): Uint8Array;
|
|
99
|
+
setData(data: Uint8Array): void;
|
|
100
|
+
getDataAsString(): string;
|
|
101
|
+
setDataFromString(str: string): void;
|
|
102
|
+
getResult(): Uint8Array;
|
|
103
|
+
setResult(data: Uint8Array): void;
|
|
104
|
+
getResultAsString(): string;
|
|
105
|
+
setResultFromString(str: string): void;
|
|
106
|
+
encodeStat(stat: {
|
|
107
|
+
isFile: boolean;
|
|
108
|
+
isDirectory: boolean;
|
|
109
|
+
isSymbolicLink: boolean;
|
|
110
|
+
mode: number;
|
|
111
|
+
size: number;
|
|
112
|
+
mtime: Date;
|
|
113
|
+
}): void;
|
|
114
|
+
decodeStat(): {
|
|
115
|
+
isFile: boolean;
|
|
116
|
+
isDirectory: boolean;
|
|
117
|
+
isSymbolicLink: boolean;
|
|
118
|
+
mode: number;
|
|
119
|
+
size: number;
|
|
120
|
+
mtime: Date;
|
|
121
|
+
};
|
|
122
|
+
waitForReady(timeout?: number): "ok" | "timed-out" | "not-equal";
|
|
123
|
+
waitForReadyAsync(timeout?: number): {
|
|
124
|
+
async: false;
|
|
125
|
+
value: "not-equal" | "timed-out";
|
|
126
|
+
} | {
|
|
127
|
+
async: true;
|
|
128
|
+
value: Promise<"ok" | "timed-out">;
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Wait for status to become READY.
|
|
132
|
+
* Returns immediately if status is already READY, or waits until it changes.
|
|
133
|
+
*/
|
|
134
|
+
waitUntilReady(timeout: number): Promise<boolean>;
|
|
135
|
+
waitForResult(timeout?: number): "ok" | "timed-out" | "not-equal";
|
|
136
|
+
notify(): number;
|
|
137
|
+
reset(): void;
|
|
138
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* python3 - Execute Python code via Pyodide (Python in WebAssembly)
|
|
3
|
+
*
|
|
4
|
+
* Runs Python code in an isolated worker thread with access to the
|
|
5
|
+
* virtual filesystem via SharedArrayBuffer bridge.
|
|
6
|
+
*
|
|
7
|
+
* This command is Node.js only (uses worker_threads).
|
|
8
|
+
*/
|
|
9
|
+
import type { Command } from "../../types.js";
|
|
10
|
+
export declare const python3Command: Command;
|
|
11
|
+
export declare const pythonCommand: Command;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worker-side synchronous filesystem backend
|
|
3
|
+
*
|
|
4
|
+
* Runs in the worker thread and makes synchronous calls to the main thread
|
|
5
|
+
* via SharedArrayBuffer + Atomics.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Synchronous filesystem backend for Pyodide worker.
|
|
9
|
+
*/
|
|
10
|
+
export declare class SyncFsBackend {
|
|
11
|
+
private protocol;
|
|
12
|
+
constructor(sharedBuffer: SharedArrayBuffer);
|
|
13
|
+
private execSync;
|
|
14
|
+
readFile(path: string): Uint8Array;
|
|
15
|
+
writeFile(path: string, data: Uint8Array): void;
|
|
16
|
+
stat(path: string): {
|
|
17
|
+
isFile: boolean;
|
|
18
|
+
isDirectory: boolean;
|
|
19
|
+
isSymbolicLink: boolean;
|
|
20
|
+
mode: number;
|
|
21
|
+
size: number;
|
|
22
|
+
mtime: Date;
|
|
23
|
+
};
|
|
24
|
+
lstat(path: string): {
|
|
25
|
+
isFile: boolean;
|
|
26
|
+
isDirectory: boolean;
|
|
27
|
+
isSymbolicLink: boolean;
|
|
28
|
+
mode: number;
|
|
29
|
+
size: number;
|
|
30
|
+
mtime: Date;
|
|
31
|
+
};
|
|
32
|
+
readdir(path: string): string[];
|
|
33
|
+
mkdir(path: string, recursive?: boolean): void;
|
|
34
|
+
rm(path: string, recursive?: boolean, force?: boolean): void;
|
|
35
|
+
exists(path: string): boolean;
|
|
36
|
+
appendFile(path: string, data: Uint8Array): void;
|
|
37
|
+
symlink(target: string, linkPath: string): void;
|
|
38
|
+
readlink(path: string): string;
|
|
39
|
+
chmod(path: string, mode: number): void;
|
|
40
|
+
realpath(path: string): string;
|
|
41
|
+
writeStdout(data: string): void;
|
|
42
|
+
writeStderr(data: string): void;
|
|
43
|
+
exit(code: number): void;
|
|
44
|
+
/**
|
|
45
|
+
* Make an HTTP request through the main thread's secureFetch.
|
|
46
|
+
* Returns the response as a parsed object.
|
|
47
|
+
*/
|
|
48
|
+
httpRequest(url: string, options?: {
|
|
49
|
+
method?: string;
|
|
50
|
+
headers?: Record<string, string>;
|
|
51
|
+
body?: string;
|
|
52
|
+
}): {
|
|
53
|
+
status: number;
|
|
54
|
+
statusText: string;
|
|
55
|
+
headers: Record<string, string>;
|
|
56
|
+
body: string;
|
|
57
|
+
url: string;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worker thread for Python execution via Pyodide.
|
|
3
|
+
* Keeps Pyodide loaded and handles multiple execution requests.
|
|
4
|
+
*/
|
|
5
|
+
export interface WorkerInput {
|
|
6
|
+
sharedBuffer: SharedArrayBuffer;
|
|
7
|
+
pythonCode: string;
|
|
8
|
+
cwd: string;
|
|
9
|
+
env: Record<string, string>;
|
|
10
|
+
args: string[];
|
|
11
|
+
scriptPath?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface WorkerOutput {
|
|
14
|
+
success: boolean;
|
|
15
|
+
error?: string;
|
|
16
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Command } from "../types.js";
|
|
2
2
|
/** All available built-in command names (excludes network commands) */
|
|
3
|
-
export type CommandName = "echo" | "cat" | "printf" | "ls" | "mkdir" | "rmdir" | "touch" | "rm" | "cp" | "mv" | "ln" | "chmod" | "pwd" | "readlink" | "head" | "tail" | "wc" | "stat" | "grep" | "fgrep" | "egrep" | "rg" | "sed" | "awk" | "sort" | "uniq" | "comm" | "cut" | "paste" | "tr" | "rev" | "nl" | "fold" | "expand" | "unexpand" | "strings" | "split" | "column" | "join" | "tee" | "find" | "basename" | "dirname" | "tree" | "du" | "env" | "printenv" | "alias" | "unalias" | "history" | "xargs" | "true" | "false" | "clear" | "bash" | "sh" | "jq" | "base64" | "diff" | "date" | "sleep" | "timeout" | "seq" | "expr" | "md5sum" | "sha1sum" | "sha256sum" | "file" | "html-to-markdown" | "help" | "which" | "tac" | "hostname" | "od" | "gzip" | "gunzip" | "zcat" | "tar" | "yq" | "xan" | "sqlite3" | "time" | "whoami";
|
|
3
|
+
export type CommandName = "echo" | "cat" | "printf" | "ls" | "mkdir" | "rmdir" | "touch" | "rm" | "cp" | "mv" | "ln" | "chmod" | "pwd" | "readlink" | "head" | "tail" | "wc" | "stat" | "grep" | "fgrep" | "egrep" | "rg" | "sed" | "awk" | "sort" | "uniq" | "comm" | "cut" | "paste" | "tr" | "rev" | "nl" | "fold" | "expand" | "unexpand" | "strings" | "split" | "column" | "join" | "tee" | "find" | "basename" | "dirname" | "tree" | "du" | "env" | "printenv" | "alias" | "unalias" | "history" | "xargs" | "true" | "false" | "clear" | "bash" | "sh" | "jq" | "base64" | "diff" | "date" | "sleep" | "timeout" | "seq" | "expr" | "md5sum" | "sha1sum" | "sha256sum" | "file" | "html-to-markdown" | "help" | "which" | "tac" | "hostname" | "od" | "gzip" | "gunzip" | "zcat" | "tar" | "yq" | "xan" | "sqlite3" | "time" | "whoami" | "python3" | "python";
|
|
4
4
|
/** Network command names (only available when network is configured) */
|
|
5
5
|
export type NetworkCommandName = "curl";
|
|
6
6
|
/** All command names including network commands */
|
package/dist/limits.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ export interface ExecutionLimits {
|
|
|
23
23
|
maxJqIterations?: number;
|
|
24
24
|
/** Maximum sqlite3 query execution time in milliseconds (default: 5000) */
|
|
25
25
|
maxSqliteTimeoutMs?: number;
|
|
26
|
+
/** Maximum Python execution time in milliseconds (default: 30000) */
|
|
27
|
+
maxPythonTimeoutMs?: number;
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
30
|
* Resolve execution limits by merging user-provided limits with defaults.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "just-bash",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"description": "A simulated bash environment with virtual filesystem",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -73,6 +73,7 @@
|
|
|
73
73
|
"minimatch": "^10.1.1",
|
|
74
74
|
"modern-tar": "^0.7.3",
|
|
75
75
|
"papaparse": "^5.5.3",
|
|
76
|
+
"pyodide": "^0.27.0",
|
|
76
77
|
"smol-toml": "^1.6.0",
|
|
77
78
|
"sprintf-js": "^1.1.3",
|
|
78
79
|
"sql.js": "^1.13.0",
|
|
@@ -84,12 +85,13 @@
|
|
|
84
85
|
},
|
|
85
86
|
"packageManager": "pnpm@8.15.9+sha512.499434c9d8fdd1a2794ebf4552b3b25c0a633abcee5bb15e7b5de90f32f47b513aca98cd5cfd001c31f0db454bc3804edccd578501e4ca293a6816166bbd9f81",
|
|
86
87
|
"scripts": {
|
|
87
|
-
"build": "rm -rf dist && tsc && pnpm build:lib && pnpm build:browser && pnpm build:cli && pnpm build:shell && pnpm build:clean && sed '1,/^-->/d' AGENTS.npm.md > dist/AGENTS.md",
|
|
88
|
+
"build": "rm -rf dist && tsc && pnpm build:lib && pnpm build:browser && pnpm build:cli && pnpm build:shell && pnpm build:worker && pnpm build:clean && sed '1,/^-->/d' AGENTS.npm.md > dist/AGENTS.md",
|
|
88
89
|
"build:clean": "find dist -name '*.test.js' -delete && find dist -name '*.test.d.ts' -delete",
|
|
89
|
-
"build:
|
|
90
|
+
"build:worker": "esbuild src/commands/python3/worker.ts --bundle --platform=node --format=esm --outfile=src/commands/python3/worker.js --external:pyodide && cp src/commands/python3/worker.js dist/commands/python3/worker.js && mkdir -p dist/bin/chunks && cp src/commands/python3/worker.js dist/bin/chunks/worker.js && mkdir -p dist/bundle/chunks && cp src/commands/python3/worker.js dist/bundle/chunks/worker.js",
|
|
91
|
+
"build:lib": "esbuild dist/index.js --bundle --splitting --platform=node --format=esm --minify --outdir=dist/bundle --chunk-names=chunks/[name]-[hash] --external:diff --external:minimatch --external:sprintf-js --external:turndown --external:sql.js --external:pyodide --external:@mongodb-js/zstd --external:node-liblzma --external:compressjs",
|
|
90
92
|
"build:browser": "esbuild dist/browser.js --bundle --platform=browser --format=esm --minify --outfile=dist/bundle/browser.js --external:diff --external:minimatch --external:sprintf-js --external:turndown --external:node:* --external:@mongodb-js/zstd --external:node-liblzma --external:compressjs --define:__BROWSER__=true",
|
|
91
|
-
"build:cli": "esbuild dist/cli/just-bash.js --bundle --splitting --platform=node --format=esm --minify --outdir=dist/bin --entry-names=[name] --chunk-names=chunks/[name]-[hash] --banner:js='#!/usr/bin/env node' --external:sql.js --external:@mongodb-js/zstd --external:node-liblzma --external:compressjs",
|
|
92
|
-
"build:shell": "esbuild dist/cli/shell.js --bundle --splitting --platform=node --format=esm --minify --outdir=dist/bin/shell --entry-names=[name] --chunk-names=chunks/[name]-[hash] --banner:js='#!/usr/bin/env node' --external:sql.js --external:@mongodb-js/zstd --external:node-liblzma --external:compressjs",
|
|
93
|
+
"build:cli": "esbuild dist/cli/just-bash.js --bundle --splitting --platform=node --format=esm --minify --outdir=dist/bin --entry-names=[name] --chunk-names=chunks/[name]-[hash] --banner:js='#!/usr/bin/env node' --external:sql.js --external:pyodide --external:@mongodb-js/zstd --external:node-liblzma --external:compressjs",
|
|
94
|
+
"build:shell": "esbuild dist/cli/shell.js --bundle --splitting --platform=node --format=esm --minify --outdir=dist/bin/shell --entry-names=[name] --chunk-names=chunks/[name]-[hash] --banner:js='#!/usr/bin/env node' --external:sql.js --external:pyodide --external:@mongodb-js/zstd --external:node-liblzma --external:compressjs",
|
|
93
95
|
"validate": "pnpm lint && pnpm knip && pnpm typecheck && pnpm build && pnpm test:run && pnpm test:dist",
|
|
94
96
|
"typecheck": "tsc --noEmit",
|
|
95
97
|
"lint": "biome check .",
|