@neurynae/toolcairn-mcp 0.1.3 → 0.1.4
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 +535 -48
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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>ToolPilot 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 TOOLPILOT_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 = 'TOOLPILOT_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: "@toolpilot/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();
|
|
@@ -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 =
|
|
184
|
-
var CREDENTIALS_FILE =
|
|
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
|
|
204
|
-
await
|
|
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
|
|
352
|
-
var
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
1440
|
+
var logger3 = pino3({ name: "@toolpilot/tools:toolpilot-init" });
|
|
964
1441
|
async function handleToolpilotInit(args) {
|
|
965
1442
|
try {
|
|
966
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
|
1052
|
-
var
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1102
|
-
var
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1163
|
-
var
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1747
|
+
import pino8 from "pino";
|
|
1271
1748
|
|
|
1272
1749
|
// src/middleware/event-logger.ts
|
|
1273
1750
|
init_esm_shims();
|
|
1274
|
-
import { appendFile, mkdir as
|
|
1751
|
+
import { appendFile, mkdir as mkdir3 } from "fs/promises";
|
|
1275
1752
|
import { dirname } from "path";
|
|
1276
|
-
import
|
|
1277
|
-
var
|
|
1753
|
+
import pino7 from "pino";
|
|
1754
|
+
var logger7 = pino7({ name: "@toolpilot/mcp-server:event-logger" });
|
|
1278
1755
|
var _prisma = null;
|
|
1279
1756
|
async function getPrisma() {
|
|
1280
1757
|
if (!_prisma) {
|
|
@@ -1325,11 +1802,11 @@ function extractMetadata(toolName, result) {
|
|
|
1325
1802
|
}
|
|
1326
1803
|
async function writeToFile(eventsPath, event) {
|
|
1327
1804
|
try {
|
|
1328
|
-
await
|
|
1805
|
+
await mkdir3(dirname(eventsPath), { recursive: true });
|
|
1329
1806
|
await appendFile(eventsPath, `${JSON.stringify(event)}
|
|
1330
1807
|
`, "utf-8");
|
|
1331
1808
|
} catch (e) {
|
|
1332
|
-
|
|
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
|
-
|
|
1828
|
+
logger7.warn({ err: e }, "Failed to write McpEvent to Prisma");
|
|
1352
1829
|
}
|
|
1353
1830
|
}
|
|
1354
1831
|
function withEventLogging(toolName, handler) {
|
|
@@ -1389,7 +1866,7 @@ function withEventLogging(toolName, handler) {
|
|
|
1389
1866
|
}
|
|
1390
1867
|
|
|
1391
1868
|
// src/server.prod.ts
|
|
1392
|
-
var
|
|
1869
|
+
var logger8 = pino8({ name: "@toolpilot/mcp-server:prod" });
|
|
1393
1870
|
var SETUP_INSTRUCTIONS = `
|
|
1394
1871
|
# ToolPilot \u2014 Agent Setup Instructions
|
|
1395
1872
|
|
|
@@ -1397,18 +1874,27 @@ You are connected to the ToolPilot MCP server. ToolPilot is your active tool int
|
|
|
1397
1874
|
|
|
1398
1875
|
## On Every Session Start \u2014 Do This First
|
|
1399
1876
|
|
|
1400
|
-
|
|
1877
|
+
Read \`.toolpilot/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
|
-
###
|
|
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
1882
|
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
|
|
1883
|
+
3. Call \`init_project_config\` \u2014 pass project name, language, framework, and any tools you detect.
|
|
1406
1884
|
4. Write the returned \`config_json\` to \`.toolpilot/config.json\`.
|
|
1407
1885
|
|
|
1408
|
-
###
|
|
1409
|
-
|
|
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 \`toolpilot_init\` with your agent type, project root, and detected files.
|
|
1890
|
+
This appends ToolPilot 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 \`.toolpilot/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
|
|
1897
|
+
3. If \`pending_evaluation\` is non-empty, offer to run \`search_tools\` or \`compare_tools\`.
|
|
1412
1898
|
|
|
1413
1899
|
## When to Use ToolPilot Tools
|
|
1414
1900
|
|
|
@@ -1430,7 +1916,7 @@ async function buildProdServer() {
|
|
|
1430
1916
|
baseUrl: import_config.config.TOOLPILOT_API_URL,
|
|
1431
1917
|
apiKey: creds.client_id
|
|
1432
1918
|
});
|
|
1433
|
-
|
|
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
|
);
|
|
@@ -1577,16 +2063,17 @@ function createTransport() {
|
|
|
1577
2063
|
|
|
1578
2064
|
// src/index.prod.ts
|
|
1579
2065
|
process.env.TOOLPILOT_MODE = "production";
|
|
1580
|
-
var
|
|
2066
|
+
var logger9 = pino9({ name: "@toolpilot/mcp-server" });
|
|
1581
2067
|
async function main() {
|
|
1582
|
-
|
|
2068
|
+
logger9.info("Starting ToolPilot 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
|
-
|
|
2073
|
+
logger9.info("ToolPilot MCP Server started");
|
|
1587
2074
|
}
|
|
1588
2075
|
main().catch((error) => {
|
|
1589
|
-
|
|
2076
|
+
pino9({ name: "@toolpilot/mcp-server" }).error({ err: error }, "Failed to start MCP server");
|
|
1590
2077
|
process.exit(1);
|
|
1591
2078
|
});
|
|
1592
2079
|
//# sourceMappingURL=index.js.map
|