@pumpkin-plugins/build 0.1.0 → 0.1.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.
Files changed (2) hide show
  1. package/dist/cli.js +150 -98
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/cli.ts
4
4
  import * as fs9 from "node:fs";
5
- import { createRequire as createRequire3 } from "node:module";
5
+ import { createRequire as createRequire4 } from "node:module";
6
6
  import * as os from "node:os";
7
7
  import * as path9 from "node:path";
8
8
  import { fileURLToPath } from "node:url";
@@ -12,9 +12,9 @@ import { CommanderError } from "commander";
12
12
 
13
13
  // src/bundle.ts
14
14
  import { execFileSync as execFileSync2 } from "node:child_process";
15
- import * as fs3 from "node:fs";
15
+ import * as fs4 from "node:fs";
16
16
  import { createRequire as createRequire2 } from "node:module";
17
- import * as path3 from "node:path";
17
+ import * as path4 from "node:path";
18
18
  import { buildStaticHermesComponent, staticHermesImportsPlugin } from "@pumpkin-plugins/static-hermes-runtime";
19
19
  import * as esbuild from "esbuild";
20
20
 
@@ -40,22 +40,35 @@ function errorMessage(error) {
40
40
  return error instanceof Error ? error.message : String(error);
41
41
  }
42
42
 
43
+ // src/repo.ts
44
+ import * as fs from "node:fs";
45
+ import * as path from "node:path";
46
+ function findRepoRoot(from) {
47
+ for (let dir = path.resolve(from); ; dir = path.dirname(dir)) {
48
+ if (fs.existsSync(path.join(dir, "pnpm-workspace.yaml"))) return dir;
49
+ if (path.dirname(dir) === dir) return path.resolve(from);
50
+ }
51
+ }
52
+ function cacheDir(from) {
53
+ return process.env.PUMPKIN_PLUGINS_CACHE_DIR || path.join(findRepoRoot(from), ".cache");
54
+ }
55
+
43
56
  // src/types.ts
44
57
  import { execFileSync } from "node:child_process";
45
- import * as fs from "node:fs";
58
+ import * as fs2 from "node:fs";
46
59
  import { createRequire } from "node:module";
47
- import * as path from "node:path";
60
+ import * as path2 from "node:path";
48
61
  var require2 = createRequire(import.meta.url);
49
62
  function generateTypes(witDir, outDir) {
50
63
  const jco = resolveJcoCli();
51
- const output = path.resolve(outDir);
52
- const parent = path.dirname(output);
53
- fs.mkdirSync(parent, { recursive: true });
54
- const temporary = fs.mkdtempSync(path.join(parent, `.${path.basename(output)}-`));
55
- const generated = path.join(temporary, "generated");
64
+ const output = path2.resolve(outDir);
65
+ const parent = path2.dirname(output);
66
+ fs2.mkdirSync(parent, { recursive: true });
67
+ const temporary = fs2.mkdtempSync(path2.join(parent, `.${path2.basename(output)}-`));
68
+ const generated = path2.join(temporary, "generated");
56
69
  let preserveTemporary = false;
57
70
  try {
58
- fs.mkdirSync(generated);
71
+ fs2.mkdirSync(generated);
59
72
  execFileSync(
60
73
  process.execPath,
61
74
  [jco, "guest-types", witDir, "-n", "plugin", "-o", generated, "--name", "index", "--quiet"],
@@ -67,7 +80,7 @@ function generateTypes(witDir, outDir) {
67
80
  preserveTemporary = true;
68
81
  });
69
82
  } finally {
70
- if (!preserveTemporary) fs.rmSync(temporary, { recursive: true, force: true });
83
+ if (!preserveTemporary) fs2.rmSync(temporary, { recursive: true, force: true });
71
84
  }
72
85
  }
