create-walle 0.9.13 → 0.9.15

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 (98) hide show
  1. package/README.md +8 -3
  2. package/bin/create-walle.js +232 -32
  3. package/bin/mcp-inject.js +18 -53
  4. package/package.json +3 -1
  5. package/template/claude-task-manager/api-prompts.js +11 -2
  6. package/template/claude-task-manager/approval-agent.js +7 -0
  7. package/template/claude-task-manager/db.js +94 -75
  8. package/template/claude-task-manager/docs/session-standup-command-center-design.md +242 -0
  9. package/template/claude-task-manager/docs/session-tooltip-freshness-design.md +224 -0
  10. package/template/claude-task-manager/docs/session-ux-issue-review-2026-05-01.md +369 -0
  11. package/template/claude-task-manager/fuzzy-utils.js +10 -2
  12. package/template/claude-task-manager/git-utils.js +140 -10
  13. package/template/claude-task-manager/lib/agent-capabilities.js +1 -1
  14. package/template/claude-task-manager/lib/agent-presets.js +38 -5
  15. package/template/claude-task-manager/lib/codex-terminal-final.js +53 -0
  16. package/template/claude-task-manager/lib/ctm-session-context-api.js +222 -0
  17. package/template/claude-task-manager/lib/session-diagnostics.js +56 -0
  18. package/template/claude-task-manager/lib/session-history.js +309 -16
  19. package/template/claude-task-manager/lib/session-standup.js +409 -0
  20. package/template/claude-task-manager/lib/session-stream.js +253 -20
  21. package/template/claude-task-manager/lib/standup-attention.js +200 -0
  22. package/template/claude-task-manager/lib/status-hooks.js +8 -2
  23. package/template/claude-task-manager/lib/update-telemetry.js +114 -0
  24. package/template/claude-task-manager/lib/walle-ctm-history.js +49 -6
  25. package/template/claude-task-manager/lib/walle-default-model.js +55 -0
  26. package/template/claude-task-manager/lib/walle-mcp-auto-config.js +66 -0
  27. package/template/claude-task-manager/lib/walle-supervisor.js +86 -19
  28. package/template/claude-task-manager/lib/walle-transcript.js +1 -3
  29. package/template/claude-task-manager/lib/worktree-cwd.js +82 -0
  30. package/template/claude-task-manager/package.json +1 -0
  31. package/template/claude-task-manager/providers/codex-mcp.js +104 -0
  32. package/template/claude-task-manager/providers/index.js +2 -0
  33. package/template/claude-task-manager/public/css/setup.css +2 -1
  34. package/template/claude-task-manager/public/css/walle.css +71 -0
  35. package/template/claude-task-manager/public/index.html +2388 -429
  36. package/template/claude-task-manager/public/js/message-renderer.js +314 -35
  37. package/template/claude-task-manager/public/js/session-search-utils.js +185 -3
  38. package/template/claude-task-manager/public/js/session-status-precedence.js +125 -0
  39. package/template/claude-task-manager/public/js/setup.js +62 -19
  40. package/template/claude-task-manager/public/js/stream-view.js +396 -55
  41. package/template/claude-task-manager/public/js/terminal-restore-state.js +57 -0
  42. package/template/claude-task-manager/public/js/walle-session.js +234 -26
  43. package/template/claude-task-manager/public/js/walle.js +143 -2
  44. package/template/claude-task-manager/server.js +1402 -433
  45. package/template/claude-task-manager/session-integrity.js +77 -28
  46. package/template/claude-task-manager/workers/approval-widget-validator.js +15 -5
  47. package/template/claude-task-manager/workers/scrollback-worker.js +5 -6
  48. package/template/claude-task-manager/workers/state-detectors/codex.js +6 -0
  49. package/template/package.json +1 -1
  50. package/template/wall-e/agent-runners/claude-code.js +2 -0
  51. package/template/wall-e/agent.js +63 -8
  52. package/template/wall-e/api-walle.js +330 -52
  53. package/template/wall-e/brain.js +291 -42
  54. package/template/wall-e/chat.js +172 -15
  55. package/template/wall-e/coding/compaction-service.js +19 -5
  56. package/template/wall-e/coding/stream-processor.js +22 -2
  57. package/template/wall-e/coding/workspace-replay.js +1 -4
  58. package/template/wall-e/coding-orchestrator.js +250 -80
  59. package/template/wall-e/compat.js +0 -28
  60. package/template/wall-e/context/context-builder.js +3 -1
  61. package/template/wall-e/embeddings.js +2 -7
  62. package/template/wall-e/eval/agent-runner.js +30 -9
  63. package/template/wall-e/eval/benchmark-generator.js +21 -1
  64. package/template/wall-e/eval/benchmarks/chat-eval.json +66 -6
  65. package/template/wall-e/eval/benchmarks/coding-agent.json +0 -596
  66. package/template/wall-e/eval/cc-replay.js +1 -0
  67. package/template/wall-e/eval/codex-cli-baseline.js +633 -0
  68. package/template/wall-e/eval/debug-agent003.js +1 -0
  69. package/template/wall-e/eval/eval-orchestrator.js +3 -3
  70. package/template/wall-e/eval/run-agent-benchmarks.js +11 -3
  71. package/template/wall-e/eval/run-codex-cli-baseline.js +177 -0
  72. package/template/wall-e/eval/run-model-comparison.js +1 -0
  73. package/template/wall-e/eval/swebench-adapter.js +1 -0
  74. package/template/wall-e/evaluation/quorum-evaluator.js +0 -1
  75. package/template/wall-e/extraction/knowledge-extractor.js +1 -2
  76. package/template/wall-e/lib/mcp-integration.js +336 -0
  77. package/template/wall-e/llm/ollama.js +47 -8
  78. package/template/wall-e/llm/ollama.plugin.json +1 -1
  79. package/template/wall-e/llm/tool-adapter.js +1 -0
  80. package/template/wall-e/loops/ingest.js +42 -8
  81. package/template/wall-e/loops/initiative.js +87 -2
  82. package/template/wall-e/mcp-server.js +872 -19
  83. package/template/wall-e/memory/ctm-context-client.js +230 -0
  84. package/template/wall-e/memory/ctm-session-context.js +1376 -0
  85. package/template/wall-e/prompts/coding/memory-protocol.md +6 -0
  86. package/template/wall-e/server.js +30 -1
  87. package/template/wall-e/skills/_bundled/memory-search/SKILL.md +8 -0
  88. package/template/wall-e/skills/_bundled/scan-ctm-sessions/SKILL.md +20 -0
  89. package/template/wall-e/skills/_bundled/scan-ctm-sessions/run.js +43 -0
  90. package/template/wall-e/skills/_bundled/slack-mentions/run.js +471 -188
  91. package/template/wall-e/skills/skill-planner.js +86 -4
  92. package/template/wall-e/slack/socket-mode-listener.js +276 -0
  93. package/template/wall-e/telemetry.js +70 -2
  94. package/template/wall-e/tools/builtin-middleware.js +55 -2
  95. package/template/wall-e/tools/shell-policy.js +1 -1
  96. package/template/wall-e/tools/slack-owner.js +104 -0
  97. package/template/website/index.html +4 -4
  98. package/template/builder-journal.md +0 -17
