typescript-virtual-container 1.5.0 → 1.5.1
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 +32 -18
- package/builds/{self-standalone.mjs → fortune-nyx-v1.5.1-directbash-k6.1.0.mjs} +18 -18
- package/builds/{standalone-wo-sftp.js → fortune-nyx-v1.5.1-ssh-nosftp.js} +20 -20
- package/builds/{standalone.cjs → fortune-nyx-v1.5.1-ssh.cjs} +11 -11
- package/dist/VirtualFileSystem/journal.d.ts.map +1 -1
- package/dist/VirtualFileSystem/journal.js +3 -1
- package/dist/VirtualFileSystem/journal.js.map +1 -1
- package/docs/classes/HoneyPot.html +9 -9
- package/docs/classes/IdleManager.html +8 -8
- package/docs/classes/SshClient.html +18 -18
- package/docs/classes/VirtualFileSystem.html +34 -34
- package/docs/classes/VirtualPackageManager.html +13 -13
- package/docs/classes/VirtualSftpServer.html +3 -3
- package/docs/classes/VirtualShell.html +28 -28
- package/docs/classes/VirtualSshServer.html +5 -5
- package/docs/classes/VirtualUserManager.html +27 -27
- package/docs/functions/assertDiff.html +2 -2
- package/docs/functions/diffSnapshots.html +2 -2
- package/docs/functions/formatDiff.html +2 -2
- package/docs/functions/getArg.html +2 -2
- package/docs/functions/getFlag.html +2 -2
- package/docs/functions/ifFlag.html +2 -2
- package/docs/hierarchy.html +1 -1
- package/docs/index.html +34 -30
- package/docs/interfaces/AuditLogEntry.html +3 -3
- package/docs/interfaces/CommandContext.html +12 -12
- package/docs/interfaces/CommandResult.html +13 -13
- package/docs/interfaces/ExecStream.html +6 -6
- package/docs/interfaces/HoneyPotStats.html +3 -3
- package/docs/interfaces/IdleManagerOptions.html +3 -3
- package/docs/interfaces/InstalledPackage.html +11 -11
- package/docs/interfaces/NanoEditorSession.html +5 -5
- package/docs/interfaces/PackageDefinition.html +14 -14
- package/docs/interfaces/PackageFile.html +5 -5
- package/docs/interfaces/PasswordChallenge.html +9 -9
- package/docs/interfaces/RemoveOptions.html +3 -3
- package/docs/interfaces/ShellEnv.html +4 -4
- package/docs/interfaces/ShellModule.html +8 -8
- package/docs/interfaces/ShellProperties.html +5 -5
- package/docs/interfaces/ShellStream.html +7 -7
- package/docs/interfaces/SudoChallenge.html +9 -9
- package/docs/interfaces/VfsBaseNode.html +7 -7
- package/docs/interfaces/VfsDiff.html +6 -6
- package/docs/interfaces/VfsDiffEntry.html +4 -4
- package/docs/interfaces/VfsDiffModified.html +6 -6
- package/docs/interfaces/VfsDirectoryNode.html +8 -8
- package/docs/interfaces/VfsFileNode.html +9 -9
- package/docs/interfaces/VfsOptions.html +6 -6
- package/docs/interfaces/VfsSnapshot.html +3 -3
- package/docs/interfaces/VfsSnapshotBaseNode.html +4 -4
- package/docs/interfaces/VfsSnapshotDirectoryNode.html +5 -5
- package/docs/interfaces/VfsSnapshotFileNode.html +6 -6
- package/docs/interfaces/VirtualActiveSession.html +7 -7
- package/docs/interfaces/VirtualSftpServerOptions.html +3 -3
- package/docs/interfaces/VirtualShellVfsLike.html +3 -3
- package/docs/interfaces/VirtualShellVfsOptions.html +3 -3
- package/docs/interfaces/WriteFileOptions.html +4 -4
- package/docs/modules.html +1 -1
- package/docs/types/ArgParseOptions.html +3 -3
- package/docs/types/CommandMode.html +2 -2
- package/docs/types/CommandOutcome.html +2 -2
- package/docs/types/IdleState.html +1 -1
- package/docs/types/VfsNodeStats.html +2 -2
- package/docs/types/VfsNodeType.html +2 -2
- package/docs/types/VfsPersistenceMode.html +2 -2
- package/docs/types/VfsSnapshotNode.html +2 -2
- package/package.json +5 -4
- package/scripts/build-all.mjs +198 -0
- package/scripts/build-names.mjs +44 -0
- package/src/VirtualFileSystem/journal.ts +3 -1
- /package/builds/{web-full-api.min.js → fortune-nyx-v1.5.1-web-full.min.js} +0 -0
- /package/builds/{web.min.js → fortune-nyx-v1.5.1-web.min.js} +0 -0
package/README.md
CHANGED
|
@@ -54,8 +54,12 @@
|
|
|
54
54
|
| Mode | Entry point | Use case |
|
|
55
55
|
|------|-------------|----------|
|
|
56
56
|
| **SSH/SFTP server** | `VirtualSshServer` / `VirtualSftpServer` | Honeypots, remote testing, training environments |
|
|
57
|
-
| **Web shell** |
|
|
58
|
-
|
|
57
|
+
| **Web shell** | <!-- BUILD:web -->
|
|
58
|
+
`builds/fortune-nyx-v1.5.1-web.min.js` / `builds/fortune-nyx-v1.5.1-web-full.min.js`
|
|
59
|
+
<!-- /BUILD:web --> (ESM) | Embedded terminals, interactive tutorials, browser demos |
|
|
60
|
+
| **Standalone CLI** | <!-- BUILD:selfStandalone -->
|
|
61
|
+
`builds/fortune-nyx-v1.5.1-directbash-k6.1.0.mjs`
|
|
62
|
+
<!-- /BUILD:selfStandalone --> (single file) | Local shell, one-liner demos, no install required |
|
|
59
63
|
|
|
60
64
|
All three modes share the same core: a pure in-memory VFS, a real shell interpreter, a virtual package manager, and a typed programmatic API.
|
|
61
65
|
|
|
@@ -73,27 +77,31 @@ npm install typescript-virtual-container
|
|
|
73
77
|
### Try instantly (zero install)
|
|
74
78
|
|
|
75
79
|
```bash
|
|
80
|
+
<!-- BUILD:curl-start -->
|
|
76
81
|
# Interactive local shell — persists VFS in .vfs/ in the current directory
|
|
77
|
-
curl -s https://raw.githubusercontent.com/itsrealfortune/typescript-virtual-container/refs/heads/main/builds/
|
|
82
|
+
curl -s https://raw.githubusercontent.com/itsrealfortune/typescript-virtual-container/refs/heads/main/builds/fortune-nyx-v1.5.0-directbash-k6.1.0.mjs -o fortune-nyx-directbash.mjs && node fortune-nyx-directbash.mjs && rm -f fortune-nyx-directbash.mjs
|
|
78
83
|
|
|
79
84
|
# SSH server (connect with any SSH client on port 2222)
|
|
80
|
-
curl -s https://raw.githubusercontent.com/itsrealfortune/typescript-virtual-container/refs/heads/main/builds/
|
|
85
|
+
curl -s https://raw.githubusercontent.com/itsrealfortune/typescript-virtual-container/refs/heads/main/builds/fortune-nyx-v1.5.0-ssh.cjs -o fortune-nyx-ssh.cjs && node fortune-nyx-ssh.cjs && rm -f fortune-nyx-ssh.cjs
|
|
81
86
|
|
|
82
87
|
# SSH server without SFTP (lighter build)
|
|
83
|
-
curl -s https://raw.githubusercontent.com/itsrealfortune/typescript-virtual-container/refs/heads/main/builds/
|
|
88
|
+
curl -s https://raw.githubusercontent.com/itsrealfortune/typescript-virtual-container/refs/heads/main/builds/fortune-nyx-v1.5.0-ssh-nosftp.js -o fortune-nyx-ssh-nosftp.js && node fortune-nyx-ssh-nosftp.js && rm -f fortune-nyx-ssh-nosftp.js
|
|
89
|
+
<!-- BUILD:curl-end -->
|
|
84
90
|
```
|
|
85
91
|
|
|
86
92
|
> [!NOTE]
|
|
87
93
|
> The standalone builds are intended for quick demos and testing. For production use, it's recommended to install the package and import the relevant classes directly in your codebase for better performance, stability, and security.
|
|
88
94
|
|
|
89
|
-
|
|
95
|
+
<!-- BUILD:selfStandalone-options -->
|
|
96
|
+
**`fortune-nyx-v1.5.1-directbash-k6.1.0.mjs` options:**
|
|
90
97
|
|
|
91
98
|
```bash
|
|
92
|
-
node
|
|
93
|
-
node
|
|
94
|
-
node
|
|
95
|
-
SSH_MIMIC_HOSTNAME=my-box node
|
|
99
|
+
node fortune-nyx-v1.5.1-directbash-k6.1.0.mjs # boot as root
|
|
100
|
+
node fortune-nyx-v1.5.1-directbash-k6.1.0.mjs --user alice # boot as alice (prompts for password if set)
|
|
101
|
+
node fortune-nyx-v1.5.1-directbash-k6.1.0.mjs --user=alice # same, inline form
|
|
102
|
+
SSH_MIMIC_HOSTNAME=my-box node fortune-nyx-v1.5.1-directbash-k6.1.0.mjs # custom hostname
|
|
96
103
|
```
|
|
104
|
+
<!-- /BUILD:selfStandalone-options -->
|
|
97
105
|
|
|
98
106
|
The VFS is persisted automatically to `.vfs/vfs-snapshot.vfsb` in the current directory — state survives between runs. Delete `.vfs/` to start fresh.
|
|
99
107
|
|
|
@@ -115,8 +123,10 @@ Two browser bundles are available:
|
|
|
115
123
|
|
|
116
124
|
| Bundle | Format | Entry point | Use case |
|
|
117
125
|
|--------|--------|-------------|----------|
|
|
118
|
-
|
|
119
|
-
| `builds/
|
|
126
|
+
<!-- BUILD:web-table -->
|
|
127
|
+
| `builds/fortune-nyx-v1.5.1-web.min.js` | ESM | `createWebShell()` | Embedded terminals, modern bundlers |
|
|
128
|
+
| `builds/fortune-nyx-v1.5.1-web-full.min.js` | ESM | `createVirtualShellShim()` | Full `VirtualShell`-like API in the browser |
|
|
129
|
+
<!-- /BUILD:web-table -->
|
|
120
130
|
|
|
121
131
|
Both bundles persist the VFS in **IndexedDB** — state survives page reloads.
|
|
122
132
|
|
|
@@ -126,11 +136,12 @@ bun run web-full-build # → builds/web-full-api.min.js
|
|
|
126
136
|
bun run build-all # rebuild everything
|
|
127
137
|
```
|
|
128
138
|
|
|
129
|
-
|
|
139
|
+
<!-- BUILD:web-options -->
|
|
140
|
+
**`fortune-nyx-v1.5.1-web.min.js`** — lightweight shell with IndexedDB VFS:
|
|
130
141
|
|
|
131
142
|
```html
|
|
132
143
|
<script type="module">
|
|
133
|
-
import { createWebShell } from "./builds/web.min.js";
|
|
144
|
+
import { createWebShell } from "./builds/fortune-nyx-v1.5.1-web.min.js";
|
|
134
145
|
|
|
135
146
|
const shell = createWebShell("web-vm", {
|
|
136
147
|
vfs: { databaseName: "virtual-env-js", storeName: "vfs" },
|
|
@@ -142,11 +153,11 @@ bun run build-all # rebuild everything
|
|
|
142
153
|
</script>
|
|
143
154
|
```
|
|
144
155
|
|
|
145
|
-
**`web-full
|
|
156
|
+
**`fortune-nyx-v1.5.1-web-full.min.js`** — mirrors the `VirtualShell` programmatic API:
|
|
146
157
|
|
|
147
158
|
```html
|
|
148
159
|
<script type="module">
|
|
149
|
-
import { createVirtualShellShim } from "./builds/web-full
|
|
160
|
+
import { createVirtualShellShim } from "./builds/fortune-nyx-v1.5.1-web-full.min.js";
|
|
150
161
|
|
|
151
162
|
const shell = createVirtualShellShim("web-vm");
|
|
152
163
|
await shell.ensureInitialized();
|
|
@@ -154,6 +165,7 @@ bun run build-all # rebuild everything
|
|
|
154
165
|
console.log(shell.getVfs().readFile("/app/file.txt")); // hello
|
|
155
166
|
</script>
|
|
156
167
|
```
|
|
168
|
+
<!-- /BUILD:web-options -->
|
|
157
169
|
|
|
158
170
|
**Run the demo locally:**
|
|
159
171
|
|
|
@@ -1634,8 +1646,10 @@ Open:
|
|
|
1634
1646
|
- [x] `/proc/self` and `/proc/<pid>` per-session entries
|
|
1635
1647
|
- [x] Snapshot diff tooling — `diffSnapshots`, `formatDiff`, `assertDiff`
|
|
1636
1648
|
- [x] `node`/`python3`/`npm`/`npx` — package-gated virtual REPL stubs
|
|
1637
|
-
|
|
1638
|
-
- [x]
|
|
1649
|
+
<!-- BUILD:changelog -->
|
|
1650
|
+
- [x] Web shell bundles (`fortune-nyx-v1.5.1-web.min.js`, `fortune-nyx-v1.5.1-web-full.min.js`) — fully browser-native with IndexedDB VFS
|
|
1651
|
+
- [x] Self-standalone CLI (`fortune-nyx-v1.5.1-directbash-k6.1.0.mjs`) — single-file interactive shell, per-user history, tab completion
|
|
1652
|
+
<!-- /BUILD:changelog -->
|
|
1639
1653
|
- [x] 120+ `man` pages — all built-in commands documented via `man <cmd>`
|
|
1640
1654
|
- [x] Shared `tokenize.ts` — unified tokenizer for shell parser and runtime (eliminates duplication)
|
|
1641
1655
|
- [x] `PasswordChallenge` type — generic interactive password flow for `adduser`, `passwd`, `deluser`
|
|
@@ -964,17 +964,17 @@ Hint: install it with: apt install npm
|
|
|
964
964
|
`),exitCode:0}}};function _i(e,t){let n=0,r="",i=0;for(;i<e.length;){if(e[i]==="\\"&&i+1<e.length)switch(e[i+1]){case"n":r+=`
|
|
965
965
|
`,i+=2;continue;case"t":r+=" ",i+=2;continue;case"r":r+="\r",i+=2;continue;case"\\":r+="\\",i+=2;continue;case"a":r+="\x07",i+=2;continue;case"b":r+="\b",i+=2;continue;case"f":r+="\f",i+=2;continue;case"v":r+="\v",i+=2;continue;default:r+=e[i],i++;continue}if(e[i]==="%"&&i+1<e.length){let s=i+1,o=!1;e[s]==="-"&&(o=!0,s++);let a=!1;e[s]==="0"&&(a=!0,s++);let l=0;for(;s<e.length&&/\d/.test(e[s]);)l=l*10+parseInt(e[s],10),s++;let c=-1;if(e[s]===".")for(s++,c=0;s<e.length&&/\d/.test(e[s]);)c=c*10+parseInt(e[s],10),s++;let u=e[s],d=t[n++]??"",p=(m,g=" ")=>{if(l<=0||m.length>=l)return m;let S=g.repeat(l-m.length);return o?m+S:S+m};switch(u){case"s":{let m=String(d);c>=0&&(m=m.slice(0,c)),r+=p(m);break}case"d":case"i":r+=p(String(parseInt(d,10)||0),a?"0":" ");break;case"f":{let m=c>=0?c:6;r+=p((parseFloat(d)||0).toFixed(m));break}case"o":r+=p((parseInt(d,10)||0).toString(8),a?"0":" ");break;case"x":r+=p((parseInt(d,10)||0).toString(16),a?"0":" ");break;case"X":r+=p((parseInt(d,10)||0).toString(16).toUpperCase(),a?"0":" ");break;case"%":r+="%",n--;break;default:r+=e[i],i++;continue}i=s+1;continue}r+=e[i],i++}return r}var Pr={name:"printf",description:"Format and print data",category:"shell",params:["<format> [args...]"],run:({args:e})=>{let t=e[0];return t?{stdout:_i(t,e.slice(1)),exitCode:0}:{stderr:"printf: missing format string",exitCode:1}}};var $r={name:"ps",description:"Report process status",category:"system",params:["[-a] [-u] [-x] [aux]"],run:({authUser:e,shell:t,args:n})=>{let r=t.users.listActiveSessions(),i=v(n,["-u"])||n.includes("u")||n.includes("aux")||n.includes("au"),s=v(n,["-a","-x"])||n.includes("a")||n.includes("aux");if(i){let u=["USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND"],d=1e3;for(let p of r){let m=p.username.padEnd(10).slice(0,10),g=(Math.random()*.5).toFixed(1),S=Math.floor(Math.random()*2e4+5e3),C=Math.floor(Math.random()*5e3+1e3);u.push(`${m} ${String(d).padStart(6)} 0.0 ${g.padStart(4)} ${String(S).padStart(6)} ${String(C).padStart(5)} ${p.tty.padEnd(8)} Ss 00:00 0:00 bash`),d++}return u.push(`root ${String(d).padStart(6)} 0.0 0.0 0 0 ? S 00:00 0:00 ps`),{stdout:u.join(`
|
|
966
966
|
`),exitCode:0}}let a=[" PID TTY TIME CMD"],l=1e3;for(let c of r)!s&&c.username!==e||(a.push(`${String(l).padStart(5)} ${c.tty.padEnd(12)} 00:00:00 ${c.username===e?"bash":`bash (${c.username})`}`),l++);return a.push(`${String(l).padStart(5)} pts/0 00:00:00 ps`),{stdout:a.join(`
|
|
967
|
-
`),exitCode:0}}};var kr={name:"pwd",description:"Print working directory",category:"navigation",params:[],run:({cwd:e})=>({stdout:e,exitCode:0})};var Oi="Python 3.11.2";var ct="3.11.2 (default, Mar 13 2023, 12:18:29) [GCC 12.2.0]",y={__pytype__:"none"};function J(e=[]){return{__pytype__:"dict",data:new Map(e)}}function Ot(e,t,n=1){return{__pytype__:"range",start:e,stop:t,step:n}}function Y(e){return!!e&&typeof e=="object"&&!Array.isArray(e)&&e.__pytype__==="dict"}function Le(e){return!!e&&typeof e=="object"&&!Array.isArray(e)&&e.__pytype__==="range"}function xe(e){return!!e&&typeof e=="object"&&!Array.isArray(e)&&e.__pytype__==="func"}function Tt(e){return!!e&&typeof e=="object"&&!Array.isArray(e)&&e.__pytype__==="class"}function je(e){return!!e&&typeof e=="object"&&!Array.isArray(e)&&e.__pytype__==="instance"}function Pe(e){return!!e&&typeof e=="object"&&!Array.isArray(e)&&e.__pytype__==="none"}function
|
|
967
|
+
`),exitCode:0}}};var kr={name:"pwd",description:"Print working directory",category:"navigation",params:[],run:({cwd:e})=>({stdout:e,exitCode:0})};var Oi="Python 3.11.2";var ct="3.11.2 (default, Mar 13 2023, 12:18:29) [GCC 12.2.0]",y={__pytype__:"none"};function J(e=[]){return{__pytype__:"dict",data:new Map(e)}}function Ot(e,t,n=1){return{__pytype__:"range",start:e,stop:t,step:n}}function Y(e){return!!e&&typeof e=="object"&&!Array.isArray(e)&&e.__pytype__==="dict"}function Le(e){return!!e&&typeof e=="object"&&!Array.isArray(e)&&e.__pytype__==="range"}function xe(e){return!!e&&typeof e=="object"&&!Array.isArray(e)&&e.__pytype__==="func"}function Tt(e){return!!e&&typeof e=="object"&&!Array.isArray(e)&&e.__pytype__==="class"}function je(e){return!!e&&typeof e=="object"&&!Array.isArray(e)&&e.__pytype__==="instance"}function Pe(e){return!!e&&typeof e=="object"&&!Array.isArray(e)&&e.__pytype__==="none"}function ne(e){return e===null||Pe(e)?"None":e===!0?"True":e===!1?"False":typeof e=="number"?Number.isInteger(e)?String(e):e.toPrecision(12).replace(/\.?0+$/,""):typeof e=="string"?`'${e.replace(/'/g,"\\'")}'`:Array.isArray(e)?`[${e.map(ne).join(", ")}]`:Y(e)?`{${[...e.data.entries()].map(([t,n])=>`'${t}': ${ne(n)}`).join(", ")}}`:Le(e)?`range(${e.start}, ${e.stop}${e.step!==1?`, ${e.step}`:""})`:xe(e)?`<function ${e.name} at 0x...>`:Tt(e)?`<class '${e.name}'>`:je(e)?`<${e.cls.name} object at 0x...>`:String(e)}function R(e){return e===null||Pe(e)?"None":e===!0?"True":e===!1?"False":typeof e=="number"?Number.isInteger(e)?String(e):e.toPrecision(12).replace(/\.?0+$/,""):typeof e=="string"?e:Array.isArray(e)?`[${e.map(ne).join(", ")}]`:Y(e)?`{${[...e.data.entries()].map(([t,n])=>`'${t}': ${ne(n)}`).join(", ")}}`:Le(e)?`range(${e.start}, ${e.stop}${e.step!==1?`, ${e.step}`:""})`:ne(e)}function pe(e){return e===null||Pe(e)?!1:typeof e=="boolean"?e:typeof e=="number"?e!==0:typeof e=="string"||Array.isArray(e)?e.length>0:Y(e)?e.data.size>0:Le(e)?Nr(e)>0:!0}function Nr(e){if(e.step===0)return 0;let t=Math.ceil((e.stop-e.start)/e.step);return Math.max(0,t)}function Ti(e){let t=[];for(let n=e.start;(e.step>0?n<e.stop:n>e.stop)&&(t.push(n),!(t.length>1e4));n+=e.step);return t}function te(e){if(Array.isArray(e))return e;if(typeof e=="string")return[...e];if(Le(e))return Ti(e);if(Y(e))return[...e.data.keys()];throw new K("TypeError",`'${Ie(e)}' object is not iterable`)}function Ie(e){return e===null||Pe(e)?"NoneType":typeof e=="boolean"?"bool":typeof e=="number"?Number.isInteger(e)?"int":"float":typeof e=="string"?"str":Array.isArray(e)?"list":Y(e)?"dict":Le(e)?"range":xe(e)?"function":Tt(e)?"type":je(e)?e.cls.name:"object"}var K=class{constructor(t,n){this.type=t;this.message=n}type;message;toString(){return`${this.type}: ${this.message}`}},De=class{constructor(t){this.value=t}value},We=class{},He=class{},qe=class{constructor(t){this.code=t}code};function Fi(e){let t=new Map,n=J([["sep","/"],["linesep",`
|
|
968
968
|
`],["curdir","."],["pardir",".."]]);return n.__methods__={getcwd:()=>e,getenv:r=>typeof r=="string"?process.env[r]??y:y,path:J([["join",y],["exists",y],["dirname",y],["basename",y]]),listdir:()=>[]},t.set("__builtins__",y),t.set("__name__","__main__"),t.set("__cwd__",e),t}function Ri(e){let t=J([["sep","/"],["curdir","."]]),n=J([["sep","/"],["linesep",`
|
|
969
969
|
`],["name","posix"]]);return n._cwd=e,t._cwd=e,n.path=t,n}function Di(){return J([["version",ct],["version_info",J([["major",3],["minor",11],["micro",2]].map(([e,t])=>[e,t]))],["platform","linux"],["executable","/usr/bin/python3"],["prefix","/usr"],["path",["/usr/lib/python3.11","/usr/lib/python3.11/lib-dynload"]],["argv",[""]],["maxsize",9007199254740991]])}function Li(){return J([["pi",Math.PI],["e",Math.E],["tau",Math.PI*2],["inf",1/0],["nan",NaN],["sqrt",y],["floor",y],["ceil",y],["log",y],["pow",y],["sin",y],["cos",y],["tan",y],["fabs",y],["factorial",y]])}function Ui(){return J([["dumps",y],["loads",y]])}function Vi(){return J([["match",y],["search",y],["findall",y],["sub",y],["split",y],["compile",y]])}var Mr={os:Ri,sys:()=>Di(),math:()=>Li(),json:()=>Ui(),re:()=>Vi(),random:()=>J([["random",y],["randint",y],["choice",y],["shuffle",y]]),time:()=>J([["time",y],["sleep",y],["ctime",y]]),datetime:()=>J([["datetime",y],["date",y],["timedelta",y]]),collections:()=>J([["Counter",y],["defaultdict",y],["OrderedDict",y]]),itertools:()=>J([["chain",y],["product",y],["combinations",y],["permutations",y]]),functools:()=>J([["reduce",y],["partial",y],["lru_cache",y]]),string:()=>J([["ascii_letters","abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"],["digits","0123456789"],["punctuation","!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"]])},ut=class{constructor(t){this.cwd=t}cwd;output=[];stderr=[];modules=new Map;getOutput(){return this.output.join(`
|
|
970
970
|
`)+(this.output.length?`
|
|
971
971
|
`:"")}getStderr(){return this.stderr.join(`
|
|
972
972
|
`)+(this.stderr.length?`
|
|
973
973
|
`:"")}splitArgs(t){let n=[],r=0,i="",s=!1,o="";for(let a=0;a<t.length;a++){let l=t[a];s?(i+=l,l===o&&t[a-1]!=="\\"&&(s=!1)):l==='"'||l==="'"?(s=!0,o=l,i+=l):"([{".includes(l)?(r++,i+=l):")]}".includes(l)?(r--,i+=l):l===","&&r===0?(n.push(i.trim()),i=""):i+=l}return i.trim()&&n.push(i.trim()),n}pyEval(t,n){if(t=t.trim(),!t||t==="None")return y;if(t==="True")return!0;if(t==="False")return!1;if(t==="...")return y;if(/^-?\d+$/.test(t))return parseInt(t,10);if(/^-?\d+\.\d*$/.test(t))return parseFloat(t);if(/^0x[0-9a-fA-F]+$/.test(t))return parseInt(t,16);if(/^0o[0-7]+$/.test(t))return parseInt(t.slice(2),8);if(/^('''[\s\S]*'''|"""[\s\S]*""")$/.test(t))return t.slice(3,-3);if(/^(['"])(.*)\1$/s.test(t))return t.slice(1,-1).replace(/\\n/g,`
|
|
974
|
-
`).replace(/\\t/g," ").replace(/\\r/g,"\r").replace(/\\\\/g,"\\").replace(/\\'/g,"'").replace(/\\"/g,'"');let r=t.match(/^f(['"])([\s\S]*)\1$/);if(r){let c=r[2];return c=c.replace(/\{([^{}]+)\}/g,(u,d)=>{try{return R(this.pyEval(d.trim(),n))}catch{return`{${d}}`}}),c}let i=t.match(/^b(['"])(.*)\1$/s);if(i)return i[2];if(t.startsWith("[")&&t.endsWith("]")){let c=t.slice(1,-1).trim();if(!c)return[];let u=c.match(/^(.+?)\s+for\s+(\w+)\s+in\s+(.+?)(?:\s+if\s+(.+))?$/);if(u){let[,d,p,m,g]=u,S=
|
|
975
|
-
`);case"join":return
|
|
976
|
-
`.replace(/\\n/g,"")),y;case"input":return this.output.push(R(n[0]??"")),"";case"int":{if(n.length===0)return 0;let i=n[1]??10,s=parseInt(R(n[0]??0),i);return Number.isNaN(s)?(()=>{throw new K("ValueError","invalid literal for int()")})():s}case"float":{if(n.length===0)return 0;let i=parseFloat(R(n[0]??0));return Number.isNaN(i)?(()=>{throw new K("ValueError","could not convert to float")})():i}case"str":return n.length===0?"":R(n[0]??y);case"bool":return n.length===0?!1:pe(n[0]??y);case"list":return n.length===0?[]:
|
|
977
|
-
`);this.execLines(r,0,n)}execLines(t,n,r){let i=n;for(;i<t.length;){let s=t[i];if(!s.trim()||s.trim().startsWith("#")){i++;continue}i=this.execStatement(t,i,r)}return i}execBlock(t,n){try{this.execLines(t,0,n)}catch(r){if(r instanceof De)return r.value;throw r}return y}getIndent(t){let n=0;for(let r of t)if(r===" ")n++;else if(r===" ")n+=4;else break;return n}collectBlock(t,n,r){let i=[];for(let s=n;s<t.length;s++){let o=t[s];if(!o.trim()){i.push("");continue}if(this.getIndent(o)<=r)break;i.push(o.slice(r+4))}return i}execStatement(t,n,r){let i=t[n],s=i.trim(),o=this.getIndent(i);if(s==="pass")return n+1;if(s==="break")throw new We;if(s==="continue")throw new He;let a=s.match(/^return(?:\s+(.+))?$/);if(a)throw new De(a[1]?this.pyEval(a[1],r):y);let l=s.match(/^raise(?:\s+(.+))?$/);if(l){if(l[1]){let b=this.pyEval(l[1],r);throw new K(typeof b=="string"?b:Ie(b),R(b))}throw new K("RuntimeError","")}let c=s.match(/^assert\s+(.+?)(?:,\s*(.+))?$/);if(c){if(!pe(this.pyEval(c[1],r)))throw new K("AssertionError",c[2]?R(this.pyEval(c[2],r)):"");return n+1}let u=s.match(/^del\s+(.+)$/);if(u)return r.delete(u[1].trim()),n+1;let d=s.match(/^import\s+(\w+)(?:\s+as\s+(\w+))?$/);if(d){let[,b,E]=d,T=Mr[b];if(T){let k=T(this.cwd);this.modules.set(b,k),r.set(E??b,k)}return n+1}let p=s.match(/^from\s+(\w+)\s+import\s+(.+)$/);if(p){let[,b,E]=p,T=Mr[b];if(T){let k=T(this.cwd);if(E?.trim()==="*")for(let[M,F]of k.data)r.set(M,F);else for(let M of E.split(",").map(F=>F.trim()))r.set(M,k.data.get(M)??y)}return n+1}let m=s.match(/^def\s+(\w+)\s*\(([^)]*)\)\s*:$/);if(m){let[,b,E]=m,T=E.split(",").map(F=>F.trim()).filter(Boolean),k=this.collectBlock(t,n+1,o),M={__pytype__:"func",name:b,params:T,body:k,closure:new Map(r)};return r.set(b,M),n+1+k.length}let g=s.match(/^class\s+(\w+)(?:\(([^)]*)\))?\s*:$/);if(g){let[,b,E]=g,T=E?E.split(",").map(Q=>Q.trim()):[],k=this.collectBlock(t,n+1,o),M={__pytype__:"class",name:b,methods:new Map,bases:T},F=0;for(;F<k.length;){let G=k[F].trim().match(/^def\s+(\w+)\s*\(([^)]*)\)\s*:$/);if(G){let[,
|
|
974
|
+
`).replace(/\\t/g," ").replace(/\\r/g,"\r").replace(/\\\\/g,"\\").replace(/\\'/g,"'").replace(/\\"/g,'"');let r=t.match(/^f(['"])([\s\S]*)\1$/);if(r){let c=r[2];return c=c.replace(/\{([^{}]+)\}/g,(u,d)=>{try{return R(this.pyEval(d.trim(),n))}catch{return`{${d}}`}}),c}let i=t.match(/^b(['"])(.*)\1$/s);if(i)return i[2];if(t.startsWith("[")&&t.endsWith("]")){let c=t.slice(1,-1).trim();if(!c)return[];let u=c.match(/^(.+?)\s+for\s+(\w+)\s+in\s+(.+?)(?:\s+if\s+(.+))?$/);if(u){let[,d,p,m,g]=u,S=te(this.pyEval(m.trim(),n)),C=[];for(let P of S){let x=new Map(n);x.set(p,P),!(g&&!pe(this.pyEval(g,x)))&&C.push(this.pyEval(d.trim(),x))}return C}return this.splitArgs(c).map(d=>this.pyEval(d,n))}if(t.startsWith("(")&&t.endsWith(")")){let c=t.slice(1,-1).trim();if(!c)return[];let u=this.splitArgs(c);return u.length===1&&!c.endsWith(",")?this.pyEval(u[0],n):u.map(d=>this.pyEval(d,n))}if(t.startsWith("{")&&t.endsWith("}")){let c=t.slice(1,-1).trim();if(!c)return J();let u=J();for(let d of this.splitArgs(c)){let p=d.indexOf(":");if(p===-1)continue;let m=R(this.pyEval(d.slice(0,p).trim(),n)),g=this.pyEval(d.slice(p+1).trim(),n);u.data.set(m,g)}return u}let s=t.match(/^not\s+(.+)$/);if(s)return!pe(this.pyEval(s[1],n));let o=[["or"],["and"],["in","not in","is not","is","==","!=","<=",">=","<",">"],["+","-"],["**"],["*","//","/","%"]];for(let c of o){let u=this.tryBinaryOp(t,c,n);if(u!==void 0)return u}if(t.startsWith("-")){let c=this.pyEval(t.slice(1),n);if(typeof c=="number")return-c}if(process.env.PY_DEBUG&&console.error("eval:",JSON.stringify(t)),t.endsWith("]")&&!t.startsWith("[")){let c=this.findMatchingBracket(t,"[");if(c!==-1){let u=this.pyEval(t.slice(0,c),n),d=t.slice(c+1,-1);return this.subscript(u,d,n)}}let a=t.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*\(([\s\S]*)\)$/);if(a){let[,c,u]=a,d=(u?.trim()?this.splitArgs(u):[]).map(p=>this.pyEval(p,n));return this.callBuiltin(c,d,n)}let l=this.findDotAccess(t);if(l){let{objExpr:c,attr:u,callPart:d}=l,p=this.pyEval(c,n);if(d!==void 0){let m=d.slice(1,-1),g=m.trim()?this.splitArgs(m).map(S=>this.pyEval(S,n)):[];return this.callMethod(p,u,g,n)}return this.getAttr(p,u,n)}if(/^[A-Za-z_][A-Za-z0-9_]*$/.test(t)){if(n.has(t))return n.get(t);throw new K("NameError",`name '${t}' is not defined`)}if(/^[A-Za-z_][A-Za-z0-9_.]+$/.test(t)){let c=t.split("."),u=n.get(c[0])??(()=>{throw new K("NameError",`name '${c[0]}' is not defined`)})();for(let d of c.slice(1))u=this.getAttr(u,d,n);return u}return y}findMatchingBracket(t,n){let r=n==="["?"]":n==="("?")":"}",i=0;for(let s=t.length-1;s>=0;s--)if(t[s]===r&&i++,t[s]===n&&(i--,i===0))return s;return-1}findDotAccess(t){let n=0,r=!1,i="";for(let s=t.length-1;s>0;s--){let o=t[s];if(r){o===i&&t[s-1]!=="\\"&&(r=!1);continue}if(o==='"'||o==="'"){r=!0,i=o;continue}if(")]}".includes(o)){n++;continue}if("([{".includes(o)){n--;continue}if(n!==0||o!==".")continue;let a=t.slice(0,s).trim(),c=t.slice(s+1).match(/^(\w+)(\([\s\S]*\))?$/);if(c&&!/^-?\d+$/.test(a))return{objExpr:a,attr:c[1],callPart:c[2]}}return null}tryBinaryOp(t,n,r){let i=0,s=!1,o="";for(let a=t.length-1;a>=0;a--){let l=t[a];if(s){l===o&&t[a-1]!=="\\"&&(s=!1);continue}if(l==='"'||l==="'"){s=!0,o=l;continue}if(")]}".includes(l)){i++;continue}if("([{".includes(l)){i--;continue}if(i===0){for(let c of n)if(t.slice(a,a+c.length)===c){if(c==="*"&&(t[a+1]==="*"||t[a-1]==="*"))continue;let u=t[a-1],d=t[a+c.length];if(/^[a-z]/.test(c)&&(u&&/\w/.test(u)||d&&/\w/.test(d)))continue;let m=t.slice(0,a).trim(),g=t.slice(a+c.length).trim();if(!m||!g)continue;return this.applyBinaryOp(c,m,g,r)}}}}applyBinaryOp(t,n,r,i){if(t==="and"){let a=this.pyEval(n,i);return pe(a)?this.pyEval(r,i):a}if(t==="or"){let a=this.pyEval(n,i);return pe(a)?a:this.pyEval(r,i)}let s=this.pyEval(n,i),o=this.pyEval(r,i);switch(t){case"+":return typeof s=="string"&&typeof o=="string"?s+o:Array.isArray(s)&&Array.isArray(o)?[...s,...o]:s+o;case"-":return s-o;case"*":if(typeof s=="string"&&typeof o=="number")return s.repeat(o);if(Array.isArray(s)&&typeof o=="number"){let a=[];for(let l=0;l<o;l++)a.push(...s);return a}return s*o;case"/":{if(o===0)throw new K("ZeroDivisionError","division by zero");return s/o}case"//":{if(o===0)throw new K("ZeroDivisionError","integer division or modulo by zero");return Math.floor(s/o)}case"%":{if(typeof s=="string")return this.pyStringFormat(s,Array.isArray(o)?o:[o]);if(o===0)throw new K("ZeroDivisionError","integer division or modulo by zero");return s%o}case"**":return s**o;case"==":return ne(s)===ne(o)||s===o;case"!=":return ne(s)!==ne(o)&&s!==o;case"<":return s<o;case"<=":return s<=o;case">":return s>o;case">=":return s>=o;case"in":return this.pyIn(o,s);case"not in":return!this.pyIn(o,s);case"is":return s===o||Pe(s)&&Pe(o);case"is not":return!(s===o||Pe(s)&&Pe(o))}return y}pyIn(t,n){return typeof t=="string"?typeof n=="string"&&t.includes(n):Array.isArray(t)?t.some(r=>ne(r)===ne(n)):Y(t)?t.data.has(R(n)):!1}subscript(t,n,r){if(n.includes(":")){let s=n.split(":").map(l=>l.trim()),o=s[0]?this.pyEval(s[0],r):void 0,a=s[1]?this.pyEval(s[1],r):void 0;return typeof t=="string"||Array.isArray(t)?t.slice(o,a):y}let i=this.pyEval(n,r);if(Array.isArray(t)){let s=i;return s<0&&(s=t.length+s),t[s]??y}if(typeof t=="string"){let s=i;return s<0&&(s=t.length+s),t[s]??y}if(Y(t))return t.data.get(R(i))??y;throw new K("TypeError",`'${Ie(t)}' is not subscriptable`)}getAttr(t,n,r){return Y(t)?t.data.has(n)?t.data.get(n):n==="path"&&t.path?t.path:y:je(t)?t.attrs.get(n)??y:typeof t=="string"?{__class__:{__pytype__:"class",name:"str"}}[n]??y:y}callMethod(t,n,r,i){if(typeof t=="string")switch(n){case"upper":return t.toUpperCase();case"lower":return t.toLowerCase();case"strip":return(r[0]?t.replace(new RegExp(`[${r[0]}]+`,"g"),""):t).trim();case"lstrip":return t.trimStart();case"rstrip":return t.trimEnd();case"split":return t.split(typeof r[0]=="string"?r[0]:/\s+/).filter((s,o)=>o>0||s!=="");case"splitlines":return t.split(`
|
|
975
|
+
`);case"join":return te(r[0]??[]).map(R).join(t);case"replace":return t.replaceAll(R(r[0]??""),R(r[1]??""));case"startswith":return t.startsWith(R(r[0]??""));case"endswith":return t.endsWith(R(r[0]??""));case"find":return t.indexOf(R(r[0]??""));case"index":{let s=t.indexOf(R(r[0]??""));if(s===-1)throw new K("ValueError","substring not found");return s}case"count":return t.split(R(r[0]??"")).length-1;case"format":return this.pyStringFormat(t,r);case"encode":return t;case"decode":return t;case"isdigit":return/^\d+$/.test(t);case"isalpha":return/^[a-zA-Z]+$/.test(t);case"isalnum":return/^[a-zA-Z0-9]+$/.test(t);case"isspace":return/^\s+$/.test(t);case"isupper":return t===t.toUpperCase()&&t!==t.toLowerCase();case"islower":return t===t.toLowerCase()&&t!==t.toUpperCase();case"center":{let s=r[0]??0,o=R(r[1]??" ");return t.padStart(Math.floor((s+t.length)/2),o).padEnd(s,o)}case"ljust":return t.padEnd(r[0]??0,R(r[1]??" "));case"rjust":return t.padStart(r[0]??0,R(r[1]??" "));case"zfill":return t.padStart(r[0]??0,"0");case"title":return t.replace(/\b\w/g,s=>s.toUpperCase());case"capitalize":return t[0]?.toUpperCase()+t.slice(1).toLowerCase();case"swapcase":return[...t].map(s=>s===s.toUpperCase()?s.toLowerCase():s.toUpperCase()).join("")}if(Array.isArray(t))switch(n){case"append":return t.push(r[0]??y),y;case"extend":for(let s of te(r[0]??[]))t.push(s);return y;case"insert":return t.splice(r[0]??0,0,r[1]??y),y;case"pop":{let s=r[0]!==void 0?r[0]:-1,o=s<0?t.length+s:s;return t.splice(o,1)[0]??y}case"remove":{let s=t.findIndex(o=>ne(o)===ne(r[0]??y));return s!==-1&&t.splice(s,1),y}case"index":{let s=t.findIndex(o=>ne(o)===ne(r[0]??y));if(s===-1)throw new K("ValueError","is not in list");return s}case"count":return t.filter(s=>ne(s)===ne(r[0]??y)).length;case"sort":return t.sort((s,o)=>typeof s=="number"&&typeof o=="number"?s-o:R(s).localeCompare(R(o))),y;case"reverse":return t.reverse(),y;case"copy":return[...t];case"clear":return t.splice(0),y}if(Y(t))switch(n){case"keys":return[...t.data.keys()];case"values":return[...t.data.values()];case"items":return[...t.data.entries()].map(([s,o])=>[s,o]);case"get":return t.data.get(R(r[0]??""))??r[1]??y;case"update":{if(Y(r[0]??y))for(let[s,o]of r[0].data)t.data.set(s,o);return y}case"pop":{let s=R(r[0]??""),o=t.data.get(s)??r[1]??y;return t.data.delete(s),o}case"clear":return t.data.clear(),y;case"copy":return J([...t.data.entries()]);case"setdefault":{let s=R(r[0]??"");return t.data.has(s)||t.data.set(s,r[1]??y),t.data.get(s)??y}}if(Y(t)&&t.data.has("name")&&t.data.get("name")==="posix")switch(n){case"getcwd":return this.cwd;case"getenv":return typeof r[0]=="string"?process.env[r[0]]??r[1]??y:y;case"listdir":return[];case"path":return t}if(Y(t))switch(n){case"join":return r.map(R).join("/").replace(/\/+/g,"/");case"exists":return!1;case"dirname":return R(r[0]??"").split("/").slice(0,-1).join("/")||"/";case"basename":return R(r[0]??"").split("/").pop()??"";case"abspath":return R(r[0]??"");case"splitext":{let s=R(r[0]??""),o=s.lastIndexOf(".");return o>0?[s.slice(0,o),s.slice(o)]:[s,""]}case"isfile":return!1;case"isdir":return!1}if(Y(t)&&t.data.has("version")&&t.data.get("version")===ct&&n==="exit")throw new qe(r[0]??0);if(Y(t)){let s={sqrt:Math.sqrt,floor:Math.floor,ceil:Math.ceil,fabs:Math.abs,log:Math.log,log2:Math.log2,log10:Math.log10,sin:Math.sin,cos:Math.cos,tan:Math.tan,asin:Math.asin,acos:Math.acos,atan:Math.atan,atan2:Math.atan2,pow:Math.pow,exp:Math.exp,hypot:Math.hypot};if(n in s){let o=s[n];return o(...r.map(a=>a))}if(n==="factorial"){let o=r[0]??0,a=1;for(;o>1;)a*=o--;return a}if(n==="gcd"){let o=Math.abs(r[0]??0),a=Math.abs(r[1]??0);for(;a;)[o,a]=[a,o%a];return o}}if(Y(t)){if(n==="dumps"){let s=Y(r[1]??y)?r[1]:void 0,o=s?s.data.get("indent"):void 0;return JSON.stringify(this.pyToJs(r[0]??y),null,o)}if(n==="loads")return this.jsToPy(JSON.parse(R(r[0]??"")))}if(je(t)){let s=t.attrs.get(n)??t.cls.methods.get(n)??y;if(xe(s)){let o=new Map(s.closure);return o.set("self",t),s.params.slice(1).forEach((a,l)=>o.set(a,r[l]??y)),this.execBlock(s.body,o)}}throw new K("AttributeError",`'${Ie(t)}' object has no attribute '${n}'`)}pyStringFormat(t,n){let r=0;return t.replace(/%([diouxXeEfFgGcrs%])/g,(i,s)=>{if(s==="%")return"%";let o=n[r++];switch(s){case"d":case"i":return String(Math.trunc(o));case"f":return o.toFixed(6);case"s":return R(o??y);case"r":return ne(o??y);default:return String(o)}})}pyToJs(t){return Pe(t)?null:Y(t)?Object.fromEntries([...t.data.entries()].map(([n,r])=>[n,this.pyToJs(r)])):Array.isArray(t)?t.map(n=>this.pyToJs(n)):t}jsToPy(t){return t==null?y:typeof t=="boolean"||typeof t=="number"||typeof t=="string"?t:Array.isArray(t)?t.map(n=>this.jsToPy(n)):typeof t=="object"?J(Object.entries(t).map(([n,r])=>[n,this.jsToPy(r)])):y}callBuiltin(t,n,r){if(r.has(t)){let i=r.get(t)??y;return xe(i)?this.callFunc(i,n,r):Tt(i)?this.instantiate(i,n,r):i}switch(t){case"print":return this.output.push(n.map(R).join(" ")+`
|
|
976
|
+
`.replace(/\\n/g,"")),y;case"input":return this.output.push(R(n[0]??"")),"";case"int":{if(n.length===0)return 0;let i=n[1]??10,s=parseInt(R(n[0]??0),i);return Number.isNaN(s)?(()=>{throw new K("ValueError","invalid literal for int()")})():s}case"float":{if(n.length===0)return 0;let i=parseFloat(R(n[0]??0));return Number.isNaN(i)?(()=>{throw new K("ValueError","could not convert to float")})():i}case"str":return n.length===0?"":R(n[0]??y);case"bool":return n.length===0?!1:pe(n[0]??y);case"list":return n.length===0?[]:te(n[0]??[]);case"tuple":return n.length===0?[]:te(n[0]??[]);case"set":return n.length===0?[]:[...new Set(te(n[0]??[]).map(ne))].map(i=>te(n[0]??[]).find(o=>ne(o)===i)??y);case"dict":return n.length===0?J():Y(n[0]??y)?n[0]:J();case"bytes":return typeof n[0]=="string"?n[0]:R(n[0]??"");case"bytearray":return n.length===0?"":R(n[0]??"");case"type":return n.length===1?`<class '${Ie(n[0]??y)}'>`:y;case"isinstance":return Ie(n[0]??y)===R(n[1]??"");case"issubclass":return!1;case"callable":return xe(n[0]??y);case"hasattr":return Y(n[0]??y)?n[0].data.has(R(n[1]??"")):!1;case"getattr":return Y(n[0]??y)?n[0].data.get(R(n[1]??""))??n[2]??y:n[2]??y;case"setattr":return Y(n[0]??y)&&n[0].data.set(R(n[1]??""),n[2]??y),y;case"len":{let i=n[0]??y;if(typeof i=="string"||Array.isArray(i))return i.length;if(Y(i))return i.data.size;if(Le(i))return Nr(i);throw new K("TypeError",`object of type '${Ie(i)}' has no len()`)}case"range":return n.length===1?Ot(0,n[0]):n.length===2?Ot(n[0],n[1]):Ot(n[0],n[1],n[2]);case"enumerate":{let i=n[1]??0;return te(n[0]??[]).map((s,o)=>[o+i,s])}case"zip":{let i=n.map(te),s=Math.min(...i.map(o=>o.length));return Array.from({length:s},(o,a)=>i.map(l=>l[a]??y))}case"map":{let i=n[0]??y;return te(n[1]??[]).map(s=>xe(i)?this.callFunc(i,[s],r):y)}case"filter":{let i=n[0]??y;return te(n[1]??[]).filter(s=>xe(i)?pe(this.callFunc(i,[s],r)):pe(s))}case"reduce":{let i=n[0]??y,s=te(n[1]??[]);if(s.length===0)return n[2]??y;let o=n[2]!==void 0?n[2]:s[0];for(let a of n[2]!==void 0?s:s.slice(1))o=xe(i)?this.callFunc(i,[o,a],r):y;return o}case"sorted":{let i=[...te(n[0]??[])],s=n[1]??y,o=Y(s)?s.data.get("key")??y:s;return i.sort((a,l)=>{let c=xe(o)?this.callFunc(o,[a],r):a,u=xe(o)?this.callFunc(o,[l],r):l;return typeof c=="number"&&typeof u=="number"?c-u:R(c).localeCompare(R(u))}),i}case"reversed":return[...te(n[0]??[])].reverse();case"any":return te(n[0]??[]).some(pe);case"all":return te(n[0]??[]).every(pe);case"sum":return te(n[0]??[]).reduce((i,s)=>i+s,n[1]??0);case"max":return(n.length===1?te(n[0]??[]):n).reduce((s,o)=>s>=o?s:o);case"min":return(n.length===1?te(n[0]??[]):n).reduce((s,o)=>s<=o?s:o);case"abs":return Math.abs(n[0]??0);case"round":return n[1]!==void 0?parseFloat(n[0].toFixed(n[1])):Math.round(n[0]??0);case"divmod":{let i=n[0],s=n[1];return[Math.floor(i/s),i%s]}case"pow":return n[0]**n[1];case"hex":return`0x${n[0].toString(16)}`;case"oct":return`0o${n[0].toString(8)}`;case"bin":return`0b${n[0].toString(2)}`;case"ord":return R(n[0]??"").charCodeAt(0);case"chr":return String.fromCharCode(n[0]??0);case"id":return Math.floor(Math.random()*4294967295);case"hash":return typeof n[0]=="number"?n[0]:R(n[0]??"").split("").reduce((i,s)=>i*31+s.charCodeAt(0)|0,0);case"open":throw new K("PermissionError","open() not available in virtual runtime");case"repr":return ne(n[0]??y);case"iter":return n[0]??y;case"next":return Array.isArray(n[0])&&n[0].length>0?n[0].shift():n[1]??(()=>{throw new K("StopIteration","")})();case"vars":return J([...r.entries()].map(([i,s])=>[i,s]));case"globals":return J([...r.entries()].map(([i,s])=>[i,s]));case"locals":return J([...r.entries()].map(([i,s])=>[i,s]));case"dir":{if(n.length===0)return[...r.keys()];let i=n[0]??y;return typeof i=="string"?["upper","lower","strip","split","join","replace","find","format","encode","startswith","endswith","count","isdigit","isalpha","title","capitalize"]:Array.isArray(i)?["append","extend","insert","pop","remove","index","count","sort","reverse","copy","clear"]:Y(i)?["keys","values","items","get","update","pop","clear","copy","setdefault"]:[]}case"Exception":case"ValueError":case"TypeError":case"KeyError":case"IndexError":case"AttributeError":case"NameError":case"RuntimeError":case"StopIteration":case"NotImplementedError":case"OSError":case"IOError":throw new K(t,R(n[0]??""));case"exec":return this.execScript(R(n[0]??""),r),y;case"eval":return this.pyEval(R(n[0]??""),r);default:throw new K("NameError",`name '${t}' is not defined`)}}callFunc(t,n,r){let i=new Map(t.closure);t.params.forEach((s,o)=>{if(s.startsWith("*")){i.set(s.slice(1),n.slice(o));return}i.set(s,n[o]??y)});try{return this.execBlock(t.body,i)}catch(s){if(s instanceof De)return s.value;throw s}}instantiate(t,n,r){let i={__pytype__:"instance",cls:t,attrs:new Map};return t.methods.get("__init__")&&this.callMethod(i,"__init__",n,r),i}execScript(t,n){let r=t.split(`
|
|
977
|
+
`);this.execLines(r,0,n)}execLines(t,n,r){let i=n;for(;i<t.length;){let s=t[i];if(!s.trim()||s.trim().startsWith("#")){i++;continue}i=this.execStatement(t,i,r)}return i}execBlock(t,n){try{this.execLines(t,0,n)}catch(r){if(r instanceof De)return r.value;throw r}return y}getIndent(t){let n=0;for(let r of t)if(r===" ")n++;else if(r===" ")n+=4;else break;return n}collectBlock(t,n,r){let i=[];for(let s=n;s<t.length;s++){let o=t[s];if(!o.trim()){i.push("");continue}if(this.getIndent(o)<=r)break;i.push(o.slice(r+4))}return i}execStatement(t,n,r){let i=t[n],s=i.trim(),o=this.getIndent(i);if(s==="pass")return n+1;if(s==="break")throw new We;if(s==="continue")throw new He;let a=s.match(/^return(?:\s+(.+))?$/);if(a)throw new De(a[1]?this.pyEval(a[1],r):y);let l=s.match(/^raise(?:\s+(.+))?$/);if(l){if(l[1]){let b=this.pyEval(l[1],r);throw new K(typeof b=="string"?b:Ie(b),R(b))}throw new K("RuntimeError","")}let c=s.match(/^assert\s+(.+?)(?:,\s*(.+))?$/);if(c){if(!pe(this.pyEval(c[1],r)))throw new K("AssertionError",c[2]?R(this.pyEval(c[2],r)):"");return n+1}let u=s.match(/^del\s+(.+)$/);if(u)return r.delete(u[1].trim()),n+1;let d=s.match(/^import\s+(\w+)(?:\s+as\s+(\w+))?$/);if(d){let[,b,E]=d,T=Mr[b];if(T){let k=T(this.cwd);this.modules.set(b,k),r.set(E??b,k)}return n+1}let p=s.match(/^from\s+(\w+)\s+import\s+(.+)$/);if(p){let[,b,E]=p,T=Mr[b];if(T){let k=T(this.cwd);if(E?.trim()==="*")for(let[M,F]of k.data)r.set(M,F);else for(let M of E.split(",").map(F=>F.trim()))r.set(M,k.data.get(M)??y)}return n+1}let m=s.match(/^def\s+(\w+)\s*\(([^)]*)\)\s*:$/);if(m){let[,b,E]=m,T=E.split(",").map(F=>F.trim()).filter(Boolean),k=this.collectBlock(t,n+1,o),M={__pytype__:"func",name:b,params:T,body:k,closure:new Map(r)};return r.set(b,M),n+1+k.length}let g=s.match(/^class\s+(\w+)(?:\(([^)]*)\))?\s*:$/);if(g){let[,b,E]=g,T=E?E.split(",").map(Q=>Q.trim()):[],k=this.collectBlock(t,n+1,o),M={__pytype__:"class",name:b,methods:new Map,bases:T},F=0;for(;F<k.length;){let G=k[F].trim().match(/^def\s+(\w+)\s*\(([^)]*)\)\s*:$/);if(G){let[,ee,ve]=G,ge=ve.split(",").map(O=>O.trim()).filter(Boolean),Ce=this.collectBlock(k,F+1,0);M.methods.set(ee,{__pytype__:"func",name:ee,params:ge,body:Ce,closure:new Map(r)}),F+=1+Ce.length}else F++}return r.set(b,M),n+1+k.length}if(s.startsWith("if ")&&s.endsWith(":")){let b=s.slice(3,-1).trim(),E=this.collectBlock(t,n+1,o),T=E.length+1;if(pe(this.pyEval(b,r))){this.execBlock(E,new Map(r).also?.(F=>{for(let[Q,G]of r)F.set(Q,G)})??r),this.runBlockInScope(E,r);let M=n+1+E.length;for(;M<t.length;){let F=t[M].trim();if(this.getIndent(t[M])<o||!F.startsWith("elif")&&!F.startsWith("else"))break;let Q=this.collectBlock(t,M+1,o);M+=1+Q.length}return M}let k=n+1+E.length;for(;k<t.length;){let M=t[k],F=M.trim();if(this.getIndent(M)!==o)break;let Q=F.match(/^elif\s+(.+):$/);if(Q){let G=this.collectBlock(t,k+1,o);if(pe(this.pyEval(Q[1],r))){for(this.runBlockInScope(G,r),k+=1+G.length;k<t.length;){let ee=t[k].trim();if(this.getIndent(t[k])!==o||!ee.startsWith("elif")&&!ee.startsWith("else"))break;let ve=this.collectBlock(t,k+1,o);k+=1+ve.length}return k}k+=1+G.length;continue}if(F==="else:"){let G=this.collectBlock(t,k+1,o);return this.runBlockInScope(G,r),k+1+G.length}break}return k}let S=s.match(/^for\s+(.+?)\s+in\s+(.+?)\s*:$/);if(S){let[,b,E]=S,T=te(this.pyEval(E.trim(),r)),k=this.collectBlock(t,n+1,o),M=[],F=n+1+k.length;F<t.length&&t[F]?.trim()==="else:"&&(M=this.collectBlock(t,F+1,o),F+=1+M.length);let Q=!1;for(let G of T){if(b.includes(",")){let ee=b.split(",").map(ge=>ge.trim()),ve=Array.isArray(G)?G:[G];ee.forEach((ge,Ce)=>r.set(ge,ve[Ce]??y))}else r.set(b.trim(),G);try{this.runBlockInScope(k,r)}catch(ee){if(ee instanceof We){Q=!0;break}if(ee instanceof He)continue;throw ee}}return!Q&&M.length&&this.runBlockInScope(M,r),F}let C=s.match(/^while\s+(.+?)\s*:$/);if(C){let b=C[1],E=this.collectBlock(t,n+1,o),T=0;for(;pe(this.pyEval(b,r))&&T++<1e5;)try{this.runBlockInScope(E,r)}catch(k){if(k instanceof We)break;if(k instanceof He)continue;throw k}return n+1+E.length}if(s==="try:"){let b=this.collectBlock(t,n+1,o),E=n+1+b.length,T=[],k=[],M=[];for(;E<t.length;){let Q=t[E],G=Q.trim();if(this.getIndent(Q)!==o)break;if(G.startsWith("except")){let ee=G.match(/^except(?:\s+(\w+)(?:\s+as\s+(\w+))?)?\s*:$/),ve=ee?.[1]??null,ge=ee?.[2],Ce=this.collectBlock(t,E+1,o);T.push({exc:ve,body:Ce}),ge&&r.set(ge,""),E+=1+Ce.length}else if(G==="else:")M=this.collectBlock(t,E+1,o),E+=1+M.length;else if(G==="finally:")k=this.collectBlock(t,E+1,o),E+=1+k.length;else break}let F=null;try{this.runBlockInScope(b,r),M.length&&this.runBlockInScope(M,r)}catch(Q){if(Q instanceof K){F=Q;let G=!1;for(let ee of T)if(ee.exc===null||ee.exc===Q.type||ee.exc==="Exception"){this.runBlockInScope(ee.body,r),G=!0;break}if(!G)throw Q}else throw Q}finally{k.length&&this.runBlockInScope(k,r)}return E}let P=s.match(/^with\s+(.+?)\s+as\s+(\w+)\s*:$/);if(P){let b=this.collectBlock(t,n+1,o);return r.set(P[2],y),this.runBlockInScope(b,r),n+1+b.length}let x=s.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*(\+=|-=|\*=|\/\/=|\/=|%=|\*\*=|&=|\|=)\s*(.+)$/);if(x){let[,b,E,T]=x,k=r.get(b)??0,M=this.pyEval(T,r),F;switch(E){case"+=":F=typeof k=="string"?k+R(M):k+M;break;case"-=":F=k-M;break;case"*=":F=k*M;break;case"/=":F=k/M;break;case"//=":F=Math.floor(k/M);break;case"%=":F=k%M;break;case"**=":F=k**M;break;default:F=M}return r.set(b,F),n+1}let _=s.match(/^([A-Za-z_][A-Za-z0-9_]*)\[(.+)\]\s*=\s*(.+)$/);if(_){let[,b,E,T]=_,k=r.get(b)??y,M=this.pyEval(T,r)??y,F=this.pyEval(E,r)??y;return Array.isArray(k)?k[F]=M:Y(k)&&k.data.set(R(F),M),n+1}let w=s.match(/^([A-Za-z_][A-Za-z0-9_.]+)\s*=\s*(.+)$/);if(w){let b=w[1].lastIndexOf(".");if(b!==-1){let E=w[1].slice(0,b),T=w[1].slice(b+1),k=this.pyEval(w[2],r),M=this.pyEval(E,r);return Y(M)?M.data.set(T,k):je(M)&&M.attrs.set(T,k),n+1}}let A=s.match(/^([A-Za-z_][A-Za-z0-9_,\s]*),\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.+)$/);if(A){let b=this.pyEval(A[3],r),E=s.split("=")[0].split(",").map(k=>k.trim()),T=te(b);return E.forEach((k,M)=>r.set(k,T[M]??y)),n+1}let N=s.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*(?::[^=]+)?\s*=\s*(.+)$/);if(N){let[,b,E]=N;return r.set(b,this.pyEval(E,r)),n+1}try{this.pyEval(s,r)}catch(b){if(b instanceof K||b instanceof qe)throw b}return n+1}runBlockInScope(t,n){this.execLines(t,0,n)}run(t){let n=Fi(this.cwd);try{this.execScript(t,n)}catch(r){return r instanceof qe?{stdout:this.getOutput(),stderr:this.getStderr(),exitCode:r.code}:r instanceof K?(this.stderr.push(r.toString()),{stdout:this.getOutput(),stderr:this.getStderr(),exitCode:1}):r instanceof De?{stdout:this.getOutput(),stderr:this.getStderr(),exitCode:0}:(this.stderr.push(`RuntimeError: ${r}`),{stdout:this.getOutput(),stderr:this.getStderr(),exitCode:1})}return{stdout:this.getOutput(),stderr:this.getStderr(),exitCode:0}}},Er={name:"python3",aliases:["python"],description:"Python 3 interpreter (virtual)",category:"system",params:["[--version] [-c <code>] [-V] [file]"],run:({args:e,shell:t,cwd:n})=>{if(!t.packageManager.isInstalled("python3"))return{stderr:`bash: python3: command not found
|
|
978
978
|
Hint: install it with: apt install python3
|
|
979
979
|
`,exitCode:127};if(v(e,["--version","-V"]))return{stdout:`${Oi}
|
|
980
980
|
`,exitCode:0};if(v(e,["--version-full"]))return{stdout:`${ct}
|
|
@@ -1029,7 +1029,7 @@ ${p} 100%[==================>] ${S.length} B`),{stderr:m.join(`
|
|
|
1029
1029
|
`).replace(/\r/g,`
|
|
1030
1030
|
`).replace(/\n/g,`\r
|
|
1031
1031
|
`)}function ps(e,t){let n=Number.isFinite(t.cols)&&t.cols>0?Math.floor(t.cols):80,r=Number.isFinite(t.rows)&&t.rows>0?Math.floor(t.rows):24;return`stty cols ${n} rows ${r} 2>/dev/null; ${e}`}function ft(e,t){return!t||t.trim()===""||t==="."?e:t.startsWith("/")?mt.posix.normalize(t):mt.posix.normalize(mt.posix.join(e,t))}async function ms(e){try{let n=(await Hi(`/proc/${e}/task/${e}/children`,"utf8")).trim().split(/\s+/).filter(Boolean).map(i=>Number.parseInt(i,10)).filter(i=>Number.isInteger(i)&&i>0),r=await Promise.all(n.map(i=>ms(i)));return[...n,...r.flat()]}catch{return[]}}async function fs(e=process.pid){let t=await ms(e),n=Array.from(new Set(t)).sort((r,i)=>r-i);return n.length===0?null:n.join(",")}function hs(e,t,n){let r=ps(e,t),i=qi("script",["-qfec",r,"/dev/null"],{stdio:["pipe","pipe","pipe"],env:{...process.env,TERM:process.env.TERM??"xterm-256color"}});return i.stdout.on("data",s=>{n.write(s.toString("utf8"))}),i.stderr.on("data",s=>{n.write(s.toString("utf8"))}),i}function ht(e,t,n){return hs(`nano -- ${Ut(e)}`,t,n)}function gs(e,t,n){return hs(`htop -p ${Ut(e)}`,t,n)}function gt(e,t,n){let r=[`Linux ${e} ${t.kernel} ${t.arch}`,"","The programs included with the Fortune GNU/Linux system are free software;","the exact distribution terms for each program are described in the","individual files in /usr/share/doc/*/copyright.","","Fortune GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent","permitted by applicable law."];if(n){let i=new Date(n.at),s=Number.isNaN(i.getTime())?n.at:dt(i);r.push(`Last login: ${s} from ${n.from||"unknown"}`)}return r.push(""),`${r.map(i=>`${i}\r
|
|
1032
|
-
`).join("")}`}function yt(e,t,n){let r=e==="root",i=r?"\x1B[31;1m":"\x1B[35;1m",s="\x1B[37;1m",o="\x1B[34;1m",a="\x1B[0m";return`${s}[${i}${e}${s}@${o}${t}${a} ${n}${s}]${a}${r?"#":"$"} `}import{EventEmitter as ko}from"node:events";import*as we from"node:os";import{EventEmitter as Qi}from"node:events";import*as B from"node:fs";import*as ce from"node:path";import{gunzipSync as qt,gzipSync as Cs}from"node:zlib";var jt=Buffer.from([86,70,83,33]),Gi=1,Vt=1,ys=2,zt=class{chunks=[];write(t){this.chunks.push(t)}writeUint8(t){let n=Buffer.allocUnsafe(1);n.writeUInt8(t,0),this.chunks.push(n)}writeUint16(t){let n=Buffer.allocUnsafe(2);n.writeUInt16LE(t,0),this.chunks.push(n)}writeUint32(t){let n=Buffer.allocUnsafe(4);n.writeUInt32LE(t,0),this.chunks.push(n)}writeFloat64(t){let n=Buffer.allocUnsafe(8);n.writeDoubleBE(t,0),this.chunks.push(n)}writeString(t){let n=Buffer.from(t,"utf8");this.writeUint16(n.length),this.chunks.push(n)}writeBytes(t){this.writeUint32(t.length),this.chunks.push(t)}toBuffer(){return Buffer.concat(this.chunks)}};function Ss(e,t){if(t.type==="file"){let n=t;e.writeUint8(Vt),e.writeString(n.name),e.writeUint32(n.mode),e.writeFloat64(n.createdAt),e.writeFloat64(n.updatedAt),e.writeUint8(n.compressed?1:0),e.writeBytes(n.content)}else if(t.type==="stub"){let n=t;e.writeUint8(Vt),e.writeString(n.name),e.writeUint32(n.mode),e.writeFloat64(n.createdAt),e.writeFloat64(n.updatedAt),e.writeUint8(0),e.writeBytes(Buffer.from(n.stubContent,"utf8"))}else{let n=t;e.writeUint8(ys),e.writeString(n.name),e.writeUint32(n.mode),e.writeFloat64(n.createdAt),e.writeFloat64(n.updatedAt);let r=Object.values(n.children);e.writeUint32(r.length);for(let i of r)Ss(e,i)}}function Wt(e){let t=new zt;return t.write(jt),t.writeUint8(Gi),Ss(t,e),t.toBuffer()}var Bt=class{constructor(t){this.buf=t}buf;pos=0;readUint8(){return this.buf.readUInt8(this.pos++)}readUint16(){let t=this.buf.readUInt16LE(this.pos);return this.pos+=2,t}readUint32(){let t=this.buf.readUInt32LE(this.pos);return this.pos+=4,t}readFloat64(){let t=this.buf.readDoubleBE(this.pos);return this.pos+=8,t}readString(){let t=this.readUint16(),n=this.buf.toString("utf8",this.pos,this.pos+t);return this.pos+=t,n}readBytes(){let t=this.readUint32(),n=this.buf.slice(this.pos,this.pos+t);return this.pos+=t,n}remaining(){return this.buf.length-this.pos}};function bs(e){let t=e.readUint8(),n=e.readString(),r=e.readUint32(),i=e.readFloat64(),s=e.readFloat64();if(t===Vt){let o=e.readUint8()===1,a=e.readBytes();return{type:"file",name:n,mode:r,createdAt:i,updatedAt:s,compressed:o,content:a}}if(t===ys){let o=e.readUint32(),a=Object.create(null);for(let l=0;l<o;l++){let c=bs(e);a[c.name]=c}return{type:"directory",name:n,mode:r,createdAt:i,updatedAt:s,children:a,_childCount:o}}throw new Error(`[VFS binary] Unknown node type: 0x${t.toString(16)}`)}function Ne(e){if(e.length<5)throw new Error("[VFS binary] Buffer too short");if(!e.slice(0,4).equals(jt))throw new Error("[VFS binary] Invalid magic \u2014 not a VFS binary snapshot");let n=new Bt(e);for(let i=0;i<5;i++)n.readUint8();let r=bs(n);if(r.type!=="directory")throw new Error("[VFS binary] Root node must be a directory");return r}function xs(e){return e.length>=4&&e.slice(0,4).equals(jt)}import*as se from"node:fs";var W={WRITE:1,MKDIR:2,REMOVE:3,CHMOD:4,MOVE:5,SYMLINK:6},Ke="utf8";function Yi(e,t,n){let r=Buffer.from(n,Ke);return e.writeUInt16LE(r.length,t),r.copy(e,t+2),2+r.length}function Ki(e){let t=Buffer.from(e.path,Ke),n=0;e.op===W.WRITE?n=4+(e.content?.length??0)+4:e.op===W.MKDIR?n=4:e.op===W.REMOVE?n=0:e.op===W.CHMOD?n=4:(e.op===W.MOVE||e.op===W.SYMLINK)&&(n=2+Buffer.byteLength(e.dest??"",Ke));let r=3+t.length+n,i=Buffer.allocUnsafe(r),s=0;if(i.writeUInt8(e.op,s++),i.writeUInt16LE(t.length,s),s+=2,t.copy(i,s),s+=t.length,e.op===W.WRITE){let o=e.content??Buffer.alloc(0);i.writeUInt32LE(o.length,s),s+=4,o.copy(i,s),s+=o.length,i.writeUInt32LE(e.mode??420,s),s+=4}else e.op===W.MKDIR?(i.writeUInt32LE(e.mode??493,s),s+=4):e.op===W.CHMOD?(i.writeUInt32LE(e.mode??420,s),s+=4):(e.op===W.MOVE||e.op===W.SYMLINK)&&(s+=Yi(i,s,e.dest??""));return i}function Ji(e){let t=[],n=0;try{for(;n<e.length&&!(n+3>e.length);){let r=e.readUInt8(n++),i=e.readUInt16LE(n);if(n+=2,n+i>e.length)break;let s=e.subarray(n,n+i).toString(Ke);if(n+=i,r===W.WRITE){if(n+4>e.length)break;let o=e.readUInt32LE(n);if(n+=4,n+o+4>e.length)break;let a=Buffer.from(e.subarray(n,n+o));n+=o;let l=e.readUInt32LE(n);n+=4,t.push({op:r,path:s,content:a,mode:l})}else if(r===W.MKDIR){if(n+4>e.length)break;let o=e.readUInt32LE(n);n+=4,t.push({op:r,path:s,mode:o})}else if(r===W.REMOVE)t.push({op:r,path:s});else if(r===W.CHMOD){if(n+4>e.length)break;let o=e.readUInt32LE(n);n+=4,t.push({op:r,path:s,mode:o})}else if(r===W.MOVE||r===W.SYMLINK){if(n+2>e.length)break;let o=e.readUInt16LE(n);if(n+=2,n+o>e.length)break;let a=e.subarray(n,n+o).toString(Ke);n+=o,t.push({op:r,path:s,dest:a})}else break}}catch{}return t}function ws(e,t){let n=Ki(t);if(console.log(`[Journal] Appending entry: op=${t.op} path=${t.path} ${t.content?`content_len=${t.content.length}`:""}${t.mode?` mode=${t.mode.toString(8)}`:""}${t.dest?` dest=${t.dest}`:""}`),se.existsSync(e)){let r=se.openSync(e,se.constants.O_WRONLY|se.constants.O_CREAT|se.constants.O_APPEND);try{se.writeSync(r,n)}finally{se.closeSync(r)}}else se.writeFileSync(e,n)}function Ht(e){if(!se.existsSync(e))return[];let t=se.readFileSync(e);return t.length===0?[]:Ji(t)}function vs(e){se.existsSync(e)&&se.unlinkSync(e)}import*as St from"node:path";function H(e){if(!e||e.trim()==="")return"/";let t=St.posix.normalize(e.startsWith("/")?e:`/${e}`);return t===""?"/":t}function Zi(e){return e.split("/").filter(Boolean)}function oe(e,t){let n=H(t);if(n==="/")return e;let r=Zi(n),i=e;for(let s of r){if(i.type!=="directory")throw new Error(`Path '${n}' does not exist.`);let o=i.children[s];if(!o)throw new Error(`Path '${n}' does not exist.`);i=o}return i}function Ae(e,t,n,r){let i=H(t);if(i==="/")throw new Error("Root path has no parent directory.");let s=St.posix.dirname(i),o=St.posix.basename(i);if(!o)throw new Error(`Invalid path '${t}'.`);n&&r(s);let a=oe(e,s);if(a.type!=="directory")throw new Error(`Parent path '${s}' is not a directory.`);return{parent:a,name:o}}var Gt=class e extends Qi{root;mode;snapshotFile;journalFile;evictionThreshold;flushAfterNWrites;_writesSinceFlush=0;_flushTimer=null;_dirty=!1;mounts=new Map;static isBrowser=typeof process>"u"||typeof process.versions?.node>"u";constructor(t={}){if(super(),this.mode=t.mode??"memory",this.mode==="fs"){if(!t.snapshotPath)throw new Error('VirtualFileSystem: "snapshotPath" is required when mode is "fs".');this.snapshotFile=ce.resolve(t.snapshotPath,"vfs-snapshot.vfsb"),this.journalFile=ce.resolve(t.snapshotPath,"vfs-journal.bin"),this.evictionThreshold=t.evictionThresholdBytes??64*1024,this.flushAfterNWrites=t.flushAfterNWrites??500;let n=t.flushIntervalMs??1e3;n>0&&(this._flushTimer=setInterval(()=>{this._dirty&&this._autoFlush()},n),typeof this._flushTimer=="object"&&this._flushTimer!==null&&"unref"in this._flushTimer&&this._flushTimer.unref())}else this.snapshotFile=null,this.journalFile=null,this.evictionThreshold=0,this.flushAfterNWrites=0;this.root=this.makeDir("",493)}makeDir(t,n){let r=Date.now();return{type:"directory",name:t,mode:n,createdAt:r,updatedAt:r,children:Object.create(null),_childCount:0}}makeFile(t,n,r,i){let s=Date.now();return{type:"file",name:t,content:n,mode:r,compressed:i,createdAt:s,updatedAt:s}}makeStub(t,n,r){let i=Date.now();return{type:"stub",name:t,stubContent:n,mode:r,createdAt:i,updatedAt:i}}writeStub(t,n,r=420){let i=H(t),{parent:s,name:o}=Ae(this.root,i,!0,l=>this.mkdirRecursive(l,493)),a=s.children[o];if(a?.type==="directory")throw new Error(`Cannot write stub '${i}': path is a directory.`);a?.type!=="file"&&(a||s._childCount++,s.children[o]=this.makeStub(o,n,r))}mkdirRecursive(t,n){let r=H(t);if(r==="/")return;let i=r.split("/").filter(Boolean),s=this.root,o="";for(let a of i){o+=`/${a}`;let l=s.children[a];if(!l)l=this.makeDir(a,n),s.children[a]=l,s._childCount++,this.emit("dir:create",{path:o,mode:n}),this._journal({op:W.MKDIR,path:o,mode:n});else if(l.type!=="directory")throw new Error(`Cannot create directory '${o}': path is a file.`);s=l}}async restoreMirror(){if(!(this.mode!=="fs"||!this.snapshotFile)){if(!B.existsSync(this.snapshotFile)){if(this.journalFile){let t=Ht(this.journalFile);t.length>0&&this._replayJournal(t)}return}try{let t=B.readFileSync(this.snapshotFile);if(xs(t))this.root=Ne(t);else{let n=JSON.parse(t.toString("utf8"));this.root=this.deserializeDir(n.root,""),console.info("[VirtualFileSystem] Migrating legacy JSON snapshot to binary format.")}if(this.emit("snapshot:restore",{path:this.snapshotFile}),this.journalFile){let n=Ht(this.journalFile);n.length>0&&this._replayJournal(n)}}catch(t){console.warn(`[VirtualFileSystem] Could not restore snapshot from ${this.snapshotFile}:`,t instanceof Error?t.message:String(t))}}}async flushMirror(){if(this.mode!=="fs"||!this.snapshotFile){this.emit("mirror:flush");return}let t=ce.dirname(this.snapshotFile);B.mkdirSync(t,{recursive:!0});let n=this.root,r=Wt(n);B.writeFileSync(this.snapshotFile,r),this.journalFile&&vs(this.journalFile),this._dirty=!1,this._writesSinceFlush=0,this.emit("mirror:flush",{path:this.snapshotFile}),this.evictLargeFiles()}getMode(){return this.mode}getSnapshotPath(){return this.snapshotFile}async _autoFlush(){this._dirty&&await this.flushMirror()}_markDirty(){this._dirty=!0,this.flushAfterNWrites>0&&(this._writesSinceFlush++,this._writesSinceFlush>=this.flushAfterNWrites&&(this._writesSinceFlush=0,this._autoFlush()))}async stopAutoFlush(){this._flushTimer!==null&&(clearInterval(this._flushTimer),this._flushTimer=null),this._dirty&&await this.flushMirror()}importRootTree(t){let n=this._replayMode;this._replayMode=!0;try{this.root=t}finally{this._replayMode=n}}mergeRootTree(t){let n=this._replayMode;this._replayMode=!0;try{this._mergeDir(this.root,t)}finally{this._replayMode=n}}_mergeDir(t,n){for(let[r,i]of Object.entries(n.children)){let s=t.children[r];i.type==="directory"?s?s.type==="directory"&&this._mergeDir(s,i):(t.children[r]=i,t._childCount++):s||(t.children[r]=i,t._childCount++)}}encodeBinary(){return Wt(this.root)}releaseTree(){this.root=this.makeDir("",493)}_replayMode=!1;_journal(t){this.journalFile&&!this._replayMode&&(ws(this.journalFile,t),this._markDirty())}_replayJournal(t){this._replayMode=!0;try{for(let n of t)try{n.op===W.WRITE?this.writeFile(n.path,n.content??Buffer.alloc(0),{mode:n.mode}):n.op===W.MKDIR?this.mkdir(n.path,n.mode):n.op===W.REMOVE?this.exists(n.path)&&this.remove(n.path,{recursive:!0}):n.op===W.CHMOD?this.exists(n.path)&&this.chmod(n.path,n.mode??420):n.op===W.MOVE?this.exists(n.path)&&n.dest&&this.move(n.path,n.dest):n.op===W.SYMLINK&&n.dest&&this.symlink(n.dest,n.path)}catch{}}finally{this._replayMode=!1}}evictLargeFiles(){!this.snapshotFile||this.evictionThreshold===0||B.existsSync(this.snapshotFile)&&this._evictDir(this.root)}_evictDir(t){for(let n of Object.values(t.children))if(n.type==="directory")this._evictDir(n);else if(n.type==="file"&&!n.evicted){let r=n.compressed?n.size??n.content.length*2:n.content.length;r>this.evictionThreshold&&(n.size=r,n.content=Buffer.alloc(0),n.evicted=!0)}}_reloadEvicted(t,n){if(!(!t.evicted||!this.snapshotFile)&&B.existsSync(this.snapshotFile))try{let r=B.readFileSync(this.snapshotFile),i=Ne(r),s=n.split("/").filter(Boolean),o=i;for(let a of s){if(o.type!=="directory")return;let l=o.children[a];if(!l)return;o=l}o.type==="file"&&(t.content=o.content,t.compressed=o.compressed,t.evicted=void 0)}catch{}}mount(t,n,{readOnly:r=!0}={}){if(e.isBrowser)return;let i=H(t),s=ce.resolve(n);if(!B.existsSync(s))throw new Error(`VirtualFileSystem.mount: host path does not exist: "${s}"`);if(!B.statSync(s).isDirectory())throw new Error(`VirtualFileSystem.mount: host path is not a directory: "${s}"`);this.mkdir(i),this.mounts.set(i,{hostPath:s,readOnly:r}),this.emit("mount",{vPath:i,hostPath:s,readOnly:r})}unmount(t){let n=H(t);this.mounts.delete(n)&&this.emit("unmount",{vPath:n})}getMounts(){return[...this.mounts.entries()].map(([t,n])=>({vPath:t,...n}))}resolveMount(t){let n=H(t),r=[...this.mounts.entries()].sort(([i],[s])=>s.length-i.length);for(let[i,s]of r)if(n===i||n.startsWith(`${i}/`)){let o=n.slice(i.length).replace(/^\//,""),a=o?ce.join(s.hostPath,o):s.hostPath;return{hostPath:s.hostPath,readOnly:s.readOnly,relPath:o,fullHostPath:a}}return null}mkdir(t,n=493){let r=H(t),i=(()=>{try{return oe(this.root,r)}catch{return null}})();if(i&&i.type!=="directory")throw new Error(`Cannot create directory '${r}': path is a file.`);this.mkdirRecursive(r,n)}writeFile(t,n,r={}){let i=this.resolveMount(t);if(i){if(i.readOnly)throw new Error(`EROFS: read-only file system, open '${i.fullHostPath}'`);let m=ce.dirname(i.fullHostPath);B.existsSync(m)||B.mkdirSync(m,{recursive:!0}),B.writeFileSync(i.fullHostPath,Buffer.isBuffer(n)?n:Buffer.from(n,"utf8"));return}let s=H(t),{parent:o,name:a}=Ae(this.root,s,!0,m=>this.mkdirRecursive(m,493)),l=o.children[a];if(l?.type==="directory")throw new Error(`Cannot write file '${s}': path is a directory.`);let c=Buffer.isBuffer(n)?n:Buffer.from(n,"utf8"),u=r.compress??!1,d=u?Cs(c):c,p=r.mode??420;if(l&&l.type==="file"){let m=l;m.content=d,m.compressed=u,m.mode=p,m.updatedAt=Date.now()}else l||o._childCount++,o.children[a]=this.makeFile(a,d,p,u);this.emit("file:write",{path:s,size:d.length}),this._journal({op:W.WRITE,path:s,content:c,mode:p})}readFile(t){let n=this.resolveMount(t);if(n){if(!B.existsSync(n.fullHostPath))throw new Error(`ENOENT: no such file or directory, open '${n.fullHostPath}'`);return B.readFileSync(n.fullHostPath,"utf8")}let r=H(t),i=oe(this.root,r);if(i.type==="stub")return this.emit("file:read",{path:r,size:i.stubContent.length}),i.stubContent;if(i.type!=="file")throw new Error(`Cannot read '${t}': not a file.`);let s=i;s.evicted&&this._reloadEvicted(s,r);let o=s.compressed?qt(s.content):s.content;return this.emit("file:read",{path:r,size:o.length}),o.toString("utf8")}readFileRaw(t){let n=this.resolveMount(t);if(n){if(!B.existsSync(n.fullHostPath))throw new Error(`ENOENT: no such file or directory, open '${n.fullHostPath}'`);return B.readFileSync(n.fullHostPath)}let r=H(t),i=oe(this.root,r);if(i.type==="stub"){let a=Buffer.from(i.stubContent,"utf8");return this.emit("file:read",{path:r,size:a.length}),a}if(i.type!=="file")throw new Error(`Cannot read '${t}': not a file.`);let s=i;s.evicted&&this._reloadEvicted(s,r);let o=s.compressed?qt(s.content):s.content;return this.emit("file:read",{path:r,size:o.length}),o}exists(t){let n=this.resolveMount(t);if(n)return B.existsSync(n.fullHostPath);try{return oe(this.root,H(t)),!0}catch{return!1}}chmod(t,n){let r=H(t);oe(this.root,r).mode=n,this._journal({op:W.CHMOD,path:r,mode:n})}stat(t){let n=this.resolveMount(t);if(n){if(!B.existsSync(n.fullHostPath))throw new Error(`ENOENT: stat '${n.fullHostPath}'`);let a=B.statSync(n.fullHostPath),l=n.relPath.split("/").pop()??n.fullHostPath.split("/").pop()??"",c=a.mtime;return a.isDirectory()?{type:"directory",name:l,path:H(t),mode:493,createdAt:a.birthtime,updatedAt:c,childrenCount:B.readdirSync(n.fullHostPath).length}:{type:"file",name:l,path:H(t),mode:n.readOnly?292:420,createdAt:a.birthtime,updatedAt:c,compressed:!1,size:a.size}}let r=H(t),i=oe(this.root,r),s=r==="/"?"":ce.posix.basename(r);if(i.type==="stub"){let a=i;return{type:"file",name:s,path:r,mode:a.mode,createdAt:new Date(a.createdAt),updatedAt:new Date(a.updatedAt),compressed:!1,size:a.stubContent.length}}if(i.type==="file"){let a=i;return{type:"file",name:s,path:r,mode:a.mode,createdAt:new Date(a.createdAt),updatedAt:new Date(a.updatedAt),compressed:a.compressed,size:a.evicted?a.size??0:a.content.length}}let o=i;return{type:"directory",name:s,path:r,mode:o.mode,createdAt:new Date(o.createdAt),updatedAt:new Date(o.updatedAt),childrenCount:o._childCount}}list(t="/"){let n=this.resolveMount(t);if(n){if(!B.existsSync(n.fullHostPath))return[];try{return B.readdirSync(n.fullHostPath).sort()}catch{return[]}}let r=H(t),i=oe(this.root,r);if(i.type!=="directory")throw new Error(`Cannot list '${t}': not a directory.`);return Object.keys(i.children).sort()}tree(t="/"){let n=H(t),r=oe(this.root,n);if(r.type!=="directory")throw new Error(`Cannot render tree for '${t}': not a directory.`);let i=t==="/"?"/":ce.posix.basename(n);return this.renderTreeLines(r,i)}renderTreeLines(t,n){let r=[n],i=Object.keys(t.children).sort();for(let s=0;s<i.length;s++){let o=i[s],a=t.children[o],l=s===i.length-1,c=l?"\u2514\u2500\u2500 ":"\u251C\u2500\u2500 ",u=l?" ":"\u2502 ";if(r.push(`${c}${o}`),a.type==="directory"){let d=this.renderTreeLines(a,"").split(`
|
|
1032
|
+
`).join("")}`}function yt(e,t,n){let r=e==="root",i=r?"\x1B[31;1m":"\x1B[35;1m",s="\x1B[37;1m",o="\x1B[34;1m",a="\x1B[0m";return`${s}[${i}${e}${s}@${o}${t}${a} ${n}${s}]${a}${r?"#":"$"} `}import{EventEmitter as ko}from"node:events";import*as we from"node:os";import{EventEmitter as Qi}from"node:events";import*as B from"node:fs";import*as ce from"node:path";import{gunzipSync as qt,gzipSync as Cs}from"node:zlib";var jt=Buffer.from([86,70,83,33]),Gi=1,Vt=1,ys=2,zt=class{chunks=[];write(t){this.chunks.push(t)}writeUint8(t){let n=Buffer.allocUnsafe(1);n.writeUInt8(t,0),this.chunks.push(n)}writeUint16(t){let n=Buffer.allocUnsafe(2);n.writeUInt16LE(t,0),this.chunks.push(n)}writeUint32(t){let n=Buffer.allocUnsafe(4);n.writeUInt32LE(t,0),this.chunks.push(n)}writeFloat64(t){let n=Buffer.allocUnsafe(8);n.writeDoubleBE(t,0),this.chunks.push(n)}writeString(t){let n=Buffer.from(t,"utf8");this.writeUint16(n.length),this.chunks.push(n)}writeBytes(t){this.writeUint32(t.length),this.chunks.push(t)}toBuffer(){return Buffer.concat(this.chunks)}};function Ss(e,t){if(t.type==="file"){let n=t;e.writeUint8(Vt),e.writeString(n.name),e.writeUint32(n.mode),e.writeFloat64(n.createdAt),e.writeFloat64(n.updatedAt),e.writeUint8(n.compressed?1:0),e.writeBytes(n.content)}else if(t.type==="stub"){let n=t;e.writeUint8(Vt),e.writeString(n.name),e.writeUint32(n.mode),e.writeFloat64(n.createdAt),e.writeFloat64(n.updatedAt),e.writeUint8(0),e.writeBytes(Buffer.from(n.stubContent,"utf8"))}else{let n=t;e.writeUint8(ys),e.writeString(n.name),e.writeUint32(n.mode),e.writeFloat64(n.createdAt),e.writeFloat64(n.updatedAt);let r=Object.values(n.children);e.writeUint32(r.length);for(let i of r)Ss(e,i)}}function Wt(e){let t=new zt;return t.write(jt),t.writeUint8(Gi),Ss(t,e),t.toBuffer()}var Bt=class{constructor(t){this.buf=t}buf;pos=0;readUint8(){return this.buf.readUInt8(this.pos++)}readUint16(){let t=this.buf.readUInt16LE(this.pos);return this.pos+=2,t}readUint32(){let t=this.buf.readUInt32LE(this.pos);return this.pos+=4,t}readFloat64(){let t=this.buf.readDoubleBE(this.pos);return this.pos+=8,t}readString(){let t=this.readUint16(),n=this.buf.toString("utf8",this.pos,this.pos+t);return this.pos+=t,n}readBytes(){let t=this.readUint32(),n=this.buf.slice(this.pos,this.pos+t);return this.pos+=t,n}remaining(){return this.buf.length-this.pos}};function bs(e){let t=e.readUint8(),n=e.readString(),r=e.readUint32(),i=e.readFloat64(),s=e.readFloat64();if(t===Vt){let o=e.readUint8()===1,a=e.readBytes();return{type:"file",name:n,mode:r,createdAt:i,updatedAt:s,compressed:o,content:a}}if(t===ys){let o=e.readUint32(),a=Object.create(null);for(let l=0;l<o;l++){let c=bs(e);a[c.name]=c}return{type:"directory",name:n,mode:r,createdAt:i,updatedAt:s,children:a,_childCount:o}}throw new Error(`[VFS binary] Unknown node type: 0x${t.toString(16)}`)}function Ne(e){if(e.length<5)throw new Error("[VFS binary] Buffer too short");if(!e.slice(0,4).equals(jt))throw new Error("[VFS binary] Invalid magic \u2014 not a VFS binary snapshot");let n=new Bt(e);for(let i=0;i<5;i++)n.readUint8();let r=bs(n);if(r.type!=="directory")throw new Error("[VFS binary] Root node must be a directory");return r}function xs(e){return e.length>=4&&e.slice(0,4).equals(jt)}import*as X from"node:fs";var W={WRITE:1,MKDIR:2,REMOVE:3,CHMOD:4,MOVE:5,SYMLINK:6},Ke="utf8";function Yi(e,t,n){let r=Buffer.from(n,Ke);return e.writeUInt16LE(r.length,t),r.copy(e,t+2),2+r.length}function Ki(e){let t=Buffer.from(e.path,Ke),n=0;e.op===W.WRITE?n=4+(e.content?.length??0)+4:e.op===W.MKDIR?n=4:e.op===W.REMOVE?n=0:e.op===W.CHMOD?n=4:(e.op===W.MOVE||e.op===W.SYMLINK)&&(n=2+Buffer.byteLength(e.dest??"",Ke));let r=3+t.length+n,i=Buffer.allocUnsafe(r),s=0;if(i.writeUInt8(e.op,s++),i.writeUInt16LE(t.length,s),s+=2,t.copy(i,s),s+=t.length,e.op===W.WRITE){let o=e.content??Buffer.alloc(0);i.writeUInt32LE(o.length,s),s+=4,o.copy(i,s),s+=o.length,i.writeUInt32LE(e.mode??420,s),s+=4}else e.op===W.MKDIR?(i.writeUInt32LE(e.mode??493,s),s+=4):e.op===W.CHMOD?(i.writeUInt32LE(e.mode??420,s),s+=4):(e.op===W.MOVE||e.op===W.SYMLINK)&&(s+=Yi(i,s,e.dest??""));return i}function Ji(e){let t=[],n=0;try{for(;n<e.length&&!(n+3>e.length);){let r=e.readUInt8(n++),i=e.readUInt16LE(n);if(n+=2,n+i>e.length)break;let s=e.subarray(n,n+i).toString(Ke);if(n+=i,r===W.WRITE){if(n+4>e.length)break;let o=e.readUInt32LE(n);if(n+=4,n+o+4>e.length)break;let a=Buffer.from(e.subarray(n,n+o));n+=o;let l=e.readUInt32LE(n);n+=4,t.push({op:r,path:s,content:a,mode:l})}else if(r===W.MKDIR){if(n+4>e.length)break;let o=e.readUInt32LE(n);n+=4,t.push({op:r,path:s,mode:o})}else if(r===W.REMOVE)t.push({op:r,path:s});else if(r===W.CHMOD){if(n+4>e.length)break;let o=e.readUInt32LE(n);n+=4,t.push({op:r,path:s,mode:o})}else if(r===W.MOVE||r===W.SYMLINK){if(n+2>e.length)break;let o=e.readUInt16LE(n);if(n+=2,n+o>e.length)break;let a=e.subarray(n,n+o).toString(Ke);n+=o,t.push({op:r,path:s,dest:a})}else break}}catch{}return t}function ws(e,t){let n=Ki(t);if(X.existsSync(e)){let r=X.openSync(e,X.constants.O_WRONLY|X.constants.O_CREAT|X.constants.O_APPEND);try{X.writeSync(r,n)}finally{X.closeSync(r)}}else X.existsSync(".vfs")||X.mkdirSync(".vfs"),X.writeFileSync(e,n)}function Ht(e){if(!X.existsSync(e))return[];let t=X.readFileSync(e);return t.length===0?[]:Ji(t)}function vs(e){X.existsSync(e)&&X.unlinkSync(e)}import*as St from"node:path";function H(e){if(!e||e.trim()==="")return"/";let t=St.posix.normalize(e.startsWith("/")?e:`/${e}`);return t===""?"/":t}function Zi(e){return e.split("/").filter(Boolean)}function oe(e,t){let n=H(t);if(n==="/")return e;let r=Zi(n),i=e;for(let s of r){if(i.type!=="directory")throw new Error(`Path '${n}' does not exist.`);let o=i.children[s];if(!o)throw new Error(`Path '${n}' does not exist.`);i=o}return i}function Ae(e,t,n,r){let i=H(t);if(i==="/")throw new Error("Root path has no parent directory.");let s=St.posix.dirname(i),o=St.posix.basename(i);if(!o)throw new Error(`Invalid path '${t}'.`);n&&r(s);let a=oe(e,s);if(a.type!=="directory")throw new Error(`Parent path '${s}' is not a directory.`);return{parent:a,name:o}}var Gt=class e extends Qi{root;mode;snapshotFile;journalFile;evictionThreshold;flushAfterNWrites;_writesSinceFlush=0;_flushTimer=null;_dirty=!1;mounts=new Map;static isBrowser=typeof process>"u"||typeof process.versions?.node>"u";constructor(t={}){if(super(),this.mode=t.mode??"memory",this.mode==="fs"){if(!t.snapshotPath)throw new Error('VirtualFileSystem: "snapshotPath" is required when mode is "fs".');this.snapshotFile=ce.resolve(t.snapshotPath,"vfs-snapshot.vfsb"),this.journalFile=ce.resolve(t.snapshotPath,"vfs-journal.bin"),this.evictionThreshold=t.evictionThresholdBytes??64*1024,this.flushAfterNWrites=t.flushAfterNWrites??500;let n=t.flushIntervalMs??1e3;n>0&&(this._flushTimer=setInterval(()=>{this._dirty&&this._autoFlush()},n),typeof this._flushTimer=="object"&&this._flushTimer!==null&&"unref"in this._flushTimer&&this._flushTimer.unref())}else this.snapshotFile=null,this.journalFile=null,this.evictionThreshold=0,this.flushAfterNWrites=0;this.root=this.makeDir("",493)}makeDir(t,n){let r=Date.now();return{type:"directory",name:t,mode:n,createdAt:r,updatedAt:r,children:Object.create(null),_childCount:0}}makeFile(t,n,r,i){let s=Date.now();return{type:"file",name:t,content:n,mode:r,compressed:i,createdAt:s,updatedAt:s}}makeStub(t,n,r){let i=Date.now();return{type:"stub",name:t,stubContent:n,mode:r,createdAt:i,updatedAt:i}}writeStub(t,n,r=420){let i=H(t),{parent:s,name:o}=Ae(this.root,i,!0,l=>this.mkdirRecursive(l,493)),a=s.children[o];if(a?.type==="directory")throw new Error(`Cannot write stub '${i}': path is a directory.`);a?.type!=="file"&&(a||s._childCount++,s.children[o]=this.makeStub(o,n,r))}mkdirRecursive(t,n){let r=H(t);if(r==="/")return;let i=r.split("/").filter(Boolean),s=this.root,o="";for(let a of i){o+=`/${a}`;let l=s.children[a];if(!l)l=this.makeDir(a,n),s.children[a]=l,s._childCount++,this.emit("dir:create",{path:o,mode:n}),this._journal({op:W.MKDIR,path:o,mode:n});else if(l.type!=="directory")throw new Error(`Cannot create directory '${o}': path is a file.`);s=l}}async restoreMirror(){if(!(this.mode!=="fs"||!this.snapshotFile)){if(!B.existsSync(this.snapshotFile)){if(this.journalFile){let t=Ht(this.journalFile);t.length>0&&this._replayJournal(t)}return}try{let t=B.readFileSync(this.snapshotFile);if(xs(t))this.root=Ne(t);else{let n=JSON.parse(t.toString("utf8"));this.root=this.deserializeDir(n.root,""),console.info("[VirtualFileSystem] Migrating legacy JSON snapshot to binary format.")}if(this.emit("snapshot:restore",{path:this.snapshotFile}),this.journalFile){let n=Ht(this.journalFile);n.length>0&&this._replayJournal(n)}}catch(t){console.warn(`[VirtualFileSystem] Could not restore snapshot from ${this.snapshotFile}:`,t instanceof Error?t.message:String(t))}}}async flushMirror(){if(this.mode!=="fs"||!this.snapshotFile){this.emit("mirror:flush");return}let t=ce.dirname(this.snapshotFile);B.mkdirSync(t,{recursive:!0});let n=this.root,r=Wt(n);B.writeFileSync(this.snapshotFile,r),this.journalFile&&vs(this.journalFile),this._dirty=!1,this._writesSinceFlush=0,this.emit("mirror:flush",{path:this.snapshotFile}),this.evictLargeFiles()}getMode(){return this.mode}getSnapshotPath(){return this.snapshotFile}async _autoFlush(){this._dirty&&await this.flushMirror()}_markDirty(){this._dirty=!0,this.flushAfterNWrites>0&&(this._writesSinceFlush++,this._writesSinceFlush>=this.flushAfterNWrites&&(this._writesSinceFlush=0,this._autoFlush()))}async stopAutoFlush(){this._flushTimer!==null&&(clearInterval(this._flushTimer),this._flushTimer=null),this._dirty&&await this.flushMirror()}importRootTree(t){let n=this._replayMode;this._replayMode=!0;try{this.root=t}finally{this._replayMode=n}}mergeRootTree(t){let n=this._replayMode;this._replayMode=!0;try{this._mergeDir(this.root,t)}finally{this._replayMode=n}}_mergeDir(t,n){for(let[r,i]of Object.entries(n.children)){let s=t.children[r];i.type==="directory"?s?s.type==="directory"&&this._mergeDir(s,i):(t.children[r]=i,t._childCount++):s||(t.children[r]=i,t._childCount++)}}encodeBinary(){return Wt(this.root)}releaseTree(){this.root=this.makeDir("",493)}_replayMode=!1;_journal(t){this.journalFile&&!this._replayMode&&(ws(this.journalFile,t),this._markDirty())}_replayJournal(t){this._replayMode=!0;try{for(let n of t)try{n.op===W.WRITE?this.writeFile(n.path,n.content??Buffer.alloc(0),{mode:n.mode}):n.op===W.MKDIR?this.mkdir(n.path,n.mode):n.op===W.REMOVE?this.exists(n.path)&&this.remove(n.path,{recursive:!0}):n.op===W.CHMOD?this.exists(n.path)&&this.chmod(n.path,n.mode??420):n.op===W.MOVE?this.exists(n.path)&&n.dest&&this.move(n.path,n.dest):n.op===W.SYMLINK&&n.dest&&this.symlink(n.dest,n.path)}catch{}}finally{this._replayMode=!1}}evictLargeFiles(){!this.snapshotFile||this.evictionThreshold===0||B.existsSync(this.snapshotFile)&&this._evictDir(this.root)}_evictDir(t){for(let n of Object.values(t.children))if(n.type==="directory")this._evictDir(n);else if(n.type==="file"&&!n.evicted){let r=n.compressed?n.size??n.content.length*2:n.content.length;r>this.evictionThreshold&&(n.size=r,n.content=Buffer.alloc(0),n.evicted=!0)}}_reloadEvicted(t,n){if(!(!t.evicted||!this.snapshotFile)&&B.existsSync(this.snapshotFile))try{let r=B.readFileSync(this.snapshotFile),i=Ne(r),s=n.split("/").filter(Boolean),o=i;for(let a of s){if(o.type!=="directory")return;let l=o.children[a];if(!l)return;o=l}o.type==="file"&&(t.content=o.content,t.compressed=o.compressed,t.evicted=void 0)}catch{}}mount(t,n,{readOnly:r=!0}={}){if(e.isBrowser)return;let i=H(t),s=ce.resolve(n);if(!B.existsSync(s))throw new Error(`VirtualFileSystem.mount: host path does not exist: "${s}"`);if(!B.statSync(s).isDirectory())throw new Error(`VirtualFileSystem.mount: host path is not a directory: "${s}"`);this.mkdir(i),this.mounts.set(i,{hostPath:s,readOnly:r}),this.emit("mount",{vPath:i,hostPath:s,readOnly:r})}unmount(t){let n=H(t);this.mounts.delete(n)&&this.emit("unmount",{vPath:n})}getMounts(){return[...this.mounts.entries()].map(([t,n])=>({vPath:t,...n}))}resolveMount(t){let n=H(t),r=[...this.mounts.entries()].sort(([i],[s])=>s.length-i.length);for(let[i,s]of r)if(n===i||n.startsWith(`${i}/`)){let o=n.slice(i.length).replace(/^\//,""),a=o?ce.join(s.hostPath,o):s.hostPath;return{hostPath:s.hostPath,readOnly:s.readOnly,relPath:o,fullHostPath:a}}return null}mkdir(t,n=493){let r=H(t),i=(()=>{try{return oe(this.root,r)}catch{return null}})();if(i&&i.type!=="directory")throw new Error(`Cannot create directory '${r}': path is a file.`);this.mkdirRecursive(r,n)}writeFile(t,n,r={}){let i=this.resolveMount(t);if(i){if(i.readOnly)throw new Error(`EROFS: read-only file system, open '${i.fullHostPath}'`);let m=ce.dirname(i.fullHostPath);B.existsSync(m)||B.mkdirSync(m,{recursive:!0}),B.writeFileSync(i.fullHostPath,Buffer.isBuffer(n)?n:Buffer.from(n,"utf8"));return}let s=H(t),{parent:o,name:a}=Ae(this.root,s,!0,m=>this.mkdirRecursive(m,493)),l=o.children[a];if(l?.type==="directory")throw new Error(`Cannot write file '${s}': path is a directory.`);let c=Buffer.isBuffer(n)?n:Buffer.from(n,"utf8"),u=r.compress??!1,d=u?Cs(c):c,p=r.mode??420;if(l&&l.type==="file"){let m=l;m.content=d,m.compressed=u,m.mode=p,m.updatedAt=Date.now()}else l||o._childCount++,o.children[a]=this.makeFile(a,d,p,u);this.emit("file:write",{path:s,size:d.length}),this._journal({op:W.WRITE,path:s,content:c,mode:p})}readFile(t){let n=this.resolveMount(t);if(n){if(!B.existsSync(n.fullHostPath))throw new Error(`ENOENT: no such file or directory, open '${n.fullHostPath}'`);return B.readFileSync(n.fullHostPath,"utf8")}let r=H(t),i=oe(this.root,r);if(i.type==="stub")return this.emit("file:read",{path:r,size:i.stubContent.length}),i.stubContent;if(i.type!=="file")throw new Error(`Cannot read '${t}': not a file.`);let s=i;s.evicted&&this._reloadEvicted(s,r);let o=s.compressed?qt(s.content):s.content;return this.emit("file:read",{path:r,size:o.length}),o.toString("utf8")}readFileRaw(t){let n=this.resolveMount(t);if(n){if(!B.existsSync(n.fullHostPath))throw new Error(`ENOENT: no such file or directory, open '${n.fullHostPath}'`);return B.readFileSync(n.fullHostPath)}let r=H(t),i=oe(this.root,r);if(i.type==="stub"){let a=Buffer.from(i.stubContent,"utf8");return this.emit("file:read",{path:r,size:a.length}),a}if(i.type!=="file")throw new Error(`Cannot read '${t}': not a file.`);let s=i;s.evicted&&this._reloadEvicted(s,r);let o=s.compressed?qt(s.content):s.content;return this.emit("file:read",{path:r,size:o.length}),o}exists(t){let n=this.resolveMount(t);if(n)return B.existsSync(n.fullHostPath);try{return oe(this.root,H(t)),!0}catch{return!1}}chmod(t,n){let r=H(t);oe(this.root,r).mode=n,this._journal({op:W.CHMOD,path:r,mode:n})}stat(t){let n=this.resolveMount(t);if(n){if(!B.existsSync(n.fullHostPath))throw new Error(`ENOENT: stat '${n.fullHostPath}'`);let a=B.statSync(n.fullHostPath),l=n.relPath.split("/").pop()??n.fullHostPath.split("/").pop()??"",c=a.mtime;return a.isDirectory()?{type:"directory",name:l,path:H(t),mode:493,createdAt:a.birthtime,updatedAt:c,childrenCount:B.readdirSync(n.fullHostPath).length}:{type:"file",name:l,path:H(t),mode:n.readOnly?292:420,createdAt:a.birthtime,updatedAt:c,compressed:!1,size:a.size}}let r=H(t),i=oe(this.root,r),s=r==="/"?"":ce.posix.basename(r);if(i.type==="stub"){let a=i;return{type:"file",name:s,path:r,mode:a.mode,createdAt:new Date(a.createdAt),updatedAt:new Date(a.updatedAt),compressed:!1,size:a.stubContent.length}}if(i.type==="file"){let a=i;return{type:"file",name:s,path:r,mode:a.mode,createdAt:new Date(a.createdAt),updatedAt:new Date(a.updatedAt),compressed:a.compressed,size:a.evicted?a.size??0:a.content.length}}let o=i;return{type:"directory",name:s,path:r,mode:o.mode,createdAt:new Date(o.createdAt),updatedAt:new Date(o.updatedAt),childrenCount:o._childCount}}list(t="/"){let n=this.resolveMount(t);if(n){if(!B.existsSync(n.fullHostPath))return[];try{return B.readdirSync(n.fullHostPath).sort()}catch{return[]}}let r=H(t),i=oe(this.root,r);if(i.type!=="directory")throw new Error(`Cannot list '${t}': not a directory.`);return Object.keys(i.children).sort()}tree(t="/"){let n=H(t),r=oe(this.root,n);if(r.type!=="directory")throw new Error(`Cannot render tree for '${t}': not a directory.`);let i=t==="/"?"/":ce.posix.basename(n);return this.renderTreeLines(r,i)}renderTreeLines(t,n){let r=[n],i=Object.keys(t.children).sort();for(let s=0;s<i.length;s++){let o=i[s],a=t.children[o],l=s===i.length-1,c=l?"\u2514\u2500\u2500 ":"\u251C\u2500\u2500 ",u=l?" ":"\u2502 ";if(r.push(`${c}${o}`),a.type==="directory"){let d=this.renderTreeLines(a,"").split(`
|
|
1033
1033
|
`).slice(1).map(p=>`${u}${p}`);r.push(...d)}}return r.join(`
|
|
1034
1034
|
`)}getUsageBytes(t="/"){return this.computeUsage(oe(this.root,H(t)))}computeUsage(t){if(t.type==="file")return t.content.length;if(t.type==="stub")return t.stubContent.length;let n=0;for(let r of Object.values(t.children))n+=this.computeUsage(r);return n}compressFile(t){let n=oe(this.root,H(t));if(n.type!=="file")throw new Error(`Cannot compress '${t}': not a file.`);let r=n;r.compressed||(r.content=Cs(r.content),r.compressed=!0,r.updatedAt=Date.now())}decompressFile(t){let n=oe(this.root,H(t));if(n.type!=="file")throw new Error(`Cannot decompress '${t}': not a file.`);let r=n;r.compressed&&(r.content=qt(r.content),r.compressed=!1,r.updatedAt=Date.now())}symlink(t,n){let r=H(n),i=t.startsWith("/")?H(t):t,{parent:s,name:o}=Ae(this.root,r,!0,l=>this.mkdirRecursive(l,493)),a={type:"file",name:o,content:Buffer.from(i,"utf8"),mode:41471,compressed:!1,createdAt:Date.now(),updatedAt:Date.now()};s.children[o]=a,s._childCount++,this._journal({op:W.SYMLINK,path:r,dest:i}),this.emit("symlink:create",{link:r,target:i})}isSymlink(t){try{let n=oe(this.root,H(t));return n.type==="file"&&n.mode===41471}catch{return!1}}resolveSymlink(t,n=8){let r=H(t);for(let i=0;i<n;i++){try{let s=oe(this.root,r);if(s.type==="file"&&s.mode===41471){let o=s.content.toString("utf8");r=o.startsWith("/")?o:H(ce.posix.join(ce.posix.dirname(r),o));continue}}catch{break}return r}throw new Error(`Too many levels of symbolic links: ${t}`)}remove(t,n={}){let r=this.resolveMount(t);if(r){if(r.readOnly)throw new Error(`EROFS: read-only file system, unlink '${r.fullHostPath}'`);if(!B.existsSync(r.fullHostPath))throw new Error(`ENOENT: no such file or directory, unlink '${r.fullHostPath}'`);B.statSync(r.fullHostPath).isDirectory()?B.rmSync(r.fullHostPath,{recursive:n.recursive??!1}):B.unlinkSync(r.fullHostPath);return}let i=H(t);if(i==="/")throw new Error("Cannot remove root directory.");let s=oe(this.root,i);if(s.type==="directory"){let l=s;if(!n.recursive&&l._childCount>0)throw new Error(`Directory '${i}' is not empty. Use recursive option.`)}let{parent:o,name:a}=Ae(this.root,i,!1,()=>{});delete o.children[a],o._childCount--,this.emit("node:remove",{path:i}),this._journal({op:W.REMOVE,path:i})}move(t,n){let r=H(t),i=H(n);if(r==="/"||i==="/")throw new Error("Cannot move root directory.");let s=oe(this.root,r);if(this.exists(i))throw new Error(`Destination '${i}' already exists.`);this.mkdirRecursive(ce.posix.dirname(i),493);let{parent:o,name:a}=Ae(this.root,i,!1,()=>{}),{parent:l,name:c}=Ae(this.root,r,!1,()=>{});delete l.children[c],l._childCount--,s.name=a,o.children[a]=s,o._childCount++,this._journal({op:W.MOVE,path:r,dest:i})}toSnapshot(){return{root:this.serializeDir(this.root)}}serializeDir(t){let n=[];for(let r of Object.values(t.children))r.type==="stub"?n.push({type:"file",name:r.name,mode:r.mode,createdAt:new Date(r.createdAt).toISOString(),updatedAt:new Date(r.updatedAt).toISOString(),compressed:!1,contentBase64:Buffer.from(r.stubContent,"utf8").toString("base64")}):r.type==="file"?n.push(this.serializeFile(r)):n.push(this.serializeDir(r));return{type:"directory",name:t.name,mode:t.mode,createdAt:new Date(t.createdAt).toISOString(),updatedAt:new Date(t.updatedAt).toISOString(),children:n}}serializeFile(t){return{type:"file",name:t.name,mode:t.mode,createdAt:new Date(t.createdAt).toISOString(),updatedAt:new Date(t.updatedAt).toISOString(),compressed:t.compressed,contentBase64:t.content.toString("base64")}}static fromSnapshot(t){let n=new e;return n.root=n.deserializeDir(t.root,""),n}importSnapshot(t){this.root=this.deserializeDir(t.root,""),this.emit("snapshot:import")}deserializeDir(t,n){let r={type:"directory",name:n,mode:t.mode,createdAt:Date.parse(t.createdAt),updatedAt:Date.parse(t.updatedAt),children:Object.create(null),_childCount:0};for(let i of t.children){if(i.type==="file"){let s=i;r.children[s.name]={type:"file",name:s.name,mode:s.mode,createdAt:Date.parse(s.createdAt),updatedAt:Date.parse(s.updatedAt),compressed:s.compressed,content:Buffer.from(s.contentBase64,"base64")}}else{let s=this.deserializeDir(i,i.name);r.children[i.name]=s}r._childCount++}return r}},bt=Gt;function h(e,t,n=493){e.exists(t)||e.mkdir(t,n)}function f(e,t,n,r=420){e.writeStub(t,n,r)}function $(e,t,n){e.writeFile(t,n)}function Xi(e){let t=2166136261;for(let n=0;n<e.length;n++)t^=e.charCodeAt(n),t=Math.imul(t,16777619);return t>>>0}function eo(e,t,n){h(e,"/etc"),f(e,"/etc/os-release",`${['NAME="Fortune GNU/Linux"',`PRETTY_NAME="${n.os}"`,"ID=fortune","ID_LIKE=debian",'HOME_URL="https://github.com/itsrealfortune/typescript-virtual-container"',"VERSION_CODENAME=nyx",'VERSION_ID="24.04"',"FORTUNE_CODENAME=nyx"].join(`
|
|
1035
1035
|
`)}
|
|
@@ -1703,7 +1703,7 @@ echo 'neofetch: virtual stub'
|
|
|
1703
1703
|
`),exitCode:0}}remove(t,n={}){let r=[],i=[];for(let s of t){let o=this.installed.get(s.toLowerCase());o?i.push(o):r.push(`Package '${s}' is not installed, so not removed`)}if(i.length===0)return{output:r.join(`
|
|
1704
1704
|
`)||"Nothing to remove.",exitCode:0};n.quiet||r.push("Reading package lists... Done","Building dependency tree... Done","The following packages will be REMOVED:",` ${i.map(s=>s.name).join(" ")}`,`0 upgraded, 0 newly installed, ${i.length} to remove and 0 not upgraded.`);for(let s of i){n.quiet||r.push(`Removing ${s.name} (${s.version}) ...`);for(let a of s.files)if(!(!n.purge&&(a.startsWith("/etc/")||a.endsWith(".conf"))))try{this.vfs.exists(a)&&this.vfs.remove(a)}catch{}this.findInRegistry(s.name)?.onRemove?.(this.vfs),this.installed.delete(s.name),this.log(`remove ${s.name} ${s.version}`)}return this.aptLog("remove",i.map(s=>s.name)),this.persist(),{output:r.join(`
|
|
1705
1705
|
`),exitCode:0}}search(t){let n=t.toLowerCase();return Kt.filter(r=>r.name.includes(n)||r.description.toLowerCase().includes(n)||(r.shortDesc??"").toLowerCase().includes(n)).sort((r,i)=>r.name.localeCompare(i.name))}show(t){let n=this.findInRegistry(t);if(!n)return null;let r=this.installed.get(t);return[`Package: ${n.name}`,`Version: ${n.version}`,`Architecture: ${n.architecture??"amd64"}`,`Maintainer: ${n.maintainer??"Fortune Maintainers <pkg@fortune.local>"}`,`Installed-Size: ${n.installedSizeKb??0}`,`Depends: ${(n.depends??[]).join(", ")||"(none)"}`,`Section: ${n.section??"misc"}`,"Priority: optional",`Description: ${n.description}`,`Status: ${r?"install ok installed":"install ok not-installed"}`].join(`
|
|
1706
|
-
`)}};import{createHash as Is,randomBytes as ho,randomUUID as go,scryptSync as yo,timingSafeEqual as So}from"node:crypto";import{EventEmitter as bo}from"node:events";import*as _s from"node:path";function xo(){let e=process.env.SSH_MIMIC_FAST_PASSWORD_HASH;return!!e&&!["0","false","no","off"].includes(e.toLowerCase())}var
|
|
1706
|
+
`)}};import{createHash as Is,randomBytes as ho,randomUUID as go,scryptSync as yo,timingSafeEqual as So}from"node:crypto";import{EventEmitter as bo}from"node:events";import*as _s from"node:path";function xo(){let e=process.env.SSH_MIMIC_FAST_PASSWORD_HASH;return!!e&&!["0","false","no","off"].includes(e.toLowerCase())}var re=wt("VirtualUserManager"),Ct=class e extends bo{constructor(n,r=!0){super();this.vfs=n;this.autoSudoForNewUsers=r;re.mark("constructor")}vfs;autoSudoForNewUsers;static recordCache=new Map;static fastPasswordHash=xo();usersPath="/etc/htpasswd";sudoersPath="/etc/sudoers";quotasPath="/etc/quotas";authDirPath="/.virtual-env-js/.auth";users=new Map;sudoers=new Set;quotas=new Map;activeSessions=new Map;nextTty=0;async initialize(){re.mark("initialize"),this.loadFromVfs(),this.loadSudoersFromVfs(),this.loadQuotasFromVfs();let n=!1;this.users.has("root")||(this.users.set("root",this.createRecord("root","")),n=!0),this.sudoers.add("root");let r="/root";this.vfs.exists(r)||(this.vfs.mkdir(r,493),this.vfs.writeFile(`${r}/README.txt`,"Welcome to the virtual environment, root")),n&&await this.persist(),this.emit("initialized")}async setQuotaBytes(n,r){if(re.mark("setQuotaBytes"),this.validateUsername(n),!this.users.has(n))throw new Error(`quota: user '${n}' does not exist`);if(!Number.isFinite(r)||r<0)throw new Error("quota: maxBytes must be a non-negative number");this.quotas.set(n,Math.floor(r)),await this.persist()}async clearQuota(n){re.mark("clearQuota"),this.validateUsername(n),this.quotas.delete(n),await this.persist()}getQuotaBytes(n){return re.mark("getQuotaBytes"),this.quotas.get(n)??null}getUsageBytes(n){re.mark("getUsageBytes");let r=n==="root"?"/root":`/home/${n}`;return this.vfs.exists(r)?this.vfs.getUsageBytes(r):0}assertWriteWithinQuota(n,r,i){re.mark("assertWriteWithinQuota");let s=this.quotas.get(n);if(s===void 0)return;let o=As(r),a=As(n==="root"?"/root":`/home/${n}`);if(!(o===a||o.startsWith(`${a}/`)))return;let c=this.getUsageBytes(n),u=0;if(this.vfs.exists(o)){let m=this.vfs.stat(o);m.type==="file"&&(u=m.size)}let d=Buffer.isBuffer(i)?i.length:Buffer.byteLength(i,"utf8"),p=c-u+d;if(p>s)throw new Error(`quota exceeded for '${n}': ${p}/${s} bytes`)}verifyPassword(n,r){re.mark("verifyPassword");let i=this.users.get(n);if(!i)return this.hashPassword(r,""),!1;let s=this.hashPassword(r,i.salt),o=i.passwordHash;try{let a=Buffer.from(s,"hex"),l=Buffer.from(o,"hex");return a.length!==l.length?!1:So(a,l)}catch{return s===o}}async addUser(n,r){if(re.mark("addUser"),this.validateUsername(n),this.validatePassword(r),this.users.has(n))return;this.users.set(n,this.createRecord(n,r)),this.autoSudoForNewUsers&&this.sudoers.add(n);let i=n==="root"?"/root":`/home/${n}`;this.vfs.exists(i)||(this.vfs.mkdir(i,493),this.vfs.writeFile(`${i}/README.txt`,`Welcome to the virtual environment, ${n}`)),await this.persist(),this.emit("user:add",{username:n})}getPasswordHash(n){re.mark("getPasswordHash");let r=this.users.get(n);return r?r.passwordHash:null}async setPassword(n,r){if(re.mark("setPassword"),this.validateUsername(n),this.validatePassword(r),!this.users.has(n))throw new Error(`passwd: user '${n}' does not exist`);this.users.set(n,this.createRecord(n,r)),await this.persist()}async deleteUser(n){if(re.mark("deleteUser"),this.validateUsername(n),n==="root")throw new Error("deluser: cannot delete root");if(!this.users.delete(n))throw new Error(`deluser: user '${n}' does not exist`);this.sudoers.delete(n),this.emit("user:delete",{username:n}),await this.persist()}isSudoer(n){return re.mark("isSudoer"),this.sudoers.has(n)}async addSudoer(n){if(re.mark("addSudoer"),this.validateUsername(n),!this.users.has(n))throw new Error(`sudoers: user '${n}' does not exist`);this.sudoers.add(n),await this.persist()}async removeSudoer(n){if(re.mark("removeSudoer"),this.validateUsername(n),n==="root")throw new Error("sudoers: cannot remove root");this.sudoers.delete(n),await this.persist()}registerSession(n,r){re.mark("registerSession");let i={id:go(),username:n,tty:`pts/${this.nextTty++}`,remoteAddress:r,startedAt:new Date().toISOString()};return this.activeSessions.set(i.id,i),this.emit("session:register",{sessionId:i.id,username:n,remoteAddress:r}),i}unregisterSession(n){if(re.mark("unregisterSession"),!n)return;let r=this.activeSessions.get(n);this.activeSessions.delete(n),r&&this.emit("session:unregister",{sessionId:n,username:r.username}),this.activeSessions.delete(n)}updateSession(n,r,i){if(re.mark("updateSession"),!n)return;let s=this.activeSessions.get(n);s&&this.activeSessions.set(n,{...s,username:r,remoteAddress:i})}listActiveSessions(){return re.mark("listActiveSessions"),Array.from(this.activeSessions.values()).sort((n,r)=>n.startedAt.localeCompare(r.startedAt))}listUsers(){return Array.from(this.users.keys()).sort()}loadFromVfs(){if(this.users.clear(),!this.vfs.exists(this.usersPath))return;let n=this.vfs.readFile(this.usersPath);for(let r of n.split(`
|
|
1707
1707
|
`)){let i=r.trim();if(i.length===0)continue;let s=i.split(":");if(s.length<3)continue;let[o,a,l]=s;!o||!a||!l||this.users.set(o,{username:o,salt:a,passwordHash:l})}}loadSudoersFromVfs(){if(this.sudoers.clear(),!this.vfs.exists(this.sudoersPath))return;let n=this.vfs.readFile(this.sudoersPath);for(let r of n.split(`
|
|
1708
1708
|
`)){let i=r.trim();i.length>0&&this.sudoers.add(i)}}loadQuotasFromVfs(){if(this.quotas.clear(),!this.vfs.exists(this.quotasPath))return;let n=this.vfs.readFile(this.quotasPath);for(let r of n.split(`
|
|
1709
1709
|
`)){let i=r.trim();if(i.length===0)continue;let[s,o]=i.split(":"),a=Number.parseInt(o??"",10);!s||!Number.isFinite(a)||a<0||this.quotas.set(s,a)}}async persist(){this.vfs.exists(this.authDirPath)||this.vfs.mkdir(this.authDirPath,448);let n=Array.from(this.users.values()).sort((o,a)=>o.username.localeCompare(a.username)).map(o=>[o.username,o.salt,o.passwordHash].join(":")).join(`
|
|
@@ -1712,7 +1712,7 @@ echo 'neofetch: virtual stub'
|
|
|
1712
1712
|
`),s=!1;s=this.writeIfChanged(this.usersPath,n.length>0?`${n}
|
|
1713
1713
|
`:"",384)||s,s=this.writeIfChanged(this.sudoersPath,r.length>0?`${r}
|
|
1714
1714
|
`:"",384)||s,s=this.writeIfChanged(this.quotasPath,i.length>0?`${i}
|
|
1715
|
-
`:"",384)||s,s&&await this.vfs.flushMirror()}writeIfChanged(n,r,i){return this.vfs.exists(n)&&this.vfs.readFile(n)===r?(this.vfs.chmod(n,i),!1):(this.vfs.writeFile(n,r,{mode:i}),!0)}createRecord(n,r){let i=Is("sha256").update(n).update(":").update(r).digest("hex"),s=e.recordCache.get(i);if(s)return s;let o=ho(16).toString("hex"),a={username:n,salt:o,passwordHash:this.hashPassword(r,o)};return e.recordCache.set(i,a),a}hasPassword(n){
|
|
1715
|
+
`:"",384)||s,s&&await this.vfs.flushMirror()}writeIfChanged(n,r,i){return this.vfs.exists(n)&&this.vfs.readFile(n)===r?(this.vfs.chmod(n,i),!1):(this.vfs.writeFile(n,r,{mode:i}),!0)}createRecord(n,r){let i=Is("sha256").update(n).update(":").update(r).digest("hex"),s=e.recordCache.get(i);if(s)return s;let o=ho(16).toString("hex"),a={username:n,salt:o,passwordHash:this.hashPassword(r,o)};return e.recordCache.set(i,a),a}hasPassword(n){re.mark("hasPassword");let r=this.users.get(n);if(!r)return!1;let i=this.hashPassword("",r.salt);return r.passwordHash===i?!1:!!r.passwordHash}hashPassword(n,r=""){return e.fastPasswordHash?Is("sha256").update(r).update(n).digest("hex"):yo(n,r||"",32).toString("hex")}validateUsername(n){if(!n||n.trim()==="")throw new Error("invalid username");if(!/^[a-z_][a-z0-9_-]{0,31}$/i.test(n))throw new Error("invalid username")}validatePassword(n){if(!n||n.trim()==="")throw new Error("invalid password")}authorizedKeys=new Map;addAuthorizedKey(n,r,i){re.mark("addAuthorizedKey");let s=this.authorizedKeys.get(n)??[];s.push({algo:r,data:i}),this.authorizedKeys.set(n,s),this.emit("key:add",{username:n,algo:r})}removeAuthorizedKeys(n){this.authorizedKeys.delete(n),this.emit("key:remove",{username:n})}getAuthorizedKeys(n){return this.authorizedKeys.get(n)??[]}};function As(e){let t=_s.posix.normalize(e);return t.startsWith("/")?t:`/${t}`}import{EventEmitter as wo}from"node:events";var Pt=class extends wo{vfs;idleThresholdMs;checkIntervalMs;_state="active";_lastActivity=Date.now();_frozenBuffer=null;_checkTimer=null;constructor(t,n={}){super(),this.vfs=t,this.idleThresholdMs=n.idleThresholdMs??6e4,this.checkIntervalMs=n.checkIntervalMs??15e3}start(){this._checkTimer||(this._lastActivity=Date.now(),this._checkTimer=setInterval(()=>this._check(),this.checkIntervalMs),typeof this._checkTimer=="object"&&this._checkTimer!==null&&"unref"in this._checkTimer&&this._checkTimer.unref())}async stop(){this._checkTimer&&(clearInterval(this._checkTimer),this._checkTimer=null),this._state==="frozen"&&this._thaw()}ping(){this._lastActivity=Date.now(),this._state==="frozen"&&this._thaw()}get state(){return this._state}get idleMs(){return Date.now()-this._lastActivity}_check(){this._state!=="frozen"&&Date.now()-this._lastActivity>=this.idleThresholdMs&&this._freeze()}async _freeze(){this._state!=="frozen"&&(await this.vfs.stopAutoFlush(),this._frozenBuffer=this.vfs.encodeBinary(),this.vfs.releaseTree(),this._state="frozen",this.emit("freeze"))}_thaw(){if(this._state!=="frozen"||!this._frozenBuffer)return;let t=Ne(this._frozenBuffer);this.vfs.importRootTree(t),this._frozenBuffer=null,this._state="active",this.emit("thaw")}};import{readFile as vo,unlink as Co,writeFile as Po}from"node:fs/promises";import*as Jt from"node:path";function Os(e,t,n,r,i,s="unknown",o={cols:80,rows:24},a){let l="",c=0,u=$o(a.vfs,n),d=null,p="",m=q(n),g=Te(n,r),S=null,C=null,P=()=>{let O=q(n),U=m===O?"~":Jt.posix.basename(m)||"/";return yt(n,r,U)},x=Array.from(new Set(Ve())).sort();console.log(`[${i}] Shell started for user '${n}' at ${s}`),(async()=>{let O=`${q(n)}/.bashrc`;if(a.vfs.exists(O))try{let U=a.vfs.readFile(O);for(let z of U.split(`
|
|
1716
1716
|
`)){let D=z.trim();!D||D.startsWith("#")||await Z(D,n,r,"shell",m,a,void 0,g)}}catch{}})();function _(){let O=P();t.write(`\r${O}${l}\x1B[K`);let U=l.length-c;U>0&&t.write(`\x1B[${U}D`)}function w(){t.write("\r\x1B[K")}function A(O){C={...O,buffer:""},w(),t.write(O.prompt)}async function N(O){if(!C)return;let U=C;if(C=null,!O){t.write(`\r
|
|
1717
1717
|
Sorry, try again.\r
|
|
1718
1718
|
`),_();return}if(!U.commandLine){n=U.targetUser,U.loginShell&&(m=q(n)),a.users.updateSession(i,n,s),t.write(`\r
|
|
@@ -1720,24 +1720,24 @@ Sorry, try again.\r
|
|
|
1720
1720
|
`),D.openEditor){await E(D.openEditor.targetPath,D.openEditor.initialContent,D.openEditor.tempPath);return}if(D.openHtop){await T();return}D.clearScreen&&t.write("\x1B[2J\x1B[H"),D.stdout&&t.write(`${Ye(D.stdout)}\r
|
|
1721
1721
|
`),D.stderr&&t.write(`${Ye(D.stderr)}\r
|
|
1722
1722
|
`),D.switchUser?(n=D.switchUser,m=D.nextCwd??q(n),a.users.updateSession(i,n,s)):D.nextCwd&&(m=D.nextCwd),_()}async function b(){if(!S)return;let O=S;if(O.kind==="nano"){try{let U=await vo(O.tempPath,"utf8");a.writeFileAsUser(n,O.targetPath,U)}catch{}await Co(O.tempPath).catch(()=>{})}S=null,l="",c=0,t.write(`\r
|
|
1723
|
-
`),_()}async function E(O,U,z){a.vfs.exists(O)&&await Po(z,U,"utf8");let D=ht(z,o,t);D.on("error",
|
|
1723
|
+
`),_()}async function E(O,U,z){a.vfs.exists(O)&&await Po(z,U,"utf8");let D=ht(z,o,t);D.on("error",se=>{t.write(`nano: ${se.message}\r
|
|
1724
1724
|
`),b()}),D.on("close",()=>{b()}),S={kind:"nano",targetPath:O,tempPath:z,process:D}}async function T(){let O=await fs();if(!O){t.write(`htop: no child_process processes to display\r
|
|
1725
1725
|
`);return}let U=gs(O,o,t);U.on("error",z=>{t.write(`htop: ${z.message}\r
|
|
1726
|
-
`),b()}),U.on("close",()=>{b()}),S={kind:"htop",targetPath:"",tempPath:"",process:U}}function k(O){l=O,c=l.length,_()}function M(O){l=`${l.slice(0,c)}${O}${l.slice(c)}`,c+=O.length,_()}function F(O,U){let z=U;for(;z>0&&!/\s/.test(O[z-1]);)z-=1;let D=U;for(;D<O.length&&!/\s/.test(O[D]);)D+=1;return{start:z,end:D}}function Q(O){let U=O.lastIndexOf("/"),z=U>=0?O.slice(0,U+1):"",D=U>=0?O.slice(U+1):O,
|
|
1726
|
+
`),b()}),U.on("close",()=>{b()}),S={kind:"htop",targetPath:"",tempPath:"",process:U}}function k(O){l=O,c=l.length,_()}function M(O){l=`${l.slice(0,c)}${O}${l.slice(c)}`,c+=O.length,_()}function F(O,U){let z=U;for(;z>0&&!/\s/.test(O[z-1]);)z-=1;let D=U;for(;D<O.length&&!/\s/.test(O[D]);)D+=1;return{start:z,end:D}}function Q(O){let U=O.lastIndexOf("/"),z=U>=0?O.slice(0,U+1):"",D=U>=0?O.slice(U+1):O,se=ft(m,z||".");try{return a.vfs.list(se).filter(V=>!V.startsWith(".")).filter(V=>V.startsWith(D)).map(V=>{let ye=Jt.posix.join(se,V),Ee=a.vfs.stat(ye).type==="directory"?"/":"";return`${z}${V}${Ee}`}).sort()}catch{return[]}}function G(){let{start:O,end:U}=F(l,c),z=l.slice(O,c);if(z.length===0)return;let se=l.slice(0,O).trim().length===0?x.filter(me=>me.startsWith(z)):[],V=Q(z),ye=Array.from(new Set([...se,...V])).sort();if(ye.length!==0){if(ye.length===1){let me=ye[0],Ee=me.endsWith("/")?"":" ";l=`${l.slice(0,O)}${me}${Ee}${l.slice(U)}`,c=O+me.length+Ee.length,_();return}t.write(`\r
|
|
1727
1727
|
`),t.write(`${ye.join(" ")}\r
|
|
1728
|
-
`),_()}}function
|
|
1728
|
+
`),_()}}function ee(O){if(O.length===0)return;u.push(O),u.length>500&&(u=u.slice(u.length-500));let U=u.length>0?`${u.join(`
|
|
1729
1729
|
`)}
|
|
1730
|
-
`:"";a.vfs.writeFile(`${q(n)}/.bash_history`,U)}function ve(){let O=`${q(n)}/.lastlog.json`;if(!a.vfs.exists(O))return null;try{return JSON.parse(a.vfs.readFile(O))}catch{return null}}function ge(O){let U=`${q(n)}/.lastlog`;a.vfs.writeFile(U,JSON.stringify({at:O,from:s}))}function Ce(){let O=ve(),U=new Date().toISOString();t.write(gt(r,e,O)),ge(U)}Ce(),_(),t.on("data",async O=>{if(S){S.process.stdin.write(O);return}if(C){let z=O.toString("utf8");for(let D=0;D<z.length;D+=1){let
|
|
1731
|
-
`),_();return}if(
|
|
1730
|
+
`:"";a.vfs.writeFile(`${q(n)}/.bash_history`,U)}function ve(){let O=`${q(n)}/.lastlog.json`;if(!a.vfs.exists(O))return null;try{return JSON.parse(a.vfs.readFile(O))}catch{return null}}function ge(O){let U=`${q(n)}/.lastlog`;a.vfs.writeFile(U,JSON.stringify({at:O,from:s}))}function Ce(){let O=ve(),U=new Date().toISOString();t.write(gt(r,e,O)),ge(U)}Ce(),_(),t.on("data",async O=>{if(S){S.process.stdin.write(O);return}if(C){let z=O.toString("utf8");for(let D=0;D<z.length;D+=1){let se=z[D];if(se===""){C=null,t.write(`^C\r
|
|
1731
|
+
`),_();return}if(se==="\x7F"||se==="\b"){C.buffer=C.buffer.slice(0,-1);continue}if(se==="\r"||se===`
|
|
1732
1732
|
`){let V=C.buffer;if(C.buffer="",C.onPassword){let{result:me,nextPrompt:Ee}=await C.onPassword(V,a);t.write(`\r
|
|
1733
1733
|
`),me!==null?(C=null,me.stdout&&t.write(me.stdout.replace(/\n/g,`\r
|
|
1734
1734
|
`)),me.stderr&&t.write(me.stderr.replace(/\n/g,`\r
|
|
1735
|
-
`)),_()):(Ee&&(C.prompt=Ee),t.write(C.prompt));return}let ye=a.users.verifyPassword(C.username,V);await N(ye);return}
|
|
1736
|
-
`),
|
|
1737
|
-
`),t.exit(0),t.end();return}if(D===" "){G();continue}if(D==="\x1B"){let
|
|
1735
|
+
`)),_()):(Ee&&(C.prompt=Ee),t.write(C.prompt));return}let ye=a.users.verifyPassword(C.username,V);await N(ye);return}se>=" "&&(C.buffer+=se)}return}let U=O.toString("utf8");for(let z=0;z<U.length;z+=1){let D=U[z];if(D===""){l="",c=0,d=null,p="",t.write(`bye\r
|
|
1736
|
+
`),ee("bye"),t.write(`logout\r
|
|
1737
|
+
`),t.exit(0),t.end();return}if(D===" "){G();continue}if(D==="\x1B"){let se=U[z+1],V=U[z+2],ye=U[z+3];if(se==="["&&V){if(V==="A"){z+=2,u.length>0&&(d===null?(p=l,d=u.length-1):d>0&&(d-=1),k(u[d]??""));continue}if(V==="B"){z+=2,d!==null&&(d<u.length-1?(d+=1,k(u[d]??"")):(d=null,k(p)));continue}if(V==="C"){z+=2,c<l.length&&(c+=1,t.write("\x1B[C"));continue}if(V==="D"){z+=2,c>0&&(c-=1,t.write("\x1B[D"));continue}if(V==="3"&&ye==="~"){z+=3,c<l.length&&(l=`${l.slice(0,c)}${l.slice(c+1)}`,_());continue}}}if(D===""){l="",c=0,d=null,p="",t.write(`^C\r
|
|
1738
1738
|
`),_();continue}if(D==="\r"||D===`
|
|
1739
|
-
`){let
|
|
1740
|
-
`),
|
|
1739
|
+
`){let se=l.trim();if(l="",c=0,d=null,p="",t.write(`\r
|
|
1740
|
+
`),se.length>0){let V=await Promise.resolve(Z(se,n,r,"shell",m,a,void 0,g));if(ee(se),V.openEditor){await E(V.openEditor.targetPath,V.openEditor.initialContent,V.openEditor.tempPath);return}if(V.openHtop){await T();return}if(V.sudoChallenge){A(V.sudoChallenge);return}if(V.clearScreen&&t.write("\x1B[2J\x1B[H"),V.stdout&&t.write(`${Ye(V.stdout)}\r
|
|
1741
1741
|
`),V.stderr&&t.write(`${Ye(V.stderr)}\r
|
|
1742
1742
|
`),V.closeSession){t.write(`logout\r
|
|
1743
1743
|
`),t.exit(V.exitCode??0),t.end();return}V.nextCwd&&(m=V.nextCwd),V.switchUser&&(n=V.switchUser,m=V.nextCwd??q(n),a.users.updateSession(i,n,s),l="",c=0)}_();continue}if(D==="\x7F"||D==="\b"){c>0&&(l=`${l.slice(0,c-1)}${l.slice(c)}`,c-=1,_());continue}M(D)}}),t.on("close",()=>{S&&(S.process.kill("SIGTERM"),S=null)})}function $o(e,t){let n=`${q(t)}/.bash_history`;return e.exists(n)?e.readFile(n).split(`
|