@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
@@ -555,8 +555,8 @@ function ccSwitchTab(id) {
555
555
  var label = 'Thinking...';
556
556
  for (var pi = phases.length - 1; pi >= 0; pi--) { if (ms >= phases[pi][0]) { label = phases[pi][1]; break; } }
557
557
  var secs = Math.floor(ms / 1000);
558
- html += '<div style="margin-top:' + (text ? '6px' : '0') + ';display:flex;align-items:center;gap:6px"><span style="color:var(--muted);font-size:11px">' + label + '</span>' + dotPulse + '<span style="margin-left:auto;font-size:10px;color:var(--muted)">' + secs + 's</span>' +
559
- '<button onclick="ccAbort()" style="font-size:9px;padding:2px 8px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--red);cursor:pointer;margin-left:4px">Stop</button></div>';
558
+ html += '<div style="margin-top:' + (text ? '6px' : '0') + ';display:flex;align-items:center;gap:6px"><span style="color:var(--muted);font-size:var(--text-base)">' + label + '</span>' + dotPulse + '<span style="margin-left:auto;font-size:var(--text-sm);color:var(--muted)">' + secs + 's</span>' +
559
+ '<button onclick="ccAbort()" style="font-size:var(--text-xs);padding:2px 8px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--red);cursor:pointer;margin-left:4px">Stop</button></div>';
560
560
  return html;
561
561
  }
562
562
  ccAddMessage('assistant', _restoreStreamHtml(), true);