package/README.md CHANGED
@@ -20,10 +20,10 @@ A web dashboard for running and managing AI coding sessions across multiple prov
20
20
 
21
21
  An always-on AI agent that learns from your Slack, email, calendar, and coding sessions.
22
22
 
23
- - **Second Brain** — Automatically ingests your digital life into a searchable memory store with full-text search, knowledge extraction, and pattern detection
23
+ - **Second Brain** — Automatically ingests your digital life and coding sessions into a searchable memory store with full-text search, knowledge extraction, and pattern detection
24
24
  - **Proactive Intelligence** — Surfaces time-sensitive items, suggests actions, and delivers morning briefings and weekly reflections without being asked
25
- - **Chat with Tools** — Talk to Wall-E in the browser — it can search your memories, look up people, run skills, and call external tools via MCP (Slack, Glean, etc.)
26
- - **19 Bundled Skills** — Morning briefing, weekly reflection, proactive alerts, Slack monitoring, email sync, calendar integration, coding agent, model training, model pricing sync, and more
25
+ - **Chat with Tools** — Talk to Wall-E in the browser — it can search memories, recall prior coding sessions, look up people, run skills, and call external tools via MCP
26
+ - **20 Bundled Skills** — Morning briefing, weekly reflection, proactive alerts, Slack monitoring, email sync, calendar integration, coding agent, memory search, model training, model pricing sync, and more
27
27
  - **Multi-Model** — Works with Claude, GPT, Gemini, DeepSeek, and local models via Ollama, LM Studio, or MLX with smart routing
