@lxpack/cli 0.2.2 → 0.3.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 +18 -4
- package/dist/cli.d.ts +52 -5
- package/dist/cli.js +123 -23
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
Command-line tool for scaffolding, previewing, validating, and packaging LXPack courses.
|
|
9
9
|
|
|
10
|
-
Part of [LXPack](https://github.com/eddiethedean/lxpack) — an AI-native learning experience compiler and runtime (**v0.
|
|
10
|
+
Part of [LXPack](https://github.com/eddiethedean/lxpack) — an AI-native learning experience compiler and runtime (**v0.3.0**).
|
|
11
11
|
|
|
12
12
|
| Related | Package |
|
|
13
13
|
|---------|---------|
|
|
@@ -34,6 +34,8 @@ lxpack preview # http://127.0.0.1:3847 by default
|
|
|
34
34
|
lxpack validate
|
|
35
35
|
lxpack build --target scorm12
|
|
36
36
|
lxpack build --target scorm2004
|
|
37
|
+
lxpack build --target xapi
|
|
38
|
+
lxpack build --target cmi5
|
|
37
39
|
```
|
|
38
40
|
|
|
39
41
|
Output lands in `.lxpack/` unless overridden by `-o` or `lxpack.config.json`.
|
|
@@ -44,14 +46,14 @@ Output lands in `.lxpack/` unless overridden by `-o` or `lxpack.config.json`.
|
|
|
44
46
|
|---------|-------------|
|
|
45
47
|
| `init <name>` | Scaffold a new course (`-d, --dir <path>`, `-f, --force`) |
|
|
46
48
|
| `preview` | Start local preview server (`-p, --port`, `-H, --host`) |
|
|
47
|
-
| `validate` | Validate `course.yaml` and referenced files |
|
|
49
|
+
| `validate` | Validate `course.yaml` and referenced files (`-t, --target` for export checks) |
|
|
48
50
|
| `build` | Package for LMS or standalone export |
|
|
49
51
|
|
|
50
52
|
### `build` options
|
|
51
53
|
|
|
52
54
|
| Option | Description |
|
|
53
55
|
|--------|-------------|
|
|
54
|
-
| `-t, --target <target>` | `scorm12` (default), `scorm2004`, or `
|
|
56
|
+
| `-t, --target <target>` | `scorm12` (default), `scorm2004`, `standalone`, `xapi`, or `cmi5` |
|
|
55
57
|
| `-o, --output <path>` | Output ZIP file or directory |
|
|
56
58
|
| `--dir` | Write an unpacked directory instead of a ZIP |
|
|
57
59
|
|
|
@@ -59,7 +61,19 @@ Output lands in `.lxpack/` unless overridden by `-o` or `lxpack.config.json`.
|
|
|
59
61
|
|
|
60
62
|
**SCORM 2004** builds produce a multi-SCO ZIP: one launch page per activity under `sco/<activityId>/index.html`, plus shared `lxpack-runtime.js` and `lxpack-components.js`.
|
|
61
63
|
|
|
62
|
-
**Preview** serves the runtime client
|
|
64
|
+
**Preview** serves the runtime client and optional components bundle at `/runtime/components.js`. Configure SCORM simulators in `lxpack.config.json`:
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{ "preview": { "scormMode": "local" } }
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
| `scormMode` | Behavior |
|
|
71
|
+
|-------------|----------|
|
|
72
|
+
| `local` | `localStorage` progress (default) |
|
|
73
|
+
| `scorm12` | SCORM 1.2 simulator on `window.API` |
|
|
74
|
+
| `scorm2004` | SCORM 2004 simulator on `window.API_1484_11` |
|
|
75
|
+
|
|
76
|
+
Direct HTTP access to `assessments/`, `course.yaml`, `lxpack.config.json`, and `.lxpack/` under `/course/` returns 404; quiz content is embedded in the preview page config only.
|
|
63
77
|
|
|
64
78
|
### Course discovery
|
|
65
79
|
|
package/dist/cli.d.ts
CHANGED
|
@@ -3,11 +3,40 @@ import { z } from 'zod';
|
|
|
3
3
|
|
|
4
4
|
declare const lxpackConfigSchema: z.ZodObject<{
|
|
5
5
|
exports: z.ZodOptional<z.ZodObject<{
|
|
6
|
-
defaultTarget: z.ZodOptional<z.ZodEnum<["scorm12", "scorm2004", "standalone"]>>;
|
|
6
|
+
defaultTarget: z.ZodOptional<z.ZodEnum<["scorm12", "scorm2004", "standalone", "xapi", "cmi5"]>>;
|
|
7
7
|
}, "strip", z.ZodTypeAny, {
|
|
8
|
-
defaultTarget?: "scorm12" | "scorm2004" | "standalone" | undefined;
|
|
8
|
+
defaultTarget?: "scorm12" | "scorm2004" | "standalone" | "xapi" | "cmi5" | undefined;
|
|
9
9
|
}, {
|
|
10
|
-
defaultTarget?: "scorm12" | "scorm2004" | "standalone" | undefined;
|
|
10
|
+
defaultTarget?: "scorm12" | "scorm2004" | "standalone" | "xapi" | "cmi5" | undefined;
|
|
11
|
+
}>>;
|
|
12
|
+
preview: z.ZodOptional<z.ZodObject<{
|
|
13
|
+
scormMode: z.ZodOptional<z.ZodEnum<["local", "scorm12", "scorm2004"]>>;
|
|
14
|
+
}, "strict", z.ZodTypeAny, {
|
|
15
|
+
scormMode?: "scorm12" | "scorm2004" | "local" | undefined;
|
|
16
|
+
}, {
|
|
17
|
+
scormMode?: "scorm12" | "scorm2004" | "local" | undefined;
|
|
18
|
+
}>>;
|
|
19
|
+
xapi: z.ZodOptional<z.ZodObject<{
|
|
20
|
+
preview: z.ZodOptional<z.ZodObject<{
|
|
21
|
+
logStatements: z.ZodOptional<z.ZodBoolean>;
|
|
22
|
+
mockLrs: z.ZodOptional<z.ZodBoolean>;
|
|
23
|
+
}, "strict", z.ZodTypeAny, {
|
|
24
|
+
logStatements?: boolean | undefined;
|
|
25
|
+
mockLrs?: boolean | undefined;
|
|
26
|
+
}, {
|
|
27
|
+
logStatements?: boolean | undefined;
|
|
28
|
+
mockLrs?: boolean | undefined;
|
|
29
|
+
}>>;
|
|
30
|
+
}, "strict", z.ZodTypeAny, {
|
|
31
|
+
preview?: {
|
|
32
|
+
logStatements?: boolean | undefined;
|
|
33
|
+
mockLrs?: boolean | undefined;
|
|
34
|
+
} | undefined;
|
|
35
|
+
}, {
|
|
36
|
+
preview?: {
|
|
37
|
+
logStatements?: boolean | undefined;
|
|
38
|
+
mockLrs?: boolean | undefined;
|
|
39
|
+
} | undefined;
|
|
11
40
|
}>>;
|
|
12
41
|
output: z.ZodOptional<z.ZodObject<{
|
|
13
42
|
dir: z.ZodOptional<z.ZodString>;
|
|
@@ -17,15 +46,33 @@ declare const lxpackConfigSchema: z.ZodObject<{
|
|
|
17
46
|
dir?: string | undefined;
|
|
18
47
|
}>>;
|
|
19
48
|
}, "strict", z.ZodTypeAny, {
|
|
49
|
+
preview?: {
|
|
50
|
+
scormMode?: "scorm12" | "scorm2004" | "local" | undefined;
|
|
51
|
+
} | undefined;
|
|
52
|
+
xapi?: {
|
|
53
|
+
preview?: {
|
|
54
|
+
logStatements?: boolean | undefined;
|
|
55
|
+
mockLrs?: boolean | undefined;
|
|
56
|
+
} | undefined;
|
|
57
|
+
} | undefined;
|
|
20
58
|
exports?: {
|
|
21
|
-
defaultTarget?: "scorm12" | "scorm2004" | "standalone" | undefined;
|
|
59
|
+
defaultTarget?: "scorm12" | "scorm2004" | "standalone" | "xapi" | "cmi5" | undefined;
|
|
22
60
|
} | undefined;
|
|
23
61
|
output?: {
|
|
24
62
|
dir?: string | undefined;
|
|
25
63
|
} | undefined;
|
|
26
64
|
}, {
|
|
65
|
+
preview?: {
|
|
66
|
+
scormMode?: "scorm12" | "scorm2004" | "local" | undefined;
|
|
67
|
+
} | undefined;
|
|
68
|
+
xapi?: {
|
|
69
|
+
preview?: {
|
|
70
|
+
logStatements?: boolean | undefined;
|
|
71
|
+
mockLrs?: boolean | undefined;
|
|
72
|
+
} | undefined;
|
|
73
|
+
} | undefined;
|
|
27
74
|
exports?: {
|
|
28
|
-
defaultTarget?: "scorm12" | "scorm2004" | "standalone" | undefined;
|
|
75
|
+
defaultTarget?: "scorm12" | "scorm2004" | "standalone" | "xapi" | "cmi5" | undefined;
|
|
29
76
|
} | undefined;
|
|
30
77
|
output?: {
|
|
31
78
|
dir?: string | undefined;
|
package/dist/cli.js
CHANGED
|
@@ -85,8 +85,17 @@ import { z } from "zod";
|
|
|
85
85
|
import { formatErrorMessage, isPathContained } from "@lxpack/validators";
|
|
86
86
|
var lxpackConfigSchema = z.object({
|
|
87
87
|
exports: z.object({
|
|
88
|
-
defaultTarget: z.enum(["scorm12", "scorm2004", "standalone"]).optional()
|
|
88
|
+
defaultTarget: z.enum(["scorm12", "scorm2004", "standalone", "xapi", "cmi5"]).optional()
|
|
89
89
|
}).optional(),
|
|
90
|
+
preview: z.object({
|
|
91
|
+
scormMode: z.enum(["local", "scorm12", "scorm2004"]).optional()
|
|
92
|
+
}).strict().optional(),
|
|
93
|
+
xapi: z.object({
|
|
94
|
+
preview: z.object({
|
|
95
|
+
logStatements: z.boolean().optional(),
|
|
96
|
+
mockLrs: z.boolean().optional()
|
|
97
|
+
}).strict().optional()
|
|
98
|
+
}).strict().optional(),
|
|
90
99
|
output: z.object({
|
|
91
100
|
dir: z.string().optional()
|
|
92
101
|
}).optional()
|
|
@@ -178,7 +187,7 @@ assessments:
|
|
|
178
187
|
- id: final_quiz
|
|
179
188
|
file: assessments/final.yaml
|
|
180
189
|
|
|
181
|
-
# Optional
|
|
190
|
+
# Optional branching (see examples/branching-demo):
|
|
182
191
|
# variables:
|
|
183
192
|
# path:
|
|
184
193
|
# default: intro
|
|
@@ -188,6 +197,12 @@ assessments:
|
|
|
188
197
|
# variable:
|
|
189
198
|
# eq: [path, advanced]
|
|
190
199
|
# goto: component_lesson
|
|
200
|
+
|
|
201
|
+
# Optional xAPI/cmi5 export (see examples/xapi-awareness):
|
|
202
|
+
# tracking:
|
|
203
|
+
# xapi:
|
|
204
|
+
# activityIri: "https://example.test/courses/my-course"
|
|
205
|
+
# displayName: My Course
|
|
191
206
|
`;
|
|
192
207
|
var WELCOME_MD = `# Welcome
|
|
193
208
|
|
|
@@ -274,6 +289,9 @@ var LXPACK_CONFIG = `{
|
|
|
274
289
|
"exports": {
|
|
275
290
|
"defaultTarget": "scorm12"
|
|
276
291
|
},
|
|
292
|
+
"preview": {
|
|
293
|
+
"scormMode": "local"
|
|
294
|
+
},
|
|
277
295
|
"output": {
|
|
278
296
|
"dir": ".lxpack"
|
|
279
297
|
}
|
|
@@ -361,14 +379,44 @@ function printValidationIssues(validation) {
|
|
|
361
379
|
|
|
362
380
|
// src/commands/preview.ts
|
|
363
381
|
import { buildLearnerPageHtml, safeJsonForHtml } from "@lxpack/scorm";
|
|
382
|
+
import { getCourseActivityIri } from "@lxpack/validators";
|
|
383
|
+
|
|
384
|
+
// src/lib/preview-paths.ts
|
|
385
|
+
function isPreviewBlockedCoursePath(urlPath) {
|
|
386
|
+
const path = urlPath.split("?")[0] ?? "";
|
|
387
|
+
if (!path.startsWith("/course/")) {
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
const rel = path.slice("/course/".length);
|
|
391
|
+
if (rel.startsWith("assessments/")) {
|
|
392
|
+
return true;
|
|
393
|
+
}
|
|
394
|
+
if (rel === "course.yaml" || rel === "lxpack.config.json") {
|
|
395
|
+
return true;
|
|
396
|
+
}
|
|
397
|
+
if (rel.startsWith(".lxpack/") || rel === ".lxpack") {
|
|
398
|
+
return true;
|
|
399
|
+
}
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// src/commands/preview.ts
|
|
364
404
|
async function loadPreviewStyles(assetsDir = getRuntimeAssetsDir()) {
|
|
365
405
|
return loadRuntimeStyles(assetsDir);
|
|
366
406
|
}
|
|
367
|
-
function buildPreviewConfig(manifest, assessmentBundle) {
|
|
407
|
+
function buildPreviewConfig(manifest, assessmentBundle, options) {
|
|
368
408
|
return safeJsonForHtml({
|
|
369
409
|
manifest,
|
|
370
410
|
baseUrl: "/course",
|
|
371
411
|
mode: "preview",
|
|
412
|
+
...options?.previewScormMode && options.previewScormMode !== "local" ? { previewScormMode: options.previewScormMode } : {},
|
|
413
|
+
...options?.activityIri ? { activityIri: options.activityIri } : {},
|
|
414
|
+
...options?.xapiPreview ? {
|
|
415
|
+
xapi: {
|
|
416
|
+
previewLog: options.xapiPreview.logStatements ?? true,
|
|
417
|
+
mockLrs: options.xapiPreview.mockLrs ?? true
|
|
418
|
+
}
|
|
419
|
+
} : {},
|
|
372
420
|
...assessmentBundle ? {
|
|
373
421
|
assessments: assessmentBundle.assessments,
|
|
374
422
|
answerKeys: assessmentBundle.answerKeys,
|
|
@@ -382,7 +430,7 @@ async function createPreviewServer(courseDir, manifest, assessmentBundle) {
|
|
|
382
430
|
const app = Fastify({ logger: false });
|
|
383
431
|
app.addHook("onRequest", async (request, reply) => {
|
|
384
432
|
const path = request.url.split("?")[0] ?? "";
|
|
385
|
-
if (path
|
|
433
|
+
if (isPreviewBlockedCoursePath(path)) {
|
|
386
434
|
return reply.code(404).send("Not found");
|
|
387
435
|
}
|
|
388
436
|
});
|
|
@@ -397,7 +445,14 @@ async function createPreviewServer(courseDir, manifest, assessmentBundle) {
|
|
|
397
445
|
decorateReply: false
|
|
398
446
|
});
|
|
399
447
|
const stylesCss = await loadPreviewStyles(runtimeDir);
|
|
400
|
-
const
|
|
448
|
+
const lxpackConfig = await loadLxpackConfig(courseDir);
|
|
449
|
+
const activityIri = getCourseActivityIri(manifest);
|
|
450
|
+
const previewScormMode = lxpackConfig?.preview?.scormMode ?? "local";
|
|
451
|
+
const config = buildPreviewConfig(manifest, assessmentBundle, {
|
|
452
|
+
activityIri,
|
|
453
|
+
previewScormMode,
|
|
454
|
+
xapiPreview: lxpackConfig?.xapi?.preview
|
|
455
|
+
});
|
|
401
456
|
const componentsJs = await readComponentsBundle();
|
|
402
457
|
if (componentsJs) {
|
|
403
458
|
app.get("/runtime/components.js", async (_req, reply) => {
|
|
@@ -484,11 +539,42 @@ function logPreviewStarted(host, port) {
|
|
|
484
539
|
}
|
|
485
540
|
|
|
486
541
|
// src/commands/validate.ts
|
|
487
|
-
import {
|
|
542
|
+
import {
|
|
543
|
+
validateCourse as validateCourse3,
|
|
544
|
+
validateXapiTracking
|
|
545
|
+
} from "@lxpack/validators";
|
|
488
546
|
import pc3 from "picocolors";
|
|
489
|
-
|
|
547
|
+
|
|
548
|
+
// src/lib/targets.ts
|
|
549
|
+
var VALID_EXPORT_TARGETS = [
|
|
550
|
+
"scorm12",
|
|
551
|
+
"scorm2004",
|
|
552
|
+
"standalone",
|
|
553
|
+
"xapi",
|
|
554
|
+
"cmi5"
|
|
555
|
+
];
|
|
556
|
+
function isValidExportTarget(target) {
|
|
557
|
+
return VALID_EXPORT_TARGETS.includes(target);
|
|
558
|
+
}
|
|
559
|
+
function formatInvalidTargetMessage(target) {
|
|
560
|
+
return `Invalid target: ${target}. Valid targets: ${VALID_EXPORT_TARGETS.join(", ")}`;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// src/commands/validate.ts
|
|
564
|
+
var XAPI_TARGETS = ["xapi", "cmi5"];
|
|
565
|
+
async function validateCommand(options) {
|
|
566
|
+
if (options?.target !== void 0 && !isValidExportTarget(options.target)) {
|
|
567
|
+
console.error(pc3.red(formatInvalidTargetMessage(options.target)));
|
|
568
|
+
process.exit(1);
|
|
569
|
+
}
|
|
490
570
|
const courseDir = findCourseDir();
|
|
491
571
|
const result = await validateCourse3(courseDir);
|
|
572
|
+
const issues = [...result.issues];
|
|
573
|
+
const target = options?.target;
|
|
574
|
+
const needsXapiCheck = target && XAPI_TARGETS.includes(target) || Boolean(result.manifest?.tracking?.xapi);
|
|
575
|
+
if (needsXapiCheck && result.manifest) {
|
|
576
|
+
issues.push(...validateXapiTracking(result.manifest));
|
|
577
|
+
}
|
|
492
578
|
if (result.manifest) {
|
|
493
579
|
console.log(
|
|
494
580
|
pc3.dim(`Course: ${result.manifest.title} v${result.manifest.version}`)
|
|
@@ -496,11 +582,13 @@ async function validateCommand() {
|
|
|
496
582
|
console.log(pc3.dim(`Lessons: ${result.manifest.lessons.length}`));
|
|
497
583
|
console.log();
|
|
498
584
|
}
|
|
499
|
-
|
|
585
|
+
const hasErrors = issues.some((i) => i.severity === "error");
|
|
586
|
+
const valid = result.valid && !hasErrors;
|
|
587
|
+
for (const issue of issues) {
|
|
500
588
|
const icon = issue.severity === "error" ? pc3.red("\u2717") : pc3.yellow("!");
|
|
501
589
|
console.log(`${icon} ${issue.path}: ${issue.message}`);
|
|
502
590
|
}
|
|
503
|
-
if (
|
|
591
|
+
if (valid) {
|
|
504
592
|
console.log(pc3.green("\u2713 Course validation passed"));
|
|
505
593
|
process.exit(0);
|
|
506
594
|
} else {
|
|
@@ -524,12 +612,16 @@ import {
|
|
|
524
612
|
var zipPackagers = {
|
|
525
613
|
scorm12: { package: packageCourse },
|
|
526
614
|
scorm2004: { package: packageCourse },
|
|
527
|
-
standalone: { package: packageCourse }
|
|
615
|
+
standalone: { package: packageCourse },
|
|
616
|
+
xapi: { package: packageCourse },
|
|
617
|
+
cmi5: { package: packageCourse }
|
|
528
618
|
};
|
|
529
619
|
var dirPackagers = {
|
|
530
620
|
scorm12: { package: packageStandaloneDir },
|
|
531
621
|
scorm2004: { package: packageScorm2004Dir },
|
|
532
|
-
standalone: { package: packageStandaloneDir }
|
|
622
|
+
standalone: { package: packageStandaloneDir },
|
|
623
|
+
xapi: { package: packageStandaloneDir },
|
|
624
|
+
cmi5: { package: packageStandaloneDir }
|
|
533
625
|
};
|
|
534
626
|
function getZipPackager(target) {
|
|
535
627
|
return zipPackagers[target];
|
|
@@ -539,18 +631,13 @@ function getDirPackager(target) {
|
|
|
539
631
|
}
|
|
540
632
|
|
|
541
633
|
// src/commands/build.ts
|
|
542
|
-
import { validateCourse as validateCourse4 } from "@lxpack/validators";
|
|
543
|
-
var VALID_TARGETS = ["scorm12", "scorm2004", "standalone"];
|
|
634
|
+
import { validateCourse as validateCourse4, validateXapiTracking as validateXapiTracking2 } from "@lxpack/validators";
|
|
544
635
|
async function buildCommand(options) {
|
|
545
636
|
const courseDir = findCourseDir();
|
|
546
637
|
const config = await loadLxpackConfig(courseDir);
|
|
547
638
|
const target = options.target ?? config?.exports?.defaultTarget ?? "scorm12";
|
|
548
|
-
if (!
|
|
549
|
-
console.error(
|
|
550
|
-
pc4.red(
|
|
551
|
-
`Invalid target: ${target}. Valid targets: ${VALID_TARGETS.join(", ")}`
|
|
552
|
-
)
|
|
553
|
-
);
|
|
639
|
+
if (!isValidExportTarget(target)) {
|
|
640
|
+
console.error(pc4.red(formatInvalidTargetMessage(target)));
|
|
554
641
|
process.exit(1);
|
|
555
642
|
}
|
|
556
643
|
const ctx = await loadValidatedCourseContext(courseDir);
|
|
@@ -561,6 +648,16 @@ async function buildCommand(options) {
|
|
|
561
648
|
process.exit(1);
|
|
562
649
|
}
|
|
563
650
|
const { manifest, assessmentBundle } = ctx;
|
|
651
|
+
if (target === "xapi" || target === "cmi5") {
|
|
652
|
+
const xapiIssues = validateXapiTracking2(manifest);
|
|
653
|
+
if (xapiIssues.length > 0) {
|
|
654
|
+
console.error(pc4.red("Cannot build: course validation failed"));
|
|
655
|
+
for (const issue of xapiIssues) {
|
|
656
|
+
console.error(` ${issue.path}: ${issue.message}`);
|
|
657
|
+
}
|
|
658
|
+
process.exit(1);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
564
661
|
const [{ clientJs, css }, componentsBundleJs] = await Promise.all([
|
|
565
662
|
readRuntimeBundle(),
|
|
566
663
|
readComponentsBundle()
|
|
@@ -588,7 +685,7 @@ async function buildCommand(options) {
|
|
|
588
685
|
console.log(` Output: ${result.outputDir}`);
|
|
589
686
|
console.log(` Files: ${result.fileCount}`);
|
|
590
687
|
} else {
|
|
591
|
-
const defaultName = target === "standalone" ? `${slug}-standalone.zip` : target === "scorm2004" ? `${slug}-scorm2004.zip` : `${slug}-scorm12.zip`;
|
|
688
|
+
const defaultName = target === "standalone" ? `${slug}-standalone.zip` : target === "scorm2004" ? `${slug}-scorm2004.zip` : target === "xapi" ? `${slug}-xapi.zip` : target === "cmi5" ? `${slug}-cmi5.zip` : `${slug}-scorm12.zip`;
|
|
592
689
|
const outputPath = options.output ?? join5(outputRoot, defaultName);
|
|
593
690
|
const result = await getZipPackager(target).package({
|
|
594
691
|
...packageOptions,
|
|
@@ -615,12 +712,15 @@ function createCliProgram() {
|
|
|
615
712
|
host: options.host
|
|
616
713
|
});
|
|
617
714
|
});
|
|
618
|
-
program.command("validate").description("Validate course structure and assets").
|
|
619
|
-
|
|
715
|
+
program.command("validate").description("Validate course structure and assets").option(
|
|
716
|
+
"-t, --target <target>",
|
|
717
|
+
"Also validate export requirements for scorm12, scorm2004, standalone, xapi, or cmi5"
|
|
718
|
+
).action(async (options) => {
|
|
719
|
+
await validateCommand(options);
|
|
620
720
|
});
|
|
621
721
|
program.command("build").description("Build LMS-compatible package").option(
|
|
622
722
|
"-t, --target <target>",
|
|
623
|
-
"Export target: scorm12, scorm2004, standalone",
|
|
723
|
+
"Export target: scorm12, scorm2004, standalone, xapi, cmi5",
|
|
624
724
|
void 0
|
|
625
725
|
).option("-o, --output <path>", "Output file or directory path").option("--dir", "Output as directory instead of ZIP").action(
|
|
626
726
|
async (options) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lxpack/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "CLI for building, validating, and packaging LXPack courses",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -39,10 +39,10 @@
|
|
|
39
39
|
"picocolors": "^1.1.1",
|
|
40
40
|
"yaml": "^2.7.0",
|
|
41
41
|
"zod": "^3.24.2",
|
|
42
|
-
"@lxpack/components": "0.
|
|
43
|
-
"@lxpack/runtime": "0.
|
|
44
|
-
"@lxpack/
|
|
45
|
-
"@lxpack/
|
|
42
|
+
"@lxpack/components": "0.3.0",
|
|
43
|
+
"@lxpack/runtime": "0.3.0",
|
|
44
|
+
"@lxpack/scorm": "0.3.0",
|
|
45
|
+
"@lxpack/validators": "0.3.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/node": "^22.13.10",
|