@yemi33/minions 0.1.2110 → 0.1.2111

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 (38) hide show
  1. package/dashboard/js/command-center.js +36 -36
  2. package/dashboard/js/detail-panel.js +12 -12
  3. package/dashboard/js/fre.js +9 -9
  4. package/dashboard/js/live-stream.js +2 -2
  5. package/dashboard/js/modal-qa.js +17 -17
  6. package/dashboard/js/qa.js +3 -3
  7. package/dashboard/js/refresh.js +8 -8
  8. package/dashboard/js/render-agents.js +12 -12
  9. package/dashboard/js/render-dispatch.js +8 -8
  10. package/dashboard/js/render-inbox.js +5 -5
  11. package/dashboard/js/render-managed.js +16 -16
  12. package/dashboard/js/render-meetings.js +36 -36
  13. package/dashboard/js/render-other.js +23 -23
  14. package/dashboard/js/render-pinned.js +1 -1
  15. package/dashboard/js/render-pipelines.js +36 -36
  16. package/dashboard/js/render-plans.js +23 -23
  17. package/dashboard/js/render-prd.js +100 -100
  18. package/dashboard/js/render-prs.js +10 -10
  19. package/dashboard/js/render-schedules.js +23 -23
  20. package/dashboard/js/render-skills.js +7 -7
  21. package/dashboard/js/render-utils.js +22 -22
  22. package/dashboard/js/render-watches.js +37 -37
  23. package/dashboard/js/render-work-items.js +34 -34
  24. package/dashboard/js/utils.js +8 -8
  25. package/dashboard/layout.html +20 -20
  26. package/dashboard/pages/engine.html +4 -4
  27. package/dashboard/pages/home.html +4 -4
  28. package/dashboard/pages/inbox.html +3 -3
  29. package/dashboard/pages/meetings.html +2 -2
  30. package/dashboard/pages/pipelines.html +2 -2
  31. package/dashboard/pages/plans.html +3 -3
  32. package/dashboard/pages/prs.html +2 -2
  33. package/dashboard/pages/schedule.html +2 -2
  34. package/dashboard/pages/tools.html +1 -1
  35. package/dashboard/pages/watches.html +2 -2
  36. package/dashboard/pages/work.html +3 -3
  37. package/dashboard/styles.css +38 -38
  38. package/package.json +1 -1
@@ -32,7 +32,7 @@ function _runtimeTagHtml(runtime) {
32
32
  }
33
33
  // Unknown runtime — fall back to a small text pill so the user still sees something
34
34
  const fallback = runtime || 'unknown';
35
- return '<span class="agent-runtime-tag" title="Runtime: ' + escapeHtml(fallback) + '" style="font-size:9px;font-weight:600;letter-spacing:0.4px;text-transform:uppercase;padding:1px 5px;margin-left:6px;border:1px solid var(--muted);border-radius:3px;color:var(--muted);background:transparent">' + escapeHtml(fallback) + '</span>';
35
+ return '<span class="agent-runtime-tag" title="Runtime: ' + escapeHtml(fallback) + '" style="font-size:var(--text-xs);font-weight:600;letter-spacing:0.4px;text-transform:uppercase;padding:1px 5px;margin-left:6px;border:1px solid var(--muted);border-radius:3px;color:var(--muted);background:transparent">' + escapeHtml(fallback) + '</span>';
36
36
  }
37
37
 
38
38
  // W-mpmwxk4y00053271 — compact text chip showing the resolved model next to
