@neurynae/toolcairn-mcp 0.1.3 → 0.2.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/dist/index.js CHANGED
@@ -62,7 +62,484 @@ var require_dist = __commonJS({
62
62
 
63
63
  // src/index.prod.ts
64
64
  init_esm_shims();
65
- import pino8 from "pino";
65
+ import pino9 from "pino";
66
+
67
+ // src/project-setup.ts
68
+ init_esm_shims();
69
+ import { access, mkdir, writeFile } from "fs/promises";
70
+ import { platform, type } from "os";
71
+ import { join } from "path";
72
+ import pino from "pino";
73
+
74
+ // src/tools/generate-tracker.ts
75
+ init_esm_shims();
76
+ function generateTrackerHtml(eventsPath) {
77
+ return `<!DOCTYPE html>
78
+ <html lang="en">
79
+ <head>
80
+ <meta charset="UTF-8" />
81
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
82
+ <title>ToolCairn Tracker</title>
83
+ <style>
84
+ :root {
85
+ --bg: #0a0a0f;
86
+ --surface: #12121a;
87
+ --surface2: #1a1a26;
88
+ --border: #2a2a3a;
89
+ --accent: #7c5cfc;
90
+ --accent2: #5b8def;
91
+ --green: #22c55e;
92
+ --red: #ef4444;
93
+ --yellow: #f59e0b;
94
+ --text: #e2e8f0;
95
+ --muted: #64748b;
96
+ --mono: 'JetBrains Mono', 'Fira Code', monospace;
97
+ }
98
+ * { box-sizing: border-box; margin: 0; padding: 0; }
99
+ body { background: var(--bg); color: var(--text); font-family: system-ui, sans-serif; font-size: 14px; min-height: 100vh; }
100
+
101
+ header { display: flex; align-items: center; gap: 12px; padding: 16px 24px; border-bottom: 1px solid var(--border); background: var(--surface); }
102
+ header h1 { font-size: 16px; font-weight: 700; letter-spacing: -0.02em; }
103
+ header h1 span { color: var(--accent); }
104
+ .status-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--green); animation: pulse 2s infinite; margin-left: auto; }
105
+ .status-dot.paused { background: var(--yellow); animation: none; }
106
+ @keyframes pulse { 0%,100%{ opacity:1; } 50%{ opacity:0.4; } }
107
+
108
+ .controls { display: flex; gap: 8px; align-items: center; padding: 12px 24px; border-bottom: 1px solid var(--border); background: var(--surface); }
109
+ .btn { padding: 5px 12px; border-radius: 6px; border: 1px solid var(--border); background: var(--surface2); color: var(--text); cursor: pointer; font-size: 12px; transition: border-color .15s; }
110
+ .btn:hover { border-color: var(--accent); }
111
+ .btn.active { background: var(--accent); border-color: var(--accent); color: #fff; }
112
+ input[type=range] { accent-color: var(--accent); }
113
+ .label { color: var(--muted); font-size: 12px; }
114
+
115
+ .metrics { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 1px; background: var(--border); border-bottom: 1px solid var(--border); }
116
+ .metric { background: var(--surface); padding: 14px 18px; }
117
+ .metric-label { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 4px; }
118
+ .metric-value { font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; }
119
+ .metric-value.green { color: var(--green); }
120
+ .metric-value.red { color: var(--red); }
121
+ .metric-value.accent { color: var(--accent); }
122
+ .metric-sub { font-size: 11px; color: var(--muted); margin-top: 2px; }
123
+
124
+ .layout { display: grid; grid-template-columns: 1fr 340px; height: calc(100vh - 140px); }
125
+ .feed { overflow-y: auto; border-right: 1px solid var(--border); }
126
+ .sidebar { overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 12px; }
127
+
128
+ .event-row { display: grid; grid-template-columns: 80px 160px 1fr auto auto; gap: 12px; align-items: center; padding: 8px 16px; border-bottom: 1px solid #1a1a22; transition: background .1s; cursor: pointer; }
129
+ .event-row:hover { background: var(--surface2); }
130
+ .event-row.selected { background: #1e1a30; }
131
+ .event-row .time { font-family: var(--mono); font-size: 11px; color: var(--muted); }
132
+ .event-row .tool { font-family: var(--mono); font-size: 12px; color: var(--accent); font-weight: 600; }
133
+ .event-row .summary { font-size: 12px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
134
+ .event-row .dur { font-family: var(--mono); font-size: 11px; color: var(--muted); text-align: right; }
135
+ .badge { display: inline-flex; align-items: center; padding: 2px 7px; border-radius: 4px; font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; }
136
+ .badge.ok { background: rgba(34,197,94,.15); color: var(--green); }
137
+ .badge.error { background: rgba(239,68,68,.15); color: var(--red); }
138
+ .badge.warn { background: rgba(245,158,11,.15); color: var(--yellow); }
139
+
140
+ .detail-card { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 14px; }
141
+ .detail-card h3 { font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); margin-bottom: 10px; }
142
+ .kv { display: flex; justify-content: space-between; padding: 3px 0; border-bottom: 1px solid #1a1a22; font-size: 12px; }
143
+ .kv:last-child { border-bottom: none; }
144
+ .kv .k { color: var(--muted); }
145
+ .kv .v { font-family: var(--mono); color: var(--text); }
146
+ .kv .v.green { color: var(--green); }
147
+ .kv .v.red { color: var(--red); }
148
+ .kv .v.yellow { color: var(--yellow); }
149
+
150
+ .bar-chart { margin-top: 6px; }
151
+ .bar-row { display: flex; align-items: center; gap: 8px; margin-bottom: 5px; font-size: 11px; }
152
+ .bar-label { width: 120px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-align: right; }
153
+ .bar-track { flex: 1; height: 6px; background: var(--surface2); border-radius: 3px; }
154
+ .bar-fill { height: 100%; border-radius: 3px; background: var(--accent); transition: width .3s; }
155
+ .bar-count { width: 28px; text-align: right; color: var(--text); }
156
+
157
+ .empty { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; color: var(--muted); gap: 8px; }
158
+ .empty svg { opacity: .3; }
159
+ .empty p { font-size: 13px; }
160
+ .empty code { font-family: var(--mono); font-size: 11px; background: var(--surface2); padding: 3px 8px; border-radius: 4px; color: var(--accent); }
161
+
162
+ .insights-list { list-style: none; display: flex; flex-direction: column; gap: 6px; }
163
+ .insight-item { background: var(--surface2); border: 1px solid var(--border); border-radius: 6px; padding: 8px 10px; font-size: 12px; }
164
+ .insight-item .i-tool { color: var(--accent); font-family: var(--mono); font-weight: 600; }
165
+ .insight-item .i-text { color: var(--muted); margin-top: 2px; }
166
+
167
+ ::-webkit-scrollbar { width: 4px; }
168
+ ::-webkit-scrollbar-track { background: transparent; }
169
+ ::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
170
+ </style>
171
+ </head>
172
+ <body>
173
+
174
+ <header>
175
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none">
176
+ <circle cx="10" cy="10" r="9" stroke="#7c5cfc" stroke-width="1.5"/>
177
+ <path d="M6 10h8M10 6v8" stroke="#7c5cfc" stroke-width="1.5" stroke-linecap="round"/>
178
+ </svg>
179
+ <h1><span>Tool</span>Pilot Tracker</h1>
180
+ <div id="statusText" style="font-size:12px; color:var(--muted);">Loading...</div>
181
+ <div id="statusDot" class="status-dot paused"></div>
182
+ </header>
183
+
184
+ <div class="controls">
185
+ <button class="btn active" id="btnLive" onclick="toggleLive()">\u2B24 Live</button>
186
+ <button class="btn" id="btnClear" onclick="clearEvents()">Clear</button>
187
+ <span class="label" style="margin-left:8px;">Interval:</span>
188
+ <input type="range" min="1" max="30" value="3" id="intervalSlider" onchange="setInterval_(this.value)" style="width:80px;" />
189
+ <span class="label" id="intervalLabel">3s</span>
190
+ <span style="margin-left:auto; font-size:11px; color:var(--muted);" id="lastRefresh">\u2014</span>
191
+ </div>
192
+
193
+ <div class="metrics" id="metrics">
194
+ <div class="metric"><div class="metric-label">Total Calls</div><div class="metric-value accent" id="mTotal">0</div></div>
195
+ <div class="metric"><div class="metric-label">Success Rate</div><div class="metric-value green" id="mSuccess">\u2014</div></div>
196
+ <div class="metric"><div class="metric-label">Avg Latency</div><div class="metric-value" id="mLatency">\u2014</div></div>
197
+ <div class="metric"><div class="metric-label">Issues Caught</div><div class="metric-value yellow" id="mIssues">0</div><div class="metric-sub">check_issue calls</div></div>
198
+ <div class="metric"><div class="metric-label">Deprecation Warns</div><div class="metric-value yellow" id="mDeprecation">0</div></div>
199
+ <div class="metric"><div class="metric-label">Non-OSS Guided</div><div class="metric-value" id="mNonOss">0</div></div>
200
+ <div class="metric"><div class="metric-label">Graph Updates</div><div class="metric-value accent" id="mGraph">0</div></div>
201
+ </div>
202
+
203
+ <div class="layout">
204
+ <div class="feed" id="feed">
205
+ <div class="empty" id="emptyState">
206
+ <svg width="40" height="40" viewBox="0 0 40 40"><circle cx="20" cy="20" r="18" stroke="currentColor" stroke-width="1.5" fill="none"/><path d="M13 20h14M20 13v14" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
207
+ <p>Waiting for MCP tool calls...</p>
208
+ <code>Set TOOLCAIRN_EVENTS_PATH in your MCP server env</code>
209
+ </div>
210
+ </div>
211
+ <div class="sidebar">
212
+ <div class="detail-card" id="detailPanel" style="display:none">
213
+ <h3>Event Detail</h3>
214
+ <div id="detailContent"></div>
215
+ </div>
216
+ <div class="detail-card">
217
+ <h3>Calls by Tool</h3>
218
+ <div id="toolChart" class="bar-chart"></div>
219
+ </div>
220
+ <div class="detail-card">
221
+ <h3>Recent Insights</h3>
222
+ <ul class="insights-list" id="insightsList"></ul>
223
+ </div>
224
+ </div>
225
+ </div>
226
+
227
+ <script>
228
+ // \u2500\u2500\u2500 Config \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
229
+ const EVENTS_PATH = ${JSON.stringify(eventsPath)};
230
+
231
+ // \u2500\u2500\u2500 State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
232
+ let allEvents = [];
233
+ let selectedId = null;
234
+ let isLive = true;
235
+ let pollIntervalMs = 3000;
236
+ let pollHandle = null;
237
+ let lastByteOffset = 0;
238
+
239
+ // \u2500\u2500\u2500 Polling \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
240
+ async function fetchEvents() {
241
+ if (!EVENTS_PATH) return;
242
+ try {
243
+ // Fetch with range header to only get new bytes
244
+ const headers = lastByteOffset > 0 ? { 'Range': \`bytes=\${lastByteOffset}-\` } : {};
245
+ const res = await fetch(\`file://\${EVENTS_PATH}\`, { headers }).catch(() => null);
246
+ if (!res) return;
247
+
248
+ const text = await res.text();
249
+ if (!text.trim()) return;
250
+
251
+ const newLines = text.trim().split('\\n').filter(Boolean);
252
+ let added = 0;
253
+ for (const line of newLines) {
254
+ try {
255
+ const ev = JSON.parse(line);
256
+ if (!allEvents.find(e => e.id === ev.id)) {
257
+ allEvents.push(ev);
258
+ added++;
259
+ }
260
+ } catch {}
261
+ }
262
+
263
+ if (added > 0) {
264
+ allEvents.sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
265
+ renderAll();
266
+ }
267
+
268
+ document.getElementById('lastRefresh').textContent = 'Updated ' + new Date().toLocaleTimeString();
269
+ document.getElementById('statusDot').className = 'status-dot' + (isLive ? '' : ' paused');
270
+ document.getElementById('statusText').textContent = \`\${allEvents.length} events\`;
271
+ } catch (e) {
272
+ console.warn('Fetch error', e);
273
+ }
274
+ }
275
+
276
+ function toggleLive() {
277
+ isLive = !isLive;
278
+ document.getElementById('btnLive').className = 'btn' + (isLive ? ' active' : '');
279
+ document.getElementById('statusDot').className = 'status-dot' + (isLive ? '' : ' paused');
280
+ if (isLive) startPolling(); else stopPolling();
281
+ }
282
+
283
+ function clearEvents() {
284
+ allEvents = [];
285
+ selectedId = null;
286
+ renderAll();
287
+ }
288
+
289
+ function setInterval_(v) {
290
+ pollIntervalMs = Number(v) * 1000;
291
+ document.getElementById('intervalLabel').textContent = v + 's';
292
+ if (isLive) { stopPolling(); startPolling(); }
293
+ }
294
+
295
+ function startPolling() {
296
+ if (pollHandle) clearInterval(pollHandle);
297
+ fetchEvents();
298
+ pollHandle = setInterval(fetchEvents, pollIntervalMs);
299
+ }
300
+
301
+ function stopPolling() {
302
+ if (pollHandle) { clearInterval(pollHandle); pollHandle = null; }
303
+ }
304
+
305
+ // \u2500\u2500\u2500 Render \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
306
+ function fmtTime(iso) {
307
+ return new Date(iso).toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });
308
+ }
309
+
310
+ function toolSummary(ev) {
311
+ const m = ev.metadata || {};
312
+ if (ev.tool_name === 'search_tools' || ev.tool_name === 'search_tools_respond') {
313
+ const parts = [];
314
+ if (m.is_two_option) parts.push('2-option result');
315
+ if (m.had_non_indexed_guidance) parts.push('non-OSS guidance');
316
+ if (m.had_deprecation_warning) parts.push('\u26A0 deprecated tool');
317
+ if (m.had_credibility_warning) parts.push('\u26A0 low-stars warning');
318
+ return parts.join(' \xB7 ') || m.status || '';
319
+ }
320
+ if (ev.tool_name === 'check_issue') return m.status ? \`status: \${m.status}\` : '';
321
+ if (ev.tool_name === 'suggest_graph_update') {
322
+ if (m.auto_graduated) return '\u2713 auto-graduated to graph';
323
+ if (m.staged) return 'staged for review';
324
+ return '';
325
+ }
326
+ if (ev.tool_name === 'compare_tools') return m.recommendation ? \`rec: \${m.recommendation}\` : '';
327
+ if (ev.tool_name === 'check_compatibility') return m.compatibility_signal ? m.compatibility_signal : '';
328
+ return m.status || '';
329
+ }
330
+
331
+ function renderFeed() {
332
+ const feed = document.getElementById('feed');
333
+ const empty = document.getElementById('emptyState');
334
+ if (allEvents.length === 0) {
335
+ empty.style.display = 'flex';
336
+ feed.querySelectorAll('.event-row').forEach(r => r.remove());
337
+ return;
338
+ }
339
+ empty.style.display = 'none';
340
+
341
+ // Remove rows not in allEvents
342
+ const existingIds = new Set(Array.from(feed.querySelectorAll('.event-row')).map(r => r.dataset.id));
343
+ const currentIds = new Set(allEvents.map(e => e.id));
344
+ existingIds.forEach(id => { if (!currentIds.has(id)) feed.querySelector(\`[data-id="\${id}"]\`)?.remove(); });
345
+
346
+ // Add new rows at top
347
+ for (const ev of allEvents) {
348
+ if (feed.querySelector(\`[data-id="\${ev.id}"]\`)) continue;
349
+ const row = document.createElement('div');
350
+ row.className = 'event-row' + (selectedId === ev.id ? ' selected' : '');
351
+ row.dataset.id = ev.id;
352
+ row.onclick = () => selectEvent(ev.id);
353
+
354
+ const badgeClass = ev.status === 'ok' ? 'ok' : 'error';
355
+ const summary = toolSummary(ev);
356
+ row.innerHTML = \`
357
+ <span class="time">\${fmtTime(ev.created_at)}</span>
358
+ <span class="tool">\${ev.tool_name}</span>
359
+ <span class="summary">\${summary}</span>
360
+ <span class="dur">\${ev.duration_ms}ms</span>
361
+ <span class="badge \${badgeClass}">\${ev.status}</span>
362
+ \`;
363
+
364
+ // Insert in chronological order (newest first)
365
+ const firstRow = feed.querySelector('.event-row');
366
+ if (firstRow) feed.insertBefore(row, firstRow);
367
+ else feed.appendChild(row);
368
+ }
369
+ }
370
+
371
+ function renderMetrics() {
372
+ const total = allEvents.length;
373
+ const okCount = allEvents.filter(e => e.status === 'ok').length;
374
+ const avgMs = total > 0 ? Math.round(allEvents.reduce((s, e) => s + e.duration_ms, 0) / total) : 0;
375
+ const issueCount = allEvents.filter(e => e.tool_name === 'check_issue').length;
376
+ const deprecCount = allEvents.filter(e => e.metadata?.had_deprecation_warning).length;
377
+ const nonOssCount = allEvents.filter(e => e.metadata?.had_non_indexed_guidance).length;
378
+ const graphCount = allEvents.filter(e => e.tool_name === 'suggest_graph_update').length;
379
+
380
+ document.getElementById('mTotal').textContent = total;
381
+ document.getElementById('mSuccess').textContent = total > 0 ? Math.round(okCount / total * 100) + '%' : '\u2014';
382
+ document.getElementById('mLatency').textContent = total > 0 ? avgMs + 'ms' : '\u2014';
383
+ document.getElementById('mIssues').textContent = issueCount;
384
+ document.getElementById('mDeprecation').textContent = deprecCount;
385
+ document.getElementById('mNonOss').textContent = nonOssCount;
386
+ document.getElementById('mGraph').textContent = graphCount;
387
+ }
388
+
389
+ function renderToolChart() {
390
+ const counts = {};
391
+ for (const ev of allEvents) counts[ev.tool_name] = (counts[ev.tool_name] || 0) + 1;
392
+ const sorted = Object.entries(counts).sort((a, b) => b[1] - a[1]).slice(0, 8);
393
+ const max = sorted[0]?.[1] || 1;
394
+ const html = sorted.map(([tool, count]) => \`
395
+ <div class="bar-row">
396
+ <span class="bar-label">\${tool}</span>
397
+ <div class="bar-track"><div class="bar-fill" style="width:\${count/max*100}%"></div></div>
398
+ <span class="bar-count">\${count}</span>
399
+ </div>
400
+ \`).join('');
401
+ document.getElementById('toolChart').innerHTML = html || '<span style="color:var(--muted);font-size:12px">No data yet</span>';
402
+ }
403
+
404
+ function renderInsights() {
405
+ const insights = [];
406
+ for (const ev of allEvents.slice(0, 50)) {
407
+ const m = ev.metadata || {};
408
+ if (ev.tool_name === 'check_issue' && ev.status === 'ok') {
409
+ insights.push({ tool: ev.tool_name, text: 'Issue check ran \u2014 may have prevented a debug loop', time: ev.created_at });
410
+ }
411
+ if (m.had_deprecation_warning) {
412
+ insights.push({ tool: ev.tool_name, text: 'Deprecated/unmaintained tool detected in results', time: ev.created_at });
413
+ }
414
+ if (m.auto_graduated) {
415
+ insights.push({ tool: 'suggest_graph_update', text: 'New edge auto-graduated to graph (confidence \u22650.8)', time: ev.created_at });
416
+ }
417
+ if (m.had_non_indexed_guidance) {
418
+ insights.push({ tool: ev.tool_name, text: 'Non-indexed tool detected \u2014 non-OSS guidance provided', time: ev.created_at });
419
+ }
420
+ if (m.recommendation) {
421
+ insights.push({ tool: 'compare_tools', text: \`Tool comparison recommended: \${m.recommendation}\`, time: ev.created_at });
422
+ }
423
+ }
424
+ const list = document.getElementById('insightsList');
425
+ if (insights.length === 0) {
426
+ list.innerHTML = '<li style="color:var(--muted);font-size:12px">No insights yet</li>';
427
+ return;
428
+ }
429
+ list.innerHTML = insights.slice(0, 8).map(i => \`
430
+ <li class="insight-item">
431
+ <div class="i-tool">\${i.tool}</div>
432
+ <div class="i-text">\${i.text}</div>
433
+ </li>
434
+ \`).join('');
435
+ }
436
+
437
+ function selectEvent(id) {
438
+ selectedId = id;
439
+ document.querySelectorAll('.event-row').forEach(r => r.classList.toggle('selected', r.dataset.id === id));
440
+ const ev = allEvents.find(e => e.id === id);
441
+ if (!ev) return;
442
+ const panel = document.getElementById('detailPanel');
443
+ const content = document.getElementById('detailContent');
444
+ panel.style.display = 'block';
445
+ const m = ev.metadata || {};
446
+ const rows = [
447
+ ['Tool', ev.tool_name],
448
+ ['Status', ev.status],
449
+ ['Duration', ev.duration_ms + 'ms'],
450
+ ['Time', new Date(ev.created_at).toLocaleString()],
451
+ ev.query_id ? ['Session ID', ev.query_id.slice(0, 8) + '...'] : null,
452
+ ...Object.entries(m).filter(([k]) => k !== 'tool').map(([k, v]) => [k, String(v)])
453
+ ].filter(Boolean);
454
+ content.innerHTML = rows.map(([k, v]) => {
455
+ const cls = v === 'true' || v === 'ok' ? 'green' : v === 'false' || v === 'error' ? 'red' : '';
456
+ return \`<div class="kv"><span class="k">\${k}</span><span class="v \${cls}">\${v}</span></div>\`;
457
+ }).join('');
458
+ }
459
+
460
+ function renderAll() {
461
+ renderFeed();
462
+ renderMetrics();
463
+ renderToolChart();
464
+ renderInsights();
465
+ }
466
+
467
+ // \u2500\u2500\u2500 Boot \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
468
+ if (!EVENTS_PATH || EVENTS_PATH === 'null') {
469
+ document.getElementById('statusText').textContent = 'No events path configured';
470
+ document.getElementById('emptyState').querySelector('p').textContent = 'TOOLCAIRN_EVENTS_PATH not set in MCP server environment';
471
+ } else {
472
+ startPolling();
473
+ }
474
+ </script>
475
+ </body>
476
+ </html>`;
477
+ }
478
+
479
+ // src/project-setup.ts
480
+ var logger = pino({ name: "@toolcairn/mcp-server:project-setup" });
481
+ var INITIAL_CONFIG = {
482
+ version: "1.0",
483
+ project: {
484
+ name: "",
485
+ language: "",
486
+ framework: ""
487
+ },
488
+ tools: {
489
+ confirmed: [],
490
+ pending_evaluation: []
491
+ },
492
+ audit_log: []
493
+ };
494
+ function detectOs() {
495
+ const p = platform();
496
+ const labels = {
497
+ win32: "Windows",
498
+ darwin: "macOS",
499
+ linux: "Linux",
500
+ freebsd: "FreeBSD",
501
+ openbsd: "OpenBSD",
502
+ sunos: "Solaris",
503
+ android: "Android"
504
+ };
505
+ return { platform: p, label: labels[p] ?? type() };
506
+ }
507
+ function toFileUrl(absPath) {
508
+ return absPath.replace(/\\/g, "/");
509
+ }
510
+ async function ensureProjectSetup(projectRoot = process.cwd()) {
511
+ const os = detectOs();
512
+ logger.info(
513
+ { os: os.label, platform: os.platform, projectRoot },
514
+ "Detected OS \u2014 starting project setup"
515
+ );
516
+ const dir = join(projectRoot, ".toolpilot");
517
+ const configPath = join(dir, "config.json");
518
+ const trackerPath = join(dir, "tracker.html");
519
+ const eventsPath = join(dir, "events.jsonl");
520
+ const eventsPathForUrl = toFileUrl(eventsPath);
521
+ try {
522
+ await mkdir(dir, { recursive: true });
523
+ await createIfAbsent(configPath, JSON.stringify(INITIAL_CONFIG, null, 2), "config.json");
524
+ await createIfAbsent(trackerPath, generateTrackerHtml(eventsPathForUrl), "tracker.html");
525
+ await createIfAbsent(eventsPath, "", "events.jsonl");
526
+ logger.info({ dir, os: os.label }, ".toolpilot setup ready");
527
+ } catch (e) {
528
+ logger.warn(
529
+ { err: e, dir, os: os.label },
530
+ "Project setup failed \u2014 continuing without .toolpilot files"
531
+ );
532
+ }
533
+ }
534
+ async function createIfAbsent(filePath, content, label) {
535
+ try {
536
+ await access(filePath);
537
+ logger.debug({ file: label }, "Already exists \u2014 skipping");
538
+ } catch {
539
+ await writeFile(filePath, content, "utf-8");
540
+ logger.info({ file: label }, "Created");
541
+ }
542
+ }
66
543
 
67
544
  // src/server.prod.ts
68
545
  init_esm_shims();
@@ -75,7 +552,7 @@ init_esm_shims();
75
552
  // ../../packages/remote/dist/client.js
76
553
  init_esm_shims();
77
554
  var DEFAULT_TIMEOUT_MS = 3e4;
78
- var ToolPilotClient = class {
555
+ var ToolCairnClient = class {
79
556
  baseUrl;
80
557
  apiKey;
81
558
  timeoutMs;
@@ -153,7 +630,7 @@ var ToolPilotClient = class {
153
630
  text: JSON.stringify({
154
631
  ok: false,
155
632
  error: "network_error",
156
- message: `ToolPilot API unreachable: ${msg}. Check your internet connection or try again later.`
633
+ message: `ToolCairn API unreachable: ${msg}. Check your internet connection or try again later.`
157
634
  })
158
635
  }
159
636
  ],
@@ -166,7 +643,7 @@ var ToolPilotClient = class {
166
643
  method: "POST",
167
644
  headers: {
168
645
  "Content-Type": "application/json",
169
- "X-ToolPilot-Key": this.apiKey,
646
+ "X-ToolCairn-Key": this.apiKey,
170
647
  "Accept-Encoding": "gzip"
171
648
  },
172
649
  body: JSON.stringify(body),
@@ -177,11 +654,11 @@ var ToolPilotClient = class {
177
654
 
178
655
  // ../../packages/remote/dist/credentials.js
179
656
  init_esm_shims();
180
- import { mkdir, readFile, writeFile } from "fs/promises";
657
+ import { mkdir as mkdir2, readFile, writeFile as writeFile2 } from "fs/promises";
181
658
  import { homedir } from "os";
182
- import { join } from "path";
183
- var CREDENTIALS_DIR = join(homedir(), ".toolpilot");
184
- var CREDENTIALS_FILE = join(CREDENTIALS_DIR, "credentials.json");
659
+ import { join as join2 } from "path";
660
+ var CREDENTIALS_DIR = join2(homedir(), ".toolpilot");
661
+ var CREDENTIALS_FILE = join2(CREDENTIALS_DIR, "credentials.json");
185
662
  async function loadOrCreateCredentials(registerFn) {
186
663
  try {
187
664
  const raw = await readFile(CREDENTIALS_FILE, "utf-8");
@@ -200,8 +677,8 @@ async function loadOrCreateCredentials(registerFn) {
200
677
  }
201
678
  }
202
679
  async function saveCredentials(creds) {
203
- await mkdir(CREDENTIALS_DIR, { recursive: true });
204
- await writeFile(CREDENTIALS_FILE, JSON.stringify(creds, null, 2), "utf-8");
680
+ await mkdir2(CREDENTIALS_DIR, { recursive: true });
681
+ await writeFile2(CREDENTIALS_FILE, JSON.stringify(creds, null, 2), "utf-8");
205
682
  }
206
683
 
207
684
  // ../../packages/tools/dist/local.js
@@ -348,8 +825,8 @@ function errResult(error, message) {
348
825
 
349
826
  // ../../packages/tools/dist/handlers/classify-prompt.js
350
827
  init_esm_shims();
351
- import pino from "pino";
352
- var logger = pino({ name: "@toolpilot/tools:classify-prompt" });
828
+ import pino2 from "pino";
829
+ var logger2 = pino2({ name: "@toolpilot/tools:classify-prompt" });
353
830
  var TOOL_REQUIRED_CLASSIFICATIONS = [
354
831
  "tool_discovery",
355
832
  "stack_building",
@@ -357,7 +834,7 @@ var TOOL_REQUIRED_CLASSIFICATIONS = [
357
834
  ];
358
835
  async function handleClassifyPrompt(args) {
359
836
  try {
360
- logger.info({ promptLen: args.prompt.length }, "classify_prompt called");
837
+ logger2.info({ promptLen: args.prompt.length }, "classify_prompt called");
361
838
  const projectToolsContext = args.project_tools && args.project_tools.length > 0 ? `
362
839
 
363
840
  The project already uses: ${args.project_tools.join(", ")}. Consider whether the prompt relates to tools already confirmed in the project.` : "";
@@ -403,14 +880,14 @@ Respond with ONLY 0 or 1.`;
403
880
  instructions: "Step 1: Send classification_prompt to the LLM and get a classification. Step 2: If classification is in tool_required_if, call refine_requirement with the classification. Otherwise, proceed without ToolPilot search."
404
881
  });
405
882
  } catch (e) {
406
- logger.error({ err: e }, "classify_prompt failed");
883
+ logger2.error({ err: e }, "classify_prompt failed");
407
884
  return errResult("classify_error", e instanceof Error ? e.message : String(e));
408
885
  }
409
886
  }
410
887
 
411
888
  // ../../packages/tools/dist/handlers/toolpilot-init.js
412
889
  init_esm_shims();
413
- import pino2 from "pino";
890
+ import pino3 from "pino";
414
891
 
415
892
  // ../../packages/tools/dist/templates/agent-instructions.js
416
893
  init_esm_shims();
@@ -556,7 +1033,7 @@ function getOpenCodeMcpEntry(serverPath) {
556
1033
 
557
1034
  // ../../packages/tools/dist/templates/generate-tracker.js
558
1035
  init_esm_shims();
559
- function generateTrackerHtml(eventsPath) {
1036
+ function generateTrackerHtml2(eventsPath) {
560
1037
  return `<!DOCTYPE html>
561
1038
  <html lang="en">
562
1039
  <head>
@@ -960,10 +1437,10 @@ if (!EVENTS_PATH || EVENTS_PATH === 'null') {
960
1437
  }
961
1438
 
962
1439
  // ../../packages/tools/dist/handlers/toolpilot-init.js
963
- var logger2 = pino2({ name: "@toolpilot/tools:toolpilot-init" });
1440
+ var logger3 = pino3({ name: "@toolpilot/tools:toolpilot-init" });
964
1441
  async function handleToolpilotInit(args) {
965
1442
  try {
966
- logger2.info({ agent: args.agent, project_root: args.project_root }, "toolpilot_init called");
1443
+ logger3.info({ agent: args.agent, project_root: args.project_root }, "toolpilot_init called");
967
1444
  const instructions = getInstructionsForAgent(args.agent);
968
1445
  const isOpenCode = args.agent === "opencode";
969
1446
  const mcpConfigEntry = isOpenCode ? getOpenCodeMcpEntry(args.server_path) : getMcpConfigEntry(args.server_path);
@@ -1005,7 +1482,7 @@ async function handleToolpilotInit(args) {
1005
1482
  step: step++,
1006
1483
  action: "create",
1007
1484
  file: ".toolpilot/tracker.html",
1008
- content: generateTrackerHtml(eventsPath),
1485
+ content: generateTrackerHtml2(eventsPath),
1009
1486
  note: `Open .toolpilot/tracker.html in your browser to monitor MCP tool calls in real time. Set TOOLPILOT_EVENTS_PATH=${eventsPath} in your MCP server environment to enable event logging.`
1010
1487
  });
1011
1488
  }
@@ -1041,18 +1518,18 @@ async function handleToolpilotInit(args) {
1041
1518
  next_steps: hasToolpilotConfig ? "Setup complete. Open .toolpilot/tracker.html to monitor tool calls." : "After completing setup steps, call init_project_config to initialize .toolpilot/config.json."
1042
1519
  });
1043
1520
  } catch (e) {
1044
- logger2.error({ err: e }, "toolpilot_init failed");
1521
+ logger3.error({ err: e }, "toolpilot_init failed");
1045
1522
  return errResult("init_error", e instanceof Error ? e.message : String(e));
1046
1523
  }
1047
1524
  }
1048
1525
 
1049
1526
  // ../../packages/tools/dist/handlers/init-project-config.js
1050
1527
  init_esm_shims();
1051
- import pino3 from "pino";
1052
- var logger3 = pino3({ name: "@toolpilot/tools:init-project-config" });
1528
+ import pino4 from "pino";
1529
+ var logger4 = pino4({ name: "@toolpilot/tools:init-project-config" });
1053
1530
  async function handleInitProjectConfig(args) {
1054
1531
  try {
1055
- logger3.info({ project: args.project_name }, "init_project_config called");
1532
+ logger4.info({ project: args.project_name }, "init_project_config called");
1056
1533
  const now = (/* @__PURE__ */ new Date()).toISOString();
1057
1534
  const confirmedTools = (args.detected_tools ?? []).map((t) => ({
1058
1535
  name: t.name,
@@ -1091,22 +1568,22 @@ async function handleInitProjectConfig(args) {
1091
1568
  next_step: confirmedTools.length > 0 ? "Config initialized with auto-detected tools. Use search_tools to find any additional tools you need." : "Config initialized. Use classify_prompt \u2192 refine_requirement \u2192 search_tools to discover tools for your project."
1092
1569
  });
1093
1570
  } catch (e) {
1094
- logger3.error({ err: e }, "init_project_config failed");
1571
+ logger4.error({ err: e }, "init_project_config failed");
1095
1572
  return errResult("init_config_error", e instanceof Error ? e.message : String(e));
1096
1573
  }
1097
1574
  }
1098
1575
 
1099
1576
  // ../../packages/tools/dist/handlers/read-project-config.js
1100
1577
  init_esm_shims();
1101
- import pino4 from "pino";
1102
- var logger4 = pino4({ name: "@toolpilot/tools:read-project-config" });
1578
+ import pino5 from "pino";
1579
+ var logger5 = pino5({ name: "@toolpilot/tools:read-project-config" });
1103
1580
  var STALENESS_THRESHOLD_DAYS = 90;
1104
1581
  function daysSince(isoDate) {
1105
1582
  return (Date.now() - new Date(isoDate).getTime()) / (1e3 * 60 * 60 * 24);
1106
1583
  }
1107
1584
  async function handleReadProjectConfig(args) {
1108
1585
  try {
1109
- logger4.info("read_project_config called");
1586
+ logger5.info("read_project_config called");
1110
1587
  let config3;
1111
1588
  try {
1112
1589
  config3 = JSON.parse(args.config_content);
@@ -1152,18 +1629,18 @@ async function handleReadProjectConfig(args) {
1152
1629
  ].filter(Boolean).join("\n")
1153
1630
  });
1154
1631
  } catch (e) {
1155
- logger4.error({ err: e }, "read_project_config failed");
1632
+ logger5.error({ err: e }, "read_project_config failed");
1156
1633
  return errResult("read_config_error", e instanceof Error ? e.message : String(e));
1157
1634
  }
1158
1635
  }
1159
1636
 
1160
1637
  // ../../packages/tools/dist/handlers/update-project-config.js
1161
1638
  init_esm_shims();
1162
- import pino5 from "pino";
1163
- var logger5 = pino5({ name: "@toolpilot/tools:update-project-config" });
1639
+ import pino6 from "pino";
1640
+ var logger6 = pino6({ name: "@toolpilot/tools:update-project-config" });
1164
1641
  async function handleUpdateProjectConfig(args) {
1165
1642
  try {
1166
- logger5.info({ action: args.action, tool: args.tool_name }, "update_project_config called");
1643
+ logger6.info({ action: args.action, tool: args.tool_name }, "update_project_config called");
1167
1644
  let config3;
1168
1645
  try {
1169
1646
  config3 = JSON.parse(args.current_config);
@@ -1261,20 +1738,20 @@ async function handleUpdateProjectConfig(args) {
1261
1738
  instructions: "Write updated_config_json to .toolpilot/config.json to persist this change."
1262
1739
  });
1263
1740
  } catch (e) {
1264
- logger5.error({ err: e }, "update_project_config failed");
1741
+ logger6.error({ err: e }, "update_project_config failed");
1265
1742
  return errResult("update_config_error", e instanceof Error ? e.message : String(e));
1266
1743
  }
1267
1744
  }
1268
1745
 
1269
1746
  // src/server.prod.ts
1270
- import pino7 from "pino";
1747
+ import pino8 from "pino";
1271
1748
 
1272
1749
  // src/middleware/event-logger.ts
1273
1750
  init_esm_shims();
1274
- import { appendFile, mkdir as mkdir2 } from "fs/promises";
1751
+ import { appendFile, mkdir as mkdir3 } from "fs/promises";
1275
1752
  import { dirname } from "path";
1276
- import pino6 from "pino";
1277
- var logger6 = pino6({ name: "@toolpilot/mcp-server:event-logger" });
1753
+ import pino7 from "pino";
1754
+ var logger7 = pino7({ name: "@toolcairn/mcp-server:event-logger" });
1278
1755
  var _prisma = null;
1279
1756
  async function getPrisma() {
1280
1757
  if (!_prisma) {
@@ -1287,10 +1764,10 @@ async function getPrisma() {
1287
1764
  return _prisma;
1288
1765
  }
1289
1766
  function isTrackingEnabled() {
1290
- return process.env.TOOLPILOT_TRACKING_ENABLED !== "false";
1767
+ return process.env.TOOLCAIRN_TRACKING_ENABLED !== "false";
1291
1768
  }
1292
1769
  function getEventsPath() {
1293
- return process.env.TOOLPILOT_EVENTS_PATH ?? null;
1770
+ return process.env.TOOLCAIRN_EVENTS_PATH ?? null;
1294
1771
  }
1295
1772
  function extractQueryId(args) {
1296
1773
  if (typeof args.query_id === "string") return args.query_id;
@@ -1325,11 +1802,11 @@ function extractMetadata(toolName, result) {
1325
1802
  }
1326
1803
  async function writeToFile(eventsPath, event) {
1327
1804
  try {
1328
- await mkdir2(dirname(eventsPath), { recursive: true });
1805
+ await mkdir3(dirname(eventsPath), { recursive: true });
1329
1806
  await appendFile(eventsPath, `${JSON.stringify(event)}
1330
1807
  `, "utf-8");
1331
1808
  } catch (e) {
1332
- logger6.warn({ err: e, path: eventsPath }, "Failed to write event to JSONL file");
1809
+ logger7.warn({ err: e, path: eventsPath }, "Failed to write event to JSONL file");
1333
1810
  }
1334
1811
  }
1335
1812
  async function writeToPrisma(event) {
@@ -1348,7 +1825,7 @@ async function writeToPrisma(event) {
1348
1825
  }
1349
1826
  });
1350
1827
  } catch (e) {
1351
- logger6.warn({ err: e }, "Failed to write McpEvent to Prisma");
1828
+ logger7.warn({ err: e }, "Failed to write McpEvent to Prisma");
1352
1829
  }
1353
1830
  }
1354
1831
  function withEventLogging(toolName, handler) {
@@ -1389,28 +1866,37 @@ function withEventLogging(toolName, handler) {
1389
1866
  }
1390
1867
 
1391
1868
  // src/server.prod.ts
1392
- var logger7 = pino7({ name: "@toolpilot/mcp-server:prod" });
1869
+ var logger8 = pino8({ name: "@toolcairn/mcp-server:prod" });
1393
1870
  var SETUP_INSTRUCTIONS = `
1394
- # ToolPilot \u2014 Agent Setup Instructions
1871
+ # ToolCairn \u2014 Agent Setup Instructions
1395
1872
 
1396
- You are connected to the ToolPilot MCP server. ToolPilot is your active tool intelligence co-pilot.
1873
+ You are connected to the ToolCairn MCP server. ToolCairn is your active tool intelligence co-pilot.
1397
1874
 
1398
1875
  ## On Every Session Start \u2014 Do This First
1399
1876
 
1400
- Check whether \`.toolpilot/config.json\` exists in the project root.
1877
+ Read \`.toolcairn/config.json\` in the project root. The server auto-creates this file on startup,
1878
+ so it will almost always exist \u2014 but it may be an empty scaffold that still needs configuration.
1401
1879
 
1402
- ### If it does NOT exist (new project or first-time setup):
1880
+ ### Case 1 \u2014 File does NOT exist (rare: read-only filesystem or manual deletion):
1403
1881
  1. List the project root files (package.json, requirements.txt, CLAUDE.md, .cursorrules, .mcp.json, etc.)
1404
- 2. Call \`toolpilot_init\` with your agent type, project root path, and the list of detected files.
1405
- 3. Call \`init_project_config\` \u2014 pass your project name, language, framework, and any tools you can detect.
1406
- 4. Write the returned \`config_json\` to \`.toolpilot/config.json\`.
1407
-
1408
- ### If it DOES exist (returning to an existing project):
1409
- 1. Read \`.toolpilot/config.json\` and call \`read_project_config\` with its content.
1882
+ 2. Call \`toolcairn_init\` with your agent type, project root path, and the list of detected files.
1883
+ 3. Call \`init_project_config\` \u2014 pass project name, language, framework, and any tools you detect.
1884
+ 4. Write the returned \`config_json\` to \`.toolcairn/config.json\`.
1885
+
1886
+ ### Case 2 \u2014 File EXISTS but \`project.name\` is empty (auto-created scaffold \u2014 not yet configured):
1887
+ The server wrote the file at startup. You still need to fill in the project details:
1888
+ 1. List the project root files to detect the tech stack.
1889
+ 2. Call \`toolcairn_init\` with your agent type, project root, and detected files.
1890
+ This appends ToolCairn rules to CLAUDE.md (or equivalent) and sets up the tracker.
1891
+ 3. Call \`init_project_config\` with the project name, language, framework, and detected tools.
1892
+ 4. Write the returned \`config_json\` to \`.toolcairn/config.json\` (overwrites the empty scaffold).
1893
+
1894
+ ### Case 3 \u2014 File EXISTS and \`project.name\` is set (returning to a configured project):
1895
+ 1. Call \`read_project_config\` with the file content.
1410
1896
  2. If \`stale_tools\` is non-empty, inform the user and offer to re-verify those tools.
1411
- 3. If \`pending_evaluation\` is non-empty, offer to run \`search_tools\` or \`compare_tools\` to resolve them.
1897
+ 3. If \`pending_evaluation\` is non-empty, offer to run \`search_tools\` or \`compare_tools\`.
1412
1898
 
1413
- ## When to Use ToolPilot Tools
1899
+ ## When to Use ToolCairn Tools
1414
1900
 
1415
1901
  | Situation | Tool to call |
1416
1902
  |-----------|-------------|
@@ -1426,38 +1912,38 @@ Check whether \`.toolpilot/config.json\` exists in the project root.
1426
1912
  `.trim();
1427
1913
  async function buildProdServer() {
1428
1914
  const creds = await loadOrCreateCredentials();
1429
- const remote = new ToolPilotClient({
1915
+ const remote = new ToolCairnClient({
1430
1916
  baseUrl: import_config.config.TOOLPILOT_API_URL,
1431
1917
  apiKey: creds.client_id
1432
1918
  });
1433
- logger7.info(
1919
+ logger8.info(
1434
1920
  { apiUrl: import_config.config.TOOLPILOT_API_URL, clientId: `${creds.client_id.slice(0, 8)}...` },
1435
1921
  "Production MCP mode: connecting to remote API"
1436
1922
  );
1437
1923
  const server = new McpServer(
1438
- { name: "toolpilot", version: "0.1.0" },
1924
+ { name: "toolcairn", version: "0.1.0" },
1439
1925
  { instructions: SETUP_INSTRUCTIONS }
1440
1926
  );
1441
1927
  server.registerTool(
1442
1928
  "classify_prompt",
1443
1929
  {
1444
- description: "Classify a developer prompt to determine if ToolPilot tool search is needed. Returns a structured classification prompt for the agent to evaluate.",
1930
+ description: "Classify a developer prompt to determine if ToolCairn tool search is needed. Returns a structured classification prompt for the agent to evaluate.",
1445
1931
  inputSchema: classifyPromptSchema
1446
1932
  },
1447
1933
  withEventLogging("classify_prompt", async (args) => handleClassifyPrompt(args))
1448
1934
  );
1449
1935
  server.registerTool(
1450
- "toolpilot_init",
1936
+ "toolcairn_init",
1451
1937
  {
1452
- description: "Set up ToolPilot integration for the current project. Generates agent instruction content, MCP config entry, and project config initializer.",
1938
+ description: "Set up ToolCairn integration for the current project. Generates agent instruction content, MCP config entry, and project config initializer.",
1453
1939
  inputSchema: toolpilotInitSchema
1454
1940
  },
1455
- withEventLogging("toolpilot_init", async (args) => handleToolpilotInit(args))
1941
+ withEventLogging("toolcairn_init", async (args) => handleToolpilotInit(args))
1456
1942
  );
1457
1943
  server.registerTool(
1458
1944
  "init_project_config",
1459
1945
  {
1460
- description: "Initialize a .toolpilot/config.json file for the current project. Returns the config JSON for the agent to write to disk.",
1946
+ description: "Initialize a .toolcairn/config.json file for the current project. Returns the config JSON for the agent to write to disk.",
1461
1947
  inputSchema: initProjectConfigSchema
1462
1948
  },
1463
1949
  withEventLogging("init_project_config", async (args) => handleInitProjectConfig(args))
@@ -1465,7 +1951,7 @@ async function buildProdServer() {
1465
1951
  server.registerTool(
1466
1952
  "read_project_config",
1467
1953
  {
1468
- description: "Parse and validate a .toolpilot/config.json file. Returns confirmed tools, pending evaluations, stale tools, and agent instructions.",
1954
+ description: "Parse and validate a .toolcairn/config.json file. Returns confirmed tools, pending evaluations, stale tools, and agent instructions.",
1469
1955
  inputSchema: readProjectConfigSchema
1470
1956
  },
1471
1957
  withEventLogging("read_project_config", async (args) => handleReadProjectConfig(args))
@@ -1473,7 +1959,7 @@ async function buildProdServer() {
1473
1959
  server.registerTool(
1474
1960
  "update_project_config",
1475
1961
  {
1476
- description: "Apply a mutation to .toolpilot/config.json and return the updated content. Actions: add_tool, remove_tool, update_tool, add_evaluation.",
1962
+ description: "Apply a mutation to .toolcairn/config.json and return the updated content. Actions: add_tool, remove_tool, update_tool, add_evaluation.",
1477
1963
  inputSchema: updateProjectConfigSchema
1478
1964
  },
1479
1965
  withEventLogging("update_project_config", async (args) => handleUpdateProjectConfig(args))
@@ -1537,7 +2023,7 @@ async function buildProdServer() {
1537
2023
  server.registerTool(
1538
2024
  "verify_suggestion",
1539
2025
  {
1540
- description: "Validate agent-suggested tools against the ToolPilot graph.",
2026
+ description: "Validate agent-suggested tools against the ToolCairn graph.",
1541
2027
  inputSchema: verifySuggestionSchema
1542
2028
  },
1543
2029
  withEventLogging("verify_suggestion", async (args) => remote.verifySuggestion(args))
@@ -1545,7 +2031,7 @@ async function buildProdServer() {
1545
2031
  server.registerTool(
1546
2032
  "report_outcome",
1547
2033
  {
1548
- description: "Report the outcome of using a tool recommended by ToolPilot (fire-and-forget).",
2034
+ description: "Report the outcome of using a tool recommended by ToolCairn (fire-and-forget).",
1549
2035
  inputSchema: reportOutcomeSchema
1550
2036
  },
1551
2037
  withEventLogging("report_outcome", async (args) => remote.reportOutcome(args))
@@ -1553,7 +2039,7 @@ async function buildProdServer() {
1553
2039
  server.registerTool(
1554
2040
  "suggest_graph_update",
1555
2041
  {
1556
- description: "Suggest a new tool, relationship, use case, or health update to the ToolPilot graph.",
2042
+ description: "Suggest a new tool, relationship, use case, or health update to the ToolCairn graph.",
1557
2043
  inputSchema: suggestGraphUpdateSchema
1558
2044
  },
1559
2045
  withEventLogging("suggest_graph_update", async (args) => remote.suggestGraphUpdate(args))
@@ -1577,16 +2063,17 @@ function createTransport() {
1577
2063
 
1578
2064
  // src/index.prod.ts
1579
2065
  process.env.TOOLPILOT_MODE = "production";
1580
- var logger8 = pino8({ name: "@toolpilot/mcp-server" });
2066
+ var logger9 = pino9({ name: "@toolcairn/mcp-server" });
1581
2067
  async function main() {
1582
- logger8.info("Starting ToolPilot MCP Server (production mode)");
2068
+ logger9.info("Starting ToolCairn MCP Server (production mode)");
2069
+ await ensureProjectSetup();
1583
2070
  const server = await buildProdServer();
1584
2071
  const transport = createTransport();
1585
2072
  await server.connect(transport);
1586
- logger8.info("ToolPilot MCP Server started");
2073
+ logger9.info("ToolCairn MCP Server started");
1587
2074
  }
1588
2075
  main().catch((error) => {
1589
- pino8({ name: "@toolpilot/mcp-server" }).error({ err: error }, "Failed to start MCP server");
2076
+ pino9({ name: "@toolcairn/mcp-server" }).error({ err: error }, "Failed to start MCP server");
1590
2077
  process.exit(1);
1591
2078
  });
1592
2079
  //# sourceMappingURL=index.js.map