Leon4gr45 commited on
Commit
33953c0
Β·
verified Β·
1 Parent(s): 1c16487

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -58,3 +58,4 @@ node_modules/monaco-editor/dev/vs/editor/editor.main.js.map filter=lfs diff=lfs
58
  node_modules/monaco-editor/dev/vs/language/typescript/tsWorker.js filter=lfs diff=lfs merge=lfs -text
59
  node_modules/monaco-editor/esm/vs/language/typescript/ts.worker.js filter=lfs diff=lfs merge=lfs -text
60
  node_modules/monaco-editor/min-maps/vs/editor/editor.main.js.map filter=lfs diff=lfs merge=lfs -text
 
 
58
  node_modules/monaco-editor/dev/vs/language/typescript/tsWorker.js filter=lfs diff=lfs merge=lfs -text
59
  node_modules/monaco-editor/esm/vs/language/typescript/ts.worker.js filter=lfs diff=lfs merge=lfs -text
60
  node_modules/monaco-editor/min-maps/vs/editor/editor.main.js.map filter=lfs diff=lfs merge=lfs -text
61
+ public/osws-demo.gif filter=lfs diff=lfs merge=lfs -text
package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
package.json ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "osw-studio-v1",
3
+ "version": "1.84.0",
4
+ "private": true,
5
+ "license": "MIT",
6
+ "scripts": {
7
+ "dev": "next dev",
8
+ "build": "next build",
9
+ "start": "next start",
10
+ "lint": "next lint",
11
+ "test": "vitest run",
12
+ "test:watch": "vitest",
13
+ "postinstall": "cp node_modules/esbuild-wasm/esbuild.wasm public/esbuild.wasm 2>/dev/null || true"
14
+ },
15
+ "dependencies": {
16
+ "@huggingface/hub": "^2.9.0",
17
+ "@jitl/quickjs-wasmfile-release-sync": "^0.31.0",
18
+ "@monaco-editor/react": "^4.7.0-rc.0",
19
+ "@mozilla/readability": "^0.6.0",
20
+ "@radix-ui/react-checkbox": "^1.3.3",
21
+ "@radix-ui/react-collapsible": "^1.1.11",
22
+ "@radix-ui/react-context-menu": "^2.2.15",
23
+ "@radix-ui/react-dialog": "^1.1.14",
24
+ "@radix-ui/react-dropdown-menu": "^2.1.15",
25
+ "@radix-ui/react-label": "^2.1.7",
26
+ "@radix-ui/react-popover": "^1.1.14",
27
+ "@radix-ui/react-select": "^2.2.5",
28
+ "@radix-ui/react-slot": "^1.2.3",
29
+ "@radix-ui/react-switch": "^1.2.5",
30
+ "@radix-ui/react-tabs": "^1.1.13",
31
+ "@radix-ui/react-toggle-group": "^1.1.11",
32
+ "@radix-ui/react-tooltip": "^1.2.7",
33
+ "@tailwindcss/postcss": "^4.1.12",
34
+ "@tanstack/react-query": "^5.80.6",
35
+ "@types/node": "20.19.11",
36
+ "@xterm/addon-fit": "^0.11.0",
37
+ "@xterm/xterm": "^6.0.0",
38
+ "bcrypt": "^6.0.0",
39
+ "better-sqlite3": "^11.7.0",
40
+ "class-variance-authority": "^0.7.1",
41
+ "clsx": "^2.1.1",
42
+ "cron-parser": "^4.9.0",
43
+ "date-fns": "^4.1.0",
44
+ "esbuild-wasm": "^0.24.0",
45
+ "handlebars": "^4.7.8",
46
+ "html2canvas": "^1.4.1",
47
+ "jose": "^6.1.0",
48
+ "jszip": "^3.10.1",
49
+ "lucide-react": "^0.513.0",
50
+ "lz-string": "^1.5.0",
51
+ "monaco-editor": "^0.52.2",
52
+ "next": "^15.5.9",
53
+ "next-themes": "^0.4.6",
54
+ "postcss": "^8",
55
+ "quickjs-emscripten": "^0.31.0",
56
+ "quickjs-emscripten-core": "^0.31.0",
57
+ "react": "^19.0.0",
58
+ "react-dom": "^19.0.0",
59
+ "react-markdown": "^10.1.0",
60
+ "react-resizable-panels": "^3.0.4",
61
+ "remark-gfm": "^4.0.1",
62
+ "server-only": "^0.0.1",
63
+ "sonner": "^2.0.5",
64
+ "tailwind-merge": "^3.3.0",
65
+ "tailwindcss": "^4",
66
+ "turndown": "^7.2.4",
67
+ "typescript": "5.9.2",
68
+ "uuid": "^11.1.0",
69
+ "zustand": "^5.0.13"
70
+ },
71
+ "devDependencies": {
72
+ "@eslint/eslintrc": "^3",
73
+ "@playwright/test": "^1.60.0",
74
+ "@types/bcrypt": "^6.0.0",
75
+ "@types/better-sqlite3": "^7.6.12",
76
+ "@types/lz-string": "^1.3.34",
77
+ "@types/react": "^19",
78
+ "@types/react-dom": "^19",
79
+ "@types/turndown": "^5.0.6",
80
+ "@types/uuid": "^10.0.0",
81
+ "eslint": "^9.39.2",
82
+ "eslint-config-next": "^15.5.19",
83
+ "fake-indexeddb": "^6.2.5",
84
+ "jsdom": "^27.0.1",
85
+ "vitest": "^3.2.4"
86
+ }
87
+ }
postcss.config.mjs ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ const config = {
2
+ plugins: ["@tailwindcss/postcss"],
3
+ };
4
+
5
+ export default config;
public/esbuild.wasm ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e2b4b98297e04ef12981bafabf0a3c2d7c3c5cf6af603ef79d886deac3b5eeb3
3
+ size 11907565
public/example-background.jpg ADDED
public/osw-studio-logo.svg ADDED
public/osws-demo.gif ADDED

