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.
- package/README.md +8 -3
- package/bin/create-walle.js +232 -32
- package/bin/mcp-inject.js +18 -53
- package/package.json +3 -1
- package/template/claude-task-manager/api-prompts.js +11 -2
- package/template/claude-task-manager/approval-agent.js +7 -0
- package/template/claude-task-manager/db.js +94 -75
- package/template/claude-task-manager/docs/session-standup-command-center-design.md +242 -0
- package/template/claude-task-manager/docs/session-tooltip-freshness-design.md +224 -0
- package/template/claude-task-manager/docs/session-ux-issue-review-2026-05-01.md +369 -0
- package/template/claude-task-manager/fuzzy-utils.js +10 -2
- package/template/claude-task-manager/git-utils.js +140 -10
- package/template/claude-task-manager/lib/agent-capabilities.js +1 -1
- package/template/claude-task-manager/lib/agent-presets.js +38 -5
- package/template/claude-task-manager/lib/codex-terminal-final.js +53 -0
- package/template/claude-task-manager/lib/ctm-session-context-api.js +222 -0
- package/template/claude-task-manager/lib/session-diagnostics.js +56 -0
- package/template/claude-task-manager/lib/session-history.js +309 -16
- package/template/claude-task-manager/lib/session-standup.js +409 -0
- package/template/claude-task-manager/lib/session-stream.js +253 -20
- package/template/claude-task-manager/lib/standup-attention.js +200 -0
- package/template/claude-task-manager/lib/status-hooks.js +8 -2
- package/template/claude-task-manager/lib/update-telemetry.js +114 -0
- package/template/claude-task-manager/lib/walle-ctm-history.js +49 -6
- package/template/claude-task-manager/lib/walle-default-model.js +55 -0
- package/template/claude-task-manager/lib/walle-mcp-auto-config.js +66 -0
- package/template/claude-task-manager/lib/walle-supervisor.js +86 -19
- package/template/claude-task-manager/lib/walle-transcript.js +1 -3
- package/template/claude-task-manager/lib/worktree-cwd.js +82 -0
- package/template/claude-task-manager/package.json +1 -0
- package/template/claude-task-manager/providers/codex-mcp.js +104 -0
- package/template/claude-task-manager/providers/index.js +2 -0
- package/template/claude-task-manager/public/css/setup.css +2 -1
- package/template/claude-task-manager/public/css/walle.css +71 -0
- package/template/claude-task-manager/public/index.html +2388 -429
- package/template/claude-task-manager/public/js/message-renderer.js +314 -35
- package/template/claude-task-manager/public/js/session-search-utils.js +185 -3
- package/template/claude-task-manager/public/js/session-status-precedence.js +125 -0
- package/template/claude-task-manager/public/js/setup.js +62 -19
- package/template/claude-task-manager/public/js/stream-view.js +396 -55
- package/template/claude-task-manager/public/js/terminal-restore-state.js +57 -0
- package/template/claude-task-manager/public/js/walle-session.js +234 -26
- package/template/claude-task-manager/public/js/walle.js +143 -2
- package/template/claude-task-manager/server.js +1402 -433
- package/template/claude-task-manager/session-integrity.js +77 -28
- package/template/claude-task-manager/workers/approval-widget-validator.js +15 -5
- package/template/claude-task-manager/workers/scrollback-worker.js +5 -6
- package/template/claude-task-manager/workers/state-detectors/codex.js +6 -0
- package/template/package.json +1 -1
- package/template/wall-e/agent-runners/claude-code.js +2 -0
- package/template/wall-e/agent.js +63 -8
- package/template/wall-e/api-walle.js +330 -52
- package/template/wall-e/brain.js +291 -42
- package/template/wall-e/chat.js +172 -15
- package/template/wall-e/coding/compaction-service.js +19 -5
- package/template/wall-e/coding/stream-processor.js +22 -2
- package/template/wall-e/coding/workspace-replay.js +1 -4
- package/template/wall-e/coding-orchestrator.js +250 -80
- package/template/wall-e/compat.js +0 -28
- package/template/wall-e/context/context-builder.js +3 -1
- package/template/wall-e/embeddings.js +2 -7
- package/template/wall-e/eval/agent-runner.js +30 -9
- package/template/wall-e/eval/benchmark-generator.js +21 -1
- package/template/wall-e/eval/benchmarks/chat-eval.json +66 -6
- package/template/wall-e/eval/benchmarks/coding-agent.json +0 -596
- package/template/wall-e/eval/cc-replay.js +1 -0
- package/template/wall-e/eval/codex-cli-baseline.js +633 -0
- package/template/wall-e/eval/debug-agent003.js +1 -0
- package/template/wall-e/eval/eval-orchestrator.js +3 -3
- package/template/wall-e/eval/run-agent-benchmarks.js +11 -3
- package/template/wall-e/eval/run-codex-cli-baseline.js +177 -0
- package/template/wall-e/eval/run-model-comparison.js +1 -0
- package/template/wall-e/eval/swebench-adapter.js +1 -0
- package/template/wall-e/evaluation/quorum-evaluator.js +0 -1
- package/template/wall-e/extraction/knowledge-extractor.js +1 -2
- package/template/wall-e/lib/mcp-integration.js +336 -0
- package/template/wall-e/llm/ollama.js +47 -8
- package/template/wall-e/llm/ollama.plugin.json +1 -1
- package/template/wall-e/llm/tool-adapter.js +1 -0
- package/template/wall-e/loops/ingest.js +42 -8
- package/template/wall-e/loops/initiative.js +87 -2
- package/template/wall-e/mcp-server.js +872 -19
- package/template/wall-e/memory/ctm-context-client.js +230 -0
- package/template/wall-e/memory/ctm-session-context.js +1376 -0
- package/template/wall-e/prompts/coding/memory-protocol.md +6 -0
- package/template/wall-e/server.js +30 -1
- package/template/wall-e/skills/_bundled/memory-search/SKILL.md +8 -0
- package/template/wall-e/skills/_bundled/scan-ctm-sessions/SKILL.md +20 -0
- package/template/wall-e/skills/_bundled/scan-ctm-sessions/run.js +43 -0
- package/template/wall-e/skills/_bundled/slack-mentions/run.js +471 -188
- package/template/wall-e/skills/skill-planner.js +86 -4
- package/template/wall-e/slack/socket-mode-listener.js +276 -0
- package/template/wall-e/telemetry.js +70 -2
- package/template/wall-e/tools/builtin-middleware.js +55 -2
- package/template/wall-e/tools/shell-policy.js +1 -1
- package/template/wall-e/tools/slack-owner.js +104 -0
- package/template/website/index.html +4 -4
- 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
|
|
26
|
-
- **
|
|
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:
|
package/bin/create-walle.js
CHANGED
|
@@ -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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
} else if (command
|
|
48
|
-
|
|
49
|
-
} else {
|
|
50
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
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
|
-
|
|
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
|
-
|
|
50
|
-
|
|
5
|
+
const runtimePath = path.join(__dirname, '..', 'template', 'wall-e', 'lib', 'mcp-integration');
|
|
6
|
+
let runtime = null;
|
|
51
7
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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 = {
|
|
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.
|
|
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
|
|
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).
|