wolverine-ai 3.8.1 → 3.8.3
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": "3.8.
|
|
3
|
+
"version": "3.8.3",
|
|
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": {
|
|
@@ -331,7 +331,7 @@ class AgentEngine {
|
|
|
331
331
|
this.logger = options.logger;
|
|
332
332
|
this.cwd = options.cwd || process.cwd();
|
|
333
333
|
this.mcp = options.mcp || null; // McpRegistry for external tools
|
|
334
|
-
this.category = options.category || "
|
|
334
|
+
this.category = options.category || "reasoning"; // Analytics category — matches model role
|
|
335
335
|
|
|
336
336
|
// Budget constraints (claw-code: QueryEngineConfig)
|
|
337
337
|
this.maxTurns = options.maxTurns || 15;
|
package/src/agent/sub-agents.js
CHANGED
|
@@ -97,8 +97,9 @@ async function spawnAgent(type, task, options = {}) {
|
|
|
97
97
|
});
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
// Map sub-agent type to analytics category
|
|
101
|
-
|
|
100
|
+
// Map sub-agent type to analytics category matching the 9 model roles:
|
|
101
|
+
// explore/plan/verify = classifier (triage), fix/database = tool (uses tools to fix), research = research, security = audit
|
|
102
|
+
const categoryMap = { explore: "classifier", plan: "classifier", verify: "classifier", research: "research", fix: "tool", database: "tool", security: "audit" };
|
|
102
103
|
const agent = new AgentEngine({
|
|
103
104
|
sandbox: options.sandbox,
|
|
104
105
|
logger: options.logger,
|
package/src/brain/brain.js
CHANGED
|
@@ -114,7 +114,7 @@ const SEED_DOCS = [
|
|
|
114
114
|
metadata: { topic: "sub-agent-tools" },
|
|
115
115
|
},
|
|
116
116
|
{
|
|
117
|
-
text: "Heal pipeline
|
|
117
|
+
text: "Heal pipeline with analytics categories matching 9 model roles: (1) Injection scan → AUDIT_MODEL → 'audit'. (2) Fast path single-shot repair → CODING_MODEL → 'coding'. (3) Main agent with tools → REASONING_MODEL → 'reasoning'. (4) Sub-agents: explore/plan/verify → CLASSIFIER_MODEL → 'classifier'; fix/database → TOOL_MODEL → 'tool'; research → RESEARCH_MODEL → 'research'; security → AUDIT_MODEL → 'audit'. (5) Brain compaction → COMPACTING_MODEL → 'compacting'. (6) Embeddings → EMBEDDING_MODEL → 'embedding'. (7) Notifier/perf summaries → CHAT_MODEL → 'chat'. All 9 roles tracked: reasoning, coding, chat, tool, classifier, audit, compacting, research, embedding. Billing: all calls go through unified credit proxy (WOLVERINE_API_KEY). Billing errors (402) stop healing immediately.",
|
|
118
118
|
metadata: { topic: "heal-escalation" },
|
|
119
119
|
},
|
|
120
120
|
{
|
package/src/core/wolverine.js
CHANGED
|
@@ -339,6 +339,7 @@ async function _healImpl({ stderr, cwd, sandbox, notifier, rateLimiter, backupMa
|
|
|
339
339
|
sandbox, logger, cwd, mcp,
|
|
340
340
|
maxTurns: agentMaxTurns,
|
|
341
341
|
maxTokens: tokenBudget.agent,
|
|
342
|
+
category: "reasoning",
|
|
342
343
|
});
|
|
343
344
|
|
|
344
345
|
const agentResult = await agent.run({
|
|
@@ -487,8 +488,11 @@ async function tryOperationalFix(parsed, cwd, logger) {
|
|
|
487
488
|
}
|
|
488
489
|
}
|
|
489
490
|
|
|
490
|
-
// Pattern 2: ENOENT
|
|
491
|
-
const enoent = msg.match(/ENOENT.*?'([^']+)'/)
|
|
491
|
+
// Pattern 2: Missing files — ENOENT or error messages mentioning missing file paths
|
|
492
|
+
const enoent = msg.match(/ENOENT.*?'([^']+)'/)
|
|
493
|
+
|| msg.match(/[Mm]issing\s+(?:required\s+)?(?:config\s+)?file:\s*([^\s,."]+\.\w+)/)
|
|
494
|
+
|| msg.match(/no such file.*?'([^']+)'/)
|
|
495
|
+
|| msg.match(/cannot find.*?'([^']+\.\w+)'/i);
|
|
492
496
|
if (enoent) {
|
|
493
497
|
const missingFile = enoent[1];
|
|
494
498
|
const fs = require("fs");
|
|
@@ -501,10 +505,31 @@ async function tryOperationalFix(parsed, cwd, logger) {
|
|
|
501
505
|
fs.mkdirSync(path.dirname(missingFile), { recursive: true });
|
|
502
506
|
const ext = path.extname(missingFile).toLowerCase();
|
|
503
507
|
|
|
504
|
-
// For JSON config files, try to infer expected structure from the code
|
|
508
|
+
// For JSON config files, try to infer expected structure from the code or error message
|
|
505
509
|
let content = "";
|
|
506
510
|
if (ext === ".json") {
|
|
507
|
-
content = _inferJsonConfig(missingFile, cwd, parsed)
|
|
511
|
+
content = _inferJsonConfig(missingFile, cwd, parsed);
|
|
512
|
+
// Also try to extract fields from the error message: "Expected JSON with { field1, field2 }"
|
|
513
|
+
if (!content) {
|
|
514
|
+
const fieldsMatch = msg.match(/(?:expected|with|fields?)[:\s]*\{\s*([^}]+)\}/i);
|
|
515
|
+
if (fieldsMatch) {
|
|
516
|
+
const fields = fieldsMatch[1].split(/[,\s]+/).filter(f => /^[a-zA-Z_]\w*$/.test(f.trim()));
|
|
517
|
+
if (fields.length > 0) {
|
|
518
|
+
const config = {};
|
|
519
|
+
for (const f of fields) {
|
|
520
|
+
const lower = f.toLowerCase();
|
|
521
|
+
if (/url|endpoint|host|uri/.test(lower)) config[f] = "http://localhost:3000";
|
|
522
|
+
else if (/timeout|delay/.test(lower)) config[f] = 5000;
|
|
523
|
+
else if (/port/.test(lower)) config[f] = 3000;
|
|
524
|
+
else if (/enabled|active/.test(lower)) config[f] = true;
|
|
525
|
+
else config[f] = "";
|
|
526
|
+
}
|
|
527
|
+
console.log(chalk.gray(` 🔍 Inferred ${fields.length} fields from error message: ${fields.join(", ")}`));
|
|
528
|
+
content = JSON.stringify(config, null, 2);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
content = content || "{}";
|
|
508
533
|
} else {
|
|
509
534
|
const defaults = { ".yaml": "", ".yml": "", ".log": "", ".txt": "", ".csv": "", ".env": "" };
|
|
510
535
|
content = defaults[ext] || "";
|
|
@@ -178,7 +178,7 @@ class Notifier {
|
|
|
178
178
|
systemPrompt: "You summarize server errors for developers. Write 1-2 short sentences. Be direct and actionable. Do not include any secrets, passwords, or API key values — only refer to them by name (e.g. 'the OPENAI_API_KEY').",
|
|
179
179
|
userPrompt: `Summarize this error for a developer notification:\n\nCategory: ${classification.category}\nError: ${safeError}\n\nStack (first 300 chars): ${safeStack.slice(0, 300)}`,
|
|
180
180
|
maxTokens: 100,
|
|
181
|
-
category: "
|
|
181
|
+
category: "chat",
|
|
182
182
|
});
|
|
183
183
|
|
|
184
184
|
// Double-sanitize the AI response (in case the AI echoes something)
|