@velarscript/cli 0.12.0 → 0.13.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.
Files changed (140) hide show
  1. package/README.md +4 -12
  2. package/dist/browser-process-owner.d.ts +23 -0
  3. package/dist/browser-process-owner.d.ts.map +1 -1
  4. package/dist/browser-process-owner.js +46 -2
  5. package/dist/browser-process-owner.js.map +1 -1
  6. package/dist/browser-test-runner.d.ts.map +1 -1
  7. package/dist/browser-test-runner.js +110 -14
  8. package/dist/browser-test-runner.js.map +1 -1
  9. package/dist/cli.js +131 -68
  10. package/dist/cli.js.map +1 -1
  11. package/dist/config.d.ts.map +1 -1
  12. package/dist/config.js +28 -4
  13. package/dist/config.js.map +1 -1
  14. package/dist/dev-server.d.ts +18 -0
  15. package/dist/dev-server.d.ts.map +1 -1
  16. package/dist/dev-server.js +168 -8
  17. package/dist/dev-server.js.map +1 -1
  18. package/dist/extension-metadata.d.ts +6 -0
  19. package/dist/extension-metadata.d.ts.map +1 -1
  20. package/dist/extension-metadata.js +70 -4
  21. package/dist/extension-metadata.js.map +1 -1
  22. package/dist/format-guard.d.ts +20 -0
  23. package/dist/format-guard.d.ts.map +1 -0
  24. package/dist/format-guard.js +13 -0
  25. package/dist/format-guard.js.map +1 -0
  26. package/dist/framework-host.d.ts.map +1 -1
  27. package/dist/framework-host.js +15 -2
  28. package/dist/framework-host.js.map +1 -1
  29. package/dist/language-server-bundle-entry.js +0 -2
  30. package/dist/language-server-bundle-entry.js.map +1 -1
  31. package/dist/language-server-tool.d.ts.map +1 -1
  32. package/dist/language-server-tool.js +0 -2
  33. package/dist/language-server-tool.js.map +1 -1
  34. package/dist/language-server.d.ts +1 -1
  35. package/dist/language-server.d.ts.map +1 -1
  36. package/dist/language-server.js +87 -293
  37. package/dist/language-server.js.map +1 -1
  38. package/dist/local-request-guard.d.ts +18 -0
  39. package/dist/local-request-guard.d.ts.map +1 -0
  40. package/dist/local-request-guard.js +75 -0
  41. package/dist/local-request-guard.js.map +1 -0
  42. package/dist/mechanical-fixer.d.ts.map +1 -1
  43. package/dist/mechanical-fixer.js +116 -2
  44. package/dist/mechanical-fixer.js.map +1 -1
  45. package/dist/module-assets.d.ts +23 -0
  46. package/dist/module-assets.d.ts.map +1 -1
  47. package/dist/module-assets.js +216 -14
  48. package/dist/module-assets.js.map +1 -1
  49. package/dist/node-application.d.ts +7 -2
  50. package/dist/node-application.d.ts.map +1 -1
  51. package/dist/node-application.js +44 -14
  52. package/dist/node-application.js.map +1 -1
  53. package/dist/node-runtime-dependencies.d.ts +2 -0
  54. package/dist/node-runtime-dependencies.d.ts.map +1 -0
  55. package/dist/node-runtime-dependencies.js +24 -0
  56. package/dist/node-runtime-dependencies.js.map +1 -0
  57. package/dist/npm.d.ts +29 -0
  58. package/dist/npm.d.ts.map +1 -1
  59. package/dist/npm.js +39 -2
  60. package/dist/npm.js.map +1 -1
  61. package/dist/ownership-graph.d.ts.map +1 -1
  62. package/dist/ownership-graph.js +155 -38
  63. package/dist/ownership-graph.js.map +1 -1
  64. package/dist/package-manager.d.ts.map +1 -1
  65. package/dist/package-manager.js +4 -1
  66. package/dist/package-manager.js.map +1 -1
  67. package/dist/preview-server.d.ts.map +1 -1
  68. package/dist/preview-server.js +12 -4
  69. package/dist/preview-server.js.map +1 -1
  70. package/dist/production-build.d.ts.map +1 -1
  71. package/dist/production-build.js +24 -6
  72. package/dist/production-build.js.map +1 -1
  73. package/dist/production-verifier.js +3 -0
  74. package/dist/production-verifier.js.map +1 -1
  75. package/dist/project-check.d.ts +14 -1
  76. package/dist/project-check.d.ts.map +1 -1
  77. package/dist/project-check.js +17 -4
  78. package/dist/project-check.js.map +1 -1
  79. package/dist/project-format.d.ts +9 -0
  80. package/dist/project-format.d.ts.map +1 -1
  81. package/dist/project-format.js +13 -0
  82. package/dist/project-format.js.map +1 -1
  83. package/dist/project-semantic.d.ts.map +1 -1
  84. package/dist/project-semantic.js +15 -4
  85. package/dist/project-semantic.js.map +1 -1
  86. package/dist/project.d.ts +25 -0
  87. package/dist/project.d.ts.map +1 -1
  88. package/dist/project.js +341 -42
  89. package/dist/project.js.map +1 -1
  90. package/dist/reproduction.d.ts +18 -0
  91. package/dist/reproduction.d.ts.map +1 -1
  92. package/dist/reproduction.js +47 -6
  93. package/dist/reproduction.js.map +1 -1
  94. package/dist/stable-order.d.ts +17 -0
  95. package/dist/stable-order.d.ts.map +1 -0
  96. package/dist/stable-order.js +19 -0
  97. package/dist/stable-order.js.map +1 -0
  98. package/dist/standard-modules.d.ts +2 -2
  99. package/dist/standard-modules.d.ts.map +1 -1
  100. package/dist/standard-modules.js +2 -2
  101. package/dist/standard-modules.js.map +1 -1
  102. package/dist/static-deployment.d.ts.map +1 -1
  103. package/dist/static-deployment.js +27 -0
  104. package/dist/static-deployment.js.map +1 -1
  105. package/dist/test-runner.d.ts.map +1 -1
  106. package/dist/test-runner.js +196 -100
  107. package/dist/test-runner.js.map +1 -1
  108. package/dist/test-worker.d.ts +64 -0
  109. package/dist/test-worker.d.ts.map +1 -0
  110. package/dist/test-worker.js +161 -0
  111. package/dist/test-worker.js.map +1 -0
  112. package/dist/typescript-declarations.d.ts +1 -1
  113. package/dist/typescript-declarations.d.ts.map +1 -1
  114. package/dist/typescript-declarations.js +233 -21
  115. package/dist/typescript-declarations.js.map +1 -1
  116. package/dist/unowned-errors.d.ts +15 -2
  117. package/dist/unowned-errors.d.ts.map +1 -1
  118. package/dist/unowned-errors.js +13 -2
  119. package/dist/unowned-errors.js.map +1 -1
  120. package/dist/version.d.ts +1 -1
  121. package/dist/version.js +1 -1
  122. package/dist/workspace-index.d.ts.map +1 -1
  123. package/dist/workspace-index.js +42 -17
  124. package/dist/workspace-index.js.map +1 -1
  125. package/package.json +7 -8
  126. package/skill/ai-skill-node.md +91 -12
  127. package/skill/ai-skill-web.md +51 -1
  128. package/skill/ai-skill.md +36 -13
  129. package/dist/official-script-language-service.d.ts +0 -2
  130. package/dist/official-script-language-service.d.ts.map +0 -1
  131. package/dist/official-script-language-service.js +0 -10
  132. package/dist/official-script-language-service.js.map +0 -1
  133. package/dist/official-tool-assets.d.ts +0 -3
  134. package/dist/official-tool-assets.d.ts.map +0 -1
  135. package/dist/official-tool-assets.js +0 -60
  136. package/dist/official-tool-assets.js.map +0 -1
  137. package/dist/script-language-service.d.ts +0 -82
  138. package/dist/script-language-service.d.ts.map +0 -1
  139. package/dist/script-language-service.js +0 -18
  140. package/dist/script-language-service.js.map +0 -1
