@volter/browser-toolbelt 0.1.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.
Files changed (39) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +9 -0
  3. package/dist/browser-git-filesystem.d.ts +18 -0
  4. package/dist/browser-git-filesystem.d.ts.map +1 -0
  5. package/dist/browser-git-filesystem.js +84 -0
  6. package/dist/browser-git-filesystem.js.map +1 -0
  7. package/dist/browser-git-http.d.ts +32 -0
  8. package/dist/browser-git-http.d.ts.map +1 -0
  9. package/dist/browser-git-http.js +127 -0
  10. package/dist/browser-git-http.js.map +1 -0
  11. package/dist/browser-git.d.ts +38 -0
  12. package/dist/browser-git.d.ts.map +1 -0
  13. package/dist/browser-git.js +514 -0
  14. package/dist/browser-git.js.map +1 -0
  15. package/dist/browser-share-command.d.ts +11 -0
  16. package/dist/browser-share-command.d.ts.map +1 -0
  17. package/dist/browser-share-command.js +59 -0
  18. package/dist/browser-share-command.js.map +1 -0
  19. package/dist/browser-shell-filesystem.d.ts +39 -0
  20. package/dist/browser-shell-filesystem.d.ts.map +1 -0
  21. package/dist/browser-shell-filesystem.js +138 -0
  22. package/dist/browser-shell-filesystem.js.map +1 -0
  23. package/dist/browser-shell.d.ts +38 -0
  24. package/dist/browser-shell.d.ts.map +1 -0
  25. package/dist/browser-shell.js +412 -0
  26. package/dist/browser-shell.js.map +1 -0
  27. package/dist/github-device-auth.d.ts +56 -0
  28. package/dist/github-device-auth.d.ts.map +1 -0
  29. package/dist/github-device-auth.js +157 -0
  30. package/dist/github-device-auth.js.map +1 -0
  31. package/dist/index.d.ts +8 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +8 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/install.d.ts +17 -0
  36. package/dist/install.d.ts.map +1 -0
  37. package/dist/install.js +21 -0
  38. package/dist/install.js.map +1 -0
  39. package/package.json +27 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-share-command.js","sourceRoot":"","sources":["../src/browser-share-command.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { BrowserFileSystem } from "@volter/browser-runtime/browser-filesystem.js";