Git LFS Details

  • SHA256: fb750991f675275137b993e4611b3c7d4d921827c231bdf58f53939fcd023017
  • Pointer size: 132 Bytes
  • Size of remote file: 2.49 MB
public/workers/script-worker.js ADDED
@@ -0,0 +1,247 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Script Worker β€” Executes Python (Pyodide) and Lua (wasmoon) scripts
3
+ * in a Web Worker to avoid blocking the UI thread.
4
+ *
5
+ * Receives: { type: 'execute', payload: { runtime, entryPoint, files } }
6
+ * { type: 'abort' }
7
+ * Posts: { type: 'stdout'|'stderr'|'status'|'error'|'complete'|'output-file', ... }
8
+ */
9
+
10
+ /* global self, importScripts, postMessage */
11
+
12
+ let pyodide = null;
13
+ let luaFactory = null;
14
+
15
+ /**
16
+ * Post a message back to the main thread.
17
+ */
18
+ function send(type, data) {
19
+ self.postMessage({ type, data });
20
+ }
21
+
22
+ function sendFile(path, content) {
23
+ self.postMessage({ type: 'output-file', path, content });
24
+ }
25
+
26
+ // ─── Python (Pyodide) ──────────────────────────────────────────────
27
+
28
+ async function ensurePyodide() {
29
+ if (pyodide) return pyodide;
30
+
31
+ send('status', 'Loading Python runtime...');
32
+
33
+ try {
34
+ importScripts('https://cdn.jsdelivr.net/pyodide/v0.27.4/full/pyodide.js');
35
+ } catch (err) {
36
+ send('error', 'Failed to load Pyodide from CDN: ' + String(err));
37
+ throw err;
38
+ }
39
+
40
+ try {
41
+ pyodide = await self.loadPyodide({
42
+ stdout: (msg) => send('stdout', msg),
43
+ stderr: (msg) => send('stderr', msg),
44
+ });
45
+ } catch (err) {
46
+ send('error', 'Failed to initialize Pyodide: ' + String(err));
47
+ throw err;
48
+ }
49
+
50
+ // Pre-load micropip so users can install packages
51
+ await pyodide.loadPackage('micropip');
52
+
53
+ send('status', 'Python runtime ready');
54
+ return pyodide;
55
+ }
56
+
57
+ async function executePython(entryPoint, files) {
58
+ const py = await ensurePyodide();
59
+
60
+ // Mount VFS files into Pyodide's filesystem
61
+ // Create /output/ directory for visual output
62
+ try { py.FS.mkdir('/output'); } catch (_e) { /* exists */ }
63
+
64
+ for (const [path, content] of Object.entries(files)) {
65
+ // Skip dotfiles
66
+ if (path.startsWith('/.')) continue;
67
+ const dir = path.substring(0, path.lastIndexOf('/')) || '/';
68
+ // Ensure parent directories exist
69
+ const parts = dir.split('/').filter(Boolean);
70
+ let current = '';
71
+ for (const part of parts) {
72
+ current += '/' + part;
73
+ try { py.FS.mkdir(current); } catch (_e) { /* exists */ }
74
+ }
75
+ py.FS.writeFile(path, content);
76
+ }
77
+
78
+ // Run the entry point script
79
+ const code = files[entryPoint];
80
+ if (!code) {
81
+ send('error', `Entry point not found: ${entryPoint}`);
82
+ return { exitCode: 1 };
83
+ }
84
+
85
+ // Set up Python environment so module imports work:
86
+ const entryDir = entryPoint.substring(0, entryPoint.lastIndexOf('/')) || '/';
87
+ try {
88
+ await py.runPythonAsync(`
89
+ import sys, os
90
+ os.chdir(${JSON.stringify(entryDir)})
91
+ _ep_dir = ${JSON.stringify(entryDir)}
92
+ if _ep_dir not in sys.path:
93
+ sys.path.insert(0, _ep_dir)
94
+ if '/' not in sys.path:
95
+ sys.path.insert(0, '/')
96
+ __file__ = ${JSON.stringify(entryPoint)}
97
+ del _ep_dir
98
+ `);
99
+ } catch (_e) { /* best effort */ }
100
+
101
+ try {
102
+ await py.runPythonAsync(code);
103
+ } catch (err) {
104
+ send('stderr', String(err));
105
+ return { exitCode: 1 };
106
+ }
107
+
108
+ // Scan /output/ for new files and send them back
109
+ try {
110
+ const outputFiles = py.FS.readdir('/output').filter(f => f !== '.' && f !== '..');
111
+ for (const filename of outputFiles) {
112
+ const filePath = '/output/' + filename;
113
+ try {
114
+ const data = py.FS.readFile(filePath);
115
+ const ext = filename.split('.').pop().toLowerCase();
116
+ if (['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp'].includes(ext)) {
117
+ let binary = '';
118
+ for (let i = 0; i < data.length; i++) {
119
+ binary += String.fromCharCode(data[i]);
120
+ }
121
+ const base64 = btoa(binary);
122
+ sendFile(filePath, base64);
123
+ } else {
124
+ const decoder = new TextDecoder();
125
+ sendFile(filePath, decoder.decode(data));
126
+ }
127
+ } catch (_e) { /* skip unreadable files */ }
128
+ }
129
+ } catch (_e) { /* /output/ may not have new files */ }
130
+
131
+ return { exitCode: 0 };
132
+ }
133
+
134
+ // ─── Lua (wasmoon) ──────────────────────────────────────────────────
135
+
136
+ async function ensureLuaFactory() {
137
+ if (luaFactory) return luaFactory;
138
+
139
+ send('status', 'Loading Lua runtime...');
140
+
141
+ try {
142
+ // Dynamic import of wasmoon from CDN
143
+ const wasmoon = await import('https://esm.sh/wasmoon@1');
144
+ luaFactory = new wasmoon.LuaFactory();
145
+ } catch (err) {
146
+ send('error', 'Failed to load Lua runtime: ' + String(err));
147
+ throw err;
148
+ }
149
+
150
+ send('status', 'Lua runtime ready');
151
+ return luaFactory;
152
+ }
153
+
154
+ async function executeLua(entryPoint, files) {
155
+ const factory = await ensureLuaFactory();
156
+ const engine = await factory.createEngine();
157
+
158
+ try {
159
+ // Override print to capture stdout
160
+ engine.global.set('print', function (...args) {
161
+ send('stdout', args.map(String).join('\t'));
162
+ });
163
+
164
+ // Pre-load module files so require() works
165
+ const moduleFiles = {};
166
+ for (const [path, content] of Object.entries(files)) {
167
+ if (path.endsWith('.lua') && path !== entryPoint) {
168
+ const modName = path
169
+ .replace(/^\//, '')
170
+ .replace(/\.lua$/, '')
171
+ .replace(/\//g, '.');
172
+ moduleFiles[modName] = content;
173
+ }
174
+ }
175
+
176
+ // Register custom searcher for VFS modules
177
+ engine.global.set('__vfs_modules', JSON.stringify(moduleFiles));
178
+
179
+ await engine.doString(`
180
+ local vfs_modules = {}
181
+ local json_str = __vfs_modules
182
+ -- Simple JSON parse for module map (keys and string values only)
183
+ for key, value in json_str:gmatch('"([^"]+)":"(.-[^\\\\])"') do
184
+ -- Unescape basic sequences
185
+ value = value:gsub('\\\\n', '\\n'):gsub('\\\\t', '\\t'):gsub('\\\\"', '"'):gsub('\\\\\\\\', '\\\\')
186
+ vfs_modules[key] = value
187
+ end
188
+ __vfs_modules = nil
189
+
190
+ table.insert(package.searchers, 2, function(modname)
191
+ local source = vfs_modules[modname]
192
+ if source then
193
+ local fn, err = load(source, "@" .. modname .. ".lua")
194
+ if fn then return fn
195
+ else return "\\n\\tload error: " .. err end
196
+ end
197
+ return "\\n\\tno VFS module '" .. modname .. "'"
198
+ end)
199
+ `);
200
+
201
+ // Run the entry point
202
+ const code = files[entryPoint];
203
+ if (!code) {
204
+ send('error', 'Entry point not found: ' + entryPoint);
205
+ engine.global.close();
206
+ return { exitCode: 1 };
207
+ }
208
+
209
+ await engine.doString(code);
210
+
211
+ engine.global.close();
212
+ return { exitCode: 0 };
213
+
214
+ } catch (err) {
215
+ send('stderr', String(err));
216
+ try { engine.global.close(); } catch (_e) { /* best effort */ }
217
+ return { exitCode: 1 };
218
+ }
219
+ }
220
+
221
+ // ─── Message handler ────────────────────────────────────────────────
222
+
223
+ self.onmessage = async function (event) {
224
+ const msg = event.data;
225
+
226
+ if (msg.type === 'execute') {
227
+ const { runtime, entryPoint, files } = msg.payload;
228
+
229
+ try {
230
+ let result;
231
+ if (runtime === 'python') {
232
+ result = await executePython(entryPoint, files);
233
+ } else if (runtime === 'lua') {
234
+ result = await executeLua(entryPoint, files);
235
+ } else {
236
+ send('error', 'Unknown runtime: ' + runtime);
237
+ self.postMessage({ type: 'complete', exitCode: 1 });
238
+ return;
239
+ }
240
+
241
+ self.postMessage({ type: 'complete', exitCode: result.exitCode });
242
+ } catch (err) {
243
+ send('error', String(err));
244
+ self.postMessage({ type: 'complete', exitCode: 1 });
245
+ }
246
+ }
247
+ };
tsconfig.json ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "preserve",
15
+ "incremental": true,
16
+ "plugins": [
17
+ {
18
+ "name": "next"
19
+ }
20
+ ],
21
+ "paths": {
22
+ "@/*": ["./*"]
23
+ }
24
+ },
25
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
26
+ "exclude": ["node_modules", "desktop"]
27
+ }
vitest.config.ts ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { defineConfig } from 'vitest/config';
2
+ import path from 'path';
3
+
4
+ export default defineConfig({
5
+ test: {
6
+ environment: 'node',
7
+ globals: true,
8
+ exclude: ['e2e/**', '**/node_modules/**', 'desktop/app/**', 'desktop/dist/**'],
9
+ },
10
+ resolve: {
11
+ alias: {
12
+ '@': path.resolve(__dirname),
13
+ },
14
+ },
15
+ });