28
28
  - **Skill Management GUI** — Search, filter, create, edit, and monitor skills from the browser with rich cards, config forms, execution history, export/import, and pre-flight validation
29
29
  - **Multi-Device** — Share your brain across machines via Dropbox or iCloud
@@ -49,6 +49,11 @@ npx create-walle uninstall # Remove the auto-start service
49
49
  npx create-walle -v # Show version
50
50
  ```
51
51
 
52
+ Install, update, and start verify Node-native modules such as `better-sqlite3`
53
+ against the exact Node.js binary Wall-E will use. If you switch Node versions,
54
+ Wall-E automatically runs the needed `npm rebuild` before starting so CTM does
55
+ not crash with a `NODE_MODULE_VERSION` mismatch.
56
+
52
57
  ## Setup
53
58
 
54
59
  On first launch, the browser setup page guides you through:
@@ -17,37 +17,70 @@ const { injectMcpConfigs } = require('./mcp-inject');
17
17
  const TEMPLATE_DIR = path.join(__dirname, '..', 'template');
18
18
  const LABEL = 'com.walle.server';
19
19
  const INSTALL_PATH_FILE = path.join(process.env.HOME, '.walle', 'install-path');
20
+ const TELEMETRY_DATA_DIR = process.env.WALL_E_DATA_DIR || path.join(process.env.HOME || '/tmp', '.walle', 'data');
21
+ const CLI_LIFECYCLE_FILE = path.join(TELEMETRY_DATA_DIR, '.cli-lifecycle.jsonl');
22
+ const MANAGED_PACKAGE_DIRS = ['claude-task-manager', 'wall-e'];
23
+ const NATIVE_DEPENDENCIES = new Set([
24
+ 'better-sqlite3',
25
+ 'node-pty',
26
+ 'sqlite-vec',
27
+ 'tree-sitter-bash',
28
+ ]);
20
29
 
21
30
  // Files to preserve during update (user config, not code)
22
31
  const PRESERVE_ON_UPDATE = ['.env', 'wall-e/wall-e-config.json'];
23
32
 
33
+ function writeCliLifecycleEvent(event, meta = {}) {
34
+ if (process.env.WALLE_TELEMETRY === '0' || process.env.WALLE_TELEMETRY === 'false') return;
35
+ try {
36
+ fs.mkdirSync(TELEMETRY_DATA_DIR, { recursive: true });
37
+ const pkg = require('../package.json');
38
+ const entry = {
39
+ event,
40
+ meta: {
41
+ command: meta.command || '',
42
+ package_version: pkg.version || 'unknown',
43
+ elapsed_ms: Number.isFinite(meta.elapsed_ms) ? meta.elapsed_ms : undefined,
44
+ },
45
+ t: Date.now(),
46
+ };
47
+ fs.appendFileSync(CLI_LIFECYCLE_FILE, JSON.stringify(entry) + '\n', { mode: 0o600 });
48
+ } catch {}
49
+ }
50
+
24
51
  // ── CLI Router ──
25
52
 
26
- const command = process.argv[2] || '';
27
-
28
- if (command === 'install') {
29
- install(process.argv[3]);
30
- } else if (command === 'update' || command === 'upgrade') {
31
- update();
32
- } else if (command === 'start') {
33
- start();
34
- } else if (command === 'stop') {
35
- stop();
36
- } else if (command === 'status') {
37
- status();
38
- } else if (command === 'logs') {
39
- logs();
40
- } else if (command === 'uninstall') {
41
- uninstall();
42
- } else if (command === '--help' || command === '-h' || command === 'help') {
43
- usage();
44
- } else if (command === '--version' || command === '-v') {
45
- const pkg = require('../package.json');
46
- console.log(pkg.version);
47
- } else if (command && !command.startsWith('-')) {
48
- install(command);
49
- } else {
50
- usage();
53
+ if (require.main === module) {
54
+ main(process.argv.slice(2));
55
+ }
56
+
57
+ function main(argv = []) {
58
+ const command = argv[0] || '';
59
+
60
+ if (command === 'install') {
61
+ install(argv[1]);
62
+ } else if (command === 'update' || command === 'upgrade') {
63
+ update();
64
+ } else if (command === 'start') {
65
+ start();
66
+ } else if (command === 'stop') {
67
+ stop();
68
+ } else if (command === 'status') {
69
+ status();
70
+ } else if (command === 'logs') {
71
+ logs();
72
+ } else if (command === 'uninstall') {
73
+ uninstall();
74
+ } else if (command === '--help' || command === '-h' || command === 'help') {
75
+ usage();
76
+ } else if (command === '--version' || command === '-v') {
77
+ const pkg = require('../package.json');
78
+ console.log(pkg.version);
79
+ } else if (command && !command.startsWith('-')) {
80
+ install(command);
81
+ } else {
82
+ usage();
83
+ }
51
84
  }
52
85
 
53
86
  // ── Commands ──
@@ -84,9 +117,11 @@ function printMcpResults(wallePort) {
84
117
  } else if (r.action === 'already_configured') {
85
118
  console.log(` ${DIM}= ${r.tool} -- already configured${RESET}`);
86
119
  } else if (r.action === 'updated') {
87
- console.log(` ${GREEN}~ ${r.tool}${RESET} -- updated port in ${DIM}${r.configPath}${RESET}`);
120
+ const label = r.kind === 'agent_instructions' ? 'updated memory routing in' : 'updated port in';
121
+ console.log(` ${GREEN}~ ${r.tool}${RESET} -- ${label} ${DIM}${r.configPath}${RESET}`);
88
122
  } else {
89
- console.log(` ${GREEN}+ ${r.tool}${RESET} -- added Wall-E to ${DIM}${r.configPath}${RESET}`);
123
+ const label = r.kind === 'agent_instructions' ? 'added memory routing to' : 'added Wall-E to';
124
+ console.log(` ${GREEN}+ ${r.tool}${RESET} -- ${label} ${DIM}${r.configPath}${RESET}`);
90
125
  }
91
126
  }
92
127
  console.log(`\n ${DIM}Your AI coding tools can now access Wall-E's memory and knowledge.`);
