@vue-skuilder/cli 0.1.5 ā 0.1.7
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/CLAUDE.md +84 -0
- package/dist/cli.js +8 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +46 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/pack.js +17 -0
- package/dist/commands/pack.js.map +1 -1
- package/dist/commands/studio.d.ts +3 -0
- package/dist/commands/studio.d.ts.map +1 -0
- package/dist/commands/studio.js +396 -0
- package/dist/commands/studio.js.map +1 -0
- package/dist/commands/unpack.d.ts +3 -0
- package/dist/commands/unpack.d.ts.map +1 -0
- package/dist/commands/unpack.js +228 -0
- package/dist/commands/unpack.js.map +1 -0
- package/dist/studio-ui-assets/assets/BrowseView-BJbixGOU.js +2 -0
- package/dist/studio-ui-assets/assets/BrowseView-BJbixGOU.js.map +1 -0
- package/dist/studio-ui-assets/assets/BrowseView-CM4HBO4j.css +1 -0
- package/dist/studio-ui-assets/assets/BulkImportView-DB6DYDJU.js +2 -0
- package/dist/studio-ui-assets/assets/BulkImportView-DB6DYDJU.js.map +1 -0
- package/dist/studio-ui-assets/assets/BulkImportView-g4wQUfPA.css +1 -0
- package/dist/studio-ui-assets/assets/CourseEditorView-BIlhlhw1.js +2 -0
- package/dist/studio-ui-assets/assets/CourseEditorView-BIlhlhw1.js.map +1 -0
- package/dist/studio-ui-assets/assets/CourseEditorView-WuPNLVKp.css +1 -0
- package/dist/studio-ui-assets/assets/CreateCardView-CyNOKCkm.css +1 -0
- package/dist/studio-ui-assets/assets/CreateCardView-DPjPvzzt.js +2 -0
- package/dist/studio-ui-assets/assets/CreateCardView-DPjPvzzt.js.map +1 -0
- package/dist/studio-ui-assets/assets/edit-ui.es-DiUxqbgF.js +330 -0
- package/dist/studio-ui-assets/assets/edit-ui.es-DiUxqbgF.js.map +1 -0
- package/dist/studio-ui-assets/assets/index--zY88pg6.css +14 -0
- package/dist/studio-ui-assets/assets/index-BnAv1C72.js +287 -0
- package/dist/studio-ui-assets/assets/index-BnAv1C72.js.map +1 -0
- package/dist/studio-ui-assets/assets/index-DHMXQY3-.js +192 -0
- package/dist/studio-ui-assets/assets/index-DHMXQY3-.js.map +1 -0
- package/dist/studio-ui-assets/assets/materialdesignicons-webfont-B7mPwVP_.ttf +0 -0
- package/dist/studio-ui-assets/assets/materialdesignicons-webfont-CSr8KVlo.eot +0 -0
- package/dist/studio-ui-assets/assets/materialdesignicons-webfont-Dp5v-WZN.woff2 +0 -0
- package/dist/studio-ui-assets/assets/materialdesignicons-webfont-PXm3-2wK.woff +0 -0
- package/dist/studio-ui-assets/assets/vue-DZcMATiC.js +28 -0
- package/dist/studio-ui-assets/assets/vue-DZcMATiC.js.map +1 -0
- package/dist/studio-ui-assets/assets/vuetify-qg7mRxy_.js +6 -0
- package/dist/studio-ui-assets/assets/vuetify-qg7mRxy_.js.map +1 -0
- package/dist/studio-ui-assets/index.html +16 -0
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/NodeFileSystemAdapter.d.ts +14 -0
- package/dist/utils/NodeFileSystemAdapter.d.ts.map +1 -0
- package/dist/utils/NodeFileSystemAdapter.js +55 -0
- package/dist/utils/NodeFileSystemAdapter.js.map +1 -0
- package/dist/utils/pack-courses.d.ts +13 -0
- package/dist/utils/pack-courses.d.ts.map +1 -0
- package/dist/utils/pack-courses.js +54 -0
- package/dist/utils/pack-courses.js.map +1 -0
- package/dist/utils/prompts.d.ts.map +1 -1
- package/dist/utils/prompts.js +206 -21
- package/dist/utils/prompts.js.map +1 -1
- package/dist/utils/template.d.ts +5 -1
- package/dist/utils/template.d.ts.map +1 -1
- package/dist/utils/template.js +71 -7
- package/dist/utils/template.js.map +1 -1
- package/package.json +7 -4
- package/src/cli.ts +8 -0
- package/src/commands/init.ts +62 -6
- package/src/commands/pack.ts +24 -1
- package/src/commands/studio.ts +497 -0
- package/src/commands/unpack.ts +259 -0
- package/src/types.ts +6 -0
- package/src/utils/NodeFileSystemAdapter.ts +72 -0
- package/src/utils/pack-courses.ts +77 -0
- package/src/utils/prompts.ts +252 -39
- package/src/utils/template.ts +83 -8
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { spawn } from 'child_process';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import { dirname } from 'path';
|
|
8
|
+
import http from 'http';
|
|
9
|
+
import { CouchDBManager } from '@vue-skuilder/common/docker';
|
|
10
|
+
// TODO: Re-enable once module import issues are resolved
|
|
11
|
+
// import { StaticToCouchDBMigrator, validateStaticCourse } from '@vue-skuilder/db';
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = dirname(__filename);
|
|
14
|
+
export function createStudioCommand() {
|
|
15
|
+
return new Command('studio')
|
|
16
|
+
.description('Launch studio mode for editing a static course')
|
|
17
|
+
.argument('[coursePath]', 'Path to static course directory', '.')
|
|
18
|
+
.option('-p, --port <port>', 'CouchDB port for studio session', '5985')
|
|
19
|
+
.option('--no-browser', 'Skip automatic browser launch')
|
|
20
|
+
.action(launchStudio);
|
|
21
|
+
}
|
|
22
|
+
// Global references for cleanup
|
|
23
|
+
let couchDBManager = null;
|
|
24
|
+
let studioUIServer = null;
|
|
25
|
+
async function launchStudio(coursePath, options) {
|
|
26
|
+
try {
|
|
27
|
+
console.log(chalk.cyan(`šØ Launching Skuilder Studio...`));
|
|
28
|
+
// Phase 2: Course Detection & Validation
|
|
29
|
+
const resolvedPath = path.resolve(coursePath);
|
|
30
|
+
console.log(chalk.gray(`š Course path: ${resolvedPath}`));
|
|
31
|
+
if (!(await validateSuiCourse(resolvedPath))) {
|
|
32
|
+
console.error(chalk.red(`ā Not a valid standalone-ui course directory`));
|
|
33
|
+
console.log(chalk.yellow(`š” Studio mode requires a vue-skuilder course with:`));
|
|
34
|
+
console.log(chalk.yellow(` - package.json with @vue-skuilder/* dependencies`));
|
|
35
|
+
console.log(chalk.yellow(` - static-data/ OR public/static-courses/ directory with course content`));
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
console.log(chalk.green(`ā
Valid standalone-ui course detected`));
|
|
39
|
+
// Phase 1: CouchDB Management
|
|
40
|
+
const studioDatabaseName = generateStudioDatabaseName(resolvedPath);
|
|
41
|
+
console.log(chalk.cyan(`šļø Starting studio CouchDB instance: ${studioDatabaseName}`));
|
|
42
|
+
couchDBManager = await startStudioCouchDB(studioDatabaseName, parseInt(options.port));
|
|
43
|
+
// Phase 4: Populate CouchDB with course data
|
|
44
|
+
console.log(chalk.cyan(`š¦ Unpacking course data to studio database...`));
|
|
45
|
+
const unpackResult = await unpackCourseToStudio(resolvedPath, couchDBManager.getConnectionDetails());
|
|
46
|
+
// Phase 7: Launch studio-ui server
|
|
47
|
+
console.log(chalk.cyan(`š Starting studio-ui server...`));
|
|
48
|
+
console.log(chalk.gray(` Debug: Unpack result - Database: "${unpackResult.databaseName}", Course ID: "${unpackResult.courseId}"`));
|
|
49
|
+
const studioUIPort = await startStudioUIServer(couchDBManager.getConnectionDetails(), unpackResult);
|
|
50
|
+
console.log(chalk.green(`ā
Studio session ready!`));
|
|
51
|
+
console.log(chalk.white(`šØ Studio URL: http://localhost:${studioUIPort}`));
|
|
52
|
+
console.log(chalk.gray(` Database: ${studioDatabaseName} on port ${options.port}`));
|
|
53
|
+
if (options.browser) {
|
|
54
|
+
console.log(chalk.cyan(`š Opening browser...`));
|
|
55
|
+
await openBrowser(`http://localhost:${studioUIPort}`);
|
|
56
|
+
}
|
|
57
|
+
console.log(chalk.gray(` Press Ctrl+C to stop studio session`));
|
|
58
|
+
// Keep process alive and handle cleanup
|
|
59
|
+
process.on('SIGINT', () => {
|
|
60
|
+
void (async () => {
|
|
61
|
+
console.log(chalk.cyan(`\nš Stopping studio session...`));
|
|
62
|
+
await stopStudioSession();
|
|
63
|
+
console.log(chalk.green(`ā
Studio session stopped`));
|
|
64
|
+
process.exit(0);
|
|
65
|
+
})();
|
|
66
|
+
});
|
|
67
|
+
process.on('SIGTERM', () => {
|
|
68
|
+
void (async () => {
|
|
69
|
+
console.log(chalk.cyan(`\nš Stopping studio session...`));
|
|
70
|
+
await stopStudioSession();
|
|
71
|
+
process.exit(0);
|
|
72
|
+
})();
|
|
73
|
+
});
|
|
74
|
+
// Keep process alive
|
|
75
|
+
await new Promise(() => { });
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
console.error(chalk.red(`ā Studio launch failed:`), error);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Phase 2: Validate that the given path contains a standalone-ui course
|
|
84
|
+
*/
|
|
85
|
+
async function validateSuiCourse(coursePath) {
|
|
86
|
+
try {
|
|
87
|
+
// Check if directory exists
|
|
88
|
+
if (!fs.existsSync(coursePath)) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
// Check for package.json
|
|
92
|
+
const packageJsonPath = path.join(coursePath, 'package.json');
|
|
93
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
// Read and validate package.json
|
|
97
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
98
|
+
// Check for vue-skuilder course indicators (either standalone-ui or required packages)
|
|
99
|
+
const hasStandaloneUi = (packageJson.dependencies && packageJson.dependencies['@vue-skuilder/standalone-ui']) ||
|
|
100
|
+
(packageJson.devDependencies && packageJson.devDependencies['@vue-skuilder/standalone-ui']);
|
|
101
|
+
const hasRequiredPackages = packageJson.dependencies &&
|
|
102
|
+
packageJson.dependencies['@vue-skuilder/common-ui'] &&
|
|
103
|
+
packageJson.dependencies['@vue-skuilder/courses'] &&
|
|
104
|
+
packageJson.dependencies['@vue-skuilder/db'];
|
|
105
|
+
if (!hasStandaloneUi && !hasRequiredPackages) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
// Check for course content directory (static-data OR public/static-courses)
|
|
109
|
+
const staticDataPath = path.join(coursePath, 'static-data');
|
|
110
|
+
const publicStaticCoursesPath = path.join(coursePath, 'public', 'static-courses');
|
|
111
|
+
if (!fs.existsSync(staticDataPath) && !fs.existsSync(publicStaticCoursesPath)) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Generate a unique database name for this studio session
|
|
122
|
+
*/
|
|
123
|
+
function generateStudioDatabaseName(coursePath) {
|
|
124
|
+
const courseName = path.basename(coursePath);
|
|
125
|
+
const timestamp = Date.now();
|
|
126
|
+
return `studio-${courseName.toLowerCase().replace(/[^a-z0-9]/g, '-')}-${timestamp}`;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Phase 1: Start CouchDB for studio session
|
|
130
|
+
*/
|
|
131
|
+
async function startStudioCouchDB(_databaseName, port) {
|
|
132
|
+
const manager = new CouchDBManager({
|
|
133
|
+
mode: 'blank',
|
|
134
|
+
port: port,
|
|
135
|
+
containerName: `skuilder-studio-${port}`,
|
|
136
|
+
}, {
|
|
137
|
+
onLog: (message) => console.log(chalk.gray(` ${message}`)),
|
|
138
|
+
onError: (error) => console.error(chalk.red(` Error: ${error}`)),
|
|
139
|
+
});
|
|
140
|
+
try {
|
|
141
|
+
await manager.start();
|
|
142
|
+
const connectionDetails = manager.getConnectionDetails();
|
|
143
|
+
console.log(chalk.green(`ā
CouchDB studio instance ready`));
|
|
144
|
+
console.log(chalk.gray(` URL: ${connectionDetails.url}`));
|
|
145
|
+
console.log(chalk.gray(` Username: ${connectionDetails.username}`));
|
|
146
|
+
console.log(chalk.gray(` Password: ${connectionDetails.password}`));
|
|
147
|
+
return manager;
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
151
|
+
console.error(chalk.red(`Failed to start CouchDB: ${errorMessage}`));
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Stop entire studio session (CouchDB + UI server)
|
|
157
|
+
*/
|
|
158
|
+
async function stopStudioSession() {
|
|
159
|
+
// Stop studio-ui server
|
|
160
|
+
if (studioUIServer) {
|
|
161
|
+
try {
|
|
162
|
+
studioUIServer.close();
|
|
163
|
+
console.log(chalk.green(`ā
Studio-UI server stopped`));
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
167
|
+
console.error(chalk.red(`Error stopping studio-ui server: ${errorMessage}`));
|
|
168
|
+
}
|
|
169
|
+
studioUIServer = null;
|
|
170
|
+
}
|
|
171
|
+
// Stop CouchDB
|
|
172
|
+
if (couchDBManager) {
|
|
173
|
+
try {
|
|
174
|
+
await couchDBManager.remove(); // This stops and removes the container
|
|
175
|
+
console.log(chalk.green(`ā
CouchDB studio instance cleaned up`));
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
179
|
+
console.error(chalk.red(`Error cleaning up CouchDB: ${errorMessage}`));
|
|
180
|
+
}
|
|
181
|
+
couchDBManager = null;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async function startStudioUIServer(connectionDetails, unpackResult) {
|
|
185
|
+
const studioAssetsPath = path.join(__dirname, '..', 'studio-ui-assets');
|
|
186
|
+
if (!fs.existsSync(studioAssetsPath)) {
|
|
187
|
+
throw new Error('Studio-UI assets not found. Please rebuild the CLI package.');
|
|
188
|
+
}
|
|
189
|
+
// Find available port starting from 7174
|
|
190
|
+
let port = 7174;
|
|
191
|
+
while (port < 7200) {
|
|
192
|
+
try {
|
|
193
|
+
await new Promise((resolve, reject) => {
|
|
194
|
+
const server = http.createServer((req, res) => {
|
|
195
|
+
let filePath = path.join(studioAssetsPath, req.url === '/' ? 'index.html' : req.url || '');
|
|
196
|
+
// Security: prevent directory traversal
|
|
197
|
+
if (!filePath.startsWith(studioAssetsPath)) {
|
|
198
|
+
res.writeHead(403);
|
|
199
|
+
res.end('Forbidden');
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
// Check if file exists
|
|
203
|
+
if (!fs.existsSync(filePath)) {
|
|
204
|
+
// If it's not a file, serve index.html for SPA routing
|
|
205
|
+
filePath = path.join(studioAssetsPath, 'index.html');
|
|
206
|
+
}
|
|
207
|
+
// Determine content type
|
|
208
|
+
const ext = path.extname(filePath);
|
|
209
|
+
const contentType = {
|
|
210
|
+
'.html': 'text/html',
|
|
211
|
+
'.js': 'text/javascript',
|
|
212
|
+
'.css': 'text/css',
|
|
213
|
+
'.woff2': 'font/woff2',
|
|
214
|
+
'.woff': 'font/woff',
|
|
215
|
+
'.ttf': 'font/ttf',
|
|
216
|
+
'.eot': 'application/vnd.ms-fontobject',
|
|
217
|
+
}[ext] || 'application/octet-stream';
|
|
218
|
+
res.writeHead(200, { 'Content-Type': contentType });
|
|
219
|
+
// For HTML files, inject CouchDB connection details
|
|
220
|
+
if (ext === '.html') {
|
|
221
|
+
let html = fs.readFileSync(filePath, 'utf8');
|
|
222
|
+
// Inject connection details as script tag before </head>
|
|
223
|
+
const connectionScript = `
|
|
224
|
+
<script>
|
|
225
|
+
window.STUDIO_CONFIG = {
|
|
226
|
+
couchdb: {
|
|
227
|
+
url: '${connectionDetails.url}',
|
|
228
|
+
username: '${connectionDetails.username}',
|
|
229
|
+
password: '${connectionDetails.password}'
|
|
230
|
+
},
|
|
231
|
+
database: {
|
|
232
|
+
name: '${unpackResult.databaseName}',
|
|
233
|
+
courseId: '${unpackResult.courseId}'
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
</script>
|
|
237
|
+
`;
|
|
238
|
+
html = html.replace('</head>', connectionScript + '</head>');
|
|
239
|
+
res.end(html);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
// Serve static files
|
|
243
|
+
const stream = fs.createReadStream(filePath);
|
|
244
|
+
stream.pipe(res);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
server.listen(port, '127.0.0.1', () => {
|
|
248
|
+
studioUIServer = server;
|
|
249
|
+
resolve();
|
|
250
|
+
});
|
|
251
|
+
server.on('error', (err) => {
|
|
252
|
+
if (err.code === 'EADDRINUSE') {
|
|
253
|
+
reject(err);
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
reject(err);
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
// Port is available
|
|
261
|
+
console.log(chalk.green(`ā
Studio-UI server running on port ${port}`));
|
|
262
|
+
return port;
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
if (error instanceof Error && 'code' in error && error.code === 'EADDRINUSE') {
|
|
266
|
+
port++;
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
throw error;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
throw new Error('Unable to find an available port for studio-ui server');
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Open browser to studio URL
|
|
278
|
+
*/
|
|
279
|
+
async function openBrowser(url) {
|
|
280
|
+
const { spawn } = await import('child_process');
|
|
281
|
+
let command;
|
|
282
|
+
let args;
|
|
283
|
+
switch (process.platform) {
|
|
284
|
+
case 'darwin':
|
|
285
|
+
command = 'open';
|
|
286
|
+
args = [url];
|
|
287
|
+
break;
|
|
288
|
+
case 'win32':
|
|
289
|
+
command = 'start';
|
|
290
|
+
args = ['', url];
|
|
291
|
+
break;
|
|
292
|
+
default:
|
|
293
|
+
command = 'xdg-open';
|
|
294
|
+
args = [url];
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
297
|
+
try {
|
|
298
|
+
spawn(command, args, { detached: true, stdio: 'ignore' });
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
console.log(chalk.yellow(`ā ļø Could not automatically open browser. Please visit: ${url}`));
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Phase 4: Unpack course data to studio CouchDB
|
|
306
|
+
*/
|
|
307
|
+
async function unpackCourseToStudio(coursePath, connectionDetails) {
|
|
308
|
+
return new Promise((resolve, reject) => {
|
|
309
|
+
// Find the course data directory (static-data OR public/static-courses)
|
|
310
|
+
let courseDataPath = path.join(coursePath, 'static-data');
|
|
311
|
+
if (!fs.existsSync(courseDataPath)) {
|
|
312
|
+
// Try public/static-courses directory
|
|
313
|
+
const publicStaticPath = path.join(coursePath, 'public', 'static-courses');
|
|
314
|
+
if (fs.existsSync(publicStaticPath)) {
|
|
315
|
+
// Find the first course directory inside public/static-courses
|
|
316
|
+
const courses = fs
|
|
317
|
+
.readdirSync(publicStaticPath, { withFileTypes: true })
|
|
318
|
+
.filter((dirent) => dirent.isDirectory())
|
|
319
|
+
.map((dirent) => dirent.name);
|
|
320
|
+
if (courses.length > 0) {
|
|
321
|
+
courseDataPath = path.join(publicStaticPath, courses[0]);
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
reject(new Error('No course directories found in public/static-courses/'));
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
reject(new Error('No course data found in static-data/ or public/static-courses/'));
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
console.log(chalk.gray(` Course data path: ${courseDataPath}`));
|
|
334
|
+
// Build the unpack command arguments
|
|
335
|
+
const args = [
|
|
336
|
+
'unpack',
|
|
337
|
+
courseDataPath,
|
|
338
|
+
'--server',
|
|
339
|
+
connectionDetails.url,
|
|
340
|
+
'--username',
|
|
341
|
+
connectionDetails.username,
|
|
342
|
+
'--password',
|
|
343
|
+
connectionDetails.password,
|
|
344
|
+
];
|
|
345
|
+
console.log(chalk.gray(` Running: skuilder ${args.join(' ')}`));
|
|
346
|
+
// Spawn the unpack command as a child process
|
|
347
|
+
const unpackProcess = spawn('node', [path.join(__dirname, '..', 'cli.js'), ...args], {
|
|
348
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
349
|
+
cwd: process.cwd(),
|
|
350
|
+
});
|
|
351
|
+
let stdout = '';
|
|
352
|
+
let stderr = '';
|
|
353
|
+
unpackProcess.stdout?.on('data', (data) => {
|
|
354
|
+
const output = data.toString();
|
|
355
|
+
stdout += output;
|
|
356
|
+
// Forward output with indentation
|
|
357
|
+
process.stdout.write(chalk.gray(` ${output.replace(/\n/g, '\n ')}`));
|
|
358
|
+
});
|
|
359
|
+
unpackProcess.stderr?.on('data', (data) => {
|
|
360
|
+
const output = data.toString();
|
|
361
|
+
stderr += output;
|
|
362
|
+
// Forward error output with indentation
|
|
363
|
+
process.stderr.write(chalk.gray(` ${output.replace(/\n/g, '\n ')}`));
|
|
364
|
+
});
|
|
365
|
+
unpackProcess.on('close', (code) => {
|
|
366
|
+
if (code === 0) {
|
|
367
|
+
console.log(chalk.green(`ā
Course data unpacked successfully`));
|
|
368
|
+
// Parse the output to extract database name and course ID
|
|
369
|
+
console.log(chalk.gray(` Debug: Parsing unpack output...`));
|
|
370
|
+
const databaseMatch = stdout.match(/Database: ([\w-_]+)/);
|
|
371
|
+
const courseIdMatch = stdout.match(/Course: .* \(([a-f0-9]+)\)/);
|
|
372
|
+
const fullDatabaseName = databaseMatch ? databaseMatch[1] : '';
|
|
373
|
+
const courseId = courseIdMatch ? courseIdMatch[1] : '';
|
|
374
|
+
// Extract the course database ID by removing 'coursedb-' prefix
|
|
375
|
+
const databaseName = fullDatabaseName.startsWith('coursedb-')
|
|
376
|
+
? fullDatabaseName.substring('coursedb-'.length)
|
|
377
|
+
: fullDatabaseName;
|
|
378
|
+
console.log(chalk.gray(` Debug: Parsed - Full DB: "${fullDatabaseName}", Course DB ID: "${databaseName}", Course ID: "${courseId}"`));
|
|
379
|
+
if (!databaseName || !courseId) {
|
|
380
|
+
console.warn(chalk.yellow(`ā ļø Could not parse database name or course ID from unpack output`));
|
|
381
|
+
console.log(chalk.gray(` Raw stdout length: ${stdout.length} chars`));
|
|
382
|
+
}
|
|
383
|
+
resolve({ databaseName, courseId });
|
|
384
|
+
}
|
|
385
|
+
else {
|
|
386
|
+
console.error(chalk.red(`ā Failed to unpack course data (exit code: ${code})`));
|
|
387
|
+
reject(new Error(`Unpack failed with code ${code}\nstdout: ${stdout}\nstderr: ${stderr}`));
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
unpackProcess.on('error', (error) => {
|
|
391
|
+
console.error(chalk.red(`ā Failed to start unpack process: ${error.message}`));
|
|
392
|
+
reject(error);
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
//# sourceMappingURL=studio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"studio.js","sourceRoot":"","sources":["../../src/commands/studio.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unpack.d.ts","sourceRoot":"","sources":["../../src/commands/unpack.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,wBAAgB,mBAAmB,IAAI,OAAO,CAa7C"}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import PouchDB from 'pouchdb';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { StaticToCouchDBMigrator, validateStaticCourse, CourseLookup, ENV } from '@vue-skuilder/db';
|
|
6
|
+
import { NodeFileSystemAdapter } from '../utils/NodeFileSystemAdapter.js';
|
|
7
|
+
export function createUnpackCommand() {
|
|
8
|
+
return new Command('unpack')
|
|
9
|
+
.description('Unpack a static course directory into CouchDB')
|
|
10
|
+
.argument('<coursePath>', 'Path to static course directory')
|
|
11
|
+
.option('-s, --server <url>', 'CouchDB server URL', 'http://localhost:5984')
|
|
12
|
+
.option('-u, --username <username>', 'CouchDB username')
|
|
13
|
+
.option('-p, --password <password>', 'CouchDB password')
|
|
14
|
+
.option('-d, --database <name>', 'Target database name (auto-generated if not provided)')
|
|
15
|
+
.option('--as <name>', 'Set a custom name for the unpacked course')
|
|
16
|
+
.option('--chunk-size <size>', 'Documents per batch', '100')
|
|
17
|
+
.option('--validate', 'Run migration validation')
|
|
18
|
+
.option('--cleanup-on-error', 'Clean up database if migration fails')
|
|
19
|
+
.action(unpackCourse);
|
|
20
|
+
}
|
|
21
|
+
async function unpackCourse(coursePath, options) {
|
|
22
|
+
// Store original ENV values for cleanup
|
|
23
|
+
const originalEnv = {
|
|
24
|
+
COUCHDB_SERVER_PROTOCOL: ENV.COUCHDB_SERVER_PROTOCOL,
|
|
25
|
+
COUCHDB_SERVER_URL: ENV.COUCHDB_SERVER_URL,
|
|
26
|
+
COUCHDB_USERNAME: ENV.COUCHDB_USERNAME,
|
|
27
|
+
COUCHDB_PASSWORD: ENV.COUCHDB_PASSWORD,
|
|
28
|
+
};
|
|
29
|
+
try {
|
|
30
|
+
console.log(chalk.cyan(`š§ Unpacking static course to CouchDB...`));
|
|
31
|
+
console.log(chalk.gray(`š Source: ${path.resolve(coursePath)}`));
|
|
32
|
+
// Create file system adapter
|
|
33
|
+
const fileSystemAdapter = new NodeFileSystemAdapter();
|
|
34
|
+
// Validate static course directory
|
|
35
|
+
console.log(chalk.cyan('š Validating static course...'));
|
|
36
|
+
const validation = await validateStaticCourse(coursePath, fileSystemAdapter);
|
|
37
|
+
if (!validation.valid) {
|
|
38
|
+
console.log(chalk.red('ā Static course validation failed:'));
|
|
39
|
+
validation.errors.forEach((error) => {
|
|
40
|
+
console.log(chalk.red(` ⢠${error}`));
|
|
41
|
+
});
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
if (validation.warnings.length > 0) {
|
|
45
|
+
console.log(chalk.yellow('ā ļø Validation warnings:'));
|
|
46
|
+
validation.warnings.forEach((warning) => {
|
|
47
|
+
console.log(chalk.yellow(` ⢠${warning}`));
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
console.log(chalk.green('ā
Static course validation passed'));
|
|
51
|
+
console.log(chalk.gray(`š Course: ${validation.courseName || 'Unknown'} (${validation.courseId || 'Unknown ID'})`));
|
|
52
|
+
// Generate studio course ID and database name if not provided
|
|
53
|
+
let targetDbName = options.database;
|
|
54
|
+
let studioCourseId;
|
|
55
|
+
if (!targetDbName) {
|
|
56
|
+
const timestamp = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
|
57
|
+
const random = Math.random().toString(36).substring(2, 8);
|
|
58
|
+
studioCourseId = `unpacked_${validation.courseId || 'unknown'}_${timestamp}_${random}`;
|
|
59
|
+
targetDbName = `coursedb-${studioCourseId}`;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// If user provided custom database name, extract studio course ID from it
|
|
63
|
+
studioCourseId = targetDbName.startsWith('coursedb-')
|
|
64
|
+
? targetDbName.substring(9)
|
|
65
|
+
: targetDbName;
|
|
66
|
+
}
|
|
67
|
+
// Construct database URL
|
|
68
|
+
const dbUrl = `${options.server}/${targetDbName}`;
|
|
69
|
+
console.log(chalk.gray(`š” Target: ${dbUrl}`));
|
|
70
|
+
// Setup database connection options
|
|
71
|
+
const dbOptions = {};
|
|
72
|
+
if (options.username && options.password) {
|
|
73
|
+
dbOptions.auth = {
|
|
74
|
+
username: options.username,
|
|
75
|
+
password: options.password,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// Create and connect to target database
|
|
79
|
+
console.log(chalk.cyan('š Creating target database...'));
|
|
80
|
+
const targetDB = new PouchDB(dbUrl, dbOptions);
|
|
81
|
+
// Test connection by trying to get database info
|
|
82
|
+
try {
|
|
83
|
+
await targetDB.info();
|
|
84
|
+
console.log(chalk.green('ā
Connected to target database'));
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
let errorMessage = 'Unknown error';
|
|
88
|
+
if (error instanceof Error) {
|
|
89
|
+
errorMessage = error.message;
|
|
90
|
+
}
|
|
91
|
+
else if (typeof error === 'string') {
|
|
92
|
+
errorMessage = error;
|
|
93
|
+
}
|
|
94
|
+
else if (error && typeof error === 'object' && 'message' in error) {
|
|
95
|
+
errorMessage = String(error.message);
|
|
96
|
+
}
|
|
97
|
+
throw new Error(`Failed to connect to target database: ${errorMessage}`);
|
|
98
|
+
}
|
|
99
|
+
// Setup ENV variables for CourseLookup (temporarily override for this operation)
|
|
100
|
+
try {
|
|
101
|
+
// Parse server URL to extract protocol and host
|
|
102
|
+
const serverUrl = new URL(options.server);
|
|
103
|
+
ENV.COUCHDB_SERVER_PROTOCOL = serverUrl.protocol.slice(0, -1); // Remove trailing ':'
|
|
104
|
+
ENV.COUCHDB_SERVER_URL = serverUrl.host;
|
|
105
|
+
if (options.username)
|
|
106
|
+
ENV.COUCHDB_USERNAME = options.username;
|
|
107
|
+
if (options.password)
|
|
108
|
+
ENV.COUCHDB_PASSWORD = options.password;
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
throw new Error(`Invalid server URL: ${options.server}`);
|
|
112
|
+
}
|
|
113
|
+
// Configure migrator
|
|
114
|
+
const migratorOptions = {
|
|
115
|
+
chunkBatchSize: parseInt(options.chunkSize),
|
|
116
|
+
validateRoundTrip: options.validate,
|
|
117
|
+
cleanupOnFailure: options.cleanupOnError,
|
|
118
|
+
};
|
|
119
|
+
console.log(chalk.gray(`š¦ Batch size: ${migratorOptions.chunkBatchSize} documents`));
|
|
120
|
+
console.log(chalk.gray(`š Validation enabled: ${migratorOptions.validateRoundTrip}`));
|
|
121
|
+
// Setup progress reporting
|
|
122
|
+
const migrator = new StaticToCouchDBMigrator(migratorOptions, fileSystemAdapter);
|
|
123
|
+
migrator.setProgressCallback((progress) => {
|
|
124
|
+
const percentage = progress.total > 0 ? Math.round((progress.current / progress.total) * 100) : 0;
|
|
125
|
+
console.log(chalk.cyan(`š ${progress.phase}: ${progress.message} (${progress.current}/${progress.total} - ${percentage}%)`));
|
|
126
|
+
});
|
|
127
|
+
// Perform migration
|
|
128
|
+
console.log(chalk.cyan('š Starting migration...'));
|
|
129
|
+
const result = await migrator.migrateCourse(coursePath, targetDB);
|
|
130
|
+
if (!result.success) {
|
|
131
|
+
console.log(chalk.red('\nā Migration failed:'));
|
|
132
|
+
result.errors.forEach((error) => {
|
|
133
|
+
console.log(chalk.red(` ⢠${error}`));
|
|
134
|
+
});
|
|
135
|
+
if (result.warnings.length > 0) {
|
|
136
|
+
console.log(chalk.yellow('\nā ļø Warnings:'));
|
|
137
|
+
result.warnings.forEach((warning) => {
|
|
138
|
+
console.log(chalk.yellow(` ⢠${warning}`));
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
const courseName = options.as || validation.courseName || 'Unknown Course';
|
|
144
|
+
// Update CourseConfig with new name if provided
|
|
145
|
+
if (options.as) {
|
|
146
|
+
try {
|
|
147
|
+
console.log(chalk.cyan(`š Updating course name to "${courseName}"...`));
|
|
148
|
+
const courseConfig = await targetDB.get('CourseConfig');
|
|
149
|
+
courseConfig.name = courseName;
|
|
150
|
+
await targetDB.put(courseConfig);
|
|
151
|
+
console.log(chalk.green('ā
Course name updated.'));
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
console.log(chalk.yellow('ā ļø Warning: Failed to update course name in CourseConfig.'));
|
|
155
|
+
console.log(chalk.yellow(` ${error instanceof Error ? error.message : String(error)}`));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// Success! Register course in lookup and display results
|
|
159
|
+
console.log(chalk.green('\nā
Successfully unpacked course!'));
|
|
160
|
+
try {
|
|
161
|
+
console.log(chalk.cyan('š Registering course in course lookup...'));
|
|
162
|
+
await CourseLookup.addWithId(studioCourseId, courseName);
|
|
163
|
+
console.log(chalk.green('ā
Course registered in course lookup'));
|
|
164
|
+
}
|
|
165
|
+
catch (lookupError) {
|
|
166
|
+
console.log(chalk.yellow('ā ļø Warning: Failed to register course in lookup database'));
|
|
167
|
+
console.log(chalk.yellow(` ${lookupError instanceof Error ? lookupError.message : String(lookupError)}`));
|
|
168
|
+
console.log(chalk.yellow(' The unpacked course data is still available, but may not appear in the course browser.'));
|
|
169
|
+
}
|
|
170
|
+
console.log('');
|
|
171
|
+
console.log(chalk.white(`š Course: ${courseName}`));
|
|
172
|
+
console.log(chalk.white(`š Documents: ${result.documentsRestored}`));
|
|
173
|
+
console.log(chalk.white(`šļø Design Docs: ${result.designDocsRestored}`));
|
|
174
|
+
console.log(chalk.white(`š Attachments: ${result.attachmentsRestored}`));
|
|
175
|
+
console.log(chalk.white(`ā±ļø Migration Time: ${(result.migrationTime / 1000).toFixed(1)}s`));
|
|
176
|
+
console.log(chalk.white(`š” Database: ${targetDbName}`));
|
|
177
|
+
if (result.warnings.length > 0) {
|
|
178
|
+
console.log(chalk.yellow('\nā ļø Migration warnings:'));
|
|
179
|
+
result.warnings.forEach((warning) => {
|
|
180
|
+
console.log(chalk.yellow(` ⢠${warning}`));
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
// Display next steps
|
|
184
|
+
console.log('');
|
|
185
|
+
console.log(chalk.cyan('š Next steps:'));
|
|
186
|
+
console.log(chalk.gray(' ⢠Test the migrated course data in your application'));
|
|
187
|
+
console.log(chalk.gray(' ⢠Verify document counts and content manually if needed'));
|
|
188
|
+
console.log(chalk.gray(` ⢠Use database: ${targetDbName}`));
|
|
189
|
+
if (!options.validate) {
|
|
190
|
+
console.log(chalk.gray(' ⢠Consider running with --validate flag for comprehensive verification'));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
console.error(chalk.red('\nā Unpacking failed:'));
|
|
195
|
+
let errorMessage = 'Unknown error';
|
|
196
|
+
if (error instanceof Error) {
|
|
197
|
+
errorMessage = error.message;
|
|
198
|
+
// Show stack trace in development/debug mode
|
|
199
|
+
if (process.env.DEBUG || process.env.NODE_ENV === 'development') {
|
|
200
|
+
console.error(chalk.gray('\nStack trace:'));
|
|
201
|
+
console.error(chalk.gray(error.stack || 'No stack trace available'));
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
else if (typeof error === 'string') {
|
|
205
|
+
errorMessage = error;
|
|
206
|
+
}
|
|
207
|
+
else if (error && typeof error === 'object' && 'message' in error) {
|
|
208
|
+
errorMessage = String(error.message);
|
|
209
|
+
}
|
|
210
|
+
console.error(chalk.red(errorMessage));
|
|
211
|
+
console.error('');
|
|
212
|
+
console.error(chalk.yellow('š” Troubleshooting tips:'));
|
|
213
|
+
console.error(chalk.gray(' ⢠Verify the static course directory path is correct'));
|
|
214
|
+
console.error(chalk.gray(' ⢠Ensure CouchDB is running and accessible'));
|
|
215
|
+
console.error(chalk.gray(' ⢠Check that manifest.json and chunks/ directory exist'));
|
|
216
|
+
console.error(chalk.gray(' ⢠Verify database permissions if using authentication'));
|
|
217
|
+
console.error(chalk.gray(' ⢠Use --validate flag for detailed error information'));
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
220
|
+
finally {
|
|
221
|
+
// Restore original ENV values
|
|
222
|
+
ENV.COUCHDB_SERVER_PROTOCOL = originalEnv.COUCHDB_SERVER_PROTOCOL;
|
|
223
|
+
ENV.COUCHDB_SERVER_URL = originalEnv.COUCHDB_SERVER_URL;
|
|
224
|
+
ENV.COUCHDB_USERNAME = originalEnv.COUCHDB_USERNAME;
|
|
225
|
+
ENV.COUCHDB_PASSWORD = originalEnv.COUCHDB_PASSWORD;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=unpack.js.map
|