wolverine-ai 2.3.1 ā 2.3.2
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.3.
|
|
3
|
+
"version": "2.3.2",
|
|
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": {
|
|
@@ -20,6 +20,16 @@ const MANIFEST_FILE = path.join(BACKUPS_DIR, "manifest.json");
|
|
|
20
20
|
const STABILITY_THRESHOLD_MS = 30 * 60 * 1000;
|
|
21
21
|
const RETENTION_MS = 7 * 24 * 60 * 60 * 1000;
|
|
22
22
|
|
|
23
|
+
// Files that should NEVER be overwritten during rollback.
|
|
24
|
+
// These are platform/infrastructure files that would break the server if rolled back.
|
|
25
|
+
const NEVER_ROLLBACK = [
|
|
26
|
+
"server/config/settings.json",
|
|
27
|
+
"server/lib/db.js",
|
|
28
|
+
"server/lib/redis.js",
|
|
29
|
+
".env",
|
|
30
|
+
".env.local",
|
|
31
|
+
];
|
|
32
|
+
|
|
23
33
|
class BackupManager {
|
|
24
34
|
constructor(projectRoot) {
|
|
25
35
|
this.projectRoot = path.resolve(projectRoot);
|
|
@@ -97,8 +107,12 @@ class BackupManager {
|
|
|
97
107
|
|
|
98
108
|
let allRestored = true;
|
|
99
109
|
for (const file of entry.files) {
|
|
110
|
+
// Skip protected config/infrastructure files
|
|
111
|
+
if (NEVER_ROLLBACK.some(p => file.relative === p || file.relative.endsWith(p))) {
|
|
112
|
+
console.log(chalk.gray(` š Skipped (protected): ${file.relative}`));
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
100
115
|
if (fs.existsSync(file.backup)) {
|
|
101
|
-
// Ensure parent dir exists
|
|
102
116
|
fs.mkdirSync(path.dirname(file.original), { recursive: true });
|
|
103
117
|
fs.copyFileSync(file.backup, file.original);
|
|
104
118
|
console.log(chalk.yellow(` ā©ļø Restored: ${file.relative}`));
|
|
@@ -150,6 +164,7 @@ class BackupManager {
|
|
|
150
164
|
|
|
151
165
|
let allRestored = true;
|
|
152
166
|
for (const file of entry.files) {
|
|
167
|
+
if (NEVER_ROLLBACK.some(p => file.relative === p || file.relative.endsWith(p))) continue;
|
|
153
168
|
if (fs.existsSync(file.backup)) {
|
|
154
169
|
fs.mkdirSync(path.dirname(file.original), { recursive: true });
|
|
155
170
|
fs.copyFileSync(file.backup, file.original);
|
package/src/core/verifier.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { spawn } = require("child_process");
|
|
2
|
+
const path = require("path");
|
|
2
3
|
const chalk = require("chalk");
|
|
3
4
|
const { parseError, classifyError } = require("./error-parser");
|
|
4
5
|
|
|
@@ -131,12 +132,13 @@ function bootProbe(scriptPath, cwd, originalErrorSignature) {
|
|
|
131
132
|
* @param {object} routeContext ā optional { path, method } for route-level testing
|
|
132
133
|
*/
|
|
133
134
|
async function verifyFix(scriptPath, cwd, originalErrorSignature, routeContext) {
|
|
134
|
-
// Simple errors
|
|
135
|
-
//
|
|
136
|
-
//
|
|
137
|
-
//
|
|
138
|
-
const
|
|
139
|
-
const
|
|
135
|
+
// Simple errors ā trust syntax+boot, skip route probe entirely.
|
|
136
|
+
// The route probe spawns a full server process which crashes on external deps
|
|
137
|
+
// (pg, redis, cors, etc.) even when the actual fix is correct. ErrorMonitor
|
|
138
|
+
// catches any remaining 500s as the real safety net.
|
|
139
|
+
const sig = originalErrorSignature || "";
|
|
140
|
+
const isSimpleError = /TypeError|ReferenceError|SyntaxError|Cannot find module|Cannot read prop|is not defined|is not a function|Unexpected token/.test(sig);
|
|
141
|
+
const skipRouteProbe = true; // ALWAYS skip route probe ā it fails on servers with external deps
|
|
140
142
|
const steps = (!skipRouteProbe && routeContext?.path) ? 3 : 2;
|
|
141
143
|
|
|
142
144
|
console.log(chalk.yellow("\nš¬ Verifying fix...\n"));
|
|
@@ -178,8 +180,38 @@ async function verifyFix(scriptPath, cwd, originalErrorSignature, routeContext)
|
|
|
178
180
|
} else {
|
|
179
181
|
console.log(chalk.gray(` ā ļø Route probe skipped: ${routeResult.reason || "unknown"}`));
|
|
180
182
|
}
|
|
181
|
-
} else if (
|
|
182
|
-
console.log(chalk.gray(` ā” Skipping route probe
|
|
183
|
+
} else if (routeContext?.path) {
|
|
184
|
+
console.log(chalk.gray(` ā” Skipping route probe ā ErrorMonitor is the safety net`));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Step 3 (replacement): Isolated module load test ā can the changed file be required?
|
|
188
|
+
// This catches cases where the AI fix introduces a require error or crashes on load,
|
|
189
|
+
// without needing to boot the full server (which fails on external deps).
|
|
190
|
+
if (scriptPath) {
|
|
191
|
+
const changedFile = scriptPath;
|
|
192
|
+
const relPath = path.relative(cwd, changedFile).replace(/\\/g, "/");
|
|
193
|
+
if (relPath.startsWith("server/") && relPath.endsWith(".js")) {
|
|
194
|
+
try {
|
|
195
|
+
const { execSync } = require("child_process");
|
|
196
|
+
const testCode = `try{require('./${relPath}');console.log('MODULE_OK')}catch(e){console.error(e.message);process.exit(1)}`;
|
|
197
|
+
const out = execSync(`node -e "${testCode}"`, {
|
|
198
|
+
cwd, timeout: 5000, encoding: "utf-8",
|
|
199
|
+
env: { ...process.env, NODE_PATH: path.join(cwd, "node_modules") },
|
|
200
|
+
});
|
|
201
|
+
if (out.includes("MODULE_OK")) {
|
|
202
|
+
console.log(chalk.green(` ā
Module loads OK: ${relPath}`));
|
|
203
|
+
}
|
|
204
|
+
} catch (e) {
|
|
205
|
+
// Module failed to load ā but this might be because of external deps (pg, redis)
|
|
206
|
+
// Don't fail the verification for this ā just log it
|
|
207
|
+
const errMsg = (e.stderr || e.message || "").slice(0, 100);
|
|
208
|
+
if (/Cannot find module/.test(errMsg) && !/\.\//.test(errMsg)) {
|
|
209
|
+
console.log(chalk.gray(` ā ļø Module test skipped (external dep: ${errMsg.slice(0, 60)})`));
|
|
210
|
+
} else {
|
|
211
|
+
console.log(chalk.yellow(` ā ļø Module load warning: ${errMsg.slice(0, 80)}`));
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
183
215
|
}
|
|
184
216
|
|
|
185
217
|
return { verified: true, status: "fixed" };
|