wolverine-ai 2.4.4 → 2.4.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wolverine-ai",
3
- "version": "2.4.4",
3
+ "version": "2.4.5",
4
4
  "description": "Self-healing Node.js server framework powered by AI. Catches crashes, diagnoses errors, generates fixes, verifies, and restarts — automatically.",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -91,25 +91,46 @@ function isNewer(latest, current) {
91
91
  }
92
92
 
93
93
  /**
94
- * Protect config files before update and restore after.
94
+ * Protect ALL user files before update and restore after.
95
+ * The entire server/ directory is sacred — auto-update must never touch it.
96
+ * Also protects .env files and any user config.
95
97
  */
96
- function backupConfigs(cwd) {
97
- const configs = [
98
- "server/config/settings.json",
99
- ".env.local",
100
- ".env",
101
- ];
98
+ function backupUserFiles(cwd) {
102
99
  const backups = {};
103
- for (const file of configs) {
100
+
101
+ // Protect individual config files
102
+ const protectedFiles = [".env.local", ".env", ".wolverine/mcp.json", ".wolverine/pricing.json"];
103
+ for (const file of protectedFiles) {
104
104
  const fullPath = path.join(cwd, file);
105
105
  if (fs.existsSync(fullPath)) {
106
106
  backups[file] = fs.readFileSync(fullPath, "utf-8");
107
107
  }
108
108
  }
109
+
110
+ // Protect entire server/ directory (recursive)
111
+ const serverDir = path.join(cwd, "server");
112
+ if (fs.existsSync(serverDir)) {
113
+ const walk = (dir, base) => {
114
+ try {
115
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
116
+ for (const entry of entries) {
117
+ if (entry.name === "node_modules") continue;
118
+ const fullPath = path.join(dir, entry.name);
119
+ const relPath = path.join(base, entry.name).replace(/\\/g, "/");
120
+ if (entry.isDirectory()) { walk(fullPath, relPath); }
121
+ else {
122
+ try { backups[relPath] = fs.readFileSync(fullPath, "utf-8"); } catch {}
123
+ }
124
+ }
125
+ } catch {}
126
+ };
127
+ walk(serverDir, "server");
128
+ }
129
+
109
130
  return backups;
110
131
  }
111
132
 
112
- function restoreConfigs(cwd, backups) {
133
+ function restoreUserFiles(cwd, backups) {
113
134
  for (const [file, content] of Object.entries(backups)) {
114
135
  const fullPath = path.join(cwd, file);
115
136
  try {
@@ -144,33 +165,35 @@ function upgrade(cwd, logger) {
144
165
  console.log(chalk.blue(`\n 🔄 Wolverine update available: ${current} → ${latest}`));
145
166
  if (logger) logger.info("update.start", `Upgrading ${current} → ${latest}`, { from: current, to: latest });
146
167
 
147
- // Back up configs
148
- const configBackups = backupConfigs(cwd);
149
- console.log(chalk.gray(` 🔒 Backed up ${Object.keys(configBackups).length} config files`));
168
+ // Back up ALL user files (server/, .env, configs)
169
+ const userBackups = backupUserFiles(cwd);
170
+ console.log(chalk.gray(` 🔒 Backed up ${Object.keys(userBackups).length} user files (server/ protected)`));
150
171
 
151
172
  try {
152
- // Detect install method: git clone or npm package
153
173
  const useGit = isGitRepo(cwd);
154
- let cmd;
155
174
 
156
175
  if (useGit) {
157
- // Git-cloned: pull latest from origin, then npm install for deps
158
- cmd = "git pull origin master && npm install";
159
- console.log(chalk.blue(` 📦 Git repo detected pulling latest`));
176
+ // Git-cloned: ONLY update framework files, NEVER touch server/
177
+ // Fetch latest, then selectively checkout only framework dirs
178
+ console.log(chalk.blue(` 📦 Git repo — selective framework update (server/ untouched)`));
179
+ execSync("git fetch origin master", { cwd, stdio: "pipe", timeout: 30000 });
180
+ // Only update: src/, bin/, package.json, examples/, tests/, CLAUDE.md, README.md, CHANGELOG.md
181
+ const frameworkPaths = "src/ bin/ package.json package-lock.json examples/ tests/ CLAUDE.md README.md CHANGELOG.md .npmignore";
182
+ execSync(`git checkout origin/master -- ${frameworkPaths}`, { cwd, stdio: "pipe", timeout: 30000 });
183
+ execSync("npm install", { cwd, stdio: "pipe", timeout: 120000 });
160
184
  } else {
161
185
  // npm-installed: update the package
162
186
  const isGlobal = __dirname.includes("node_modules") && !cwd.includes("node_modules");
163
- cmd = isGlobal
187
+ const cmd = isGlobal
164
188
  ? `npm install -g ${PACKAGE_NAME}@${latest}`
165
189
  : `npm install ${PACKAGE_NAME}@${latest}`;
190
+ console.log(chalk.blue(` 📦 Running: ${cmd}`));
191
+ execSync(cmd, { cwd, stdio: "pipe", timeout: 120000 });
166
192
  }
167
193
 
168
- console.log(chalk.blue(` 📦 Running: ${cmd}`));
169
- execSync(cmd, { cwd, stdio: "pipe", timeout: 120000 });
170
-
171
- // Restore configs (npm might have overwritten them)
172
- restoreConfigs(cwd, configBackups);
173
- console.log(chalk.gray(` 🔒 Restored config files`));
194
+ // Restore ALL user files (server/, .env, configs) — belt AND suspenders
195
+ restoreUserFiles(cwd, userBackups);
196
+ console.log(chalk.gray(` 🔒 Restored ${Object.keys(userBackups).length} user files`));
174
197
 
175
198
  // Clear version cache
176
199
  _currentVersion = null;