@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 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/runtime` directly.
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 readRuntimeBundle();
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.1.1",
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.1.1",
43
- "@lxpack/scorm": "0.1.1",
44
- "@lxpack/validators": "0.1.1"
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",