@lessonkit/cli 0.9.3 → 1.0.1
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 +110 -139
- package/dist/index.js +110 -139
- package/package.json +3 -3
- 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-Dg5lKLi0.js +0 -8
- package/template/vite-react/dist/index.html +0 -14
package/dist/index.js
CHANGED
|
@@ -156,6 +156,12 @@ async function runInit(opts, logger) {
|
|
|
156
156
|
exitCode: EXIT_INVALID_PROJECT
|
|
157
157
|
});
|
|
158
158
|
}
|
|
159
|
+
if (opts.force && !opts.here) {
|
|
160
|
+
throw new CliError("--force requires --here (initialize in the current directory).", {
|
|
161
|
+
code: "INVALID_PROJECT",
|
|
162
|
+
exitCode: EXIT_INVALID_PROJECT
|
|
163
|
+
});
|
|
164
|
+
}
|
|
159
165
|
const slug = slugifyId(rawName ?? "my-course");
|
|
160
166
|
const projectName = rawName ?? slug;
|
|
161
167
|
const projectDir = opts.here ? cwd : resolve(cwd, slug);
|
|
@@ -207,18 +213,13 @@ async function runInit(opts, logger) {
|
|
|
207
213
|
import { readFileSync, existsSync as existsSync2 } from "fs";
|
|
208
214
|
import { readFile as readFile2 } from "fs/promises";
|
|
209
215
|
import { dirname as dirname2, join as join2, parse, resolve as resolve2 } from "path";
|
|
210
|
-
import {
|
|
216
|
+
import { parseLessonkitManifest } from "@lessonkit/lxpack";
|
|
211
217
|
var LESSONKIT_JSON = "lessonkit.json";
|
|
212
218
|
var PACKAGE_JSON = "package.json";
|
|
213
|
-
var DEFAULT_PATHS = {
|
|
214
|
-
spaDistDir: "dist",
|
|
215
|
-
lxpackOutDir: ".lxpack/course",
|
|
216
|
-
outputBaseDir: ".lxpack/out"
|
|
217
|
-
};
|
|
218
219
|
function isProjectManifest(configPath) {
|
|
219
220
|
try {
|
|
220
221
|
const raw = JSON.parse(readFileSync(configPath, "utf8"));
|
|
221
|
-
return raw.schemaVersion === 1 && typeof raw.name === "string" && raw.course !== null && typeof raw.course === "object";
|
|
222
|
+
return raw.schemaVersion === 1 && typeof raw.name === "string" && raw.course !== null && typeof raw.course === "object" && !Array.isArray(raw.course);
|
|
222
223
|
} catch {
|
|
223
224
|
return false;
|
|
224
225
|
}
|
|
@@ -251,124 +252,63 @@ async function loadLessonkitJson(projectRoot) {
|
|
|
251
252
|
exitCode: EXIT_INVALID_PROJECT
|
|
252
253
|
});
|
|
253
254
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
exitCode: EXIT_INVALID_PROJECT
|
|
258
|
-
});
|
|
255
|
+
const parsed = parseLessonkitManifest(raw, configPath, projectRoot);
|
|
256
|
+
if (!parsed.ok) {
|
|
257
|
+
throwManifestCliError(configPath, parsed.issues);
|
|
259
258
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
exitCode: EXIT_INVALID_PROJECT
|
|
273
|
-
});
|
|
259
|
+
return {
|
|
260
|
+
...parsed.manifest,
|
|
261
|
+
root: projectRoot
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function throwManifestCliError(configPath, issues) {
|
|
265
|
+
const layoutIssue = issues.find((i) => i.path === "course.layout");
|
|
266
|
+
if (layoutIssue?.message.includes("per-lesson-spa")) {
|
|
267
|
+
throw new CliError(
|
|
268
|
+
`${configPath}: per-lesson-spa layout is not supported by lessonkit package yet. Use single-spa or package via @lessonkit/lxpack directly.`,
|
|
269
|
+
{ code: "INVALID_PROJECT", exitCode: EXIT_INVALID_PROJECT }
|
|
270
|
+
);
|
|
274
271
|
}
|
|
275
|
-
const
|
|
276
|
-
if (
|
|
277
|
-
throw new CliError(`${configPath}: "course" must be an
|
|
272
|
+
const lessonsIssue = issues.find((i) => i.path === "course.lessons");
|
|
273
|
+
if (lessonsIssue) {
|
|
274
|
+
throw new CliError(`${configPath}: "course.lessons" must be an array.`, {
|
|
278
275
|
code: "INVALID_PROJECT",
|
|
279
276
|
exitCode: EXIT_INVALID_PROJECT
|
|
280
277
|
});
|
|
281
278
|
}
|
|
282
|
-
const
|
|
283
|
-
if (
|
|
284
|
-
throw new CliError(`${configPath}: "
|
|
279
|
+
const spaDistTypeIssue = issues.find((i) => i.path === "paths.spaDistDir");
|
|
280
|
+
if (spaDistTypeIssue && spaDistTypeIssue.message.includes("non-empty string")) {
|
|
281
|
+
throw new CliError(`${configPath}: "paths.spaDistDir" must be a non-empty string.`, {
|
|
285
282
|
code: "INVALID_PROJECT",
|
|
286
283
|
exitCode: EXIT_INVALID_PROJECT
|
|
287
284
|
});
|
|
288
285
|
}
|
|
289
|
-
|
|
290
|
-
|
|
286
|
+
const courseSpaIssue = issues.find((i) => i.path === "course.spaDistDir");
|
|
287
|
+
if (courseSpaIssue) {
|
|
288
|
+
throw new CliError(`${configPath}: ${courseSpaIssue.message}`, {
|
|
291
289
|
code: "INVALID_PROJECT",
|
|
292
290
|
exitCode: EXIT_INVALID_PROJECT
|
|
293
291
|
});
|
|
294
292
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
throw new CliError(`${configPath}: invalid course descriptor.`, {
|
|
293
|
+
if (issues.some((i) => i.path.startsWith("paths."))) {
|
|
294
|
+
throw new CliError(`${configPath}: invalid paths.`, {
|
|
298
295
|
code: "INVALID_PROJECT",
|
|
299
296
|
exitCode: EXIT_INVALID_PROJECT,
|
|
300
|
-
issues:
|
|
301
|
-
path: i.path,
|
|
302
|
-
message: i.message
|
|
303
|
-
}))
|
|
297
|
+
issues: issues.map((i) => ({ path: i.path, message: i.message }))
|
|
304
298
|
});
|
|
305
299
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
{ code: "INVALID_PROJECT", exitCode: EXIT_INVALID_PROJECT }
|
|
310
|
-
);
|
|
311
|
-
}
|
|
312
|
-
const pathsRaw = config.paths;
|
|
313
|
-
const paths = { ...DEFAULT_PATHS };
|
|
314
|
-
if (pathsRaw !== void 0 && (typeof pathsRaw !== "object" || pathsRaw === null)) {
|
|
315
|
-
throw new CliError(`${configPath}: "paths" must be an object.`, {
|
|
300
|
+
const schemaIssue = issues.find((i) => i.path === "schemaVersion");
|
|
301
|
+
if (schemaIssue) {
|
|
302
|
+
throw new CliError(`${configPath}: schemaVersion must be 1 (got ${schemaIssue.message.replace(/^must be 1 \(got /, "").replace(/\)$/, "")}).`, {
|
|
316
303
|
code: "INVALID_PROJECT",
|
|
317
304
|
exitCode: EXIT_INVALID_PROJECT
|
|
318
305
|
});
|
|
319
306
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
code: "INVALID_PROJECT",
|
|
326
|
-
exitCode: EXIT_INVALID_PROJECT
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
paths.spaDistDir = p.spaDistDir;
|
|
330
|
-
}
|
|
331
|
-
if (p.lxpackOutDir !== void 0) {
|
|
332
|
-
if (typeof p.lxpackOutDir !== "string" || !p.lxpackOutDir.trim()) {
|
|
333
|
-
throw new CliError(`${configPath}: "paths.lxpackOutDir" must be a non-empty string.`, {
|
|
334
|
-
code: "INVALID_PROJECT",
|
|
335
|
-
exitCode: EXIT_INVALID_PROJECT
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
paths.lxpackOutDir = p.lxpackOutDir;
|
|
339
|
-
}
|
|
340
|
-
if (p.outputBaseDir !== void 0) {
|
|
341
|
-
if (typeof p.outputBaseDir !== "string" || !p.outputBaseDir.trim()) {
|
|
342
|
-
throw new CliError(`${configPath}: "paths.outputBaseDir" must be a non-empty string.`, {
|
|
343
|
-
code: "INVALID_PROJECT",
|
|
344
|
-
exitCode: EXIT_INVALID_PROJECT
|
|
345
|
-
});
|
|
346
|
-
}
|
|
347
|
-
paths.outputBaseDir = p.outputBaseDir;
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
const courseSpaDistDir = validation.descriptor.spaDistDir?.trim();
|
|
351
|
-
if (courseSpaDistDir && courseSpaDistDir !== paths.spaDistDir) {
|
|
352
|
-
throw new CliError(
|
|
353
|
-
`${configPath}: "course.spaDistDir" (${courseSpaDistDir}) differs from "paths.spaDistDir" (${paths.spaDistDir}). Use paths.spaDistDir for CLI build and package.`,
|
|
354
|
-
{ code: "INVALID_PROJECT", exitCode: EXIT_INVALID_PROJECT }
|
|
355
|
-
);
|
|
356
|
-
}
|
|
357
|
-
const pathIssues = validateProjectPaths(projectRoot, paths);
|
|
358
|
-
if (pathIssues.length) {
|
|
359
|
-
throw new CliError(`${configPath}: invalid paths.`, {
|
|
360
|
-
code: "INVALID_PROJECT",
|
|
361
|
-
exitCode: EXIT_INVALID_PROJECT,
|
|
362
|
-
issues: pathIssues
|
|
363
|
-
});
|
|
364
|
-
}
|
|
365
|
-
return {
|
|
366
|
-
root: projectRoot,
|
|
367
|
-
schemaVersion: 1,
|
|
368
|
-
name,
|
|
369
|
-
course: validation.descriptor,
|
|
370
|
-
paths
|
|
371
|
-
};
|
|
307
|
+
throw new CliError(`${configPath}: invalid lessonkit manifest.`, {
|
|
308
|
+
code: "INVALID_PROJECT",
|
|
309
|
+
exitCode: EXIT_INVALID_PROJECT,
|
|
310
|
+
issues: issues.map((i) => ({ path: i.path, message: i.message }))
|
|
311
|
+
});
|
|
372
312
|
}
|
|
373
313
|
async function loadProject(cwd = process.cwd()) {
|
|
374
314
|
const root = findProjectRoot(cwd);
|
|
@@ -386,7 +326,7 @@ async function readPackageJson(projectRoot) {
|
|
|
386
326
|
}
|
|
387
327
|
}
|
|
388
328
|
function assertViteProject(pkg, projectRoot) {
|
|
389
|
-
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);
|
|
329
|
+
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);
|
|
390
330
|
if (!vite) {
|
|
391
331
|
throw new CliError(
|
|
392
332
|
`No Vite dependency found in ${join2(projectRoot, PACKAGE_JSON)}. LessonKit projects require Vite.`,
|
|
@@ -394,28 +334,25 @@ function assertViteProject(pkg, projectRoot) {
|
|
|
394
334
|
);
|
|
395
335
|
}
|
|
396
336
|
}
|
|
397
|
-
function
|
|
337
|
+
function resolveViteJs(projectRoot) {
|
|
398
338
|
let dir = resolve2(projectRoot);
|
|
399
339
|
const fsRoot = parse(dir).root;
|
|
400
340
|
while (true) {
|
|
401
|
-
const
|
|
402
|
-
|
|
403
|
-
if (existsSync2(bin)) return bin;
|
|
404
|
-
const binCmd = join2(binDir, "vite.cmd");
|
|
405
|
-
if (existsSync2(binCmd)) return binCmd;
|
|
341
|
+
const viteJs = join2(dir, "node_modules", "vite", "bin", "vite.js");
|
|
342
|
+
if (existsSync2(viteJs)) return viteJs;
|
|
406
343
|
if (dir === fsRoot) break;
|
|
407
344
|
dir = dirname2(dir);
|
|
408
345
|
}
|
|
409
346
|
throw new CliError(
|
|
410
|
-
`Vite
|
|
347
|
+
`Vite not found near ${projectRoot}. Run npm install in the project first.`,
|
|
411
348
|
{ code: "INVALID_PROJECT", exitCode: EXIT_INVALID_PROJECT }
|
|
412
349
|
);
|
|
413
350
|
}
|
|
414
|
-
function
|
|
351
|
+
function assertNode18ForLxpack() {
|
|
415
352
|
const major = Number(process.versions.node.split(".")[0]);
|
|
416
|
-
if (major <
|
|
353
|
+
if (major < 18) {
|
|
417
354
|
throw new CliError(
|
|
418
|
-
`LMS packaging requires Node.js
|
|
355
|
+
`LMS packaging requires Node.js 18+ (current: ${process.versions.node}). See docs/PACKAGING.md.`,
|
|
419
356
|
{ code: "NODE_VERSION", exitCode: EXIT_INVALID_PROJECT }
|
|
420
357
|
);
|
|
421
358
|
}
|
|
@@ -424,6 +361,18 @@ function assertNode20ForLxpack() {
|
|
|
424
361
|
// src/lib/paths.ts
|
|
425
362
|
import { resolve as resolve3 } from "path";
|
|
426
363
|
import { resolveSafePackageOutputOverride } from "@lessonkit/lxpack";
|
|
364
|
+
|
|
365
|
+
// src/lib/targetTypes.ts
|
|
366
|
+
var PACKAGE_TARGETS = [
|
|
367
|
+
"react-vite",
|
|
368
|
+
"scorm12",
|
|
369
|
+
"scorm2004",
|
|
370
|
+
"xapi",
|
|
371
|
+
"cmi5",
|
|
372
|
+
"standalone"
|
|
373
|
+
];
|
|
374
|
+
|
|
375
|
+
// src/lib/paths.ts
|
|
427
376
|
function resolveDistDir(project) {
|
|
428
377
|
return resolve3(project.root, project.paths.spaDistDir);
|
|
429
378
|
}
|
|
@@ -454,14 +403,6 @@ function resolveViteBuildArgs(project) {
|
|
|
454
403
|
}
|
|
455
404
|
return args;
|
|
456
405
|
}
|
|
457
|
-
var PACKAGE_TARGETS = [
|
|
458
|
-
"react-vite",
|
|
459
|
-
"scorm12",
|
|
460
|
-
"scorm2004",
|
|
461
|
-
"xapi",
|
|
462
|
-
"cmi5",
|
|
463
|
-
"standalone"
|
|
464
|
-
];
|
|
465
406
|
function parsePackageTarget(value) {
|
|
466
407
|
if (!value) {
|
|
467
408
|
throw new Error("TARGET_REQUIRED");
|
|
@@ -477,17 +418,19 @@ async function runDev(opts) {
|
|
|
477
418
|
const project = await loadProject(opts.cwd ?? process.cwd());
|
|
478
419
|
const pkg = await readPackageJson(project.root);
|
|
479
420
|
assertViteProject(pkg, project.root);
|
|
480
|
-
const
|
|
481
|
-
await runCommand(
|
|
421
|
+
const viteJs = resolveViteJs(project.root);
|
|
422
|
+
await runCommand(process.execPath, [viteJs, ...opts.viteArgs ?? []], { cwd: project.root });
|
|
482
423
|
return { ok: true, command: "dev", projectRoot: project.root };
|
|
483
424
|
}
|
|
484
425
|
async function runBuild(opts) {
|
|
485
426
|
const project = await loadProject(opts.cwd ?? process.cwd());
|
|
486
427
|
const pkg = await readPackageJson(project.root);
|
|
487
428
|
assertViteProject(pkg, project.root);
|
|
488
|
-
const
|
|
429
|
+
const viteJs = resolveViteJs(project.root);
|
|
489
430
|
const buildArgs = resolveViteBuildArgs(project);
|
|
490
|
-
await runCommand(
|
|
431
|
+
await runCommand(process.execPath, [viteJs, ...buildArgs, ...opts.viteArgs ?? []], {
|
|
432
|
+
cwd: project.root
|
|
433
|
+
});
|
|
491
434
|
return { ok: true, command: "build", projectRoot: project.root };
|
|
492
435
|
}
|
|
493
436
|
|
|
@@ -510,8 +453,17 @@ async function runPackage(opts) {
|
|
|
510
453
|
}
|
|
511
454
|
const project = await loadProject(opts.cwd ?? process.cwd());
|
|
512
455
|
const distDir = resolveDistDir(project);
|
|
456
|
+
if (opts.noBuild && !existsSync3(distDir)) {
|
|
457
|
+
throw new CliError(
|
|
458
|
+
`dist directory not found at ${distDir}. Run lessonkit build before packaging with --no-build.`,
|
|
459
|
+
{
|
|
460
|
+
code: "INVALID_PROJECT",
|
|
461
|
+
exitCode: EXIT_INVALID_PROJECT
|
|
462
|
+
}
|
|
463
|
+
);
|
|
464
|
+
}
|
|
513
465
|
if (target === "react-vite") {
|
|
514
|
-
if (!opts.noBuild
|
|
466
|
+
if (!opts.noBuild) {
|
|
515
467
|
await runBuild({ cwd: project.root, json: opts.json });
|
|
516
468
|
}
|
|
517
469
|
if (!existsSync3(distDir)) {
|
|
@@ -520,10 +472,10 @@ async function runPackage(opts) {
|
|
|
520
472
|
exitCode: EXIT_INVALID_PROJECT
|
|
521
473
|
});
|
|
522
474
|
}
|
|
523
|
-
return { ok: true, target, projectRoot: project.root, distDir };
|
|
475
|
+
return { ok: true, command: "package", target, projectRoot: project.root, distDir };
|
|
524
476
|
}
|
|
525
|
-
|
|
526
|
-
if (!opts.noBuild
|
|
477
|
+
assertNode18ForLxpack();
|
|
478
|
+
if (!opts.noBuild) {
|
|
527
479
|
await runBuild({ cwd: project.root, json: opts.json });
|
|
528
480
|
}
|
|
529
481
|
if (!existsSync3(distDir)) {
|
|
@@ -553,6 +505,7 @@ async function runPackage(opts) {
|
|
|
553
505
|
}
|
|
554
506
|
return {
|
|
555
507
|
ok: true,
|
|
508
|
+
command: "package",
|
|
556
509
|
target,
|
|
557
510
|
projectRoot: project.root,
|
|
558
511
|
outputPath: result.outputPath,
|
|
@@ -596,7 +549,10 @@ async function handleCommand(fn, logger, json) {
|
|
|
596
549
|
function createProgram(baseLogger = console) {
|
|
597
550
|
const program = new Command();
|
|
598
551
|
program.name("lessonkit").description("LessonKit CLI").version(version);
|
|
599
|
-
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(
|
|
552
|
+
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(
|
|
553
|
+
"--force",
|
|
554
|
+
"Requires --here: allow init when the directory is empty or contains only dotfiles"
|
|
555
|
+
).option("--json", "Emit structured JSON result").action(async (name, opts) => {
|
|
600
556
|
const logger = createLogger({ json: opts.json });
|
|
601
557
|
await handleCommand(
|
|
602
558
|
() => runInit({ name, here: opts.here, skipInstall: opts.skipInstall, force: opts.force, json: opts.json }, logger),
|
|
@@ -616,7 +572,9 @@ function createProgram(baseLogger = console) {
|
|
|
616
572
|
Boolean(opts.json)
|
|
617
573
|
);
|
|
618
574
|
});
|
|
619
|
-
addCwdAndJson(
|
|
575
|
+
addCwdAndJson(
|
|
576
|
+
program.command("build").description("Production Vite build").allowUnknownOption().allowExcessArguments()
|
|
577
|
+
).action(
|
|
620
578
|
async (opts, command) => {
|
|
621
579
|
const logger = createLogger({ json: opts.json });
|
|
622
580
|
const viteArgs = command.args;
|
|
@@ -630,13 +588,26 @@ function createProgram(baseLogger = console) {
|
|
|
630
588
|
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) => {
|
|
631
589
|
const logger = createLogger({ json: opts.json });
|
|
632
590
|
await handleCommand(
|
|
633
|
-
() =>
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
591
|
+
async () => {
|
|
592
|
+
const result = await runPackage({
|
|
593
|
+
target: opts.target,
|
|
594
|
+
cwd: opts.cwd,
|
|
595
|
+
noBuild: opts.build === false,
|
|
596
|
+
out: opts.out,
|
|
597
|
+
json: opts.json
|
|
598
|
+
});
|
|
599
|
+
if (!opts.json && result.ok) {
|
|
600
|
+
if (result.command === "package" && result.target === "react-vite") {
|
|
601
|
+
logger.log(`Built react-vite \u2192 ${result.distDir}`);
|
|
602
|
+
} else if (result.command === "package") {
|
|
603
|
+
const dest = result.outputPath ?? result.outputDir;
|
|
604
|
+
logger.log(
|
|
605
|
+
`Packaged ${result.target}${dest ? ` \u2192 ${dest}` : ""} (${result.fileCount} files)`
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
return result;
|
|
610
|
+
},
|
|
640
611
|
logger,
|
|
641
612
|
Boolean(opts.json)
|
|
642
613
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lessonkit/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "LessonKit CLI — init, dev, build, and package learning experiences.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"lint": "echo \"(no lint configured yet)\""
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@lessonkit/core": "0.
|
|
46
|
-
"@lessonkit/lxpack": "0.
|
|
45
|
+
"@lessonkit/core": "1.0.1",
|
|
46
|
+
"@lessonkit/lxpack": "1.0.1",
|
|
47
47
|
"commander": "^14.0.1"
|
|
48
48
|
},
|
|
49
49
|
"engines": {
|
|
@@ -1,19 +1,21 @@
|
|
|
1
|
-
# LessonKit
|
|
1
|
+
# LessonKit starter template
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[](https://github.com/eddiethedean/lessonkit/blob/main/LICENSE)
|
|
3
|
+
Vite + React scaffold for new LessonKit courses. Created by `lessonkit init`.
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
## Run
|
|
5
|
+
## Commands
|
|
9
6
|
|
|
10
7
|
```bash
|
|
11
8
|
npm install
|
|
12
|
-
npm run dev
|
|
9
|
+
npm run dev # lessonkit dev
|
|
10
|
+
npm run build # lessonkit build
|
|
11
|
+
npm run package:scorm12
|
|
13
12
|
```
|
|
14
13
|
|
|
15
|
-
##
|
|
14
|
+
## Files
|
|
15
|
+
|
|
16
|
+
- `src/App.tsx` — course UI (IDs match `lessonkit.json`)
|
|
17
|
+
- `lessonkit.json` — manifest for CLI and LXPack packaging
|
|
18
|
+
|
|
19
|
+
## Docs
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
- Copied by [`@lessonkit/cli`](https://lessonkit.readthedocs.io/en/latest/reference/cli.html) when you run `lessonkit init`.
|
|
19
|
-
- Package for an LMS with the [packaging guide](https://lessonkit.readthedocs.io/en/latest/guides/react-developers/packaging-and-cli.html).
|
|
21
|
+
[CLI reference](https://lessonkit.readthedocs.io/en/latest/reference/cli.html) · [React quickstart](https://lessonkit.readthedocs.io/en/latest/guides/react-developers/quickstart.html) · [Packaging guide](https://lessonkit.readthedocs.io/en/latest/guides/react-developers/packaging-and-cli.html)
|
|
@@ -13,16 +13,16 @@
|
|
|
13
13
|
"test:coverage": "vitest run --coverage --passWithNoTests=false"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@lessonkit/core": "^0.
|
|
17
|
-
"@lessonkit/react": "^0.
|
|
18
|
-
"@lessonkit/themes": "^0.
|
|
19
|
-
"@lessonkit/xapi": "^0.
|
|
16
|
+
"@lessonkit/core": "^1.0.1",
|
|
17
|
+
"@lessonkit/react": "^1.0.1",
|
|
18
|
+
"@lessonkit/themes": "^1.0.1",
|
|
19
|
+
"@lessonkit/xapi": "^1.0.1",
|
|
20
20
|
"react": "^18.3.1",
|
|
21
21
|
"react-dom": "^18.3.1"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@lessonkit/cli": "^0.
|
|
25
|
-
"@lessonkit/lxpack": "^0.
|
|
24
|
+
"@lessonkit/cli": "^1.0.1",
|
|
25
|
+
"@lessonkit/lxpack": "^1.0.1",
|
|
26
26
|
"@testing-library/react": "^16.3.0",
|
|
27
27
|
"@types/react": "^18.3.23",
|
|
28
28
|
"@types/react-dom": "^18.3.7",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
html,body{height:100%}body{margin:0;background:var(--lk-color-background);color:var(--lk-color-foreground);font-family:var(--lk-font-family);font-size:var(--lk-font-size-base);line-height:var(--lk-line-height-base)}.app-shell{margin:0 auto;padding:var(--lk-space-xl) var(--lk-space-lg);max-width:720px}section,article{border:1px solid var(--lk-color-border);border-radius:var(--lk-radius-lg);padding:var(--lk-space-lg);margin:var(--lk-space-md) 0;background:var(--lk-color-panel);box-shadow:var(--lk-shadow-md)}h1,h2{margin:0 0 var(--lk-space-sm);font-weight:var(--lk-font-weight-strong)}button{border:1px solid var(--lk-color-border);background:var(--lk-color-panel);color:var(--lk-color-foreground);border-radius:var(--lk-radius-md);padding:var(--lk-space-sm) var(--lk-space-md);font-weight:var(--lk-font-weight-strong);cursor:pointer}input[type=radio]{accent-color:var(--lk-color-primary)}label{display:block;margin:var(--lk-space-xs) 0}
|