@idajs/create-mod 0.2.15-dev.19 → 0.2.15-dev.37

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
@@ -24,6 +24,12 @@ npx @idajs/create-mod
24
24
 
25
25
  The tool will guide you through the setup process with interactive prompts.
26
26
 
27
+ Refresh scaffolder-managed files in an existing mod project:
28
+
29
+ ```pwsh
30
+ npx @idajs/create-mod --update
31
+ ```
32
+
27
33
  ## Usage
28
34
 
29
35
  ```pwsh
@@ -0,0 +1,107 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const yazl = require("yazl");
4
+
5
+ function normalizeZipPath(value) {
6
+ return String(value || "")
7
+ .split(path.sep)
8
+ .join("/")
9
+ .replace(/\/+/g, "/")
10
+ .replace(/^\/+/, "")
11
+ .replace(/\/+$/, "");
12
+ }
13
+
14
+ async function collectDirectoryEntries(sourceDir, zipRoot) {
15
+ const dirents = await fs.promises.readdir(sourceDir, { withFileTypes: true });
16
+ const sortedDirents = dirents.slice().sort((a, b) => a.name.localeCompare(b.name));
17
+ const entries = [];
18
+
19
+ if (sortedDirents.length === 0 && zipRoot) {
20
+ entries.push({
21
+ type: "directory",
22
+ metadataPath: normalizeZipPath(zipRoot),
23
+ });
24
+ }
25
+
26
+ for (const dirent of sortedDirents) {
27
+ const sourcePath = path.join(sourceDir, dirent.name);
28
+ const metadataPath = normalizeZipPath(path.posix.join(zipRoot, dirent.name));
29
+
30
+ if (dirent.isDirectory()) {
31
+ entries.push(...(await collectDirectoryEntries(sourcePath, metadataPath)));
32
+ continue;
33
+ }
34
+
35
+ if (dirent.isFile()) {
36
+ entries.push({
37
+ type: "file",
38
+ sourcePath,
39
+ metadataPath,
40
+ });
41
+ continue;
42
+ }
43
+
44
+ throw new Error(`Unsupported entry type in archive source: ${sourcePath}`);
45
+ }
46
+
47
+ return entries;
48
+ }
49
+
50
+ async function createZipFromDirectories(zipPath, mappings, options = {}) {
51
+ const zipfile = new yazl.ZipFile();
52
+ const output = fs.createWriteStream(zipPath);
53
+ const zipOptions = {};
54
+
55
+ if (typeof options.compressionLevel === "number") {
56
+ zipOptions.compressionLevel = options.compressionLevel;
57
+ }
58
+
59
+ const collectedEntries = [];
60
+ for (const mapping of mappings) {
61
+ if (!fs.existsSync(mapping.sourceDir)) {
62
+ throw new Error(`Source directory not found: ${mapping.sourceDir}`);
63
+ }
64
+
65
+ collectedEntries.push(...(await collectDirectoryEntries(mapping.sourceDir, mapping.zipRoot)));
66
+ }
67
+
68
+ return new Promise((resolve, reject) => {
69
+ let settled = false;
70
+
71
+ function finish(error) {
72
+ if (settled) {
73
+ return;
74
+ }
75
+ settled = true;
76
+ if (error) {
77
+ reject(error);
78
+ return;
79
+ }
80
+ resolve();
81
+ }
82
+
83
+ output.on("close", () => finish());
84
+ output.on("error", finish);
85
+ zipfile.outputStream.on("error", finish);
86
+
87
+ zipfile.outputStream.pipe(output);
88
+
89
+ try {
90
+ for (const entry of collectedEntries) {
91
+ if (entry.type === "directory") {
92
+ zipfile.addEmptyDirectory(entry.metadataPath);
93
+ } else {
94
+ zipfile.addFile(entry.sourcePath, entry.metadataPath, zipOptions);
95
+ }
96
+ }
97
+
98
+ zipfile.end();
99
+ } catch (error) {
100
+ finish(error);
101
+ }
102
+ });
103
+ }
104
+
105
+ module.exports = {
106
+ createZipFromDirectories,
107
+ };
@@ -1,14 +1,15 @@
1
1
  const { execSync } = require("child_process");
2
2
  const path = require("path");
3
3
  const fs = require("fs");
4
- const archiver = require("archiver");
4
+ const { createZipFromDirectories } = require("./archive");
5
+ const { getPackageName } = require("./project");
5
6
 
6
7
  // Get mod name from command line argument
7
- const modName = process.argv[2];
8
+ const modName = process.argv[2] || getPackageName();
8
9
 
9
10
  if (!modName) {
10
11
  console.error("Error: Mod name is required as an argument");
11
- console.error("Usage: node build.js <mod-name>");
12
+ console.error("Usage: node build.js [mod-name]");
12
13
  process.exit(1);
13
14
  }
14
15
 
@@ -61,47 +62,31 @@ if (!fs.existsSync(buildFolder)) {
61
62
 
62
63
  // Create zip file
63
64
  const zipPath = path.join(buildFolder, `${modName}.zip`);
64
- const output = fs.createWriteStream(zipPath);
65
- const archive = archiver("zip", {
66
- zlib: { level: 9 }, // Maximum compression
67
- });
68
65
 
69
- console.log(`Creating ${zipPath}...`);
66
+ async function main() {
67
+ console.log(`Creating ${zipPath}...`);
70
68
 
71
- // Handle archive events
72
- output.on("close", () => {
73
- const sizeInKB = (archive.pointer() / 1024).toFixed(2);
74
- console.log(`✓ Build complete: ${zipPath} (${sizeInKB} KB)`);
75
- });
69
+ const mappings = [{ sourceDir: sourceFolder, zipRoot: modName }];
76
70
 
77
- archive.on("error", (err) => {
78
- console.error("Error creating archive:", err);
79
- process.exit(1);
80
- });
71
+ console.log(`Adding ${sourceFolder}/ ${modName}/`);
81
72
 
82
- archive.on("warning", (err) => {
83
- if (err.code === "ENOENT") {
84
- console.warn("Warning:", err);
73
+ const mediaFolder = "media";
74
+ if (fs.existsSync(mediaFolder)) {
75
+ console.log(`Adding ${mediaFolder}/ → ${modName}/media/`);
76
+ mappings.push({ sourceDir: mediaFolder, zipRoot: `${modName}/media` });
85
77
  } else {
86
- throw err;
78
+ console.log("No media folder found, skipping");
87
79
  }
88
- });
89
-
90
- // Pipe archive data to the file
91
- archive.pipe(output);
92
80
 
93
- // Add source folder contents to zip under modName directory
94
- console.log(`Adding ${sourceFolder}/ → ${modName}/`);
95
- archive.directory(sourceFolder, modName);
81
+ await createZipFromDirectories(zipPath, mappings, {
82
+ compressionLevel: 9,
83
+ });
96
84
 
97
- // Add media folder if it exists
98
- const mediaFolder = "media";
99
- if (fs.existsSync(mediaFolder)) {
100
- console.log(`Adding ${mediaFolder}/ → ${modName}/media/`);
101
- archive.directory(mediaFolder, `${modName}/media`);
102
- } else {
103
- console.log("No media folder found, skipping");
85
+ const sizeInKB = (fs.statSync(zipPath).size / 1024).toFixed(2);
86
+ console.log(`✓ Build complete: ${zipPath} (${sizeInKB} KB)`);
104
87
  }
105
88
 
106
- // Finalize the archive
107
- archive.finalize();
89
+ main().catch((error) => {
90
+ console.error("Error creating archive:", error);
91
+ process.exit(1);
92
+ });
@@ -6,14 +6,14 @@
6
6
  "watch": "node watch.js",
7
7
  "sync": "node sync.js",
8
8
  "start": "node start.js",
9
- "build": "node build.js %npm_package_name%",
9
+ "build": "node build.js",
10
10
  "update:types": "npm update @idajs/types"
11
11
  },
12
- "devDependencies": {
13
- "archiver": "^7.0.1",
14
- "chokidar-cli": "^3.0.0",
15
- "@idajs/types": "^0.2.0",
16
- "@idajs/sync": "^1.1.0",
12
+ "devDependencies": {
13
+ "yazl": "^3.3.1",
14
+ "chokidar-cli": "^3.0.0",
15
+ "@idajs/types": "^0.2.0",
16
+ "@idajs/sync": "^1.1.0",
17
17
  "typescript": "^5.9.3"
18
18
  }
19
19
  }
@@ -1,10 +1,10 @@
1
- const archiver = require("archiver");
2
1
  const fs = require("fs");
3
2
  const http = require("http");
4
3
  const https = require("https");
5
4
  const path = require("path");
6
5
  const { spawn } = require("child_process");
7
6
 
7
+ const { createZipFromDirectories } = require("./archive");
8
8
  const { getPackageName } = require("./project");
9
9
 
10
10
  function runNodeScript(scriptName, args = []) {
@@ -27,25 +27,11 @@ function runNodeScript(scriptName, args = []) {
27
27
  }
28
28
 
29
29
  function createZip(zipPath, sourceDir, rootName) {
30
- return new Promise((resolve, reject) => {
31
- const output = fs.createWriteStream(zipPath);
32
- const archive = archiver("zip", {
33
- store: true,
34
- });
35
-
36
- output.on("close", resolve);
37
- output.on("error", reject);
38
- archive.on("error", reject);
39
- archive.on("warning", (error) => {
40
- if (error.code !== "ENOENT") {
41
- reject(error);
42
- }
43
- });
44
-
45
- archive.pipe(output);
46
- archive.directory(sourceDir, rootName);
47
- archive.finalize();
48
- });
30
+ return createZipFromDirectories(
31
+ zipPath,
32
+ [{ sourceDir, zipRoot: rootName }],
33
+ { compressionLevel: 0 }
34
+ );
49
35
  }
50
36
 
51
37
  function request(server, method, requestPath, body, headers = {}) {
package/index.js CHANGED
@@ -4,6 +4,7 @@ const fs = require("fs");
4
4
  const path = require("path");
5
5
  const os = require("os");
6
6
  const { execSync } = require("child_process");
7
+ const readline = require("readline");
7
8
  const IdaSync = require("@idajs/sync");
8
9
 
9
10
  // Parse command line arguments
@@ -26,7 +27,9 @@ const idajsDir = getArgValue("--idajs-dir") || getArgValue("--idajs");
26
27
  const useTypeScript = args.includes("--typescript") || args.includes("--ts");
27
28
  const useJavaScript = args.includes("--javascript") || args.includes("--js");
28
29
  const skipInstall = args.includes("--skip-install");
30
+ const updateMode = args.includes("--update");
29
31
  const helpRequested = args.includes("--help") || args.includes("-h");
32
+ const requiredUpdatePackages = ["@idajs/types", "@idajs/sync"];
30
33
 
31
34
  // Show help if requested
32
35
  if (helpRequested) {
@@ -41,7 +44,8 @@ Options:
41
44
  --idajs-dir, --idajs <path> IdaJS installation directory
42
45
  --typescript, --ts Use TypeScript
43
46
  --javascript, --js Use JavaScript
44
- --skip-install Skip npm install
47
+ --update Refresh scaffolder-managed files in the current mod folder
48
+ --skip-install Skip npm install (and type update in --update mode)
45
49
  -h, --help Show this help message
46
50
 
47
51
  Examples:
@@ -50,6 +54,7 @@ Examples:
50
54
  npx @idajs/create-mod my-mod --typescript
51
55
  npx @idajs/create-mod my-mod --dir ./projects/my-mod --idajs C:/Projects/idajs --js
52
56
  npx @idajs/create-mod my-mod --skip-install
57
+ npx @idajs/create-mod --update
53
58
  `);