@@ -41,7 +41,7 @@ function _runtimeTagHtml(runtime) {
41
41
  // "The model is really critical piece of information to me as a user."
42
42
  function _modelChipHtml(model) {
43
43
  if (!model || typeof model !== 'string') return '';
44
- return '<span class="agent-model-tag" title="Model: ' + escapeHtml(model) + '" style="font-size:9px;font-weight:600;letter-spacing:0.4px;padding:1px 5px;margin-left:4px;border:1px solid var(--muted);border-radius:3px;color:var(--muted);background:transparent">' + escapeHtml(model) + '</span>';
44
+ return '<span class="agent-model-tag" title="Model: ' + escapeHtml(model) + '" style="font-size:var(--text-xs);font-weight:600;letter-spacing:0.4px;padding:1px 5px;margin-left:4px;border:1px solid var(--muted);border-radius:3px;color:var(--muted);background:transparent">' + escapeHtml(model) + '</span>';
45
45
  }
46
46
 
47
47
  function renderAgents(agents) {
@@ -59,12 +59,12 @@ function renderAgents(agents) {
59
59
  <div class="agent-action" title="${escapeHtml(a.lastAction)}">${escapeHtml(a.lastAction)}</div>
60
60
  ${(function() {
61
61
  var s = a.started_at, c = a.completed_at;
62
- if (s && c) { var d = new Date(c) - new Date(s); if (d > 0) { var sec = Math.floor(d/1000)%60, min = Math.floor(d/60000)%60, hr = Math.floor(d/3600000); return '<div style="font-size:9px;color:var(--muted)">Last run: ' + (hr > 0 ? hr + 'h ' : '') + min + 'm ' + sec + 's</div>'; } }
63
- if (s && a.status === 'working') return '<div class="agent-runtime-tick" data-started="' + s + '" style="font-size:9px;color:var(--yellow)"></div>';
62
+ if (s && c) { var d = new Date(c) - new Date(s); if (d > 0) { var sec = Math.floor(d/1000)%60, min = Math.floor(d/60000)%60, hr = Math.floor(d/3600000); return '<div style="font-size:var(--text-xs);color:var(--muted)">Last run: ' + (hr > 0 ? hr + 'h ' : '') + min + 'm ' + sec + 's</div>'; } }
63
+ if (s && a.status === 'working') return '<div class="agent-runtime-tick" data-started="' + s + '" style="font-size:var(--text-xs);color:var(--yellow)"></div>';
64
64
  return '';
65
65
  })()}
66
- ${a._blockingToolCall ? `<div style="margin-top:4px;padding:4px 8px;background:rgba(130,160,210,0.13);border:1px solid rgba(130,160,210,0.3);border-radius:4px;font-size:10px;color:var(--muted)">&#x23F3; Blocking tool call (${escapeHtml(a._blockingToolCall.tool)}) &mdash; silent ${Math.round(a._blockingToolCall.silentMs/60000)}min, timeout in ${Math.round(a._blockingToolCall.remainingMs/60000)}min</div>` : ''}
67
- ${a._warning ? `<div style="margin-top:4px;padding:4px 8px;background:rgba(210,153,34,0.15);border:1px solid rgba(210,153,34,0.3);border-radius:4px;font-size:10px;color:var(--yellow)">&#x26A0; ${escapeHtml(a._warning)}</div>` : ''}
66
+ ${a._blockingToolCall ? `<div style="margin-top:4px;padding:4px 8px;background:rgba(130,160,210,0.13);border:1px solid rgba(130,160,210,0.3);border-radius:4px;font-size:var(--text-sm);color:var(--muted)">&#x23F3; Blocking tool call (${escapeHtml(a._blockingToolCall.tool)}) &mdash; silent ${Math.round(a._blockingToolCall.silentMs/60000)}min, timeout in ${Math.round(a._blockingToolCall.remainingMs/60000)}min</div>` : ''}
67
+ ${a._warning ? `<div style="margin-top:4px;padding:4px 8px;background:rgba(210,153,34,0.15);border:1px solid rgba(210,153,34,0.3);border-radius:4px;font-size:var(--text-sm);color:var(--yellow)">&#x26A0; ${escapeHtml(a._warning)}</div>` : ''}
68
68
  ${a.resultSummary ? `<div class="agent-result" title="${escapeHtml(a.resultSummary)}">${renderMd(a.resultSummary.slice(0, 200))}${a.resultSummary.length > 200 ? '...' : ''}</div>` : ''}
69
69
  </div>
70
70
  `).join('');
@@ -99,7 +99,7 @@ async function openAgentDetail(id) {
99
99
  runtimeSpan.innerHTML = runtimeMeta.svg.replace('width="13"', 'width="18"').replace('height="13"', 'height="18"');
100
100
  runtimeSpan.setAttribute('aria-label', runtimeMeta.label + ' runtime');
101
101
  } else {
102
- runtimeSpan.style.cssText += ';font-size:10px;font-weight:600;letter-spacing:0.4px;text-transform:uppercase;padding:2px 6px;border:1px solid var(--muted);border-radius:3px;color:var(--muted)';
102
+ runtimeSpan.style.cssText += ';font-size:var(--text-sm);font-weight:600;letter-spacing:0.4px;text-transform:uppercase;padding:2px 6px;border:1px solid var(--muted);border-radius:3px;color:var(--muted)';
103
103
  runtimeSpan.textContent = agent.runtime || 'unknown';
104
104
  }
105
105
  // W-mpmwxk4y00053271 — mirror the model chip the card shows so the detail
@@ -109,7 +109,7 @@ async function openAgentDetail(id) {
109
109
  ? (() => {
110
110
  const s = document.createElement('span');
111
111
  s.title = 'Model: ' + agent.model;
112
- s.style.cssText = 'display:inline-block;margin-left:6px;font-size:10px;font-weight:600;letter-spacing:0.4px;padding:2px 6px;border:1px solid var(--muted);border-radius:3px;color:var(--muted)';
112
+ s.style.cssText = 'display:inline-block;margin-left:6px;font-size:var(--text-sm);font-weight:600;letter-spacing:0.4px;padding:2px 6px;border:1px solid var(--muted);border-radius:3px;color:var(--muted)';
113
113
  s.textContent = agent.model;
114
114
  return s;
115
115
  })()
@@ -127,8 +127,8 @@ async function openAgentDetail(id) {
127
127
  document.getElementById('detail-status-line').innerHTML =
128
128
  '<span class="status-badge ' + badgeClass + '">' + agent.status.toUpperCase() + '</span> ' +
129
129
  '<span style="color:var(--muted)">' + escapeHtml(agent.lastAction) + '</span>' +
130
- (agent._blockingToolCall ? '<div style="margin-top:4px;padding:4px 8px;background:rgba(130,160,210,0.13);border:1px solid rgba(130,160,210,0.3);border-radius:4px;font-size:11px;color:var(--muted)">&#x23F3; Blocking tool call (' + escapeHtml(agent._blockingToolCall.tool) + ') &mdash; silent ' + Math.round(agent._blockingToolCall.silentMs/60000) + 'min, timeout in ' + Math.round(agent._blockingToolCall.remainingMs/60000) + 'min</div>' : '') +
131
- (agent.resultSummary ? '<div style="margin-top:4px;font-size:11px;color:var(--text);line-height:1.4">' + renderMd(agent.resultSummary.slice(0, 300)) + '</div>' : '');
130
+ (agent._blockingToolCall ? '<div style="margin-top:4px;padding:4px 8px;background:rgba(130,160,210,0.13);border:1px solid rgba(130,160,210,0.3);border-radius:4px;font-size:var(--text-base);color:var(--muted)">&#x23F3; Blocking tool call (' + escapeHtml(agent._blockingToolCall.tool) + ') &mdash; silent ' + Math.round(agent._blockingToolCall.silentMs/60000) + 'min, timeout in ' + Math.round(agent._blockingToolCall.remainingMs/60000) + 'min</div>' : '') +
131
+ (agent.resultSummary ? '<div style="margin-top:4px;font-size:var(--text-base);color:var(--text);line-height:1.4">' + renderMd(agent.resultSummary.slice(0, 300)) + '</div>' : '');
132
132
 
133
133
  // Show panel immediately with loading state — don't wait for API
134
134
  document.getElementById('detail-content').innerHTML = '<div style="padding:24px;text-align:center;color:var(--muted)">Loading...</div>';
@@ -143,8 +143,8 @@ async function openAgentDetail(id) {
143
143
  document.getElementById('detail-content').innerHTML =
144
144
  '<div style="padding:24px;text-align:center">' +
145
145
  '<div style="color:var(--red);margin-bottom:12px">Error loading agent detail: ' + escapeHtml(e.message) + '</div>' +
146
- '<button data-agent-id="' + escapeHtml(id) + '" onclick="openAgentDetail(this.dataset.agentId)" style="padding:6px 16px;background:var(--blue);color:#fff;border:none;border-radius:var(--radius-sm);cursor:pointer;font-size:12px">Retry</button>' +
147
- ' <button onclick="closeDetail()" style="padding:6px 16px;background:var(--surface2);border:1px solid var(--border);border-radius:var(--radius-sm);cursor:pointer;font-size:12px;color:var(--text)">Close</button>' +
146
+ '<button data-agent-id="' + escapeHtml(id) + '" onclick="openAgentDetail(this.dataset.agentId)" style="padding:6px 16px;background:var(--blue);color:#fff;border:none;border-radius:var(--radius-sm);cursor:pointer;font-size:var(--text-md)">Retry</button>' +
147
+ ' <button onclick="closeDetail()" style="padding:6px 16px;background:var(--surface2);border:1px solid var(--border);border-radius:var(--radius-sm);cursor:pointer;font-size:var(--text-md);color:var(--text)">Close</button>' +
148
148
  '</div>';
149
149
  }
150
150
 
@@ -272,21 +272,21 @@ function renderDispatch(dispatch, opts) {
272
272
  const activeEl = document.getElementById('dispatch-active');
273
273
  if ((dispatch.active || []).length > 0) {
274
274
  // eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; all user data wrapped in escHtml() (fields: dispatch type, agent, task)
275
- activeEl.innerHTML = '<div style="font-size:11px;color:var(--green);margin-bottom:6px;font-weight:600">ACTIVE</div><div class="dispatch-list">' +
275
+ activeEl.innerHTML = '<div style="font-size:var(--text-base);color:var(--green);margin-bottom:6px;font-weight:600">ACTIVE</div><div class="dispatch-list">' +
276
276
  dispatch.active.map(d => dispatchItemHtml(d,
277
277
  '<span class="dispatch-time">' + shortTime(d.started_at) + '</span>'
278
278
  )).join('') + '</div>';
279
279
  } else {
280
- activeEl.innerHTML = '<div style="color:var(--muted);font-size:11px;margin-bottom:8px">No active dispatches</div>';
280
+ activeEl.innerHTML = '<div style="color:var(--muted);font-size:var(--text-base);margin-bottom:8px">No active dispatches</div>';
281
281
  }
282
282
 
283
283
  // Pending
284
284
  const pendingEl = document.getElementById('dispatch-pending');
285
285
  if ((dispatch.pending || []).length > 0) {
286
286
  // eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; all user data wrapped in escHtml() (fields: dispatch type, agent, task, skip reason)
287
- pendingEl.innerHTML = '<div style="font-size:11px;color:var(--yellow);margin:8px 0 6px;font-weight:600">PENDING</div><div class="dispatch-list">' +
287
+ pendingEl.innerHTML = '<div style="font-size:var(--text-base);color:var(--yellow);margin:8px 0 6px;font-weight:600">PENDING</div><div class="dispatch-list">' +
288
288
  dispatch.pending.map(d => dispatchItemHtml(d,
289
- d.skipReason ? '<span style="font-size:9px;color:var(--muted);margin-left:6px" title="' + escHtml(d.skipReason) + '">' + escHtml(d.skipReason.replace(/_/g, ' ')) + '</span>' : ''
289
+ d.skipReason ? '<span style="font-size:var(--text-xs);color:var(--muted);margin-left:6px" title="' + escHtml(d.skipReason) + '">' + escHtml(d.skipReason.replace(/_/g, ' ')) + '</span>' : ''
290
290
  )).join('') + '</div>';
291
291
  } else {
292
292
  pendingEl.innerHTML = '';
@@ -317,7 +317,7 @@ function renderDispatch(dispatch, opts) {
317
317
  ? ' <button class="error-details-btn" data-agent="' + escHtml(agentId) + '" data-reason="' + escHtml(d.reason || 'No reason recorded') + '" data-task="' + escHtml((d.task || '').slice(0, 100)) + '" onclick="showErrorDetails(this.dataset.agent, this.dataset.reason, this.dataset.task)" title="View error details">details</button>'
318
318
  : '';
319
319
  return '<tr>' +
320
- '<td style="font-family:Consolas;font-size:10px" title="' + escHtml(d.id || '') + '">' + escHtml(d.id || '') + '</td>' +
320
+ '<td style="font-family:Consolas;font-size:var(--text-sm)" title="' + escHtml(d.id || '') + '">' + escHtml(d.id || '') + '</td>' +
321
321
  '<td><span class="dispatch-type ' + (d.type || '') + '">' + escHtml(d.type || '') + '</span></td>' +
322
322
  '<td>' + escHtml(d.agentName || d.agent || '') + '</td>' +
323
323
  '<td style="max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + escHtml((d.task || '').slice(0, 60)) + '</td>' +
@@ -452,7 +452,7 @@ function renderVersionBanner(version) {
452
452
 
453
453
  const v = version.dashboardRunning || version.running || version.disk || '?';
454
454
  const commitLabel = version.dashboardRunningCommit ? ' (' + version.dashboardRunningCommit + ')' : '';
455
- const warnStyle = 'font-size:9px;padding:2px 8px;background:rgba(210,153,34,0.15);border:1px solid rgba(210,153,34,0.3);border-radius:4px;color:var(--yellow);cursor:help';
455
+ const warnStyle = 'font-size:var(--text-xs);padding:2px 8px;background:rgba(210,153,34,0.15);border:1px solid rgba(210,153,34,0.3);border-radius:4px;color:var(--yellow);cursor:help';
456
456
 
457
457
  // During the post-restart grace window the old engine's reported codeVersion
458
458
  // can still be in the cached payload — silently swallow the engineStale flag
@@ -474,11 +474,11 @@ function renderVersionBanner(version) {
474
474
  el.textContent = '\u26A0 Dashboard running v' + (version.dashboardRunning || '?') + ' — disk has v' + (version.disk || '?') + '. Run: minions restart';
475
475
  el.title = 'The dashboard process is running older code. Run: minions restart';
476
476
  } else if (version.updateAvailable) {
477
- el.style.cssText = 'font-size:9px;padding:2px 8px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:4px;color:var(--green);cursor:help';
477
+ el.style.cssText = 'font-size:var(--text-xs);padding:2px 8px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:4px;color:var(--green);cursor:help';
478
478
  el.textContent = 'v' + v + commitLabel + ' — v' + version.latest + ' available. Run: minions update or npm install -g @yemi33/minions@latest';
479
479
  el.title = 'A newer version is available on npm. Run minions update to upgrade and restart.';
480
480
  } else {
481
- el.style.cssText = 'font-size:9px;color:var(--muted)';
481
+ el.style.cssText = 'font-size:var(--text-xs);color:var(--muted)';
482
482
  el.textContent = 'v' + v + commitLabel;
483
483
  el.title = 'Minions v' + v + (version.latest ? ' (latest)' : '');
484
484
  }
@@ -111,9 +111,9 @@ function renderInbox(inbox, opts) {
111
111
  <div class="inbox-preview" onclick="openModal(${idx})" style="cursor:pointer">${escapeHtml(item.content.slice(0,200))}</div>
112
112
  <div style="display:flex;gap:6px;margin-top:6px;align-items:center">
113
113
  ${pinButton(pk, pinned, 'inbox')}
114
- <button class="pr-pager-btn" style="font-size:9px;padding:2px 8px" data-inbox-name="${escapeHtml(item.name)}" onclick="event.stopPropagation();promoteToKB(this.dataset.inboxName)">Add to Knowledge Base</button>
115
- <button class="pr-pager-btn" style="font-size:9px;padding:2px 8px" data-inbox-name="${escapeHtml(item.name)}" onclick="event.stopPropagation();openInboxInExplorer(this.dataset.inboxName)">Open in Explorer</button>
116
- <button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--red)" data-inbox-name="${escapeHtml(item.name)}" onclick="event.stopPropagation();deleteInboxItem(this.dataset.inboxName)">Delete</button>
114
+ <button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px" data-inbox-name="${escapeHtml(item.name)}" onclick="event.stopPropagation();promoteToKB(this.dataset.inboxName)">Add to Knowledge Base</button>
115
+ <button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px" data-inbox-name="${escapeHtml(item.name)}" onclick="event.stopPropagation();openInboxInExplorer(this.dataset.inboxName)">Open in Explorer</button>
116
+ <button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--red)" data-inbox-name="${escapeHtml(item.name)}" onclick="event.stopPropagation();deleteInboxItem(this.dataset.inboxName)">Delete</button>
117
117
  </div>
118
118
  </div>`;
119
119
  }).join('');
@@ -137,10 +137,10 @@ function promoteToKB(name) {
137
137
  { id: 'reviews', label: 'Reviews' },
138
138
  ];
139
139
  const picker = '<div style="padding:16px 20px">' +
140
- '<p style="font-size:13px;color:var(--text);margin-bottom:12px">Choose a category for <strong>' + escapeHtml(name) + '</strong>:</p>' +
140
+ '<p style="font-size:var(--text-lg);color:var(--text);margin-bottom:12px">Choose a category for <strong>' + escapeHtml(name) + '</strong>:</p>' +
141
141
  '<div style="display:flex;flex-direction:column;gap:8px">' +
142
142
  categories.map(c =>
143
- '<button class="pr-pager-btn" style="font-size:12px;padding:8px 16px;text-align:left" onclick="doPromoteToKB(\'' + escapeHtml(name) + '\',\'' + c.id + '\')">' + c.label + '</button>'
143
+ '<button class="pr-pager-btn" style="font-size:var(--text-md);padding:8px 16px;text-align:left" onclick="doPromoteToKB(\'' + escapeHtml(name) + '\',\'' + c.id + '\')">' + c.label + '</button>'
144
144
  ).join('') +
145
145
  '</div></div>';
146
146
  document.getElementById('modal-title').textContent = 'Add to Knowledge Base';
@@ -87,22 +87,22 @@ function _renderManagedTable(items) {
87
87
  const ttlColor = (s.ttl_expires_at && s.ttl_expires_at - Date.now() < 5 * 60 * 1000) ? 'var(--yellow)' : 'var(--muted)';
88
88
  const nameAttr = encodeURIComponent(s.name || '');
89
89
  return '<tr>' +
90
- '<td style="padding:4px 8px;font-family:monospace;font-size:11px">' + escHtml(s.name || '') + '</td>' +
91
- '<td style="padding:4px 8px;font-family:monospace;font-size:11px">' + (s.pid || '') + '</td>' +
92
- '<td style="padding:4px 8px;font-size:11px">' + healthBadge + '</td>' +
93
- '<td style="padding:4px 8px;font-size:11px;font-family:monospace">' + escHtml(ports) + '</td>' +
94
- '<td style="padding:4px 8px;font-size:10px;color:var(--muted);max-width:280px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="' + escHtml(_fmtAttrs(s.attrs).replace(/<[^>]+>/g, '')) + '">' + _fmtAttrs(s.attrs) + '</td>' +
95
- '<td style="padding:4px 8px;font-size:11px;color:var(--muted)">' + escHtml(uptime) + '</td>' +
96
- '<td style="padding:4px 8px;font-size:11px;color:' + ttlColor + '">' + escHtml(ttl) + '</td>' +
90
+ '<td style="padding:4px 8px;font-family:monospace;font-size:var(--text-base)">' + escHtml(s.name || '') + '</td>' +
91
+ '<td style="padding:4px 8px;font-family:monospace;font-size:var(--text-base)">' + (s.pid || '') + '</td>' +
92
+ '<td style="padding:4px 8px;font-size:var(--text-base)">' + healthBadge + '</td>' +
93
+ '<td style="padding:4px 8px;font-size:var(--text-base);font-family:monospace">' + escHtml(ports) + '</td>' +
94
+ '<td style="padding:4px 8px;font-size:var(--text-sm);color:var(--muted);max-width:280px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="' + escHtml(_fmtAttrs(s.attrs).replace(/<[^>]+>/g, '')) + '">' + _fmtAttrs(s.attrs) + '</td>' +
95
+ '<td style="padding:4px 8px;font-size:var(--text-base);color:var(--muted)">' + escHtml(uptime) + '</td>' +
96
+ '<td style="padding:4px 8px;font-size:var(--text-base);color:' + ttlColor + '">' + escHtml(ttl) + '</td>' +
97
97
  '<td style="padding:4px 8px;text-align:right;white-space:nowrap">' +
98
- '<button onclick="openManagedLog(decodeURIComponent(\'' + nameAttr + '\'))" style="font-size:10px;padding:2px 6px;margin-right:4px;border:1px solid var(--border);background:var(--surface);color:var(--fg);border-radius:3px;cursor:pointer">Log</button>' +
99
- '<button onclick="restartManagedSpec(decodeURIComponent(\'' + nameAttr + '\'))" style="font-size:10px;padding:2px 6px;margin-right:4px;border:1px solid var(--blue);background:transparent;color:var(--blue);border-radius:3px;cursor:pointer">Restart</button>' +
100
- '<button onclick="killManagedSpec(decodeURIComponent(\'' + nameAttr + '\'))" style="font-size:10px;padding:2px 6px;border:1px solid var(--red);background:transparent;color:var(--red);border-radius:3px;cursor:pointer">Kill</button>' +
98
+ '<button onclick="openManagedLog(decodeURIComponent(\'' + nameAttr + '\'))" style="font-size:var(--text-sm);padding:2px 6px;margin-right:4px;border:1px solid var(--border);background:var(--surface);color:var(--fg);border-radius:3px;cursor:pointer">Log</button>' +
99
+ '<button onclick="restartManagedSpec(decodeURIComponent(\'' + nameAttr + '\'))" style="font-size:var(--text-sm);padding:2px 6px;margin-right:4px;border:1px solid var(--blue);background:transparent;color:var(--blue);border-radius:3px;cursor:pointer">Restart</button>' +
100
+ '<button onclick="killManagedSpec(decodeURIComponent(\'' + nameAttr + '\'))" style="font-size:var(--text-sm);padding:2px 6px;border:1px solid var(--red);background:transparent;color:var(--red);border-radius:3px;cursor:pointer">Kill</button>' +
101
101
  '</td>' +
102
102
  '</tr>';
103
103
  }).join('');
