clementine-agent 1.18.80 → 1.18.81
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/cli/dashboard.js +180 -5
- package/package.json +1 -1
package/dist/cli/dashboard.js
CHANGED
|
@@ -16356,14 +16356,18 @@ if('serviceWorker' in navigator){navigator.serviceWorker.getRegistrations().then
|
|
|
16356
16356
|
|
|
16357
16357
|
<!-- ═══ Tasks Page — single unified surface ═══ -->
|
|
16358
16358
|
<div class="page" id="page-build">
|
|
16359
|
-
<!--
|
|
16360
|
-
|
|
16361
|
-
?tab=workflows
|
|
16362
|
-
|
|
16359
|
+
<!-- PRD Phase 2: top-level tab strip within the Tasks domain.
|
|
16360
|
+
Tasks (default) + Tools & MCP catalog. Workflows still reachable
|
|
16361
|
+
via deep-link ?tab=workflows for power users with existing
|
|
16362
|
+
multi-step workflows. -->
|
|
16363
|
+
<div id="build-tabs" style="display:flex;gap:4px;padding:8px 18px 0;background:var(--bg-secondary);border-bottom:1px solid var(--border);flex-shrink:0">
|
|
16363
16364
|
<button class="build-tab-btn active" data-build-tab="crons" onclick="switchBuildTab('crons')" style="padding:8px 14px;border-radius:6px 6px 0 0;border:none;background:transparent;color:var(--text-primary);font-size:13px;font-weight:500;cursor:pointer;border-bottom:2px solid transparent">
|
|
16364
16365
|
<span style="margin-right:6px">📅</span>Tasks <span id="build-tab-cron-count" style="display:none;margin-left:4px;font-size:10px;background:var(--bg-tertiary);padding:1px 6px;border-radius:999px;color:var(--text-muted)">0</span>
|
|
16365
16366
|
</button>
|
|
16366
|
-
<button class="build-tab-btn" data-build-tab="
|
|
16367
|
+
<button class="build-tab-btn" data-build-tab="toolsmcp" onclick="switchBuildTab('toolsmcp')" style="padding:8px 14px;border-radius:6px 6px 0 0;border:none;background:transparent;color:var(--text-secondary);font-size:13px;font-weight:500;cursor:pointer;border-bottom:2px solid transparent">
|
|
16368
|
+
<span style="margin-right:6px">🧰</span>Tools & MCP <span id="build-tab-toolsmcp-count" style="display:none;margin-left:4px;font-size:10px;background:var(--bg-tertiary);padding:1px 6px;border-radius:999px;color:var(--text-muted)">0</span>
|
|
16369
|
+
</button>
|
|
16370
|
+
<button class="build-tab-btn" data-build-tab="workflows" onclick="switchBuildTab('workflows')" style="display:none;padding:8px 14px;border-radius:6px 6px 0 0;border:none;background:transparent;color:var(--text-secondary);font-size:13px;font-weight:500;cursor:pointer;border-bottom:2px solid transparent">
|
|
16367
16371
|
<span style="margin-right:6px">🔧</span>Workflows <span id="build-tab-workflows-count" style="display:none;margin-left:4px;font-size:10px;background:var(--bg-tertiary);padding:1px 6px;border-radius:999px;color:var(--text-muted)">0</span>
|
|
16368
16372
|
</button>
|
|
16369
16373
|
</div>
|
|
@@ -16375,6 +16379,12 @@ if('serviceWorker' in navigator){navigator.serviceWorker.getRegistrations().then
|
|
|
16375
16379
|
<div id="build-tab-crons" style="display:none;flex:1;min-height:0;overflow-y:auto;padding:18px;background:var(--bg-primary)">
|
|
16376
16380
|
<div id="panel-cron"><div class="empty-state" style="padding:24px;color:var(--text-muted)">Loading scheduled tasks…</div></div>
|
|
16377
16381
|
</div>
|
|
16382
|
+
<!-- ── PRD Phase 2: Tools & MCP catalog ────────────────────────────────
|
|
16383
|
+
Read-only foundation in 1.18.81. Future slices: per-tool bindings,
|
|
16384
|
+
Reconnect/Toggle/Edit actions, Approval Mode + Max-auto-runs config. -->
|
|
16385
|
+
<div id="build-tab-toolsmcp" style="display:none;flex:1;min-height:0;overflow-y:auto;padding:18px;background:var(--bg-primary)">
|
|
16386
|
+
<div id="panel-toolsmcp"><div class="empty-state" style="padding:24px;color:var(--text-muted)">Loading Tools & MCP catalog…</div></div>
|
|
16387
|
+
</div>
|
|
16378
16388
|
<!-- Tricks (workflows) tab — existing RoutinesUI surface ─────────────────── -->
|
|
16379
16389
|
<div id="build-tab-workflows" style="display:none;flex:1;min-height:0;display:flex;flex-direction:column">
|
|
16380
16390
|
<!-- Toolbar -->
|
|
@@ -21148,12 +21158,27 @@ function switchBuildTab(tab) {
|
|
|
21148
21158
|
var workPane = document.getElementById('build-tab-workflows');
|
|
21149
21159
|
var cronPane = document.getElementById('build-tab-crons');
|
|
21150
21160
|
var tplPane = document.getElementById('build-tab-templates');
|
|
21161
|
+
var toolsmcpPane = document.getElementById('build-tab-toolsmcp');
|
|
21151
21162
|
var headerStrip = document.getElementById('build-header-strip');
|
|
21152
21163
|
var usagePanel = document.getElementById('build-usage-panel');
|
|
21153
21164
|
var newBtn = document.getElementById('builder-new-btn');
|
|
21154
21165
|
// Always close any open workflow when changing tabs — switching context
|
|
21155
21166
|
// is a clean slate, not a stale node hanging on the canvas.
|
|
21156
21167
|
if (typeof closeBuilderCanvas === 'function') closeBuilderCanvas();
|
|
21168
|
+
// Default: hide the Tools & MCP pane unless we're explicitly on it.
|
|
21169
|
+
if (toolsmcpPane && tab !== 'toolsmcp') toolsmcpPane.style.display = 'none';
|
|
21170
|
+
if (tab === 'toolsmcp') {
|
|
21171
|
+
// PRD Phase 2: Tools & MCP catalog. Read-only foundation in 1.18.81.
|
|
21172
|
+
if (workPane) workPane.style.display = 'none';
|
|
21173
|
+
if (cronPane) cronPane.style.display = 'none';
|
|
21174
|
+
if (tplPane) tplPane.style.display = 'none';
|
|
21175
|
+
if (toolsmcpPane) toolsmcpPane.style.display = 'block';
|
|
21176
|
+
if (headerStrip) headerStrip.style.display = 'none';
|
|
21177
|
+
if (usagePanel) usagePanel.style.display = 'none';
|
|
21178
|
+
if (newBtn) newBtn.style.display = 'none';
|
|
21179
|
+
if (typeof refreshToolsMcpCatalog === 'function') refreshToolsMcpCatalog();
|
|
21180
|
+
return;
|
|
21181
|
+
}
|
|
21157
21182
|
if (tab === 'templates') {
|
|
21158
21183
|
if (workPane) workPane.style.display = 'none';
|
|
21159
21184
|
if (cronPane) cronPane.style.display = 'none';
|
|
@@ -23532,6 +23557,156 @@ function renderRunningCard(item) {
|
|
|
23532
23557
|
+ '</div></div>';
|
|
23533
23558
|
}
|
|
23534
23559
|
|
|
23560
|
+
// ── PRD Phase 2: Tools & MCP catalog ──────────────────────────────────
|
|
23561
|
+
// Read-only foundation in 1.18.81. Renders the four-card taxonomy:
|
|
23562
|
+
// • Built-in — Claude SDK native tools (Read/Write/Bash/etc.)
|
|
23563
|
+
// • Custom MCP — in-process SDK MCP servers
|
|
23564
|
+
// • Shell command — CLI wrappers
|
|
23565
|
+
// • External MCP — stdio / sse / http MCP servers
|
|
23566
|
+
// Pulls from /api/mcp-status (live status) + /api/mcp-servers (config).
|
|
23567
|
+
// Future slices wire Reconnect/Toggle/Edit + the McpToolBinding modal.
|
|
23568
|
+
async function refreshToolsMcpCatalog() {
|
|
23569
|
+
var panel = document.getElementById('panel-toolsmcp');
|
|
23570
|
+
if (!panel) return;
|
|
23571
|
+
panel.innerHTML = '<div class="empty-state" style="padding:24px;color:var(--text-muted)">Loading Tools & MCP catalog…</div>';
|
|
23572
|
+
var statusMap = {};
|
|
23573
|
+
var servers = [];
|
|
23574
|
+
try {
|
|
23575
|
+
var sR = await apiFetch('/api/mcp-status');
|
|
23576
|
+
var statusJson = await sR.json();
|
|
23577
|
+
statusMap = statusJson || {};
|
|
23578
|
+
} catch (e) { /* status is optional — servers still render without it */ }
|
|
23579
|
+
try {
|
|
23580
|
+
var lR = await apiFetch('/api/mcp-servers');
|
|
23581
|
+
var lJson = await lR.json();
|
|
23582
|
+
servers = (lJson && lJson.servers) || [];
|
|
23583
|
+
} catch (e) {
|
|
23584
|
+
panel.innerHTML = '<div class="empty-state" style="padding:24px;color:var(--red)">Failed to load MCP servers: ' + esc(String(e)) + '</div>';
|
|
23585
|
+
return;
|
|
23586
|
+
}
|
|
23587
|
+
var tabCount = document.getElementById('build-tab-toolsmcp-count');
|
|
23588
|
+
if (tabCount) {
|
|
23589
|
+
tabCount.textContent = servers.length;
|
|
23590
|
+
tabCount.style.display = servers.length > 0 ? '' : 'none';
|
|
23591
|
+
}
|
|
23592
|
+
// Bucket servers into the four PRD categories. The existing
|
|
23593
|
+
// ManagedMcpServer type doesn't have an explicit "kind" field, so we
|
|
23594
|
+
// infer: stdio with a known shell binary → 'shell', stdio bundled with
|
|
23595
|
+
// clementine → 'builtin', stdio external command → 'external_stdio',
|
|
23596
|
+
// http/sse → 'external_remote'. The bucket keys map to the PRD's four
|
|
23597
|
+
// taxonomy cards.
|
|
23598
|
+
var buckets = { builtin: [], custom: [], shell: [], external: [] };
|
|
23599
|
+
for (var i = 0; i < servers.length; i++) {
|
|
23600
|
+
var s = servers[i];
|
|
23601
|
+
var name = s.name || '';
|
|
23602
|
+
var type = s.type || 'stdio';
|
|
23603
|
+
var cmd = s.command || '';
|
|
23604
|
+
var kind;
|
|
23605
|
+
// The clementine-tools server is an in-process bundle
|
|
23606
|
+
if (name === 'clementine-tools' || name === 'kernel') kind = 'builtin';
|
|
23607
|
+
else if (type === 'http' || type === 'sse') kind = 'external';
|
|
23608
|
+
else if (/^(sf|gh|gcloud|kubectl|docker|aws|az|terraform)$/.test(cmd) || /\\b(sf|gh|gcloud|kubectl)$/.test(cmd)) kind = 'shell';
|
|
23609
|
+
else kind = 'external'; // default for stdio external MCP
|
|
23610
|
+
buckets[kind].push(s);
|
|
23611
|
+
}
|
|
23612
|
+
var html = '';
|
|
23613
|
+
// Header strip
|
|
23614
|
+
html += '<div style="margin-bottom:18px"><h2 style="margin:0 0 4px;font-size:18px;font-weight:600;color:var(--text-primary)">Tools & MCP catalog</h2>'
|
|
23615
|
+
+ '<div style="font-size:12px;color:var(--text-muted)">'+ esc(servers.length) +' MCP server' + (servers.length === 1 ? '' : 's') + ' configured. Click any task in the Tasks tab to bind specific tools to that task.</div></div>';
|
|
23616
|
+
// Four-card taxonomy. Each section is a labeled bucket of cards.
|
|
23617
|
+
var sections = [
|
|
23618
|
+
{ key: 'builtin', label: 'Built-in', desc: 'Claude SDK native tools — always available to every task at the agent profile\\x27s permission tier.' },
|
|
23619
|
+
{ key: 'custom', label: 'Custom in-process MCP', desc: 'MCP servers defined in clementine\\x27s code, loaded inside the daemon process.' },
|
|
23620
|
+
{ key: 'shell', label: 'Shell commands', desc: 'Local CLI binaries (sf, gh, gcloud…) wrapped as MCP servers.' },
|
|
23621
|
+
{ key: 'external', label: 'External MCP servers', desc: 'Third-party MCP servers reached over stdio, SSE, or HTTP.' },
|
|
23622
|
+
];
|
|
23623
|
+
for (var k = 0; k < sections.length; k++) {
|
|
23624
|
+
var sec = sections[k];
|
|
23625
|
+
var bucket = buckets[sec.key] || [];
|
|
23626
|
+
html += '<div style="margin-bottom:24px">';
|
|
23627
|
+
html += '<div style="display:flex;align-items:baseline;gap:10px;margin-bottom:10px">'
|
|
23628
|
+
+ '<h3 style="margin:0;font-size:14px;font-weight:600;color:var(--text-primary)">' + esc(sec.label) + '</h3>'
|
|
23629
|
+
+ '<span style="font-size:11px;color:var(--text-muted);font-weight:500">' + bucket.length + '</span>'
|
|
23630
|
+
+ '</div>';
|
|
23631
|
+
html += '<div style="font-size:11px;color:var(--text-muted);margin-bottom:12px">' + esc(sec.desc) + '</div>';
|
|
23632
|
+
if (bucket.length === 0) {
|
|
23633
|
+
html += '<div class="empty-state" style="padding:14px;color:var(--text-muted);font-size:12px;background:var(--bg-secondary);border:1px dashed var(--border);border-radius:6px">No servers in this bucket.</div>';
|
|
23634
|
+
} else {
|
|
23635
|
+
html += '<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px">';
|
|
23636
|
+
for (var b = 0; b < bucket.length; b++) html += renderMcpCatalogCard(bucket[b], statusMap);
|
|
23637
|
+
html += '</div>';
|
|
23638
|
+
}
|
|
23639
|
+
html += '</div>';
|
|
23640
|
+
}
|
|
23641
|
+
panel.innerHTML = html;
|
|
23642
|
+
}
|
|
23643
|
+
|
|
23644
|
+
// Render one MCP server card. Status pill colors mirror the PRD's five
|
|
23645
|
+
// states (connected / failed / needs-auth / pending / disabled). The
|
|
23646
|
+
// statusMap shape comes from gw.getMcpStatus() — varies a bit between
|
|
23647
|
+
// SDK versions; we defensively probe for connected/healthy fields.
|
|
23648
|
+
function renderMcpCatalogCard(server, statusMap) {
|
|
23649
|
+
var name = server.name || '(unnamed)';
|
|
23650
|
+
var transport = server.type || 'stdio';
|
|
23651
|
+
var enabled = server.enabled !== false;
|
|
23652
|
+
var status = statusMap && statusMap[name];
|
|
23653
|
+
var statusKind, statusLabel, statusColor;
|
|
23654
|
+
if (!enabled) { statusKind = 'disabled'; statusLabel = 'disabled'; statusColor = 'var(--text-muted)'; }
|
|
23655
|
+
else if (status && (status.connected === true || status.status === 'connected' || status.healthy === true)) { statusKind = 'connected'; statusLabel = 'connected'; statusColor = 'var(--green)'; }
|
|
23656
|
+
else if (status && (status.needsAuth === true || status.status === 'needs-auth')) { statusKind = 'needsauth'; statusLabel = 'needs auth'; statusColor = 'var(--yellow)'; }
|
|
23657
|
+
else if (status && (status.connected === false || status.status === 'failed' || status.error)) { statusKind = 'failed'; statusLabel = 'failed'; statusColor = 'var(--red)'; }
|
|
23658
|
+
else { statusKind = 'pending'; statusLabel = 'pending'; statusColor = 'var(--text-muted)'; }
|
|
23659
|
+
var toolCount = (status && (status.toolCount != null ? status.toolCount : (Array.isArray(status.tools) ? status.tools.length : null))) || (Array.isArray(server.exposedTools) ? server.exposedTools.length : null);
|
|
23660
|
+
var lastChecked = status && (status.lastCheckedAt || status.checkedAt || status.updatedAt);
|
|
23661
|
+
var src = server.source === 'auto-detected' ? 'auto-detected' : 'user-configured';
|
|
23662
|
+
var lastError = status && status.error;
|
|
23663
|
+
var html = ''
|
|
23664
|
+
+ '<div style="background:var(--bg-secondary);border:1px solid var(--border);border-radius:8px;padding:14px;display:flex;flex-direction:column;gap:8px">'
|
|
23665
|
+
+ '<div style="display:flex;align-items:center;gap:8px">'
|
|
23666
|
+
+ '<div style="font-size:13px;font-weight:600;color:var(--text-primary);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="' + esc(name) + '">' + esc(name) + '</div>'
|
|
23667
|
+
+ '<span style="display:inline-flex;align-items:center;gap:5px;font-size:10px;font-weight:500;color:' + statusColor + ';background:' + statusColor + '20;padding:2px 8px;border-radius:999px;text-transform:uppercase;letter-spacing:0.04em">'
|
|
23668
|
+
+ '<span style="display:inline-block;width:6px;height:6px;border-radius:50%;background:' + statusColor + '"></span>' + esc(statusLabel)
|
|
23669
|
+
+ '</span>'
|
|
23670
|
+
+ '</div>'
|
|
23671
|
+
+ '<div style="display:flex;align-items:center;gap:10px;font-size:11px;color:var(--text-muted)">'
|
|
23672
|
+
+ '<span style="text-transform:uppercase;letter-spacing:0.04em">' + esc(transport) + '</span>'
|
|
23673
|
+
+ '<span>·</span>'
|
|
23674
|
+
+ '<span>' + esc(src) + '</span>'
|
|
23675
|
+
+ (toolCount != null ? '<span>·</span><span>' + esc(toolCount) + ' tool' + (toolCount === 1 ? '' : 's') + '</span>' : '')
|
|
23676
|
+
+ '</div>'
|
|
23677
|
+
+ (server.description ? '<div style="font-size:12px;color:var(--text-secondary);line-height:1.45">' + esc(String(server.description).slice(0, 240)) + '</div>' : '')
|
|
23678
|
+
+ (lastError ? '<div style="font-size:11px;color:var(--red);background:rgba(239,68,68,0.06);padding:6px 8px;border-radius:4px;word-break:break-word">' + esc(String(lastError).slice(0, 200)) + '</div>' : '')
|
|
23679
|
+
+ (lastChecked ? '<div style="font-size:11px;color:var(--text-muted)">Checked ' + esc(timeAgo(lastChecked)) + '</div>' : '')
|
|
23680
|
+
+ '<div style="display:flex;gap:6px;margin-top:4px">'
|
|
23681
|
+
+ '<button class="btn-sm" onclick="toggleMcpServerEnabled(\\x27' + jsStr(name) + '\\x27,' + (enabled ? 'false' : 'true') + ')" title="' + (enabled ? 'Disable this MCP server for all tasks' : 'Enable this MCP server') + '">' + (enabled ? 'Disable' : 'Enable') + '</button>'
|
|
23682
|
+
+ '<button class="btn-sm" disabled title="Edit + Reconnect coming in the next slice" style="opacity:0.55;cursor:not-allowed">Edit</button>'
|
|
23683
|
+
+ '</div>'
|
|
23684
|
+
+ '</div>';
|
|
23685
|
+
return html;
|
|
23686
|
+
}
|
|
23687
|
+
|
|
23688
|
+
// PUT helper for the Toggle button. Lazy: re-fetches the catalog after
|
|
23689
|
+
// the round-trip so the new state is reflected. Future slice will swap
|
|
23690
|
+
// to optimistic update + rollback on error.
|
|
23691
|
+
async function toggleMcpServerEnabled(name, nextEnabled) {
|
|
23692
|
+
try {
|
|
23693
|
+
var r = await apiFetch('/api/mcp-servers/' + encodeURIComponent(name), {
|
|
23694
|
+
method: 'PUT',
|
|
23695
|
+
headers: { 'Content-Type': 'application/json' },
|
|
23696
|
+
body: JSON.stringify({ enabled: nextEnabled }),
|
|
23697
|
+
});
|
|
23698
|
+
var d = await r.json();
|
|
23699
|
+
if (!r.ok || d.error) {
|
|
23700
|
+
toast('Toggle failed: ' + (d.error || 'unknown'), 'error');
|
|
23701
|
+
return;
|
|
23702
|
+
}
|
|
23703
|
+
toast(name + ' is now ' + (nextEnabled ? 'enabled' : 'disabled'), 'success');
|
|
23704
|
+
refreshToolsMcpCatalog();
|
|
23705
|
+
} catch (e) {
|
|
23706
|
+
toast('Toggle failed: ' + String(e), 'error');
|
|
23707
|
+
}
|
|
23708
|
+
}
|
|
23709
|
+
|
|
23535
23710
|
async function refreshCron() {
|
|
23536
23711
|
try {
|
|
23537
23712
|
// Fetch operations + cross-job recent runs in parallel for the three-zone
|