@lxpack/cli 0.1.1 → 0.2.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 +16 -3
- package/dist/cli.d.ts +5 -5
- package/dist/cli.js +41 -7
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -7,13 +7,14 @@
|
|
|
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.
|
|
10
|
+
Part of [LXPack](https://github.com/eddiethedean/lxpack) — an AI-native learning experience compiler and runtime (**v0.2.0**).
|
|
11
11
|
|
|
12
12
|
| Related | Package |
|
|
13
13
|
|---------|---------|
|
|
14
14
|
| Validation | [`@lxpack/validators`](../validators/README.md) |
|
|
15
15
|
| Browser runtime | [`@lxpack/runtime`](../runtime/README.md) |
|
|
16
16
|
| Export / ZIP | [`@lxpack/scorm`](../scorm/README.md) |
|
|
17
|
+
| Lesson widgets | [`@lxpack/components`](../components/README.md) |
|
|
17
18
|
|
|
18
19
|
## Install
|
|
19
20
|
|
|
@@ -32,6 +33,7 @@ cd my-course
|
|
|
32
33
|
lxpack preview # http://127.0.0.1:3847 by default
|
|
33
34
|
lxpack validate
|
|
34
35
|
lxpack build --target scorm12
|
|
36
|
+
lxpack build --target scorm2004
|
|
35
37
|
```
|
|
36
38
|
|
|
37
39
|
Output lands in `.lxpack/` unless overridden by `-o` or `lxpack.config.json`.
|
|
@@ -49,12 +51,16 @@ Output lands in `.lxpack/` unless overridden by `-o` or `lxpack.config.json`.
|
|
|
49
51
|
|
|
50
52
|
| Option | Description |
|
|
51
53
|
|--------|-------------|
|
|
52
|
-
| `-t, --target <target>` | `scorm12` (default) or `standalone` |
|
|
54
|
+
| `-t, --target <target>` | `scorm12` (default), `scorm2004`, or `standalone` |
|
|
53
55
|
| `-o, --output <path>` | Output ZIP file or directory |
|
|
54
56
|
| `--dir` | Write an unpacked directory instead of a ZIP |
|
|
55
57
|
|
|
56
58
|
`build` and `preview` use the same validation rules: errors fail the command (exit code 1). `build` reuses the validated manifest and bakes a sanitized [assessment bundle](../validators/README.md#assessment-packaging) into the exported HTML config.
|
|
57
59
|
|
|
60
|
+
**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
|
+
|
|
62
|
+
**Preview** serves the runtime client, optional components bundle at `/runtime/components.js`, and installs SCORM API simulators (1.2 and 2004) for local testing.
|
|
63
|
+
|
|
58
64
|
### Course discovery
|
|
59
65
|
|
|
60
66
|
Commands walk up from the current working directory until they find `course.yaml`. Run them from inside your course project (or a subdirectory).
|
|
@@ -73,10 +79,13 @@ my-course/
|
|
|
73
79
|
lessons/
|
|
74
80
|
interactions/
|
|
75
81
|
assessments/ # authoring only — omitted from export ZIPs
|
|
82
|
+
components/ # optional widget overrides
|
|
76
83
|
assets/
|
|
77
84
|
.lxpack/ # build output (generated)
|
|
78
85
|
```
|
|
79
86
|
|
|
87
|
+
`init` scaffolds commented examples for `variables`, `flow`, and `type: component` lessons. See [branching-demo](https://github.com/eddiethedean/lxpack/tree/main/examples/branching-demo) for a full v0.2 course.
|
|
88
|
+
|
|
80
89
|
### `lxpack.config.json`
|
|
81
90
|
|
|
82
91
|
```json
|
|
@@ -88,11 +97,13 @@ my-course/
|
|
|
88
97
|
}
|
|
89
98
|
```
|
|
90
99
|
|
|
100
|
+
Use `"defaultTarget": "scorm2004"` when your LMS expects SCORM 2004 4th Edition packages.
|
|
101
|
+
|
|
91
102
|
See the [root README](https://github.com/eddiethedean/lxpack#course-structure) for a full `course.yaml` example.
|
|
92
103
|
|
|
93
104
|
## Programmatic use
|
|
94
105
|
|
|
95
|
-
The CLI is built with [Commander](https://github.com/tj/commander.js). For library integration, import from the built package or depend on `@lxpack/validators`, `@lxpack/scorm`, and `@lxpack/
|
|
106
|
+
The CLI is built with [Commander](https://github.com/tj/commander.js). For library integration, import from the built package or depend on `@lxpack/validators`, `@lxpack/scorm`, `@lxpack/runtime`, and `@lxpack/components` directly.
|
|
96
107
|
|
|
97
108
|
## Development
|
|
98
109
|
|
|
@@ -107,6 +118,8 @@ pnpm --filter @lxpack/cli typecheck
|
|
|
107
118
|
## Links
|
|
108
119
|
|
|
109
120
|
- [LXPack repository](https://github.com/eddiethedean/lxpack)
|
|
121
|
+
- [Documentation index](https://github.com/eddiethedean/lxpack/blob/main/docs/README.md)
|
|
122
|
+
- [Roadmap & phases](https://github.com/eddiethedean/lxpack/blob/main/docs/ROADMAP.md)
|
|
110
123
|
- [Changelog](https://github.com/eddiethedean/lxpack/blob/main/CHANGELOG.md)
|
|
111
124
|
|
|
112
125
|
## License
|
package/dist/cli.d.ts
CHANGED
|
@@ -3,11 +3,11 @@ 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", "standalone"]>>;
|
|
6
|
+
defaultTarget: z.ZodOptional<z.ZodEnum<["scorm12", "scorm2004", "standalone"]>>;
|
|
7
7
|
}, "strip", z.ZodTypeAny, {
|
|
8
|
-
defaultTarget?: "scorm12" | "standalone" | undefined;
|
|
8
|
+
defaultTarget?: "scorm12" | "scorm2004" | "standalone" | undefined;
|
|
9
9
|
}, {
|
|
10
|
-
defaultTarget?: "scorm12" | "standalone" | undefined;
|
|
10
|
+
defaultTarget?: "scorm12" | "scorm2004" | "standalone" | undefined;
|
|
11
11
|
}>>;
|
|
12
12
|
output: z.ZodOptional<z.ZodObject<{
|
|
13
13
|
dir: z.ZodOptional<z.ZodString>;
|
|
@@ -18,14 +18,14 @@ declare const lxpackConfigSchema: z.ZodObject<{
|
|
|
18
18
|
}>>;
|
|
19
19
|
}, "strict", z.ZodTypeAny, {
|
|
20
20
|
exports?: {
|
|
21
|
-
defaultTarget?: "scorm12" | "standalone" | undefined;
|
|
21
|
+
defaultTarget?: "scorm12" | "scorm2004" | "standalone" | undefined;
|
|
22
22
|
} | undefined;
|
|
23
23
|
output?: {
|
|
24
24
|
dir?: string | undefined;
|
|
25
25
|
} | undefined;
|
|
26
26
|
}, {
|
|
27
27
|
exports?: {
|
|
28
|
-
defaultTarget?: "scorm12" | "standalone" | undefined;
|
|
28
|
+
defaultTarget?: "scorm12" | "scorm2004" | "standalone" | undefined;
|
|
29
29
|
} | undefined;
|
|
30
30
|
output?: {
|
|
31
31
|
dir?: string | undefined;
|
package/dist/cli.js
CHANGED
|
@@ -66,9 +66,17 @@ async function readRuntimeBundle(assetsDir = getRuntimeAssetsDir()) {
|
|
|
66
66
|
}
|
|
67
67
|
return { clientJs, css };
|
|
68
68
|
}
|
|
69
|
+
async function readComponentsBundle() {
|
|
70
|
+
try {
|
|
71
|
+
const bundlePath = require2.resolve("@lxpack/components/bundle");
|
|
72
|
+
return await readFile(bundlePath, "utf-8");
|
|
73
|
+
} catch {
|
|
74
|
+
return void 0;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
69
77
|
var lxpackConfigSchema = z.object({
|
|
70
78
|
exports: z.object({
|
|
71
|
-
defaultTarget: z.enum(["scorm12", "standalone"]).optional()
|
|
79
|
+
defaultTarget: z.enum(["scorm12", "scorm2004", "standalone"]).optional()
|
|
72
80
|
}).optional(),
|
|
73
81
|
output: z.object({
|
|
74
82
|
dir: z.string().optional()
|
|
@@ -157,6 +165,17 @@ lessons:
|
|
|
157
165
|
assessments:
|
|
158
166
|
- id: final_quiz
|
|
159
167
|
file: assessments/final.yaml
|
|
168
|
+
|
|
169
|
+
# Optional Phase 2 features (see examples/branching-demo):
|
|
170
|
+
# variables:
|
|
171
|
+
# path:
|
|
172
|
+
# default: intro
|
|
173
|
+
# type: string
|
|
174
|
+
# flow:
|
|
175
|
+
# - when:
|
|
176
|
+
# variable:
|
|
177
|
+
# eq: [path, advanced]
|
|
178
|
+
# goto: component_lesson
|
|
160
179
|
`;
|
|
161
180
|
var WELCOME_MD = `# Welcome
|
|
162
181
|
|
|
@@ -269,7 +288,8 @@ async function initCommand(projectName, options = {}) {
|
|
|
269
288
|
join2(targetDir, "interactions", "phishing-lab"),
|
|
270
289
|
join2(targetDir, "assets"),
|
|
271
290
|
join2(targetDir, "assessments"),
|
|
272
|
-
join2(targetDir, "theme")
|
|
291
|
+
join2(targetDir, "theme"),
|
|
292
|
+
join2(targetDir, "components")
|
|
273
293
|
];
|
|
274
294
|
for (const dir of dirs) {
|
|
275
295
|
await mkdir(dir, { recursive: true });
|
|
@@ -286,6 +306,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
286
306
|
await writeFile(join2(targetDir, "assessments", "final.yaml"), FINAL_ASSESSMENT);
|
|
287
307
|
await writeFile(join2(targetDir, "lxpack.config.json"), LXPACK_CONFIG);
|
|
288
308
|
await writeFile(join2(targetDir, "theme", ".gitkeep"), "");
|
|
309
|
+
await writeFile(join2(targetDir, "components", ".gitkeep"), "");
|
|
289
310
|
console.log(pc.green(`\u2713 Created LXPack course: ${targetDir}`));
|
|
290
311
|
console.log();
|
|
291
312
|
console.log("Next steps:");
|
|
@@ -311,7 +332,9 @@ function buildPreviewConfig(manifest, assessmentBundle) {
|
|
|
311
332
|
mode: "preview",
|
|
312
333
|
...assessmentBundle ? {
|
|
313
334
|
assessments: assessmentBundle.assessments,
|
|
314
|
-
answerKeys: assessmentBundle.answerKeys
|
|
335
|
+
answerKeys: assessmentBundle.answerKeys,
|
|
336
|
+
assessmentConfigs: assessmentBundle.configs,
|
|
337
|
+
assessmentFeedback: assessmentBundle.feedback
|
|
315
338
|
} : {}
|
|
316
339
|
});
|
|
317
340
|
}
|
|
@@ -330,6 +353,12 @@ async function createPreviewServer(courseDir, manifest, assessmentBundle) {
|
|
|
330
353
|
});
|
|
331
354
|
const stylesCss = await loadPreviewStyles(runtimeDir);
|
|
332
355
|
const config = buildPreviewConfig(manifest, assessmentBundle);
|
|
356
|
+
const componentsJs = await readComponentsBundle();
|
|
357
|
+
if (componentsJs) {
|
|
358
|
+
app.get("/runtime/components.js", async (_req, reply) => {
|
|
359
|
+
return reply.type("application/javascript").send(componentsJs);
|
|
360
|
+
});
|
|
361
|
+
}
|
|
333
362
|
app.get("/", async (_req, reply) => {
|
|
334
363
|
const html = `<!DOCTYPE html>
|
|
335
364
|
<html lang="en">
|
|
@@ -345,6 +374,7 @@ async function createPreviewServer(courseDir, manifest, assessmentBundle) {
|
|
|
345
374
|
<script>
|
|
346
375
|
window.__LXPACK_CONFIG__ = JSON.parse(document.getElementById('lxpack-config').textContent);
|
|
347
376
|
</script>
|
|
377
|
+
${componentsJs ? '<script type="module" src="/runtime/components.js"></script>' : ""}
|
|
348
378
|
<script type="module" src="/runtime/client.js"></script>
|
|
349
379
|
</body>
|
|
350
380
|
</html>`;
|
|
@@ -456,7 +486,7 @@ import {
|
|
|
456
486
|
buildRuntimeAssessmentBundle as buildRuntimeAssessmentBundle2
|
|
457
487
|
} from "@lxpack/validators";
|
|
458
488
|
import pc4 from "picocolors";
|
|
459
|
-
var VALID_TARGETS = ["scorm12", "standalone"];
|
|
489
|
+
var VALID_TARGETS = ["scorm12", "scorm2004", "standalone"];
|
|
460
490
|
async function buildCommand(options) {
|
|
461
491
|
const courseDir = findCourseDir();
|
|
462
492
|
const config = await loadLxpackConfig(courseDir);
|
|
@@ -482,7 +512,10 @@ async function buildCommand(options) {
|
|
|
482
512
|
courseDir,
|
|
483
513
|
manifest
|
|
484
514
|
);
|
|
485
|
-
const { clientJs, css } = await
|
|
515
|
+
const [{ clientJs, css }, componentsBundleJs] = await Promise.all([
|
|
516
|
+
readRuntimeBundle(),
|
|
517
|
+
readComponentsBundle()
|
|
518
|
+
]);
|
|
486
519
|
const slug = courseSlug(manifest);
|
|
487
520
|
const outputBase = config?.output?.dir ?? ".lxpack";
|
|
488
521
|
const outputRoot = resolveOutputDir(courseDir, outputBase);
|
|
@@ -493,6 +526,7 @@ async function buildCommand(options) {
|
|
|
493
526
|
target,
|
|
494
527
|
runtimeClientJs: clientJs,
|
|
495
528
|
runtimeCss: css,
|
|
529
|
+
componentsBundleJs,
|
|
496
530
|
assessmentBundle
|
|
497
531
|
};
|
|
498
532
|
if (options.dir) {
|
|
@@ -505,7 +539,7 @@ async function buildCommand(options) {
|
|
|
505
539
|
console.log(` Output: ${result.outputDir}`);
|
|
506
540
|
console.log(` Files: ${result.fileCount}`);
|
|
507
541
|
} else {
|
|
508
|
-
const defaultName = target === "standalone" ? `${slug}-standalone.zip` : `${slug}-scorm12.zip`;
|
|
542
|
+
const defaultName = target === "standalone" ? `${slug}-standalone.zip` : target === "scorm2004" ? `${slug}-scorm2004.zip` : `${slug}-scorm12.zip`;
|
|
509
543
|
const outputPath = options.output ?? join3(outputRoot, defaultName);
|
|
510
544
|
const result = await packageCourse({
|
|
511
545
|
...packageOptions,
|
|
@@ -537,7 +571,7 @@ function createCliProgram() {
|
|
|
537
571
|
});
|
|
538
572
|
program.command("build").description("Build LMS-compatible package").option(
|
|
539
573
|
"-t, --target <target>",
|
|
540
|
-
"Export target: scorm12, standalone",
|
|
574
|
+
"Export target: scorm12, scorm2004, standalone",
|
|
541
575
|
void 0
|
|
542
576
|
).option("-o, --output <path>", "Output file or directory path").option("--dir", "Output as directory instead of ZIP").action(
|
|
543
577
|
async (options) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lxpack/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "CLI for building, validating, and packaging LXPack courses",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -39,9 +39,10 @@
|
|
|
39
39
|
"picocolors": "^1.1.1",
|
|
40
40
|
"yaml": "^2.7.0",
|
|
41
41
|
"zod": "^3.24.2",
|
|
42
|
-
"@lxpack/runtime": "0.
|
|
43
|
-
"@lxpack/
|
|
44
|
-
"@lxpack/
|
|
42
|
+
"@lxpack/runtime": "0.2.0",
|
|
43
|
+
"@lxpack/components": "0.2.0",
|
|
44
|
+
"@lxpack/scorm": "0.2.0",
|
|
45
|
+
"@lxpack/validators": "0.2.0"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
48
|
"@types/node": "^22.13.10",
|