clementine-agent 1.18.95 → 1.18.97

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.
@@ -10190,12 +10190,6 @@ If the tool returns nothing or errors, return an empty array \`[]\`.`,
10190
10190
  sendPolicy: a.sendPolicy ?? null,
10191
10191
  agentStatus: a.status ?? 'active',
10192
10192
  budgetMonthlyCents: a.budgetMonthlyCents ?? 0,
10193
- // Mission & persona — what the agent edit modal renders in
10194
- // its single combined textarea.
10195
- systemPromptBody: a.systemPromptBody ?? '',
10196
- // Multi-project access list (separate from the legacy single
10197
- // `project` binding above).
10198
- projects: a.projects ?? [],
10199
10193
  };
10200
10194
  }));
10201
10195
  }
@@ -24514,6 +24508,62 @@ async function refreshMiniDashboards() {
24514
24508
  failHtml += '</div>';
24515
24509
  }
24516
24510
 
24511
+ // ── Activity card (PRD §12 / 1.18.96) ──────────────────────────────
24512
+ // Fourth mini-dashboard card. Lite version of the PRD Agent Behavior
24513
+ // metrics — full per-tool / per-turn data needs Path B hooks, but
24514
+ // there is plenty to surface from CronRunEntry alone:
24515
+ // - runs/day average across the 7d window
24516
+ // - busiest task (highest run count)
24517
+ // - trigger breakdown (manual / scheduled / after / api / webhook)
24518
+ // The trigger bar is the most actionable signal — heavy "manual" =
24519
+ // automatable work; heavy "after" = chained workflows dragging cost.
24520
+ var runsPerDay = last7.length > 0 ? (last7.length / 7).toFixed(1) : '0';
24521
+ var taskCounts = {};
24522
+ for (var ti = 0; ti < last7.length; ti++) {
24523
+ var jn = last7[ti].jobName;
24524
+ if (!jn) continue;
24525
+ taskCounts[jn] = (taskCounts[jn] || 0) + 1;
24526
+ }
24527
+ var busiestTask = '—';
24528
+ var busiestCount = 0;
24529
+ Object.keys(taskCounts).forEach(function(name) {
24530
+ if (taskCounts[name] > busiestCount) { busiestTask = name; busiestCount = taskCounts[name]; }
24531
+ });
24532
+ var triggerOrder = ['manual', 'scheduled', 'after', 'api', 'webhook', 'other'];
24533
+ var triggerCounts = { manual: 0, scheduled: 0, after: 0, api: 0, webhook: 0, other: 0 };
24534
+ for (var tg = 0; tg < last7.length; tg++) {
24535
+ var trg = last7[tg].trigger;
24536
+ if (trg && triggerCounts[trg] !== undefined) triggerCounts[trg] += 1;
24537
+ else triggerCounts.other += 1;
24538
+ }
24539
+ var triggerColors = {
24540
+ manual: '#3b82f6',
24541
+ scheduled: '#10b981',
24542
+ after: '#f59e0b',
24543
+ api: '#8b5cf6',
24544
+ webhook: '#ec4899',
24545
+ other: '#6b7280'
24546
+ };
24547
+ var triggerBarHtml;
24548
+ if (last7.length === 0) {
24549
+ triggerBarHtml = '<div class="mini-fails-empty">No runs in 7d</div>';
24550
+ } else {
24551
+ triggerBarHtml = '<div class="mini-split">';
24552
+ var legendHtml = '<div class="mini-split-legend">';
24553
+ for (var tk = 0; tk < triggerOrder.length; tk++) {
24554
+ var key = triggerOrder[tk];
24555
+ var n = triggerCounts[key];
24556
+ if (n === 0) continue;
24557
+ var pctW = Math.max(2, Math.round((n / last7.length) * 100));
24558
+ triggerBarHtml += '<div class="mini-split-seg" style="background:' + triggerColors[key] + ';width:' + pctW + '%" title="' + key + ': ' + n + ' run' + (n === 1 ? '' : 's') + '">' + (pctW >= 14 ? key : '') + '</div>';
24559
+ legendHtml += '<span><span class="mini-split-legend-dot" style="background:' + triggerColors[key] + '"></span>' + key + ' ' + n + '</span>';
24560
+ }
24561
+ triggerBarHtml += '</div>' + legendHtml + '</div>';
24562
+ }
24563
+ var activitySub = last7.length === 0
24564
+ ? 'no runs yet'
24565
+ : (busiestCount > 0 ? runsPerDay + ' runs/day · busiest: ' + busiestTask + ' (' + busiestCount + ')' : runsPerDay + ' runs/day');
24566
+
24517
24567
  // ── Compose ────────────────────────────────────────────────────────