2
+ import type { BufferEncoding, CpOptions, FileContent, FsStat, IFileSystem, MkdirOptions, RmOptions } from "just-bash/browser";
3
+ interface DirentEntry {
4
+ name: string;
5
+ isFile: boolean;
6
+ isDirectory: boolean;
7
+ isSymbolicLink: boolean;
8
+ }
9
+ /** Live just-bash adapter over the same AlmostNode VFS used by WALI. */
10
+ export declare class BrowserShellFileSystem implements IFileSystem {
11
+ private readonly filesystem;
12
+ constructor(filesystem: BrowserFileSystem);
13
+ readFile(path: string, options?: {
14
+ encoding?: BufferEncoding | null;
15
+ } | BufferEncoding): Promise<string>;
16
+ readFileBuffer(path: string): Promise<Uint8Array>;
17
+ writeFile(path: string, content: FileContent): Promise<void>;
18
+ appendFile(path: string, content: FileContent): Promise<void>;
19
+ exists(path: string): Promise<boolean>;
20
+ stat(path: string): Promise<FsStat>;
21
+ mkdir(path: string, options?: MkdirOptions): Promise<void>;
22
+ readdir(path: string): Promise<string[]>;
23
+ readdirWithFileTypes(path: string): Promise<DirentEntry[]>;
24
+ rm(path: string, options?: RmOptions): Promise<void>;
25
+ cp(source: string, destination: string, options?: CpOptions): Promise<void>;
26
+ mv(source: string, destination: string): Promise<void>;
27
+ resolvePath(base: string, path: string): string;
28
+ getAllPaths(): string[];
29
+ chmod(path: string, mode: number): Promise<void>;
30
+ symlink(_target: string, _path: string): Promise<void>;
31
+ link(_source: string, _path: string): Promise<void>;
32
+ readlink(_path: string): Promise<string>;
33
+ lstat(path: string): Promise<FsStat>;
34
+ realpath(path: string): Promise<string>;
35
+ utimes(path: string, atime: Date, mtime: Date): Promise<void>;
36
+ private assertExists;
37
+ }
38
+ export {};
39
+ //# sourceMappingURL=browser-shell-filesystem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-shell-filesystem.d.ts","sourceRoot":"","sources":["../src/browser-shell-filesystem.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;AAEvF,OAAO,KAAK,EACV,cAAc,EACd,SAAS,EACT,WAAW,EACX,MAAM,EACN,WAAW,EACX,YAAY,EACZ,SAAS,EACV,MAAM,mBAAmB,CAAC;AAE3B,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,wEAAwE;AACxE,qBAAa,sBAAuB,YAAW,WAAW;IAC5C,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAAV,UAAU,EAAE,iBAAiB;IAEpD,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,cAAc,GAAG,IAAI,CAAA;KAAE,GAAG,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;IAOxG,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAIjD,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5D,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAS7D,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAEtC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAanC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1D,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAExC,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAO1D,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAapD,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAU3E,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAC5D,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAE/C,WAAW,IAAI,MAAM,EAAE;IAcjB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhD,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IACtD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IACxC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IACvC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnE,OAAO,CAAC,YAAY;CAGrB"}
@@ -0,0 +1,138 @@
1
+ /** Live just-bash adapter over the same AlmostNode VFS used by WALI. */
2
+ export class BrowserShellFileSystem {
3
+ filesystem;
4
+ constructor(filesystem) {
5
+ this.filesystem = filesystem;
6
+ }
7
+ async readFile(path, options) {
8
+ const encoding = typeof options === "string" ? options : options?.encoding;
9
+ const bytes = this.filesystem.readFileSync(path);
10
+ if (encoding === "binary" || encoding === "latin1")
11
+ return binaryString(bytes);
12
+ return new TextDecoder().decode(bytes);
13
+ }
14
+ async readFileBuffer(path) {
15
+ return this.filesystem.readFileSync(path);
16
+ }
17
+ async writeFile(path, content) {
18
+ this.filesystem.writeFileSync(path, content);
19
+ }
20
+ async appendFile(path, content) {
21
+ const previous = this.filesystem.existsSync(path) ? this.filesystem.readFileSync(path) : new Uint8Array();
22
+ const next = typeof content === "string" ? new TextEncoder().encode(content) : content;
23
+ const combined = new Uint8Array(previous.byteLength + next.byteLength);
24
+ combined.set(previous);
25
+ combined.set(next, previous.byteLength);
26
+ this.filesystem.writeFileSync(path, combined);
27
+ }
28
+ async exists(path) { return this.filesystem.existsSync(path); }
29
+ async stat(path) {
30
+ const value = this.filesystem.statSync(path);
31
+ const executablePackageBin = value.isFile() && path.includes("/node_modules/.bin/");
32
+ return {
33
+ isFile: value.isFile(),
34
+ isDirectory: value.isDirectory(),
35
+ isSymbolicLink: false,
36
+ mode: executablePackageBin ? 0o755 : value.mode ?? (value.isDirectory() ? 0o755 : 0o644),
37
+ size: value.size,
38
+ mtime: new Date(value.mtimeMs ?? Date.now()),
39
+ };
40
+ }
41
+ async mkdir(path, options) {
42
+ this.filesystem.mkdirSync(path, options);
43
+ }
44
+ async readdir(path) { return this.filesystem.readdirSync(path); }
45
+ async readdirWithFileTypes(path) {
46
+ return this.filesystem.readdirSync(path).map((name) => {
47
+ const value = this.filesystem.statSync(join(path, name));
48
+ return { name, isFile: value.isFile(), isDirectory: value.isDirectory(), isSymbolicLink: false };
49
+ });
50
+ }
51
+ async rm(path, options) {
52
+ if (!this.filesystem.existsSync(path)) {
53
+ if (options?.force)
54
+ return;
55
+ throw filesystemError("ENOENT", path);
56
+ }
57
+ const value = this.filesystem.statSync(path);
58
+ if (!value.isDirectory()) {
59
+ this.filesystem.unlinkSync(path);
60
+ return;
61
+ }
62
+ if (options?.recursive) {
63
+ for (const name of this.filesystem.readdirSync(path))
64
+ await this.rm(join(path, name), options);
65
+ }
66
+ this.filesystem.rmdirSync(path);
67
+ }
68
+ async cp(source, destination, options) {
69
+ const value = this.filesystem.statSync(source);
70
+ if (!value.isDirectory()) {
71
+ this.filesystem.writeFileSync(destination, this.filesystem.readFileSync(source));
72
+ return;
73
+ }
74
+ if (!options?.recursive)
75
+ throw filesystemError("EISDIR", source);
76
+ this.filesystem.mkdirSync(destination, { recursive: true });
77
+ for (const name of this.filesystem.readdirSync(source)) {
78
+ await this.cp(join(source, name), join(destination, name), options);
79
+ }
80
+ }
81
+ async mv(source, destination) { this.filesystem.renameSync(source, destination); }
82
+ resolvePath(base, path) { return normalize(path.startsWith("/") ? path : join(base, path)); }
83
+ getAllPaths() {
84
+ const result = [];
85
+ const visit = (directory) => {
86
+ if (!this.filesystem.existsSync(directory) || !this.filesystem.statSync(directory).isDirectory())
87
+ return;
88
+ for (const name of this.filesystem.readdirSync(directory)) {
89
+ const path = join(directory, name);
90
+ result.push(path);
91
+ visit(path);
92
+ }
93
+ };
94
+ visit("/");
95
+ return result;
96
+ }
97
+ async chmod(path, mode) {
98
+ this.assertExists(path);
99
+ this.filesystem.chmodSync(path, mode);
100
+ }
101
+ async symlink(_target, _path) { throw new Error("Symbolic links are not supported."); }
102
+ async link(_source, _path) { throw new Error("Hard links are not supported."); }
103
+ async readlink(_path) { throw new Error("Symbolic links are not supported."); }
104
+ async lstat(path) { return this.stat(path); }
105
+ async realpath(path) { this.assertExists(path); return normalize(path); }
106
+ async utimes(path, atime, mtime) {
107
+ this.assertExists(path);
108
+ this.filesystem.utimesSync(path, atime, mtime);
109
+ }
110
+ assertExists(path) {
111
+ if (!this.filesystem.existsSync(path))
112
+ throw filesystemError("ENOENT", path);
113
+ }
114
+ }
115
+ function join(base, name) { return normalize(`${base}/${name}`); }
116
+ function normalize(value) {
117
+ const parts = [];
118
+ for (const part of `/${value}`.split("/")) {
119
+ if (!part || part === ".")
120
+ continue;
121
+ if (part === "..")
122
+ parts.pop();
123
+ else
124
+ parts.push(part);
125
+ }
126
+ return `/${parts.join("/")}`;
127
+ }
128
+ function filesystemError(code, path) {
129
+ return Object.assign(new Error(`${code}: ${path}`), { code, path });
130
+ }
131
+ function binaryString(bytes) {
132
+ let value = "";
133
+ for (let offset = 0; offset < bytes.byteLength; offset += 0x8000) {
134
+ value += String.fromCharCode(...bytes.subarray(offset, offset + 0x8000));
135
+ }
136
+ return value;
137
+ }
138
+ //# sourceMappingURL=browser-shell-filesystem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-shell-filesystem.js","sourceRoot":"","sources":["../src/browser-shell-filesystem.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import type { BrowserFileSystem } from "@volter/browser-runtime/browser-filesystem.js";
2
+ export interface BrowserShellRunOptions {
3
+ cwd?: string;
4
+ env?: Readonly<Record<string, string>>;
5
+ stdin?: string;
6
+ signal?: AbortSignal;
7
+ onStdout?: (data: string) => void;
8
+ onStderr?: (data: string) => void;
9
+ }
10
+ export interface BrowserShellResult {
11
+ stdout: string;
12
+ stderr: string;
13
+ exitCode: number;
14
+ cwd?: string;
15
+ env?: Readonly<Record<string, string>>;
16
+ }
17
+ export type BrowserShellProgramRunner = (argv: readonly string[], options: BrowserShellRunOptions) => Promise<BrowserShellResult>;
18
+ /** AST Bash, standard toolbelt, and a small persistent browser job table. */
19
+ export declare class BrowserShell {
20
+ private readonly bash;
21
+ private readonly virtualFilesystem;
22
+ private readonly filesystem;
23
+ private readonly jobs;
24
+ private readonly registeredPrograms;
25
+ private readonly streamingRuns;
26
+ private nextPid;
27
+ constructor(filesystem: BrowserFileSystem);
28
+ registerProgram(name: string, runner: BrowserShellProgramRunner): void;
29
+ run(command: string, options?: BrowserShellRunOptions): Promise<BrowserShellResult>;
30
+ terminate(): void;
31
+ private ensureRuntimeDirectories;
32
+ private changeDirectory;
33
+ private runForeground;
34
+ private startBackground;
35
+ private registerJobCommands;
36
+ private registerShellExecutables;
37
+ }
38
+ //# sourceMappingURL=browser-shell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-shell.d.ts","sourceRoot":"","sources":["../src/browser-shell.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;AAMvF,MAAM,WAAW,sBAAsB;IACrC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACxC;AAED,MAAM,MAAM,yBAAyB,GAAG,CACtC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,sBAAsB,KAC5B,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAWjC,6EAA6E;AAC7E,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAO;IAC5B,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAoB;IACtD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyB;IACpD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAiC;IACtD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqB;IACxD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsD;IACpF,OAAO,CAAC,OAAO,CAAQ;gBAEX,UAAU,EAAE,iBAAiB;IAmBzC,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,yBAAyB,GAAG,IAAI;IA4BhE,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA4B7F,SAAS,IAAI,IAAI;IAKjB,OAAO,CAAC,wBAAwB;YAKlB,eAAe;YA2Bf,aAAa;IAoB3B,OAAO,CAAC,eAAe;IA0CvB,OAAO,CAAC,mBAAmB;IAgC3B,OAAO,CAAC,wBAAwB;CA0BjC"}
@@ -0,0 +1,412 @@
1
+ import { Bash, defineCommand } from "just-bash/browser";
2
+ import { BrowserShellFileSystem } from "./browser-shell-filesystem.js";
3
+ /** AST Bash, standard toolbelt, and a small persistent browser job table. */
4
+ export class BrowserShell {
5
+ bash;
6
+ virtualFilesystem;
7
+ filesystem;
8
+ jobs = new Map();
9
+ registeredPrograms = new Set();
10
+ streamingRuns = new WeakMap();
11
+ nextPid = 1000;
12
+ constructor(filesystem) {
13
+ this.virtualFilesystem = filesystem;
14
+ this.filesystem = new BrowserShellFileSystem(filesystem);
15
+ this.ensureRuntimeDirectories();
16
+ this.bash = new Bash({
17
+ fs: this.filesystem,
18
+ cwd: "/",
19
+ env: {
20
+ HOME: "/home/supercode",
21
+ USER: "supercode",
22
+ PATH: "/usr/local/bin:/usr/bin:/bin:/node_modules/.bin",
23
+ NODE_ENV: "development",
24
+ },
25
+ processInfo: { pid: 1, ppid: 0, uid: 1000, gid: 1000 },
26
+ });
27
+ this.registerShellExecutables();
28
+ this.registerJobCommands();
29
+ }
30
+ registerProgram(name, runner) {
31
+ this.registeredPrograms.add(name);
32
+ this.bash.registerCommand(trustedCommand(name, async (args, context) => {
33
+ const streaming = context.signal ? this.streamingRuns.get(context.signal) : undefined;
34
+ let streamedStdout = false;
35
+ let streamedStderr = false;
36
+ const result = await runner([name, ...args], {
37
+ cwd: context.cwd,
38
+ env: Object.fromEntries(context.env),
39
+ stdin: context.stdin,
40
+ ...(context.signal ? { signal: context.signal } : {}),
41
+ ...(streaming?.onStdout ? { onStdout: (data) => {
42
+ streamedStdout = true;
43
+ streaming.onStdout(data);
44
+ } } : {}),
45
+ ...(streaming?.onStderr ? { onStderr: (data) => {
46
+ streamedStderr = true;
47
+ streaming.onStderr(data);
48
+ } } : {}),
49
+ });
50
+ return {
51
+ ...result,
52
+ stdout: streamedStdout ? "" : result.stdout,
53
+ stderr: streamedStderr ? "" : result.stderr,
54
+ };
55
+ }));
56
+ }
57
+ async run(command, options = {}) {
58
+ // Project restoration replaces the VFS contents after the shell is created.
59
+ // Reassert process-owned directories at the command boundary so restores and
60
+ // project resets cannot invalidate the shell environment.
61
+ this.ensureRuntimeDirectories();
62
+ const changedDirectory = await this.changeDirectory(command, options);
63
+ if (changedDirectory)
64
+ return changedDirectory;
65
+ const sequence = splitBackgroundSequence(command);
66
+ if (sequence) {
67
+ const background = this.startBackground(sequence.background, options);
68
+ // A background server commonly registers its port on a microtask. Let
69
+ // that startup settle before the foreground dev server claims its own
70
+ // port so process ownership remains deterministic.
71
+ await new Promise((resolve) => globalThis.setTimeout(resolve, 0));
72
+ const foreground = await this.run(sequence.foreground, options);
73
+ return {
74
+ stdout: `${background.stdout}${foreground.stdout}`,
75
+ stderr: `${background.stderr}${foreground.stderr}`,
76
+ exitCode: foreground.exitCode,
77
+ ...(foreground.cwd ? { cwd: foreground.cwd } : {}),
78
+ ...(foreground.env ? { env: foreground.env } : {}),
79
+ };
80
+ }
81
+ const background = stripBackgroundOperator(command);
82
+ if (background !== undefined)
83
+ return this.startBackground(background, options);
84
+ return this.runForeground(command, options);
85
+ }
86
+ terminate() {
87
+ for (const job of this.jobs.values())
88
+ job.controller.abort(new DOMException("Shell terminated", "AbortError"));
89
+ this.jobs.clear();
90
+ }
91
+ ensureRuntimeDirectories() {
92
+ this.virtualFilesystem.mkdirSync("/tmp", { recursive: true });
93
+ this.virtualFilesystem.mkdirSync("/home/supercode", { recursive: true });
94
+ }
95
+ async changeDirectory(command, options) {
96
+ let words;
97
+ try {
98
+ words = parseWords(command);
99
+ }
100
+ catch {
101
+ return;
102
+ }
103
+ if (words[0] !== "cd")
104
+ return;
105
+ if (words.length > 2)
106
+ return { stdout: "", stderr: "bash: cd: too many arguments\n", exitCode: 1 };
107
+ const current = options.cwd ?? "/";
108
+ const requested = words[1] ?? options.env?.HOME ?? "/home/supercode";
109
+ const destination = this.filesystem.resolvePath(current, requested);
110
+ try {
111
+ const value = await this.filesystem.stat(destination);
112
+ if (!value.isDirectory)
113
+ return { stdout: "", stderr: `bash: cd: ${requested}: Not a directory\n`, exitCode: 1 };
114
+ return {
115
+ stdout: "",
116
+ stderr: "",
117
+ exitCode: 0,
118
+ cwd: destination,
119
+ env: { ...options.env, OLDPWD: current, PWD: destination },
120
+ };
121
+ }
122
+ catch {
123
+ return { stdout: "", stderr: `bash: cd: ${requested}: No such file or directory\n`, exitCode: 1 };
124
+ }
125
+ }
126
+ async runForeground(command, options) {
127
+ if (options.signal?.aborted)
128
+ return { stdout: "", stderr: "", exitCode: 130 };
129
+ const cwd = options.cwd ?? "/";
130
+ try {
131
+ const result = await this.bash.exec(command, {
132
+ cwd,
133
+ env: withNodeModuleBinPath(options.env, cwd),
134
+ ...(options.stdin !== undefined ? { stdin: options.stdin } : {}),
135
+ ...(options.signal ? { signal: options.signal } : {}),
136
+ rawScript: true,
137
+ });
138
+ options.onStdout?.(result.stdout);
139
+ options.onStderr?.(result.stderr);
140
+ return { stdout: result.stdout, stderr: result.stderr, exitCode: result.exitCode, env: result.env };
141
+ }
142
+ catch (cause) {
143
+ if (options.signal?.aborted)
144
+ return { stdout: "", stderr: "", exitCode: 130 };
145
+ return { stdout: "", stderr: `${cause instanceof Error ? cause.message : String(cause)}\n`, exitCode: 1 };
146
+ }
147
+ }
148
+ startBackground(command, options) {
149
+ if (!command)
150
+ return { stdout: "", stderr: "bash: syntax error near unexpected token `&'\n", exitCode: 2 };
151
+ const pid = this.nextPid++;
152
+ const controller = new AbortController();
153
+ const abortWithParent = () => {
154
+ if (!controller.signal.aborted) {
155
+ controller.abort(options.signal?.reason ?? new DOMException("Parent process terminated", "AbortError"));
156
+ }
157
+ };
158
+ if (options.signal?.aborted)
159
+ abortWithParent();
160
+ else
161
+ options.signal?.addEventListener("abort", abortWithParent, { once: true });
162
+ const job = {
163
+ pid,
164
+ command,
165
+ controller,
166
+ state: "running",
167
+ promise: Promise.resolve({ stdout: "", stderr: "", exitCode: 0 }),
168
+ };
169
+ const streamProgram = isSimpleCommand(command)
170
+ && this.registeredPrograms.has(parseWords(command)[0] ?? "");
171
+ if (streamProgram)
172
+ this.streamingRuns.set(controller.signal, options);
173
+ const { onStdout: _onStdout, onStderr: _onStderr, ...jobOptions } = options;
174
+ job.promise = this.runForeground(command, {
175
+ ...jobOptions,
176
+ signal: controller.signal,
177
+ }).then((result) => {
178
+ options.signal?.removeEventListener("abort", abortWithParent);
179
+ job.state = "done";
180
+ job.result = result;
181
+ if (!streamProgram) {
182
+ options.onStdout?.(result.stdout);
183
+ options.onStderr?.(result.stderr);
184
+ }
185
+ options.onStderr?.(`[${pid}] Done (${result.exitCode}) ${command}\n`);
186
+ return result;
187
+ });
188
+ this.jobs.set(pid, job);
189
+ const stdout = `[${pid}] ${pid}\n`;
190
+ options.onStdout?.(stdout);
191
+ return { stdout, stderr: "", exitCode: 0 };
192
+ }
193
+ registerJobCommands() {
194
+ this.bash.registerCommand(trustedCommand("jobs", async () => ({
195
+ stdout: [...this.jobs.values()].map((job) => `[${job.pid}] ${job.state === "running" ? "Running" : "Done"} ${job.command}\n`).join(""),
196
+ stderr: "",
197
+ exitCode: 0,
198
+ })));
199
+ this.bash.registerCommand(trustedCommand("kill", async (args) => {
200
+ const targets = args.filter((arg) => !arg.startsWith("-"));
201
+ if (targets.length === 0)
202
+ return { stdout: "", stderr: "kill: usage: kill PID...\n", exitCode: 2 };
203
+ let stderr = "";
204
+ for (const target of targets) {
205
+ const pid = Number(target.replace(/^%/u, ""));
206
+ const job = this.jobs.get(pid);
207
+ if (!job || job.state !== "running")
208
+ stderr += `kill: (${target}) - No such process\n`;
209
+ else
210
+ job.controller.abort(new DOMException("Terminated", "AbortError"));
211
+ }
212
+ return { stdout: "", stderr, exitCode: stderr ? 1 : 0 };
213
+ }));
214
+ this.bash.registerCommand(trustedCommand("wait", async (args) => {
215
+ const selected = args.length === 0
216
+ ? [...this.jobs.values()]
217
+ : args.map((arg) => this.jobs.get(Number(arg.replace(/^%/u, "")))).filter((job) => !!job);
218
+ if (args.length > 0 && selected.length !== args.length) {
219
+ return { stdout: "", stderr: "wait: pid is not a child of this shell\n", exitCode: 127 };
220
+ }
221
+ const results = await Promise.all(selected.map((job) => job.promise));
222
+ for (const job of selected)
223
+ this.jobs.delete(job.pid);
224
+ return { stdout: "", stderr: "", exitCode: results.at(-1)?.exitCode ?? 0 };
225
+ }));
226
+ }
227
+ registerShellExecutables() {
228
+ for (const name of ["bash", "sh", "zsh"]) {
229
+ this.bash.registerCommand(trustedCommand(name, async (args, context) => {
230
+ if (args.includes("--version")) {
231
+ return {
232
+ // Native harnesses use this as an executability probe and often
233
+ // attach null stdio. Success is the contract; keeping it silent
234
+ // also avoids leaking a detached probe into the parent terminal.
235
+ stdout: "",
236
+ stderr: "",
237
+ exitCode: 0,
238
+ };
239
+ }
240
+ const commandIndex = args.findIndex((argument) => argument === "-c" || argument.endsWith("lc") || argument.endsWith("ilc"));
241
+ const script = commandIndex >= 0 ? args[commandIndex + 1] : context.stdin;
242
+ if (!script)
243
+ return { stdout: "", stderr: "", exitCode: 0 };
244
+ return this.bash.exec(script, {
245
+ cwd: context.cwd,
246
+ env: Object.fromEntries(context.env),
247
+ ...(context.signal ? { signal: context.signal } : {}),
248
+ rawScript: true,
249
+ });
250
+ }));
251
+ }
252
+ }
253
+ }
254
+ function withNodeModuleBinPath(environment, cwd) {
255
+ const executableDirectories = [];
256
+ let directory = normalizeShellPath(cwd);
257
+ for (;;) {
258
+ executableDirectories.push(`${directory === "/" ? "" : directory}/node_modules/.bin`);
259
+ if (directory === "/")
260
+ break;
261
+ directory = directory.slice(0, directory.lastIndexOf("/")) || "/";
262
+ }
263
+ const inherited = environment?.PATH ?? "/usr/local/bin:/usr/bin:/bin";
264
+ const path = [...new Set([...executableDirectories, ...inherited.split(":").filter(Boolean)])].join(":");
265
+ return { ...environment, PATH: path };
266
+ }
267
+ function normalizeShellPath(value) {
268
+ const parts = [];
269
+ for (const part of `/${value}`.split("/")) {
270
+ if (!part || part === ".")
271
+ continue;
272
+ if (part === "..")
273
+ parts.pop();
274
+ else
275
+ parts.push(part);
276
+ }
277
+ return `/${parts.join("/")}`;
278
+ }
279
+ function splitBackgroundSequence(command) {
280
+ let quote = "";
281
+ let escaped = false;
282
+ for (let index = 0; index < command.length; index += 1) {
283
+ const character = command[index];
284
+ if (escaped) {
285
+ escaped = false;
286
+ continue;
287
+ }
288
+ if (character === "\\" && quote !== "'") {
289
+ escaped = true;
290
+ continue;
291
+ }
292
+ if (quote) {
293
+ if (character === quote)
294
+ quote = "";
295
+ continue;
296
+ }
297
+ if (character === "'" || character === '"') {
298
+ quote = character;
299
+ continue;
300
+ }
301
+ if (character !== "&" || command[index - 1] === "&" || command[index + 1] === "&"
302
+ || command[index - 1] === ">" || !/\s/u.test(command[index - 1] ?? "")
303
+ || !/\s/u.test(command[index + 1] ?? ""))
304
+ continue;
305
+ const background = command.slice(0, index).trim();
306
+ const foreground = command.slice(index + 1).trim();
307
+ if (background && foreground)
308
+ return { background, foreground };
309
+ }
310
+ return;
311
+ }
312
+ function stripBackgroundOperator(command) {
313
+ const value = command.trimEnd();
314
+ if (!value.endsWith("&") || value.endsWith("&&"))
315
+ return;
316
+ let quote = "";
317
+ let escaped = false;
318
+ for (let index = 0; index < value.length - 1; index += 1) {
319
+ const character = value[index];
320
+ if (escaped) {
321
+ escaped = false;
322
+ continue;
323
+ }
324
+ if (character === "\\" && quote !== "'") {
325
+ escaped = true;
326
+ continue;
327
+ }
328
+ if (quote) {
329
+ if (character === quote)
330
+ quote = "";
331
+ continue;
332
+ }
333
+ if (character === "'" || character === '"')
334
+ quote = character;
335
+ }
336
+ if (quote || escaped)
337
+ return;
338
+ return value.slice(0, -1).trimEnd();
339
+ }
340
+ function isSimpleCommand(command) {
341
+ let quote = "";
342
+ let escaped = false;
343
+ for (const character of command) {
344
+ if (escaped) {
345
+ escaped = false;
346
+ continue;
347
+ }
348
+ if (character === "\\" && quote !== "'") {
349
+ escaped = true;
350
+ continue;
351
+ }
352
+ if (quote) {
353
+ if (character === quote)
354
+ quote = "";
355
+ continue;
356
+ }
357
+ if (character === "'" || character === '"') {
358
+ quote = character;
359
+ continue;
360
+ }
361
+ if (/[|&;<>]/u.test(character))
362
+ return false;
363
+ }
364
+ return true;
365
+ }
366
+ function parseWords(command) {
367
+ const words = [];
368
+ let word = "";
369
+ let quote = "";
370
+ let escaped = false;
371
+ for (const character of command.trim()) {
372
+ if (escaped) {
373
+ word += character;
374
+ escaped = false;
375
+ continue;
376
+ }
377
+ if (character === "\\" && quote !== "'") {
378
+ escaped = true;
379
+ continue;
380
+ }
381
+ if (quote) {
382
+ if (character === quote)
383
+ quote = "";
384
+ else
385
+ word += character;
386
+ continue;
387
+ }
388
+ if (character === "'" || character === '"') {
389
+ quote = character;
390
+ continue;
391
+ }
392
+ if (/\s/u.test(character)) {
393
+ if (word) {
394
+ words.push(word);
395
+ word = "";
396
+ }
397
+ continue;
398
+ }
399
+ if (/[|&;<>]/u.test(character))
400
+ throw new Error("Compound command");
401
+ word += character;
402
+ }
403
+ if (quote || escaped)
404
+ throw new Error("Unterminated quoting");
405
+ if (word)
406
+ words.push(word);
407
+ return words;
408
+ }
409
+ function trustedCommand(name, execute) {
410
+ return { ...defineCommand(name, execute), trusted: true };
411
+ }
412
+ //# sourceMappingURL=browser-shell.js.map