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
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
(function initSessionStatusPrecedence(root, factory) {
|
|
4
|
+
if (typeof module === 'object' && module.exports) {
|
|
5
|
+
module.exports = factory();
|
|
6
|
+
} else {
|
|
7
|
+
root.SessionStatusPrecedence = factory();
|
|
8
|
+
}
|
|
9
|
+
})(typeof globalThis !== 'undefined' ? globalThis : this, function buildSessionStatusPrecedence() {
|
|
10
|
+
const AUTHORITATIVE_STATUS_TTL_MS = 120000;
|
|
11
|
+
const SERVER_LIVE_STATUS_TTL_MS = 10000;
|
|
12
|
+
const STREAM_STATUS_TTL_MS = 60000;
|
|
13
|
+
const SERVER_WORKING_TTL_MS = 10000;
|
|
14
|
+
const RECENT_OUTPUT_TTL_MS = 5000;
|
|
15
|
+
const RECENT_INPUT_TTL_MS = 3000;
|
|
16
|
+
|
|
17
|
+
const STATUS_TEXT = {
|
|
18
|
+
running: 'Running',
|
|
19
|
+
waiting: 'Waiting',
|
|
20
|
+
idle: 'Idle',
|
|
21
|
+
exited: 'Exited',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
function normalizeLiveSessionStatus(status) {
|
|
25
|
+
const text = String(status || '').toLowerCase();
|
|
26
|
+
if (!text) return '';
|
|
27
|
+
if (text === 'busy' || text === 'active' || text === 'thinking') return 'running';
|
|
28
|
+
if (text === 'waiting_input' || text === 'waiting-for-input') return 'waiting';
|
|
29
|
+
if (Object.prototype.hasOwnProperty.call(STATUS_TEXT, text)) return text;
|
|
30
|
+
return '';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function result(status, source) {
|
|
34
|
+
const normalized = normalizeLiveSessionStatus(status);
|
|
35
|
+
if (!normalized) return null;
|
|
36
|
+
return {
|
|
37
|
+
cls: normalized,
|
|
38
|
+
text: STATUS_TEXT[normalized] || 'Idle',
|
|
39
|
+
source: source || normalized,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function parseTimeMs(value, fallback = 0, parser) {
|
|
44
|
+
if (value == null || value === '') return fallback || 0;
|
|
45
|
+
if (typeof parser === 'function') {
|
|
46
|
+
const parsed = parser(value);
|
|
47
|
+
if (parsed) return parsed;
|
|
48
|
+
}
|
|
49
|
+
if (typeof value === 'number' && Number.isFinite(value)) return value;
|
|
50
|
+
const parsed = Date.parse(String(value));
|
|
51
|
+
return Number.isFinite(parsed) ? parsed : (fallback || 0);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function isFresh(timestamp, now, ttl) {
|
|
55
|
+
return Boolean(timestamp && (now - timestamp) < ttl);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function resolveSessionStatus(input = {}, options = {}) {
|
|
59
|
+
const now = options.now || Date.now();
|
|
60
|
+
const parser = options.parseTimeMs;
|
|
61
|
+
if (input.metaType === 'walle') {
|
|
62
|
+
return input.walleGenerating
|
|
63
|
+
? result('running', 'walle-generating')
|
|
64
|
+
: result('idle', 'walle-idle');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const serverLiveStatusAt = parseTimeMs(input.serverLiveStatusAt, 0, parser);
|
|
68
|
+
const serverLive = result(input.serverLiveStatus, 'server-live');
|
|
69
|
+
if (serverLive && isFresh(serverLiveStatusAt, now, SERVER_LIVE_STATUS_TTL_MS)) {
|
|
70
|
+
return serverLive;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const serverWorkingAt = parseTimeMs(input.serverWorkingAt, 0, parser);
|
|
74
|
+
const serverWorkingEventAt = parseTimeMs(input.serverWorkingEventAt, serverWorkingAt, parser);
|
|
75
|
+
const waitingAt = parseTimeMs(input.waitingForInputAt, 0, parser);
|
|
76
|
+
const waitingForInput = Boolean(input.waitingForInput);
|
|
77
|
+
const serverWorking = Boolean(serverWorkingAt &&
|
|
78
|
+
(now - serverWorkingAt) < SERVER_WORKING_TTL_MS &&
|
|
79
|
+
(!waitingForInput || !waitingAt || serverWorkingEventAt >= waitingAt));
|
|
80
|
+
|
|
81
|
+
const streamStatusAt = parseTimeMs(input.streamStatusAt, 0, parser);
|
|
82
|
+
const streamStatus = normalizeLiveSessionStatus(input.streamStatus);
|
|
83
|
+
const streamFresh = Boolean(streamStatus && isFresh(streamStatusAt, now, STREAM_STATUS_TTL_MS));
|
|
84
|
+
const streamRunning = streamFresh && streamStatus === 'running';
|
|
85
|
+
const lastOutputAt = Math.max(
|
|
86
|
+
parseTimeMs(input.lastOutputAt, 0, parser),
|
|
87
|
+
parseTimeMs(input.metaLastPtyActivity, 0, parser)
|
|
88
|
+
);
|
|
89
|
+
const recentOutput = Boolean(lastOutputAt && (now - lastOutputAt) < RECENT_OUTPUT_TTL_MS);
|
|
90
|
+
const codexRunningHold = Boolean(input.codexRunningHold);
|
|
91
|
+
|
|
92
|
+
if (input.authoritativeSource) {
|
|
93
|
+
const authAt = parseTimeMs(input.authoritativeStatusAt, 0, parser);
|
|
94
|
+
if (isFresh(authAt, now, AUTHORITATIVE_STATUS_TTL_MS)) {
|
|
95
|
+
if (input.working) return result('running', 'authoritative-working');
|
|
96
|
+
if (waitingForInput) return result('waiting', 'authoritative-waiting');
|
|
97
|
+
const newerRunningEvidence =
|
|
98
|
+
serverWorking ||
|
|
99
|
+
(streamRunning && (!authAt || streamStatusAt >= authAt)) ||
|
|
100
|
+
(recentOutput && (!authAt || lastOutputAt >= authAt));
|
|
101
|
+
if (newerRunningEvidence) return result('running', 'newer-running-evidence');
|
|
102
|
+
return result('idle', 'authoritative-idle');
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (serverWorking) return result('running', 'server-working');
|
|
107
|
+
if (waitingForInput) return result('waiting', 'waiting-for-input');
|
|
108
|
+
if (codexRunningHold) return result('running', 'codex-running-hold');
|
|
109
|
+
if (streamFresh) return result(streamStatus, 'stream-status');
|
|
110
|
+
if (waitingForInput && !recentOutput) return result('waiting', 'waiting-fallback');
|
|
111
|
+
if (recentOutput) return result('running', 'recent-output');
|
|
112
|
+
const lastInputAt = parseTimeMs(input.lastInputAt, 0, parser);
|
|
113
|
+
if (lastInputAt && (now - lastInputAt) < RECENT_INPUT_TTL_MS) return result('running', 'recent-input');
|
|
114
|
+
return result('idle', 'default-idle');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
AUTHORITATIVE_STATUS_TTL_MS,
|
|
119
|
+
SERVER_LIVE_STATUS_TTL_MS,
|
|
120
|
+
normalizeLiveSessionStatus,
|
|
121
|
+
liveStatusResult: (status) => result(status, 'live-status'),
|
|
122
|
+
parseTimeMs,
|
|
123
|
+
resolveSessionStatus,
|
|
124
|
+
};
|
|
125
|
+
});
|
|
@@ -443,8 +443,12 @@ async function loadStatus() {
|
|
|
443
443
|
}
|
|
444
444
|
// Slack status now handled by loadConnectedServices()
|
|
445
445
|
if (d.version) {
|
|
446
|
-
|
|
447
|
-
|
|
446
|
+
if (typeof window.setAppVersion === 'function') {
|
|
447
|
+
window.setAppVersion(d.version, { product: 'create-walle' });
|
|
448
|
+
} else {
|
|
449
|
+
var vl = document.getElementById('setup-version-label');
|
|
450
|
+
if (vl) vl.textContent = 'CTM / Wall-E v' + d.version;
|
|
451
|
+
}
|
|
448
452
|
}
|
|
449
453
|
if (d.ctm_data_dir) document.getElementById('setup-ctm-data-dir').value = d.ctm_data_dir;
|
|
450
454
|
if (d.walle_data_dir) document.getElementById('setup-walle-data-dir').value = d.walle_data_dir;
|
|
@@ -1069,11 +1073,19 @@ async function saveDataDirs() {
|
|
|
1069
1073
|
}
|
|
1070
1074
|
|
|
1071
1075
|
// ── MCP Integrations ────────────────────────────────────────────────
|
|
1072
|
-
var MCP_ICONS = {
|
|
1076
|
+
var MCP_ICONS = {
|
|
1077
|
+
'Claude Code': '\uD83E\uDD16',
|
|
1078
|
+
'Claude Code Global': '\uD83E\uDD16',
|
|
1079
|
+
'Codex': '\u25CE',
|
|
1080
|
+
'Cursor': '\u2328\uFE0F',
|
|
1081
|
+
'Windsurf': '\uD83C\uDF0A',
|
|
1082
|
+
'Claude Desktop': '\uD83D\uDDA5\uFE0F',
|
|
1083
|
+
};
|
|
1073
1084
|
var MCP_STATUS_MAP = {
|
|
1074
1085
|
configured: { label: 'Connected', cls: 'badge-connected' },
|
|
1075
1086
|
not_configured: { label: 'Not configured', cls: 'badge-missing' },
|
|
1076
1087
|
wrong_port: { label: 'Wrong port', cls: 'badge-warn' },
|
|
1088
|
+
invalid_config: { label: 'Invalid config', cls: 'badge-warn' },
|
|
1077
1089
|
not_installed: { label: 'Not installed', cls: 'badge-dim' },
|
|
1078
1090
|
};
|
|
1079
1091
|
|
|
@@ -1084,6 +1096,14 @@ function mcpDimMsg(text) {
|
|
|
1084
1096
|
return d;
|
|
1085
1097
|
}
|
|
1086
1098
|
|
|
1099
|
+
function mcpActionText(item) {
|
|
1100
|
+
if (item.status === 'configured') return 'Ready for new agent sessions. Restart the AI tool if it was already open.';
|
|
1101
|
+
if (item.status === 'not_configured') return 'Repair Configs will add the wall-e MCP server entry.';
|
|
1102
|
+
if (item.status === 'wrong_port') return 'Repair Configs will update the wall-e entry to the current Wall-E port.';
|
|
1103
|
+
if (item.status === 'invalid_config') return 'Fix the JSON syntax in this file, then run Repair Configs again.';
|
|
1104
|
+
return '';
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1087
1107
|
function buildMcpRow(item) {
|
|
1088
1108
|
var info = MCP_STATUS_MAP[item.status] || { label: item.status, cls: 'badge-dim' };
|
|
1089
1109
|
var row = document.createElement('div');
|
|
@@ -1108,6 +1128,13 @@ function buildMcpRow(item) {
|
|
|
1108
1128
|
descDiv.textContent = item.configPath;
|
|
1109
1129
|
textWrap.appendChild(descDiv);
|
|
1110
1130
|
}
|
|
1131
|
+
var actionText = mcpActionText(item);
|
|
1132
|
+
if (actionText) {
|
|
1133
|
+
var actionDiv = document.createElement('div');
|
|
1134
|
+
actionDiv.className = 'integration-desc integration-action';
|
|
1135
|
+
actionDiv.textContent = actionText;
|
|
1136
|
+
textWrap.appendChild(actionDiv);
|
|
1137
|
+
}
|
|
1111
1138
|
|
|
1112
1139
|
infoDiv.appendChild(iconDiv);
|
|
1113
1140
|
infoDiv.appendChild(textWrap);
|
|
@@ -1123,25 +1150,38 @@ function buildMcpRow(item) {
|
|
|
1123
1150
|
|
|
1124
1151
|
async function loadMcpIntegrations() {
|
|
1125
1152
|
var container = document.getElementById('setup-mcp-integrations');
|
|
1153
|
+
var testBtn = document.getElementById('setup-mcp-test-btn');
|
|
1154
|
+
var fixBtn = document.getElementById('setup-mcp-fix-btn');
|
|
1126
1155
|
try {
|
|
1127
1156
|
var r = await fetch('/api/wall-e/mcp/integrations');
|
|
1128
1157
|
var d = await r.json();
|
|
1129
|
-
if (d.wallePort) {
|
|
1130
|
-
|
|
1158
|
+
if (d.wallePort) {
|
|
1159
|
+
_mcpPort = d.wallePort;
|
|
1160
|
+
['setup-mcp-port-display', 'setup-mcp-port-display-toml'].forEach(function(id) {
|
|
1161
|
+
var portEl = document.getElementById(id);
|
|
1162
|
+
if (portEl) portEl.textContent = d.wallePort;
|
|
1163
|
+
});
|
|
1164
|
+
}
|
|
1165
|
+
if (!d.data || !d.data.length) {
|
|
1166
|
+
container.replaceChildren(mcpDimMsg('No AI tools detected.'));
|
|
1167
|
+
if (testBtn) testBtn.disabled = false;
|
|
1168
|
+
if (fixBtn) fixBtn.style.display = 'none';
|
|
1169
|
+
return;
|
|
1170
|
+
}
|
|
1131
1171
|
|
|
1132
|
-
var
|
|
1172
|
+
var needsFix = false;
|
|
1133
1173
|
var frag = document.createDocumentFragment();
|
|
1134
1174
|
for (var i = 0; i < d.data.length; i++) {
|
|
1135
1175
|
var item = d.data[i];
|
|
1136
|
-
if (item.status === '
|
|
1137
|
-
if (item.status === 'not_configured' || item.status === 'wrong_port') needsFix = true;
|
|
1176
|
+
if (item.status === 'not_configured' || item.status === 'wrong_port' || item.status === 'invalid_config') needsFix = true;
|
|
1138
1177
|
frag.appendChild(buildMcpRow(item));
|
|
1139
1178
|
}
|
|
1140
1179
|
container.replaceChildren(frag);
|
|
1141
|
-
|
|
1142
|
-
if (
|
|
1180
|
+
if (testBtn) testBtn.disabled = false;
|
|
1181
|
+
if (fixBtn) fixBtn.style.display = needsFix ? '' : 'none';
|
|
1143
1182
|
} catch {
|
|
1144
1183
|
container.replaceChildren(mcpDimMsg('Could not load integrations.'));
|
|
1184
|
+
if (testBtn) testBtn.disabled = false;
|
|
1145
1185
|
}
|
|
1146
1186
|
}
|
|
1147
1187
|
|
|
@@ -1151,17 +1191,15 @@ async function testMcpConnection() {
|
|
|
1151
1191
|
btn.disabled = true; btn.textContent = 'Testing\u2026';
|
|
1152
1192
|
resultEl.style.display = 'none';
|
|
1153
1193
|
try {
|
|
1154
|
-
var r = await fetch('
|
|
1155
|
-
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
1156
|
-
body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'initialize', params: { protocolVersion: '2025-03-26', capabilities: {}, clientInfo: { name: 'setup-wizard', version: '1.0' } } }),
|
|
1157
|
-
});
|
|
1194
|
+
var r = await fetch('/api/wall-e/mcp/test');
|
|
1158
1195
|
var d = await r.json();
|
|
1159
|
-
|
|
1196
|
+
var data = d.data || {};
|
|
1197
|
+
if (data.ok) {
|
|
1160
1198
|
resultEl.className = 'test-result ok'; resultEl.style.display = 'block';
|
|
1161
|
-
resultEl.textContent = '\u2713 MCP
|
|
1199
|
+
resultEl.textContent = '\u2713 Wall-E MCP endpoint is reachable with ' + (data.toolCount || 0) + ' tools.';
|
|
1162
1200
|
} else {
|
|
1163
1201
|
resultEl.className = 'test-result fail'; resultEl.style.display = 'block';
|
|
1164
|
-
resultEl.textContent = '\u2715
|
|
1202
|
+
resultEl.textContent = '\u2715 Wall-E MCP endpoint is not reachable on port ' + _mcpPort + ': ' + (data.error || 'unexpected response');
|
|
1165
1203
|
}
|
|
1166
1204
|
} catch (e) {
|
|
1167
1205
|
resultEl.className = 'test-result fail'; resultEl.style.display = 'block';
|
|
@@ -1177,13 +1215,18 @@ async function fixMcpConfigs() {
|
|
|
1177
1215
|
var r = await fetch('/api/wall-e/mcp/inject', { method: 'POST' });
|
|
1178
1216
|
var d = await r.json();
|
|
1179
1217
|
if (d.ok) {
|
|
1180
|
-
|
|
1218
|
+
var errors = (d.results || []).filter(function(x) { return x.action === 'error'; });
|
|
1219
|
+
if (errors.length) {
|
|
1220
|
+
setupToast('Some MCP configs need manual repair: ' + errors.map(function(x) { return x.tool; }).join(', '), 'error');
|
|
1221
|
+
} else {
|
|
1222
|
+
setupToast('MCP configs updated');
|
|
1223
|
+
}
|
|
1181
1224
|
loadMcpIntegrations();
|
|
1182
1225
|
} else {
|
|
1183
1226
|
setupToast(d.error || 'Fix failed', 'error');
|
|
1184
1227
|
}
|
|
1185
1228
|
} catch (e) { setupToast(e.message, 'error'); }
|
|
1186
|
-
btn.disabled = false; btn.textContent = '
|
|
1229
|
+
btn.disabled = false; btn.textContent = 'Repair Configs';
|
|
1187
1230
|
}
|
|
1188
1231
|
|
|
1189
1232
|
// ── Embeddings ──────────────────────────────────────────────────────
|