package/dist/cli.js CHANGED
@@ -7,12 +7,10 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
7
7
  }
8
8
  return path;
9
9
  };
10
- import { cp, lstat, mkdir, mkdtemp, readFile, readdir, rename, rm, writeFile } from "node:fs/promises";
11
- import { createRequire } from "node:module";
12
- import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
13
- import { tmpdir } from "node:os";
10
+ import { lstat, mkdir, mkdtemp, readFile, readdir, rename, rm, writeFile } from "node:fs/promises";
11
+ import { basename, dirname, extname, isAbsolute, join, parse as parsePath, relative, resolve } from "node:path";
12
+ import { homedir, tmpdir } from "node:os";
14
13
  import { fileURLToPath, pathToFileURL } from "node:url";
15
- import { formatSource } from "@velarscript/compiler";
16
14
  import { createVelarProject, parseCreateArguments } from "create-velar";
17
15
  import { projectImportKey } from "./project.js";
18
16
  import { checkResolvedProject, discoverVelarSources, formatCheckOutput, projectTestModules } from "./project-check.js";
@@ -21,10 +19,11 @@ import { runDevServer } from "./dev-server.js";
21
19
  import { nodeApplicationConfig, nodeApplicationEntry, nodeApplicationLauncherSource, runNodeApplication, runNodeDevelopment, } from "./node-application.js";
