@viji-dev/sdk 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +70 -63
  2. package/bin/viji.js +9 -29
  3. package/dist/assets/artist-dts-BHUsvSI6.js +613 -0
  4. package/dist/assets/artist-dts-p5-Cyw8vmy_.js +736 -0
  5. package/dist/assets/core-CiQx3w0t.js +12 -0
  6. package/dist/assets/dark-plus-C3mMm8J8.js +1 -0
  7. package/dist/assets/docs-api-PBLtY4Ni.js +12381 -0
  8. package/dist/assets/engine-javascript-CXyY7cc8.js +141 -0
  9. package/dist/assets/essentia-wasm.web-0S-sW98u-CYV1l1zv.js +38 -0
  10. package/dist/assets/essentia.js-core.es-DnrJE0uR-DOSrF5_G.js +32 -0
  11. package/dist/assets/glsl-DMyvO4G4.js +1 -0
  12. package/dist/assets/index-BhFxsauQ.js +215 -0
  13. package/dist/assets/index-BqhVeA7U.css +1 -0
  14. package/dist/assets/index-T4TOjvD0.js +1 -0
  15. package/dist/assets/index-Wz9WqGqz.js +52 -0
  16. package/dist/assets/index-t24aGwla.js +1 -0
  17. package/dist/assets/javascript-wDzz0qaB.js +1 -0
  18. package/dist/assets/shader-uniforms-GdaUkQPK.js +1 -0
  19. package/dist/assets/typescript-BPQ3VLAy.js +1 -0
  20. package/dist/assets/viji.worker-CQSJ0SiO-ljtBlcNZ.js +27018 -0
  21. package/{index.html → dist/index.html} +2 -1
  22. package/package.json +31 -35
  23. package/src/cli/commands/build.js +50 -99
  24. package/src/cli/commands/create.js +49 -46
  25. package/src/cli/commands/dev.js +30 -97
  26. package/src/cli/server/dev-server.js +233 -0
  27. package/src/cli/server/scene-scanner.js +93 -0
  28. package/src/cli/server/vite-scene-plugin.d.ts +2 -0
  29. package/src/cli/server/vite-scene-plugin.js +134 -0
  30. package/src/cli/utils/cli-utils.js +29 -139
  31. package/src/cli/utils/scene-compiler.js +10 -17
  32. package/src/templates/scene-templates.js +85 -0
  33. package/.gitignore +0 -29
  34. package/eslint.config.js +0 -37
  35. package/postcss.config.js +0 -6
  36. package/scenes/audio-visualizer/main.js +0 -287
  37. package/scenes/core-demo/main.js +0 -532
  38. package/scenes/demo-scene/main.js +0 -619
  39. package/scenes/global.d.ts +0 -15
  40. package/scenes/particle-system/main.js +0 -349
  41. package/scenes/tsconfig.json +0 -12
  42. package/scenes/video-mirror/main.ts +0 -436
  43. package/src/App.css +0 -42
  44. package/src/App.tsx +0 -279
  45. package/src/cli/commands/init.js +0 -262
  46. package/src/components/SDKPage.tsx +0 -337
  47. package/src/components/core/CoreContainer.tsx +0 -126
  48. package/src/components/ui/DeviceSelectionList.tsx +0 -137
  49. package/src/components/ui/FPSCounter.tsx +0 -78
  50. package/src/components/ui/FileDropzonePanel.tsx +0 -120
  51. package/src/components/ui/FileListPanel.tsx +0 -285
  52. package/src/components/ui/InputExpansionPanel.tsx +0 -31
  53. package/src/components/ui/MediaPlayerControls.tsx +0 -191
  54. package/src/components/ui/MenuContainer.tsx +0 -71
  55. package/src/components/ui/ParametersMenu.tsx +0 -797
  56. package/src/components/ui/ProjectSwitcherMenu.tsx +0 -192
  57. package/src/components/ui/QuickInputControls.tsx +0 -542
  58. package/src/components/ui/SDKMenuSystem.tsx +0 -96
  59. package/src/components/ui/SettingsMenu.tsx +0 -346
  60. package/src/components/ui/SimpleInputControls.tsx +0 -137
  61. package/src/index.css +0 -68
  62. package/src/main.tsx +0 -10
  63. package/src/scenes-hmr.ts +0 -158
  64. package/src/services/project-filesystem.ts +0 -436
  65. package/src/stores/scene-player/index.ts +0 -3
  66. package/src/stores/scene-player/input-manager.store.ts +0 -1045
  67. package/src/stores/scene-player/scene-session.store.ts +0 -659
  68. package/src/styles/globals.css +0 -111
  69. package/src/templates/minimal-template.js +0 -11
  70. package/src/utils/debounce.js +0 -34
  71. package/src/vite-env.d.ts +0 -1
  72. package/tailwind.config.js +0 -18
  73. package/tsconfig.app.json +0 -27
  74. package/tsconfig.json +0 -27
  75. package/tsconfig.node.json +0 -27
  76. package/vite.config.ts +0 -54
  77. /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
-
@@ -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
- }