24518
24568
  host.innerHTML =
24519
24569
  '<div class="mini-card">'
@@ -24530,6 +24580,11 @@ async function refreshMiniDashboards() {
24530
24580
  + '<div class="mini-card-head"><span class="mini-card-title">Reliability · 7d</span><span class="mini-card-figure">' + totalFails7 + ' fail' + (totalFails7 === 1 ? '' : 's') + '</span></div>'
24531
24581
  + failHtml
24532
24582
  + '<div class="mini-card-sub">click a column in the run list to filter by category</div>'
24583
+ + '</div>'
24584
+ + '<div class="mini-card">'
24585
+ + '<div class="mini-card-head"><span class="mini-card-title">Activity · 7d</span><span class="mini-card-figure">' + last7.length + ' run' + (last7.length === 1 ? '' : 's') + '</span></div>'
24586
+ + triggerBarHtml
24587
+ + '<div class="mini-card-sub">' + esc(activitySub) + '</div>'
24533
24588
  + '</div>';
24534
24589
  }
24535
24590
 
@@ -26798,10 +26853,14 @@ async function openPromptHistory() {
26798
26853
  html += '<span style="font-size:11px;color:var(--text-muted)">· by ' + esc(who) + '</span>';
26799
26854
  html += '<span style="flex:1"></span>';
26800
26855
  html += '<button class="btn-sm" onclick="document.getElementById(\\x27' + rowId + '\\x27).style.display=document.getElementById(\\x27' + rowId + '\\x27).style.display===\\x27none\\x27?\\x27block\\x27:\\x27none\\x27" style="font-size:11px;padding:3px 8px">Show full</button>';
26856
+ // PRD §13 Phase 5.0c / 1.18.97: line-level diff vs editor draft.
26857
+ html += '<button class="btn-sm" onclick="togglePromptDiff(\\x27' + rowId + '-diff\\x27,\\x27' + promptB64 + '\\x27)" style="font-size:11px;padding:3px 8px">Show diff</button>';
26801
26858
  html += '<button class="btn-sm btn-primary" onclick="restorePromptVersion(\\x27' + promptB64 + '\\x27)" style="font-size:11px;padding:3px 10px">Restore</button>';
26802
26859
  html += '</div>';
26803
26860
  html += '<div style="font-size:12px;color:var(--text-secondary);line-height:1.5;font-family:\\x27JetBrains Mono\\x27,monospace">' + esc(preview) + (prompt.length > 200 ? '…' : '') + '</div>';
26804
26861
  html += '<pre id="' + rowId + '" style="display:none;margin-top:10px;font-size:11px;font-family:\\x27JetBrains Mono\\x27,monospace;background:var(--bg-tertiary);border:1px solid var(--border);padding:10px;border-radius:6px;white-space:pre-wrap;word-break:break-word;max-height:280px;overflow-y:auto">' + esc(prompt) + '</pre>';
26862
+ // PRD §13 Phase 5.0c / 1.18.97: diff placeholder filled by togglePromptDiff.
26863
+ html += '<div id="' + rowId + '-diff" style="display:none;margin-top:10px;font-size:11px;font-family:\\x27JetBrains Mono\\x27,monospace;background:var(--bg-tertiary);border:1px solid var(--border);padding:10px;border-radius:6px;max-height:320px;overflow-y:auto"></div>';
26805
26864
  html += '</div>';
26806
26865
  }
26807
26866
  list.innerHTML = html;
@@ -26815,6 +26874,78 @@ function closePromptHistory() {
26815
26874
  if (modal) modal.classList.remove('show');
26816
26875
  }
26817
26876
 