22
20
  import { createFrameworkArtifacts } from "./framework-host.js";
23
21
  import { resolveVelarProject } from "./config.js";
24
- import { STANDARD_MODULE_ADAPTER_DEPENDENCIES, standardModuleClosure, standardModuleSource, standardModuleSources } from "./standard-modules.js";
22
+ import { standardModuleClosure, standardModuleSource, standardModuleSources } from "./standard-modules.js";
25
23
  import { runTests } from "./test-runner.js";
26
24
  import { runProgram } from "./program-runner.js";
27
- import { buildProductionFramework, writeProductionManifest } from "./production-build.js";
25
+ import { buildProductionFramework, PRODUCTION_MANIFEST_NAME, writeProductionManifest } from "./production-build.js";
26
+ import { formatSourceChecked } from "./format-guard.js";
28
27
  import { VELAR_VERSION } from "./version.js";
29
28
  import { assertRequiredPublicAssets, copyPublicAssets, writeStaticDeployment } from "./static-deployment.js";
30
29
  import { verifyProductionBuild } from "./production-verifier.js";
@@ -37,8 +36,8 @@ import { loadApplicationPackageHost, validateApplicationPackageResult } from "./
37
36
  import { buildLanguageServerTool } from "./language-server-tool.js";
38
37
  import { applyProjectMechanicalFixes } from "./mechanical-fixer.js";
39
38
  import { bundleStandaloneJavaScript, needsStandaloneJavaScriptBundle } from "./standalone-build.js";
40
- import { resolveInstalledPackageRoot } from "./installed-package.js";
41
39
  import { BUILD_STAGING_MARKER } from "./build-staging.js";
40
+ import { writeWebSocketDependency } from "./node-runtime-dependencies.js";
42
41
  import { assertUniqueEmbeddedModuleOutputs, embeddedModuleFileContents, embeddedModuleOutputPath, VELAR_EMBEDDED_MODULE_MARKER, } from "./embedded-modules.js";
43
42
  import { resourceOutputRelativePath, writeBuildResourcePackageManifests, writeProjectResources } from "./resource-output.js";
