@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
@@ -17,7 +17,7 @@ function renderPinned(entries) {
17
17
  ';border-radius:4px;cursor:pointer" onclick="if(shouldIgnoreSelectionClick(event))return;openPinnedView(' + i + ')">' +
18
18
  '<div style="display:flex;justify-content:space-between;align-items:center">' +
19
19
  '<strong style="font-size:var(--text-md)">' + escHtml(e.title) + '</strong>' +
20
- '<button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--red);border-color:var(--red)" data-pin-title="' + escHtml(e.title) + '" onclick="event.stopPropagation();removePinnedNote(this.dataset.pinTitle)">Unpin</button>' +
20
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:1px 6px;color:var(--red);border-color:var(--red)" data-pin-title="' + escHtml(e.title) + '" onclick="event.stopPropagation();removePinnedNote(this.dataset.pinTitle)">Unpin</button>' +
21
21
  '</div>' +
22
22
  '<div style="font-size:var(--text-sm);color:var(--muted);margin-top:4px">' + renderMd(e.content.slice(0, 200)) + (e.content.length > 200 ? '...' : '') + '</div>' +
23
23
  '</div>'
@@ -44,7 +44,7 @@ function _renderMonitoredResources(resources, options) {
44
44
  var overflow = resources.length - maxShow;
45
45
 
46
46
  var iconMap = { pr: '๐Ÿ”€', workitem: 'โš™', url: '๐Ÿ”—', issue: '๐Ÿ›' };
47
- var pillStyle = 'display:inline-flex;align-items:center;gap:2px;padding:1px 6px;border-radius:10px;font-size:10px;text-decoration:none;' +
47
+ var pillStyle = 'display:inline-flex;align-items:center;gap:2px;padding:1px 6px;border-radius:10px;font-size:var(--text-sm);text-decoration:none;' +
48
48
  'color:var(--text);background:color-mix(in srgb, var(--muted) 10%, transparent);border:1px solid color-mix(in srgb, var(--muted) 20%, transparent);max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap';
49
49
 
50
50
  var pills = shown.map(function(r) {
@@ -63,7 +63,7 @@ function _renderMonitoredResources(resources, options) {
63
63
  pills.push('<span style="' + pillStyle + ';cursor:default;opacity:0.7" title="' + overflow + ' more resource' + (overflow !== 1 ? 's' : '') + '">+' + overflow + ' more</span>');
64
64
  }
65
65
 
66
- var heading = compact ? '' : '<span style="font-size:10px;color:var(--muted);margin-right:4px">Monitoring:</span>';
66
+ var heading = compact ? '' : '<span style="font-size:var(--text-sm);color:var(--muted);margin-right:4px">Monitoring:</span>';
67
67
  return '<div style="margin-top:4px;display:flex;flex-wrap:wrap;gap:3px;align-items:center">' + heading + pills.join('') + '</div>';
68
68
  }
69
69
 
@@ -105,7 +105,7 @@ function _getPipelineDisplayTitle(pipeline) {
105
105
  function _renderArtifactLinks(artifacts, pipelineId) {
106
106
  if (!artifacts) return '';
107
107
  var links = [];
108
- var linkStyle = 'display:inline-flex;align-items:center;gap:2px;padding:1px 6px;border-radius:10px;font-size:10px;cursor:pointer;text-decoration:none;color:var(--blue);background:color-mix(in srgb, var(--blue) 10%, transparent);border:1px solid color-mix(in srgb, var(--blue) 20%, transparent)';
108
+ var linkStyle = 'display:inline-flex;align-items:center;gap:2px;padding:1px 6px;border-radius:10px;font-size:var(--text-sm);cursor:pointer;text-decoration:none;color:var(--blue);background:color-mix(in srgb, var(--blue) 10%, transparent);border:1px solid color-mix(in srgb, var(--blue) 20%, transparent)';
109
109
 
110
110
  // Pushes current pipeline modal onto back stack so detail modals can navigate back
111
111
  var backFn = pipelineId ? "pushModalBack(function(){openPipelineDetail('" + escHtml(pipelineId) + "')});" : '';
@@ -344,9 +344,9 @@ function renderPipelines(pipelines, opts) {
344
344
  '</div>' +
345
345
  '</div>' +
346
346
  '<div class="pipeline-card-badges">' +
347
- '<span style="color:' + statusColor + ';font-size:11px;font-weight:600">' + escHtml(statusLabel) + '</span>' +
348
- (p.stopWhen ? '<span style="font-size:9px;color:var(--yellow)" title="Auto-stops when condition met: ' + escHtml(typeof p.stopWhen === 'string' ? p.stopWhen : (p.stopWhen.check || 'condition')) + '">STOP-WHEN</span>' : '') +
349
- (p.enabled === false ? '<span style="font-size:9px;color:var(--red)"' + (p._stopReason ? ' title="' + escHtml(p._stopReason) + '"' : '') + '>' + (p._stoppedBy ? 'AUTO-STOPPED' : 'DISABLED') + '</span>' : '') +
347
+ '<span style="color:' + statusColor + ';font-size:var(--text-base);font-weight:600">' + escHtml(statusLabel) + '</span>' +
348
+ (p.stopWhen ? '<span style="font-size:var(--text-xs);color:var(--yellow)" title="Auto-stops when condition met: ' + escHtml(typeof p.stopWhen === 'string' ? p.stopWhen : (p.stopWhen.check || 'condition')) + '">STOP-WHEN</span>' : '') +
349
+ (p.enabled === false ? '<span style="font-size:var(--text-xs);color:var(--red)"' + (p._stopReason ? ' title="' + escHtml(p._stopReason) + '"' : '') + '>' + (p._stoppedBy ? 'AUTO-STOPPED' : 'DISABLED') + '</span>' : '') +
350
350
  '</div>' +
351
351
  '</div>' +
352
352
  resourcesHtml +
@@ -396,15 +396,15 @@ function openPipelineDetail(id) {
396
396
  // Status + actions
397
397
  var activeRun = _getPipelineActiveRun(p);
398
398
  html += '<div style="display:flex;justify-content:space-between;align-items:center">' +
399
- '<span style="font-size:10px;color:var(--muted)">' + _renderPipelineTriggerLabel(p.trigger?.cron) + ' ยท ' + escHtml(_getPipelineStageLabel(p)) + '</span>' +
399
+ '<span style="font-size:var(--text-sm);color:var(--muted)">' + _renderPipelineTriggerLabel(p.trigger?.cron) + ' ยท ' + escHtml(_getPipelineStageLabel(p)) + '</span>' +
400
400
  '<div style="display:flex;gap:6px">' +
401
401
  (activeRun
402
- ? '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--red);border-color:var(--red)" onclick="_abortPipeline(\'' + escHtml(id) + '\',this)">Abort</button>' +
403
- '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--yellow);border-color:var(--yellow)" onclick="_retriggerPipeline(\'' + escHtml(id) + '\',this)">Retrigger</button>'
404
- : '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--green);border-color:var(--green)" onclick="_triggerPipeline(\'' + escHtml(id) + '\',this)">Run Now</button>') +
405
- '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--blue);border-color:var(--blue)" onclick="openEditPipelineModal(\'' + escHtml(id) + '\')">Edit</button>' +
406
- '<button class="pr-pager-btn' + (_pipelineToggleInFlight.has(id) ? ' disabled' : '') + '" style="font-size:9px;padding:2px 8px" onclick="_togglePipelineEnabled(\'' + escHtml(id) + '\',' + !p.enabled + ',this)">' + (p.enabled !== false ? 'Disable' : 'Enable') + '</button>' +
407
- '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--red);border-color:var(--red)" onclick="_deletePipelineConfirm(\'' + escHtml(id) + '\')">Delete</button>' +
402
+ ? '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--red);border-color:var(--red)" onclick="_abortPipeline(\'' + escHtml(id) + '\',this)">Abort</button>' +
403
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--yellow);border-color:var(--yellow)" onclick="_retriggerPipeline(\'' + escHtml(id) + '\',this)">Retrigger</button>'
404
+ : '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--green);border-color:var(--green)" onclick="_triggerPipeline(\'' + escHtml(id) + '\',this)">Run Now</button>') +
405
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--blue);border-color:var(--blue)" onclick="openEditPipelineModal(\'' + escHtml(id) + '\')">Edit</button>' +
406
+ '<button class="pr-pager-btn' + (_pipelineToggleInFlight.has(id) ? ' disabled' : '') + '" style="font-size:var(--text-xs);padding:2px 8px" onclick="_togglePipelineEnabled(\'' + escHtml(id) + '\',' + !p.enabled + ',this)">' + (p.enabled !== false ? 'Disable' : 'Enable') + '</button>' +
407
+ '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--red);border-color:var(--red)" onclick="_deletePipelineConfirm(\'' + escHtml(id) + '\')">Delete</button>' +
408
408
  '</div>' +
409
409
  '</div>';
410
410
 
@@ -417,7 +417,7 @@ function openPipelineDetail(id) {
417
417
  var pipelineResources = _collectMonitoredResources(p);
418
418
  if (pipelineResources.length > 0) {
419
419
  html += '<div style="border:1px solid color-mix(in srgb, var(--blue) 20%, transparent);border-radius:6px;padding:6px 10px;background:color-mix(in srgb, var(--blue) 4%, transparent)">' +
420
- '<span style="font-size:10px;font-weight:600;color:var(--blue)">๐Ÿ“ก Monitored Resources</span>' +
420
+ '<span style="font-size:var(--text-sm);font-weight:600;color:var(--blue)">๐Ÿ“ก Monitored Resources</span>' +
421
421
  _renderMonitoredResources(pipelineResources) +
422
422
  '</div>';
423
423
  }
@@ -425,18 +425,18 @@ function openPipelineDetail(id) {
425
425
  // stopWhen info
426
426
  if (p.stopWhen) {
427
427
  var swLabel = typeof p.stopWhen === 'string' ? p.stopWhen : (p.stopWhen.check || JSON.stringify(p.stopWhen));
428
- html += '<div style="border:1px solid color-mix(in srgb, var(--yellow) 30%, transparent);border-radius:6px;padding:4px 10px;background:color-mix(in srgb, var(--yellow) 6%, transparent);font-size:11px">' +
428
+ html += '<div style="border:1px solid color-mix(in srgb, var(--yellow) 30%, transparent);border-radius:6px;padding:4px 10px;background:color-mix(in srgb, var(--yellow) 6%, transparent);font-size:var(--text-base)">' +
429
429
  '<span style="color:var(--yellow);font-weight:600">Stop When:</span> <span style="color:var(--text)">' + escHtml(swLabel) + '</span>' +
430
- (p._stoppedBy ? ' <span style="color:var(--green);font-size:10px">\u2714 triggered' + (p._stoppedAt ? ' at ' + escHtml(formatLocalDateTime(p._stoppedAt)) : '') + '</span>' : '') +
430
+ (p._stoppedBy ? ' <span style="color:var(--green);font-size:var(--text-sm)">\u2714 triggered' + (p._stoppedAt ? ' at ' + escHtml(formatLocalDateTime(p._stoppedAt)) : '') + '</span>' : '') +
431
431
  '</div>';
432
432
  }
433
433
  if (p._stopReason && p.enabled === false) {
434
- html += '<div style="border:1px solid color-mix(in srgb, var(--red) 30%, transparent);border-radius:6px;padding:4px 10px;background:color-mix(in srgb, var(--red) 6%, transparent);font-size:11px">' +
434
+ html += '<div style="border:1px solid color-mix(in srgb, var(--red) 30%, transparent);border-radius:6px;padding:4px 10px;background:color-mix(in srgb, var(--red) 6%, transparent);font-size:var(--text-base)">' +
435
435
  '<span style="color:var(--red);font-weight:600">Auto-stopped:</span> <span style="color:var(--text)">' + escHtml(p._stopReason) + '</span>' +
436
436
  '</div>';
437
437
  }
438
438
 
439
- html += '<h4 style="font-size:12px;color:var(--blue);margin:0">Stages</h4>';
439
+ html += '<h4 style="font-size:var(--text-md);color:var(--blue);margin:0">Stages</h4>';
440
440
  (p.stages || []).forEach(function(s, i) {
441
441
  var stageRun = activeRun?.stages?.[s.id] || {};
442
442
  var stageStatus = stageRun.status || 'pending';
@@ -445,30 +445,30 @@ function openPipelineDetail(id) {
445
445
 
446
446
  html += '<div style="border:1px solid var(--border);border-radius:6px;padding:8px 12px;background:var(--surface2)">' +
447
447
  '<div style="display:flex;justify-content:space-between;align-items:center">' +
448
- '<span style="font-weight:600;font-size:12px">' + (i + 1) + '. ' + escHtml(s.title || s.id) + '</span>' +
449
- '<span style="color:' + statusColor + ';font-size:10px;font-weight:600">' + stageStatus.toUpperCase() + '</span>' +
448
+ '<span style="font-weight:600;font-size:var(--text-md)">' + (i + 1) + '. ' + escHtml(s.title || s.id) + '</span>' +
449
+ '<span style="color:' + statusColor + ';font-size:var(--text-sm);font-weight:600">' + stageStatus.toUpperCase() + '</span>' +
450
450
  '</div>' +
451
- '<div style="font-size:10px;color:var(--muted);margin-top:4px">Type: ' + escHtml(s.type) + ' | Depends on: ' + escHtml(deps) + (s.agent ? ' | Agent: ' + escHtml(s.agent) : '') +
451
+ '<div style="font-size:var(--text-sm);color:var(--muted);margin-top:4px">Type: ' + escHtml(s.type) + ' | Depends on: ' + escHtml(deps) + (s.agent ? ' | Agent: ' + escHtml(s.agent) : '') +
452
452
  (s.type === 'condition' ? ' | Check: ' + escHtml(typeof (s.check || s.condition) === 'string' ? (s.check || s.condition) : ((s.check || s.condition || {}).check || '?')) + (s.onMet ? ' | onMet: ' + escHtml(s.onMet) : '') + (s.onUnmet ? ' | onUnmet: ' + escHtml(s.onUnmet) : '') : '') +
453
453
  '</div>' +
454
454
  _renderMonitoredResources(s.monitoredResources || []) +
455
455
  _renderArtifactLinks(stageRun.artifacts, id) +
456
- (stageRun.output ? '<div class="pipeline-stage-output" style="margin-top:6px;font-size:11px;max-height:150px;overflow-y:auto">' + renderMd(stageRun.output.slice(0, 500)) + '</div>' : '') +
457
- (stageStatus === 'waiting-human' ? '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--green);border-color:var(--green);margin-top:6px" onclick="_continuePipeline(\'' + escHtml(id) + '\',\'' + escHtml(s.id) + '\',this)">Continue</button>' : '') +
456
+ (stageRun.output ? '<div class="pipeline-stage-output" style="margin-top:6px;font-size:var(--text-base);max-height:150px;overflow-y:auto">' + renderMd(stageRun.output.slice(0, 500)) + '</div>' : '') +
457
+ (stageStatus === 'waiting-human' ? '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--green);border-color:var(--green);margin-top:6px" onclick="_continuePipeline(\'' + escHtml(id) + '\',\'' + escHtml(s.id) + '\',this)">Continue</button>' : '') +
458
458
  '</div>';
459
459
  });
460
460
 
461
461
  // Run history
462
462
  var runs = (p.runs || []).slice(-5).reverse();
463
463
  if (runs.length > 0) {
464
- html += '<h4 style="font-size:12px;color:var(--blue);margin:0">Recent Runs</h4>';
464
+ html += '<h4 style="font-size:var(--text-md);color:var(--blue);margin:0">Recent Runs</h4>';
465
465
  runs.forEach(function(r, ri) {
466
466
  var color = r.status === 'completed' ? 'var(--green)' : r.status === 'failed' ? 'var(--red)' : r.status === 'running' ? 'var(--blue)' : r.status === 'stopped' ? 'var(--yellow)' : 'var(--muted)';
467
467
  // Collect all artifacts across stages for this run
468
468
  var runArtifacts = _collectRunArtifacts(r);
469
469
  var artifactCount = runArtifacts.total;
470
470
  var toggleId = 'run-artifacts-' + ri;
471
- html += '<div style="font-size:10px">' +
471
+ html += '<div style="font-size:var(--text-sm)">' +
472
472
  '<div style="display:flex;gap:8px;align-items:center">' +
473
473
  '<span style="color:' + color + ';font-weight:600">' + r.status + '</span>' +
474
474
  '<span style="color:var(--muted)">' + (r.startedAt ? formatLocalDateTime(r.startedAt) : '') + '</span>' +
@@ -676,8 +676,8 @@ async function _deletePipelineConfirm(id) {
676
676
 
677
677
  function openCreatePipelineModal() {
678
678
  var inputStyle = 'display:block;width:100%;margin-top:4px;padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text);font-size:var(--text-md);font-family:inherit';
679
- var pillStyle = 'display:inline-block;padding:4px 10px;margin:2px;border:1px solid var(--border);border-radius:12px;cursor:pointer;font-size:11px;color:var(--text);background:var(--bg);user-select:none;transition:all 0.15s';
680
- var linkStyle = 'font-size:10px;color:var(--blue);cursor:pointer;text-decoration:underline;margin-right:8px';
679
+ var pillStyle = 'display:inline-block;padding:4px 10px;margin:2px;border:1px solid var(--border);border-radius:12px;cursor:pointer;font-size:var(--text-base);color:var(--text);background:var(--bg);user-select:none;transition:all 0.15s';
680
+ var linkStyle = 'font-size:var(--text-sm);color:var(--blue);cursor:pointer;text-decoration:underline;margin-right:8px';
681
681
  var tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
682
682
 
683
683
  // Hour options (0-23)
@@ -705,14 +705,14 @@ function openCreatePipelineModal() {
705
705
  '<div>' +
706
706
  '<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">' +
707
707
  '<label style="color:var(--text);font-size:var(--text-md);margin:0">Schedule</label>' +
708
- '<label style="font-size:11px;color:var(--muted);cursor:pointer"><input type="checkbox" id="pl-use-cron" checked onchange="_updatePlCronPreview()" style="accent-color:var(--blue)"> Enable automatic trigger</label>' +
708
+ '<label style="font-size:var(--text-base);color:var(--muted);cursor:pointer"><input type="checkbox" id="pl-use-cron" checked onchange="_updatePlCronPreview()" style="accent-color:var(--blue)"> Enable automatic trigger</label>' +
709
709
  '</div>' +
710
710
  '<div id="pl-cron-picker">' +
711
711
  '<div style="display:flex;gap:8px;align-items:center">' +
712
712
  '<select id="pl-pick-hour" style="' + inputStyle + ';width:auto;display:inline-block" onchange="_updatePlCronPreview()">' + hourOpts + '</select>' +
713
713
  '<span style="color:var(--muted)">:</span>' +
714
714
  '<select id="pl-pick-minute" style="' + inputStyle + ';width:auto;display:inline-block" onchange="_updatePlCronPreview()">' + minOpts + '</select>' +
715
- '<span style="font-size:10px;color:var(--muted)">' + escHtml(tz) + '</span>' +
715
+ '<span style="font-size:var(--text-sm);color:var(--muted)">' + escHtml(tz) + '</span>' +
716
716
  '</div>' +
717
717
  '<div style="margin-top:8px">' + dayPills + '</div>' +
718
718
  '<div style="margin-top:6px">' +
@@ -720,7 +720,7 @@ function openCreatePipelineModal() {
720
720
  '<span style="' + linkStyle + '" onclick="_quickSelectDays(\'weekdays\');_updatePlCronPreview()">Weekdays</span>' +
721
721
  '<span style="' + linkStyle + '" onclick="_quickSelectDays(\'weekends\');_updatePlCronPreview()">Weekends</span>' +
722
722
  '</div>' +
723
- '<div id="pl-cron-preview" style="margin-top:4px;font-size:11px;color:var(--blue)"></div>' +
723
+ '<div id="pl-cron-preview" style="margin-top:4px;font-size:var(--text-base);color:var(--blue)"></div>' +
724
724
  '</div>' +
725
725
  '</div>' +
726
726
  '<label style="color:var(--text);font-size:var(--text-md)">Stages (JSON array)<textarea id="pl-stages" rows="10" style="' + inputStyle + ';resize:vertical;font-family:Consolas,monospace" placeholder=\'[{"id":"audit","type":"task","title":"Audit codebase","taskType":"explore"},{"id":"discuss","type":"meeting","title":"Discuss findings","dependsOn":["audit"],"participants":["all"]}]\'></textarea></label>' +
@@ -776,8 +776,8 @@ function openEditPipelineModal(id) {
776
776
  if (!p) return;
777
777
  var displayTitle = _getPipelineDisplayTitle(p);
778
778
  var inputStyle = 'display:block;width:100%;margin-top:4px;padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text);font-size:var(--text-md);font-family:inherit';
779
- var pillStyle = 'display:inline-block;padding:4px 10px;margin:2px;border:1px solid var(--border);border-radius:12px;cursor:pointer;font-size:11px;color:var(--text);background:var(--bg);user-select:none;transition:all 0.15s';
780
- var linkStyle = 'font-size:10px;color:var(--blue);cursor:pointer;text-decoration:underline;margin-right:8px';
779
+ var pillStyle = 'display:inline-block;padding:4px 10px;margin:2px;border:1px solid var(--border);border-radius:12px;cursor:pointer;font-size:var(--text-base);color:var(--text);background:var(--bg);user-select:none;transition:all 0.15s';
780
+ var linkStyle = 'font-size:var(--text-sm);color:var(--blue);cursor:pointer;text-decoration:underline;margin-right:8px';
781
781
  var tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
782
782
  var hasCron = !!p.trigger?.cron;
783
783
  var picker = hasCron ? _parseCronToPicker(p.trigger.cron) : { hour: 9, minute: 0, days: [1,2,3,4,5] };
@@ -802,19 +802,19 @@ function openEditPipelineModal(id) {
802
802
  // eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; all user data wrapped in escHtml() (fields: pipeline id, title, stages JSON, timezone)
803
803
  document.getElementById('modal-body').innerHTML =
804
804
  '<div style="display:flex;flex-direction:column;gap:10px">' +
805
- '<div style="color:var(--muted);font-size:11px">ID: <strong style="color:var(--text)">' + escHtml(id) + '</strong></div>' +
805
+ '<div style="color:var(--muted);font-size:var(--text-base)">ID: <strong style="color:var(--text)">' + escHtml(id) + '</strong></div>' +
806
806
  '<label style="color:var(--text);font-size:var(--text-md)">Title<input id="pl-title" value="' + escHtml(p.title || '') + '" style="' + inputStyle + '"></label>' +
807
807
  '<div>' +
808
808
  '<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">' +
809
809
  '<label style="color:var(--text);font-size:var(--text-md);margin:0">Schedule</label>' +
810
- '<label style="font-size:11px;color:var(--muted);cursor:pointer"><input type="checkbox" id="pl-use-cron"' + (hasCron ? ' checked' : '') + ' onchange="_updatePlCronPreview()" style="accent-color:var(--blue)"> Enable automatic trigger</label>' +
810
+ '<label style="font-size:var(--text-base);color:var(--muted);cursor:pointer"><input type="checkbox" id="pl-use-cron"' + (hasCron ? ' checked' : '') + ' onchange="_updatePlCronPreview()" style="accent-color:var(--blue)"> Enable automatic trigger</label>' +
811
811
  '</div>' +
812
812
  '<div id="pl-cron-picker">' +
813
813
  '<div style="display:flex;gap:8px;align-items:center">' +
814
814
  '<select id="pl-pick-hour" style="' + inputStyle + ';width:auto;display:inline-block" onchange="_updatePlCronPreview()">' + hourOpts + '</select>' +
815
815
  '<span style="color:var(--muted)">:</span>' +
816
816
  '<select id="pl-pick-minute" style="' + inputStyle + ';width:auto;display:inline-block" onchange="_updatePlCronPreview()">' + minOpts + '</select>' +
817
- '<span style="font-size:10px;color:var(--muted)">' + escHtml(tz) + '</span>' +
817
+ '<span style="font-size:var(--text-sm);color:var(--muted)">' + escHtml(tz) + '</span>' +
818
818
  '</div>' +
819
819
  '<div style="margin-top:8px">' + dayPills + '</div>' +
820
820
  '<div style="margin-top:6px">' +
@@ -822,7 +822,7 @@ function openEditPipelineModal(id) {
822
822
  '<span style="' + linkStyle + '" onclick="_quickSelectDays(\'weekdays\');_updatePlCronPreview()">Weekdays</span>' +
823
823
  '<span style="' + linkStyle + '" onclick="_quickSelectDays(\'weekends\');_updatePlCronPreview()">Weekends</span>' +
824
824
  '</div>' +
825
- '<div id="pl-cron-preview" style="margin-top:4px;font-size:11px;color:var(--blue)"></div>' +
825
+ '<div id="pl-cron-preview" style="margin-top:4px;font-size:var(--text-base);color:var(--blue)"></div>' +
826
826
  '</div>' +
827
827
  '</div>' +
828
828
  '<label style="color:var(--text);font-size:var(--text-md)">Stages (JSON array)<textarea id="pl-stages" rows="10" style="' + inputStyle + ';resize:vertical;font-family:Consolas,monospace">' + escHtml(JSON.stringify(p.stages || [], null, 2)) + '</textarea></label>' +
@@ -17,9 +17,9 @@ function openCreatePlanModal() {
17
17
  document.getElementById('modal-body').innerHTML =
18
18
  '<div style="display:flex;flex-direction:column;gap:10px">' +
19
19
  '<label style="color:var(--text);font-size:var(--text-md)">Title <input id="plan-new-title" style="' + inputStyle + '" placeholder="e.g. Add user authentication with JWT"></label>' +
20
- '<label style="color:var(--text);font-size:var(--text-md)">Project <select id="plan-new-project" style="' + inputStyle + '"><option value="">Multiple / cross-repo (agent routes per item)</option>' + projOpts + '</select><span style="display:block;font-size:10px;color:var(--muted);margin-top:2px">Pick a project to scope every item to one repo. Leave on cross-repo for plans that span multiple projects.</span></label>' +
21
- '<label style="color:var(--text);font-size:var(--text-md)">Plan Content <textarea id="plan-new-content" rows="12" style="' + inputStyle + ';resize:vertical;font-family:monospace;font-size:12px" placeholder="Write your plan in markdown...\n\nDescribe what needs to be built, the approach, requirements, and any constraints.\n\nThe squad will convert this into a PRD with structured work items."></textarea></label>' +
22
- '<div style="font-size:11px;color:var(--muted)">After creating, click Execute on the plan card to have an agent convert it into a PRD with work items.</div>' +
20
+ '<label style="color:var(--text);font-size:var(--text-md)">Project <select id="plan-new-project" style="' + inputStyle + '"><option value="">Multiple / cross-repo (agent routes per item)</option>' + projOpts + '</select><span style="display:block;font-size:var(--text-sm);color:var(--muted);margin-top:2px">Pick a project to scope every item to one repo. Leave on cross-repo for plans that span multiple projects.</span></label>' +
21
+ '<label style="color:var(--text);font-size:var(--text-md)">Plan Content <textarea id="plan-new-content" rows="12" style="' + inputStyle + ';resize:vertical;font-family:monospace;font-size:var(--text-md)" placeholder="Write your plan in markdown...\n\nDescribe what needs to be built, the approach, requirements, and any constraints.\n\nThe squad will convert this into a PRD with structured work items."></textarea></label>' +
22
+ '<div style="font-size:var(--text-base);color:var(--muted)">After creating, click Execute on the plan card to have an agent convert it into a PRD with work items.</div>' +
23
23
  '<div style="display:flex;justify-content:flex-end;gap:8px;margin-top:4px">' +
24
24
  '<button onclick="closeModal()" class="pr-pager-btn">Cancel</button>' +
25
25
  '<button onclick="_submitCreatePlan(event)" style="padding:6px 16px;background:var(--blue);color:#fff;border:none;border-radius:var(--radius-sm);cursor:pointer">Create Plan</button>' +
@@ -308,7 +308,7 @@ function renderPlans(plans) {
308
308
  actions = '<div class="plan-card-meta" style="margin-top:6px;color:var(--purple,#a855f7)">Revision in progress: ' + escapeHtml((p.revisionFeedback || '').slice(0, 100)) + '</div>';
309
309
  }
310
310
 
311
- const executeBtn = isDraft && (effectiveStatus === 'active' || effectiveStatus === 'draft') && !isArchived && !prdFile ? '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--green);font-weight:600" ' +
311
+ const executeBtn = isDraft && (effectiveStatus === 'active' || effectiveStatus === 'draft') && !isArchived && !prdFile ? '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--green);font-weight:600" ' +
312
312
  'onclick="event.stopPropagation();planExecute(\'' + escapeHtml(p.file) + '\',\'' + escapeHtml(p.project) + '\',this)">Execute</button>' : '';
313
313
  const showPause = effectiveStatus === 'dispatched' && prdFile && !isArchived;
314
314
  // Resume pill not needed โ€” paused state is handled by the actions block above
@@ -316,26 +316,26 @@ function renderPlans(plans) {
316
316
  const verifyWi = allWi.find(w => w.itemType === 'verify' && w.sourcePlan === prdFile);
317
317
  const hasVerifyWi = !!verifyWi;
318
318
  const showVerify = effectiveStatus === 'completed' && prdFile && !isArchived && !hasVerifyWi;
319
- const pauseBtn = showPause ? '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--yellow)" ' +
319
+ const pauseBtn = showPause ? '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--yellow)" ' +
320
320
  'onclick="event.stopPropagation();planPause(\'' + escapeHtml(prdFile) + '\',this)">Pause</button>' : '';
321
321
  const resumeBtn = showResume
322
- ? '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--green)" ' +
322
+ ? '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--green)" ' +
323
323
  'onclick="event.stopPropagation();planApprove(\'' + escapeHtml(prdFile) + '\',this)">Resume</button>'
324
324
  : '';
325
- const verifyBtn = showVerify ? '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--green)" ' +
325
+ const verifyBtn = showVerify ? '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--green)" ' +
326
326
  'onclick="event.stopPropagation();triggerVerify(\'' + escapeHtml(prdFile) + '\',this)">Verify</button>' : '';
327
327
  const showArchive = !isArchived;
328
328
  const archiveFile = prdFile || p.file;
329
329
  const archiveReady = p.archiveReady && !isArchived;
330
- const archiveBtn = showArchive ? '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px' +
330
+ const archiveBtn = showArchive ? '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px' +
331
331
  (archiveReady ? ';color:var(--green);font-weight:600;border:1px solid var(--green)' : '') + '" ' +
332
332
  'onclick="event.stopPropagation();planArchive(\'' + escapeHtml(archiveFile) + '\',this)">' +
333
333
  (archiveReady ? 'โœ“ Archive' : 'Archive') + '</button>' : '';
334
- const archiveReadyBadge = archiveReady ? '<span style="font-size:9px;font-weight:600;padding:1px 6px;border-radius:3px;background:rgba(63,185,80,0.15);color:var(--green);vertical-align:middle" title="Verification passed โ€” ready to archive">Ready to archive</span>' : '';
335
- const deleteBtn = !isArchived ? '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--red)" ' +
334
+ const archiveReadyBadge = archiveReady ? '<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);vertical-align:middle" title="Verification passed โ€” ready to archive">Ready to archive</span>' : '';
335
+ const deleteBtn = !isArchived ? '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;color:var(--red)" ' +
336
336
  'onclick="event.stopPropagation();planDelete(\'' + escapeHtml(p.file) + '\')">Delete</button>' : '';
337
337
 
338
- const versionBadge = p.version ? ' <span style="font-size:9px;font-weight:700;padding:1px 5px;border-radius:3px;background:rgba(56,139,253,0.15);color:var(--blue);vertical-align:middle">v' + p.version + '</span>' : '';
338
+ const versionBadge = p.version ? ' <span style="font-size:var(--text-xs);font-weight:700;padding:1px 5px;border-radius:3px;background:rgba(56,139,253,0.15);color:var(--blue);vertical-align:middle">v' + p.version + '</span>' : '';
339
339
  const statusColors = { 'completed': 'var(--green)', 'dispatched': 'var(--blue)', 'converting': 'var(--yellow)', 'paused': 'var(--muted)', 'awaiting-approval': 'var(--yellow)', 'approved': 'var(--green)', 'rejected': 'var(--red)', 'has-failures': 'var(--red)', 'revision-requested': 'var(--purple,#a855f7)', 'active': 'var(--muted)' };
340
340
  const cardClass = effectiveStatus === 'dispatched' || effectiveStatus === 'converting' ? 'working' : effectiveStatus === 'awaiting-approval' || effectiveStatus === 'paused' ? 'awaiting' : effectiveStatus;
341
341
  return '<div class="plan-card ' + cardClass + '" data-file="plans/' + escapeHtml(p.file) + '" style="cursor:pointer' + (isArchived ? ';opacity:0.7' : '') + '" onclick="if(shouldIgnoreSelectionClick(event))return;planView(\'' + escapeHtml(p.file) + '\')">' +
@@ -378,7 +378,7 @@ function renderPlans(plans) {
378
378
  window._archivedPlans = archivedPlans;
379
379
  window._archivedPlanRenderer = renderPlanCard;
380
380
  html += '<div style="margin-top:8px;text-align:right;position:relative" data-file="plan-archives">' +
381
- '<button class="pr-pager-btn" style="font-size:10px;padding:3px 10px;color:var(--muted)" onclick="openArchivedPlansModal()">' +
381
+ '<button class="pr-pager-btn" style="font-size:var(--text-sm);padding:3px 10px;color:var(--muted)" onclick="openArchivedPlansModal()">' +
382
382
  'View Archives (' + archivedPlans.length + ')' +
383
383
  '</button>' +
384
384
  '</div>';
@@ -401,7 +401,7 @@ function openArchivedPlansModal() {
401
401
  const completed = p.completedAt ? p.completedAt.slice(0, 10) : '';
402
402
  return '<div class="plan-card" data-file="plans/' + escapeHtml(p.file) + '" style="cursor:pointer;opacity:0.8" onclick="if(shouldIgnoreSelectionClick(event))return;planView(\'' + escapeHtml(p.file) + '\')">' +
403
403
  '<div class="plan-card-header">' +
404
- '<div><div class="plan-card-title" style="font-size:13px">' + escapeHtml(p.summary || p.file) + '</div>' +
404
+ '<div><div class="plan-card-title" style="font-size:var(--text-lg)">' + escapeHtml(p.summary || p.file) + '</div>' +
405
405
  '<div class="plan-card-meta">' +
406
406
  '<span style="color:var(--green);font-weight:600">Completed</span>' +
407
407
  (p.project ? '<span>' + escapeHtml(p.project) + '</span>' : '') +
@@ -461,11 +461,11 @@ function planReexecuteModal(file, project) {
461
461
  document.getElementById('modal-title').textContent = 'Re-execute Plan';
462
462
  document.getElementById('modal-body').innerHTML =
463
463
  '<div style="display:flex;flex-direction:column;gap:10px">' +
464
- '<div style="font-size:12px;color:var(--muted)">' + escapeHtml(file) + '</div>' +
464
+ '<div style="font-size:var(--text-md);color:var(--muted)">' + escapeHtml(file) + '</div>' +
465
465
  '<label style="color:var(--text);font-size:var(--text-md)">Steer the regeneration โ€” what should be fixed in the PRD?' +
466
466
  '<textarea id="plan-reexec-feedback" rows="6" style="' + inputStyle + ';resize:vertical" placeholder="(Optional) Describe what was wrong with the previous PRD or what the agent should change..."></textarea>' +
467
467
  '</label>' +
468
- '<div style="font-size:11px;color:var(--muted)">Leave blank to re-run without steering. The agent will read the existing PRD and rewrite it.</div>' +
468
+ '<div style="font-size:var(--text-base);color:var(--muted)">Leave blank to re-run without steering. The agent will read the existing PRD and rewrite it.</div>' +
469
469
  '<div style="display:flex;justify-content:flex-end;gap:8px;margin-top:4px">' +
470
470
  '<button onclick="closeModal()" class="pr-pager-btn">Cancel</button>' +
471
471
  '<button onclick="planReexecuteSubmit(\'' + escapeHtml(file) + '\',\'' + escapeHtml(project || '') + '\')" style="padding:6px 16px;background:var(--blue);color:#fff;border:none;border-radius:var(--radius-sm);cursor:pointer">Re-execute</button>' +
@@ -548,7 +548,7 @@ function _renderPlanModal(normalizedFile, raw, lastMod) {
548
548
  if (normalizedFile.endsWith('.json')) {
549
549
  let plan;
550
550
  try { plan = JSON.parse(raw); } catch (e) {
551
- document.getElementById('modal-body').innerHTML = '<p style="color:var(--red)">Failed to parse plan JSON: ' + escapeHtml(e.message) + '</p><pre style="font-size:10px;max-height:200px;overflow:auto">' + escapeHtml((raw || '').slice(0, 500)) + '</pre>';
551
+ document.getElementById('modal-body').innerHTML = '<p style="color:var(--red)">Failed to parse plan JSON: ' + escapeHtml(e.message) + '</p><pre style="font-size:var(--text-sm);max-height:200px;overflow:auto">' + escapeHtml((raw || '').slice(0, 500)) + '</pre>';
552
552
  return;
553
553
  }
554
554
  title = plan.plan_summary || normalizedFile;
@@ -590,7 +590,7 @@ function _renderPlanModal(normalizedFile, raw, lastMod) {
590
590
  const isDraft = isMdPlan && !prdFile && !isCompleted;
591
591
  const isNeedsAction = (effectiveStatus === 'awaiting-approval' || effectiveStatus === 'paused') && !isArchived;
592
592
 
593
- const bs = 'font-size:10px;padding:2px 10px'; // button style
593
+ const bs = 'font-size:var(--text-sm);padding:2px 10px'; // button style
594
594
  let modalActions = '';
595
595
 
596
596
  // Approve/Reject for awaiting-approval or paused
@@ -632,11 +632,11 @@ function _renderPlanModal(normalizedFile, raw, lastMod) {
632
632
  modalActions += '<button class="pr-pager-btn" style="' + bs + ';color:var(--red)" onclick="planDelete(\'' + escapeHtml(normalizedFile) + '\')">Delete</button>';
633
633
  }
634
634
 
635
- const lastModLabel = lastMod ? '<div style="font-size:10px;color:var(--muted);font-weight:400;margin-top:2px">Last updated: ' + formatLocalDateTime(lastMod) + '</div>' : '';
635
+ const lastModLabel = lastMod ? '<div style="font-size:var(--text-sm);color:var(--muted);font-weight:400;margin-top:2px">Last updated: ' + formatLocalDateTime(lastMod) + '</div>' : '';
636
636
  const actionBtns = '<div style="display:flex;gap:4px;flex-wrap:wrap;margin-top:4px">' + modalActions + '</div>';
637
637
 
638
638
  // eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; all user data wrapped in escapeHtml() (fields: plan title, version label, action target files)
639
- document.getElementById('modal-title').innerHTML = escapeHtml(title) + (versionLabel ? ' <span style="font-size:11px;font-weight:700;padding:1px 6px;border-radius:3px;background:rgba(56,139,253,0.15);color:var(--blue)">' + escapeHtml(versionLabel) + '</span>' : '') + lastModLabel + actionBtns;
639
+ document.getElementById('modal-title').innerHTML = escapeHtml(title) + (versionLabel ? ' <span style="font-size:var(--text-base);font-weight:700;padding:1px 6px;border-radius:3px;background:rgba(56,139,253,0.15);color:var(--blue)">' + escapeHtml(versionLabel) + '</span>' : '') + lastModLabel + actionBtns;
640
640
  const modalBody = document.getElementById('modal-body');
641
641
  const scrollTop = modalBody.scrollTop;
642
642
  if (normalizedFile.endsWith('.json')) {
@@ -928,13 +928,13 @@ function _renderVerifyBadge(verifyWi) {
928
928
  const planFile = verifyWi.sourcePlan || '';
929
929
  const planSlug = planFile.replace('.json', '');
930
930
  const verifyPr = allPrs.find(pr => (pr.prdItems || []).includes(verifyWi.id) || (pr.branch && pr.branch.includes(planSlug) && (pr.title || '').includes('[E2E]')));
931
- const prLink = verifyPr?.url ? ' <a href="' + escapeHtml(verifyPr.url) + '" target="_blank" onclick="event.stopPropagation()" style="color:var(--blue);text-decoration:underline;font-size:9px">' + escapeHtml(verifyPr.id || 'E2E PR') + '</a>' : '';
931
+ const prLink = verifyPr?.url ? ' <a href="' + escapeHtml(verifyPr.url) + '" target="_blank" onclick="event.stopPropagation()" style="color:var(--blue);text-decoration:underline;font-size:var(--text-xs)">' + escapeHtml(verifyPr.id || 'E2E PR') + '</a>' : '';
932
932
  // Testing guide. verifyGuides moved to /api/verify-guides
933
933
  // (window._lastVerifyGuides set by refresh.js).
934
934
  const guides = window._lastVerifyGuides || [];
935
935
  const guide = guides.find(g => g.planFile === planFile);
936
- const guideLink = guide ? ' <span onclick="event.stopPropagation();openVerifyGuide(\'' + escapeHtml(guide.file) + '\')" style="color:var(--green);cursor:pointer;text-decoration:underline;font-size:9px">Testing Guide</span>' : '';
937
- return '<span style="font-size:9px;font-weight:600;color:' + color + ';padding:0 4px">' + label + '</span>' + prLink + guideLink;
936
+ const guideLink = guide ? ' <span onclick="event.stopPropagation();openVerifyGuide(\'' + escapeHtml(guide.file) + '\')" style="color:var(--green);cursor:pointer;text-decoration:underline;font-size:var(--text-xs)">Testing Guide</span>' : '';
937
+ return '<span style="font-size:var(--text-xs);font-weight:600;color:' + color + ';padding:0 4px">' + label + '</span>' + prLink + guideLink;
938
938
  }
939
939
 
940
940
  async function openVerifyGuide(file) {
@@ -942,7 +942,7 @@ async function openVerifyGuide(file) {
942
942
  const normalizedFile = normalizePlanFile(file);
943
943
  const content = await fetch('/api/plans/' + encodeURIComponent(normalizedFile)).then(r => r.text());
944
944
  document.getElementById('modal-title').innerHTML = 'Manual Testing Guide' +
945
- ' <button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;margin-left:8px;vertical-align:middle" onclick="openArchivedPrdModal()">Back</button>';
945
+ ' <button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;margin-left:8px;vertical-align:middle" onclick="openArchivedPrdModal()">Back</button>';
946
946
  // eslint-disable-next-line no-unsanitized/property -- reason: renderMd() escapes all user-controlled fields before assembling HTML (see dashboard/js/utils.js)
947
947
  document.getElementById('modal-body').innerHTML = renderMd(content);
948
948
  _modalDocContext = { title: 'Manual Testing Guide', content, selection: '' };