26877
+ // PRD §13 Phase 5.0c / 1.18.97: line-level diff between this version and
26878
+ // the editor current prompt text. Uses LCS-based diff. Toggles on click.
26879
+ function togglePromptDiff(elemId, promptB64) {
26880
+ var el = document.getElementById(elemId);
26881
+ if (!el) return;
26882
+ if (el.style.display !== 'none') { el.style.display = 'none'; return; }
26883
+ var oldPrompt;
26884
+ try { oldPrompt = decodeURIComponent(escape(atob(promptB64))); }
26885
+ catch (e) { el.innerHTML = '<span style="color:var(--red)">Failed to decode old prompt: ' + esc(String(e)) + '</span>'; el.style.display = 'block'; return; }
26886
+ var ta = document.getElementById('cron-prompt');
26887
+ var newPrompt = ta ? ta.value : '';
26888
+ el.innerHTML = renderPromptDiff(oldPrompt, newPrompt);
26889
+ el.style.display = 'block';
26890
+ }
26891
+
26892
+ function renderPromptDiff(oldText, newText) {
26893
+ var oldLines = (oldText || '').split('\\n');
26894
+ var newLines = (newText || '').split('\\n');
26895
+ if (oldText === newText) {
26896
+ return '<div style="color:var(--text-muted);font-style:italic">Identical to the current prompt — no changes between this version and now.</div>';
26897
+ }
26898
+ var n = oldLines.length, m = newLines.length;
26899
+ if (n > 1000 || m > 1000) {
26900
+ return '<div style="color:var(--text-muted);font-style:italic">Diff too large to render inline (' + n + ' x ' + m + ' lines). Use Show full to view the old prompt and copy/paste into your favorite diff tool.</div>';
26901
+ }
26902
+ // Build LCS table.
26903
+ var dp = [];
26904
+ for (var i = 0; i <= n; i++) dp.push(new Array(m + 1).fill(0));
26905
+ for (var ii = 1; ii <= n; ii++) {
26906
+ for (var jj = 1; jj <= m; jj++) {
26907
+ if (oldLines[ii - 1] === newLines[jj - 1]) dp[ii][jj] = dp[ii - 1][jj - 1] + 1;
26908
+ else dp[ii][jj] = Math.max(dp[ii - 1][jj], dp[ii][jj - 1]);
26909
+ }
26910
+ }
26911
+ // Walk back to produce ops in reverse.
26912
+ var ops = [];
26913
+ var ri = n, rj = m;
26914
+ while (ri > 0 || rj > 0) {
26915
+ if (ri > 0 && rj > 0 && oldLines[ri - 1] === newLines[rj - 1]) {
26916
+ ops.push({ kind: 'equal', text: oldLines[ri - 1] });
26917
+ ri--; rj--;
26918
+ } else if (rj > 0 && (ri === 0 || dp[ri][rj - 1] >= dp[ri - 1][rj])) {
26919
+ ops.push({ kind: 'add', text: newLines[rj - 1] });
26920
+ rj--;
26921
+ } else {
26922
+ ops.push({ kind: 'remove', text: oldLines[ri - 1] });
26923
+ ri--;
26924
+ }
26925
+ }
26926
+ ops.reverse();
26927
+ var added = 0, removed = 0;
26928
+ for (var oi = 0; oi < ops.length; oi++) {
26929
+ if (ops[oi].kind === 'add') added++;
26930
+ else if (ops[oi].kind === 'remove') removed++;
26931
+ }
26932
+ var html = '<div style="font-size:11px;color:var(--text-muted);margin-bottom:8px">'
26933
+ + '<span style="color:var(--green)">+' + added + '</span> &middot; '
26934
+ + '<span style="color:var(--red)">-' + removed + '</span> &middot; '
26935
+ + 'comparing version above &harr; current editor draft</div>';
26936
+ html += '<div style="white-space:pre-wrap;word-break:break-word;line-height:1.5">';
26937
+ for (var k = 0; k < ops.length; k++) {
26938
+ var op = ops[k];
26939
+ var prefix, color, bg;
26940
+ if (op.kind === 'add') { prefix = '+ '; color = 'var(--green)'; bg = 'rgba(16,185,129,0.08)'; }
26941
+ else if (op.kind === 'remove') { prefix = '- '; color = 'var(--red)'; bg = 'rgba(239,68,68,0.08)'; }
26942
+ else { prefix = ' '; color = 'var(--text-muted)'; bg = 'transparent'; }
26943
+ html += '<div style="color:' + color + ';background:' + bg + ';padding:1px 4px">' + esc(prefix) + esc(op.text || ' ') + '</div>';
26944
+ }
26945
+ html += '</div>';
26946
+ return html;
26947
+ }
26948
+
26818
26949
  // Restore copies the old prompt back into the editor's textarea. Doesn't
26819
26950
  // auto-save — the user must click Save Changes to commit, which keeps the
26820
26951
  // dirty-guard semantics intact and gives them a chance to back out.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clementine-agent",
3
- "version": "1.18.95",
3
+ "version": "1.18.97",
4
4
  "description": "Clementine — Personal AI Assistant (TypeScript)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",