44
43
  async function main(arguments_) {
@@ -338,10 +337,19 @@ async function main(arguments_) {
338
337
  return 1;
339
338
  }
340
339
  const changed = [];
340
+ const unstable = [];
341
341
  try {
342
342
  for (const input of inputs) {
343
343
  const source = await readVelarSourceFile(input);
344
- const formatted = formatSource(source, { extensions: formattingExtensions });
344
+ const { text: formatted, stable } = formatSourceChecked(source, { extensions: formattingExtensions });
345
+ // Formatting is idempotent by contract. A result the formatter would
346
+ // change again is a formatter defect, and writing it would replace a
347
+ // module that compiles with one that may not, so the file keeps the
348
+ // bytes the author wrote and the command reports the defect.
349
+ if (!stable) {
350
+ unstable.push(input);
351
+ continue;
352
+ }
345
353
  if (formatted === source)
346
354
  continue;
347
355
  changed.push(input);
@@ -353,6 +361,12 @@ async function main(arguments_) {
353
361
  process.stderr.write(`velar format: ${hostErrorMessage(error)}\n`);
354
362
  return 1;
355
363
  }
364
+ if (unstable.length > 0) {
365
+ for (const input of unstable) {
366
+ process.stderr.write(`velar format: ${displayPath(input)}: the formatter did not reach a fixed point; the file was left unchanged\n`);
367
+ }
368
+ return 1;
369
+ }
356
370
  if (parsed.check && changed.length > 0) {
357
371
  for (const input of changed)
358
372
  process.stderr.write(`${displayPath(input)} is not formatted\n`);
@@ -442,7 +456,7 @@ async function main(arguments_) {
442
456
  }
443
457
  return runTests(projectConfig, parsed.input);
444
458
  }
445
- const parsed = command === "package" ? parsePackageArguments(rest) : parseCommandArguments(rest);
459
+ const parsed = command === "package" ? parsePackageArguments(rest) : parseCommandArguments(rest, command === "build");
446
460
  if (typeof parsed === "string") {
447
461
  process.stderr.write(`velar ${command}: ${parsed}\n`);
448
462
  return 2;
@@ -470,7 +484,13 @@ async function main(arguments_) {
470
484
  }
471
485
  if (command === "check") {
472
486
  const count = checked.compiled.size;
473
- process.stdout.write(`Checked ${count} module${count === 1 ? "" : "s"} from ${displayInput(parsed.input, projectConfig)}\n`);
487
+ // D89: a passing check that carried advisories says how many. Folding them
488
+ // into a silent "checked N modules" would hide the one thing the advisory
489
+ // channel exists to make impossible to miss; the exit code stays 0 either
490
+ // way, because an advisory is not a failure.
491
+ const advisories = checked.advisories.length;
492
+ process.stdout.write(`Checked ${count} module${count === 1 ? "" : "s"} from ${displayInput(parsed.input, projectConfig)}`
493
+ + `${advisories > 0 ? ` — ${advisories} advisor${advisories === 1 ? "y" : "ies"}` : ""}\n`);
474
494
  return 0;
475
495
  }
476
496
  if (command === "package") {
@@ -490,7 +510,7 @@ async function main(arguments_) {
490
510
  if (buildRequests > 1)
491
511
  throw new Error("application package host requested more than one framework build");
492
512
  const outputDirectory = packageFrameworkOutput(projectConfig.root, requestedOutput);
493
- frameworkBuild = writeFrameworkProductionApplication(project, outputDirectory);
513
+ frameworkBuild = writeFrameworkProductionApplication(project, outputDirectory, { forced: false, declared: false });
494
514
  await frameworkBuild;
495
515
  },
496
516
  });
@@ -535,9 +555,15 @@ async function main(arguments_) {
535
555
  return 0;
536
556
  }
537
557
  const outputDirectory = parsed.outputDirectory ? resolve(parsed.outputDirectory) : projectConfig.outDir;
558
+ // `outDir` is the project manifest's own declaration of a directory velar
559
+ // owns, and config.ts already refuses one that is the project root or that
560
+ // overlaps the entry or the public directory. `--out-dir` carries no such
561
+ // declaration, so a path it names has to prove ownership before the build
562
+ // replaces what is there.
563
+ const replacement = { forced: parsed.force, declared: outputDirectory === projectConfig.outDir };
538
564
  if (project.framework) {
539
565
  try {
540
- await writeFrameworkProductionApplication(project, outputDirectory);
566
+ await writeFrameworkProductionApplication(project, outputDirectory, replacement);
541
567
  }
542
568
  catch (error) {
543
569
  process.stderr.write(`velar build: ${hostErrorMessage(error)}\n`);
@@ -549,7 +575,7 @@ async function main(arguments_) {
549
575
  const nodeConfig = nodeApplicationConfig(projectConfig);
550
576
  if (nodeConfig) {
551
577
  try {
552
- await writeNodeProductionApplication(project, outputDirectory, nodeConfig);
578
+ await writeNodeProductionApplication(project, outputDirectory, nodeConfig, replacement);
553
579
  }
554
580
  catch (error) {
555
581
  process.stderr.write(`velar build: ${hostErrorMessage(error)}\n`);
@@ -558,7 +584,14 @@ async function main(arguments_) {
558
584
  process.stdout.write(`Built production Node app -> ${outputDirectory}\n`);
559
585
  return 0;
560
586
  }
561
- const staging = await prepareBuildStaging(outputDirectory);
587
+ let staging;
588
+ try {
589
+ staging = await prepareBuildStaging(outputDirectory, replacement);
590
+ }
591
+ catch (error) {
592
+ process.stderr.write(`velar build: ${hostErrorMessage(error)}\n`);
593
+ return 1;
594
+ }
562
595
  try {
563
596
  assertUniqueEmbeddedModuleOutputs(project.modules.map((module) => ({
564
597
  ownerPath: join(staging, module.relativePath.replace(/\.vel$/, ".js")),
@@ -582,12 +615,12 @@ async function main(arguments_) {
582
615
  process.stdout.write(`Built ${project.modules.length} module${project.modules.length === 1 ? "" : "s"} -> ${outputDirectory}\n`);
583
616
  return 0;
584
617
  }
585
- async function writeFrameworkProductionApplication(project, outputDirectory) {
618
+ async function writeFrameworkProductionApplication(project, outputDirectory, replacement) {
586
619
  if (!project.framework)
587
620
  throw new Error("the checked project has no framework host");
588
621
  const framework = project.framework;
589
622
  await assertRequiredPublicAssets(project.publicRoot, project.projectRoot, framework.host.requiredPublicAssets?.(framework.config) ?? []);
590
- const staging = await prepareBuildStaging(outputDirectory);
623
+ const staging = await prepareBuildStaging(outputDirectory, replacement);
591
624
  try {
592
625
  await copyPublicAssets(project.publicRoot, staging);
593
626
  const production = await buildProductionFramework(project, staging);
@@ -608,9 +641,12 @@ async function writeFrameworkProductionApplication(project, outputDirectory) {
608
641
  throw error;
609
642
  }
610
643
  }
611
- async function writeNodeProductionApplication(project, outputDirectory, config) {
612
- const entry = nodeApplicationEntry(project, config);
613
- const staging = await prepareBuildStaging(outputDirectory);
644
+ /** The receipt a node build leaves in its output; it also proves velar owns the directory. */
645
+ const NODE_BUILD_MANIFEST_NAME = "velar-node.json";
646
+ async function writeNodeProductionApplication(project, outputDirectory, config, replacement) {
647
+ const application = nodeApplicationEntry(project, config);
648
+ const entry = application.entry;
649
+ const staging = await prepareBuildStaging(outputDirectory, replacement);
614
650
  try {
615
651
  assertUniqueEmbeddedModuleOutputs(project.modules.map((module) => ({
616
652
  ownerPath: join(staging, module.relativePath.replace(/\.vel$/u, ".js")),
@@ -627,9 +663,9 @@ async function writeNodeProductionApplication(project, outputDirectory, config)
627
663
  await copyPublicAssets(project.publicRoot, join(staging, "public"), true);
628
664
  const entryPath = `./${relative(project.sourceRoot, entry.inputPath).replace(/\.vel$/u, ".js").replaceAll("\\", "/")}`;
629
665
  const launcher = ".velar-node-entry.mjs";
630
- await writeFile(join(staging, launcher), nodeApplicationLauncherSource(entryPath, config, {}, false), "utf8");
666
+ await writeFile(join(staging, launcher), nodeApplicationLauncherSource(entryPath, config, {}, false, application.kind), "utf8");
631
667
  await writeFile(join(staging, "package.json"), `${JSON.stringify({ name: "velar-node-build", private: true, type: "module" }, null, 2)}\n`, "utf8");
632
- await writeFile(join(staging, "velar-node.json"), `${JSON.stringify({
668
+ await writeFile(join(staging, NODE_BUILD_MANIFEST_NAME), `${JSON.stringify({
633
669
  formatVersion: 1,
634
670
  kind: "velar-node-build",
635
671
  entry: launcher,
@@ -661,8 +697,9 @@ function packageFrameworkOutput(root, input) {
661
697
  * output. A process cut can happen before or after either rename, so recovery
662
698
  * also finishes restoring the previous output when installation never began.
663
699
  */
664
- async function prepareBuildStaging(outputDirectory) {
700
+ async function prepareBuildStaging(outputDirectory, replacement) {
665
701
  const normalizedOutput = resolve(outputDirectory);
702
+ await assertReplaceableBuildOutput(normalizedOutput, replacement);
666
703
  const parent = dirname(normalizedOutput);
667
704
  await mkdir(parent, { recursive: true });
668
705
  await recoverInterruptedBuilds(normalizedOutput);
@@ -677,6 +714,67 @@ async function prepareBuildStaging(outputDirectory) {
677
714
  await writeFile(join(staging, BUILD_STAGING_MARKER), `${JSON.stringify(ownership, null, 2)}\n`, "utf8");
678
715
  return staging;
679
716
  }
717
+ /**
718
+ * A build replaces its output directory wholesale, so the path is accepted only
719
+ * when velar owns it: absent, empty, carrying a manifest a previous build wrote,
720
+ * or named by the project manifest's own `outDir`. Every other destructive path
721
+ * in this repository makes the same test first — `assertReplaceableReleaseOutput`
722
+ * in scripts/release-toolchain.mjs, `prepareDirectory` in reproduction.ts, and
723
+ * `createVelarProject` — and `--out-dir` was the one an author runs daily that
724
+ * did not. `--force` waives the ownership test and nothing else: the home
725
+ * directory, the filesystem root and a symbolic link stay refused.
726
+ */
727
+ async function assertReplaceableBuildOutput(outputDirectory, replacement) {
728
+ const directory = resolve(outputDirectory);
729
+ if (directory === parsePath(directory).root || directory === resolve(homedir())) {
730
+ throw new Error(`refusing to replace '${directory}': a build output cannot be the filesystem root or the home directory`);
731
+ }
732
+ let metadata;
733
+ try {
734
+ metadata = await lstat(directory);
735
+ }
736
+ catch (error) {
737
+ if (isHostErrorCode(error, "ENOENT") || isHostErrorCode(error, "ENOTDIR"))
738
+ return;
739
+ throw error;
740
+ }
741
+ if (metadata.isSymbolicLink())
742
+ throw new Error(`refusing to replace '${directory}': it is a symbolic link`);
743
+ if (!metadata.isDirectory())
744
+ throw new Error(`refusing to replace '${directory}': it is not a directory`);
745
+ if (replacement.forced || replacement.declared)
746
+ return;
747
+ if ((await readdir(directory)).length === 0)
748
+ return;
749
+ if (await isBuildOutputDirectory(directory))
750
+ return;
751
+ throw new Error(`refusing to replace '${directory}': it is not empty and was not produced by velar build (pass --force to overwrite)`);
752
+ }
753
+ /**
754
+ * The three build shapes leave three different receipts: a framework build
755
+ * writes `velar-build.json`, a node build writes `velar-node.json`, and a build
756
+ * cut between the two renames leaves the staging marker naming this same output.
757
+ */
758
+ async function isBuildOutputDirectory(directory) {
759
+ if (await buildStagingOwnership(directory, directory, null))
760
+ return true;
761
+ return await buildManifestKind(join(directory, PRODUCTION_MANIFEST_NAME)) === "velar-framework-build"
762
+ || await buildManifestKind(join(directory, NODE_BUILD_MANIFEST_NAME)) === "velar-node-build";
763
+ }
764
+ async function buildManifestKind(path) {
765
+ try {
766
+ const metadata = await lstat(path);
767
+ if (!metadata.isFile() || metadata.isSymbolicLink())
768
+ return null;
769
+ const parsed = JSON.parse(await readFile(path, "utf8"));
770
+ return Number.isSafeInteger(parsed.formatVersion) && typeof parsed.kind === "string" ? parsed.kind : null;
771
+ }
772
+ catch (error) {
773
+ if (isHostErrorCode(error, "ENOENT") || isHostErrorCode(error, "ENOTDIR") || error instanceof SyntaxError)
774
+ return null;
775
+ throw error;
776
+ }
777
+ }
680
778
  async function recoverInterruptedBuilds(outputDirectory) {
681
779
  const parent = dirname(outputDirectory);
682
780
  const prefix = `.velar-${basename(outputDirectory)}-`;
@@ -789,7 +887,6 @@ async function writeNodeStandardModules(outputRoot, project, replaceExisting = f
789
887
  await writeNodeStandardModulePackage(packageRoot, used, project);
790
888
  if (used.has("velar/websocket"))
791
889
  await writeWebSocketDependency(dirname(packageRoot));
792
- await writeAdapterDependencies(dirname(packageRoot), used);
793
890
  return;
794
891
  }
795
892
  const ownership = await generatedRuntimePackageOwnership(packageRoot);
@@ -810,50 +907,12 @@ async function writeNodeStandardModules(outputRoot, project, replaceExisting = f
810
907
  await rename(staging, packageRoot);
811
908
  if (used.has("velar/websocket"))
812
909
  await writeWebSocketDependency(dirname(packageRoot));
813
- await writeAdapterDependencies(dirname(packageRoot), used);
814
910
  }
815
911
  catch (error) {
816
912
  await rm(staging, { recursive: true, force: true });
817
913
  throw error;
818
914
  }
819
915
  }
820
- async function writeWebSocketDependency(nodeModulesRoot) {
821
- const target = join(nodeModulesRoot, "ws");
822
- try {
823
- const manifest = JSON.parse(await readFile(join(target, "package.json"), "utf8"));
824
- if (manifest.name !== "ws" || manifest.version !== "8.21.1")
825
- throw new Error(`Refusing to use incompatible WebSocket runtime package '${target}'`);
826
- return;
827
- }
828
- catch (error) {
829
- if (!isHostErrorCode(error, "ENOENT"))
830
- throw error;
831
- }
832
- const require = createRequire(import.meta.url);
833
- const source = dirname(require.resolve("ws/package.json"));
834
- await cp(source, target, { recursive: true, errorOnExist: true });
835
- }
836
- async function writeAdapterDependencies(nodeModulesRoot, used) {
837
- const require = createRequire(import.meta.url);
838
- for (const [moduleName, dependency] of STANDARD_MODULE_ADAPTER_DEPENDENCIES) {
839
- if (!used.has(moduleName))
840
- continue;
841
- const target = join(nodeModulesRoot, dependency.packageName);
842
- try {
843
- const manifest = JSON.parse(await readFile(join(target, "package.json"), "utf8"));
844
- if (manifest.name !== dependency.packageName || manifest.version !== dependency.version) {
845
- throw new Error(`Refusing to use incompatible ${moduleName} runtime package '${target}'`);
846
- }
847
- continue;
848
- }
849
- catch (error) {
850
- if (!isHostErrorCode(error, "ENOENT"))
851
- throw error;
852
- }
853
- const source = await resolveInstalledPackageRoot(dependency.packageName, dependency.packageName, require);
854
- await cp(source, target, { recursive: true, errorOnExist: true });
855
- }
856
- }
857
916
  function requiredNodeStandardModules(project) {
858
917
  const sources = standardModuleSources(project.compilerExtensions);
859
918
  const roots = new Set(project.modules.flatMap((module) => module.result.dependencies
@@ -1018,13 +1077,17 @@ function parseFormatArguments(arguments_) {
1018
1077
  }
1019
1078
  return { input, check };
1020
1079
  }
1021
- function parseCommandArguments(arguments_) {
1080
+ function parseCommandArguments(arguments_, allowForce = false) {
1022
1081
  let input = null;
1023
1082
  let output = null;
1024
1083
  let outputDirectory = null;
1084
+ let force = false;
1025
1085
  for (let index = 0; index < arguments_.length; index += 1) {
1026
1086
  const argument = arguments_[index];
1027
- if (argument === "--out" || argument === "--out-dir") {
1087
+ if (allowForce && argument === "--force") {
1088
+ force = true;
1089
+ }
1090
+ else if (argument === "--out" || argument === "--out-dir") {
1028
1091
  const value = arguments_[index + 1];
1029
1092
  if (!value || value.startsWith("--")) {
1030
1093
  return `${argument} requires a path`;
@@ -1049,7 +1112,7 @@ function parseCommandArguments(arguments_) {
1049
1112
  input = argument;
1050
1113
  }
1051
1114
  }
1052
- return { input, output, outputDirectory };
1115
+ return { input, output, outputDirectory, force };
1053
1116
  }
1054
1117
  function parseReproArguments(arguments_) {
1055
1118
  let input = null;
@@ -1089,7 +1152,7 @@ function parsePackageArguments(arguments_) {
1089
1152
  return `unexpected extra input '${arguments_[1]}'`;
1090
1153
  if (arguments_[0]?.startsWith("-"))
1091
1154
  return `unknown option '${arguments_[0]}'`;
1092
- return { input: arguments_[0] ?? null, output: null, outputDirectory: null };
1155
+ return { input: arguments_[0] ?? null, output: null, outputDirectory: null, force: false };
1093
1156
  }
1094
1157
  function parseDevArguments(arguments_) {
1095
1158
  let input = null;
@@ -1304,7 +1367,7 @@ function printHelp(output = process.stdout) {
1304
1367
  " velar update [package...]",
1305
1368
  " velar dev [entry.vel | project-directory] [--port <port>]",
1306
1369
  " velar serve [project-directory] [--host <host>] [--port <port>]",
1307
- " velar build [entry.vel | project-directory] [--out-dir <directory>]",
1370
+ " velar build [entry.vel | project-directory] [--out-dir <directory>] [--force]",
1308
1371
  " velar run [entry.vel | project-directory] [--stack] [-- <program-arguments>...]",
1309
1372
  " velar verify [project-directory | build-directory]",
1310
1373
  " velar preview [project-directory | build-directory] [--port <port>]",
@@ -1336,7 +1399,7 @@ function printCommandHelp(command, output = process.stdout) {
1336
1399
  update: ["Usage: velar update [package...]", "Updates all or selected direct dependencies within package.json ranges through npm."],
1337
1400
  dev: ["Usage: velar dev [entry.vel | project-directory] [--port <1-65535>]", "Watches a framework app or last-good Node ServeApp; Web defaults to 5173 and Node reads node.port."],
1338
1401
  serve: ["Usage: velar serve [project-directory] [--host <host>] [--port <1-65535>]", "Checks and runs a Node ServeApp with production runtime behavior; node.host and node.port provide the defaults."],
1339
- build: ["Usage: velar build [entry.vel | project-directory] [--out-dir <directory>]", " velar build <single.vel> --out <file.js>", "Builds isolated Web/Desktop output, a standalone Node application, or JavaScript modules."],
1402
+ build: ["Usage: velar build [entry.vel | project-directory] [--out-dir <directory>] [--force]", " velar build <single.vel> --out <file.js>", "Builds isolated Web/Desktop output, a standalone Node application, or JavaScript modules.", "--out-dir refuses a directory that is not empty and was not produced by a previous build; --force replaces one anyway."],
1340
1403
  package: ["Usage: velar package [project-directory]", "Packages an application through its target-owned native packaging host."],
1341
1404
  run: ["Usage: velar run [entry.vel | project-directory] [--stack] [-- <program-arguments>...]", "Compiles the resolved Core project and executes its entry module once on Node.js; arguments after '--' reach the program.", "--stack prints the full Node.js trace behind an uncaught program error instead of the VelarScript frames."],
1342
1405
  verify: ["Usage: velar verify [project-directory | build-directory]", "Verifies the exact production manifest, inventory, sizes, hashes, and relationships."],