clementine-agent 1.18.127 → 1.18.128
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 +109 -21
- package/package.json +1 -1
package/dist/cli/dashboard.js
CHANGED
|
@@ -21254,6 +21254,21 @@ if('serviceWorker' in navigator){navigator.serviceWorker.getRegistrations().then
|
|
|
21254
21254
|
</div>
|
|
21255
21255
|
</div>
|
|
21256
21256
|
|
|
21257
|
+
<!-- 1.18.128 — Project Context promoted to Basics. Was buried in
|
|
21258
|
+
the Scope tab where users were missing it. Selecting a project
|
|
21259
|
+
gives the task that project's CLAUDE.md, MCP config, and cwd —
|
|
21260
|
+
usually the single most impactful field after Prompt. -->
|
|
21261
|
+
<div class="cron-section-card" data-config-tab="basics">
|
|
21262
|
+
<h4>Project Context <span style="color:var(--text-muted);font-weight:normal;font-size:13px">(optional)</span></h4>
|
|
21263
|
+
<p class="cron-section-desc">Run this task inside a project directory. The agent picks up that project's <code>CLAUDE.md</code>, MCP config, and any context files alongside the cwd.</p>
|
|
21264
|
+
<div class="form-group">
|
|
21265
|
+
<select id="cron-workdir">
|
|
21266
|
+
<option value="">None — runs in default context</option>
|
|
21267
|
+
</select>
|
|
21268
|
+
<div class="form-hint">No projects yet? <a href="#" onclick="navigateTo(\\x27settings\\x27, { tab: \\x27projects\\x27 }); closeCronModal(); return false" style="color:var(--accent)">Add one →</a></div>
|
|
21269
|
+
</div>
|
|
21270
|
+
</div>
|
|
21271
|
+
|
|
21257
21272
|
<!-- Schedule -->
|
|
21258
21273
|
<div class="cron-section-card" data-config-tab="basics">
|
|
21259
21274
|
<h4>Schedule</h4>
|
|
@@ -21449,25 +21464,18 @@ if('serviceWorker' in navigator){navigator.serviceWorker.getRegistrations().then
|
|
|
21449
21464
|
</div>
|
|
21450
21465
|
</div>
|
|
21451
21466
|
|
|
21452
|
-
<!-- ── Scope:
|
|
21467
|
+
<!-- ── Scope: extra read directories beyond the project cwd ── -->
|
|
21468
|
+
<!-- 1.18.128 — Project Context picker moved up to Basics. This
|
|
21469
|
+
section now only owns Additional read directories, which is
|
|
21470
|
+
a power-user feature anyway. -->
|
|
21453
21471
|
<div class="cron-section-card" data-config-tab="scope">
|
|
21454
21472
|
<h4>Scope</h4>
|
|
21455
|
-
<p class="cron-section-desc">
|
|
21456
|
-
<div class="form-row">
|
|
21457
|
-
<div class="form-group">
|
|
21458
|
-
<label class="form-label">Project Context <span style="color:var(--text-muted);font-weight:normal">(optional)</span></label>
|
|
21459
|
-
<select id="cron-workdir">
|
|
21460
|
-
<option value="">None — runs in default context</option>
|
|
21461
|
-
</select>
|
|
21462
|
-
<div class="form-hint">Run inside a project directory. Agent gets that project's CLAUDE.md.</div>
|
|
21463
|
-
</div>
|
|
21464
|
-
</div>
|
|
21465
|
-
<!-- PRD Phase 1: read scope beyond cwd. One absolute path per line. -->
|
|
21473
|
+
<p class="cron-section-desc">Extra directories the agent gets read access to beyond the project cwd. Most tasks won't need this.</p>
|
|
21466
21474
|
<div class="form-row">
|
|
21467
21475
|
<div class="form-group" style="flex:1">
|
|
21468
21476
|
<label class="form-label">Additional read directories <span style="color:var(--text-muted);font-weight:normal">(optional)</span></label>
|
|
21469
21477
|
<textarea id="cron-add-dirs" rows="2" placeholder="/Users/me/notes /Users/me/clients/acme" style="font-family:'JetBrains Mono',monospace;font-size:11px"></textarea>
|
|
21470
|
-
<div class="form-hint">One absolute path per line. The
|
|
21478
|
+
<div class="form-hint">One absolute path per line. The Project Context above already gives the agent its cwd; use this for extra read scope only.</div>
|
|
21471
21479
|
</div>
|
|
21472
21480
|
</div>
|
|
21473
21481
|
</div>
|
|
@@ -27096,9 +27104,14 @@ async function refreshProjects(preloaded) {
|
|
|
27096
27104
|
? '<div style="color:var(--accent);margin-bottom:4px;font-size:12px">' + esc(p.userDescription) + '</div>'
|
|
27097
27105
|
: '';
|
|
27098
27106
|
const idx = projectsData.indexOf(p);
|
|
27107
|
+
// 1.18.128 — "+ New task in this project" CTA: opens the cron creation
|
|
27108
|
+
// modal with the project pre-selected as Project Context. Closes the
|
|
27109
|
+
// mental gap between "I have a project with built-up context" and
|
|
27110
|
+
// "I need to schedule a task that uses it."
|
|
27111
|
+
const newTaskBtn = '<button class="btn btn-sm" style="font-size:11px" onclick="openCronModalForProject(' + idx + ')" title="Create a scheduled task that runs inside this project">+ New task</button>';
|
|
27099
27112
|
const linkBtn = p.linked
|
|
27100
|
-
? '<button class="btn btn-sm" style="font-size:11px" onclick="openProjectEditorByIdx(' + idx + ')">Edit</button> <button class="btn btn-sm btn-danger" style="font-size:11px" onclick="unlinkProjectByIdx(' + idx + ')">Unlink</button>'
|
|
27101
|
-
: '<button class="btn btn-sm btn-primary" style="font-size:11px" onclick="openProjectEditorByIdx(' + idx + ')">Link</button>';
|
|
27113
|
+
? newTaskBtn + ' <button class="btn btn-sm" style="font-size:11px" onclick="openProjectEditorByIdx(' + idx + ')">Edit</button> <button class="btn btn-sm btn-danger" style="font-size:11px" onclick="unlinkProjectByIdx(' + idx + ')">Unlink</button>'
|
|
27114
|
+
: newTaskBtn + ' <button class="btn btn-sm btn-primary" style="font-size:11px" onclick="openProjectEditorByIdx(' + idx + ')">Link</button>';
|
|
27102
27115
|
html += '<div class="card" style="cursor:default">'
|
|
27103
27116
|
+ '<div class="card-header" style="display:flex;align-items:center;justify-content:space-between">'
|
|
27104
27117
|
+ '<strong>' + esc(p.name) + '</strong>'
|
|
@@ -28592,13 +28605,50 @@ async function loadSkillsCatalog() {
|
|
|
28592
28605
|
|
|
28593
28606
|
async function loadMcpCatalog() {
|
|
28594
28607
|
if (_mcpCatalog) return _mcpCatalog;
|
|
28608
|
+
// 1.18.128 — merge Composio toolkits into the picker. discoverMcpServers()
|
|
28609
|
+
// only sees Claude Desktop / Claude Code / Extensions / user-managed
|
|
28610
|
+
// config, but the runtime ALSO injects every connected Composio toolkit
|
|
28611
|
+
// via buildExtraMcpForRunAgent. The picker was blind to all that — users
|
|
28612
|
+
// would scroll and not see Gmail, Slack, Salesforce, etc., even though
|
|
28613
|
+
// those servers fire correctly when the cron runs. This fixes the picker
|
|
28614
|
+
// to match runtime reality.
|
|
28615
|
+
var servers = [];
|
|
28595
28616
|
try {
|
|
28596
28617
|
var r = await apiFetch('/api/mcp-servers');
|
|
28597
28618
|
var d = await r.json();
|
|
28598
|
-
|
|
28599
|
-
|
|
28600
|
-
|
|
28601
|
-
}
|
|
28619
|
+
servers = (d.servers || []).map(function(s) {
|
|
28620
|
+
return Object.assign({}, s, { _origin: s.source || 'config' });
|
|
28621
|
+
});
|
|
28622
|
+
} catch (_) { servers = []; }
|
|
28623
|
+
try {
|
|
28624
|
+
var rc = await apiFetch('/api/composio/toolkits');
|
|
28625
|
+
var dc = await rc.json();
|
|
28626
|
+
if (dc && dc.enabled !== false && Array.isArray(dc.toolkits)) {
|
|
28627
|
+
// Only show toolkits with at least one ACTIVE connection — those are
|
|
28628
|
+
// the ones the runtime can actually call. Auth-config-only toolkits
|
|
28629
|
+
// would fail tool calls, so showing them here would mislead.
|
|
28630
|
+
var connected = dc.toolkits.filter(function(t) {
|
|
28631
|
+
return Array.isArray(t.connections) && t.connections.some(function(c) { return c && c.status === 'ACTIVE'; });
|
|
28632
|
+
});
|
|
28633
|
+
var existingNames = new Set(servers.map(function(s) { return s.name; }));
|
|
28634
|
+
for (var i = 0; i < connected.length; i++) {
|
|
28635
|
+
var t = connected[i];
|
|
28636
|
+
if (existingNames.has(t.slug)) continue; // dedup — local config wins
|
|
28637
|
+
servers.push({
|
|
28638
|
+
name: t.slug,
|
|
28639
|
+
type: 'composio',
|
|
28640
|
+
description: t.description || (t.displayName + ' (via Composio)'),
|
|
28641
|
+
enabled: true,
|
|
28642
|
+
source: 'composio',
|
|
28643
|
+
_origin: 'composio',
|
|
28644
|
+
_displayName: t.displayName,
|
|
28645
|
+
_toolCount: t.toolCount,
|
|
28646
|
+
_connectionCount: (t.connections || []).filter(function(c) { return c && c.status === 'ACTIVE'; }).length,
|
|
28647
|
+
});
|
|
28648
|
+
}
|
|
28649
|
+
}
|
|
28650
|
+
} catch (_) { /* Composio not enabled / API down — picker still works */ }
|
|
28651
|
+
_mcpCatalog = { servers: servers };
|
|
28602
28652
|
return _mcpCatalog;
|
|
28603
28653
|
}
|
|
28604
28654
|
|
|
@@ -28739,13 +28789,26 @@ function renderMcpPickerList() {
|
|
|
28739
28789
|
listEl.innerHTML = servers.slice(0, 50).map(function(s) {
|
|
28740
28790
|
var sel = _cronSelectedMcp.indexOf(s.name) !== -1;
|
|
28741
28791
|
var enabledTag = s.enabled === false ? ' <span style="color:var(--text-muted);font-size:10px">(disabled)</span>' : '';
|
|
28792
|
+
// 1.18.128 — distinct badge for Composio-sourced toolkits so users can
|
|
28793
|
+
// see at a glance which servers come from local config vs the
|
|
28794
|
+
// Composio account, plus a connection count for managed accounts.
|
|
28795
|
+
var sourceBadge = '';
|
|
28796
|
+
if (s._origin === 'composio') {
|
|
28797
|
+
var connTxt = s._connectionCount ? s._connectionCount + ' conn' : 'connected';
|
|
28798
|
+
sourceBadge = ' <span style="background:rgba(124,58,237,0.12);color:var(--purple);font-size:9px;padding:1px 6px;border-radius:4px;font-weight:600;text-transform:uppercase;letter-spacing:0.04em" title="Sourced from Composio account">composio</span>'
|
|
28799
|
+
+ ' <span style="color:var(--text-muted);font-size:10px">' + esc(connTxt) + '</span>';
|
|
28800
|
+
} else if (s.source && s.source !== 'auto-detected') {
|
|
28801
|
+
sourceBadge = ' <span style="background:var(--bg-tertiary);color:var(--text-muted);font-size:9px;padding:1px 6px;border-radius:4px;font-weight:600;text-transform:uppercase;letter-spacing:0.04em">' + esc(s.source) + '</span>';
|
|
28802
|
+
}
|
|
28803
|
+
var displayName = s._displayName || s.name;
|
|
28742
28804
|
return '<div class="cap-picker-row mcp' + (sel ? ' selected' : '') + '" onclick="addMcpToTrick(\\x27' + jsStr(s.name) + '\\x27)">'
|
|
28743
28805
|
+ '<div class="cap-picker-row-body">'
|
|
28744
|
-
+ '<div class="cap-picker-row-title">' + esc(
|
|
28806
|
+
+ '<div class="cap-picker-row-title">' + esc(displayName)
|
|
28807
|
+
+ (displayName !== s.name ? ' <span style="color:var(--text-muted);font-weight:normal;font-size:10px">' + esc(s.name) + '</span>' : '')
|
|
28808
|
+
+ enabledTag + sourceBadge
|
|
28745
28809
|
+ (sel ? ' <span style="color:var(--purple);font-size:11px">✓ allowed</span>' : '')
|
|
28746
28810
|
+ '</div>'
|
|
28747
28811
|
+ (s.description ? '<div class="cap-picker-row-desc">' + esc(s.description) + '</div>' : '')
|
|
28748
|
-
+ (s.source ? '<div class="cap-picker-row-meta">source: ' + esc(s.source) + '</div>' : '')
|
|
28749
28812
|
+ '</div></div>';
|
|
28750
28813
|
}).join('');
|
|
28751
28814
|
}
|
|
@@ -29406,6 +29469,31 @@ async function enablePredictableFromBanner() {
|
|
|
29406
29469
|
}
|
|
29407
29470
|
}
|
|
29408
29471
|
|
|
29472
|
+
// 1.18.128 — open the cron modal pre-wired to a project. Called from the
|
|
29473
|
+
// "+ New task" button on each project card. Pre-fills cron-workdir and
|
|
29474
|
+
// suggests a name based on the project so the user only has to fill in
|
|
29475
|
+
// the prompt + schedule. The dropdown is populated by refreshProjects()
|
|
29476
|
+
// at page load, so the pre-filled value resolves cleanly to one of the
|
|
29477
|
+
// existing options.
|
|
29478
|
+
function openCronModalForProject(projectIdx) {
|
|
29479
|
+
var p = (typeof projectsData !== 'undefined' && Array.isArray(projectsData)) ? projectsData[projectIdx] : null;
|
|
29480
|
+
if (!p) { toast('Project not found.', 'error'); return; }
|
|
29481
|
+
openCreateCronModal();
|
|
29482
|
+
// Pre-set the project context. dropdown options were populated by
|
|
29483
|
+
// refreshProjects on page load, so the value matches one of them.
|
|
29484
|
+
var sel = document.getElementById('cron-workdir');
|
|
29485
|
+
if (sel) sel.value = p.path;
|
|
29486
|
+
// Suggest a task name based on the project — replaces non-slug chars
|
|
29487
|
+
// and truncates so the slug rule passes. User can override.
|
|
29488
|
+
var slugBase = (p.name || 'project').toLowerCase()
|
|
29489
|
+
.replace(/[^a-z0-9-]+/g, '-')
|
|
29490
|
+
.replace(/^-+|-+$/g, '')
|
|
29491
|
+
.slice(0, 40);
|
|
29492
|
+
var nameInput = document.getElementById('cron-name');
|
|
29493
|
+
if (nameInput && !nameInput.value) nameInput.value = slugBase + '-task';
|
|
29494
|
+
toast('Project Context set to "' + (p.name || p.path) + '" — fill in the prompt and schedule.', 'info');
|
|
29495
|
+
}
|
|
29496
|
+
|
|
29409
29497
|
function openCreateCronModal(agentSlug) {
|
|
29410
29498
|
_cronAgentContext = agentSlug || '';
|
|
29411
29499
|
editingCronJob = null;
|