clementine-agent 1.4.1 → 1.4.2
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 +113 -64
- package/package.json +1 -1
package/dist/cli/dashboard.js
CHANGED
|
@@ -8718,13 +8718,15 @@ if('serviceWorker' in navigator){navigator.serviceWorker.getRegistrations().then
|
|
|
8718
8718
|
.home-rail {
|
|
8719
8719
|
display: flex;
|
|
8720
8720
|
flex-direction: column;
|
|
8721
|
-
gap:
|
|
8721
|
+
gap: 8px;
|
|
8722
8722
|
overflow-y: auto;
|
|
8723
8723
|
position: relative;
|
|
8724
8724
|
}
|
|
8725
8725
|
.home-rail.collapsed {
|
|
8726
8726
|
display: none;
|
|
8727
8727
|
}
|
|
8728
|
+
/* Auto-hide cards that have no actionable content (set via JS toggling .rail-card.empty) */
|
|
8729
|
+
.rail-card.empty { display: none; }
|
|
8728
8730
|
.rail-collapse-btn {
|
|
8729
8731
|
position: absolute;
|
|
8730
8732
|
top: -4px;
|
|
@@ -8745,23 +8747,24 @@ if('serviceWorker' in navigator){navigator.serviceWorker.getRegistrations().then
|
|
|
8745
8747
|
.rail-card {
|
|
8746
8748
|
background: var(--bg-card);
|
|
8747
8749
|
border: 1px solid var(--border);
|
|
8748
|
-
border-radius:
|
|
8750
|
+
border-radius: var(--radius-md);
|
|
8749
8751
|
overflow: hidden;
|
|
8750
|
-
box-shadow:
|
|
8752
|
+
box-shadow: var(--shadow-xs);
|
|
8751
8753
|
}
|
|
8752
8754
|
.rail-header {
|
|
8753
8755
|
display: flex;
|
|
8754
8756
|
align-items: center;
|
|
8755
8757
|
justify-content: space-between;
|
|
8756
|
-
padding:
|
|
8757
|
-
font-size:
|
|
8758
|
+
padding: 8px 12px;
|
|
8759
|
+
font-size: var(--text-xs);
|
|
8758
8760
|
font-weight: 600;
|
|
8759
|
-
|
|
8760
|
-
|
|
8761
|
-
|
|
8761
|
+
text-transform: uppercase;
|
|
8762
|
+
letter-spacing: 0.04em;
|
|
8763
|
+
color: var(--text-muted);
|
|
8764
|
+
background: transparent;
|
|
8762
8765
|
}
|
|
8763
|
-
.rail-body { padding: 12px
|
|
8764
|
-
.rail-body .empty-state, .rail-body .skel-row { font-size:
|
|
8766
|
+
.rail-body { padding: 8px 12px 10px; font-size: var(--text-sm); line-height: 1.45; }
|
|
8767
|
+
.rail-body .empty-state, .rail-body .skel-row { font-size: var(--text-xs); }
|
|
8765
8768
|
.rail-badge {
|
|
8766
8769
|
display: inline-flex;
|
|
8767
8770
|
align-items: center;
|
|
@@ -10540,35 +10543,39 @@ if('serviceWorker' in navigator){navigator.serviceWorker.getRegistrations().then
|
|
|
10540
10543
|
margin-top: 4px;
|
|
10541
10544
|
}
|
|
10542
10545
|
|
|
10543
|
-
/* ── Timeline
|
|
10546
|
+
/* ── Timeline (compact) ───────────────────── */
|
|
10544
10547
|
.timeline {
|
|
10545
10548
|
position: relative;
|
|
10546
|
-
padding-left:
|
|
10549
|
+
padding-left: 18px;
|
|
10547
10550
|
}
|
|
10548
10551
|
.timeline::before {
|
|
10549
10552
|
content: '';
|
|
10550
10553
|
position: absolute;
|
|
10551
|
-
left:
|
|
10554
|
+
left: 5px;
|
|
10552
10555
|
top: 4px;
|
|
10553
10556
|
bottom: 4px;
|
|
10554
|
-
width:
|
|
10557
|
+
width: 1px;
|
|
10555
10558
|
background: var(--border);
|
|
10556
10559
|
}
|
|
10557
10560
|
.timeline-item {
|
|
10558
10561
|
position: relative;
|
|
10559
|
-
padding:
|
|
10560
|
-
font-size:
|
|
10562
|
+
padding: 4px 0;
|
|
10563
|
+
font-size: var(--text-sm);
|
|
10561
10564
|
display: flex;
|
|
10562
|
-
align-items:
|
|
10563
|
-
gap:
|
|
10565
|
+
align-items: center;
|
|
10566
|
+
gap: 8px;
|
|
10567
|
+
border-radius: var(--radius-xs);
|
|
10568
|
+
transition: background var(--motion);
|
|
10564
10569
|
}
|
|
10570
|
+
.timeline-item:hover { background: var(--bg-hover); }
|
|
10565
10571
|
.timeline-item::before {
|
|
10566
10572
|
content: '';
|
|
10567
10573
|
position: absolute;
|
|
10568
|
-
left: -
|
|
10569
|
-
top:
|
|
10570
|
-
|
|
10571
|
-
|
|
10574
|
+
left: -16px;
|
|
10575
|
+
top: 50%;
|
|
10576
|
+
transform: translateY(-50%);
|
|
10577
|
+
width: 7px;
|
|
10578
|
+
height: 7px;
|
|
10572
10579
|
border-radius: 50%;
|
|
10573
10580
|
background: var(--text-muted);
|
|
10574
10581
|
border: 2px solid var(--bg-primary);
|
|
@@ -10576,8 +10583,32 @@ if('serviceWorker' in navigator){navigator.serviceWorker.getRegistrations().then
|
|
|
10576
10583
|
}
|
|
10577
10584
|
.timeline-item.ok::before { background: var(--green); }
|
|
10578
10585
|
.timeline-item.error::before { background: var(--red); }
|
|
10579
|
-
.timeline-msg {
|
|
10580
|
-
|
|
10586
|
+
.timeline-msg {
|
|
10587
|
+
flex: 1;
|
|
10588
|
+
color: var(--text-primary);
|
|
10589
|
+
line-height: 1.35;
|
|
10590
|
+
white-space: nowrap;
|
|
10591
|
+
overflow: hidden;
|
|
10592
|
+
text-overflow: ellipsis;
|
|
10593
|
+
min-width: 0;
|
|
10594
|
+
}
|
|
10595
|
+
.timeline-title { font-weight: 500; }
|
|
10596
|
+
.timeline-agent {
|
|
10597
|
+
color: var(--clementine);
|
|
10598
|
+
font-size: var(--text-xs);
|
|
10599
|
+
margin-left: 6px;
|
|
10600
|
+
font-weight: 500;
|
|
10601
|
+
}
|
|
10602
|
+
.timeline-body {
|
|
10603
|
+
color: var(--text-muted);
|
|
10604
|
+
font-size: var(--text-xs);
|
|
10605
|
+
margin-left: 4px;
|
|
10606
|
+
}
|
|
10607
|
+
.timeline-time { flex-shrink: 0; color: var(--text-muted); font-size: var(--text-xs); }
|
|
10608
|
+
/* Cap activity card height so chat dominates the page */
|
|
10609
|
+
.home-activity .card-body { max-height: 320px; overflow-y: auto; padding: 10px 16px; }
|
|
10610
|
+
/* Hide chat profile selector when default — the row gets cleaner */
|
|
10611
|
+
.home-chat-input-row .chat-profile-spacer { display: none; }
|
|
10581
10612
|
|
|
10582
10613
|
/* ── Task Cards ─────────────────────────── */
|
|
10583
10614
|
.task-grid {
|
|
@@ -17260,15 +17291,15 @@ var sourceIcons = {
|
|
|
17260
17291
|
};
|
|
17261
17292
|
|
|
17262
17293
|
function activityEventHtml(e) {
|
|
17263
|
-
var icon = sourceIcons[e.source] || '●';
|
|
17264
17294
|
var statusCls = e.status === 'ok' || e.status === 'approved' ? 'ok'
|
|
17265
17295
|
: (e.status === 'error' || e.eventType === 'cron_error') ? 'error'
|
|
17266
|
-
: e.status === 'pending' ? '' : '';
|
|
17267
|
-
var agentLabel = e.agentSlug ? '<span
|
|
17268
|
-
return '<div class="timeline-item ' + statusCls + '">'
|
|
17269
|
-
+ '<span
|
|
17270
|
-
|
|
17271
|
-
|
|
17296
|
+
: e.status === 'pending' ? 'pending' : '';
|
|
17297
|
+
var agentLabel = e.agentSlug ? '<span class="timeline-agent">[' + esc(e.agentSlug) + ']</span>' : '';
|
|
17298
|
+
return '<div class="timeline-item ' + statusCls + '" title="' + esc(e.body || e.title) + '">'
|
|
17299
|
+
+ '<span class="timeline-msg">'
|
|
17300
|
+
+ '<span class="timeline-title">' + esc(e.title) + '</span>'
|
|
17301
|
+
+ agentLabel
|
|
17302
|
+
+ (e.body ? ' <span class="timeline-body">· ' + esc(e.body) + '</span>' : '')
|
|
17272
17303
|
+ '</span>'
|
|
17273
17304
|
+ '<span class="timeline-time">' + timeAgo(e.timestamp) + '</span>'
|
|
17274
17305
|
+ '</div>';
|
|
@@ -18396,13 +18427,17 @@ async function loadProfiles() {
|
|
|
18396
18427
|
var d = await r.json();
|
|
18397
18428
|
var sel = document.getElementById('chat-profile-select');
|
|
18398
18429
|
sel.innerHTML = '<option value="">Default</option>';
|
|
18430
|
+
var customCount = 0;
|
|
18399
18431
|
for (var p of (d.profiles || [])) {
|
|
18400
18432
|
var opt = document.createElement('option');
|
|
18401
18433
|
opt.value = p.slug;
|
|
18402
18434
|
opt.textContent = p.name + (p.description ? ' — ' + p.description : '');
|
|
18403
18435
|
if (p.slug === d.active) opt.selected = true;
|
|
18404
18436
|
sel.appendChild(opt);
|
|
18437
|
+
customCount++;
|
|
18405
18438
|
}
|
|
18439
|
+
// Hide the picker entirely if there are no custom profiles — declutters the chat input row.
|
|
18440
|
+
sel.style.display = customCount === 0 ? 'none' : '';
|
|
18406
18441
|
} catch(e) { /* profiles are optional */ }
|
|
18407
18442
|
}
|
|
18408
18443
|
|
|
@@ -20561,44 +20596,53 @@ function toggleHomeRail() {
|
|
|
20561
20596
|
}
|
|
20562
20597
|
}
|
|
20563
20598
|
|
|
20599
|
+
function _railCard(bodyId) {
|
|
20600
|
+
var body = document.getElementById(bodyId);
|
|
20601
|
+
return body ? body.closest('.rail-card') : null;
|
|
20602
|
+
}
|
|
20603
|
+
function _setRailEmpty(bodyId, isEmpty) {
|
|
20604
|
+
var card = _railCard(bodyId);
|
|
20605
|
+
if (card) card.classList.toggle('empty', !!isEmpty);
|
|
20606
|
+
}
|
|
20607
|
+
|
|
20564
20608
|
async function refreshHomeRail() {
|
|
20565
|
-
// Daemon status
|
|
20609
|
+
// Daemon status — only surface when explicitly stopped. Treat null/undefined
|
|
20610
|
+
// (running-state unknown) as "fine, hide" since the dashboard wouldn't be
|
|
20611
|
+
// serving requests if the daemon were truly down.
|
|
20566
20612
|
try {
|
|
20567
20613
|
var rs = await apiFetch('/api/status');
|
|
20568
20614
|
var ds = await rs.json();
|
|
20615
|
+
var stopped = ds.running === false;
|
|
20569
20616
|
var pip = document.querySelector('#rail-daemon-body .agent-activity-dot');
|
|
20570
20617
|
var label = document.querySelector('#rail-daemon-body .agent-activity span:last-child');
|
|
20571
|
-
if (label) label.textContent =
|
|
20572
|
-
if (pip) pip.style.background =
|
|
20618
|
+
if (label) label.textContent = stopped ? 'Daemon stopped' : 'Running';
|
|
20619
|
+
if (pip) pip.style.background = stopped ? '#ef4444' : '#22c55e';
|
|
20573
20620
|
var up = document.getElementById('rail-daemon-uptime');
|
|
20574
20621
|
if (up && ds.uptimeMs) up.textContent = Math.round(ds.uptimeMs / 60000) + 'm';
|
|
20575
|
-
|
|
20622
|
+
_setRailEmpty('rail-daemon-body', !stopped);
|
|
20623
|
+
} catch { _setRailEmpty('rail-daemon-body', true); }
|
|
20576
20624
|
|
|
20577
|
-
// Today's plan (compact)
|
|
20625
|
+
// Today's plan (compact). Hide card if no plan or zero items.
|
|
20578
20626
|
try {
|
|
20579
20627
|
var rp = await apiFetch('/api/daily-plan');
|
|
20580
20628
|
var dp = await rp.json();
|
|
20581
20629
|
var planEl = document.getElementById('home-plan-content');
|
|
20630
|
+
var items = dp && dp.plan ? (dp.plan.items || []) : [];
|
|
20582
20631
|
if (planEl) {
|
|
20583
|
-
if (
|
|
20584
|
-
planEl.innerHTML = '<div style="font-size:
|
|
20632
|
+
if (items.length === 0) {
|
|
20633
|
+
planEl.innerHTML = '<div style="font-size:11px;color:var(--text-muted)">No plan yet today.</div>';
|
|
20585
20634
|
} else {
|
|
20586
|
-
|
|
20587
|
-
|
|
20588
|
-
|
|
20589
|
-
} else {
|
|
20590
|
-
planEl.innerHTML = items.map(function(it) {
|
|
20591
|
-
return '<div class="rail-row"><span class="label">' + esc(it.title || it.text || '') + '</span><span class="meta">' + esc(it.time || '') + '</span></div>';
|
|
20592
|
-
}).join('');
|
|
20593
|
-
}
|
|
20635
|
+
planEl.innerHTML = items.slice(0, 4).map(function(it) {
|
|
20636
|
+
return '<div class="rail-row"><span class="label">' + esc(it.title || it.text || '') + '</span><span class="meta">' + esc(it.time || '') + '</span></div>';
|
|
20637
|
+
}).join('');
|
|
20594
20638
|
}
|
|
20595
20639
|
}
|
|
20640
|
+
_setRailEmpty('home-plan-content', items.length === 0);
|
|
20596
20641
|
} catch {
|
|
20597
|
-
|
|
20598
|
-
if (pe) pe.innerHTML = '<div style="font-size:11px;color:var(--text-muted)">No plan available.</div>';
|
|
20642
|
+
_setRailEmpty('home-plan-content', true);
|
|
20599
20643
|
}
|
|
20600
20644
|
|
|
20601
|
-
// Upcoming cron fires (next 3)
|
|
20645
|
+
// Upcoming cron fires (next 3) — hide card if nothing scheduled
|
|
20602
20646
|
try {
|
|
20603
20647
|
var rc = await apiFetch('/api/cron');
|
|
20604
20648
|
var dc = await rc.json();
|
|
@@ -20609,13 +20653,14 @@ async function refreshHomeRail() {
|
|
|
20609
20653
|
var uc = document.getElementById('rail-upcoming-count');
|
|
20610
20654
|
if (uc) uc.textContent = String(jobs.length);
|
|
20611
20655
|
if (ue) {
|
|
20612
|
-
ue.innerHTML = top.
|
|
20656
|
+
ue.innerHTML = top.map(function(j) {
|
|
20613
20657
|
return '<div class="rail-row clickable-row" onclick="navigateTo(\\x27build\\x27,{tab:\\x27crons\\x27})"><span class="label">' + esc(j.name) + '</span><span class="meta">' + esc(timeUntil(j.nextRun)) + '</span></div>';
|
|
20614
|
-
}).join('')
|
|
20658
|
+
}).join('');
|
|
20615
20659
|
}
|
|
20616
|
-
|
|
20660
|
+
_setRailEmpty('rail-upcoming', top.length === 0);
|
|
20661
|
+
} catch { _setRailEmpty('rail-upcoming', true); }
|
|
20617
20662
|
|
|
20618
|
-
// Active unleashed runs
|
|
20663
|
+
// Active unleashed runs — hide card unless something running
|
|
20619
20664
|
try {
|
|
20620
20665
|
var ru = await apiFetch('/api/unleashed');
|
|
20621
20666
|
var du = await ru.json();
|
|
@@ -20627,25 +20672,27 @@ async function refreshHomeRail() {
|
|
|
20627
20672
|
else ac.style.display = 'none';
|
|
20628
20673
|
}
|
|
20629
20674
|
if (ae) {
|
|
20630
|
-
ae.innerHTML = active.
|
|
20675
|
+
ae.innerHTML = active.map(function(t) {
|
|
20631
20676
|
return '<div class="rail-row clickable-row" onclick="navigateTo(\\x27build\\x27,{tab:\\x27workflows\\x27})"><span class="label">' + esc(t.name) + '</span><span class="meta">' + esc(t.phase || '') + '</span></div>';
|
|
20632
|
-
}).join('')
|
|
20677
|
+
}).join('');
|
|
20633
20678
|
}
|
|
20634
|
-
|
|
20679
|
+
_setRailEmpty('rail-active', active.length === 0);
|
|
20680
|
+
} catch { _setRailEmpty('rail-active', true); }
|
|
20635
20681
|
|
|
20636
|
-
// Time saved (
|
|
20682
|
+
// Time saved (compact). Hide if zero.
|
|
20637
20683
|
try {
|
|
20638
20684
|
var rm = await apiFetch('/api/metrics?period=week');
|
|
20639
20685
|
var dm = await rm.json();
|
|
20640
20686
|
var minutes = ((dm.cronRuns || 0) * 5) + ((dm.exchanges || 0) * 2);
|
|
20641
20687
|
var ts = document.getElementById('rail-time-saved');
|
|
20642
20688
|
if (ts) {
|
|
20643
|
-
if (minutes >= 60) ts.innerHTML = '<div style="font-size:
|
|
20644
|
-
else ts.innerHTML = '<div style="font-size:
|
|
20689
|
+
if (minutes >= 60) ts.innerHTML = '<div style="font-size:var(--text-md);font-weight:600">' + (minutes / 60).toFixed(1) + 'h</div><div style="font-size:11px;color:var(--text-muted)">' + (dm.cronRuns || 0) + ' runs · ' + (dm.exchanges || 0) + ' chats</div>';
|
|
20690
|
+
else ts.innerHTML = '<div style="font-size:var(--text-md);font-weight:600">' + minutes + 'm</div><div style="font-size:11px;color:var(--text-muted)">' + (dm.cronRuns || 0) + ' runs</div>';
|
|
20645
20691
|
}
|
|
20646
|
-
|
|
20692
|
+
_setRailEmpty('rail-time-saved', minutes === 0);
|
|
20693
|
+
} catch { _setRailEmpty('rail-time-saved', true); }
|
|
20647
20694
|
|
|
20648
|
-
// Approvals
|
|
20695
|
+
// Approvals — hide card unless something pending
|
|
20649
20696
|
try {
|
|
20650
20697
|
var rsi = await apiFetch('/api/self-improve');
|
|
20651
20698
|
var dsi = await rsi.json();
|
|
@@ -20657,12 +20704,12 @@ async function refreshHomeRail() {
|
|
|
20657
20704
|
else ac2.style.display = 'none';
|
|
20658
20705
|
}
|
|
20659
20706
|
if (ae2) {
|
|
20660
|
-
|
|
20661
|
-
else ae2.innerHTML = pending.slice(0, 3).map(function(p) {
|
|
20707
|
+
ae2.innerHTML = pending.slice(0, 3).map(function(p) {
|
|
20662
20708
|
return '<div class="rail-row clickable-row" onclick="navigateTo(\\x27brain\\x27,{tab:\\x27learning\\x27})"><span class="label">' + esc(p.area || 'proposal') + ': ' + esc((p.target || '').slice(0, 40)) + '</span><span class="meta">' + esc(((p.score || 0) * 100).toFixed(0)) + '%</span></div>';
|
|
20663
20709
|
}).join('');
|
|
20664
20710
|
}
|
|
20665
|
-
|
|
20711
|
+
_setRailEmpty('rail-approvals', pending.length === 0);
|
|
20712
|
+
} catch { _setRailEmpty('rail-approvals', true); }
|
|
20666
20713
|
}
|
|
20667
20714
|
|
|
20668
20715
|
function timeUntil(iso) {
|
|
@@ -23992,6 +24039,8 @@ async function refreshSalesforce() {
|
|
|
23992
24039
|
if (d.status) { try { refreshStatus(d.status); } catch(e) { console.warn('init: status', e); } }
|
|
23993
24040
|
if (d.activity) { try { refreshActivity(false, d.activity); } catch(e) { console.warn('init: activity', e); } }
|
|
23994
24041
|
else { try { refreshActivity(); } catch(e) { console.warn('init: activity fallback', e); } }
|
|
24042
|
+
// Populate the home right rail (daemon, plan, runs, time-saved, approvals)
|
|
24043
|
+
if (typeof refreshHomeRail === 'function') { try { refreshHomeRail(); } catch(e) { console.warn('init: rail', e); } }
|
|
23995
24044
|
if (d.office) { try { refreshTeamNav(d.office); refreshTeamPulse(d.office); } catch(e) { console.warn('init: office', e); } }
|
|
23996
24045
|
if (d.plan) { try { refreshHomePlan(d.plan); } catch(e) { console.warn('init: plan', e); } }
|
|
23997
24046
|
if (d.version) { try { _loadedHash = d.version.started; } catch(e) { /* ignore */ } }
|