@@ -127,6 +162,8 @@ function install(targetDir) {
127
162
  console.error(' Template not found. Try: npm cache clean --force && npx create-walle@latest');
128
163
  process.exit(1);
129
164
  }
165
+ const installStartedAt = Date.now();
166
+ writeCliLifecycleEvent('cli_install_started', { command: 'install' });
130
167
 
131
168
  const ownerName = detectName().replace(/[\r\n=]/g, '').trim().slice(0, 200);
132
169
  const timezone = detectTimezone();
@@ -203,12 +240,18 @@ function install(targetDir) {
203
240
  npx create-walle logs ${DIM}View logs${RESET}
204
241
  `);
205
242
  printMcpResults(parseInt(wallePort));
243
+ writeCliLifecycleEvent('cli_install_completed', {
244
+ command: 'install',
245
+ elapsed_ms: Date.now() - installStartedAt,
246
+ });
206
247
  }
207
248
 
208
249
  function update() {
209
250
  const dir = findWalleDir();
210
251
  const port = readPort(dir);
211
252
  const pkg = require('../package.json');
253
+ const updateStartedAt = Date.now();
254
+ writeCliLifecycleEvent('cli_update_started', { command: 'update' });
212
255
 
213
256
  console.log(`${BOLD}${CYAN} Wall-E${RESET} — Updating to v${pkg.version}...\n`);
214
257
  console.log(` ${DIM}Directory: ${dir}${RESET}`);
@@ -261,12 +304,25 @@ function update() {
261
304
  ${DIM}Your .env and config were preserved.${RESET}
262
305
  `);
263
306
  printMcpResults(parseInt(readWallePort(dir)));
307
+ writeCliLifecycleEvent('cli_update_completed', {
308
+ command: 'update',
309
+ elapsed_ms: Date.now() - updateStartedAt,
310
+ });
264
311
  }
265
312
 
