wolverine-ai 6.2.1 → 6.2.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/claw/setup.js +169 -22
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wolverine-ai",
3
- "version": "6.2.1",
3
+ "version": "6.2.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": {
package/src/claw/setup.js CHANGED
@@ -247,19 +247,41 @@ function detectWolverine(cwd) {
247
247
  brainExists: fs.existsSync(path.join(cwd, ".wolverine", "brain")),
248
248
  };
249
249
 
250
+ // Check if we're inside the wolverine repo itself
250
251
  try {
251
252
  const pkg = JSON.parse(fs.readFileSync(path.join(cwd, "package.json"), "utf-8"));
252
- if (pkg.name === "wolverine-ai" || pkg.dependencies?.["wolverine-ai"]) {
253
+ if (pkg.name === "wolverine-ai") {
253
254
  result.installed = true;
254
- result.version = pkg.version || pkg.dependencies?.["wolverine-ai"];
255
+ result.version = pkg.version;
256
+ return result;
255
257
  }
256
- // Also check if we're inside the wolverine repo itself
257
- if (fs.existsSync(path.join(cwd, "src", "core", "wolverine.js"))) {
258
+ // Check if wolverine-ai is a dependency
259
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies, ...pkg.optionalDependencies };
260
+ if (deps["wolverine-ai"]) {
258
261
  result.installed = true;
259
- result.version = pkg.version;
262
+ result.version = deps["wolverine-ai"];
260
263
  }
261
264
  } catch {}
262
265
 
266
+ // Check if wolverine.js exists in src/ (repo checkout)
267
+ if (fs.existsSync(path.join(cwd, "src", "core", "wolverine.js"))) {
268
+ result.installed = true;
269
+ try {
270
+ const pkg = JSON.parse(fs.readFileSync(path.join(cwd, "package.json"), "utf-8"));
271
+ result.version = pkg.version;
272
+ } catch {}
273
+ }
274
+
275
+ // Check node_modules
276
+ if (!result.installed) {
277
+ try {
278
+ const pkgPath = require.resolve("wolverine-ai/package.json", { paths: [cwd] });
279
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
280
+ result.installed = true;
281
+ result.version = pkg.version;
282
+ } catch {}
283
+ }
284
+
263
285
  return result;
264
286
  }
265
287
 
@@ -325,13 +347,48 @@ function mergeConfig(openclawConfig, defaults) {
325
347
 
326
348
  // ── Scaffolding ─────────────────────────────────────────────────
327
349
 
350
+ /**
351
+ * Find the wolverine-ai template directory.
352
+ * Works whether wolverine is the project root OR installed in node_modules.
353
+ */
354
+ function _findTemplateDir() {
355
+ // 1. Relative to this file (we're in src/claw/setup.js → ../../wolverine-claw/)
356
+ const fromSrc = path.join(__dirname, "..", "..", "wolverine-claw");
357
+ if (fs.existsSync(path.join(fromSrc, "index.js"))) return fromSrc;
358
+
359
+ // 2. Via require.resolve (works when wolverine-ai is a node_modules dep)
360
+ try {
361
+ const pkgPath = require.resolve("wolverine-ai/package.json");
362
+ const pkgDir = path.dirname(pkgPath);
363
+ const fromPkg = path.join(pkgDir, "wolverine-claw");
364
+ if (fs.existsSync(path.join(fromPkg, "index.js"))) return fromPkg;
365
+ } catch {}
366
+
367
+ // 3. Check common node_modules locations
368
+ const candidates = [
369
+ path.join(process.cwd(), "node_modules", "wolverine-ai", "wolverine-claw"),
370
+ path.join(os.homedir(), "node_modules", "wolverine-ai", "wolverine-claw"),
371
+ ];
372
+ for (const c of candidates) {
373
+ if (fs.existsSync(path.join(c, "index.js"))) return c;
374
+ }
375
+
376
+ return null;
377
+ }
378
+
328
379
  /**
329
380
  * Scaffold the wolverine-claw directory from template + merged config.
330
381
  */
331
382
  function scaffold(cwd, mergedConfig, env) {
332
383
  const clawDir = path.join(cwd, "wolverine-claw");
384
+ const templateDir = _findTemplateDir();
333
385
  const results = { created: [], skipped: [], errors: [] };
334
386
 
387
+ if (!templateDir) {
388
+ results.errors.push("Could not find wolverine-ai templates. Is wolverine-ai installed?");
389
+ return results;
390
+ }
391
+
335
392
  // Create directories
336
393
  const dirs = ["config", "plugins", "workspace", "skills"];
337
394
  for (const d of dirs) {
@@ -352,12 +409,11 @@ function scaffold(cwd, mergedConfig, env) {
352
409
  }
353
410
 
354
411
  // Copy index.js from template
355
- const indexSrc = path.join(cwd, "wolverine-claw", "index.js");
356
- if (!fs.existsSync(indexSrc)) {
357
- // Copy from our built-in template
358
- const templateIndex = path.join(__dirname, "..", "..", "wolverine-claw", "index.js");
359
- if (fs.existsSync(templateIndex)) {
360
- fs.copyFileSync(templateIndex, indexSrc);
412
+ const indexDest = path.join(clawDir, "index.js");
413
+ if (!fs.existsSync(indexDest)) {
414
+ const indexSrc = path.join(templateDir, "index.js");
415
+ if (fs.existsSync(indexSrc)) {
416
+ fs.copyFileSync(indexSrc, indexDest);
361
417
  results.created.push("index.js");
362
418
  }
363
419
  } else {
@@ -367,15 +423,10 @@ function scaffold(cwd, mergedConfig, env) {
367
423
  // Copy plugin
368
424
  const pluginDest = path.join(clawDir, "plugins", "wolverine-integration.js");
369
425
  if (!fs.existsSync(pluginDest)) {
370
- const pluginSrc = path.join(cwd, "wolverine-claw", "plugins", "wolverine-integration.js");
426
+ const pluginSrc = path.join(templateDir, "plugins", "wolverine-integration.js");
371
427
  if (fs.existsSync(pluginSrc)) {
372
- results.skipped.push("plugins/wolverine-integration.js (already exists at source)");
373
- } else {
374
- const templatePlugin = path.join(__dirname, "..", "..", "wolverine-claw", "plugins", "wolverine-integration.js");
375
- if (fs.existsSync(templatePlugin)) {
376
- fs.copyFileSync(templatePlugin, pluginDest);
377
- results.created.push("plugins/wolverine-integration.js");
378
- }
428
+ fs.copyFileSync(pluginSrc, pluginDest);
429
+ results.created.push("plugins/wolverine-integration.js");
379
430
  }
380
431
  } else {
381
432
  results.skipped.push("plugins/wolverine-integration.js (already exists)");
@@ -471,6 +522,79 @@ function ensureEnvFile(cwd, env) {
471
522
  return result;
472
523
  }
473
524
 
525
+ /**
526
+ * Ensure wolverine-ai is installed as a dependency.
527
+ * Skips if we're running from the wolverine repo itself.
528
+ */
529
+ function ensureWolverineDep(cwd) {
530
+ // If we're inside the wolverine repo, skip
531
+ const pkgPath = path.join(cwd, "package.json");
532
+ try {
533
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
534
+ if (pkg.name === "wolverine-ai") {
535
+ return { installed: true, isRepo: true, alreadyPresent: true };
536
+ }
537
+ // Already a dependency?
538
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
539
+ if (deps["wolverine-ai"]) {
540
+ return { installed: true, alreadyPresent: true };
541
+ }
542
+ } catch {}
543
+
544
+ // Install it
545
+ if (!fs.existsSync(pkgPath)) {
546
+ return { installed: false, reason: "no package.json" };
547
+ }
548
+
549
+ try {
550
+ console.log(chalk.gray(" Installing wolverine-ai..."));
551
+ execSync("npm install wolverine-ai@latest 2>&1", {
552
+ cwd,
553
+ encoding: "utf-8",
554
+ timeout: 120000,
555
+ stdio: ["pipe", "pipe", "pipe"],
556
+ });
557
+ return { installed: true, alreadyPresent: false };
558
+ } catch (err) {
559
+ return { installed: false, reason: `npm install failed: ${err.message?.split("\n")[0]}` };
560
+ }
561
+ }
562
+
563
+ /**
564
+ * Add claw-related npm scripts to the user's package.json.
565
+ */
566
+ function addClawScripts(cwd) {
567
+ const pkgPath = path.join(cwd, "package.json");
568
+ if (!fs.existsSync(pkgPath)) return { added: 0 };
569
+
570
+ try {
571
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
572
+ if (!pkg.scripts) pkg.scripts = {};
573
+
574
+ const toAdd = {
575
+ "claw": "wolverine-claw",
576
+ "claw:direct": "wolverine-claw --direct",
577
+ "claw:info": "wolverine-claw --info",
578
+ };
579
+
580
+ let added = 0;
581
+ for (const [name, cmd] of Object.entries(toAdd)) {
582
+ if (!pkg.scripts[name]) {
583
+ pkg.scripts[name] = cmd;
584
+ added++;
585
+ }
586
+ }
587
+
588
+ if (added > 0) {
589
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
590
+ }
591
+
592
+ return { added, skipped: added === 0 };
593
+ } catch {
594
+ return { added: 0 };
595
+ }
596
+ }
597
+
474
598
  /**
475
599
  * Ensure openclaw is installed as a dependency.
476
600
  */
@@ -730,9 +854,21 @@ async function setup(cwd, options = {}) {
730
854
 
731
855
  log("");
732
856
 
733
- // ── Step 6: Install OpenClaw ────────────────────────────────
857
+ // ── Step 6: Install dependencies ─────────────────────────────
858
+ log(chalk.bold(" Dependencies...\n"));
859
+
860
+ // 6a: Install wolverine-ai itself if not already a dep
861
+ const wolverineDepResult = ensureWolverineDep(cwd);
862
+ if (wolverineDepResult.installed) {
863
+ log(chalk.green(` ✅ wolverine-ai ${wolverineDepResult.alreadyPresent ? "already installed" : "installed"}`));
864
+ } else if (wolverineDepResult.isRepo) {
865
+ log(chalk.gray(" ○ wolverine-ai (running from repo)"));
866
+ } else {
867
+ log(chalk.yellow(` ⚠️ wolverine-ai: ${wolverineDepResult.reason}`));
868
+ }
869
+
870
+ // 6b: Install openclaw if not already present
734
871
  if (!env.openclaw.localInstall) {
735
- log(chalk.bold(" Dependencies...\n"));
736
872
  const depResult = ensureOpenClawDep(cwd);
737
873
  if (depResult.installed) {
738
874
  log(chalk.green(` ✅ openclaw ${depResult.alreadyPresent ? "already installed" : "installed"}`));
@@ -742,9 +878,18 @@ async function setup(cwd, options = {}) {
742
878
  log(chalk.gray(` ${depResult.fallback}`));
743
879
  }
744
880
  }
745
- log("");
746
881
  }
747
882
 
883
+ // 6c: Add claw npm scripts to user's package.json
884
+ const scriptsResult = addClawScripts(cwd);
885
+ if (scriptsResult.added > 0) {
886
+ log(chalk.green(` ✅ Added ${scriptsResult.added} npm scripts (claw, claw:info, claw:direct)`));
887
+ } else if (scriptsResult.skipped) {
888
+ log(chalk.gray(" ○ npm scripts already present"));
889
+ }
890
+
891
+ log("");
892
+
748
893
  // ── Step 7: Validate ───────────────────────────────────────
749
894
  log(chalk.bold(" Validating...\n"));
750
895
 
@@ -873,4 +1018,6 @@ module.exports = {
873
1018
  validate,
874
1019
  ensureEnvFile,
875
1020
  ensureOpenClawDep,
1021
+ ensureWolverineDep,
1022
+ addClawScripts,
876
1023
  };