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.
Files changed (2) hide show
  1. package/dist/cli/dashboard.js +109 -21
  2. package/package.json +1 -1
@@ -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: where the task can read/write ── -->
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">Where the agent runs and what files it can read.</p>
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&#10;/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 agent gets read access to these in addition to the Project Context cwd.</div>
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
- _mcpCatalog = { servers: d.servers || [] };
28599
- } catch {
28600
- _mcpCatalog = { servers: [] };
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(s.name) + enabledTag
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clementine-agent",
3
- "version": "1.18.127",
3
+ "version": "1.18.128",
4
4
  "description": "Clementine — Personal AI Assistant (TypeScript)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",