@@ -742,10 +742,10 @@ function ccRestoreMessages() {
742
742
  var elapsed = Date.now() - sendingState.startedAt;
743
743
  var thinking = document.createElement('div');
744
744
  thinking.id = 'cc-thinking';
745
- thinking.style.cssText = 'padding:8px 12px;border-radius:8px;font-size:11px;color:var(--muted);align-self:flex-start;display:flex;align-items:center;gap:8px';
745
+ thinking.style.cssText = 'padding:8px 12px;border-radius:8px;font-size:var(--text-base);color:var(--muted);align-self:flex-start;display:flex;align-items:center;gap:8px';
746
746
  // eslint-disable-next-line no-unsanitized/property -- reason: composed from elapsed timer and compile-time thinking UI strings (no user data flows in)
747
- thinking.innerHTML = '<span class="dot-pulse" style="display:inline-flex;gap:3px"><span style="width:4px;height:4px;background:var(--blue);border-radius:50%;animation:dotPulse 1.2s infinite"></span><span style="width:4px;height:4px;background:var(--blue);border-radius:50%;animation:dotPulse 1.2s infinite;animation-delay:0.2s"></span><span style="width:4px;height:4px;background:var(--blue);border-radius:50%;animation:dotPulse 1.2s infinite;animation-delay:0.4s"></span></span> <span id="cc-thinking-text">Still working...</span> <span id="cc-thinking-time" style="font-size:10px;color:var(--border)">' + Math.floor(elapsed / 1000) + 's</span>' +
748
- ' <button onclick="ccNewTab()" style="font-size:9px;padding:2px 8px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--red);cursor:pointer">Reset</button>';
747
+ thinking.innerHTML = '<span class="dot-pulse" style="display:inline-flex;gap:3px"><span style="width:4px;height:4px;background:var(--blue);border-radius:50%;animation:dotPulse 1.2s infinite"></span><span style="width:4px;height:4px;background:var(--blue);border-radius:50%;animation:dotPulse 1.2s infinite;animation-delay:0.2s"></span><span style="width:4px;height:4px;background:var(--blue);border-radius:50%;animation:dotPulse 1.2s infinite;animation-delay:0.4s"></span></span> <span id="cc-thinking-text">Still working...</span> <span id="cc-thinking-time" style="font-size:var(--text-sm);color:var(--border)">' + Math.floor(elapsed / 1000) + 's</span>' +
748
+ ' <button onclick="ccNewTab()" style="font-size:var(--text-xs);padding:2px 8px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--red);cursor:pointer">Reset</button>';
749
749
  el.appendChild(thinking);
750
750
  el.scrollTop = el.scrollHeight;
751
751
  // Update timer
@@ -831,7 +831,7 @@ function ccAddMessage(role, html, skipSave, targetTabId, meta) {
831
831
  div.setAttribute('data-cc-message-id', messageId);
832
832
  }
833
833
  if (meta && meta.retryId) div.setAttribute('data-cc-retry-id', meta.retryId);
834
- div.style.cssText = 'padding:8px 12px;border-radius:8px;font-size:12px;line-height:1.6;max-width:95%;' +
834
+ div.style.cssText = 'padding:8px 12px;border-radius:8px;font-size:var(--text-md);line-height:1.6;max-width:95%;' +
835
835
  (isUser ? 'background:var(--blue);color:#fff;align-self:flex-end' : isSystem ? 'align-self:center;max-width:100%' : isAction ? 'align-self:flex-start;padding:2px 0' : 'background:var(--surface2);color:var(--text);align-self:flex-start;border:1px solid var(--border);position:relative');
836
836
  // eslint-disable-next-line no-unsanitized/property -- reason: renderMd()/escHtml() call sites escape user-controlled message HTML before ccAddMessage() assigns it (see dashboard/js/utils.js)
837
837
  div.innerHTML = (isAssistant && !html.includes('color:var(--red)') && !html.includes('cc-queued-pill') ? llmCopyBtn() : '') + html;
@@ -908,9 +908,9 @@ function _renderQueueIndicator() {
908
908
  queue.forEach(function(m) {
909
909
  var el = document.createElement('div');
910
910
  el.className = 'cc-queue-item';
911
- el.style.cssText = 'padding:8px 12px;border-radius:8px;font-size:12px;line-height:1.6;max-width:95%;align-self:flex-end;background:var(--blue);color:#fff;opacity:0.5;order:9999';
911
+ el.style.cssText = 'padding:8px 12px;border-radius:8px;font-size:var(--text-md);line-height:1.6;max-width:95%;align-self:flex-end;background:var(--blue);color:#fff;opacity:0.5;order:9999';
912
912
  // eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; queued message text wrapped in escHtml() (fields: m.message)
913
- el.innerHTML = escHtml(typeof m === 'string' ? m : m.message) + '<div style="font-size:9px;opacity:0.7;font-style:italic;margin-top:2px">queued</div>';
913
+ el.innerHTML = escHtml(typeof m === 'string' ? m : m.message) + '<div style="font-size:var(--text-xs);opacity:0.7;font-style:italic;margin-top:2px">queued</div>';
914
914
  msgs.appendChild(el);
915
915
  });
916
916
  if (msgs.scrollHeight - msgs.scrollTop - msgs.clientHeight < 150) msgs.scrollTop = msgs.scrollHeight;
@@ -983,7 +983,7 @@ async function _ccDoSend(message, skipUserMsg, forceTabId, intentMetadata) {
983
983
  var tabSessionId = activeTab ? activeTab.sessionId : null;
984
984
 
985
985
  // Show thinking immediately — before fetch starts
986
- addMsg('assistant', '<span style="color:var(--muted);font-size:11px">Thinking...</span>', true);
986
+ addMsg('assistant', '<span style="color:var(--muted);font-size:var(--text-base)">Thinking...</span>', true);
987
987
  var msgs = document.getElementById('cc-messages');
988
988
  var streamDiv = msgs.lastElementChild;
989
989
  if (streamDiv) streamDiv.setAttribute('data-stream-tab', activeTabId);
@@ -1004,8 +1004,8 @@ async function _ccDoSend(message, skipUserMsg, forceTabId, intentMetadata) {
1004
1004
  if (elapsed >= phases[pi][0]) { label = phases[pi][1]; break; }
1005
1005
  }
1006
1006
  var secs = Math.floor(elapsed / 1000);
1007
- return '<div style="display:flex;align-items:center;gap:6px"><span style="color:var(--muted);font-size:11px">' + label + '</span>' + dotPulse + '<span style="margin-left:auto;font-size:10px;color:var(--muted)">' + secs + 's</span>' +
1008
- '<button onclick="ccAbort()" style="font-size:9px;padding:2px 8px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--red);cursor:pointer;margin-left:4px">Stop</button></div>';
1007
+ return '<div style="display:flex;align-items:center;gap:6px"><span style="color:var(--muted);font-size:var(--text-base)">' + label + '</span>' + dotPulse + '<span style="margin-left:auto;font-size:var(--text-sm);color:var(--muted)">' + secs + 's</span>' +
1008
+ '<button onclick="ccAbort()" style="font-size:var(--text-xs);padding:2px 8px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--red);cursor:pointer;margin-left:4px">Stop</button></div>';
1009
1009
  }
1010
1010
  function updateStreamDiv() {
1011
1011
  // Skip DOM updates if user switched to a different tab (restore interval handles that tab)
@@ -1023,7 +1023,7 @@ async function _ccDoSend(message, skipUserMsg, forceTabId, intentMetadata) {
1023
1023
  html += renderMd(streamedText);
1024
1024
  }
1025
1025
  if (streamStatusNote) {
1026
- html += '<div style="margin-top:6px;font-size:10px;color:var(--muted)">' + escHtml(streamStatusNote) + '</div>';
1026
+ html += '<div style="margin-top:6px;font-size:var(--text-sm);color:var(--muted)">' + escHtml(streamStatusNote) + '</div>';
1027
1027
  }
1028
1028
  html += '<div style="margin-top:' + (streamedText ? '6px' : '0') + '">' + _getThinkingHtml() + '</div>';
1029
1029
  // eslint-disable-next-line no-unsanitized/property -- reason: renderMd() and renderToolChip() escape streamed text/tool fields before assembling live stream HTML
@@ -1034,15 +1034,15 @@ async function _ccDoSend(message, skipUserMsg, forceTabId, intentMetadata) {
1034
1034
  }
1035
1035
  function _ccElapsedFooter(label) {
1036
1036
  var seconds = Math.round((Date.now() - ccStartTime) / 1000);
1037
- return '<div style="font-size:9px;color:var(--muted);margin-top:6px;display:flex;justify-content:flex-end;padding-right:30px">' + label.replace('{seconds}', seconds) + '</div>';
1037
+ return '<div style="font-size:var(--text-xs);color:var(--muted);margin-top:6px;display:flex;justify-content:flex-end;padding-right:30px">' + label.replace('{seconds}', seconds) + '</div>';
1038
1038
  }
1039
1039
  function _ccRetryControls(retryRequest, extraHtml, showReload) {
1040
1040
  var retryTabId = retryRequest && retryRequest.tabId ? retryRequest.tabId : activeTabId;
1041
1041
  var retryId = retryRequest && retryRequest.id ? retryRequest.id : '';
1042
1042
  return (extraHtml || '') +
1043
- '<button onclick="ccRetryLast(' + _ccJsArg(retryTabId) + ',' + _ccJsArg(retryId) + ')" style="margin-top:6px;padding:4px 12px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--blue);cursor:pointer;font-size:11px">Retry</button>' +
1044
- (showReload ? ' <button onclick="ccRestartMinions(this)" style="margin-top:6px;padding:4px 12px;background:var(--orange);color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:11px">Restart Minions</button>' : '') +
1045
- ' <button onclick="ccNewTab()" style="margin-top:6px;padding:4px 12px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--muted);cursor:pointer;font-size:11px">New Session</button>';
1043
+ '<button onclick="ccRetryLast(' + _ccJsArg(retryTabId) + ',' + _ccJsArg(retryId) + ')" style="margin-top:6px;padding:4px 12px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--blue);cursor:pointer;font-size:var(--text-base)">Retry</button>' +
1044
+ (showReload ? ' <button onclick="ccRestartMinions(this)" style="margin-top:6px;padding:4px 12px;background:var(--orange);color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:var(--text-base)">Restart Minions</button>' : '') +
1045
+ ' <button onclick="ccNewTab()" style="margin-top:6px;padding:4px 12px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--muted);cursor:pointer;font-size:var(--text-base)">New Session</button>';
1046
1046
  }
1047
1047
  // Start phase timer immediately so thinking text updates while waiting for SSE
1048
1048
  var phaseTimer = setInterval(updateStreamDiv, 1000);
@@ -1125,7 +1125,7 @@ async function _ccDoSend(message, skipUserMsg, forceTabId, intentMetadata) {
1125
1125
  } else {
1126
1126
  resetText = 'Minions was updated — started a fresh session with latest context.';
1127
1127
  }
1128
- addMsg('system', '<div style="text-align:center;padding:6px 12px;font-size:11px;color:var(--muted);background:var(--surface2);border-radius:6px;margin:4px 0">' + resetText + '</div>', false, activeTabId);
1128
+ addMsg('system', '<div style="text-align:center;padding:6px 12px;font-size:var(--text-base);color:var(--muted);background:var(--surface2);border-radius:6px;margin:4px 0">' + resetText + '</div>', false, activeTabId);
1129
1129
  }
1130
1130
  var finalText = _ccMergeStreamText(streamedText, evt.text || '');
1131
1131
  if (evt.actions && evt.actions.length > 0) _tagServerExecuted(evt.actions, evt.actionResults);
@@ -1159,7 +1159,7 @@ async function _ccDoSend(message, skipUserMsg, forceTabId, intentMetadata) {
1159
1159
  // Issue #1834: server saw ===ACTIONS=== but couldn't parse the JSON.
1160
1160
  // Surface as an inline warning so the user knows actions were dropped
1161
1161
  // (was previously silent — appeared as "actions failed" with no signal).
1162
- addMsg('system', '<div style="padding:6px 12px;font-size:11px;color:var(--red);background:var(--surface2);border-radius:6px;margin:4px 0">⚠️ Actions block emitted but JSON could not be parsed — no actions were executed. Resend or rephrase. (' + escHtml(String(evt.actionParseError).slice(0, 200)) + ')</div>', false, activeTabId);
1162
+ addMsg('system', '<div style="padding:6px 12px;font-size:var(--text-base);color:var(--red);background:var(--surface2);border-radius:6px;margin:4px 0">⚠️ Actions block emitted but JSON could not be parsed — no actions were executed. Resend or rephrase. (' + escHtml(String(evt.actionParseError).slice(0, 200)) + ')</div>', false, activeTabId);
1163
1163
  }
1164
1164
  } else if (evt.type === 'error') {
1165
1165
  terminalEventSeen = true;
@@ -1174,12 +1174,12 @@ async function _ccDoSend(message, skipUserMsg, forceTabId, intentMetadata) {
1174
1174
  var ccErrCode = typeof evt.code === 'string' ? evt.code : '';
1175
1175
  var ccRetry = _ccStoreRetryRequest(activeTab, activeTabId, message);
1176
1176
  var codeChip = ccErrCode
1177
- ? '<span style="display:inline-block;margin-left:6px;padding:1px 6px;font-size:9px;color:var(--muted);background:var(--surface2);border:1px solid var(--border);border-radius:3px;font-family:monospace">' + escHtml(ccErrCode) + '</span>'
1177
+ ? '<span style="display:inline-block;margin-left:6px;padding:1px 6px;font-size:var(--text-xs);color:var(--muted);background:var(--surface2);border:1px solid var(--border);border-radius:3px;font-family:monospace">' + escHtml(ccErrCode) + '</span>'
1178
1178
  : '';
1179
1179
  var availList = Array.isArray(evt.availableModels) && evt.availableModels.length
1180
- ? '<div style="font-size:10px;color:var(--muted);margin-top:6px">Available models: ' + escHtml(evt.availableModels.slice(0, 8).join(', ')) + (evt.availableModels.length > 8 ? '…' : '') + '</div>'
1180
+ ? '<div style="font-size:var(--text-sm);color:var(--muted);margin-top:6px">Available models: ' + escHtml(evt.availableModels.slice(0, 8).join(', ')) + (evt.availableModels.length > 8 ? '…' : '') + '</div>'
1181
1181
  : '';
1182
- var errorBubble = '<div class="cc-error" role="alert" aria-live="assertive" style="padding:8px 12px;background:rgba(220,80,80,0.08);border-left:3px solid var(--red);border-radius:4px;color:var(--red);font-size:12px"><strong>Error</strong>' + codeChip + '<div style="margin-top:4px;color:var(--text)">' + escHtml(ccErrMsg) + '</div>' + availList + '</div>';
1182
+ var errorBubble = '<div class="cc-error" role="alert" aria-live="assertive" style="padding:8px 12px;background:rgba(220,80,80,0.08);border-left:3px solid var(--red);border-radius:4px;color:var(--red);font-size:var(--text-md)"><strong>Error</strong>' + codeChip + '<div style="margin-top:4px;color:var(--text)">' + escHtml(ccErrMsg) + '</div>' + availList + '</div>';
1183
1183
  addMsg('assistant', errorBubble + _ccRetryControls(ccRetry, '', false), false, { retryId: ccRetry.id });
1184
1184
  }
1185
1185
  }
@@ -1261,7 +1261,7 @@ async function _ccDoSend(message, skipUserMsg, forceTabId, intentMetadata) {
1261
1261
  if (!consume.interrupted) break;
1262
1262
  if (!consume.reconnectable || reconnectAttempts >= 2) {
1263
1263
  _cleanupStreamDiv();
1264
- var streamEndedHint = '<div style="font-size:10px;color:var(--muted);margin-top:4px">The response stream ended before completion. Retry to resend the interrupted message.</div>';
1264
+ var streamEndedHint = '<div style="font-size:var(--text-sm);color:var(--muted);margin-top:4px">The response stream ended before completion. Retry to resend the interrupted message.</div>';
1265
1265
  var streamEndedRetry = _ccStoreRetryRequest(activeTab, activeTabId, message);
1266
1266
  if (streamedText) {
1267
1267
  addMsg('assistant', renderMd(streamedText) + _ccElapsedFooter('Stream interrupted after {seconds}s') + _ccRetryControls(streamEndedRetry, streamEndedHint, false), false, { retryId: streamEndedRetry.id });
@@ -1274,8 +1274,8 @@ async function _ccDoSend(message, skipUserMsg, forceTabId, intentMetadata) {
1274
1274
  if (!reconnectHealth.reachable || reconnectHealth.restarted) {
1275
1275
  _cleanupStreamDiv();
1276
1276
  var reconnectHint = reconnectHealth.restarted
1277
- ? '<div style="font-size:10px;color:var(--muted);margin-top:4px">Dashboard restarted while this response was streaming. Restart Minions to reconnect to the new instance.</div>'
1278
- : '<div style="font-size:10px;color:var(--muted);margin-top:4px">The request stream was interrupted, but the dashboard is still reachable. Retry or start a new session.</div>';
1277
+ ? '<div style="font-size:var(--text-sm);color:var(--muted);margin-top:4px">Dashboard restarted while this response was streaming. Restart Minions to reconnect to the new instance.</div>'
1278
+ : '<div style="font-size:var(--text-sm);color:var(--muted);margin-top:4px">The request stream was interrupted, but the dashboard is still reachable. Retry or start a new session.</div>';
1279
1279
  var reconnectRetry = _ccStoreRetryRequest(activeTab, activeTabId, message);
1280
1280
  addMsg('assistant', (streamedText ? renderMd(streamedText) + _ccElapsedFooter('Stream interrupted after {seconds}s') : '') +
1281
1281
  _ccRetryControls(reconnectRetry, reconnectHint, reconnectHealth.restarted), false, { retryId: reconnectRetry.id });
@@ -1296,7 +1296,7 @@ async function _ccDoSend(message, skipUserMsg, forceTabId, intentMetadata) {
1296
1296
  if (streamedText) {
1297
1297
  addMsg('assistant', renderMd(streamedText) + _ccElapsedFooter('Stopped after {seconds}s'));
1298
1298
  } else {
1299
- addMsg('assistant', '<span style="color:var(--red);font-size:11px">Stopped</span>');
1299
+ addMsg('assistant', '<span style="color:var(--red);font-size:var(--text-base)">Stopped</span>');
1300
1300
  }
1301
1301
  } else {
1302
1302
  var isNetworkError = _ccIsReconnectableStreamError(e);
@@ -1304,10 +1304,10 @@ async function _ccDoSend(message, skipUserMsg, forceTabId, intentMetadata) {
1304
1304
  var connectionHint = '';
1305
1305
  if (isNetworkError) {
1306
1306
  connectionHint = dashboardHealth.restarted
1307
- ? '<div style="font-size:10px;color:var(--muted);margin-top:4px">Dashboard restarted while this response was streaming. Restart Minions to reconnect to the new instance.</div>'
1307
+ ? '<div style="font-size:var(--text-sm);color:var(--muted);margin-top:4px">Dashboard restarted while this response was streaming. Restart Minions to reconnect to the new instance.</div>'
1308
1308
  : dashboardHealth.reachable
1309
- ? '<div style="font-size:10px;color:var(--muted);margin-top:4px">The request stream was interrupted, but the dashboard is still reachable. Retry or start a new session.</div>'
1310
- : '<div style="font-size:10px;color:var(--muted);margin-top:4px">Dashboard connection lost. Restart Minions to reconnect.</div>';
1309
+ ? '<div style="font-size:var(--text-sm);color:var(--muted);margin-top:4px">The request stream was interrupted, but the dashboard is still reachable. Retry or start a new session.</div>'
1310
+ : '<div style="font-size:var(--text-sm);color:var(--muted);margin-top:4px">Dashboard connection lost. Restart Minions to reconnect.</div>';
1311
1311
  }
1312
1312
  var errorRetry = _ccStoreRetryRequest(activeTab, activeTabId, message);
1313
1313
  // W-mpmwxni2000c25c7-d — if the thrower attached a parsed CC error
@@ -1319,12 +1319,12 @@ async function _ccDoSend(message, skipUserMsg, forceTabId, intentMetadata) {
1319
1319
  var errorRendered;
1320
1320
  if (ccEnv) {
1321
1321
  var ccCodeChip = ccEnv.code
1322
- ? '<span style="display:inline-block;margin-left:6px;padding:1px 6px;font-size:9px;color:var(--muted);background:var(--surface2);border:1px solid var(--border);border-radius:3px;font-family:monospace">' + escHtml(ccEnv.code) + '</span>'
1322
+ ? '<span style="display:inline-block;margin-left:6px;padding:1px 6px;font-size:var(--text-xs);color:var(--muted);background:var(--surface2);border:1px solid var(--border);border-radius:3px;font-family:monospace">' + escHtml(ccEnv.code) + '</span>'
1323
1323
  : '';
1324
1324
  var ccAvail = Array.isArray(ccEnv.availableModels) && ccEnv.availableModels.length
1325
- ? '<div style="font-size:10px;color:var(--muted);margin-top:6px">Available models: ' + escHtml(ccEnv.availableModels.slice(0, 8).join(', ')) + (ccEnv.availableModels.length > 8 ? '…' : '') + '</div>'
1325
+ ? '<div style="font-size:var(--text-sm);color:var(--muted);margin-top:6px">Available models: ' + escHtml(ccEnv.availableModels.slice(0, 8).join(', ')) + (ccEnv.availableModels.length > 8 ? '…' : '') + '</div>'
1326
1326
  : '';
1327
- errorRendered = '<div class="cc-error" role="alert" aria-live="assertive" style="padding:8px 12px;background:rgba(220,80,80,0.08);border-left:3px solid var(--red);border-radius:4px;color:var(--red);font-size:12px"><strong>Error</strong>' + ccCodeChip + '<div style="margin-top:4px;color:var(--text)">' + escHtml(ccEnv.message) + '</div>' + ccAvail + '</div>';
1327
+ errorRendered = '<div class="cc-error" role="alert" aria-live="assertive" style="padding:8px 12px;background:rgba(220,80,80,0.08);border-left:3px solid var(--red);border-radius:4px;color:var(--red);font-size:var(--text-md)"><strong>Error</strong>' + ccCodeChip + '<div style="margin-top:4px;color:var(--text)">' + escHtml(ccEnv.message) + '</div>' + ccAvail + '</div>';
1328
1328
  } else {
1329
1329
  errorRendered = '<span style="color:var(--red)">Error: ' + escHtml(e.message) + '</span>';
1330
1330
  }
@@ -1421,7 +1421,7 @@ function _ccActionResultType(action, result) {
1421
1421
  return String((result && result.type) || (action && action.type) || 'action').trim() || 'action';
1422
1422
  }
1423
1423
 
1424
- var CC_ACTION_CHIP_STYLE = 'display:block;width:fit-content;max-width:100%;padding:4px 10px;margin:4px 0 0 0;border-radius:4px;font-size:10px;border:1px dashed var(--border);background:var(--surface)';
1424
+ var CC_ACTION_CHIP_STYLE = 'display:block;width:fit-content;max-width:100%;padding:4px 10px;margin:4px 0 0 0;border-radius:4px;font-size:var(--text-sm);border:1px dashed var(--border);background:var(--surface)';
1425
1425
 
1426
1426
  function _ccActionResultLine(action, result) {
1427
1427
  var type = _ccActionResultType(action, result);
@@ -1486,7 +1486,7 @@ function _tagServerExecuted(actions, actionResults) {
1486
1486
  async function ccExecuteAction(action, targetTabId, opts) {
1487
1487
  action = _ccNormalizeDispatchAction(action);
1488
1488
  var status = document.createElement('div');
1489
- status.style.cssText = 'padding:4px 10px;border-radius:4px;font-size:10px;align-self:flex-start;border:1px dashed var(--border);color:var(--muted)';
1489
+ status.style.cssText = 'padding:4px 10px;border-radius:4px;font-size:var(--text-sm);align-self:flex-start;border:1px dashed var(--border);color:var(--muted)';
1490
1490
 
1491
1491
  // Server-executed actions: just show status, don't re-fire the API
1492
1492
  if (action._serverExecuted) {
@@ -1501,8 +1501,8 @@ async function ccExecuteAction(action, targetTabId, opts) {
1501
1501
  var successLabel = serverActionType === 'dispatch' ? 'Dispatched' : serverActionType;
1502
1502
  // eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; label and warning wrapped in escHtml(), success label is a normalized server action type (fields: label, action._serverWarning)
1503
1503
  status.innerHTML = '&#10003; ' + escHtml(successLabel) + ': <strong>' + label + '</strong>' +
1504
- (action._serverDuplicate ? '<div style="font-size:10px;color:var(--orange);margin-top:2px">Already existed from a previous request; no duplicate work item was created.</div>' : '') +
1505
- (action._serverWarning ? '<div style="font-size:10px;color:var(--muted);margin-top:2px">' + escHtml(action._serverWarning) + '</div>' : '');
1504
+ (action._serverDuplicate ? '<div style="font-size:var(--text-sm);color:var(--orange);margin-top:2px">Already existed from a previous request; no duplicate work item was created.</div>' : '') +
1505
+ (action._serverWarning ? '<div style="font-size:var(--text-sm);color:var(--muted);margin-top:2px">' + escHtml(action._serverWarning) + '</div>' : '');
1506
1506
  status.style.color = 'var(--green)';
1507
1507
  }
1508
1508
  if (opts && opts.originMessageId && _ccAppendHtmlToMessage(targetTabId || _ccActiveTabId, opts.originMessageId, status.outerHTML)) {
@@ -1832,7 +1832,7 @@ async function ccExecuteAction(action, targetTabId, opts) {
1832
1832
  var prLinkData = await prLinkRes.json().catch(function() { return {}; });
1833
1833
  // eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; PR URL and server message wrapped in escHtml() (fields: action.url, prLinkData.message)
1834
1834
  status.innerHTML = '&#10003; PR linked: <strong>' + escHtml(action.url) + '</strong>' +
1835
- (prLinkData.message ? '<div style="font-size:11px;color:var(--muted);margin-top:4px">' + escHtml(prLinkData.message) + '</div>' : '');
1835
+ (prLinkData.message ? '<div style="font-size:var(--text-base);color:var(--muted);margin-top:4px">' + escHtml(prLinkData.message) + '</div>' : '');
1836
1836
  status.style.color = 'var(--green)';
1837
1837
  break;
1838
1838
  }
@@ -98,17 +98,17 @@ function renderDetailContent(detail, tab) {
98
98
  el.innerHTML =
99
99
  '<div id="live-chat" style="display:flex;flex-direction:column;height:60vh">' +
100
100
  '<div id="live-terminal-banner"></div>' +
101
- '<div id="live-messages" style="flex:1;overflow-y:auto;padding:8px;font-size:11px;line-height:1.6;display:flex;flex-direction:column"></div>' +
101
+ '<div id="live-messages" style="flex:1;overflow-y:auto;padding:8px;font-size:var(--text-base);line-height:1.6;display:flex;flex-direction:column"></div>' +
102
102
  '<div id="live-status-bar" style="padding:4px 8px;display:flex;align-items:center;gap:8px;border-top:1px solid var(--border)">' +
103
- '<span class="pulse"></span><span id="live-status-label" style="font-size:11px;color:var(--green)">Streaming live</span>' +
104
- '<span id="live-runtime" style="font-size:10px;color:var(--muted)" data-started="' + (startedAt || '') + '"></span>' +
105
- '<button class="pr-pager-btn" onclick="refreshLiveOutput()" style="font-size:10px">Refresh</button>' +
103
+ '<span class="pulse"></span><span id="live-status-label" style="font-size:var(--text-base);color:var(--green)">Streaming live</span>' +
104
+ '<span id="live-runtime" style="font-size:var(--text-sm);color:var(--muted)" data-started="' + (startedAt || '') + '"></span>' +
105
+ '<button class="pr-pager-btn" onclick="refreshLiveOutput()" style="font-size:var(--text-sm)">Refresh</button>' +
106
106
  '</div>' +
107
107
  '<div id="live-steer-bar" style="display:flex;gap:8px;padding:8px;border-top:1px solid var(--border)">' +
108
108
  '<input id="live-steer-input" type="text" placeholder="Message this agent — ask for status, give context, or redirect..." ' +
109
- 'style="flex:1;padding:6px 10px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text);font-size:12px;font-family:inherit" ' +
109
+ 'style="flex:1;padding:6px 10px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text);font-size:var(--text-md);font-family:inherit" ' +
110
110
  'onkeydown="if(event.key===\'Enter\')sendSteering()" />' +
111
- '<button onclick="sendSteering()" style="padding:6px 12px;background:var(--blue);color:#fff;border:none;border-radius:var(--radius-sm);cursor:pointer;font-size:11px">Send</button>' +
111
+ '<button onclick="sendSteering()" style="padding:6px 12px;background:var(--blue);color:#fff;border:none;border-radius:var(--radius-sm);cursor:pointer;font-size:var(--text-base)">Send</button>' +
112
112
  '</div>' +
113
113
  '</div>';
114
114
  startLiveStream(currentAgentId);
@@ -117,12 +117,12 @@ function renderDetailContent(detail, tab) {
117
117
  // eslint-disable-next-line no-unsanitized/property -- reason: renderMd() escapes charter display content and escHtml() escapes textarea content before assembling HTML (see dashboard/js/utils.js)
118
118
  el.innerHTML =
119
119
  '<div style="display:flex;gap:6px;margin-bottom:8px">' +
120
- '<button class="pr-pager-btn" id="charter-edit-btn" style="font-size:10px;padding:2px 10px" onclick="_toggleCharterEdit()">Edit</button>' +
121
- '<button class="pr-pager-btn" id="charter-save-btn" style="font-size:10px;padding:2px 10px;color:var(--green);border-color:var(--green);display:none" onclick="_saveCharter()">Save</button>' +
122
- '<button class="pr-pager-btn" id="charter-cancel-btn" style="font-size:10px;padding:2px 10px;display:none" onclick="_cancelCharterEdit()">Cancel</button>' +
120
+ '<button class="pr-pager-btn" id="charter-edit-btn" style="font-size:var(--text-sm);padding:2px 10px" onclick="_toggleCharterEdit()">Edit</button>' +
121
+ '<button class="pr-pager-btn" id="charter-save-btn" style="font-size:var(--text-sm);padding:2px 10px;color:var(--green);border-color:var(--green);display:none" onclick="_saveCharter()">Save</button>' +
122
+ '<button class="pr-pager-btn" id="charter-cancel-btn" style="font-size:var(--text-sm);padding:2px 10px;display:none" onclick="_cancelCharterEdit()">Cancel</button>' +
123
123
  '</div>' +
124
124
  '<div id="charter-view" class="section">' + renderMd(charterContent || 'No charter found. Click Edit to create one.') + '</div>' +
125
- '<textarea id="charter-editor" style="display:none;width:100%;min-height:300px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text);font-family:Consolas,monospace;font-size:12px;resize:vertical">' + escHtml(charterContent) + '</textarea>';
125
+ '<textarea id="charter-editor" style="display:none;width:100%;min-height:300px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text);font-family:Consolas,monospace;font-size:var(--text-md);resize:vertical">' + escHtml(charterContent) + '</textarea>';
126
126
  _charterRawCache = charterContent;
127
127
  } else if (tab === 'history') {
128
128
  let html = '';
@@ -136,8 +136,8 @@ function renderDetailContent(detail, tab) {
136
136
  html += '<tr>' +
137
137
  '<td style="max-width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="' + escHtml(d.task) + '">' + escHtml(d.task.slice(0, 80)) + '</td>' +
138
138
  '<td><span class="dispatch-type ' + d.type + '">' + escHtml(d.type) + '</span></td>' +
139
- '<td style="color:' + color + '"' + reason + '>' + escHtml(d.result) + (isError && d.reason ? ' <span style="font-size:10px;color:var(--muted)">(' + escHtml(d.reason.slice(0, 50)) + ')</span>' : '') + '</td>' +
140
- '<td style="font-size:10px;color:var(--muted)">' + (d.completed_at ? formatLocalDateTime(d.completed_at) : '') + '</td>' +
139
+ '<td style="color:' + color + '"' + reason + '>' + escHtml(d.result) + (isError && d.reason ? ' <span style="font-size:var(--text-sm);color:var(--muted)">(' + escHtml(d.reason.slice(0, 50)) + ')</span>' : '') + '</td>' +
140
+ '<td style="font-size:var(--text-sm);color:var(--muted)">' + (d.completed_at ? formatLocalDateTime(d.completed_at) : '') + '</td>' +
141
141
  '</tr>';
142
142
  });
143
143
  html += '</tbody></table>';
@@ -92,7 +92,7 @@ function renderFre(statusOrProjects) {
92
92
  'border:1px solid var(--blue)',
93
93
  'border-radius:var(--radius-lg)',
94
94
  'color:var(--text)',
95
- 'font-size:13px',
95
+ 'font-size:var(--text-lg)',
96
96
  'box-shadow:var(--shadow-md)',
97
97
  ].join(';');
98
98
 
@@ -116,7 +116,7 @@ function renderFre(statusOrProjects) {
116
116
  'background:var(--blue)',
117
117
  'color:#fff',
118
118
  'font-weight:700',
119
- 'font-size:11px',
119
+ 'font-size:var(--text-base)',
120
120
  'flex-shrink:0',
121
121
  ].join(';');
122
122
 
@@ -127,7 +127,7 @@ function renderFre(statusOrProjects) {
127
127
  'border:none',
128
128
  'border-radius:var(--radius-sm)',
129
129
  'cursor:pointer',
130
- 'font-size:12px',
130
+ 'font-size:var(--text-md)',
131
131
  'font-weight:600',
132
132
  'margin-top:8px',
133
133
  ].join(';');
@@ -139,7 +139,7 @@ function renderFre(statusOrProjects) {
139
139
  'border:1px solid var(--blue)',
140
140
  'border-radius:var(--radius-sm)',
141
141
  'cursor:pointer',
142
- 'font-size:12px',
142
+ 'font-size:var(--text-md)',
143
143
  'font-weight:600',
144
144
  'margin-top:8px',
145
145
  ].join(';');
@@ -149,7 +149,7 @@ function renderFre(statusOrProjects) {
149
149
  'border:none',
150
150
  'color:var(--muted)',
151
151
  'cursor:pointer',
152
- 'font-size:11px',
152
+ 'font-size:var(--text-base)',
153
153
  'padding:2px 8px',
154
154
  ].join(';');
155
155
 
@@ -162,17 +162,17 @@ function renderFre(statusOrProjects) {
162
162
  mount.innerHTML =
163
163
  '<div id="fre-card" style="' + cardStyle + '">' +
164
164
  '<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:10px">' +
165
- '<div style="font-size:15px;font-weight:700;color:var(--blue)">&#x1F44B; Welcome to Minions</div>' +
165
+ '<div style="font-size:var(--text-xl);font-weight:700;color:var(--blue)">&#x1F44B; Welcome to Minions</div>' +
166
166
  '<button onclick="dismissFre()" style="' + dismissBtn + '" title="Hide this banner — clear localStorage.minions_fre_dismissed to re-show">Dismiss</button>' +
167
167
  '</div>' +
168
- '<div style="color:var(--muted);font-size:12px;margin-bottom:12px">Two quick steps to get your fleet ready.</div>' +
168
+ '<div style="color:var(--muted);font-size:var(--text-md);margin-bottom:12px">Two quick steps to get your fleet ready.</div>' +
169
169
  '<div style="display:flex;flex-direction:column;gap:10px">' +
170
170
 
171
171
  '<div style="' + stepBox + '">' +
172
172
  '<span style="' + stepNum + '">1</span>' +
173
173
  '<div style="flex:1">' +
174
174
  '<div style="font-weight:600;margin-bottom:2px">Pick your runtime CLI</div>' +
175
- '<div style="color:var(--muted);font-size:12px;line-height:1.5">' +
175
+ '<div style="color:var(--muted);font-size:var(--text-md);line-height:1.5">' +
176
176
  'Minions spawns agents through this CLI. Switch via Settings &rarr; Engine &rarr; Default CLI (<code>claude</code> or <code>copilot</code>). ' +
177
177
  'Currently: <code style="background:var(--bg);padding:1px 6px;border-radius:3px;color:var(--text)">' + safeRuntime + '</code>' +
178
178
  '</div>' +
@@ -184,7 +184,7 @@ function renderFre(statusOrProjects) {
184
184
  '<span style="' + stepNum + '">2</span>' +
185
185
  '<div style="flex:1">' +
186
186
  '<div style="font-weight:600;margin-bottom:2px">Add your first project</div>' +
187
- '<div style="color:var(--muted);font-size:12px;line-height:1.5">' +
187
+ '<div style="color:var(--muted);font-size:var(--text-md);line-height:1.5">' +
188
188
  'Projects map a local git worktree to a remote repo. Without a project, agents have nowhere to run.' +
189
189
  '</div>' +
190
190
  '<button onclick="addProject()" style="' + btnPrimary + '">+ Add Project</button>' +
@@ -160,8 +160,8 @@ async function sendSteering() {
160
160
  const el = document.getElementById('live-messages');
161
161
  if (el) {
162
162
  // eslint-disable-next-line no-unsanitized/method -- reason: structural HTML is a string literal; all user data wrapped in escHtml() (fields: steering message)
163
- el.insertAdjacentHTML('beforeend', '<div style="align-self:flex-end;background:var(--blue);color:#fff;padding:6px 12px;border-radius:12px 12px 2px 12px;max-width:80%;margin:4px 0;font-size:12px">' + escHtml(message) +
164
- '<div id="steer-pending" style="font-size:9px;opacity:0.7;margin-top:2px">\u2197 Sending...</div></div>');
163
+ el.insertAdjacentHTML('beforeend', '<div style="align-self:flex-end;background:var(--blue);color:#fff;padding:6px 12px;border-radius:12px 12px 2px 12px;max-width:80%;margin:4px 0;font-size:var(--text-md)">' + escHtml(message) +
164
+ '<div id="steer-pending" style="font-size:var(--text-xs);opacity:0.7;margin-top:2px">\u2197 Sending...</div></div>');
165
165
  el.scrollTop = el.scrollHeight;
166
166
  }
167
167
  showToast('cmd-toast', 'Steering message sent to ' + currentAgentId, true);
@@ -297,16 +297,16 @@ function _qaBuildUserMessageHtml(message, selection) {
297
297
 
298
298
  function _qaBuildQueuedHtml(message) {
299
299
  const preview = escHtml(message.length > 60 ? message.slice(0, 57) + '...' : message);
300
- return '<div class="qa-queued-item" style="color:var(--muted);font-size:10px;padding:4px 8px">Queued: "' + preview + '"</div>';
300
+ return '<div class="qa-queued-item" style="color:var(--muted);font-size:var(--text-sm);padding:4px 8px">Queued: "' + preview + '"</div>';
301
301
  }
302
302
 
303
303
  function _qaBuildLoadingHtml(loadingId, queueCount) {
304
- const qaQueueBadge = queueCount > 0 ? ' <span style="font-size:9px;color:var(--muted);background:var(--surface);padding:1px 5px;border-radius:8px;border:1px solid var(--border)">+' + queueCount + ' queued</span>' : '';
304
+ const qaQueueBadge = queueCount > 0 ? ' <span style="font-size:var(--text-xs);color:var(--muted);background:var(--surface);padding:1px 5px;border-radius:8px;border:1px solid var(--border)">+' + queueCount + ' queued</span>' : '';
305
305
  return '<div class="modal-qa-loading" id="' + loadingId + '">' +
306
306
  '<div class="dot-pulse"><span></span><span></span><span></span></div> ' +
307
307
  '<span id="' + loadingId + '-text">Thinking...</span> ' +
308
- '<span id="' + loadingId + '-time" style="font-size:10px;color:var(--muted)"></span>' +
309
- ' <button onclick="qaAbort()" style="font-size:9px;padding:2px 8px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--red);cursor:pointer">Stop</button>' +
308
+ '<span id="' + loadingId + '-time" style="font-size:var(--text-sm);color:var(--muted)"></span>' +
309
+ ' <button onclick="qaAbort()" style="font-size:var(--text-xs);padding:2px 8px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--red);cursor:pointer">Stop</button>' +
310
310
  qaQueueBadge + '</div>';
311
311
  }
312
312
 
@@ -320,17 +320,17 @@ function _qaBuildRawErrorHtml(err) {
320
320
  if (err.errorClass) meta.push('class: ' + escHtml(String(err.errorClass)));
321
321
  if (err.code !== null && err.code !== undefined) meta.push('exit: ' + escHtml(String(err.code)));
322
322
  const metaLine = meta.length
323
- ? '<div style="font-size:10px;color:var(--muted);margin-bottom:4px">' + meta.join(' · ') + '</div>'
323
+ ? '<div style="font-size:var(--text-sm);color:var(--muted);margin-bottom:4px">' + meta.join(' · ') + '</div>'
324
324
  : '';
325
325
  const adapterMessage = err.errorMessage
326
- ? '<div style="font-size:11px;color:var(--text);margin-bottom:6px;white-space:pre-wrap">' + escHtml(String(err.errorMessage)) + '</div>'
326
+ ? '<div style="font-size:var(--text-base);color:var(--text);margin-bottom:6px;white-space:pre-wrap">' + escHtml(String(err.errorMessage)) + '</div>'
327
327
  : '';
328
328
  const stderrText = err.stderr ? String(err.stderr) : '';
329
329
  const stderrBlock = stderrText
330
- ? '<pre style="margin:0;padding:6px 8px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;font-size:11px;white-space:pre-wrap;word-break:break-word;max-height:240px;overflow:auto">' + escHtml(stderrText) + '</pre>'
331
- : '<div style="font-size:11px;color:var(--muted)">(no stderr captured)</div>';
330
+ ? '<pre style="margin:0;padding:6px 8px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;font-size:var(--text-base);white-space:pre-wrap;word-break:break-word;max-height:240px;overflow:auto">' + escHtml(stderrText) + '</pre>'
331
+ : '<div style="font-size:var(--text-base);color:var(--muted)">(no stderr captured)</div>';
332
332
  return '<details class="modal-qa-raw-error" style="margin:6px 0 12px;padding:6px 8px;border:1px solid var(--red);border-radius:4px;background:var(--surface)">' +
333
- '<summary style="cursor:pointer;font-size:11px;color:var(--red)">Raw error output</summary>' +
333
+ '<summary style="cursor:pointer;font-size:var(--text-base);color:var(--red)">Raw error output</summary>' +
334
334
  '<div style="margin-top:6px">' + metaLine + adapterMessage + stderrBlock + '</div>' +
335
335
  '</details>';
336
336
  }
@@ -344,7 +344,7 @@ function _qaBuildAssistantHtml(text, opts) {
344
344
  return '<div class="modal-qa-a" style="' + style + '">' +
345
345
  (opts?.isError ? '' : llmCopyBtn()) +
346
346
  body +
347
- '<div style="font-size:9px;color:var(--muted);margin-top:4px;text-align:right;' + pad + '">' + opts.elapsed + 's</div>' +
347
+ '<div style="font-size:var(--text-xs);color:var(--muted);margin-top:4px;text-align:right;' + pad + '">' + opts.elapsed + 's</div>' +
348
348
  '</div>';
349
349
  }
350
350
 
@@ -366,20 +366,20 @@ function _qaBuildActionFeedbackHtml(actionFeedback) {
366
366
  if (!Array.isArray(actionFeedback) || actionFeedback.length === 0) return '';
367
367
  return actionFeedback.map(function(item) {
368
368
  const type = escHtml(item.type || 'dispatch');
369
- const baseStyle = 'padding:4px 10px;border-radius:4px;font-size:10px;align-self:flex-start;border:1px dashed var(--border);margin:4px 0;';
369
+ const baseStyle = 'padding:4px 10px;border-radius:4px;font-size:var(--text-sm);align-self:flex-start;border:1px dashed var(--border);margin:4px 0;';
370
370
  if (item.error) {
371
371
  return '<div class="modal-qa-action-feedback" style="' + baseStyle + 'color:var(--red)">&#10007; ' + type + ' failed: ' + escHtml(item.error) + '</div>';
372
372
  }
373
373
  const label = escHtml(item.id || item.duplicateOf || '');
374
374
  const verb = item.type === 'dispatch' ? 'Dispatched' : type;
375
- const duplicate = item.duplicate ? '<div style="font-size:10px;color:var(--orange);margin-top:2px">Already existed from a previous request; no duplicate work item was created.</div>' : '';
376
- const warning = item.warning ? '<div style="font-size:10px;color:var(--muted);margin-top:2px">' + escHtml(item.warning) + '</div>' : '';
375
+ const duplicate = item.duplicate ? '<div style="font-size:var(--text-sm);color:var(--orange);margin-top:2px">Already existed from a previous request; no duplicate work item was created.</div>' : '';
376
+ const warning = item.warning ? '<div style="font-size:var(--text-sm);color:var(--muted);margin-top:2px">' + escHtml(item.warning) + '</div>' : '';
377
377
  return '<div class="modal-qa-action-feedback" style="' + baseStyle + 'color:var(--green)">&#10003; ' + verb + ': <strong>' + label + '</strong>' + duplicate + warning + '</div>';
378
378
  }).join('');
379
379
  }
380
380
 
381
381
  function _qaBuildLiveProgressHtml(loadingId, label, elapsedSeconds, streamedText, toolsUsed, queueCount) {
382
- const qaQueueBadge = queueCount > 0 ? ' <span style="font-size:9px;color:var(--muted);background:var(--surface);padding:1px 5px;border-radius:8px;border:1px solid var(--border)">+' + queueCount + ' queued</span>' : '';
382
+ const qaQueueBadge = queueCount > 0 ? ' <span style="font-size:var(--text-xs);color:var(--muted);background:var(--surface);padding:1px 5px;border-radius:8px;border:1px solid var(--border)">+' + queueCount + ' queued</span>' : '';
383
383
  // Wrap in a column-flex container so chain-of-thought (tool calls) stack
384
384
  // vertically on top and the progress block sits at the bottom. Overrides the
385
385
  // parent .modal-qa-loading row-flex (which is right for the simple
@@ -390,7 +390,7 @@ function _qaBuildLiveProgressHtml(loadingId, label, elapsedSeconds, streamedText
390
390
  toolsUsed.forEach(function(t) {
391
391
  const name = typeof t === 'string' ? t : t.name;
392
392
  const input = typeof t === 'string' ? {} : (t.input || {});
393
- html += '<div style="color:var(--muted);font-size:10px;font-family:monospace;display:flex;align-items:flex-start;gap:6px"><span style="flex-shrink:0">&#9679;</span><span style="word-break:break-all">' + formatToolSummary(name, input) + '</span></div>';
393
+ html += '<div style="color:var(--muted);font-size:var(--text-sm);font-family:monospace;display:flex;align-items:flex-start;gap:6px"><span style="flex-shrink:0">&#9679;</span><span style="word-break:break-all">' + formatToolSummary(name, input) + '</span></div>';
394
394
  });
395
395
  html += '</div>';
396
396
  }
@@ -398,8 +398,8 @@ function _qaBuildLiveProgressHtml(loadingId, label, elapsedSeconds, streamedText
398
398
  html += '<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">' +
399
399
  '<span class="dot-pulse"><span></span><span></span><span></span></span>' +
400
400
  '<span id="' + loadingId + '-text">' + escHtml(label) + '</span>' +
401
- '<span id="' + loadingId + '-time" style="font-size:10px;color:var(--muted)">' + elapsedSeconds + 's</span>' +
402
- '<button onclick="qaAbort()" style="font-size:9px;padding:2px 8px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--red);cursor:pointer">Stop</button>' +
401
+ '<span id="' + loadingId + '-time" style="font-size:var(--text-sm);color:var(--muted)">' + elapsedSeconds + 's</span>' +
402
+ '<button onclick="qaAbort()" style="font-size:var(--text-xs);padding:2px 8px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--red);cursor:pointer">Stop</button>' +
403
403
  qaQueueBadge +
404
404
  '</div>';
405
405
  html += '</div>';
@@ -1133,17 +1133,17 @@ function _qaInstallModalStyle() {
1133
1133
  ' padding: 12px 16px; border-bottom: 1px solid var(--border, #ddd);',
1134
1134
  '}',
1135
1135
  '.qa-modal-title { font-weight: 600; }',
1136
- '.qa-modal-close { font-size: 20px; padding: 0 8px; }',
1136
+ '.qa-modal-close { font-size:var(--text-stat); padding: 0 8px; }',
1137
1137
  '.qa-modal-meta {',
1138
1138
  ' display: flex; gap: 12px; flex-wrap: wrap;',
1139
1139
  ' padding: 8px 16px; border-bottom: 1px solid var(--border, #ddd);',
1140
- ' font-size: 12px; color: var(--muted, #666);',
1140
+ ' font-size:var(--text-md); color: var(--muted, #666);',
1141
1141
  '}',
1142
1142
  '.qa-modal-meta-item { white-space: nowrap; }',
1143
1143
  '.qa-modal-body { flex: 1; overflow: auto; padding: 12px 16px; }',
1144
1144
  '.qa-modal-code {',
1145
1145
  ' font-family: ui-monospace, Menlo, Consolas, monospace;',
1146
- ' font-size: 12px; line-height: 1.5;',
1146
+ ' font-size:var(--text-md); line-height: 1.5;',
1147
1147
  ' background: var(--surface2, #f6f6f6);',
1148
1148
  ' border: 1px solid var(--border, #ddd);',
1149
1149
  ' border-radius: 4px; padding: 12px;',
@@ -414,7 +414,7 @@ function _processStatusUpdate(data, opts) {
414
414
  const autoEl = document.getElementById('auto-approve-badge');
415
415
  // eslint-disable-next-line no-unsanitized/property -- reason: composed from compile-time constants (no user data flows in)
416
416
  if (autoEl) autoEl.innerHTML = data.autoMode?.approvePlans
417
- ? '<span style="font-size:9px;font-weight:600;padding:1px 6px;border-radius:3px;background:rgba(63,185,80,0.15);color:var(--green);border:1px solid rgba(63,185,80,0.3)">AUTO-APPROVE</span>'
417
+ ? '<span style="font-size:var(--text-xs);font-weight:600;padding:1px 6px;border-radius:3px;background:rgba(63,185,80,0.15);color:var(--green);border:1px solid rgba(63,185,80,0.3)">AUTO-APPROVE</span>'
418
418
  : '';
419
419
  const ccLabelEl = document.getElementById('cmd-powered-by');
420
420
  if (ccLabelEl) ccLabelEl.textContent = _formatCcPowerLabel(data.autoMode);
@@ -1338,7 +1338,7 @@ window.MinionsRefresh = { refresh };
1338
1338
  chip.title = 'Open dashboard refresh diagnostics';
1339
1339
  // Bottom-LEFT (not right) to avoid overlapping the Command Center Send
1340
1340
  // button when the CC drawer is open (the drawer covers the right edge).
1341
- chip.style.cssText = 'position:fixed;left:12px;bottom:12px;z-index:9999;background:var(--surface,#222);color:var(--muted,#aaa);border:1px solid var(--border,#444);border-radius:10px;padding:3px 8px;font-size:10px;font-family:inherit;cursor:pointer;opacity:0.75';
1341
+ chip.style.cssText = 'position:fixed;left:12px;bottom:12px;z-index:9999;background:var(--surface,#222);color:var(--muted,#aaa);border:1px solid var(--border,#444);border-radius:10px;padding:3px 8px;font-size:var(--text-sm);font-family:inherit;cursor:pointer;opacity:0.75';
1342
1342
  chip.addEventListener('click', _openRefreshDiagModal);
1343
1343
  document.body.appendChild(chip);
1344
1344
  } catch { /* DOM may not be ready in unusual test embeds */ }
@@ -1354,18 +1354,18 @@ function _openRefreshDiagModal() {
1354
1354
  overlay.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:10000;display:flex;align-items:center;justify-content:center;padding:24px';
1355
1355
  overlay.addEventListener('click', function(e) { if (e.target === overlay) overlay.remove(); });
1356
1356
  const panel = document.createElement('div');
1357
- panel.style.cssText = 'background:var(--surface,#1c1c1c);color:var(--text,#ddd);border:1px solid var(--border,#444);border-radius:8px;max-width:1200px;max-height:80vh;width:100%;display:flex;flex-direction:column;overflow:hidden;font-family:inherit;font-size:11px';
1357
+ panel.style.cssText = 'background:var(--surface,#1c1c1c);color:var(--text,#ddd);border:1px solid var(--border,#444);border-radius:8px;max-width:1200px;max-height:80vh;width:100%;display:flex;flex-direction:column;overflow:hidden;font-family:inherit;font-size:var(--text-base)';
1358
1358
  const head = document.createElement('div');
1359
1359
  head.style.cssText = 'padding:10px 14px;border-bottom:1px solid var(--border,#444);display:flex;align-items:center;justify-content:space-between;gap:8px';
1360
1360
  const title = document.createElement('div');
1361
- title.style.cssText = 'font-weight:700;color:var(--blue,#58a6ff);font-size:13px';
1361
+ title.style.cssText = 'font-weight:700;color:var(--blue,#58a6ff);font-size:var(--text-lg)';
1362
1362
  title.textContent = 'Refresh diagnostics — ' + entries.length + ' / ' + _DIAG_RING_SIZE + ' entries';
1363
1363
  const actions = document.createElement('div');
1364
1364
  actions.style.cssText = 'display:flex;gap:6px';
1365
1365
  const sendBtn = document.createElement('button');
1366
1366
  sendBtn.type = 'button';
1367
1367
  sendBtn.textContent = 'Send to engine';
1368
- sendBtn.style.cssText = 'background:var(--blue,#1f6feb);color:#fff;border:none;border-radius:4px;padding:4px 10px;font-size:11px;cursor:pointer';
1368
+ sendBtn.style.cssText = 'background:var(--blue,#1f6feb);color:#fff;border:none;border-radius:4px;padding:4px 10px;font-size:var(--text-base);cursor:pointer';
1369
1369
  sendBtn.addEventListener('click', function() {
1370
1370
  sendBtn.disabled = true;
1371
1371
  sendBtn.textContent = 'Sending…';
@@ -1384,12 +1384,12 @@ function _openRefreshDiagModal() {
1384
1384
  const clearBtn = document.createElement('button');
1385
1385
  clearBtn.type = 'button';
1386
1386
  clearBtn.textContent = 'Clear';
1387
- clearBtn.style.cssText = 'background:none;color:var(--muted,#aaa);border:1px solid var(--border,#444);border-radius:4px;padding:4px 10px;font-size:11px;cursor:pointer';
1387
+ clearBtn.style.cssText = 'background:none;color:var(--muted,#aaa);border:1px solid var(--border,#444);border-radius:4px;padding:4px 10px;font-size:var(--text-base);cursor:pointer';
1388
1388
  clearBtn.addEventListener('click', function() { window._refreshDiagnosticsClear(); overlay.remove(); });
1389
1389
  const closeBtn = document.createElement('button');
1390
1390
  closeBtn.type = 'button';
1391
1391
  closeBtn.textContent = 'Close';
1392
- closeBtn.style.cssText = 'background:none;color:var(--muted,#aaa);border:1px solid var(--border,#444);border-radius:4px;padding:4px 10px;font-size:11px;cursor:pointer';
1392
+ closeBtn.style.cssText = 'background:none;color:var(--muted,#aaa);border:1px solid var(--border,#444);border-radius:4px;padding:4px 10px;font-size:var(--text-base);cursor:pointer';
1393
1393
  closeBtn.addEventListener('click', function() { overlay.remove(); });
1394
1394
  actions.appendChild(sendBtn);
1395
1395
  actions.appendChild(clearBtn);
@@ -1407,7 +1407,7 @@ function _openRefreshDiagModal() {
1407
1407
 
1408
1408
  function _renderRefreshDiagTable(entries) {
1409
1409
  const table = document.createElement('table');
1410
- table.style.cssText = 'width:100%;border-collapse:collapse;font-family:monospace;font-size:11px';
1410
+ table.style.cssText = 'width:100%;border-collapse:collapse;font-family:monospace;font-size:var(--text-base)';
1411
1411
  const cols = ['ts', 'kind', 'gap', 'vis', 'status', 'etag↓', 'bytes', 'cacheV', 'wi', 'wiΔ', 'changed', 'render(ms)', 'note'];
1412
1412
  const thead = document.createElement('thead');
1413
1413
  const trh = document.createElement('tr');