@lessonkit/cli 0.9.2 → 1.0.0
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 +20 -34
- package/dist/bin.js +83 -132
- package/dist/index.js +83 -132
- package/package.json +3 -2
- package/template/vite-react/README.md +13 -11
- package/template/vite-react/lessonkit.json +6 -1
- package/template/vite-react/package.json +6 -6
- package/template/vite-react/dist/assets/index-CP3MNJ8s.css +0 -1
- package/template/vite-react/dist/assets/index-CRuKbzTV.js +0 -8
- package/template/vite-react/dist/index.html +0 -14
package/README.md
CHANGED
|
@@ -1,55 +1,41 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @lessonkit/cli
|
|
2
2
|
|
|
3
|
-
[](https://github.com/eddiethedean/lessonkit/actions/workflows/ci.yml)
|
|
4
|
-
[](https://lessonkit.readthedocs.io/en/latest/)
|
|
5
3
|
[](https://www.npmjs.com/package/@lessonkit/cli)
|
|
4
|
+
[](https://lessonkit.readthedocs.io/en/latest/reference/cli.html)
|
|
6
5
|
[](https://github.com/eddiethedean/lessonkit/blob/main/LICENSE)
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
**Docs:** [CLI reference](https://lessonkit.readthedocs.io/en/latest/reference/cli.html) · [Packaging & CLI guide](https://lessonkit.readthedocs.io/en/latest/guides/react-developers/packaging-and-cli.html) · [Vibe coding: shipping to LMS](https://lessonkit.readthedocs.io/en/latest/guides/vibe-coding/shipping-to-lms.html)
|
|
7
|
+
Scaffold, develop, build, and package LessonKit courses. Node.js **18+**.
|
|
11
8
|
|
|
12
9
|
## Install
|
|
13
10
|
|
|
14
11
|
```bash
|
|
15
12
|
npm install -g @lessonkit/cli
|
|
16
|
-
# or
|
|
13
|
+
# or one-shot:
|
|
17
14
|
npx @lessonkit/cli init my-course
|
|
18
15
|
```
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
## Quick start
|
|
17
|
+
## Commands
|
|
23
18
|
|
|
24
19
|
```bash
|
|
25
|
-
lessonkit init my-course
|
|
26
|
-
|
|
27
|
-
lessonkit
|
|
28
|
-
lessonkit
|
|
29
|
-
lessonkit package --target scorm12
|
|
20
|
+
lessonkit init my-course # scaffold Vite + React project
|
|
21
|
+
lessonkit dev # Vite dev server
|
|
22
|
+
lessonkit build # production build → dist/
|
|
23
|
+
lessonkit package --target scorm12 # LMS artifact
|
|
30
24
|
```
|
|
31
25
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
|
35
|
-
|
|
36
|
-
| `
|
|
37
|
-
| `
|
|
38
|
-
| `lessonkit build` | Production Vite build |
|
|
39
|
-
| `lessonkit package --target <target>` | Build or package for web / LMS |
|
|
40
|
-
| `lessonkit publish` | Stub — see [`RELEASING.md`](https://github.com/eddiethedean/lessonkit/blob/main/RELEASING.md) |
|
|
41
|
-
|
|
42
|
-
### Package targets
|
|
26
|
+
| Target | Output |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| `react-vite` | Vite build only |
|
|
29
|
+
| `scorm12`, `scorm2004` | SCORM package |
|
|
30
|
+
| `standalone` | Self-contained web bundle |
|
|
31
|
+
| `xapi`, `cmi5` | xAPI / cmi5 packages |
|
|
43
32
|
|
|
44
|
-
|
|
45
|
-
- `scorm12`, `scorm2004`, `xapi`, `cmi5`, `standalone` — via `@lessonkit/lxpack`
|
|
33
|
+
Every project includes a root `lessonkit.json` manifest (`schemaVersion: 1`).
|
|
46
34
|
|
|
47
|
-
##
|
|
35
|
+
## Docs
|
|
48
36
|
|
|
49
|
-
|
|
37
|
+
[CLI reference](https://lessonkit.readthedocs.io/en/latest/reference/cli.html) · [Packaging guide](https://lessonkit.readthedocs.io/en/latest/guides/react-developers/packaging-and-cli.html) · [Template source](https://github.com/eddiethedean/lessonkit/tree/main/templates/vite-react)
|
|
50
38
|
|
|
51
|
-
##
|
|
39
|
+
## License
|
|
52
40
|
|
|
53
|
-
-
|
|
54
|
-
- [React quickstart](https://lessonkit.readthedocs.io/en/latest/guides/react-developers/quickstart.html)
|
|
55
|
-
- [`templates/vite-react`](https://github.com/eddiethedean/lessonkit/tree/main/templates/vite-react) — starter template
|
|
41
|
+
Apache-2.0
|
package/dist/bin.js
CHANGED
|
@@ -5,6 +5,7 @@ import { createRequire } from "module";
|
|
|
5
5
|
import { Command } from "commander";
|
|
6
6
|
|
|
7
7
|
// src/commands/init.ts
|
|
8
|
+
import { slugifyId } from "@lessonkit/core";
|
|
8
9
|
import { cp, mkdir, readdir, readFile, writeFile } from "fs/promises";
|
|
9
10
|
import { existsSync } from "fs";
|
|
10
11
|
import { basename, dirname, join, resolve } from "path";
|
|
@@ -101,9 +102,6 @@ function getTemplateDir() {
|
|
|
101
102
|
}
|
|
102
103
|
return candidates[0];
|
|
103
104
|
}
|
|
104
|
-
function slugifyName(name) {
|
|
105
|
-
return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64) || "my-course";
|
|
106
|
-
}
|
|
107
105
|
async function isDirEmpty(dir) {
|
|
108
106
|
if (!existsSync(dir)) return true;
|
|
109
107
|
const entries = await readdir(dir);
|
|
@@ -153,14 +151,14 @@ async function applyTemplateSubstitutions(projectDir, projectName, slug) {
|
|
|
153
151
|
}
|
|
154
152
|
async function runInit(opts, logger) {
|
|
155
153
|
const cwd = process.cwd();
|
|
156
|
-
const rawName = opts.name ?? (opts.here ?
|
|
154
|
+
const rawName = opts.name ?? (opts.here ? slugifyId(basename(process.cwd()) || "my-course") : void 0);
|
|
157
155
|
if (!rawName && !opts.here) {
|
|
158
156
|
throw new CliError("Project name is required. Usage: lessonkit init <name> or lessonkit init --here", {
|
|
159
157
|
code: "INVALID_PROJECT",
|
|
160
158
|
exitCode: EXIT_INVALID_PROJECT
|
|
161
159
|
});
|
|
162
160
|
}
|
|
163
|
-
const slug =
|
|
161
|
+
const slug = slugifyId(rawName ?? "my-course");
|
|
164
162
|
const projectName = rawName ?? slug;
|
|
165
163
|
const projectDir = opts.here ? cwd : resolve(cwd, slug);
|
|
166
164
|
if (!opts.here && existsSync(projectDir)) {
|
|
@@ -211,18 +209,13 @@ async function runInit(opts, logger) {
|
|
|
211
209
|
import { readFileSync, existsSync as existsSync2 } from "fs";
|
|
212
210
|
import { readFile as readFile2 } from "fs/promises";
|
|
213
211
|
import { dirname as dirname2, join as join2, parse, resolve as resolve2 } from "path";
|
|
214
|
-
import {
|
|
212
|
+
import { parseLessonkitManifest } from "@lessonkit/lxpack";
|
|
215
213
|
var LESSONKIT_JSON = "lessonkit.json";
|
|
216
214
|
var PACKAGE_JSON = "package.json";
|
|
217
|
-
var DEFAULT_PATHS = {
|
|
218
|
-
spaDistDir: "dist",
|
|
219
|
-
lxpackOutDir: ".lxpack/course",
|
|
220
|
-
outputBaseDir: ".lxpack/out"
|
|
221
|
-
};
|
|
222
215
|
function isProjectManifest(configPath) {
|
|
223
216
|
try {
|
|
224
217
|
const raw = JSON.parse(readFileSync(configPath, "utf8"));
|
|
225
|
-
return raw.schemaVersion === 1 && typeof raw.name === "string" && raw.course !== null && typeof raw.course === "object";
|
|
218
|
+
return raw.schemaVersion === 1 && typeof raw.name === "string" && raw.course !== null && typeof raw.course === "object" && !Array.isArray(raw.course);
|
|
226
219
|
} catch {
|
|
227
220
|
return false;
|
|
228
221
|
}
|
|
@@ -255,124 +248,66 @@ async function loadLessonkitJson(projectRoot) {
|
|
|
255
248
|
exitCode: EXIT_INVALID_PROJECT
|
|
256
249
|
});
|
|
257
250
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
exitCode: EXIT_INVALID_PROJECT
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
const config = raw;
|
|
265
|
-
const schemaVersion = config.schemaVersion;
|
|
266
|
-
if (schemaVersion !== 1) {
|
|
267
|
-
throw new CliError(`${configPath}: schemaVersion must be 1 (got ${String(schemaVersion)}).`, {
|
|
268
|
-
code: "INVALID_PROJECT",
|
|
269
|
-
exitCode: EXIT_INVALID_PROJECT
|
|
270
|
-
});
|
|
251
|
+
const parsed = parseLessonkitManifest(raw, configPath, projectRoot);
|
|
252
|
+
if (!parsed.ok) {
|
|
253
|
+
throwManifestCliError(configPath, parsed.issues);
|
|
271
254
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
255
|
+
return {
|
|
256
|
+
root: projectRoot,
|
|
257
|
+
schemaVersion: 1,
|
|
258
|
+
name: parsed.manifest.name,
|
|
259
|
+
course: parsed.manifest.course,
|
|
260
|
+
paths: parsed.manifest.paths
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
function throwManifestCliError(configPath, issues) {
|
|
264
|
+
const layoutIssue = issues.find((i) => i.path === "course.layout");
|
|
265
|
+
if (layoutIssue?.message.includes("per-lesson-spa")) {
|
|
266
|
+
throw new CliError(
|
|
267
|
+
`${configPath}: per-lesson-spa layout is not supported by lessonkit package yet. Use single-spa or package via @lessonkit/lxpack directly.`,
|
|
268
|
+
{ code: "INVALID_PROJECT", exitCode: EXIT_INVALID_PROJECT }
|
|
269
|
+
);
|
|
278
270
|
}
|
|
279
|
-
const
|
|
280
|
-
if (
|
|
281
|
-
throw new CliError(`${configPath}: "course" must be an
|
|
271
|
+
const lessonsIssue = issues.find((i) => i.path === "course.lessons");
|
|
272
|
+
if (lessonsIssue) {
|
|
273
|
+
throw new CliError(`${configPath}: "course.lessons" must be an array.`, {
|
|
282
274
|
code: "INVALID_PROJECT",
|
|
283
275
|
exitCode: EXIT_INVALID_PROJECT
|
|
284
276
|
});
|
|
285
277
|
}
|
|
286
|
-
const
|
|
287
|
-
if (
|
|
288
|
-
throw new CliError(`${configPath}: "
|
|
278
|
+
const spaDistTypeIssue = issues.find((i) => i.path === "paths.spaDistDir");
|
|
279
|
+
if (spaDistTypeIssue && spaDistTypeIssue.message.includes("non-empty string")) {
|
|
280
|
+
throw new CliError(`${configPath}: "paths.spaDistDir" must be a non-empty string.`, {
|
|
289
281
|
code: "INVALID_PROJECT",
|
|
290
282
|
exitCode: EXIT_INVALID_PROJECT
|
|
291
283
|
});
|
|
292
284
|
}
|
|
293
|
-
|
|
294
|
-
|
|
285
|
+
const courseSpaIssue = issues.find((i) => i.path === "course.spaDistDir");
|
|
286
|
+
if (courseSpaIssue) {
|
|
287
|
+
throw new CliError(`${configPath}: ${courseSpaIssue.message}`, {
|
|
295
288
|
code: "INVALID_PROJECT",
|
|
296
289
|
exitCode: EXIT_INVALID_PROJECT
|
|
297
290
|
});
|
|
298
291
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
throw new CliError(`${configPath}: invalid course descriptor.`, {
|
|
292
|
+
if (issues.some((i) => i.path.startsWith("paths."))) {
|
|
293
|
+
throw new CliError(`${configPath}: invalid paths.`, {
|
|
302
294
|
code: "INVALID_PROJECT",
|
|
303
295
|
exitCode: EXIT_INVALID_PROJECT,
|
|
304
|
-
issues:
|
|
305
|
-
path: i.path,
|
|
306
|
-
message: i.message
|
|
307
|
-
}))
|
|
296
|
+
issues: issues.map((i) => ({ path: i.path, message: i.message }))
|
|
308
297
|
});
|
|
309
298
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
{ code: "INVALID_PROJECT", exitCode: EXIT_INVALID_PROJECT }
|
|
314
|
-
);
|
|
315
|
-
}
|
|
316
|
-
const pathsRaw = config.paths;
|
|
317
|
-
const paths = { ...DEFAULT_PATHS };
|
|
318
|
-
if (pathsRaw !== void 0 && (typeof pathsRaw !== "object" || pathsRaw === null)) {
|
|
319
|
-
throw new CliError(`${configPath}: "paths" must be an object.`, {
|
|
299
|
+
const schemaIssue = issues.find((i) => i.path === "schemaVersion");
|
|
300
|
+
if (schemaIssue) {
|
|
301
|
+
throw new CliError(`${configPath}: schemaVersion must be 1 (got ${schemaIssue.message.replace(/^must be 1 \(got /, "").replace(/\)$/, "")}).`, {
|
|
320
302
|
code: "INVALID_PROJECT",
|
|
321
303
|
exitCode: EXIT_INVALID_PROJECT
|
|
322
304
|
});
|
|
323
305
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
code: "INVALID_PROJECT",
|
|
330
|
-
exitCode: EXIT_INVALID_PROJECT
|
|
331
|
-
});
|
|
332
|
-
}
|
|
333
|
-
paths.spaDistDir = p.spaDistDir;
|
|
334
|
-
}
|
|
335
|
-
if (p.lxpackOutDir !== void 0) {
|
|
336
|
-
if (typeof p.lxpackOutDir !== "string" || !p.lxpackOutDir.trim()) {
|
|
337
|
-
throw new CliError(`${configPath}: "paths.lxpackOutDir" must be a non-empty string.`, {
|
|
338
|
-
code: "INVALID_PROJECT",
|
|
339
|
-
exitCode: EXIT_INVALID_PROJECT
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
paths.lxpackOutDir = p.lxpackOutDir;
|
|
343
|
-
}
|
|
344
|
-
if (p.outputBaseDir !== void 0) {
|
|
345
|
-
if (typeof p.outputBaseDir !== "string" || !p.outputBaseDir.trim()) {
|
|
346
|
-
throw new CliError(`${configPath}: "paths.outputBaseDir" must be a non-empty string.`, {
|
|
347
|
-
code: "INVALID_PROJECT",
|
|
348
|
-
exitCode: EXIT_INVALID_PROJECT
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
paths.outputBaseDir = p.outputBaseDir;
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
const courseSpaDistDir = validation.descriptor.spaDistDir?.trim();
|
|
355
|
-
if (courseSpaDistDir && courseSpaDistDir !== paths.spaDistDir) {
|
|
356
|
-
throw new CliError(
|
|
357
|
-
`${configPath}: "course.spaDistDir" (${courseSpaDistDir}) differs from "paths.spaDistDir" (${paths.spaDistDir}). Use paths.spaDistDir for CLI build and package.`,
|
|
358
|
-
{ code: "INVALID_PROJECT", exitCode: EXIT_INVALID_PROJECT }
|
|
359
|
-
);
|
|
360
|
-
}
|
|
361
|
-
const pathIssues = validateProjectPaths(projectRoot, paths);
|
|
362
|
-
if (pathIssues.length) {
|
|
363
|
-
throw new CliError(`${configPath}: invalid paths.`, {
|
|
364
|
-
code: "INVALID_PROJECT",
|
|
365
|
-
exitCode: EXIT_INVALID_PROJECT,
|
|
366
|
-
issues: pathIssues
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
return {
|
|
370
|
-
root: projectRoot,
|
|
371
|
-
schemaVersion: 1,
|
|
372
|
-
name,
|
|
373
|
-
course: validation.descriptor,
|
|
374
|
-
paths
|
|
375
|
-
};
|
|
306
|
+
throw new CliError(`${configPath}: invalid lessonkit manifest.`, {
|
|
307
|
+
code: "INVALID_PROJECT",
|
|
308
|
+
exitCode: EXIT_INVALID_PROJECT,
|
|
309
|
+
issues: issues.map((i) => ({ path: i.path, message: i.message }))
|
|
310
|
+
});
|
|
376
311
|
}
|
|
377
312
|
async function loadProject(cwd = process.cwd()) {
|
|
378
313
|
const root = findProjectRoot(cwd);
|
|
@@ -390,7 +325,7 @@ async function readPackageJson(projectRoot) {
|
|
|
390
325
|
}
|
|
391
326
|
}
|
|
392
327
|
function assertViteProject(pkg, projectRoot) {
|
|
393
|
-
const vite = pkg.devDependencies?.vite ?? pkg.dependencies?.vite ?? (existsSync2(join2(projectRoot, "node_modules", ".bin", "vite")) || existsSync2(join2(projectRoot, "node_modules", ".bin", "vite.cmd")) ? "present" : void 0);
|
|
328
|
+
const vite = pkg.devDependencies?.vite ?? pkg.dependencies?.vite ?? (existsSync2(join2(projectRoot, "node_modules", "vite", "bin", "vite.js")) || existsSync2(join2(projectRoot, "node_modules", ".bin", "vite")) || existsSync2(join2(projectRoot, "node_modules", ".bin", "vite.cmd")) ? "present" : void 0);
|
|
394
329
|
if (!vite) {
|
|
395
330
|
throw new CliError(
|
|
396
331
|
`No Vite dependency found in ${join2(projectRoot, PACKAGE_JSON)}. LessonKit projects require Vite.`,
|
|
@@ -398,28 +333,25 @@ function assertViteProject(pkg, projectRoot) {
|
|
|
398
333
|
);
|
|
399
334
|
}
|
|
400
335
|
}
|
|
401
|
-
function
|
|
336
|
+
function resolveViteJs(projectRoot) {
|
|
402
337
|
let dir = resolve2(projectRoot);
|
|
403
338
|
const fsRoot = parse(dir).root;
|
|
404
339
|
while (true) {
|
|
405
|
-
const
|
|
406
|
-
|
|
407
|
-
if (existsSync2(bin)) return bin;
|
|
408
|
-
const binCmd = join2(binDir, "vite.cmd");
|
|
409
|
-
if (existsSync2(binCmd)) return binCmd;
|
|
340
|
+
const viteJs = join2(dir, "node_modules", "vite", "bin", "vite.js");
|
|
341
|
+
if (existsSync2(viteJs)) return viteJs;
|
|
410
342
|
if (dir === fsRoot) break;
|
|
411
343
|
dir = dirname2(dir);
|
|
412
344
|
}
|
|
413
345
|
throw new CliError(
|
|
414
|
-
`Vite
|
|
346
|
+
`Vite not found near ${projectRoot}. Run npm install in the project first.`,
|
|
415
347
|
{ code: "INVALID_PROJECT", exitCode: EXIT_INVALID_PROJECT }
|
|
416
348
|
);
|
|
417
349
|
}
|
|
418
|
-
function
|
|
350
|
+
function assertNode18ForLxpack() {
|
|
419
351
|
const major = Number(process.versions.node.split(".")[0]);
|
|
420
|
-
if (major <
|
|
352
|
+
if (major < 18) {
|
|
421
353
|
throw new CliError(
|
|
422
|
-
`LMS packaging requires Node.js
|
|
354
|
+
`LMS packaging requires Node.js 18+ (current: ${process.versions.node}). See docs/PACKAGING.md.`,
|
|
423
355
|
{ code: "NODE_VERSION", exitCode: EXIT_INVALID_PROJECT }
|
|
424
356
|
);
|
|
425
357
|
}
|
|
@@ -481,17 +413,19 @@ async function runDev(opts) {
|
|
|
481
413
|
const project = await loadProject(opts.cwd ?? process.cwd());
|
|
482
414
|
const pkg = await readPackageJson(project.root);
|
|
483
415
|
assertViteProject(pkg, project.root);
|
|
484
|
-
const
|
|
485
|
-
await runCommand(
|
|
416
|
+
const viteJs = resolveViteJs(project.root);
|
|
417
|
+
await runCommand(process.execPath, [viteJs, ...opts.viteArgs ?? []], { cwd: project.root });
|
|
486
418
|
return { ok: true, command: "dev", projectRoot: project.root };
|
|
487
419
|
}
|
|
488
420
|
async function runBuild(opts) {
|
|
489
421
|
const project = await loadProject(opts.cwd ?? process.cwd());
|
|
490
422
|
const pkg = await readPackageJson(project.root);
|
|
491
423
|
assertViteProject(pkg, project.root);
|
|
492
|
-
const
|
|
424
|
+
const viteJs = resolveViteJs(project.root);
|
|
493
425
|
const buildArgs = resolveViteBuildArgs(project);
|
|
494
|
-
await runCommand(
|
|
426
|
+
await runCommand(process.execPath, [viteJs, ...buildArgs, ...opts.viteArgs ?? []], {
|
|
427
|
+
cwd: project.root
|
|
428
|
+
});
|
|
495
429
|
return { ok: true, command: "build", projectRoot: project.root };
|
|
496
430
|
}
|
|
497
431
|
|
|
@@ -526,7 +460,7 @@ async function runPackage(opts) {
|
|
|
526
460
|
}
|
|
527
461
|
return { ok: true, target, projectRoot: project.root, distDir };
|
|
528
462
|
}
|
|
529
|
-
|
|
463
|
+
assertNode18ForLxpack();
|
|
530
464
|
if (!opts.noBuild || !existsSync3(distDir)) {
|
|
531
465
|
await runBuild({ cwd: project.root, json: opts.json });
|
|
532
466
|
}
|
|
@@ -600,7 +534,10 @@ async function handleCommand(fn, logger, json) {
|
|
|
600
534
|
function createProgram(baseLogger = console) {
|
|
601
535
|
const program = new Command();
|
|
602
536
|
program.name("lessonkit").description("LessonKit CLI").version(version);
|
|
603
|
-
program.command("init").description("Initialize a LessonKit project from the Vite + React template").argument("[name]", "Project directory name").option("--here", "Initialize in the current directory").option("--skip-install", "Skip npm install").option(
|
|
537
|
+
program.command("init").description("Initialize a LessonKit project from the Vite + React template").argument("[name]", "Project directory name").option("--here", "Initialize in the current directory").option("--skip-install", "Skip npm install").option(
|
|
538
|
+
"--force",
|
|
539
|
+
"With --here, allow init when the directory is empty or contains only dotfiles"
|
|
540
|
+
).option("--json", "Emit structured JSON result").action(async (name, opts) => {
|
|
604
541
|
const logger = createLogger({ json: opts.json });
|
|
605
542
|
await handleCommand(
|
|
606
543
|
() => runInit({ name, here: opts.here, skipInstall: opts.skipInstall, force: opts.force, json: opts.json }, logger),
|
|
@@ -634,13 +571,27 @@ function createProgram(baseLogger = console) {
|
|
|
634
571
|
program.command("package").description("Build or package for web / LMS delivery").requiredOption("--target <target>", `Export target (${PACKAGE_TARGETS.join(", ")})`).option("--cwd <dir>", "Project root directory").option("--no-build", "Skip implicit Vite build for LMS targets").option("--out <path>", "Override output artifact path").option("--json", "Emit structured JSON result").action(async (opts) => {
|
|
635
572
|
const logger = createLogger({ json: opts.json });
|
|
636
573
|
await handleCommand(
|
|
637
|
-
() =>
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
574
|
+
async () => {
|
|
575
|
+
const result = await runPackage({
|
|
576
|
+
target: opts.target,
|
|
577
|
+
cwd: opts.cwd,
|
|
578
|
+
noBuild: opts.build === false,
|
|
579
|
+
out: opts.out,
|
|
580
|
+
json: opts.json
|
|
581
|
+
});
|
|
582
|
+
if (!opts.json && result.ok) {
|
|
583
|
+
if (result.target === "react-vite" && "distDir" in result) {
|
|
584
|
+
logger.log(`Built react-vite \u2192 ${result.distDir}`);
|
|
585
|
+
} else if ("outputPath" in result || "outputDir" in result) {
|
|
586
|
+
const dest = result.outputPath ?? result.outputDir;
|
|
587
|
+
const count = "fileCount" in result ? result.fileCount : void 0;
|
|
588
|
+
logger.log(
|
|
589
|
+
`Packaged ${result.target}${dest ? ` \u2192 ${dest}` : ""}${count != null ? ` (${count} files)` : ""}`
|
|
590
|
+
);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
return result;
|
|
594
|
+
},
|
|
644
595
|
logger,
|
|
645
596
|
Boolean(opts.json)
|
|
646
597
|
);
|