54
59
  process.exit(0);
55
60
  }
@@ -101,9 +106,93 @@ function parseIdaConnection(value) {
101
106
  };
102
107
  }
103
108
 
109
+ function loadJson(filePath) {
110
+ try {
111
+ return JSON.parse(fs.readFileSync(filePath, "utf8"));
112
+ } catch (error) {
113
+ throw new Error(`Failed to parse JSON file: ${filePath}`);
114
+ }
115
+ }
116
+
117
+ function isInteractiveTerminal() {
118
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY);
119
+ }
120
+
121
+ function askYesNo(question) {
122
+ return new Promise((resolve) => {
123
+ const rl = readline.createInterface({
124
+ input: process.stdin,
125
+ output: process.stdout,
126
+ });
127
+
128
+ rl.question(question, (answer) => {
129
+ rl.close();
130
+ const normalized = String(answer || "").trim().toLowerCase();
131
+ resolve(normalized === "y" || normalized === "yes");
132
+ });
133
+ });
134
+ }
135
+
136
+ async function runUpdateMode() {
137
+ const targetDir = process.cwd();
138
+ const packageJsonPath = path.join(targetDir, "package.json");
139
+
140
+ if (!fs.existsSync(packageJsonPath)) {
141
+ console.error(`\n❌ Error: No package.json found in ${targetDir}`);
142
+ console.error("Run this command from inside an existing IdaJS mod folder.");
143
+ process.exit(1);
144
+ }
145
+
146
+ const packageJson = loadJson(packageJsonPath);
147
+ const devDependencies = packageJson.devDependencies || {};
148
+ const missingPackages = requiredUpdatePackages.filter((name) => !devDependencies[name]);
149
+
150
+ if (missingPackages.length > 0) {
151
+ console.warn(
152
+ `\n⚠️ Warning: Missing IdaJS devDependencies: ${missingPackages.join(", ")}.`
153
+ );
154
+ console.warn("This may not be an IdaJS mod, or the project may differ significantly from the scaffold.");
155
+
156
+ if (!isInteractiveTerminal()) {
157
+ console.error("\n❌ Error: Confirmation required. Rerun this command in an interactive terminal to continue.");
158
+ process.exit(1);
159
+ }
160
+
161
+ const confirmed = await askYesNo("Continue with scaffolder update? [y/N] ");
162
+ if (!confirmed) {
163
+ console.log("\nUpdate cancelled.");
164
+ process.exit(1);
165
+ }
166
+ }
167
+
168
+ console.log(`\nUpdating IdaJS mod in ${targetDir}...`);
169
+
170
+ const installScript = path.join(__dirname, "install.js");
171
+ const installArgs = [installScript, targetDir, "--update"];
172
+
173
+ if (skipInstall) {
174
+ installArgs.push("--skip-install");
175
+ }
176
+
177
+ try {
178
+ execSync(`node ${installArgs.map((arg) => `"${arg}"`).join(" ")}`, {
179
+ stdio: "inherit",
180
+ });
181
+ console.log("\n✅ Scaffolder update completed successfully.");
182
+ } catch (error) {
183
+ console.error(`\n❌ Error updating project: ${error.message}`);
184
+ process.exit(1);
185
+ }
186
+ }
187
+
104
188
  async function main() {
105
189
  console.log("Welcome to IdaJS Mod Creator!\n");
106
190
 
191
+ if (updateMode) {
192
+ await runUpdateMode();
193
+ return;
194
+ }
195
+
107
196
  // Determine if we need prompts
108
197
  const needsPrompts =
109
198
  !projectName || (!useTypeScript && !useJavaScript) || (!idajsDir && !getIdaJsDirFromConfig());
package/install.js CHANGED
@@ -2,12 +2,13 @@
2
2
 
3
3
  const fs = require("fs");
4
4
  const path = require("path");
5
- const { exec } = require("child_process");
5
+ const { exec, execSync } = require("child_process");
6
6
 
7
7
  // Get configuration from arguments or defaults
8
8
  const args = process.argv.slice(2);
9
9
  const targetDirArg = args.find((arg) => !arg.startsWith("--"));
10
10
  const skipInstall = args.includes("--skip-install");
11
+ const updateMode = args.includes("--update");
11
12
  const idaRootArg = args.find((arg) => arg.startsWith("--ida-root="));
12
13
 
13
14
  // Get the directory where this script was called from or use provided argument
@@ -30,48 +31,34 @@ const isTypeScriptProject = (() => {
30
31
  const files = fs.readdirSync(srcDir);
31
32
  return files.some((file) => file.endsWith(".ts"));
32
33
  })();
33
-
34
- console.log(`Installing development environment in: ${targetDir}`);
34
+ const protectedUpdateFields = new Set([
35
+ "name",
36
+ "description",
37
+ "version",
38
+ "author",
39
+ "private",
40
+ "license",
41
+ ]);
42
+ const obsoleteScaffolderDevDependencies = ["archiver"];
43
+
44
+ console.log(`${updateMode ? "Updating" : "Installing"} development environment in: ${targetDir}`);
35
45
  if (idaRoot) {
36
46
  console.log(`Ida root: ${idaRoot}`);
37
47
  } else {
38
48
  console.log(`Running in standalone mode`);
39
49
  }
40
50
 
41
- // Step 1: Merge package.template.json files to create package.json
42
- function mergePackageJson() {
43
- const packagePath = path.join(targetDir, "package.json");
44
- const globalTemplatePath = path.join(configDir, "package.template.json");
45
- const sampleTemplatePath = path.join(targetDir, "package.template.json");
46
-
47
- if (!fs.existsSync(globalTemplatePath)) {
48
- console.error("Error: package.template.json not found in config directory");
49
- process.exit(1);
50
- }
51
-
52
- if (!fs.existsSync(sampleTemplatePath)) {
53
- console.error("Error: package.template.json not found in sample directory");
54
- process.exit(1);
55
- }
56
-
57
- console.log("Merging package.template.json files to create package.json...");
58
-
59
- // Start with global template
60
- const packageJson = JSON.parse(fs.readFileSync(globalTemplatePath, "utf8"));
61
- const sampleTemplate = JSON.parse(fs.readFileSync(sampleTemplatePath, "utf8"));
62
-
63
- // Get version from version.js or package.json (standalone mode)
51
+ function getPackageVersion() {
64
52
  let version = null;
53
+
65
54
  if (versionScriptPath && fs.existsSync(versionScriptPath)) {
66
55
  try {
67
- const { execSync } = require("child_process");
68
56
  version = execSync(`node "${versionScriptPath}"`, { encoding: "utf8" }).trim();
69
57
  console.log(`Using version from version.js: ${version}`);
70
58
  } catch (error) {
71
59
  console.warn("Warning: Could not read version from version.js");
72
60
  }
73
61
  } else {
74
- // Standalone mode: get version from package.json in the same directory as this script
75
62
  const localPackagePath = path.join(__dirname, "package.json");
76
63
  if (fs.existsSync(localPackagePath)) {
77
64
  try {
@@ -84,7 +71,51 @@ function mergePackageJson() {
84
71
  }
85
72
  }
86
73
 
87
- // Set version if available
74
+ return version;
75
+ }
76
+
77
+ function orderPackageJson(packageJson) {
78
+ const orderedPackageJson = {};
79
+ const propertyOrder = ["name", "description", "version", "author", "license", "private", "scripts"];
80
+
81
+ propertyOrder.forEach((key) => {
82
+ if (packageJson[key] !== undefined) {
83
+ orderedPackageJson[key] = packageJson[key];
84
+ }
85
+ });
86
+
87
+ Object.keys(packageJson).forEach((key) => {
88
+ if (!propertyOrder.includes(key)) {
89
+ orderedPackageJson[key] = packageJson[key];
90
+ }
91
+ });
92
+
93
+ return orderedPackageJson;
94
+ }
95
+
96
+ // Step 1: Merge package.template.json files to create package.json
97
+ function mergePackageJsonForCreate() {
98
+ const packagePath = path.join(targetDir, "package.json");
99
+ const globalTemplatePath = path.join(configDir, "package.template.json");
100
+ const sampleTemplatePath = path.join(targetDir, "package.template.json");
101
+
102
+ if (!fs.existsSync(globalTemplatePath)) {
103
+ console.error("Error: package.template.json not found in config directory");
104
+ process.exit(1);
105
+ }
106
+
107
+ if (!fs.existsSync(sampleTemplatePath)) {
108
+ console.error("Error: package.template.json not found in sample directory");
109
+ process.exit(1);
110
+ }
111
+
112
+ console.log("Merging package.template.json files to create package.json...");
113
+
114
+ // Start with global template
115
+ const packageJson = JSON.parse(fs.readFileSync(globalTemplatePath, "utf8"));
116
+ const sampleTemplate = JSON.parse(fs.readFileSync(sampleTemplatePath, "utf8"));
117
+
118
+ const version = getPackageVersion();
88
119
  if (version) {
89
120
  packageJson.version = version;
90
121
  }
@@ -116,31 +147,71 @@ function mergePackageJson() {
116
147
  packageJson.dependencies = { ...packageJson.dependencies, ...sampleTemplate.dependencies };
117
148
  }
118
149
 
119
- // Reorder properties to ensure consistent ordering
120
- const orderedPackageJson = {};
121
- const propertyOrder = ["name", "description", "version", "author", "private", "scripts"];
150
+ fs.writeFileSync(packagePath, JSON.stringify(orderPackageJson(packageJson), null, 2) + "\n");
151
+ console.log("✓ Package.json created successfully");
152
+ }
122
153
 
123
- // Add properties in the specified order
124
- propertyOrder.forEach((key) => {
125
- if (packageJson[key] !== undefined) {
126
- orderedPackageJson[key] = packageJson[key];
154
+ function mergePackageJsonForUpdate() {
155
+ const packagePath = path.join(targetDir, "package.json");
156
+ const globalTemplatePath = path.join(configDir, "package.template.json");
157
+
158
+ if (!fs.existsSync(globalTemplatePath)) {
159
+ console.error("Error: package.template.json not found in config directory");
160
+ process.exit(1);
161
+ }
162
+
163
+ if (!fs.existsSync(packagePath)) {
164
+ console.error("Error: package.json not found in target directory");
165
+ process.exit(1);
166
+ }
167
+
168
+ console.log("Refreshing package.json from scaffolder template...");
169
+
170
+ const existingPackageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
171
+ const configTemplate = JSON.parse(fs.readFileSync(globalTemplatePath, "utf8"));
172
+ const packageJson = { ...existingPackageJson };
173
+ const existingDevDependencies = existingPackageJson.devDependencies || {};
174
+
175
+ Object.entries(configTemplate).forEach(([key, value]) => {
176
+ if (protectedUpdateFields.has(key)) {
177
+ return;
127
178
  }
128
- });
129
179
 
130
- // Add all remaining properties
131
- Object.keys(packageJson).forEach((key) => {
132
- if (!propertyOrder.includes(key)) {
133
- orderedPackageJson[key] = packageJson[key];
180
+ if (key === "scripts" || key === "devDependencies") {
181
+ const templateValue = { ...value };
182
+
183
+ if (
184
+ key === "devDependencies" &&
185
+ !isTypeScriptProject &&
186
+ !Object.prototype.hasOwnProperty.call(existingDevDependencies, "typescript")
187
+ ) {
188
+ delete templateValue.typescript;
189
+ }
190
+
191
+ packageJson[key] = {
192
+ ...(existingPackageJson[key] || {}),
193
+ ...templateValue,
194
+ };
195
+ return;
134
196
  }
197
+
198
+ packageJson[key] = value;
135
199
  });
136
200
 
137
- fs.writeFileSync(packagePath, JSON.stringify(orderedPackageJson, null, 2) + "\n");
138
- console.log("✓ Package.json created successfully");
201
+ if (packageJson.devDependencies) {
202
+ obsoleteScaffolderDevDependencies.forEach((dependency) => {
203
+ delete packageJson.devDependencies[dependency];
204
+ });
205
+ }
206
+
207
+ fs.writeFileSync(packagePath, JSON.stringify(orderPackageJson(packageJson), null, 2) + "\n");
208
+ console.log("✓ Package.json refreshed successfully");
139
209
  }
140
210
 
141
211
  // Step 2: Copy necessary files
142
212
  function copyFiles() {
143
213
  const filesToCopy = [
214
+ { source: "archive.js" },
144
215
  { source: "project.js" },
145
216
  { source: "remote.js" },
146
217
  { source: "run.ps1" },
@@ -204,11 +275,49 @@ function runNpmInstall() {
204
275
  npmProcess.stderr.pipe(process.stderr);
205
276
  }
206
277
 
278
+ function runCommand(command, errorMessage) {
279
+ try {
280
+ execSync(command, {
281
+ cwd: targetDir,
282
+ stdio: "inherit",
283
+ });
284
+ } catch (error) {
285
+ console.error(errorMessage);
286
+ process.exit(1);
287
+ }
288
+ }
289
+
290
+ function runUpdatePostInstall() {
291
+ if (skipInstall) {
292
+ console.log("\nSkipped npm install and update:types");
293
+ console.log("\nInfrastructure update complete.");
294
+ return;
295
+ }
296
+
297
+ console.log("Running npm install...");
298
+ runCommand("npm install", "Error running npm install");
299
+ console.log("✓ npm install completed successfully");
300
+
301
+ console.log("Running npm run update:types...");
302
+ runCommand(
303
+ "npm run update:types",
304
+ "Error running npm run update:types. Infrastructure refresh and npm install already completed."
305
+ );
306
+ console.log("✓ npm run update:types completed successfully");
307
+ console.log("\nInfrastructure update complete! You can now use the refreshed development scripts.");
308
+ }
309
+
207
310
  // Main execution
208
311
  try {
209
- mergePackageJson();
312
+ if (updateMode) {
313
+ mergePackageJsonForUpdate();
314
+ } else {
315
+ mergePackageJsonForCreate();
316
+ }
210
317
  copyFiles();
211
- if (!skipInstall) {
318
+ if (updateMode) {
319
+ runUpdatePostInstall();
320
+ } else if (!skipInstall) {
212
321
  runNpmInstall();
213
322
  } else {
214
323
  console.log("\nSkipped npm install");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@idajs/create-mod",
3
- "version": "0.2.15-dev.19",
3
+ "version": "0.2.15-dev.37",
4
4
  "description": "Scaffolding tool for creating IdaJS game mods for Little Big Adventure 2. Use with: npx @idajs/create-mod",
5
5
  "author": "Andriy Tevelyev",
6
6
  "license": "GPL-2.0",