104
104
  return '<table style="width:100%;border-collapse:collapse;margin-bottom:8px">' +
105
- '<thead><tr style="text-align:left;font-size:10px;color:var(--muted);text-transform:uppercase">' +
105
+ '<thead><tr style="text-align:left;font-size:var(--text-sm);color:var(--muted);text-transform:uppercase">' +
106
106
  '<th style="padding:4px 8px">name</th>' +
107
107
  '<th style="padding:4px 8px">pid</th>' +
108
108
  '<th style="padding:4px 8px">health</th>' +
@@ -165,7 +165,7 @@ async function renderManagedProcesses() {
165
165
  const group = groups[proj];
166
166
  group.sort(function (a, b) { return (a.name || '').localeCompare(b.name || ''); });
167
167
  return '<div style="border:1px solid var(--border);border-radius:4px;padding:8px;margin-bottom:8px;background:var(--surface2)">' +
168
- '<div style="font-weight:600;font-size:11px;margin-bottom:6px">' + escHtml(proj) +
168
+ '<div style="font-weight:600;font-size:var(--text-base);margin-bottom:6px">' + escHtml(proj) +
169
169
  ' <span style="color:var(--muted);font-weight:400">(' + group.length + ')</span>' +
170
170
  '</div>' +
171
171
  _renderManagedTable(group) +
@@ -235,11 +235,11 @@ function _ensureManagedLogModal() {
235
235
  const tpl = '' +
236
236
  '<div style="background:var(--bg);border:1px solid var(--border);border-radius:6px;width:100%;max-width:1100px;height:80vh;display:flex;flex-direction:column">' +
237
237
  '<div style="display:flex;align-items:center;padding:8px 12px;border-bottom:1px solid var(--border)">' +
238
- '<div id="managed-log-title" style="flex:1;font-weight:600;font-size:12px;font-family:monospace">Managed log</div>' +
239
- '<div id="managed-log-status" style="font-size:10px;color:var(--muted);margin-right:12px">connecting...</div>' +
240
- '<button id="managed-log-close-btn" style="font-size:10px;padding:4px 10px;border:1px solid var(--border);background:transparent;color:var(--fg);border-radius:3px;cursor:pointer">Close</button>' +
238
+ '<div id="managed-log-title" style="flex:1;font-weight:600;font-size:var(--text-md);font-family:monospace">Managed log</div>' +
239
+ '<div id="managed-log-status" style="font-size:var(--text-sm);color:var(--muted);margin-right:12px">connecting...</div>' +
240
+ '<button id="managed-log-close-btn" style="font-size:var(--text-sm);padding:4px 10px;border:1px solid var(--border);background:transparent;color:var(--fg);border-radius:3px;cursor:pointer">Close</button>' +
241
241
  '</div>' +
242
- '<pre id="managed-log-body" style="flex:1;overflow:auto;margin:0;padding:8px 12px;font-family:monospace;font-size:11px;white-space:pre-wrap;word-break:break-all;background:var(--surface2)"></pre>' +
242
+ '<pre id="managed-log-body" style="flex:1;overflow:auto;margin:0;padding:8px 12px;font-family:monospace;font-size:var(--text-base);white-space:pre-wrap;word-break:break-all;background:var(--surface2)"></pre>' +
243
243
  '</div>';
244
244
  const frag = document.createRange().createContextualFragment(tpl);
245
245
  overlay.appendChild(frag);
@@ -89,7 +89,7 @@ function renderMeetings(meetings, opts) {
89
89
  if (visible.length === 0) {
90
90
  el.innerHTML = '<p class="empty">No active meetings.</p>';
91
91
  // eslint-disable-next-line no-unsanitized/method -- reason: composed from internal archived count and fixed toggle markup (no user data flows in)
92
- if (archived.length) el.insertAdjacentHTML('beforeend', '<div style="text-align:center;margin-top:8px"><button class="pr-pager-btn" style="font-size:10px" onclick="_toggleArchivedMeetings()">Show ' + archived.length + ' archived</button></div>');
92
+ if (archived.length) el.insertAdjacentHTML('beforeend', '<div style="text-align:center;margin-top:8px"><button class="pr-pager-btn" style="font-size:var(--text-sm)" onclick="_toggleArchivedMeetings()">Show ' + archived.length + ' archived</button></div>');
93
93
  _mtgTotalPages = 1;
94
94
  restoreDashboardScrollState(el, scrollState);
95
95
  return;
@@ -109,7 +109,7 @@ function renderMeetings(meetings, opts) {
109
109
  const hasFindings = m.findings?.[p];
110
110
  const hasDebate = m.debate?.[p];
111
111
  const icon = m.status === 'completed' ? '✓' : m.status === 'debating' ? (hasDebate ? '✓' : (hasFindings ? '⏳' : '○')) : (hasFindings ? '✓' : '⏳');
112
- return '<span style="background:var(--surface2);border:1px solid var(--border);border-radius:4px;padding:2px 6px;font-size:10px">' + icon + ' ' + escHtml(p) + '</span>';
112
+ return '<span style="background:var(--surface2);border:1px solid var(--border);border-radius:4px;padding:2px 6px;font-size:var(--text-sm)">' + icon + ' ' + escHtml(p) + '</span>';
113
113
  }).join(' ');
114
114
 
115
115
  const dt = m.completedAt || m.createdAt;
@@ -117,18 +117,18 @@ function renderMeetings(meetings, opts) {
117
117
 
118
118
  return '<div data-file="meetings/' + escHtml(m.id) + '.json" style="background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:12px 16px;margin-bottom:8px;cursor:pointer;position:relative" onclick="if(shouldIgnoreSelectionClick(event))return;openMeetingDetail(\'' + escHtml(m.id) + '\')">' +
119
119
  '<div style="display:flex;justify-content:space-between;align-items:center">' +
120
- '<strong style="font-size:13px">' + escHtml(m.title) + '</strong>' +
120
+ '<strong style="font-size:var(--text-lg)">' + escHtml(m.title) + '</strong>' +
121
121
  '<div style="display:flex;align-items:center;gap:8px">' +
122
- '<span style="color:' + statusColor + ';font-size:11px;font-weight:600">' + statusLabel + '</span>' +
122
+ '<span style="color:' + statusColor + ';font-size:var(--text-base);font-weight:600">' + statusLabel + '</span>' +
123
123
  (m.status === 'archived'
124
- ? '<button class="pr-pager-btn" style="font-size:9px;padding:1px 6px" onclick="event.stopPropagation();_unarchiveMeeting(\'' + escHtml(m.id) + '\')">Unarchive</button>'
125
- : (m.status === 'completed' ? '<button class="pr-pager-btn" style="font-size:9px;padding:1px 6px" onclick="event.stopPropagation();_archiveMeeting(\'' + escHtml(m.id) + '\')">Archive</button>' : '')) +
126
- '<button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--red);border-color:var(--red)" onclick="event.stopPropagation();_deleteMeeting(\'' + escHtml(m.id) + '\')">Delete</button>' +
124
+ ? '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:1px 6px" onclick="event.stopPropagation();_unarchiveMeeting(\'' + escHtml(m.id) + '\')">Unarchive</button>'
125
+ : (m.status === 'completed' ? '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:1px 6px" onclick="event.stopPropagation();_archiveMeeting(\'' + escHtml(m.id) + '\')">Archive</button>' : '')) +
126
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:1px 6px;color:var(--red);border-color:var(--red)" onclick="event.stopPropagation();_deleteMeeting(\'' + escHtml(m.id) + '\')">Delete</button>' +
127
127
  '</div>' +
128
128
  '</div>' +
129
- (timeStr ? '<div style="margin-top:4px;font-size:10px;color:var(--muted)">' + escHtml(timeStr) + '</div>' : '') +
129
+ (timeStr ? '<div style="margin-top:4px;font-size:var(--text-sm);color:var(--muted)">' + escHtml(timeStr) + '</div>' : '') +
130
130
  '<div style="margin-top:6px;display:flex;gap:6px;flex-wrap:wrap">' + participantBadges + '</div>' +
131
- '<div style="margin-top:6px;font-size:11px;color:var(--muted)">' + escHtml((m.agenda || '').slice(0, 100)) + (m.agenda?.length > 100 ? '...' : '') + '</div>' +
131
+ '<div style="margin-top:6px;font-size:var(--text-base);color:var(--muted)">' + escHtml((m.agenda || '').slice(0, 100)) + (m.agenda?.length > 100 ? '...' : '') + '</div>' +
132
132
  '</div>';
133
133
  }).join('');
134
134
 
@@ -144,7 +144,7 @@ function renderMeetings(meetings, opts) {
144
144
 
145
145
  if (archived.length > 0) {
146
146
  // eslint-disable-next-line no-unsanitized/method -- reason: composed from internal archived count and fixed toggle label (no user data flows in)
147
- el.insertAdjacentHTML('beforeend', '<div style="text-align:center;margin-top:8px"><button class="pr-pager-btn" style="font-size:10px" onclick="_toggleArchivedMeetings()">' +
147
+ el.insertAdjacentHTML('beforeend', '<div style="text-align:center;margin-top:8px"><button class="pr-pager-btn" style="font-size:var(--text-sm)" onclick="_toggleArchivedMeetings()">' +
148
148
  (_showArchived ? 'Hide' : 'Show') + ' ' + archived.length + ' archived</button></div>');
149
149
  }
150
150
  restoreDashboardScrollState(el, scrollState);
@@ -193,35 +193,35 @@ function _renderMeetingDetail(m) {
193
193
  // Status bar
194
194
  html += '<div style="display:flex;justify-content:space-between;align-items:center">' +
195
195
  '<span style="color:' + (statusColors[m.status] || 'var(--muted)') + ';font-weight:600">' + (statusLabels[m.status] || m.status) + '</span>' +
196
- '<span style="font-size:10px;color:var(--muted)">' + escHtml(m.createdAt?.slice(0, 16).replace('T', ' ') || '') + '</span>' +
196
+ '<span style="font-size:var(--text-sm);color:var(--muted)">' + escHtml(m.createdAt?.slice(0, 16).replace('T', ' ') || '') + '</span>' +
197
197
  '</div>';
198
198
 
199
199
  // Agenda — render markdown-like formatting
200
- html += '<div style="background:var(--surface2);padding:8px 12px;border-radius:6px;font-size:12px;white-space:pre-wrap;line-height:1.6">' +
200
+ html += '<div style="background:var(--surface2);padding:8px 12px;border-radius:6px;font-size:var(--text-md);white-space:pre-wrap;line-height:1.6">' +
201
201
  '<strong>Agenda:</strong>\n' + renderMd(m.agenda || '') + '</div>';
202
202
 
203
203
  // Per-agent panels
204
204
  for (const agent of (m.participants || [])) {
205
205
  html += '<div style="border:1px solid var(--border);border-radius:6px;overflow:hidden">';
206
- html += '<div style="background:var(--surface2);padding:6px 12px;font-weight:600;font-size:12px">' + escHtml(agent) + '</div>';
206
+ html += '<div style="background:var(--surface2);padding:6px 12px;font-weight:600;font-size:var(--text-md)">' + escHtml(agent) + '</div>';
207
207
 
208
208
  // Findings
209
209
  if (m.findings?.[agent]) {
210
- html += '<div style="padding:8px 12px;font-size:11px;border-bottom:1px solid var(--border)">' +
211
- '<div style="color:var(--muted);font-size:10px;margin-bottom:4px">Round 1 — Findings</div>' +
210
+ html += '<div style="padding:8px 12px;font-size:var(--text-base);border-bottom:1px solid var(--border)">' +
211
+ '<div style="color:var(--muted);font-size:var(--text-sm);margin-bottom:4px">Round 1 — Findings</div>' +
212
212
  '<div class="meeting-scroll-panel" style="word-break:break-word;max-height:300px;overflow-y:auto">' + renderMd(m.findings[agent].content || '') + '</div></div>';
213
213
  }
214
214
 
215
215
  // Debate
216
216
  if (m.debate?.[agent]) {
217
- html += '<div style="padding:8px 12px;font-size:11px;border-bottom:1px solid var(--border)">' +
218
- '<div style="color:var(--muted);font-size:10px;margin-bottom:4px">Round 2 — Debate</div>' +
217
+ html += '<div style="padding:8px 12px;font-size:var(--text-base);border-bottom:1px solid var(--border)">' +
218
+ '<div style="color:var(--muted);font-size:var(--text-sm);margin-bottom:4px">Round 2 — Debate</div>' +
219
219
  '<div class="meeting-scroll-panel" style="word-break:break-word;max-height:300px;overflow-y:auto">' + renderMd(m.debate[agent].content || '') + '</div></div>';
220
220
  }
221
221
 
222
222
  // Status
223
223
  if (!m.findings?.[agent] && m.status !== 'completed') {
224
- html += '<div style="padding:6px 12px;font-size:10px;color:var(--muted)">⏳ Waiting...</div>';
224
+ html += '<div style="padding:6px 12px;font-size:var(--text-sm);color:var(--muted)">⏳ Waiting...</div>';
225
225
  }
226
226
 
227
227
  html += '</div>';
@@ -230,45 +230,45 @@ function _renderMeetingDetail(m) {
230
230
  // Conclusion
231
231
  if (m.conclusion) {
232
232
  html += '<div style="background:rgba(63,185,80,0.08);border:1px solid var(--green);border-radius:6px;padding:10px 14px">' +
233
- '<div style="color:var(--green);font-weight:600;font-size:12px;margin-bottom:6px">Conclusion (by ' + escHtml(m.conclusion.agent || '?') + ')</div>' +
234
- '<div class="meeting-scroll-panel" style="font-size:12px;word-break:break-word;max-height:400px;overflow-y:auto">' + renderMd(m.conclusion.content || '') + '</div></div>';
233
+ '<div style="color:var(--green);font-weight:600;font-size:var(--text-md);margin-bottom:6px">Conclusion (by ' + escHtml(m.conclusion.agent || '?') + ')</div>' +
234
+ '<div class="meeting-scroll-panel" style="font-size:var(--text-md);word-break:break-word;max-height:400px;overflow-y:auto">' + renderMd(m.conclusion.content || '') + '</div></div>';
235
235
  }
236
236
 
237
237
  // Human notes
238
238
  if (m.humanNotes?.length > 0) {
239
239
  html += '<div style="border-top:1px solid var(--border);padding-top:8px">' +
240
- '<div style="color:var(--muted);font-size:10px;margin-bottom:4px">Human Notes</div>' +
241
- m.humanNotes.map(n => '<div style="font-size:11px;margin-bottom:2px">• ' + escHtml(n) + '</div>').join('') +
240
+ '<div style="color:var(--muted);font-size:var(--text-sm);margin-bottom:4px">Human Notes</div>' +
241
+ m.humanNotes.map(n => '<div style="font-size:var(--text-base);margin-bottom:2px">• ' + escHtml(n) + '</div>').join('') +
242
242
  '</div>';
243
243
  }
244
244
 
245
245
  // Actions
246
246
  if (m.status === 'archived') {
247
247
  html += '<div style="display:flex;gap:8px;border-top:1px solid var(--border);padding-top:8px">' +
248
- '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px" onclick="_unarchiveMeeting(\'' + escHtml(m.id) + '\')">Unarchive</button>' +
249
- '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--red);border-color:var(--red)" onclick="_deleteMeeting(\'' + escHtml(m.id) + '\')">Delete</button>' +
248
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px" onclick="_unarchiveMeeting(\'' + escHtml(m.id) + '\')">Unarchive</button>' +
249
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--red);border-color:var(--red)" onclick="_deleteMeeting(\'' + escHtml(m.id) + '\')">Delete</button>' +
250
250
  '</div>';
251
251
  } else if (m.status === 'completed') {
252
252
  const linkedPlan = _findLinkedPlan(m);
253
253
  html += '<div style="display:flex;gap:8px;flex-wrap:wrap;border-top:1px solid var(--border);padding-top:8px">' +
254
254
  (linkedPlan
255
- ? '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--blue);border-color:var(--blue)" onclick="_viewPlanWithBack(\'' + escHtml(linkedPlan.file) + '\',\'' + escHtml(m.id) + '\')">View Plan</button>' +
256
- '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--green);border-color:var(--green)" onclick="_createPlanFromMeeting(\'' + escHtml(m.id) + '\',this)">New Plan</button>'
257
- : '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--green);border-color:var(--green)" onclick="_createPlanFromMeeting(\'' + escHtml(m.id) + '\',this)">Create Plan from Meeting</button>') +
258
- '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px" onclick="_archiveMeeting(\'' + escHtml(m.id) + '\')">Archive</button>' +
259
- '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--red);border-color:var(--red)" onclick="_deleteMeeting(\'' + escHtml(m.id) + '\')">Delete</button>' +
255
+ ? '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--blue);border-color:var(--blue)" onclick="_viewPlanWithBack(\'' + escHtml(linkedPlan.file) + '\',\'' + escHtml(m.id) + '\')">View Plan</button>' +
256
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--green);border-color:var(--green)" onclick="_createPlanFromMeeting(\'' + escHtml(m.id) + '\',this)">New Plan</button>'
257
+ : '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--green);border-color:var(--green)" onclick="_createPlanFromMeeting(\'' + escHtml(m.id) + '\',this)">Create Plan from Meeting</button>') +
258
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px" onclick="_archiveMeeting(\'' + escHtml(m.id) + '\')">Archive</button>' +
259
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--red);border-color:var(--red)" onclick="_deleteMeeting(\'' + escHtml(m.id) + '\')">Delete</button>' +
260
260
  '</div>' +
261
261
  '<div id="meeting-plan-toast" class="cmd-toast cmd-toast-inline" style="margin-top:6px"></div>' +
262
- '<div style="font-size:9px;color:var(--muted);margin-top:4px">Use the Q&amp;A below to discuss action items' + (linkedPlan ? '' : ', then create a plan to execute them') + '.</div>';
262
+ '<div style="font-size:var(--text-xs);color:var(--muted);margin-top:4px">Use the Q&amp;A below to discuss action items' + (linkedPlan ? '' : ', then create a plan to execute them') + '.</div>';
263
263
  } else {
264
264
  html += '<div style="display:flex;gap:8px;border-top:1px solid var(--border);padding-top:8px">' +
265
- '<input id="meeting-note-input" type="text" placeholder="Add context for all agents..." style="flex:1;padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text);font-size:12px" onkeydown="if(event.key===\'Enter\')_submitMeetingNote(\'' + escHtml(m.id) + '\')">' +
266
- '<button onclick="_submitMeetingNote(\'' + escHtml(m.id) + '\',this)" style="padding:6px 12px;background:var(--blue);color:#fff;border:none;border-radius:var(--radius-sm);cursor:pointer;font-size:11px">Add Note</button>' +
265
+ '<input id="meeting-note-input" type="text" placeholder="Add context for all agents..." style="flex:1;padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text);font-size:var(--text-md)" onkeydown="if(event.key===\'Enter\')_submitMeetingNote(\'' + escHtml(m.id) + '\')">' +
266
+ '<button onclick="_submitMeetingNote(\'' + escHtml(m.id) + '\',this)" style="padding:6px 12px;background:var(--blue);color:#fff;border:none;border-radius:var(--radius-sm);cursor:pointer;font-size:var(--text-base)">Add Note</button>' +
267
267
  '</div>' +
268
268
  '<div style="display:flex;gap:8px;margin-top:4px">' +
269
- '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--yellow);border-color:var(--yellow)" onclick="_advanceMeeting(\'' + escHtml(m.id) + '\',this)">Skip to Next Round</button>' +
270
- '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--red);border-color:var(--red)" onclick="_endMeeting(\'' + escHtml(m.id) + '\',this)">End Meeting</button>' +
271
- '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--red);border-color:var(--red)" onclick="_deleteMeeting(\'' + escHtml(m.id) + '\')">Delete</button>' +
269
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--yellow);border-color:var(--yellow)" onclick="_advanceMeeting(\'' + escHtml(m.id) + '\',this)">Skip to Next Round</button>' +
270
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--red);border-color:var(--red)" onclick="_endMeeting(\'' + escHtml(m.id) + '\',this)">End Meeting</button>' +
271
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--red);border-color:var(--red)" onclick="_deleteMeeting(\'' + escHtml(m.id) + '\')">Delete</button>' +
272
272
  '</div>';
273
273
  }
274
274
 
@@ -465,7 +465,7 @@ function _viewPlanWithBack(file, meetingId) {
465
465
  if (title && !title.querySelector('.mtg-back-btn')) {
466
466
  const back = document.createElement('button');
467
467
  back.className = 'pr-pager-btn mtg-back-btn';
468
- back.style.cssText = 'font-size:9px;padding:2px 8px;margin-right:8px;vertical-align:middle';
468
+ back.style.cssText = 'font-size:var(--text-xs);padding:2px 8px;margin-right:8px;vertical-align:middle';
469
469
  back.textContent = '\u2190 Back to Meeting';
470
470
  back.onclick = function() { openMeetingDetail(meetingId); };
471
471
  title.prepend(back);
@@ -6,7 +6,7 @@ function renderProjects(projects) {
6
6
  if (!visible.length) {
7
7
  list.innerHTML = '<span style="color:var(--muted);font-style:italic">No projects linked.</span>' +
8
8
  '<span onclick="addProject()" style="background:var(--surface2);border:1px solid var(--border);border-radius:4px;padding:3px 10px;color:var(--green);font-weight:500;cursor:pointer;border-style:dashed;margin-left:8px">+ Add Project</span>' +
9
- '<span onclick="openScanProjectsModal()" style="background:var(--surface2);border:1px solid var(--border);border-radius:4px;padding:3px 10px;color:var(--blue);font-weight:500;cursor:pointer;border-style:dashed;font-size:10px">Scan</span>';
9
+ '<span onclick="openScanProjectsModal()" style="background:var(--surface2);border:1px solid var(--border);border-radius:4px;padding:3px 10px;color:var(--blue);font-weight:500;cursor:pointer;border-style:dashed;font-size:var(--text-sm)">Scan</span>';
10
10
  return;
11
11
  }
12
12
  // eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; all user data wrapped in escHtml() (fields: project name, path, branch metadata)
@@ -18,7 +18,7 @@ function renderProjects(projects) {
18
18
  '</span>'
19
19
  ).join('') +
20
20
  '<span onclick="addProject()" style="background:var(--surface2);border:1px solid var(--border);border-radius:4px;padding:3px 10px;color:var(--muted);font-weight:500;cursor:pointer;border-style:dashed">+ Add</span>' +
21
- '<span onclick="openScanProjectsModal()" style="background:var(--surface2);border:1px solid var(--border);border-radius:4px;padding:3px 10px;color:var(--blue);font-weight:500;cursor:pointer;border-style:dashed;font-size:10px">Scan</span>';
21
+ '<span onclick="openScanProjectsModal()" style="background:var(--surface2);border:1px solid var(--border);border-radius:4px;padding:3px 10px;color:var(--blue);font-weight:500;cursor:pointer;border-style:dashed;font-size:var(--text-sm)">Scan</span>';
22
22
 
23
23
  }
24
24
 
@@ -141,13 +141,13 @@ function renderMcpServers(servers) {
141
141
  // eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; all user data wrapped in escHtml() (fields: server source, status, args, command, name)
142
142
  el.innerHTML = '<div style="display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px">' +
143
143
  servers.map(s =>
144
- '<div style="font-size:11px;padding:5px 10px;background:var(--surface2);border:1px solid var(--border);border-radius:6px;color:var(--text)" title="' + escHtml([s.source, s.status, s.args || s.command].filter(Boolean).join(' · ')) + '">' +
144
+ '<div style="font-size:var(--text-base);padding:5px 10px;background:var(--surface2);border:1px solid var(--border);border-radius:6px;color:var(--text)" title="' + escHtml([s.source, s.status, s.args || s.command].filter(Boolean).join(' · ')) + '">' +
145
145
  escHtml(s.name) +
146
146
  (s.source ? ' <span style="color:var(--muted)">(' + escHtml(s.source) + ')</span>' : '') +
147
147
  '</div>'
148
148
  ).join('') +
149
149
  '</div>' +
150
- '<p style="font-size:10px;color:var(--muted);margin:0">Mirrors <code style="color:var(--blue)">claude mcp list</code> + <code style="color:var(--blue)">copilot mcp list --json</code>, plus workspace <code>.mcp.json</code> from each registered project. Cached ~5 min.</p>';
150
+ '<p style="font-size:var(--text-sm);color:var(--muted);margin:0">Mirrors <code style="color:var(--blue)">claude mcp list</code> + <code style="color:var(--blue)">copilot mcp list --json</code>, plus workspace <code>.mcp.json</code> from each registered project. Cached ~5 min.</p>';
151
151
  }
152
152
 
153
153
  function renderMetrics(metrics) {
@@ -247,7 +247,7 @@ function renderLlmPerf(metrics) {
247
247
  if (perTask.length > 0) {
248
248
  // Visual divider + caption row to distinguish per-call (above) from
249
249
  // per-task (below) — column units differ.
250
- html += '<tr><td colspan="5" style="border-top:2px solid var(--border);padding-top:6px;font-size:10px;color:var(--muted);font-style:italic">— per agent task (calls = dispatched work items, time = wall-clock of agent process) —</td></tr>';
250
+ html += '<tr><td colspan="5" style="border-top:2px solid var(--border);padding-top:6px;font-size:var(--text-sm);color:var(--muted);font-style:italic">— per agent task (calls = dispatched work items, time = wall-clock of agent process) —</td></tr>';
251
251
  for (const [type, m] of perTask) {
252
252
  html += renderRow(type + ' (per task)', m);
253
253
  }
@@ -330,7 +330,7 @@ function renderTokenUsage(metrics) {
330
330
  const days = Object.keys(daily).sort().slice(-14);
331
331
  if (days.length > 1) {
332
332
  const maxCost = Math.max(...days.map(d => daily[d].costUsd || 0), 0.01);
333
- html += '<div style="font-size:10px;color:var(--muted);margin:8px 0 4px">Daily Cost (last ' + days.length + ' days)</div>';
333
+ html += '<div style="font-size:var(--text-sm);color:var(--muted);margin:8px 0 4px">Daily Cost (last ' + days.length + ' days)</div>';
334
334
  html += '<div class="token-chart">';
335
335
  for (const day of days) {
336
336
  const d = daily[day];
@@ -365,7 +365,7 @@ function renderTokenUsage(metrics) {
365
365
  }
366
366
  var agentsWithUsage = tokenRows.filter(function(a) { return (a[1].totalCostUsd || 0) > 0; });
367
367
  if (agentsWithUsage.length > 0) {
368
- html += '<div style="font-size:10px;color:var(--muted);margin:12px 0 4px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px">Agent Usage</div>';
368
+ html += '<div style="font-size:var(--text-sm);color:var(--muted);margin:12px 0 4px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px">Agent Usage</div>';
369
369
  html += '<table class="token-agent-table"><thead><tr><th style="width:20%">Agent</th><th style="width:10%">Model</th><th style="width:14%">Cost</th><th style="width:14%">Input</th><th style="width:14%">Output</th><th style="width:14%">Cache</th><th style="width:14%">$/task</th></tr></thead><tbody>';
370
370
  for (const [id, m] of agentsWithUsage.sort((a, b) => (b[1].totalCostUsd || 0) - (a[1].totalCostUsd || 0))) {
371
371
  const tasks = (m.tasksCompleted || 0) + (m.tasksErrored || 0);
@@ -373,7 +373,7 @@ function renderTokenUsage(metrics) {
373
373
  const modelLabel = (m.model || '').replace(/^claude-/, '').replace(/\[.*\]$/, '') || '-';
374
374
  html += '<tr>' +
375
375
  '<td style="font-weight:600">' + escHtml(id) + '</td>' +
376
- '<td style="color:var(--muted);font-size:10px">' + escHtml(modelLabel) + '</td>' +
376
+ '<td style="color:var(--muted);font-size:var(--text-sm)">' + escHtml(modelLabel) + '</td>' +
377
377
  '<td>' + fmtCost(m.totalCostUsd || 0) + '</td>' +
378
378
  '<td>' + fmtTokens(m.totalInputTokens || 0) + '</td>' +
379
379
  '<td>' + fmtTokens(m.totalOutputTokens || 0) + '</td>' +
@@ -388,7 +388,7 @@ function renderTokenUsage(metrics) {
388
388
  const engineEntries = Object.entries(engine).filter(([, e]) => (e.costUsd || 0) > 0 || (e.calls || 0) > 0);
389
389
  if (engineEntries.length > 0) {
390
390
  const labels = { 'consolidation': 'Consolidation', 'command-center': 'Command Center', 'doc-chat': 'Doc Chat', 'kb-sweep': 'KB Sweep', 'schedule-parse': 'Schedule Parse' };
391
- html += '<div style="font-size:10px;color:var(--muted);margin:12px 0 4px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px">Engine Usage</div>';
391
+ html += '<div style="font-size:var(--text-sm);color:var(--muted);margin:12px 0 4px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px">Engine Usage</div>';
392
392
  html += '<table class="token-agent-table"><thead><tr><th style="width:20%">Operation</th><th style="width:10%">Calls</th><th style="width:14%">Cost</th><th style="width:14%">Input</th><th style="width:14%">Output</th><th style="width:14%">Cache</th><th style="width:14%">$/call</th></tr></thead><tbody>';
393
393
  for (const [cat, e] of engineEntries.sort((a, b) => (b[1].costUsd || 0) - (a[1].costUsd || 0))) {
394
394
  const perCall = (e.calls || 0) > 0 ? fmtCost((e.costUsd || 0) / e.calls) : '-';
@@ -424,7 +424,7 @@ async function openScanProjectsModal() {
424
424
  '</label>' +
425
425
  '<button onclick="_runProjectScan()" style="padding:6px 16px;background:var(--blue);color:#fff;border:none;border-radius:var(--radius-sm);cursor:pointer;white-space:nowrap">Scan</button>' +
426
426
  '</div>' +
427
- '<div id="scan-results" style="color:var(--muted);font-size:12px">Click Scan to find git repos in the directory.</div>' +
427
+ '<div id="scan-results" style="color:var(--muted);font-size:var(--text-md)">Click Scan to find git repos in the directory.</div>' +
428
428
  '<div class="cmd-toast" id="scan-toast" style="margin-top:0"></div>' +
429
429
  '</div>';
430
430
  document.getElementById('modal-body').style.whiteSpace = 'normal';
@@ -451,27 +451,27 @@ async function _runProjectScan() {
451
451
  // eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; all user data wrapped in escHtml() (fields: scan path)
452
452
  if (repos.length === 0) { resultsEl.innerHTML = '<span style="color:var(--muted)">No git repos found in ' + escHtml(scanPath) + '</span>'; return; }
453
453
 
454
- var html = '<div style="margin-bottom:8px;font-size:11px;color:var(--muted)">' + repos.length + ' repos found — select to add:</div>';
454
+ var html = '<div style="margin-bottom:8px;font-size:var(--text-base);color:var(--muted)">' + repos.length + ' repos found — select to add:</div>';
455
455
  html += '<div style="max-height:400px;overflow-y:auto;display:flex;flex-direction:column;gap:4px">';
456
456
  repos.forEach(function(r, i) {
457
457
  var linked = r.linked;
458
- var hostBadge = '<span style="font-size:9px;padding:1px 5px;border-radius:3px;background:' +
458
+ var hostBadge = '<span style="font-size:var(--text-xs);padding:1px 5px;border-radius:3px;background:' +
459
459
  (r.host === 'GitHub' ? 'rgba(88,166,255,0.15);color:var(--blue)' : r.host === 'ADO' ? 'rgba(188,140,255,0.15);color:var(--purple)' : 'var(--surface2);color:var(--muted)') +
460
460
  '">' + escHtml(r.host) + '</span>';
461
461
  html += '<label style="display:flex;align-items:center;gap:8px;padding:6px 10px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;cursor:' + (linked ? 'default' : 'pointer') + ';opacity:' + (linked ? '0.5' : '1') + '">' +
462
462
  '<input type="checkbox" data-scan-idx="' + i + '" ' + (linked ? 'disabled checked' : '') + ' style="accent-color:var(--blue);width:16px;height:16px">' +
463
463
  '<div style="flex:1;min-width:0">' +
464
- '<div style="font-weight:600;font-size:12px">' + escHtml(r.name) + ' ' + hostBadge + (linked ? ' <span style="font-size:9px;color:var(--green)">linked</span>' : '') + '</div>' +
465
- '<div style="font-size:10px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + escHtml(r.path) + '</div>' +
466
- (r.description ? '<div style="font-size:10px;color:var(--muted)">' + escHtml(r.description) + '</div>' : '') +
464
+ '<div style="font-weight:600;font-size:var(--text-md)">' + escHtml(r.name) + ' ' + hostBadge + (linked ? ' <span style="font-size:var(--text-xs);color:var(--green)">linked</span>' : '') + '</div>' +
465
+ '<div style="font-size:var(--text-sm);color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + escHtml(r.path) + '</div>' +
466
+ (r.description ? '<div style="font-size:var(--text-sm);color:var(--muted)">' + escHtml(r.description) + '</div>' : '') +
467
467
  '</div>' +
468
468
  '</label>';
469
469
  });
470
470
  html += '</div>';
471
471
  html += '<div style="display:flex;justify-content:space-between;align-items:center;margin-top:8px">' +
472
472
  '<div style="display:flex;gap:8px">' +
473
- '<span onclick="_scanSelectAll()" style="font-size:10px;color:var(--blue);cursor:pointer;text-decoration:underline">Select all</span>' +
474
- '<span onclick="_scanSelectNone()" style="font-size:10px;color:var(--muted);cursor:pointer;text-decoration:underline">Clear</span>' +
473
+ '<span onclick="_scanSelectAll()" style="font-size:var(--text-sm);color:var(--blue);cursor:pointer;text-decoration:underline">Select all</span>' +
474
+ '<span onclick="_scanSelectNone()" style="font-size:var(--text-sm);color:var(--muted);cursor:pointer;text-decoration:underline">Clear</span>' +
475
475
  '</div>' +
476
476
  '<button onclick="_addSelectedProjects()" style="padding:6px 16px;background:var(--green);color:#fff;border:none;border-radius:var(--radius-sm);cursor:pointer">Add Selected</button>' +
477
477
  '</div>';
@@ -612,8 +612,8 @@ async function renderKeepProcesses() {
612
612
  if (!it.valid) {
613
613
  return '<div style="border:1px solid var(--border);border-radius:4px;padding:8px;margin-bottom:8px;background:var(--surface2)">' +
614
614
  '<div style="color:var(--red);font-weight:600">' + escHtml(it.agentId) + ' INVALID</div>' +
615
- '<div style="font-size:11px;color:var(--muted)">reason: ' + escHtml(it.reason || '?') + '</div>' +
616
- '<div style="font-size:10px;color:var(--muted)">file: ' + escHtml(it.filePath || '') + '</div>' +
615
+ '<div style="font-size:var(--text-base);color:var(--muted)">reason: ' + escHtml(it.reason || '?') + '</div>' +
616
+ '<div style="font-size:var(--text-sm);color:var(--muted)">file: ' + escHtml(it.filePath || '') + '</div>' +
617
617
  '</div>';
618
618
  }
619
619
  const pidRows = (it.pids || []).map(function (p) {
@@ -622,10 +622,10 @@ async function renderKeepProcesses() {
622
622
  : '<span style="color:var(--muted)">○</span> dead';
623
623
  return '<tr>' +
624
624
  '<td style="padding:2px 8px;font-family:monospace">' + p.pid + '</td>' +
625
- '<td style="padding:2px 8px;font-size:11px">' + aliveBadge + '</td>' +
625
+ '<td style="padding:2px 8px;font-size:var(--text-base)">' + aliveBadge + '</td>' +
626
626
  '<td style="padding:2px 8px;text-align:right">' +
627
627
  (p.alive
628
- ? '<button onclick="killKeepPid(\'' + escHtml(it.agentId) + '\',' + p.pid + ')" style="font-size:10px;padding:2px 6px;color:var(--red);border:1px solid var(--red);background:transparent;border-radius:3px;cursor:pointer">Kill now</button>'
628
+ ? '<button onclick="killKeepPid(\'' + escHtml(it.agentId) + '\',' + p.pid + ')" style="font-size:var(--text-sm);padding:2px 6px;color:var(--red);border:1px solid var(--red);background:transparent;border-radius:3px;cursor:pointer">Kill now</button>'
629
629
  : '') +
630
630
  '</td>' +
631
631
  '</tr>';
@@ -635,8 +635,8 @@ async function renderKeepProcesses() {
635
635
  '<div style="font-weight:600">' + escHtml(it.agentId) +
636
636
  (it.wi_id ? ' <span style="color:var(--muted);font-weight:400">(' + escHtml(it.wi_id) + ')</span>' : '') +
637
637
  '</div>' +
638
- '<div style="font-size:11px;color:var(--muted)">' + escHtml(it.purpose || '(no purpose set)') + portsLine + '</div>' +
639
- '<div style="font-size:10px;color:var(--muted)">cwd: ' + escHtml(it.cwd || '?') +
638
+ '<div style="font-size:var(--text-base);color:var(--muted)">' + escHtml(it.purpose || '(no purpose set)') + portsLine + '</div>' +
639
+ '<div style="font-size:var(--text-sm);color:var(--muted)">cwd: ' + escHtml(it.cwd || '?') +
640
640
  ' expires in ' + (it.expires_in_minutes != null ? it.expires_in_minutes : '?') + 'min age ' + (it.age_minutes != null ? it.age_minutes : '?') + 'min</div>' +
641
641
  '<table style="margin-top:6px;width:100%;border-collapse:collapse">' + pidRows + '</table>' +
642
642
  '</div>';