73
86
  function resolveJcoCli() {
@@ -77,37 +90,37 @@ function resolveJcoCli() {
77
90
  } catch {
78
91
  throw new Error("@bytecodealliance/jco is missing from @pumpkin-plugins/build dependencies");
79
92
  }
80
- for (let directory = path.dirname(entry); ; directory = path.dirname(directory)) {
81
- const packagePath = path.join(directory, "package.json");
82
- if (fs.existsSync(packagePath)) {
83
- const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
93
+ for (let directory = path2.dirname(entry); ; directory = path2.dirname(directory)) {
94
+ const packagePath = path2.join(directory, "package.json");
95
+ if (fs2.existsSync(packagePath)) {
96
+ const packageJson = JSON.parse(fs2.readFileSync(packagePath, "utf8"));
84
97
  if (packageJson.name === "@bytecodealliance/jco") {
85
98
  const command = typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin?.jco;
86
99
  if (!command) throw new Error("@bytecodealliance/jco package metadata does not declare its jco binary");
87
- const binaryPath = path.resolve(directory, command);
88
- if (!fs.existsSync(binaryPath))
100
+ const binaryPath = path2.resolve(directory, command);
101
+ if (!fs2.existsSync(binaryPath))
89
102
  throw new Error(`jco binary is missing from its package: ${binaryPath}`);
90
103
  return binaryPath;
91
104
  }
92
105
  }
93
- const parent = path.dirname(directory);
106
+ const parent = path2.dirname(directory);
94
107
  if (parent === directory) break;
95
108
  }
96
109
  throw new Error(`could not locate @bytecodealliance/jco package metadata from ${entry}`);
97
110
  }
98
111
  function publishTypes(generated, output, temporary, preserveForRecovery) {
99
- if (!fs.existsSync(output)) {
100
- fs.renameSync(generated, output);
112
+ if (!fs2.existsSync(output)) {
113
+ fs2.renameSync(generated, output);
101
114
  return;
102
115
  }
103
- if (!fs.statSync(output).isDirectory()) throw new Error(`type output is not a directory: ${output}`);
104
- const previous = path.join(temporary, "previous");
105
- fs.renameSync(output, previous);
116
+ if (!fs2.statSync(output).isDirectory()) throw new Error(`type output is not a directory: ${output}`);
117
+ const previous = path2.join(temporary, "previous");
118
+ fs2.renameSync(output, previous);
106
119
  try {
107
- fs.renameSync(generated, output);
120
+ fs2.renameSync(generated, output);
108
121
  } catch (publishError) {
109
122
  try {
110
- fs.renameSync(previous, output);
123
+ fs2.renameSync(previous, output);
111
124
  } catch (restoreError) {
112
125
  preserveForRecovery();
113
126
  throw new AggregateError(
@@ -120,24 +133,38 @@ function publishTypes(generated, output, temporary, preserveForRecovery) {
120
133
  }
121
134
 
122
135
  // src/wit-method-usage.ts
123
- import * as fs2 from "node:fs";
124
- import * as path2 from "node:path";
136
+ import * as fs3 from "node:fs";
137
+ import * as path3 from "node:path";
125
138
  import * as ts from "typescript";
126
139
  function findUsedWitMethods(entry, additionalTypesDir) {
127
- const absoluteEntry = path2.resolve(entry);
128
- if (!fs2.existsSync(absoluteEntry)) return void 0;
129
- const configPath = ts.findConfigFile(path2.dirname(absoluteEntry), ts.sys.fileExists, "tsconfig.json");
130
- if (!configPath) return void 0;
131
- const config = ts.readConfigFile(configPath, ts.sys.readFile);
132
- if (config.error) throw new Error(ts.flattenDiagnosticMessageText(config.error.messageText, "\n"));
133
- const parsed = ts.parseJsonConfigFileContent(config.config, ts.sys, path2.dirname(configPath));
140
+ const absoluteEntry = path3.resolve(entry);
141
+ if (!fs3.existsSync(absoluteEntry)) return void 0;
142
+ const configPath = ts.findConfigFile(path3.dirname(absoluteEntry), ts.sys.fileExists, "tsconfig.json");
143
+ let parsed;
144
+ if (configPath) {
145
+ const config = ts.readConfigFile(configPath, ts.sys.readFile);
146
+ if (config.error) throw new Error(ts.flattenDiagnosticMessageText(config.error.messageText, "\n"));
147
+ parsed = ts.parseJsonConfigFileContent(config.config, ts.sys, path3.dirname(configPath));
148
+ } else {
149
+ parsed = ts.parseJsonConfigFileContent({}, ts.sys, path3.dirname(absoluteEntry));
150
+ }
134
151
  if (parsed.errors.length) {
135
152
  throw new Error(
136
153
  parsed.errors.map((error) => ts.flattenDiagnosticMessageText(error.messageText, "\n")).join("\n")
137
154
  );
138
155
  }
139
156
  const additionalTypeFiles = additionalTypesDir ? ts.sys.readDirectory(additionalTypesDir, [".d.ts"], void 0, ["**/*.d.ts"]) : [];
140
- const options = { ...parsed.options, allowJs: true, maxNodeModuleJsDepth: 100 };
157
+ const options = {
158
+ ...configPath ? {} : {
159
+ target: ts.ScriptTarget.ES2022,
160
+ module: ts.ModuleKind.ESNext,
161
+ moduleResolution: ts.ModuleResolutionKind.Bundler,
162
+ strict: true
163
+ },
164
+ ...parsed.options,
165
+ allowJs: true,
166
+ maxNodeModuleJsDepth: 100
167
+ };
141
168
  const implementationFiles = /* @__PURE__ */ new Set();
142
169
  const runtimeHost = {
143
170
  ...ts.sys,
@@ -577,22 +604,24 @@ function toWitName(name) {
577
604
 
578
605
  // src/bundle.ts
579
606
  var require3 = createRequire2(import.meta.url);
607
+ var buildPackageJsonPath = require3.resolve("../package.json");
608
+ var buildPackageRepositoryUrl = packageRepositoryUrl(require3(buildPackageJsonPath));
580
609
  var MAX_PRODUCTION_COMPONENT_BYTES = 5 * 1024 * 1024;
581
610
  var TEMPORARY_DIRECTORY_PREFIX = ".pumpkin-build-";
582
611
  var LEGACY_TEMPORARY_DIRECTORY_MAX_AGE_MS = 60 * 60 * 1e3;
583
612
  var activeTemporaryDirectories = /* @__PURE__ */ new Set();
584
613
  async function bundlePlugin(options) {
585
- const output = path3.resolve(options.output);
586
- const outputDir = path3.dirname(output);
587
- fs3.mkdirSync(outputDir, { recursive: true });
614
+ const output = path4.resolve(options.output);
615
+ const outputDir = path4.dirname(output);
616
+ fs4.mkdirSync(outputDir, { recursive: true });
588
617
  removeAbandonedTemporaryDirectories(outputDir);
589
- const temporaryDir = fs3.mkdtempSync(path3.join(outputDir, `${TEMPORARY_DIRECTORY_PREFIX}${process.pid}-`));
618
+ const temporaryDir = fs4.mkdtempSync(path4.join(outputDir, `${TEMPORARY_DIRECTORY_PREFIX}${process.pid}-`));
590
619
  activeTemporaryDirectories.add(temporaryDir);
591
- const bundle = path3.join(temporaryDir, "bundle.js");
592
- const component = path3.join(temporaryDir, "plugin.wasm");
620
+ const bundle = path4.join(temporaryDir, "bundle.js");
621
+ const component = path4.join(temporaryDir, "plugin.wasm");
593
622
  const engine = options.engine ?? "static-hermes";
594
623
  const quietRuntimeOutput = options.quietRuntimeOutput ?? false;
595
- const projectRoot = path3.resolve(options.projectRoot ?? process.cwd());
624
+ const projectRoot = path4.resolve(options.projectRoot ?? process.cwd());
596
625
  const resolvedWasiImports = /* @__PURE__ */ new Set();
597
626
  let preserveTemporaryDir = false;
598
627
  try {
@@ -606,7 +635,7 @@ async function bundlePlugin(options) {
606
635
  globalName: "__pumpkinPlugin",
607
636
  plugins: [
608
637
  staticHermesImportsPlugin({
609
- resolveDir: path3.dirname(path3.resolve(options.entry)),
638
+ resolveDir: path4.dirname(path4.resolve(options.entry)),
610
639
  workspaceRoot: projectRoot,
611
640
  witDir: options.witDir,
612
641
  developmentMode: options.developmentMode ?? false,
@@ -625,7 +654,7 @@ async function bundlePlugin(options) {
625
654
  }
626
655
  });
627
656
  if (engine === "static-hermes") {
628
- const source = fs3.readFileSync(bundle, "utf8");
657
+ const source = fs4.readFileSync(bundle, "utf8");
629
658
  const unsupportedWasiImports = staticHermesWasiImports(buildResult.metafile).filter(
630
659
  (specifier) => !resolvedWasiImports.has(specifier)
631
660
  );
@@ -634,8 +663,8 @@ async function bundlePlugin(options) {
634
663
  `Static Hermes JavaScript bundle imports WASI interface${unsupportedWasiImports.length === 1 ? "" : "s"} without a JSI adapter: ${unsupportedWasiImports.join(", ")}`
635
664
  );
636
665
  }
637
- fs3.writeFileSync(bundle, unwrapStaticHermesExports(source));
638
- const generatedTypes = path3.join(temporaryDir, "wit-types");
666
+ fs4.writeFileSync(bundle, unwrapStaticHermesExports(source));
667
+ const generatedTypes = path4.join(temporaryDir, "wit-types");
639
668
  generateTypes(options.witDir, generatedTypes);
640
669
  const usedWitMethods = findUsedWitMethods(options.entry, generatedTypes);
641
670
  options.onOutput?.({
@@ -678,13 +707,13 @@ async function bundlePlugin(options) {
678
707
  throw runtimeBuildError("Static Hermes", error);
679
708
  }
680
709
  } else {
681
- const componentizerPackage = path3.dirname(require3.resolve("@di-framework/componentize-qjs/package.json"));
710
+ const componentizerPackage = path4.dirname(require3.resolve("@di-framework/componentize-qjs/package.json"));
682
711
  options.onOutput?.({ type: "componentize", engine });
683
712
  try {
684
713
  execFileSync2(
685
714
  process.execPath,
686
715
  [
687
- path3.join(componentizerPackage, "bin/componentize-qjs.cjs"),
716
+ path4.join(componentizerPackage, "bin/componentize-qjs.cjs"),
688
717
  "--world",
689
718
  "plugin",
690
719
  "--wit",
@@ -692,7 +721,7 @@ async function bundlePlugin(options) {
692
721
  "--js",
693
722
  bundle,
694
723
  "--runtime",
695
- path3.join(import.meta.dirname, "../runtime/quickjs-runtime-bigint.wasm"),
724
+ path4.join(import.meta.dirname, "../runtime/quickjs-runtime-bigint.wasm"),
696
725
  "--output",
697
726
  component
698
727
  ],
@@ -706,11 +735,11 @@ async function bundlePlugin(options) {
706
735
  throw runtimeBuildError("QuickJS", error);
707
736
  }
708
737
  }
709
- const size = fs3.statSync(component).size;
738
+ const size = fs4.statSync(component).size;
710
739
  if (!options.developmentMode && size > MAX_PRODUCTION_COMPONENT_BYTES) {
711
- throw new Error(
712
- `Production WebAssembly component is ${size} bytes; maximum is ${MAX_PRODUCTION_COMPONENT_BYTES} bytes (5 MiB)`
713
- );
740
+ const message = `Production WebAssembly component is ${size} bytes; maximum is ${MAX_PRODUCTION_COMPONENT_BYTES} bytes (5 MiB)`;
741
+ if (isRepositoryProject(projectRoot)) throw new Error(message);
742
+ options.onOutput?.({ type: "warning", message });
714
743
  }
715
744
  publishComponent(component, output, temporaryDir, () => {
716
745
  preserveTemporaryDir = true;
@@ -718,25 +747,47 @@ async function bundlePlugin(options) {
718
747
  return size;
719
748
  } finally {
720
749
  activeTemporaryDirectories.delete(temporaryDir);
721
- if (!preserveTemporaryDir) fs3.rmSync(temporaryDir, { recursive: true, force: true });
750
+ if (!preserveTemporaryDir) fs4.rmSync(temporaryDir, { recursive: true, force: true });
751
+ }
752
+ }
753
+ function isRepositoryProject(projectRoot) {
754
+ if (buildPackageRepositoryUrl === void 0) return false;
755
+ let projectManifest;
756
+ try {
757
+ projectManifest = JSON.parse(fs4.readFileSync(path4.join(findRepoRoot(projectRoot), "package.json"), "utf8"));
758
+ } catch {
759
+ return false;
722
760
  }
761
+ const projectRepositoryUrl = packageRepositoryUrl(projectManifest);
762
+ return projectRepositoryUrl !== void 0 && normalizeRepositoryUrl(projectRepositoryUrl) === normalizeRepositoryUrl(buildPackageRepositoryUrl);
763
+ }
764
+ function packageRepositoryUrl(manifest) {
765
+ if (typeof manifest !== "object" || manifest === null || Array.isArray(manifest)) return void 0;
766
+ const repository = manifest.repository;
767
+ if (typeof repository === "string") return repository;
768
+ if (typeof repository !== "object" || repository === null || Array.isArray(repository)) return void 0;
769
+ const url = repository.url;
770
+ return typeof url === "string" ? url : void 0;
771
+ }
772
+ function normalizeRepositoryUrl(url) {
773
+ return url.replace(/^git\+/, "").replace(/\.git$/, "").replace(/\/$/, "");
723
774
  }
724
775
  function removeAbandonedTemporaryDirectories(outputDir) {
725
- for (const entry of fs3.readdirSync(outputDir, { withFileTypes: true })) {
776
+ for (const entry of fs4.readdirSync(outputDir, { withFileTypes: true })) {
726
777
  if (!entry.isDirectory() || !entry.name.startsWith(TEMPORARY_DIRECTORY_PREFIX)) continue;
727
- const temporaryDir = path3.join(outputDir, entry.name);
728
- if (activeTemporaryDirectories.has(temporaryDir) || fs3.existsSync(path3.join(temporaryDir, "previous.wasm"))) {
778
+ const temporaryDir = path4.join(outputDir, entry.name);
779
+ if (activeTemporaryDirectories.has(temporaryDir) || fs4.existsSync(path4.join(temporaryDir, "previous.wasm"))) {
729
780
  continue;
730
781
  }
731
782
  const owner = /^\.pumpkin-build-(\d+)-/.exec(entry.name);
732
783
  if (owner) {
733
784
  const pid = Number(owner[1]);
734
785
  if (pid !== process.pid && isProcessRunning(pid)) continue;
735
- fs3.rmSync(temporaryDir, { recursive: true, force: true });
786
+ fs4.rmSync(temporaryDir, { recursive: true, force: true });
736
787
  continue;
737
788
  }
738
- if (Date.now() - fs3.statSync(temporaryDir).mtimeMs >= LEGACY_TEMPORARY_DIRECTORY_MAX_AGE_MS) {
739
- fs3.rmSync(temporaryDir, { recursive: true, force: true });
789
+ if (Date.now() - fs4.statSync(temporaryDir).mtimeMs >= LEGACY_TEMPORARY_DIRECTORY_MAX_AGE_MS) {
790
+ fs4.rmSync(temporaryDir, { recursive: true, force: true });
740
791
  }
741
792
  }
742
793
  }
@@ -779,18 +830,18 @@ function isTrailingLicenseComment(source) {
779
830
  }
780
831
  function publishComponent(component, output, temporaryDir, preserveForRecovery) {
781
832
  try {
782
- fs3.renameSync(component, output);
833
+ fs4.renameSync(component, output);
783
834
  } catch (error) {
784
- if (!isReplaceError(error) || !fs3.existsSync(output)) throw error;
785
- const existing = fs3.lstatSync(output);
835
+ if (!isReplaceError(error) || !fs4.existsSync(output)) throw error;
836
+ const existing = fs4.lstatSync(output);
786
837
  if (!existing.isFile() && !existing.isSymbolicLink()) throw error;
787
- const previous = path3.join(temporaryDir, "previous.wasm");
788
- fs3.renameSync(output, previous);
838
+ const previous = path4.join(temporaryDir, "previous.wasm");
839
+ fs4.renameSync(output, previous);
789
840
  try {
790
- fs3.renameSync(component, output);
841
+ fs4.renameSync(component, output);
791
842
  } catch (publishError) {
792
843
  try {
793
- fs3.renameSync(previous, output);
844
+ fs4.renameSync(previous, output);
794
845
  } catch (restoreError) {
795
846
  preserveForRecovery();
796
847
  throw new AggregateError(
@@ -955,10 +1006,11 @@ addNamedFormatters(ansi, "ansi");
955
1006
 
956
1007
  // src/output.ts
957
1008
  function formatBuildOutput(message) {
958
- if (message.type === "error") {
1009
+ if (message.type === "error" || message.type === "warning") {
1010
+ const formatLine = message.type === "error" ? ansi.named.error : ansi.named.value;
959
1011
  return message.message.split(/\r?\n/).map((line, index) => {
960
- const prefix = index === 0 ? "Error: " : " ";
961
- return `[build] ${prefix}${ansi.named.error(line)}`;
1012
+ const prefix = index === 0 ? `${message.type === "error" ? "Error" : "Warning"}: ` : " ";
1013
+ return `[build] ${prefix}${formatLine(line)}`;
962
1014
  }).join("\n");
963
1015
  }
964
1016
  if (message.type === "built") {
@@ -982,6 +1034,7 @@ function formatBuildOutput(message) {
982
1034
  function printBuildOutput(message) {
983
1035
  const formatted = formatBuildOutput(message);
984
1036
  if (message.type === "error") console.error(formatted);
1037
+ else if (message.type === "warning") console.warn(formatted);
985
1038
  else console.log(formatted);
986
1039
  }
987
1040
  function runtimeLabel(engine, runtimeVariant, gcVariant, parseTypeScript) {
@@ -997,12 +1050,12 @@ function formatSelectionOption(option, selection, omittedValue) {
997
1050
  }
998
1051
 
999
1052
  // src/plugin-config.ts
1000
- import * as fs4 from "node:fs";
1001
- import * as path4 from "node:path";
1053
+ import * as fs5 from "node:fs";
1054
+ import * as path5 from "node:path";
1002
1055
  function readPluginConfig(pluginDir) {
1003
1056
  let pkg;
1004
1057
  try {
1005
- pkg = JSON.parse(fs4.readFileSync(path4.join(pluginDir, "package.json"), "utf8"));
1058
+ pkg = JSON.parse(fs5.readFileSync(path5.join(pluginDir, "package.json"), "utf8"));
1006
1059
  } catch (error) {
1007
1060
  if (error instanceof SyntaxError) throw new BuildError(`package.json is not valid JSON (${error.message})`);
1008
1061
  if (typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR")) {
@@ -1077,11 +1130,11 @@ function optionalRelativePath(value, name) {
1077
1130
  }
1078
1131
  function requiredRelativePath(value, name) {
1079
1132
  if (typeof value !== "string") throw new BuildError(`"pumpkinPlugin.${name}" must be a relative path`);
1080
- const normalized = path4.posix.normalize(value.replaceAll("\\", "/"));
1081
- if (value.length === 0 || value.includes("\0") || path4.isAbsolute(value) || path4.win32.isAbsolute(value) || path4.win32.parse(value).root !== "" || normalized === "." || normalized === ".." || normalized.startsWith("../")) {
1133
+ const normalized = path5.posix.normalize(value.replaceAll("\\", "/"));
1134
+ if (value.length === 0 || value.includes("\0") || path5.isAbsolute(value) || path5.win32.isAbsolute(value) || path5.win32.parse(value).root !== "" || normalized === "." || normalized === ".." || normalized.startsWith("../")) {
1082
1135
  throw new BuildError(`"pumpkinPlugin.${name}" must be a path inside the package`);
1083
1136
  }
1084
- if (name === "output" && path4.posix.extname(normalized).toLowerCase() !== ".wasm") {
1137
+ if (name === "output" && path5.posix.extname(normalized).toLowerCase() !== ".wasm") {
1085
1138
  throw new BuildError('"pumpkinPlugin.output" must name a .wasm file');
1086
1139
  }
1087
1140
  return normalized;
@@ -1090,22 +1143,13 @@ function isRecord(value) {
1090
1143
  return typeof value === "object" && value !== null && !Array.isArray(value);
1091
1144
  }
1092
1145
 
1093
- // src/repo.ts
1094
- import * as fs5 from "node:fs";
1095
- import * as path5 from "node:path";
1096
- function findRepoRoot(from) {
1097
- for (let dir = path5.resolve(from); ; dir = path5.dirname(dir)) {
1098
- if (fs5.existsSync(path5.join(dir, "pnpm-workspace.yaml"))) return dir;
1099
- if (path5.dirname(dir) === dir) return path5.resolve(from);
1100
- }
1101
- }
1102
- function cacheDir(from) {
1103
- return process.env.PUMPKIN_PLUGINS_CACHE_DIR || path5.join(findRepoRoot(from), ".cache");
1104
- }
1105
-
1106
1146
  // src/update-check.ts
1147
+ import { createRequire as createRequire3 } from "node:module";
1107
1148
  import { latestVersion, ONE_DAY } from "@badisi/latest-version";
1108
- var packageName = "@pumpkin-plugins/build";
1149
+ var packageMetadata = createRequire3(import.meta.url)("../package.json");
1150
+ var packageName = packageMetadata.name;
1151
+ var repositoryUrl = packageMetadata.repository.url.replace(/^git\+/, "").replace(/\.git$/, "");
1152
+ var releaseComponent = packageName.split("/").at(-1) ?? packageName;
1109
1153
  var requestTimeout = 5e3;
1110
1154
  function isBuildUpdateCheckAllowed(args, environment, isTTY) {
1111
1155
  return isTTY && !environment.CI && environment.PUMPKIN_DEV_MODE !== "1" && environment.PUMPKIN_PLUGINS_NO_UPDATE_NOTIFIER !== "1" && !args.some((argument) => ["--help", "-h", "--version", "-V", "--no-update-notifier"].includes(argument));
@@ -1130,14 +1174,22 @@ async function startBuildUpdateCheck(args, options) {
1130
1174
  }
1131
1175
  function formatBuildUpdateNotice(currentVersion, latestVersion2) {
1132
1176
  const content = [
1133
- `[build] Update available: ${packageName} ${currentVersion} \u2192 ${latestVersion2}.`,
1134
- "Review the migration with:",
1135
- " pnpm dlx @pumpkin-plugins/codemod update-build ."
1177
+ "",
1178
+ `Update available v${currentVersion} \u226B v${latestVersion2}`,
1179
+ `Changelog: ${new URL(`releases/tag/${releaseComponent}-v${latestVersion2}`, `${repositoryUrl}/`).href}`,
1180
+ 'Run "pnpm dlx @pumpkin-plugins/codemod update-build ." to update',
1181
+ "",
1182
+ "Follow Filiph Sandstr\xF6m for updates: https://x.com/filiphsandstrom",
1183
+ ""
1136
1184
  ];
1137
1185
  const contentWidth = Math.max(...content.map((line) => line.length));
1138
1186
  const border = "\u2500".repeat(contentWidth + 2);
1139
- const body = content.map((line) => `\u2502 ${line.padEnd(contentWidth)} \u2502`);
1140
- return [`\u250C${border}\u2510`, ...body, `\u2514${border}\u2518`, ""].join("\n");
1187
+ const body = content.map((line) => {
1188
+ const leftPadding = Math.floor((contentWidth - line.length) / 2);
1189
+ const centeredLine = `${" ".repeat(leftPadding)}${line}${" ".repeat(contentWidth - line.length - leftPadding)}`;
1190
+ return `\u2502 ${centeredLine} \u2502`;
1191
+ });
1192
+ return [`\u256D${border}\u256E`, ...body, `\u2570${border}\u256F`, ""].join("\n");
1141
1193
  }
1142
1194
 
1143
1195
  // src/wasi-wit.ts
@@ -1561,7 +1613,7 @@ function isInputOutputError(error) {
1561
1613
 
1562
1614
  // src/cli.ts
1563
1615
  async function run(args, pluginDir) {
1564
- const command = new Command().name("pumpkin-plugins-build").description("Build the Pumpkin plugin in the current directory.").version(createRequire3(import.meta.url)("../package.json").version).option("--types-only", "Generate guest declarations without building a component").option("--parse-ts", "Use Hermes TypeScript parsing for the component bundle").option("--no-update-notifier", "Skip the npm update check").configureOutput({ outputError: () => {
1616
+ const command = new Command().name("pumpkin-plugins-build").description("Build the Pumpkin plugin in the current directory.").version(createRequire4(import.meta.url)("../package.json").version).option("--types-only", "Generate guest declarations without building a component").option("--parse-ts", "Use Hermes TypeScript parsing for the component bundle").option("--no-update-notifier", "Skip the npm update check").configureOutput({ outputError: () => {
1565
1617
  } }).exitOverride();
1566
1618
  try {
1567
1619
  command.parse(args, { from: "user" });
@@ -1657,7 +1709,7 @@ async function executeCli(args, pluginDir, options = {}) {
1657
1709
  }
1658
1710
  await main(args, pluginDir);
1659
1711
  }
1660
- function resolveApiWit(pluginDir, resolvePackageJson = (root, packageSpecifier) => createRequire3(path9.join(root, "package.json")).resolve(packageSpecifier)) {
1712
+ function resolveApiWit(pluginDir, resolvePackageJson = (root, packageSpecifier) => createRequire4(path9.join(root, "package.json")).resolve(packageSpecifier)) {
1661
1713
  let packageJson;
1662
1714
  try {
1663
1715
  const canonicalSpecifier = "@pumpkin-plugins/pumpkin-api/package.json";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pumpkin-plugins/build",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Shared build tool for the plugins",
5
5
  "keywords": [
6
6
  "minecraft",
@@ -57,7 +57,7 @@
57
57
  "typescript": "6.0.3"
58
58
  },
59
59
  "devDependencies": {
60
- "@pumpkin-plugins/docs": "0.1.0",
60
+ "@pumpkin-plugins/docs": "0.1.2",
61
61
  "@types/node": "24.19.1",
62
62
  "@vitest/coverage-v8": "5.0.4",
63
63
  "vitest": "5.0.4"