266
313
  function start() {
267
314
  const dir = findWalleDir();
268
315
  const port = readPort(dir);
269
316
  console.log(`\n Starting Wall-E from ${DIM}${dir}${RESET} on port ${port}...`);
317
+ try {
318
+ repairNativeDependencies(dir, { phase: 'start' });
319
+ } catch (err) {
320
+ console.error(`\n ${RED}Native module repair failed.${RESET}`);
321
+ console.error(` ${DIM}${err.message}${RESET}`);
322
+ console.error(` Try: ${BOLD}cd ${dir}/claude-task-manager && npm rebuild better-sqlite3 node-pty${RESET}`);
323
+ console.error(` ${BOLD}cd ${dir}/wall-e && npm rebuild better-sqlite3 sqlite-vec tree-sitter-bash${RESET}\n`);
324
+ process.exit(1);
325
+ }
270
326
  installService(dir, port);
271
327
  console.log(` ${GREEN}Running!${RESET} http://localhost:${port}\n`);
272
328
  printMcpResults(parseInt(readWallePort(dir)));
@@ -326,7 +382,7 @@ function stopQuiet(dir, port) {
326
382
  const wallePort = dir ? readWallePort(dir) : String(parseInt(port) + 1);
327
383
  for (const p of [port, wallePort]) {
328
384
  try {
329
- const pids = execFileSync('lsof', ['-ti', ':' + p], { encoding: 'utf8', timeout: 3000 }).trim().split('\n').filter(Boolean);
385
+ const pids = execFileSync('lsof', ['-ti', '-sTCP:LISTEN', ':' + p], { encoding: 'utf8', timeout: 3000 }).trim().split('\n').filter(Boolean);
330
386
  for (const pid of pids) { try { process.kill(parseInt(pid), 'SIGTERM'); } catch {} }
331
387
  } catch {}
332
388
  }
@@ -464,14 +520,146 @@ done
464
520
 
465
521
  function npmInstall(dir) {
466
522
  try {
467
- execFileSync('npm', ['install', '--loglevel=warn'], { cwd: path.join(dir, 'claude-task-manager'), stdio: 'inherit' });
468
- execFileSync('npm', ['install', '--loglevel=warn'], { cwd: path.join(dir, 'wall-e'), stdio: 'inherit' });
469
- } catch {
470
- console.error(`\n ${RED}npm install failed.${RESET} Try manually:\n cd ${dir}/claude-task-manager && npm install\n cd ${dir}/wall-e && npm install\n`);
523
+ for (const relDir of MANAGED_PACKAGE_DIRS) {
524
+ runNpm(path.join(dir, relDir), ['install', '--loglevel=warn']);
525
+ }
526
+ repairNativeDependencies(dir, { phase: 'install' });
527
+ } catch (err) {
528
+ console.error(`\n ${RED}npm install failed.${RESET}`);
529
+ if (err && err.message) console.error(` ${DIM}${err.message}${RESET}`);
530
+ console.error(` Try manually with the same Node version used by Wall-E:\n cd ${dir}/claude-task-manager && npm install && npm rebuild better-sqlite3 node-pty\n cd ${dir}/wall-e && npm install && npm rebuild better-sqlite3 sqlite-vec tree-sitter-bash\n`);
471
531
  process.exit(1);
472
532
  }
473
533
  }
474
534
 
535
+ function repairNativeDependencies(walleDir, {
536
+ phase = 'install',
537
+ checkDependency = checkNativeDependency,
538
+ runNpmCommand = runNpm,
539
+ log = console.log,
540
+ } = {}) {
541
+ const repairs = [];
542
+ for (const relDir of MANAGED_PACKAGE_DIRS) {
543
+ const packageDir = path.join(walleDir, relDir);
544
+ const deps = nativeDependenciesForPackage(packageDir);
545
+ if (!deps.length) continue;
546
+
547
+ const failed = [];
548
+ for (const dep of deps) {
549
+ const check = checkDependency(packageDir, dep);
550
+ if (!check.ok) failed.push(dep);
551
+ }
552
+ if (!failed.length) continue;
553
+
554
+ log(` ${YELLOW}Rebuilding native modules for ${relDir}${RESET} ${DIM}(Node ${process.version}, ABI ${process.versions.modules})${RESET}`);
555
+ runNpmCommand(packageDir, ['rebuild', ...failed, '--loglevel=warn']);
556
+
557
+ const stillBroken = [];
558
+ for (const dep of failed) {
559
+ const check = checkDependency(packageDir, dep);
560
+ if (!check.ok) stillBroken.push(`${dep}: ${firstLine(check.error)}`);
561
+ }
562
+ if (stillBroken.length) {
563
+ throw new Error(`Native module repair failed in ${relDir} after ${phase}: ${stillBroken.join('; ')}`);
564
+ }
565
+ repairs.push(`${relDir}: ${failed.join(', ')}`);
566
+ }
567
+
568
+ if (repairs.length) {
569
+ log(` ${GREEN}Native modules rebuilt successfully${RESET} ${DIM}(${repairs.join('; ')})${RESET}`);
570
+ }
571
+ return repairs;
572
+ }
573
+
574
+ function nativeDependenciesForPackage(packageDir) {
575
+ const pkgPath = path.join(packageDir, 'package.json');
576
+ let pkg;
577
+ try {
578
+ pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
579
+ } catch {
580
+ return [];
581
+ }
582
+ const declared = {
583
+ ...(pkg.dependencies || {}),
584
+ ...(pkg.optionalDependencies || {}),
585
+ };
586
+ return Object.keys(declared).filter((name) => NATIVE_DEPENDENCIES.has(name));
587
+ }
588
+
589
+ function checkNativeDependency(packageDir, dependency) {
590
+ try {
591
+ execFileSync(process.execPath, ['-e', `require(${JSON.stringify(dependency)})`], {
592
+ cwd: packageDir,
593
+ encoding: 'utf8',
594
+ stdio: ['ignore', 'pipe', 'pipe'],
595
+ timeout: 15000,
596
+ env: npmChildEnv(),
597
+ });
598
+ return { ok: true };
599
+ } catch (err) {
600
+ const error = [err && err.message, err && err.stdout, err && err.stderr].filter(Boolean).join('\n');
601
+ return { ok: false, error };
602
+ }
603
+ }
604
+
605
+ function runNpm(cwd, args) {
606
+ const runner = resolveNpmRunner();
607
+ if (runner.type === 'node-cli') {
608
+ execFileSync(process.execPath, [runner.path, ...args], {
609
+ cwd,
610
+ stdio: 'inherit',
611
+ env: npmChildEnv(),
612
+ });
613
+ return;
614
+ }
615
+ execFileSync('npm', args, {
616
+ cwd,
617
+ stdio: 'inherit',
618
+ env: npmChildEnv(),
619
+ });
620
+ }
621
+
622
+ function resolveNpmRunner(env = process.env, execPath = process.execPath) {
623
+ const envPath = normalizeNpmExecPath(env.npm_execpath);
624
+ if (envPath && fs.existsSync(envPath)) return { type: 'node-cli', path: envPath };
625
+
626
+ for (const candidate of npmCliCandidates(execPath)) {
627
+ if (fs.existsSync(candidate)) return { type: 'node-cli', path: candidate };
628
+ }
629
+ return { type: 'bin', path: 'npm' };
630
+ }
631
+
632
+ function normalizeNpmExecPath(value) {
633
+ if (!value) return null;
634
+ const resolved = path.resolve(value);
635
+ if (path.basename(resolved) === 'npx-cli.js') {
636
+ return path.join(path.dirname(resolved), 'npm-cli.js');
637
+ }
638
+ return resolved;
639
+ }
640
+
641
+ function npmCliCandidates(execPath = process.execPath) {
642
+ const binDir = path.dirname(execPath);
643
+ return [
644
+ path.join(binDir, 'node_modules', 'npm', 'bin', 'npm-cli.js'),
645
+ path.join(binDir, '..', 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js'),
646
+ path.join(binDir, '..', 'libexec', 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js'),
647
+ ].map((candidate) => path.resolve(candidate));
648
+ }
649
+
650
+ function npmChildEnv() {
651
+ const nodeDir = path.dirname(process.execPath);
652
+ return {
653
+ ...process.env,
654
+ PATH: [nodeDir, process.env.PATH || ''].filter(Boolean).join(path.delimiter),
655
+ npm_config_update_notifier: 'false',
656
+ };
657
+ }
658
+
659
+ function firstLine(value) {
660
+ return String(value || '').split(/\r?\n/).find(Boolean) || 'unknown error';
661
+ }
662
+
475
663
  function stampVersion(dir) {
476
664
  try {
477
665
  const ver = require('../package.json').version;
@@ -568,3 +756,15 @@ function copyRecursive(src, dest) {
568
756
  fs.copyFileSync(src, dest);
569
757
  }
570
758
  }
759
+
760
+ module.exports = {
761
+ checkNativeDependency,
762
+ firstLine,
763
+ main,
764
+ nativeDependenciesForPackage,
765
+ normalizeNpmExecPath,
766
+ npmCliCandidates,
767
+ repairNativeDependencies,
768
+ resolveNpmRunner,
769
+ writeCliLifecycleEvent,
770
+ };
package/bin/mcp-inject.js CHANGED
@@ -1,60 +1,25 @@
1
1
  'use strict';
2
- const fs = require('fs');
3
- const path = require('path');
4
-
5
- const MCP_TARGETS = [
6
- { tool: 'Claude Code', configPath: '.claude/mcp.json', detectDir: '.claude' },
7
- { tool: 'Cursor', configPath: '.cursor/mcp.json', detectDir: '.cursor' },
8
- { tool: 'Windsurf', configPath: '.codeium/windsurf/mcp_config.json', detectDir: '.codeium/windsurf' },
9
- { tool: 'Claude Desktop', configPath: 'Library/Application Support/Claude/claude_desktop_config.json', detectDir: 'Library/Application Support/Claude' },
10
- ];
11
-
12
- /**
13
- * Inject Wall-E MCP server config into detected AI tool config files.
14
- * @param {number} wallePort - The Wall-E HTTP port
15
- * @param {string} [homeDir] - Home directory override for testing
16
- * @returns {Array<{tool: string, action: string, configPath?: string}>}
17
- */
18
- function injectMcpConfigs(wallePort, homeDir) {
19
- const home = homeDir || process.env.HOME;
20
- const walleUrl = `http://localhost:${wallePort}/mcp`;
21
- const results = [];
22
-
23
- for (const target of MCP_TARGETS) {
24
- const detectPath = path.join(home, target.detectDir);
25
- const configPath = path.join(home, target.configPath);
26
-
27
- if (!fs.existsSync(detectPath)) {
28
- results.push({ tool: target.tool, action: 'not_installed' });
29
- continue;
30
- }
31
2
 
32
- let config = {};
33
- if (fs.existsSync(configPath)) {
34
- try {
35
- config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
36
- } catch {
37
- config = {};
38
- }
39
- }
40
-
41
- if (!config.mcpServers) config.mcpServers = {};
42
-
43
- const existing = config.mcpServers['wall-e'];
44
- if (existing && existing.url === walleUrl) {
45
- results.push({ tool: target.tool, action: 'already_configured', configPath });
46
- continue;
47
- }
3
+ const path = require('path');
48
4
 
49
- const action = existing ? 'updated' : 'added';
50
- config.mcpServers['wall-e'] = { type: 'http', url: walleUrl };
5
+ const runtimePath = path.join(__dirname, '..', 'template', 'wall-e', 'lib', 'mcp-integration');
6
+ let runtime = null;
51
7
 
52
- fs.mkdirSync(path.dirname(configPath), { recursive: true });
53
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
54
- results.push({ tool: target.tool, action, configPath });
8
+ function loadRuntime() {
9
+ if (runtime) return runtime;
10
+ try {
11
+ runtime = require(runtimePath);
12
+ } catch {
13
+ runtime = require('../../wall-e/lib/mcp-integration');
55
14
  }
56
-
57
- return results;
15
+ return runtime;
58
16
  }
59
17
 
60
- module.exports = { injectMcpConfigs, MCP_TARGETS };
18
+ module.exports = {
19
+ get MCP_TARGETS() { return loadRuntime().MCP_TARGETS; },
20
+ detectMcpIntegrations: (...args) => loadRuntime().detectMcpIntegrations(...args),
21
+ ensureMcpIntegrations: (...args) => loadRuntime().ensureMcpIntegrations(...args),
22
+ injectMcpConfigs: (...args) => loadRuntime().injectMcpConfigs(...args),
23
+ testWallEMcpEndpoint: (...args) => loadRuntime().testWallEMcpEndpoint(...args),
24
+ wallEMcpUrl: (...args) => loadRuntime().wallEMcpUrl(...args),
25
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-walle",
3
- "version": "0.9.13",
3
+ "version": "0.9.15",
4
4
  "description": "CTM + Wall-E \u2014 AI coding dashboard and personal digital twin agent. Multi-agent terminal for Claude Code, Codex, Gemini, Aider, OpenCode, and more, plus prompt editor, task queue, and an agent that learns from Slack, email & calendar.",
5
5
  "bin": {
6
6
  "create-walle": "bin/create-walle.js"
@@ -12,6 +12,8 @@
12
12
  ],
13
13
  "scripts": {
14
14
  "build": "bash build.sh",
15
+ "test": "node --test tests/*.test.js",
16
+ "test:npx-e2e": "CREATE_WALLE_NPX_E2E=1 node --test tests/npx-install-update.e2e.test.js",
15
17
  "prepublishOnly": "bash build.sh"
16
18
  },
17
19
  "license": "MIT",
@@ -10,6 +10,12 @@ const walleClient = require('./lib/walle-client');
10
10
  const claudeDesktopSessions = require('./lib/claude-desktop-sessions');
11
11
  // AI search uses direct HTTP calls to Claude API (supports Portkey proxy)
12
12
 
13
+ let dbMaintenanceRunner = null;
14
+
15
+ function setDbMaintenanceRunner(fn) {
16
+ dbMaintenanceRunner = typeof fn === 'function' ? fn : null;
17
+ }
18
+
13
19
  // Embed a prompt (async, fire-and-forget)
14
20
  async function _embedPrompt(promptId, title, content) {
15
21
  try {
@@ -1467,7 +1473,10 @@ async function handleRestoreBackup(req, res) {
1467
1473
  try {
1468
1474
  const data = await readBody(req);
1469
1475
  if (!data.name) return jsonResponse(res, 400, { error: 'Missing backup name' });
1470
- const result = db.restoreBackup(data.name);
1476
+ const restore = () => db.restoreBackup(data.name);
1477
+ const result = dbMaintenanceRunner
1478
+ ? await dbMaintenanceRunner({ kind: 'restore-backup', backupName: data.name }, restore)
1479
+ : restore();
1471
1480
  jsonResponse(res, 200, result);
1472
1481
  } catch (e) { jsonResponse(res, 500, { error: e.message }); }
1473
1482
  }
@@ -2814,4 +2823,4 @@ function safeParse(json, fallback) {
2814
2823
  try { return JSON.parse(json); } catch { return fallback; }
2815
2824
  }
2816
2825
 
2817
- module.exports = { handlePromptApi, queueEngine, importPermissionsToDb, runIncrementalConversationImport, importSessionFile, setUiPrefsBroadcaster };
2826
+ module.exports = { handlePromptApi, queueEngine, importPermissionsToDb, runIncrementalConversationImport, importSessionFile, setUiPrefsBroadcaster, setDbMaintenanceRunner };
@@ -356,6 +356,13 @@ function reviewWithHeuristics(context) {
356
356
  const tool = (context.toolName || '').replace(/^[⏺●\s]+/, '').toLowerCase();
357
357
  const warning = (context.warning || '').toLowerCase();
358
358
 
359
+ if (/^mcp\b/.test(tool)
360
+ && /\bwall-e\.walle_memory_status\b|\bwall-e\b[\s\S]*\bwalle_memory_status\b/.test(cmd)) {
361
+ return { decision: 'approve', reasoning: 'Read-only Wall-E memory status MCP call (heuristic)', riskLevel: 'low',
362
+ ruleLabel: 'Wall-E memory status', rulePattern: 'wall-e.*walle_memory_status',
363
+ ruleDescription: 'Read Wall-E MCP memory status' };
364
+ }
365
+
359
366
  // Low-risk tools — auto-approve immediately (before high-risk content check,
360
367
  // because Edit/Write diffs may contain code with "drop table" or "rm -rf" as
361
368
  // string literals — those are code content, not dangerous operations).