@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 CHANGED
@@ -1,55 +1,41 @@
1
- # `@lessonkit/cli`
1
+ # @lessonkit/cli
2
2
 
3
- [![CI](https://github.com/eddiethedean/lessonkit/actions/workflows/ci.yml/badge.svg)](https://github.com/eddiethedean/lessonkit/actions/workflows/ci.yml)
4
- [![Documentation](https://readthedocs.org/projects/lessonkit/badge/?version=latest)](https://lessonkit.readthedocs.io/en/latest/)
5
3
  [![npm](https://img.shields.io/npm/v/@lessonkit/cli.svg)](https://www.npmjs.com/package/@lessonkit/cli)
4
+ [![Documentation](https://readthedocs.org/projects/lessonkit/badge/?version=latest)](https://lessonkit.readthedocs.io/en/latest/reference/cli.html)
6
5
  [![License](https://img.shields.io/github/license/eddiethedean/lessonkit)](https://github.com/eddiethedean/lessonkit/blob/main/LICENSE)
7
6
 
8
- LessonKit CLI — scaffold, dev, build, and package learning experiences.
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
- **Node.js:** dev/build on Node 18+. LMS packaging targets require **Node.js 20+**.
21
-
22
- ## Quick start
17
+ ## Commands
23
18
 
24
19
  ```bash
25
- lessonkit init my-course
26
- cd my-course
27
- lessonkit dev
28
- lessonkit build
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
- ## Commands
33
-
34
- | Command | Description |
35
- |---------|-------------|
36
- | `lessonkit init [name]` | Scaffold a Vite + React project |
37
- | `lessonkit dev` | Run Vite dev server |
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
- - `react-vite` Vite production build `dist/`
45
- - `scorm12`, `scorm2004`, `xapi`, `cmi5`, `standalone` — via `@lessonkit/lxpack`
33
+ Every project includes a root `lessonkit.json` manifest (`schemaVersion: 1`).
46
34
 
47
- ## Project manifest
35
+ ## Docs
48
36
 
49
- Projects include a `lessonkit.json` at the root. See the [CLI reference](https://lessonkit.readthedocs.io/en/latest/reference/cli.html) for the schema, flags, exit codes, and JSON output mode.
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
- ## Related
39
+ ## License
52
40
 
53
- - [Packaging reference](https://lessonkit.readthedocs.io/en/latest/reference/packaging.html) — LXPack output layout
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
@@ -158,6 +158,12 @@ async function runInit(opts, logger) {
158
158
  exitCode: EXIT_INVALID_PROJECT
159
159
  });
160
160
  }
161
+ if (opts.force && !opts.here) {
162
+ throw new CliError("--force requires --here (initialize in the current directory).", {
163
+ code: "INVALID_PROJECT",
164
+ exitCode: EXIT_INVALID_PROJECT
165
+ });
166
+ }
161
167
  const slug = slugifyId(rawName ?? "my-course");
162
168
  const projectName = rawName ?? slug;
163
169
  const projectDir = opts.here ? cwd : resolve(cwd, slug);
@@ -209,18 +215,13 @@ async function runInit(opts, logger) {
209
215
  import { readFileSync, existsSync as existsSync2 } from "fs";
210
216
  import { readFile as readFile2 } from "fs/promises";
211
217
  import { dirname as dirname2, join as join2, parse, resolve as resolve2 } from "path";
212
- import { validateDescriptor, validateProjectPaths } from "@lessonkit/lxpack";
218
+ import { parseLessonkitManifest } from "@lessonkit/lxpack";
213
219
  var LESSONKIT_JSON = "lessonkit.json";
214
220
  var PACKAGE_JSON = "package.json";
215
- var DEFAULT_PATHS = {
216
- spaDistDir: "dist",
217
- lxpackOutDir: ".lxpack/course",
218
- outputBaseDir: ".lxpack/out"
219
- };
220
221
  function isProjectManifest(configPath) {
221
222
  try {
222
223
  const raw = JSON.parse(readFileSync(configPath, "utf8"));
223
- return raw.schemaVersion === 1 && typeof raw.name === "string" && raw.course !== null && typeof raw.course === "object";
224
+ return raw.schemaVersion === 1 && typeof raw.name === "string" && raw.course !== null && typeof raw.course === "object" && !Array.isArray(raw.course);
224
225
  } catch {
225
226
  return false;
226
227
  }
@@ -253,124 +254,63 @@ async function loadLessonkitJson(projectRoot) {
253
254
  exitCode: EXIT_INVALID_PROJECT
254
255
  });
255
256
  }
256
- if (!raw || typeof raw !== "object") {
257
- throw new CliError(`${configPath} must be a JSON object.`, {
258
- code: "INVALID_PROJECT",
259
- exitCode: EXIT_INVALID_PROJECT
260
- });
257
+ const parsed = parseLessonkitManifest(raw, configPath, projectRoot);
258
+ if (!parsed.ok) {
259
+ throwManifestCliError(configPath, parsed.issues);
261
260
  }
262
- const config = raw;
263
- const schemaVersion = config.schemaVersion;
264
- if (schemaVersion !== 1) {
265
- throw new CliError(`${configPath}: schemaVersion must be 1 (got ${String(schemaVersion)}).`, {
266
- code: "INVALID_PROJECT",
267
- exitCode: EXIT_INVALID_PROJECT
268
- });
269
- }
270
- const name = config.name;
271
- if (typeof name !== "string" || !name.trim()) {
272
- throw new CliError(`${configPath}: "name" must be a non-empty string.`, {
273
- code: "INVALID_PROJECT",
274
- exitCode: EXIT_INVALID_PROJECT
275
- });
261
+ return {
262
+ ...parsed.manifest,
263
+ root: projectRoot
264
+ };
265
+ }
266
+ function throwManifestCliError(configPath, issues) {
267
+ const layoutIssue = issues.find((i) => i.path === "course.layout");
268
+ if (layoutIssue?.message.includes("per-lesson-spa")) {
269
+ throw new CliError(
270
+ `${configPath}: per-lesson-spa layout is not supported by lessonkit package yet. Use single-spa or package via @lessonkit/lxpack directly.`,
271
+ { code: "INVALID_PROJECT", exitCode: EXIT_INVALID_PROJECT }
272
+ );
276
273
  }
277
- const courseRaw = config.course;
278
- if (!courseRaw || typeof courseRaw !== "object") {
279
- throw new CliError(`${configPath}: "course" must be an object.`, {
274
+ const lessonsIssue = issues.find((i) => i.path === "course.lessons");
275
+ if (lessonsIssue) {
276
+ throw new CliError(`${configPath}: "course.lessons" must be an array.`, {
280
277
  code: "INVALID_PROJECT",
281
278
  exitCode: EXIT_INVALID_PROJECT
282
279
  });
283
280
  }
284
- const courseObj = courseRaw;
285
- if (courseObj.lessons !== void 0 && !Array.isArray(courseObj.lessons)) {
286
- throw new CliError(`${configPath}: "course.lessons" must be an array.`, {
281
+ const spaDistTypeIssue = issues.find((i) => i.path === "paths.spaDistDir");
282
+ if (spaDistTypeIssue && spaDistTypeIssue.message.includes("non-empty string")) {
283
+ throw new CliError(`${configPath}: "paths.spaDistDir" must be a non-empty string.`, {
287
284
  code: "INVALID_PROJECT",
288
285
  exitCode: EXIT_INVALID_PROJECT
289
286
  });
290
287
  }
291
- if (courseObj.assessments !== void 0 && !Array.isArray(courseObj.assessments)) {
292
- throw new CliError(`${configPath}: "course.assessments" must be an array.`, {
288
+ const courseSpaIssue = issues.find((i) => i.path === "course.spaDistDir");
289
+ if (courseSpaIssue) {
290
+ throw new CliError(`${configPath}: ${courseSpaIssue.message}`, {
293
291
  code: "INVALID_PROJECT",
294
292
  exitCode: EXIT_INVALID_PROJECT
295
293
  });
296
294
  }
297
- const validation = validateDescriptor(courseRaw);
298
- if (!validation.ok) {
299
- throw new CliError(`${configPath}: invalid course descriptor.`, {
295
+ if (issues.some((i) => i.path.startsWith("paths."))) {
296
+ throw new CliError(`${configPath}: invalid paths.`, {
300
297
  code: "INVALID_PROJECT",
301
298
  exitCode: EXIT_INVALID_PROJECT,
302
- issues: validation.issues.map((i) => ({
303
- path: i.path,
304
- message: i.message
305
- }))
299
+ issues: issues.map((i) => ({ path: i.path, message: i.message }))
306
300
  });
307
301
  }
308
- if (validation.descriptor.layout === "per-lesson-spa") {
309
- throw new CliError(
310
- `${configPath}: per-lesson-spa layout is not supported by lessonkit package yet. Use single-spa or package via @lessonkit/lxpack directly.`,
311
- { code: "INVALID_PROJECT", exitCode: EXIT_INVALID_PROJECT }
312
- );
313
- }
314
- const pathsRaw = config.paths;
315
- const paths = { ...DEFAULT_PATHS };
316
- if (pathsRaw !== void 0 && (typeof pathsRaw !== "object" || pathsRaw === null)) {
317
- throw new CliError(`${configPath}: "paths" must be an object.`, {
302
+ const schemaIssue = issues.find((i) => i.path === "schemaVersion");
303
+ if (schemaIssue) {
304
+ throw new CliError(`${configPath}: schemaVersion must be 1 (got ${schemaIssue.message.replace(/^must be 1 \(got /, "").replace(/\)$/, "")}).`, {
318
305
  code: "INVALID_PROJECT",
319
306
  exitCode: EXIT_INVALID_PROJECT
320
307
  });
321
308
  }
322
- if (pathsRaw && typeof pathsRaw === "object") {
323
- const p = pathsRaw;
324
- if (p.spaDistDir !== void 0) {
325
- if (typeof p.spaDistDir !== "string" || !p.spaDistDir.trim()) {
326
- throw new CliError(`${configPath}: "paths.spaDistDir" must be a non-empty string.`, {
327
- code: "INVALID_PROJECT",
328
- exitCode: EXIT_INVALID_PROJECT
329
- });
330
- }
331
- paths.spaDistDir = p.spaDistDir;
332
- }
333
- if (p.lxpackOutDir !== void 0) {
334
- if (typeof p.lxpackOutDir !== "string" || !p.lxpackOutDir.trim()) {
335
- throw new CliError(`${configPath}: "paths.lxpackOutDir" must be a non-empty string.`, {
336
- code: "INVALID_PROJECT",
337
- exitCode: EXIT_INVALID_PROJECT
338
- });
339
- }
340
- paths.lxpackOutDir = p.lxpackOutDir;
341
- }
342
- if (p.outputBaseDir !== void 0) {
343
- if (typeof p.outputBaseDir !== "string" || !p.outputBaseDir.trim()) {
344
- throw new CliError(`${configPath}: "paths.outputBaseDir" must be a non-empty string.`, {
345
- code: "INVALID_PROJECT",
346
- exitCode: EXIT_INVALID_PROJECT
347
- });
348
- }
349
- paths.outputBaseDir = p.outputBaseDir;
350
- }
351
- }
352
- const courseSpaDistDir = validation.descriptor.spaDistDir?.trim();
353
- if (courseSpaDistDir && courseSpaDistDir !== paths.spaDistDir) {
354
- throw new CliError(
355
- `${configPath}: "course.spaDistDir" (${courseSpaDistDir}) differs from "paths.spaDistDir" (${paths.spaDistDir}). Use paths.spaDistDir for CLI build and package.`,
356
- { code: "INVALID_PROJECT", exitCode: EXIT_INVALID_PROJECT }
357
- );
358
- }
359
- const pathIssues = validateProjectPaths(projectRoot, paths);
360
- if (pathIssues.length) {
361
- throw new CliError(`${configPath}: invalid paths.`, {
362
- code: "INVALID_PROJECT",
363
- exitCode: EXIT_INVALID_PROJECT,
364
- issues: pathIssues
365
- });
366
- }
367
- return {
368
- root: projectRoot,
369
- schemaVersion: 1,
370
- name,
371
- course: validation.descriptor,
372
- paths
373
- };
309
+ throw new CliError(`${configPath}: invalid lessonkit manifest.`, {
310
+ code: "INVALID_PROJECT",
311
+ exitCode: EXIT_INVALID_PROJECT,
312
+ issues: issues.map((i) => ({ path: i.path, message: i.message }))
313
+ });
374
314
  }
375
315
  async function loadProject(cwd = process.cwd()) {
376
316
  const root = findProjectRoot(cwd);
@@ -388,7 +328,7 @@ async function readPackageJson(projectRoot) {
388
328
  }
389
329
  }
390
330
  function assertViteProject(pkg, projectRoot) {
391
- 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);
331
+ 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);
392
332
  if (!vite) {
393
333
  throw new CliError(
394
334
  `No Vite dependency found in ${join2(projectRoot, PACKAGE_JSON)}. LessonKit projects require Vite.`,
@@ -396,28 +336,25 @@ function assertViteProject(pkg, projectRoot) {
396
336
  );
397
337
  }
398
338
  }
399
- function resolveViteBin(projectRoot) {
339
+ function resolveViteJs(projectRoot) {
400
340
  let dir = resolve2(projectRoot);
401
341
  const fsRoot = parse(dir).root;
402
342
  while (true) {
403
- const binDir = join2(dir, "node_modules", ".bin");
404
- const bin = join2(binDir, "vite");
405
- if (existsSync2(bin)) return bin;
406
- const binCmd = join2(binDir, "vite.cmd");
407
- if (existsSync2(binCmd)) return binCmd;
343
+ const viteJs = join2(dir, "node_modules", "vite", "bin", "vite.js");
344
+ if (existsSync2(viteJs)) return viteJs;
408
345
  if (dir === fsRoot) break;
409
346
  dir = dirname2(dir);
410
347
  }
411
348
  throw new CliError(
412
- `Vite binary not found near ${projectRoot}. Run npm install in the project first.`,
349
+ `Vite not found near ${projectRoot}. Run npm install in the project first.`,
413
350
  { code: "INVALID_PROJECT", exitCode: EXIT_INVALID_PROJECT }
414
351
  );
415
352
  }
416
- function assertNode20ForLxpack() {
353
+ function assertNode18ForLxpack() {
417
354
  const major = Number(process.versions.node.split(".")[0]);
418
- if (major < 20) {
355
+ if (major < 18) {
419
356
  throw new CliError(
420
- `LMS packaging requires Node.js 20+ (current: ${process.versions.node}). See docs/PACKAGING.md.`,
357
+ `LMS packaging requires Node.js 18+ (current: ${process.versions.node}). See docs/PACKAGING.md.`,
421
358
  { code: "NODE_VERSION", exitCode: EXIT_INVALID_PROJECT }
422
359
  );
423
360
  }
@@ -426,6 +363,18 @@ function assertNode20ForLxpack() {
426
363
  // src/lib/paths.ts
427
364
  import { resolve as resolve3 } from "path";
428
365
  import { resolveSafePackageOutputOverride } from "@lessonkit/lxpack";
366
+
367
+ // src/lib/targetTypes.ts
368
+ var PACKAGE_TARGETS = [
369
+ "react-vite",
370
+ "scorm12",
371
+ "scorm2004",
372
+ "xapi",
373
+ "cmi5",
374
+ "standalone"
375
+ ];
376
+
377
+ // src/lib/paths.ts
429
378
  function resolveDistDir(project) {
430
379
  return resolve3(project.root, project.paths.spaDistDir);
431
380
  }
@@ -456,14 +405,6 @@ function resolveViteBuildArgs(project) {
456
405
  }
457
406
  return args;
458
407
  }
459
- var PACKAGE_TARGETS = [
460
- "react-vite",
461
- "scorm12",
462
- "scorm2004",
463
- "xapi",
464
- "cmi5",
465
- "standalone"
466
- ];
467
408
  function parsePackageTarget(value) {
468
409
  if (!value) {
469
410
  throw new Error("TARGET_REQUIRED");
@@ -479,17 +420,19 @@ async function runDev(opts) {
479
420
  const project = await loadProject(opts.cwd ?? process.cwd());
480
421
  const pkg = await readPackageJson(project.root);
481
422
  assertViteProject(pkg, project.root);
482
- const viteBin = resolveViteBin(project.root);
483
- await runCommand(viteBin, opts.viteArgs ?? [], { cwd: project.root });
423
+ const viteJs = resolveViteJs(project.root);
424
+ await runCommand(process.execPath, [viteJs, ...opts.viteArgs ?? []], { cwd: project.root });
484
425
  return { ok: true, command: "dev", projectRoot: project.root };
485
426
  }
486
427
  async function runBuild(opts) {
487
428
  const project = await loadProject(opts.cwd ?? process.cwd());
488
429
  const pkg = await readPackageJson(project.root);
489
430
  assertViteProject(pkg, project.root);
490
- const viteBin = resolveViteBin(project.root);
431
+ const viteJs = resolveViteJs(project.root);
491
432
  const buildArgs = resolveViteBuildArgs(project);
492
- await runCommand(viteBin, [...buildArgs, ...opts.viteArgs ?? []], { cwd: project.root });
433
+ await runCommand(process.execPath, [viteJs, ...buildArgs, ...opts.viteArgs ?? []], {
434
+ cwd: project.root
435
+ });
493
436
  return { ok: true, command: "build", projectRoot: project.root };
494
437
  }
495
438
 
@@ -512,8 +455,17 @@ async function runPackage(opts) {
512
455
  }
513
456
  const project = await loadProject(opts.cwd ?? process.cwd());
514
457
  const distDir = resolveDistDir(project);
458
+ if (opts.noBuild && !existsSync3(distDir)) {
459
+ throw new CliError(
460
+ `dist directory not found at ${distDir}. Run lessonkit build before packaging with --no-build.`,
461
+ {
462
+ code: "INVALID_PROJECT",
463
+ exitCode: EXIT_INVALID_PROJECT
464
+ }
465
+ );
466
+ }
515
467
  if (target === "react-vite") {
516
- if (!opts.noBuild || !existsSync3(distDir)) {
468
+ if (!opts.noBuild) {
517
469
  await runBuild({ cwd: project.root, json: opts.json });
518
470
  }
519
471
  if (!existsSync3(distDir)) {
@@ -522,10 +474,10 @@ async function runPackage(opts) {
522
474
  exitCode: EXIT_INVALID_PROJECT
523
475
  });
524
476
  }
525
- return { ok: true, target, projectRoot: project.root, distDir };
477
+ return { ok: true, command: "package", target, projectRoot: project.root, distDir };
526
478
  }
527
- assertNode20ForLxpack();
528
- if (!opts.noBuild || !existsSync3(distDir)) {
479
+ assertNode18ForLxpack();
480
+ if (!opts.noBuild) {
529
481
  await runBuild({ cwd: project.root, json: opts.json });
530
482
  }
531
483
  if (!existsSync3(distDir)) {
@@ -555,6 +507,7 @@ async function runPackage(opts) {
555
507
  }
556
508
  return {
557
509
  ok: true,
510
+ command: "package",
558
511
  target,
559
512
  projectRoot: project.root,
560
513
  outputPath: result.outputPath,
@@ -598,7 +551,10 @@ async function handleCommand(fn, logger, json) {
598
551
  function createProgram(baseLogger = console) {
599
552
  const program = new Command();
600
553
  program.name("lessonkit").description("LessonKit CLI").version(version);
601
- 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("--force", "Initialize into a non-empty directory").option("--json", "Emit structured JSON result").action(async (name, opts) => {
554
+ 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(
555
+ "--force",
556
+ "Requires --here: allow init when the directory is empty or contains only dotfiles"
557
+ ).option("--json", "Emit structured JSON result").action(async (name, opts) => {
602
558
  const logger = createLogger({ json: opts.json });
603
559
  await handleCommand(
604
560
  () => runInit({ name, here: opts.here, skipInstall: opts.skipInstall, force: opts.force, json: opts.json }, logger),
@@ -618,7 +574,9 @@ function createProgram(baseLogger = console) {
618
574
  Boolean(opts.json)
619
575
  );
620
576
  });
621
- addCwdAndJson(program.command("build").description("Production Vite build")).action(
577
+ addCwdAndJson(
578
+ program.command("build").description("Production Vite build").allowUnknownOption().allowExcessArguments()
579
+ ).action(
622
580
  async (opts, command) => {
623
581
  const logger = createLogger({ json: opts.json });
624
582
  const viteArgs = command.args;
@@ -632,13 +590,26 @@ function createProgram(baseLogger = console) {
632
590
  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) => {
633
591
  const logger = createLogger({ json: opts.json });
634
592
  await handleCommand(
635
- () => runPackage({
636
- target: opts.target,
637
- cwd: opts.cwd,
638
- noBuild: opts.build === false,
639
- out: opts.out,
640
- json: opts.json
641
- }),
593
+ async () => {
594
+ const result = await runPackage({
595
+ target: opts.target,
596
+ cwd: opts.cwd,
597
+ noBuild: opts.build === false,
598
+ out: opts.out,
599
+ json: opts.json
600
+ });
601
+ if (!opts.json && result.ok) {
602
+ if (result.command === "package" && result.target === "react-vite") {
603
+ logger.log(`Built react-vite \u2192 ${result.distDir}`);
604
+ } else if (result.command === "package") {
605
+ const dest = result.outputPath ?? result.outputDir;
606
+ logger.log(
607
+ `Packaged ${result.target}${dest ? ` \u2192 ${dest}` : ""} (${result.fileCount} files)`
608
+ );
609
+ }
610
+ }
611
+ return result;
612
+ },
642
613
  logger,
643
614
  Boolean(opts.json)
644
615
  );