@cloudflare/sandbox 0.0.0-d55b0f4 → 0.0.0-d81d2a5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/Dockerfile +36 -13
- package/README.md +784 -0
- package/container_src/bun.lock +122 -0
- package/container_src/handler/exec.ts +17 -14
- package/container_src/handler/process.ts +1 -1
- package/container_src/index.ts +171 -1
- package/container_src/jupyter-server.ts +336 -0
- package/container_src/mime-processor.ts +255 -0
- package/container_src/package.json +9 -0
- package/container_src/startup.sh +52 -0
- package/container_src/types.ts +8 -3
- package/package.json +1 -1
- package/src/client.ts +47 -64
- package/src/index.ts +13 -4
- package/src/interpreter-types.ts +383 -0
- package/src/interpreter.ts +150 -0
- package/src/jupyter-client.ts +266 -0
- package/src/sandbox.ts +281 -149
- package/src/types.ts +15 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lockfileVersion": 1,
|
|
3
|
+
"workspaces": {
|
|
4
|
+
"": {
|
|
5
|
+
"name": "sandbox-server",
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@jupyterlab/services": "^7.0.0",
|
|
8
|
+
"uuid": "^9.0.1",
|
|
9
|
+
"ws": "^8.16.0",
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"@types/uuid": "^9.0.7",
|
|
13
|
+
"@types/ws": "^8.5.10",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
"packages": {
|
|
18
|
+
"@jupyter/ydoc": ["@jupyter/ydoc@3.1.0", "", { "dependencies": { "@jupyterlab/nbformat": "^3.0.0 || ^4.0.0-alpha.21 || ^4.0.0", "@lumino/coreutils": "^1.11.0 || ^2.0.0", "@lumino/disposable": "^1.10.0 || ^2.0.0", "@lumino/signaling": "^1.10.0 || ^2.0.0", "y-protocols": "^1.0.5", "yjs": "^13.5.40" } }, "sha512-+hLNUBZr8Zz8NiuaoYKINDURDJHbjFGxg8EcSU52y+rBe412TsoFxfPSng4eP7w3cZFrVlm7D+8K0nAMHxj0ZQ=="],
|
|
19
|
+
|
|
20
|
+
"@jupyterlab/coreutils": ["@jupyterlab/coreutils@6.4.5", "", { "dependencies": { "@lumino/coreutils": "^2.2.1", "@lumino/disposable": "^2.1.4", "@lumino/signaling": "^2.1.4", "minimist": "~1.2.0", "path-browserify": "^1.0.0", "url-parse": "~1.5.4" } }, "sha512-fNEefnqTNP/3alrmGYDb0Mu1heS5Cu39FIDiDDoZuuWv4bsdE2xf7VaStuwjljsQm7VZwi5aeholi1+ciBkZKg=="],
|
|
21
|
+
|
|
22
|
+
"@jupyterlab/nbformat": ["@jupyterlab/nbformat@4.4.5", "", { "dependencies": { "@lumino/coreutils": "^2.2.1" } }, "sha512-VOlm1klsb1LUNp47AL8iDZPP71pXu9a+WqukJFuuWVxg//+iR6wdqTYcunE9Lx/7SZDqMsXGD+doBZC36Lzenw=="],
|
|
23
|
+
|
|
24
|
+
"@jupyterlab/services": ["@jupyterlab/services@7.4.5", "", { "dependencies": { "@jupyter/ydoc": "^3.0.4", "@jupyterlab/coreutils": "^6.4.5", "@jupyterlab/nbformat": "^4.4.5", "@jupyterlab/settingregistry": "^4.4.5", "@jupyterlab/statedb": "^4.4.5", "@lumino/coreutils": "^2.2.1", "@lumino/disposable": "^2.1.4", "@lumino/polling": "^2.1.4", "@lumino/properties": "^2.0.3", "@lumino/signaling": "^2.1.4", "ws": "^8.11.0" } }, "sha512-JEr8+4VS2MqFyYHh4AnpK/g5V0qRBpmnfXmU0p9YFjcIgGR365D8JF0880IJ0e8+jaW88gSAvZFB8x3o9xRoAQ=="],
|
|
25
|
+
|
|
26
|
+
"@jupyterlab/settingregistry": ["@jupyterlab/settingregistry@4.4.5", "", { "dependencies": { "@jupyterlab/nbformat": "^4.4.5", "@jupyterlab/statedb": "^4.4.5", "@lumino/commands": "^2.3.2", "@lumino/coreutils": "^2.2.1", "@lumino/disposable": "^2.1.4", "@lumino/signaling": "^2.1.4", "@rjsf/utils": "^5.13.4", "ajv": "^8.12.0", "json5": "^2.2.3" }, "peerDependencies": { "react": ">=16" } }, "sha512-6hEBq3qI99VZwO97W0AM0mP1is57bWC8Vk2xudic1a90wA9G6ovUBzayqSMm/6QhTuIbCY+vruznwhhsLrVMeg=="],
|
|
27
|
+
|
|
28
|
+
"@jupyterlab/statedb": ["@jupyterlab/statedb@4.4.5", "", { "dependencies": { "@lumino/commands": "^2.3.2", "@lumino/coreutils": "^2.2.1", "@lumino/disposable": "^2.1.4", "@lumino/properties": "^2.0.3", "@lumino/signaling": "^2.1.4" } }, "sha512-UpqhOujKwoWoxtNBL2Qk0nrw+ORLJ3ckwiJg2eA0CI+n5kO3IBYAnPzak0tSS0mQNspayXr3KAm4GQ80op5yuA=="],
|
|
29
|
+
|
|
30
|
+
"@lumino/algorithm": ["@lumino/algorithm@2.0.3", "", {}, "sha512-DIcF7cIrGEC1Wh8DNjdwaL7IdcNs4Jj1VjO/90oHefeQPszKgc6DSfCxvbQiRanKR6tl/JL7tq4ZRPZES2oVAA=="],
|
|
31
|
+
|
|
32
|
+
"@lumino/commands": ["@lumino/commands@2.3.2", "", { "dependencies": { "@lumino/algorithm": "^2.0.3", "@lumino/coreutils": "^2.2.1", "@lumino/disposable": "^2.1.4", "@lumino/domutils": "^2.0.3", "@lumino/keyboard": "^2.0.3", "@lumino/signaling": "^2.1.4", "@lumino/virtualdom": "^2.0.3" } }, "sha512-aAFEiUpp2hrkQU82Z85w1L80g0iDzsQRncLBa+pqVR/k0k1lz6H9F6xZ1ff+lBumZKKtsxBxNomvd0hfxLLqGw=="],
|
|
33
|
+
|
|
34
|
+
"@lumino/coreutils": ["@lumino/coreutils@2.2.1", "", { "dependencies": { "@lumino/algorithm": "^2.0.3" } }, "sha512-yij4TnxDIum7xfFUsVvZB0oLv4shs2mNbn3juwtEIsruvVBPmurNzKX0Y8z2QetbP2AZ6MSFtBzEKsihf0H0VA=="],
|
|
35
|
+
|
|
36
|
+
"@lumino/disposable": ["@lumino/disposable@2.1.4", "", { "dependencies": { "@lumino/signaling": "^2.1.4" } }, "sha512-qTJiDbglPE2QnG4x4gtBcRbcfKQibxyyinNGKcNDrcK2TGTbbhK5PpMQ8d70l2V2Xw2pb/LfksBAg5pxkJ/G4A=="],
|
|
37
|
+
|
|
38
|
+
"@lumino/domutils": ["@lumino/domutils@2.0.3", "", {}, "sha512-bXAbZg3mf2ZDNdBBpCGDike3U+osRGHePTh8H2Ud2KwaN4g/5IryFJm/TiO4K5IYs91bWF2Zqhf3FsdbZKHlGw=="],
|
|
39
|
+
|
|
40
|
+
"@lumino/keyboard": ["@lumino/keyboard@2.0.3", "", {}, "sha512-bU2OxAR8a9eNBdV0YFjU6/lVVpbOw1gM7yHOuDGDdNu4J0UpKapFoR9gopNGSaHTmTwDtx9RHdFfIAgHwjZ+VQ=="],
|
|
41
|
+
|
|
42
|
+
"@lumino/polling": ["@lumino/polling@2.1.4", "", { "dependencies": { "@lumino/coreutils": "^2.2.1", "@lumino/disposable": "^2.1.4", "@lumino/signaling": "^2.1.4" } }, "sha512-gSkxlIJ/4/esY2G7bsRrY9A4KimDMHTo0shaD+MCbhd09fZMCWJoDMcA447/dykB1rM5NXgugNLjpdGGL/e8cw=="],
|
|
43
|
+
|
|
44
|
+
"@lumino/properties": ["@lumino/properties@2.0.3", "", {}, "sha512-zkXIU5uYz/ScHCHGl5Bt4gMYsfPxZEduZd80zqDslBWvTIMro3NnzLe66NMnecbdr5N3hDJagYyA8//Qy3XjiA=="],
|
|
45
|
+
|
|
46
|
+
"@lumino/signaling": ["@lumino/signaling@2.1.4", "", { "dependencies": { "@lumino/algorithm": "^2.0.3", "@lumino/coreutils": "^2.2.1" } }, "sha512-nC5Z6d9om369Jkh1Vp3b7C89hV4cjr1fQDVcxhemyKXwc9r6VW7FpKixC+jElcAknP5KLj1FAa8Np+K06mMkEA=="],
|
|
47
|
+
|
|
48
|
+
"@lumino/virtualdom": ["@lumino/virtualdom@2.0.3", "", { "dependencies": { "@lumino/algorithm": "^2.0.3" } }, "sha512-q2C8eBxPvvOOQjN3KuxZ+vJi082JH/GF7KwMdaWsy5g+7wjKdnXPuLQFTBLOrVqIzmbxBDlLeFr93CEhdQXcyQ=="],
|
|
49
|
+
|
|
50
|
+
"@rjsf/utils": ["@rjsf/utils@5.24.12", "", { "dependencies": { "json-schema-merge-allof": "^0.8.1", "jsonpointer": "^5.0.1", "lodash": "^4.17.21", "lodash-es": "^4.17.21", "react-is": "^18.2.0" }, "peerDependencies": { "react": "^16.14.0 || >=17" } }, "sha512-fDwQB0XkjZjpdFUz5UAnuZj8nnbxDbX5tp+jTOjjJKw2TMQ9gFFYCQ12lSpdhezA2YgEGZfxyYTGW0DKDL5Drg=="],
|
|
51
|
+
|
|
52
|
+
"@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="],
|
|
53
|
+
|
|
54
|
+
"@types/uuid": ["@types/uuid@9.0.8", "", {}, "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA=="],
|
|
55
|
+
|
|
56
|
+
"@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
|
|
57
|
+
|
|
58
|
+
"ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
|
|
59
|
+
|
|
60
|
+
"compute-gcd": ["compute-gcd@1.2.1", "", { "dependencies": { "validate.io-array": "^1.0.3", "validate.io-function": "^1.0.2", "validate.io-integer-array": "^1.0.0" } }, "sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg=="],
|
|
61
|
+
|
|
62
|
+
"compute-lcm": ["compute-lcm@1.1.2", "", { "dependencies": { "compute-gcd": "^1.2.1", "validate.io-array": "^1.0.3", "validate.io-function": "^1.0.2", "validate.io-integer-array": "^1.0.0" } }, "sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ=="],
|
|
63
|
+
|
|
64
|
+
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
|
65
|
+
|
|
66
|
+
"fast-uri": ["fast-uri@3.0.6", "", {}, "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw=="],
|
|
67
|
+
|
|
68
|
+
"isomorphic.js": ["isomorphic.js@0.2.5", "", {}, "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw=="],
|
|
69
|
+
|
|
70
|
+
"json-schema-compare": ["json-schema-compare@0.2.2", "", { "dependencies": { "lodash": "^4.17.4" } }, "sha512-c4WYmDKyJXhs7WWvAWm3uIYnfyWFoIp+JEoX34rctVvEkMYCPGhXtvmFFXiffBbxfZsvQ0RNnV5H7GvDF5HCqQ=="],
|
|
71
|
+
|
|
72
|
+
"json-schema-merge-allof": ["json-schema-merge-allof@0.8.1", "", { "dependencies": { "compute-lcm": "^1.1.2", "json-schema-compare": "^0.2.2", "lodash": "^4.17.20" } }, "sha512-CTUKmIlPJbsWfzRRnOXz+0MjIqvnleIXwFTzz+t9T86HnYX/Rozria6ZVGLktAU9e+NygNljveP+yxqtQp/Q4w=="],
|
|
73
|
+
|
|
74
|
+
"json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
|
75
|
+
|
|
76
|
+
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
|
|
77
|
+
|
|
78
|
+
"jsonpointer": ["jsonpointer@5.0.1", "", {}, "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ=="],
|
|
79
|
+
|
|
80
|
+
"lib0": ["lib0@0.2.114", "", { "dependencies": { "isomorphic.js": "^0.2.4" }, "bin": { "0gentesthtml": "bin/gentesthtml.js", "0serve": "bin/0serve.js", "0ecdsa-generate-keypair": "bin/0ecdsa-generate-keypair.js" } }, "sha512-gcxmNFzA4hv8UYi8j43uPlQ7CGcyMJ2KQb5kZASw6SnAKAf10hK12i2fjrS3Cl/ugZa5Ui6WwIu1/6MIXiHttQ=="],
|
|
81
|
+
|
|
82
|
+
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
|
|
83
|
+
|
|
84
|
+
"lodash-es": ["lodash-es@4.17.21", "", {}, "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="],
|
|
85
|
+
|
|
86
|
+
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
|
|
87
|
+
|
|
88
|
+
"path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="],
|
|
89
|
+
|
|
90
|
+
"querystringify": ["querystringify@2.2.0", "", {}, "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="],
|
|
91
|
+
|
|
92
|
+
"react": ["react@19.1.1", "", {}, "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ=="],
|
|
93
|
+
|
|
94
|
+
"react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
|
|
95
|
+
|
|
96
|
+
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
|
|
97
|
+
|
|
98
|
+
"requires-port": ["requires-port@1.0.0", "", {}, "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="],
|
|
99
|
+
|
|
100
|
+
"undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
|
|
101
|
+
|
|
102
|
+
"url-parse": ["url-parse@1.5.10", "", { "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" } }, "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ=="],
|
|
103
|
+
|
|
104
|
+
"uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
|
|
105
|
+
|
|
106
|
+
"validate.io-array": ["validate.io-array@1.0.6", "", {}, "sha512-DeOy7CnPEziggrOO5CZhVKJw6S3Yi7e9e65R1Nl/RTN1vTQKnzjfvks0/8kQ40FP/dsjRAOd4hxmJ7uLa6vxkg=="],
|
|
107
|
+
|
|
108
|
+
"validate.io-function": ["validate.io-function@1.0.2", "", {}, "sha512-LlFybRJEriSuBnUhQyG5bwglhh50EpTL2ul23MPIuR1odjO7XaMLFV8vHGwp7AZciFxtYOeiSCT5st+XSPONiQ=="],
|
|
109
|
+
|
|
110
|
+
"validate.io-integer": ["validate.io-integer@1.0.5", "", { "dependencies": { "validate.io-number": "^1.0.3" } }, "sha512-22izsYSLojN/P6bppBqhgUDjCkr5RY2jd+N2a3DCAUey8ydvrZ/OkGvFPR7qfOpwR2LC5p4Ngzxz36g5Vgr/hQ=="],
|
|
111
|
+
|
|
112
|
+
"validate.io-integer-array": ["validate.io-integer-array@1.0.0", "", { "dependencies": { "validate.io-array": "^1.0.3", "validate.io-integer": "^1.0.4" } }, "sha512-mTrMk/1ytQHtCY0oNO3dztafHYyGU88KL+jRxWuzfOmQb+4qqnWmI+gykvGp8usKZOM0H7keJHEbRaFiYA0VrA=="],
|
|
113
|
+
|
|
114
|
+
"validate.io-number": ["validate.io-number@1.0.3", "", {}, "sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg=="],
|
|
115
|
+
|
|
116
|
+
"ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
|
|
117
|
+
|
|
118
|
+
"y-protocols": ["y-protocols@1.0.6", "", { "dependencies": { "lib0": "^0.2.85" }, "peerDependencies": { "yjs": "^13.0.0" } }, "sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q=="],
|
|
119
|
+
|
|
120
|
+
"yjs": ["yjs@13.6.27", "", { "dependencies": { "lib0": "^0.2.99" } }, "sha512-OIDwaflOaq4wC6YlPBy2L6ceKeKuF7DeTxx+jPzv1FHn9tCZ0ZwSRnUBxD05E3yed46fv/FWJbvR+Ud7x0L7zw=="],
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { type SpawnOptions, spawn } from "node:child_process";
|
|
2
|
-
import type { ExecuteRequest, SessionData } from "../types";
|
|
2
|
+
import type { ExecuteOptions, ExecuteRequest, SessionData } from "../types";
|
|
3
3
|
|
|
4
4
|
function executeCommand(
|
|
5
5
|
sessions: Map<string, SessionData>,
|
|
6
6
|
command: string,
|
|
7
|
-
|
|
8
|
-
background?: boolean
|
|
7
|
+
options: ExecuteOptions,
|
|
9
8
|
): Promise<{
|
|
10
9
|
success: boolean;
|
|
11
10
|
stdout: string;
|
|
@@ -16,14 +15,16 @@ function executeCommand(
|
|
|
16
15
|
const spawnOptions: SpawnOptions = {
|
|
17
16
|
shell: true,
|
|
18
17
|
stdio: ["pipe", "pipe", "pipe"] as const,
|
|
19
|
-
detached: background || false,
|
|
18
|
+
detached: options.background || false,
|
|
19
|
+
cwd: options.cwd || "/workspace", // Default to clean /workspace directory
|
|
20
|
+
env: options.env ? { ...process.env, ...options.env } : process.env
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
const child = spawn(command, spawnOptions);
|
|
23
24
|
|
|
24
25
|
// Store the process reference for cleanup if sessionId is provided
|
|
25
|
-
if (sessionId && sessions.has(sessionId)) {
|
|
26
|
-
const session = sessions.get(sessionId)!;
|
|
26
|
+
if (options.sessionId && sessions.has(options.sessionId)) {
|
|
27
|
+
const session = sessions.get(options.sessionId)!;
|
|
27
28
|
session.activeProcess = child;
|
|
28
29
|
}
|
|
29
30
|
|
|
@@ -38,7 +39,7 @@ function executeCommand(
|
|
|
38
39
|
stderr += data.toString();
|
|
39
40
|
});
|
|
40
41
|
|
|
41
|
-
if (background) {
|
|
42
|
+
if (options.background) {
|
|
42
43
|
// For background processes, unref and return quickly
|
|
43
44
|
child.unref();
|
|
44
45
|
|
|
@@ -61,8 +62,8 @@ function executeCommand(
|
|
|
61
62
|
// Normal synchronous execution
|
|
62
63
|
child.on("close", (code) => {
|
|
63
64
|
// Clear the active process reference
|
|
64
|
-
if (sessionId && sessions.has(sessionId)) {
|
|
65
|
-
const session = sessions.get(sessionId)!;
|
|
65
|
+
if (options.sessionId && sessions.has(options.sessionId)) {
|
|
66
|
+
const session = sessions.get(options.sessionId)!;
|
|
66
67
|
session.activeProcess = null;
|
|
67
68
|
}
|
|
68
69
|
|
|
@@ -78,8 +79,8 @@ function executeCommand(
|
|
|
78
79
|
|
|
79
80
|
child.on("error", (error) => {
|
|
80
81
|
// Clear the active process reference
|
|
81
|
-
if (sessionId && sessions.has(sessionId)) {
|
|
82
|
-
const session = sessions.get(sessionId)!;
|
|
82
|
+
if (options.sessionId && sessions.has(options.sessionId)) {
|
|
83
|
+
const session = sessions.get(options.sessionId)!;
|
|
83
84
|
session.activeProcess = null;
|
|
84
85
|
}
|
|
85
86
|
|
|
@@ -96,7 +97,7 @@ export async function handleExecuteRequest(
|
|
|
96
97
|
): Promise<Response> {
|
|
97
98
|
try {
|
|
98
99
|
const body = (await req.json()) as ExecuteRequest;
|
|
99
|
-
const { command, sessionId, background } = body;
|
|
100
|
+
const { command, sessionId, background, cwd, env } = body;
|
|
100
101
|
|
|
101
102
|
if (!command || typeof command !== "string") {
|
|
102
103
|
return new Response(
|
|
@@ -115,7 +116,7 @@ export async function handleExecuteRequest(
|
|
|
115
116
|
|
|
116
117
|
console.log(`[Server] Executing command: ${command}`);
|
|
117
118
|
|
|
118
|
-
const result = await executeCommand(sessions, command, sessionId, background);
|
|
119
|
+
const result = await executeCommand(sessions, command, { sessionId, background, cwd, env });
|
|
119
120
|
|
|
120
121
|
return new Response(
|
|
121
122
|
JSON.stringify({
|
|
@@ -158,7 +159,7 @@ export async function handleStreamingExecuteRequest(
|
|
|
158
159
|
): Promise<Response> {
|
|
159
160
|
try {
|
|
160
161
|
const body = (await req.json()) as ExecuteRequest;
|
|
161
|
-
const { command, sessionId, background } = body;
|
|
162
|
+
const { command, sessionId, background, cwd, env } = body;
|
|
162
163
|
|
|
163
164
|
if (!command || typeof command !== "string") {
|
|
164
165
|
return new Response(
|
|
@@ -185,6 +186,8 @@ export async function handleStreamingExecuteRequest(
|
|
|
185
186
|
shell: true,
|
|
186
187
|
stdio: ["pipe", "pipe", "pipe"] as const,
|
|
187
188
|
detached: background || false,
|
|
189
|
+
cwd: cwd || "/workspace", // Default to clean /workspace directory
|
|
190
|
+
env: env ? { ...process.env, ...env } : process.env
|
|
188
191
|
};
|
|
189
192
|
|
|
190
193
|
const child = spawn(command, spawnOptions);
|
|
@@ -72,7 +72,7 @@ export async function handleStartProcessRequest(
|
|
|
72
72
|
// Start the actual process
|
|
73
73
|
try {
|
|
74
74
|
const spawnOptions: SpawnOptions = {
|
|
75
|
-
cwd: options.cwd ||
|
|
75
|
+
cwd: options.cwd || "/workspace", // Default to /workspace for consistency with exec commands
|
|
76
76
|
env: { ...process.env, ...options.env },
|
|
77
77
|
detached: false,
|
|
78
78
|
shell: true,
|
package/container_src/index.ts
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
handleStartProcessRequest,
|
|
26
26
|
handleStreamProcessLogsRequest,
|
|
27
27
|
} from "./handler/process";
|
|
28
|
+
import { type CreateContextRequest, JupyterServer } from "./jupyter-server";
|
|
28
29
|
import type { ProcessRecord, SessionData } from "./types";
|
|
29
30
|
|
|
30
31
|
// In-memory session storage (in production, you'd want to use a proper database)
|
|
@@ -55,8 +56,28 @@ function cleanupOldSessions() {
|
|
|
55
56
|
// Run cleanup every 10 minutes
|
|
56
57
|
setInterval(cleanupOldSessions, 10 * 60 * 1000);
|
|
57
58
|
|
|
59
|
+
// Initialize Jupyter server
|
|
60
|
+
const jupyterServer = new JupyterServer();
|
|
61
|
+
let jupyterInitialized = false;
|
|
62
|
+
|
|
63
|
+
// Initialize Jupyter immediately since startup.sh ensures it's ready
|
|
64
|
+
(async () => {
|
|
65
|
+
try {
|
|
66
|
+
await jupyterServer.initialize();
|
|
67
|
+
jupyterInitialized = true;
|
|
68
|
+
console.log("[Container] Jupyter integration initialized successfully");
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error("[Container] Failed to initialize Jupyter:", error);
|
|
71
|
+
// Log more details to help debug
|
|
72
|
+
if (error instanceof Error) {
|
|
73
|
+
console.error("[Container] Error details:", error.message);
|
|
74
|
+
console.error("[Container] Stack trace:", error.stack);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
})();
|
|
78
|
+
|
|
58
79
|
const server = serve({
|
|
59
|
-
fetch(req: Request) {
|
|
80
|
+
async fetch(req: Request) {
|
|
60
81
|
const url = new URL(req.url);
|
|
61
82
|
const pathname = url.pathname;
|
|
62
83
|
|
|
@@ -159,6 +180,7 @@ const server = serve({
|
|
|
159
180
|
JSON.stringify({
|
|
160
181
|
message: "pong",
|
|
161
182
|
timestamp: new Date().toISOString(),
|
|
183
|
+
jupyter: jupyterInitialized ? "ready" : "not ready",
|
|
162
184
|
}),
|
|
163
185
|
{
|
|
164
186
|
headers: {
|
|
@@ -280,7 +302,151 @@ const server = serve({
|
|
|
280
302
|
}
|
|
281
303
|
break;
|
|
282
304
|
|
|
305
|
+
// Code interpreter endpoints
|
|
306
|
+
case "/api/contexts":
|
|
307
|
+
if (req.method === "POST") {
|
|
308
|
+
if (!jupyterInitialized) {
|
|
309
|
+
return new Response(
|
|
310
|
+
JSON.stringify({
|
|
311
|
+
error: "Jupyter server is not ready. Please try again in a moment."
|
|
312
|
+
}),
|
|
313
|
+
{
|
|
314
|
+
status: 503,
|
|
315
|
+
headers: {
|
|
316
|
+
"Content-Type": "application/json",
|
|
317
|
+
...corsHeaders,
|
|
318
|
+
},
|
|
319
|
+
}
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
try {
|
|
323
|
+
const body = await req.json() as CreateContextRequest;
|
|
324
|
+
const context = await jupyterServer.createContext(body);
|
|
325
|
+
return new Response(
|
|
326
|
+
JSON.stringify({
|
|
327
|
+
id: context.id,
|
|
328
|
+
language: context.language,
|
|
329
|
+
cwd: context.cwd,
|
|
330
|
+
createdAt: context.createdAt,
|
|
331
|
+
lastUsed: context.lastUsed
|
|
332
|
+
}),
|
|
333
|
+
{
|
|
334
|
+
headers: {
|
|
335
|
+
"Content-Type": "application/json",
|
|
336
|
+
...corsHeaders,
|
|
337
|
+
},
|
|
338
|
+
}
|
|
339
|
+
);
|
|
340
|
+
} catch (error) {
|
|
341
|
+
console.error("[Container] Error creating context:", error);
|
|
342
|
+
return new Response(
|
|
343
|
+
JSON.stringify({
|
|
344
|
+
error: error instanceof Error ? error.message : "Failed to create context"
|
|
345
|
+
}),
|
|
346
|
+
{
|
|
347
|
+
status: 500,
|
|
348
|
+
headers: {
|
|
349
|
+
"Content-Type": "application/json",
|
|
350
|
+
...corsHeaders,
|
|
351
|
+
},
|
|
352
|
+
}
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
} else if (req.method === "GET") {
|
|
356
|
+
if (!jupyterInitialized) {
|
|
357
|
+
return new Response(
|
|
358
|
+
JSON.stringify({ contexts: [] }),
|
|
359
|
+
{
|
|
360
|
+
headers: {
|
|
361
|
+
"Content-Type": "application/json",
|
|
362
|
+
...corsHeaders,
|
|
363
|
+
},
|
|
364
|
+
}
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
const contexts = await jupyterServer.listContexts();
|
|
368
|
+
return new Response(
|
|
369
|
+
JSON.stringify({ contexts }),
|
|
370
|
+
{
|
|
371
|
+
headers: {
|
|
372
|
+
"Content-Type": "application/json",
|
|
373
|
+
...corsHeaders,
|
|
374
|
+
},
|
|
375
|
+
}
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
break;
|
|
379
|
+
|
|
380
|
+
case "/api/execute/code":
|
|
381
|
+
if (req.method === "POST") {
|
|
382
|
+
if (!jupyterInitialized) {
|
|
383
|
+
return new Response(
|
|
384
|
+
JSON.stringify({
|
|
385
|
+
error: "Jupyter server is not ready. Please try again in a moment."
|
|
386
|
+
}),
|
|
387
|
+
{
|
|
388
|
+
status: 503,
|
|
389
|
+
headers: {
|
|
390
|
+
"Content-Type": "application/json",
|
|
391
|
+
...corsHeaders,
|
|
392
|
+
},
|
|
393
|
+
}
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
try {
|
|
397
|
+
const body = await req.json() as { context_id: string; code: string; language?: string };
|
|
398
|
+
return await jupyterServer.executeCode(body.context_id, body.code, body.language);
|
|
399
|
+
} catch (error) {
|
|
400
|
+
console.error("[Container] Error executing code:", error);
|
|
401
|
+
return new Response(
|
|
402
|
+
JSON.stringify({
|
|
403
|
+
error: error instanceof Error ? error.message : "Failed to execute code"
|
|
404
|
+
}),
|
|
405
|
+
{
|
|
406
|
+
status: 500,
|
|
407
|
+
headers: {
|
|
408
|
+
"Content-Type": "application/json",
|
|
409
|
+
...corsHeaders,
|
|
410
|
+
},
|
|
411
|
+
}
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
break;
|
|
416
|
+
|
|
283
417
|
default:
|
|
418
|
+
// Handle dynamic routes for contexts
|
|
419
|
+
if (pathname.startsWith("/api/contexts/") && pathname.split('/').length === 4) {
|
|
420
|
+
const contextId = pathname.split('/')[3];
|
|
421
|
+
if (req.method === "DELETE") {
|
|
422
|
+
try {
|
|
423
|
+
await jupyterServer.deleteContext(contextId);
|
|
424
|
+
return new Response(
|
|
425
|
+
JSON.stringify({ success: true }),
|
|
426
|
+
{
|
|
427
|
+
headers: {
|
|
428
|
+
"Content-Type": "application/json",
|
|
429
|
+
...corsHeaders,
|
|
430
|
+
},
|
|
431
|
+
}
|
|
432
|
+
);
|
|
433
|
+
} catch (error) {
|
|
434
|
+
return new Response(
|
|
435
|
+
JSON.stringify({
|
|
436
|
+
error: error instanceof Error ? error.message : "Failed to delete context"
|
|
437
|
+
}),
|
|
438
|
+
{
|
|
439
|
+
status: error instanceof Error && error.message.includes("not found") ? 404 : 500,
|
|
440
|
+
headers: {
|
|
441
|
+
"Content-Type": "application/json",
|
|
442
|
+
...corsHeaders,
|
|
443
|
+
},
|
|
444
|
+
}
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
284
450
|
// Handle dynamic routes for individual processes
|
|
285
451
|
if (pathname.startsWith("/api/process/")) {
|
|
286
452
|
const segments = pathname.split('/');
|
|
@@ -357,5 +523,9 @@ console.log(` GET /api/process/{id}/logs - Get process logs`);
|
|
|
357
523
|
console.log(` GET /api/process/{id}/stream - Stream process logs (SSE)`);
|
|
358
524
|
console.log(` DELETE /api/process/kill-all - Kill all processes`);
|
|
359
525
|
console.log(` GET /proxy/{port}/* - Proxy requests to exposed ports`);
|
|
526
|
+
console.log(` POST /api/contexts - Create a code execution context`);
|
|
527
|
+
console.log(` GET /api/contexts - List all contexts`);
|
|
528
|
+
console.log(` DELETE /api/contexts/{id} - Delete a context`);
|
|
529
|
+
console.log(` POST /api/execute/code - Execute code in a context (streaming)`);
|
|
360
530
|
console.log(` GET /api/ping - Health check`);
|
|
361
531
|
console.log(` GET /api/commands - List available commands`);
|