@viji-dev/sdk 1.0.0 → 1.0.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 +155 -60
- package/bin/viji.js +9 -29
- package/dist/assets/artist-dts-BHUsvSI6.js +613 -0
- package/dist/assets/artist-dts-p5-Cyw8vmy_.js +736 -0
- package/dist/assets/core-CiQx3w0t.js +12 -0
- package/dist/assets/dark-plus-C3mMm8J8.js +1 -0
- package/dist/assets/docs-api-PBLtY4Ni.js +12381 -0
- package/dist/assets/engine-javascript-CXyY7cc8.js +141 -0
- package/dist/assets/essentia-wasm.web-0S-sW98u-CYV1l1zv.js +38 -0
- package/dist/assets/essentia.js-core.es-DnrJE0uR-DOSrF5_G.js +32 -0
- package/dist/assets/glsl-DMyvO4G4.js +1 -0
- package/dist/assets/index-BhFxsauQ.js +215 -0
- package/dist/assets/index-BqhVeA7U.css +1 -0
- package/dist/assets/index-T4TOjvD0.js +1 -0
- package/dist/assets/index-Wz9WqGqz.js +52 -0
- package/dist/assets/index-t24aGwla.js +1 -0
- package/dist/assets/javascript-wDzz0qaB.js +1 -0
- package/dist/assets/shader-uniforms-GdaUkQPK.js +1 -0
- package/dist/assets/typescript-BPQ3VLAy.js +1 -0
- package/dist/assets/viji.worker-CQSJ0SiO-ljtBlcNZ.js +27018 -0
- package/{index.html → dist/index.html} +2 -1
- package/package.json +31 -35
- package/src/cli/commands/build.js +50 -99
- package/src/cli/commands/create.js +32 -47
- package/src/cli/commands/dev.js +30 -97
- package/src/cli/server/dev-server.js +233 -0
- package/src/cli/server/scene-scanner.js +93 -0
- package/src/cli/server/vite-scene-plugin.d.ts +2 -0
- package/src/cli/server/vite-scene-plugin.js +134 -0
- package/src/cli/utils/cli-utils.js +29 -139
- package/src/cli/utils/scene-compiler.js +10 -17
- package/src/templates/scene-templates.js +85 -0
- package/.gitignore +0 -29
- package/eslint.config.js +0 -37
- package/postcss.config.js +0 -6
- package/scenes/audio-visualizer/main.js +0 -287
- package/scenes/core-demo/main.js +0 -532
- package/scenes/demo-scene/main.js +0 -619
- package/scenes/global.d.ts +0 -15
- package/scenes/particle-system/main.js +0 -349
- package/scenes/tsconfig.json +0 -12
- package/scenes/video-mirror/main.ts +0 -436
- package/src/App.css +0 -42
- package/src/App.tsx +0 -279
- package/src/cli/commands/init.js +0 -262
- package/src/components/SDKPage.tsx +0 -337
- package/src/components/core/CoreContainer.tsx +0 -126
- package/src/components/ui/DeviceSelectionList.tsx +0 -137
- package/src/components/ui/FPSCounter.tsx +0 -78
- package/src/components/ui/FileDropzonePanel.tsx +0 -120
- package/src/components/ui/FileListPanel.tsx +0 -285
- package/src/components/ui/InputExpansionPanel.tsx +0 -31
- package/src/components/ui/MediaPlayerControls.tsx +0 -191
- package/src/components/ui/MenuContainer.tsx +0 -71
- package/src/components/ui/ParametersMenu.tsx +0 -797
- package/src/components/ui/ProjectSwitcherMenu.tsx +0 -192
- package/src/components/ui/QuickInputControls.tsx +0 -542
- package/src/components/ui/SDKMenuSystem.tsx +0 -96
- package/src/components/ui/SettingsMenu.tsx +0 -346
- package/src/components/ui/SimpleInputControls.tsx +0 -137
- package/src/index.css +0 -68
- package/src/main.tsx +0 -10
- package/src/scenes-hmr.ts +0 -158
- package/src/services/project-filesystem.ts +0 -436
- package/src/stores/scene-player/index.ts +0 -3
- package/src/stores/scene-player/input-manager.store.ts +0 -1045
- package/src/stores/scene-player/scene-session.store.ts +0 -659
- package/src/styles/globals.css +0 -111
- package/src/templates/minimal-template.js +0 -11
- package/src/utils/debounce.js +0 -34
- package/src/vite-env.d.ts +0 -1
- package/tailwind.config.js +0 -18
- package/tsconfig.app.json +0 -27
- package/tsconfig.json +0 -27
- package/tsconfig.node.json +0 -27
- package/vite.config.ts +0 -54
- /package/{public → dist}/favicon.png +0 -0
package/src/App.tsx
DELETED
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect, useRef } from 'react';
|
|
2
|
-
import { HeroUIProvider } from '@heroui/react';
|
|
3
|
-
import SDKPage from './components/SDKPage';
|
|
4
|
-
import { projectFileSystem } from './services/project-filesystem';
|
|
5
|
-
// Force Vite to include /scenes files in module graph for HMR
|
|
6
|
-
import { sceneHmrCount } from './scenes-hmr';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
interface Project {
|
|
10
|
-
id: string;
|
|
11
|
-
name: string;
|
|
12
|
-
path: string;
|
|
13
|
-
mainFile: string;
|
|
14
|
-
lastModified: Date;
|
|
15
|
-
sceneType: 'javascript' | 'typescript' | 'shader';
|
|
16
|
-
isBuilt: boolean;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const App: React.FC = () => {
|
|
20
|
-
// Transform ESM exports to runtime-friendly code for worker eval (initial load)
|
|
21
|
-
// No longer needed - parameter object API scenes are passed directly as strings to VijiCore
|
|
22
|
-
|
|
23
|
-
const [sceneError, setSceneError] = useState<string>('');
|
|
24
|
-
const [currentSceneCode, setCurrentSceneCode] = useState<string>('');
|
|
25
|
-
const [currentProject, setCurrentProject] = useState<Project | undefined>();
|
|
26
|
-
const hmrCooldownUntilRef = useRef<number>(0);
|
|
27
|
-
const lastCodeRef = useRef<string>('');
|
|
28
|
-
useEffect(() => { lastCodeRef.current = currentSceneCode; }, [currentSceneCode]);
|
|
29
|
-
|
|
30
|
-
const hashString = (str: string): string => {
|
|
31
|
-
let hash = 2166136261; // FNV offset basis
|
|
32
|
-
for (let i = 0; i < str.length; i++) {
|
|
33
|
-
hash ^= str.charCodeAt(i);
|
|
34
|
-
hash = (hash * 16777619) >>> 0; // FNV prime, convert to unsigned 32-bit
|
|
35
|
-
}
|
|
36
|
-
return hash.toString(16);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
// Load first available project on initial load
|
|
40
|
-
useEffect(() => {
|
|
41
|
-
console.log('🧷 scenes HMR files attached:', sceneHmrCount);
|
|
42
|
-
const loadInitialProject = async () => {
|
|
43
|
-
if (!currentProject) {
|
|
44
|
-
try {
|
|
45
|
-
const projects = await projectFileSystem.getProjects();
|
|
46
|
-
if (projects.length > 0) {
|
|
47
|
-
// Convert ProjectInfo to Project format
|
|
48
|
-
const firstProject: Project = {
|
|
49
|
-
id: projects[0].id,
|
|
50
|
-
name: projects[0].name,
|
|
51
|
-
path: projects[0].path,
|
|
52
|
-
mainFile: projects[0].mainFile,
|
|
53
|
-
lastModified: projects[0].lastModified,
|
|
54
|
-
sceneType: projects[0].projectType,
|
|
55
|
-
isBuilt: projects[0].isBuilt || false,
|
|
56
|
-
};
|
|
57
|
-
await handleProjectSwitch(firstProject);
|
|
58
|
-
}
|
|
59
|
-
} catch (error) {
|
|
60
|
-
console.error('❌ Failed to load initial project:', error);
|
|
61
|
-
setSceneError('No projects found. Create a project to get started.');
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
loadInitialProject();
|
|
66
|
-
}, [currentProject]);
|
|
67
|
-
// Vite HMR: watch current project's files and reload scene code on save
|
|
68
|
-
useEffect(() => {
|
|
69
|
-
const hot: any = (import.meta as any).hot;
|
|
70
|
-
if (!currentProject || !hot) return;
|
|
71
|
-
|
|
72
|
-
const stripQuery = (p: string) => (p || '').replace(/\?.*$/, '');
|
|
73
|
-
const normalize = (p: string) => stripQuery(p).replace(/^\/@fs\//, '/');
|
|
74
|
-
|
|
75
|
-
const onAfterUpdate = async (payload: any) => {
|
|
76
|
-
try {
|
|
77
|
-
if (Date.now() < hmrCooldownUntilRef.current) return;
|
|
78
|
-
const updates = payload?.updates || [];
|
|
79
|
-
console.log('🛰️ Vite HMR payload:', updates);
|
|
80
|
-
// Ignore HMR updates that come from virtual modules or outside /scenes
|
|
81
|
-
const changed = updates.some((u: any) => {
|
|
82
|
-
const p = normalize(u.path || u.acceptedPath || '');
|
|
83
|
-
// Any file change under the active project's folder triggers reload (multi-file support)
|
|
84
|
-
const hit = p.includes(`/scenes/${currentProject.id}/`);
|
|
85
|
-
if (hit) console.log('🔁 Matched HMR path:', p);
|
|
86
|
-
return hit;
|
|
87
|
-
});
|
|
88
|
-
if (!changed) return;
|
|
89
|
-
|
|
90
|
-
console.log(`🔥 HMR detected change in ${currentProject.name}, reloading scene code...`);
|
|
91
|
-
// For multi-file projects, bundle local relative imports too
|
|
92
|
-
const code = await projectFileSystem.loadBundledProjectCode(currentProject.id);
|
|
93
|
-
const prevHash = hashString(lastCodeRef.current || '');
|
|
94
|
-
const nextHash = hashString(code || '');
|
|
95
|
-
console.log('♻️ [HMR] reloading active project code', {
|
|
96
|
-
project: currentProject.id,
|
|
97
|
-
prevLen: lastCodeRef.current?.length || 0,
|
|
98
|
-
nextLen: code.length,
|
|
99
|
-
prevHash,
|
|
100
|
-
nextHash
|
|
101
|
-
});
|
|
102
|
-
setSceneError('');
|
|
103
|
-
setCurrentSceneCode(code);
|
|
104
|
-
} catch (e: any) {
|
|
105
|
-
console.error('❌ HMR reload failed:', e);
|
|
106
|
-
setSceneError(e?.message || 'Hot reload failed');
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
const onBeforeUpdate = (payload: any) => {
|
|
111
|
-
try {
|
|
112
|
-
console.log('🛰️ Vite HMR beforeUpdate:', payload?.updates);
|
|
113
|
-
} catch {}
|
|
114
|
-
};
|
|
115
|
-
const onInvalidate = (payload: any) => {
|
|
116
|
-
try {
|
|
117
|
-
console.log('🛰️ Vite HMR invalidate:', payload?.path || payload);
|
|
118
|
-
} catch {}
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
hot.on('vite:beforeUpdate', onBeforeUpdate);
|
|
122
|
-
hot.on('vite:afterUpdate', onAfterUpdate);
|
|
123
|
-
hot.on('vite:invalidate', onInvalidate);
|
|
124
|
-
return () => {
|
|
125
|
-
try {
|
|
126
|
-
hot.off?.('vite:beforeUpdate', onBeforeUpdate);
|
|
127
|
-
hot.off?.('vite:afterUpdate', onAfterUpdate);
|
|
128
|
-
hot.off?.('vite:invalidate', onInvalidate);
|
|
129
|
-
} catch {}
|
|
130
|
-
};
|
|
131
|
-
}, [currentProject?.id]);
|
|
132
|
-
|
|
133
|
-
// Also listen to custom scene file update events and reload code
|
|
134
|
-
useEffect(() => {
|
|
135
|
-
if (!currentProject) return;
|
|
136
|
-
const handler = async (e: any) => {
|
|
137
|
-
try {
|
|
138
|
-
const path = e?.detail?.path || '';
|
|
139
|
-
if (!path.includes(`/scenes/${currentProject.id}/`)) return;
|
|
140
|
-
|
|
141
|
-
console.log('🧨 [Scenes HMR] event for active project:', path);
|
|
142
|
-
const code = await projectFileSystem.loadBundledProjectCode(currentProject.id);
|
|
143
|
-
// Debug logs disabled - HMR working correctly
|
|
144
|
-
|
|
145
|
-
console.log('🧨 [Scenes HMR] applying bundle for active project', {
|
|
146
|
-
path,
|
|
147
|
-
project: currentProject.id,
|
|
148
|
-
prevLen: lastCodeRef.current?.length || 0,
|
|
149
|
-
nextLen: code.length,
|
|
150
|
-
codeChanged: lastCodeRef.current !== code
|
|
151
|
-
});
|
|
152
|
-
setSceneError('');
|
|
153
|
-
// Always force update when file is saved, regardless of content
|
|
154
|
-
// Add a timestamp comment to ensure React always sees it as a new value
|
|
155
|
-
const timestamp = Date.now();
|
|
156
|
-
const timestampedCode = `// File modified: ${timestamp}\n${code}`;
|
|
157
|
-
|
|
158
|
-
console.log('🔄 [App] Setting new scene code with timestamp:', {
|
|
159
|
-
oldLen: currentSceneCode.length,
|
|
160
|
-
newLen: timestampedCode.length,
|
|
161
|
-
timestamp: timestamp
|
|
162
|
-
});
|
|
163
|
-
setCurrentSceneCode(timestampedCode);
|
|
164
|
-
} catch (err) {
|
|
165
|
-
console.error('❌ Scenes HMR event reload failed:', err);
|
|
166
|
-
}
|
|
167
|
-
};
|
|
168
|
-
window.addEventListener('viji-scene-file-updated', handler as any);
|
|
169
|
-
return () => {
|
|
170
|
-
window.removeEventListener('viji-scene-file-updated', handler as any);
|
|
171
|
-
};
|
|
172
|
-
}, [currentProject?.id]);
|
|
173
|
-
|
|
174
|
-
// Fallback dev polling: periodically re-read active project's code and update if changed
|
|
175
|
-
useEffect(() => {
|
|
176
|
-
if (!currentProject) return;
|
|
177
|
-
let cancelled = false;
|
|
178
|
-
const interval = window.setInterval(async () => {
|
|
179
|
-
if (cancelled) return;
|
|
180
|
-
if (Date.now() < hmrCooldownUntilRef.current) return;
|
|
181
|
-
try {
|
|
182
|
-
const code = await projectFileSystem.loadBundledProjectCode(currentProject.id);
|
|
183
|
-
if (code && code !== lastCodeRef.current) {
|
|
184
|
-
setSceneError('');
|
|
185
|
-
setCurrentSceneCode(code);
|
|
186
|
-
}
|
|
187
|
-
} catch {}
|
|
188
|
-
}, 900);
|
|
189
|
-
return () => {
|
|
190
|
-
cancelled = true;
|
|
191
|
-
try { window.clearInterval(interval); } catch {}
|
|
192
|
-
};
|
|
193
|
-
}, [currentProject?.id]);
|
|
194
|
-
|
|
195
|
-
const handleSceneError = (error: string) => {
|
|
196
|
-
setSceneError(error);
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
// Project management functions
|
|
201
|
-
const handleProjectSwitch = async (project: Project) => {
|
|
202
|
-
console.log('🎯 USER CLICKED PROJECT:', {
|
|
203
|
-
id: project.id,
|
|
204
|
-
name: project.name,
|
|
205
|
-
path: project.path,
|
|
206
|
-
mainFile: project.mainFile
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
const requestId = Symbol(project.id);
|
|
210
|
-
const latestRequestRef = (handleProjectSwitch as any).latestRef || { current: requestId };
|
|
211
|
-
latestRequestRef.current = requestId;
|
|
212
|
-
(handleProjectSwitch as any).latestRef = latestRequestRef;
|
|
213
|
-
|
|
214
|
-
try {
|
|
215
|
-
// Load scene code dynamically from the filesystem
|
|
216
|
-
// Scene code is now in parameter object API format - passed directly to VijiCore
|
|
217
|
-
console.log(`📂 Loading project with ID: "${project.id}"`);
|
|
218
|
-
const sceneCode = await projectFileSystem.loadBundledProjectCode(project.id);
|
|
219
|
-
// Guard against out-of-order async resolutions
|
|
220
|
-
if (latestRequestRef.current !== requestId) return;
|
|
221
|
-
// Update both the selected project and its code together so effects see a consistent pair
|
|
222
|
-
setCurrentProject(project);
|
|
223
|
-
setCurrentSceneCode(sceneCode);
|
|
224
|
-
setSceneError(''); // Clear any previous errors
|
|
225
|
-
// avoid immediate HMR loop right after loading
|
|
226
|
-
hmrCooldownUntilRef.current = Date.now() + 1000;
|
|
227
|
-
console.log('✅ Successfully loaded scene for:', project.name, `(${sceneCode.length} chars)`);
|
|
228
|
-
} catch (error) {
|
|
229
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
230
|
-
setSceneError(`Failed to load scene: ${errorMessage}`);
|
|
231
|
-
console.error('❌ Failed to load scene code for project ID:', project.id, 'Project name:', project.name, 'Error:', error);
|
|
232
|
-
}
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
// Note: UI CRUD handlers removed - project management now done manually/CLI
|
|
236
|
-
|
|
237
|
-
// Error display component
|
|
238
|
-
if (sceneError) {
|
|
239
|
-
return (
|
|
240
|
-
<HeroUIProvider>
|
|
241
|
-
<div className="fixed inset-0 bg-black flex items-center justify-center">
|
|
242
|
-
<div className="text-center text-white max-w-lg p-8">
|
|
243
|
-
<h2 className="text-xl font-bold mb-4 text-red-400">Scene Error</h2>
|
|
244
|
-
<pre className="text-sm bg-red-900/20 p-4 rounded border border-red-500/50 overflow-auto whitespace-pre-wrap">
|
|
245
|
-
{sceneError}
|
|
246
|
-
</pre>
|
|
247
|
-
<div className="flex space-x-2 mt-4">
|
|
248
|
-
<button
|
|
249
|
-
onClick={() => setSceneError('')}
|
|
250
|
-
className="px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white rounded"
|
|
251
|
-
>
|
|
252
|
-
Dismiss Error
|
|
253
|
-
</button>
|
|
254
|
-
</div>
|
|
255
|
-
</div>
|
|
256
|
-
</div>
|
|
257
|
-
</HeroUIProvider>
|
|
258
|
-
);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
return (
|
|
264
|
-
<HeroUIProvider>
|
|
265
|
-
<div className="relative">
|
|
266
|
-
<SDKPage
|
|
267
|
-
sceneCode={currentSceneCode}
|
|
268
|
-
onSceneError={handleSceneError}
|
|
269
|
-
currentProject={currentProject}
|
|
270
|
-
onProjectSwitch={handleProjectSwitch}
|
|
271
|
-
/>
|
|
272
|
-
|
|
273
|
-
</div>
|
|
274
|
-
</HeroUIProvider>
|
|
275
|
-
);
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
export default App;
|
|
279
|
-
|
package/src/cli/commands/init.js
DELETED
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Init Command - Initialize a new Viji workspace
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { mkdir, writeFile, readFile, copyFile, readdir, stat } from 'fs/promises';
|
|
6
|
-
import { existsSync, readFileSync } from 'fs';
|
|
7
|
-
import { join, resolve, dirname, basename } from 'path';
|
|
8
|
-
import { fileURLToPath } from 'url';
|
|
9
|
-
import { spawn } from 'child_process';
|
|
10
|
-
import { createRequire } from 'module';
|
|
11
|
-
|
|
12
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
-
const __dirname = dirname(__filename);
|
|
14
|
-
|
|
15
|
-
export async function initCommand(workspaceName, options) {
|
|
16
|
-
try {
|
|
17
|
-
console.log('🎨 Initializing Viji workspace...');
|
|
18
|
-
|
|
19
|
-
// Determine workspace path
|
|
20
|
-
let workspacePath;
|
|
21
|
-
if (workspaceName === '.' || workspaceName === './') {
|
|
22
|
-
workspacePath = process.cwd();
|
|
23
|
-
workspaceName = basename(workspacePath);
|
|
24
|
-
console.log(`📁 Initializing in current directory: ${workspacePath}`);
|
|
25
|
-
console.log(`🏷️ Workspace name: ${workspaceName}`);
|
|
26
|
-
} else {
|
|
27
|
-
workspacePath = resolve(process.cwd(), workspaceName);
|
|
28
|
-
console.log(`📁 Creating workspace: ${workspacePath}`);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Check if directory exists and is not empty
|
|
32
|
-
if (existsSync(workspacePath)) {
|
|
33
|
-
const files = await readdir(workspacePath);
|
|
34
|
-
if (files.length > 0) {
|
|
35
|
-
console.error(`❌ Directory ${workspacePath} is not empty`);
|
|
36
|
-
console.log('💡 Use "viji init ." to initialize in current directory');
|
|
37
|
-
process.exit(1);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Find SDK directory (where this command is running from)
|
|
42
|
-
const sdkDir = findSDKDirectory();
|
|
43
|
-
if (!sdkDir) {
|
|
44
|
-
console.error('❌ Could not find Viji SDK installation');
|
|
45
|
-
process.exit(1);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
console.log('🛠️ SDK directory:', sdkDir);
|
|
49
|
-
console.log('🚀 Copying workspace files...');
|
|
50
|
-
|
|
51
|
-
// Create workspace directory if it doesn't exist
|
|
52
|
-
await mkdir(workspacePath, { recursive: true });
|
|
53
|
-
|
|
54
|
-
// Copy SDK structure to workspace
|
|
55
|
-
await copyWorkspaceFiles(sdkDir, workspacePath, workspaceName);
|
|
56
|
-
|
|
57
|
-
console.log('📦 Installing dependencies...');
|
|
58
|
-
|
|
59
|
-
// Install dependencies in the new workspace
|
|
60
|
-
await installDependencies(workspacePath);
|
|
61
|
-
|
|
62
|
-
console.log('✅ Workspace initialized successfully!');
|
|
63
|
-
console.log('');
|
|
64
|
-
console.log('🎯 Next steps:');
|
|
65
|
-
if (workspaceName !== basename(process.cwd())) {
|
|
66
|
-
console.log(` cd ${workspaceName}`);
|
|
67
|
-
}
|
|
68
|
-
console.log(' viji create my-first-scene --lang=js');
|
|
69
|
-
console.log(' viji dev');
|
|
70
|
-
console.log('');
|
|
71
|
-
console.log('🚀 Happy creating!');
|
|
72
|
-
|
|
73
|
-
} catch (error) {
|
|
74
|
-
console.error('💥 Failed to initialize workspace:', error.message);
|
|
75
|
-
process.exit(1);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async function copyWorkspaceFiles(sdkDir, workspacePath, workspaceName) {
|
|
80
|
-
// Files and directories to copy from SDK to workspace
|
|
81
|
-
const filesToCopy = [
|
|
82
|
-
'src',
|
|
83
|
-
'scenes',
|
|
84
|
-
'public',
|
|
85
|
-
'index.html',
|
|
86
|
-
'vite.config.ts',
|
|
87
|
-
'tsconfig.json',
|
|
88
|
-
'tsconfig.app.json',
|
|
89
|
-
'tsconfig.node.json',
|
|
90
|
-
'tailwind.config.js',
|
|
91
|
-
'postcss.config.js',
|
|
92
|
-
'eslint.config.js',
|
|
93
|
-
'.gitignore'
|
|
94
|
-
];
|
|
95
|
-
|
|
96
|
-
// Files to exclude from copying
|
|
97
|
-
const excludePatterns = [
|
|
98
|
-
'node_modules',
|
|
99
|
-
'dist',
|
|
100
|
-
'build',
|
|
101
|
-
'.git',
|
|
102
|
-
'package-lock.json',
|
|
103
|
-
'tsconfig.tsbuildinfo',
|
|
104
|
-
'vite.config.d.ts'
|
|
105
|
-
];
|
|
106
|
-
|
|
107
|
-
for (const item of filesToCopy) {
|
|
108
|
-
const sourcePath = join(sdkDir, item);
|
|
109
|
-
const targetPath = join(workspacePath, item);
|
|
110
|
-
|
|
111
|
-
if (existsSync(sourcePath)) {
|
|
112
|
-
await copyRecursive(sourcePath, targetPath, excludePatterns);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Create workspace-specific package.json
|
|
117
|
-
await createWorkspacePackageJson(sdkDir, workspacePath, workspaceName);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
async function copyRecursive(source, target, excludePatterns = []) {
|
|
121
|
-
const stats = await stat(source);
|
|
122
|
-
|
|
123
|
-
// Check if this path should be excluded
|
|
124
|
-
const sourceName = basename(source);
|
|
125
|
-
if (excludePatterns.some(pattern => sourceName.includes(pattern))) {
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (stats.isDirectory()) {
|
|
130
|
-
await mkdir(target, { recursive: true });
|
|
131
|
-
const files = await readdir(source);
|
|
132
|
-
|
|
133
|
-
for (const file of files) {
|
|
134
|
-
await copyRecursive(
|
|
135
|
-
join(source, file),
|
|
136
|
-
join(target, file),
|
|
137
|
-
excludePatterns
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
} else {
|
|
141
|
-
await copyFile(source, target);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
async function createWorkspacePackageJson(sdkDir, workspacePath, workspaceName) {
|
|
146
|
-
// Read the SDK package.json as template
|
|
147
|
-
const sdkPackageJson = JSON.parse(readFileSync(join(sdkDir, 'package.json'), 'utf8'));
|
|
148
|
-
|
|
149
|
-
// Create workspace package.json
|
|
150
|
-
const workspacePackageJson = {
|
|
151
|
-
name: workspaceName,
|
|
152
|
-
private: true,
|
|
153
|
-
version: "0.1.0",
|
|
154
|
-
type: "module",
|
|
155
|
-
description: `Viji workspace: ${workspaceName}`,
|
|
156
|
-
scripts: {
|
|
157
|
-
dev: "vite",
|
|
158
|
-
build: "tsc -b && vite build",
|
|
159
|
-
lint: "eslint .",
|
|
160
|
-
preview: "vite preview"
|
|
161
|
-
},
|
|
162
|
-
dependencies: {
|
|
163
|
-
// Copy runtime dependencies from SDK
|
|
164
|
-
"@heroicons/react": sdkPackageJson.dependencies["@heroicons/react"],
|
|
165
|
-
"@heroui/react": sdkPackageJson.dependencies["@heroui/react"],
|
|
166
|
-
"@viji-dev/core": sdkPackageJson.dependencies["@viji-dev/core"],
|
|
167
|
-
"autoprefixer": sdkPackageJson.dependencies["autoprefixer"],
|
|
168
|
-
"chokidar": sdkPackageJson.dependencies["chokidar"],
|
|
169
|
-
"clsx": sdkPackageJson.dependencies["clsx"],
|
|
170
|
-
"framer-motion": sdkPackageJson.dependencies["framer-motion"],
|
|
171
|
-
"react": sdkPackageJson.dependencies["react"],
|
|
172
|
-
"react-dom": sdkPackageJson.dependencies["react-dom"],
|
|
173
|
-
"tailwind-merge": sdkPackageJson.dependencies["tailwind-merge"],
|
|
174
|
-
"tailwindcss": sdkPackageJson.dependencies["tailwindcss"],
|
|
175
|
-
"zustand": sdkPackageJson.dependencies["zustand"]
|
|
176
|
-
},
|
|
177
|
-
devDependencies: {
|
|
178
|
-
// Copy dev dependencies from SDK
|
|
179
|
-
"@eslint/js": sdkPackageJson.devDependencies["@eslint/js"],
|
|
180
|
-
"@types/node": sdkPackageJson.devDependencies["@types/node"],
|
|
181
|
-
"@types/react": sdkPackageJson.devDependencies["@types/react"],
|
|
182
|
-
"@types/react-dom": sdkPackageJson.devDependencies["@types/react-dom"],
|
|
183
|
-
"@vitejs/plugin-react": sdkPackageJson.devDependencies["@vitejs/plugin-react"],
|
|
184
|
-
"eslint": sdkPackageJson.devDependencies["eslint"],
|
|
185
|
-
"eslint-plugin-react-hooks": sdkPackageJson.devDependencies["eslint-plugin-react-hooks"],
|
|
186
|
-
"eslint-plugin-react-refresh": sdkPackageJson.devDependencies["eslint-plugin-react-refresh"],
|
|
187
|
-
"globals": sdkPackageJson.devDependencies["globals"],
|
|
188
|
-
"typescript": sdkPackageJson.devDependencies["typescript"],
|
|
189
|
-
"typescript-eslint": sdkPackageJson.devDependencies["typescript-eslint"],
|
|
190
|
-
"vite": sdkPackageJson.devDependencies["vite"]
|
|
191
|
-
},
|
|
192
|
-
viji: {
|
|
193
|
-
sdkVersion: sdkPackageJson.version,
|
|
194
|
-
initDate: new Date().toISOString(),
|
|
195
|
-
workspaceVersion: "1.0.0"
|
|
196
|
-
}
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
await writeFile(
|
|
200
|
-
join(workspacePath, 'package.json'),
|
|
201
|
-
JSON.stringify(workspacePackageJson, null, 2)
|
|
202
|
-
);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
async function installDependencies(workspacePath) {
|
|
206
|
-
return new Promise((resolve, reject) => {
|
|
207
|
-
// Use platform-specific npm command
|
|
208
|
-
const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
209
|
-
|
|
210
|
-
const installProcess = spawn(npmCommand, ['install'], {
|
|
211
|
-
cwd: workspacePath,
|
|
212
|
-
stdio: 'inherit',
|
|
213
|
-
shell: true
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
installProcess.on('exit', (code) => {
|
|
217
|
-
if (code === 0) {
|
|
218
|
-
resolve();
|
|
219
|
-
} else {
|
|
220
|
-
reject(new Error(`npm install failed with code ${code}`));
|
|
221
|
-
}
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
installProcess.on('error', (error) => {
|
|
225
|
-
reject(error);
|
|
226
|
-
});
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function findSDKDirectory() {
|
|
231
|
-
// Try relative to this CLI file first (for development)
|
|
232
|
-
const relativeSDK = resolve(__dirname, '..', '..', '..');
|
|
233
|
-
if (existsSync(join(relativeSDK, 'package.json'))) {
|
|
234
|
-
const packageJson = JSON.parse(readFileSync(join(relativeSDK, 'package.json'), 'utf8'));
|
|
235
|
-
if (packageJson.name === 'viji-sdk') {
|
|
236
|
-
return relativeSDK;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Try to find global installation
|
|
241
|
-
try {
|
|
242
|
-
const require = createRequire(import.meta.url);
|
|
243
|
-
const globalSDK = require.resolve('viji-sdk');
|
|
244
|
-
if (globalSDK) {
|
|
245
|
-
return dirname(dirname(globalSDK)); // Go up from lib/index.js to root
|
|
246
|
-
}
|
|
247
|
-
} catch (error) {
|
|
248
|
-
// Not found globally
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// Try to find in node_modules
|
|
252
|
-
let currentPath = process.cwd();
|
|
253
|
-
while (currentPath !== dirname(currentPath)) {
|
|
254
|
-
const potentialSDK = join(currentPath, 'node_modules', 'viji-sdk');
|
|
255
|
-
if (existsSync(potentialSDK)) {
|
|
256
|
-
return potentialSDK;
|
|
257
|
-
}
|
|
258
|
-
currentPath = dirname(currentPath);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
return null;
|
|
262
|
-
}
|