spawnpack 0.1.10 → 0.1.11

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/dist/spawnpack.js CHANGED
@@ -1539,7 +1539,9 @@ import { join } from "node:path";
1539
1539
  var VERSIONS = {
1540
1540
  minEngineVersion: [1, 26, 0],
1541
1541
  manifestFormat: 2,
1542
- esbuildFilter: "0.3.0"
1542
+ rolldown: "^1.0.0-beta.56",
1543
+ esToolkit: "^1.43.0",
1544
+ jsoncParser: "^3.3.1"
1543
1545
  };
1544
1546
  var DEFAULT_MINECRAFT_DEPENDENCY_VERSIONS = {
1545
1547
  server: "2.6.0",
@@ -1744,7 +1746,7 @@ function generatePackageJson(config, versions) {
1744
1746
  if (!config.useRgl) {
1745
1747
  scripts.build = "tsc --project tsconfig.json";
1746
1748
  }
1747
- scripts.typecheck = "tsc --project tsconfig.json --noEmit";
1749
+ scripts.typecheck = config.useRgl ? "tsc --project data/scripts/tsconfig.json --noEmit" : "tsc --project tsconfig.json --noEmit";
1748
1750
  scripts.format = "dprint fmt";
1749
1751
  }
1750
1752
  if (config.scripting === "javascript") {
@@ -1754,6 +1756,7 @@ function generatePackageJson(config, versions) {
1754
1756
  name: `${config.identifier}-${config.projectId}`,
1755
1757
  version: PACK_VERSION2,
1756
1758
  private: true,
1759
+ ...config.useRgl ? { workspaces: ["./filters/*"] } : {},
1757
1760
  type: "module",
1758
1761
  scripts,
1759
1762
  dependencies: getSelectedScriptDependencies(config, versions)
@@ -1815,7 +1818,7 @@ function generateDprintConfig() {
1815
1818
  }
1816
1819
  function generateRglConfig(config) {
1817
1820
  return {
1818
- $schema: "https://raw.githubusercontent.com/ink0rr/rgl-schemas/main/config/v1.0.json",
1821
+ $schema: "https://raw.githubusercontent.com/ink0rr/rgl-schemas/main/config/v1.1.json",
1819
1822
  author: config.author,
1820
1823
  name: config.projectName,
1821
1824
  packs: {
@@ -1825,41 +1828,93 @@ function generateRglConfig(config) {
1825
1828
  regolith: {
1826
1829
  dataPath: "./data",
1827
1830
  filterDefinitions: {
1828
- esbuild: {
1829
- url: "github.com/ink0rr/regolith-filters",
1830
- version: VERSIONS.esbuildFilter
1831
+ typegen: {
1832
+ runWith: "nodejs",
1833
+ script: "./filters/typegen/main.js"
1834
+ },
1835
+ rolldown: {
1836
+ runWith: "nodejs",
1837
+ script: "./filters/rolldown/main.js"
1831
1838
  }
1832
1839
  },
1833
1840
  profiles: {
1834
1841
  default: {
1835
1842
  export: { target: "development" },
1836
1843
  filters: [
1837
- {
1838
- filter: "esbuild",
1839
- settings: {
1840
- outfile: `./BP/${getScriptEntryPath(config)}`,
1841
- sourcemap: true,
1842
- minify: false
1843
- }
1844
- }
1844
+ { filter: "typegen" },
1845
+ { filter: "rolldown" }
1845
1846
  ]
1846
1847
  },
1847
1848
  build: {
1848
1849
  export: { target: "local" },
1849
1850
  filters: [
1850
- {
1851
- filter: "esbuild",
1852
- settings: {
1853
- outfile: `./BP/${getScriptEntryPath(config)}`,
1854
- minify: true
1855
- }
1856
- }
1851
+ { filter: "typegen" },
1852
+ { filter: "rolldown", arguments: ["--prod"] }
1853
+ ]
1854
+ },
1855
+ preview: {
1856
+ export: { target: "development" },
1857
+ filters: [
1858
+ { profile: "build" }
1857
1859
  ]
1858
1860
  }
1859
1861
  }
1860
1862
  }
1861
1863
  };
1862
1864
  }
1865
+ function getRolldownExternalModules(config) {
1866
+ return ["@minecraft/server", ...config.scriptPackages.serverUi ? ["@minecraft/server-ui"] : []];
1867
+ }
1868
+ function generateRolldownFilterMain(config) {
1869
+ const external = getRolldownExternalModules(config).map((moduleName) => JSON.stringify(moduleName)).join(", ");
1870
+ const outfile = `./BP/${getScriptEntryPath(config)}`;
1871
+ return `import { build, defineConfig } from "rolldown";
1872
+
1873
+ const arg = process.argv[2];
1874
+
1875
+ const config = defineConfig({
1876
+ external: [${external}],
1877
+ input: "./data/scripts/main.ts",
1878
+ output: {
1879
+ format: "esm",
1880
+ file: ${JSON.stringify(outfile)},
1881
+ sourcemap: true,
1882
+ },
1883
+ tsconfig: "./data/scripts/tsconfig.json",
1884
+ });
1885
+
1886
+ if (arg === "--prod") {
1887
+ config.output.minify = true;
1888
+ config.output.sourcemap = false;
1889
+ config.transform = {
1890
+ dropLabels: ["DEBUG"],
1891
+ };
1892
+ }
1893
+
1894
+ await build(config);
1895
+ `;
1896
+ }
1897
+ function generateRolldownFilterPackageJson() {
1898
+ return {
1899
+ name: "rolldown-filter",
1900
+ private: true,
1901
+ type: "module",
1902
+ dependencies: {
1903
+ rolldown: VERSIONS.rolldown
1904
+ }
1905
+ };
1906
+ }
1907
+ function generateTypegenFilterPackageJson() {
1908
+ return {
1909
+ name: "typegen",
1910
+ private: true,
1911
+ type: "module",
1912
+ dependencies: {
1913
+ "es-toolkit": VERSIONS.esToolkit,
1914
+ "jsonc-parser": VERSIONS.jsoncParser
1915
+ }
1916
+ };
1917
+ }
1863
1918
  function generateMainTs(config) {
1864
1919
  return `import { world } from "@minecraft/server";
1865
1920
 
@@ -1882,11 +1937,74 @@ function generateLangFile(projectName, packType) {
1882
1937
  pack.description=Generated with Spawnpack
1883
1938
  `;
1884
1939
  }
1885
- function generateGitignore() {
1886
- return `node_modules/
1887
- dist/
1888
- .logs/
1889
- *.zip
1940
+ function generateScriptsTsConfig() {
1941
+ return {
1942
+ compilerOptions: {
1943
+ lib: [
1944
+ "ES2015",
1945
+ "ES2016.Array.Include",
1946
+ "ES2017.ArrayBuffer",
1947
+ "ES2017.Date",
1948
+ "ES2017.Object",
1949
+ "ES2017.String",
1950
+ "ES2017.TypedArrays",
1951
+ "ES2018.AsyncIterable",
1952
+ "ES2018.AsyncGenerator",
1953
+ "ES2018.Promise",
1954
+ "ES2018.Regexp",
1955
+ "ES2019.Array",
1956
+ "ES2019.Object",
1957
+ "ES2019.String",
1958
+ "ES2019.Symbol",
1959
+ "ES2020.BigInt",
1960
+ "ES2020.Date",
1961
+ "ES2020.Number",
1962
+ "ES2015.Promise",
1963
+ "ES2020.String",
1964
+ "ES2020.Promise",
1965
+ "ES2020.Symbol.WellKnown",
1966
+ "ES2021.Promise",
1967
+ "ES2021.String",
1968
+ "ES2022.Array",
1969
+ "ES2022.Error",
1970
+ "ES2022.Object",
1971
+ "ES2022.RegExp",
1972
+ "ES2022.String",
1973
+ "ES2023.Array",
1974
+ "ES2023.Collection",
1975
+ "ES2024.ArrayBuffer",
1976
+ "ES2024.Collection",
1977
+ "ES2024.Object",
1978
+ "ES2024.Promise",
1979
+ "ES2024.Regexp",
1980
+ "ES2024.String"
1981
+ ],
1982
+ target: "es2024",
1983
+ module: "es2022",
1984
+ moduleDetection: "force",
1985
+ allowJs: true,
1986
+ moduleResolution: "bundler",
1987
+ noEmit: true,
1988
+ strict: true,
1989
+ skipLibCheck: true,
1990
+ noFallthroughCasesInSwitch: true,
1991
+ noImplicitOverride: true,
1992
+ noUnusedLocals: true,
1993
+ noUnusedParameters: true,
1994
+ paths: { "~/*": ["./*"] }
1995
+ }
1996
+ };
1997
+ }
1998
+ function generateGitignore(config) {
1999
+ const lines = ["node_modules/", "dist/", ".logs/", "*.zip"];
2000
+ if (config.useRgl) {
2001
+ lines.push("/.regolith", "/build");
2002
+ }
2003
+ if (config.useRgl && config.scripting === "typescript") {
2004
+ lines.push("data/scripts/generated_types.ts");
2005
+ }
2006
+ return `${lines.join(`
2007
+ `)}
1890
2008
  `;
1891
2009
  }
1892
2010
  function generateReadme(config) {
@@ -1895,13 +2013,14 @@ function generateReadme(config) {
1895
2013
  const installStep = config.scripting !== "none" ? "1. Install dependencies with `bun install` or `npm install`." : "1. No package install is required for this scaffold.";
1896
2014
  const buildSteps = config.scripting === "none" ? "2. Edit your BP/RP JSON files directly inside `packs/`." : config.useRgl ? "2. Run `rgl watch` while developing to rebuild and export your add-on automatically.\n3. Run `rgl run build` when you want a production build." : config.scripting === "typescript" ? "2. Write your gameplay scripts in `data/scripts/`.\n3. Run `bun run build` or `npm run build` to compile TypeScript into `packs/BP/scripts/`." : "2. Write your gameplay scripts in `packs/BP/scripts/` and let Minecraft copy the pack into `com.mojang`.";
1897
2015
  const aiDocFilename = getAiDocFilename(config.aiSetup);
2016
+ const ponytailAiLine = config.installPonytail ? config.aiSetup === "other" ? "Ponytail is enabled via `opencode.json`.\n\n" : "To enable ponytail in Claude Code, run `/plugin marketplace add DietrichGebert/ponytail` then `/plugin install ponytail@ponytail`.\n\n" : "";
1898
2017
  const aiSection = aiDocFilename !== null ? `## AI Tooling
1899
2018
 
1900
2019
  Spawnpack generated \`${aiDocFilename}\` and \`.mcp.json\` for AI-assisted development. The configured MCP servers work out of the box — no API keys required.
1901
2020
 
1902
2021
  Exa's hosted MCP runs on a rate-limited free tier. If you need higher limits, you can add your own Exa API key to \`.mcp.json\` (optional): https://dashboard.exa.ai/api-keys
1903
2022
 
1904
- ` : "";
2023
+ ${ponytailAiLine}` : "";
1905
2024
  const scriptPackageSection = config.scripting !== "none" ? `## Script Packages
1906
2025
 
1907
2026
  Selected npm packages are installed through \`package.json\`. Only runtime Script API modules such as \`@minecraft/server\` and \`@minecraft/server-ui\` are written to \`packs/BP/manifest.json\`; npm-side libraries such as \`@minecraft/vanilla-data\` and \`@minecraft/math\` are imported and bundled from \`package.json\`.
@@ -1935,6 +2054,7 @@ ${scriptPackageSection}${config.useRgl ? `## rgl Workflow
1935
2054
  - \`rgl watch\` rebuilds your scripts and exports your add-on while you work.
1936
2055
  - \`rgl run\` builds a development export once.
1937
2056
  - \`rgl run build\` creates a production-ready build.
2057
+ - \`typegen\` auto-generates typed custom IDs (\`BlockId\`/\`EntityId\`/\`ItemId\`) into \`data/scripts/generated_types.ts\` on each build.
1938
2058
 
1939
2059
  The generated \`config.json\` already points the script bundle to \`${runtimeEntry}\`.
1940
2060
 
@@ -1970,6 +2090,10 @@ function generateTerrainTexture(config) {
1970
2090
  }
1971
2091
 
1972
2092
  // src/engine/generator.ts
2093
+ var TYPEGEN_FILTER_TEMPLATE_URLS = [
2094
+ new URL("../../templates/filters/typegen/main.js", import.meta.url),
2095
+ new URL("../templates/filters/typegen/main.js", import.meta.url)
2096
+ ];
1973
2097
  var BP_NAMESPACED_DIRECTORIES = [
1974
2098
  "animation_controllers",
1975
2099
  "animations",
@@ -2009,6 +2133,16 @@ async function writeJsonFile(filePath, value) {
2009
2133
  async function writeTextFile(filePath, value) {
2010
2134
  await writeFile(filePath, value, "utf8");
2011
2135
  }
2136
+ async function createTypegenFilterMain() {
2137
+ for (const templateUrl of TYPEGEN_FILTER_TEMPLATE_URLS) {
2138
+ const templateFile = Bun.file(templateUrl);
2139
+ const exists = await templateFile.exists().then((value) => value, () => false);
2140
+ if (exists) {
2141
+ return await templateFile.text();
2142
+ }
2143
+ }
2144
+ return await Bun.file(TYPEGEN_FILTER_TEMPLATE_URLS[0]).text();
2145
+ }
2012
2146
  function getScopedContentDirectory(basePath, folder, config) {
2013
2147
  return join(basePath, folder, ...getMarketplaceScopeSegments(config));
2014
2148
  }
@@ -2069,6 +2203,9 @@ async function generateProject(config) {
2069
2203
  directories.push(join(bpPath, "scripts"), join(bpPath, "scripts", config.identifier), bpScriptPath);
2070
2204
  }
2071
2205
  }
2206
+ if (config.useRgl && config.scripting !== "none") {
2207
+ directories.push(join(destination, "filters"), join(destination, "filters", "rolldown"), join(destination, "filters", "typegen"));
2208
+ }
2072
2209
  await Promise.all(directories.filter(shouldCreateDirectory).map((directory) => mkdir(directory, { recursive: true })));
2073
2210
  const bpUuid = crypto.randomUUID();
2074
2211
  const rpUuid = crypto.randomUUID();
@@ -2086,7 +2223,7 @@ async function generateProject(config) {
2086
2223
  writeTextFile(join(rpPath, "textures", "flipbook_textures.json"), "[]"),
2087
2224
  writeTextFile(join(bpPath, "texts", "languages.json"), '["en_US"]'),
2088
2225
  writeTextFile(join(rpPath, "texts", "languages.json"), '["en_US"]'),
2089
- writeTextFile(join(destination, ".gitignore"), generateGitignore()),
2226
+ writeTextFile(join(destination, ".gitignore"), generateGitignore(config)),
2090
2227
  writeTextFile(join(destination, "README.md"), generateReadme(config))
2091
2228
  ];
2092
2229
  if (config.scripting !== "none") {
@@ -2096,10 +2233,11 @@ async function generateProject(config) {
2096
2233
  writes.push(writeTextFile(join(bpScriptPath, "main.js"), generateMainJs(config)));
2097
2234
  }
2098
2235
  if (config.scripting === "typescript") {
2099
- writes.push(writeJsonFile(join(destination, "tsconfig.json"), generateTsConfig(config)), writeJsonFile(join(destination, "dprint.json"), generateDprintConfig()), writeTextFile(join(dataScriptsPath, "main.ts"), generateMainTs(config)));
2236
+ const tsconfigWrite = config.useRgl ? writeJsonFile(join(dataScriptsPath, "tsconfig.json"), generateScriptsTsConfig()) : writeJsonFile(join(destination, "tsconfig.json"), generateTsConfig(config));
2237
+ writes.push(tsconfigWrite, writeJsonFile(join(destination, "dprint.json"), generateDprintConfig()), writeTextFile(join(dataScriptsPath, "main.ts"), generateMainTs(config)));
2100
2238
  }
2101
2239
  if (config.scripting !== "none" && config.useRgl) {
2102
- writes.push(writeJsonFile(join(destination, "config.json"), generateRglConfig(config)));
2240
+ writes.push(writeJsonFile(join(destination, "config.json"), generateRglConfig(config)), writeTextFile(join(destination, "filters", "rolldown", "main.js"), generateRolldownFilterMain(config)), writeJsonFile(join(destination, "filters", "rolldown", "package.json"), generateRolldownFilterPackageJson()), writeJsonFile(join(destination, "filters", "typegen", "package.json"), generateTypegenFilterPackageJson()), writeTextFile(join(destination, "filters", "typegen", "main.js"), await createTypegenFilterMain()));
2103
2241
  }
2104
2242
  await Promise.all(writes);
2105
2243
  }
@@ -2142,6 +2280,7 @@ var AI_EXCLUDE_LINES = [
2142
2280
  "/CLAUDE.md",
2143
2281
  "/AGENTS.md",
2144
2282
  "/.mcp.json",
2283
+ "/opencode.json",
2145
2284
  "/.claude/"
2146
2285
  ];
2147
2286
  function getTemplateUrls(filename) {
@@ -2201,13 +2340,42 @@ async function setupGitExcludes(projectPath) {
2201
2340
  return;
2202
2341
  });
2203
2342
  }
2204
- async function setupAi(projectPath, aiSetup) {
2343
+ async function writeOpencodePluginConfig(projectPath) {
2344
+ const configPath = join3(projectPath, "opencode.json");
2345
+ const pluginId = "@dietrichgebert/ponytail";
2346
+ const file = Bun.file(configPath);
2347
+ const exists = await file.exists().then((value) => value, () => false);
2348
+ let nextConfig = {
2349
+ $schema: "https://opencode.ai/config.json",
2350
+ plugin: [pluginId]
2351
+ };
2352
+ if (exists) {
2353
+ try {
2354
+ const parsed = await file.json();
2355
+ const plugins = Array.isArray(parsed.plugin) ? [...parsed.plugin] : [];
2356
+ if (!plugins.includes(pluginId)) {
2357
+ plugins.push(pluginId);
2358
+ }
2359
+ nextConfig = { ...parsed, plugin: plugins };
2360
+ } catch {}
2361
+ }
2362
+ await Bun.write(configPath, `${JSON.stringify(nextConfig, null, 4)}
2363
+ `).then(() => {
2364
+ return;
2365
+ }, () => {
2366
+ return;
2367
+ });
2368
+ }
2369
+ async function setupAi(projectPath, aiSetup, installPonytail) {
2205
2370
  if (aiSetup === "none") {
2206
2371
  return;
2207
2372
  }
2208
2373
  await generateAiDoc(projectPath, aiSetup);
2209
2374
  await setupGitExcludes(projectPath);
2210
2375
  await generateMcpConfig(projectPath);
2376
+ if (installPonytail && aiSetup === "other") {
2377
+ await writeOpencodePluginConfig(projectPath);
2378
+ }
2211
2379
  }
2212
2380
 
2213
2381
  // src/provisioning/tools.ts
@@ -2405,8 +2573,20 @@ function showFolderTree(config) {
2405
2573
  lines.push(import_picocolors.default.dim("│ └─ manifest.json"));
2406
2574
  if (config.scripting === "typescript") {
2407
2575
  lines.push(import_picocolors.default.dim("├─ data/scripts/"));
2408
- lines.push(import_picocolors.default.dim("│ └─ main.ts"));
2409
- lines.push(import_picocolors.default.dim("├─ tsconfig.json"));
2576
+ if (config.useRgl) {
2577
+ lines.push(import_picocolors.default.dim("├─ main.ts"));
2578
+ lines.push(import_picocolors.default.dim("│ └─ tsconfig.json"));
2579
+ lines.push(import_picocolors.default.dim("├─ filters/"));
2580
+ lines.push(import_picocolors.default.dim("│ ├─ rolldown/"));
2581
+ lines.push(import_picocolors.default.dim("│ │ ├─ main.js"));
2582
+ lines.push(import_picocolors.default.dim("│ │ └─ package.json"));
2583
+ lines.push(import_picocolors.default.dim("│ └─ typegen/"));
2584
+ lines.push(import_picocolors.default.dim("│ ├─ main.js"));
2585
+ lines.push(import_picocolors.default.dim("│ └─ package.json"));
2586
+ } else {
2587
+ lines.push(import_picocolors.default.dim("│ └─ main.ts"));
2588
+ lines.push(import_picocolors.default.dim("├─ tsconfig.json"));
2589
+ }
2410
2590
  lines.push(import_picocolors.default.dim("├─ dprint.json"));
2411
2591
  }
2412
2592
  if (config.scripting === "javascript") {
@@ -2422,6 +2602,9 @@ function showFolderTree(config) {
2422
2602
  if (aiDocFilename !== null) {
2423
2603
  lines.push(import_picocolors.default.dim(`├─ ${aiDocFilename}`));
2424
2604
  lines.push(import_picocolors.default.dim("├─ .mcp.json"));
2605
+ if (config.installPonytail && config.aiSetup === "other") {
2606
+ lines.push(import_picocolors.default.dim("├─ opencode.json"));
2607
+ }
2425
2608
  }
2426
2609
  lines.push(import_picocolors.default.dim("├─ .gitignore"));
2427
2610
  lines.push(import_picocolors.default.dim("└─ README.md"));
@@ -2449,6 +2632,7 @@ function showReview(config) {
2449
2632
  `${border} ${import_picocolors.default.dim(padLabel("rgl:"))} ${formatToggle(config.useRgl)}`,
2450
2633
  `${border} ${import_picocolors.default.dim(padLabel("Rockide:"))} ${formatToggle(config.installRockide)}`,
2451
2634
  `${border} ${import_picocolors.default.dim(padLabel("AI Setup:"))} ${formatValue(getAiSetupLabel(config.aiSetup))}`,
2635
+ ...config.aiSetup !== "none" ? [`${border} ${import_picocolors.default.dim(padLabel("Ponytail:"))} ${formatToggle(config.installPonytail)}`] : [],
2452
2636
  "",
2453
2637
  `${border} ${teal(import_picocolors.default.bold("Planned structure"))}`,
2454
2638
  ...showFolderTree(config).split(`
@@ -2483,6 +2667,16 @@ function showPostGeneration(config) {
2483
2667
  usefulCommands.push("");
2484
2668
  usefulCommands.push(`${teal(import_picocolors.default.bold("Note"))} ${import_picocolors.default.dim(".mcp.json is ready to use — the configured MCP servers need no API keys.")}`);
2485
2669
  }
2670
+ if (config.installPonytail) {
2671
+ usefulCommands.push("");
2672
+ if (config.aiSetup === "claude") {
2673
+ usefulCommands.push(`${teal(import_picocolors.default.bold("Ponytail"))} ${import_picocolors.default.dim("Run inside Claude Code:")}`);
2674
+ usefulCommands.push(` ${import_picocolors.default.cyan("/plugin marketplace add DietrichGebert/ponytail")}`);
2675
+ usefulCommands.push(` ${import_picocolors.default.cyan("/plugin install ponytail@ponytail")}`);
2676
+ } else {
2677
+ usefulCommands.push(`${teal(import_picocolors.default.bold("Ponytail"))} ${import_picocolors.default.dim("Added to opencode.json — installs on next opencode run.")}`);
2678
+ }
2679
+ }
2486
2680
  O2.message([...nextSteps, "", ...usefulCommands].join(`
2487
2681
  `), {
2488
2682
  symbol: teal("▲")
@@ -2655,7 +2849,7 @@ async function runWizard() {
2655
2849
  message: import_picocolors2.default.bold("AI setup"),
2656
2850
  initialValue: "none",
2657
2851
  options: [
2658
- { value: "none", label: "None", hint: "no AI docs or MCP config" },
2852
+ { value: "none", label: "None", hint: "No AI configuration setup" },
2659
2853
  { value: "claude", label: "Claude", hint: "generate CLAUDE.md and .mcp.json" },
2660
2854
  { value: "other", label: "Other", hint: "generate AGENTS.md and .mcp.json" }
2661
2855
  ]
@@ -2663,6 +2857,17 @@ async function runWizard() {
2663
2857
  if (q(aiSetup)) {
2664
2858
  return abortWizard();
2665
2859
  }
2860
+ let installPonytail = false;
2861
+ if (aiSetup !== "none") {
2862
+ const ponytailChoice = await ot2({
2863
+ message: `${import_picocolors2.default.bold("Install ponytail plugin?")} ${import_picocolors2.default.dim("Makes your AI agent think like the laziest senior dev in the room. The best code is the code you never wrote. https://github.com/DietrichGebert/ponytail")}`,
2864
+ initialValue: true
2865
+ });
2866
+ if (q(ponytailChoice)) {
2867
+ return abortWizard();
2868
+ }
2869
+ installPonytail = ponytailChoice;
2870
+ }
2666
2871
  const config = {
2667
2872
  projectName: trimmedProjectName,
2668
2873
  author: author.trim(),
@@ -2674,7 +2879,8 @@ async function runWizard() {
2674
2879
  useMarketplaceStructure,
2675
2880
  useRgl: scripting === "none" ? false : useRgl,
2676
2881
  aiSetup,
2677
- installRockide: installRockide2
2882
+ installRockide: installRockide2,
2883
+ installPonytail
2678
2884
  };
2679
2885
  showReview(config);
2680
2886
  const shouldGenerate = await ot2({
@@ -2703,7 +2909,7 @@ var generation = fe();
2703
2909
  generation.start(teal3("Generating your Bedrock addon scaffold..."));
2704
2910
  await generateProject(config);
2705
2911
  if (config.aiSetup !== "none") {
2706
- await setupAi(config.destination, config.aiSetup);
2912
+ await setupAi(config.destination, config.aiSetup, config.installPonytail);
2707
2913
  }
2708
2914
  await runProvisioning(config);
2709
2915
  generation.stop(import_picocolors3.default.green("Spawnpack scaffold generated."));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spawnpack",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "Minecraft Bedrock addon project generator — scaffold your BP+RP in seconds",
5
5
  "author": "veedy-dev",
6
6
  "license": "MIT",
@@ -13,6 +13,7 @@
13
13
  "dist/spawnpack.js",
14
14
  "templates/CLAUDE.md",
15
15
  "templates/AGENTS.md",
16
+ "templates/filters/typegen/main.js",
16
17
  "README.md",
17
18
  "LICENSE",
18
19
  "package.json"
@@ -0,0 +1,86 @@
1
+ import { pascalCase } from "es-toolkit";
2
+ import * as JSONC from "jsonc-parser";
3
+ import { glob, mkdir, readFile, writeFile } from "node:fs/promises";
4
+ import { matchesGlob } from "node:path";
5
+
6
+ const entries = [
7
+ {
8
+ type: "BlockId",
9
+ pattern: "BP/blocks/**/*.json",
10
+ jsonPath: ["minecraft:block", "description", "identifier"],
11
+ identifiers: [],
12
+ },
13
+ {
14
+ type: "EntityId",
15
+ pattern: "BP/entities/**/*.json",
16
+ jsonPath: ["minecraft:entity", "description", "identifier"],
17
+ identifiers: [],
18
+ },
19
+ {
20
+ type: "ItemId",
21
+ pattern: "BP/items/**/*.json",
22
+ jsonPath: ["minecraft:item", "description", "identifier"],
23
+ identifiers: [],
24
+ },
25
+ ];
26
+
27
+ for (const dir of ["BP", "RP"]) {
28
+ for await (const path of glob(`${dir}/**/*.json`)) {
29
+ const entry = entries.find((f) => matchesGlob(path, f.pattern));
30
+ if (!entry) continue;
31
+
32
+ let found = false;
33
+ const text = await readFile(path, "utf8");
34
+ JSONC.visit(text, {
35
+ onArrayBegin() {
36
+ return !found;
37
+ },
38
+ onObjectBegin() {
39
+ return !found;
40
+ },
41
+ onLiteralValue(value, _offset, _length, _startLine, _startCharacter, pathSupplier) {
42
+ if (typeof value !== "string") return;
43
+ if (!pathSupplier().every((segment, i) => segment === entry.jsonPath[i])) return;
44
+
45
+ found = true;
46
+ entry.identifiers.push(value);
47
+ },
48
+ });
49
+ }
50
+ }
51
+
52
+ const lines = ["// Auto-generated file. DO NOT EDIT MANUALLY!\n"];
53
+
54
+ for (const entry of entries) {
55
+ if (entry.identifiers.length === 0) continue;
56
+
57
+ lines.push(`export const enum ${entry.type} {`);
58
+ for (const id of entry.identifiers) {
59
+ const colIndex = id.indexOf(":");
60
+ if (colIndex === -1) {
61
+ console.warn(`Invalid identifier: ${id}`);
62
+ continue;
63
+ }
64
+ const name = id.slice(colIndex + 1).trim();
65
+ if (name === "") {
66
+ console.warn(`Invalid identifier: ${id}`);
67
+ continue;
68
+ }
69
+ lines.push(`\t${pascalCase(name)} = "${id}",`);
70
+ }
71
+ lines.push(`}\n`);
72
+ }
73
+
74
+ const res = lines.join("\n");
75
+
76
+ const ROOT_DIR = process.env.ROOT_DIR;
77
+
78
+ const current = await readFile(`${ROOT_DIR}/data/scripts/generated_types.ts`, "utf8")
79
+ .catch(() => null);
80
+
81
+ if (current !== res) {
82
+ await Promise.all([
83
+ writeFile(`${ROOT_DIR}/data/scripts/generated_types.ts`, res),
84
+ writeFile("./data/scripts/generated_types.ts", res),
85
+ ]);
86
+ }