wolverine-ai 1.7.1 → 2.0.0

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
@@ -204,7 +204,7 @@ The error hook auto-patches Fastify and Express via `--require` preload. No midd
204
204
 
205
205
  ## Agent Tool Harness
206
206
 
207
- The AI agent has 16 built-in tools (inspired by [claw-code](https://github.com/ultraworkers/claw-code)):
207
+ The AI agent has 18 built-in tools (inspired by [claw-code](https://github.com/ultraworkers/claw-code)):
208
208
 
209
209
  | Tool | Category | Description |
210
210
  |------|----------|-------------|
@@ -222,6 +222,8 @@ The AI agent has 16 built-in tools (inspired by [claw-code](https://github.com/u
222
222
  | `run_db_fix` | Database | UPDATE/DELETE/INSERT/ALTER on SQLite (auto-backup before write) |
223
223
  | `check_port` | Diagnostic | Check if a port is in use and by what process |
224
224
  | `check_env` | Diagnostic | Check environment variables (values auto-redacted) |
225
+ | `audit_deps` | Deps | Full health check: vulnerabilities, outdated, peer conflicts, unused |
226
+ | `check_migration` | Deps | Known upgrade paths (express→fastify, moment→dayjs, etc.) |
225
227
  | `web_fetch` | Research | Fetch URL content for documentation/research |
226
228
  | `done` | Control | Signal task completion with summary |
227
229
 
@@ -286,23 +288,35 @@ Secured with `WOLVERINE_ADMIN_KEY` + IP allowlist (localhost + `WOLVERINE_ADMIN_
286
288
 
287
289
  ---
288
290
 
289
- ## 10-Model Configuration
291
+ ## 10-Model Configuration (OpenAI + Anthropic)
290
292
 
291
- Every AI task has its own model slot. Customize in `.env.local`:
293
+ Every AI task has its own model slot. **Mix and match providers** — set any slot to a `claude-*` model for Anthropic or `gpt-*` for OpenAI. Provider is auto-detected from the model name.
292
294
 
293
- | Env Variable | Role | Needs Tools? | Cost Impact |
295
+ ```bash
296
+ # .env.local — use Anthropic for reasoning, OpenAI for coding
297
+ REASONING_MODEL=claude-sonnet-4-20250514
298
+ CODING_MODEL=gpt-5.3-codex
299
+ CHAT_MODEL=claude-haiku-4-20250414
300
+ AUDIT_MODEL=claude-haiku-4-20250414
301
+ ```
302
+
303
+ | Env Variable | Role | Needs Tools? | Example Models |
294
304
  |---|---|---|---|
295
- | `REASONING_MODEL` | Multi-file agent | Yes | High (agent loop) |
296
- | `CODING_MODEL` | Code repair/generation | Responses API | Medium-high |
297
- | `CHAT_MODEL` | Simple text responses | No | Low |
298
- | `TOOL_MODEL` | Chat with function calling | **Yes** | Medium |
299
- | `CLASSIFIER_MODEL` | SIMPLE/TOOLS/AGENT routing | No | ~10 tokens |
300
- | `AUDIT_MODEL` | Injection detection (every error) | No | Low |
301
- | `COMPACTING_MODEL` | Text compression for brain | No | Low |
302
- | `RESEARCH_MODEL` | Deep research on failures | No | High (rare) |
303
- | `TEXT_EMBEDDING_MODEL` | Brain vector embeddings | No | Very low |
304
-
305
- Reasoning models (`o-series`, `gpt-5-nano`) automatically get 4x token limits to accommodate chain-of-thought.
305
+ | `REASONING_MODEL` | Multi-file agent | Yes | `claude-sonnet-4`, `gpt-5.4` |
306
+ | `CODING_MODEL` | Code repair/generation | Yes | `claude-sonnet-4`, `gpt-5.3-codex` |
307
+ | `CHAT_MODEL` | Simple text responses | No | `claude-haiku-4`, `gpt-5.4-mini` |
308
+ | `TOOL_MODEL` | Chat with function calling | **Yes** | `claude-sonnet-4`, `gpt-4o-mini` |
309
+ | `CLASSIFIER_MODEL` | SIMPLE/TOOLS/AGENT routing | No | `claude-haiku-4`, `gpt-4o-mini` |
310
+ | `AUDIT_MODEL` | Injection detection (every error) | No | `claude-haiku-4`, `gpt-5.4-nano` |
311
+ | `COMPACTING_MODEL` | Text compression for brain | No | `claude-haiku-4`, `gpt-5.4-nano` |
312
+ | `RESEARCH_MODEL` | Deep research on failures | No | `claude-opus-4`, `gpt-4o` |
313
+ | `TEXT_EMBEDDING_MODEL` | Brain vector embeddings | No | `text-embedding-3-small` (OpenAI only) |
314
+
315
+ **Notes:**
316
+ - Embeddings always use OpenAI (Anthropic doesn't have an embedding API)
317
+ - Tools (all 18) work identically on both providers — normalized at the client level
318
+ - Telemetry tracks usage by model AND by provider (`openai` / `anthropic`)
319
+ - Any future model from either provider works automatically — just set the model name
306
320
 
307
321
  ---
308
322
 
@@ -492,6 +506,19 @@ Auto-discovered from `src/skills/`. Each skill exports metadata for the registry
492
506
  - **db.idempotent(key, fn)** — Database-level dedup for critical writes (payments, orders)
493
507
  - Auto-injected into agent prompts when building database features
494
508
 
509
+ ### Dependency Manager (`src/skills/deps.js`)
510
+ - **diagnose()** — structured diagnosis of dependency errors before AI runs (zero tokens)
511
+ - **healthReport()** — full audit: vulnerabilities, outdated, peer conflicts, unused packages, lock file, health score
512
+ - **getMigration()** — known upgrade paths with code transformation patterns:
513
+
514
+ | From | To | Why |
515
+ |------|----|-----|
516
+ | `express` | `fastify` | 5.6x faster, async-first, built-in validation |
517
+ | `moment` | `dayjs` | Maintenance mode, 70KB → 2KB |
518
+ | `request` | `node-fetch` | Deprecated since 2020 |
519
+ | `body-parser` | built-in | Included in Express 4.16+ / Fastify |
520
+ | callbacks | `async/await` | Cleaner error handling, no callback hell |
521
+
495
522
  Add new skills by creating a file in `src/skills/` with `SKILL_NAME`, `SKILL_DESCRIPTION`, `SKILL_KEYWORDS`, `SKILL_USAGE` exports.
496
523
 
497
524
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wolverine-ai",
3
- "version": "1.7.1",
3
+ "version": "2.0.0",
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": {
@@ -55,6 +55,7 @@
55
55
  "README.md"
56
56
  ],
57
57
  "dependencies": {
58
+ "@anthropic-ai/sdk": "^0.82.0",
58
59
  "chalk": "^4.1.2",
59
60
  "diff": "^7.0.0",
60
61
  "dotenv": "^16.4.7",
@@ -261,6 +261,33 @@ const TOOL_DEFINITIONS = [
261
261
  },
262
262
  },
263
263
  },
264
+ // ── DEPENDENCY MANAGEMENT ──
265
+ {
266
+ type: "function",
267
+ function: {
268
+ name: "audit_deps",
269
+ description: "Run a full dependency health check: npm audit (vulnerabilities), outdated packages, peer dep conflicts, unused packages, lock file status. Returns a health score and actionable fixes. Use BEFORE editing code when the error might be a dependency issue.",
270
+ parameters: {
271
+ type: "object",
272
+ properties: {},
273
+ required: [],
274
+ },
275
+ },
276
+ },
277
+ {
278
+ type: "function",
279
+ function: {
280
+ name: "check_migration",
281
+ description: "Check if a package has a known migration/upgrade path. Use when a deprecated API or old package is causing errors. Returns the recommended replacement and code transformation patterns.",
282
+ parameters: {
283
+ type: "object",
284
+ properties: {
285
+ package: { type: "string", description: "Package name to check (e.g. 'express', 'moment', 'request')" },
286
+ },
287
+ required: ["package"],
288
+ },
289
+ },
290
+ },
264
291
  // ── COMPLETION ──
265
292
  {
266
293
  type: "function",
@@ -352,6 +379,10 @@ DIAGNOSTICS:
352
379
  - check_port: Check if a port is in use and by what process
353
380
  - check_env: Check environment variables (values auto-redacted for security)
354
381
 
382
+ DEPENDENCY MANAGEMENT:
383
+ - audit_deps: Full health check (vulnerabilities, outdated, peer conflicts, unused). Use FIRST for dependency errors.
384
+ - check_migration: Check if a package has a known upgrade path (express→fastify, moment→dayjs, etc.)
385
+
355
386
  RESEARCH:
356
387
  - web_fetch: Fetch a URL (docs, npm packages, error solutions)
357
388
 
@@ -365,7 +396,7 @@ RESEARCH:
365
396
 
366
397
  | Error Pattern | Category | Diagnostic Steps | Fix |
367
398
  |---|---|---|---|
368
- | Cannot find module 'X' | DEPENDENCY | check package.json | bash_exec: npm install X |
399
+ | Cannot find module 'X' | DEPENDENCY | audit_deps first, check package.json | bash_exec: npm install X |
369
400
  | Cannot find module './X' | IMPORT | glob_files to find real path | edit_file: fix require path |
370
401
  | ENOENT: no such file | FILE MISSING | list_dir to check structure | write_file or move_file |
371
402
  | EACCES/EPERM | PERMISSION | bash_exec: ls -la | bash_exec: chmod 755 |
@@ -530,6 +561,8 @@ Project root: ${this.cwd}${primaryFile ? `\nPrimary crash file: ${primaryFile}`
530
561
  case "check_env": return this._checkEnv(args);
531
562
  case "inspect_db": return this._inspectDb(args);
532
563
  case "run_db_fix": return this._runDbFix(args);
564
+ case "audit_deps": return this._auditDeps(args);
565
+ case "check_migration": return this._checkMigration(args);
533
566
  case "done": return this._done(args);
534
567
  // Legacy aliases
535
568
  case "list_files": return this._globFiles({ pattern: (args.dir || ".") + "/*" + (args.pattern || "") });
@@ -932,6 +965,52 @@ Project root: ${this.cwd}${primaryFile ? `\nPrimary crash file: ${primaryFile}`
932
965
  } catch (e) { return { content: `DB error: ${e.message}` }; }
933
966
  }
934
967
 
968
+ _auditDeps() {
969
+ try {
970
+ const { healthReport } = require("../skills/deps");
971
+ const report = healthReport(this.cwd);
972
+ const { redact } = require("../security/secret-redactor");
973
+ const lines = [
974
+ `Dependency Health Score: ${report.score}/100 (${report.summary})`,
975
+ "",
976
+ `Vulnerabilities: ${report.audit.vulnerabilities} (${report.audit.critical} critical, ${report.audit.high} high, ${report.audit.moderate} moderate)`,
977
+ report.audit.fixes.length > 0 ? `Fix: ${report.audit.fixes.join(", ")}` : "",
978
+ "",
979
+ `Outdated: ${report.outdated.length} packages`,
980
+ ...report.outdated.slice(0, 10).map(p => ` ${p.name}: ${p.current} → ${p.latest}`),
981
+ report.outdated.length > 10 ? ` ... and ${report.outdated.length - 10} more` : "",
982
+ "",
983
+ `Peer Dependency Issues: ${report.peerDeps.length}`,
984
+ ...report.peerDeps.slice(0, 5).map(p => ` ${p.package}: ${p.requires}`),
985
+ "",
986
+ `Unused Packages: ${report.unused.length}`,
987
+ report.unused.length > 0 ? ` ${report.unused.join(", ")}` : "",
988
+ "",
989
+ `Lock File: ${report.lockFile.healthy ? "OK" : report.lockFile.issue}`,
990
+ report.lockFile.fix ? ` Fix: ${report.lockFile.fix}` : "",
991
+ ].filter(l => l !== undefined);
992
+ console.log(chalk.gray(` 📦 Deps audit: score ${report.score}/100, ${report.audit.vulnerabilities} vulns, ${report.outdated.length} outdated`));
993
+ return { content: redact(lines.join("\n")) };
994
+ } catch (e) { return { content: `Deps audit error: ${e.message}` }; }
995
+ }
996
+
997
+ _checkMigration(args) {
998
+ try {
999
+ const { getMigration } = require("../skills/deps");
1000
+ const migration = getMigration(args.package);
1001
+ if (!migration) return { content: `No known migration path for '${args.package}'.` };
1002
+ const lines = [
1003
+ `Migration: ${args.package} → ${migration.to}`,
1004
+ `Reason: ${migration.reason}`,
1005
+ "",
1006
+ "Code patterns:",
1007
+ ...migration.patterns.map(p => ` ${p.from}\n → ${p.to}`),
1008
+ ];
1009
+ console.log(chalk.gray(` 📦 Migration: ${args.package} → ${migration.to}`));
1010
+ return { content: lines.join("\n") };
1011
+ } catch (e) { return { content: `Migration check error: ${e.message}` }; }
1012
+ }
1013
+
935
1014
  _done(args) {
936
1015
  console.log(chalk.green(` ✅ Agent done: ${args.summary}`));
937
1016
  if (this.logger) {
@@ -23,9 +23,9 @@ const { getModel } = require("../core/models");
23
23
 
24
24
  // Tool restrictions per agent type (claw-code: allowed_tools_for_subagent)
25
25
  const AGENT_TOOL_SETS = {
26
- explore: ["read_file", "glob_files", "grep_code", "git_log", "git_diff", "list_dir", "check_env", "check_port", "inspect_db", "done"],
27
- plan: ["read_file", "glob_files", "grep_code", "list_dir", "inspect_db", "check_env", "search_brain", "done"],
28
- fix: ["read_file", "write_file", "edit_file", "glob_files", "grep_code", "bash_exec", "move_file", "run_db_fix", "done"],
26
+ explore: ["read_file", "glob_files", "grep_code", "git_log", "git_diff", "list_dir", "check_env", "check_port", "inspect_db", "audit_deps", "done"],
27
+ plan: ["read_file", "glob_files", "grep_code", "list_dir", "inspect_db", "check_env", "audit_deps", "check_migration", "search_brain", "done"],
28
+ fix: ["read_file", "write_file", "edit_file", "glob_files", "grep_code", "bash_exec", "move_file", "run_db_fix", "audit_deps", "done"],
29
29
  verify: ["read_file", "glob_files", "grep_code", "bash_exec", "inspect_db", "check_port", "done"],
30
30
  research: ["read_file", "grep_code", "web_fetch", "search_brain", "done"],
31
31
  security: ["read_file", "glob_files", "grep_code", "inspect_db", "done"],
@@ -44,7 +44,7 @@ const SEED_DOCS = [
44
44
  metadata: { topic: "security" },
45
45
  },
46
46
  {
47
- text: "Wolverine model tiers: REASONING_MODEL for deep multi-step debugging. CODING_MODEL for code repair generation. CHAT_MODEL for explanations and summaries. AUDIT_MODEL for security scans (runs every error, keep cheap). UTILITY_MODEL for JSON formatting and thought compaction. TEXT_EMBEDDING_MODEL for brain vector embeddings.",
47
+ text: "Wolverine supports both OpenAI and Anthropic models. Provider auto-detected from model name: claude-* Anthropic, gpt-*/o1-*/o3-* → OpenAI. Mix and match per role: e.g., Anthropic for reasoning (claude-sonnet-4), OpenAI for coding (gpt-5.3-codex). 10 model slots: REASONING_MODEL, CODING_MODEL, CHAT_MODEL, TOOL_MODEL, CLASSIFIER_MODEL, AUDIT_MODEL, COMPACTING_MODEL, RESEARCH_MODEL, TEXT_EMBEDDING_MODEL (always OpenAI Anthropic has no embeddings). Configure in .env.local or settings.json. Tools work identically on both providers — ai-client.js normalizes all responses to same {content, toolCalls, usage} shape. Telemetry tracks usage byModel AND byProvider (openai/anthropic) automatically.",
48
48
  metadata: { topic: "model-config" },
49
49
  },
50
50
  {
@@ -228,9 +228,13 @@ const SEED_DOCS = [
228
228
  metadata: { topic: "idempotency" },
229
229
  },
230
230
  {
231
- text: "Heal pipeline no longer requires a file path. When no file is identified from the error (database errors, config problems, port conflicts), the pipeline skips fast path and goes straight to the agent, which uses investigation tools (glob_files, grep_code, list_dir, inspect_db, check_env, check_port) to find the root cause. Agent verification for no-file errors: if agent made changes or ran commands, trust the agent's assessment. For file-based errors, verification uses syntax check + boot probe as before.",
231
+ text: "Heal pipeline no longer requires a file path. When no file is identified from the error (database errors, config problems, port conflicts), the pipeline skips fast path and goes straight to the agent, which uses investigation tools (glob_files, grep_code, list_dir, inspect_db, check_env, check_port, audit_deps) to find the root cause. Agent verification for no-file errors: if agent made changes or ran commands, trust the agent's assessment. For file-based errors, verification uses syntax check + boot probe + route probe as before.",
232
232
  metadata: { topic: "fileless-heal" },
233
233
  },
234
+ {
235
+ text: "Dependency manager skill (src/skills/deps.js): structured npm dependency analysis + repair. diagnose(errorMessage, cwd) returns {diagnosed, category, summary, fixes} — categories: missing_install, missing_package, version_conflict, outdated_api, corrupted_modules. healthReport(cwd) returns full health check: npm audit (vulnerabilities), outdated packages, peer dep conflicts, unused packages, lock file status, health score 0-100. getMigration(packageName) returns known upgrade paths: express→fastify (5.6x faster), moment→dayjs (2KB vs 70KB), request→node-fetch (deprecated), body-parser→built-in, callbacks→async/await. Agent tools: audit_deps (full health check), check_migration (upgrade paths). Heal pipeline uses diagnose() in tryOperationalFix before AI — zero tokens for dependency issues.",
236
+ metadata: { topic: "skill-deps" },
237
+ },
234
238
  ];
235
239
 
236
240
  class Brain {
@@ -1,4 +1,4 @@
1
- const { getClient, aiCall } = require("../core/ai-client");
1
+ const { getClient, aiCall, detectProvider } = require("../core/ai-client");
2
2
  const { getModel } = require("../core/models");
3
3
 
4
4
  /**
@@ -41,7 +41,8 @@ async function embed(text) {
41
41
  const cached = _cacheGet(text);
42
42
  if (cached) return cached;
43
43
 
44
- const openai = getClient();
44
+ // Embeddings always use OpenAI (Anthropic doesn't have an embedding API)
45
+ const openai = getClient("openai");
45
46
  const model = getModel("embedding");
46
47
 
47
48
  const response = await openai.embeddings.create({
@@ -78,7 +79,8 @@ async function embedBatch(texts) {
78
79
 
79
80
  if (uncached.length === 0) return results;
80
81
 
81
- const openai = getClient();
82
+ // Embeddings always use OpenAI (Anthropic doesn't have an embedding API)
83
+ const openai = getClient("openai");
82
84
  const model = getModel("embedding");
83
85
 
84
86
  const response = await openai.embeddings.create({