wolverine-ai 2.6.3 → 2.7.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
@@ -552,6 +552,15 @@ All backups stored in **`~/.wolverine-safe-backups/`** — outside the project d
552
552
  - **Retention**: unstable/verified pruned after 7 days, stable keeps 1/day after 7 days
553
553
  - Protected files never overwritten during rollback: `settings.json`, `db.js`, `.env.local`
554
554
 
555
+ ```bash
556
+ # CLI commands
557
+ wolverine --backup "before auth changes" # create snapshot
558
+ wolverine --list-backups # show all with status/age
559
+ wolverine --rollback mngt8mwb-v0sm # restore specific backup
560
+ wolverine --rollback-latest # restore most recent
561
+ wolverine --undo-rollback # undo last rollback
562
+ ```
563
+
555
564
  **Rollback & Recovery:**
556
565
 
557
566
  | Action | What it does |
package/bin/wolverine.js CHANGED
@@ -72,7 +72,45 @@ if (args.includes("--restore")) {
72
72
  process.exit(0);
73
73
  }
74
74
 
75
- // --backups: list safe backups
75
+ // --backup: create server snapshot
76
+ if (args.includes("--backup")) {
77
+ const reason = args[args.indexOf("--backup") + 1] || "manual";
78
+ const { backup } = require("../src/skills/backup");
79
+ backup(process.cwd(), reason);
80
+ process.exit(0);
81
+ }
82
+
83
+ // --list-backups: list all server snapshots
84
+ if (args.includes("--list-backups")) {
85
+ const { listBackups } = require("../src/skills/backup");
86
+ listBackups(process.cwd());
87
+ process.exit(0);
88
+ }
89
+
90
+ // --rollback: rollback to specific backup
91
+ if (args.includes("--rollback") && !args.includes("--rollback-latest") && !args.includes("--undo-rollback")) {
92
+ const id = args[args.indexOf("--rollback") + 1];
93
+ if (!id) { console.log("Usage: wolverine --rollback <backup-id>"); process.exit(1); }
94
+ const { rollback } = require("../src/skills/backup");
95
+ const result = rollback(process.cwd(), id);
96
+ process.exit(result.success ? 0 : 1);
97
+ }
98
+
99
+ // --rollback-latest: rollback to most recent backup
100
+ if (args.includes("--rollback-latest")) {
101
+ const { rollbackLatest } = require("../src/skills/backup");
102
+ const result = rollbackLatest(process.cwd());
103
+ process.exit(result.success ? 0 : 1);
104
+ }
105
+
106
+ // --undo-rollback: undo last rollback
107
+ if (args.includes("--undo-rollback")) {
108
+ const { undoRollback } = require("../src/skills/backup");
109
+ const result = undoRollback(process.cwd());
110
+ process.exit(result.success ? 0 : 1);
111
+ }
112
+
113
+ // --backups: list safe backups (update snapshots)
76
114
  if (args.includes("--backups")) {
77
115
  const { listSafeBackups } = require("../src/skills/update");
78
116
  const backups = listSafeBackups();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wolverine-ai",
3
- "version": "2.6.3",
3
+ "version": "2.7.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,7 +55,7 @@ class ResearchAgent {
55
55
 
56
56
  const namespace = success ? "fixes" : "errors";
57
57
  const prefix = success ? "FIXED" : "FAILED";
58
- const text = `${prefix}: ${safeError} in ${filePath}. ${success ? "Solution" : "Attempted"}: ${safeExplanation}`;
58
+ const text = `${prefix}: ${safeError} in ${filePath}. ${success ? "Solution" : "Attempted (DO NOT REPEAT)"}: ${safeExplanation}`;
59
59
 
60
60
  await this.brain.remember(namespace, text, { type: success ? "fix-success" : "fix-failure", file: filePath });
61
61
  console.log(chalk.gray(` 🧠 ${success ? "✅" : "❌"} Recorded ${prefix.toLowerCase()} for ${safeError.slice(0, 50)}`));
@@ -237,6 +237,10 @@ const SEED_DOCS = [
237
237
  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.",
238
238
  metadata: { topic: "skill-deps" },
239
239
  },
240
+ {
241
+ text: "Backup skill (src/skills/backup.js): agent-friendly backup/rollback. Functions: backup(cwd, reason) creates snapshot, rollback(cwd, id) restores specific backup, rollbackLatest(cwd) restores most recent, undoRollback(cwd) undoes last rollback, listBackups(cwd) shows all with status/age/reason. Agent can use via bash_exec: node -e \"require('./src/skills/backup').backup('.', 'before change')\". CLI: wolverine --backup 'reason', wolverine --list-backups, wolverine --rollback <id>, wolverine --rollback-latest, wolverine --undo-rollback. All stored in ~/.wolverine-safe-backups/snapshots/. Create backup BEFORE any risky server change.",
242
+ metadata: { topic: "backup-skill" },
243
+ },
240
244
  {
241
245
  text: "CRITICAL: Never run raw 'npm install wolverine-ai' or 'git pull' to update — these OVERWRITE server/, .wolverine/ (brain, backups, events), and .env.local. Always use the safe update skill: wolverine --update (CLI), safeUpdate(cwd) (programmatic), or let auto-update handle it. ALL backups (heal snapshots + update snapshots) stored in ~/.wolverine-safe-backups/ (OUTSIDE project, survives git clean, rm -rf, project deletion). Structure: ~/.wolverine-safe-backups/snapshots/ (heal backups), ~/.wolverine-safe-backups/updates/ (pre-update snapshots), ~/.wolverine-safe-backups/manifest.json (backup registry). Old .wolverine/backups/ auto-migrated on first run. Restore with: wolverine --restore <name>. List: wolverine --backups.",
242
246
  metadata: { topic: "safe-update-warning" },
@@ -413,6 +413,29 @@ async function _healImpl({ stderr, cwd, sandbox, notifier, rateLimiter, backupMa
413
413
  });
414
414
  }
415
415
 
416
+ // Record outcome to brain — both successes AND failures with full context
417
+ if (brain && brain._initialized) {
418
+ try {
419
+ if (goalResult.success) {
420
+ await brain.remember("fixes",
421
+ `FIXED (${goalResult.mode}, iter ${goalResult.iteration}): ${parsed.errorMessage} in ${parsed.filePath}:${parsed.line}. ` +
422
+ `Solution: ${goalResult.explanation?.slice(0, 200)}. Files: ${(goalResult.agentStats?.filesModified || []).join(", ")}`,
423
+ { type: "fix-success", file: parsed.filePath, error: parsed.errorMessage, mode: goalResult.mode }
424
+ );
425
+ } else {
426
+ // Record failure with all attempts so brain knows what NOT to do
427
+ const attemptSummary = (goalResult.attempts || []).map(a =>
428
+ `Iter ${a.iteration} (${a.mode}): ${a.explanation?.slice(0, 80)}`
429
+ ).join("; ");
430
+ await brain.remember("errors",
431
+ `UNRESOLVED: ${parsed.errorMessage} in ${parsed.filePath}:${parsed.line}. ` +
432
+ `Tried ${goalResult.iteration} iterations: ${attemptSummary}. All failed.`,
433
+ { type: "fix-failure", file: parsed.filePath, error: parsed.errorMessage, attempts: goalResult.iteration }
434
+ );
435
+ }
436
+ } catch {}
437
+ }
438
+
416
439
  if (goalResult.success) {
417
440
  if (logger) logger.info(EVENT_TYPES.HEAL_SUCCESS, goalResult.explanation, { iteration: goalResult.iteration, mode: goalResult.mode });
418
441
  return { healed: true, ...goalResult };
package/src/index.js CHANGED
@@ -37,6 +37,7 @@ const { sqlGuard, SafeDB, scanForInjection, idempotencyGuard, idempotencyAfterHo
37
37
  const { diagnose: diagnoseDeps, healthReport: depsHealthReport, getMigration } = require("./skills/deps");
38
38
  const { checkForUpdate, upgrade: upgradeWolverine, getCurrentVersion } = require("./platform/auto-update");
39
39
  const { safeUpdate, createSafeBackup, listSafeBackups, restoreFromSafeBackup } = require("./skills/update");
40
+ const { backup, rollback, rollbackLatest, undoRollback, listBackups } = require("./skills/backup");
40
41
 
41
42
  module.exports = {
42
43
  // Core
@@ -108,4 +109,9 @@ module.exports = {
108
109
  createSafeBackup,
109
110
  listSafeBackups,
110
111
  restoreFromSafeBackup,
112
+ backup,
113
+ rollback,
114
+ rollbackLatest,
115
+ undoRollback,
116
+ listBackups,
111
117
  };
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Backup Skill — agent-friendly backup/rollback interface.
3
+ *
4
+ * Wraps BackupManager with simple callable functions and CLI commands.
5
+ * The agent can create snapshots, list backups, rollback, and undo —
6
+ * all through bash_exec or direct function calls.
7
+ *
8
+ * CLI commands (via wolverine):
9
+ * wolverine --backup "reason" Create a snapshot
10
+ * wolverine --rollback <id> Rollback to a specific backup
11
+ * wolverine --rollback-latest Rollback to most recent backup
12
+ * wolverine --undo-rollback Undo the last rollback
13
+ * wolverine --list-backups List all backups with status
14
+ *
15
+ * Programmatic:
16
+ * const { backup, rollback, listBackups } = require("wolverine-ai");
17
+ *
18
+ * Agent tool usage (via bash_exec):
19
+ * bash_exec: node -e "require('./src/skills/backup').backup('.', 'before risky change')"
20
+ * bash_exec: node -e "require('./src/skills/backup').rollbackLatest('.')"
21
+ */
22
+
23
+ const path = require("path");
24
+ const chalk = require("chalk");
25
+
26
+ /**
27
+ * Create a backup snapshot of server/.
28
+ * @param {string} cwd — project root
29
+ * @param {string} reason — why this backup was created
30
+ * @returns {{ id, fileCount, reason }}
31
+ */
32
+ function backup(cwd, reason = "manual") {
33
+ const { BackupManager } = require("../backup/backup-manager");
34
+ const bm = new BackupManager(cwd);
35
+ const id = bm.createBackup(reason);
36
+ const entry = bm.manifest.backups.find(b => b.id === id);
37
+ console.log(chalk.green(` 💾 Backup created: ${id} (${entry?.fileCount || 0} files) — ${reason}`));
38
+ return { id, fileCount: entry?.fileCount || 0, reason };
39
+ }
40
+
41
+ /**
42
+ * Rollback to a specific backup.
43
+ * @param {string} cwd — project root
44
+ * @param {string} backupId — backup to restore
45
+ * @returns {{ success, preRollbackId }}
46
+ */
47
+ function rollback(cwd, backupId) {
48
+ const { BackupManager } = require("../backup/backup-manager");
49
+ const bm = new BackupManager(cwd);
50
+ const result = bm.rollbackTo(backupId);
51
+ if (result.success) {
52
+ console.log(chalk.green(` ↩️ Rolled back to ${backupId} (pre-rollback: ${result.preRollbackId})`));
53
+ } else {
54
+ console.log(chalk.red(` ❌ Rollback failed: backup ${backupId} not found`));
55
+ }
56
+ return result;
57
+ }
58
+
59
+ /**
60
+ * Rollback to the most recent backup.
61
+ */
62
+ function rollbackLatest(cwd) {
63
+ const { BackupManager } = require("../backup/backup-manager");
64
+ const bm = new BackupManager(cwd);
65
+ const result = bm.rollbackLatest();
66
+ if (result.success) {
67
+ console.log(chalk.green(` ↩️ Rolled back to latest backup (pre-rollback: ${result.preRollbackId})`));
68
+ } else {
69
+ console.log(chalk.red(" ❌ No backups available to rollback"));
70
+ }
71
+ return result;
72
+ }
73
+
74
+ /**
75
+ * Undo the last rollback.
76
+ */
77
+ function undoRollback(cwd) {
78
+ const { BackupManager } = require("../backup/backup-manager");
79
+ const bm = new BackupManager(cwd);
80
+ const result = bm.undoRollback();
81
+ if (result.success) {
82
+ console.log(chalk.green(" ↩️ Undo rollback — restored pre-rollback state"));
83
+ } else {
84
+ console.log(chalk.red(" ❌ No rollback to undo"));
85
+ }
86
+ return result;
87
+ }
88
+
89
+ /**
90
+ * List all backups with status, age, reason, file count.
91
+ * @returns {Array<{ id, status, reason, fileCount, age, timestamp }>}
92
+ */
93
+ function listBackups(cwd) {
94
+ const { BackupManager } = require("../backup/backup-manager");
95
+ const bm = new BackupManager(cwd);
96
+ const backups = bm.getAll();
97
+ const stats = bm.getStats();
98
+
99
+ console.log(chalk.bold(`\n Backups: ${stats.total} total (${stats.stable} stable, ${stats.verified} verified, ${stats.unstable} unstable)\n`));
100
+
101
+ for (const b of backups.slice(-15).reverse()) {
102
+ const age = Math.round((Date.now() - b.timestamp) / 60000);
103
+ const ageStr = age < 60 ? `${age}m ago` : `${Math.round(age / 60)}h ago`;
104
+ const icon = b.status === "stable" ? "🟢" : b.status === "verified" ? "🔵" : "⚪";
105
+ console.log(` ${icon} ${b.id} ${b.status.padEnd(9)} ${b.fileCount} files ${ageStr} ${b.reason || ""}`);
106
+ }
107
+ console.log("");
108
+
109
+ return backups.map(b => ({
110
+ id: b.id,
111
+ status: b.status,
112
+ reason: b.reason,
113
+ fileCount: b.fileCount,
114
+ age: Math.round((Date.now() - b.timestamp) / 60000),
115
+ timestamp: b.timestamp,
116
+ }));
117
+ }
118
+
119
+ /**
120
+ * Get rollback log.
121
+ */
122
+ function getRollbackLog(cwd) {
123
+ const { BackupManager } = require("../backup/backup-manager");
124
+ const bm = new BackupManager(cwd);
125
+ return bm.getRollbackLog();
126
+ }
127
+
128
+ // ── Skill Metadata ──
129
+
130
+ const SKILL_NAME = "backup";
131
+ const SKILL_DESCRIPTION = "Backup and rollback for server/ directory. Create snapshots before risky changes, rollback to any previous state, undo rollbacks. All backups stored safely in ~/.wolverine-safe-backups/. Agent can use via bash_exec or direct tool calls.";
132
+ const SKILL_KEYWORDS = ["backup", "rollback", "restore", "undo", "snapshot", "revert", "save", "recovery"];
133
+ const SKILL_USAGE = `// Create backup before making changes
134
+ const { backup } = require("wolverine-ai");
135
+ backup(process.cwd(), "before adding auth routes");
136
+
137
+ // List all backups
138
+ const { listBackups } = require("wolverine-ai");
139
+ listBackups(process.cwd());
140
+
141
+ // Rollback to specific backup
142
+ const { rollback } = require("wolverine-ai");
143
+ rollback(process.cwd(), "mngt8mwb-v0sm");
144
+
145
+ // Rollback to latest
146
+ const { rollbackLatest } = require("wolverine-ai");
147
+ rollbackLatest(process.cwd());
148
+
149
+ // Undo last rollback
150
+ const { undoRollback } = require("wolverine-ai");
151
+ undoRollback(process.cwd());
152
+
153
+ // CLI:
154
+ // wolverine --backup "before auth changes"
155
+ // wolverine --list-backups
156
+ // wolverine --rollback mngt8mwb-v0sm
157
+ // wolverine --rollback-latest
158
+ // wolverine --undo-rollback`;
159
+
160
+ module.exports = {
161
+ SKILL_NAME, SKILL_DESCRIPTION, SKILL_KEYWORDS, SKILL_USAGE,
162
+ backup, rollback, rollbackLatest, undoRollback, listBackups, getRollbackLog,
163
+ };